as_dataop.cpp

changeset 1
d64aaa7d146f
child 3
c1941114ca88
     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 +}

mercurial