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