as_dataop.cpp

Thu, 06 Aug 2009 13:21:30 +0200

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 06 Aug 2009 13:21:30 +0200
changeset 15
0e0eb7c91312
parent 12
ceb4ba3d2d00
permissions
-rw-r--r--

Remove seemingly declarations unnecessary according to Qt 4.5.2 headers.

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

mercurial