|
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 // |
|
31 |
|
32 // System headers |
|
33 #include <map> |
|
34 #include <string> |
|
35 |
|
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> |
|
43 |
|
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 |
|
50 |
|
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[] |
|
55 |
|
56 |
|
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 } |
|
80 |
|
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 |
|
91 |
|
92 QString Line; // Used for linewise editing and whitespace eating |
|
93 |
|
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 } |
|
99 |
|
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 } |
|
107 |
|
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 |
|
113 |
|
114 Asline.skipWhiteSpace(); // Remove whitespaces |
|
115 Asline >> Temp; // Copy revision indicator |
|
116 |
|
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 } |
|
122 |
|
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 } |
|
131 |
|
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'; |
|
135 |
|
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++) { |
|
139 |
|
140 // Count the number of lines of sorted task names |
|
141 int nNumlines = QString(Numiter->second).contains('\n'); |
|
142 |
|
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 } |
|
148 |
|
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 } |
|
169 |
|
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 |
|
179 |
|
180 QPixmap Statokay(s_kpcStatokay_xpm); |
|
181 QPixmap Statwarn(s_kpcStatwarn_xpm); |
|
182 QPixmap Staterror(s_kpcStaterror_xpm); |
|
183 |
|
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 } |
|
191 |
|
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 } |
|
200 |
|
201 // // Going into data churning, so prepare date and time parsing and conversion |
|
202 // Converdate.setSeparator(trUtf8(".")); |
|
203 // Convertime.setSeparator(trUtf8(":")); |
|
204 |
|
205 // Optimize viewing by repainting cells only once after processing |
|
206 m_pMaintable->setUpdatesEnabled(false); |
|
207 |
|
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 |
|
215 |
|
216 if (nIter % g_knBlocks == 0) // Add blocks of rows to optimize loading |
|
217 m_pMaintable->setNumRows(m_pMaintable->numRows() + g_knBlocks); |
|
218 |
|
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; |
|
225 |
|
226 Asline.skipWhiteSpace(); // Remove whitespaces |
|
227 Asline >> Guid; // Copy the GUID field |
|
228 // Postpone actual text delivery, to autoinsert GUIDs! |
|
229 |
|
230 Asline.skipWhiteSpace(); // Remove whitespaces |
|
231 Asline >> Crc; // Copy the CRC field |
|
232 // Postpone actual text delivery, to autoinsert CRCs! |
|
233 |
|
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; |
|
240 |
|
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; |
|
247 |
|
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; |
|
254 |
|
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; |
|
261 |
|
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; |
|
268 |
|
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; |
|
280 |
|
281 Asline.skipWhiteSpace(); // Remove whitespaces |
|
282 Remark = Asline.read(); // Copy the remark field |
|
283 |
|
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 |
|
288 |
|
289 if (!Remark.isEmpty()) |
|
290 m_pMaintable->setText(nIter, TITRAQ_IDXREMARK, Remark); |
|
291 |
|
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 } |
|
300 |
|
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; |
|
313 |
|
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; |
|
329 |
|
330 nIter++; // The big increment |
|
331 Line = QString(""); // Clear line for next round |
|
332 |
|
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 } |
|
340 |
|
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); |
|
346 |
|
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'))); |
|
350 |
|
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 |
|
355 |
|
356 if (!bValid) |
|
357 throw Genexcept("Warning: invalid accounting data."); |
|
358 } |
|
359 |
|
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 } |
|
378 |
|
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 |
|
388 |
|
389 // Start by prepending the AS data format version symbol |
|
390 Tstream << TITRAQ_DATAPATTERN << TITRAQ_DATAVERSIONMAJ |
|
391 << QChar('.') << TITRAQ_DATAVERSIONMIN << endl; |
|
392 |
|
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 |
|
398 |
|
399 Tempfield = m_pMaintable->text(nIter, TITRAQ_IDXGUID); // Load GUID field text |
|
400 if (Tempfield != NULL) |
|
401 Tstream << trUtf8(" ") << Tempfield; // Save GUID field text |
|
402 |
|
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 |
|
407 |
|
408 Tempfield = m_pMaintable->text(nIter, TITRAQ_IDXREV); // Load rev field text |
|
409 if (Tempfield != NULL) |
|
410 Tstream << trUtf8(" ") << Tempfield; // Save rev field text |
|
411 |
|
412 Tempfield = m_pMaintable->text(nIter, TITRAQ_IDXDATE); // Load date field text |
|
413 if (Tempfield != NULL) |
|
414 Tstream << trUtf8(" ") << Tempfield; // Save date field text |
|
415 |
|
416 Tempfield = m_pMaintable->text(nIter, TITRAQ_IDXSTART); // Load start field text |
|
417 if (Tempfield != NULL) |
|
418 Tstream << trUtf8(" ") << Tempfield; // Save start field text |
|
419 |
|
420 Tempfield = m_pMaintable->text(nIter, TITRAQ_IDXFINISH); // Load end field text |
|
421 if (Tempfield != NULL) |
|
422 Tstream << trUtf8(" ") << Tempfield; // Save end field text |
|
423 |
|
424 Tempfield = m_pMaintable->text(nIter, TITRAQ_IDXAMOUNT); // Load amount field text |
|
425 if (Tempfield != NULL) |
|
426 Tstream << trUtf8(" ") << Tempfield; // Save amount |
|
427 |
|
428 Tempfield = m_pMaintable->text(nIter, TITRAQ_IDXTASK); // Load acct field text |
|
429 if (Tempfield != NULL) |
|
430 Tstream << trUtf8(" ") << Tempfield; // Save acct field text |
|
431 |
|
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 |
|
443 |
|
444 Tstream << endl; // Append a newline |
|
445 } |
|
446 } |
|
447 |
|
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 |
|
455 |
|
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 } |
|
469 |
|
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 } |
|
478 |
|
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 |
|
485 |
|
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; |
|
512 |
|
513 return bRet; // Not reached in case of failure |
|
514 } |
|
515 |
|
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 |
|
524 |
|
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 } |
|
563 |
|
564 return Rowdata; |
|
565 } |
|
566 |
|
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 |
|
578 |
|
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 |
|
582 |
|
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 |
|
586 |
|
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); |
|
597 |
|
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); |
|
603 |
|
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); |
|
610 |
|
611 // Continue with field processing business as usual |
|
612 m_pMaintable->setText(nCurrentrow + nIter, TITRAQ_IDXREMARK, Remark.simplifyWhiteSpace()); |
|
613 } |
|
614 } |
|
615 |
|
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 |
|
622 |
|
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; |
|
626 |
|
627 return nIter - 1; // Return one less to account for start of item offset |
|
628 } |