as_table.cpp

Wed, 07 Jan 2009 18:49:25 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 07 Jan 2009 18:49:25 +0100
changeset 12
ceb4ba3d2d00
parent 3
c1941114ca88
child 15
0e0eb7c91312
permissions
-rw-r--r--

Bump copyright year number.

michael@1 1 //
michael@1 2 // OSSP asgui - Accounting system graphical user interface
michael@12 3 // Copyright (c) 2002-2009 The OSSP Project (http://www.ossp.org/)
michael@12 4 // Copyright (c) 2002-2009 Ralf S. Engelschall <rse@engelschall.com>
michael@12 5 // Copyright (c) 2002-2009 Michael Schloh von Bennewitz <michael@schloh.com>
michael@12 6 // Copyright (c) 2002-2009 Cable & Wireless Telecommunications Services GmbH
michael@1 7 //
michael@1 8 // This file is part of OSSP asgui, an accounting system graphical user
michael@3 9 // interface which can be found at http://asgui.europalab.com/.
michael@1 10 //
michael@1 11 // Permission to use, copy, modify, and distribute this software for
michael@1 12 // any purpose with or without fee is hereby granted, provided that
michael@1 13 // the above copyright notice and this permission notice appear in all
michael@1 14 // copies.
michael@1 15 //
michael@1 16 // THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
michael@1 17 // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
michael@1 18 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
michael@1 19 // IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
michael@1 20 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
michael@1 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
michael@1 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
michael@1 23 // USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
michael@1 24 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
michael@1 25 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
michael@1 26 // OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
michael@1 27 // SUCH DAMAGE.
michael@1 28 //
michael@1 29 // as_table.cpp: ISO C++ implementation
michael@1 30 //
michael@1 31
michael@3 32 #define QT3_SUPPORT
michael@3 33
michael@3 34 #include <q3header.h>
michael@3 35
michael@3 36 //Added by qt3to4:
michael@3 37 #include <QEvent>
michael@3 38 #include <QMouseEvent>
michael@3 39 #include <QKeyEvent>
michael@1 40
michael@1 41 #include "as_const.h"
michael@1 42 #include "as_table.h"
michael@1 43
michael@1 44
michael@1 45 // Implements an event filter for catching header double click events
michael@1 46 bool TiTable::eventFilter(QObject *pObject, QEvent *pEvent)
michael@1 47 {
michael@1 48 if (pObject == horizontalHeader() && pEvent->type() == QEvent::MouseButtonDblClick)
michael@1 49 return true;
michael@1 50 if (pEvent->type() == QEvent::MouseButtonPress && // Ignore mid, right clicks
michael@3 51 ((QMouseEvent *)pEvent)->button() == Qt::RightButton ||
michael@3 52 ((QMouseEvent *)pEvent)->button() == Qt::MidButton)
michael@1 53 return true;
michael@1 54 else if (pEvent->type() == QEvent::KeyPress) {
michael@1 55 if (((QKeyEvent *)pEvent)->key() == Qt::Key_Tab) { // Handle tab key
michael@1 56 if (this->getEdition() >= 0) {
michael@1 57 int nIter = 1; // Logic to skip invisible or read only columns
michael@1 58 while (columnWidth((currentColumn() + nIter) % TITRAQ_IDXTAIL) <= 0
michael@1 59 || isColumnReadOnly((currentColumn() + nIter) % TITRAQ_IDXTAIL))
michael@1 60 nIter++;
michael@1 61
michael@1 62 // Advance the column or both row and column possibly
michael@1 63 int nColadvance = ((currentColumn() + nIter) % TITRAQ_IDXTAIL);
michael@1 64 if ((currentColumn() + nIter) >= TITRAQ_IDXTAIL) {
michael@1 65 this->clearSelection(true);
michael@1 66 this->setCurrentCell(currentRow() + 1, nColadvance);
michael@1 67 // this->repaint(false); // Really necessary?
michael@1 68 }
michael@1 69 else
michael@1 70 this->setCurrentCell(currentRow(), nColadvance);
michael@1 71 this->setReadOnly(false);
michael@1 72 this->editCell(currentRow(), currentColumn());
michael@1 73 this->setEdition(currentColumn());
michael@1 74 }
michael@1 75 return true; // Handle the tab key event and cancel its progress
michael@1 76 }
michael@1 77 else if (((QKeyEvent *)pEvent)->key() == Qt::Key_Backtab) { // Handle shift tab key
michael@1 78 if (this->getEdition() >= 0) {
michael@1 79 int nIter = 1; // Logic to skip invisible or read only columns
michael@1 80 while (columnWidth((currentColumn() - nIter + TITRAQ_IDXTAIL) % TITRAQ_IDXTAIL) <= 0
michael@1 81 || isColumnReadOnly((currentColumn() - nIter + TITRAQ_IDXTAIL) % TITRAQ_IDXTAIL))
michael@1 82 nIter++;
michael@1 83
michael@1 84 // Advance the column or both row and column possibly
michael@1 85 int nColadvance = (currentColumn() - nIter + TITRAQ_IDXTAIL) % TITRAQ_IDXTAIL;
michael@1 86 if ((currentColumn() - nIter) < 0) {
michael@1 87 this->clearSelection(true);
michael@1 88 this->setCurrentCell(currentRow() - 1, nColadvance);
michael@1 89 // this->repaint(false); // Really necessary?
michael@1 90 }
michael@1 91 else
michael@1 92 this->setCurrentCell(currentRow(), nColadvance);
michael@1 93 this->setReadOnly(false);
michael@1 94 this->editCell(currentRow(), currentColumn());
michael@1 95 this->setEdition(currentColumn());
michael@1 96 }
michael@1 97 return true; // Handle the shift tab key event and cancel its progress
michael@1 98 }
michael@1 99 else if (((QKeyEvent *)pEvent)->key() == Qt::Key_Return && this->getEdition() >= 0) { // Return key
michael@1 100 this->endEdit(currEditRow(), currEditCol(), true, false);
michael@1 101 this->setEdition(); // Reset edition
michael@1 102 return true; // Cancel progress
michael@1 103 }
michael@1 104 else if (((QKeyEvent *)pEvent)->key() == Qt::Key_Enter && this->getEdition() >= 0) { // Enter key
michael@1 105 this->endEdit(currEditRow(), currEditCol(), true, false);
michael@1 106 this->setEdition(); // Reset edition
michael@1 107 return true; // Cancel progress
michael@1 108 }
michael@1 109 else if (((QKeyEvent *)pEvent)->key() == Qt::Key_Return) { // Return key without edition
michael@1 110 this->setReadOnly(false); // Allow edition
michael@1 111 this->editCell(currentRow(), currentColumn()); // Begin edition
michael@1 112 this->setEdition(currentColumn()); // Store edition state
michael@1 113 return true; // Cancel further progress
michael@1 114 }
michael@1 115 else if (((QKeyEvent *)pEvent)->key() == Qt::Key_Enter) { // Enter key without edition
michael@1 116 this->setReadOnly(false); // Allow edition
michael@1 117 this->editCell(currentRow(), currentColumn()); // Begin edition
michael@1 118 this->setEdition(currentColumn()); // Store edition state
michael@1 119 return true; // Cancel further progress
michael@1 120 }
michael@1 121 else if (((QKeyEvent *)pEvent)->key() == Qt::Key_Escape) // Handle escape key
michael@1 122 this->setEdition();
michael@1 123 else if (((QKeyEvent *)pEvent)->key() == Qt::Key_Up && this->getEdition() >= 0) // Handle up key
michael@1 124 return true; // Capture
michael@1 125 else if (((QKeyEvent *)pEvent)->key() == Qt::Key_Down && this->getEdition() >= 0) // Handle down key
michael@1 126 return true; // Capture
michael@1 127
michael@1 128 // Forward incompletely handled key events
michael@3 129 return Q3Table::eventFilter(pObject, pEvent);
michael@1 130 }
michael@1 131 else // Default behaviour is to pass the event onwards
michael@3 132 return Q3Table::eventFilter(pObject, pEvent);
michael@1 133 }
michael@1 134
michael@1 135 // Overridden member hack to allow externally connected control
michael@1 136 // widgets to influence dirty or clean state of table data
michael@1 137 void TiTable::setText(int nRow, int nCol, const QString &nText)
michael@1 138 {
michael@1 139 if (this->numRows() > 0) {
michael@1 140 // If a cell was edited, emit a signal indicating so
michael@1 141 // We can't rely on valueChanged for unknown reasons
michael@1 142 if (nText != this->text(nRow, nCol) && nCol != TITRAQ_IDXLINE)
michael@1 143 emit textEdited(nRow, nCol);
michael@1 144
michael@3 145 Q3Table::setText(nRow, nCol, nText);
michael@1 146 }
michael@1 147 }
michael@1 148
michael@1 149 // Overridden member hack to allow externally connected control
michael@1 150 // widgets to influence dirty or clean state of table data
michael@1 151 void TiTable::sortColumn(int nCol, bool bAscend, bool bWhole)
michael@1 152 {
michael@1 153 // Guard against a repeat sort behaviour
michael@1 154 if (nCol == this->getSortcol() && bAscend == this->getSortdir())
michael@1 155 this->setSortdir(!bAscend);
michael@1 156 else
michael@1 157 this->setSortdir(bAscend);
michael@1 158
michael@1 159 this->setSortcol(nCol);
michael@3 160 Q3Table::sortColumn(nCol, this->getSortdir(), true);
michael@1 161
michael@1 162 // // Announce sorting policy with multiple selections
michael@1 163 // QTableSelection Testsel = this->selection(this->currentSelection());
michael@1 164 // if (Testsel.topRow() != Testsel.bottomRow())
michael@1 165 // m_pStatbar->message(trUtf8("Multiple selections dropped when sorting"), 4000);
michael@1 166
michael@1 167 // Move and display the selection highlight
michael@1 168 this->removeSelection(this->currentSelection());
michael@1 169 this->selectRow(this->currentRow());
michael@1 170 this->ensureCellVisible(this->currentRow(), 0);
michael@1 171
michael@1 172 // Write nonsaving line numbers for all rows
michael@1 173 for (int nIter = this->numRows() - 1; nIter >= 0; nIter--)
michael@1 174 this->setText(nIter, TITRAQ_IDXLINE, QString::number(nIter).rightJustify(4, QChar('0')));
michael@1 175 }
michael@1 176
michael@1 177 // Overriden member to render edge rows differently according to a sort key
michael@1 178 void TiTable::paintCell(QPainter *pPainter, int nRow, int nCol, const QRect &Recto, bool bSelect, const QColorGroup &Colgroup)
michael@1 179 {
michael@1 180 QColorGroup Cgroup(Colgroup);
michael@1 181 int nRed, nGreen, nBlue;
michael@1 182
michael@1 183 nRed = m_pTiprefs->getNumber(TITRAQ_PREFLIGHTRED, TITRAQ_DEFLIGHTRED);
michael@1 184 nGreen = m_pTiprefs->getNumber(TITRAQ_PREFLIGHTGREEN, TITRAQ_DEFLIGHTGREEN);
michael@1 185 nBlue = m_pTiprefs->getNumber(TITRAQ_PREFLIGHTBLUE, TITRAQ_DEFLIGHTBLUE);
michael@1 186 QColor Bright = QColor(nRed, nGreen, nBlue);
michael@1 187 nRed = m_pTiprefs->getNumber(TITRAQ_PREFDARKRED, TITRAQ_DEFDARKRED);
michael@1 188 nGreen = m_pTiprefs->getNumber(TITRAQ_PREFDARKGREEN, TITRAQ_DEFDARKGREEN);
michael@1 189 nBlue = m_pTiprefs->getNumber(TITRAQ_PREFDARKBLUE, TITRAQ_DEFDARKBLUE);
michael@1 190 QColor Dark = QColor(nRed, nGreen, nBlue);
michael@1 191
michael@1 192 // Alternate color for nonmatching sort keys
michael@1 193 QString Cur = this->text(nRow, this->getSortcol());
michael@1 194 QString Las = this->text(nRow - 1, this->getSortcol());
michael@1 195
michael@1 196 // A nice cascade of conditions providing a linewise base color test and set
michael@1 197 // The algorythm:
michael@1 198 // 1 Determine if the current row's index key differs from the former one
michael@1 199 // 2a If they are the same, then current row should have the same color
michael@1 200 // 2b If they are different, then current row should have an alt color
michael@1 201 // 3 Store information about which color we chose for the current row
michael@1 202 if (!Cur.isNull() && !Las.isNull() && Cur == Las) { // Set the base color conditionally
michael@1 203 if (this->text(nRow - 1, TITRAQ_IDXSTATUS).at(TITRAQ_IDXSTATCOLOR) == QChar(TITRAQ_BRIGHT)) {
michael@1 204 Cgroup.setColor(QColorGroup::Base, Bright); // Bright
michael@1 205 if (this->text(nRow, TITRAQ_IDXSTATUS).at(TITRAQ_IDXSTATCOLOR) != QChar(TITRAQ_BRIGHT))
michael@1 206 this->setText(nRow, TITRAQ_IDXSTATUS, this->text(nRow, TITRAQ_IDXSTATUS).replace(TITRAQ_IDXSTATCOLOR, sizeof(char), QChar(TITRAQ_BRIGHT)));
michael@1 207 }
michael@1 208 else {
michael@1 209 Cgroup.setColor(QColorGroup::Base, Dark); // Dark
michael@1 210 if (this->text(nRow, TITRAQ_IDXSTATUS).at(TITRAQ_IDXSTATCOLOR) != QChar(TITRAQ_DARK))
michael@1 211 this->setText(nRow, TITRAQ_IDXSTATUS, this->text(nRow, TITRAQ_IDXSTATUS).replace(TITRAQ_IDXSTATCOLOR, sizeof(char), QChar(TITRAQ_DARK)));
michael@1 212 }
michael@1 213 }
michael@1 214 else {
michael@1 215 if (this->text(nRow - 1, TITRAQ_IDXSTATUS).at(TITRAQ_IDXSTATCOLOR) == QChar(TITRAQ_BRIGHT)) {
michael@1 216 Cgroup.setColor(QColorGroup::Base, Dark); // Dark
michael@1 217 if (this->text(nRow, TITRAQ_IDXSTATUS).at(TITRAQ_IDXSTATCOLOR) != QChar(TITRAQ_DARK))
michael@1 218 this->setText(nRow, TITRAQ_IDXSTATUS, this->text(nRow, TITRAQ_IDXSTATUS).replace(TITRAQ_IDXSTATCOLOR, sizeof(char), QChar(TITRAQ_DARK)));
michael@1 219 }
michael@1 220 else {
michael@1 221 Cgroup.setColor(QColorGroup::Base, Bright); // Bright
michael@1 222 if (this->text(nRow, TITRAQ_IDXSTATUS).at(TITRAQ_IDXSTATCOLOR) != QChar(TITRAQ_BRIGHT))
michael@1 223 this->setText(nRow, TITRAQ_IDXSTATUS, this->text(nRow, TITRAQ_IDXSTATUS).replace(TITRAQ_IDXSTATCOLOR, sizeof(char), QChar(TITRAQ_BRIGHT)));
michael@1 224 }
michael@1 225 }
michael@1 226
michael@3 227 Q3Table::paintCell(pPainter, nRow, nCol, Recto, bSelect, Cgroup);
michael@1 228 };
michael@1 229
michael@1 230 // Blah
michael@1 231 void TiTable::activateNextCell(void)
michael@1 232 {
michael@1 233 int nIter = 1; // Logic to skip invisible or read only columns
michael@1 234 while (columnWidth((currentColumn() + nIter) % TITRAQ_IDXTAIL) <= 0
michael@1 235 || isColumnReadOnly((currentColumn() + nIter) % TITRAQ_IDXTAIL))
michael@1 236 nIter++;
michael@1 237
michael@1 238 // Advance the column or both row and column possibly
michael@1 239 int nColadvance = ((currentColumn() + nIter) % TITRAQ_IDXTAIL);
michael@1 240 if ((currentColumn() + nIter) >= TITRAQ_IDXTAIL)
michael@1 241 this->setCurrentCell(currentRow() + 1, nColadvance);
michael@1 242 else
michael@1 243 this->setCurrentCell(currentRow(), nColadvance);
michael@1 244 this->setReadOnly(false);
michael@1 245 this->editCell(currentRow(), currentColumn());
michael@1 246 this->setEdition(currentColumn());
michael@1 247 }
michael@1 248
michael@1 249 // Overriden member to properly handle read only attribute after edition
michael@1 250 void TiTable::endEdit(int nRow, int nCol, bool bAccept, bool bReplace)
michael@1 251 {
michael@3 252 Q3Table::endEdit(nRow, nCol, bAccept, bReplace);
michael@1 253
michael@1 254 // Table read only attribute must be set to return to the normal
michael@1 255 // row highlight and selection behaviour of AS. The reason it was
michael@1 256 // reset in inplaceEdit() was to allow editing in the first place.
michael@1 257 this->setReadOnly(true);
michael@1 258 }

mercurial