1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/as_table.cpp Fri Nov 28 11:21:08 2008 +0100 1.3 @@ -0,0 +1,251 @@ 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_table.cpp: ISO C++ implementation 1.33 +// 1.34 + 1.35 +#include <qheader.h> 1.36 + 1.37 +#include "as_const.h" 1.38 +#include "as_table.h" 1.39 + 1.40 + 1.41 +// Implements an event filter for catching header double click events 1.42 +bool TiTable::eventFilter(QObject *pObject, QEvent *pEvent) 1.43 +{ 1.44 + if (pObject == horizontalHeader() && pEvent->type() == QEvent::MouseButtonDblClick) 1.45 + return true; 1.46 + if (pEvent->type() == QEvent::MouseButtonPress && // Ignore mid, right clicks 1.47 + ((QMouseEvent *)pEvent)->button() == QMouseEvent::RightButton || 1.48 + ((QMouseEvent *)pEvent)->button() == QMouseEvent::MidButton) 1.49 + return true; 1.50 + else if (pEvent->type() == QEvent::KeyPress) { 1.51 + if (((QKeyEvent *)pEvent)->key() == Qt::Key_Tab) { // Handle tab key 1.52 + if (this->getEdition() >= 0) { 1.53 + int nIter = 1; // Logic to skip invisible or read only columns 1.54 + while (columnWidth((currentColumn() + nIter) % TITRAQ_IDXTAIL) <= 0 1.55 + || isColumnReadOnly((currentColumn() + nIter) % TITRAQ_IDXTAIL)) 1.56 + nIter++; 1.57 + 1.58 + // Advance the column or both row and column possibly 1.59 + int nColadvance = ((currentColumn() + nIter) % TITRAQ_IDXTAIL); 1.60 + if ((currentColumn() + nIter) >= TITRAQ_IDXTAIL) { 1.61 + this->clearSelection(true); 1.62 + this->setCurrentCell(currentRow() + 1, nColadvance); 1.63 +// this->repaint(false); // Really necessary? 1.64 + } 1.65 + else 1.66 + this->setCurrentCell(currentRow(), nColadvance); 1.67 + this->setReadOnly(false); 1.68 + this->editCell(currentRow(), currentColumn()); 1.69 + this->setEdition(currentColumn()); 1.70 + } 1.71 + return true; // Handle the tab key event and cancel its progress 1.72 + } 1.73 + else if (((QKeyEvent *)pEvent)->key() == Qt::Key_Backtab) { // Handle shift tab key 1.74 + if (this->getEdition() >= 0) { 1.75 + int nIter = 1; // Logic to skip invisible or read only columns 1.76 + while (columnWidth((currentColumn() - nIter + TITRAQ_IDXTAIL) % TITRAQ_IDXTAIL) <= 0 1.77 + || isColumnReadOnly((currentColumn() - nIter + TITRAQ_IDXTAIL) % TITRAQ_IDXTAIL)) 1.78 + nIter++; 1.79 + 1.80 + // Advance the column or both row and column possibly 1.81 + int nColadvance = (currentColumn() - nIter + TITRAQ_IDXTAIL) % TITRAQ_IDXTAIL; 1.82 + if ((currentColumn() - nIter) < 0) { 1.83 + this->clearSelection(true); 1.84 + this->setCurrentCell(currentRow() - 1, nColadvance); 1.85 +// this->repaint(false); // Really necessary? 1.86 + } 1.87 + else 1.88 + this->setCurrentCell(currentRow(), nColadvance); 1.89 + this->setReadOnly(false); 1.90 + this->editCell(currentRow(), currentColumn()); 1.91 + this->setEdition(currentColumn()); 1.92 + } 1.93 + return true; // Handle the shift tab key event and cancel its progress 1.94 + } 1.95 + else if (((QKeyEvent *)pEvent)->key() == Qt::Key_Return && this->getEdition() >= 0) { // Return key 1.96 + this->endEdit(currEditRow(), currEditCol(), true, false); 1.97 + this->setEdition(); // Reset edition 1.98 + return true; // Cancel progress 1.99 + } 1.100 + else if (((QKeyEvent *)pEvent)->key() == Qt::Key_Enter && this->getEdition() >= 0) { // Enter key 1.101 + this->endEdit(currEditRow(), currEditCol(), true, false); 1.102 + this->setEdition(); // Reset edition 1.103 + return true; // Cancel progress 1.104 + } 1.105 + else if (((QKeyEvent *)pEvent)->key() == Qt::Key_Return) { // Return key without edition 1.106 + this->setReadOnly(false); // Allow edition 1.107 + this->editCell(currentRow(), currentColumn()); // Begin edition 1.108 + this->setEdition(currentColumn()); // Store edition state 1.109 + return true; // Cancel further progress 1.110 + } 1.111 + else if (((QKeyEvent *)pEvent)->key() == Qt::Key_Enter) { // Enter key without edition 1.112 + this->setReadOnly(false); // Allow edition 1.113 + this->editCell(currentRow(), currentColumn()); // Begin edition 1.114 + this->setEdition(currentColumn()); // Store edition state 1.115 + return true; // Cancel further progress 1.116 + } 1.117 + else if (((QKeyEvent *)pEvent)->key() == Qt::Key_Escape) // Handle escape key 1.118 + this->setEdition(); 1.119 + else if (((QKeyEvent *)pEvent)->key() == Qt::Key_Up && this->getEdition() >= 0) // Handle up key 1.120 + return true; // Capture 1.121 + else if (((QKeyEvent *)pEvent)->key() == Qt::Key_Down && this->getEdition() >= 0) // Handle down key 1.122 + return true; // Capture 1.123 + 1.124 + // Forward incompletely handled key events 1.125 + return QTable::eventFilter(pObject, pEvent); 1.126 + } 1.127 + else // Default behaviour is to pass the event onwards 1.128 + return QTable::eventFilter(pObject, pEvent); 1.129 +} 1.130 + 1.131 +// Overridden member hack to allow externally connected control 1.132 +// widgets to influence dirty or clean state of table data 1.133 +void TiTable::setText(int nRow, int nCol, const QString &nText) 1.134 +{ 1.135 + if (this->numRows() > 0) { 1.136 + // If a cell was edited, emit a signal indicating so 1.137 + // We can't rely on valueChanged for unknown reasons 1.138 + if (nText != this->text(nRow, nCol) && nCol != TITRAQ_IDXLINE) 1.139 + emit textEdited(nRow, nCol); 1.140 + 1.141 + QTable::setText(nRow, nCol, nText); 1.142 + } 1.143 +} 1.144 + 1.145 +// Overridden member hack to allow externally connected control 1.146 +// widgets to influence dirty or clean state of table data 1.147 +void TiTable::sortColumn(int nCol, bool bAscend, bool bWhole) 1.148 +{ 1.149 + // Guard against a repeat sort behaviour 1.150 + if (nCol == this->getSortcol() && bAscend == this->getSortdir()) 1.151 + this->setSortdir(!bAscend); 1.152 + else 1.153 + this->setSortdir(bAscend); 1.154 + 1.155 + this->setSortcol(nCol); 1.156 + QTable::sortColumn(nCol, this->getSortdir(), true); 1.157 + 1.158 +// // Announce sorting policy with multiple selections 1.159 +// QTableSelection Testsel = this->selection(this->currentSelection()); 1.160 +// if (Testsel.topRow() != Testsel.bottomRow()) 1.161 +// m_pStatbar->message(trUtf8("Multiple selections dropped when sorting"), 4000); 1.162 + 1.163 + // Move and display the selection highlight 1.164 + this->removeSelection(this->currentSelection()); 1.165 + this->selectRow(this->currentRow()); 1.166 + this->ensureCellVisible(this->currentRow(), 0); 1.167 + 1.168 + // Write nonsaving line numbers for all rows 1.169 + for (int nIter = this->numRows() - 1; nIter >= 0; nIter--) 1.170 + this->setText(nIter, TITRAQ_IDXLINE, QString::number(nIter).rightJustify(4, QChar('0'))); 1.171 +} 1.172 + 1.173 +// Overriden member to render edge rows differently according to a sort key 1.174 +void TiTable::paintCell(QPainter *pPainter, int nRow, int nCol, const QRect &Recto, bool bSelect, const QColorGroup &Colgroup) 1.175 +{ 1.176 + QColorGroup Cgroup(Colgroup); 1.177 + int nRed, nGreen, nBlue; 1.178 + 1.179 + nRed = m_pTiprefs->getNumber(TITRAQ_PREFLIGHTRED, TITRAQ_DEFLIGHTRED); 1.180 + nGreen = m_pTiprefs->getNumber(TITRAQ_PREFLIGHTGREEN, TITRAQ_DEFLIGHTGREEN); 1.181 + nBlue = m_pTiprefs->getNumber(TITRAQ_PREFLIGHTBLUE, TITRAQ_DEFLIGHTBLUE); 1.182 + QColor Bright = QColor(nRed, nGreen, nBlue); 1.183 + nRed = m_pTiprefs->getNumber(TITRAQ_PREFDARKRED, TITRAQ_DEFDARKRED); 1.184 + nGreen = m_pTiprefs->getNumber(TITRAQ_PREFDARKGREEN, TITRAQ_DEFDARKGREEN); 1.185 + nBlue = m_pTiprefs->getNumber(TITRAQ_PREFDARKBLUE, TITRAQ_DEFDARKBLUE); 1.186 + QColor Dark = QColor(nRed, nGreen, nBlue); 1.187 + 1.188 + // Alternate color for nonmatching sort keys 1.189 + QString Cur = this->text(nRow, this->getSortcol()); 1.190 + QString Las = this->text(nRow - 1, this->getSortcol()); 1.191 + 1.192 + // A nice cascade of conditions providing a linewise base color test and set 1.193 + // The algorythm: 1.194 + // 1 Determine if the current row's index key differs from the former one 1.195 + // 2a If they are the same, then current row should have the same color 1.196 + // 2b If they are different, then current row should have an alt color 1.197 + // 3 Store information about which color we chose for the current row 1.198 + if (!Cur.isNull() && !Las.isNull() && Cur == Las) { // Set the base color conditionally 1.199 + if (this->text(nRow - 1, TITRAQ_IDXSTATUS).at(TITRAQ_IDXSTATCOLOR) == QChar(TITRAQ_BRIGHT)) { 1.200 + Cgroup.setColor(QColorGroup::Base, Bright); // Bright 1.201 + if (this->text(nRow, TITRAQ_IDXSTATUS).at(TITRAQ_IDXSTATCOLOR) != QChar(TITRAQ_BRIGHT)) 1.202 + this->setText(nRow, TITRAQ_IDXSTATUS, this->text(nRow, TITRAQ_IDXSTATUS).replace(TITRAQ_IDXSTATCOLOR, sizeof(char), QChar(TITRAQ_BRIGHT))); 1.203 + } 1.204 + else { 1.205 + Cgroup.setColor(QColorGroup::Base, Dark); // Dark 1.206 + if (this->text(nRow, TITRAQ_IDXSTATUS).at(TITRAQ_IDXSTATCOLOR) != QChar(TITRAQ_DARK)) 1.207 + this->setText(nRow, TITRAQ_IDXSTATUS, this->text(nRow, TITRAQ_IDXSTATUS).replace(TITRAQ_IDXSTATCOLOR, sizeof(char), QChar(TITRAQ_DARK))); 1.208 + } 1.209 + } 1.210 + else { 1.211 + if (this->text(nRow - 1, TITRAQ_IDXSTATUS).at(TITRAQ_IDXSTATCOLOR) == QChar(TITRAQ_BRIGHT)) { 1.212 + Cgroup.setColor(QColorGroup::Base, Dark); // Dark 1.213 + if (this->text(nRow, TITRAQ_IDXSTATUS).at(TITRAQ_IDXSTATCOLOR) != QChar(TITRAQ_DARK)) 1.214 + this->setText(nRow, TITRAQ_IDXSTATUS, this->text(nRow, TITRAQ_IDXSTATUS).replace(TITRAQ_IDXSTATCOLOR, sizeof(char), QChar(TITRAQ_DARK))); 1.215 + } 1.216 + else { 1.217 + Cgroup.setColor(QColorGroup::Base, Bright); // Bright 1.218 + if (this->text(nRow, TITRAQ_IDXSTATUS).at(TITRAQ_IDXSTATCOLOR) != QChar(TITRAQ_BRIGHT)) 1.219 + this->setText(nRow, TITRAQ_IDXSTATUS, this->text(nRow, TITRAQ_IDXSTATUS).replace(TITRAQ_IDXSTATCOLOR, sizeof(char), QChar(TITRAQ_BRIGHT))); 1.220 + } 1.221 + } 1.222 + 1.223 + QTable::paintCell(pPainter, nRow, nCol, Recto, bSelect, Cgroup); 1.224 +}; 1.225 + 1.226 +// Blah 1.227 +void TiTable::activateNextCell(void) 1.228 +{ 1.229 + int nIter = 1; // Logic to skip invisible or read only columns 1.230 + while (columnWidth((currentColumn() + nIter) % TITRAQ_IDXTAIL) <= 0 1.231 + || isColumnReadOnly((currentColumn() + nIter) % TITRAQ_IDXTAIL)) 1.232 + nIter++; 1.233 + 1.234 + // Advance the column or both row and column possibly 1.235 + int nColadvance = ((currentColumn() + nIter) % TITRAQ_IDXTAIL); 1.236 + if ((currentColumn() + nIter) >= TITRAQ_IDXTAIL) 1.237 + this->setCurrentCell(currentRow() + 1, nColadvance); 1.238 + else 1.239 + this->setCurrentCell(currentRow(), nColadvance); 1.240 + this->setReadOnly(false); 1.241 + this->editCell(currentRow(), currentColumn()); 1.242 + this->setEdition(currentColumn()); 1.243 +} 1.244 + 1.245 +// Overriden member to properly handle read only attribute after edition 1.246 +void TiTable::endEdit(int nRow, int nCol, bool bAccept, bool bReplace) 1.247 +{ 1.248 + QTable::endEdit(nRow, nCol, bAccept, bReplace); 1.249 + 1.250 + // Table read only attribute must be set to return to the normal 1.251 + // row highlight and selection behaviour of AS. The reason it was 1.252 + // reset in inplaceEdit() was to allow editing in the first place. 1.253 + this->setReadOnly(true); 1.254 +}