source: trunk/src/table/qtable.cpp@ 172

Last change on this file since 172 was 166, checked in by dmik, 19 years ago

Table: Added #ifndef QT_NO_SQL to allow building when no sql module is available.

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