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