author | Eckhart Koeppen <eckhart.koppen@nokia.com> |
Fri, 16 Apr 2010 11:39:52 +0300 | |
branch | RCL_3 |
changeset 8 | 740e5562c97f |
parent 4 | 3b1da2848fc7 |
permissions | -rw-r--r-- |
0 | 1 |
/**************************************************************************** |
2 |
** |
|
4
3b1da2848fc7
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
3 |
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). |
0 | 4 |
** All rights reserved. |
5 |
** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 |
** |
|
7 |
** This file is part of the Qt3Support module of the Qt Toolkit. |
|
8 |
** |
|
9 |
** $QT_BEGIN_LICENSE:LGPL$ |
|
10 |
** No Commercial Usage |
|
11 |
** This file contains pre-release code and may not be distributed. |
|
12 |
** You may use this file in accordance with the terms and conditions |
|
13 |
** contained in the Technology Preview License Agreement accompanying |
|
14 |
** this package. |
|
15 |
** |
|
16 |
** GNU Lesser General Public License Usage |
|
17 |
** Alternatively, this file may be used under the terms of the GNU Lesser |
|
18 |
** General Public License version 2.1 as published by the Free Software |
|
19 |
** Foundation and appearing in the file LICENSE.LGPL included in the |
|
20 |
** packaging of this file. Please review the following information to |
|
21 |
** ensure the GNU Lesser General Public License version 2.1 requirements |
|
22 |
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
23 |
** |
|
24 |
** In addition, as a special exception, Nokia gives you certain additional |
|
25 |
** rights. These rights are described in the Nokia Qt LGPL Exception |
|
26 |
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
27 |
** |
|
28 |
** If you have questions regarding the use of this file, please contact |
|
29 |
** Nokia at qt-info@nokia.com. |
|
30 |
** |
|
31 |
** |
|
32 |
** |
|
33 |
** |
|
34 |
** |
|
35 |
** |
|
36 |
** |
|
37 |
** |
|
38 |
** $QT_END_LICENSE$ |
|
39 |
** |
|
40 |
****************************************************************************/ |
|
41 |
||
42 |
#include "qglobal.h" |
|
43 |
#if defined(Q_CC_BOR) |
|
44 |
// needed for qsort() because of a std namespace problem on Borland |
|
45 |
#include "qplatformdefs.h" |
|
46 |
#endif |
|
47 |
||
48 |
#include "q3table.h" |
|
49 |
||
50 |
||
51 |
#include <qpainter.h> |
|
52 |
#include <qlineedit.h> |
|
53 |
#include <qcursor.h> |
|
54 |
#include <qapplication.h> |
|
55 |
#include <qtimer.h> |
|
56 |
#include <qicon.h> |
|
57 |
#include <q3combobox.h> |
|
58 |
#include <qstyleoption.h> |
|
59 |
#include <qcheckbox.h> |
|
60 |
#include <q3dragobject.h> |
|
61 |
#include <qevent.h> |
|
62 |
#include <q3listbox.h> |
|
63 |
#include <qstyle.h> |
|
64 |
#include <q3datatable.h> |
|
65 |
#include <qvalidator.h> |
|
66 |
#include <q3button.h> |
|
67 |
||
68 |
#include <stdlib.h> |
|
69 |
#include <limits.h> |
|
70 |
||
71 |
QT_BEGIN_NAMESPACE |
|
72 |
||
73 |
using namespace Qt; |
|
74 |
||
75 |
class Q3HeaderData; |
|
76 |
extern bool qt_get_null_label_bit(Q3HeaderData *data, int section); |
|
77 |
extern void qt_set_null_label_bit(Q3HeaderData *data, int section, bool b); |
|
78 |
||
79 |
static bool qt_update_cell_widget = true; |
|
80 |
static bool qt_table_clipper_enabled = true; |
|
81 |
#ifndef QT_INTERNAL_TABLE |
|
82 |
Q_COMPAT_EXPORT |
|
83 |
#endif |
|
84 |
void qt_set_table_clipper_enabled(bool enabled) |
|
85 |
{ |
|
86 |
qt_table_clipper_enabled = enabled; |
|
87 |
} |
|
88 |
||
89 |
class Q_COMPAT_EXPORT Q3TableHeader : public Q3Header |
|
90 |
{ |
|
91 |
friend class Q3Table; |
|
92 |
Q_OBJECT |
|
93 |
||
94 |
public: |
|
95 |
enum SectionState { |
|
96 |
Normal, |
|
97 |
Bold, |
|
98 |
Selected |
|
99 |
}; |
|
100 |
||
101 |
Q3TableHeader(int, Q3Table *t, QWidget* parent=0, const char* name=0); |
|
102 |
~Q3TableHeader() {}; |
|
103 |
void addLabel(const QString &s, int size); |
|
104 |
void setLabel(int section, const QString & s, int size = -1); |
|
105 |
void setLabel(int section, const QIconSet & iconset, const QString & s, |
|
106 |
int size = -1); |
|
107 |
||
108 |
void setLabels(const QStringList & labels); |
|
109 |
||
110 |
void removeLabel(int section); |
|
111 |
||
112 |
void setSectionState(int s, SectionState state); |
|
113 |
void setSectionStateToAll(SectionState state); |
|
114 |
SectionState sectionState(int s) const; |
|
115 |
||
116 |
int sectionSize(int section) const; |
|
117 |
int sectionPos(int section) const; |
|
118 |
int sectionAt(int section) const; |
|
119 |
||
120 |
void setSectionStretchable(int s, bool b); |
|
121 |
bool isSectionStretchable(int s) const; |
|
122 |
||
123 |
void updateCache(); |
|
124 |
||
125 |
signals: |
|
126 |
void sectionSizeChanged(int s); |
|
127 |
||
128 |
protected: |
|
129 |
void paintEvent(QPaintEvent *e); |
|
130 |
void paintSection(QPainter *p, int index, const QRect& fr); |
|
131 |
void mousePressEvent(QMouseEvent *e); |
|
132 |
void mouseMoveEvent(QMouseEvent *e); |
|
133 |
void mouseReleaseEvent(QMouseEvent *e); |
|
134 |
void mouseDoubleClickEvent(QMouseEvent *e); |
|
135 |
void resizeEvent(QResizeEvent *e); |
|
136 |
||
137 |
private slots: |
|
138 |
void doAutoScroll(); |
|
139 |
void sectionWidthChanged(int col, int os, int ns); |
|
140 |
void indexChanged(int sec, int oldIdx, int newIdx); |
|
141 |
void updateStretches(); |
|
142 |
void updateWidgetStretches(); |
|
143 |
||
144 |
private: |
|
145 |
void updateSelections(); |
|
146 |
void saveStates(); |
|
147 |
void setCaching(bool b); |
|
148 |
void swapSections(int oldIdx, int newIdx, bool swapTable = true); |
|
149 |
bool doSelection(QMouseEvent *e); |
|
150 |
void sectionLabelChanged(int section); |
|
151 |
void resizeArrays(int n); |
|
152 |
||
153 |
private: |
|
154 |
Q3MemArray<int> states, oldStates; |
|
155 |
Q3MemArray<bool> stretchable; |
|
156 |
Q3MemArray<int> sectionSizes, sectionPoses; |
|
157 |
bool mousePressed; |
|
158 |
int pressPos, startPos, endPos; |
|
159 |
Q3Table *table; |
|
160 |
QTimer *autoScrollTimer; |
|
161 |
QWidget *line1, *line2; |
|
162 |
bool caching; |
|
163 |
int resizedSection; |
|
164 |
bool isResizing; |
|
165 |
int numStretches; |
|
166 |
QTimer *stretchTimer, *widgetStretchTimer; |
|
167 |
Q3TableHeaderPrivate *d; |
|
168 |
||
169 |
Q_DISABLE_COPY(Q3TableHeader) |
|
170 |
}; |
|
171 |
||
172 |
#ifdef _WS_QWS_ |
|
173 |
# define NO_LINE_WIDGET |
|
174 |
#endif |
|
175 |
||
176 |
||
177 |
||
178 |
struct Q3TablePrivate |
|
179 |
{ |
|
180 |
Q3TablePrivate() : hasRowSpan(false), hasColSpan(false), |
|
181 |
inMenuMode(false), redirectMouseEvent(false) |
|
182 |
{ |
|
183 |
hiddenRows.setAutoDelete(true); |
|
184 |
hiddenCols.setAutoDelete(true); |
|
185 |
} |
|
186 |
uint hasRowSpan : 1; |
|
187 |
uint hasColSpan : 1; |
|
188 |
uint inMenuMode : 1; |
|
189 |
uint redirectMouseEvent : 1; |
|
190 |
Q3IntDict<int> hiddenRows, hiddenCols; |
|
191 |
QTimer *geomTimer; |
|
192 |
int lastVisRow; |
|
193 |
int lastVisCol; |
|
194 |
}; |
|
195 |
||
196 |
struct Q3TableHeaderPrivate |
|
197 |
{ |
|
198 |
#ifdef NO_LINE_WIDGET |
|
199 |
int oldLinePos; |
|
200 |
#endif |
|
201 |
}; |
|
202 |
||
203 |
static bool isRowSelection(Q3Table::SelectionMode selMode) |
|
204 |
{ |
|
205 |
return selMode == Q3Table::SingleRow || selMode == Q3Table::MultiRow; |
|
206 |
} |
|
207 |
||
208 |
/*! |
|
209 |
\class Q3TableSelection |
|
210 |
\brief The Q3TableSelection class provides access to a selected area in a |
|
211 |
Q3Table. |
|
212 |
||
213 |
\compat |
|
214 |
||
215 |
The selection is a rectangular set of cells in a Q3Table. One of |
|
216 |
the rectangle's cells is called the anchor cell; this is the cell |
|
217 |
that was selected first. The init() function sets the anchor and |
|
218 |
the selection rectangle to exactly this cell; the expandTo() |
|
219 |
function expands the selection rectangle to include additional |
|
220 |
cells. |
|
221 |
||
222 |
There are various access functions to find out about the area: |
|
223 |
anchorRow() and anchorCol() return the anchor's position; |
|
224 |
leftCol(), rightCol(), topRow() and bottomRow() return the |
|
225 |
rectangle's four edges. All four are part of the selection. |
|
226 |
||
227 |
A newly created Q3TableSelection is inactive -- isActive() returns |
|
228 |
false. You must use init() and expandTo() to activate it. |
|
229 |
||
230 |
\sa Q3Table Q3Table::addSelection() Q3Table::selection() |
|
231 |
Q3Table::selectCells() Q3Table::selectRow() Q3Table::selectColumn() |
|
232 |
*/ |
|
233 |
||
234 |
/*! |
|
235 |
Creates an inactive selection. Use init() and expandTo() to |
|
236 |
activate it. |
|
237 |
*/ |
|
238 |
||
239 |
Q3TableSelection::Q3TableSelection() |
|
240 |
: active(false), inited(false), tRow(-1), lCol(-1), |
|
241 |
bRow(-1), rCol(-1), aRow(-1), aCol(-1) |
|
242 |
{ |
|
243 |
} |
|
244 |
||
245 |
/*! |
|
246 |
Creates an active selection, starting at \a start_row and \a |
|
247 |
start_col, ending at \a end_row and \a end_col. |
|
248 |
*/ |
|
249 |
||
250 |
Q3TableSelection::Q3TableSelection(int start_row, int start_col, int end_row, int end_col) |
|
251 |
: active(false), inited(false), tRow(-1), lCol(-1), |
|
252 |
bRow(-1), rCol(-1), aRow(-1), aCol(-1) |
|
253 |
{ |
|
254 |
init(start_row, start_col); |
|
255 |
expandTo(end_row, end_col); |
|
256 |
} |
|
257 |
||
258 |
/*! |
|
259 |
Sets the selection anchor to cell \a row, \a col and the selection |
|
260 |
to only contain this cell. The selection is not active until |
|
261 |
expandTo() is called. |
|
262 |
||
263 |
To extend the selection to include additional cells, call |
|
264 |
expandTo(). |
|
265 |
||
266 |
\sa isActive() |
|
267 |
*/ |
|
268 |
||
269 |
void Q3TableSelection::init(int row, int col) |
|
270 |
{ |
|
271 |
aCol = lCol = rCol = col; |
|
272 |
aRow = tRow = bRow = row; |
|
273 |
active = false; |
|
274 |
inited = true; |
|
275 |
} |
|
276 |
||
277 |
/*! |
|
278 |
Expands the selection to include cell \a row, \a col. The new |
|
279 |
selection rectangle is the bounding rectangle of \a row, \a col |
|
280 |
and the previous selection rectangle. After calling this function |
|
281 |
the selection is active. |
|
282 |
||
283 |
If you haven't called init(), this function does nothing. |
|
284 |
||
285 |
\sa init() isActive() |
|
286 |
*/ |
|
287 |
||
288 |
void Q3TableSelection::expandTo(int row, int col) |
|
289 |
{ |
|
290 |
if (!inited) |
|
291 |
return; |
|
292 |
active = true; |
|
293 |
||
294 |
if (row < aRow) { |
|
295 |
tRow = row; |
|
296 |
bRow = aRow; |
|
297 |
} else { |
|
298 |
tRow = aRow; |
|
299 |
bRow = row; |
|
300 |
} |
|
301 |
||
302 |
if (col < aCol) { |
|
303 |
lCol = col; |
|
304 |
rCol = aCol; |
|
305 |
} else { |
|
306 |
lCol = aCol; |
|
307 |
rCol = col; |
|
308 |
} |
|
309 |
} |
|
310 |
||
311 |
/*! |
|
312 |
Returns true if \a s includes the same cells as the selection; |
|
313 |
otherwise returns false. |
|
314 |
*/ |
|
315 |
||
316 |
bool Q3TableSelection::operator==(const Q3TableSelection &s) const |
|
317 |
{ |
|
318 |
return (s.active == active && |
|
319 |
s.tRow == tRow && s.bRow == bRow && |
|
320 |
s.lCol == lCol && s.rCol == rCol); |
|
321 |
} |
|
322 |
||
323 |
/*! |
|
324 |
\fn bool Q3TableSelection::operator!=(const Q3TableSelection &s) const |
|
325 |
||
326 |
Returns true if \a s does not include the same cells as the |
|
327 |
selection; otherwise returns false. |
|
328 |
*/ |
|
329 |
||
330 |
||
331 |
/*! |
|
332 |
\fn int Q3TableSelection::topRow() const |
|
333 |
||
334 |
Returns the top row of the selection. |
|
335 |
||
336 |
\sa bottomRow() leftCol() rightCol() |
|
337 |
*/ |
|
338 |
||
339 |
/*! |
|
340 |
\fn int Q3TableSelection::bottomRow() const |
|
341 |
||
342 |
Returns the bottom row of the selection. |
|
343 |
||
344 |
\sa topRow() leftCol() rightCol() |
|
345 |
*/ |
|
346 |
||
347 |
/*! |
|
348 |
\fn int Q3TableSelection::leftCol() const |
|
349 |
||
350 |
Returns the left column of the selection. |
|
351 |
||
352 |
\sa topRow() bottomRow() rightCol() |
|
353 |
*/ |
|
354 |
||
355 |
/*! |
|
356 |
\fn int Q3TableSelection::rightCol() const |
|
357 |
||
358 |
Returns the right column of the selection. |
|
359 |
||
360 |
\sa topRow() bottomRow() leftCol() |
|
361 |
*/ |
|
362 |
||
363 |
/*! |
|
364 |
\fn int Q3TableSelection::anchorRow() const |
|
365 |
||
366 |
Returns the anchor row of the selection. |
|
367 |
||
368 |
\sa anchorCol() expandTo() |
|
369 |
*/ |
|
370 |
||
371 |
/*! |
|
372 |
\fn int Q3TableSelection::anchorCol() const |
|
373 |
||
374 |
Returns the anchor column of the selection. |
|
375 |
||
376 |
\sa anchorRow() expandTo() |
|
377 |
*/ |
|
378 |
||
379 |
/*! |
|
380 |
\fn int Q3TableSelection::numRows() const |
|
381 |
||
382 |
Returns the number of rows in the selection. |
|
383 |
||
384 |
\sa numCols() |
|
385 |
*/ |
|
386 |
int Q3TableSelection::numRows() const |
|
387 |
{ |
|
388 |
return (tRow < 0) ? 0 : bRow - tRow + 1; |
|
389 |
} |
|
390 |
||
391 |
/*! |
|
392 |
Returns the number of columns in the selection. |
|
393 |
||
394 |
\sa numRows() |
|
395 |
*/ |
|
396 |
int Q3TableSelection::numCols() const |
|
397 |
{ |
|
398 |
return (lCol < 0) ? 0 : rCol - lCol + 1; |
|
399 |
} |
|
400 |
||
401 |
/*! |
|
402 |
\fn bool Q3TableSelection::isActive() const |
|
403 |
||
404 |
Returns whether the selection is active or not. A selection is |
|
405 |
active after init() \e and expandTo() have been called. |
|
406 |
*/ |
|
407 |
||
408 |
/*! |
|
409 |
\fn bool Q3TableSelection::isEmpty() const |
|
410 |
||
411 |
Returns whether the selection is empty or not. |
|
412 |
||
413 |
\sa numRows(), numCols() |
|
414 |
*/ |
|
415 |
||
416 |
/*! |
|
417 |
\class Q3TableItem |
|
418 |
\brief The Q3TableItem class provides the cell content for Q3Table cells. |
|
419 |
||
420 |
\compat |
|
421 |
||
422 |
For many applications Q3TableItems are ideal for presenting and |
|
423 |
editing the contents of Q3Table cells. In situations where you need |
|
424 |
to create very large tables you may prefer an alternative approach |
|
425 |
to using Q3TableItems: see the notes on large tables. |
|
426 |
||
427 |
A Q3TableItem contains a cell's data, by default, a string and a |
|
428 |
pixmap. The table item also holds the cell's display size and how |
|
429 |
the data should be aligned. The table item specifies the cell's |
|
430 |
\l EditType and the editor used for in-place editing (by default a |
|
431 |
QLineEdit). If you want checkboxes use \l{Q3CheckTableItem}, and if |
|
432 |
you want comboboxes use \l{Q3ComboTableItem}. The \l EditType (set |
|
433 |
in the constructor) determines whether the cell's contents may be |
|
434 |
edited. |
|
435 |
||
436 |
If a pixmap is specified it is displayed to the left of any text. |
|
437 |
You can change the text or pixmap with setText() and setPixmap() |
|
438 |
respectively. For text you can use setWordWrap(). |
|
439 |
||
440 |
When sorting table items the key() function is used; by default |
|
441 |
this returns the table item's text(). Reimplement key() to |
|
442 |
customize how your table items will sort. |
|
443 |
||
444 |
Table items are inserted into a table using Q3Table::setItem(). If |
|
445 |
you insert an item into a cell that already contains a table item |
|
446 |
the original item will be deleted. |
|
447 |
||
448 |
Example: |
|
449 |
\snippet doc/src/snippets/code/src_qt3support_itemviews_q3table.cpp 0 |
|
450 |
||
451 |
You can move a table item from one cell to another, in the same or |
|
452 |
a different table, using Q3Table::takeItem() and Q3Table::setItem() |
|
453 |
but see also Q3Table::swapCells(). |
|
454 |
||
455 |
Table items can be deleted with delete in the standard way; the |
|
456 |
table and cell will be updated accordingly. |
|
457 |
||
458 |
Note, that if you have a table item that is not currently in a table |
|
459 |
then anything you do to that item other than insert it into a table |
|
460 |
will result in undefined behaviour. |
|
461 |
||
462 |
Reimplement createEditor() and setContentFromEditor() if you want |
|
463 |
to use your own widget instead of a QLineEdit for editing cell |
|
464 |
contents. Reimplement paint() if you want to display custom |
|
465 |
content. |
|
466 |
||
467 |
It is important to ensure that your custom widget can accept the |
|
468 |
keyboard focus, so that the user can use the tab key to navigate the |
|
469 |
table as normal. Therefore, if the widget returned by createEditor() |
|
470 |
does not itself accept the keyboard focus, it is necessary to |
|
471 |
nominate a child widget to do so on its behalf. For example, a |
|
472 |
QHBox with two child QLineEdit widgets may use one of them to |
|
473 |
accept the keyboard focus: |
|
474 |
||
475 |
\snippet doc/src/snippets/code/src_qt3support_itemviews_q3table.cpp 1 |
|
476 |
||
477 |
By default, table items may be replaced by new Q3TableItems |
|
478 |
during the lifetime of a Q3Table. Therefore, if you create your |
|
479 |
own subclass of Q3TableItem, and you want to ensure that |
|
480 |
this does not happen, you must call setReplaceable(false) |
|
481 |
in the constructor of your subclass. |
|
482 |
||
483 |
\img qtableitems.png Table Items |
|
484 |
||
485 |
\sa Q3CheckTableItem Q3ComboTableItem |
|
486 |
||
487 |
*/ |
|
488 |
||
489 |
/*! |
|
490 |
\fn Q3Table *Q3TableItem::table() const |
|
491 |
||
492 |
Returns the Q3Table the table item belongs to. |
|
493 |
||
494 |
\sa Q3Table::setItem() Q3TableItem() |
|
495 |
*/ |
|
496 |
||
497 |
/*! |
|
498 |
\enum Q3TableItem::EditType |
|
499 |
||
500 |
\target wheneditable |
|
501 |
This enum is used to define whether a cell is editable or |
|
502 |
read-only (in conjunction with other settings), and how the cell |
|
503 |
should be displayed. |
|
504 |
||
505 |
\value Always |
|
506 |
The cell always \e looks editable. |
|
507 |
||
508 |
Using this EditType ensures that the editor created with |
|
509 |
createEditor() (by default a QLineEdit) is always visible. This |
|
510 |
has implications for the alignment of the content: the default |
|
511 |
editor aligns everything (even numbers) to the left whilst |
|
512 |
numerical values in the cell are by default aligned to the right. |
|
513 |
||
514 |
If a cell with the edit type \c Always looks misaligned you could |
|
515 |
reimplement createEditor() for these items. |
|
516 |
||
517 |
\value WhenCurrent |
|
518 |
The cell \e looks editable only when it has keyboard focus (see |
|
519 |
Q3Table::setCurrentCell()). |
|
520 |
||
521 |
\value OnTyping |
|
522 |
The cell \e looks editable only when the user types in it or |
|
523 |
double-clicks it. It resembles the \c WhenCurrent functionality |
|
524 |
but is, perhaps, nicer. |
|
525 |
||
526 |
The \c OnTyping edit type is the default when Q3TableItem objects |
|
527 |
are created by the convenience functions Q3Table::setText() and |
|
528 |
Q3Table::setPixmap(). |
|
529 |
||
530 |
\value Never The cell is not editable. |
|
531 |
||
532 |
The cell is actually editable only if Q3Table::isRowReadOnly() is |
|
533 |
false for its row, Q3Table::isColumnReadOnly() is false for its |
|
534 |
column, and Q3Table::isReadOnly() is false. |
|
535 |
||
536 |
Q3ComboTableItems have an isEditable() property. This property is |
|
537 |
used to indicate whether the user may enter their own text or are |
|
538 |
restricted to choosing one of the choices in the list. |
|
539 |
Q3ComboTableItems may be interacted with only if they are editable |
|
540 |
in accordance with their EditType as described above. |
|
541 |
||
542 |
*/ |
|
543 |
||
544 |
/*! |
|
545 |
Creates a table item that is a child of table \a table with no |
|
546 |
text. The item has the \l EditType \a et. |
|
547 |
||
548 |
The table item will use a QLineEdit for its editor, will not |
|
549 |
word-wrap and will occupy a single cell. Insert the table item |
|
550 |
into a table with Q3Table::setItem(). |
|
551 |
||
552 |
The table takes ownership of the table item, so a table item |
|
553 |
should not be inserted into more than one table at a time. |
|
554 |
*/ |
|
555 |
||
556 |
Q3TableItem::Q3TableItem(Q3Table *table, EditType et) |
|
557 |
: txt(), pix(), t(table), edType(et), wordwrap(false), |
|
558 |
tcha(true), rw(-1), cl(-1), rowspan(1), colspan(1) |
|
559 |
{ |
|
560 |
enabled = true; |
|
561 |
} |
|
562 |
||
563 |
/*! |
|
564 |
Creates a table item that is a child of table \a table with text |
|
565 |
\a text. The item has the \l EditType \a et. |
|
566 |
||
567 |
The table item will use a QLineEdit for its editor, will not |
|
568 |
word-wrap and will occupy a single cell. Insert the table item |
|
569 |
into a table with Q3Table::setItem(). |
|
570 |
||
571 |
The table takes ownership of the table item, so a table item |
|
572 |
should not be inserted into more than one table at a time. |
|
573 |
*/ |
|
574 |
||
575 |
Q3TableItem::Q3TableItem(Q3Table *table, EditType et, const QString &text) |
|
576 |
: txt(text), pix(), t(table), edType(et), wordwrap(false), |
|
577 |
tcha(true), rw(-1), cl(-1), rowspan(1), colspan(1) |
|
578 |
{ |
|
579 |
enabled = true; |
|
580 |
} |
|
581 |
||
582 |
/*! |
|
583 |
Creates a table item that is a child of table \a table with text |
|
584 |
\a text and pixmap \a p. The item has the \l EditType \a et. |
|
585 |
||
586 |
The table item will display the pixmap to the left of the text. It |
|
587 |
will use a QLineEdit for editing the text, will not word-wrap and |
|
588 |
will occupy a single cell. Insert the table item into a table with |
|
589 |
Q3Table::setItem(). |
|
590 |
||
591 |
The table takes ownership of the table item, so a table item |
|
592 |
should not be inserted in more than one table at a time. |
|
593 |
*/ |
|
594 |
||
595 |
Q3TableItem::Q3TableItem(Q3Table *table, EditType et, |
|
596 |
const QString &text, const QPixmap &p) |
|
597 |
: txt(text), pix(p), t(table), edType(et), wordwrap(false), |
|
598 |
tcha(true), rw(-1), cl(-1), rowspan(1), colspan(1) |
|
599 |
{ |
|
600 |
enabled = true; |
|
601 |
} |
|
602 |
||
603 |
/*! |
|
604 |
The destructor deletes this item and frees all allocated |
|
605 |
resources. |
|
606 |
||
607 |
If the table item is in a table (i.e. was inserted with |
|
608 |
setItem()), it will be removed from the table and the cell it |
|
609 |
occupied. |
|
610 |
*/ |
|
611 |
||
612 |
Q3TableItem::~Q3TableItem() |
|
613 |
{ |
|
614 |
if (table()) |
|
615 |
table()->takeItem(this); |
|
616 |
} |
|
617 |
||
618 |
int Q3TableItem::RTTI = 0; |
|
619 |
||
620 |
/*! |
|
621 |
Returns the Run Time Type Identification value for this table item |
|
622 |
which for Q3TableItems is 0. |
|
623 |
||
624 |
When you create subclasses based on Q3TableItem make sure that each |
|
625 |
subclass returns a unique rtti() value. It is advisable to use |
|
626 |
values greater than 1000, preferably large random numbers, to |
|
627 |
allow for extensions to this class. |
|
628 |
||
629 |
\sa Q3CheckTableItem::rtti() Q3ComboTableItem::rtti() |
|
630 |
*/ |
|
631 |
||
632 |
int Q3TableItem::rtti() const |
|
633 |
{ |
|
634 |
return RTTI; |
|
635 |
} |
|
636 |
||
637 |
/*! |
|
638 |
Returns the table item's pixmap or a null pixmap if no pixmap has |
|
639 |
been set. |
|
640 |
||
641 |
\sa setPixmap() text() |
|
642 |
*/ |
|
643 |
||
644 |
QPixmap Q3TableItem::pixmap() const |
|
645 |
{ |
|
646 |
return pix; |
|
647 |
} |
|
648 |
||
649 |
||
650 |
/*! |
|
651 |
Returns the text of the table item or an empty string if there is |
|
652 |
no text. |
|
653 |
||
654 |
To ensure that the current value of the editor is returned, |
|
655 |
setContentFromEditor() is called: |
|
656 |
\list 1 |
|
657 |
\i if the editMode() is \c Always, or |
|
658 |
\i if editMode() is \e not \c Always but the editor of the cell is |
|
659 |
active and the editor is not a QLineEdit. |
|
660 |
\endlist |
|
661 |
||
662 |
This means that text() returns the original text value of the item |
|
663 |
if the editor is a line edit, until the user commits an edit (e.g. |
|
664 |
by pressing Enter or Tab) in which case the new text is returned. |
|
665 |
For other editors (e.g. a combobox) setContentFromEditor() is |
|
666 |
always called so the currently display value is the one returned. |
|
667 |
||
668 |
\sa setText() pixmap() |
|
669 |
*/ |
|
670 |
||
671 |
QString Q3TableItem::text() const |
|
672 |
{ |
|
673 |
QWidget *w = table()->cellWidget(rw, cl); |
|
674 |
if (w && (edType == Always || |
|
675 |
rtti() == Q3ComboTableItem::RTTI || |
|
676 |
rtti() == Q3CheckTableItem::RTTI)) |
|
677 |
((Q3TableItem*)this)->setContentFromEditor(w); |
|
678 |
return txt; |
|
679 |
} |
|
680 |
||
681 |
/*! |
|
682 |
Sets pixmap \a p to be this item's pixmap. |
|
683 |
||
684 |
Note that setPixmap() does not update the cell the table item |
|
685 |
belongs to. Use Q3Table::updateCell() to repaint the cell's |
|
686 |
contents. |
|
687 |
||
688 |
For \l{Q3ComboTableItem}s and \l{Q3CheckTableItem}s this function |
|
689 |
has no visible effect. |
|
690 |
||
691 |
\sa Q3Table::setPixmap() pixmap() setText() |
|
692 |
*/ |
|
693 |
||
694 |
void Q3TableItem::setPixmap(const QPixmap &p) |
|
695 |
{ |
|
696 |
pix = p; |
|
697 |
} |
|
698 |
||
699 |
/*! |
|
700 |
Changes the table item's text to \a str. |
|
701 |
||
702 |
Note that setText() does not update the cell the table item |
|
703 |
belongs to. Use Q3Table::updateCell() to repaint the cell's |
|
704 |
contents. |
|
705 |
||
706 |
\sa Q3Table::setText() text() setPixmap() Q3Table::updateCell() |
|
707 |
*/ |
|
708 |
||
709 |
void Q3TableItem::setText(const QString &str) |
|
710 |
{ |
|
711 |
txt = str; |
|
712 |
} |
|
713 |
||
714 |
/*! |
|
715 |
This virtual function is used to paint the contents of an item |
|
716 |
using the painter \a p in the rectangular area \a cr using the |
|
717 |
color group \a cg. |
|
718 |
||
719 |
If \a selected is true the cell is displayed in a way that |
|
720 |
indicates that it is highlighted. |
|
721 |
||
722 |
You don't usually need to use this function but if you want to |
|
723 |
draw custom content in a cell you will need to reimplement it. |
|
724 |
||
725 |
The painter passed to this function is translated so that 0, 0 |
|
726 |
is the top-left corner of the item that is being painted. |
|
727 |
||
728 |
Note that the painter is not clipped by default in order to get |
|
729 |
maximum efficiency. If you want clipping, use |
|
730 |
||
731 |
\snippet doc/src/snippets/code/src_qt3support_itemviews_q3table.cpp 2 |
|
732 |
||
733 |
*/ |
|
734 |
||
735 |
void Q3TableItem::paint(QPainter *p, const QColorGroup &cg, |
|
736 |
const QRect &cr, bool selected) |
|
737 |
{ |
|
738 |
p->fillRect(0, 0, cr.width(), cr.height(), |
|
739 |
selected ? cg.brush(QColorGroup::Highlight) |
|
740 |
: cg.brush(QColorGroup::Base)); |
|
741 |
||
742 |
int w = cr.width(); |
|
743 |
int h = cr.height(); |
|
744 |
||
745 |
int x = 0; |
|
746 |
if (!pix.isNull()) { |
|
747 |
p->drawPixmap(0, (cr.height() - pix.height()) / 2, pix); |
|
748 |
x = pix.width() + 2; |
|
749 |
} |
|
750 |
||
751 |
if (selected) |
|
752 |
p->setPen(cg.highlightedText()); |
|
753 |
else |
|
754 |
p->setPen(cg.text()); |
|
755 |
p->drawText(x + 2, 0, w - x - 4, h, |
|
756 |
wordwrap ? (alignment() | WordBreak) : alignment(), text()); |
|
757 |
} |
|
758 |
||
759 |
/*! |
|
760 |
This virtual function creates an editor which the user can |
|
761 |
interact with to edit the cell's contents. The default |
|
762 |
implementation creates a QLineEdit. |
|
763 |
||
764 |
If the function returns 0, the cell is read-only. |
|
765 |
||
766 |
The returned widget should preferably be invisible, ideally with |
|
767 |
Q3Table::viewport() as parent. |
|
768 |
||
769 |
If you reimplement this function you'll almost certainly need to |
|
770 |
reimplement setContentFromEditor(), and may need to reimplement |
|
771 |
sizeHint(). |
|
772 |
||
773 |
\sa Q3Table::createEditor() setContentFromEditor() Q3Table::viewport() setReplaceable() |
|
774 |
*/ |
|
775 |
||
776 |
QWidget *Q3TableItem::createEditor() const |
|
777 |
{ |
|
778 |
QLineEdit *e = new QLineEdit(table()->viewport(), "qt_tableeditor"); |
|
779 |
e->setFrame(false); |
|
780 |
e->setText(text()); |
|
781 |
return e; |
|
782 |
} |
|
783 |
||
784 |
/*! |
|
785 |
Whenever the content of a cell has been edited by the editor \a w, |
|
786 |
Q3Table calls this virtual function to copy the new values into the |
|
787 |
Q3TableItem. |
|
788 |
||
789 |
If you reimplement createEditor() and return something that is not |
|
790 |
a QLineEdit you will need to reimplement this function. |
|
791 |
||
792 |
\sa Q3Table::setCellContentFromEditor() |
|
793 |
*/ |
|
794 |
||
795 |
void Q3TableItem::setContentFromEditor(QWidget *w) |
|
796 |
{ |
|
797 |
QLineEdit *le = qobject_cast<QLineEdit*>(w); |
|
798 |
if (le) { |
|
799 |
QString input = le->text(); |
|
800 |
if (le->validator()) |
|
801 |
le->validator()->fixup(input); |
|
802 |
setText(input); |
|
803 |
} |
|
804 |
} |
|
805 |
||
806 |
/*! |
|
807 |
The alignment function returns how the text contents of the cell |
|
808 |
are aligned when drawn. The default implementation aligns numbers |
|
809 |
to the right and any other text to the left. |
|
810 |
||
811 |
\sa Qt::Alignment |
|
812 |
*/ |
|
813 |
||
814 |
// ed: For consistency reasons a setAlignment() should be provided |
|
815 |
// as well. |
|
816 |
||
817 |
int Q3TableItem::alignment() const |
|
818 |
{ |
|
819 |
bool num; |
|
820 |
bool ok1 = false, ok2 = false; |
|
821 |
(void)text().toInt(&ok1); |
|
822 |
if (!ok1) |
|
823 |
(void)text().toDouble(&ok2); // ### should be .-aligned |
|
824 |
num = ok1 || ok2; |
|
825 |
||
826 |
return (num ? AlignRight : AlignLeft) | AlignVCenter; |
|
827 |
} |
|
828 |
||
829 |
/*! |
|
830 |
If \a b is true, the cell's text will be wrapped over multiple |
|
831 |
lines, when necessary, to fit the width of the cell; otherwise the |
|
832 |
text will be written as a single line. |
|
833 |
||
834 |
\sa wordWrap() Q3Table::adjustColumn() Q3Table::setColumnStretchable() |
|
835 |
*/ |
|
836 |
||
837 |
void Q3TableItem::setWordWrap(bool b) |
|
838 |
{ |
|
839 |
wordwrap = b; |
|
840 |
} |
|
841 |
||
842 |
/*! |
|
843 |
Returns true if word wrap is enabled for the cell; otherwise |
|
844 |
returns false. |
|
845 |
||
846 |
\sa setWordWrap() |
|
847 |
*/ |
|
848 |
||
849 |
bool Q3TableItem::wordWrap() const |
|
850 |
{ |
|
851 |
return wordwrap; |
|
852 |
} |
|
853 |
||
854 |
/*! \internal */ |
|
855 |
||
856 |
void Q3TableItem::updateEditor(int oldRow, int oldCol) |
|
857 |
{ |
|
858 |
if (edType != Always) |
|
859 |
return; |
|
860 |
if (oldRow != -1 && oldCol != -1) |
|
861 |
table()->clearCellWidget(oldRow, oldCol); |
|
862 |
if (rw != -1 && cl != -1) |
|
863 |
table()->setCellWidget(rw, cl, createEditor()); |
|
864 |
} |
|
865 |
||
866 |
/*! |
|
867 |
Returns the table item's edit type. |
|
868 |
||
869 |
This is set when the table item is constructed. |
|
870 |
||
871 |
\sa EditType Q3TableItem() |
|
872 |
*/ |
|
873 |
||
874 |
Q3TableItem::EditType Q3TableItem::editType() const |
|
875 |
{ |
|
876 |
return edType; |
|
877 |
} |
|
878 |
||
879 |
/*! |
|
880 |
If \a b is true it is acceptable to replace the contents of the |
|
881 |
cell with the contents of another Q3TableItem. If \a b is false the |
|
882 |
contents of the cell may not be replaced by the contents of |
|
883 |
another table item. Table items that span more than one cell may |
|
884 |
not have their contents replaced by another table item. |
|
885 |
||
886 |
(This differs from \l EditType because EditType is concerned with |
|
887 |
whether the \e user is able to change the contents of a cell.) |
|
888 |
||
889 |
\sa isReplaceable() |
|
890 |
*/ |
|
891 |
||
892 |
void Q3TableItem::setReplaceable(bool b) |
|
893 |
{ |
|
894 |
tcha = b; |
|
895 |
} |
|
896 |
||
897 |
/*! |
|
898 |
This function returns whether the contents of the cell may be |
|
899 |
replaced with the contents of another table item. Regardless of |
|
900 |
this setting, table items that span more than one cell may not |
|
901 |
have their contents replaced by another table item. |
|
902 |
||
903 |
(This differs from \l EditType because EditType is concerned with |
|
904 |
whether the \e user is able to change the contents of a cell.) |
|
905 |
||
906 |
\sa setReplaceable() EditType |
|
907 |
*/ |
|
908 |
||
909 |
bool Q3TableItem::isReplaceable() const |
|
910 |
{ |
|
911 |
if (rowspan > 1 || colspan > 1) |
|
912 |
return false; |
|
913 |
return tcha; |
|
914 |
} |
|
915 |
||
916 |
/*! |
|
917 |
This virtual function returns the key that should be used for |
|
918 |
sorting. The default implementation returns the text() of the |
|
919 |
relevant item. |
|
920 |
||
921 |
\sa Q3Table::setSorting() |
|
922 |
*/ |
|
923 |
||
924 |
QString Q3TableItem::key() const |
|
925 |
{ |
|
926 |
return text(); |
|
927 |
} |
|
928 |
||
929 |
/*! |
|
930 |
This virtual function returns the size a cell needs to show its |
|
931 |
entire content. |
|
932 |
||
933 |
If you subclass Q3TableItem you will often need to reimplement this |
|
934 |
function. |
|
935 |
*/ |
|
936 |
||
937 |
QSize Q3TableItem::sizeHint() const |
|
938 |
{ |
|
939 |
QSize strutSize = QApplication::globalStrut(); |
|
940 |
if (edType == Always && table()->cellWidget(rw, cl)) |
|
941 |
return table()->cellWidget(rw, cl)->sizeHint().expandedTo(strutSize); |
|
942 |
||
943 |
QSize s; |
|
944 |
int x = 0; |
|
945 |
if (!pix.isNull()) { |
|
946 |
s = pix.size(); |
|
947 |
s.setWidth(s.width() + 2); |
|
948 |
x = pix.width() + 2; |
|
949 |
} |
|
950 |
||
951 |
QString t = text(); |
|
952 |
if (!wordwrap && t.find(QLatin1Char('\n')) == -1) |
|
953 |
return QSize(s.width() + table()->fontMetrics().width(text()) + 10, |
|
954 |
QMAX(s.height(), table()->fontMetrics().height())).expandedTo(strutSize); |
|
955 |
||
956 |
QRect r = table()->fontMetrics().boundingRect(x + 2, 0, table()->columnWidth(col()) - x - 4, 0, |
|
957 |
wordwrap ? (alignment() | WordBreak) : alignment(), |
|
958 |
text()); |
|
959 |
r.setWidth(QMAX(r.width() + 10, table()->columnWidth(col()))); |
|
960 |
return QSize(r.width(), QMAX(s.height(), r.height())).expandedTo(strutSize); |
|
961 |
} |
|
962 |
||
963 |
/*! |
|
964 |
Changes the extent of the Q3TableItem so that it spans multiple |
|
965 |
cells covering \a rs rows and \a cs columns. The top left cell is |
|
966 |
the original cell. |
|
967 |
||
968 |
\warning This function only works if the item has already been |
|
969 |
inserted into the table using e.g. Q3Table::setItem(). This |
|
970 |
function also checks to make sure if \a rs and \a cs are within |
|
971 |
the bounds of the table and returns without changing the span if |
|
972 |
they are not. In addition swapping, inserting or removing rows and |
|
973 |
columns that cross Q3TableItems spanning more than one cell is not |
|
974 |
supported. |
|
975 |
||
976 |
\sa rowSpan() colSpan() |
|
977 |
*/ |
|
978 |
||
979 |
void Q3TableItem::setSpan(int rs, int cs) |
|
980 |
{ |
|
981 |
if (rs == rowspan && cs == colspan) |
|
982 |
return; |
|
983 |
||
984 |
if (!table()->d->hasRowSpan) |
|
985 |
table()->d->hasRowSpan = rs > 1; |
|
986 |
if (!table()->d->hasColSpan) |
|
987 |
table()->d->hasColSpan = cs > 1; |
|
988 |
// return if we are thinking too big... |
|
989 |
if (rw + rs > table()->numRows()) |
|
990 |
return; |
|
991 |
||
992 |
if (cl + cs > table()->numCols()) |
|
993 |
return; |
|
994 |
||
995 |
if (rw == -1 || cl == -1) |
|
996 |
return; |
|
997 |
||
998 |
int rrow = rw; |
|
999 |
int rcol = cl; |
|
1000 |
if (rowspan > 1 || colspan > 1) { |
|
1001 |
Q3Table* t = table(); |
|
1002 |
t->takeItem(this); |
|
1003 |
t->setItem(rrow, rcol, this); |
|
1004 |
} |
|
1005 |
||
1006 |
rowspan = rs; |
|
1007 |
colspan = cs; |
|
1008 |
||
1009 |
for (int r = 0; r < rowspan; ++r) { |
|
1010 |
for (int c = 0; c < colspan; ++c) { |
|
1011 |
if (r == 0 && c == 0) |
|
1012 |
continue; |
|
1013 |
qt_update_cell_widget = false; |
|
1014 |
table()->setItem(r + rw, c + cl, this); |
|
1015 |
qt_update_cell_widget = true; |
|
1016 |
rw = rrow; |
|
1017 |
cl = rcol; |
|
1018 |
} |
|
1019 |
} |
|
1020 |
||
1021 |
table()->updateCell(rw, cl); |
|
1022 |
QWidget *w = table()->cellWidget(rw, cl); |
|
1023 |
if (w) |
|
1024 |
w->resize(table()->cellGeometry(rw, cl).size()); |
|
1025 |
} |
|
1026 |
||
1027 |
/*! |
|
1028 |
Returns the row span of the table item, usually 1. |
|
1029 |
||
1030 |
\sa setSpan() colSpan() |
|
1031 |
*/ |
|
1032 |
||
1033 |
int Q3TableItem::rowSpan() const |
|
1034 |
{ |
|
1035 |
return rowspan; |
|
1036 |
} |
|
1037 |
||
1038 |
/*! |
|
1039 |
Returns the column span of the table item, usually 1. |
|
1040 |
||
1041 |
\sa setSpan() rowSpan() |
|
1042 |
*/ |
|
1043 |
||
1044 |
int Q3TableItem::colSpan() const |
|
1045 |
{ |
|
1046 |
return colspan; |
|
1047 |
} |
|
1048 |
||
1049 |
/*! |
|
1050 |
Sets row \a r as the table item's row. Usually you do not need to |
|
1051 |
call this function. |
|
1052 |
||
1053 |
If the cell spans multiple rows, this function sets the top row |
|
1054 |
and retains the height of the multi-cell table item. |
|
1055 |
||
1056 |
\sa row() setCol() rowSpan() |
|
1057 |
*/ |
|
1058 |
||
1059 |
void Q3TableItem::setRow(int r) |
|
1060 |
{ |
|
1061 |
rw = r; |
|
1062 |
} |
|
1063 |
||
1064 |
/*! |
|
1065 |
Sets column \a c as the table item's column. Usually you will not |
|
1066 |
need to call this function. |
|
1067 |
||
1068 |
If the cell spans multiple columns, this function sets the |
|
1069 |
left-most column and retains the width of the multi-cell table |
|
1070 |
item. |
|
1071 |
||
1072 |
\sa col() setRow() colSpan() |
|
1073 |
*/ |
|
1074 |
||
1075 |
void Q3TableItem::setCol(int c) |
|
1076 |
{ |
|
1077 |
cl = c; |
|
1078 |
} |
|
1079 |
||
1080 |
/*! |
|
1081 |
Returns the row where the table item is located. If the cell spans |
|
1082 |
multiple rows, this function returns the top-most row. |
|
1083 |
||
1084 |
\sa col() setRow() |
|
1085 |
*/ |
|
1086 |
||
1087 |
int Q3TableItem::row() const |
|
1088 |
{ |
|
1089 |
return rw; |
|
1090 |
} |
|
1091 |
||
1092 |
/*! |
|
1093 |
Returns the column where the table item is located. If the cell |
|
1094 |
spans multiple columns, this function returns the left-most |
|
1095 |
column. |
|
1096 |
||
1097 |
\sa row() setCol() |
|
1098 |
*/ |
|
1099 |
||
1100 |
int Q3TableItem::col() const |
|
1101 |
{ |
|
1102 |
return cl; |
|
1103 |
} |
|
1104 |
||
1105 |
/*! |
|
1106 |
If \a b is true, the table item is enabled; if \a b is false the |
|
1107 |
table item is disabled. |
|
1108 |
||
1109 |
A disabled item doesn't respond to user interaction. |
|
1110 |
||
1111 |
\sa isEnabled() |
|
1112 |
*/ |
|
1113 |
||
1114 |
void Q3TableItem::setEnabled(bool b) |
|
1115 |
{ |
|
1116 |
if (b == (bool)enabled) |
|
1117 |
return; |
|
1118 |
enabled = b; |
|
1119 |
table()->updateCell(row(), col()); |
|
1120 |
} |
|
1121 |
||
1122 |
/*! |
|
1123 |
Returns true if the table item is enabled; otherwise returns false. |
|
1124 |
||
1125 |
\sa setEnabled() |
|
1126 |
*/ |
|
1127 |
||
1128 |
bool Q3TableItem::isEnabled() const |
|
1129 |
{ |
|
1130 |
return (bool)enabled; |
|
1131 |
} |
|
1132 |
||
1133 |
/*! |
|
1134 |
\class Q3ComboTableItem |
|
1135 |
\brief The Q3ComboTableItem class provides a means of using |
|
1136 |
comboboxes in Q3Tables. |
|
1137 |
||
1138 |
\compat |
|
1139 |
||
1140 |
A Q3ComboTableItem is a table item which looks and behaves like a |
|
1141 |
combobox. The advantage of using Q3ComboTableItems rather than real |
|
1142 |
comboboxes is that a Q3ComboTableItem uses far less resources than |
|
1143 |
real comboboxes in \l{Q3Table}s. When the cell has the focus it |
|
1144 |
displays a real combobox which the user can interact with. When |
|
1145 |
the cell does not have the focus the cell \e looks like a |
|
1146 |
combobox. Only text items (i.e. no pixmaps) may be used in |
|
1147 |
Q3ComboTableItems. |
|
1148 |
||
1149 |
Q3ComboTableItem items have the edit type \c WhenCurrent (see |
|
1150 |
\l{EditType}). The Q3ComboTableItem's list of items is provided by |
|
1151 |
a QStringList passed to the constructor. |
|
1152 |
||
1153 |
The list of items may be changed using setStringList(). The |
|
1154 |
current item can be set with setCurrentItem() and retrieved with |
|
1155 |
currentItem(). The text of the current item can be obtained with |
|
1156 |
currentText(), and the text of a particular item can be retrieved |
|
1157 |
with text(). |
|
1158 |
||
1159 |
If isEditable() is true the Q3ComboTableItem will permit the user |
|
1160 |
to either choose an existing list item, or create a new list item |
|
1161 |
by entering their own text; otherwise the user may only choose one |
|
1162 |
of the existing list items. |
|
1163 |
||
1164 |
To populate a table cell with a Q3ComboTableItem use |
|
1165 |
Q3Table::setItem(). |
|
1166 |
||
1167 |
Q3ComboTableItems may be deleted with Q3Table::clearCell(). |
|
1168 |
||
1169 |
Q3ComboTableItems can be distinguished from \l{Q3TableItem}s and |
|
1170 |
\l{Q3CheckTableItem}s using their Run Time Type Identification |
|
1171 |
number (see rtti()). |
|
1172 |
||
1173 |
\img qtableitems.png Table Items |
|
1174 |
||
1175 |
\sa Q3CheckTableItem Q3TableItem Q3ComboBox |
|
1176 |
*/ |
|
1177 |
||
1178 |
Q3ComboBox *Q3ComboTableItem::fakeCombo = 0; |
|
1179 |
QWidget *Q3ComboTableItem::fakeComboWidget = 0; |
|
1180 |
int Q3ComboTableItem::fakeRef = 0; |
|
1181 |
||
1182 |
/*! |
|
1183 |
Creates a combo table item for the table \a table. The combobox's |
|
1184 |
list of items is passed in the \a list argument. If \a editable is |
|
1185 |
true the user may type in new list items; if \a editable is false |
|
1186 |
the user may only select from the list of items provided. |
|
1187 |
||
1188 |
By default Q3ComboTableItems cannot be replaced by other table |
|
1189 |
items since isReplaceable() returns false by default. |
|
1190 |
||
1191 |
\sa Q3Table::clearCell() EditType |
|
1192 |
*/ |
|
1193 |
||
1194 |
Q3ComboTableItem::Q3ComboTableItem(Q3Table *table, const QStringList &list, bool editable) |
|
1195 |
: Q3TableItem(table, WhenCurrent, QLatin1String("")), entries(list), current(0), edit(editable) |
|
1196 |
{ |
|
1197 |
setReplaceable(false); |
|
1198 |
if (!Q3ComboTableItem::fakeCombo) { |
|
1199 |
Q3ComboTableItem::fakeComboWidget = new QWidget(0, 0); |
|
1200 |
Q3ComboTableItem::fakeCombo = new Q3ComboBox(false, Q3ComboTableItem::fakeComboWidget, 0); |
|
1201 |
Q3ComboTableItem::fakeCombo->hide(); |
|
1202 |
} |
|
1203 |
++Q3ComboTableItem::fakeRef; |
|
1204 |
if (entries.count()) |
|
1205 |
setText(entries.at(current)); |
|
1206 |
} |
|
1207 |
||
1208 |
/*! |
|
1209 |
Q3ComboTableItem destructor. |
|
1210 |
*/ |
|
1211 |
Q3ComboTableItem::~Q3ComboTableItem() |
|
1212 |
{ |
|
1213 |
if (--Q3ComboTableItem::fakeRef <= 0) { |
|
1214 |
delete Q3ComboTableItem::fakeComboWidget; |
|
1215 |
Q3ComboTableItem::fakeComboWidget = 0; |
|
1216 |
Q3ComboTableItem::fakeCombo = 0; |
|
1217 |
} |
|
1218 |
} |
|
1219 |
||
1220 |
/*! |
|
1221 |
Sets the list items of this Q3ComboTableItem to the strings in the |
|
1222 |
string list \a l. |
|
1223 |
*/ |
|
1224 |
||
1225 |
void Q3ComboTableItem::setStringList(const QStringList &l) |
|
1226 |
{ |
|
1227 |
entries = l; |
|
1228 |
current = 0; |
|
1229 |
if (entries.count()) |
|
1230 |
setText(entries.at(current)); |
|
1231 |
if (table()->cellWidget(row(), col())) { |
|
1232 |
cb->clear(); |
|
1233 |
cb->insertStringList(entries); |
|
1234 |
} |
|
1235 |
table()->updateCell(row(), col()); |
|
1236 |
} |
|
1237 |
||
1238 |
/*! \reimp */ |
|
1239 |
||
1240 |
QWidget *Q3ComboTableItem::createEditor() const |
|
1241 |
{ |
|
1242 |
// create an editor - a combobox in our case |
|
1243 |
((Q3ComboTableItem*)this)->cb = new Q3ComboBox(edit, table()->viewport(), "qt_editor_cb"); |
|
1244 |
cb->insertStringList(entries); |
|
1245 |
cb->setCurrentItem(current); |
|
1246 |
QObject::connect(cb, SIGNAL(activated(int)), table(), SLOT(doValueChanged())); |
|
1247 |
return cb; |
|
1248 |
} |
|
1249 |
||
1250 |
/*! \reimp */ |
|
1251 |
||
1252 |
void Q3ComboTableItem::setContentFromEditor(QWidget *w) |
|
1253 |
{ |
|
1254 |
Q3ComboBox *cb = qobject_cast<Q3ComboBox*>(w); |
|
1255 |
if (cb) { |
|
1256 |
entries.clear(); |
|
1257 |
for (int i = 0; i < cb->count(); ++i) |
|
1258 |
entries << cb->text(i); |
|
1259 |
current = cb->currentItem(); |
|
1260 |
setText(cb->currentText()); |
|
1261 |
} |
|
1262 |
} |
|
1263 |
||
1264 |
/*! \reimp */ |
|
1265 |
||
1266 |
void Q3ComboTableItem::paint(QPainter *p, const QColorGroup &cg, |
|
1267 |
const QRect &cr, bool selected) |
|
1268 |
{ |
|
1269 |
fakeCombo->resize(cr.width(), cr.height()); |
|
1270 |
||
1271 |
QPalette pal2(cg); |
|
1272 |
if (selected) { |
|
1273 |
pal2.setBrush(QPalette::Base, cg.QPalette::brush(QPalette::Highlight)); |
|
1274 |
pal2.setColor(QPalette::Text, cg.highlightedText()); |
|
1275 |
} |
|
1276 |
||
1277 |
QStyle::State flags = QStyle::State_None; |
|
1278 |
if(isEnabled() && table()->isEnabled()) |
|
1279 |
flags |= QStyle::State_Enabled; |
|
1280 |
// Since we still have the "fakeCombo" may as well use it in this case. |
|
1281 |
QStyleOptionComboBox opt; |
|
1282 |
opt.initFrom(table()); |
|
1283 |
opt.rect = fakeCombo->rect(); |
|
1284 |
opt.palette = pal2; |
|
1285 |
opt.state &= ~QStyle::State_HasFocus; |
|
1286 |
opt.state &= ~QStyle::State_MouseOver; |
|
1287 |
opt.state |= flags; |
|
1288 |
opt.subControls = QStyle::SC_All; |
|
1289 |
opt.activeSubControls = QStyle::SC_None; |
|
1290 |
opt.editable = fakeCombo->editable(); |
|
1291 |
table()->style()->drawComplexControl(QStyle::CC_ComboBox, &opt, p, fakeCombo); |
|
1292 |
||
1293 |
p->save(); |
|
1294 |
QRect textR = table()->style()->subControlRect(QStyle::CC_ComboBox, &opt, |
|
1295 |
QStyle::SC_ComboBoxEditField, fakeCombo); |
|
1296 |
int align = alignment(); // alignment() changes entries |
|
1297 |
p->drawText(textR, wordWrap() ? (align | Qt::WordBreak) : align, entries.value(current)); |
|
1298 |
p->restore(); |
|
1299 |
} |
|
1300 |
||
1301 |
/*! |
|
1302 |
Sets the list item \a i to be the combo table item's current list |
|
1303 |
item. |
|
1304 |
||
1305 |
\sa currentItem() |
|
1306 |
*/ |
|
1307 |
||
1308 |
void Q3ComboTableItem::setCurrentItem(int i) |
|
1309 |
{ |
|
1310 |
QWidget *w = table()->cellWidget(row(), col()); |
|
1311 |
Q3ComboBox *cb = qobject_cast<Q3ComboBox*>(w); |
|
1312 |
if (cb) { |
|
1313 |
cb->setCurrentItem(i); |
|
1314 |
current = cb->currentItem(); |
|
1315 |
setText(cb->currentText()); |
|
1316 |
} else { |
|
1317 |
if (i < 0 || i >= entries.count()) |
|
1318 |
return; |
|
1319 |
current = i; |
|
1320 |
setText(entries.at(i)); |
|
1321 |
table()->updateCell(row(), col()); |
|
1322 |
} |
|
1323 |
} |
|
1324 |
||
1325 |
/*! |
|
1326 |
\overload |
|
1327 |
||
1328 |
Sets the list item whose text is \a s to be the combo table item's |
|
1329 |
current list item. Does nothing if no list item has the text \a s. |
|
1330 |
||
1331 |
\sa currentItem() |
|
1332 |
*/ |
|
1333 |
||
1334 |
void Q3ComboTableItem::setCurrentItem(const QString &s) |
|
1335 |
{ |
|
1336 |
int i = entries.findIndex(s); |
|
1337 |
if (i != -1) |
|
1338 |
setCurrentItem(i); |
|
1339 |
} |
|
1340 |
||
1341 |
/*! |
|
1342 |
Returns the index of the combo table item's current list item. |
|
1343 |
||
1344 |
\sa setCurrentItem() |
|
1345 |
*/ |
|
1346 |
||
1347 |
int Q3ComboTableItem::currentItem() const |
|
1348 |
{ |
|
1349 |
QWidget *w = table()->cellWidget(row(), col()); |
|
1350 |
Q3ComboBox *cb = qobject_cast<Q3ComboBox*>(w); |
|
1351 |
if (cb) |
|
1352 |
return cb->currentItem(); |
|
1353 |
return current; |
|
1354 |
} |
|
1355 |
||
1356 |
/*! |
|
1357 |
Returns the text of the combo table item's current list item. |
|
1358 |
||
1359 |
\sa currentItem() text() |
|
1360 |
*/ |
|
1361 |
||
1362 |
QString Q3ComboTableItem::currentText() const |
|
1363 |
{ |
|
1364 |
QWidget *w = table()->cellWidget(row(), col()); |
|
1365 |
Q3ComboBox *cb = qobject_cast<Q3ComboBox*>(w); |
|
1366 |
if (cb) |
|
1367 |
return cb->currentText(); |
|
1368 |
return entries.value(current); |
|
1369 |
} |
|
1370 |
||
1371 |
/*! |
|
1372 |
Returns the total number of list items in the combo table item. |
|
1373 |
*/ |
|
1374 |
||
1375 |
int Q3ComboTableItem::count() const |
|
1376 |
{ |
|
1377 |
QWidget *w = table()->cellWidget(row(), col()); |
|
1378 |
Q3ComboBox *cb = qobject_cast<Q3ComboBox*>(w); |
|
1379 |
if (cb) |
|
1380 |
return cb->count(); |
|
1381 |
return (int)entries.count(); |
|
1382 |
} |
|
1383 |
||
1384 |
/*! |
|
1385 |
Returns the text of the combo's list item at index \a i. |
|
1386 |
||
1387 |
\sa currentText() |
|
1388 |
*/ |
|
1389 |
||
1390 |
QString Q3ComboTableItem::text(int i) const |
|
1391 |
{ |
|
1392 |
QWidget *w = table()->cellWidget(row(), col()); |
|
1393 |
Q3ComboBox *cb = qobject_cast<Q3ComboBox*>(w); |
|
1394 |
if (cb) |
|
1395 |
return cb->text(i); |
|
1396 |
return entries.value(i); |
|
1397 |
} |
|
1398 |
||
1399 |
/*! |
|
1400 |
If \a b is true the combo table item can be edited, i.e. the user |
|
1401 |
may enter a new text item themselves. If \a b is false the user may |
|
1402 |
may only choose one of the existing items. |
|
1403 |
||
1404 |
\sa isEditable() |
|
1405 |
*/ |
|
1406 |
||
1407 |
void Q3ComboTableItem::setEditable(bool b) |
|
1408 |
{ |
|
1409 |
edit = b; |
|
1410 |
} |
|
1411 |
||
1412 |
/*! |
|
1413 |
Returns true if the user can add their own list items to the |
|
1414 |
combobox's list of items; otherwise returns false. |
|
1415 |
||
1416 |
\sa setEditable() |
|
1417 |
*/ |
|
1418 |
||
1419 |
bool Q3ComboTableItem::isEditable() const |
|
1420 |
{ |
|
1421 |
return edit; |
|
1422 |
} |
|
1423 |
||
1424 |
int Q3ComboTableItem::RTTI = 1; |
|
1425 |
||
1426 |
/*! |
|
1427 |
\fn int Q3ComboTableItem::rtti() const |
|
1428 |
||
1429 |
Returns 1. |
|
1430 |
||
1431 |
Make your derived classes return their own values for rtti()to |
|
1432 |
distinguish between different table item subclasses. You should |
|
1433 |
use values greater than 1000, preferably a large random number, to |
|
1434 |
allow for extensions to this class. |
|
1435 |
||
1436 |
||
1437 |
\sa Q3TableItem::rtti() |
|
1438 |
*/ |
|
1439 |
||
1440 |
int Q3ComboTableItem::rtti() const |
|
1441 |
{ |
|
1442 |
return RTTI; |
|
1443 |
} |
|
1444 |
||
1445 |
/*! \reimp */ |
|
1446 |
||
1447 |
QSize Q3ComboTableItem::sizeHint() const |
|
1448 |
{ |
|
1449 |
fakeCombo->insertItem(currentText()); |
|
1450 |
fakeCombo->setCurrentItem(fakeCombo->count() - 1); |
|
1451 |
QSize sh = fakeCombo->sizeHint(); |
|
1452 |
fakeCombo->removeItem(fakeCombo->count() - 1); |
|
1453 |
return sh.expandedTo(QApplication::globalStrut()); |
|
1454 |
} |
|
1455 |
||
1456 |
/*! |
|
1457 |
\fn QString Q3ComboTableItem::text() const |
|
1458 |
||
1459 |
Returns the text of the table item or an empty string if there is |
|
1460 |
no text. |
|
1461 |
||
1462 |
\sa Q3TableItem::text() |
|
1463 |
*/ |
|
1464 |
||
1465 |
/*! |
|
1466 |
\class Q3CheckTableItem |
|
1467 |
\brief The Q3CheckTableItem class provides checkboxes in Q3Tables. |
|
1468 |
||
1469 |
\compat |
|
1470 |
||
1471 |
A Q3CheckTableItem is a table item which looks and behaves like a |
|
1472 |
checkbox. The advantage of using Q3CheckTableItems rather than real |
|
1473 |
checkboxes is that a Q3CheckTableItem uses far less resources than |
|
1474 |
a real checkbox would in a \l{Q3Table}. When the cell has the focus |
|
1475 |
it displays a real checkbox which the user can interact with. When |
|
1476 |
the cell does not have the focus the cell \e looks like a |
|
1477 |
checkbox. Pixmaps may not be used in Q3CheckTableItems. |
|
1478 |
||
1479 |
Q3CheckTableItem items have the edit type \c WhenCurrent (see |
|
1480 |
\l{EditType}). |
|
1481 |
||
1482 |
To change the checkbox's label use setText(). The checkbox can be |
|
1483 |
checked and unchecked with setChecked() and its state retrieved |
|
1484 |
using isChecked(). |
|
1485 |
||
1486 |
To populate a table cell with a Q3CheckTableItem use |
|
1487 |
Q3Table::setItem(). |
|
1488 |
||
1489 |
Q3CheckTableItems can be distinguished from \l{Q3TableItem}s and |
|
1490 |
\l{Q3ComboTableItem}s using their Run Time Type Identification |
|
1491 |
(rtti) value. |
|
1492 |
||
1493 |
\img qtableitems.png Table Items |
|
1494 |
||
1495 |
\sa rtti() EditType Q3ComboTableItem Q3TableItem QCheckBox |
|
1496 |
*/ |
|
1497 |
||
1498 |
/*! |
|
1499 |
Creates a Q3CheckTableItem with an \l{EditType} of \c WhenCurrent |
|
1500 |
as a child of \a table. The checkbox is initially unchecked and |
|
1501 |
its label is set to the string \a txt. |
|
1502 |
*/ |
|
1503 |
||
1504 |
Q3CheckTableItem::Q3CheckTableItem(Q3Table *table, const QString &txt) |
|
1505 |
: Q3TableItem(table, WhenCurrent, txt), checked(false) |
|
1506 |
{ |
|
1507 |
} |
|
1508 |
||
1509 |
/*! \reimp */ |
|
1510 |
||
1511 |
void Q3CheckTableItem::setText(const QString &t) |
|
1512 |
{ |
|
1513 |
Q3TableItem::setText(t); |
|
1514 |
QWidget *w = table()->cellWidget(row(), col()); |
|
1515 |
QCheckBox *cb = qobject_cast<QCheckBox*>(w); |
|
1516 |
if (cb) |
|
1517 |
cb->setText(t); |
|
1518 |
} |
|
1519 |
||
1520 |
||
1521 |
/*! \reimp */ |
|
1522 |
||
1523 |
QWidget *Q3CheckTableItem::createEditor() const |
|
1524 |
{ |
|
1525 |
// create an editor - a combobox in our case |
|
1526 |
((Q3CheckTableItem*)this)->cb = new QCheckBox(table()->viewport(), "qt_editor_checkbox"); |
|
1527 |
cb->setChecked(checked); |
|
1528 |
cb->setText(text()); |
|
1529 |
cb->setBackgroundColor(table()->viewport()->backgroundColor()); |
|
1530 |
cb->setAutoFillBackground(true); |
|
1531 |
QObject::connect(cb, SIGNAL(toggled(bool)), table(), SLOT(doValueChanged())); |
|
1532 |
return cb; |
|
1533 |
} |
|
1534 |
||
1535 |
/*! \reimp */ |
|
1536 |
||
1537 |
void Q3CheckTableItem::setContentFromEditor(QWidget *w) |
|
1538 |
{ |
|
1539 |
QCheckBox *cb = qobject_cast<QCheckBox*>(w); |
|
1540 |
if (cb) |
|
1541 |
checked = cb->isChecked(); |
|
1542 |
} |
|
1543 |
||
1544 |
/*! \reimp */ |
|
1545 |
||
1546 |
void Q3CheckTableItem::paint(QPainter *p, const QColorGroup &cg, |
|
1547 |
const QRect &cr, bool selected) |
|
1548 |
{ |
|
1549 |
QPalette pal = cg; |
|
1550 |
||
1551 |
p->fillRect(0, 0, cr.width(), cr.height(), |
|
1552 |
selected ? pal.brush(QPalette::Highlight) |
|
1553 |
: pal.brush(QPalette::Base)); |
|
1554 |
||
1555 |
QSize sz = QSize(table()->style()->pixelMetric(QStyle::PM_IndicatorWidth), |
|
1556 |
table()->style()->pixelMetric(QStyle::PM_IndicatorHeight)); |
|
1557 |
QPalette pal2(pal); |
|
1558 |
pal2.setBrush(QPalette::Window, pal.brush(QPalette::Base)); |
|
1559 |
QStyleOptionButton opt; |
|
1560 |
opt.initFrom(table()); |
|
1561 |
opt.rect.setRect(0, (cr.height() - sz.height()) / 2, sz.width(), sz.height()); |
|
1562 |
opt.palette = pal2; |
|
1563 |
opt.state &= ~QStyle::State_HasFocus; |
|
1564 |
opt.state &= ~QStyle::State_MouseOver; |
|
1565 |
if(isEnabled()) |
|
1566 |
opt.state |= QStyle::State_Enabled; |
|
1567 |
if (checked) |
|
1568 |
opt.state |= QStyle::State_On; |
|
1569 |
else |
|
1570 |
opt.state |= QStyle::State_Off; |
|
1571 |
if (isEnabled() && table()->isEnabled()) |
|
1572 |
opt.state |= QStyle::State_Enabled; |
|
1573 |
table()->style()->drawPrimitive(QStyle::PE_IndicatorCheckBox, &opt, p, table()); |
|
1574 |
if (selected) |
|
1575 |
p->setPen(pal.highlightedText().color()); |
|
1576 |
else |
|
1577 |
p->setPen(pal.text().color()); |
|
1578 |
opt.rect.setRect(0, 0, cr.width(), cr.height()); |
|
1579 |
QRect textRect = table()->style()->subElementRect(QStyle::SE_CheckBoxContents, &opt, table()); |
|
1580 |
p->drawText(textRect, wordWrap() ? (alignment() | Qt::WordBreak) : alignment(), text()); |
|
1581 |
} |
|
1582 |
||
1583 |
/*! |
|
1584 |
If \a b is true the checkbox is checked; if \a b is false the |
|
1585 |
checkbox is unchecked. |
|
1586 |
||
1587 |
\sa isChecked() |
|
1588 |
*/ |
|
1589 |
||
1590 |
void Q3CheckTableItem::setChecked(bool b) |
|
1591 |
{ |
|
1592 |
checked = b; |
|
1593 |
table()->updateCell(row(), col()); |
|
1594 |
QWidget *w = table()->cellWidget(row(), col()); |
|
1595 |
QCheckBox *cb = qobject_cast<QCheckBox*>(w); |
|
1596 |
if (cb) |
|
1597 |
cb->setChecked(b); |
|
1598 |
} |
|
1599 |
||
1600 |
/*! |
|
1601 |
Returns true if the checkbox table item is checked; otherwise |
|
1602 |
returns false. |
|
1603 |
||
1604 |
\sa setChecked() |
|
1605 |
*/ |
|
1606 |
||
1607 |
bool Q3CheckTableItem::isChecked() const |
|
1608 |
{ |
|
1609 |
// #### why was this next line here. It must not be here, as |
|
1610 |
// #### people want to call isChecked() from within paintCell() |
|
1611 |
// #### and end up in an infinite loop that way |
|
1612 |
// table()->updateCell(row(), col()); |
|
1613 |
QWidget *w = table()->cellWidget(row(), col()); |
|
1614 |
QCheckBox *cb = qobject_cast<QCheckBox*>(w); |
|
1615 |
if (cb) |
|
1616 |
return cb->isChecked(); |
|
1617 |
return checked; |
|
1618 |
} |
|
1619 |
||
1620 |
int Q3CheckTableItem::RTTI = 2; |
|
1621 |
||
1622 |
/*! |
|
1623 |
\fn int Q3CheckTableItem::rtti() const |
|
1624 |
||
1625 |
Returns 2. |
|
1626 |
||
1627 |
Make your derived classes return their own values for rtti()to |
|
1628 |
distinguish between different table item subclasses. You should |
|
1629 |
use values greater than 1000, preferably a large random number, to |
|
1630 |
allow for extensions to this class. |
|
1631 |
||
1632 |
\sa Q3TableItem::rtti() |
|
1633 |
*/ |
|
1634 |
||
1635 |
int Q3CheckTableItem::rtti() const |
|
1636 |
{ |
|
1637 |
return RTTI; |
|
1638 |
} |
|
1639 |
||
1640 |
/*! \reimp */ |
|
1641 |
||
1642 |
QSize Q3CheckTableItem::sizeHint() const |
|
1643 |
{ |
|
1644 |
QSize sz = QSize(table()->style()->pixelMetric(QStyle::PM_IndicatorWidth), |
|
1645 |
table()->style()->pixelMetric(QStyle::PM_IndicatorHeight)); |
|
1646 |
sz.setWidth(sz.width() + 6); |
|
1647 |
QSize sh(Q3TableItem::sizeHint()); |
|
1648 |
return QSize(sh.width() + sz.width(), QMAX(sh.height(), sz.height())). |
|
1649 |
expandedTo(QApplication::globalStrut()); |
|
1650 |
} |
|
1651 |
||
1652 |
/*! |
|
1653 |
\class Q3Table |
|
1654 |
\brief The Q3Table class provides a flexible editable table widget. |
|
1655 |
||
1656 |
\compat |
|
1657 |
||
1658 |
Q3Table is easy to use, although it does have a large API because |
|
1659 |
of the comprehensive functionality that it provides. Q3Table |
|
1660 |
includes functions for manipulating \link #headers |
|
1661 |
headers\endlink, \link #columnsrows rows and columns\endlink, |
|
1662 |
\link #cells cells\endlink and \link #selections |
|
1663 |
selections\endlink. Q3Table also provides in-place editing and |
|
1664 |
drag and drop, as well as a useful set of |
|
1665 |
\link #signals signals\endlink. Q3Table efficiently supports very |
|
1666 |
large tables, for example, tables one million by one million cells |
|
1667 |
are perfectly possible. Q3Table is economical with memory, using |
|
1668 |
none for unused cells. |
|
1669 |
||
1670 |
\snippet doc/src/snippets/code/src_qt3support_itemviews_q3table.cpp 3 |
|
1671 |
||
1672 |
The first line constructs the table specifying its size in rows |
|
1673 |
and columns. We then insert a pixmap and some text into the \e |
|
1674 |
same \link #cells cell\endlink, with the pixmap appearing to the |
|
1675 |
left of the text. Q3Table cells can be populated with |
|
1676 |
\l{Q3TableItem}s, \l{Q3ComboTableItem}s or by \l{Q3CheckTableItem}s. |
|
1677 |
By default a vertical header appears at the left of the table |
|
1678 |
showing row numbers and a horizontal header appears at the top of |
|
1679 |
the table showing column numbers. (The numbers displayed start at |
|
1680 |
1, although row and column numbers within Q3Table begin at 0.) |
|
1681 |
||
1682 |
If you want to use mouse tracking call setMouseTracking(true) on |
|
1683 |
the \e viewport. |
|
1684 |
||
1685 |
\img qtableitems.png Table Items |
|
1686 |
||
1687 |
\target headers |
|
1688 |
\section1 Headers |
|
1689 |
||
1690 |
Q3Table supports a header column, e.g. to display row numbers, and |
|
1691 |
a header row, e.g to display column titles. To set row or column |
|
1692 |
labels use Q3Header::setLabel() on the pointers returned by |
|
1693 |
verticalHeader() and horizontalHeader() respectively. The vertical |
|
1694 |
header is displayed within the table's left margin whose width is |
|
1695 |
set with setLeftMargin(). The horizontal header is displayed |
|
1696 |
within the table's top margin whose height is set with |
|
1697 |
setTopMargin(). The table's grid can be switched off with |
|
1698 |
setShowGrid(). If you want to hide a horizontal header call |
|
1699 |
hide(), and call setTopMargin(0) so that the area the header |
|
1700 |
would have occupied is reduced to zero size. |
|
1701 |
||
1702 |
Header labels are indexed via their section numbers. Note that the |
|
1703 |
default behavior of Q3Header regarding section numbers is overridden |
|
1704 |
for Q3Table. See the explanation below in the Rows and Columns |
|
1705 |
section in the discussion of moving columns and rows. |
|
1706 |
||
1707 |
\target columnsrows |
|
1708 |
\section1 Rows and Columns |
|
1709 |
||
1710 |
Row and column sizes are set with setRowHeight() and |
|
1711 |
setColumnWidth(). If you want a row high enough to show the |
|
1712 |
tallest item in its entirety, use adjustRow(). Similarly, to make |
|
1713 |
a column wide enough to show the widest item use adjustColumn(). |
|
1714 |
If you want the row height and column width to adjust |
|
1715 |
automatically as the height and width of the table changes use |
|
1716 |
setRowStretchable() and setColumnStretchable(). |
|
1717 |
||
1718 |
Rows and columns can be hidden and shown with hideRow(), |
|
1719 |
hideColumn(), showRow() and showColumn(). New rows and columns are |
|
1720 |
inserted using insertRows() and insertColumns(). Additional rows |
|
1721 |
and columns are added at the bottom (rows) or right (columns) if |
|
1722 |
you set setNumRows() or setNumCols() to be larger than numRows() |
|
1723 |
or numCols(). Existing rows and columns are removed with |
|
1724 |
removeRow() and removeColumn(). Multiple rows and columns can be |
|
1725 |
removed with removeRows() and removeColumns(). |
|
1726 |
||
1727 |
Rows and columns can be set to be movable using |
|
1728 |
rowMovingEnabled() and columnMovingEnabled(). The user can drag |
|
1729 |
them to reorder them holding down the Ctrl key and dragging the |
|
1730 |
mouse. For performance reasons, the default behavior of Q3Header |
|
1731 |
section numbers is overridden by Q3Table. Currently in Q3Table, when |
|
1732 |
a row or column is dragged and reordered, the section number is |
|
1733 |
also changed to its new position. Therefore, there is no |
|
1734 |
difference between the section and the index fields in Q3Header. |
|
1735 |
The Q3Table Q3Header classes do not provide a mechanism for indexing |
|
1736 |
independently of the user interface ordering. |
|
1737 |
||
1738 |
The table can be sorted using sortColumn(). Users can sort a |
|
1739 |
column by clicking its header if setSorting() is set to true. Rows |
|
1740 |
can be swapped with swapRows(), columns with swapColumns() and |
|
1741 |
cells with swapCells(). |
|
1742 |
||
1743 |
For editable tables (see setReadOnly()) you can set the read-only |
|
1744 |
property of individual rows and columns with setRowReadOnly() and |
|
1745 |
setColumnReadOnly(). (Whether a cell is editable or read-only |
|
1746 |
depends on these settings and the cell's Q3TableItem. |
|
1747 |
||
1748 |
The row and column which have the focus are returned by |
|
1749 |
currentRow() and currentColumn() respectively. |
|
1750 |
||
1751 |
Although many Q3Table functions operate in terms of rows and |
|
1752 |
columns the indexOf() function returns a single integer |
|
1753 |
identifying a particular cell. |
|
1754 |
||
1755 |
\target cells |
|
1756 |
\section1 Cells |
|
1757 |
||
1758 |
All of a Q3Table's cells are empty when the table is constructed. |
|
1759 |
||
1760 |
There are two approaches to populating the table's cells. The |
|
1761 |
first and simplest approach is to use Q3TableItems or Q3TableItem |
|
1762 |
subclasses. The second approach doesn't use Q3TableItems at all |
|
1763 |
which is useful for very large sparse tables but requires you to |
|
1764 |
reimplement a number of functions. We'll look at each approach in |
|
1765 |
turn. |
|
1766 |
||
1767 |
To put a string in a cell use setText(). This function will create |
|
1768 |
a new Q3TableItem for the cell if one doesn't already exist, and |
|
1769 |
displays the text in it. By default the table item's widget will |
|
1770 |
be a QLineEdit. A pixmap may be put in a cell with setPixmap(), |
|
1771 |
which also creates a table item if required. A cell may contain \e |
|
1772 |
both a pixmap and text; the pixmap is displayed to the left of the |
|
1773 |
text. Another approach is to construct a Q3TableItem or Q3TableItem |
|
1774 |
subclass, set its properties, then insert it into a cell with |
|
1775 |
setItem(). |
|
1776 |
||
1777 |
If you want cells which contain comboboxes use the Q3ComboTableItem |
|
1778 |
class. Similarly if you require cells containing checkboxes use |
|
1779 |
the Q3CheckTableItem class. These table items look and behave just |
|
1780 |
like the combobox or checkbox widgets but consume far less memory. |
|
1781 |
||
1782 |
Q3Table takes ownership of its Q3TableItems and will delete them |
|
1783 |
when the table itself is destroyed. You can take ownership of a |
|
1784 |
table item using takeItem() which you use to move a cell's |
|
1785 |
contents from one cell to another, either within the same table, |
|
1786 |
or from one table to another. (See also, swapCells()). |
|
1787 |
||
1788 |
In-place editing of the text in Q3TableItems, and the values in |
|
1789 |
Q3ComboTableItems and Q3CheckTableItems works automatically. Cells |
|
1790 |
may be editable or read-only, see Q3TableItem::EditType. If you |
|
1791 |
want fine control over editing see beginEdit() and endEdit(). |
|
1792 |
||
1793 |
The contents of a cell can be retrieved as a Q3TableItem using |
|
1794 |
item(), or as a string with text() or as a pixmap (if there is |
|
1795 |
one) with pixmap(). A cell's bounding rectangle is given by |
|
1796 |
cellGeometry(). Use updateCell() to repaint a cell, for example to |
|
1797 |
clear away a cell's visual representation after it has been |
|
1798 |
deleted with clearCell(). The table can be forced to scroll to |
|
1799 |
show a particular cell with ensureCellVisible(). The isSelected() |
|
1800 |
function indicates if a cell is selected. |
|
1801 |
||
1802 |
It is possible to use your own widget as a cell's widget using |
|
1803 |
setCellWidget(), but subclassing Q3TableItem might be a simpler |
|
1804 |
approach. The cell's widget (if there is one) can be removed with |
|
1805 |
clearCellWidget(). |
|
1806 |
||
1807 |
\keyword notes on large tables |
|
1808 |
\target bigtables |
|
1809 |
\section2 Large tables |
|
1810 |
||
1811 |
For large, sparse, tables using Q3TableItems or other widgets is |
|
1812 |
inefficient. The solution is to \e draw the cell as it should |
|
1813 |
appear and to create and destroy cell editors on demand. |
|
1814 |
||
1815 |
This approach requires that you reimplement various functions. |
|
1816 |
Reimplement paintCell() to display your data, and createEditor() |
|
1817 |
and setCellContentFromEditor() to support in-place editing. It |
|
1818 |
is very important to reimplement resizeData() to have no |
|
1819 |
functionality, to prevent Q3Table from attempting to create a huge |
|
1820 |
array. You will also need to reimplement item(), setItem(), |
|
1821 |
takeItem(), clearCell(), and insertWidget(), cellWidget() and |
|
1822 |
clearCellWidget(). In almost every circumstance (for sorting, |
|
1823 |
removing and inserting columns and rows, etc.), you also need |
|
1824 |
to reimplement swapRows(), swapCells() and swapColumns(), including |
|
1825 |
header handling. |
|
1826 |
||
1827 |
If you represent active cells with a dictionary of Q3TableItems and |
|
1828 |
QWidgets, i.e. only store references to cells that are actually |
|
1829 |
used, many of the functions can be implemented with a single line |
|
1830 |
of code. |
|
1831 |
||
1832 |
For more information on cells see the Q3TableItem documenation. |
|
1833 |
||
1834 |
\target selections |
|
1835 |
\section1 Selections |
|
1836 |
||
1837 |
Q3Table's support single selection, multi-selection (multiple |
|
1838 |
cells) or no selection. The selection mode is set with |
|
1839 |
setSelectionMode(). Use isSelected() to determine if a particular |
|
1840 |
cell is selected, and isRowSelected() and isColumnSelected() to |
|
1841 |
see if a row or column is selected. |
|
1842 |
||
1843 |
Q3Table's support many simultaneous selections. You can |
|
1844 |
programmatically select cells with addSelection(). The number of |
|
1845 |
selections is given by numSelections(). The current selection is |
|
1846 |
returned by currentSelection(). You can remove a selection with |
|
1847 |
removeSelection() and remove all selections with |
|
1848 |
clearSelection(). Selections are Q3TableSelection objects. |
|
1849 |
||
1850 |
To easily add a new selection use selectCells(), selectRow() or |
|
1851 |
selectColumn(). |
|
1852 |
||
1853 |
Alternatively, use addSelection() to add new selections using |
|
1854 |
Q3TableSelection objects. The advantage of using Q3TableSelection |
|
1855 |
objects is that you can call Q3TableSelection::expandTo() to resize |
|
1856 |
the selection and can query and compare them. |
|
1857 |
||
1858 |
The number of selections is given by numSelections(). The current |
|
1859 |
selection is returned by currentSelection(). You can remove a |
|
1860 |
selection with removeSelection() and remove all selections with |
|
1861 |
clearSelection(). |
|
1862 |
||
1863 |
\target signals |
|
1864 |
\section1 Signals |
|
1865 |
||
1866 |
When the user clicks a cell the currentChanged() signal is |
|
1867 |
emitted. You can also connect to the lower level clicked(), |
|
1868 |
doubleClicked() and pressed() signals. If the user changes the |
|
1869 |
selection the selectionChanged() signal is emitted; similarly if |
|
1870 |
the user changes a cell's value the valueChanged() signal is |
|
1871 |
emitted. If the user right-clicks (or presses the appropriate |
|
1872 |
platform-specific key sequence) the contextMenuRequested() signal |
|
1873 |
is emitted. If the user drops a drag and drop object the dropped() |
|
1874 |
signal is emitted with the drop event. |
|
1875 |
*/ |
|
1876 |
||
1877 |
/*! |
|
1878 |
\fn void Q3Table::currentChanged(int row, int col) |
|
1879 |
||
1880 |
This signal is emitted when the current cell has changed to \a |
|
1881 |
row, \a col. |
|
1882 |
*/ |
|
1883 |
||
1884 |
/*! |
|
1885 |
\fn void Q3Table::valueChanged(int row, int col) |
|
1886 |
||
1887 |
This signal is emitted when the user changed the value in the cell |
|
1888 |
at \a row, \a col. |
|
1889 |
*/ |
|
1890 |
||
1891 |
/*! |
|
1892 |
\fn int Q3Table::currentRow() const |
|
1893 |
||
1894 |
Returns the current row. |
|
1895 |
||
1896 |
\sa currentColumn() |
|
1897 |
*/ |
|
1898 |
||
1899 |
/*! |
|
1900 |
\fn int Q3Table::currentColumn() const |
|
1901 |
||
1902 |
Returns the current column. |
|
1903 |
||
1904 |
\sa currentRow() |
|
1905 |
*/ |
|
1906 |
||
1907 |
/*! |
|
1908 |
\enum Q3Table::EditMode |
|
1909 |
||
1910 |
\value NotEditing No cell is currently being edited. |
|
1911 |
||
1912 |
\value Editing A cell is currently being edited. The editor was |
|
1913 |
initialised with the cell's contents. |
|
1914 |
||
1915 |
\value Replacing A cell is currently being edited. The editor was |
|
1916 |
not initialised with the cell's contents. |
|
1917 |
*/ |
|
1918 |
||
1919 |
/*! |
|
1920 |
\enum Q3Table::SelectionMode |
|
1921 |
||
1922 |
\value NoSelection No cell can be selected by the user. |
|
1923 |
||
1924 |
\value Single The user may only select a single range of cells. |
|
1925 |
||
1926 |
\value Multi The user may select multiple ranges of cells. |
|
1927 |
||
1928 |
\value SingleRow The user may select one row at once. |
|
1929 |
||
1930 |
\value MultiRow The user may select multiple rows. |
|
1931 |
*/ |
|
1932 |
||
1933 |
/*! |
|
1934 |
\enum Q3Table::FocusStyle |
|
1935 |
||
1936 |
Specifies how the current cell (focus cell) is drawn. |
|
1937 |
||
1938 |
\value FollowStyle The current cell is drawn according to the |
|
1939 |
current style and the cell's background is also drawn selected, if |
|
1940 |
the current cell is within a selection |
|
1941 |
||
1942 |
\value SpreadSheet The current cell is drawn as in a spreadsheet. |
|
1943 |
This means, it is signified by a black rectangle around the cell, |
|
1944 |
and the background of the current cell is always drawn with the |
|
1945 |
widget's base color - even when selected. |
|
1946 |
||
1947 |
*/ |
|
1948 |
||
1949 |
/*! |
|
1950 |
\fn void Q3Table::clicked(int row, int col, int button, const QPoint &mousePos) |
|
1951 |
||
1952 |
This signal is emitted when mouse button \a button is clicked. The |
|
1953 |
cell where the event took place is at \a row, \a col, and the |
|
1954 |
mouse's position is in \a mousePos. |
|
1955 |
||
1956 |
\sa Qt::MouseButton |
|
1957 |
*/ |
|
1958 |
||
1959 |
/*! |
|
1960 |
\fn void Q3Table::doubleClicked(int row, int col, int button, const QPoint &mousePos) |
|
1961 |
||
1962 |
This signal is emitted when mouse button \a button is |
|
1963 |
double-clicked. The cell where the event took place is at \a row, |
|
1964 |
\a col, and the mouse's position is in \a mousePos. |
|
1965 |
||
1966 |
\sa Qt::MouseButton |
|
1967 |
*/ |
|
1968 |
||
1969 |
/*! |
|
1970 |
\fn void Q3Table::pressed(int row, int col, int button, const QPoint &mousePos) |
|
1971 |
||
1972 |
This signal is emitted when mouse button \a button is pressed. The |
|
1973 |
cell where the event took place is at \a row, \a col, and the |
|
1974 |
mouse's position is in \a mousePos. |
|
1975 |
||
1976 |
\sa Qt::MouseButton |
|
1977 |
*/ |
|
1978 |
||
1979 |
/*! |
|
1980 |
\fn void Q3Table::selectionChanged() |
|
1981 |
||
1982 |
This signal is emitted whenever a selection changes. |
|
1983 |
||
1984 |
\sa Q3TableSelection |
|
1985 |
*/ |
|
1986 |
||
1987 |
/*! |
|
1988 |
\fn void Q3Table::contextMenuRequested(int row, int col, const QPoint & pos) |
|
1989 |
||
1990 |
This signal is emitted when the user invokes a context menu with |
|
1991 |
the right mouse button (or with a system-specific keypress). The |
|
1992 |
cell where the event took place is at \a row, \a col. \a pos is |
|
1993 |
the position where the context menu will appear in the global |
|
1994 |
coordinate system. This signal is always emitted, even if the |
|
1995 |
contents of the cell are disabled. |
|
1996 |
*/ |
|
1997 |
||
1998 |
/*! |
|
1999 |
Creates an empty table object called \a name as a child of \a |
|
2000 |
parent. |
|
2001 |
||
2002 |
Call setNumRows() and setNumCols() to set the table size before |
|
2003 |
populating the table if you're using Q3TableItems. |
|
2004 |
*/ |
|
2005 |
||
2006 |
Q3Table::Q3Table(QWidget *parent, const char *name) |
|
2007 |
: Q3ScrollView(parent, name, WNoAutoErase | WStaticContents), |
|
2008 |
leftHeader(0), topHeader(0), |
|
2009 |
currentSel(0), lastSortCol(-1), sGrid(true), mRows(false), mCols(false), |
|
2010 |
asc(true), doSort(true), readOnly(false) |
|
2011 |
{ |
|
2012 |
init(0, 0); |
|
2013 |
} |
|
2014 |
||
2015 |
/*! |
|
2016 |
Constructs an empty table called \a name with \a numRows rows and |
|
2017 |
\a numCols columns. The table is a child of \a parent. |
|
2018 |
||
2019 |
If you're using \l{Q3TableItem}s to populate the table's cells, you |
|
2020 |
can create Q3TableItem, Q3ComboTableItem and Q3CheckTableItem items |
|
2021 |
and insert them into the table using setItem(). (See the notes on |
|
2022 |
large tables for an alternative to using Q3TableItems.) |
|
2023 |
*/ |
|
2024 |
||
2025 |
Q3Table::Q3Table(int numRows, int numCols, QWidget *parent, const char *name) |
|
2026 |
: Q3ScrollView(parent, name, WNoAutoErase | WStaticContents), |
|
2027 |
leftHeader(0), topHeader(0), |
|
2028 |
currentSel(0), lastSortCol(-1), sGrid(true), mRows(false), mCols(false), |
|
2029 |
asc(true), doSort(true), readOnly(false) |
|
2030 |
{ |
|
2031 |
init(numRows, numCols); |
|
2032 |
} |
|
2033 |
||
2034 |
/*! \internal |
|
2035 |
*/ |
|
2036 |
||
2037 |
void Q3Table::init(int rows, int cols) |
|
2038 |
{ |
|
2039 |
#ifndef QT_NO_DRAGANDDROP |
|
2040 |
setDragAutoScroll(false); |
|
2041 |
#endif |
|
2042 |
d = new Q3TablePrivate; |
|
2043 |
d->geomTimer = new QTimer(this); |
|
2044 |
d->lastVisCol = 0; |
|
2045 |
d->lastVisRow = 0; |
|
2046 |
connect(d->geomTimer, SIGNAL(timeout()), this, SLOT(updateGeometriesSlot())); |
|
2047 |
shouldClearSelection = false; |
|
2048 |
dEnabled = false; |
|
2049 |
roRows.setAutoDelete(true); |
|
2050 |
roCols.setAutoDelete(true); |
|
2051 |
setSorting(false); |
|
2052 |
||
2053 |
unused = true; // It's unused, ain't it? :) |
|
2054 |
||
2055 |
selMode = Multi; |
|
2056 |
||
2057 |
contents.setAutoDelete(true); |
|
2058 |
widgets.setAutoDelete(true); |
|
2059 |
||
2060 |
// Enable clipper and set background mode |
|
2061 |
enableClipper(qt_table_clipper_enabled); |
|
2062 |
||
2063 |
viewport()->setFocusProxy(this); |
|
2064 |
viewport()->setFocusPolicy(Qt::WheelFocus); |
|
2065 |
setFocusPolicy(Qt::WheelFocus); |
|
2066 |
||
2067 |
viewport()->setBackgroundMode(PaletteBase); |
|
2068 |
setBackgroundMode(PaletteBackground, PaletteBase); |
|
2069 |
setResizePolicy(Manual); |
|
2070 |
selections.setAutoDelete(true); |
|
2071 |
||
2072 |
// Create headers |
|
2073 |
leftHeader = new Q3TableHeader(rows, this, this, "left table header"); |
|
2074 |
leftHeader->setOrientation(Vertical); |
|
2075 |
leftHeader->setTracking(true); |
|
2076 |
leftHeader->setMovingEnabled(true); |
|
2077 |
topHeader = new Q3TableHeader(cols, this, this, "right table header"); |
|
2078 |
topHeader->setOrientation(Horizontal); |
|
2079 |
topHeader->setTracking(true); |
|
2080 |
topHeader->setMovingEnabled(true); |
|
2081 |
if (QApplication::reverseLayout()) |
|
2082 |
setMargins(0, fontMetrics().height() + 4, 30, 0); |
|
2083 |
else |
|
2084 |
setMargins(30, fontMetrics().height() + 4, 0, 0); |
|
2085 |
||
2086 |
topHeader->setUpdatesEnabled(false); |
|
2087 |
leftHeader->setUpdatesEnabled(false); |
|
2088 |
// Initialize headers |
|
2089 |
int i = 0; |
|
2090 |
for (i = 0; i < numCols(); ++i) |
|
2091 |
topHeader->resizeSection(i, QMAX(100, QApplication::globalStrut().height())); |
|
2092 |
for (i = 0; i < numRows(); ++i) |
|
2093 |
leftHeader->resizeSection(i, QMAX(20, QApplication::globalStrut().width())); |
|
2094 |
topHeader->setUpdatesEnabled(true); |
|
2095 |
leftHeader->setUpdatesEnabled(true); |
|
2096 |
||
2097 |
// Prepare for contents |
|
2098 |
contents.setAutoDelete(false); |
|
2099 |
||
2100 |
// Connect header, table and scroll bars |
|
2101 |
connect(horizontalScrollBar(), SIGNAL(valueChanged(int)), |
|
2102 |
topHeader, SLOT(setOffset(int))); |
|
2103 |
connect(verticalScrollBar(), SIGNAL(valueChanged(int)), |
|
2104 |
leftHeader, SLOT(setOffset(int))); |
|
2105 |
connect(topHeader, SIGNAL(sectionSizeChanged(int)), |
|
2106 |
this, SLOT(columnWidthChanged(int))); |
|
2107 |
connect(topHeader, SIGNAL(indexChange(int,int,int)), |
|
2108 |
this, SLOT(columnIndexChanged(int,int,int))); |
|
2109 |
connect(topHeader, SIGNAL(sectionClicked(int)), |
|
2110 |
this, SLOT(columnClicked(int))); |
|
2111 |
connect(leftHeader, SIGNAL(sectionSizeChanged(int)), |
|
2112 |
this, SLOT(rowHeightChanged(int))); |
|
2113 |
connect(leftHeader, SIGNAL(indexChange(int,int,int)), |
|
2114 |
this, SLOT(rowIndexChanged(int,int,int))); |
|
2115 |
||
2116 |
// Initialize variables |
|
2117 |
autoScrollTimer = new QTimer(this); |
|
2118 |
connect(autoScrollTimer, SIGNAL(timeout()), |
|
2119 |
this, SLOT(doAutoScroll())); |
|
2120 |
curRow = curCol = 0; |
|
2121 |
topHeader->setSectionState(curCol, Q3TableHeader::Bold); |
|
2122 |
leftHeader->setSectionState(curRow, Q3TableHeader::Bold); |
|
2123 |
edMode = NotEditing; |
|
2124 |
editRow = editCol = -1; |
|
2125 |
||
2126 |
drawActiveSelection = true; |
|
2127 |
||
2128 |
installEventFilter(this); |
|
2129 |
||
2130 |
focusStl = SpreadSheet; |
|
2131 |
||
2132 |
was_visible = false; |
|
2133 |
||
2134 |
// initial size |
|
2135 |
resize(640, 480); |
|
2136 |
} |
|
2137 |
||
2138 |
/*! |
|
2139 |
Releases all the resources used by the Q3Table object, |
|
2140 |
including all \l{Q3TableItem}s and their widgets. |
|
2141 |
*/ |
|
2142 |
||
2143 |
Q3Table::~Q3Table() |
|
2144 |
{ |
|
2145 |
setUpdatesEnabled(false); |
|
2146 |
contents.setAutoDelete(true); |
|
2147 |
contents.clear(); |
|
2148 |
widgets.clear(); |
|
2149 |
||
2150 |
delete d; |
|
2151 |
} |
|
2152 |
||
2153 |
void Q3Table::setReadOnly(bool b) |
|
2154 |
{ |
|
2155 |
readOnly = b; |
|
2156 |
||
2157 |
Q3TableItem *i = item(curRow, curCol); |
|
2158 |
if (readOnly && isEditing()) { |
|
2159 |
endEdit(editRow, editCol, true, false); |
|
2160 |
} else if (!readOnly && i && (i->editType() == Q3TableItem::WhenCurrent |
|
2161 |
|| i->editType() == Q3TableItem::Always)) { |
|
2162 |
editCell(curRow, curCol); |
|
2163 |
} |
|
2164 |
} |
|
2165 |
||
2166 |
/*! |
|
2167 |
If \a ro is true, row \a row is set to be read-only; otherwise the |
|
2168 |
row is set to be editable. |
|
2169 |
||
2170 |
Whether a cell in this row is editable or read-only depends on the |
|
2171 |
cell's EditType, and this setting. |
|
2172 |
||
2173 |
\sa isRowReadOnly() setColumnReadOnly() setReadOnly() |
|
2174 |
*/ |
|
2175 |
||
2176 |
void Q3Table::setRowReadOnly(int row, bool ro) |
|
2177 |
{ |
|
2178 |
if (ro) |
|
2179 |
roRows.replace(row, new int(0)); |
|
2180 |
else |
|
2181 |
roRows.remove(row); |
|
2182 |
||
2183 |
if (curRow == row) { |
|
2184 |
Q3TableItem *i = item(curRow, curCol); |
|
2185 |
if (ro && isEditing()) { |
|
2186 |
endEdit(editRow, editCol, true, false); |
|
2187 |
} else if (!ro && i && (i->editType() == Q3TableItem::WhenCurrent |
|
2188 |
|| i->editType() == Q3TableItem::Always)) { |
|
2189 |
editCell(curRow, curCol); |
|
2190 |
} |
|
2191 |
} |
|
2192 |
} |
|
2193 |
||
2194 |
/*! |
|
2195 |
If \a ro is true, column \a col is set to be read-only; otherwise |
|
2196 |
the column is set to be editable. |
|
2197 |
||
2198 |
Whether a cell in this column is editable or read-only depends on |
|
2199 |
the cell's EditType, and this setting. |
|
2200 |
||
2201 |
\sa isColumnReadOnly() setRowReadOnly() setReadOnly() |
|
2202 |
||
2203 |
*/ |
|
2204 |
||
2205 |
void Q3Table::setColumnReadOnly(int col, bool ro) |
|
2206 |
{ |
|
2207 |
if (ro) |
|
2208 |
roCols.replace(col, new int(0)); |
|
2209 |
else |
|
2210 |
roCols.remove(col); |
|
2211 |
||
2212 |
if (curCol == col) { |
|
2213 |
Q3TableItem *i = item(curRow, curCol); |
|
2214 |
if (ro && isEditing()) { |
|
2215 |
endEdit(editRow, editCol, true, false); |
|
2216 |
} else if (!ro && i && (i->editType() == Q3TableItem::WhenCurrent |
|
2217 |
|| i->editType() == Q3TableItem::Always)) { |
|
2218 |
editCell(curRow, curCol); |
|
2219 |
} |
|
2220 |
} |
|
2221 |
} |
|
2222 |
||
2223 |
/*! |
|
2224 |
\property Q3Table::readOnly |
|
2225 |
\brief whether the table is read-only |
|
2226 |
||
2227 |
Whether a cell in the table is editable or read-only depends on |
|
2228 |
the cell's \link Q3TableItem::EditType EditType\endlink, and this setting. |
|
2229 |
||
2230 |
\sa QWidget::enabled setColumnReadOnly() setRowReadOnly() |
|
2231 |
*/ |
|
2232 |
||
2233 |
bool Q3Table::isReadOnly() const |
|
2234 |
{ |
|
2235 |
return readOnly; |
|
2236 |
} |
|
2237 |
||
2238 |
/*! |
|
2239 |
Returns true if row \a row is read-only; otherwise returns false. |
|
2240 |
||
2241 |
Whether a cell in this row is editable or read-only depends on the |
|
2242 |
cell's \link Q3TableItem::EditType EditType\endlink, and this |
|
2243 |
setting. |
|
2244 |
||
2245 |
\sa setRowReadOnly() isColumnReadOnly() |
|
2246 |
*/ |
|
2247 |
||
2248 |
bool Q3Table::isRowReadOnly(int row) const |
|
2249 |
{ |
|
2250 |
return (roRows.find(row) != 0); |
|
2251 |
} |
|
2252 |
||
2253 |
/*! |
|
2254 |
Returns true if column \a col is read-only; otherwise returns |
|
2255 |
false. |
|
2256 |
||
2257 |
Whether a cell in this column is editable or read-only depends on |
|
2258 |
the cell's EditType, and this setting. |
|
2259 |
||
2260 |
\sa setColumnReadOnly() isRowReadOnly() |
|
2261 |
*/ |
|
2262 |
||
2263 |
bool Q3Table::isColumnReadOnly(int col) const |
|
2264 |
{ |
|
2265 |
return (roCols.find(col) != 0); |
|
2266 |
} |
|
2267 |
||
2268 |
void Q3Table::setSelectionMode(SelectionMode mode) |
|
2269 |
{ |
|
2270 |
if (mode == selMode) |
|
2271 |
return; |
|
2272 |
selMode = mode; |
|
2273 |
clearSelection(); |
|
2274 |
if (isRowSelection(selMode) && numRows() > 0 && numCols() > 0) { |
|
2275 |
currentSel = new Q3TableSelection(); |
|
2276 |
selections.append(currentSel); |
|
2277 |
currentSel->init(curRow, 0); |
|
2278 |
currentSel->expandTo(curRow, numCols() - 1); |
|
2279 |
repaintSelections(0, currentSel); |
|
2280 |
} |
|
2281 |
} |
|
2282 |
||
2283 |
/*! |
|
2284 |
\property Q3Table::selectionMode |
|
2285 |
\brief the current selection mode |
|
2286 |
||
2287 |
The default mode is \c Multi which allows the user to select |
|
2288 |
multiple ranges of cells. |
|
2289 |
*/ |
|
2290 |
||
2291 |
Q3Table::SelectionMode Q3Table::selectionMode() const |
|
2292 |
{ |
|
2293 |
return selMode; |
|
2294 |
} |
|
2295 |
||
2296 |
/*! |
|
2297 |
\property Q3Table::focusStyle |
|
2298 |
\brief how the current (focus) cell is drawn |
|
2299 |
||
2300 |
The default style is \c SpreadSheet. |
|
2301 |
||
2302 |
\sa Q3Table::FocusStyle |
|
2303 |
*/ |
|
2304 |
||
2305 |
void Q3Table::setFocusStyle(FocusStyle fs) |
|
2306 |
{ |
|
2307 |
focusStl = fs; |
|
2308 |
updateCell(curRow, curCol); |
|
2309 |
} |
|
2310 |
||
2311 |
Q3Table::FocusStyle Q3Table::focusStyle() const |
|
2312 |
{ |
|
2313 |
return focusStl; |
|
2314 |
} |
|
2315 |
||
2316 |
/*! |
|
2317 |
This functions updates all the header states to be in sync with |
|
2318 |
the current selections. This should be called after |
|
2319 |
programmatically changing, adding or removing selections, so that |
|
2320 |
the headers are updated. |
|
2321 |
*/ |
|
2322 |
||
2323 |
void Q3Table::updateHeaderStates() |
|
2324 |
{ |
|
2325 |
horizontalHeader()->setUpdatesEnabled(false); |
|
2326 |
verticalHeader()->setUpdatesEnabled(false); |
|
2327 |
||
2328 |
((Q3TableHeader*)verticalHeader())->setSectionStateToAll(Q3TableHeader::Normal); |
|
2329 |
((Q3TableHeader*)horizontalHeader())->setSectionStateToAll(Q3TableHeader::Normal); |
|
2330 |
||
2331 |
Q3PtrListIterator<Q3TableSelection> it(selections); |
|
2332 |
Q3TableSelection *s; |
|
2333 |
while ((s = it.current()) != 0) { |
|
2334 |
++it; |
|
2335 |
if (s->isActive()) { |
|
2336 |
if (s->leftCol() == 0 && |
|
2337 |
s->rightCol() == numCols() - 1) { |
|
2338 |
for (int i = 0; i < s->bottomRow() - s->topRow() + 1; ++i) |
|
2339 |
leftHeader->setSectionState(s->topRow() + i, Q3TableHeader::Selected); |
|
2340 |
} |
|
2341 |
if (s->topRow() == 0 && |
|
2342 |
s->bottomRow() == numRows() - 1) { |
|
2343 |
for (int i = 0; i < s->rightCol() - s->leftCol() + 1; ++i) |
|
2344 |
topHeader->setSectionState(s->leftCol() + i, Q3TableHeader::Selected); |
|
2345 |
} |
|
2346 |
} |
|
2347 |
} |
|
2348 |
||
2349 |
horizontalHeader()->setUpdatesEnabled(true); |
|
2350 |
verticalHeader()->setUpdatesEnabled(true); |
|
2351 |
horizontalHeader()->repaint(false); |
|
2352 |
verticalHeader()->repaint(false); |
|
2353 |
} |
|
2354 |
||
2355 |
/*! |
|
2356 |
Returns the table's top Q3Header. |
|
2357 |
||
2358 |
This header contains the column labels. |
|
2359 |
||
2360 |
To modify a column label use Q3Header::setLabel(). |
|
2361 |
||
2362 |
\sa verticalHeader() setTopMargin() Q3Header |
|
2363 |
*/ |
|
2364 |
||
2365 |
Q3Header *Q3Table::horizontalHeader() const |
|
2366 |
{ |
|
2367 |
return (Q3Header*)topHeader; |
|
2368 |
} |
|
2369 |
||
2370 |
/*! |
|
2371 |
Returns the table's vertical Q3Header. |
|
2372 |
||
2373 |
This header contains the row labels. |
|
2374 |
||
2375 |
\sa horizontalHeader() setLeftMargin() Q3Header |
|
2376 |
*/ |
|
2377 |
||
2378 |
Q3Header *Q3Table::verticalHeader() const |
|
2379 |
{ |
|
2380 |
return (Q3Header*)leftHeader; |
|
2381 |
} |
|
2382 |
||
2383 |
void Q3Table::setShowGrid(bool b) |
|
2384 |
{ |
|
2385 |
if (sGrid == b) |
|
2386 |
return; |
|
2387 |
sGrid = b; |
|
2388 |
updateContents(); |
|
2389 |
} |
|
2390 |
||
2391 |
/*! |
|
2392 |
\property Q3Table::showGrid |
|
2393 |
\brief whether the table's grid is displayed |
|
2394 |
||
2395 |
The grid is shown by default. |
|
2396 |
*/ |
|
2397 |
||
2398 |
bool Q3Table::showGrid() const |
|
2399 |
{ |
|
2400 |
return sGrid; |
|
2401 |
} |
|
2402 |
||
2403 |
/*! |
|
2404 |
\property Q3Table::columnMovingEnabled |
|
2405 |
\brief whether columns can be moved by the user |
|
2406 |
||
2407 |
The default is false. Columns are moved by dragging whilst holding |
|
2408 |
down the Ctrl key. |
|
2409 |
||
2410 |
\sa rowMovingEnabled |
|
2411 |
*/ |
|
2412 |
||
2413 |
void Q3Table::setColumnMovingEnabled(bool b) |
|
2414 |
{ |
|
2415 |
mCols = b; |
|
2416 |
} |
|
2417 |
||
2418 |
bool Q3Table::columnMovingEnabled() const |
|
2419 |
{ |
|
2420 |
return mCols; |
|
2421 |
} |
|
2422 |
||
2423 |
/*! |
|
2424 |
\property Q3Table::rowMovingEnabled |
|
2425 |
\brief whether rows can be moved by the user |
|
2426 |
||
2427 |
The default is false. Rows are moved by dragging whilst holding |
|
2428 |
down the Ctrl key. |
|
2429 |
||
2430 |
||
2431 |
\sa columnMovingEnabled |
|
2432 |
*/ |
|
2433 |
||
2434 |
void Q3Table::setRowMovingEnabled(bool b) |
|
2435 |
{ |
|
2436 |
mRows = b; |
|
2437 |
} |
|
2438 |
||
2439 |
bool Q3Table::rowMovingEnabled() const |
|
2440 |
{ |
|
2441 |
return mRows; |
|
2442 |
} |
|
2443 |
||
2444 |
/*! |
|
2445 |
This is called when Q3Table's internal array needs to be resized to |
|
2446 |
\a len elements. |
|
2447 |
||
2448 |
If you don't use Q3TableItems you should reimplement this as an |
|
2449 |
empty method to avoid wasting memory. See the notes on large |
|
2450 |
tables for further details. |
|
2451 |
*/ |
|
2452 |
||
2453 |
void Q3Table::resizeData(int len) |
|
2454 |
{ |
|
2455 |
contents.resize(len); |
|
2456 |
widgets.resize(len); |
|
2457 |
} |
|
2458 |
||
2459 |
/*! |
|
2460 |
Swaps the data in \a row1 and \a row2. |
|
2461 |
||
2462 |
This function is used to swap the positions of two rows. It is |
|
2463 |
called when the user changes the order of rows (see |
|
2464 |
setRowMovingEnabled()), and when rows are sorted. |
|
2465 |
||
2466 |
If you don't use \l{Q3TableItem}s and want your users to be able to |
|
2467 |
swap rows, e.g. for sorting, you will need to reimplement this |
|
2468 |
function. (See the notes on large tables.) |
|
2469 |
||
2470 |
If \a swapHeader is true, the rows' header contents is also |
|
2471 |
swapped. |
|
2472 |
||
2473 |
This function will not update the Q3Table, you will have to do |
|
2474 |
this manually, e.g. by calling updateContents(). |
|
2475 |
||
2476 |
\sa swapColumns() swapCells() |
|
2477 |
*/ |
|
2478 |
||
2479 |
void Q3Table::swapRows(int row1, int row2, bool swapHeader) |
|
2480 |
{ |
|
2481 |
if (swapHeader) |
|
2482 |
leftHeader->swapSections(row1, row2, false); |
|
2483 |
||
2484 |
Q3PtrVector<Q3TableItem> tmpContents; |
|
2485 |
tmpContents.resize(numCols()); |
|
2486 |
Q3PtrVector<QWidget> tmpWidgets; |
|
2487 |
tmpWidgets.resize(numCols()); |
|
2488 |
int i; |
|
2489 |
||
2490 |
contents.setAutoDelete(false); |
|
2491 |
widgets.setAutoDelete(false); |
|
2492 |
for (i = 0; i < numCols(); ++i) { |
|
2493 |
Q3TableItem *i1, *i2; |
|
2494 |
i1 = item(row1, i); |
|
2495 |
i2 = item(row2, i); |
|
2496 |
if (i1 || i2) { |
|
2497 |
tmpContents.insert(i, i1); |
|
2498 |
contents.remove(indexOf(row1, i)); |
|
2499 |
contents.insert(indexOf(row1, i), i2); |
|
2500 |
contents.remove(indexOf(row2, i)); |
|
2501 |
contents.insert(indexOf(row2, i), tmpContents[ i ]); |
|
2502 |
if (contents[ indexOf(row1, i) ]) |
|
2503 |
contents[ indexOf(row1, i) ]->setRow(row1); |
|
2504 |
if (contents[ indexOf(row2, i) ]) |
|
2505 |
contents[ indexOf(row2, i) ]->setRow(row2); |
|
2506 |
} |
|
2507 |
||
2508 |
QWidget *w1, *w2; |
|
2509 |
w1 = cellWidget(row1, i); |
|
2510 |
w2 = cellWidget(row2, i); |
|
2511 |
if (w1 || w2) { |
|
2512 |
tmpWidgets.insert(i, w1); |
|
2513 |
widgets.remove(indexOf(row1, i)); |
|
2514 |
widgets.insert(indexOf(row1, i), w2); |
|
2515 |
widgets.remove(indexOf(row2, i)); |
|
2516 |
widgets.insert(indexOf(row2, i), tmpWidgets[ i ]); |
|
2517 |
} |
|
2518 |
} |
|
2519 |
contents.setAutoDelete(false); |
|
2520 |
widgets.setAutoDelete(true); |
|
2521 |
||
2522 |
updateRowWidgets(row1); |
|
2523 |
updateRowWidgets(row2); |
|
2524 |
if (curRow == row1) |
|
2525 |
curRow = row2; |
|
2526 |
else if (curRow == row2) |
|
2527 |
curRow = row1; |
|
2528 |
if (editRow == row1) |
|
2529 |
editRow = row2; |
|
2530 |
else if (editRow == row2) |
|
2531 |
editRow = row1; |
|
2532 |
} |
|
2533 |
||
2534 |
/*! |
|
2535 |
Sets the left margin to be \a m pixels wide. |
|
2536 |
||
2537 |
The verticalHeader(), which displays row labels, occupies this |
|
2538 |
margin. |
|
2539 |
||
2540 |
In an Arabic or Hebrew localization, the verticalHeader() will |
|
2541 |
appear on the right side of the table, and this call will set the |
|
2542 |
right margin. |
|
2543 |
||
2544 |
\sa leftMargin() setTopMargin() verticalHeader() |
|
2545 |
*/ |
|
2546 |
||
2547 |
void Q3Table::setLeftMargin(int m) |
|
2548 |
{ |
|
2549 |
if (QApplication::reverseLayout()) |
|
2550 |
setMargins(leftMargin(), topMargin(), m, bottomMargin()); |
|
2551 |
else |
|
2552 |
setMargins(m, topMargin(), rightMargin(), bottomMargin()); |
|
2553 |
updateGeometries(); |
|
2554 |
} |
|
2555 |
||
2556 |
/*! |
|
2557 |
Sets the top margin to be \a m pixels high. |
|
2558 |
||
2559 |
The horizontalHeader(), which displays column labels, occupies |
|
2560 |
this margin. |
|
2561 |
||
2562 |
\sa topMargin() setLeftMargin() |
|
2563 |
*/ |
|
2564 |
||
2565 |
void Q3Table::setTopMargin(int m) |
|
2566 |
{ |
|
2567 |
setMargins(leftMargin(), m, rightMargin(), bottomMargin()); |
|
2568 |
updateGeometries(); |
|
2569 |
} |
|
2570 |
||
2571 |
/*! |
|
2572 |
Swaps the data in \a col1 with \a col2. |
|
2573 |
||
2574 |
This function is used to swap the positions of two columns. It is |
|
2575 |
called when the user changes the order of columns (see |
|
2576 |
setColumnMovingEnabled(), and when columns are sorted. |
|
2577 |
||
2578 |
If you don't use \l{Q3TableItem}s and want your users to be able to |
|
2579 |
swap columns you will need to reimplement this function. (See the |
|
2580 |
notes on large tables.) |
|
2581 |
||
2582 |
If \a swapHeader is true, the columns' header contents is also |
|
2583 |
swapped. |
|
2584 |
||
2585 |
\sa swapCells() |
|
2586 |
*/ |
|
2587 |
||
2588 |
void Q3Table::swapColumns(int col1, int col2, bool swapHeader) |
|
2589 |
{ |
|
2590 |
if (swapHeader) |
|
2591 |
topHeader->swapSections(col1, col2, false); |
|
2592 |
||
2593 |
Q3PtrVector<Q3TableItem> tmpContents; |
|
2594 |
tmpContents.resize(numRows()); |
|
2595 |
Q3PtrVector<QWidget> tmpWidgets; |
|
2596 |
tmpWidgets.resize(numRows()); |
|
2597 |
int i; |
|
2598 |
||
2599 |
contents.setAutoDelete(false); |
|
2600 |
widgets.setAutoDelete(false); |
|
2601 |
for (i = 0; i < numRows(); ++i) { |
|
2602 |
Q3TableItem *i1, *i2; |
|
2603 |
i1 = item(i, col1); |
|
2604 |
i2 = item(i, col2); |
|
2605 |
if (i1 || i2) { |
|
2606 |
tmpContents.insert(i, i1); |
|
2607 |
contents.remove(indexOf(i, col1)); |
|
2608 |
contents.insert(indexOf(i, col1), i2); |
|
2609 |
contents.remove(indexOf(i, col2)); |
|
2610 |
contents.insert(indexOf(i, col2), tmpContents[ i ]); |
|
2611 |
if (contents[ indexOf(i, col1) ]) |
|
2612 |
contents[ indexOf(i, col1) ]->setCol(col1); |
|
2613 |
if (contents[ indexOf(i, col2) ]) |
|
2614 |
contents[ indexOf(i, col2) ]->setCol(col2); |
|
2615 |
} |
|
2616 |
||
2617 |
QWidget *w1, *w2; |
|
2618 |
w1 = cellWidget(i, col1); |
|
2619 |
w2 = cellWidget(i, col2); |
|
2620 |
if (w1 || w2) { |
|
2621 |
tmpWidgets.insert(i, w1); |
|
2622 |
widgets.remove(indexOf(i, col1)); |
|
2623 |
widgets.insert(indexOf(i, col1), w2); |
|
2624 |
widgets.remove(indexOf(i, col2)); |
|
2625 |
widgets.insert(indexOf(i, col2), tmpWidgets[ i ]); |
|
2626 |
} |
|
2627 |
} |
|
2628 |
contents.setAutoDelete(false); |
|
2629 |
widgets.setAutoDelete(true); |
|
2630 |
||
2631 |
columnWidthChanged(col1); |
|
2632 |
columnWidthChanged(col2); |
|
2633 |
if (curCol == col1) |
|
2634 |
curCol = col2; |
|
2635 |
else if (curCol == col2) |
|
2636 |
curCol = col1; |
|
2637 |
if (editCol == col1) |
|
2638 |
editCol = col2; |
|
2639 |
else if (editCol == col2) |
|
2640 |
editCol = col1; |
|
2641 |
} |
|
2642 |
||
2643 |
/*! |
|
2644 |
Swaps the contents of the cell at \a row1, \a col1 with the |
|
2645 |
contents of the cell at \a row2, \a col2. |
|
2646 |
||
2647 |
This function is also called when the table is sorted. |
|
2648 |
||
2649 |
If you don't use \l{Q3TableItem}s and want your users to be able to |
|
2650 |
swap cells, you will need to reimplement this function. (See the |
|
2651 |
notes on large tables.) |
|
2652 |
||
2653 |
\sa swapColumns() swapRows() |
|
2654 |
*/ |
|
2655 |
||
2656 |
void Q3Table::swapCells(int row1, int col1, int row2, int col2) |
|
2657 |
{ |
|
2658 |
contents.setAutoDelete(false); |
|
2659 |
widgets.setAutoDelete(false); |
|
2660 |
Q3TableItem *i1, *i2; |
|
2661 |
i1 = item(row1, col1); |
|
2662 |
i2 = item(row2, col2); |
|
2663 |
if (i1 || i2) { |
|
2664 |
Q3TableItem *tmp = i1; |
|
2665 |
contents.remove(indexOf(row1, col1)); |
|
2666 |
contents.insert(indexOf(row1, col1), i2); |
|
2667 |
contents.remove(indexOf(row2, col2)); |
|
2668 |
contents.insert(indexOf(row2, col2), tmp); |
|
2669 |
if (contents[ indexOf(row1, col1) ]) { |
|
2670 |
contents[ indexOf(row1, col1) ]->setRow(row1); |
|
2671 |
contents[ indexOf(row1, col1) ]->setCol(col1); |
|
2672 |
} |
|
2673 |
if (contents[ indexOf(row2, col2) ]) { |
|
2674 |
contents[ indexOf(row2, col2) ]->setRow(row2); |
|
2675 |
contents[ indexOf(row2, col2) ]->setCol(col2); |
|
2676 |
} |
|
2677 |
} |
|
2678 |
||
2679 |
QWidget *w1, *w2; |
|
2680 |
w1 = cellWidget(row1, col1); |
|
2681 |
w2 = cellWidget(row2, col2); |
|
2682 |
if (w1 || w2) { |
|
2683 |
QWidget *tmp = w1; |
|
2684 |
widgets.remove(indexOf(row1, col1)); |
|
2685 |
widgets.insert(indexOf(row1, col1), w2); |
|
2686 |
widgets.remove(indexOf(row2, col2)); |
|
2687 |
widgets.insert(indexOf(row2, col2), tmp); |
|
2688 |
} |
|
2689 |
||
2690 |
updateRowWidgets(row1); |
|
2691 |
updateRowWidgets(row2); |
|
2692 |
updateColWidgets(col1); |
|
2693 |
updateColWidgets(col2); |
|
2694 |
contents.setAutoDelete(false); |
|
2695 |
widgets.setAutoDelete(true); |
|
2696 |
} |
|
2697 |
||
2698 |
static bool is_child_of(QWidget *child, QWidget *parent) |
|
2699 |
{ |
|
2700 |
while (child) { |
|
2701 |
if (child == parent) |
|
2702 |
return true; |
|
2703 |
child = child->parentWidget(); |
|
2704 |
} |
|
2705 |
return false; |
|
2706 |
} |
|
2707 |
||
2708 |
/*! |
|
2709 |
Draws the table contents on the painter \a p. This function is |
|
2710 |
optimized so that it only draws the cells inside the \a cw pixels |
|
2711 |
wide and \a ch pixels high clipping rectangle at position \a cx, |
|
2712 |
\a cy. |
|
2713 |
||
2714 |
Additionally, drawContents() highlights the current cell. |
|
2715 |
*/ |
|
2716 |
||
2717 |
void Q3Table::drawContents(QPainter *p, int cx, int cy, int cw, int ch) |
|
2718 |
{ |
|
2719 |
int colfirst = columnAt(cx); |
|
2720 |
int collast = columnAt(cx + cw); |
|
2721 |
int rowfirst = rowAt(cy); |
|
2722 |
int rowlast = rowAt(cy + ch); |
|
2723 |
||
2724 |
if (rowfirst == -1 || colfirst == -1) { |
|
2725 |
paintEmptyArea(p, cx, cy, cw, ch); |
|
2726 |
return; |
|
2727 |
} |
|
2728 |
||
2729 |
drawActiveSelection = hasFocus() || viewport()->hasFocus() || d->inMenuMode |
|
2730 |
|| is_child_of(qApp->focusWidget(), viewport()) |
|
2731 |
|| !style()->styleHint(QStyle::SH_ItemView_ChangeHighlightOnFocus, 0, this); |
|
2732 |
if (rowlast == -1) |
|
2733 |
rowlast = numRows() - 1; |
|
2734 |
if (collast == -1) |
|
2735 |
collast = numCols() - 1; |
|
2736 |
||
2737 |
bool currentInSelection = false; |
|
2738 |
||
2739 |
Q3PtrListIterator<Q3TableSelection> it( selections ); |
|
2740 |
Q3TableSelection *s; |
|
2741 |
while ( ( s = it.current() ) != 0 ) { |
|
2742 |
++it; |
|
2743 |
if (s->isActive() && |
|
2744 |
curRow >= s->topRow() && |
|
2745 |
curRow <= s->bottomRow() && |
|
2746 |
curCol >= s->leftCol() && |
|
2747 |
curCol <= s->rightCol()) { |
|
2748 |
currentInSelection = s->topRow() != curRow || s->bottomRow() != curRow || s->leftCol() != curCol || s->rightCol() != curCol; |
|
2749 |
break; |
|
2750 |
} |
|
2751 |
} |
|
2752 |
||
2753 |
// Go through the rows |
|
2754 |
for (int r = rowfirst; r <= rowlast; ++r) { |
|
2755 |
// get row position and height |
|
2756 |
int rowp = rowPos(r); |
|
2757 |
int rowh = rowHeight(r); |
|
2758 |
||
2759 |
// Go through the columns in row r |
|
2760 |
// if we know from where to where, go through [colfirst, collast], |
|
2761 |
// else go through all of them |
|
2762 |
for (int c = colfirst; c <= collast; ++c) { |
|
2763 |
// get position and width of column c |
|
2764 |
int colp, colw; |
|
2765 |
colp = columnPos(c); |
|
2766 |
colw = columnWidth(c); |
|
2767 |
int oldrp = rowp; |
|
2768 |
int oldrh = rowh; |
|
2769 |
||
2770 |
Q3TableItem *itm = item(r, c); |
|
2771 |
if (itm && |
|
2772 |
(itm->colSpan() > 1 || itm->rowSpan() > 1)) { |
|
2773 |
bool goon = (r == itm->row() && c == itm->col()) |
|
2774 |
|| (r == rowfirst && c == itm->col()) |
|
2775 |
|| (r == itm->row() && c == colfirst); |
|
2776 |
if (!goon) |
|
2777 |
continue; |
|
2778 |
rowp = rowPos(itm->row()); |
|
2779 |
rowh = 0; |
|
2780 |
int i; |
|
2781 |
for (i = 0; i < itm->rowSpan(); ++i) |
|
2782 |
rowh += rowHeight(i + itm->row()); |
|
2783 |
colp = columnPos(itm->col()); |
|
2784 |
colw = 0; |
|
2785 |
for (i = 0; i < itm->colSpan(); ++i) |
|
2786 |
colw += columnWidth(i + itm->col()); |
|
2787 |
} |
|
2788 |
||
2789 |
// Translate painter and draw the cell |
|
2790 |
p->translate(colp, rowp); |
|
2791 |
bool selected = isSelected(r, c); |
|
2792 |
if (focusStl != FollowStyle && selected && !currentInSelection && |
|
2793 |
r == curRow && c == curCol ) |
|
2794 |
selected = false; |
|
2795 |
paintCell(p, r, c, QRect(colp, rowp, colw, rowh), selected); |
|
2796 |
p->translate(-colp, -rowp); |
|
2797 |
||
2798 |
rowp = oldrp; |
|
2799 |
rowh = oldrh; |
|
2800 |
||
2801 |
QWidget *w = cellWidget(r, c); |
|
2802 |
QRect cg(cellGeometry(r, c)); |
|
2803 |
if (w && w->geometry() != QRect(contentsToViewport(cg.topLeft()), cg.size() - QSize(1, 1))) { |
|
2804 |
moveChild(w, colp, rowp); |
|
2805 |
w->resize(cg.size() - QSize(1, 1)); |
|
2806 |
} |
|
2807 |
} |
|
2808 |
} |
|
2809 |
d->lastVisCol = collast; |
|
2810 |
d->lastVisRow = rowlast; |
|
2811 |
||
2812 |
// draw indication of current cell |
|
2813 |
QRect focusRect = cellGeometry(curRow, curCol); |
|
2814 |
p->translate(focusRect.x(), focusRect.y()); |
|
2815 |
paintFocus(p, focusRect); |
|
2816 |
p->translate(-focusRect.x(), -focusRect.y()); |
|
2817 |
||
2818 |
// Paint empty rects |
|
2819 |
paintEmptyArea(p, cx, cy, cw, ch); |
|
2820 |
||
2821 |
drawActiveSelection = true; |
|
2822 |
} |
|
2823 |
||
2824 |
/*! |
|
2825 |
\reimp |
|
2826 |
||
2827 |
(Implemented to get rid of a compiler warning.) |
|
2828 |
*/ |
|
2829 |
||
2830 |
void Q3Table::drawContents(QPainter *) |
|
2831 |
{ |
|
2832 |
} |
|
2833 |
||
2834 |
/*! |
|
2835 |
Returns the geometry of cell \a row, \a col in the cell's |
|
2836 |
coordinate system. This is a convenience function useful in |
|
2837 |
paintCell(). It is equivalent to QRect(QPoint(0,0), cellGeometry( |
|
2838 |
row, col).size()); |
|
2839 |
||
2840 |
\sa cellGeometry() |
|
2841 |
*/ |
|
2842 |
||
2843 |
QRect Q3Table::cellRect(int row, int col) const |
|
2844 |
{ |
|
2845 |
return QRect(QPoint(0,0), cellGeometry(row, col).size()); |
|
2846 |
} |
|
2847 |
||
2848 |
/*! |
|
2849 |
\overload |
|
2850 |
||
2851 |
Use the other paintCell() function. This function is only included |
|
2852 |
for backwards compatibility. |
|
2853 |
*/ |
|
2854 |
||
2855 |
void Q3Table::paintCell(QPainter* p, int row, int col, |
|
2856 |
const QRect &cr, bool selected) |
|
2857 |
{ |
|
2858 |
if (cr.width() == 0 || cr.height() == 0) |
|
2859 |
return; |
|
2860 |
#if defined(Q_WS_WIN) |
|
2861 |
const QColorGroup &cg = (!drawActiveSelection && style()->styleHint(QStyle::SH_ItemView_ChangeHighlightOnFocus) ? palette().inactive() : colorGroup()); |
|
2862 |
#else |
|
2863 |
const QColorGroup &cg = colorGroup(); |
|
2864 |
#endif |
|
2865 |
||
2866 |
Q3TableItem *itm = item(row, col); |
|
2867 |
QColorGroup cg2(cg); |
|
2868 |
if (itm && !itm->isEnabled()) |
|
2869 |
cg2 = palette().disabled(); |
|
2870 |
||
2871 |
paintCell(p, row, col, cr, selected, cg2); |
|
2872 |
} |
|
2873 |
||
2874 |
/*! |
|
2875 |
Paints the cell at \a row, \a col on the painter \a p. The painter |
|
2876 |
has already been translated to the cell's origin. \a cr describes |
|
2877 |
the cell coordinates in the content coordinate system. |
|
2878 |
||
2879 |
If \a selected is true the cell is highlighted. |
|
2880 |
||
2881 |
\a cg is the colorgroup which should be used to draw the cell |
|
2882 |
content. |
|
2883 |
||
2884 |
If you want to draw custom cell content, for example right-aligned |
|
2885 |
text, you must either reimplement paintCell(), or subclass |
|
2886 |
Q3TableItem and reimplement Q3TableItem::paint() to do the custom |
|
2887 |
drawing. |
|
2888 |
||
2889 |
If you're using a Q3TableItem subclass, for example, to store a |
|
2890 |
data structure, then reimplementing Q3TableItem::paint() may be the |
|
2891 |
best approach. For data you want to draw immediately, e.g. data |
|
2892 |
retrieved from a database, it is probably best to reimplement |
|
2893 |
paintCell(). Note that if you reimplement paintCell(), i.e. don't |
|
2894 |
use \l{Q3TableItem}s, you must reimplement other functions: see the |
|
2895 |
notes on large tables. |
|
2896 |
||
2897 |
Note that the painter is not clipped by default in order to get |
|
2898 |
maximum efficiency. If you want clipping, use code like this: |
|
2899 |
||
2900 |
\snippet doc/src/snippets/code/src_qt3support_itemviews_q3table.cpp 4 |
|
2901 |
*/ |
|
2902 |
||
2903 |
void Q3Table::paintCell(QPainter *p, int row, int col, |
|
2904 |
const QRect &cr, bool selected, const QColorGroup &cg) |
|
2905 |
{ |
|
2906 |
if (focusStl == SpreadSheet && selected && |
|
2907 |
row == curRow && |
|
2908 |
col == curCol && (hasFocus() || viewport()->hasFocus())) |
|
2909 |
selected = false; |
|
2910 |
||
2911 |
QPalette pal = cg; |
|
2912 |
int w = cr.width(); |
|
2913 |
int h = cr.height(); |
|
2914 |
int x2 = w - 1; |
|
2915 |
int y2 = h - 1; |
|
2916 |
||
2917 |
||
2918 |
Q3TableItem *itm = item(row, col); |
|
2919 |
if (itm) { |
|
2920 |
p->save(); |
|
2921 |
itm->paint(p, pal, cr, selected); |
|
2922 |
p->restore(); |
|
2923 |
} else { |
|
2924 |
p->fillRect(0, 0, w, h, selected ? pal.brush(QPalette::Highlight) : pal.brush(QPalette::Base)); |
|
2925 |
} |
|
2926 |
||
2927 |
if (sGrid) { |
|
2928 |
// Draw our lines |
|
2929 |
QPen pen(p->pen()); |
|
2930 |
int gridColor = style()->styleHint(QStyle::SH_Table_GridLineColor, 0, this); |
|
2931 |
if (gridColor != -1) { |
|
2932 |
if (palette() != pal) |
|
2933 |
p->setPen(pal.mid().color()); |
|
2934 |
else |
|
2935 |
p->setPen((QRgb)gridColor); |
|
2936 |
} else { |
|
2937 |
p->setPen(pal.mid().color()); |
|
2938 |
} |
|
2939 |
p->drawLine(x2, 0, x2, y2); |
|
2940 |
p->drawLine(0, y2, x2, y2); |
|
2941 |
p->setPen(pen); |
|
2942 |
} |
|
2943 |
} |
|
2944 |
||
2945 |
/*! |
|
2946 |
Draws the focus rectangle of the current cell (see currentRow(), |
|
2947 |
currentColumn()). |
|
2948 |
||
2949 |
The painter \a p is already translated to the cell's origin, while |
|
2950 |
\a cr specifies the cell's geometry in content coordinates. |
|
2951 |
*/ |
|
2952 |
||
2953 |
void Q3Table::paintFocus(QPainter *p, const QRect &cr) |
|
2954 |
{ |
|
2955 |
if (!hasFocus() && !viewport()->hasFocus()) |
|
2956 |
return; |
|
2957 |
QRect focusRect(0, 0, cr.width(), cr.height()); |
|
2958 |
if (focusStyle() == SpreadSheet) { |
|
2959 |
p->setPen(QPen(Qt::black, 1)); |
|
2960 |
p->setBrush(Qt::NoBrush); |
|
2961 |
p->drawRect(focusRect.x(), focusRect.y(), focusRect.width() - 1, focusRect.height() - 1); |
|
2962 |
p->drawRect(focusRect.x() - 1, focusRect.y() - 1, focusRect.width() + 1, focusRect.height() + 1); |
|
2963 |
} else { |
|
2964 |
QStyleOptionFocusRect opt; |
|
2965 |
opt.init(this); |
|
2966 |
opt.rect = focusRect; |
|
2967 |
opt.palette = palette(); |
|
2968 |
opt.state |= QStyle::State_KeyboardFocusChange; |
|
2969 |
if (isSelected(curRow, curCol, false)) { |
|
2970 |
opt.state |= QStyle::State_FocusAtBorder; |
|
2971 |
opt.backgroundColor = palette().highlight().color(); |
|
2972 |
} else { |
|
2973 |
opt.state |= QStyle::State_None; |
|
2974 |
opt.backgroundColor = palette().base().color(); |
|
2975 |
} |
|
2976 |
style()->drawPrimitive(QStyle::PE_FrameFocusRect, &opt, p, this); |
|
2977 |
} |
|
2978 |
} |
|
2979 |
||
2980 |
/*! |
|
2981 |
This function fills the \a cw pixels wide and \a ch pixels high |
|
2982 |
rectangle starting at position \a cx, \a cy with the background |
|
2983 |
color using the painter \a p. |
|
2984 |
||
2985 |
paintEmptyArea() is invoked by drawContents() to erase or fill |
|
2986 |
unused areas. |
|
2987 |
*/ |
|
2988 |
||
2989 |
void Q3Table::paintEmptyArea(QPainter *p, int cx, int cy, int cw, int ch) |
|
2990 |
{ |
|
2991 |
// Regions work with shorts, so avoid an overflow and adjust the |
|
2992 |
// table size to the visible size |
|
2993 |
QSize ts(tableSize()); |
|
2994 |
ts.setWidth(QMIN(ts.width(), visibleWidth())); |
|
2995 |
ts.setHeight(QMIN(ts.height(), visibleHeight())); |
|
2996 |
||
2997 |
// Region of the rect we should draw, calculated in viewport |
|
2998 |
// coordinates, as a region can't handle bigger coordinates |
|
2999 |
contentsToViewport2(cx, cy, cx, cy); |
|
3000 |
QRegion reg(QRect(cx, cy, cw, ch)); |
|
3001 |
||
3002 |
// Subtract the table from it |
|
3003 |
reg = reg.subtracted(QRect(QPoint(0, 0), ts)); |
|
3004 |
||
3005 |
// And draw the rectangles (transformed inc contents coordinates as needed) |
|
3006 |
Q3MemArray<QRect> r = reg.rects(); |
|
3007 |
for (int i = 0; i < (int)r.count(); ++i) |
|
3008 |
p->fillRect(QRect(viewportToContents2(r[i].topLeft()),r[i].size()), viewport()->backgroundBrush()); |
|
3009 |
} |
|
3010 |
||
3011 |
/*! |
|
3012 |
Returns the Q3TableItem representing the contents of the cell at \a |
|
3013 |
row, \a col. |
|
3014 |
||
3015 |
If \a row or \a col are out of range or no content has been set |
|
3016 |
for this cell, item() returns 0. |
|
3017 |
||
3018 |
If you don't use \l{Q3TableItem}s you may need to reimplement this |
|
3019 |
function: see the notes on large tables. |
|
3020 |
||
3021 |
\sa setItem() |
|
3022 |
*/ |
|
3023 |
||
3024 |
Q3TableItem *Q3Table::item(int row, int col) const |
|
3025 |
{ |
|
3026 |
if (row < 0 || col < 0 || row > numRows() - 1 || |
|
3027 |
col > numCols() - 1 || row * col >= (int)contents.size()) |
|
3028 |
return 0; |
|
3029 |
||
3030 |
return contents[ indexOf(row, col) ]; // contents array lookup |
|
3031 |
} |
|
3032 |
||
3033 |
/*! |
|
3034 |
Inserts the table item \a item into the table at row \a row, |
|
3035 |
column \a col, and repaints the cell. If a table item already |
|
3036 |
exists in this cell it is deleted and replaced with \a item. The |
|
3037 |
table takes ownership of the table item. |
|
3038 |
||
3039 |
If you don't use \l{Q3TableItem}s you may need to reimplement this |
|
3040 |
function: see the notes on large tables. |
|
3041 |
||
3042 |
\sa item() takeItem() |
|
3043 |
*/ |
|
3044 |
||
3045 |
void Q3Table::setItem(int row, int col, Q3TableItem *item) |
|
3046 |
{ |
|
3047 |
if (!item) |
|
3048 |
return; |
|
3049 |
||
3050 |
if ((int)contents.size() != numRows() * numCols()) |
|
3051 |
resizeData(numRows() * numCols()); |
|
3052 |
||
3053 |
int orow = item->row(); |
|
3054 |
int ocol = item->col(); |
|
3055 |
clearCell(row, col); |
|
3056 |
||
3057 |
contents.insert(indexOf(row, col), item); |
|
3058 |
item->setRow(row); |
|
3059 |
item->setCol(col); |
|
3060 |
item->t = this; |
|
3061 |
updateCell(row, col); |
|
3062 |
if (qt_update_cell_widget) |
|
3063 |
item->updateEditor(orow, ocol); |
|
3064 |
||
3065 |
if (row == curRow && col == curCol && item->editType() == Q3TableItem::WhenCurrent) { |
|
3066 |
if (beginEdit(row, col, false)) |
|
3067 |
setEditMode(Editing, row, col); |
|
3068 |
} |
|
3069 |
} |
|
3070 |
||
3071 |
/*! |
|
3072 |
Removes the Q3TableItem at \a row, \a col. |
|
3073 |
||
3074 |
If you don't use \l{Q3TableItem}s you may need to reimplement this |
|
3075 |
function: see the notes on large tables. |
|
3076 |
*/ |
|
3077 |
||
3078 |
void Q3Table::clearCell(int row, int col) |
|
3079 |
{ |
|
3080 |
if ((int)contents.size() != numRows() * numCols()) |
|
3081 |
resizeData(numRows() * numCols()); |
|
3082 |
clearCellWidget(row, col); |
|
3083 |
contents.setAutoDelete(true); |
|
3084 |
contents.remove(indexOf(row, col)); |
|
3085 |
contents.setAutoDelete(false); |
|
3086 |
} |
|
3087 |
||
3088 |
/*! |
|
3089 |
Sets the text in the cell at \a row, \a col to \a text. |
|
3090 |
||
3091 |
If the cell does not contain a table item a Q3TableItem is created |
|
3092 |
with an \link Q3TableItem::EditType EditType\endlink of \c OnTyping, |
|
3093 |
otherwise the existing table item's text (if any) is replaced with |
|
3094 |
\a text. |
|
3095 |
||
3096 |
\sa text() setPixmap() setItem() Q3TableItem::setText() |
|
3097 |
*/ |
|
3098 |
||
3099 |
void Q3Table::setText(int row, int col, const QString &text) |
|
3100 |
{ |
|
3101 |
Q3TableItem *itm = item(row, col); |
|
3102 |
if (itm) { |
|
3103 |
itm->setText(text); |
|
3104 |
itm->updateEditor(row, col); |
|
3105 |
updateCell(row, col); |
|
3106 |
} else { |
|
3107 |
Q3TableItem *i = new Q3TableItem(this, Q3TableItem::OnTyping, |
|
3108 |
text, QPixmap()); |
|
3109 |
setItem(row, col, i); |
|
3110 |
} |
|
3111 |
} |
|
3112 |
||
3113 |
/*! |
|
3114 |
Sets the pixmap in the cell at \a row, \a col to \a pix. |
|
3115 |
||
3116 |
If the cell does not contain a table item a Q3TableItem is created |
|
3117 |
with an \link Q3TableItem::EditType EditType\endlink of \c OnTyping, |
|
3118 |
otherwise the existing table item's pixmap (if any) is replaced |
|
3119 |
with \a pix. |
|
3120 |
||
3121 |
Note that \l{Q3ComboTableItem}s and \l{Q3CheckTableItem}s don't show |
|
3122 |
pixmaps. |
|
3123 |
||
3124 |
\sa pixmap() setText() setItem() Q3TableItem::setPixmap() |
|
3125 |
*/ |
|
3126 |
||
3127 |
void Q3Table::setPixmap(int row, int col, const QPixmap &pix) |
|
3128 |
{ |
|
3129 |
Q3TableItem *itm = item(row, col); |
|
3130 |
if (itm) { |
|
3131 |
itm->setPixmap(pix); |
|
3132 |
updateCell(row, col); |
|
3133 |
} else { |
|
3134 |
Q3TableItem *i = new Q3TableItem(this, Q3TableItem::OnTyping, |
|
3135 |
QString(), pix); |
|
3136 |
setItem(row, col, i); |
|
3137 |
} |
|
3138 |
} |
|
3139 |
||
3140 |
/*! |
|
3141 |
Returns the text in the cell at \a row, \a col, or an empty string |
|
3142 |
if the relevant item does not exist or has no text. |
|
3143 |
||
3144 |
\sa setText() setPixmap() |
|
3145 |
*/ |
|
3146 |
||
3147 |
QString Q3Table::text(int row, int col) const |
|
3148 |
{ |
|
3149 |
Q3TableItem *itm = item(row, col); |
|
3150 |
if (itm) |
|
3151 |
return itm->text(); |
|
3152 |
return QString(); |
|
3153 |
} |
|
3154 |
||
3155 |
/*! |
|
3156 |
Returns the pixmap set for the cell at \a row, \a col, or a |
|
3157 |
null-pixmap if the cell contains no pixmap. |
|
3158 |
||
3159 |
\sa setPixmap() |
|
3160 |
*/ |
|
3161 |
||
3162 |
QPixmap Q3Table::pixmap(int row, int col) const |
|
3163 |
{ |
|
3164 |
Q3TableItem *itm = item(row, col); |
|
3165 |
if (itm) |
|
3166 |
return itm->pixmap(); |
|
3167 |
return QPixmap(); |
|
3168 |
} |
|
3169 |
||
3170 |
/*! |
|
3171 |
Moves the focus to the cell at \a row, \a col. |
|
3172 |
||
3173 |
\sa currentRow() currentColumn() |
|
3174 |
*/ |
|
3175 |
||
3176 |
void Q3Table::setCurrentCell(int row, int col) |
|
3177 |
{ |
|
3178 |
setCurrentCell(row, col, true, true); |
|
3179 |
} |
|
3180 |
||
3181 |
// need to use a define, as leftMargin() is protected |
|
3182 |
#define VERTICALMARGIN \ |
|
3183 |
(QApplication::reverseLayout() ? \ |
|
3184 |
rightMargin() \ |
|
3185 |
: \ |
|
3186 |
leftMargin() \ |
|
3187 |
) |
|
3188 |
||
3189 |
/*! |
|
3190 |
\reimp |
|
3191 |
*/ |
|
3192 |
QVariant Q3Table::inputMethodQuery(Qt::InputMethodQuery query) const |
|
3193 |
{ |
|
3194 |
if (query == Qt::ImMicroFocus) |
|
3195 |
return QRect(columnPos(curCol) + leftMargin() - contentsX(), rowPos(curRow) + topMargin() - contentsY(), |
|
3196 |
columnWidth(curCol), rowHeight(curRow)); |
|
3197 |
return QWidget::inputMethodQuery(query); |
|
3198 |
||
3199 |
} |
|
3200 |
||
3201 |
/*! \internal */ |
|
3202 |
||
3203 |
void Q3Table::setCurrentCell(int row, int col, bool updateSelections, bool ensureVisible) |
|
3204 |
{ |
|
3205 |
Q3TableItem *oldItem = item(curRow, curCol); |
|
3206 |
||
3207 |
if (row > numRows() - 1) |
|
3208 |
row = numRows() - 1; |
|
3209 |
if (col > numCols() - 1) |
|
3210 |
col = numCols() - 1; |
|
3211 |
||
3212 |
if (curRow == row && curCol == col) |
|
3213 |
return; |
|
3214 |
||
3215 |
||
3216 |
Q3TableItem *itm = oldItem; |
|
3217 |
if (itm && itm->editType() != Q3TableItem::Always && itm->editType() != Q3TableItem::Never) |
|
3218 |
endEdit(curRow, curCol, true, false); |
|
3219 |
int oldRow = curRow; |
|
3220 |
int oldCol = curCol; |
|
3221 |
curRow = row; |
|
3222 |
curCol = col; |
|
3223 |
repaintCell(oldRow, oldCol); |
|
3224 |
repaintCell(curRow, curCol); |
|
3225 |
if (ensureVisible) |
|
3226 |
ensureCellVisible(curRow, curCol); |
|
3227 |
emit currentChanged(row, col); |
|
3228 |
||
3229 |
if (oldCol != curCol) { |
|
3230 |
if (!isColumnSelected(oldCol)) |
|
3231 |
topHeader->setSectionState(oldCol, Q3TableHeader::Normal); |
|
3232 |
else if (isRowSelection(selectionMode())) |
|
3233 |
topHeader->setSectionState(oldCol, Q3TableHeader::Selected); |
|
3234 |
topHeader->setSectionState(curCol, isColumnSelected(curCol, true) ? |
|
3235 |
Q3TableHeader::Selected : Q3TableHeader::Bold); |
|
3236 |
} |
|
3237 |
||
3238 |
if (oldRow != curRow) { |
|
3239 |
if (!isRowSelected(oldRow)) |
|
3240 |
leftHeader->setSectionState(oldRow, Q3TableHeader::Normal); |
|
3241 |
leftHeader->setSectionState(curRow, isRowSelected(curRow, true) ? |
|
3242 |
Q3TableHeader::Selected : Q3TableHeader::Bold); |
|
3243 |
} |
|
3244 |
||
3245 |
itm = item(curRow, curCol); |
|
3246 |
||
3247 |
||
3248 |
if (cellWidget(oldRow, oldCol) && |
|
3249 |
cellWidget(oldRow, oldCol)->hasFocus()) |
|
3250 |
viewport()->setFocus(); |
|
3251 |
||
3252 |
if (itm && itm->editType() == Q3TableItem::WhenCurrent) { |
|
3253 |
if (beginEdit(curRow, curCol, false)) |
|
3254 |
setEditMode(Editing, row, col); |
|
3255 |
} else if (itm && itm->editType() == Q3TableItem::Always) { |
|
3256 |
if (cellWidget(itm->row(), itm->col())) |
|
3257 |
cellWidget(itm->row(), itm->col())->setFocus(); |
|
3258 |
} |
|
3259 |
||
3260 |
if (updateSelections && isRowSelection(selectionMode()) && |
|
3261 |
!isSelected(curRow, curCol, false)) { |
|
3262 |
if (selectionMode() == Q3Table::SingleRow) |
|
3263 |
clearSelection(); |
|
3264 |
currentSel = new Q3TableSelection(); |
|
3265 |
selections.append(currentSel); |
|
3266 |
currentSel->init(curRow, 0); |
|
3267 |
currentSel->expandTo(curRow, numCols() - 1); |
|
3268 |
repaintSelections(0, currentSel); |
|
3269 |
} |
|
3270 |
} |
|
3271 |
||
3272 |
/*! |
|
3273 |
Scrolls the table until the cell at \a row, \a col becomes |
|
3274 |
visible. |
|
3275 |
*/ |
|
3276 |
||
3277 |
void Q3Table::ensureCellVisible(int row, int col) |
|
3278 |
{ |
|
3279 |
if (!updatesEnabled() || !viewport()->updatesEnabled()) |
|
3280 |
return; |
|
3281 |
int cw = columnWidth(col); |
|
3282 |
int rh = rowHeight(row); |
|
3283 |
if (cw < visibleWidth()) |
|
3284 |
ensureVisible(columnPos(col) + cw / 2, rowPos(row) + rh / 2, cw / 2, rh / 2); |
|
3285 |
else |
|
3286 |
ensureVisible(columnPos(col), rowPos(row) + rh / 2, 0, rh / 2); |
|
3287 |
} |
|
3288 |
||
3289 |
/*! |
|
3290 |
Returns true if the cell at \a row, \a col is selected; otherwise |
|
3291 |
returns false. |
|
3292 |
||
3293 |
\sa isRowSelected() isColumnSelected() |
|
3294 |
*/ |
|
3295 |
||
3296 |
bool Q3Table::isSelected(int row, int col) const |
|
3297 |
{ |
|
3298 |
return isSelected(row, col, true); |
|
3299 |
} |
|
3300 |
||
3301 |
/*! \internal */ |
|
3302 |
||
3303 |
bool Q3Table::isSelected(int row, int col, bool includeCurrent) const |
|
3304 |
{ |
|
3305 |
Q3PtrListIterator<Q3TableSelection> it(selections); |
|
3306 |
Q3TableSelection *s; |
|
3307 |
while ((s = it.current()) != 0) { |
|
3308 |
++it; |
|
3309 |
if (s->isActive() && |
|
3310 |
row >= s->topRow() && |
|
3311 |
row <= s->bottomRow() && |
|
3312 |
col >= s->leftCol() && |
|
3313 |
col <= s->rightCol()) |
|
3314 |
return true; |
|
3315 |
if (includeCurrent && row == currentRow() && col == currentColumn()) |
|
3316 |
return true; |
|
3317 |
} |
|
3318 |
return false; |
|
3319 |
} |
|
3320 |
||
3321 |
/*! |
|
3322 |
Returns true if row \a row is selected; otherwise returns false. |
|
3323 |
||
3324 |
If \a full is false (the default), 'row is selected' means that at |
|
3325 |
least one cell in the row is selected. If \a full is true, then 'row |
|
3326 |
is selected' means every cell in the row is selected. |
|
3327 |
||
3328 |
\sa isColumnSelected() isSelected() |
|
3329 |
*/ |
|
3330 |
||
3331 |
bool Q3Table::isRowSelected(int row, bool full) const |
|
3332 |
{ |
|
3333 |
if (!full) { |
|
3334 |
Q3PtrListIterator<Q3TableSelection> it(selections); |
|
3335 |
Q3TableSelection *s; |
|
3336 |
while ((s = it.current()) != 0) { |
|
3337 |
++it; |
|
3338 |
if (s->isActive() && |
|
3339 |
row >= s->topRow() && |
|
3340 |
row <= s->bottomRow()) |
|
3341 |
return true; |
|
3342 |
if (row == currentRow()) |
|
3343 |
return true; |
|
3344 |
} |
|
3345 |
} else { |
|
3346 |
Q3PtrListIterator<Q3TableSelection> it(selections); |
|
3347 |
Q3TableSelection *s; |
|
3348 |
while ((s = it.current()) != 0) { |
|
3349 |
++it; |
|
3350 |
if (s->isActive() && |
|
3351 |
row >= s->topRow() && |
|
3352 |
row <= s->bottomRow() && |
|
3353 |
s->leftCol() == 0 && |
|
3354 |
s->rightCol() == numCols() - 1) |
|
3355 |
return true; |
|
3356 |
} |
|
3357 |
} |
|
3358 |
return false; |
|
3359 |
} |
|
3360 |
||
3361 |
/*! |
|
3362 |
Returns true if column \a col is selected; otherwise returns false. |
|
3363 |
||
3364 |
If \a full is false (the default), 'column is selected' means that |
|
3365 |
at least one cell in the column is selected. If \a full is true, |
|
3366 |
then 'column is selected' means every cell in the column is |
|
3367 |
selected. |
|
3368 |
||
3369 |
\sa isRowSelected() isSelected() |
|
3370 |
*/ |
|
3371 |
||
3372 |
bool Q3Table::isColumnSelected(int col, bool full) const |
|
3373 |
{ |
|
3374 |
if (!full) { |
|
3375 |
Q3PtrListIterator<Q3TableSelection> it(selections); |
|
3376 |
Q3TableSelection *s; |
|
3377 |
while ((s = it.current()) != 0) { |
|
3378 |
++it; |
|
3379 |
if (s->isActive() && |
|
3380 |
col >= s->leftCol() && |
|
3381 |
col <= s->rightCol()) |
|
3382 |
return true; |
|
3383 |
if (col == currentColumn()) |
|
3384 |
return true; |
|
3385 |
} |
|
3386 |
} else { |
|
3387 |
Q3PtrListIterator<Q3TableSelection> it(selections); |
|
3388 |
Q3TableSelection *s; |
|
3389 |
while ((s = it.current()) != 0) { |
|
3390 |
++it; |
|
3391 |
if (s->isActive() && |
|
3392 |
col >= s->leftCol() && |
|
3393 |
col <= s->rightCol() && |
|
3394 |
s->topRow() == 0 && |
|
3395 |
s->bottomRow() == numRows() - 1) |
|
3396 |
return true; |
|
3397 |
} |
|
3398 |
} |
|
3399 |
return false; |
|
3400 |
} |
|
3401 |
||
3402 |
/*! |
|
3403 |
\property Q3Table::numSelections |
|
3404 |
\brief The number of selections. |
|
3405 |
||
3406 |
\sa currentSelection() |
|
3407 |
*/ |
|
3408 |
||
3409 |
int Q3Table::numSelections() const |
|
3410 |
{ |
|
3411 |
return selections.count(); |
|
3412 |
} |
|
3413 |
||
3414 |
/*! |
|
3415 |
Returns selection number \a num, or an inactive Q3TableSelection if \a |
|
3416 |
num is out of range (see Q3TableSelection::isActive()). |
|
3417 |
*/ |
|
3418 |
||
3419 |
Q3TableSelection Q3Table::selection(int num) const |
|
3420 |
{ |
|
3421 |
if (num < 0 || num >= (int)selections.count()) |
|
3422 |
return Q3TableSelection(); |
|
3423 |
||
3424 |
Q3TableSelection *s = ((Q3Table*)this)->selections.at(num); |
|
3425 |
return *s; |
|
3426 |
} |
|
3427 |
||
3428 |
/*! |
|
3429 |
Adds a selection described by \a s to the table and returns its |
|
3430 |
number or -1 if the selection is invalid. |
|
3431 |
||
3432 |
Remember to call Q3TableSelection::init() and |
|
3433 |
Q3TableSelection::expandTo() to make the selection valid (see also |
|
3434 |
Q3TableSelection::isActive(), or use the |
|
3435 |
Q3TableSelection(int,int,int,int) constructor). |
|
3436 |
||
3437 |
\sa numSelections() removeSelection() clearSelection() |
|
3438 |
*/ |
|
3439 |
||
3440 |
int Q3Table::addSelection(const Q3TableSelection &s) |
|
3441 |
{ |
|
3442 |
if (!s.isActive()) |
|
3443 |
return -1; |
|
3444 |
||
3445 |
const int maxr = numRows()-1; |
|
3446 |
const int maxc = numCols()-1; |
|
3447 |
currentSel = new Q3TableSelection(QMIN(s.anchorRow(), maxr), QMIN(s.anchorCol(), maxc), |
|
3448 |
QMIN(s.bottomRow(), maxr), QMIN(s.rightCol(), maxc)); |
|
3449 |
||
3450 |
selections.append(currentSel); |
|
3451 |
||
3452 |
repaintSelections(0, currentSel, true, true); |
|
3453 |
||
3454 |
emit selectionChanged(); |
|
3455 |
||
3456 |
return selections.count() - 1; |
|
3457 |
} |
|
3458 |
||
3459 |
/*! |
|
3460 |
If the table has a selection, \a s, this selection is removed from |
|
3461 |
the table. |
|
3462 |
||
3463 |
\sa addSelection() numSelections() |
|
3464 |
*/ |
|
3465 |
||
3466 |
void Q3Table::removeSelection(const Q3TableSelection &s) |
|
3467 |
{ |
|
3468 |
selections.setAutoDelete(false); |
|
3469 |
for (Q3TableSelection *sel = selections.first(); sel; sel = selections.next()) { |
|
3470 |
if (s == *sel) { |
|
3471 |
selections.removeRef(sel); |
|
3472 |
repaintSelections(sel, 0, true, true); |
|
3473 |
if (sel == currentSel) |
|
3474 |
currentSel = 0; |
|
3475 |
delete sel; |
|
3476 |
} |
|
3477 |
} |
|
3478 |
selections.setAutoDelete(true); |
|
3479 |
emit selectionChanged(); |
|
3480 |
} |
|
3481 |
||
3482 |
/*! |
|
3483 |
\overload |
|
3484 |
||
3485 |
Removes selection number \a num from the table. |
|
3486 |
||
3487 |
\sa numSelections() addSelection() clearSelection() |
|
3488 |
*/ |
|
3489 |
||
3490 |
void Q3Table::removeSelection(int num) |
|
3491 |
{ |
|
3492 |
if (num < 0 || num >= (int)selections.count()) |
|
3493 |
return; |
|
3494 |
||
3495 |
Q3TableSelection *s = selections.at(num); |
|
3496 |
if (s == currentSel) |
|
3497 |
currentSel = 0; |
|
3498 |
selections.removeRef(s); |
|
3499 |
repaintContents(false); |
|
3500 |
} |
|
3501 |
||
3502 |
/*! |
|
3503 |
Returns the number of the current selection or -1 if there is no |
|
3504 |
current selection. |
|
3505 |
||
3506 |
\sa numSelections() |
|
3507 |
*/ |
|
3508 |
||
3509 |
int Q3Table::currentSelection() const |
|
3510 |
{ |
|
3511 |
if (!currentSel) |
|
3512 |
return -1; |
|
3513 |
return ((Q3Table*)this)->selections.findRef(currentSel); |
|
3514 |
} |
|
3515 |
||
3516 |
/*! Selects the range starting at \a start_row and \a start_col and |
|
3517 |
ending at \a end_row and \a end_col. |
|
3518 |
||
3519 |
\sa Q3TableSelection |
|
3520 |
*/ |
|
3521 |
||
3522 |
void Q3Table::selectCells(int start_row, int start_col, int end_row, int end_col) |
|
3523 |
{ |
|
3524 |
const int maxr = numRows()-1; |
|
3525 |
const int maxc = numCols()-1; |
|
3526 |
||
3527 |
start_row = QMIN(maxr, QMAX(0, start_row)); |
|
3528 |
start_col = QMIN(maxc, QMAX(0, start_col)); |
|
3529 |
end_row = QMIN(maxr, end_row); |
|
3530 |
end_col = QMIN(maxc, end_col); |
|
3531 |
Q3TableSelection sel(start_row, start_col, end_row, end_col); |
|
3532 |
addSelection(sel); |
|
3533 |
} |
|
3534 |
||
3535 |
/*! Selects the row \a row. |
|
3536 |
||
3537 |
\sa Q3TableSelection |
|
3538 |
*/ |
|
3539 |
||
3540 |
void Q3Table::selectRow(int row) |
|
3541 |
{ |
|
3542 |
row = QMIN(numRows()-1, row); |
|
3543 |
if (row < 0) |
|
3544 |
return; |
|
3545 |
if (selectionMode() == SingleRow) { |
|
3546 |
setCurrentCell(row, currentColumn()); |
|
3547 |
} else { |
|
3548 |
Q3TableSelection sel(row, 0, row, numCols() - 1); |
|
3549 |
addSelection(sel); |
|
3550 |
} |
|
3551 |
} |
|
3552 |
||
3553 |
/*! Selects the column \a col. |
|
3554 |
||
3555 |
\sa Q3TableSelection |
|
3556 |
*/ |
|
3557 |
||
3558 |
void Q3Table::selectColumn(int col) |
|
3559 |
{ |
|
3560 |
col = QMIN(numCols()-1, col); |
|
3561 |
if (col < 0) |
|
3562 |
return; |
|
3563 |
Q3TableSelection sel(0, col, numRows() - 1, col); |
|
3564 |
addSelection(sel); |
|
3565 |
} |
|
3566 |
||
3567 |
/*! \reimp |
|
3568 |
*/ |
|
3569 |
void Q3Table::contentsMousePressEvent(QMouseEvent* e) |
|
3570 |
{ |
|
3571 |
contentsMousePressEventEx(e); |
|
3572 |
} |
|
3573 |
||
3574 |
void Q3Table::contentsMousePressEventEx(QMouseEvent* e) |
|
3575 |
{ |
|
3576 |
shouldClearSelection = false; |
|
3577 |
if (isEditing()) { |
|
3578 |
if (!cellGeometry(editRow, editCol).contains(e->pos())) { |
|
3579 |
endEdit(editRow, editCol, true, edMode != Editing); |
|
3580 |
} else { |
|
3581 |
e->ignore(); |
|
3582 |
return; |
|
3583 |
} |
|
3584 |
} |
|
3585 |
||
3586 |
d->redirectMouseEvent = false; |
|
3587 |
||
3588 |
int tmpRow = rowAt(e->pos().y()); |
|
3589 |
int tmpCol = columnAt(e->pos().x()); |
|
3590 |
pressedRow = tmpRow; |
|
3591 |
pressedCol = tmpCol; |
|
3592 |
fixRow(tmpRow, e->pos().y()); |
|
3593 |
fixCol(tmpCol, e->pos().x()); |
|
3594 |
startDragCol = -1; |
|
3595 |
startDragRow = -1; |
|
3596 |
||
3597 |
if (isSelected(tmpRow, tmpCol)) { |
|
3598 |
startDragCol = tmpCol; |
|
3599 |
startDragRow = tmpRow; |
|
3600 |
dragStartPos = e->pos(); |
|
3601 |
} |
|
3602 |
||
3603 |
Q3TableItem *itm = item(pressedRow, pressedCol); |
|
3604 |
if (itm && !itm->isEnabled()) { |
|
3605 |
emit pressed(tmpRow, tmpCol, e->button(), e->pos()); |
|
3606 |
return; |
|
3607 |
} |
|
3608 |
||
3609 |
if ((e->state() & ShiftButton) == ShiftButton) { |
|
3610 |
int oldRow = curRow; |
|
3611 |
int oldCol = curCol; |
|
3612 |
setCurrentCell(tmpRow, tmpCol, selMode == SingleRow, true); |
|
3613 |
if (selMode != NoSelection && selMode != SingleRow) { |
|
3614 |
if (!currentSel) { |
|
3615 |
currentSel = new Q3TableSelection(); |
|
3616 |
selections.append(currentSel); |
|
3617 |
if (!isRowSelection(selectionMode())) |
|
3618 |
currentSel->init(oldRow, oldCol); |
|
3619 |
else |
|
3620 |
currentSel->init(oldRow, 0); |
|
3621 |
} |
|
3622 |
Q3TableSelection oldSelection = *currentSel; |
|
3623 |
if (!isRowSelection(selectionMode())) |
|
3624 |
currentSel->expandTo(tmpRow, tmpCol); |
|
3625 |
else |
|
3626 |
currentSel->expandTo(tmpRow, numCols() - 1); |
|
3627 |
repaintSelections(&oldSelection, currentSel); |
|
3628 |
emit selectionChanged(); |
|
3629 |
} |
|
3630 |
} else if ((e->state() & ControlButton) == ControlButton) { |
|
3631 |
setCurrentCell(tmpRow, tmpCol, false, true); |
|
3632 |
if (selMode != NoSelection) { |
|
3633 |
if (selMode == Single || (selMode == SingleRow && !isSelected(tmpRow, tmpCol, false))) |
|
3634 |
clearSelection(); |
|
3635 |
if (!(selMode == SingleRow && isSelected(tmpRow, tmpCol, false))) { |
|
3636 |
currentSel = new Q3TableSelection(); |
|
3637 |
selections.append(currentSel); |
|
3638 |
if (!isRowSelection(selectionMode())) { |
|
3639 |
currentSel->init(tmpRow, tmpCol); |
|
3640 |
currentSel->expandTo(tmpRow, tmpCol); |
|
3641 |
} else { |
|
3642 |
currentSel->init(tmpRow, 0); |
|
3643 |
currentSel->expandTo(tmpRow, numCols() - 1); |
|
3644 |
repaintSelections(0, currentSel); |
|
3645 |
} |
|
3646 |
emit selectionChanged(); |
|
3647 |
} |
|
3648 |
} |
|
3649 |
} else { |
|
3650 |
setCurrentCell(tmpRow, tmpCol, false, true); |
|
3651 |
Q3TableItem *itm = item(tmpRow, tmpCol); |
|
3652 |
if (itm && itm->editType() == Q3TableItem::WhenCurrent) { |
|
3653 |
QWidget *w = cellWidget(tmpRow, tmpCol); |
|
3654 |
if (qobject_cast<Q3ComboBox*>(w) || qobject_cast<QAbstractButton*>(w)) { |
|
3655 |
QMouseEvent ev(e->type(), w->mapFromGlobal(e->globalPos()), |
|
3656 |
e->globalPos(), e->button(), e->state()); |
|
3657 |
QApplication::sendPostedEvents(w, 0); |
|
3658 |
QApplication::sendEvent(w, &ev); |
|
3659 |
d->redirectMouseEvent = true; |
|
3660 |
} |
|
3661 |
} |
|
3662 |
if (isSelected(tmpRow, tmpCol, false)) { |
|
3663 |
shouldClearSelection = true; |
|
3664 |
} else { |
|
3665 |
bool b = signalsBlocked(); |
|
3666 |
if (selMode != NoSelection) |
|
3667 |
blockSignals(true); |
|
3668 |
clearSelection(); |
|
3669 |
blockSignals(b); |
|
3670 |
if (selMode != NoSelection) { |
|
3671 |
currentSel = new Q3TableSelection(); |
|
3672 |
selections.append(currentSel); |
|
3673 |
if (!isRowSelection(selectionMode())) { |
|
3674 |
currentSel->init(tmpRow, tmpCol); |
|
3675 |
currentSel->expandTo(tmpRow, tmpCol); |
|
3676 |
} else { |
|
3677 |
currentSel->init(tmpRow, 0); |
|
3678 |
currentSel->expandTo(tmpRow, numCols() - 1); |
|
3679 |
repaintSelections(0, currentSel); |
|
3680 |
} |
|
3681 |
emit selectionChanged(); |
|
3682 |
} |
|
3683 |
} |
|
3684 |
} |
|
3685 |
||
3686 |
emit pressed(tmpRow, tmpCol, e->button(), e->pos()); |
|
3687 |
} |
|
3688 |
||
3689 |
/*! \reimp |
|
3690 |
*/ |
|
3691 |
||
3692 |
void Q3Table::contentsMouseDoubleClickEvent(QMouseEvent *e) |
|
3693 |
{ |
|
3694 |
if (e->button() != LeftButton) |
|
3695 |
return; |
|
3696 |
if (!isRowSelection(selectionMode())) |
|
3697 |
clearSelection(); |
|
3698 |
int tmpRow = rowAt(e->pos().y()); |
|
3699 |
int tmpCol = columnAt(e->pos().x()); |
|
3700 |
Q3TableItem *itm = item(tmpRow, tmpCol); |
|
3701 |
if (itm && !itm->isEnabled()) |
|
3702 |
return; |
|
3703 |
if (tmpRow != -1 && tmpCol != -1) { |
|
3704 |
if (beginEdit(tmpRow, tmpCol, false)) |
|
3705 |
setEditMode(Editing, tmpRow, tmpCol); |
|
3706 |
} |
|
3707 |
||
3708 |
emit doubleClicked(tmpRow, tmpCol, e->button(), e->pos()); |
|
3709 |
} |
|
3710 |
||
3711 |
/*! |
|
3712 |
Sets the current edit mode to \a mode, the current edit row to \a |
|
3713 |
row and the current edit column to \a col. |
|
3714 |
||
3715 |
\sa EditMode |
|
3716 |
*/ |
|
3717 |
||
3718 |
void Q3Table::setEditMode(EditMode mode, int row, int col) |
|
3719 |
{ |
|
3720 |
edMode = mode; |
|
3721 |
editRow = row; |
|
3722 |
editCol = col; |
|
3723 |
} |
|
3724 |
||
3725 |
||
3726 |
/*! \reimp |
|
3727 |
*/ |
|
3728 |
||
3729 |
void Q3Table::contentsMouseMoveEvent(QMouseEvent *e) |
|
3730 |
{ |
|
3731 |
if ((e->state() & MouseButtonMask) == NoButton) |
|
3732 |
return; |
|
3733 |
int tmpRow = rowAt(e->pos().y()); |
|
3734 |
int tmpCol = columnAt(e->pos().x()); |
|
3735 |
fixRow(tmpRow, e->pos().y()); |
|
3736 |
fixCol(tmpCol, e->pos().x()); |
|
3737 |
||
3738 |
#ifndef QT_NO_DRAGANDDROP |
|
3739 |
if (dragEnabled() && startDragRow != -1 && startDragCol != -1) { |
|
3740 |
if (QPoint(dragStartPos - e->pos()).manhattanLength() > QApplication::startDragDistance()) |
|
3741 |
startDrag(); |
|
3742 |
return; |
|
3743 |
} |
|
3744 |
#endif |
|
3745 |
if (selectionMode() == MultiRow && (e->state() & ControlButton) == ControlButton) |
|
3746 |
shouldClearSelection = false; |
|
3747 |
||
3748 |
if (shouldClearSelection) { |
|
3749 |
clearSelection(); |
|
3750 |
if (selMode != NoSelection) { |
|
3751 |
currentSel = new Q3TableSelection(); |
|
3752 |
selections.append(currentSel); |
|
3753 |
if (!isRowSelection(selectionMode())) |
|
3754 |
currentSel->init(tmpRow, tmpCol); |
|
3755 |
else |
|
3756 |
currentSel->init(tmpRow, 0); |
|
3757 |
emit selectionChanged(); |
|
3758 |
} |
|
3759 |
shouldClearSelection = false; |
|
3760 |
} |
|
3761 |
||
3762 |
QPoint pos = mapFromGlobal(e->globalPos()); |
|
3763 |
pos -= QPoint(leftHeader->width(), topHeader->height()); |
|
3764 |
autoScrollTimer->stop(); |
|
3765 |
doAutoScroll(); |
|
3766 |
if (pos.x() < 0 || pos.x() > visibleWidth() || pos.y() < 0 || pos.y() > visibleHeight()) |
|
3767 |
autoScrollTimer->start(100, true); |
|
3768 |
} |
|
3769 |
||
3770 |
/*! \internal |
|
3771 |
*/ |
|
3772 |
||
3773 |
void Q3Table::doValueChanged() |
|
3774 |
{ |
|
3775 |
emit valueChanged(editRow, editCol); |
|
3776 |
} |
|
3777 |
||
3778 |
/*! \internal |
|
3779 |
*/ |
|
3780 |
||
3781 |
void Q3Table::doAutoScroll() |
|
3782 |
{ |
|
3783 |
QPoint pos = QCursor::pos(); |
|
3784 |
pos = mapFromGlobal(pos); |
|
3785 |
pos -= QPoint(leftHeader->width(), topHeader->height()); |
|
3786 |
||
3787 |
int tmpRow = curRow; |
|
3788 |
int tmpCol = curCol; |
|
3789 |
if (pos.y() < 0) |
|
3790 |
tmpRow--; |
|
3791 |
else if (pos.y() > visibleHeight()) |
|
3792 |
tmpRow++; |
|
3793 |
if (pos.x() < 0) |
|
3794 |
tmpCol--; |
|
3795 |
else if (pos.x() > visibleWidth()) |
|
3796 |
tmpCol++; |
|
3797 |
||
3798 |
pos += QPoint(contentsX(), contentsY()); |
|
3799 |
if (tmpRow == curRow) |
|
3800 |
tmpRow = rowAt(pos.y()); |
|
3801 |
if (tmpCol == curCol) |
|
3802 |
tmpCol = columnAt(pos.x()); |
|
3803 |
pos -= QPoint(contentsX(), contentsY()); |
|
3804 |
||
3805 |
fixRow(tmpRow, pos.y()); |
|
3806 |
fixCol(tmpCol, pos.x()); |
|
3807 |
||
3808 |
if (tmpRow < 0 || tmpRow > numRows() - 1) |
|
3809 |
tmpRow = currentRow(); |
|
3810 |
if (tmpCol < 0 || tmpCol > numCols() - 1) |
|
3811 |
tmpCol = currentColumn(); |
|
3812 |
||
3813 |
ensureCellVisible(tmpRow, tmpCol); |
|
3814 |
||
3815 |
if (currentSel && selMode != NoSelection) { |
|
3816 |
Q3TableSelection oldSelection = *currentSel; |
|
3817 |
bool useOld = true; |
|
3818 |
if (selMode != SingleRow) { |
|
3819 |
if (!isRowSelection(selectionMode())) { |
|
3820 |
currentSel->expandTo(tmpRow, tmpCol); |
|
3821 |
} else { |
|
3822 |
currentSel->expandTo(tmpRow, numCols() - 1); |
|
3823 |
} |
|
3824 |
} else { |
|
3825 |
bool currentInSelection = tmpRow == curRow && isSelected(tmpRow, tmpCol); |
|
3826 |
if (!currentInSelection) { |
|
3827 |
useOld = false; |
|
3828 |
clearSelection(); |
|
3829 |
currentSel = new Q3TableSelection(); |
|
3830 |
selections.append(currentSel); |
|
3831 |
currentSel->init(tmpRow, 0); |
|
3832 |
currentSel->expandTo(tmpRow, numCols() - 1); |
|
3833 |
repaintSelections(0, currentSel); |
|
3834 |
} else { |
|
3835 |
currentSel->expandTo(tmpRow, numCols() - 1); |
|
3836 |
} |
|
3837 |
} |
|
3838 |
setCurrentCell(tmpRow, tmpCol, false, true); |
|
3839 |
repaintSelections(useOld ? &oldSelection : 0, currentSel); |
|
3840 |
if (currentSel && oldSelection != *currentSel) |
|
3841 |
emit selectionChanged(); |
|
3842 |
} else { |
|
3843 |
setCurrentCell(tmpRow, tmpCol, false, true); |
|
3844 |
} |
|
3845 |
||
3846 |
if (pos.x() < 0 || pos.x() > visibleWidth() || pos.y() < 0 || pos.y() > visibleHeight()) |
|
3847 |
autoScrollTimer->start(100, true); |
|
3848 |
} |
|
3849 |
||
3850 |
/*! \reimp |
|
3851 |
*/ |
|
3852 |
||
3853 |
void Q3Table::contentsMouseReleaseEvent(QMouseEvent *e) |
|
3854 |
{ |
|
3855 |
if (pressedRow == curRow && pressedCol == curCol) |
|
3856 |
emit clicked(curRow, curCol, e->button(), e->pos()); |
|
3857 |
||
3858 |
if (e->button() != LeftButton) |
|
3859 |
return; |
|
3860 |
if (shouldClearSelection) { |
|
3861 |
int tmpRow = rowAt(e->pos().y()); |
|
3862 |
int tmpCol = columnAt(e->pos().x()); |
|
3863 |
fixRow(tmpRow, e->pos().y()); |
|
3864 |
fixCol(tmpCol, e->pos().x()); |
|
3865 |
clearSelection(); |
|
3866 |
if (selMode != NoSelection) { |
|
3867 |
currentSel = new Q3TableSelection(); |
|
3868 |
selections.append(currentSel); |
|
3869 |
if (!isRowSelection(selectionMode())) { |
|
3870 |
currentSel->init(tmpRow, tmpCol); |
|
3871 |
} else { |
|
3872 |
currentSel->init(tmpRow, 0); |
|
3873 |
currentSel->expandTo(tmpRow, numCols() - 1); |
|
3874 |
repaintSelections(0, currentSel); |
|
3875 |
} |
|
3876 |
emit selectionChanged(); |
|
3877 |
} |
|
3878 |
shouldClearSelection = false; |
|
3879 |
} |
|
3880 |
autoScrollTimer->stop(); |
|
3881 |
||
3882 |
if (d->redirectMouseEvent && pressedRow == curRow && pressedCol == curCol && |
|
3883 |
item(pressedRow, pressedCol) && item(pressedRow, pressedCol)->editType() == |
|
3884 |
Q3TableItem::WhenCurrent) { |
|
3885 |
QWidget *w = cellWidget(pressedRow, pressedCol); |
|
3886 |
if (w) { |
|
3887 |
QMouseEvent ev(e->type(), w->mapFromGlobal(e->globalPos()), |
|
3888 |
e->globalPos(), e->button(), e->state()); |
|
3889 |
QApplication::sendPostedEvents(w, 0); |
|
3890 |
bool old = w->testAttribute(Qt::WA_NoMousePropagation); |
|
3891 |
w->setAttribute(Qt::WA_NoMousePropagation, true); |
|
3892 |
QApplication::sendEvent(w, &ev); |
|
3893 |
w->setAttribute(Qt::WA_NoMousePropagation, old); |
|
3894 |
} |
|
3895 |
} |
|
3896 |
} |
|
3897 |
||
3898 |
/*! |
|
3899 |
\reimp |
|
3900 |
*/ |
|
3901 |
||
3902 |
void Q3Table::contentsContextMenuEvent(QContextMenuEvent *e) |
|
3903 |
{ |
|
3904 |
if (!receivers(SIGNAL(contextMenuRequested(int,int,QPoint)))) { |
|
3905 |
e->ignore(); |
|
3906 |
return; |
|
3907 |
} |
|
3908 |
if (e->reason() == QContextMenuEvent::Keyboard) { |
|
3909 |
QRect r = cellGeometry(curRow, curCol); |
|
3910 |
emit contextMenuRequested(curRow, curCol, viewport()->mapToGlobal(contentsToViewport(r.center()))); |
|
3911 |
} else { |
|
3912 |
int tmpRow = rowAt(e->pos().y()); |
|
3913 |
int tmpCol = columnAt(e->pos().x()); |
|
3914 |
emit contextMenuRequested(tmpRow, tmpCol, e->globalPos()); |
|
3915 |
} |
|
3916 |
} |
|
3917 |
||
3918 |
||
3919 |
/*! \reimp |
|
3920 |
*/ |
|
3921 |
||
3922 |
bool Q3Table::eventFilter(QObject *o, QEvent *e) |
|
3923 |
{ |
|
3924 |
switch (e->type()) { |
|
3925 |
case QEvent::KeyPress: { |
|
3926 |
Q3TableItem *itm = item(curRow, curCol); |
|
3927 |
QWidget *editorWidget = cellWidget(editRow, editCol); |
|
3928 |
||
3929 |
if (isEditing() && editorWidget && o == editorWidget) { |
|
3930 |
itm = item(editRow, editCol); |
|
3931 |
QKeyEvent *ke = (QKeyEvent*)e; |
|
3932 |
if (ke->key() == Key_Escape) { |
|
3933 |
if (!itm || itm->editType() == Q3TableItem::OnTyping) |
|
3934 |
endEdit(editRow, editCol, false, edMode != Editing); |
|
3935 |
return true; |
|
3936 |
} |
|
3937 |
||
3938 |
if ((ke->state() == NoButton || ke->state() == Keypad) |
|
3939 |
&& (ke->key() == Key_Return || ke->key() == Key_Enter)) { |
|
3940 |
if (!itm || itm->editType() == Q3TableItem::OnTyping) |
|
3941 |
endEdit(editRow, editCol, true, edMode != Editing); |
|
3942 |
activateNextCell(); |
|
3943 |
return true; |
|
3944 |
} |
|
3945 |
||
3946 |
if (ke->key() == Key_Tab || ke->key() == Key_BackTab) { |
|
3947 |
if (ke->state() & Qt::ControlButton) |
|
3948 |
return false; |
|
3949 |
if (!itm || itm->editType() == Q3TableItem::OnTyping) |
|
3950 |
endEdit(editRow, editCol, true, edMode != Editing); |
|
3951 |
if ((ke->key() == Key_Tab) && !(ke->state() & ShiftButton)) { |
|
3952 |
if (currentColumn() >= numCols() - 1) |
|
3953 |
return true; |
|
3954 |
int cc = QMIN(numCols() - 1, currentColumn() + 1); |
|
3955 |
while (cc < numCols()) { |
|
3956 |
Q3TableItem *i = item(currentRow(), cc); |
|
3957 |
if (!d->hiddenCols.find(cc) && !isColumnReadOnly(cc) && (!i || i->isEnabled())) |
|
3958 |
break; |
|
3959 |
++cc; |
|
3960 |
} |
|
3961 |
setCurrentCell(currentRow(), cc); |
|
3962 |
} else { // Key_BackTab |
|
3963 |
if (currentColumn() == 0) |
|
3964 |
return true; |
|
3965 |
int cc = QMAX(0, currentColumn() - 1); |
|
3966 |
while (cc >= 0) { |
|
3967 |
Q3TableItem *i = item(currentRow(), cc); |
|
3968 |
if (!d->hiddenCols.find(cc) && !isColumnReadOnly(cc) && (!i || i->isEnabled())) |
|
3969 |
break; |
|
3970 |
--cc; |
|
3971 |
} |
|
3972 |
setCurrentCell(currentRow(), cc); |
|
3973 |
} |
|
3974 |
itm = item(curRow, curCol); |
|
3975 |
if (beginEdit(curRow, curCol, false)) |
|
3976 |
setEditMode(Editing, curRow, curCol); |
|
3977 |
return true; |
|
3978 |
} |
|
3979 |
||
3980 |
if ((edMode == Replacing || |
|
3981 |
(itm && itm->editType() == Q3TableItem::WhenCurrent)) && |
|
3982 |
(ke->key() == Key_Up || ke->key() == Key_Prior || |
|
3983 |
ke->key() == Key_Home || ke->key() == Key_Down || |
|
3984 |
ke->key() == Key_Next || ke->key() == Key_End || |
|
3985 |
ke->key() == Key_Left || ke->key() == Key_Right)) { |
|
3986 |
if (!itm || itm->editType() == Q3TableItem::OnTyping) { |
|
3987 |
endEdit(editRow, editCol, true, edMode != Editing); |
|
3988 |
} |
|
3989 |
keyPressEvent(ke); |
|
3990 |
return true; |
|
3991 |
} |
|
3992 |
} else { |
|
3993 |
QObjectList l = viewport()->queryList("QWidget"); |
|
3994 |
if (l.contains(o)) { |
|
3995 |
QKeyEvent *ke = (QKeyEvent*)e; |
|
3996 |
if ((ke->state() & ControlButton) == ControlButton || |
|
3997 |
(ke->key() != Key_Left && ke->key() != Key_Right && |
|
3998 |
ke->key() != Key_Up && ke->key() != Key_Down && |
|
3999 |
ke->key() != Key_Prior && ke->key() != Key_Next && |
|
4000 |
ke->key() != Key_Home && ke->key() != Key_End)) |
|
4001 |
return false; |
|
4002 |
keyPressEvent((QKeyEvent*)e); |
|
4003 |
return true; |
|
4004 |
} |
|
4005 |
} |
|
4006 |
||
4007 |
} break; |
|
4008 |
case QEvent::FocusOut: { |
|
4009 |
QWidget *editorWidget = cellWidget(editRow, editCol); |
|
4010 |
if (isEditing() && editorWidget && o == editorWidget && ((QFocusEvent*)e)->reason() != Qt::PopupFocusReason) { |
|
4011 |
// if the editor is the parent of the new focus widget, do nothing |
|
4012 |
QWidget *w = QApplication::focusWidget(); |
|
4013 |
while (w) { |
|
4014 |
w = w->parentWidget(); |
|
4015 |
if (w == editorWidget) |
|
4016 |
break; |
|
4017 |
} |
|
4018 |
if (w) |
|
4019 |
break; |
|
4020 |
// otherwise, end editing |
|
4021 |
Q3TableItem *itm = item(editRow, editCol); |
|
4022 |
if (!itm || itm->editType() == Q3TableItem::OnTyping) { |
|
4023 |
endEdit(editRow, editCol, true, edMode != Editing); |
|
4024 |
return true; |
|
4025 |
} |
|
4026 |
} |
|
4027 |
break; |
|
4028 |
} |
|
4029 |
#ifndef QT_NO_WHEELEVENT |
|
4030 |
case QEvent::Wheel: |
|
4031 |
if (o == this || o == viewport()) { |
|
4032 |
QWheelEvent* we = (QWheelEvent*)e; |
|
4033 |
scrollBy(0, -we->delta()); |
|
4034 |
we->accept(); |
|
4035 |
return true; |
|
4036 |
} |
|
4037 |
#endif |
|
4038 |
default: |
|
4039 |
break; |
|
4040 |
} |
|
4041 |
||
4042 |
return Q3ScrollView::eventFilter(o, e); |
|
4043 |
} |
|
4044 |
||
4045 |
void Q3Table::fixCell(int &row, int &col, int key) |
|
4046 |
{ |
|
4047 |
if (rowHeight(row) > 0 && columnWidth(col) > 0) |
|
4048 |
return; |
|
4049 |
if (rowHeight(row) <= 0) { |
|
4050 |
if (key == Key_Down || |
|
4051 |
key == Key_Next || |
|
4052 |
key == Key_End) { |
|
4053 |
while (row < numRows() && rowHeight(row) <= 0) |
|
4054 |
row++; |
|
4055 |
if (rowHeight(row) <= 0) |
|
4056 |
row = curRow; |
|
4057 |
} else if (key == Key_Up || |
|
4058 |
key == Key_Prior || |
|
4059 |
key == Key_Home) |
|
4060 |
while (row >= 0 && rowHeight(row) <= 0) |
|
4061 |
row--; |
|
4062 |
if (rowHeight(row) <= 0) |
|
4063 |
row = curRow; |
|
4064 |
} else if (columnWidth(col) <= 0) { |
|
4065 |
if (key == Key_Left) { |
|
4066 |
while (col >= 0 && columnWidth(col) <= 0) |
|
4067 |
col--; |
|
4068 |
if (columnWidth(col) <= 0) |
|
4069 |
col = curCol; |
|
4070 |
} else if (key == Key_Right) { |
|
4071 |
while (col < numCols() && columnWidth(col) <= 0) |
|
4072 |
col++; |
|
4073 |
if (columnWidth(col) <= 0) |
|
4074 |
col = curCol; |
|
4075 |
} |
|
4076 |
} |
|
4077 |
} |
|
4078 |
||
4079 |
/*! \reimp |
|
4080 |
*/ |
|
4081 |
||
4082 |
void Q3Table::keyPressEvent(QKeyEvent* e) |
|
4083 |
{ |
|
4084 |
if (isEditing() && item(editRow, editCol) && |
|
4085 |
item(editRow, editCol)->editType() == Q3TableItem::OnTyping) |
|
4086 |
return; |
|
4087 |
||
4088 |
int tmpRow = curRow; |
|
4089 |
int tmpCol = curCol; |
|
4090 |
int oldRow = tmpRow; |
|
4091 |
int oldCol = tmpCol; |
|
4092 |
||
4093 |
bool navigationKey = false; |
|
4094 |
int r; |
|
4095 |
switch (e->key()) { |
|
4096 |
case Key_Left: |
|
4097 |
tmpCol = QMAX(0, tmpCol - 1); |
|
4098 |
navigationKey = true; |
|
4099 |
break; |
|
4100 |
case Key_Right: |
|
4101 |
tmpCol = QMIN(numCols() - 1, tmpCol + 1); |
|
4102 |
navigationKey = true; |
|
4103 |
break; |
|
4104 |
case Key_Up: |
|
4105 |
tmpRow = QMAX(0, tmpRow - 1); |
|
4106 |
navigationKey = true; |
|
4107 |
break; |
|
4108 |
case Key_Down: |
|
4109 |
tmpRow = QMIN(numRows() - 1, tmpRow + 1); |
|
4110 |
navigationKey = true; |
|
4111 |
break; |
|
4112 |
case Key_Prior: |
|
4113 |
r = QMAX(0, rowAt(rowPos(tmpRow) - visibleHeight())); |
|
4114 |
if (r < tmpRow || tmpRow < 0) |
|
4115 |
tmpRow = r; |
|
4116 |
navigationKey = true; |
|
4117 |
break; |
|
4118 |
case Key_Next: |
|
4119 |
r = QMIN(numRows() - 1, rowAt(rowPos(tmpRow) + visibleHeight())); |
|
4120 |
if (r > tmpRow) |
|
4121 |
tmpRow = r; |
|
4122 |
else |
|
4123 |
tmpRow = numRows() - 1; |
|
4124 |
navigationKey = true; |
|
4125 |
break; |
|
4126 |
case Key_Home: |
|
4127 |
tmpRow = 0; |
|
4128 |
navigationKey = true; |
|
4129 |
break; |
|
4130 |
case Key_End: |
|
4131 |
tmpRow = numRows() - 1; |
|
4132 |
navigationKey = true; |
|
4133 |
break; |
|
4134 |
case Key_F2: |
|
4135 |
if (beginEdit(tmpRow, tmpCol, false)) |
|
4136 |
setEditMode(Editing, tmpRow, tmpCol); |
|
4137 |
break; |
|
4138 |
case Key_Enter: case Key_Return: |
|
4139 |
activateNextCell(); |
|
4140 |
return; |
|
4141 |
case Key_Tab: case Key_BackTab: |
|
4142 |
if ((e->key() == Key_Tab) && !(e->state() & ShiftButton)) { |
|
4143 |
if (currentColumn() >= numCols() - 1) |
|
4144 |
return; |
|
4145 |
int cc = QMIN(numCols() - 1, currentColumn() + 1); |
|
4146 |
while (cc < numCols()) { |
|
4147 |
Q3TableItem *i = item(currentRow(), cc); |
|
4148 |
if (!d->hiddenCols.find(cc) && !isColumnReadOnly(cc) && (!i || i->isEnabled())) |
|
4149 |
break; |
|
4150 |
++cc; |
|
4151 |
} |
|
4152 |
setCurrentCell(currentRow(), cc); |
|
4153 |
} else { // Key_BackTab |
|
4154 |
if (currentColumn() == 0) |
|
4155 |
return; |
|
4156 |
int cc = QMAX(0, currentColumn() - 1); |
|
4157 |
while (cc >= 0) { |
|
4158 |
Q3TableItem *i = item(currentRow(), cc); |
|
4159 |
if (!d->hiddenCols.find(cc) && !isColumnReadOnly(cc) && (!i || i->isEnabled())) |
|
4160 |
break; |
|
4161 |
--cc; |
|
4162 |
} |
|
4163 |
setCurrentCell(currentRow(), cc); |
|
4164 |
} |
|
4165 |
return; |
|
4166 |
case Key_Escape: |
|
4167 |
e->ignore(); |
|
4168 |
return; |
|
4169 |
default: // ... or start in-place editing |
|
4170 |
if (e->text()[ 0 ].isPrint()) { |
|
4171 |
Q3TableItem *itm = item(tmpRow, tmpCol); |
|
4172 |
if (!itm || itm->editType() == Q3TableItem::OnTyping) { |
|
4173 |
QWidget *w = beginEdit(tmpRow, tmpCol, |
|
4174 |
itm ? itm->isReplaceable() : true); |
|
4175 |
if (w) { |
|
4176 |
setEditMode((!itm || (itm && itm->isReplaceable()) |
|
4177 |
? Replacing : Editing), tmpRow, tmpCol); |
|
4178 |
QApplication::sendEvent(w, e); |
|
4179 |
return; |
|
4180 |
} |
|
4181 |
} |
|
4182 |
} |
|
4183 |
e->ignore(); |
|
4184 |
return; |
|
4185 |
} |
|
4186 |
||
4187 |
if (navigationKey) { |
|
4188 |
fixCell(tmpRow, tmpCol, e->key()); |
|
4189 |
if ((e->state() & ShiftButton) == ShiftButton && |
|
4190 |
selMode != NoSelection && selMode != SingleRow) { |
|
4191 |
bool justCreated = false; |
|
4192 |
setCurrentCell(tmpRow, tmpCol, false, true); |
|
4193 |
if (!currentSel) { |
|
4194 |
justCreated = true; |
|
4195 |
currentSel = new Q3TableSelection(); |
|
4196 |
selections.append(currentSel); |
|
4197 |
if (!isRowSelection(selectionMode())) |
|
4198 |
currentSel->init(oldRow, oldCol); |
|
4199 |
else |
|
4200 |
currentSel->init(oldRow < 0 ? 0 : oldRow, 0); |
|
4201 |
} |
|
4202 |
Q3TableSelection oldSelection = *currentSel; |
|
4203 |
if (!isRowSelection(selectionMode())) |
|
4204 |
currentSel->expandTo(tmpRow, tmpCol); |
|
4205 |
else |
|
4206 |
currentSel->expandTo(tmpRow, numCols() - 1); |
|
4207 |
repaintSelections(justCreated ? 0 : &oldSelection, currentSel); |
|
4208 |
emit selectionChanged(); |
|
4209 |
} else { |
|
4210 |
setCurrentCell(tmpRow, tmpCol, false, true); |
|
4211 |
if (!isRowSelection(selectionMode())) { |
|
4212 |
clearSelection(); |
|
4213 |
} else { |
|
4214 |
bool currentInSelection = tmpRow == oldRow && isSelected(tmpRow, tmpCol, false); |
|
4215 |
if (!currentInSelection) { |
|
4216 |
bool hasOldSel = false; |
|
4217 |
Q3TableSelection oldSelection; |
|
4218 |
if (selectionMode() == MultiRow) { |
|
4219 |
bool b = signalsBlocked(); |
|
4220 |
blockSignals(true); |
|
4221 |
clearSelection(); |
|
4222 |
blockSignals(b); |
|
4223 |
} else { |
|
4224 |
if (currentSel) { |
|
4225 |
oldSelection = *currentSel; |
|
4226 |
hasOldSel = true; |
|
4227 |
selections.removeRef(currentSel); |
|
4228 |
leftHeader->setSectionState(oldSelection.topRow(), Q3TableHeader::Normal); |
|
4229 |
} |
|
4230 |
} |
|
4231 |
currentSel = new Q3TableSelection(); |
|
4232 |
selections.append(currentSel); |
|
4233 |
currentSel->init(tmpRow, 0); |
|
4234 |
currentSel->expandTo(tmpRow, numCols() - 1); |
|
4235 |
repaintSelections(hasOldSel ? &oldSelection : 0, currentSel, !hasOldSel); |
|
4236 |
emit selectionChanged(); |
|
4237 |
} |
|
4238 |
} |
|
4239 |
} |
|
4240 |
} else { |
|
4241 |
setCurrentCell(tmpRow, tmpCol, false, true); |
|
4242 |
} |
|
4243 |
} |
|
4244 |
||
4245 |
/*! \reimp |
|
4246 |
*/ |
|
4247 |
||
4248 |
void Q3Table::focusInEvent(QFocusEvent*) |
|
4249 |
{ |
|
4250 |
d->inMenuMode = false; |
|
4251 |
QWidget *editorWidget = cellWidget(editRow, editCol); |
|
4252 |
updateCell(curRow, curCol); |
|
4253 |
if (style()->styleHint(QStyle::SH_ItemView_ChangeHighlightOnFocus, 0, this)) |
|
4254 |
repaintSelections(); |
|
4255 |
if (isEditing() && editorWidget) |
|
4256 |
editorWidget->setFocus(); |
|
4257 |
||
4258 |
} |
|
4259 |
||
4260 |
||
4261 |
/*! \reimp |
|
4262 |
*/ |
|
4263 |
||
4264 |
void Q3Table::focusOutEvent(QFocusEvent *e) |
|
4265 |
{ |
|
4266 |
updateCell(curRow, curCol); |
|
4267 |
if (style()->styleHint(QStyle::SH_ItemView_ChangeHighlightOnFocus, 0, this)) { |
|
4268 |
d->inMenuMode = |
|
4269 |
e->reason() == Qt::PopupFocusReason || |
|
4270 |
(qApp->focusWidget() && qApp->focusWidget()->inherits("QMenuBar")); |
|
4271 |
if (!d->inMenuMode) |
|
4272 |
repaintSelections(); |
|
4273 |
} |
|
4274 |
} |
|
4275 |
||
4276 |
/*! \reimp |
|
4277 |
*/ |
|
4278 |
||
4279 |
QSize Q3Table::sizeHint() const |
|
4280 |
{ |
|
4281 |
if (cachedSizeHint().isValid()) |
|
4282 |
return cachedSizeHint(); |
|
4283 |
||
4284 |
constPolish(); |
|
4285 |
||
4286 |
QSize s = tableSize(); |
|
4287 |
QSize sh; |
|
4288 |
if (s.width() < 500 && s.height() < 500) { |
|
4289 |
sh = QSize(tableSize().width() + VERTICALMARGIN + 5, |
|
4290 |
tableSize().height() + topMargin() + 5); |
|
4291 |
} else { |
|
4292 |
sh = Q3ScrollView::sizeHint(); |
|
4293 |
if (!topHeader->isHidden()) |
|
4294 |
sh.setHeight(sh.height() + topHeader->height()); |
|
4295 |
if (!leftHeader->isHidden()) |
|
4296 |
sh.setWidth(sh.width() + leftHeader->width()); |
|
4297 |
} |
|
4298 |
setCachedSizeHint(sh); |
|
4299 |
return sh; |
|
4300 |
} |
|
4301 |
||
4302 |
/*! \reimp |
|
4303 |
*/ |
|
4304 |
||
4305 |
void Q3Table::viewportResizeEvent(QResizeEvent *e) |
|
4306 |
{ |
|
4307 |
Q3ScrollView::viewportResizeEvent(e); |
|
4308 |
updateGeometries(); |
|
4309 |
} |
|
4310 |
||
4311 |
/*! \reimp |
|
4312 |
*/ |
|
4313 |
||
4314 |
void Q3Table::showEvent(QShowEvent *e) |
|
4315 |
{ |
|
4316 |
Q3ScrollView::showEvent(e); |
|
4317 |
QRect r(cellGeometry(numRows() - 1, numCols() - 1)); |
|
4318 |
resizeContents(r.right() + 1, r.bottom() + 1); |
|
4319 |
updateGeometries(); |
|
4320 |
} |
|
4321 |
||
4322 |
/*! \reimp |
|
4323 |
*/ |
|
4324 |
||
4325 |
void Q3Table::paintEvent(QPaintEvent *e) |
|
4326 |
{ |
|
4327 |
QRect topLeftCorner = QStyle::visualRect(layoutDirection(), rect(), QRect(frameWidth(), frameWidth(), VERTICALMARGIN, topMargin())); |
|
4328 |
erase(topLeftCorner); // erase instead of widget on top |
|
4329 |
Q3ScrollView::paintEvent(e); |
|
4330 |
||
4331 |
#ifdef Q_OS_WINCE |
|
4332 |
QPainter p(this); |
|
4333 |
p.drawLine(topLeftCorner.bottomLeft(), topLeftCorner.bottomRight()); |
|
4334 |
p.drawLine(topLeftCorner.bottomRight(), topLeftCorner.topRight()); |
|
4335 |
#endif |
|
4336 |
} |
|
4337 |
||
4338 |
static bool inUpdateCell = false; |
|
4339 |
||
4340 |
/*! |
|
4341 |
Repaints the cell at \a row, \a col. |
|
4342 |
*/ |
|
4343 |
||
4344 |
void Q3Table::updateCell(int row, int col) |
|
4345 |
{ |
|
4346 |
if (inUpdateCell || row < 0 || col < 0) |
|
4347 |
return; |
|
4348 |
inUpdateCell = true; |
|
4349 |
QRect cg = cellGeometry(row, col); |
|
4350 |
QRect r(contentsToViewport(QPoint(cg.x() - 2, cg.y() - 2)), |
|
4351 |
QSize(cg.width() + 4, cg.height() + 4)); |
|
4352 |
viewport()->update(r); |
|
4353 |
inUpdateCell = false; |
|
4354 |
} |
|
4355 |
||
4356 |
void Q3Table::repaintCell(int row, int col) |
|
4357 |
{ |
|
4358 |
if (row == -1 || col == -1) |
|
4359 |
return; |
|
4360 |
QRect cg = cellGeometry(row, col); |
|
4361 |
QRect r(QPoint(cg.x() - 2, cg.y() - 2), |
|
4362 |
QSize(cg.width() + 4, cg.height() + 4)); |
|
4363 |
repaintContents(r, false); |
|
4364 |
} |
|
4365 |
||
4366 |
void Q3Table::contentsToViewport2(int x, int y, int& vx, int& vy) |
|
4367 |
{ |
|
4368 |
const QPoint v = contentsToViewport2(QPoint(x, y)); |
|
4369 |
vx = v.x(); |
|
4370 |
vy = v.y(); |
|
4371 |
} |
|
4372 |
||
4373 |
QPoint Q3Table::contentsToViewport2(const QPoint &p) |
|
4374 |
{ |
|
4375 |
return QPoint(p.x() - contentsX(), |
|
4376 |
p.y() - contentsY()); |
|
4377 |
} |
|
4378 |
||
4379 |
QPoint Q3Table::viewportToContents2(const QPoint& vp) |
|
4380 |
{ |
|
4381 |
return QPoint(vp.x() + contentsX(), |
|
4382 |
vp.y() + contentsY()); |
|
4383 |
} |
|
4384 |
||
4385 |
void Q3Table::viewportToContents2(int vx, int vy, int& x, int& y) |
|
4386 |
{ |
|
4387 |
const QPoint c = viewportToContents2(QPoint(vx, vy)); |
|
4388 |
x = c.x(); |
|
4389 |
y = c.y(); |
|
4390 |
} |
|
4391 |
||
4392 |
/*! |
|
4393 |
This function should be called whenever the column width of \a col |
|
4394 |
has been changed. It updates the geometry of any affected columns |
|
4395 |
and repaints the table to reflect the changes it has made. |
|
4396 |
*/ |
|
4397 |
||
4398 |
void Q3Table::columnWidthChanged(int col) |
|
4399 |
{ |
|
4400 |
int p = columnPos(col); |
|
4401 |
if (d->hasColSpan) |
|
4402 |
p = contentsX(); |
|
4403 |
updateContents(p, contentsY(), contentsWidth(), visibleHeight()); |
|
4404 |
QSize s(tableSize()); |
|
4405 |
int w = contentsWidth(); |
|
4406 |
resizeContents(s.width(), s.height()); |
|
4407 |
if (contentsWidth() < w) |
|
4408 |
repaintContents(s.width(), contentsY(), |
|
4409 |
w - s.width() + 1, visibleHeight(), true); |
|
4410 |
else |
|
4411 |
repaintContents(w, contentsY(), |
|
4412 |
s.width() - w + 1, visibleHeight(), false); |
|
4413 |
||
4414 |
// update widgets that are affected by this change |
|
4415 |
if (widgets.size()) { |
|
4416 |
int last = isHidden() ? numCols() - 1 : d->lastVisCol; |
|
4417 |
for (int c = col; c <= last; ++c) |
|
4418 |
updateColWidgets(c); |
|
4419 |
} |
|
4420 |
delayedUpdateGeometries(); |
|
4421 |
} |
|
4422 |
||
4423 |
/*! |
|
4424 |
This function should be called whenever the row height of \a row |
|
4425 |
has been changed. It updates the geometry of any affected rows and |
|
4426 |
repaints the table to reflect the changes it has made. |
|
4427 |
*/ |
|
4428 |
||
4429 |
void Q3Table::rowHeightChanged(int row) |
|
4430 |
{ |
|
4431 |
int p = rowPos(row); |
|
4432 |
if (d->hasRowSpan) |
|
4433 |
p = contentsY(); |
|
4434 |
updateContents(contentsX(), p, visibleWidth(), contentsHeight()); |
|
4435 |
QSize s(tableSize()); |
|
4436 |
int h = contentsHeight(); |
|
4437 |
resizeContents(s.width(), s.height()); |
|
4438 |
if (contentsHeight() < h) { |
|
4439 |
repaintContents(contentsX(), contentsHeight(), |
|
4440 |
visibleWidth(), h - s.height() + 1, true); |
|
4441 |
} else { |
|
4442 |
repaintContents(contentsX(), h, |
|
4443 |
visibleWidth(), s.height() - h + 1, false); |
|
4444 |
} |
|
4445 |
||
4446 |
// update widgets that are affected by this change |
|
4447 |
if (widgets.size()) { |
|
4448 |
d->lastVisRow = rowAt(contentsY() + visibleHeight() + (s.height() - h + 1)); |
|
4449 |
int last = isHidden() ? numRows() - 1 : d->lastVisRow; |
|
4450 |
for (int r = row; r <= last; ++r) |
|
4451 |
updateRowWidgets(r); |
|
4452 |
} |
|
4453 |
delayedUpdateGeometries(); |
|
4454 |
} |
|
4455 |
||
4456 |
/*! \internal */ |
|
4457 |
||
4458 |
void Q3Table::updateRowWidgets(int row) |
|
4459 |
{ |
|
4460 |
for (int i = 0; i < numCols(); ++i) { |
|
4461 |
QWidget *w = cellWidget(row, i); |
|
4462 |
if (!w) |
|
4463 |
continue; |
|
4464 |
moveChild(w, columnPos(i), rowPos(row)); |
|
4465 |
w->resize(columnWidth(i) - 1, rowHeight(row) - 1); |
|
4466 |
} |
|
4467 |
} |
|
4468 |
||
4469 |
/*! \internal */ |
|
4470 |
||
4471 |
void Q3Table::updateColWidgets(int col) |
|
4472 |
{ |
|
4473 |
for (int i = 0; i < numRows(); ++i) { |
|
4474 |
QWidget *w = cellWidget(i, col); |
|
4475 |
if (!w) |
|
4476 |
continue; |
|
4477 |
moveChild(w, columnPos(col), rowPos(i)); |
|
4478 |
w->resize(columnWidth(col) - 1, rowHeight(i) - 1); |
|
4479 |
} |
|
4480 |
} |
|
4481 |
||
4482 |
/*! |
|
4483 |
This function is called when column order is to be changed, i.e. |
|
4484 |
when the user moved the column header \a section from \a fromIndex |
|
4485 |
to \a toIndex. |
|
4486 |
||
4487 |
If you want to change the column order programmatically, call |
|
4488 |
swapRows() or swapColumns(); |
|
4489 |
||
4490 |
\sa Q3Header::indexChange() rowIndexChanged() |
|
4491 |
*/ |
|
4492 |
||
4493 |
void Q3Table::columnIndexChanged(int, int fromIndex, int toIndex) |
|
4494 |
{ |
|
4495 |
if (doSort && lastSortCol == fromIndex && topHeader) |
|
4496 |
topHeader->setSortIndicator(toIndex, topHeader->sortIndicatorOrder()); |
|
4497 |
repaintContents(contentsX(), contentsY(), |
|
4498 |
visibleWidth(), visibleHeight(), false); |
|
4499 |
} |
|
4500 |
||
4501 |
/*! |
|
4502 |
This function is called when the order of the rows is to be |
|
4503 |
changed, i.e. the user moved the row header section \a section |
|
4504 |
from \a fromIndex to \a toIndex. |
|
4505 |
||
4506 |
If you want to change the order programmatically, call swapRows() |
|
4507 |
or swapColumns(); |
|
4508 |
||
4509 |
\sa Q3Header::indexChange() columnIndexChanged() |
|
4510 |
*/ |
|
4511 |
||
4512 |
void Q3Table::rowIndexChanged(int, int, int) |
|
4513 |
{ |
|
4514 |
repaintContents(contentsX(), contentsY(), |
|
4515 |
visibleWidth(), visibleHeight(), false); |
|
4516 |
} |
|
4517 |
||
4518 |
/*! |
|
4519 |
This function is called when the column \a col has been clicked. |
|
4520 |
The default implementation sorts this column if sorting() is true. |
|
4521 |
*/ |
|
4522 |
||
4523 |
void Q3Table::columnClicked(int col) |
|
4524 |
{ |
|
4525 |
if (!sorting()) |
|
4526 |
return; |
|
4527 |
||
4528 |
if (col == lastSortCol) { |
|
4529 |
asc = !asc; |
|
4530 |
} else { |
|
4531 |
lastSortCol = col; |
|
4532 |
asc = true; |
|
4533 |
} |
|
4534 |
sortColumn(lastSortCol, asc); |
|
4535 |
} |
|
4536 |
||
4537 |
/*! |
|
4538 |
\property Q3Table::sorting |
|
4539 |
\brief whether a click on the header of a column sorts that column |
|
4540 |
||
4541 |
\sa sortColumn() |
|
4542 |
*/ |
|
4543 |
||
4544 |
void Q3Table::setSorting(bool b) |
|
4545 |
{ |
|
4546 |
doSort = b; |
|
4547 |
if (topHeader) |
|
4548 |
topHeader->setSortIndicator(b ? lastSortCol : -1); |
|
4549 |
} |
|
4550 |
||
4551 |
bool Q3Table::sorting() const |
|
4552 |
{ |
|
4553 |
return doSort; |
|
4554 |
} |
|
4555 |
||
4556 |
static bool inUpdateGeometries = false; |
|
4557 |
||
4558 |
void Q3Table::delayedUpdateGeometries() |
|
4559 |
{ |
|
4560 |
d->geomTimer->start(0, true); |
|
4561 |
} |
|
4562 |
||
4563 |
void Q3Table::updateGeometriesSlot() |
|
4564 |
{ |
|
4565 |
updateGeometries(); |
|
4566 |
} |
|
4567 |
||
4568 |
/*! |
|
4569 |
This function updates the geometries of the left and top header. |
|
4570 |
You do not normally need to call this function. |
|
4571 |
*/ |
|
4572 |
||
4573 |
void Q3Table::updateGeometries() |
|
4574 |
{ |
|
4575 |
if (inUpdateGeometries) |
|
4576 |
return; |
|
4577 |
inUpdateGeometries = true; |
|
4578 |
QSize ts = tableSize(); |
|
4579 |
if (topHeader->offset() && |
|
4580 |
ts.width() < topHeader->offset() + topHeader->width()) |
|
4581 |
horizontalScrollBar()->setValue(ts.width() - topHeader->width()); |
|
4582 |
if (leftHeader->offset() && |
|
4583 |
ts.height() < leftHeader->offset() + leftHeader->height()) |
|
4584 |
verticalScrollBar()->setValue(ts.height() - leftHeader->height()); |
|
4585 |
||
4586 |
leftHeader->setGeometry(QStyle::visualRect(layoutDirection(), rect(), QRect(frameWidth(), topMargin() + frameWidth(), |
|
4587 |
VERTICALMARGIN, visibleHeight()))); |
|
4588 |
topHeader->setGeometry(QStyle::visualRect(layoutDirection(), rect(), QRect(VERTICALMARGIN + frameWidth(), frameWidth(), |
|
4589 |
visibleWidth(), topMargin()))); |
|
4590 |
horizontalScrollBar()->raise(); |
|
4591 |
verticalScrollBar()->raise(); |
|
4592 |
topHeader->updateStretches(); |
|
4593 |
leftHeader->updateStretches(); |
|
4594 |
inUpdateGeometries = false; |
|
4595 |
} |
|
4596 |
||
4597 |
/*! |
|
4598 |
Returns the width of column \a col. |
|
4599 |
||
4600 |
\sa setColumnWidth() rowHeight() |
|
4601 |
*/ |
|
4602 |
||
4603 |
int Q3Table::columnWidth(int col) const |
|
4604 |
{ |
|
4605 |
return topHeader->sectionSize(col); |
|
4606 |
} |
|
4607 |
||
4608 |
/*! |
|
4609 |
Returns the height of row \a row. |
|
4610 |
||
4611 |
\sa setRowHeight() columnWidth() |
|
4612 |
*/ |
|
4613 |
||
4614 |
int Q3Table::rowHeight(int row) const |
|
4615 |
{ |
|
4616 |
return leftHeader->sectionSize(row); |
|
4617 |
} |
|
4618 |
||
4619 |
/*! |
|
4620 |
Returns the x-coordinate of the column \a col in content |
|
4621 |
coordinates. |
|
4622 |
||
4623 |
\sa columnAt() rowPos() |
|
4624 |
*/ |
|
4625 |
||
4626 |
int Q3Table::columnPos(int col) const |
|
4627 |
{ |
|
4628 |
return topHeader->sectionPos(col); |
|
4629 |
} |
|
4630 |
||
4631 |
/*! |
|
4632 |
Returns the y-coordinate of the row \a row in content coordinates. |
|
4633 |
||
4634 |
\sa rowAt() columnPos() |
|
4635 |
*/ |
|
4636 |
||
4637 |
int Q3Table::rowPos(int row) const |
|
4638 |
{ |
|
4639 |
return leftHeader->sectionPos(row); |
|
4640 |
} |
|
4641 |
||
4642 |
/*! |
|
4643 |
Returns the number of the column at position \a x. \a x must be |
|
4644 |
given in content coordinates. |
|
4645 |
||
4646 |
\sa columnPos() rowAt() |
|
4647 |
*/ |
|
4648 |
||
4649 |
int Q3Table::columnAt(int x) const |
|
4650 |
{ |
|
4651 |
return topHeader->sectionAt(x); |
|
4652 |
} |
|
4653 |
||
4654 |
/*! |
|
4655 |
Returns the number of the row at position \a y. \a y must be given |
|
4656 |
in content coordinates. |
|
4657 |
||
4658 |
\sa rowPos() columnAt() |
|
4659 |
*/ |
|
4660 |
||
4661 |
int Q3Table::rowAt(int y) const |
|
4662 |
{ |
|
4663 |
return leftHeader->sectionAt(y); |
|
4664 |
} |
|
4665 |
||
4666 |
/*! |
|
4667 |
Returns the bounding rectangle of the cell at \a row, \a col in |
|
4668 |
content coordinates. |
|
4669 |
*/ |
|
4670 |
||
4671 |
QRect Q3Table::cellGeometry(int row, int col) const |
|
4672 |
{ |
|
4673 |
Q3TableItem *itm = item(row, col); |
|
4674 |
||
4675 |
if (!itm || (itm->rowSpan() == 1 && itm->colSpan() == 1)) |
|
4676 |
return QRect(columnPos(col), rowPos(row), |
|
4677 |
columnWidth(col), rowHeight(row)); |
|
4678 |
||
4679 |
while (row != itm->row()) |
|
4680 |
row--; |
|
4681 |
while (col != itm->col()) |
|
4682 |
col--; |
|
4683 |
||
4684 |
QRect rect(columnPos(col), rowPos(row), |
|
4685 |
columnWidth(col), rowHeight(row)); |
|
4686 |
||
4687 |
for (int r = 1; r < itm->rowSpan(); ++r) |
|
4688 |
rect.setHeight(rect.height() + rowHeight(r + row)); |
|
4689 |
||
4690 |
for (int c = 1; c < itm->colSpan(); ++c) |
|
4691 |
rect.setWidth(rect.width() + columnWidth(c + col)); |
|
4692 |
||
4693 |
return rect; |
|
4694 |
} |
|
4695 |
||
4696 |
/*! |
|
4697 |
Returns the size of the table. |
|
4698 |
||
4699 |
This is the same as the coordinates of the bottom-right edge of |
|
4700 |
the last table cell. |
|
4701 |
*/ |
|
4702 |
||
4703 |
QSize Q3Table::tableSize() const |
|
4704 |
{ |
|
4705 |
return QSize(columnPos(numCols() - 1) + columnWidth(numCols() - 1), |
|
4706 |
rowPos(numRows() - 1) + rowHeight(numRows() - 1)); |
|
4707 |
} |
|
4708 |
||
4709 |
/*! |
|
4710 |
\property Q3Table::numRows |
|
4711 |
\brief The number of rows in the table |
|
4712 |
||
4713 |
\sa numCols |
|
4714 |
*/ |
|
4715 |
||
4716 |
int Q3Table::numRows() const |
|
4717 |
{ |
|
4718 |
return leftHeader->count(); |
|
4719 |
} |
|
4720 |
||
4721 |
/*! |
|
4722 |
\property Q3Table::numCols |
|
4723 |
\brief The number of columns in the table |
|
4724 |
||
4725 |
\sa numRows |
|
4726 |
*/ |
|
4727 |
||
4728 |
int Q3Table::numCols() const |
|
4729 |
{ |
|
4730 |
return topHeader->count(); |
|
4731 |
} |
|
4732 |
||
4733 |
void Q3Table::saveContents(Q3PtrVector<Q3TableItem> &tmp, |
|
4734 |
Q3PtrVector<Q3Table::TableWidget> &tmp2) |
|
4735 |
{ |
|
4736 |
int nCols = numCols(); |
|
4737 |
if (editRow != -1 && editCol != -1) |
|
4738 |
endEdit(editRow, editCol, false, edMode != Editing); |
|
4739 |
tmp.resize(contents.size()); |
|
4740 |
tmp2.resize(widgets.size()); |
|
4741 |
int i; |
|
4742 |
for (i = 0; i < (int)tmp.size(); ++i) { |
|
4743 |
Q3TableItem *item = contents[ i ]; |
|
4744 |
if (item && (item->row() * nCols) + item->col() == i) |
|
4745 |
tmp.insert(i, item); |
|
4746 |
else |
|
4747 |
tmp.insert(i, 0); |
|
4748 |
} |
|
4749 |
for (i = 0; i < (int)tmp2.size(); ++i) { |
|
4750 |
QWidget *w = widgets[ i ]; |
|
4751 |
if (w) |
|
4752 |
tmp2.insert(i, new TableWidget(w, i / nCols, i % nCols)); |
|
4753 |
else |
|
4754 |
tmp2.insert(i, 0); |
|
4755 |
} |
|
4756 |
} |
|
4757 |
||
4758 |
void Q3Table::updateHeaderAndResizeContents(Q3TableHeader *header, |
|
4759 |
int num, int rowCol, |
|
4760 |
int width, bool &updateBefore) |
|
4761 |
{ |
|
4762 |
updateBefore = rowCol < num; |
|
4763 |
if (rowCol > num) { |
|
4764 |
header->Q3Header::resizeArrays(rowCol); |
|
4765 |
header->Q3TableHeader::resizeArrays(rowCol); |
|
4766 |
int old = num; |
|
4767 |
clearSelection(false); |
|
4768 |
int i = 0; |
|
4769 |
for (i = old; i < rowCol; ++i) |
|
4770 |
header->addLabel(QString(), width); |
|
4771 |
} else { |
|
4772 |
clearSelection(false); |
|
4773 |
if (header == leftHeader) { |
|
4774 |
while (numRows() > rowCol) |
|
4775 |
header->removeLabel(numRows() - 1); |
|
4776 |
} else { |
|
4777 |
while (numCols() > rowCol) |
|
4778 |
header->removeLabel(numCols() - 1); |
|
4779 |
} |
|
4780 |
} |
|
4781 |
||
4782 |
contents.setAutoDelete(false); |
|
4783 |
contents.clear(); |
|
4784 |
contents.setAutoDelete(true); |
|
4785 |
widgets.setAutoDelete(false); |
|
4786 |
widgets.clear(); |
|
4787 |
widgets.setAutoDelete(true); |
|
4788 |
resizeData(numRows() * numCols()); |
|
4789 |
||
4790 |
// keep numStretches in sync |
|
4791 |
int n = 0; |
|
4792 |
for (uint i = 0; i < header->stretchable.size(); i++) |
|
4793 |
n += (header->stretchable.at(i) & 1); // avoid cmp |
|
4794 |
header->numStretches = n; |
|
4795 |
} |
|
4796 |
||
4797 |
void Q3Table::restoreContents(Q3PtrVector<Q3TableItem> &tmp, |
|
4798 |
Q3PtrVector<Q3Table::TableWidget> &tmp2) |
|
4799 |
{ |
|
4800 |
int i; |
|
4801 |
int nCols = numCols(); |
|
4802 |
for (i = 0; i < (int)tmp.size(); ++i) { |
|
4803 |
Q3TableItem *it = tmp[ i ]; |
|
4804 |
if (it) { |
|
4805 |
int idx = (it->row() * nCols) + it->col(); |
|
4806 |
if ((uint)idx < contents.size() && |
|
4807 |
it->row() == idx / nCols && it->col() == idx % nCols) { |
|
4808 |
contents.insert(idx, it); |
|
4809 |
if (it->rowSpan() > 1 || it->colSpan() > 1) { |
|
4810 |
int ridx, iidx; |
|
4811 |
for (int irow = 0; irow < it->rowSpan(); irow++) { |
|
4812 |
ridx = idx + irow * nCols; |
|
4813 |
for (int icol = 0; icol < it->colSpan(); icol++) { |
|
4814 |
iidx = ridx + icol; |
|
4815 |
if (idx != iidx && (uint)iidx < contents.size()) |
|
4816 |
contents.insert(iidx, it); |
|
4817 |
} |
|
4818 |
} |
|
4819 |
||
4820 |
} |
|
4821 |
} else { |
|
4822 |
delete it; |
|
4823 |
} |
|
4824 |
} |
|
4825 |
} |
|
4826 |
for (i = 0; i < (int)tmp2.size(); ++i) { |
|
4827 |
TableWidget *w = tmp2[ i ]; |
|
4828 |
if (w) { |
|
4829 |
int idx = (w->row * nCols) + w->col; |
|
4830 |
if ((uint)idx < widgets.size() && |
|
4831 |
w->row == idx / nCols && w->col == idx % nCols) |
|
4832 |
widgets.insert(idx, w->wid); |
|
4833 |
else |
|
4834 |
delete w->wid; |
|
4835 |
delete w; |
|
4836 |
} |
|
4837 |
} |
|
4838 |
} |
|
4839 |
||
4840 |
void Q3Table::finishContentsResze(bool updateBefore) |
|
4841 |
{ |
|
4842 |
QRect r(cellGeometry(numRows() - 1, numCols() - 1)); |
|
4843 |
resizeContents(r.right() + 1, r.bottom() + 1); |
|
4844 |
updateGeometries(); |
|
4845 |
if (updateBefore) |
|
4846 |
repaintContents(contentsX(), contentsY(), |
|
4847 |
visibleWidth(), visibleHeight(), true); |
|
4848 |
else |
|
4849 |
repaintContents(contentsX(), contentsY(), |
|
4850 |
visibleWidth(), visibleHeight(), false); |
|
4851 |
||
4852 |
if (isRowSelection(selectionMode())) { |
|
4853 |
int r = curRow; |
|
4854 |
curRow = -1; |
|
4855 |
setCurrentCell(r, curCol); |
|
4856 |
} |
|
4857 |
} |
|
4858 |
||
4859 |
void Q3Table::setNumRows(int r) |
|
4860 |
{ |
|
4861 |
if (r < 0) |
|
4862 |
return; |
|
4863 |
||
4864 |
if (r < numRows()) { |
|
4865 |
// Removed rows are no longer hidden, and should thus be removed from "hiddenRows" |
|
4866 |
for (int rr = numRows()-1; rr >= r; --rr) { |
|
4867 |
if (d->hiddenRows.find(rr)) |
|
4868 |
d->hiddenRows.remove(rr); |
|
4869 |
} |
|
4870 |
} |
|
4871 |
||
4872 |
fontChange(font()); // invalidate the sizeHintCache |
|
4873 |
||
4874 |
Q3PtrVector<Q3TableItem> tmp; |
|
4875 |
Q3PtrVector<TableWidget> tmp2; |
|
4876 |
saveContents(tmp, tmp2); |
|
4877 |
||
4878 |
bool updatesEnabled = leftHeader->updatesEnabled(); |
|
4879 |
if (updatesEnabled) |
|
4880 |
leftHeader->setUpdatesEnabled(false); |
|
4881 |
||
4882 |
bool updateBefore; |
|
4883 |
updateHeaderAndResizeContents(leftHeader, numRows(), r, 20, updateBefore); |
|
4884 |
||
4885 |
int w = fontMetrics().width(QString::number(r) + QLatin1Char('W')); |
|
4886 |
if (VERTICALMARGIN > 0 && w > VERTICALMARGIN) |
|
4887 |
setLeftMargin(w); |
|
4888 |
||
4889 |
restoreContents(tmp, tmp2); |
|
4890 |
||
4891 |
leftHeader->calculatePositions(); |
|
4892 |
finishContentsResze(updateBefore); |
|
4893 |
if (updatesEnabled) { |
|
4894 |
leftHeader->setUpdatesEnabled(true); |
|
4895 |
leftHeader->update(); |
|
4896 |
} |
|
4897 |
leftHeader->updateCache(); |
|
4898 |
if (curRow >= numRows()) { |
|
4899 |
curRow = numRows() - 1; |
|
4900 |
if (curRow < 0) |
|
4901 |
curCol = -1; |
|
4902 |
else |
|
4903 |
repaintCell(curRow, curCol); |
|
4904 |
} |
|
4905 |
||
4906 |
if (curRow > numRows()) |
|
4907 |
curRow = numRows(); |
|
4908 |
} |
|
4909 |
||
4910 |
void Q3Table::setNumCols(int c) |
|
4911 |
{ |
|
4912 |
if (c < 0) |
|
4913 |
return; |
|
4914 |
||
4915 |
if (c < numCols()) { |
|
4916 |
// Removed columns are no longer hidden, and should thus be removed from "hiddenCols" |
|
4917 |
for (int cc = numCols()-1; cc >= c; --cc) { |
|
4918 |
if (d->hiddenCols.find(cc)) |
|
4919 |
d->hiddenCols.remove(cc); |
|
4920 |
} |
|
4921 |
} |
|
4922 |
||
4923 |
fontChange(font()); // invalidate the sizeHintCache |
|
4924 |
||
4925 |
Q3PtrVector<Q3TableItem> tmp; |
|
4926 |
Q3PtrVector<TableWidget> tmp2; |
|
4927 |
saveContents(tmp, tmp2); |
|
4928 |
||
4929 |
bool updatesEnabled = topHeader->updatesEnabled(); |
|
4930 |
if (updatesEnabled) |
|
4931 |
topHeader->setUpdatesEnabled(false); |
|
4932 |
||
4933 |
bool updateBefore; |
|
4934 |
updateHeaderAndResizeContents(topHeader, numCols(), c, 100, updateBefore); |
|
4935 |
||
4936 |
restoreContents(tmp, tmp2); |
|
4937 |
||
4938 |
topHeader->calculatePositions(); |
|
4939 |
finishContentsResze(updateBefore); |
|
4940 |
if (updatesEnabled) { |
|
4941 |
topHeader->setUpdatesEnabled(true); |
|
4942 |
topHeader->update(); |
|
4943 |
} |
|
4944 |
topHeader->updateCache(); |
|
4945 |
if (curCol >= numCols()) { |
|
4946 |
curCol = numCols() - 1; |
|
4947 |
if (curCol < 0) |
|
4948 |
curRow = -1; |
|
4949 |
else |
|
4950 |
repaintCell(curRow, curCol); |
|
4951 |
} |
|
4952 |
} |
|
4953 |
||
4954 |
/*! Sets the section labels of the verticalHeader() to \a labels */ |
|
4955 |
||
4956 |
void Q3Table::setRowLabels(const QStringList &labels) |
|
4957 |
{ |
|
4958 |
leftHeader->setLabels(labels); |
|
4959 |
} |
|
4960 |
||
4961 |
/*! Sets the section labels of the horizontalHeader() to \a labels */ |
|
4962 |
||
4963 |
void Q3Table::setColumnLabels(const QStringList &labels) |
|
4964 |
{ |
|
4965 |
topHeader->setLabels(labels); |
|
4966 |
} |
|
4967 |
||
4968 |
/*! |
|
4969 |
This function returns the widget which should be used as an editor |
|
4970 |
for the contents of the cell at \a row, \a col. |
|
4971 |
||
4972 |
If \a initFromCell is true, the editor is used to edit the current |
|
4973 |
contents of the cell (so the editor widget should be initialized |
|
4974 |
with this content). If \a initFromCell is false, the content of |
|
4975 |
the cell is replaced with the new content which the user entered |
|
4976 |
into the widget created by this function. |
|
4977 |
||
4978 |
The default functionality is as follows: if \a initFromCell is |
|
4979 |
true or the cell has a Q3TableItem and the table item's |
|
4980 |
Q3TableItem::isReplaceable() is false then the cell is asked to |
|
4981 |
create an appropriate editor (using Q3TableItem::createEditor()). |
|
4982 |
Otherwise a QLineEdit is used as the editor. |
|
4983 |
||
4984 |
If you want to create your own editor for certain cells, implement |
|
4985 |
a custom Q3TableItem subclass and reimplement |
|
4986 |
Q3TableItem::createEditor(). |
|
4987 |
||
4988 |
If you are not using \l{Q3TableItem}s and you don't want to use a |
|
4989 |
QLineEdit as the default editor, subclass Q3Table and reimplement |
|
4990 |
this function with code like this: |
|
4991 |
\snippet doc/src/snippets/code/src_qt3support_itemviews_q3table.cpp 5 |
|
4992 |
Ownership of the editor widget is transferred to the caller. |
|
4993 |
||
4994 |
If you reimplement this function return 0 for read-only cells. You |
|
4995 |
will need to reimplement setCellContentFromEditor() to retrieve |
|
4996 |
the data the user entered. |
|
4997 |
||
4998 |
\sa Q3TableItem::createEditor() |
|
4999 |
*/ |
|
5000 |
||
5001 |
QWidget *Q3Table::createEditor(int row, int col, bool initFromCell) const |
|
5002 |
{ |
|
5003 |
if (isReadOnly() || isRowReadOnly(row) || isColumnReadOnly(col)) |
|
5004 |
return 0; |
|
5005 |
||
5006 |
QWidget *e = 0; |
|
5007 |
||
5008 |
// the current item in the cell should be edited if possible |
|
5009 |
Q3TableItem *i = item(row, col); |
|
5010 |
if (initFromCell || (i && !i->isReplaceable())) { |
|
5011 |
if (i) { |
|
5012 |
if (i->editType() == Q3TableItem::Never) |
|
5013 |
return 0; |
|
5014 |
||
5015 |
e = i->createEditor(); |
|
5016 |
if (!e) |
|
5017 |
return 0; |
|
5018 |
} |
|
5019 |
} |
|
5020 |
||
5021 |
// no contents in the cell yet, so open the default editor |
|
5022 |
if (!e) { |
|
5023 |
e = new QLineEdit(viewport(), "qt_lineeditor"); |
|
5024 |
((QLineEdit*)e)->setFrame(false); |
|
5025 |
} |
|
5026 |
||
5027 |
return e; |
|
5028 |
} |
|
5029 |
||
5030 |
/*! |
|
5031 |
This function is called to start in-place editing of the cell at |
|
5032 |
\a row, \a col. Editing is achieved by creating an editor |
|
5033 |
(createEditor() is called) and setting the cell's editor with |
|
5034 |
setCellWidget() to the newly created editor. (After editing is |
|
5035 |
complete endEdit() will be called to replace the cell's content |
|
5036 |
with the editor's content.) If \a replace is true the editor will |
|
5037 |
start empty; otherwise it will be initialized with the cell's |
|
5038 |
content (if any), i.e. the user will be modifying the original |
|
5039 |
cell content. |
|
5040 |
||
5041 |
\sa endEdit() |
|
5042 |
*/ |
|
5043 |
||
5044 |
QWidget *Q3Table::beginEdit(int row, int col, bool replace) |
|
5045 |
{ |
|
5046 |
if (isReadOnly() || isRowReadOnly(row) || isColumnReadOnly(col)) |
|
5047 |
return 0; |
|
5048 |
if ( row < 0 || row >= numRows() || col < 0 || col >= numCols() ) |
|
5049 |
return 0; |
|
5050 |
Q3TableItem *itm = item(row, col); |
|
5051 |
if (itm && !itm->isEnabled()) |
|
5052 |
return 0; |
|
5053 |
if (cellWidget(row, col)) |
|
5054 |
return 0; |
|
5055 |
ensureCellVisible(row, col); |
|
5056 |
QWidget *e = createEditor(row, col, !replace); |
|
5057 |
if (!e) |
|
5058 |
return 0; |
|
5059 |
setCellWidget(row, col, e); |
|
5060 |
e->setActiveWindow(); |
|
5061 |
e->setFocus(); |
|
5062 |
updateCell(row, col); |
|
5063 |
return e; |
|
5064 |
} |
|
5065 |
||
5066 |
/*! |
|
5067 |
This function is called when in-place editing of the cell at \a |
|
5068 |
row, \a col is requested to stop. |
|
5069 |
||
5070 |
If the cell is not being edited or \a accept is false the function |
|
5071 |
returns and the cell's contents are left unchanged. |
|
5072 |
||
5073 |
If \a accept is true the content of the editor must be transferred |
|
5074 |
to the relevant cell. If \a replace is true the current content of |
|
5075 |
this cell should be replaced by the content of the editor (this |
|
5076 |
means removing the current Q3TableItem of the cell and creating a |
|
5077 |
new one for the cell). Otherwise (if possible) the content of the |
|
5078 |
editor should just be set to the existing Q3TableItem of this cell. |
|
5079 |
||
5080 |
setCellContentFromEditor() is called to replace the contents of |
|
5081 |
the cell with the contents of the cell's editor. |
|
5082 |
||
5083 |
Finally clearCellWidget() is called to remove the editor widget. |
|
5084 |
||
5085 |
\sa setCellContentFromEditor(), beginEdit() |
|
5086 |
*/ |
|
5087 |
||
5088 |
void Q3Table::endEdit(int row, int col, bool accept, bool replace) |
|
5089 |
{ |
|
5090 |
QWidget *editor = cellWidget(row, col); |
|
5091 |
if (!editor) |
|
5092 |
return; |
|
5093 |
||
5094 |
if (!accept) { |
|
5095 |
if (row == editRow && col == editCol) |
|
5096 |
setEditMode(NotEditing, -1, -1); |
|
5097 |
clearCellWidget(row, col); |
|
5098 |
updateCell(row, col); |
|
5099 |
viewport()->setFocus(); |
|
5100 |
updateCell(row, col); |
|
5101 |
return; |
|
5102 |
} |
|
5103 |
||
5104 |
Q3TableItem *i = item(row, col); |
|
5105 |
QString oldContent; |
|
5106 |
if (i) |
|
5107 |
oldContent = i->text(); |
|
5108 |
||
5109 |
if (!i || replace) { |
|
5110 |
setCellContentFromEditor(row, col); |
|
5111 |
i = item(row, col); |
|
5112 |
} else { |
|
5113 |
i->setContentFromEditor(editor); |
|
5114 |
} |
|
5115 |
||
5116 |
if (row == editRow && col == editCol) |
|
5117 |
setEditMode(NotEditing, -1, -1); |
|
5118 |
||
5119 |
viewport()->setFocus(); |
|
5120 |
updateCell(row, col); |
|
5121 |
||
5122 |
if (!i || (oldContent != i->text())) |
|
5123 |
emit valueChanged(row, col); |
|
5124 |
||
5125 |
clearCellWidget(row, col); |
|
5126 |
} |
|
5127 |
||
5128 |
/*! |
|
5129 |
This function is called to replace the contents of the cell at \a |
|
5130 |
row, \a col with the contents of the cell's editor. |
|
5131 |
||
5132 |
If there already exists a Q3TableItem for the cell, |
|
5133 |
it calls Q3TableItem::setContentFromEditor() on this Q3TableItem. |
|
5134 |
||
5135 |
If, for example, you want to create different \l{Q3TableItem}s |
|
5136 |
depending on the contents of the editor, you might reimplement |
|
5137 |
this function. |
|
5138 |
||
5139 |
If you want to work without \l{Q3TableItem}s, you will need to |
|
5140 |
reimplement this function to save the data the user entered into |
|
5141 |
your data structure. (See the notes on large tables.) |
|
5142 |
||
5143 |
\sa Q3TableItem::setContentFromEditor() createEditor() |
|
5144 |
*/ |
|
5145 |
||
5146 |
void Q3Table::setCellContentFromEditor(int row, int col) |
|
5147 |
{ |
|
5148 |
QWidget *editor = cellWidget(row, col); |
|
5149 |
if (!editor) |
|
5150 |
return; |
|
5151 |
||
5152 |
Q3TableItem *i = item(row, col); |
|
5153 |
if (i) { |
|
5154 |
i->setContentFromEditor(editor); |
|
5155 |
} else { |
|
5156 |
QLineEdit *le = qobject_cast<QLineEdit*>(editor); |
|
5157 |
if (le) |
|
5158 |
setText(row, col, le->text()); |
|
5159 |
} |
|
5160 |
} |
|
5161 |
||
5162 |
/*! |
|
5163 |
Returns true if the \l EditMode is \c Editing or \c Replacing; |
|
5164 |
otherwise (i.e. the \l EditMode is \c NotEditing) returns false. |
|
5165 |
||
5166 |
\sa Q3Table::EditMode |
|
5167 |
*/ |
|
5168 |
||
5169 |
bool Q3Table::isEditing() const |
|
5170 |
{ |
|
5171 |
return edMode != NotEditing; |
|
5172 |
} |
|
5173 |
||
5174 |
/*! |
|
5175 |
Returns the current edit mode |
|
5176 |
||
5177 |
\sa Q3Table::EditMode |
|
5178 |
*/ |
|
5179 |
||
5180 |
Q3Table::EditMode Q3Table::editMode() const |
|
5181 |
{ |
|
5182 |
return edMode; |
|
5183 |
} |
|
5184 |
||
5185 |
/*! |
|
5186 |
Returns the current edited row |
|
5187 |
*/ |
|
5188 |
||
5189 |
int Q3Table::currEditRow() const |
|
5190 |
{ |
|
5191 |
return editRow; |
|
5192 |
} |
|
5193 |
||
5194 |
/*! |
|
5195 |
Returns the current edited column |
|
5196 |
*/ |
|
5197 |
||
5198 |
int Q3Table::currEditCol() const |
|
5199 |
{ |
|
5200 |
return editCol; |
|
5201 |
} |
|
5202 |
||
5203 |
/*! |
|
5204 |
Returns a single integer which identifies a particular \a row and \a |
|
5205 |
col by mapping the 2D table to a 1D array. |
|
5206 |
||
5207 |
This is useful, for example, if you have a sparse table and want to |
|
5208 |
use a Q3IntDict to map integers to the cells that are used. |
|
5209 |
*/ |
|
5210 |
||
5211 |
int Q3Table::indexOf(int row, int col) const |
|
5212 |
{ |
|
5213 |
return (row * numCols()) + col; |
|
5214 |
} |
|
5215 |
||
5216 |
/*! \internal |
|
5217 |
*/ |
|
5218 |
||
5219 |
void Q3Table::repaintSelections(Q3TableSelection *oldSelection, |
|
5220 |
Q3TableSelection *newSelection, |
|
5221 |
bool updateVertical, bool updateHorizontal) |
|
5222 |
{ |
|
5223 |
if (!oldSelection && !newSelection) |
|
5224 |
return; |
|
5225 |
if (oldSelection && newSelection && *oldSelection == *newSelection) |
|
5226 |
return; |
|
5227 |
if (oldSelection && !oldSelection->isActive()) |
|
5228 |
oldSelection = 0; |
|
5229 |
||
5230 |
bool optimizeOld = false; |
|
5231 |
bool optimizeNew = false; |
|
5232 |
||
5233 |
QRect old; |
|
5234 |
if (oldSelection) |
|
5235 |
old = rangeGeometry(oldSelection->topRow(), |
|
5236 |
oldSelection->leftCol(), |
|
5237 |
oldSelection->bottomRow(), |
|
5238 |
oldSelection->rightCol(), |
|
5239 |
optimizeOld); |
|
5240 |
else |
|
5241 |
old = QRect(0, 0, 0, 0); |
|
5242 |
||
5243 |
QRect cur; |
|
5244 |
if (newSelection) |
|
5245 |
cur = rangeGeometry(newSelection->topRow(), |
|
5246 |
newSelection->leftCol(), |
|
5247 |
newSelection->bottomRow(), |
|
5248 |
newSelection->rightCol(), |
|
5249 |
optimizeNew); |
|
5250 |
else |
|
5251 |
cur = QRect(0, 0, 0, 0); |
|
5252 |
int i; |
|
5253 |
||
5254 |
if (!optimizeOld || !optimizeNew || |
|
5255 |
old.width() > SHRT_MAX || old.height() > SHRT_MAX || |
|
5256 |
cur.width() > SHRT_MAX || cur.height() > SHRT_MAX) { |
|
5257 |
QRect rr = cur.united(old); |
|
5258 |
repaintContents(rr, false); |
|
5259 |
} else { |
|
5260 |
old = QRect(contentsToViewport2(old.topLeft()), old.size()); |
|
5261 |
cur = QRect(contentsToViewport2(cur.topLeft()), cur.size()); |
|
5262 |
QRegion r1(old); |
|
5263 |
QRegion r2(cur); |
|
5264 |
QRegion r3 = r1.subtracted(r2); |
|
5265 |
QRegion r4 = r2.subtracted(r1); |
|
5266 |
||
5267 |
for (i = 0; i < (int)r3.rects().count(); ++i) { |
|
5268 |
QRect r(r3.rects()[ i ]); |
|
5269 |
r = QRect(viewportToContents2(r.topLeft()), r.size()); |
|
5270 |
repaintContents(r, false); |
|
5271 |
} |
|
5272 |
for (i = 0; i < (int)r4.rects().count(); ++i) { |
|
5273 |
QRect r(r4.rects()[ i ]); |
|
5274 |
r = QRect(viewportToContents2(r.topLeft()), r.size()); |
|
5275 |
repaintContents(r, false); |
|
5276 |
} |
|
5277 |
} |
|
5278 |
||
5279 |
int top, left, bottom, right; |
|
5280 |
{ |
|
5281 |
int oldTopRow = oldSelection ? oldSelection->topRow() : numRows() - 1; |
|
5282 |
int newTopRow = newSelection ? newSelection->topRow() : numRows() - 1; |
|
5283 |
top = QMIN(oldTopRow, newTopRow); |
|
5284 |
} |
|
5285 |
||
5286 |
{ |
|
5287 |
int oldLeftCol = oldSelection ? oldSelection->leftCol() : numCols() - 1; |
|
5288 |
int newLeftCol = newSelection ? newSelection->leftCol() : numCols() - 1; |
|
5289 |
left = QMIN(oldLeftCol, newLeftCol); |
|
5290 |
} |
|
5291 |
||
5292 |
{ |
|
5293 |
int oldBottomRow = oldSelection ? oldSelection->bottomRow() : 0; |
|
5294 |
int newBottomRow = newSelection ? newSelection->bottomRow() : 0; |
|
5295 |
bottom = QMAX(oldBottomRow, newBottomRow); |
|
5296 |
} |
|
5297 |
||
5298 |
{ |
|
5299 |
int oldRightCol = oldSelection ? oldSelection->rightCol() : 0; |
|
5300 |
int newRightCol = newSelection ? newSelection->rightCol() : 0; |
|
5301 |
right = QMAX(oldRightCol, newRightCol); |
|
5302 |
} |
|
5303 |
||
5304 |
if (updateHorizontal && numCols() > 0 && left >= 0 && !isRowSelection(selectionMode())) { |
|
5305 |
register int *s = &topHeader->states.data()[left]; |
|
5306 |
for (i = left; i <= right; ++i) { |
|
5307 |
if (!isColumnSelected(i)) |
|
5308 |
*s = Q3TableHeader::Normal; |
|
5309 |
else if (isColumnSelected(i, true)) |
|
5310 |
*s = Q3TableHeader::Selected; |
|
5311 |
else |
|
5312 |
*s = Q3TableHeader::Bold; |
|
5313 |
++s; |
|
5314 |
} |
|
5315 |
topHeader->repaint(false); |
|
5316 |
} |
|
5317 |
||
5318 |
if (updateVertical && numRows() > 0 && top >= 0) { |
|
5319 |
register int *s = &leftHeader->states.data()[top]; |
|
5320 |
for (i = top; i <= bottom; ++i) { |
|
5321 |
if (!isRowSelected(i)) |
|
5322 |
*s = Q3TableHeader::Normal; |
|
5323 |
else if (isRowSelected(i, true)) |
|
5324 |
*s = Q3TableHeader::Selected; |
|
5325 |
else |
|
5326 |
*s = Q3TableHeader::Bold; |
|
5327 |
++s; |
|
5328 |
} |
|
5329 |
leftHeader->repaint(false); |
|
5330 |
} |
|
5331 |
} |
|
5332 |
||
5333 |
/*! |
|
5334 |
Repaints all selections |
|
5335 |
*/ |
|
5336 |
||
5337 |
void Q3Table::repaintSelections() |
|
5338 |
{ |
|
5339 |
if (selections.isEmpty()) |
|
5340 |
return; |
|
5341 |
||
5342 |
QRect r; |
|
5343 |
for (Q3TableSelection *s = selections.first(); s; s = selections.next()) { |
|
5344 |
bool b; |
|
5345 |
r = r.united(rangeGeometry(s->topRow(), |
|
5346 |
s->leftCol(), |
|
5347 |
s->bottomRow(), |
|
5348 |
s->rightCol(), b)); |
|
5349 |
} |
|
5350 |
||
5351 |
repaintContents(r, false); |
|
5352 |
} |
|
5353 |
||
5354 |
/*! |
|
5355 |
Clears all selections and repaints the appropriate regions if \a |
|
5356 |
repaint is true. |
|
5357 |
||
5358 |
\sa removeSelection() |
|
5359 |
*/ |
|
5360 |
||
5361 |
void Q3Table::clearSelection(bool repaint) |
|
5362 |
{ |
|
5363 |
if (selections.isEmpty()) |
|
5364 |
return; |
|
5365 |
bool needRepaint = !selections.isEmpty(); |
|
5366 |
||
5367 |
QRect r; |
|
5368 |
for (Q3TableSelection *s = selections.first(); s; s = selections.next()) { |
|
5369 |
bool b; |
|
5370 |
r = r.united(rangeGeometry(s->topRow(), |
|
5371 |
s->leftCol(), |
|
5372 |
s->bottomRow(), |
|
5373 |
s->rightCol(), b)); |
|
5374 |
} |
|
5375 |
||
5376 |
currentSel = 0; |
|
5377 |
selections.clear(); |
|
5378 |
||
5379 |
if (needRepaint && repaint) |
|
5380 |
repaintContents(r, false); |
|
5381 |
||
5382 |
leftHeader->setSectionStateToAll(Q3TableHeader::Normal); |
|
5383 |
leftHeader->repaint(false); |
|
5384 |
if (!isRowSelection(selectionMode())) { |
|
5385 |
topHeader->setSectionStateToAll(Q3TableHeader::Normal); |
|
5386 |
topHeader->repaint(false); |
|
5387 |
} |
|
5388 |
topHeader->setSectionState(curCol, Q3TableHeader::Bold); |
|
5389 |
leftHeader->setSectionState(curRow, Q3TableHeader::Bold); |
|
5390 |
emit selectionChanged(); |
|
5391 |
} |
|
5392 |
||
5393 |
/*! \internal |
|
5394 |
*/ |
|
5395 |
||
5396 |
QRect Q3Table::rangeGeometry(int topRow, int leftCol, |
|
5397 |
int bottomRow, int rightCol, bool &optimize) |
|
5398 |
{ |
|
5399 |
topRow = QMAX(topRow, rowAt(contentsY())); |
|
5400 |
leftCol = QMAX(leftCol, columnAt(contentsX())); |
|
5401 |
int ra = rowAt(contentsY() + visibleHeight()); |
|
5402 |
if (ra != -1) |
|
5403 |
bottomRow = QMIN(bottomRow, ra); |
|
5404 |
int ca = columnAt(contentsX() + visibleWidth()); |
|
5405 |
if (ca != -1) |
|
5406 |
rightCol = QMIN(rightCol, ca); |
|
5407 |
optimize = true; |
|
5408 |
QRect rect; |
|
5409 |
for (int r = topRow; r <= bottomRow; ++r) { |
|
5410 |
for (int c = leftCol; c <= rightCol; ++c) { |
|
5411 |
rect = rect.united(cellGeometry(r, c)); |
|
5412 |
Q3TableItem *i = item(r, c); |
|
5413 |
if (i && (i->rowSpan() > 1 || i->colSpan() > 1)) |
|
5414 |
optimize = false; |
|
5415 |
} |
|
5416 |
} |
|
5417 |
return rect; |
|
5418 |
} |
|
5419 |
||
5420 |
/*! |
|
5421 |
This function is called to activate the next cell if in-place |
|
5422 |
editing was finished by pressing the Enter key. |
|
5423 |
||
5424 |
The default behaviour is to move from top to bottom, i.e. move to |
|
5425 |
the cell beneath the cell being edited. Reimplement this function |
|
5426 |
if you want different behaviour, e.g. moving from left to right. |
|
5427 |
*/ |
|
5428 |
||
5429 |
void Q3Table::activateNextCell() |
|
5430 |
{ |
|
5431 |
int firstRow = 0; |
|
5432 |
while (d->hiddenRows.find(firstRow)) |
|
5433 |
firstRow++; |
|
5434 |
int firstCol = 0; |
|
5435 |
while (d->hiddenCols.find(firstCol)) |
|
5436 |
firstCol++; |
|
5437 |
int nextRow = curRow; |
|
5438 |
int nextCol = curCol; |
|
5439 |
while (d->hiddenRows.find(++nextRow)) {} |
|
5440 |
if (nextRow >= numRows()) { |
|
5441 |
nextRow = firstRow; |
|
5442 |
while (d->hiddenCols.find(++nextCol)) {} |
|
5443 |
if (nextCol >= numCols()) |
|
5444 |
nextCol = firstCol; |
|
5445 |
} |
|
5446 |
||
5447 |
if (!currentSel || !currentSel->isActive() || |
|
5448 |
(currentSel->leftCol() == currentSel->rightCol() && |
|
5449 |
currentSel->topRow() == currentSel->bottomRow())) { |
|
5450 |
clearSelection(); |
|
5451 |
setCurrentCell(nextRow, nextCol); |
|
5452 |
} else { |
|
5453 |
if (curRow < currentSel->bottomRow()) |
|
5454 |
setCurrentCell(nextRow, curCol); |
|
5455 |
else if (curCol < currentSel->rightCol()) |
|
5456 |
setCurrentCell(currentSel->topRow(), nextCol); |
|
5457 |
else |
|
5458 |
setCurrentCell(currentSel->topRow(), currentSel->leftCol()); |
|
5459 |
} |
|
5460 |
||
5461 |
} |
|
5462 |
||
5463 |
/*! \internal |
|
5464 |
*/ |
|
5465 |
||
5466 |
void Q3Table::fixRow(int &row, int y) |
|
5467 |
{ |
|
5468 |
if (row == -1) { |
|
5469 |
if (y < 0) |
|
5470 |
row = 0; |
|
5471 |
else |
|
5472 |
row = numRows() - 1; |
|
5473 |
} |
|
5474 |
} |
|
5475 |
||
5476 |
/*! \internal |
|
5477 |
*/ |
|
5478 |
||
5479 |
void Q3Table::fixCol(int &col, int x) |
|
5480 |
{ |
|
5481 |
if (col == -1) { |
|
5482 |
if (x < 0) |
|
5483 |
col = 0; |
|
5484 |
else |
|
5485 |
col = numCols() - 1; |
|
5486 |
} |
|
5487 |
} |
|
5488 |
||
5489 |
struct SortableTableItem |
|
5490 |
{ |
|
5491 |
Q3TableItem *item; |
|
5492 |
}; |
|
5493 |
||
5494 |
#if defined(Q_C_CALLBACKS) |
|
5495 |
extern "C" { |
|
5496 |
#endif |
|
5497 |
||
5498 |
#ifdef Q_OS_WINCE |
|
5499 |
static int _cdecl cmpTableItems(const void *n1, const void *n2) |
|
5500 |
#else |
|
5501 |
static int cmpTableItems(const void *n1, const void *n2) |
|
5502 |
#endif |
|
5503 |
{ |
|
5504 |
if (!n1 || !n2) |
|
5505 |
return 0; |
|
5506 |
||
5507 |
SortableTableItem *i1 = (SortableTableItem *)n1; |
|
5508 |
SortableTableItem *i2 = (SortableTableItem *)n2; |
|
5509 |
||
5510 |
return i1->item->key().localeAwareCompare(i2->item->key()); |
|
5511 |
} |
|
5512 |
||
5513 |
#if defined(Q_C_CALLBACKS) |
|
5514 |
} |
|
5515 |
#endif |
|
5516 |
||
5517 |
/*! |
|
5518 |
Sorts column \a col. If \a ascending is true the sort is in |
|
5519 |
ascending order, otherwise the sort is in descending order. |
|
5520 |
||
5521 |
If \a wholeRows is true, entire rows are sorted using swapRows(); |
|
5522 |
otherwise only cells in the column are sorted using swapCells(). |
|
5523 |
||
5524 |
Note that if you are not using Q3TableItems you will need to |
|
5525 |
reimplement swapRows() and swapCells(). (See the notes on large |
|
5526 |
tables.) |
|
5527 |
||
5528 |
\sa swapRows() |
|
5529 |
*/ |
|
5530 |
||
5531 |
void Q3Table::sortColumn(int col, bool ascending, bool wholeRows) |
|
5532 |
{ |
|
5533 |
int filledRows = 0, i; |
|
5534 |
for (i = 0; i < numRows(); ++i) { |
|
5535 |
Q3TableItem *itm = item(i, col); |
|
5536 |
if (itm) |
|
5537 |
filledRows++; |
|
5538 |
} |
|
5539 |
||
5540 |
if (!filledRows) |
|
5541 |
return; |
|
5542 |
||
5543 |
SortableTableItem *items = new SortableTableItem[ filledRows ]; |
|
5544 |
int j = 0; |
|
5545 |
for (i = 0; i < numRows(); ++i) { |
|
5546 |
Q3TableItem *itm = item(i, col); |
|
5547 |
if (!itm) |
|
5548 |
continue; |
|
5549 |
items[ j++ ].item = itm; |
|
5550 |
} |
|
5551 |
||
5552 |
qsort(items, filledRows, sizeof(SortableTableItem), cmpTableItems); |
|
5553 |
||
5554 |
bool updatesWereEnabled = updatesEnabled(); |
|
5555 |
if (updatesWereEnabled) |
|
5556 |
setUpdatesEnabled(false); |
|
5557 |
for (i = 0; i < numRows(); ++i) { |
|
5558 |
if (i < filledRows) { |
|
5559 |
if (ascending) { |
|
5560 |
if (items[ i ].item->row() == i) |
|
5561 |
continue; |
|
5562 |
if (wholeRows) |
|
5563 |
swapRows(items[ i ].item->row(), i); |
|
5564 |
else |
|
5565 |
swapCells(items[ i ].item->row(), col, i, col); |
|
5566 |
} else { |
|
5567 |
if (items[ i ].item->row() == filledRows - i - 1) |
|
5568 |
continue; |
|
5569 |
if (wholeRows) |
|
5570 |
swapRows(items[ i ].item->row(), filledRows - i - 1); |
|
5571 |
else |
|
5572 |
swapCells(items[ i ].item->row(), col, |
|
5573 |
filledRows - i - 1, col); |
|
5574 |
} |
|
5575 |
} |
|
5576 |
} |
|
5577 |
if (updatesWereEnabled) |
|
5578 |
setUpdatesEnabled(true); |
|
5579 |
if (topHeader) |
|
5580 |
topHeader->setSortIndicator(col, ascending ? Qt::Ascending : Qt::Descending); |
|
5581 |
||
5582 |
if (!wholeRows) |
|
5583 |
repaintContents(columnPos(col), contentsY(), |
|
5584 |
columnWidth(col), visibleHeight(), false); |
|
5585 |
else |
|
5586 |
repaintContents(contentsX(), contentsY(), |
|
5587 |
visibleWidth(), visibleHeight(), false); |
|
5588 |
||
5589 |
delete [] items; |
|
5590 |
} |
|
5591 |
||
5592 |
/*! |
|
5593 |
Hides row \a row. |
|
5594 |
||
5595 |
\sa showRow() hideColumn() |
|
5596 |
*/ |
|
5597 |
||
5598 |
void Q3Table::hideRow(int row) |
|
5599 |
{ |
|
5600 |
if (d->hiddenRows.find(row)) |
|
5601 |
return; |
|
5602 |
d->hiddenRows.replace(row, new int(leftHeader->sectionSize(row))); |
|
5603 |
leftHeader->resizeSection(row, 0); |
|
5604 |
leftHeader->setResizeEnabled(false, row); |
|
5605 |
if (isRowStretchable(row)) |
|
5606 |
leftHeader->numStretches--; |
|
5607 |
rowHeightChanged(row); |
|
5608 |
if (curRow == row) { |
|
5609 |
int r = curRow; |
|
5610 |
int c = curCol; |
|
5611 |
int k = (r >= numRows() - 1 ? Key_Up : Key_Down); |
|
5612 |
fixCell(r, c, k); |
|
5613 |
if (numRows() > 0) |
|
5614 |
setCurrentCell(r, c); |
|
5615 |
} |
|
5616 |
} |
|
5617 |
||
5618 |
/*! |
|
5619 |
Hides column \a col. |
|
5620 |
||
5621 |
\sa showColumn() hideRow() |
|
5622 |
*/ |
|
5623 |
||
5624 |
void Q3Table::hideColumn(int col) |
|
5625 |
{ |
|
5626 |
if (!numCols() || d->hiddenCols.find(col)) |
|
5627 |
return; |
|
5628 |
d->hiddenCols.replace(col, new int(topHeader->sectionSize(col))); |
|
5629 |
topHeader->resizeSection(col, 0); |
|
5630 |
topHeader->setResizeEnabled(false, col); |
|
5631 |
if (isColumnStretchable(col)) |
|
5632 |
topHeader->numStretches--; |
|
5633 |
columnWidthChanged(col); |
|
5634 |
if (curCol == col) { |
|
5635 |
int r = curRow; |
|
5636 |
int c = curCol; |
|
5637 |
int k = (c >= numCols() - 1 ? Key_Left : Key_Right); |
|
5638 |
fixCell(r, c, k); |
|
5639 |
if (numCols() > 0) |
|
5640 |
setCurrentCell(r, c); |
|
5641 |
} |
|
5642 |
} |
|
5643 |
||
5644 |
/*! |
|
5645 |
Shows row \a row. |
|
5646 |
||
5647 |
\sa hideRow() showColumn() |
|
5648 |
*/ |
|
5649 |
||
5650 |
void Q3Table::showRow(int row) |
|
5651 |
{ |
|
5652 |
int *h = d->hiddenRows.find(row); |
|
5653 |
if (h) { |
|
5654 |
int rh = *h; |
|
5655 |
d->hiddenRows.remove(row); |
|
5656 |
setRowHeight(row, rh); |
|
5657 |
if (isRowStretchable(row)) |
|
5658 |
leftHeader->numStretches++; |
|
5659 |
} else if (rowHeight(row) == 0) { |
|
5660 |
setRowHeight(row, 20); |
|
5661 |
} |
|
5662 |
leftHeader->setResizeEnabled(true, row); |
|
5663 |
} |
|
5664 |
||
5665 |
/*! |
|
5666 |
Shows column \a col. |
|
5667 |
||
5668 |
\sa hideColumn() showRow() |
|
5669 |
*/ |
|
5670 |
||
5671 |
void Q3Table::showColumn(int col) |
|
5672 |
{ |
|
5673 |
int *w = d->hiddenCols.find(col); |
|
5674 |
if (w) { |
|
5675 |
int cw = *w; |
|
5676 |
d->hiddenCols.remove(col); |
|
5677 |
setColumnWidth(col, cw); |
|
5678 |
if (isColumnStretchable(col)) |
|
5679 |
topHeader->numStretches++; |
|
5680 |
} else if (columnWidth(col) == 0) { |
|
5681 |
setColumnWidth(col, 20); |
|
5682 |
} |
|
5683 |
topHeader->setResizeEnabled(true, col); |
|
5684 |
} |
|
5685 |
||
5686 |
/*! |
|
5687 |
Returns true if row \a row is hidden; otherwise returns |
|
5688 |
false. |
|
5689 |
||
5690 |
\sa hideRow(), isColumnHidden() |
|
5691 |
*/ |
|
5692 |
bool Q3Table::isRowHidden(int row) const |
|
5693 |
{ |
|
5694 |
return d->hiddenRows.find(row); |
|
5695 |
} |
|
5696 |
||
5697 |
/*! |
|
5698 |
Returns true if column \a col is hidden; otherwise returns |
|
5699 |
false. |
|
5700 |
||
5701 |
\sa hideColumn(), isRowHidden() |
|
5702 |
*/ |
|
5703 |
bool Q3Table::isColumnHidden(int col) const |
|
5704 |
{ |
|
5705 |
return d->hiddenCols.find(col); |
|
5706 |
} |
|
5707 |
||
5708 |
/*! |
|
5709 |
Resizes column \a col to be \a w pixels wide. |
|
5710 |
||
5711 |
\sa columnWidth() setRowHeight() |
|
5712 |
*/ |
|
5713 |
||
5714 |
void Q3Table::setColumnWidth(int col, int w) |
|
5715 |
{ |
|
5716 |
int *ow = d->hiddenCols.find(col); |
|
5717 |
if (ow) { |
|
5718 |
d->hiddenCols.replace(col, new int(w)); |
|
5719 |
} else { |
|
5720 |
topHeader->resizeSection(col, w); |
|
5721 |
columnWidthChanged(col); |
|
5722 |
} |
|
5723 |
} |
|
5724 |
||
5725 |
/*! |
|
5726 |
Resizes row \a row to be \a h pixels high. |
|
5727 |
||
5728 |
\sa rowHeight() setColumnWidth() |
|
5729 |
*/ |
|
5730 |
||
5731 |
void Q3Table::setRowHeight(int row, int h) |
|
5732 |
{ |
|
5733 |
int *oh = d->hiddenRows.find(row); |
|
5734 |
if (oh) { |
|
5735 |
d->hiddenRows.replace(row, new int(h)); |
|
5736 |
} else { |
|
5737 |
leftHeader->resizeSection(row, h); |
|
5738 |
rowHeightChanged(row); |
|
5739 |
} |
|
5740 |
} |
|
5741 |
||
5742 |
/*! |
|
5743 |
Resizes column \a col so that the column width is wide enough to |
|
5744 |
display the widest item the column contains. |
|
5745 |
||
5746 |
\sa adjustRow() |
|
5747 |
*/ |
|
5748 |
||
5749 |
void Q3Table::adjustColumn(int col) |
|
5750 |
{ |
|
5751 |
int w; |
|
5752 |
if ( currentColumn() == col ) { |
|
5753 |
QFont f = font(); |
|
5754 |
f.setBold(true); |
|
5755 |
w = topHeader->sectionSizeHint( col, QFontMetrics(f) ).width(); |
|
5756 |
} else { |
|
5757 |
w = topHeader->sectionSizeHint( col, fontMetrics() ).width(); |
|
5758 |
} |
|
5759 |
if (topHeader->iconSet(col)) |
|
5760 |
w += topHeader->iconSet(col)->pixmap().width(); |
|
5761 |
w = QMAX(w, 20); |
|
5762 |
for (int i = 0; i < numRows(); ++i) { |
|
5763 |
Q3TableItem *itm = item(i, col); |
|
5764 |
if (!itm) { |
|
5765 |
QWidget *widget = cellWidget(i, col); |
|
5766 |
if (widget) |
|
5767 |
w = QMAX(w, widget->sizeHint().width()); |
|
5768 |
} else { |
|
5769 |
if (itm->colSpan() > 1) |
|
5770 |
w = QMAX(w, itm->sizeHint().width() / itm->colSpan()); |
|
5771 |
else |
|
5772 |
w = QMAX(w, itm->sizeHint().width()); |
|
5773 |
} |
|
5774 |
} |
|
5775 |
w = QMAX(w, QApplication::globalStrut().width()); |
|
5776 |
setColumnWidth(col, w); |
|
5777 |
} |
|
5778 |
||
5779 |
/*! |
|
5780 |
Resizes row \a row so that the row height is tall enough to |
|
5781 |
display the tallest item the row contains. |
|
5782 |
||
5783 |
\sa adjustColumn() |
|
5784 |
*/ |
|
5785 |
||
5786 |
void Q3Table::adjustRow(int row) |
|
5787 |
{ |
|
5788 |
int h = 20; |
|
5789 |
h = QMAX(h, leftHeader->sectionSizeHint(row, leftHeader->fontMetrics()).height()); |
|
5790 |
if (leftHeader->iconSet(row)) |
|
5791 |
h = QMAX(h, leftHeader->iconSet(row)->pixmap().height()); |
|
5792 |
for (int i = 0; i < numCols(); ++i) { |
|
5793 |
Q3TableItem *itm = item(row, i); |
|
5794 |
if (!itm) { |
|
5795 |
QWidget *widget = cellWidget(row, i); |
|
5796 |
if (widget) |
|
5797 |
h = QMAX(h, widget->sizeHint().height()); |
|
5798 |
} else { |
|
5799 |
if (itm->rowSpan() > 1) |
|
5800 |
h = QMAX(h, itm->sizeHint().height() / itm->rowSpan()); |
|
5801 |
else |
|
5802 |
h = QMAX(h, itm->sizeHint().height()); |
|
5803 |
} |
|
5804 |
} |
|
5805 |
h = QMAX(h, QApplication::globalStrut().height()); |
|
5806 |
setRowHeight(row, h); |
|
5807 |
} |
|
5808 |
||
5809 |
/*! |
|
5810 |
If \a stretch is true, column \a col is set to be stretchable; |
|
5811 |
otherwise column \a col is set to be unstretchable. |
|
5812 |
||
5813 |
If the table widget's width decreases or increases stretchable |
|
5814 |
columns will grow narrower or wider to fit the space available as |
|
5815 |
completely as possible. The user cannot manually resize stretchable |
|
5816 |
columns. |
|
5817 |
||
5818 |
\sa isColumnStretchable() setRowStretchable() adjustColumn() |
|
5819 |
*/ |
|
5820 |
||
5821 |
void Q3Table::setColumnStretchable(int col, bool stretch) |
|
5822 |
{ |
|
5823 |
topHeader->setSectionStretchable(col, stretch); |
|
5824 |
||
5825 |
if (stretch && d->hiddenCols.find(col)) |
|
5826 |
topHeader->numStretches--; |
|
5827 |
} |
|
5828 |
||
5829 |
/*! |
|
5830 |
If \a stretch is true, row \a row is set to be stretchable; |
|
5831 |
otherwise row \a row is set to be unstretchable. |
|
5832 |
||
5833 |
If the table widget's height decreases or increases stretchable |
|
5834 |
rows will grow shorter or taller to fit the space available as |
|
5835 |
completely as possible. The user cannot manually resize |
|
5836 |
stretchable rows. |
|
5837 |
||
5838 |
\sa isRowStretchable() setColumnStretchable() |
|
5839 |
*/ |
|
5840 |
||
5841 |
void Q3Table::setRowStretchable(int row, bool stretch) |
|
5842 |
{ |
|
5843 |
leftHeader->setSectionStretchable(row, stretch); |
|
5844 |
||
5845 |
if (stretch && d->hiddenRows.find(row)) |
|
5846 |
leftHeader->numStretches--; |
|
5847 |
} |
|
5848 |
||
5849 |
/*! |
|
5850 |
Returns true if column \a col is stretchable; otherwise returns |
|
5851 |
false. |
|
5852 |
||
5853 |
\sa setColumnStretchable() isRowStretchable() |
|
5854 |
*/ |
|
5855 |
||
5856 |
bool Q3Table::isColumnStretchable(int col) const |
|
5857 |
{ |
|
5858 |
return topHeader->isSectionStretchable(col); |
|
5859 |
} |
|
5860 |
||
5861 |
/*! |
|
5862 |
Returns true if row \a row is stretchable; otherwise returns |
|
5863 |
false. |
|
5864 |
||
5865 |
\sa setRowStretchable() isColumnStretchable() |
|
5866 |
*/ |
|
5867 |
||
5868 |
bool Q3Table::isRowStretchable(int row) const |
|
5869 |
{ |
|
5870 |
return leftHeader->isSectionStretchable(row); |
|
5871 |
} |
|
5872 |
||
5873 |
/*! |
|
5874 |
Takes the table item \a i out of the table. This function does \e |
|
5875 |
not delete the table item. You must either delete the table item |
|
5876 |
yourself or put it into a table (using setItem()) which will then |
|
5877 |
take ownership of it. |
|
5878 |
||
5879 |
Use this function if you want to move an item from one cell in a |
|
5880 |
table to another, or to move an item from one table to another, |
|
5881 |
reinserting the item with setItem(). |
|
5882 |
||
5883 |
If you want to exchange two cells use swapCells(). |
|
5884 |
*/ |
|
5885 |
||
5886 |
void Q3Table::takeItem(Q3TableItem *i) |
|
5887 |
{ |
|
5888 |
if (!i) |
|
5889 |
return; |
|
5890 |
if (i->row() != -1 && i->col() != -1) { |
|
5891 |
QRect rect = cellGeometry(i->row(), i->col()); |
|
5892 |
contents.setAutoDelete(false); |
|
5893 |
int bottom = i->row() + i->rowSpan(); |
|
5894 |
if (bottom > numRows()) |
|
5895 |
bottom = numRows(); |
|
5896 |
int right = i->col() + i->colSpan(); |
|
5897 |
if (right > numCols()) |
|
5898 |
right = numCols(); |
|
5899 |
for (int r = i->row(); r < bottom; ++r) { |
|
5900 |
for (int c = i->col(); c < right; ++c) |
|
5901 |
contents.remove(indexOf(r, c)); |
|
5902 |
} |
|
5903 |
contents.setAutoDelete(true); |
|
5904 |
repaintContents(rect, false); |
|
5905 |
int orow = i->row(); |
|
5906 |
int ocol = i->col(); |
|
5907 |
i->setRow(-1); |
|
5908 |
i->setCol(-1); |
|
5909 |
i->updateEditor(orow, ocol); |
|
5910 |
} |
|
5911 |
i->t = 0; |
|
5912 |
} |
|
5913 |
||
5914 |
/*! |
|
5915 |
Sets the widget \a e to the cell at \a row, \a col and takes care of |
|
5916 |
placing and resizing the widget when the cell geometry changes. |
|
5917 |
||
5918 |
By default widgets are inserted into a vector with numRows() * |
|
5919 |
numCols() elements. In very large tables you will probably want to |
|
5920 |
store the widgets in a data structure that consumes less memory (see |
|
5921 |
the notes on large tables). To support the use of your own data |
|
5922 |
structure this function calls insertWidget() to add the widget to |
|
5923 |
the internal data structure. To use your own data structure |
|
5924 |
reimplement insertWidget(), cellWidget() and clearCellWidget(). |
|
5925 |
||
5926 |
Cell widgets are created dynamically with the \c new operator. The |
|
5927 |
cell widgets are destroyed automatically once the table is |
|
5928 |
destroyed; the table takes ownership of the widget when using |
|
5929 |
setCellWidget. |
|
5930 |
||
5931 |
*/ |
|
5932 |
||
5933 |
void Q3Table::setCellWidget(int row, int col, QWidget *e) |
|
5934 |
{ |
|
5935 |
if (!e || row >= numRows() || col >= numCols()) |
|
5936 |
return; |
|
5937 |
||
5938 |
QWidget *w = cellWidget(row, col); |
|
5939 |
if (w && row == editRow && col == editCol) |
|
5940 |
endEdit(editRow, editCol, false, edMode != Editing); |
|
5941 |
||
5942 |
e->installEventFilter(this); |
|
5943 |
clearCellWidget(row, col); |
|
5944 |
if (e->parent() != viewport()) |
|
5945 |
e->reparent(viewport(), QPoint(0,0)); |
|
5946 |
Q3TableItem *itm = item(row, col); |
|
5947 |
if (itm && itm->row() >= 0 && itm->col() >= 0) { // get the correct row and col if the item is spanning |
|
5948 |
row = itm->row(); |
|
5949 |
col = itm->col(); |
|
5950 |
} |
|
5951 |
insertWidget(row, col, e); |
|
5952 |
QRect cr = cellGeometry(row, col); |
|
5953 |
e->resize(cr.size()); |
|
5954 |
moveChild(e, cr.x(), cr.y()); |
|
5955 |
e->show(); |
|
5956 |
} |
|
5957 |
||
5958 |
/*! |
|
5959 |
Inserts widget \a w at \a row, \a col into the internal |
|
5960 |
data structure. See the documentation of setCellWidget() for |
|
5961 |
further details. |
|
5962 |
||
5963 |
If you don't use \l{Q3TableItem}s you may need to reimplement this |
|
5964 |
function: see the notes on large tables. |
|
5965 |
*/ |
|
5966 |
||
5967 |
void Q3Table::insertWidget(int row, int col, QWidget *w) |
|
5968 |
{ |
|
5969 |
if (row < 0 || col < 0 || row > numRows() - 1 || col > numCols() - 1) |
|
5970 |
return; |
|
5971 |
||
5972 |
if ((int)widgets.size() != numRows() * numCols()) |
|
5973 |
widgets.resize(numRows() * numCols()); |
|
5974 |
||
5975 |
widgets.insert(indexOf(row, col), w); |
|
5976 |
} |
|
5977 |
||
5978 |
/*! |
|
5979 |
Returns the widget that has been set for the cell at \a row, \a |
|
5980 |
col, or 0 if no widget has been set. |
|
5981 |
||
5982 |
If you don't use \l{Q3TableItem}s you may need to reimplement this |
|
5983 |
function: see the notes on large tables. |
|
5984 |
||
5985 |
\sa clearCellWidget() setCellWidget() |
|
5986 |
*/ |
|
5987 |
||
5988 |
QWidget *Q3Table::cellWidget(int row, int col) const |
|
5989 |
{ |
|
5990 |
if (row < 0 || col < 0 || row > numRows() - 1 || col > numCols() - 1) |
|
5991 |
return 0; |
|
5992 |
||
5993 |
if ((int)widgets.size() != numRows() * numCols()) |
|
5994 |
((Q3Table*)this)->widgets.resize(numRows() * numCols()); |
|
5995 |
||
5996 |
return widgets[ indexOf(row, col) ]; |
|
5997 |
} |
|
5998 |
||
5999 |
/*! |
|
6000 |
Removes the widget (if there is one) set for the cell at \a row, |
|
6001 |
\a col. |
|
6002 |
||
6003 |
If you don't use \l{Q3TableItem}s you may need to reimplement this |
|
6004 |
function: see the notes on large tables. |
|
6005 |
||
6006 |
This function deletes the widget at \a row, \a col. Note that the |
|
6007 |
widget is not deleted immediately; instead QObject::deleteLater() |
|
6008 |
is called on the widget to avoid problems with timing issues. |
|
6009 |
||
6010 |
\sa cellWidget() setCellWidget() |
|
6011 |
*/ |
|
6012 |
||
6013 |
void Q3Table::clearCellWidget(int row, int col) |
|
6014 |
{ |
|
6015 |
if (row < 0 || col < 0 || row > numRows() - 1 || col > numCols() - 1) |
|
6016 |
return; |
|
6017 |
||
6018 |
if ((int)widgets.size() != numRows() * numCols()) |
|
6019 |
widgets.resize(numRows() * numCols()); |
|
6020 |
||
6021 |
QWidget *w = cellWidget(row, col); |
|
6022 |
if (w) { |
|
6023 |
w->removeEventFilter(this); |
|
6024 |
w->hide(); |
|
6025 |
w->deleteLater(); |
|
6026 |
} |
|
6027 |
widgets.setAutoDelete(false); |
|
6028 |
widgets.remove(indexOf(row, col)); |
|
6029 |
widgets.setAutoDelete(true); |
|
6030 |
} |
|
6031 |
||
6032 |
/*! |
|
6033 |
\fn void Q3Table::dropped (QDropEvent * e) |
|
6034 |
||
6035 |
This signal is emitted when a drop event occurred on the table. |
|
6036 |
||
6037 |
\a e contains information about the drop. |
|
6038 |
*/ |
|
6039 |
||
6040 |
/*! |
|
6041 |
If \a b is true, the table starts a drag (see dragObject()) when |
|
6042 |
the user presses and moves the mouse on a selected cell. |
|
6043 |
*/ |
|
6044 |
||
6045 |
void Q3Table::setDragEnabled(bool b) |
|
6046 |
{ |
|
6047 |
dEnabled = b; |
|
6048 |
} |
|
6049 |
||
6050 |
/*! |
|
6051 |
If this function returns true, the table supports dragging. |
|
6052 |
||
6053 |
\sa setDragEnabled() |
|
6054 |
*/ |
|
6055 |
||
6056 |
bool Q3Table::dragEnabled() const |
|
6057 |
{ |
|
6058 |
return dEnabled; |
|
6059 |
} |
|
6060 |
||
6061 |
/*! |
|
6062 |
Inserts \a count empty rows at row \a row. Also clears the selection(s). |
|
6063 |
||
6064 |
\sa insertColumns() removeRow() |
|
6065 |
*/ |
|
6066 |
||
6067 |
void Q3Table::insertRows(int row, int count) |
|
6068 |
{ |
|
6069 |
// special case, so a call like insertRow(currentRow(), 1) also |
|
6070 |
// works, when we have 0 rows and currentRow() is -1 |
|
6071 |
if (row == -1 && curRow == -1) |
|
6072 |
row = 0; |
|
6073 |
if (row < 0 || count <= 0) |
|
6074 |
return; |
|
6075 |
||
6076 |
if (curRow >= row && curRow < row + count) |
|
6077 |
curRow = row + count; |
|
6078 |
||
6079 |
--row; |
|
6080 |
if (row >= numRows()) |
|
6081 |
return; |
|
6082 |
||
6083 |
bool updatesWereEnabled = updatesEnabled(); |
|
6084 |
if (updatesWereEnabled) |
|
6085 |
setUpdatesEnabled(false); |
|
6086 |
bool leftHeaderUpdatesEnabled = leftHeader->updatesEnabled(); |
|
6087 |
if (leftHeaderUpdatesEnabled) |
|
6088 |
leftHeader->setUpdatesEnabled(false); |
|
6089 |
int oldLeftMargin = leftMargin(); |
|
6090 |
||
6091 |
setNumRows(numRows() + count); |
|
6092 |
||
6093 |
for (int i = numRows() - count - 1; i > row; --i) |
|
6094 |
leftHeader->swapSections(i, i + count); |
|
6095 |
||
6096 |
if (leftHeaderUpdatesEnabled) |
|
6097 |
leftHeader->setUpdatesEnabled(leftHeaderUpdatesEnabled); |
|
6098 |
||
6099 |
if (updatesWereEnabled) |
|
6100 |
setUpdatesEnabled(true); |
|
6101 |
||
6102 |
int cr = QMAX(0, currentRow()); |
|
6103 |
int cc = QMAX(0, currentColumn()); |
|
6104 |
if (curRow > row) |
|
6105 |
curRow -= count; // this is where curRow was |
|
6106 |
setCurrentCell(cr, cc, true, false); // without ensureCellVisible |
|
6107 |
||
6108 |
// Repaint the header |
|
6109 |
if (leftHeaderUpdatesEnabled) { |
|
6110 |
int y = rowPos(row) - contentsY(); |
|
6111 |
if (leftMargin() != oldLeftMargin || d->hasRowSpan) |
|
6112 |
y = 0; // full repaint |
|
6113 |
QRect rect(0, y, leftHeader->width(), contentsHeight()); |
|
6114 |
leftHeader->update(rect); |
|
6115 |
} |
|
6116 |
||
6117 |
if (updatesWereEnabled) { |
|
6118 |
int p = rowPos(row); |
|
6119 |
if (d->hasRowSpan) |
|
6120 |
p = contentsY(); |
|
6121 |
updateContents(contentsX(), p, visibleWidth(), contentsHeight() + 1); |
|
6122 |
} |
|
6123 |
} |
|
6124 |
||
6125 |
/*! |
|
6126 |
Inserts \a count empty columns at column \a col. Also clears the selection(s). |
|
6127 |
||
6128 |
\sa insertRows() removeColumn() |
|
6129 |
*/ |
|
6130 |
||
6131 |
void Q3Table::insertColumns(int col, int count) |
|
6132 |
{ |
|
6133 |
// see comment in insertRows() |
|
6134 |
if (col == -1 && curCol == -1) |
|
6135 |
col = 0; |
|
6136 |
if (col < 0 || count <= 0) |
|
6137 |
return; |
|
6138 |
||
6139 |
if (curCol >= col && curCol < col + count) |
|
6140 |
curCol = col + count; |
|
6141 |
||
6142 |
--col; |
|
6143 |
if (col >= numCols()) |
|
6144 |
return; |
|
6145 |
||
6146 |
bool updatesWereEnabled = updatesEnabled(); |
|
6147 |
if (updatesWereEnabled) |
|
6148 |
setUpdatesEnabled(false); |
|
6149 |
bool topHeaderUpdatesEnabled = topHeader->updatesEnabled(); |
|
6150 |
if (topHeaderUpdatesEnabled) |
|
6151 |
topHeader->setUpdatesEnabled(false); |
|
6152 |
int oldTopMargin = topMargin(); |
|
6153 |
||
6154 |
setNumCols(numCols() + count); |
|
6155 |
||
6156 |
for (int i = numCols() - count - 1; i > col; --i) |
|
6157 |
topHeader->swapSections(i, i + count); |
|
6158 |
||
6159 |
if (topHeaderUpdatesEnabled) |
|
6160 |
topHeader->setUpdatesEnabled(true); |
|
6161 |
if (updatesWereEnabled) |
|
6162 |
setUpdatesEnabled(true); |
|
6163 |
||
6164 |
int cr = QMAX(0, currentRow()); |
|
6165 |
int cc = QMAX(0, currentColumn()); |
|
6166 |
if (curCol > col) |
|
6167 |
curCol -= count; // this is where curCol was |
|
6168 |
setCurrentCell(cr, cc, true, false); // without ensureCellVisible |
|
6169 |
||
6170 |
// Repaint the header |
|
6171 |
if (topHeaderUpdatesEnabled) { |
|
6172 |
int x = columnPos(col) - contentsX(); |
|
6173 |
if (topMargin() != oldTopMargin || d->hasColSpan) |
|
6174 |
x = 0; // full repaint |
|
6175 |
QRect rect(x, 0, contentsWidth(), topHeader->height()); |
|
6176 |
topHeader->update(rect); |
|
6177 |
} |
|
6178 |
||
6179 |
if (updatesWereEnabled) { |
|
6180 |
int p = columnPos(col); |
|
6181 |
if (d->hasColSpan) |
|
6182 |
p = contentsX(); |
|
6183 |
updateContents(p, contentsY(), contentsWidth() + 1, visibleHeight()); |
|
6184 |
} |
|
6185 |
} |
|
6186 |
||
6187 |
/*! |
|
6188 |
Removes row \a row, and deletes all its cells including any table |
|
6189 |
items and widgets the cells may contain. Also clears the selection(s). |
|
6190 |
||
6191 |
\sa hideRow() insertRows() removeColumn() removeRows() |
|
6192 |
*/ |
|
6193 |
||
6194 |
void Q3Table::removeRow(int row) |
|
6195 |
{ |
|
6196 |
if (row < 0 || row >= numRows()) |
|
6197 |
return; |
|
6198 |
if (row < numRows() - 1) { |
|
6199 |
if (d->hiddenRows.find(row)) |
|
6200 |
d->hiddenRows.remove(row); |
|
6201 |
||
6202 |
for (int i = row; i < numRows() - 1; ++i) |
|
6203 |
((Q3TableHeader*)verticalHeader())->swapSections(i, i + 1); |
|
6204 |
} |
|
6205 |
setNumRows(numRows() - 1); |
|
6206 |
} |
|
6207 |
||
6208 |
/*! |
|
6209 |
Removes the rows listed in the array \a rows, and deletes all their |
|
6210 |
cells including any table items and widgets the cells may contain. |
|
6211 |
||
6212 |
The array passed in must only contain valid rows (in the range |
|
6213 |
from 0 to numRows() - 1) with no duplicates, and must be sorted in |
|
6214 |
ascending order. Also clears the selection(s). |
|
6215 |
||
6216 |
\sa removeRow() insertRows() removeColumns() |
|
6217 |
*/ |
|
6218 |
||
6219 |
void Q3Table::removeRows(const Q3MemArray<int> &rows) |
|
6220 |
{ |
|
6221 |
if (rows.count() == 0) |
|
6222 |
return; |
|
6223 |
int i; |
|
6224 |
for (i = 0; i < (int)rows.count() - 1; ++i) { |
|
6225 |
for (int j = rows[i] - i; j < rows[i + 1] - i - 1; j++) { |
|
6226 |
((Q3TableHeader*)verticalHeader())->swapSections(j, j + i + 1); |
|
6227 |
} |
|
6228 |
} |
|
6229 |
||
6230 |
for (int j = rows[i] - i; j < numRows() - (int)rows.size(); j++) |
|
6231 |
((Q3TableHeader*)verticalHeader())->swapSections(j, j + rows.count()); |
|
6232 |
||
6233 |
setNumRows(numRows() - rows.count()); |
|
6234 |
} |
|
6235 |
||
6236 |
/*! |
|
6237 |
Removes column \a col, and deletes all its cells including any |
|
6238 |
table items and widgets the cells may contain. Also clears the |
|
6239 |
selection(s). |
|
6240 |
||
6241 |
\sa removeColumns() hideColumn() insertColumns() removeRow() |
|
6242 |
*/ |
|
6243 |
||
6244 |
void Q3Table::removeColumn(int col) |
|
6245 |
{ |
|
6246 |
if (col < 0 || col >= numCols()) |
|
6247 |
return; |
|
6248 |
if (col < numCols() - 1) { |
|
6249 |
if (d->hiddenCols.find(col)) |
|
6250 |
d->hiddenCols.remove(col); |
|
6251 |
||
6252 |
for (int i = col; i < numCols() - 1; ++i) |
|
6253 |
((Q3TableHeader*)horizontalHeader())->swapSections(i, i + 1); |
|
6254 |
} |
|
6255 |
setNumCols(numCols() - 1); |
|
6256 |
} |
|
6257 |
||
6258 |
/*! |
|
6259 |
Removes the columns listed in the array \a cols, and deletes all |
|
6260 |
their cells including any table items and widgets the cells may |
|
6261 |
contain. |
|
6262 |
||
6263 |
The array passed in must only contain valid columns (in the range |
|
6264 |
from 0 to numCols() - 1) with no duplicates, and must be sorted in |
|
6265 |
ascending order. Also clears the selection(s). |
|
6266 |
||
6267 |
\sa removeColumn() insertColumns() removeRows() |
|
6268 |
*/ |
|
6269 |
||
6270 |
void Q3Table::removeColumns(const Q3MemArray<int> &cols) |
|
6271 |
{ |
|
6272 |
if (cols.count() == 0) |
|
6273 |
return; |
|
6274 |
int i; |
|
6275 |
for (i = 0; i < (int)cols.count() - 1; ++i) { |
|
6276 |
for (int j = cols[i] - i; j < cols[i + 1] - i - 1; j++) { |
|
6277 |
((Q3TableHeader*)horizontalHeader())->swapSections(j, j + i + 1); |
|
6278 |
} |
|
6279 |
} |
|
6280 |
||
6281 |
for (int j = cols[i] - i; j < numCols() - (int)cols.size(); j++) |
|
6282 |
((Q3TableHeader*)horizontalHeader())->swapSections(j, j + cols.count()); |
|
6283 |
||
6284 |
setNumCols(numCols() - cols.count()); |
|
6285 |
} |
|
6286 |
||
6287 |
/*! |
|
6288 |
Starts editing the cell at \a row, \a col. |
|
6289 |
||
6290 |
If \a replace is true the content of this cell will be replaced by |
|
6291 |
the content of the editor when editing is finished, i.e. the user |
|
6292 |
will be entering new data; otherwise the current content of the |
|
6293 |
cell (if any) will be modified in the editor. |
|
6294 |
||
6295 |
\sa beginEdit() |
|
6296 |
*/ |
|
6297 |
||
6298 |
void Q3Table::editCell(int row, int col, bool replace) |
|
6299 |
{ |
|
6300 |
if (row < 0 || col < 0 || row > numRows() - 1 || col > numCols() - 1) |
|
6301 |
return; |
|
6302 |
||
6303 |
if (beginEdit(row, col, replace)) { |
|
6304 |
edMode = Editing; |
|
6305 |
editRow = row; |
|
6306 |
editCol = col; |
|
6307 |
} |
|
6308 |
} |
|
6309 |
||
6310 |
#ifndef QT_NO_DRAGANDDROP |
|
6311 |
||
6312 |
/*! |
|
6313 |
This event handler is called whenever a Q3Table object receives a |
|
6314 |
\l QDragEnterEvent \a e, i.e. when the user pressed the mouse |
|
6315 |
button to drag something. |
|
6316 |
||
6317 |
The focus is moved to the cell where the QDragEnterEvent occurred. |
|
6318 |
*/ |
|
6319 |
||
6320 |
void Q3Table::contentsDragEnterEvent(QDragEnterEvent *e) |
|
6321 |
{ |
|
6322 |
oldCurrentRow = curRow; |
|
6323 |
oldCurrentCol = curCol; |
|
6324 |
int tmpRow = rowAt(e->pos().y()); |
|
6325 |
int tmpCol = columnAt(e->pos().x()); |
|
6326 |
fixRow(tmpRow, e->pos().y()); |
|
6327 |
fixCol(tmpCol, e->pos().x()); |
|
6328 |
if (e->source() != (QObject*)cellWidget(currentRow(), currentColumn())) |
|
6329 |
setCurrentCell(tmpRow, tmpCol, false, true); |
|
6330 |
e->accept(); |
|
6331 |
} |
|
6332 |
||
6333 |
/*! |
|
6334 |
This event handler is called whenever a Q3Table object receives a |
|
6335 |
\l QDragMoveEvent \a e, i.e. when the user actually drags the |
|
6336 |
mouse. |
|
6337 |
||
6338 |
The focus is moved to the cell where the QDragMoveEvent occurred. |
|
6339 |
*/ |
|
6340 |
||
6341 |
void Q3Table::contentsDragMoveEvent(QDragMoveEvent *e) |
|
6342 |
{ |
|
6343 |
int tmpRow = rowAt(e->pos().y()); |
|
6344 |
int tmpCol = columnAt(e->pos().x()); |
|
6345 |
fixRow(tmpRow, e->pos().y()); |
|
6346 |
fixCol(tmpCol, e->pos().x()); |
|
6347 |
if (e->source() != (QObject*)cellWidget(currentRow(), currentColumn())) |
|
6348 |
setCurrentCell(tmpRow, tmpCol, false, true); |
|
6349 |
e->accept(); |
|
6350 |
} |
|
6351 |
||
6352 |
/*! |
|
6353 |
This event handler is called when a drag activity leaves \e this |
|
6354 |
Q3Table object with event \a e. |
|
6355 |
*/ |
|
6356 |
||
6357 |
void Q3Table::contentsDragLeaveEvent(QDragLeaveEvent *) |
|
6358 |
{ |
|
6359 |
setCurrentCell(oldCurrentRow, oldCurrentCol, false, true); |
|
6360 |
} |
|
6361 |
||
6362 |
/*! |
|
6363 |
This event handler is called when the user ends a drag and drop by |
|
6364 |
dropping something onto \e this Q3Table and thus triggers the drop |
|
6365 |
event, \a e. |
|
6366 |
*/ |
|
6367 |
||
6368 |
void Q3Table::contentsDropEvent(QDropEvent *e) |
|
6369 |
{ |
|
6370 |
setCurrentCell(oldCurrentRow, oldCurrentCol, false, true); |
|
6371 |
emit dropped(e); |
|
6372 |
} |
|
6373 |
||
6374 |
/*! |
|
6375 |
If the user presses the mouse on a selected cell, starts moving |
|
6376 |
(i.e. dragging), and dragEnabled() is true, this function is |
|
6377 |
called to obtain a drag object. A drag using this object begins |
|
6378 |
immediately unless dragObject() returns 0. |
|
6379 |
||
6380 |
By default this function returns 0. You might reimplement it and |
|
6381 |
create a Q3DragObject depending on the selected items. |
|
6382 |
||
6383 |
\sa dropped() |
|
6384 |
*/ |
|
6385 |
||
6386 |
Q3DragObject *Q3Table::dragObject() |
|
6387 |
{ |
|
6388 |
return 0; |
|
6389 |
} |
|
6390 |
||
6391 |
/*! |
|
6392 |
Starts a drag. |
|
6393 |
||
6394 |
Usually you don't need to call or reimplement this function yourself. |
|
6395 |
||
6396 |
\sa dragObject() |
|
6397 |
*/ |
|
6398 |
||
6399 |
void Q3Table::startDrag() |
|
6400 |
{ |
|
6401 |
if (startDragRow == -1 || startDragCol == -1) |
|
6402 |
return; |
|
6403 |
||
6404 |
startDragRow = startDragCol = -1; |
|
6405 |
||
6406 |
Q3DragObject *drag = dragObject(); |
|
6407 |
if (!drag) |
|
6408 |
return; |
|
6409 |
||
6410 |
drag->drag(); |
|
6411 |
} |
|
6412 |
||
6413 |
#endif |
|
6414 |
||
6415 |
/*! \internal */ |
|
6416 |
void Q3Table::windowActivationChange(bool oldActive) |
|
6417 |
{ |
|
6418 |
if (oldActive && autoScrollTimer) |
|
6419 |
autoScrollTimer->stop(); |
|
6420 |
||
6421 |
if (!isVisible()) |
|
6422 |
return; |
|
6423 |
||
6424 |
if (palette().active() != palette().inactive()) |
|
6425 |
updateContents(); |
|
6426 |
} |
|
6427 |
||
6428 |
/*! |
|
6429 |
\internal |
|
6430 |
*/ |
|
6431 |
void Q3Table::setEnabled(bool b) |
|
6432 |
{ |
|
6433 |
if (!b) { |
|
6434 |
// editor will lose focus, causing a crash deep in setEnabled(), |
|
6435 |
// so we'll end the edit early. |
|
6436 |
endEdit(editRow, editCol, true, edMode != Editing); |
|
6437 |
} |
|
6438 |
Q3ScrollView::setEnabled(b); |
|
6439 |
} |
|
6440 |
||
6441 |
||
6442 |
/* |
|
6443 |
\class Q3TableHeader |
|
6444 |
\brief The Q3TableHeader class allows for creation and manipulation |
|
6445 |
of table headers. |
|
6446 |
||
6447 |
\compat |
|
6448 |
||
6449 |
Q3Table uses this subclass of Q3Header for its headers. Q3Table has a |
|
6450 |
horizontalHeader() for displaying column labels, and a |
|
6451 |
verticalHeader() for displaying row labels. |
|
6452 |
||
6453 |
*/ |
|
6454 |
||
6455 |
/* |
|
6456 |
\enum Q3TableHeader::SectionState |
|
6457 |
||
6458 |
This enum type denotes the state of the header's text |
|
6459 |
||
6460 |
\value Normal the default |
|
6461 |
\value Bold |
|
6462 |
\value Selected typically represented by showing the section "sunken" |
|
6463 |
or "pressed in" |
|
6464 |
*/ |
|
6465 |
||
6466 |
/*! |
|
6467 |
Creates a new table header called \a name with \a i sections. It |
|
6468 |
is a child of widget \a parent and attached to table \a t. |
|
6469 |
*/ |
|
6470 |
||
6471 |
Q3TableHeader::Q3TableHeader(int i, Q3Table *t, |
|
6472 |
QWidget *parent, const char *name) |
|
6473 |
: Q3Header(i, parent, name), mousePressed(false), startPos(-1), |
|
6474 |
table(t), caching(false), resizedSection(-1), |
|
6475 |
numStretches(0) |
|
6476 |
{ |
|
6477 |
setIsATableHeader(true); |
|
6478 |
d = 0; |
|
6479 |
states.resize(i); |
|
6480 |
stretchable.resize(i); |
|
6481 |
states.fill(Normal, -1); |
|
6482 |
stretchable.fill(false, -1); |
|
6483 |
autoScrollTimer = new QTimer(this); |
|
6484 |
connect(autoScrollTimer, SIGNAL(timeout()), |
|
6485 |
this, SLOT(doAutoScroll())); |
|
6486 |
#ifndef NO_LINE_WIDGET |
|
6487 |
line1 = new QWidget(table->viewport(), "qt_line1"); |
|
6488 |
line1->hide(); |
|
6489 |
line1->setBackgroundMode(PaletteText); |
|
6490 |
table->addChild(line1); |
|
6491 |
line2 = new QWidget(table->viewport(), "qt_line2"); |
|
6492 |
line2->hide(); |
|
6493 |
line2->setBackgroundMode(PaletteText); |
|
6494 |
table->addChild(line2); |
|
6495 |
#else |
|
6496 |
d = new Q3TableHeaderPrivate; |
|
6497 |
d->oldLinePos = -1; //outside, in contents coords |
|
6498 |
#endif |
|
6499 |
connect(this, SIGNAL(sizeChange(int,int,int)), |
|
6500 |
this, SLOT(sectionWidthChanged(int,int,int))); |
|
6501 |
connect(this, SIGNAL(indexChange(int,int,int)), |
|
6502 |
this, SLOT(indexChanged(int,int,int))); |
|
6503 |
||
6504 |
stretchTimer = new QTimer(this); |
|
6505 |
widgetStretchTimer = new QTimer(this); |
|
6506 |
connect(stretchTimer, SIGNAL(timeout()), |
|
6507 |
this, SLOT(updateStretches())); |
|
6508 |
connect(widgetStretchTimer, SIGNAL(timeout()), |
|
6509 |
this, SLOT(updateWidgetStretches())); |
|
6510 |
startPos = -1; |
|
6511 |
} |
|
6512 |
||
6513 |
/*! |
|
6514 |
Adds a new section, \a size pixels wide (or high for vertical |
|
6515 |
headers) with the label \a s. If \a size is negative the section's |
|
6516 |
size is calculated based on the width (or height) of the label's |
|
6517 |
text. |
|
6518 |
*/ |
|
6519 |
||
6520 |
void Q3TableHeader::addLabel(const QString &s , int size) |
|
6521 |
{ |
|
6522 |
Q3Header::addLabel(s, size); |
|
6523 |
if (count() > (int)states.size()) { |
|
6524 |
int s = states.size(); |
|
6525 |
states.resize(count()); |
|
6526 |
stretchable.resize(count()); |
|
6527 |
for (; s < count(); ++s) { |
|
6528 |
states[ s ] = Normal; |
|
6529 |
stretchable[ s ] = false; |
|
6530 |
} |
|
6531 |
} |
|
6532 |
} |
|
6533 |
||
6534 |
void Q3TableHeader::removeLabel(int section) |
|
6535 |
{ |
|
6536 |
Q3Header::removeLabel(section); |
|
6537 |
if (section == (int)states.size() - 1) { |
|
6538 |
states.resize(states.size() - 1); |
|
6539 |
stretchable.resize(stretchable.size() - 1); |
|
6540 |
} |
|
6541 |
} |
|
6542 |
||
6543 |
void Q3TableHeader::resizeArrays(int n) |
|
6544 |
{ |
|
6545 |
int old = states.size(); |
|
6546 |
states.resize(n); |
|
6547 |
stretchable.resize(n); |
|
6548 |
if (n > old) { |
|
6549 |
for (int i = old; i < n; ++i) { |
|
6550 |
stretchable[ i ] = false; |
|
6551 |
states[ i ] = Normal; |
|
6552 |
} |
|
6553 |
} |
|
6554 |
} |
|
6555 |
||
6556 |
void Q3TableHeader::setLabel(int section, const QString & s, int size) |
|
6557 |
{ |
|
6558 |
Q3Header::setLabel(section, s, size); |
|
6559 |
sectionLabelChanged(section); |
|
6560 |
} |
|
6561 |
||
6562 |
void Q3TableHeader::setLabel(int section, const QIconSet & iconset, |
|
6563 |
const QString & s, int size) |
|
6564 |
{ |
|
6565 |
Q3Header::setLabel(section, iconset, s, size); |
|
6566 |
sectionLabelChanged(section); |
|
6567 |
} |
|
6568 |
||
6569 |
/*! |
|
6570 |
Sets the SectionState of section \a s to \a astate. |
|
6571 |
||
6572 |
\sa sectionState() |
|
6573 |
*/ |
|
6574 |
||
6575 |
void Q3TableHeader::setSectionState(int s, SectionState astate) |
|
6576 |
{ |
|
6577 |
if (s < 0 || s >= (int)states.count()) |
|
6578 |
return; |
|
6579 |
if (states.data()[ s ] == astate) |
|
6580 |
return; |
|
6581 |
if (isRowSelection(table->selectionMode()) && orientation() == Horizontal) |
|
6582 |
return; |
|
6583 |
||
6584 |
states.data()[ s ] = astate; |
|
6585 |
if (updatesEnabled()) { |
|
6586 |
if (orientation() == Horizontal) |
|
6587 |
repaint(sectionPos(s) - offset(), 0, sectionSize(s), height(), false); |
|
6588 |
else |
|
6589 |
repaint(0, sectionPos(s) - offset(), width(), sectionSize(s), false); |
|
6590 |
} |
|
6591 |
} |
|
6592 |
||
6593 |
void Q3TableHeader::setSectionStateToAll(SectionState state) |
|
6594 |
{ |
|
6595 |
if (isRowSelection(table->selectionMode()) && orientation() == Horizontal) |
|
6596 |
return; |
|
6597 |
||
6598 |
register int *d = (int *) states.data(); |
|
6599 |
int n = count(); |
|
6600 |
||
6601 |
while (n >= 4) { |
|
6602 |
d[0] = state; |
|
6603 |
d[1] = state; |
|
6604 |
d[2] = state; |
|
6605 |
d[3] = state; |
|
6606 |
d += 4; |
|
6607 |
n -= 4; |
|
6608 |
} |
|
6609 |
||
6610 |
if (n > 0) { |
|
6611 |
d[0] = state; |
|
6612 |
if (n > 1) { |
|
6613 |
d[1] = state; |
|
6614 |
if (n > 2) { |
|
6615 |
d[2] = state; |
|
6616 |
} |
|
6617 |
} |
|
6618 |
} |
|
6619 |
} |
|
6620 |
||
6621 |
/*! |
|
6622 |
Returns the SectionState of section \a s. |
|
6623 |
||
6624 |
\sa setSectionState() |
|
6625 |
*/ |
|
6626 |
||
6627 |
Q3TableHeader::SectionState Q3TableHeader::sectionState(int s) const |
|
6628 |
{ |
|
6629 |
return (s < 0 || s >= (int)states.count() ? Normal : (Q3TableHeader::SectionState)states[s]); |
|
6630 |
} |
|
6631 |
||
6632 |
/*! \reimp |
|
6633 |
*/ |
|
6634 |
||
6635 |
void Q3TableHeader::paintEvent(QPaintEvent *e) |
|
6636 |
{ |
|
6637 |
QPainter p(this); |
|
6638 |
p.setPen(colorGroup().buttonText()); |
|
6639 |
int pos = orientation() == Horizontal |
|
6640 |
? e->rect().left() |
|
6641 |
: e->rect().top(); |
|
6642 |
int id = mapToIndex(sectionAt(pos + offset())); |
|
6643 |
if (id < 0) { |
|
6644 |
if (pos > 0) |
|
6645 |
return; |
|
6646 |
else |
|
6647 |
id = 0; |
|
6648 |
} |
|
6649 |
||
6650 |
QRegion reg = e->region(); |
|
6651 |
for (int i = id; i < count(); i++) { |
|
6652 |
QRect r = sRect(i); |
|
6653 |
reg -= r; |
|
6654 |
p.save(); |
|
6655 |
if (!(orientation() == Horizontal && isRowSelection(table->selectionMode())) && |
|
6656 |
(sectionState(i) == Bold || sectionState(i) == Selected)) { |
|
6657 |
QFont f(font()); |
|
6658 |
f.setBold(true); |
|
6659 |
p.setFont(f); |
|
6660 |
} |
|
6661 |
paintSection(&p, i, r); |
|
6662 |
p.restore(); |
|
6663 |
if ((orientation() == Horizontal && r. right() >= e->rect().right()) |
|
6664 |
|| (orientation() == Vertical && r. bottom() >= e->rect().bottom())) |
|
6665 |
return; |
|
6666 |
} |
|
6667 |
p.end(); |
|
6668 |
if (!reg.isEmpty()) |
|
6669 |
erase(reg); |
|
6670 |
} |
|
6671 |
||
6672 |
/*! |
|
6673 |
\reimp |
|
6674 |
||
6675 |
Paints the header section with index \a index into the rectangular |
|
6676 |
region \a fr on the painter \a p. |
|
6677 |
*/ |
|
6678 |
||
6679 |
void Q3TableHeader::paintSection(QPainter *p, int index, const QRect& fr) |
|
6680 |
{ |
|
6681 |
int section = mapToSection(index); |
|
6682 |
if (section < 0 || cellSize(section) <= 0) |
|
6683 |
return; |
|
6684 |
||
6685 |
if (sectionState(index) != Selected || |
|
6686 |
(orientation() == Horizontal && isRowSelection(table->selectionMode()))) { |
|
6687 |
Q3Header::paintSection(p, index, fr); |
|
6688 |
} else { |
|
6689 |
QStyleOptionHeader opt; |
|
6690 |
opt.palette = palette(); |
|
6691 |
opt.rect = fr; |
|
6692 |
opt.state = QStyle::State_Off | (orient == Qt::Horizontal ? QStyle::State_Horizontal |
|
6693 |
: QStyle::State_None); |
|
6694 |
if (isEnabled()) |
|
6695 |
opt.state |= QStyle::State_Enabled; |
|
6696 |
if (isClickEnabled()) { |
|
6697 |
if (sectionState(index) == Selected) { |
|
6698 |
opt.state |= QStyle::State_Sunken; |
|
6699 |
if (!mousePressed) |
|
6700 |
opt.state |= QStyle::State_On; |
|
6701 |
} |
|
6702 |
} |
|
6703 |
if (!(opt.state & QStyle::State_Sunken)) |
|
6704 |
opt.state |= QStyle::State_Raised; |
|
6705 |
style()->drawControl(QStyle::CE_HeaderSection, &opt, p, this); |
|
6706 |
paintSectionLabel(p, index, fr); |
|
6707 |
} |
|
6708 |
} |
|
6709 |
||
6710 |
static int real_pos(const QPoint &p, Qt::Orientation o) |
|
6711 |
{ |
|
6712 |
if (o == Qt::Horizontal) |
|
6713 |
return p.x(); |
|
6714 |
return p.y(); |
|
6715 |
} |
|
6716 |
||
6717 |
/*! \reimp |
|
6718 |
*/ |
|
6719 |
||
6720 |
void Q3TableHeader::mousePressEvent(QMouseEvent *e) |
|
6721 |
{ |
|
6722 |
if (e->button() != LeftButton) |
|
6723 |
return; |
|
6724 |
Q3Header::mousePressEvent(e); |
|
6725 |
mousePressed = true; |
|
6726 |
pressPos = real_pos(e->pos(), orientation()); |
|
6727 |
if (!table->currentSel || (e->state() & ShiftButton) != ShiftButton) |
|
6728 |
startPos = -1; |
|
6729 |
setCaching(true); |
|
6730 |
resizedSection = -1; |
|
6731 |
#ifdef QT_NO_CURSOR |
|
6732 |
isResizing = false; |
|
6733 |
#else |
|
6734 |
isResizing = cursor().shape() != ArrowCursor; |
|
6735 |
if (!isResizing && sectionAt(pressPos) != -1) |
|
6736 |
doSelection(e); |
|
6737 |
#endif |
|
6738 |
} |
|
6739 |
||
6740 |
/*! \reimp |
|
6741 |
*/ |
|
6742 |
||
6743 |
void Q3TableHeader::mouseMoveEvent(QMouseEvent *e) |
|
6744 |
{ |
|
6745 |
if ((e->state() & MouseButtonMask) != LeftButton // Using LeftButton simulates old behavior. |
|
6746 |
#ifndef QT_NO_CURSOR |
|
6747 |
|| cursor().shape() != ArrowCursor |
|
6748 |
#endif |
|
6749 |
|| ((e->state() & ControlButton) == ControlButton && |
|
6750 |
(orientation() == Horizontal |
|
6751 |
? table->columnMovingEnabled() : table->rowMovingEnabled()))) { |
|
6752 |
Q3Header::mouseMoveEvent(e); |
|
6753 |
return; |
|
6754 |
} |
|
6755 |
||
6756 |
if (!doSelection(e)) |
|
6757 |
Q3Header::mouseMoveEvent(e); |
|
6758 |
} |
|
6759 |
||
6760 |
bool Q3TableHeader::doSelection(QMouseEvent *e) |
|
6761 |
{ |
|
6762 |
int p = real_pos(e->pos(), orientation()) + offset(); |
|
6763 |
||
6764 |
if (isRowSelection(table->selectionMode())) { |
|
6765 |
if (orientation() == Horizontal) |
|
6766 |
return true; |
|
6767 |
if (table->selectionMode() == Q3Table::SingleRow) { |
|
6768 |
int secAt = sectionAt(p); |
|
6769 |
if (secAt == -1) |
|
6770 |
return true; |
|
6771 |
table->setCurrentCell(secAt, table->currentColumn()); |
|
6772 |
return true; |
|
6773 |
} |
|
6774 |
} |
|
6775 |
||
6776 |
if (startPos == -1) { |
|
6777 |
int secAt = sectionAt(p); |
|
6778 |
if (((e->state() & ControlButton) != ControlButton && (e->state() & ShiftButton) != ShiftButton) |
|
6779 |
|| table->selectionMode() == Q3Table::Single |
|
6780 |
|| table->selectionMode() == Q3Table::SingleRow) { |
|
6781 |
startPos = p; |
|
6782 |
bool b = table->signalsBlocked(); |
|
6783 |
table->blockSignals(true); |
|
6784 |
table->clearSelection(); |
|
6785 |
table->blockSignals(b); |
|
6786 |
} |
|
6787 |
saveStates(); |
|
6788 |
||
6789 |
if (table->selectionMode() != Q3Table::NoSelection) { |
|
6790 |
startPos = p; |
|
6791 |
Q3TableSelection *oldSelection = table->currentSel; |
|
6792 |
||
6793 |
if (orientation() == Vertical) { |
|
6794 |
if (!table->isRowSelected(secAt, true)) { |
|
6795 |
table->currentSel = new Q3TableSelection(); |
|
6796 |
table->selections.append(table->currentSel); |
|
6797 |
table->currentSel->init(secAt, 0); |
|
6798 |
table->currentSel->expandTo(secAt, table->numCols() - 1); |
|
6799 |
emit table->selectionChanged(); |
|
6800 |
} |
|
6801 |
table->setCurrentCell(secAt, 0); |
|
6802 |
} else { // orientation == Horizontal |
|
6803 |
if (!table->isColumnSelected(secAt, true)) { |
|
6804 |
table->currentSel = new Q3TableSelection(); |
|
6805 |
table->selections.append(table->currentSel); |
|
6806 |
table->currentSel->init(0, secAt); |
|
6807 |
table->currentSel->expandTo(table->numRows() - 1, secAt); |
|
6808 |
emit table->selectionChanged(); |
|
6809 |
} |
|
6810 |
table->setCurrentCell(0, secAt); |
|
6811 |
} |
|
6812 |
||
6813 |
if ((orientation() == Horizontal && table->isColumnSelected(secAt)) |
|
6814 |
|| (orientation() == Vertical && table->isRowSelected(secAt))) { |
|
6815 |
setSectionState(secAt, Selected); |
|
6816 |
} |
|
6817 |
||
6818 |
table->repaintSelections(oldSelection, table->currentSel, |
|
6819 |
orientation() == Horizontal, |
|
6820 |
orientation() == Vertical); |
|
6821 |
if (sectionAt(p) != -1) |
|
6822 |
endPos = p; |
|
6823 |
||
6824 |
return true; |
|
6825 |
} |
|
6826 |
} |
|
6827 |
||
6828 |
if (sectionAt(p) != -1) |
|
6829 |
endPos = p; |
|
6830 |
if (startPos != -1) { |
|
6831 |
updateSelections(); |
|
6832 |
p -= offset(); |
|
6833 |
if (orientation() == Horizontal && (p < 0 || p > width())) { |
|
6834 |
doAutoScroll(); |
|
6835 |
autoScrollTimer->start(100, true); |
|
6836 |
} else if (orientation() == Vertical && (p < 0 || p > height())) { |
|
6837 |
doAutoScroll(); |
|
6838 |
autoScrollTimer->start(100, true); |
|
6839 |
} |
|
6840 |
return true; |
|
6841 |
} |
|
6842 |
return table->selectionMode() == Q3Table::NoSelection; |
|
6843 |
} |
|
6844 |
||
6845 |
static inline bool mayOverwriteMargin(int before, int after) |
|
6846 |
{ |
|
6847 |
/* |
|
6848 |
0 is the only user value that we always respect. We also never |
|
6849 |
shrink a margin, in case the user wanted it that way. |
|
6850 |
*/ |
|
6851 |
return before != 0 && before < after; |
|
6852 |
} |
|
6853 |
||
6854 |
void Q3TableHeader::sectionLabelChanged(int section) |
|
6855 |
{ |
|
6856 |
emit sectionSizeChanged(section); |
|
6857 |
||
6858 |
// this does not really belong here |
|
6859 |
if (orientation() == Horizontal) { |
|
6860 |
int h = sizeHint().height(); |
|
6861 |
if (h != height() && mayOverwriteMargin(table->topMargin(), h)) |
|
6862 |
table->setTopMargin(h); |
|
6863 |
} else { |
|
6864 |
int w = sizeHint().width(); |
|
6865 |
if (w != width() && mayOverwriteMargin((QApplication::reverseLayout() ? table->rightMargin() : table->leftMargin()), w)) |
|
6866 |
table->setLeftMargin(w); |
|
6867 |
} |
|
6868 |
} |
|
6869 |
||
6870 |
/*! \reimp */ |
|
6871 |
void Q3TableHeader::mouseReleaseEvent(QMouseEvent *e) |
|
6872 |
{ |
|
6873 |
if (e->button() != LeftButton) |
|
6874 |
return; |
|
6875 |
autoScrollTimer->stop(); |
|
6876 |
mousePressed = false; |
|
6877 |
setCaching(false); |
|
6878 |
Q3Header::mouseReleaseEvent(e); |
|
6879 |
#ifndef NO_LINE_WIDGET |
|
6880 |
line1->hide(); |
|
6881 |
line2->hide(); |
|
6882 |
#else |
|
6883 |
if (d->oldLinePos >= 0) |
|
6884 |
if (orientation() == Horizontal) |
|
6885 |
table->updateContents(d->oldLinePos, table->contentsY(), |
|
6886 |
1, table->visibleHeight()); |
|
6887 |
else |
|
6888 |
table->updateContents( table->contentsX(), d->oldLinePos, |
|
6889 |
table->visibleWidth(), 1); |
|
6890 |
d->oldLinePos = -1; |
|
6891 |
#endif |
|
6892 |
if (resizedSection != -1) { |
|
6893 |
emit sectionSizeChanged(resizedSection); |
|
6894 |
updateStretches(); |
|
6895 |
} |
|
6896 |
||
6897 |
//Make sure all newly selected sections are painted one last time |
|
6898 |
QRect selectedRects; |
|
6899 |
for (int i = 0; i < count(); i++) { |
|
6900 |
if(sectionState(i) == Selected) |
|
6901 |
selectedRects |= sRect(i); |
|
6902 |
} |
|
6903 |
if(!selectedRects.isNull()) |
|
6904 |
repaint(selectedRects); |
|
6905 |
} |
|
6906 |
||
6907 |
/*! \reimp |
|
6908 |
*/ |
|
6909 |
||
6910 |
void Q3TableHeader::mouseDoubleClickEvent(QMouseEvent *e) |
|
6911 |
{ |
|
6912 |
if (e->button() != LeftButton) |
|
6913 |
return; |
|
6914 |
if (isResizing) { |
|
6915 |
int p = real_pos(e->pos(), orientation()) + offset(); |
|
6916 |
int section = sectionAt(p); |
|
6917 |
if (section == -1) |
|
6918 |
return; |
|
6919 |
section--; |
|
6920 |
if (p >= sectionPos(count() - 1) + sectionSize(count() - 1)) |
|
6921 |
++section; |
|
6922 |
while (sectionSize(section) == 0) |
|
6923 |
section--; |
|
6924 |
if (section < 0) |
|
6925 |
return; |
|
6926 |
int oldSize = sectionSize(section); |
|
6927 |
if (orientation() == Horizontal) { |
|
6928 |
table->adjustColumn(section); |
|
6929 |
int newSize = sectionSize(section); |
|
6930 |
if (oldSize != newSize) |
|
6931 |
emit sizeChange(section, oldSize, newSize); |
|
6932 |
for (int i = 0; i < table->numCols(); ++i) { |
|
6933 |
if (table->isColumnSelected(i) && sectionSize(i) != 0) |
|
6934 |
table->adjustColumn(i); |
|
6935 |
} |
|
6936 |
} else { |
|
6937 |
table->adjustRow(section); |
|
6938 |
int newSize = sectionSize(section); |
|
6939 |
if (oldSize != newSize) |
|
6940 |
emit sizeChange(section, oldSize, newSize); |
|
6941 |
for (int i = 0; i < table->numRows(); ++i) { |
|
6942 |
if (table->isRowSelected(i) && sectionSize(i) != 0) |
|
6943 |
table->adjustRow(i); |
|
6944 |
} |
|
6945 |
} |
|
6946 |
} |
|
6947 |
} |
|
6948 |
||
6949 |
/*! \reimp |
|
6950 |
*/ |
|
6951 |
||
6952 |
void Q3TableHeader::resizeEvent(QResizeEvent *e) |
|
6953 |
{ |
|
6954 |
stretchTimer->stop(); |
|
6955 |
widgetStretchTimer->stop(); |
|
6956 |
Q3Header::resizeEvent(e); |
|
6957 |
if (numStretches == 0) |
|
6958 |
return; |
|
6959 |
stretchTimer->start(0, true); |
|
6960 |
} |
|
6961 |
||
6962 |
void Q3TableHeader::updateStretches() |
|
6963 |
{ |
|
6964 |
if (numStretches == 0) |
|
6965 |
return; |
|
6966 |
||
6967 |
int dim = orientation() == Horizontal ? width() : height(); |
|
6968 |
if (sectionPos(count() - 1) + sectionSize(count() - 1) == dim) |
|
6969 |
return; |
|
6970 |
int i; |
|
6971 |
int pd = dim - (sectionPos(count() - 1) |
|
6972 |
+ sectionSize(count() - 1)); |
|
6973 |
bool block = signalsBlocked(); |
|
6974 |
blockSignals(true); |
|
6975 |
for (i = 0; i < (int)stretchable.count(); ++i) { |
|
6976 |
if (!stretchable[i] || |
|
6977 |
(stretchable[i] && table->d->hiddenCols[i])) |
|
6978 |
continue; |
|
6979 |
pd += sectionSize(i); |
|
6980 |
} |
|
6981 |
pd /= numStretches; |
|
6982 |
for (i = 0; i < (int)stretchable.count(); ++i) { |
|
6983 |
if (!stretchable[i] || |
|
6984 |
(stretchable[i] && table->d->hiddenCols[i])) |
|
6985 |
continue; |
|
6986 |
if (i == (int)stretchable.count() - 1 && |
|
6987 |
sectionPos(i) + pd < dim) |
|
6988 |
pd = dim - sectionPos(i); |
|
6989 |
resizeSection(i, QMAX(20, pd)); |
|
6990 |
} |
|
6991 |
blockSignals(block); |
|
6992 |
table->repaintContents(false); |
|
6993 |
widgetStretchTimer->start(100, true); |
|
6994 |
} |
|
6995 |
||
6996 |
void Q3TableHeader::updateWidgetStretches() |
|
6997 |
{ |
|
6998 |
QSize s = table->tableSize(); |
|
6999 |
table->resizeContents(s.width(), s.height()); |
|
7000 |
for (int i = 0; i < table->numCols(); ++i) |
|
7001 |
table->updateColWidgets(i); |
|
7002 |
} |
|
7003 |
||
7004 |
void Q3TableHeader::updateSelections() |
|
7005 |
{ |
|
7006 |
if (table->selectionMode() == Q3Table::NoSelection || |
|
7007 |
(isRowSelection(table->selectionMode()) && orientation() != Vertical )) |
|
7008 |
return; |
|
7009 |
int a = sectionAt(startPos); |
|
7010 |
int b = sectionAt(endPos); |
|
7011 |
int start = QMIN(a, b); |
|
7012 |
int end = QMAX(a, b); |
|
7013 |
register int *s = states.data(); |
|
7014 |
for (int i = 0; i < count(); ++i) { |
|
7015 |
if (i < start || i > end) |
|
7016 |
*s = oldStates.data()[ i ]; |
|
7017 |
else |
|
7018 |
*s = Selected; |
|
7019 |
++s; |
|
7020 |
} |
|
7021 |
repaint(false); |
|
7022 |
||
7023 |
if (table->currentSel) { |
|
7024 |
Q3TableSelection oldSelection = *table->currentSel; |
|
7025 |
if (orientation() == Vertical) |
|
7026 |
table->currentSel->expandTo(b, table->horizontalHeader()->count() - 1); |
|
7027 |
else |
|
7028 |
table->currentSel->expandTo(table->verticalHeader()->count() - 1, b); |
|
7029 |
table->repaintSelections(&oldSelection, table->currentSel, |
|
7030 |
orientation() == Horizontal, |
|
7031 |
orientation() == Vertical); |
|
7032 |
} |
|
7033 |
emit table->selectionChanged(); |
|
7034 |
} |
|
7035 |
||
7036 |
void Q3TableHeader::saveStates() |
|
7037 |
{ |
|
7038 |
oldStates.resize(count()); |
|
7039 |
register int *s = states.data(); |
|
7040 |
register int *s2 = oldStates.data(); |
|
7041 |
for (int i = 0; i < count(); ++i) { |
|
7042 |
*s2 = *s; |
|
7043 |
++s2; |
|
7044 |
++s; |
|
7045 |
} |
|
7046 |
} |
|
7047 |
||
7048 |
void Q3TableHeader::doAutoScroll() |
|
7049 |
{ |
|
7050 |
QPoint pos = mapFromGlobal(QCursor::pos()); |
|
7051 |
int p = real_pos(pos, orientation()) + offset(); |
|
7052 |
if (sectionAt(p) != -1) |
|
7053 |
endPos = p; |
|
7054 |
if (orientation() == Horizontal) |
|
7055 |
table->ensureVisible(endPos, table->contentsY()); |
|
7056 |
else |
|
7057 |
table->ensureVisible(table->contentsX(), endPos); |
|
7058 |
updateSelections(); |
|
7059 |
autoScrollTimer->start(100, true); |
|
7060 |
} |
|
7061 |
||
7062 |
void Q3TableHeader::sectionWidthChanged(int col, int, int) |
|
7063 |
{ |
|
7064 |
resizedSection = col; |
|
7065 |
if (orientation() == Horizontal) { |
|
7066 |
#ifndef NO_LINE_WIDGET |
|
7067 |
table->moveChild(line1, Q3Header::sectionPos(col) - 1, |
|
7068 |
table->contentsY()); |
|
7069 |
line1->resize(1, table->visibleHeight()); |
|
7070 |
line1->show(); |
|
7071 |
line1->raise(); |
|
7072 |
table->moveChild(line2, |
|
7073 |
Q3Header::sectionPos(col) + Q3Header::sectionSize(col) - 1, |
|
7074 |
table->contentsY()); |
|
7075 |
line2->resize(1, table->visibleHeight()); |
|
7076 |
line2->show(); |
|
7077 |
line2->raise(); |
|
7078 |
#else |
|
7079 |
QPainter p(table->viewport()); |
|
7080 |
int lx = Q3Header::sectionPos(col) + Q3Header::sectionSize(col) - 1; |
|
7081 |
int ly = table->contentsY(); |
|
7082 |
||
7083 |
if (lx != d->oldLinePos) { |
|
7084 |
QPoint pt = table->contentsToViewport(QPoint(lx, ly)); |
|
7085 |
p.drawLine(pt.x(), pt.y()+1, |
|
7086 |
pt.x(), pt.y()+ table->visibleHeight()); |
|
7087 |
if (d->oldLinePos >= 0) |
|
7088 |
table->repaintContents(d->oldLinePos, table->contentsY(), |
|
7089 |
1, table->visibleHeight()); |
|
7090 |
||
7091 |
d->oldLinePos = lx; |
|
7092 |
} |
|
7093 |
#endif |
|
7094 |
} else { |
|
7095 |
#ifndef NO_LINE_WIDGET |
|
7096 |
table->moveChild(line1, table->contentsX(), |
|
7097 |
Q3Header::sectionPos(col) - 1); |
|
7098 |
line1->resize(table->visibleWidth(), 1); |
|
7099 |
line1->show(); |
|
7100 |
line1->raise(); |
|
7101 |
table->moveChild(line2, table->contentsX(), |
|
7102 |
Q3Header::sectionPos(col) + Q3Header::sectionSize(col) - 1); |
|
7103 |
line2->resize(table->visibleWidth(), 1); |
|
7104 |
line2->show(); |
|
7105 |
line2->raise(); |
|
7106 |
||
7107 |
#else |
|
7108 |
QPainter p(table->viewport()); |
|
7109 |
int lx = table->contentsX(); |
|
7110 |
int ly = Q3Header::sectionPos(col) + Q3Header::sectionSize(col) - 1; |
|
7111 |
||
7112 |
if (ly != d->oldLinePos) { |
|
7113 |
QPoint pt = table->contentsToViewport(QPoint(lx, ly)); |
|
7114 |
p.drawLine(pt.x()+1, pt.y(), |
|
7115 |
pt.x() + table->visibleWidth(), pt.y()); |
|
7116 |
if (d->oldLinePos >= 0) |
|
7117 |
table->repaintContents( table->contentsX(), d->oldLinePos, |
|
7118 |
table->visibleWidth(), 1); |
|
7119 |
d->oldLinePos = ly; |
|
7120 |
} |
|
7121 |
||
7122 |
#endif |
|
7123 |
} |
|
7124 |
} |
|
7125 |
||
7126 |
/*! |
|
7127 |
\reimp |
|
7128 |
||
7129 |
Returns the size of section \a section in pixels or -1 if \a |
|
7130 |
section is out of range. |
|
7131 |
*/ |
|
7132 |
||
7133 |
int Q3TableHeader::sectionSize(int section) const |
|
7134 |
{ |
|
7135 |
if (count() <= 0 || section < 0 || section >= count()) |
|
7136 |
return -1; |
|
7137 |
if (caching && section < (int)sectionSizes.count()) |
|
7138 |
return sectionSizes[ section ]; |
|
7139 |
return Q3Header::sectionSize(section); |
|
7140 |
} |
|
7141 |
||
7142 |
/*! |
|
7143 |
\reimp |
|
7144 |
||
7145 |
Returns the start position of section \a section in pixels or -1 |
|
7146 |
if \a section is out of range. |
|
7147 |
||
7148 |
\sa sectionAt() |
|
7149 |
*/ |
|
7150 |
||
7151 |
int Q3TableHeader::sectionPos(int section) const |
|
7152 |
{ |
|
7153 |
if (count() <= 0 || section < 0 || section >= count()) |
|
7154 |
return -1; |
|
7155 |
if (caching && section < (int)sectionPoses.count()) |
|
7156 |
return sectionPoses[ section ]; |
|
7157 |
return Q3Header::sectionPos(section); |
|
7158 |
} |
|
7159 |
||
7160 |
/*! |
|
7161 |
\reimp |
|
7162 |
||
7163 |
Returns the number of the section at index position \a pos or -1 |
|
7164 |
if there is no section at the position given. |
|
7165 |
||
7166 |
\sa sectionPos() |
|
7167 |
*/ |
|
7168 |
||
7169 |
int Q3TableHeader::sectionAt(int pos) const |
|
7170 |
{ |
|
7171 |
if (!caching || sectionSizes.count() <= 0 || sectionPoses.count() <= 0) |
|
7172 |
return Q3Header::sectionAt(pos); |
|
7173 |
if (count() <= 0 || pos > sectionPoses[ count() - 1 ] + sectionSizes[ count() - 1 ]) |
|
7174 |
return -1; |
|
7175 |
int l = 0; |
|
7176 |
int r = count() - 1; |
|
7177 |
int i = ((l+r+1) / 2); |
|
7178 |
while (r - l) { |
|
7179 |
if (sectionPoses[i] > pos) |
|
7180 |
r = i -1; |
|
7181 |
else |
|
7182 |
l = i; |
|
7183 |
i = ((l+r+1) / 2); |
|
7184 |
} |
|
7185 |
if (sectionPoses[i] <= pos && |
|
7186 |
pos <= sectionPoses[i] + sectionSizes[ mapToSection(i) ]) |
|
7187 |
return mapToSection(i); |
|
7188 |
return -1; |
|
7189 |
} |
|
7190 |
||
7191 |
void Q3TableHeader::updateCache() |
|
7192 |
{ |
|
7193 |
sectionPoses.resize(count()); |
|
7194 |
sectionSizes.resize(count()); |
|
7195 |
if (!caching) |
|
7196 |
return; |
|
7197 |
for (int i = 0; i < count(); ++i) { |
|
7198 |
sectionSizes[ i ] = Q3Header::sectionSize(i); |
|
7199 |
sectionPoses[ i ] = Q3Header::sectionPos(i); |
|
7200 |
} |
|
7201 |
} |
|
7202 |
||
7203 |
void Q3TableHeader::setCaching(bool b) |
|
7204 |
{ |
|
7205 |
if (caching == b) |
|
7206 |
return; |
|
7207 |
caching = b; |
|
7208 |
sectionPoses.resize(count()); |
|
7209 |
sectionSizes.resize(count()); |
|
7210 |
if (b) { |
|
7211 |
for (int i = 0; i < count(); ++i) { |
|
7212 |
sectionSizes[ i ] = Q3Header::sectionSize(i); |
|
7213 |
sectionPoses[ i ] = Q3Header::sectionPos(i); |
|
7214 |
} |
|
7215 |
} |
|
7216 |
} |
|
7217 |
||
7218 |
/*! |
|
7219 |
If \a b is true, section \a s is stretchable; otherwise the |
|
7220 |
section is not stretchable. |
|
7221 |
||
7222 |
\sa isSectionStretchable() |
|
7223 |
*/ |
|
7224 |
||
7225 |
void Q3TableHeader::setSectionStretchable(int s, bool b) |
|
7226 |
{ |
|
7227 |
if (stretchable[ s ] == b) |
|
7228 |
return; |
|
7229 |
stretchable[ s ] = b; |
|
7230 |
if (b) |
|
7231 |
numStretches++; |
|
7232 |
else |
|
7233 |
numStretches--; |
|
7234 |
} |
|
7235 |
||
7236 |
/*! |
|
7237 |
Returns true if section \a s is stretcheable; otherwise returns |
|
7238 |
false. |
|
7239 |
||
7240 |
\sa setSectionStretchable() |
|
7241 |
*/ |
|
7242 |
||
7243 |
bool Q3TableHeader::isSectionStretchable(int s) const |
|
7244 |
{ |
|
7245 |
return stretchable[ s ]; |
|
7246 |
} |
|
7247 |
||
7248 |
void Q3TableHeader::swapSections(int oldIdx, int newIdx, bool swapTable) |
|
7249 |
{ |
|
7250 |
extern bool qt_qheader_label_return_null_strings; // qheader.cpp |
|
7251 |
qt_qheader_label_return_null_strings = true; |
|
7252 |
||
7253 |
QIconSet oldIconSet, newIconSet; |
|
7254 |
if (iconSet(oldIdx)) |
|
7255 |
oldIconSet = *iconSet(oldIdx); |
|
7256 |
if (iconSet(newIdx)) |
|
7257 |
newIconSet = *iconSet(newIdx); |
|
7258 |
QString oldLabel = label(oldIdx); |
|
7259 |
QString newLabel = label(newIdx); |
|
7260 |
bool sectionsHasContent = !(oldIconSet.isNull() && newIconSet.isNull() |
|
7261 |
&& oldLabel.isNull() && newLabel.isNull()); |
|
7262 |
if (sectionsHasContent) { |
|
7263 |
Q3HeaderData *data = static_cast<Q3Header*>(this)->d; |
|
7264 |
bool oldNullLabel = qt_get_null_label_bit(data, oldIdx); |
|
7265 |
bool newNullLabel = qt_get_null_label_bit(data, newIdx); |
|
7266 |
setLabel(oldIdx, newIconSet, newLabel); |
|
7267 |
setLabel(newIdx, oldIconSet, oldLabel); |
|
7268 |
qt_set_null_label_bit(data, oldIdx, newNullLabel); |
|
7269 |
qt_set_null_label_bit(data, newIdx, oldNullLabel); |
|
7270 |
} |
|
7271 |
||
7272 |
qt_qheader_label_return_null_strings = false; |
|
7273 |
||
7274 |
int w1 = sectionSize(oldIdx); |
|
7275 |
int w2 = sectionSize(newIdx); |
|
7276 |
if (w1 != w2) { |
|
7277 |
resizeSection(oldIdx, w2); |
|
7278 |
resizeSection(newIdx, w1); |
|
7279 |
} |
|
7280 |
||
7281 |
if (!swapTable) |
|
7282 |
return; |
|
7283 |
if (orientation() == Horizontal) |
|
7284 |
table->swapColumns(oldIdx, newIdx); |
|
7285 |
else |
|
7286 |
table->swapRows(oldIdx, newIdx); |
|
7287 |
} |
|
7288 |
||
7289 |
void Q3TableHeader::indexChanged(int sec, int oldIdx, int newIdx) |
|
7290 |
{ |
|
7291 |
newIdx = mapToIndex(sec); |
|
7292 |
if (oldIdx > newIdx) |
|
7293 |
moveSection(sec, oldIdx + 1); |
|
7294 |
else |
|
7295 |
moveSection(sec, oldIdx); |
|
7296 |
||
7297 |
if (oldIdx < newIdx) { |
|
7298 |
while (oldIdx < newIdx) { |
|
7299 |
swapSections(oldIdx, oldIdx + 1); |
|
7300 |
oldIdx++; |
|
7301 |
} |
|
7302 |
} else { |
|
7303 |
while (oldIdx > newIdx) { |
|
7304 |
swapSections(oldIdx - 1, oldIdx); |
|
7305 |
oldIdx--; |
|
7306 |
} |
|
7307 |
} |
|
7308 |
||
7309 |
table->repaintContents(table->contentsX(), table->contentsY(), |
|
7310 |
table->visibleWidth(), table->visibleHeight()); |
|
7311 |
} |
|
7312 |
||
7313 |
void Q3TableHeader::setLabels(const QStringList & labels) |
|
7314 |
{ |
|
7315 |
int i = 0; |
|
7316 |
const int c = QMIN(count(), (int)labels.count()); |
|
7317 |
bool updates = updatesEnabled(); |
|
7318 |
if (updates) |
|
7319 |
setUpdatesEnabled(false); |
|
7320 |
for (QStringList::ConstIterator it = labels.begin(); i < c; ++i, ++it) { |
|
7321 |
if (i == c - 1) { |
|
7322 |
if (updates) |
|
7323 |
setUpdatesEnabled(true); |
|
7324 |
setLabel(i, *it); |
|
7325 |
} else { |
|
7326 |
Q3Header::setLabel(i, *it); |
|
7327 |
emit sectionSizeChanged(i); |
|
7328 |
} |
|
7329 |
} |
|
7330 |
} |
|
7331 |
||
7332 |
QT_END_NAMESPACE |
|
7333 |
||
7334 |
#include "q3table.moc" |