// // OSSP asgui - Accounting system graphical user interface // Copyright (c) 2002-2004 The OSSP Project (http://www.ossp.org/) // Copyright (c) 2002-2004 Ralf S. Engelschall // Copyright (c) 2002-2004 Michael Schloh von Bennewitz // Copyright (c) 2002-2004 Cable & Wireless Telecommunications Services GmbH // // This file is part of OSSP asgui, an accounting system graphical user // interface which can be found at http://www.ossp.org/pkg/tool/asgui/. // // Permission to use, copy, modify, and distribute this software for // any purpose with or without fee is hereby granted, provided that // the above copyright notice and this permission notice appear in all // copies. // // THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. // IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF // USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT // OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF // SUCH DAMAGE. // // as_dataops.cpp: ISO C++ implementation // // System headers #include #include // Qt general headers #include // Portable regular expressions #include #include #include #include #include // User interface #include "as_const.h" // Application constants #include "as_tableitem.h" // For class RtTableItem #include "as_crc.h" // For quality strings #include "as_uuid.h" // UUID classes #include "as_table.h" // TiTable class // Icon pixel maps #include "as_gfx/statok.xpm" // static const char *s_kpcStatokay_xpm[] #include "as_gfx/staterr.xpm" // static const char *s_kpcStaterror_xpm[] #include "as_gfx/statwrn.xpm" // static const char *s_kpcStatwarn_xpm[] // // Convenience method to load accounts from a file // void Titraqform::loadAccounts(QFile &Fileobj) { if (Fileobj.isOpen()) { // Check state of file Fileobj.flush(); // Begin processing file cleanly QTextStream Account(&Fileobj); // Convert data to stream this->loadAccounts(Account); // Pass off to do the real work } else { if (!Fileobj.open(IO_ReadOnly)) { // Try to open file QString Readerrstr; Readerrstr = trUtf8(TITRAQ_READAFILFAIL).arg(Fileobj.name()); throw Genexcept(Readerrstr.ascii()); } else Fileobj.flush(); // Begin processing file cleanly QTextStream Account(&Fileobj); // Convert data to stream this->loadAccounts(Account); // Pass off to do the real work Fileobj.close(); // Finish fileop by closing } } // // Load accounts themselves data from a stream // void Titraqform::loadAccounts(QTextStream &Tstream) { using namespace std; // Needed for hash tables with hmap map Hashnames; // Hashtable for storing names map Hashnums; // Hashtable for storing repetitions map::iterator Nameiter; // The hashtable name iterator map::iterator Numiter; // The hashtable number iterator QString Line; // Used for linewise editing and whitespace eating // Eat lines until reading the start accounts token while (!Line.startsWith(trUtf8("%!AS-ACCOUNTS")) && !Tstream.atEnd()) { Line = QString(""); // Empty line for later inspection Line = Tstream.readLine(); // Get a new line to examine } // Strip out extra line feeds in stream while (Line.isEmpty() && !Tstream.atEnd()) { Tstream.skipWhiteSpace(); // Strip and get Line = Tstream.readLine(); // the new line if (Line.at(0) == QChar('#')) // Remove comments Line = QString(""); } // Set the accounts choices by linewise reading from the input // stream and parsing the corresponding account fields out of it while (!Line.isEmpty()) { QString Temp; // For reading from stream QTextStream Asline(&Line, IO_ReadOnly); // Convert a single line Asline.skipWhiteSpace(); // Remove whitespaces Asline >> Temp; // Copy revision indicator if (Temp == QString(QChar('R'))) { // Copy the account field Asline >> Temp; // to temporary for transfer string Convstring = Temp; // Convert to string (can't cast?) Hashnames[Convstring] += Hashnames[Convstring]; } Line = QString(""); // Clear line for next round while (Line.isEmpty() && !Tstream.atEnd()) { Tstream.skipWhiteSpace(); // Strip and get Line = Tstream.readLine(); // the new line if (Line.at(0) == QChar('#')) // Remove comments Line = QString(""); } } // Hashnames.insert(map::value_type((string)QString, int)); for (Nameiter = Hashnames.begin(); Nameiter != Hashnames.end(); Nameiter++) Hashnums[Nameiter->second] += Nameiter->first + '\n'; // FIXME: Put this in loadData, to load custom and most used task names before // FIXME: default listings are sorted and inserted for (Numiter = Hashnums.begin(); Numiter != Hashnums.end(); Numiter++) { // Count the number of lines of sorted task names int nNumlines = QString(Numiter->second).contains('\n'); // Iterate through the lines of task names, feeding them into the menu for (int nIter = 0; nIter < nNumlines; nIter++) *m_pTaskentries << QString(Numiter->second).section('\n', nIter, nIter); } } // // Convenience method to load personal data from a file // void Titraqform::loadData(QFile &Fileobj) { if (Fileobj.isOpen()) { // Check state of file Fileobj.flush(); // Begin processing file cleanly QTextStream Asentry(&Fileobj); // Convert data to stream this->loadData(Asentry); // Pass off to do the real work } else { if (!Fileobj.open(IO_ReadOnly)) // Try to open file throw Genexcept(trUtf8(TITRAQ_READPFILFAIL)); else Fileobj.flush(); // Begin processing file cleanly QTextStream Asentry(&Fileobj); // Convert data to stream this->loadData(Asentry); // Pass off to do the real work Fileobj.close(); // Finish fileop by closing } } // // Load personal data from a stream // void Titraqform::loadData(QTextStream &Tstream) { bool bValid = true; // Used to warn on globally invalid accounting data int nIter = 0; // Iterator used in loop and also as a count QString Line; // Used for linewise editing and whitespace eating QString Bitbucket; // Used for null device until we find a better way QPixmap Statokay(s_kpcStatokay_xpm); QPixmap Statwarn(s_kpcStatwarn_xpm); QPixmap Staterror(s_kpcStaterror_xpm); // Strip out extra line feeds at stream start while (Line.isEmpty() && !Tstream.atEnd()) { Tstream.skipWhiteSpace(); // Strip and get Line = Tstream.readLine(); // the new line if (Line.at(0) == QChar('#')) // Remove comments Line = QString(""); } // Strip out extra line feeds after reading the data symbol Line = QString(""); // Reset our line while (Line.isEmpty() && !Tstream.atEnd()) { Tstream.skipWhiteSpace(); // Strip and get Line = Tstream.readLine(); // the new line if (Line.at(0) == QChar('#')) // Remove comments Line = QString(""); } // // Going into data churning, so prepare date and time parsing and conversion // Converdate.setSeparator(trUtf8(".")); // Convertime.setSeparator(trUtf8(":")); // Optimize viewing by repainting cells only once after processing m_pMaintable->setUpdatesEnabled(false); // Set the table text by linewise reading from the input stream // and parsing date, time, account, and other columns out of it while (!Line.isEmpty()) { bool bValid = true; // Warns on linewise invalid accounting data QString User, Guid, Crc, Rev; // Valid admin fields QString Date, Start, Finish, Account, Amount, Remark; // Valid user fields QTextStream Asline(&Line, IO_ReadOnly); // Convert a single line now if (nIter % g_knBlocks == 0) // Add blocks of rows to optimize loading m_pMaintable->setNumRows(m_pMaintable->numRows() + g_knBlocks); Asline.skipWhiteSpace(); // Remove whitespaces Asline >> User; // Copy the user field if (!User.isEmpty()) m_pMaintable->setText(nIter, TITRAQ_IDXUSER, User); else bValid = false; Asline.skipWhiteSpace(); // Remove whitespaces Asline >> Guid; // Copy the GUID field // Postpone actual text delivery, to autoinsert GUIDs! Asline.skipWhiteSpace(); // Remove whitespaces Asline >> Crc; // Copy the CRC field // Postpone actual text delivery, to autoinsert CRCs! Asline.skipWhiteSpace(); // Remove whitespaces Asline >> Rev; // Copy the rev field if (!Rev.isEmpty()) m_pMaintable->setText(nIter, TITRAQ_IDXREV, Rev); else bValid = false; Asline.skipWhiteSpace(); // Remove whitespaces Asline >> Date; // Copy the date field if (!Date.isEmpty()) m_pMaintable->setText(nIter, TITRAQ_IDXDATE, Date); else bValid = false; Asline.skipWhiteSpace(); // Remove whitespaces Asline >> Start; // Copy the start field if (!Start.isEmpty()) m_pMaintable->setText(nIter, TITRAQ_IDXSTART, Start); else bValid = false; Asline.skipWhiteSpace(); // Remove whitespaces Asline >> Finish; // Copy the finish field if (!Finish.isEmpty()) m_pMaintable->setText(nIter, TITRAQ_IDXFINISH, Finish); else bValid = false; Asline.skipWhiteSpace(); // Remove whitespaces Asline >> Amount; // Copy the amount field if (!Amount.isEmpty()) m_pMaintable->setText(nIter, TITRAQ_IDXAMOUNT, Amount); else bValid = false; Asline.skipWhiteSpace(); // Remove whitespaces Asline >> Account; // Copy the account field if (!Account.isEmpty()) { QTableItem *pOld = m_pMaintable->item(nIter, TITRAQ_IDXTASK); delete(pOld); // Get rid of the old before going with the new RtTableItem *pSwapitem = new RtTableItem(m_pMaintable, QTableItem::WhenCurrent, Account); pSwapitem->setAlignment(AlignLeft | AlignVCenter); m_pMaintable->setItem(nIter, TITRAQ_IDXTASK, pSwapitem); } else bValid = false; Asline.skipWhiteSpace(); // Remove whitespaces Remark = Asline.read(); // Copy the remark field QRegExp Quoted("\"(.*[^\\\\])\""); // Get rid of Quoted.search(Remark); // surrounding double Remark = Quoted.cap(Quoted.numCaptures()); // quotes, and Remark.replace(QRegExp("\\\\(.)"), QString("\\1")); // escape backslashes if (!Remark.isEmpty()) m_pMaintable->setText(nIter, TITRAQ_IDXREMARK, Remark); if (bValid) { // Show a bitmap to signal valid or error state m_pMaintable->setText(nIter, TITRAQ_IDXSTATUS, QString(QChar('O'))); m_pMaintable->setPixmap(nIter, TITRAQ_IDXSTATUS, Statokay); } else { m_pMaintable->setText(nIter, TITRAQ_IDXSTATUS, QString(QChar('E'))); m_pMaintable->setPixmap(nIter, TITRAQ_IDXSTATUS, Staterror); } // Set the GUID text here, in case we need to generate a fresh value if (!Guid.isEmpty()) { if (Guid != ".") // This means, generate a fresh GUID value m_pMaintable->setText(nIter, TITRAQ_IDXGUID, Guid); else { AS::Uuid Guidi; // For GUID production Guidi.genId(); m_pMaintable->setText(nIter, TITRAQ_IDXGUID, Guidi.getString()); } } else // if isEmpty() bValid = false; // Set the CRC text here, in case we need to generate a fresh value if (!Crc.isEmpty()) { if (Crc != ".") // This means, generate a fresh CRC value m_pMaintable->setText(nIter, TITRAQ_IDXCRC, "0x" + Crc); else { // Make our long tuple to run through the CRC32 generator Qualistring Testuple = User + Guid + Rev + Date + Start; Testuple += Finish + Amount + Account + Remark; U32 Valcrc = Testuple.getCrc(); // Finally set the checksum to its new value QString Crcstr = QString::number(Valcrc, 16).rightJustify(8, '0'); m_pMaintable->setText(nIter, TITRAQ_IDXCRC, "0x" + Crcstr); } } else // if isEmpty() bValid = false; nIter++; // The big increment Line = QString(""); // Clear line for next round while (Line.isEmpty() && !Tstream.atEnd()) { // Strip and get Tstream.skipWhiteSpace(); // Remove white Line = Tstream.readLine(); // the new line if (Line.at(0) == QChar('#')) // Remove comments Line = QString(""); } } // // Start sorting order and direction correctly according to user preferences // int nSortcol = (int)m_pPrefs->getNumber(TITRAQ_PREFSORTCOL, TITRAQ_DEFSORTCOL); // bool bSortdir = m_pPrefs->getBool(TITRAQ_PREFSORTDIR, TITRAQ_DEFSORTDIR); // m_pMaintable->setSortdir(!bSortdir); // Hack! Fake sortdir so we start right // m_pMaintable->sortColumn(nSortcol, bSortdir); // Write nonsaving line numbers for all rows for (int nIter = m_pMaintable->numRows() - 1; nIter >= 0; nIter--) m_pMaintable->setText(nIter, TITRAQ_IDXLINE, QString::number(nIter).rightJustify(4, QChar('0'))); m_pMaintable->setNumRows(nIter); // No excess rows m_pMaintable->setCurrentCell(nIter - 1, 0); // Move focus to last row m_pMaintable->setUpdatesEnabled(true); // Update m_pMaintable->ensureCellVisible(nIter - 1, 0); // Scroll please if (!bValid) throw Genexcept("Warning: invalid accounting data."); } // // Convenience method to save accounting data to a file // void Titraqform::saveData(QFile &Fileobj) { if (Fileobj.isOpen()) { // Check state of file Fileobj.flush(); // Begin processing file cleanly QTextStream Asentry(&Fileobj); // Convert data to stream this->saveData(Asentry); // Pass off to do the real work } else { if (!Fileobj.open(IO_WriteOnly)) // Try to open file throw Genexcept(trUtf8(TITRAQ_READPFILFAIL)); QTextStream Asentry(&Fileobj); // Convert data to stream this->saveData(Asentry); // Pass off to do the real work Fileobj.close(); // Finish fileop by closing } } // // Save accounting data to a stream // void Titraqform::saveData(QTextStream &Tstream) { const int nRows = m_pMaintable->numRows(); // Max rows used in loop QString Tempfield; // Current field string QString Strsearch; // String to strip search QRegExp Stripper("\\s*$"); // Pattern to strip off // Start by prepending the AS data format version symbol Tstream << TITRAQ_DATAPATTERN << TITRAQ_DATAVERSIONMAJ << QChar('.') << TITRAQ_DATAVERSIONMIN << endl; // Linewise save from the main table date, time, account, and others for (int nIter = 0; nIter < nRows; nIter++) { Tempfield = m_pMaintable->text(nIter, TITRAQ_IDXUSER); // Load user field text if (Tempfield != NULL) Tstream << Tempfield; // Save user field text Tempfield = m_pMaintable->text(nIter, TITRAQ_IDXGUID); // Load GUID field text if (Tempfield != NULL) Tstream << trUtf8(" ") << Tempfield; // Save GUID field text Tempfield = m_pMaintable->text(nIter, TITRAQ_IDXCRC); // Load CRC field text Tempfield.remove("0x"); if (Tempfield != NULL) Tstream << trUtf8(" ") << Tempfield; // Save CRC field text Tempfield = m_pMaintable->text(nIter, TITRAQ_IDXREV); // Load rev field text if (Tempfield != NULL) Tstream << trUtf8(" ") << Tempfield; // Save rev field text Tempfield = m_pMaintable->text(nIter, TITRAQ_IDXDATE); // Load date field text if (Tempfield != NULL) Tstream << trUtf8(" ") << Tempfield; // Save date field text Tempfield = m_pMaintable->text(nIter, TITRAQ_IDXSTART); // Load start field text if (Tempfield != NULL) Tstream << trUtf8(" ") << Tempfield; // Save start field text Tempfield = m_pMaintable->text(nIter, TITRAQ_IDXFINISH); // Load end field text if (Tempfield != NULL) Tstream << trUtf8(" ") << Tempfield; // Save end field text Tempfield = m_pMaintable->text(nIter, TITRAQ_IDXAMOUNT); // Load amount field text if (Tempfield != NULL) Tstream << trUtf8(" ") << Tempfield; // Save amount Tempfield = m_pMaintable->text(nIter, TITRAQ_IDXTASK); // Load acct field text if (Tempfield != NULL) Tstream << trUtf8(" ") << Tempfield; // Save acct field text Tempfield = m_pMaintable->text(nIter, TITRAQ_IDXREMARK); // Load remark field text Tstream << trUtf8(" \""); // Save beginning double quote if (Tempfield != NULL) { Strsearch = QRegExp::escape(Tempfield); // Incoming string escaped Stripper.search(Strsearch); Tempfield.truncate(Stripper.pos()); // Cut off whitespace Tempfield.replace(QChar('\\'), QString("\\\\")); // Escape back slashes Tempfield.replace(QChar('\"'), QString("\\\"")); // Escape double quotes Tstream << Tempfield; // Save remark field text } Tstream << trUtf8("\""); // Save ending double quote Tstream << endl; // Append a newline } } // // Convenience method to validate AS data in a file // const bool Titraqform::validateData(QFile &Filin) const { QString Firstline; // Will contain the first line of text bool bRet = false; // Set the initial return value if (Filin.isOpen()) { // Check open state of file Filin.flush(); // Not sure if this is needed Filin.reset(); // Set the file index position to 0 Filin.readLine(Firstline, QString(TITRAQ_DATAPATTERN).length() + 2L); } else { if (!Filin.open(IO_ReadOnly)) // Try to open file throw Genexcept(trUtf8(TITRAQ_READPFILFAIL)); else { // File is now open Filin.readLine(Firstline, QString(TITRAQ_DATAPATTERN).length() + 2L); Filin.close(); // Remember to close } } try { // Pass off to worker method bRet = this->validateData(Firstline); } catch (Genexcept &) { throw; // Rethrow onwards } return bRet; } // // Validate the AS data pattern in a line // const bool Titraqform::validateData(QString &Linin) const { bool bRet = false; // Initial return value // Ensure that the right data version pattern precedes the data QString Datapattern = QString(TITRAQ_DATAPATTERN); if (!Linin.startsWith(Datapattern)) { // Incompatible data format QMessageBox Problema(QString(TITRAQ_APPTITLE) + ' ' + asgui_version.v_short, TITRAQ_NOPATTERNFOUND + QString(TITRAQ_DATAPATTERN) + TITRAQ_WASNOTFOUNDIN, QMessageBox::Critical, QMessageBox::Ok | QMessageBox::Escape, QMessageBox::NoButton, QMessageBox::NoButton); Problema.exec(); // Give the user the bad news throw Genexcept(TITRAQ_INVALIDDATA); } else if (Linin.section(Datapattern, 1).section('.', 0, 0).toInt() != TITRAQ_DATAVERSIONMAJ) { QMessageBox Problema(QString(TITRAQ_APPTITLE) + ' ' + asgui_version.v_short, TITRAQ_BADVERSIONMAJ, QMessageBox::Warning, QMessageBox::Ok | QMessageBox::Escape, QMessageBox::NoButton, QMessageBox::NoButton); Problema.exec(); // Give the user the bad news throw Genexcept(TITRAQ_INCOMPATDATA); } else if (Linin.section(Datapattern, 1).section('.', 1, 1).toInt() > TITRAQ_DATAVERSIONMIN) { QMessageBox Problema(QString(TITRAQ_APPTITLE) + ' ' + asgui_version.v_short, TITRAQ_BADVERSIONMIN, QMessageBox::Warning, QMessageBox::Ok | QMessageBox::Escape, QMessageBox::NoButton, QMessageBox::NoButton); Problema.exec(); // Give the user the bad news throw Genexcept(TITRAQ_INCOMPATDATA); } else bRet = true; return bRet; // Not reached in case of failure } // // Get a whole row of data // const QString Titraqform::getRowdata(void) const { QString Rowdata, Tempstring; // For output string QTableSelection Select = m_pMaintable->selection(0); // Highlighted text int nTotal = Select.bottomRow() - Select.topRow() + 1; // Total row select // Calculate rows to delete from selection highlight for (int nIter = 0; nIter < nTotal; ++nIter) { // Build the row data string one field at a time, adding seps inbetween Tempstring = m_pMaintable->text(Select.topRow() + nIter, TITRAQ_IDXLINE); if (!Tempstring.isEmpty()) Rowdata += Tempstring; Tempstring = m_pMaintable->text(Select.topRow() + nIter, TITRAQ_IDXUSER); if (!Tempstring.isEmpty()) Rowdata += TITRAQ_SEPARATORTOK + Tempstring; Tempstring = m_pMaintable->text(Select.topRow() + nIter, TITRAQ_IDXGUID); if (!Tempstring.isEmpty()) Rowdata += TITRAQ_SEPARATORTOK + Tempstring; Tempstring = m_pMaintable->text(Select.topRow() + nIter, TITRAQ_IDXCRC); if (!Tempstring.isEmpty()) Rowdata += TITRAQ_SEPARATORTOK + Tempstring; Tempstring = m_pMaintable->text(Select.topRow() + nIter, TITRAQ_IDXREV); if (!Tempstring.isEmpty()) Rowdata += TITRAQ_SEPARATORTOK + Tempstring; Tempstring = m_pMaintable->text(Select.topRow() + nIter, TITRAQ_IDXDATE); if (!Tempstring.isEmpty()) Rowdata += TITRAQ_SEPARATORTOK + Tempstring; Tempstring = m_pMaintable->text(Select.topRow() + nIter, TITRAQ_IDXSTART); if (!Tempstring.isEmpty()) Rowdata += TITRAQ_SEPARATORTOK + Tempstring; Tempstring = m_pMaintable->text(Select.topRow() + nIter, TITRAQ_IDXFINISH); if (!Tempstring.isEmpty()) Rowdata += TITRAQ_SEPARATORTOK + Tempstring; Tempstring = m_pMaintable->text(Select.topRow() + nIter, TITRAQ_IDXAMOUNT); if (!Tempstring.isEmpty()) Rowdata += TITRAQ_SEPARATORTOK + Tempstring; Tempstring = m_pMaintable->text(Select.topRow() + nIter, TITRAQ_IDXTASK); if (!Tempstring.isEmpty()) Rowdata += TITRAQ_SEPARATORTOK + Tempstring; Tempstring = m_pMaintable->text(Select.topRow() + nIter, TITRAQ_IDXREMARK); if (!Tempstring.isEmpty()) Rowdata += TITRAQ_SEPARATORTOK + Tempstring; Rowdata += trUtf8("\n"); // Finish off line } return Rowdata; } // // Set a whole row of data // void Titraqform::setRowdata(QString &Rowdata) const { int nRows = Rowdata.contains(QChar('\n')); // Set so many rows int nCurrentrow = m_pMaintable->currentRow(); // Current table row QTableItem *pItem = NULL; // Old item to change out QString Line, User, Guid, Crc, Rev; // Admin fields in table QString Date, Start, Finish, Amount, Task, Remark; // Viewable fields in table QTextStream Datastream(&Rowdata, IO_ReadOnly); // Convert data to stream for (int nIter = 0; nIter < nRows; ++nIter) { QString Singlerow = Datastream.readLine(); // For linewise operation QTextStream Rowstream(&Singlerow, IO_ReadOnly); // Convert row to stream Rowstream >> Line >> User >> Guid >> Crc >> Rev; // Stream data fields Rowstream >> Date >> Start >> Finish >> Amount >> Task; // to corresponding vars Remark = Rowstream.readLine(); // Remark is a whole line // Set the table row data one field at a time, skipping seps inbetween // Importantly, do not copy over the GUID, which must be unique each row m_pMaintable->setText(nCurrentrow + nIter, TITRAQ_IDXLINE, Line); m_pMaintable->setText(nCurrentrow + nIter, TITRAQ_IDXUSER, User); m_pMaintable->setText(nCurrentrow + nIter, TITRAQ_IDXCRC, Crc); m_pMaintable->setText(nCurrentrow + nIter, TITRAQ_IDXREV, Rev); m_pMaintable->setText(nCurrentrow + nIter, TITRAQ_IDXDATE, Date); m_pMaintable->setText(nCurrentrow + nIter, TITRAQ_IDXSTART, Start); m_pMaintable->setText(nCurrentrow + nIter, TITRAQ_IDXFINISH, Finish); m_pMaintable->setText(nCurrentrow + nIter, TITRAQ_IDXAMOUNT, Amount); // // FIXME: Why doesn't this code change the RtTableItem text in place? // RtTableItem *pTask = NULL; // Derived and special // pItem = m_pMaintable->item(nCurrentrow + nIter, TITRAQ_IDXTASK); // pTask = static_cast(pItem); // pTask->setText(Task); // Change out old item and replace with new task data pItem = m_pMaintable->item(nCurrentrow + nIter, TITRAQ_IDXTASK); delete(pItem); // Get rid of the old before going with the new RtTableItem *pSwapitem = new RtTableItem(m_pMaintable, QTableItem::WhenCurrent, Task); pSwapitem->setAlignment(AlignLeft | AlignVCenter); m_pMaintable->setItem(nCurrentrow + nIter, TITRAQ_IDXTASK, pSwapitem); // Continue with field processing business as usual m_pMaintable->setText(nCurrentrow + nIter, TITRAQ_IDXREMARK, Remark.simplifyWhiteSpace()); } } // // Discover which column is the first in view // const int Titraqform::getFirstcol(void) const { int nIter = 0; // Is both iterator in loop and column number returned // Use column selector menu popup as sole key to determining column state while (nIter < TITRAQ_IDXTAIL && !m_pColspopup->isItemChecked(m_pColspopup->idAt(++nIter))) TITRAQ_NOP; return nIter - 1; // Return one less to account for start of item offset }