diff -r 27e940e8e5f3 -r d64aaa7d146f as_table.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/as_table.cpp Fri Nov 28 11:21:08 2008 +0100 @@ -0,0 +1,251 @@ +// +// 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); +}