source: vendor/trolltech/current/src/table/qtable.cpp

Last change on this file was 160, checked in by dmik, 19 years ago

Imported table and iconview modules and a bunch of dependent examples from the official release 3.3.1 from Trolltech.

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