1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/as_dataop.cpp Fri Nov 28 11:21:08 2008 +0100 1.3 @@ -0,0 +1,628 @@ 1.4 +// 1.5 +// OSSP asgui - Accounting system graphical user interface 1.6 +// Copyright (c) 2002-2004 The OSSP Project (http://www.ossp.org/) 1.7 +// Copyright (c) 2002-2004 Ralf S. Engelschall <rse@engelschall.com> 1.8 +// Copyright (c) 2002-2004 Michael Schloh von Bennewitz <michael@schloh.com> 1.9 +// Copyright (c) 2002-2004 Cable & Wireless Telecommunications Services GmbH 1.10 +// 1.11 +// This file is part of OSSP asgui, an accounting system graphical user 1.12 +// interface which can be found at http://www.ossp.org/pkg/tool/asgui/. 1.13 +// 1.14 +// Permission to use, copy, modify, and distribute this software for 1.15 +// any purpose with or without fee is hereby granted, provided that 1.16 +// the above copyright notice and this permission notice appear in all 1.17 +// copies. 1.18 +// 1.19 +// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 1.20 +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 1.21 +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1.22 +// IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR 1.23 +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1.24 +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 1.25 +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 1.26 +// USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 1.27 +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 1.28 +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 1.29 +// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 1.30 +// SUCH DAMAGE. 1.31 +// 1.32 +// as_dataops.cpp: ISO C++ implementation 1.33 +// 1.34 + 1.35 +// System headers 1.36 +#include <map> 1.37 +#include <string> 1.38 + 1.39 +// Qt general headers 1.40 +#include <qregexp.h> // Portable regular expressions 1.41 +#include <qdatetime.h> 1.42 +#include <qmessagebox.h> 1.43 +#include <qtextstream.h> 1.44 +#include <qpopupmenu.h> 1.45 +#include <qfile.h> 1.46 + 1.47 +// User interface 1.48 +#include "as_const.h" // Application constants 1.49 +#include "as_tableitem.h" // For class RtTableItem 1.50 +#include "as_crc.h" // For quality strings 1.51 +#include "as_uuid.h" // UUID classes 1.52 +#include "as_table.h" // TiTable class 1.53 + 1.54 +// Icon pixel maps 1.55 +#include "as_gfx/statok.xpm" // static const char *s_kpcStatokay_xpm[] 1.56 +#include "as_gfx/staterr.xpm" // static const char *s_kpcStaterror_xpm[] 1.57 +#include "as_gfx/statwrn.xpm" // static const char *s_kpcStatwarn_xpm[] 1.58 + 1.59 + 1.60 +// 1.61 +// Convenience method to load accounts from a file 1.62 +// 1.63 +void Titraqform::loadAccounts(QFile &Fileobj) 1.64 +{ 1.65 + if (Fileobj.isOpen()) { // Check state of file 1.66 + Fileobj.flush(); // Begin processing file cleanly 1.67 + QTextStream Account(&Fileobj); // Convert data to stream 1.68 + this->loadAccounts(Account); // Pass off to do the real work 1.69 + } 1.70 + else { 1.71 + if (!Fileobj.open(IO_ReadOnly)) { // Try to open file 1.72 + QString Readerrstr; 1.73 + Readerrstr = trUtf8(TITRAQ_READAFILFAIL).arg(Fileobj.name()); 1.74 + throw Genexcept(Readerrstr.ascii()); 1.75 + } 1.76 + else 1.77 + Fileobj.flush(); // Begin processing file cleanly 1.78 + QTextStream Account(&Fileobj); // Convert data to stream 1.79 + this->loadAccounts(Account); // Pass off to do the real work 1.80 + Fileobj.close(); // Finish fileop by closing 1.81 + } 1.82 +} 1.83 + 1.84 +// 1.85 +// Load accounts themselves data from a stream 1.86 +// 1.87 +void Titraqform::loadAccounts(QTextStream &Tstream) 1.88 +{ 1.89 + using namespace std; // Needed for hash tables with hmap 1.90 + map<string, int> Hashnames; // Hashtable for storing names 1.91 + map<int, string> Hashnums; // Hashtable for storing repetitions 1.92 + map<string, int>::iterator Nameiter; // The hashtable name iterator 1.93 + map<int, string>::iterator Numiter; // The hashtable number iterator 1.94 + 1.95 + QString Line; // Used for linewise editing and whitespace eating 1.96 + 1.97 + // Eat lines until reading the start accounts token 1.98 + while (!Line.startsWith(trUtf8("%!AS-ACCOUNTS")) && !Tstream.atEnd()) { 1.99 + Line = QString(""); // Empty line for later inspection 1.100 + Line = Tstream.readLine(); // Get a new line to examine 1.101 + } 1.102 + 1.103 + // Strip out extra line feeds in stream 1.104 + while (Line.isEmpty() && !Tstream.atEnd()) { 1.105 + Tstream.skipWhiteSpace(); // Strip and get 1.106 + Line = Tstream.readLine(); // the new line 1.107 + if (Line.at(0) == QChar('#')) // Remove comments 1.108 + Line = QString(""); 1.109 + } 1.110 + 1.111 + // Set the accounts choices by linewise reading from the input 1.112 + // stream and parsing the corresponding account fields out of it 1.113 + while (!Line.isEmpty()) { 1.114 + QString Temp; // For reading from stream 1.115 + QTextStream Asline(&Line, IO_ReadOnly); // Convert a single line 1.116 + 1.117 + Asline.skipWhiteSpace(); // Remove whitespaces 1.118 + Asline >> Temp; // Copy revision indicator 1.119 + 1.120 + if (Temp == QString(QChar('R'))) { // Copy the account field 1.121 + Asline >> Temp; // to temporary for transfer 1.122 + string Convstring = Temp; // Convert to string (can't cast?) 1.123 + Hashnames[Convstring] += Hashnames[Convstring]; 1.124 + } 1.125 + 1.126 + Line = QString(""); // Clear line for next round 1.127 + while (Line.isEmpty() && !Tstream.atEnd()) { 1.128 + Tstream.skipWhiteSpace(); // Strip and get 1.129 + Line = Tstream.readLine(); // the new line 1.130 + if (Line.at(0) == QChar('#')) // Remove comments 1.131 + Line = QString(""); 1.132 + } 1.133 + } 1.134 + 1.135 +// Hashnames.insert(map<string, int>::value_type((string)QString, int)); 1.136 + for (Nameiter = Hashnames.begin(); Nameiter != Hashnames.end(); Nameiter++) 1.137 + Hashnums[Nameiter->second] += Nameiter->first + '\n'; 1.138 + 1.139 +// FIXME: Put this in loadData, to load custom and most used task names before 1.140 +// FIXME: default listings are sorted and inserted 1.141 + for (Numiter = Hashnums.begin(); Numiter != Hashnums.end(); Numiter++) { 1.142 + 1.143 + // Count the number of lines of sorted task names 1.144 + int nNumlines = QString(Numiter->second).contains('\n'); 1.145 + 1.146 + // Iterate through the lines of task names, feeding them into the menu 1.147 + for (int nIter = 0; nIter < nNumlines; nIter++) 1.148 + *m_pTaskentries << QString(Numiter->second).section('\n', nIter, nIter); 1.149 + } 1.150 +} 1.151 + 1.152 +// 1.153 +// Convenience method to load personal data from a file 1.154 +// 1.155 +void Titraqform::loadData(QFile &Fileobj) 1.156 +{ 1.157 + if (Fileobj.isOpen()) { // Check state of file 1.158 + Fileobj.flush(); // Begin processing file cleanly 1.159 + QTextStream Asentry(&Fileobj); // Convert data to stream 1.160 + this->loadData(Asentry); // Pass off to do the real work 1.161 + } 1.162 + else { 1.163 + if (!Fileobj.open(IO_ReadOnly)) // Try to open file 1.164 + throw Genexcept(trUtf8(TITRAQ_READPFILFAIL)); 1.165 + else 1.166 + Fileobj.flush(); // Begin processing file cleanly 1.167 + QTextStream Asentry(&Fileobj); // Convert data to stream 1.168 + this->loadData(Asentry); // Pass off to do the real work 1.169 + Fileobj.close(); // Finish fileop by closing 1.170 + } 1.171 +} 1.172 + 1.173 +// 1.174 +// Load personal data from a stream 1.175 +// 1.176 +void Titraqform::loadData(QTextStream &Tstream) 1.177 +{ 1.178 + bool bValid = true; // Used to warn on globally invalid accounting data 1.179 + int nIter = 0; // Iterator used in loop and also as a count 1.180 + QString Line; // Used for linewise editing and whitespace eating 1.181 + QString Bitbucket; // Used for null device until we find a better way 1.182 + 1.183 + QPixmap Statokay(s_kpcStatokay_xpm); 1.184 + QPixmap Statwarn(s_kpcStatwarn_xpm); 1.185 + QPixmap Staterror(s_kpcStaterror_xpm); 1.186 + 1.187 + // Strip out extra line feeds at stream start 1.188 + while (Line.isEmpty() && !Tstream.atEnd()) { 1.189 + Tstream.skipWhiteSpace(); // Strip and get 1.190 + Line = Tstream.readLine(); // the new line 1.191 + if (Line.at(0) == QChar('#')) // Remove comments 1.192 + Line = QString(""); 1.193 + } 1.194 + 1.195 + // Strip out extra line feeds after reading the data symbol 1.196 + Line = QString(""); // Reset our line 1.197 + while (Line.isEmpty() && !Tstream.atEnd()) { 1.198 + Tstream.skipWhiteSpace(); // Strip and get 1.199 + Line = Tstream.readLine(); // the new line 1.200 + if (Line.at(0) == QChar('#')) // Remove comments 1.201 + Line = QString(""); 1.202 + } 1.203 + 1.204 +// // Going into data churning, so prepare date and time parsing and conversion 1.205 +// Converdate.setSeparator(trUtf8(".")); 1.206 +// Convertime.setSeparator(trUtf8(":")); 1.207 + 1.208 + // Optimize viewing by repainting cells only once after processing 1.209 + m_pMaintable->setUpdatesEnabled(false); 1.210 + 1.211 + // Set the table text by linewise reading from the input stream 1.212 + // and parsing date, time, account, and other columns out of it 1.213 + while (!Line.isEmpty()) { 1.214 + bool bValid = true; // Warns on linewise invalid accounting data 1.215 + QString User, Guid, Crc, Rev; // Valid admin fields 1.216 + QString Date, Start, Finish, Account, Amount, Remark; // Valid user fields 1.217 + QTextStream Asline(&Line, IO_ReadOnly); // Convert a single line now 1.218 + 1.219 + if (nIter % g_knBlocks == 0) // Add blocks of rows to optimize loading 1.220 + m_pMaintable->setNumRows(m_pMaintable->numRows() + g_knBlocks); 1.221 + 1.222 + Asline.skipWhiteSpace(); // Remove whitespaces 1.223 + Asline >> User; // Copy the user field 1.224 + if (!User.isEmpty()) 1.225 + m_pMaintable->setText(nIter, TITRAQ_IDXUSER, User); 1.226 + else 1.227 + bValid = false; 1.228 + 1.229 + Asline.skipWhiteSpace(); // Remove whitespaces 1.230 + Asline >> Guid; // Copy the GUID field 1.231 + // Postpone actual text delivery, to autoinsert GUIDs! 1.232 + 1.233 + Asline.skipWhiteSpace(); // Remove whitespaces 1.234 + Asline >> Crc; // Copy the CRC field 1.235 + // Postpone actual text delivery, to autoinsert CRCs! 1.236 + 1.237 + Asline.skipWhiteSpace(); // Remove whitespaces 1.238 + Asline >> Rev; // Copy the rev field 1.239 + if (!Rev.isEmpty()) 1.240 + m_pMaintable->setText(nIter, TITRAQ_IDXREV, Rev); 1.241 + else 1.242 + bValid = false; 1.243 + 1.244 + Asline.skipWhiteSpace(); // Remove whitespaces 1.245 + Asline >> Date; // Copy the date field 1.246 + if (!Date.isEmpty()) 1.247 + m_pMaintable->setText(nIter, TITRAQ_IDXDATE, Date); 1.248 + else 1.249 + bValid = false; 1.250 + 1.251 + Asline.skipWhiteSpace(); // Remove whitespaces 1.252 + Asline >> Start; // Copy the start field 1.253 + if (!Start.isEmpty()) 1.254 + m_pMaintable->setText(nIter, TITRAQ_IDXSTART, Start); 1.255 + else 1.256 + bValid = false; 1.257 + 1.258 + Asline.skipWhiteSpace(); // Remove whitespaces 1.259 + Asline >> Finish; // Copy the finish field 1.260 + if (!Finish.isEmpty()) 1.261 + m_pMaintable->setText(nIter, TITRAQ_IDXFINISH, Finish); 1.262 + else 1.263 + bValid = false; 1.264 + 1.265 + Asline.skipWhiteSpace(); // Remove whitespaces 1.266 + Asline >> Amount; // Copy the amount field 1.267 + if (!Amount.isEmpty()) 1.268 + m_pMaintable->setText(nIter, TITRAQ_IDXAMOUNT, Amount); 1.269 + else 1.270 + bValid = false; 1.271 + 1.272 + Asline.skipWhiteSpace(); // Remove whitespaces 1.273 + Asline >> Account; // Copy the account field 1.274 + if (!Account.isEmpty()) { 1.275 + QTableItem *pOld = m_pMaintable->item(nIter, TITRAQ_IDXTASK); 1.276 + delete(pOld); // Get rid of the old before going with the new 1.277 + RtTableItem *pSwapitem = new RtTableItem(m_pMaintable, QTableItem::WhenCurrent, Account); 1.278 + pSwapitem->setAlignment(AlignLeft | AlignVCenter); 1.279 + m_pMaintable->setItem(nIter, TITRAQ_IDXTASK, pSwapitem); 1.280 + } 1.281 + else 1.282 + bValid = false; 1.283 + 1.284 + Asline.skipWhiteSpace(); // Remove whitespaces 1.285 + Remark = Asline.read(); // Copy the remark field 1.286 + 1.287 + QRegExp Quoted("\"(.*[^\\\\])\""); // Get rid of 1.288 + Quoted.search(Remark); // surrounding double 1.289 + Remark = Quoted.cap(Quoted.numCaptures()); // quotes, and 1.290 + Remark.replace(QRegExp("\\\\(.)"), QString("\\1")); // escape backslashes 1.291 + 1.292 + if (!Remark.isEmpty()) 1.293 + m_pMaintable->setText(nIter, TITRAQ_IDXREMARK, Remark); 1.294 + 1.295 + if (bValid) { // Show a bitmap to signal valid or error state 1.296 + m_pMaintable->setText(nIter, TITRAQ_IDXSTATUS, QString(QChar('O'))); 1.297 + m_pMaintable->setPixmap(nIter, TITRAQ_IDXSTATUS, Statokay); 1.298 + } 1.299 + else { 1.300 + m_pMaintable->setText(nIter, TITRAQ_IDXSTATUS, QString(QChar('E'))); 1.301 + m_pMaintable->setPixmap(nIter, TITRAQ_IDXSTATUS, Staterror); 1.302 + } 1.303 + 1.304 + // Set the GUID text here, in case we need to generate a fresh value 1.305 + if (!Guid.isEmpty()) { 1.306 + if (Guid != ".") // This means, generate a fresh GUID value 1.307 + m_pMaintable->setText(nIter, TITRAQ_IDXGUID, Guid); 1.308 + else { 1.309 + AS::Uuid Guidi; // For GUID production 1.310 + Guidi.genId(); 1.311 + m_pMaintable->setText(nIter, TITRAQ_IDXGUID, Guidi.getString()); 1.312 + } 1.313 + } 1.314 + else // if isEmpty() 1.315 + bValid = false; 1.316 + 1.317 + // Set the CRC text here, in case we need to generate a fresh value 1.318 + if (!Crc.isEmpty()) { 1.319 + if (Crc != ".") // This means, generate a fresh CRC value 1.320 + m_pMaintable->setText(nIter, TITRAQ_IDXCRC, "0x" + Crc); 1.321 + else { 1.322 + // Make our long tuple to run through the CRC32 generator 1.323 + Qualistring Testuple = User + Guid + Rev + Date + Start; 1.324 + Testuple += Finish + Amount + Account + Remark; 1.325 + U32 Valcrc = Testuple.getCrc(); // Finally set the checksum to its new value 1.326 + QString Crcstr = QString::number(Valcrc, 16).rightJustify(8, '0'); 1.327 + m_pMaintable->setText(nIter, TITRAQ_IDXCRC, "0x" + Crcstr); 1.328 + } 1.329 + } 1.330 + else // if isEmpty() 1.331 + bValid = false; 1.332 + 1.333 + nIter++; // The big increment 1.334 + Line = QString(""); // Clear line for next round 1.335 + 1.336 + while (Line.isEmpty() && !Tstream.atEnd()) { // Strip and get 1.337 + Tstream.skipWhiteSpace(); // Remove white 1.338 + Line = Tstream.readLine(); // the new line 1.339 + if (Line.at(0) == QChar('#')) // Remove comments 1.340 + Line = QString(""); 1.341 + } 1.342 + } 1.343 + 1.344 +// // Start sorting order and direction correctly according to user preferences 1.345 +// int nSortcol = (int)m_pPrefs->getNumber(TITRAQ_PREFSORTCOL, TITRAQ_DEFSORTCOL); 1.346 +// bool bSortdir = m_pPrefs->getBool(TITRAQ_PREFSORTDIR, TITRAQ_DEFSORTDIR); 1.347 +// m_pMaintable->setSortdir(!bSortdir); // Hack! Fake sortdir so we start right 1.348 +// m_pMaintable->sortColumn(nSortcol, bSortdir); 1.349 + 1.350 + // Write nonsaving line numbers for all rows 1.351 + for (int nIter = m_pMaintable->numRows() - 1; nIter >= 0; nIter--) 1.352 + m_pMaintable->setText(nIter, TITRAQ_IDXLINE, QString::number(nIter).rightJustify(4, QChar('0'))); 1.353 + 1.354 + m_pMaintable->setUpdatesEnabled(true); // Update and repaint 1.355 + m_pMaintable->setNumRows(nIter); // No excess rows 1.356 + m_pMaintable->setCurrentCell(nIter - 1, 0); // Move focus to last row 1.357 + m_pMaintable->ensureCellVisible(nIter - 1, 0); // Scroll please 1.358 + 1.359 + if (!bValid) 1.360 + throw Genexcept("Warning: invalid accounting data."); 1.361 +} 1.362 + 1.363 +// 1.364 +// Convenience method to save accounting data to a file 1.365 +// 1.366 +void Titraqform::saveData(QFile &Fileobj) 1.367 +{ 1.368 + if (Fileobj.isOpen()) { // Check state of file 1.369 + Fileobj.flush(); // Begin processing file cleanly 1.370 + QTextStream Asentry(&Fileobj); // Convert data to stream 1.371 + this->saveData(Asentry); // Pass off to do the real work 1.372 + } 1.373 + else { 1.374 + if (!Fileobj.open(IO_WriteOnly)) // Try to open file 1.375 + throw Genexcept(trUtf8(TITRAQ_READPFILFAIL)); 1.376 + QTextStream Asentry(&Fileobj); // Convert data to stream 1.377 + this->saveData(Asentry); // Pass off to do the real work 1.378 + Fileobj.close(); // Finish fileop by closing 1.379 + } 1.380 +} 1.381 + 1.382 +// 1.383 +// Save accounting data to a stream 1.384 +// 1.385 +void Titraqform::saveData(QTextStream &Tstream) 1.386 +{ 1.387 + const int nRows = m_pMaintable->numRows(); // Max rows used in loop 1.388 + QString Tempfield; // Current field string 1.389 + QString Strsearch; // String to strip search 1.390 + QRegExp Stripper("\\s*$"); // Pattern to strip off 1.391 + 1.392 + // Start by prepending the AS data format version symbol 1.393 + Tstream << TITRAQ_DATAPATTERN << TITRAQ_DATAVERSIONMAJ 1.394 + << QChar('.') << TITRAQ_DATAVERSIONMIN << endl; 1.395 + 1.396 + // Linewise save from the main table date, time, account, and others 1.397 + for (int nIter = 0; nIter < nRows; nIter++) { 1.398 + Tempfield = m_pMaintable->text(nIter, TITRAQ_IDXUSER); // Load user field text 1.399 + if (Tempfield != NULL) 1.400 + Tstream << Tempfield; // Save user field text 1.401 + 1.402 + Tempfield = m_pMaintable->text(nIter, TITRAQ_IDXGUID); // Load GUID field text 1.403 + if (Tempfield != NULL) 1.404 + Tstream << trUtf8(" ") << Tempfield; // Save GUID field text 1.405 + 1.406 + Tempfield = m_pMaintable->text(nIter, TITRAQ_IDXCRC); // Load CRC field text 1.407 + Tempfield.remove("0x"); 1.408 + if (Tempfield != NULL) 1.409 + Tstream << trUtf8(" ") << Tempfield; // Save CRC field text 1.410 + 1.411 + Tempfield = m_pMaintable->text(nIter, TITRAQ_IDXREV); // Load rev field text 1.412 + if (Tempfield != NULL) 1.413 + Tstream << trUtf8(" ") << Tempfield; // Save rev field text 1.414 + 1.415 + Tempfield = m_pMaintable->text(nIter, TITRAQ_IDXDATE); // Load date field text 1.416 + if (Tempfield != NULL) 1.417 + Tstream << trUtf8(" ") << Tempfield; // Save date field text 1.418 + 1.419 + Tempfield = m_pMaintable->text(nIter, TITRAQ_IDXSTART); // Load start field text 1.420 + if (Tempfield != NULL) 1.421 + Tstream << trUtf8(" ") << Tempfield; // Save start field text 1.422 + 1.423 + Tempfield = m_pMaintable->text(nIter, TITRAQ_IDXFINISH); // Load end field text 1.424 + if (Tempfield != NULL) 1.425 + Tstream << trUtf8(" ") << Tempfield; // Save end field text 1.426 + 1.427 + Tempfield = m_pMaintable->text(nIter, TITRAQ_IDXAMOUNT); // Load amount field text 1.428 + if (Tempfield != NULL) 1.429 + Tstream << trUtf8(" ") << Tempfield; // Save amount 1.430 + 1.431 + Tempfield = m_pMaintable->text(nIter, TITRAQ_IDXTASK); // Load acct field text 1.432 + if (Tempfield != NULL) 1.433 + Tstream << trUtf8(" ") << Tempfield; // Save acct field text 1.434 + 1.435 + Tempfield = m_pMaintable->text(nIter, TITRAQ_IDXREMARK); // Load remark field text 1.436 + Tstream << trUtf8(" \""); // Save beginning double quote 1.437 + if (Tempfield != NULL) { 1.438 + Strsearch = QRegExp::escape(Tempfield); // Incoming string escaped 1.439 + Stripper.search(Strsearch); 1.440 + Tempfield.truncate(Stripper.pos()); // Cut off whitespace 1.441 + Tempfield.replace(QChar('\\'), QString("\\\\")); // Escape back slashes 1.442 + Tempfield.replace(QChar('\"'), QString("\\\"")); // Escape double quotes 1.443 + Tstream << Tempfield; // Save remark field text 1.444 + } 1.445 + Tstream << trUtf8("\""); // Save ending double quote 1.446 + 1.447 + Tstream << endl; // Append a newline 1.448 + } 1.449 +} 1.450 + 1.451 +// 1.452 +// Convenience method to validate AS data in a file 1.453 +// 1.454 +const bool Titraqform::validateData(QFile &Filin) const 1.455 +{ 1.456 + QString Firstline; // Will contain the first line of text 1.457 + bool bRet = false; // Set the initial return value 1.458 + 1.459 + if (Filin.isOpen()) { // Check open state of file 1.460 + Filin.flush(); // Not sure if this is needed 1.461 + Filin.reset(); // Set the file index position to 0 1.462 + Filin.readLine(Firstline, QString(TITRAQ_DATAPATTERN).length() + 2L); 1.463 + } 1.464 + else { 1.465 + if (!Filin.open(IO_ReadOnly)) // Try to open file 1.466 + throw Genexcept(trUtf8(TITRAQ_READPFILFAIL)); 1.467 + else { // File is now open 1.468 + Filin.readLine(Firstline, QString(TITRAQ_DATAPATTERN).length() + 2L); 1.469 + Filin.close(); // Remember to close 1.470 + } 1.471 + } 1.472 + 1.473 + try { // Pass off to worker method 1.474 + bRet = this->validateData(Firstline); 1.475 + } 1.476 + catch (Genexcept &) { 1.477 + throw; // Rethrow onwards 1.478 + } 1.479 + return bRet; 1.480 +} 1.481 + 1.482 +// 1.483 +// Validate the AS data pattern in a line 1.484 +// 1.485 +const bool Titraqform::validateData(QString &Linin) const 1.486 +{ 1.487 + bool bRet = false; // Initial return value 1.488 + 1.489 + // Ensure that the right data version pattern precedes the data 1.490 + QString Datapattern = QString(TITRAQ_DATAPATTERN); 1.491 + if (!Linin.startsWith(Datapattern)) { // Incompatible data format 1.492 + QMessageBox Problema(QString(TITRAQ_APPTITLE) + ' ' + asgui_version.v_short, 1.493 + TITRAQ_NOPATTERNFOUND + QString(TITRAQ_DATAPATTERN) + TITRAQ_WASNOTFOUNDIN, 1.494 + QMessageBox::Critical, QMessageBox::Ok | QMessageBox::Escape, 1.495 + QMessageBox::NoButton, QMessageBox::NoButton); 1.496 + Problema.exec(); // Give the user the bad news 1.497 + throw Genexcept(TITRAQ_INVALIDDATA); 1.498 + } 1.499 + else if (Linin.section(Datapattern, 1).section('.', 0, 0).toInt() != TITRAQ_DATAVERSIONMAJ) { 1.500 + QMessageBox Problema(QString(TITRAQ_APPTITLE) + ' ' + asgui_version.v_short, 1.501 + TITRAQ_BADVERSIONMAJ, QMessageBox::Warning, QMessageBox::Ok | QMessageBox::Escape, 1.502 + QMessageBox::NoButton, QMessageBox::NoButton); 1.503 + Problema.exec(); // Give the user the bad news 1.504 + throw Genexcept(TITRAQ_INCOMPATDATA); 1.505 + } 1.506 + else if (Linin.section(Datapattern, 1).section('.', 1, 1).toInt() > TITRAQ_DATAVERSIONMIN) { 1.507 + QMessageBox Problema(QString(TITRAQ_APPTITLE) + ' ' + asgui_version.v_short, 1.508 + TITRAQ_BADVERSIONMIN, QMessageBox::Warning, QMessageBox::Ok | QMessageBox::Escape, 1.509 + QMessageBox::NoButton, QMessageBox::NoButton); 1.510 + Problema.exec(); // Give the user the bad news 1.511 + throw Genexcept(TITRAQ_INCOMPATDATA); 1.512 + } 1.513 + else 1.514 + bRet = true; 1.515 + 1.516 + return bRet; // Not reached in case of failure 1.517 +} 1.518 + 1.519 +// 1.520 +// Get a whole row of data 1.521 +// 1.522 +const QString Titraqform::getRowdata(void) const 1.523 +{ 1.524 + QString Rowdata, Tempstring; // For output string 1.525 + QTableSelection Select = m_pMaintable->selection(0); // Highlighted text 1.526 + int nTotal = Select.bottomRow() - Select.topRow() + 1; // Total row select 1.527 + 1.528 + // Calculate rows to delete from selection highlight 1.529 + for (int nIter = 0; nIter < nTotal; ++nIter) { 1.530 + // Build the row data string one field at a time, adding seps inbetween 1.531 + Tempstring = m_pMaintable->text(Select.topRow() + nIter, TITRAQ_IDXLINE); 1.532 + if (!Tempstring.isEmpty()) 1.533 + Rowdata += Tempstring; 1.534 + Tempstring = m_pMaintable->text(Select.topRow() + nIter, TITRAQ_IDXUSER); 1.535 + if (!Tempstring.isEmpty()) 1.536 + Rowdata += TITRAQ_SEPARATORTOK + Tempstring; 1.537 + Tempstring = m_pMaintable->text(Select.topRow() + nIter, TITRAQ_IDXGUID); 1.538 + if (!Tempstring.isEmpty()) 1.539 + Rowdata += TITRAQ_SEPARATORTOK + Tempstring; 1.540 + Tempstring = m_pMaintable->text(Select.topRow() + nIter, TITRAQ_IDXCRC); 1.541 + if (!Tempstring.isEmpty()) 1.542 + Rowdata += TITRAQ_SEPARATORTOK + Tempstring; 1.543 + Tempstring = m_pMaintable->text(Select.topRow() + nIter, TITRAQ_IDXREV); 1.544 + if (!Tempstring.isEmpty()) 1.545 + Rowdata += TITRAQ_SEPARATORTOK + Tempstring; 1.546 + Tempstring = m_pMaintable->text(Select.topRow() + nIter, TITRAQ_IDXDATE); 1.547 + if (!Tempstring.isEmpty()) 1.548 + Rowdata += TITRAQ_SEPARATORTOK + Tempstring; 1.549 + Tempstring = m_pMaintable->text(Select.topRow() + nIter, TITRAQ_IDXSTART); 1.550 + if (!Tempstring.isEmpty()) 1.551 + Rowdata += TITRAQ_SEPARATORTOK + Tempstring; 1.552 + Tempstring = m_pMaintable->text(Select.topRow() + nIter, TITRAQ_IDXFINISH); 1.553 + if (!Tempstring.isEmpty()) 1.554 + Rowdata += TITRAQ_SEPARATORTOK + Tempstring; 1.555 + Tempstring = m_pMaintable->text(Select.topRow() + nIter, TITRAQ_IDXAMOUNT); 1.556 + if (!Tempstring.isEmpty()) 1.557 + Rowdata += TITRAQ_SEPARATORTOK + Tempstring; 1.558 + Tempstring = m_pMaintable->text(Select.topRow() + nIter, TITRAQ_IDXTASK); 1.559 + if (!Tempstring.isEmpty()) 1.560 + Rowdata += TITRAQ_SEPARATORTOK + Tempstring; 1.561 + Tempstring = m_pMaintable->text(Select.topRow() + nIter, TITRAQ_IDXREMARK); 1.562 + if (!Tempstring.isEmpty()) 1.563 + Rowdata += TITRAQ_SEPARATORTOK + Tempstring; 1.564 + Rowdata += trUtf8("\n"); // Finish off line 1.565 + } 1.566 + 1.567 + return Rowdata; 1.568 +} 1.569 + 1.570 +// 1.571 +// Set a whole row of data 1.572 +// 1.573 +void Titraqform::setRowdata(QString &Rowdata) const 1.574 +{ 1.575 + int nRows = Rowdata.contains(QChar('\n')); // Set so many rows 1.576 + int nCurrentrow = m_pMaintable->currentRow(); // Current table row 1.577 + QTableItem *pItem = NULL; // Old item to change out 1.578 + QString Line, User, Guid, Crc, Rev; // Admin fields in table 1.579 + QString Date, Start, Finish, Amount, Task, Remark; // Viewable fields in table 1.580 + QTextStream Datastream(&Rowdata, IO_ReadOnly); // Convert data to stream 1.581 + 1.582 + for (int nIter = 0; nIter < nRows; ++nIter) { 1.583 + QString Singlerow = Datastream.readLine(); // For linewise operation 1.584 + QTextStream Rowstream(&Singlerow, IO_ReadOnly); // Convert row to stream 1.585 + 1.586 + Rowstream >> Line >> User >> Guid >> Crc >> Rev; // Stream data fields 1.587 + Rowstream >> Date >> Start >> Finish >> Amount >> Task; // to corresponding vars 1.588 + Remark = Rowstream.readLine(); // Remark is a whole line 1.589 + 1.590 + // Set the table row data one field at a time, skipping seps inbetween 1.591 + // Importantly, do not copy over the GUID, which must be unique each row 1.592 + m_pMaintable->setText(nCurrentrow + nIter, TITRAQ_IDXLINE, Line); 1.593 + m_pMaintable->setText(nCurrentrow + nIter, TITRAQ_IDXUSER, User); 1.594 + m_pMaintable->setText(nCurrentrow + nIter, TITRAQ_IDXCRC, Crc); 1.595 + m_pMaintable->setText(nCurrentrow + nIter, TITRAQ_IDXREV, Rev); 1.596 + m_pMaintable->setText(nCurrentrow + nIter, TITRAQ_IDXDATE, Date); 1.597 + m_pMaintable->setText(nCurrentrow + nIter, TITRAQ_IDXSTART, Start); 1.598 + m_pMaintable->setText(nCurrentrow + nIter, TITRAQ_IDXFINISH, Finish); 1.599 + m_pMaintable->setText(nCurrentrow + nIter, TITRAQ_IDXAMOUNT, Amount); 1.600 + 1.601 +// // FIXME: Why doesn't this code change the RtTableItem text in place? 1.602 +// RtTableItem *pTask = NULL; // Derived and special 1.603 +// pItem = m_pMaintable->item(nCurrentrow + nIter, TITRAQ_IDXTASK); 1.604 +// pTask = static_cast<RtTableItem *>(pItem); 1.605 +// pTask->setText(Task); 1.606 + 1.607 + // Change out old item and replace with new task data 1.608 + pItem = m_pMaintable->item(nCurrentrow + nIter, TITRAQ_IDXTASK); 1.609 + delete(pItem); // Get rid of the old before going with the new 1.610 + RtTableItem *pSwapitem = new RtTableItem(m_pMaintable, QTableItem::WhenCurrent, Task); 1.611 + pSwapitem->setAlignment(AlignLeft | AlignVCenter); 1.612 + m_pMaintable->setItem(nCurrentrow + nIter, TITRAQ_IDXTASK, pSwapitem); 1.613 + 1.614 + // Continue with field processing business as usual 1.615 + m_pMaintable->setText(nCurrentrow + nIter, TITRAQ_IDXREMARK, Remark.simplifyWhiteSpace()); 1.616 + } 1.617 +} 1.618 + 1.619 +// 1.620 +// Discover which column is the first in view 1.621 +// 1.622 +const int Titraqform::getFirstcol(void) const 1.623 +{ 1.624 + int nIter = 0; // Is both iterator in loop and column number returned 1.625 + 1.626 + // Use column selector menu popup as sole key to determining column state 1.627 + while (nIter < TITRAQ_IDXTAIL && !m_pColspopup->isItemChecked(m_pColspopup->idAt(++nIter))) 1.628 + TITRAQ_NOP; 1.629 + 1.630 + return nIter - 1; // Return one less to account for start of item offset 1.631 +}