source: branches/4.5.1/src/qt3support/itemviews/q3table.cpp

Last change on this file was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

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