// // 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_table.cpp: ISO C++ implementation // #include #include "as_const.h" #include "as_table.h" // Implements an event filter for catching header double click events bool TiTable::eventFilter(QObject *pObject, QEvent *pEvent) { if (pObject == horizontalHeader() && pEvent->type() == QEvent::MouseButtonDblClick) return true; if (pEvent->type() == QEvent::MouseButtonPress && // Ignore mid, right clicks ((QMouseEvent *)pEvent)->button() == QMouseEvent::RightButton || ((QMouseEvent *)pEvent)->button() == QMouseEvent::MidButton) return true; else if (pEvent->type() == QEvent::KeyPress) { if (((QKeyEvent *)pEvent)->key() == Qt::Key_Tab) { // Handle tab key if (this->getEdition() >= 0) { int nIter = 1; // Logic to skip invisible or read only columns while (columnWidth((currentColumn() + nIter) % TITRAQ_IDXTAIL) <= 0 || isColumnReadOnly((currentColumn() + nIter) % TITRAQ_IDXTAIL)) nIter++; // Advance the column or both row and column possibly int nColadvance = ((currentColumn() + nIter) % TITRAQ_IDXTAIL); if ((currentColumn() + nIter) >= TITRAQ_IDXTAIL) { this->clearSelection(true); this->setCurrentCell(currentRow() + 1, nColadvance); // this->repaint(false); // Really necessary? } else this->setCurrentCell(currentRow(), nColadvance); this->setReadOnly(false); this->editCell(currentRow(), currentColumn()); this->setEdition(currentColumn()); } return true; // Handle the tab key event and cancel its progress } else if (((QKeyEvent *)pEvent)->key() == Qt::Key_Backtab) { // Handle shift tab key if (this->getEdition() >= 0) { int nIter = 1; // Logic to skip invisible or read only columns while (columnWidth((currentColumn() - nIter + TITRAQ_IDXTAIL) % TITRAQ_IDXTAIL) <= 0 || isColumnReadOnly((currentColumn() - nIter + TITRAQ_IDXTAIL) % TITRAQ_IDXTAIL)) nIter++; // Advance the column or both row and column possibly int nColadvance = (currentColumn() - nIter + TITRAQ_IDXTAIL) % TITRAQ_IDXTAIL; if ((currentColumn() - nIter) < 0) { this->clearSelection(true); this->setCurrentCell(currentRow() - 1, nColadvance); // this->repaint(false); // Really necessary? } else this->setCurrentCell(currentRow(), nColadvance); this->setReadOnly(false); this->editCell(currentRow(), currentColumn()); this->setEdition(currentColumn()); } return true; // Handle the shift tab key event and cancel its progress } else if (((QKeyEvent *)pEvent)->key() == Qt::Key_Return && this->getEdition() >= 0) { // Return key this->endEdit(currEditRow(), currEditCol(), true, false); this->setEdition(); // Reset edition return true; // Cancel progress } else if (((QKeyEvent *)pEvent)->key() == Qt::Key_Enter && this->getEdition() >= 0) { // Enter key this->endEdit(currEditRow(), currEditCol(), true, false); this->setEdition(); // Reset edition return true; // Cancel progress } else if (((QKeyEvent *)pEvent)->key() == Qt::Key_Return) { // Return key without edition this->setReadOnly(false); // Allow edition this->editCell(currentRow(), currentColumn()); // Begin edition this->setEdition(currentColumn()); // Store edition state return true; // Cancel further progress } else if (((QKeyEvent *)pEvent)->key() == Qt::Key_Enter) { // Enter key without edition this->setReadOnly(false); // Allow edition this->editCell(currentRow(), currentColumn()); // Begin edition this->setEdition(currentColumn()); // Store edition state return true; // Cancel further progress } else if (((QKeyEvent *)pEvent)->key() == Qt::Key_Escape) // Handle escape key this->setEdition(); else if (((QKeyEvent *)pEvent)->key() == Qt::Key_Up && this->getEdition() >= 0) // Handle up key return true; // Capture else if (((QKeyEvent *)pEvent)->key() == Qt::Key_Down && this->getEdition() >= 0) // Handle down key return true; // Capture // Forward incompletely handled key events return QTable::eventFilter(pObject, pEvent); } else // Default behaviour is to pass the event onwards return QTable::eventFilter(pObject, pEvent); } // Overridden member hack to allow externally connected control // widgets to influence dirty or clean state of table data void TiTable::setText(int nRow, int nCol, const QString &nText) { if (this->numRows() > 0) { // If a cell was edited, emit a signal indicating so // We can't rely on valueChanged for unknown reasons if (nText != this->text(nRow, nCol) && nCol != TITRAQ_IDXLINE) emit textEdited(nRow, nCol); QTable::setText(nRow, nCol, nText); } } // Overridden member hack to allow externally connected control // widgets to influence dirty or clean state of table data void TiTable::sortColumn(int nCol, bool bAscend, bool bWhole) { // Guard against a repeat sort behaviour if (nCol == this->getSortcol() && bAscend == this->getSortdir()) this->setSortdir(!bAscend); else this->setSortdir(bAscend); this->setSortcol(nCol); QTable::sortColumn(nCol, this->getSortdir(), true); // // Announce sorting policy with multiple selections // QTableSelection Testsel = this->selection(this->currentSelection()); // if (Testsel.topRow() != Testsel.bottomRow()) // m_pStatbar->message(trUtf8("Multiple selections dropped when sorting"), 4000); // Move and display the selection highlight this->removeSelection(this->currentSelection()); this->selectRow(this->currentRow()); this->ensureCellVisible(this->currentRow(), 0); // Write nonsaving line numbers for all rows for (int nIter = this->numRows() - 1; nIter >= 0; nIter--) this->setText(nIter, TITRAQ_IDXLINE, QString::number(nIter).rightJustify(4, QChar('0'))); } // Overriden member to render edge rows differently according to a sort key void TiTable::paintCell(QPainter *pPainter, int nRow, int nCol, const QRect &Recto, bool bSelect, const QColorGroup &Colgroup) { QColorGroup Cgroup(Colgroup); int nRed, nGreen, nBlue; nRed = m_pTiprefs->getNumber(TITRAQ_PREFLIGHTRED, TITRAQ_DEFLIGHTRED); nGreen = m_pTiprefs->getNumber(TITRAQ_PREFLIGHTGREEN, TITRAQ_DEFLIGHTGREEN); nBlue = m_pTiprefs->getNumber(TITRAQ_PREFLIGHTBLUE, TITRAQ_DEFLIGHTBLUE); QColor Bright = QColor(nRed, nGreen, nBlue); nRed = m_pTiprefs->getNumber(TITRAQ_PREFDARKRED, TITRAQ_DEFDARKRED); nGreen = m_pTiprefs->getNumber(TITRAQ_PREFDARKGREEN, TITRAQ_DEFDARKGREEN); nBlue = m_pTiprefs->getNumber(TITRAQ_PREFDARKBLUE, TITRAQ_DEFDARKBLUE); QColor Dark = QColor(nRed, nGreen, nBlue); // Alternate color for nonmatching sort keys QString Cur = this->text(nRow, this->getSortcol()); QString Las = this->text(nRow - 1, this->getSortcol()); // A nice cascade of conditions providing a linewise base color test and set // The algorythm: // 1 Determine if the current row's index key differs from the former one // 2a If they are the same, then current row should have the same color // 2b If they are different, then current row should have an alt color // 3 Store information about which color we chose for the current row if (!Cur.isNull() && !Las.isNull() && Cur == Las) { // Set the base color conditionally if (this->text(nRow - 1, TITRAQ_IDXSTATUS).at(TITRAQ_IDXSTATCOLOR) == QChar(TITRAQ_BRIGHT)) { Cgroup.setColor(QColorGroup::Base, Bright); // Bright if (this->text(nRow, TITRAQ_IDXSTATUS).at(TITRAQ_IDXSTATCOLOR) != QChar(TITRAQ_BRIGHT)) this->setText(nRow, TITRAQ_IDXSTATUS, this->text(nRow, TITRAQ_IDXSTATUS).replace(TITRAQ_IDXSTATCOLOR, sizeof(char), QChar(TITRAQ_BRIGHT))); } else { Cgroup.setColor(QColorGroup::Base, Dark); // Dark if (this->text(nRow, TITRAQ_IDXSTATUS).at(TITRAQ_IDXSTATCOLOR) != QChar(TITRAQ_DARK)) this->setText(nRow, TITRAQ_IDXSTATUS, this->text(nRow, TITRAQ_IDXSTATUS).replace(TITRAQ_IDXSTATCOLOR, sizeof(char), QChar(TITRAQ_DARK))); } } else { if (this->text(nRow - 1, TITRAQ_IDXSTATUS).at(TITRAQ_IDXSTATCOLOR) == QChar(TITRAQ_BRIGHT)) { Cgroup.setColor(QColorGroup::Base, Dark); // Dark if (this->text(nRow, TITRAQ_IDXSTATUS).at(TITRAQ_IDXSTATCOLOR) != QChar(TITRAQ_DARK)) this->setText(nRow, TITRAQ_IDXSTATUS, this->text(nRow, TITRAQ_IDXSTATUS).replace(TITRAQ_IDXSTATCOLOR, sizeof(char), QChar(TITRAQ_DARK))); } else { Cgroup.setColor(QColorGroup::Base, Bright); // Bright if (this->text(nRow, TITRAQ_IDXSTATUS).at(TITRAQ_IDXSTATCOLOR) != QChar(TITRAQ_BRIGHT)) this->setText(nRow, TITRAQ_IDXSTATUS, this->text(nRow, TITRAQ_IDXSTATUS).replace(TITRAQ_IDXSTATCOLOR, sizeof(char), QChar(TITRAQ_BRIGHT))); } } QTable::paintCell(pPainter, nRow, nCol, Recto, bSelect, Cgroup); }; // Blah void TiTable::activateNextCell(void) { int nIter = 1; // Logic to skip invisible or read only columns while (columnWidth((currentColumn() + nIter) % TITRAQ_IDXTAIL) <= 0 || isColumnReadOnly((currentColumn() + nIter) % TITRAQ_IDXTAIL)) nIter++; // Advance the column or both row and column possibly int nColadvance = ((currentColumn() + nIter) % TITRAQ_IDXTAIL); if ((currentColumn() + nIter) >= TITRAQ_IDXTAIL) this->setCurrentCell(currentRow() + 1, nColadvance); else this->setCurrentCell(currentRow(), nColadvance); this->setReadOnly(false); this->editCell(currentRow(), currentColumn()); this->setEdition(currentColumn()); } // Overriden member to properly handle read only attribute after edition void TiTable::endEdit(int nRow, int nCol, bool bAccept, bool bReplace) { QTable::endEdit(nRow, nCol, bAccept, bReplace); // Table read only attribute must be set to return to the normal // row highlight and selection behaviour of AS. The reason it was // reset in inplaceEdit() was to allow editing in the first place. this->setReadOnly(true); }