|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
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" |