Fri, 28 Nov 2008 14:20:00 +0100
Added tag ASGUI_0.7.7 for changeset d64aaa7d146f
1 //
2 // OSSP asgui - Accounting system graphical user interface
3 // Copyright (c) 2002-2004 The OSSP Project (http://www.ossp.org/)
4 // Copyright (c) 2002-2004 Ralf S. Engelschall <rse@engelschall.com>
5 // Copyright (c) 2002-2004 Michael Schloh von Bennewitz <michael@schloh.com>
6 // Copyright (c) 2002-2004 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://www.ossp.org/pkg/tool/asgui/.
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 #include <qheader.h>
34 #include "as_const.h"
35 #include "as_table.h"
38 // Implements an event filter for catching header double click events
39 bool TiTable::eventFilter(QObject *pObject, QEvent *pEvent)
40 {
41 if (pObject == horizontalHeader() && pEvent->type() == QEvent::MouseButtonDblClick)
42 return true;
43 if (pEvent->type() == QEvent::MouseButtonPress && // Ignore mid, right clicks
44 ((QMouseEvent *)pEvent)->button() == QMouseEvent::RightButton ||
45 ((QMouseEvent *)pEvent)->button() == QMouseEvent::MidButton)
46 return true;
47 else if (pEvent->type() == QEvent::KeyPress) {
48 if (((QKeyEvent *)pEvent)->key() == Qt::Key_Tab) { // Handle tab key
49 if (this->getEdition() >= 0) {
50 int nIter = 1; // Logic to skip invisible or read only columns
51 while (columnWidth((currentColumn() + nIter) % TITRAQ_IDXTAIL) <= 0
52 || isColumnReadOnly((currentColumn() + nIter) % TITRAQ_IDXTAIL))
53 nIter++;
55 // Advance the column or both row and column possibly
56 int nColadvance = ((currentColumn() + nIter) % TITRAQ_IDXTAIL);
57 if ((currentColumn() + nIter) >= TITRAQ_IDXTAIL) {
58 this->clearSelection(true);
59 this->setCurrentCell(currentRow() + 1, nColadvance);
60 // this->repaint(false); // Really necessary?
61 }
62 else
63 this->setCurrentCell(currentRow(), nColadvance);
64 this->setReadOnly(false);
65 this->editCell(currentRow(), currentColumn());
66 this->setEdition(currentColumn());
67 }
68 return true; // Handle the tab key event and cancel its progress
69 }
70 else if (((QKeyEvent *)pEvent)->key() == Qt::Key_Backtab) { // Handle shift tab key
71 if (this->getEdition() >= 0) {
72 int nIter = 1; // Logic to skip invisible or read only columns
73 while (columnWidth((currentColumn() - nIter + TITRAQ_IDXTAIL) % TITRAQ_IDXTAIL) <= 0
74 || isColumnReadOnly((currentColumn() - nIter + TITRAQ_IDXTAIL) % TITRAQ_IDXTAIL))
75 nIter++;
77 // Advance the column or both row and column possibly
78 int nColadvance = (currentColumn() - nIter + TITRAQ_IDXTAIL) % TITRAQ_IDXTAIL;
79 if ((currentColumn() - nIter) < 0) {
80 this->clearSelection(true);
81 this->setCurrentCell(currentRow() - 1, nColadvance);
82 // this->repaint(false); // Really necessary?
83 }
84 else
85 this->setCurrentCell(currentRow(), nColadvance);
86 this->setReadOnly(false);
87 this->editCell(currentRow(), currentColumn());
88 this->setEdition(currentColumn());
89 }
90 return true; // Handle the shift tab key event and cancel its progress
91 }
92 else if (((QKeyEvent *)pEvent)->key() == Qt::Key_Return && this->getEdition() >= 0) { // Return key
93 this->endEdit(currEditRow(), currEditCol(), true, false);
94 this->setEdition(); // Reset edition
95 return true; // Cancel progress
96 }
97 else if (((QKeyEvent *)pEvent)->key() == Qt::Key_Enter && this->getEdition() >= 0) { // Enter key
98 this->endEdit(currEditRow(), currEditCol(), true, false);
99 this->setEdition(); // Reset edition
100 return true; // Cancel progress
101 }
102 else if (((QKeyEvent *)pEvent)->key() == Qt::Key_Return) { // Return key without edition
103 this->setReadOnly(false); // Allow edition
104 this->editCell(currentRow(), currentColumn()); // Begin edition
105 this->setEdition(currentColumn()); // Store edition state
106 return true; // Cancel further progress
107 }
108 else if (((QKeyEvent *)pEvent)->key() == Qt::Key_Enter) { // Enter key without edition
109 this->setReadOnly(false); // Allow edition
110 this->editCell(currentRow(), currentColumn()); // Begin edition
111 this->setEdition(currentColumn()); // Store edition state
112 return true; // Cancel further progress
113 }
114 else if (((QKeyEvent *)pEvent)->key() == Qt::Key_Escape) // Handle escape key
115 this->setEdition();
116 else if (((QKeyEvent *)pEvent)->key() == Qt::Key_Up && this->getEdition() >= 0) // Handle up key
117 return true; // Capture
118 else if (((QKeyEvent *)pEvent)->key() == Qt::Key_Down && this->getEdition() >= 0) // Handle down key
119 return true; // Capture
121 // Forward incompletely handled key events
122 return QTable::eventFilter(pObject, pEvent);
123 }
124 else // Default behaviour is to pass the event onwards
125 return QTable::eventFilter(pObject, pEvent);
126 }
128 // Overridden member hack to allow externally connected control
129 // widgets to influence dirty or clean state of table data
130 void TiTable::setText(int nRow, int nCol, const QString &nText)
131 {
132 if (this->numRows() > 0) {
133 // If a cell was edited, emit a signal indicating so
134 // We can't rely on valueChanged for unknown reasons
135 if (nText != this->text(nRow, nCol) && nCol != TITRAQ_IDXLINE)
136 emit textEdited(nRow, nCol);
138 QTable::setText(nRow, nCol, nText);
139 }
140 }
142 // Overridden member hack to allow externally connected control
143 // widgets to influence dirty or clean state of table data
144 void TiTable::sortColumn(int nCol, bool bAscend, bool bWhole)
145 {
146 // Guard against a repeat sort behaviour
147 if (nCol == this->getSortcol() && bAscend == this->getSortdir())
148 this->setSortdir(!bAscend);
149 else
150 this->setSortdir(bAscend);
152 this->setSortcol(nCol);
153 QTable::sortColumn(nCol, this->getSortdir(), true);
155 // // Announce sorting policy with multiple selections
156 // QTableSelection Testsel = this->selection(this->currentSelection());
157 // if (Testsel.topRow() != Testsel.bottomRow())
158 // m_pStatbar->message(trUtf8("Multiple selections dropped when sorting"), 4000);
160 // Move and display the selection highlight
161 this->removeSelection(this->currentSelection());
162 this->selectRow(this->currentRow());
163 this->ensureCellVisible(this->currentRow(), 0);
165 // Write nonsaving line numbers for all rows
166 for (int nIter = this->numRows() - 1; nIter >= 0; nIter--)
167 this->setText(nIter, TITRAQ_IDXLINE, QString::number(nIter).rightJustify(4, QChar('0')));
168 }
170 // Overriden member to render edge rows differently according to a sort key
171 void TiTable::paintCell(QPainter *pPainter, int nRow, int nCol, const QRect &Recto, bool bSelect, const QColorGroup &Colgroup)
172 {
173 QColorGroup Cgroup(Colgroup);
174 int nRed, nGreen, nBlue;
176 nRed = m_pTiprefs->getNumber(TITRAQ_PREFLIGHTRED, TITRAQ_DEFLIGHTRED);
177 nGreen = m_pTiprefs->getNumber(TITRAQ_PREFLIGHTGREEN, TITRAQ_DEFLIGHTGREEN);
178 nBlue = m_pTiprefs->getNumber(TITRAQ_PREFLIGHTBLUE, TITRAQ_DEFLIGHTBLUE);
179 QColor Bright = QColor(nRed, nGreen, nBlue);
180 nRed = m_pTiprefs->getNumber(TITRAQ_PREFDARKRED, TITRAQ_DEFDARKRED);
181 nGreen = m_pTiprefs->getNumber(TITRAQ_PREFDARKGREEN, TITRAQ_DEFDARKGREEN);
182 nBlue = m_pTiprefs->getNumber(TITRAQ_PREFDARKBLUE, TITRAQ_DEFDARKBLUE);
183 QColor Dark = QColor(nRed, nGreen, nBlue);
185 // Alternate color for nonmatching sort keys
186 QString Cur = this->text(nRow, this->getSortcol());
187 QString Las = this->text(nRow - 1, this->getSortcol());
189 // A nice cascade of conditions providing a linewise base color test and set
190 // The algorythm:
191 // 1 Determine if the current row's index key differs from the former one
192 // 2a If they are the same, then current row should have the same color
193 // 2b If they are different, then current row should have an alt color
194 // 3 Store information about which color we chose for the current row
195 if (!Cur.isNull() && !Las.isNull() && Cur == Las) { // Set the base color conditionally
196 if (this->text(nRow - 1, TITRAQ_IDXSTATUS).at(TITRAQ_IDXSTATCOLOR) == QChar(TITRAQ_BRIGHT)) {
197 Cgroup.setColor(QColorGroup::Base, Bright); // Bright
198 if (this->text(nRow, TITRAQ_IDXSTATUS).at(TITRAQ_IDXSTATCOLOR) != QChar(TITRAQ_BRIGHT))
199 this->setText(nRow, TITRAQ_IDXSTATUS, this->text(nRow, TITRAQ_IDXSTATUS).replace(TITRAQ_IDXSTATCOLOR, sizeof(char), QChar(TITRAQ_BRIGHT)));
200 }
201 else {
202 Cgroup.setColor(QColorGroup::Base, Dark); // Dark
203 if (this->text(nRow, TITRAQ_IDXSTATUS).at(TITRAQ_IDXSTATCOLOR) != QChar(TITRAQ_DARK))
204 this->setText(nRow, TITRAQ_IDXSTATUS, this->text(nRow, TITRAQ_IDXSTATUS).replace(TITRAQ_IDXSTATCOLOR, sizeof(char), QChar(TITRAQ_DARK)));
205 }
206 }
207 else {
208 if (this->text(nRow - 1, TITRAQ_IDXSTATUS).at(TITRAQ_IDXSTATCOLOR) == QChar(TITRAQ_BRIGHT)) {
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 else {
214 Cgroup.setColor(QColorGroup::Base, Bright); // Bright
215 if (this->text(nRow, TITRAQ_IDXSTATUS).at(TITRAQ_IDXSTATCOLOR) != QChar(TITRAQ_BRIGHT))
216 this->setText(nRow, TITRAQ_IDXSTATUS, this->text(nRow, TITRAQ_IDXSTATUS).replace(TITRAQ_IDXSTATCOLOR, sizeof(char), QChar(TITRAQ_BRIGHT)));
217 }
218 }
220 QTable::paintCell(pPainter, nRow, nCol, Recto, bSelect, Cgroup);
221 };
223 // Blah
224 void TiTable::activateNextCell(void)
225 {
226 int nIter = 1; // Logic to skip invisible or read only columns
227 while (columnWidth((currentColumn() + nIter) % TITRAQ_IDXTAIL) <= 0
228 || isColumnReadOnly((currentColumn() + nIter) % TITRAQ_IDXTAIL))
229 nIter++;
231 // Advance the column or both row and column possibly
232 int nColadvance = ((currentColumn() + nIter) % TITRAQ_IDXTAIL);
233 if ((currentColumn() + nIter) >= TITRAQ_IDXTAIL)
234 this->setCurrentCell(currentRow() + 1, nColadvance);
235 else
236 this->setCurrentCell(currentRow(), nColadvance);
237 this->setReadOnly(false);
238 this->editCell(currentRow(), currentColumn());
239 this->setEdition(currentColumn());
240 }
242 // Overriden member to properly handle read only attribute after edition
243 void TiTable::endEdit(int nRow, int nCol, bool bAccept, bool bReplace)
244 {
245 QTable::endEdit(nRow, nCol, bAccept, bReplace);
247 // Table read only attribute must be set to return to the normal
248 // row highlight and selection behaviour of AS. The reason it was
249 // reset in inplaceEdit() was to allow editing in the first place.
250 this->setReadOnly(true);
251 }