as_dataop.cpp

Fri, 28 Nov 2008 11:21:08 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 28 Nov 2008 11:21:08 +0100
changeset 1
d64aaa7d146f
child 3
c1941114ca88
permissions
-rw-r--r--

Fork project trunk at version 0.7.7 to maintain for future usage.
The original Cable & Wireless development team no longer exists.
The OSSP CVS repository is unavailable (cvs co ossp-pkg/as fails),
however http://cvs.ossp.org/dirview?d=ossp-pkg/as/as-gui is working.

michael@1 1 //
michael@1 2 // OSSP asgui - Accounting system graphical user interface
michael@1 3 // Copyright (c) 2002-2004 The OSSP Project (http://www.ossp.org/)
michael@1 4 // Copyright (c) 2002-2004 Ralf S. Engelschall <rse@engelschall.com>
michael@1 5 // Copyright (c) 2002-2004 Michael Schloh von Bennewitz <michael@schloh.com>
michael@1 6 // Copyright (c) 2002-2004 Cable & Wireless Telecommunications Services GmbH
michael@1 7 //
michael@1 8 // This file is part of OSSP asgui, an accounting system graphical user
michael@1 9 // interface which can be found at http://www.ossp.org/pkg/tool/asgui/.
michael@1 10 //
michael@1 11 // Permission to use, copy, modify, and distribute this software for
michael@1 12 // any purpose with or without fee is hereby granted, provided that
michael@1 13 // the above copyright notice and this permission notice appear in all
michael@1 14 // copies.
michael@1 15 //
michael@1 16 // THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
michael@1 17 // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
michael@1 18 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
michael@1 19 // IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
michael@1 20 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
michael@1 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
michael@1 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
michael@1 23 // USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
michael@1 24 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
michael@1 25 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
michael@1 26 // OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
michael@1 27 // SUCH DAMAGE.
michael@1 28 //
michael@1 29 // as_dataops.cpp: ISO C++ implementation
michael@1 30 //
michael@1 31
michael@1 32 // System headers
michael@1 33 #include <map>
michael@1 34 #include <string>
michael@1 35
michael@1 36 // Qt general headers
michael@1 37 #include <qregexp.h> // Portable regular expressions
michael@1 38 #include <qdatetime.h>
michael@1 39 #include <qmessagebox.h>
michael@1 40 #include <qtextstream.h>
michael@1 41 #include <qpopupmenu.h>
michael@1 42 #include <qfile.h>
michael@1 43
michael@1 44 // User interface
michael@1 45 #include "as_const.h" // Application constants
michael@1 46 #include "as_tableitem.h" // For class RtTableItem
michael@1 47 #include "as_crc.h" // For quality strings
michael@1 48 #include "as_uuid.h" // UUID classes
michael@1 49 #include "as_table.h" // TiTable class
michael@1 50
michael@1 51 // Icon pixel maps
michael@1 52 #include "as_gfx/statok.xpm" // static const char *s_kpcStatokay_xpm[]
michael@1 53 #include "as_gfx/staterr.xpm" // static const char *s_kpcStaterror_xpm[]
michael@1 54 #include "as_gfx/statwrn.xpm" // static const char *s_kpcStatwarn_xpm[]
michael@1 55
michael@1 56
michael@1 57 //
michael@1 58 // Convenience method to load accounts from a file
michael@1 59 //
michael@1 60 void Titraqform::loadAccounts(QFile &Fileobj)
michael@1 61 {
michael@1 62 if (Fileobj.isOpen()) { // Check state of file
michael@1 63 Fileobj.flush(); // Begin processing file cleanly
michael@1 64 QTextStream Account(&Fileobj); // Convert data to stream
michael@1 65 this->loadAccounts(Account); // Pass off to do the real work
michael@1 66 }
michael@1 67 else {
michael@1 68 if (!Fileobj.open(IO_ReadOnly)) { // Try to open file
michael@1 69 QString Readerrstr;
michael@1 70 Readerrstr = trUtf8(TITRAQ_READAFILFAIL).arg(Fileobj.name());
michael@1 71 throw Genexcept(Readerrstr.ascii());
michael@1 72 }
michael@1 73 else
michael@1 74 Fileobj.flush(); // Begin processing file cleanly
michael@1 75 QTextStream Account(&Fileobj); // Convert data to stream
michael@1 76 this->loadAccounts(Account); // Pass off to do the real work
michael@1 77 Fileobj.close(); // Finish fileop by closing
michael@1 78 }
michael@1 79 }
michael@1 80
michael@1 81 //
michael@1 82 // Load accounts themselves data from a stream
michael@1 83 //
michael@1 84 void Titraqform::loadAccounts(QTextStream &Tstream)
michael@1 85 {
michael@1 86 using namespace std; // Needed for hash tables with hmap
michael@1 87 map<string, int> Hashnames; // Hashtable for storing names
michael@1 88 map<int, string> Hashnums; // Hashtable for storing repetitions
michael@1 89 map<string, int>::iterator Nameiter; // The hashtable name iterator
michael@1 90 map<int, string>::iterator Numiter; // The hashtable number iterator
michael@1 91
michael@1 92 QString Line; // Used for linewise editing and whitespace eating
michael@1 93
michael@1 94 // Eat lines until reading the start accounts token
michael@1 95 while (!Line.startsWith(trUtf8("%!AS-ACCOUNTS")) && !Tstream.atEnd()) {
michael@1 96 Line = QString(""); // Empty line for later inspection
michael@1 97 Line = Tstream.readLine(); // Get a new line to examine
michael@1 98 }
michael@1 99
michael@1 100 // Strip out extra line feeds in stream
michael@1 101 while (Line.isEmpty() && !Tstream.atEnd()) {
michael@1 102 Tstream.skipWhiteSpace(); // Strip and get
michael@1 103 Line = Tstream.readLine(); // the new line
michael@1 104 if (Line.at(0) == QChar('#')) // Remove comments
michael@1 105 Line = QString("");
michael@1 106 }
michael@1 107
michael@1 108 // Set the accounts choices by linewise reading from the input
michael@1 109 // stream and parsing the corresponding account fields out of it
michael@1 110 while (!Line.isEmpty()) {
michael@1 111 QString Temp; // For reading from stream
michael@1 112 QTextStream Asline(&Line, IO_ReadOnly); // Convert a single line
michael@1 113
michael@1 114 Asline.skipWhiteSpace(); // Remove whitespaces
michael@1 115 Asline >> Temp; // Copy revision indicator
michael@1 116
michael@1 117 if (Temp == QString(QChar('R'))) { // Copy the account field
michael@1 118 Asline >> Temp; // to temporary for transfer
michael@1 119 string Convstring = Temp; // Convert to string (can't cast?)
michael@1 120 Hashnames[Convstring] += Hashnames[Convstring];
michael@1 121 }
michael@1 122
michael@1 123 Line = QString(""); // Clear line for next round
michael@1 124 while (Line.isEmpty() && !Tstream.atEnd()) {
michael@1 125 Tstream.skipWhiteSpace(); // Strip and get
michael@1 126 Line = Tstream.readLine(); // the new line
michael@1 127 if (Line.at(0) == QChar('#')) // Remove comments
michael@1 128 Line = QString("");
michael@1 129 }
michael@1 130 }
michael@1 131
michael@1 132 // Hashnames.insert(map<string, int>::value_type((string)QString, int));
michael@1 133 for (Nameiter = Hashnames.begin(); Nameiter != Hashnames.end(); Nameiter++)
michael@1 134 Hashnums[Nameiter->second] += Nameiter->first + '\n';
michael@1 135
michael@1 136 // FIXME: Put this in loadData, to load custom and most used task names before
michael@1 137 // FIXME: default listings are sorted and inserted
michael@1 138 for (Numiter = Hashnums.begin(); Numiter != Hashnums.end(); Numiter++) {
michael@1 139
michael@1 140 // Count the number of lines of sorted task names
michael@1 141 int nNumlines = QString(Numiter->second).contains('\n');
michael@1 142
michael@1 143 // Iterate through the lines of task names, feeding them into the menu
michael@1 144 for (int nIter = 0; nIter < nNumlines; nIter++)
michael@1 145 *m_pTaskentries << QString(Numiter->second).section('\n', nIter, nIter);
michael@1 146 }
michael@1 147 }
michael@1 148
michael@1 149 //
michael@1 150 // Convenience method to load personal data from a file
michael@1 151 //
michael@1 152 void Titraqform::loadData(QFile &Fileobj)
michael@1 153 {
michael@1 154 if (Fileobj.isOpen()) { // Check state of file
michael@1 155 Fileobj.flush(); // Begin processing file cleanly
michael@1 156 QTextStream Asentry(&Fileobj); // Convert data to stream
michael@1 157 this->loadData(Asentry); // Pass off to do the real work
michael@1 158 }
michael@1 159 else {
michael@1 160 if (!Fileobj.open(IO_ReadOnly)) // Try to open file
michael@1 161 throw Genexcept(trUtf8(TITRAQ_READPFILFAIL));
michael@1 162 else
michael@1 163 Fileobj.flush(); // Begin processing file cleanly
michael@1 164 QTextStream Asentry(&Fileobj); // Convert data to stream
michael@1 165 this->loadData(Asentry); // Pass off to do the real work
michael@1 166 Fileobj.close(); // Finish fileop by closing
michael@1 167 }
michael@1 168 }
michael@1 169
michael@1 170 //
michael@1 171 // Load personal data from a stream
michael@1 172 //
michael@1 173 void Titraqform::loadData(QTextStream &Tstream)
michael@1 174 {
michael@1 175 bool bValid = true; // Used to warn on globally invalid accounting data
michael@1 176 int nIter = 0; // Iterator used in loop and also as a count
michael@1 177 QString Line; // Used for linewise editing and whitespace eating
michael@1 178 QString Bitbucket; // Used for null device until we find a better way
michael@1 179
michael@1 180 QPixmap Statokay(s_kpcStatokay_xpm);
michael@1 181 QPixmap Statwarn(s_kpcStatwarn_xpm);
michael@1 182 QPixmap Staterror(s_kpcStaterror_xpm);
michael@1 183
michael@1 184 // Strip out extra line feeds at stream start
michael@1 185 while (Line.isEmpty() && !Tstream.atEnd()) {
michael@1 186 Tstream.skipWhiteSpace(); // Strip and get
michael@1 187 Line = Tstream.readLine(); // the new line
michael@1 188 if (Line.at(0) == QChar('#')) // Remove comments
michael@1 189 Line = QString("");
michael@1 190 }
michael@1 191
michael@1 192 // Strip out extra line feeds after reading the data symbol
michael@1 193 Line = QString(""); // Reset our line
michael@1 194 while (Line.isEmpty() && !Tstream.atEnd()) {
michael@1 195 Tstream.skipWhiteSpace(); // Strip and get
michael@1 196 Line = Tstream.readLine(); // the new line
michael@1 197 if (Line.at(0) == QChar('#')) // Remove comments
michael@1 198 Line = QString("");
michael@1 199 }
michael@1 200
michael@1 201 // // Going into data churning, so prepare date and time parsing and conversion
michael@1 202 // Converdate.setSeparator(trUtf8("."));
michael@1 203 // Convertime.setSeparator(trUtf8(":"));
michael@1 204
michael@1 205 // Optimize viewing by repainting cells only once after processing
michael@1 206 m_pMaintable->setUpdatesEnabled(false);
michael@1 207
michael@1 208 // Set the table text by linewise reading from the input stream
michael@1 209 // and parsing date, time, account, and other columns out of it
michael@1 210 while (!Line.isEmpty()) {
michael@1 211 bool bValid = true; // Warns on linewise invalid accounting data
michael@1 212 QString User, Guid, Crc, Rev; // Valid admin fields
michael@1 213 QString Date, Start, Finish, Account, Amount, Remark; // Valid user fields
michael@1 214 QTextStream Asline(&Line, IO_ReadOnly); // Convert a single line now
michael@1 215
michael@1 216 if (nIter % g_knBlocks == 0) // Add blocks of rows to optimize loading
michael@1 217 m_pMaintable->setNumRows(m_pMaintable->numRows() + g_knBlocks);
michael@1 218
michael@1 219 Asline.skipWhiteSpace(); // Remove whitespaces
michael@1 220 Asline >> User; // Copy the user field
michael@1 221 if (!User.isEmpty())
michael@1 222 m_pMaintable->setText(nIter, TITRAQ_IDXUSER, User);
michael@1 223 else
michael@1 224 bValid = false;
michael@1 225
michael@1 226 Asline.skipWhiteSpace(); // Remove whitespaces
michael@1 227 Asline >> Guid; // Copy the GUID field
michael@1 228 // Postpone actual text delivery, to autoinsert GUIDs!
michael@1 229
michael@1 230 Asline.skipWhiteSpace(); // Remove whitespaces
michael@1 231 Asline >> Crc; // Copy the CRC field
michael@1 232 // Postpone actual text delivery, to autoinsert CRCs!
michael@1 233
michael@1 234 Asline.skipWhiteSpace(); // Remove whitespaces
michael@1 235 Asline >> Rev; // Copy the rev field
michael@1 236 if (!Rev.isEmpty())
michael@1 237 m_pMaintable->setText(nIter, TITRAQ_IDXREV, Rev);
michael@1 238 else
michael@1 239 bValid = false;
michael@1 240
michael@1 241 Asline.skipWhiteSpace(); // Remove whitespaces
michael@1 242 Asline >> Date; // Copy the date field
michael@1 243 if (!Date.isEmpty())
michael@1 244 m_pMaintable->setText(nIter, TITRAQ_IDXDATE, Date);
michael@1 245 else
michael@1 246 bValid = false;
michael@1 247
michael@1 248 Asline.skipWhiteSpace(); // Remove whitespaces
michael@1 249 Asline >> Start; // Copy the start field
michael@1 250 if (!Start.isEmpty())
michael@1 251 m_pMaintable->setText(nIter, TITRAQ_IDXSTART, Start);
michael@1 252 else
michael@1 253 bValid = false;
michael@1 254
michael@1 255 Asline.skipWhiteSpace(); // Remove whitespaces
michael@1 256 Asline >> Finish; // Copy the finish field
michael@1 257 if (!Finish.isEmpty())
michael@1 258 m_pMaintable->setText(nIter, TITRAQ_IDXFINISH, Finish);
michael@1 259 else
michael@1 260 bValid = false;
michael@1 261
michael@1 262 Asline.skipWhiteSpace(); // Remove whitespaces
michael@1 263 Asline >> Amount; // Copy the amount field
michael@1 264 if (!Amount.isEmpty())
michael@1 265 m_pMaintable->setText(nIter, TITRAQ_IDXAMOUNT, Amount);
michael@1 266 else
michael@1 267 bValid = false;
michael@1 268
michael@1 269 Asline.skipWhiteSpace(); // Remove whitespaces
michael@1 270 Asline >> Account; // Copy the account field
michael@1 271 if (!Account.isEmpty()) {
michael@1 272 QTableItem *pOld = m_pMaintable->item(nIter, TITRAQ_IDXTASK);
michael@1 273 delete(pOld); // Get rid of the old before going with the new
michael@1 274 RtTableItem *pSwapitem = new RtTableItem(m_pMaintable, QTableItem::WhenCurrent, Account);
michael@1 275 pSwapitem->setAlignment(AlignLeft | AlignVCenter);
michael@1 276 m_pMaintable->setItem(nIter, TITRAQ_IDXTASK, pSwapitem);
michael@1 277 }
michael@1 278 else
michael@1 279 bValid = false;
michael@1 280
michael@1 281 Asline.skipWhiteSpace(); // Remove whitespaces
michael@1 282 Remark = Asline.read(); // Copy the remark field
michael@1 283
michael@1 284 QRegExp Quoted("\"(.*[^\\\\])\""); // Get rid of
michael@1 285 Quoted.search(Remark); // surrounding double
michael@1 286 Remark = Quoted.cap(Quoted.numCaptures()); // quotes, and
michael@1 287 Remark.replace(QRegExp("\\\\(.)"), QString("\\1")); // escape backslashes
michael@1 288
michael@1 289 if (!Remark.isEmpty())
michael@1 290 m_pMaintable->setText(nIter, TITRAQ_IDXREMARK, Remark);
michael@1 291
michael@1 292 if (bValid) { // Show a bitmap to signal valid or error state
michael@1 293 m_pMaintable->setText(nIter, TITRAQ_IDXSTATUS, QString(QChar('O')));
michael@1 294 m_pMaintable->setPixmap(nIter, TITRAQ_IDXSTATUS, Statokay);
michael@1 295 }
michael@1 296 else {
michael@1 297 m_pMaintable->setText(nIter, TITRAQ_IDXSTATUS, QString(QChar('E')));
michael@1 298 m_pMaintable->setPixmap(nIter, TITRAQ_IDXSTATUS, Staterror);
michael@1 299 }
michael@1 300
michael@1 301 // Set the GUID text here, in case we need to generate a fresh value
michael@1 302 if (!Guid.isEmpty()) {
michael@1 303 if (Guid != ".") // This means, generate a fresh GUID value
michael@1 304 m_pMaintable->setText(nIter, TITRAQ_IDXGUID, Guid);
michael@1 305 else {
michael@1 306 AS::Uuid Guidi; // For GUID production
michael@1 307 Guidi.genId();
michael@1 308 m_pMaintable->setText(nIter, TITRAQ_IDXGUID, Guidi.getString());
michael@1 309 }
michael@1 310 }
michael@1 311 else // if isEmpty()
michael@1 312 bValid = false;
michael@1 313
michael@1 314 // Set the CRC text here, in case we need to generate a fresh value
michael@1 315 if (!Crc.isEmpty()) {
michael@1 316 if (Crc != ".") // This means, generate a fresh CRC value
michael@1 317 m_pMaintable->setText(nIter, TITRAQ_IDXCRC, "0x" + Crc);
michael@1 318 else {
michael@1 319 // Make our long tuple to run through the CRC32 generator
michael@1 320 Qualistring Testuple = User + Guid + Rev + Date + Start;
michael@1 321 Testuple += Finish + Amount + Account + Remark;
michael@1 322 U32 Valcrc = Testuple.getCrc(); // Finally set the checksum to its new value
michael@1 323 QString Crcstr = QString::number(Valcrc, 16).rightJustify(8, '0');
michael@1 324 m_pMaintable->setText(nIter, TITRAQ_IDXCRC, "0x" + Crcstr);
michael@1 325 }
michael@1 326 }
michael@1 327 else // if isEmpty()
michael@1 328 bValid = false;
michael@1 329
michael@1 330 nIter++; // The big increment
michael@1 331 Line = QString(""); // Clear line for next round
michael@1 332
michael@1 333 while (Line.isEmpty() && !Tstream.atEnd()) { // Strip and get
michael@1 334 Tstream.skipWhiteSpace(); // Remove white
michael@1 335 Line = Tstream.readLine(); // the new line
michael@1 336 if (Line.at(0) == QChar('#')) // Remove comments
michael@1 337 Line = QString("");
michael@1 338 }
michael@1 339 }
michael@1 340
michael@1 341 // // Start sorting order and direction correctly according to user preferences
michael@1 342 // int nSortcol = (int)m_pPrefs->getNumber(TITRAQ_PREFSORTCOL, TITRAQ_DEFSORTCOL);
michael@1 343 // bool bSortdir = m_pPrefs->getBool(TITRAQ_PREFSORTDIR, TITRAQ_DEFSORTDIR);
michael@1 344 // m_pMaintable->setSortdir(!bSortdir); // Hack! Fake sortdir so we start right
michael@1 345 // m_pMaintable->sortColumn(nSortcol, bSortdir);
michael@1 346
michael@1 347 // Write nonsaving line numbers for all rows
michael@1 348 for (int nIter = m_pMaintable->numRows() - 1; nIter >= 0; nIter--)
michael@1 349 m_pMaintable->setText(nIter, TITRAQ_IDXLINE, QString::number(nIter).rightJustify(4, QChar('0')));
michael@1 350
michael@1 351 m_pMaintable->setUpdatesEnabled(true); // Update and repaint
michael@1 352 m_pMaintable->setNumRows(nIter); // No excess rows
michael@1 353 m_pMaintable->setCurrentCell(nIter - 1, 0); // Move focus to last row
michael@1 354 m_pMaintable->ensureCellVisible(nIter - 1, 0); // Scroll please
michael@1 355
michael@1 356 if (!bValid)
michael@1 357 throw Genexcept("Warning: invalid accounting data.");
michael@1 358 }
michael@1 359
michael@1 360 //
michael@1 361 // Convenience method to save accounting data to a file
michael@1 362 //
michael@1 363 void Titraqform::saveData(QFile &Fileobj)
michael@1 364 {
michael@1 365 if (Fileobj.isOpen()) { // Check state of file
michael@1 366 Fileobj.flush(); // Begin processing file cleanly
michael@1 367 QTextStream Asentry(&Fileobj); // Convert data to stream
michael@1 368 this->saveData(Asentry); // Pass off to do the real work
michael@1 369 }
michael@1 370 else {
michael@1 371 if (!Fileobj.open(IO_WriteOnly)) // Try to open file
michael@1 372 throw Genexcept(trUtf8(TITRAQ_READPFILFAIL));
michael@1 373 QTextStream Asentry(&Fileobj); // Convert data to stream
michael@1 374 this->saveData(Asentry); // Pass off to do the real work
michael@1 375 Fileobj.close(); // Finish fileop by closing
michael@1 376 }
michael@1 377 }
michael@1 378
michael@1 379 //
michael@1 380 // Save accounting data to a stream
michael@1 381 //
michael@1 382 void Titraqform::saveData(QTextStream &Tstream)
michael@1 383 {
michael@1 384 const int nRows = m_pMaintable->numRows(); // Max rows used in loop
michael@1 385 QString Tempfield; // Current field string
michael@1 386 QString Strsearch; // String to strip search
michael@1 387 QRegExp Stripper("\\s*$"); // Pattern to strip off
michael@1 388
michael@1 389 // Start by prepending the AS data format version symbol
michael@1 390 Tstream << TITRAQ_DATAPATTERN << TITRAQ_DATAVERSIONMAJ
michael@1 391 << QChar('.') << TITRAQ_DATAVERSIONMIN << endl;
michael@1 392
michael@1 393 // Linewise save from the main table date, time, account, and others
michael@1 394 for (int nIter = 0; nIter < nRows; nIter++) {
michael@1 395 Tempfield = m_pMaintable->text(nIter, TITRAQ_IDXUSER); // Load user field text
michael@1 396 if (Tempfield != NULL)
michael@1 397 Tstream << Tempfield; // Save user field text
michael@1 398
michael@1 399 Tempfield = m_pMaintable->text(nIter, TITRAQ_IDXGUID); // Load GUID field text
michael@1 400 if (Tempfield != NULL)
michael@1 401 Tstream << trUtf8(" ") << Tempfield; // Save GUID field text
michael@1 402
michael@1 403 Tempfield = m_pMaintable->text(nIter, TITRAQ_IDXCRC); // Load CRC field text
michael@1 404 Tempfield.remove("0x");
michael@1 405 if (Tempfield != NULL)
michael@1 406 Tstream << trUtf8(" ") << Tempfield; // Save CRC field text
michael@1 407
michael@1 408 Tempfield = m_pMaintable->text(nIter, TITRAQ_IDXREV); // Load rev field text
michael@1 409 if (Tempfield != NULL)
michael@1 410 Tstream << trUtf8(" ") << Tempfield; // Save rev field text
michael@1 411
michael@1 412 Tempfield = m_pMaintable->text(nIter, TITRAQ_IDXDATE); // Load date field text
michael@1 413 if (Tempfield != NULL)
michael@1 414 Tstream << trUtf8(" ") << Tempfield; // Save date field text
michael@1 415
michael@1 416 Tempfield = m_pMaintable->text(nIter, TITRAQ_IDXSTART); // Load start field text
michael@1 417 if (Tempfield != NULL)
michael@1 418 Tstream << trUtf8(" ") << Tempfield; // Save start field text
michael@1 419
michael@1 420 Tempfield = m_pMaintable->text(nIter, TITRAQ_IDXFINISH); // Load end field text
michael@1 421 if (Tempfield != NULL)
michael@1 422 Tstream << trUtf8(" ") << Tempfield; // Save end field text
michael@1 423
michael@1 424 Tempfield = m_pMaintable->text(nIter, TITRAQ_IDXAMOUNT); // Load amount field text
michael@1 425 if (Tempfield != NULL)
michael@1 426 Tstream << trUtf8(" ") << Tempfield; // Save amount
michael@1 427
michael@1 428 Tempfield = m_pMaintable->text(nIter, TITRAQ_IDXTASK); // Load acct field text
michael@1 429 if (Tempfield != NULL)
michael@1 430 Tstream << trUtf8(" ") << Tempfield; // Save acct field text
michael@1 431
michael@1 432 Tempfield = m_pMaintable->text(nIter, TITRAQ_IDXREMARK); // Load remark field text
michael@1 433 Tstream << trUtf8(" \""); // Save beginning double quote
michael@1 434 if (Tempfield != NULL) {
michael@1 435 Strsearch = QRegExp::escape(Tempfield); // Incoming string escaped
michael@1 436 Stripper.search(Strsearch);
michael@1 437 Tempfield.truncate(Stripper.pos()); // Cut off whitespace
michael@1 438 Tempfield.replace(QChar('\\'), QString("\\\\")); // Escape back slashes
michael@1 439 Tempfield.replace(QChar('\"'), QString("\\\"")); // Escape double quotes
michael@1 440 Tstream << Tempfield; // Save remark field text
michael@1 441 }
michael@1 442 Tstream << trUtf8("\""); // Save ending double quote
michael@1 443
michael@1 444 Tstream << endl; // Append a newline
michael@1 445 }
michael@1 446 }
michael@1 447
michael@1 448 //
michael@1 449 // Convenience method to validate AS data in a file
michael@1 450 //
michael@1 451 const bool Titraqform::validateData(QFile &Filin) const
michael@1 452 {
michael@1 453 QString Firstline; // Will contain the first line of text
michael@1 454 bool bRet = false; // Set the initial return value
michael@1 455
michael@1 456 if (Filin.isOpen()) { // Check open state of file
michael@1 457 Filin.flush(); // Not sure if this is needed
michael@1 458 Filin.reset(); // Set the file index position to 0
michael@1 459 Filin.readLine(Firstline, QString(TITRAQ_DATAPATTERN).length() + 2L);
michael@1 460 }
michael@1 461 else {
michael@1 462 if (!Filin.open(IO_ReadOnly)) // Try to open file
michael@1 463 throw Genexcept(trUtf8(TITRAQ_READPFILFAIL));
michael@1 464 else { // File is now open
michael@1 465 Filin.readLine(Firstline, QString(TITRAQ_DATAPATTERN).length() + 2L);
michael@1 466 Filin.close(); // Remember to close
michael@1 467 }
michael@1 468 }
michael@1 469
michael@1 470 try { // Pass off to worker method
michael@1 471 bRet = this->validateData(Firstline);
michael@1 472 }
michael@1 473 catch (Genexcept &) {
michael@1 474 throw; // Rethrow onwards
michael@1 475 }
michael@1 476 return bRet;
michael@1 477 }
michael@1 478
michael@1 479 //
michael@1 480 // Validate the AS data pattern in a line
michael@1 481 //
michael@1 482 const bool Titraqform::validateData(QString &Linin) const
michael@1 483 {
michael@1 484 bool bRet = false; // Initial return value
michael@1 485
michael@1 486 // Ensure that the right data version pattern precedes the data
michael@1 487 QString Datapattern = QString(TITRAQ_DATAPATTERN);
michael@1 488 if (!Linin.startsWith(Datapattern)) { // Incompatible data format
michael@1 489 QMessageBox Problema(QString(TITRAQ_APPTITLE) + ' ' + asgui_version.v_short,
michael@1 490 TITRAQ_NOPATTERNFOUND + QString(TITRAQ_DATAPATTERN) + TITRAQ_WASNOTFOUNDIN,
michael@1 491 QMessageBox::Critical, QMessageBox::Ok | QMessageBox::Escape,
michael@1 492 QMessageBox::NoButton, QMessageBox::NoButton);
michael@1 493 Problema.exec(); // Give the user the bad news
michael@1 494 throw Genexcept(TITRAQ_INVALIDDATA);
michael@1 495 }
michael@1 496 else if (Linin.section(Datapattern, 1).section('.', 0, 0).toInt() != TITRAQ_DATAVERSIONMAJ) {
michael@1 497 QMessageBox Problema(QString(TITRAQ_APPTITLE) + ' ' + asgui_version.v_short,
michael@1 498 TITRAQ_BADVERSIONMAJ, QMessageBox::Warning, QMessageBox::Ok | QMessageBox::Escape,
michael@1 499 QMessageBox::NoButton, QMessageBox::NoButton);
michael@1 500 Problema.exec(); // Give the user the bad news
michael@1 501 throw Genexcept(TITRAQ_INCOMPATDATA);
michael@1 502 }
michael@1 503 else if (Linin.section(Datapattern, 1).section('.', 1, 1).toInt() > TITRAQ_DATAVERSIONMIN) {
michael@1 504 QMessageBox Problema(QString(TITRAQ_APPTITLE) + ' ' + asgui_version.v_short,
michael@1 505 TITRAQ_BADVERSIONMIN, QMessageBox::Warning, QMessageBox::Ok | QMessageBox::Escape,
michael@1 506 QMessageBox::NoButton, QMessageBox::NoButton);
michael@1 507 Problema.exec(); // Give the user the bad news
michael@1 508 throw Genexcept(TITRAQ_INCOMPATDATA);
michael@1 509 }
michael@1 510 else
michael@1 511 bRet = true;
michael@1 512
michael@1 513 return bRet; // Not reached in case of failure
michael@1 514 }
michael@1 515
michael@1 516 //
michael@1 517 // Get a whole row of data
michael@1 518 //
michael@1 519 const QString Titraqform::getRowdata(void) const
michael@1 520 {
michael@1 521 QString Rowdata, Tempstring; // For output string
michael@1 522 QTableSelection Select = m_pMaintable->selection(0); // Highlighted text
michael@1 523 int nTotal = Select.bottomRow() - Select.topRow() + 1; // Total row select
michael@1 524
michael@1 525 // Calculate rows to delete from selection highlight
michael@1 526 for (int nIter = 0; nIter < nTotal; ++nIter) {
michael@1 527 // Build the row data string one field at a time, adding seps inbetween
michael@1 528 Tempstring = m_pMaintable->text(Select.topRow() + nIter, TITRAQ_IDXLINE);
michael@1 529 if (!Tempstring.isEmpty())
michael@1 530 Rowdata += Tempstring;
michael@1 531 Tempstring = m_pMaintable->text(Select.topRow() + nIter, TITRAQ_IDXUSER);
michael@1 532 if (!Tempstring.isEmpty())
michael@1 533 Rowdata += TITRAQ_SEPARATORTOK + Tempstring;
michael@1 534 Tempstring = m_pMaintable->text(Select.topRow() + nIter, TITRAQ_IDXGUID);
michael@1 535 if (!Tempstring.isEmpty())
michael@1 536 Rowdata += TITRAQ_SEPARATORTOK + Tempstring;
michael@1 537 Tempstring = m_pMaintable->text(Select.topRow() + nIter, TITRAQ_IDXCRC);
michael@1 538 if (!Tempstring.isEmpty())
michael@1 539 Rowdata += TITRAQ_SEPARATORTOK + Tempstring;
michael@1 540 Tempstring = m_pMaintable->text(Select.topRow() + nIter, TITRAQ_IDXREV);
michael@1 541 if (!Tempstring.isEmpty())
michael@1 542 Rowdata += TITRAQ_SEPARATORTOK + Tempstring;
michael@1 543 Tempstring = m_pMaintable->text(Select.topRow() + nIter, TITRAQ_IDXDATE);
michael@1 544 if (!Tempstring.isEmpty())
michael@1 545 Rowdata += TITRAQ_SEPARATORTOK + Tempstring;
michael@1 546 Tempstring = m_pMaintable->text(Select.topRow() + nIter, TITRAQ_IDXSTART);
michael@1 547 if (!Tempstring.isEmpty())
michael@1 548 Rowdata += TITRAQ_SEPARATORTOK + Tempstring;
michael@1 549 Tempstring = m_pMaintable->text(Select.topRow() + nIter, TITRAQ_IDXFINISH);
michael@1 550 if (!Tempstring.isEmpty())
michael@1 551 Rowdata += TITRAQ_SEPARATORTOK + Tempstring;
michael@1 552 Tempstring = m_pMaintable->text(Select.topRow() + nIter, TITRAQ_IDXAMOUNT);
michael@1 553 if (!Tempstring.isEmpty())
michael@1 554 Rowdata += TITRAQ_SEPARATORTOK + Tempstring;
michael@1 555 Tempstring = m_pMaintable->text(Select.topRow() + nIter, TITRAQ_IDXTASK);
michael@1 556 if (!Tempstring.isEmpty())
michael@1 557 Rowdata += TITRAQ_SEPARATORTOK + Tempstring;
michael@1 558 Tempstring = m_pMaintable->text(Select.topRow() + nIter, TITRAQ_IDXREMARK);
michael@1 559 if (!Tempstring.isEmpty())
michael@1 560 Rowdata += TITRAQ_SEPARATORTOK + Tempstring;
michael@1 561 Rowdata += trUtf8("\n"); // Finish off line
michael@1 562 }
michael@1 563
michael@1 564 return Rowdata;
michael@1 565 }
michael@1 566
michael@1 567 //
michael@1 568 // Set a whole row of data
michael@1 569 //
michael@1 570 void Titraqform::setRowdata(QString &Rowdata) const
michael@1 571 {
michael@1 572 int nRows = Rowdata.contains(QChar('\n')); // Set so many rows
michael@1 573 int nCurrentrow = m_pMaintable->currentRow(); // Current table row
michael@1 574 QTableItem *pItem = NULL; // Old item to change out
michael@1 575 QString Line, User, Guid, Crc, Rev; // Admin fields in table
michael@1 576 QString Date, Start, Finish, Amount, Task, Remark; // Viewable fields in table
michael@1 577 QTextStream Datastream(&Rowdata, IO_ReadOnly); // Convert data to stream
michael@1 578
michael@1 579 for (int nIter = 0; nIter < nRows; ++nIter) {
michael@1 580 QString Singlerow = Datastream.readLine(); // For linewise operation
michael@1 581 QTextStream Rowstream(&Singlerow, IO_ReadOnly); // Convert row to stream
michael@1 582
michael@1 583 Rowstream >> Line >> User >> Guid >> Crc >> Rev; // Stream data fields
michael@1 584 Rowstream >> Date >> Start >> Finish >> Amount >> Task; // to corresponding vars
michael@1 585 Remark = Rowstream.readLine(); // Remark is a whole line
michael@1 586
michael@1 587 // Set the table row data one field at a time, skipping seps inbetween
michael@1 588 // Importantly, do not copy over the GUID, which must be unique each row
michael@1 589 m_pMaintable->setText(nCurrentrow + nIter, TITRAQ_IDXLINE, Line);
michael@1 590 m_pMaintable->setText(nCurrentrow + nIter, TITRAQ_IDXUSER, User);
michael@1 591 m_pMaintable->setText(nCurrentrow + nIter, TITRAQ_IDXCRC, Crc);
michael@1 592 m_pMaintable->setText(nCurrentrow + nIter, TITRAQ_IDXREV, Rev);
michael@1 593 m_pMaintable->setText(nCurrentrow + nIter, TITRAQ_IDXDATE, Date);
michael@1 594 m_pMaintable->setText(nCurrentrow + nIter, TITRAQ_IDXSTART, Start);
michael@1 595 m_pMaintable->setText(nCurrentrow + nIter, TITRAQ_IDXFINISH, Finish);
michael@1 596 m_pMaintable->setText(nCurrentrow + nIter, TITRAQ_IDXAMOUNT, Amount);
michael@1 597
michael@1 598 // // FIXME: Why doesn't this code change the RtTableItem text in place?
michael@1 599 // RtTableItem *pTask = NULL; // Derived and special
michael@1 600 // pItem = m_pMaintable->item(nCurrentrow + nIter, TITRAQ_IDXTASK);
michael@1 601 // pTask = static_cast<RtTableItem *>(pItem);
michael@1 602 // pTask->setText(Task);
michael@1 603
michael@1 604 // Change out old item and replace with new task data
michael@1 605 pItem = m_pMaintable->item(nCurrentrow + nIter, TITRAQ_IDXTASK);
michael@1 606 delete(pItem); // Get rid of the old before going with the new
michael@1 607 RtTableItem *pSwapitem = new RtTableItem(m_pMaintable, QTableItem::WhenCurrent, Task);
michael@1 608 pSwapitem->setAlignment(AlignLeft | AlignVCenter);
michael@1 609 m_pMaintable->setItem(nCurrentrow + nIter, TITRAQ_IDXTASK, pSwapitem);
michael@1 610
michael@1 611 // Continue with field processing business as usual
michael@1 612 m_pMaintable->setText(nCurrentrow + nIter, TITRAQ_IDXREMARK, Remark.simplifyWhiteSpace());
michael@1 613 }
michael@1 614 }
michael@1 615
michael@1 616 //
michael@1 617 // Discover which column is the first in view
michael@1 618 //
michael@1 619 const int Titraqform::getFirstcol(void) const
michael@1 620 {
michael@1 621 int nIter = 0; // Is both iterator in loop and column number returned
michael@1 622
michael@1 623 // Use column selector menu popup as sole key to determining column state
michael@1 624 while (nIter < TITRAQ_IDXTAIL && !m_pColspopup->isItemChecked(m_pColspopup->idAt(++nIter)))
michael@1 625 TITRAQ_NOP;
michael@1 626
michael@1 627 return nIter - 1; // Return one less to account for start of item offset
michael@1 628 }

mercurial