1
/****************************************************************************
3
** Copyright (C) 1992-2005 Trolltech AS. All rights reserved.
5
** This file is part of the Qt 3 compatibility classes of the Qt Toolkit.
7
** This file may be distributed under the terms of the Q Public License
8
** as defined by Trolltech AS of Norway and appearing in the file
9
** LICENSE.QPL included in the packaging of this file.
11
** This file may be distributed and/or modified under the terms of the
12
** GNU General Public License version 2 as published by the Free Software
13
** Foundation and appearing in the file LICENSE.GPL included in the
14
** packaging of this file.
16
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
17
** information about Qt Commercial License Agreements.
18
** See http://www.trolltech.com/qpl/ for QPL licensing information.
19
** See http://www.trolltech.com/gpl/ for GPL licensing information.
21
** Contact info@trolltech.com if any conditions of this licensing are
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.
27
****************************************************************************/
31
// needed for qsort() because of a std namespace problem on Borland
32
#include "qplatformdefs.h"
39
#include <qlineedit.h>
41
#include <qapplication.h>
44
#include <qcombobox.h>
45
#include <qcheckbox.h>
46
#include <q3dragobject.h>
48
#include <q3listbox.h>
50
#include <q3datatable.h>
51
#include <qvalidator.h>
59
static bool qt_update_cell_widget = true;
60
static bool qt_table_clipper_enabled = true;
61
#ifndef QT_INTERNAL_TABLE
64
void qt_set_table_clipper_enabled(bool enabled)
66
qt_table_clipper_enabled = enabled;
69
class Q_COMPAT_EXPORT Q3TableHeader : public Q3Header
81
Q3TableHeader(int, Q3Table *t, QWidget* parent=0, const char* name=0);
83
void addLabel(const QString &s, int size);
84
void setLabel(int section, const QString & s, int size = -1);
85
void setLabel(int section, const QIconSet & iconset, const QString & s,
88
void setLabels(const QStringList & labels);
90
void removeLabel(int section);
92
void setSectionState(int s, SectionState state);
93
void setSectionStateToAll(SectionState state);
94
SectionState sectionState(int s) const;
96
int sectionSize(int section) const;
97
int sectionPos(int section) const;
98
int sectionAt(int section) const;
100
void setSectionStretchable(int s, bool b);
101
bool isSectionStretchable(int s) const;
106
void sectionSizeChanged(int s);
109
void paintEvent(QPaintEvent *e);
110
void paintSection(QPainter *p, int index, const QRect& fr);
111
void mousePressEvent(QMouseEvent *e);
112
void mouseMoveEvent(QMouseEvent *e);
113
void mouseReleaseEvent(QMouseEvent *e);
114
void mouseDoubleClickEvent(QMouseEvent *e);
115
void resizeEvent(QResizeEvent *e);
119
void sectionWidthChanged(int col, int os, int ns);
120
void indexChanged(int sec, int oldIdx, int newIdx);
121
void updateStretches();
122
void updateWidgetStretches();
125
void updateSelections();
127
void setCaching(bool b);
128
void swapSections(int oldIdx, int newIdx, bool swapTable = true);
129
bool doSelection(QMouseEvent *e);
130
void sectionLabelChanged(int section);
131
void resizeArrays(int n);
134
Q3MemArray<int> states, oldStates;
135
Q3MemArray<bool> stretchable;
136
Q3MemArray<int> sectionSizes, sectionPoses;
138
int pressPos, startPos, endPos;
140
QTimer *autoScrollTimer;
141
QWidget *line1, *line2;
146
QTimer *stretchTimer, *widgetStretchTimer;
147
Q3TableHeaderPrivate *d;
152
# define NO_LINE_WIDGET
157
struct Q3TablePrivate
159
Q3TablePrivate() : hasRowSpan(false), hasColSpan(false),
160
inMenuMode(false), redirectMouseEvent(false)
162
hiddenRows.setAutoDelete(true);
163
hiddenCols.setAutoDelete(true);
168
uint redirectMouseEvent : 1;
169
Q3IntDict<int> hiddenRows, hiddenCols;
175
struct Q3TableHeaderPrivate
177
#ifdef NO_LINE_WIDGET
182
static bool isRowSelection(Q3Table::SelectionMode selMode)
184
return selMode == Q3Table::SingleRow || selMode == Q3Table::MultiRow;
188
\class Q3TableSelection
189
\brief The Q3TableSelection class provides access to a selected area in a
194
The selection is a rectangular set of cells in a Q3Table. One of
195
the rectangle's cells is called the anchor cell; this is the cell
196
that was selected first. The init() function sets the anchor and
197
the selection rectangle to exactly this cell; the expandTo()
198
function expands the selection rectangle to include additional
201
There are various access functions to find out about the area:
202
anchorRow() and anchorCol() return the anchor's position;
203
leftCol(), rightCol(), topRow() and bottomRow() return the
204
rectangle's four edges. All four are part of the selection.
206
A newly created Q3TableSelection is inactive -- isActive() returns
207
false. You must use init() and expandTo() to activate it.
209
\sa Q3Table Q3Table::addSelection() Q3Table::selection()
210
Q3Table::selectCells() Q3Table::selectRow() Q3Table::selectColumn()
214
Creates an inactive selection. Use init() and expandTo() to
218
Q3TableSelection::Q3TableSelection()
219
: active(false), inited(false), tRow(-1), lCol(-1),
220
bRow(-1), rCol(-1), aRow(-1), aCol(-1)
225
Creates an active selection, starting at \a start_row and \a
226
start_col, ending at \a end_row and \a end_col.
229
Q3TableSelection::Q3TableSelection(int start_row, int start_col, int end_row, int end_col)
230
: active(false), inited(false), tRow(-1), lCol(-1),
231
bRow(-1), rCol(-1), aRow(-1), aCol(-1)
233
init(start_row, start_col);
234
expandTo(end_row, end_col);
238
Sets the selection anchor to cell \a row, \a col and the selection
239
to only contain this cell. The selection is not active until
240
expandTo() is called.
242
To extend the selection to include additional cells, call
248
void Q3TableSelection::init(int row, int col)
250
aCol = lCol = rCol = col;
251
aRow = tRow = bRow = row;
257
Expands the selection to include cell \a row, \a col. The new
258
selection rectangle is the bounding rectangle of \a row, \a col
259
and the previous selection rectangle. After calling this function
260
the selection is active.
262
If you haven't called init(), this function does nothing.
264
\sa init() isActive()
267
void Q3TableSelection::expandTo(int row, int col)
291
Returns true if \a s includes the same cells as the selection;
292
otherwise returns false.
295
bool Q3TableSelection::operator==(const Q3TableSelection &s) const
297
return (s.active == active &&
298
s.tRow == tRow && s.bRow == bRow &&
299
s.lCol == lCol && s.rCol == rCol);
303
\fn bool Q3TableSelection::operator!=(const Q3TableSelection &s) const
305
Returns true if \a s does not include the same cells as the
306
selection; otherwise returns false.
311
\fn int Q3TableSelection::topRow() const
313
Returns the top row of the selection.
315
\sa bottomRow() leftCol() rightCol()
319
\fn int Q3TableSelection::bottomRow() const
321
Returns the bottom row of the selection.
323
\sa topRow() leftCol() rightCol()
327
\fn int Q3TableSelection::leftCol() const
329
Returns the left column of the selection.
331
\sa topRow() bottomRow() rightCol()
335
\fn int Q3TableSelection::rightCol() const
337
Returns the right column of the selection.
339
\sa topRow() bottomRow() leftCol()
343
\fn int Q3TableSelection::anchorRow() const
345
Returns the anchor row of the selection.
347
\sa anchorCol() expandTo()
351
\fn int Q3TableSelection::anchorCol() const
353
Returns the anchor column of the selection.
355
\sa anchorRow() expandTo()
359
\fn int Q3TableSelection::numRows() const
361
Returns the number of rows in the selection.
365
int Q3TableSelection::numRows() const
367
return (tRow < 0) ? 0 : bRow - tRow + 1;
371
Returns the number of columns in the selection.
375
int Q3TableSelection::numCols() const
377
return (lCol < 0) ? 0 : rCol - lCol + 1;
381
\fn bool Q3TableSelection::isActive() const
383
Returns whether the selection is active or not. A selection is
384
active after init() \e and expandTo() have been called.
388
\fn bool Q3TableSelection::isEmpty() const
390
Returns whether the selection is empty or not.
392
\sa numRows(), numCols()
397
\brief The Q3TableItem class provides the cell content for Q3Table cells.
401
For many applications Q3TableItems are ideal for presenting and
402
editing the contents of Q3Table cells. In situations where you need
403
to create very large tables you may prefer an alternative approach
404
to using Q3TableItems: see the notes on large tables.
406
A Q3TableItem contains a cell's data, by default, a string and a
407
pixmap. The table item also holds the cell's display size and how
408
the data should be aligned. The table item specifies the cell's
409
\l EditType and the editor used for in-place editing (by default a
410
QLineEdit). If you want checkboxes use \l{Q3CheckTableItem}, and if
411
you want comboboxes use \l{Q3ComboTableItem}. The \l EditType (set
412
in the constructor) determines whether the cell's contents may be
415
If a pixmap is specified it is displayed to the left of any text.
416
You can change the text or pixmap with setText() and setPixmap()
417
respectively. For text you can use setWordWrap().
419
When sorting table items the key() function is used; by default
420
this returns the table item's text(). Reimplement key() to
421
customize how your table items will sort.
423
Table items are inserted into a table using Q3Table::setItem(). If
424
you insert an item into a cell that already contains a table item
425
the original item will be deleted.
429
for (int row = 0; row < table->numRows(); row++) {
430
for (int col = 0; col < table->numCols(); col++) {
431
table->setItem(row, col,
432
new Q3TableItem(table, Q3TableItem::WhenCurrent, QString::number(row * col)));
437
You can move a table item from one cell to another, in the same or
438
a different table, using Q3Table::takeItem() and Q3Table::setItem()
439
but see also Q3Table::swapCells().
441
Table items can be deleted with delete in the standard way; the
442
table and cell will be updated accordingly.
444
Note, that if you have a table item that is not currently in a table
445
then anything you do to that item other than insert it into a table
446
will result in undefined behaviour.
448
Reimplement createEditor() and setContentFromEditor() if you want
449
to use your own widget instead of a QLineEdit for editing cell
450
contents. Reimplement paint() if you want to display custom
453
It is important to ensure that your custom widget can accept the
454
keyboard focus, so that the user can use the tab key to navigate the
455
table as normal. Therefore, if the widget returned by createEditor()
456
does not itself accept the keyboard focus, it is necessary to
457
nominate a child widget to do so on its behalf. For example, a
458
QHBox with two child QLineEdit widgets may use one of them to
459
accept the keyboard focus:
462
QWidget* MyTableItem::createEditor() const
464
QHBox* hbox = new QHBox(table()->viewport());
465
hbox->setFocusProxy(new QLineEdit(hbox));
471
By default, table items may be replaced by new Q3TableItems
472
during the lifetime of a Q3Table. Therefore, if you create your
473
own subclass of Q3TableItem, and you want to ensure that
474
this does not happen, you must call setReplaceable(false)
475
in the constructor of your subclass.
477
\img qtableitems.png Table Items
479
\sa Q3CheckTableItem Q3ComboTableItem
484
\fn Q3Table *Q3TableItem::table() const
486
Returns the Q3Table the table item belongs to.
488
\sa Q3Table::setItem() Q3TableItem()
492
\enum Q3TableItem::EditType
495
This enum is used to define whether a cell is editable or
496
read-only (in conjunction with other settings), and how the cell
500
The cell always \e looks editable.
502
Using this EditType ensures that the editor created with
503
createEditor() (by default a QLineEdit) is always visible. This
504
has implications for the alignment of the content: the default
505
editor aligns everything (even numbers) to the left whilst
506
numerical values in the cell are by default aligned to the right.
508
If a cell with the edit type \c Always looks misaligned you could
509
reimplement createEditor() for these items.
512
The cell \e looks editable only when it has keyboard focus (see
513
Q3Table::setCurrentCell()).
516
The cell \e looks editable only when the user types in it or
517
double-clicks it. It resembles the \c WhenCurrent functionality
518
but is, perhaps, nicer.
520
The \c OnTyping edit type is the default when Q3TableItem objects
521
are created by the convenience functions Q3Table::setText() and
522
Q3Table::setPixmap().
524
\value Never The cell is not editable.
526
The cell is actually editable only if Q3Table::isRowReadOnly() is
527
false for its row, Q3Table::isColumnReadOnly() is false for its
528
column, and Q3Table::isReadOnly() is false.
530
Q3ComboTableItems have an isEditable() property. This property is
531
used to indicate whether the user may enter their own text or are
532
restricted to choosing one of the choices in the list.
533
Q3ComboTableItems may be interacted with only if they are editable
534
in accordance with their EditType as described above.
539
Creates a table item that is a child of table \a table with no
540
text. The item has the \l EditType \a et.
542
The table item will use a QLineEdit for its editor, will not
543
word-wrap and will occupy a single cell. Insert the table item
544
into a table with Q3Table::setItem().
546
The table takes ownership of the table item, so a table item
547
should not be inserted into more than one table at a time.
550
Q3TableItem::Q3TableItem(Q3Table *table, EditType et)
551
: txt(), pix(), t(table), edType(et), wordwrap(false),
552
tcha(true), rw(-1), cl(-1), rowspan(1), colspan(1)
558
Creates a table item that is a child of table \a table with text
559
\a text. The item has the \l EditType \a et.
561
The table item will use a QLineEdit for its editor, will not
562
word-wrap and will occupy a single cell. Insert the table item
563
into a table with Q3Table::setItem().
565
The table takes ownership of the table item, so a table item
566
should not be inserted into more than one table at a time.
569
Q3TableItem::Q3TableItem(Q3Table *table, EditType et, const QString &text)
570
: txt(text), pix(), t(table), edType(et), wordwrap(false),
571
tcha(true), rw(-1), cl(-1), rowspan(1), colspan(1)
577
Creates a table item that is a child of table \a table with text
578
\a text and pixmap \a p. The item has the \l EditType \a et.
580
The table item will display the pixmap to the left of the text. It
581
will use a QLineEdit for editing the text, will not word-wrap and
582
will occupy a single cell. Insert the table item into a table with
585
The table takes ownership of the table item, so a table item
586
should not be inserted in more than one table at a time.
589
Q3TableItem::Q3TableItem(Q3Table *table, EditType et,
590
const QString &text, const QPixmap &p)
591
: txt(text), pix(p), t(table), edType(et), wordwrap(false),
592
tcha(true), rw(-1), cl(-1), rowspan(1), colspan(1)
598
The destructor deletes this item and frees all allocated
601
If the table item is in a table (i.e. was inserted with
602
setItem()), it will be removed from the table and the cell it
606
Q3TableItem::~Q3TableItem()
609
table()->takeItem(this);
612
int Q3TableItem::RTTI = 0;
615
Returns the Run Time Type Identification value for this table item
616
which for Q3TableItems is 0.
618
When you create subclasses based on Q3TableItem make sure that each
619
subclass returns a unique rtti() value. It is advisable to use
620
values greater than 1000, preferably large random numbers, to
621
allow for extensions to this class.
623
\sa Q3CheckTableItem::rtti() Q3ComboTableItem::rtti()
626
int Q3TableItem::rtti() const
632
Returns the table item's pixmap or a null pixmap if no pixmap has
635
\sa setPixmap() text()
638
QPixmap Q3TableItem::pixmap() const
645
Returns the text of the table item or an empty string if there is
648
To ensure that the current value of the editor is returned,
649
setContentFromEditor() is called:
651
\i if the editMode() is \c Always, or
652
\i if editMode() is \e not \c Always but the editor of the cell is
653
active and the editor is not a QLineEdit.
656
This means that text() returns the original text value of the item
657
if the editor is a line edit, until the user commits an edit (e.g.
658
by pressing Enter or Tab) in which case the new text is returned.
659
For other editors (e.g. a combobox) setContentFromEditor() is
660
always called so the currently display value is the one returned.
662
\sa setText() pixmap()
665
QString Q3TableItem::text() const
667
QWidget *w = table()->cellWidget(rw, cl);
668
if (w && (edType == Always ||
669
rtti() == Q3ComboTableItem::RTTI ||
670
rtti() == Q3CheckTableItem::RTTI))
671
((Q3TableItem*)this)->setContentFromEditor(w);
676
Sets pixmap \a p to be this item's pixmap.
678
Note that setPixmap() does not update the cell the table item
679
belongs to. Use Q3Table::updateCell() to repaint the cell's
682
For \l{Q3ComboTableItem}s and \l{Q3CheckTableItem}s this function
683
has no visible effect.
685
\sa Q3Table::setPixmap() pixmap() setText()
688
void Q3TableItem::setPixmap(const QPixmap &p)
694
Changes the table item's text to \a str.
696
Note that setText() does not update the cell the table item
697
belongs to. Use Q3Table::updateCell() to repaint the cell's
700
\sa Q3Table::setText() text() setPixmap() Q3Table::updateCell()
703
void Q3TableItem::setText(const QString &str)
709
This virtual function is used to paint the contents of an item
710
using the painter \a p in the rectangular area \a cr using the
713
If \a selected is true the cell is displayed in a way that
714
indicates that it is highlighted.
716
You don't usually need to use this function but if you want to
717
draw custom content in a cell you will need to reimplement it.
719
The painter passed to this function is translated so that 0, 0
720
is the top-left corner of the item that is being painted.
722
Note that the painter is not clipped by default in order to get
723
maximum efficiency. If you want clipping, use
726
p->setClipRect(table()->cellRect(row, col), QPainter::ClipPainter);
727
//... your drawing code
728
p->setClipping(false);
733
void Q3TableItem::paint(QPainter *p, const QColorGroup &cg,
734
const QRect &cr, bool selected)
736
p->fillRect(0, 0, cr.width(), cr.height(),
737
selected ? cg.brush(QColorGroup::Highlight)
738
: cg.brush(QColorGroup::Base));
745
p->drawPixmap(0, (cr.height() - pix.height()) / 2, pix);
750
p->setPen(cg.highlightedText());
752
p->setPen(cg.text());
753
p->drawText(x + 2, 0, w - x - 4, h,
754
wordwrap ? (alignment() | WordBreak) : alignment(), text());
758
This virtual function creates an editor which the user can
759
interact with to edit the cell's contents. The default
760
implementation creates a QLineEdit.
762
If the function returns 0, the cell is read-only.
764
The returned widget should preferably be invisible, ideally with
765
Q3Table::viewport() as parent.
767
If you reimplement this function you'll almost certainly need to
768
reimplement setContentFromEditor(), and may need to reimplement
771
\sa Q3Table::createEditor() setContentFromEditor() Q3Table::viewport() setReplaceable()
774
QWidget *Q3TableItem::createEditor() const
776
QLineEdit *e = new QLineEdit(table()->viewport(), "qt_tableeditor");
783
Whenever the content of a cell has been edited by the editor \a w,
784
Q3Table calls this virtual function to copy the new values into the
787
If you reimplement createEditor() and return something that is not
788
a QLineEdit you will need to reimplement this function.
790
\sa Q3Table::setCellContentFromEditor()
793
void Q3TableItem::setContentFromEditor(QWidget *w)
795
QLineEdit *le = ::qobject_cast<QLineEdit*>(w);
797
QString input = le->text();
799
le->validator()->fixup(input);
805
The alignment function returns how the text contents of the cell
806
are aligned when drawn. The default implementation aligns numbers
807
to the right and any other text to the left.
812
// ed: For consistency reasons a setAlignment() should be provided
815
int Q3TableItem::alignment() const
818
bool ok1 = false, ok2 = false;
819
(void)text().toInt(&ok1);
821
(void)text().toDouble(&ok2); // ### should be .-aligned
824
return (num ? AlignRight : AlignLeft) | AlignVCenter;
828
If \a b is true, the cell's text will be wrapped over multiple
829
lines, when necessary, to fit the width of the cell; otherwise the
830
text will be written as a single line.
832
\sa wordWrap() Q3Table::adjustColumn() Q3Table::setColumnStretchable()
835
void Q3TableItem::setWordWrap(bool b)
841
Returns true if word wrap is enabled for the cell; otherwise
847
bool Q3TableItem::wordWrap() const
854
void Q3TableItem::updateEditor(int oldRow, int oldCol)
856
if (edType != Always)
858
if (oldRow != -1 && oldCol != -1)
859
table()->clearCellWidget(oldRow, oldCol);
860
if (rw != -1 && cl != -1)
861
table()->setCellWidget(rw, cl, createEditor());
865
Returns the table item's edit type.
867
This is set when the table item is constructed.
869
\sa EditType Q3TableItem()
872
Q3TableItem::EditType Q3TableItem::editType() const
878
If \a b is true it is acceptable to replace the contents of the
879
cell with the contents of another Q3TableItem. If \a b is false the
880
contents of the cell may not be replaced by the contents of
881
another table item. Table items that span more than one cell may
882
not have their contents replaced by another table item.
884
(This differs from \l EditType because EditType is concerned with
885
whether the \e user is able to change the contents of a cell.)
890
void Q3TableItem::setReplaceable(bool b)
896
This function returns whether the contents of the cell may be
897
replaced with the contents of another table item. Regardless of
898
this setting, table items that span more than one cell may not
899
have their contents replaced by another table item.
901
(This differs from \l EditType because EditType is concerned with
902
whether the \e user is able to change the contents of a cell.)
904
\sa setReplaceable() EditType
907
bool Q3TableItem::isReplaceable() const
909
if (rowspan > 1 || colspan > 1)
915
This virtual function returns the key that should be used for
916
sorting. The default implementation returns the text() of the
919
\sa Q3Table::setSorting()
922
QString Q3TableItem::key() const
928
This virtual function returns the size a cell needs to show its
931
If you subclass Q3TableItem you will often need to reimplement this
935
QSize Q3TableItem::sizeHint() const
937
QSize strutSize = QApplication::globalStrut();
938
if (edType == Always && table()->cellWidget(rw, cl))
939
return table()->cellWidget(rw, cl)->sizeHint().expandedTo(strutSize);
945
s.setWidth(s.width() + 2);
950
if (!wordwrap && t.find('\n') == -1)
951
return QSize(s.width() + table()->fontMetrics().width(text()) + 10,
952
QMAX(s.height(), table()->fontMetrics().height())).expandedTo(strutSize);
954
QRect r = table()->fontMetrics().boundingRect(x + 2, 0, table()->columnWidth(col()) - x - 4, 0,
955
wordwrap ? (alignment() | WordBreak) : alignment(),
957
r.setWidth(QMAX(r.width() + 10, table()->columnWidth(col())));
958
return QSize(r.width(), QMAX(s.height(), r.height())).expandedTo(strutSize);
962
Changes the extent of the Q3TableItem so that it spans multiple
963
cells covering \a rs rows and \a cs columns. The top left cell is
966
\warning This function only works if the item has already been
967
inserted into the table using e.g. Q3Table::setItem(). This
968
function also checks to make sure if \a rs and \a cs are within
969
the bounds of the table and returns without changing the span if
970
they are not. In addition swapping, inserting or removing rows and
971
columns that cross Q3TableItems spanning more than one cell is not
974
\sa rowSpan() colSpan()
977
void Q3TableItem::setSpan(int rs, int cs)
979
if (rs == rowspan && cs == colspan)
982
if (!table()->d->hasRowSpan)
983
table()->d->hasRowSpan = rs > 1;
984
if (!table()->d->hasColSpan)
985
table()->d->hasColSpan = cs > 1;
986
// return if we are thinking too big...
987
if (rw + rs > table()->numRows())
990
if (cl + cs > table()->numCols())
993
if (rw == -1 || cl == -1)
998
if (rowspan > 1 || colspan > 1) {
999
Q3Table* t = table();
1001
t->setItem(rrow, rcol, this);
1007
for (int r = 0; r < rowspan; ++r) {
1008
for (int c = 0; c < colspan; ++c) {
1009
if (r == 0 && c == 0)
1011
qt_update_cell_widget = false;
1012
table()->setItem(r + rw, c + cl, this);
1013
qt_update_cell_widget = true;
1019
table()->updateCell(rw, cl);
1020
QWidget *w = table()->cellWidget(rw, cl);
1022
w->resize(table()->cellGeometry(rw, cl).size());
1026
Returns the row span of the table item, usually 1.
1028
\sa setSpan() colSpan()
1031
int Q3TableItem::rowSpan() const
1037
Returns the column span of the table item, usually 1.
1039
\sa setSpan() rowSpan()
1042
int Q3TableItem::colSpan() const
1048
Sets row \a r as the table item's row. Usually you do not need to
1051
If the cell spans multiple rows, this function sets the top row
1052
and retains the height of the multi-cell table item.
1054
\sa row() setCol() rowSpan()
1057
void Q3TableItem::setRow(int r)
1063
Sets column \a c as the table item's column. Usually you will not
1064
need to call this function.
1066
If the cell spans multiple columns, this function sets the
1067
left-most column and retains the width of the multi-cell table
1070
\sa col() setRow() colSpan()
1073
void Q3TableItem::setCol(int c)
1079
Returns the row where the table item is located. If the cell spans
1080
multiple rows, this function returns the top-most row.
1085
int Q3TableItem::row() const
1091
Returns the column where the table item is located. If the cell
1092
spans multiple columns, this function returns the left-most
1098
int Q3TableItem::col() const
1104
If \a b is true, the table item is enabled; if \a b is false the
1105
table item is disabled.
1107
A disabled item doesn't respond to user interaction.
1112
void Q3TableItem::setEnabled(bool b)
1114
if (b == (bool)enabled)
1117
table()->updateCell(row(), col());
1121
Returns true if the table item is enabled; otherwise returns false.
1126
bool Q3TableItem::isEnabled() const
1128
return (bool)enabled;
1132
\class Q3ComboTableItem
1133
\brief The Q3ComboTableItem class provides a means of using
1134
comboboxes in Q3Tables.
1138
A Q3ComboTableItem is a table item which looks and behaves like a
1139
combobox. The advantage of using Q3ComboTableItems rather than real
1140
comboboxes is that a Q3ComboTableItem uses far less resources than
1141
real comboboxes in \l{Q3Table}s. When the cell has the focus it
1142
displays a real combobox which the user can interact with. When
1143
the cell does not have the focus the cell \e looks like a
1144
combobox. Only text items (i.e. no pixmaps) may be used in
1147
Q3ComboTableItem items have the edit type \c WhenCurrent (see
1148
\l{EditType}). The Q3ComboTableItem's list of items is provided by
1149
a QStringList passed to the constructor.
1151
The list of items may be changed using setStringList(). The
1152
current item can be set with setCurrentItem() and retrieved with
1153
currentItem(). The text of the current item can be obtained with
1154
currentText(), and the text of a particular item can be retrieved
1157
If isEditable() is true the Q3ComboTableItem will permit the user
1158
to either choose an existing list item, or create a new list item
1159
by entering their own text; otherwise the user may only choose one
1160
of the existing list items.
1162
To populate a table cell with a Q3ComboTableItem use
1165
Q3ComboTableItems may be deleted with Q3Table::clearCell().
1167
Q3ComboTableItems can be distinguished from \l{Q3TableItem}s and
1168
\l{Q3CheckTableItem}s using their Run Time Type Identification
1169
number (see rtti()).
1171
\img qtableitems.png Table Items
1173
\sa Q3CheckTableItem Q3TableItem QComboBox
1176
QComboBox *Q3ComboTableItem::fakeCombo = 0;
1177
QWidget *Q3ComboTableItem::fakeComboWidget = 0;
1178
int Q3ComboTableItem::fakeRef = 0;
1181
Creates a combo table item for the table \a table. The combobox's
1182
list of items is passed in the \a list argument. If \a editable is
1183
true the user may type in new list items; if \a editable is false
1184
the user may only select from the list of items provided.
1186
By default Q3ComboTableItems cannot be replaced by other table
1187
items since isReplaceable() returns false by default.
1189
\sa Q3Table::clearCell() EditType
1192
Q3ComboTableItem::Q3ComboTableItem(Q3Table *table, const QStringList &list, bool editable)
1193
: Q3TableItem(table, WhenCurrent, ""), entries(list), current(0), edit(editable)
1195
setReplaceable(false);
1196
if (!Q3ComboTableItem::fakeCombo) {
1197
Q3ComboTableItem::fakeComboWidget = new QWidget(0, 0);
1198
Q3ComboTableItem::fakeCombo = new QComboBox(false, Q3ComboTableItem::fakeComboWidget, 0);
1199
Q3ComboTableItem::fakeCombo->hide();
1201
++Q3ComboTableItem::fakeRef;
1202
if (entries.count())
1203
setText(entries.at(current));
1207
Q3ComboTableItem destructor.
1209
Q3ComboTableItem::~Q3ComboTableItem()
1211
if (--Q3ComboTableItem::fakeRef <= 0) {
1212
delete Q3ComboTableItem::fakeComboWidget;
1213
Q3ComboTableItem::fakeComboWidget = 0;
1214
Q3ComboTableItem::fakeCombo = 0;
1219
Sets the list items of this Q3ComboTableItem to the strings in the
1223
void Q3ComboTableItem::setStringList(const QStringList &l)
1227
if (entries.count())
1228
setText(entries.at(current));
1229
if (table()->cellWidget(row(), col())) {
1231
cb->insertStringList(entries);
1233
table()->updateCell(row(), col());
1238
QWidget *Q3ComboTableItem::createEditor() const
1240
// create an editor - a combobox in our case
1241
((Q3ComboTableItem*)this)->cb = new QComboBox(edit, table()->viewport(), "qt_editor_cb");
1242
cb->insertStringList(entries);
1243
cb->setCurrentItem(current);
1244
QObject::connect(cb, SIGNAL(activated(int)), table(), SLOT(doValueChanged()));
1250
void Q3ComboTableItem::setContentFromEditor(QWidget *w)
1252
QComboBox *cb = ::qobject_cast<QComboBox*>(w);
1255
for (int i = 0; i < cb->count(); ++i)
1256
entries << cb->text(i);
1257
current = cb->currentItem();
1258
setText(entries.at(current));
1264
void Q3ComboTableItem::paint(QPainter *p, const QColorGroup &cg,
1265
const QRect &cr, bool selected)
1267
fakeCombo->resize(cr.width(), cr.height());
1271
pal2.setBrush(QPalette::Base, cg.QPalette::brush(QPalette::Highlight));
1272
pal2.setColor(QPalette::Text, cg.highlightedText());
1275
QStyle::State flags = QStyle::State_None;
1276
if(isEnabled() && table()->isEnabled())
1277
flags |= QStyle::State_Enabled;
1278
// Since we still have the "fakeCombo" may as well use it in this case.
1279
QStyleOptionComboBox opt;
1280
opt.rect = fakeCombo->rect();
1283
opt.subControls = QStyle::SC_All;
1284
opt.activeSubControls = QStyle::SC_None;
1285
opt.editable = fakeCombo->editable();
1286
table()->style()->drawComplexControl(QStyle::CC_ComboBox, &opt, p, fakeCombo);
1289
QRect textR = table()->style()->subControlRect(QStyle::CC_ComboBox, &opt,
1290
QStyle::SC_ComboBoxEditField, fakeCombo);
1291
int align = alignment(); // alignment() changes entries
1292
p->drawText(textR, wordWrap() ? (align | Qt::WordBreak) : align, entries.at(current));
1297
Sets the list item \a i to be the combo table item's current list
1303
void Q3ComboTableItem::setCurrentItem(int i)
1305
QWidget *w = table()->cellWidget(row(), col());
1306
QComboBox *cb = ::qobject_cast<QComboBox*>(w);
1308
cb->setCurrentItem(i);
1310
setText(cb->currentText());
1313
setText(entries.at(i));
1314
table()->updateCell(row(), col());
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.
1327
void Q3ComboTableItem::setCurrentItem(const QString &s)
1329
int i = entries.findIndex(s);
1335
Returns the index of the combo table item's current list item.
1337
\sa setCurrentItem()
1340
int Q3ComboTableItem::currentItem() const
1342
QWidget *w = table()->cellWidget(row(), col());
1343
QComboBox *cb = ::qobject_cast<QComboBox*>(w);
1345
return cb->currentItem();
1350
Returns the text of the combo table item's current list item.
1352
\sa currentItem() text()
1355
QString Q3ComboTableItem::currentText() const
1357
QWidget *w = table()->cellWidget(row(), col());
1358
QComboBox *cb = ::qobject_cast<QComboBox*>(w);
1360
return cb->currentText();
1361
return entries.at(current);
1365
Returns the total number of list items in the combo table item.
1368
int Q3ComboTableItem::count() const
1370
QWidget *w = table()->cellWidget(row(), col());
1371
QComboBox *cb = ::qobject_cast<QComboBox*>(w);
1374
return (int)entries.count();
1378
Returns the text of the combo's list item at index \a i.
1383
QString Q3ComboTableItem::text(int i) const
1385
QWidget *w = table()->cellWidget(row(), col());
1386
QComboBox *cb = ::qobject_cast<QComboBox*>(w);
1389
return entries.at(i);
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.
1400
void Q3ComboTableItem::setEditable(bool b)
1406
Returns true if the user can add their own list items to the
1407
combobox's list of items; otherwise returns false.
1412
bool Q3ComboTableItem::isEditable() const
1417
int Q3ComboTableItem::RTTI = 1;
1420
\fn int Q3ComboTableItem::rtti() const
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.
1430
\sa Q3TableItem::rtti()
1433
int Q3ComboTableItem::rtti() const
1440
QSize Q3ComboTableItem::sizeHint() const
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());
1450
\class Q3CheckTableItem
1451
\brief The Q3CheckTableItem class provides checkboxes in Q3Tables.
1455
A Q3CheckTableItem is a table item which looks and behaves like a
1456
checkbox. The advantage of using Q3CheckTableItems rather than real
1457
checkboxes is that a Q3CheckTableItem uses far less resources than
1458
a real checkbox would in a \l{Q3Table}. When the cell has the focus
1459
it displays a real checkbox which the user can interact with. When
1460
the cell does not have the focus the cell \e looks like a
1461
checkbox. Pixmaps may not be used in Q3CheckTableItems.
1463
Q3CheckTableItem items have the edit type \c WhenCurrent (see
1466
To change the checkbox's label use setText(). The checkbox can be
1467
checked and unchecked with setChecked() and its state retrieved
1470
To populate a table cell with a Q3CheckTableItem use
1473
Q3CheckTableItems can be distinguished from \l{Q3TableItem}s and
1474
\l{Q3ComboTableItem}s using their Run Time Type Identification
1477
\img qtableitems.png Table Items
1479
\sa rtti() EditType Q3ComboTableItem Q3TableItem QCheckBox
1483
Creates a Q3CheckTableItem with an \l{EditType} of \c WhenCurrent
1484
as a child of \a table. The checkbox is initially unchecked and
1485
its label is set to the string \a txt.
1488
Q3CheckTableItem::Q3CheckTableItem(Q3Table *table, const QString &txt)
1489
: Q3TableItem(table, WhenCurrent, txt), checked(false)
1495
void Q3CheckTableItem::setText(const QString &t)
1497
Q3TableItem::setText(t);
1498
QWidget *w = table()->cellWidget(row(), col());
1499
QCheckBox *cb = ::qobject_cast<QCheckBox*>(w);
1507
QWidget *Q3CheckTableItem::createEditor() const
1509
// create an editor - a combobox in our case
1510
((Q3CheckTableItem*)this)->cb = new QCheckBox(table()->viewport(), "qt_editor_checkbox");
1511
cb->setChecked(checked);
1512
cb->setText(text());
1513
cb->setBackgroundColor(table()->viewport()->backgroundColor());
1514
QObject::connect(cb, SIGNAL(toggled(bool)), table(), SLOT(doValueChanged()));
1520
void Q3CheckTableItem::setContentFromEditor(QWidget *w)
1522
QCheckBox *cb = ::qobject_cast<QCheckBox*>(w);
1524
checked = cb->isChecked();
1529
void Q3CheckTableItem::paint(QPainter *p, const QColorGroup &cg,
1530
const QRect &cr, bool selected)
1534
p->fillRect(0, 0, cr.width(), cr.height(),
1535
selected ? pal.brush(QPalette::Highlight)
1536
: pal.brush(QPalette::Base));
1539
int h = cr.height();
1540
QSize sz = QSize(table()->style()->pixelMetric(QStyle::PM_IndicatorWidth),
1541
table()->style()->pixelMetric(QStyle::PM_IndicatorHeight));
1543
pal2.setBrush(QPalette::Background, pal.brush(QPalette::Base));
1544
QStyleOptionButton opt;
1545
opt.rect.setRect(0, (cr.height() - sz.height()) / 2, sz.width(), sz.height());
1547
opt.state = QStyle::State_None;
1549
opt.state |= QStyle::State_Enabled;
1551
opt.state |= QStyle::State_On;
1553
opt.state |= QStyle::State_Off;
1554
if (isEnabled() && table()->isEnabled())
1555
opt.state |= QStyle::State_Enabled;
1556
table()->style()->drawPrimitive(QStyle::PE_IndicatorCheckBox, &opt, p, table());
1557
int x = sz.width() + 6;
1560
p->setPen(pal.highlightedText().color());
1562
p->setPen(pal.text().color());
1563
p->drawText(x, 0, w, h, wordWrap() ? (alignment() | Qt::WordBreak) : alignment(), text());
1567
If \a b is true the checkbox is checked; if \a b is false the
1568
checkbox is unchecked.
1573
void Q3CheckTableItem::setChecked(bool b)
1576
table()->updateCell(row(), col());
1577
QWidget *w = table()->cellWidget(row(), col());
1578
QCheckBox *cb = ::qobject_cast<QCheckBox*>(w);
1584
Returns true if the checkbox table item is checked; otherwise
1590
bool Q3CheckTableItem::isChecked() const
1592
// #### why was this next line here. It must not be here, as
1593
// #### people want to call isChecked() from within paintCell()
1594
// #### and end up in an infinite loop that way
1595
// table()->updateCell(row(), col());
1596
QWidget *w = table()->cellWidget(row(), col());
1597
QCheckBox *cb = ::qobject_cast<QCheckBox*>(w);
1599
return cb->isChecked();
1603
int Q3CheckTableItem::RTTI = 2;
1606
\fn int Q3CheckTableItem::rtti() const
1610
Make your derived classes return their own values for rtti()to
1611
distinguish between different table item subclasses. You should
1612
use values greater than 1000, preferably a large random number, to
1613
allow for extensions to this class.
1615
\sa Q3TableItem::rtti()
1618
int Q3CheckTableItem::rtti() const
1625
QSize Q3CheckTableItem::sizeHint() const
1627
QSize sz = QSize(table()->style()->pixelMetric(QStyle::PM_IndicatorWidth),
1628
table()->style()->pixelMetric(QStyle::PM_IndicatorHeight));
1629
sz.setWidth(sz.width() + 6);
1630
QSize sh(Q3TableItem::sizeHint());
1631
return QSize(sh.width() + sz.width(), QMAX(sh.height(), sz.height())).
1632
expandedTo(QApplication::globalStrut());
1637
\brief The Q3Table class provides a flexible editable table widget.
1641
Q3Table is easy to use, although it does have a large API because
1642
of the comprehensive functionality that it provides. Q3Table
1643
includes functions for manipulating \link #headers
1644
headers\endlink, \link #columnsrows rows and columns\endlink,
1645
\link #cells cells\endlink and \link #selections
1646
selections\endlink. Q3Table also provides in-place editing and
1647
drag and drop, as well as a useful set of
1648
\link #signals signals\endlink. Q3Table efficiently supports very
1649
large tables, for example, tables one million by one million cells
1650
are perfectly possible. Q3Table is economical with memory, using
1651
none for unused cells.
1654
Q3Table *table = new Q3Table(100, 250, this);
1655
table->setPixmap(3, 2, pix);
1656
table->setText(3, 2, "A pixmap");
1659
The first line constructs the table specifying its size in rows
1660
and columns. We then insert a pixmap and some text into the \e
1661
same \link #cells cell\endlink, with the pixmap appearing to the
1662
left of the text. Q3Table cells can be populated with
1663
\l{Q3TableItem}s, \l{Q3ComboTableItem}s or by \l{Q3CheckTableItem}s.
1664
By default a vertical header appears at the left of the table
1665
showing row numbers and a horizontal header appears at the top of
1666
the table showing column numbers. (The numbers displayed start at
1667
1, although row and column numbers within Q3Table begin at 0.)
1669
If you want to use mouse tracking call setMouseTracking(true) on
1672
\img qtableitems.png Table Items
1677
Q3Table supports a header column, e.g. to display row numbers, and
1678
a header row, e.g to display column titles. To set row or column
1679
labels use Q3Header::setLabel() on the pointers returned by
1680
verticalHeader() and horizontalHeader() respectively. The vertical
1681
header is displayed within the table's left margin whose width is
1682
set with setLeftMargin(). The horizontal header is displayed
1683
within the table's top margin whose height is set with
1684
setTopMargin(). The table's grid can be switched off with
1685
setShowGrid(). If you want to hide a horizontal header call
1686
hide(), and call setTopMargin(0) so that the area the header
1687
would have occupied is reduced to zero size.
1689
Header labels are indexed via their section numbers. Note that the
1690
default behavior of Q3Header regarding section numbers is overriden
1691
for Q3Table. See the explanation below in the Rows and Columns
1692
section in the discussion of moving columns and rows.
1695
\section1 Rows and Columns
1697
Row and column sizes are set with setRowHeight() and
1698
setColumnWidth(). If you want a row high enough to show the
1699
tallest item in its entirety, use adjustRow(). Similarly, to make
1700
a column wide enough to show the widest item use adjustColumn().
1701
If you want the row height and column width to adjust
1702
automatically as the height and width of the table changes use
1703
setRowStretchable() and setColumnStretchable().
1705
Rows and columns can be hidden and shown with hideRow(),
1706
hideColumn(), showRow() and showColumn(). New rows and columns are
1707
inserted using insertRows() and insertColumns(). Additional rows
1708
and columns are added at the bottom (rows) or right (columns) if
1709
you set setNumRows() or setNumCols() to be larger than numRows()
1710
or numCols(). Existing rows and columns are removed with
1711
removeRow() and removeColumn(). Multiple rows and columns can be
1712
removed with removeRows() and removeColumns().
1714
Rows and columns can be set to be movable using
1715
rowMovingEnabled() and columnMovingEnabled(). The user can drag
1716
them to reorder them holding down the Ctrl key and dragging the
1717
mouse. For performance reasons, the default behavior of Q3Header
1718
section numbers is overridden by Q3Table. Currently in Q3Table, when
1719
a row or column is dragged and reordered, the section number is
1720
also changed to its new position. Therefore, there is no
1721
difference between the section and the index fields in Q3Header.
1722
The Q3Table Q3Header classes do not provide a mechanism for indexing
1723
independently of the user interface ordering.
1725
The table can be sorted using sortColumn(). Users can sort a
1726
column by clicking its header if setSorting() is set to true. Rows
1727
can be swapped with swapRows(), columns with swapColumns() and
1728
cells with swapCells().
1730
For editable tables (see setReadOnly()) you can set the read-only
1731
property of individual rows and columns with setRowReadOnly() and
1732
setColumnReadOnly(). (Whether a cell is editable or read-only
1733
depends on these settings and the cell's Q3TableItem.
1735
The row and column which have the focus are returned by
1736
currentRow() and currentColumn() respectively.
1738
Although many Q3Table functions operate in terms of rows and
1739
columns the indexOf() function returns a single integer
1740
identifying a particular cell.
1745
All of a Q3Table's cells are empty when the table is constructed.
1747
There are two approaches to populating the table's cells. The
1748
first and simplest approach is to use Q3TableItems or Q3TableItem
1749
subclasses. The second approach doesn't use Q3TableItems at all
1750
which is useful for very large sparse tables but requires you to
1751
reimplement a number of functions. We'll look at each approach in
1754
To put a string in a cell use setText(). This function will create
1755
a new Q3TableItem for the cell if one doesn't already exist, and
1756
displays the text in it. By default the table item's widget will
1757
be a QLineEdit. A pixmap may be put in a cell with setPixmap(),
1758
which also creates a table item if required. A cell may contain \e
1759
both a pixmap and text; the pixmap is displayed to the left of the
1760
text. Another approach is to construct a Q3TableItem or Q3TableItem
1761
subclass, set its properties, then insert it into a cell with
1764
If you want cells which contain comboboxes use the Q3ComboTableItem
1765
class. Similarly if you require cells containing checkboxes use
1766
the Q3CheckTableItem class. These table items look and behave just
1767
like the combobox or checkbox widgets but consume far less memory.
1769
Q3Table takes ownership of its Q3TableItems and will delete them
1770
when the table itself is destroyed. You can take ownership of a
1771
table item using takeItem() which you use to move a cell's
1772
contents from one cell to another, either within the same table,
1773
or from one table to another. (See also, swapCells()).
1775
In-place editing of the text in Q3TableItems, and the values in
1776
Q3ComboTableItems and Q3CheckTableItems works automatically. Cells
1777
may be editable or read-only, see Q3TableItem::EditType. If you
1778
want fine control over editing see beginEdit() and endEdit().
1780
The contents of a cell can be retrieved as a Q3TableItem using
1781
item(), or as a string with text() or as a pixmap (if there is
1782
one) with pixmap(). A cell's bounding rectangle is given by
1783
cellGeometry(). Use updateCell() to repaint a cell, for example to
1784
clear away a cell's visual representation after it has been
1785
deleted with clearCell(). The table can be forced to scroll to
1786
show a particular cell with ensureCellVisible(). The isSelected()
1787
function indicates if a cell is selected.
1789
It is possible to use your own widget as a cell's widget using
1790
setCellWidget(), but subclassing Q3TableItem might be a simpler
1791
approach. The cell's widget (if there is one) can be removed with
1794
\keyword notes on large tables
1796
\section2 Large tables
1798
For large, sparse, tables using Q3TableItems or other widgets is
1799
inefficient. The solution is to \e draw the cell as it should
1800
appear and to create and destroy cell editors on demand.
1802
This approach requires that you reimplement various functions.
1803
Reimplement paintCell() to display your data, and createEditor()
1804
and setCellContentFromEditor() to support in-place editing. It
1805
is very important to reimplement resizeData() to have no
1806
functionality, to prevent Q3Table from attempting to create a huge
1807
array. You will also need to reimplement item(), setItem(),
1808
takeItem(), clearCell(), and insertWidget(), cellWidget() and
1809
clearCellWidget(). In almost every circumstance (for sorting,
1810
removing and inserting columns and rows, etc.), you also need
1811
to reimplement swapRows(), swapCells() and swapColumns(), including
1814
If you represent active cells with a dictionary of Q3TableItems and
1815
QWidgets, i.e. only store references to cells that are actually
1816
used, many of the functions can be implemented with a single line
1819
For more information on cells see the Q3TableItem documenation.
1822
\section1 Selections
1824
Q3Table's support single selection, multi-selection (multiple
1825
cells) or no selection. The selection mode is set with
1826
setSelectionMode(). Use isSelected() to determine if a particular
1827
cell is selected, and isRowSelected() and isColumnSelected() to
1828
see if a row or column is selected.
1830
Q3Table's support many simultaneous selections. You can
1831
programmatically select cells with addSelection(). The number of
1832
selections is given by numSelections(). The current selection is
1833
returned by currentSelection(). You can remove a selection with
1834
removeSelection() and remove all selections with
1835
clearSelection(). Selections are Q3TableSelection objects.
1837
To easily add a new selection use selectCells(), selectRow() or
1840
Alternatively, use addSelection() to add new selections using
1841
Q3TableSelection objects. The advantage of using Q3TableSelection
1842
objects is that you can call Q3TableSelection::expandTo() to resize
1843
the selection and can query and compare them.
1845
The number of selections is given by numSelections(). The current
1846
selection is returned by currentSelection(). You can remove a
1847
selection with removeSelection() and remove all selections with
1853
When the user clicks a cell the currentChanged() signal is
1854
emitted. You can also connect to the lower level clicked(),
1855
doubleClicked() and pressed() signals. If the user changes the
1856
selection the selectionChanged() signal is emitted; similarly if
1857
the user changes a cell's value the valueChanged() signal is
1858
emitted. If the user right-clicks (or presses the appropriate
1859
platform-specific key sequence) the contextMenuRequested() signal
1860
is emitted. If the user drops a drag and drop object the dropped()
1861
signal is emitted with the drop event.
1865
\fn void Q3Table::currentChanged(int row, int col)
1867
This signal is emitted when the current cell has changed to \a
1872
\fn void Q3Table::valueChanged(int row, int col)
1874
This signal is emitted when the user changed the value in the cell
1879
\fn int Q3Table::currentRow() const
1881
Returns the current row.
1887
\fn int Q3Table::currentColumn() const
1889
Returns the current column.
1895
\enum Q3Table::EditMode
1897
\value NotEditing No cell is currently being edited.
1899
\value Editing A cell is currently being edited. The editor was
1900
initialised with the cell's contents.
1902
\value Replacing A cell is currently being edited. The editor was
1903
not initialised with the cell's contents.
1907
\enum Q3Table::SelectionMode
1909
\value NoSelection No cell can be selected by the user.
1911
\value Single The user may only select a single range of cells.
1913
\value Multi The user may select multiple ranges of cells.
1915
\value SingleRow The user may select one row at once.
1917
\value MultiRow The user may select multiple rows.
1921
\enum Q3Table::FocusStyle
1923
Specifies how the current cell (focus cell) is drawn.
1925
\value FollowStyle The current cell is drawn according to the
1926
current style and the cell's background is also drawn selected, if
1927
the current cell is within a selection
1929
\value SpreadSheet The current cell is drawn as in a spreadsheet.
1930
This means, it is signified by a black rectangle around the cell,
1931
and the background of the current cell is always drawn with the
1932
widget's base color - even when selected.
1937
\fn void Q3Table::clicked(int row, int col, int button, const QPoint &mousePos)
1939
This signal is emitted when mouse button \a button is clicked. The
1940
cell where the event took place is at \a row, \a col, and the
1941
mouse's position is in \a mousePos.
1945
\fn void Q3Table::doubleClicked(int row, int col, int button, const QPoint &mousePos)
1947
This signal is emitted when mouse button \a button is
1948
double-clicked. The cell where the event took place is at \a row,
1949
\a col, and the mouse's position is in \a mousePos.
1953
\fn void Q3Table::pressed(int row, int col, int button, const QPoint &mousePos)
1955
This signal is emitted when mouse button \a button is pressed. The
1956
cell where the event took place is at \a row, \a col, and the
1957
mouse's position is in \a mousePos.
1961
\fn void Q3Table::selectionChanged()
1963
This signal is emitted whenever a selection changes.
1965
\sa Q3TableSelection
1969
\fn void Q3Table::contextMenuRequested(int row, int col, const QPoint & pos)
1971
This signal is emitted when the user invokes a context menu with
1972
the right mouse button (or with a system-specific keypress). The
1973
cell where the event took place is at \a row, \a col. \a pos is
1974
the position where the context menu will appear in the global
1975
coordinate system. This signal is always emitted, even if the
1976
contents of the cell are disabled.
1980
Creates an empty table object called \a name as a child of \a
1983
Call setNumRows() and setNumCols() to set the table size before
1984
populating the table if you're using Q3TableItems.
1987
Q3Table::Q3Table(QWidget *parent, const char *name)
1988
: Q3ScrollView(parent, name, WNoAutoErase | WStaticContents),
1989
leftHeader(0), topHeader(0),
1990
currentSel(0), lastSortCol(-1), sGrid(true), mRows(false), mCols(false),
1991
asc(true), doSort(true), readOnly(false)
1997
Constructs an empty table called \a name with \a numRows rows and
1998
\a numCols columns. The table is a child of \a parent.
2000
If you're using \l{Q3TableItem}s to populate the table's cells, you
2001
can create Q3TableItem, Q3ComboTableItem and Q3CheckTableItem items
2002
and insert them into the table using setItem(). (See the notes on
2003
large tables for an alternative to using Q3TableItems.)
2006
Q3Table::Q3Table(int numRows, int numCols, QWidget *parent, const char *name)
2007
: Q3ScrollView(parent, name, WNoAutoErase | WStaticContents),
2008
leftHeader(0), topHeader(0),
2009
currentSel(0), lastSortCol(-1), sGrid(true), mRows(false), mCols(false),
2010
asc(true), doSort(true), readOnly(false)
2012
init(numRows, numCols);
2018
void Q3Table::init(int rows, int cols)
2020
#ifndef QT_NO_DRAGANDDROP
2021
setDragAutoScroll(false);
2023
d = new Q3TablePrivate;
2024
d->geomTimer = new QTimer(this);
2027
connect(d->geomTimer, SIGNAL(timeout()), this, SLOT(updateGeometriesSlot()));
2028
shouldClearSelection = false;
2030
roRows.setAutoDelete(true);
2031
roCols.setAutoDelete(true);
2034
unused = true; // It's unused, ain't it? :)
2038
contents.setAutoDelete(true);
2039
widgets.setAutoDelete(true);
2041
// Enable clipper and set background mode
2042
enableClipper(qt_table_clipper_enabled);
2044
viewport()->setFocusProxy(this);
2045
viewport()->setFocusPolicy(WheelFocus);
2047
viewport()->setBackgroundMode(PaletteBase);
2048
setBackgroundMode(PaletteBackground, PaletteBase);
2049
setResizePolicy(Manual);
2050
selections.setAutoDelete(true);
2053
leftHeader = new Q3TableHeader(rows, this, this, "left table header");
2054
leftHeader->setOrientation(Vertical);
2055
leftHeader->setTracking(true);
2056
leftHeader->setMovingEnabled(true);
2057
topHeader = new Q3TableHeader(cols, this, this, "right table header");
2058
topHeader->setOrientation(Horizontal);
2059
topHeader->setTracking(true);
2060
topHeader->setMovingEnabled(true);
2061
if (QApplication::reverseLayout())
2062
setMargins(0, fontMetrics().height() + 4, 30, 0);
2064
setMargins(30, fontMetrics().height() + 4, 0, 0);
2066
topHeader->setUpdatesEnabled(false);
2067
leftHeader->setUpdatesEnabled(false);
2068
// Initialize headers
2070
for (i = 0; i < numCols(); ++i)
2071
topHeader->resizeSection(i, QMAX(100, QApplication::globalStrut().height()));
2072
for (i = 0; i < numRows(); ++i)
2073
leftHeader->resizeSection(i, QMAX(20, QApplication::globalStrut().width()));
2074
topHeader->setUpdatesEnabled(true);
2075
leftHeader->setUpdatesEnabled(true);
2077
// Prepare for contents
2078
contents.setAutoDelete(false);
2080
// Connect header, table and scrollbars
2081
connect(horizontalScrollBar(), SIGNAL(valueChanged(int)),
2082
topHeader, SLOT(setOffset(int)));
2083
connect(verticalScrollBar(), SIGNAL(valueChanged(int)),
2084
leftHeader, SLOT(setOffset(int)));
2085
connect(topHeader, SIGNAL(sectionSizeChanged(int)),
2086
this, SLOT(columnWidthChanged(int)));
2087
connect(topHeader, SIGNAL(indexChange(int,int,int)),
2088
this, SLOT(columnIndexChanged(int,int,int)));
2089
connect(topHeader, SIGNAL(sectionClicked(int)),
2090
this, SLOT(columnClicked(int)));
2091
connect(leftHeader, SIGNAL(sectionSizeChanged(int)),
2092
this, SLOT(rowHeightChanged(int)));
2093
connect(leftHeader, SIGNAL(indexChange(int,int,int)),
2094
this, SLOT(rowIndexChanged(int,int,int)));
2096
// Initialize variables
2097
autoScrollTimer = new QTimer(this);
2098
connect(autoScrollTimer, SIGNAL(timeout()),
2099
this, SLOT(doAutoScroll()));
2100
curRow = curCol = 0;
2101
topHeader->setSectionState(curCol, Q3TableHeader::Bold);
2102
leftHeader->setSectionState(curRow, Q3TableHeader::Bold);
2103
edMode = NotEditing;
2104
editRow = editCol = -1;
2106
drawActiveSelection = true;
2108
installEventFilter(this);
2110
focusStl = SpreadSheet;
2112
was_visible = false;
2119
Releases all the resources used by the Q3Table object,
2120
including all \l{Q3TableItem}s and their widgets.
2125
setUpdatesEnabled(false);
2126
contents.setAutoDelete(true);
2133
void Q3Table::setReadOnly(bool b)
2137
Q3TableItem *i = item(curRow, curCol);
2138
if (readOnly && isEditing()) {
2139
endEdit(editRow, editCol, true, false);
2140
} else if (!readOnly && i && (i->editType() == Q3TableItem::WhenCurrent
2141
|| i->editType() == Q3TableItem::Always)) {
2142
editCell(curRow, curCol);
2147
If \a ro is true, row \a row is set to be read-only; otherwise the
2148
row is set to be editable.
2150
Whether a cell in this row is editable or read-only depends on the
2151
cell's EditType, and this setting.
2153
\sa isRowReadOnly() setColumnReadOnly() setReadOnly()
2156
void Q3Table::setRowReadOnly(int row, bool ro)
2159
roRows.replace(row, new int(0));
2163
if (curRow == row) {
2164
Q3TableItem *i = item(curRow, curCol);
2165
if (ro && isEditing()) {
2166
endEdit(editRow, editCol, true, false);
2167
} else if (!ro && i && (i->editType() == Q3TableItem::WhenCurrent
2168
|| i->editType() == Q3TableItem::Always)) {
2169
editCell(curRow, curCol);
2175
If \a ro is true, column \a col is set to be read-only; otherwise
2176
the column is set to be editable.
2178
Whether a cell in this column is editable or read-only depends on
2179
the cell's EditType, and this setting.
2181
\sa isColumnReadOnly() setRowReadOnly() setReadOnly()
2185
void Q3Table::setColumnReadOnly(int col, bool ro)
2188
roCols.replace(col, new int(0));
2192
if (curCol == col) {
2193
Q3TableItem *i = item(curRow, curCol);
2194
if (ro && isEditing()) {
2195
endEdit(editRow, editCol, true, false);
2196
} else if (!ro && i && (i->editType() == Q3TableItem::WhenCurrent
2197
|| i->editType() == Q3TableItem::Always)) {
2198
editCell(curRow, curCol);
2204
\property Q3Table::readOnly
2205
\brief whether the table is read-only
2207
Whether a cell in the table is editable or read-only depends on
2208
the cell's \link Q3TableItem::EditType EditType\endlink, and this setting.
2210
\sa QWidget::enabled setColumnReadOnly() setRowReadOnly()
2213
bool Q3Table::isReadOnly() const
2219
Returns true if row \a row is read-only; otherwise returns false.
2221
Whether a cell in this row is editable or read-only depends on the
2222
cell's \link Q3TableItem::EditType EditType\endlink, and this
2225
\sa setRowReadOnly() isColumnReadOnly()
2228
bool Q3Table::isRowReadOnly(int row) const
2230
return (roRows.find(row) != 0);
2234
Returns true if column \a col is read-only; otherwise returns
2237
Whether a cell in this column is editable or read-only depends on
2238
the cell's EditType, and this setting.
2240
\sa setColumnReadOnly() isRowReadOnly()
2243
bool Q3Table::isColumnReadOnly(int col) const
2245
return (roCols.find(col) != 0);
2248
void Q3Table::setSelectionMode(SelectionMode mode)
2250
if (mode == selMode)
2254
if (isRowSelection(selMode) && numRows() > 0 && numCols() > 0) {
2255
currentSel = new Q3TableSelection();
2256
selections.append(currentSel);
2257
currentSel->init(curRow, 0);
2258
currentSel->expandTo(curRow, numCols() - 1);
2259
repaintSelections(0, currentSel);
2264
\property Q3Table::selectionMode
2265
\brief the current selection mode
2267
The default mode is \c Multi which allows the user to select
2268
multiple ranges of cells.
2271
Q3Table::SelectionMode Q3Table::selectionMode() const
2277
\property Q3Table::focusStyle
2278
\brief how the current (focus) cell is drawn
2280
The default style is \c SpreadSheet.
2282
\sa Q3Table::FocusStyle
2285
void Q3Table::setFocusStyle(FocusStyle fs)
2288
updateCell(curRow, curCol);
2291
Q3Table::FocusStyle Q3Table::focusStyle() const
2297
This functions updates all the header states to be in sync with
2298
the current selections. This should be called after
2299
programatically changing, adding or removing selections, so that
2300
the headers are updated.
2303
void Q3Table::updateHeaderStates()
2305
horizontalHeader()->setUpdatesEnabled(false);
2306
verticalHeader()->setUpdatesEnabled(false);
2308
((Q3TableHeader*)verticalHeader())->setSectionStateToAll(Q3TableHeader::Normal);
2309
((Q3TableHeader*)horizontalHeader())->setSectionStateToAll(Q3TableHeader::Normal);
2311
Q3PtrListIterator<Q3TableSelection> it(selections);
2312
Q3TableSelection *s;
2313
while ((s = it.current()) != 0) {
2315
if (s->isActive()) {
2316
if (s->leftCol() == 0 &&
2317
s->rightCol() == numCols() - 1) {
2318
for (int i = 0; i < s->bottomRow() - s->topRow() + 1; ++i)
2319
leftHeader->setSectionState(s->topRow() + i, Q3TableHeader::Selected);
2321
if (s->topRow() == 0 &&
2322
s->bottomRow() == numRows() - 1) {
2323
for (int i = 0; i < s->rightCol() - s->leftCol() + 1; ++i)
2324
topHeader->setSectionState(s->leftCol() + i, Q3TableHeader::Selected);
2329
horizontalHeader()->setUpdatesEnabled(true);
2330
verticalHeader()->setUpdatesEnabled(true);
2331
horizontalHeader()->repaint(false);
2332
verticalHeader()->repaint(false);
2336
Returns the table's top Q3Header.
2338
This header contains the column labels.
2340
To modify a column label use Q3Header::setLabel().
2342
\sa verticalHeader() setTopMargin() Q3Header
2345
Q3Header *Q3Table::horizontalHeader() const
2347
return (Q3Header*)topHeader;
2351
Returns the table's vertical Q3Header.
2353
This header contains the row labels.
2355
\sa horizontalHeader() setLeftMargin() Q3Header
2358
Q3Header *Q3Table::verticalHeader() const
2360
return (Q3Header*)leftHeader;
2363
void Q3Table::setShowGrid(bool b)
2372
\property Q3Table::showGrid
2373
\brief whether the table's grid is displayed
2375
The grid is shown by default.
2378
bool Q3Table::showGrid() const
2384
\property Q3Table::columnMovingEnabled
2385
\brief whether columns can be moved by the user
2387
The default is false. Columns are moved by dragging whilst holding
2390
\sa rowMovingEnabled
2393
void Q3Table::setColumnMovingEnabled(bool b)
2398
bool Q3Table::columnMovingEnabled() const
2404
\property Q3Table::rowMovingEnabled
2405
\brief whether rows can be moved by the user
2407
The default is false. Rows are moved by dragging whilst holding
2411
\sa columnMovingEnabled
2414
void Q3Table::setRowMovingEnabled(bool b)
2419
bool Q3Table::rowMovingEnabled() const
2425
This is called when Q3Table's internal array needs to be resized to
2428
If you don't use Q3TableItems you should reimplement this as an
2429
empty method to avoid wasting memory. See the notes on large
2430
tables for further details.
2433
void Q3Table::resizeData(int len)
2435
contents.resize(len);
2436
widgets.resize(len);
2440
Swaps the data in \a row1 and \a row2.
2442
This function is used to swap the positions of two rows. It is
2443
called when the user changes the order of rows (see
2444
setRowMovingEnabled()), and when rows are sorted.
2446
If you don't use \l{Q3TableItem}s and want your users to be able to
2447
swap rows, e.g. for sorting, you will need to reimplement this
2448
function. (See the notes on large tables.)
2450
If \a swapHeader is true, the rows' header contents is also
2453
This function will not update the Q3Table, you will have to do
2454
this manually, e.g. by calling updateContents().
2456
\sa swapColumns() swapCells()
2459
void Q3Table::swapRows(int row1, int row2, bool swapHeader)
2462
leftHeader->swapSections(row1, row2, false);
2464
Q3PtrVector<Q3TableItem> tmpContents;
2465
tmpContents.resize(numCols());
2466
Q3PtrVector<QWidget> tmpWidgets;
2467
tmpWidgets.resize(numCols());
2470
contents.setAutoDelete(false);
2471
widgets.setAutoDelete(false);
2472
for (i = 0; i < numCols(); ++i) {
2473
Q3TableItem *i1, *i2;
2477
tmpContents.insert(i, i1);
2478
contents.remove(indexOf(row1, i));
2479
contents.insert(indexOf(row1, i), i2);
2480
contents.remove(indexOf(row2, i));
2481
contents.insert(indexOf(row2, i), tmpContents[ i ]);
2482
if (contents[ indexOf(row1, i) ])
2483
contents[ indexOf(row1, i) ]->setRow(row1);
2484
if (contents[ indexOf(row2, i) ])
2485
contents[ indexOf(row2, i) ]->setRow(row2);
2489
w1 = cellWidget(row1, i);
2490
w2 = cellWidget(row2, i);
2492
tmpWidgets.insert(i, w1);
2493
widgets.remove(indexOf(row1, i));
2494
widgets.insert(indexOf(row1, i), w2);
2495
widgets.remove(indexOf(row2, i));
2496
widgets.insert(indexOf(row2, i), tmpWidgets[ i ]);
2499
contents.setAutoDelete(false);
2500
widgets.setAutoDelete(true);
2502
updateRowWidgets(row1);
2503
updateRowWidgets(row2);
2506
else if (curRow == row2)
2508
if (editRow == row1)
2510
else if (editRow == row2)
2515
Sets the left margin to be \a m pixels wide.
2517
The verticalHeader(), which displays row labels, occupies this
2520
In an Arabic or Hebrew localization, the verticalHeader() will
2521
appear on the right side of the table, and this call will set the
2524
\sa leftMargin() setTopMargin() verticalHeader()
2527
void Q3Table::setLeftMargin(int m)
2529
if (QApplication::reverseLayout())
2530
setMargins(leftMargin(), topMargin(), m, bottomMargin());
2532
setMargins(m, topMargin(), rightMargin(), bottomMargin());
2537
Sets the top margin to be \a m pixels high.
2539
The horizontalHeader(), which displays column labels, occupies
2542
\sa topMargin() setLeftMargin()
2545
void Q3Table::setTopMargin(int m)
2547
setMargins(leftMargin(), m, rightMargin(), bottomMargin());
2552
Swaps the data in \a col1 with \a col2.
2554
This function is used to swap the positions of two columns. It is
2555
called when the user changes the order of columns (see
2556
setColumnMovingEnabled(), and when columns are sorted.
2558
If you don't use \l{Q3TableItem}s and want your users to be able to
2559
swap columns you will need to reimplement this function. (See the
2560
notes on large tables.)
2562
If \a swapHeader is true, the columns' header contents is also
2568
void Q3Table::swapColumns(int col1, int col2, bool swapHeader)
2571
topHeader->swapSections(col1, col2, false);
2573
Q3PtrVector<Q3TableItem> tmpContents;
2574
tmpContents.resize(numRows());
2575
Q3PtrVector<QWidget> tmpWidgets;
2576
tmpWidgets.resize(numRows());
2579
contents.setAutoDelete(false);
2580
widgets.setAutoDelete(false);
2581
for (i = 0; i < numRows(); ++i) {
2582
Q3TableItem *i1, *i2;
2586
tmpContents.insert(i, i1);
2587
contents.remove(indexOf(i, col1));
2588
contents.insert(indexOf(i, col1), i2);
2589
contents.remove(indexOf(i, col2));
2590
contents.insert(indexOf(i, col2), tmpContents[ i ]);
2591
if (contents[ indexOf(i, col1) ])
2592
contents[ indexOf(i, col1) ]->setCol(col1);
2593
if (contents[ indexOf(i, col2) ])
2594
contents[ indexOf(i, col2) ]->setCol(col2);
2598
w1 = cellWidget(i, col1);
2599
w2 = cellWidget(i, col2);
2601
tmpWidgets.insert(i, w1);
2602
widgets.remove(indexOf(i, col1));
2603
widgets.insert(indexOf(i, col1), w2);
2604
widgets.remove(indexOf(i, col2));
2605
widgets.insert(indexOf(i, col2), tmpWidgets[ i ]);
2608
contents.setAutoDelete(false);
2609
widgets.setAutoDelete(true);
2611
columnWidthChanged(col1);
2612
columnWidthChanged(col2);
2615
else if (curCol == col2)
2617
if (editCol == col1)
2619
else if (editCol == col2)
2624
Swaps the contents of the cell at \a row1, \a col1 with the
2625
contents of the cell at \a row2, \a col2.
2627
This function is also called when the table is sorted.
2629
If you don't use \l{Q3TableItem}s and want your users to be able to
2630
swap cells, you will need to reimplement this function. (See the
2631
notes on large tables.)
2633
\sa swapColumns() swapRows()
2636
void Q3Table::swapCells(int row1, int col1, int row2, int col2)
2638
contents.setAutoDelete(false);
2639
widgets.setAutoDelete(false);
2640
Q3TableItem *i1, *i2;
2641
i1 = item(row1, col1);
2642
i2 = item(row2, col2);
2644
Q3TableItem *tmp = i1;
2645
contents.remove(indexOf(row1, col1));
2646
contents.insert(indexOf(row1, col1), i2);
2647
contents.remove(indexOf(row2, col2));
2648
contents.insert(indexOf(row2, col2), tmp);
2649
if (contents[ indexOf(row1, col1) ]) {
2650
contents[ indexOf(row1, col1) ]->setRow(row1);
2651
contents[ indexOf(row1, col1) ]->setCol(col1);
2653
if (contents[ indexOf(row2, col2) ]) {
2654
contents[ indexOf(row2, col2) ]->setRow(row2);
2655
contents[ indexOf(row2, col2) ]->setCol(col2);
2660
w1 = cellWidget(row1, col1);
2661
w2 = cellWidget(row2, col2);
2664
widgets.remove(indexOf(row1, col1));
2665
widgets.insert(indexOf(row1, col1), w2);
2666
widgets.remove(indexOf(row2, col2));
2667
widgets.insert(indexOf(row2, col2), tmp);
2670
updateRowWidgets(row1);
2671
updateRowWidgets(row2);
2672
updateColWidgets(col1);
2673
updateColWidgets(col2);
2674
contents.setAutoDelete(false);
2675
widgets.setAutoDelete(true);
2678
static bool is_child_of(QWidget *child, QWidget *parent)
2681
if (child == parent)
2683
child = child->parentWidget();
2689
Draws the table contents on the painter \a p. This function is
2690
optimized so that it only draws the cells inside the \a cw pixels
2691
wide and \a ch pixels high clipping rectangle at position \a cx,
2694
Additionally, drawContents() highlights the current cell.
2697
void Q3Table::drawContents(QPainter *p, int cx, int cy, int cw, int ch)
2699
int colfirst = columnAt(cx);
2700
int collast = columnAt(cx + cw);
2701
int rowfirst = rowAt(cy);
2702
int rowlast = rowAt(cy + ch);
2704
if (rowfirst == -1 || colfirst == -1) {
2705
paintEmptyArea(p, cx, cy, cw, ch);
2709
drawActiveSelection = hasFocus() || viewport()->hasFocus() || d->inMenuMode
2710
|| is_child_of(qApp->focusWidget(), viewport())
2711
|| !style()->styleHint(QStyle::SH_ItemView_ChangeHighlightOnFocus, 0, this);
2713
rowlast = numRows() - 1;
2715
collast = numCols() - 1;
2717
bool currentInSelection = false;
2719
Q3PtrListIterator<Q3TableSelection> it( selections );
2720
Q3TableSelection *s;
2721
while ( ( s = it.current() ) != 0 ) {
2723
if (s->isActive() &&
2724
curRow >= s->topRow() &&
2725
curRow <= s->bottomRow() &&
2726
curCol >= s->leftCol() &&
2727
curCol <= s->rightCol()) {
2728
currentInSelection = s->topRow() != curRow || s->bottomRow() != curRow || s->leftCol() != curCol || s->rightCol() != curCol;
2733
// Go through the rows
2734
for (int r = rowfirst; r <= rowlast; ++r) {
2735
// get row position and height
2736
int rowp = rowPos(r);
2737
int rowh = rowHeight(r);
2739
// Go through the columns in row r
2740
// if we know from where to where, go through [colfirst, collast],
2741
// else go through all of them
2742
for (int c = colfirst; c <= collast; ++c) {
2743
// get position and width of column c
2745
colp = columnPos(c);
2746
colw = columnWidth(c);
2750
Q3TableItem *itm = item(r, c);
2752
(itm->colSpan() > 1 || itm->rowSpan() > 1)) {
2753
bool goon = r == itm->row() && c == itm->col() ||
2754
r == rowfirst && c == itm->col() ||
2755
r == itm->row() && c == colfirst;
2758
rowp = rowPos(itm->row());
2761
for (i = 0; i < itm->rowSpan(); ++i)
2762
rowh += rowHeight(i + itm->row());
2763
colp = columnPos(itm->col());
2765
for (i = 0; i < itm->colSpan(); ++i)
2766
colw += columnWidth(i + itm->col());
2769
// Translate painter and draw the cell
2770
p->translate(colp, rowp);
2771
bool selected = isSelected(r, c);
2772
if (focusStl != FollowStyle && selected && !currentInSelection &&
2773
r == curRow && c == curCol )
2775
paintCell(p, r, c, QRect(colp, rowp, colw, rowh), selected);
2776
p->translate(-colp, -rowp);
2781
QWidget *w = cellWidget(r, c);
2782
QRect cg(cellGeometry(r, c));
2783
if (w && w->geometry() != QRect(contentsToViewport(cg.topLeft()), cg.size() - QSize(1, 1))) {
2784
moveChild(w, colp, rowp);
2785
w->resize(cg.size() - QSize(1, 1));
2789
d->lastVisCol = collast;
2790
d->lastVisRow = rowlast;
2792
// draw indication of current cell
2793
QRect focusRect = cellGeometry(curRow, curCol);
2794
p->translate(focusRect.x(), focusRect.y());
2795
paintFocus(p, focusRect);
2796
p->translate(-focusRect.x(), -focusRect.y());
2798
// Paint empty rects
2799
paintEmptyArea(p, cx, cy, cw, ch);
2801
drawActiveSelection = true;
2807
(Implemented to get rid of a compiler warning.)
2810
void Q3Table::drawContents(QPainter *)
2815
Returns the geometry of cell \a row, \a col in the cell's
2816
coordinate system. This is a convenience function useful in
2817
paintCell(). It is equivalent to QRect(QPoint(0,0), cellGeometry(
2823
QRect Q3Table::cellRect(int row, int col) const
2825
return QRect(QPoint(0,0), cellGeometry(row, col).size());
2831
Use the other paintCell() function. This function is only included
2832
for backwards compatibilty.
2835
void Q3Table::paintCell(QPainter* p, int row, int col,
2836
const QRect &cr, bool selected)
2838
if (cr.width() == 0 || cr.height() == 0)
2840
#if defined(Q_WS_WIN)
2841
const QColorGroup &cg = (!drawActiveSelection && style()->styleHint(QStyle::SH_ItemView_ChangeHighlightOnFocus) ? palette().inactive() : colorGroup());
2843
const QColorGroup &cg = colorGroup();
2846
Q3TableItem *itm = item(row, col);
2847
QColorGroup cg2(cg);
2848
if (itm && !itm->isEnabled())
2849
cg2 = palette().disabled();
2851
paintCell(p, row, col, cr, selected, cg2);
2855
Paints the cell at \a row, \a col on the painter \a p. The painter
2856
has already been translated to the cell's origin. \a cr describes
2857
the cell coordinates in the content coordinate system.
2859
If \a selected is true the cell is highlighted.
2861
\a cg is the colorgroup which should be used to draw the cell
2864
If you want to draw custom cell content, for example right-aligned
2865
text, you must either reimplement paintCell(), or subclass
2866
Q3TableItem and reimplement Q3TableItem::paint() to do the custom
2869
If you're using a Q3TableItem subclass, for example, to store a
2870
data structure, then reimplementing Q3TableItem::paint() may be the
2871
best approach. For data you want to draw immediately, e.g. data
2872
retrieved from a database, it is probably best to reimplement
2873
paintCell(). Note that if you reimplement paintCell(), i.e. don't
2874
use \l{Q3TableItem}s, you must reimplement other functions: see the
2875
notes on large tables.
2877
Note that the painter is not clipped by default in order to get
2878
maximum efficiency. If you want clipping, use code like this:
2881
p->setClipRect(cellRect(row, col), QPainter::CoordPainter);
2882
//... your drawing code
2883
p->setClipping(false);
2887
void Q3Table::paintCell(QPainter *p, int row, int col,
2888
const QRect &cr, bool selected, const QColorGroup &cg)
2890
if (focusStl == SpreadSheet && selected &&
2892
col == curCol && (hasFocus() || viewport()->hasFocus()))
2897
int h = cr.height();
2902
Q3TableItem *itm = item(row, col);
2905
itm->paint(p, pal, cr, selected);
2908
p->fillRect(0, 0, w, h, selected ? pal.brush(QPalette::Highlight) : pal.brush(QPalette::Base));
2914
int gridColor = style()->styleHint(QStyle::SH_Table_GridLineColor, 0, this);
2915
if (gridColor != -1) {
2916
if (palette() != pal)
2917
p->setPen(pal.mid().color());
2919
p->setPen((QRgb)gridColor);
2921
p->setPen(pal.mid().color());
2923
p->drawLine(x2, 0, x2, y2);
2924
p->drawLine(0, y2, x2, y2);
2930
Draws the focus rectangle of the current cell (see currentRow(),
2933
The painter \a p is already translated to the cell's origin, while
2934
\a cr specifies the cell's geometry in content coordinates.
2937
void Q3Table::paintFocus(QPainter *p, const QRect &cr)
2939
if (!hasFocus() && !viewport()->hasFocus())
2941
QRect focusRect(0, 0, cr.width(), cr.height());
2942
if (focusStyle() == SpreadSheet) {
2943
p->setPen(QPen(Qt::black, 1));
2944
p->setBrush(Qt::NoBrush);
2945
p->drawRect(focusRect.x(), focusRect.y(), focusRect.width() - 1, focusRect.height() - 1);
2946
p->drawRect(focusRect.x() - 1, focusRect.y() - 1, focusRect.width() + 1, focusRect.height() + 1);
2948
QStyleOptionFocusRect opt;
2949
opt.rect = focusRect;
2950
opt.palette = palette();
2951
if (isSelected(curRow, curCol, false)) {
2952
opt.state = QStyle::State_FocusAtBorder;
2953
opt.backgroundColor = palette().highlight().color();
2955
opt.state = QStyle::State_None;
2956
opt.backgroundColor = palette().base().color();
2958
style()->drawPrimitive(QStyle::PE_FrameFocusRect, &opt, p, this);
2963
This function fills the \a cw pixels wide and \a ch pixels high
2964
rectangle starting at position \a cx, \a cy with the background
2965
color using the painter \a p.
2967
paintEmptyArea() is invoked by drawContents() to erase or fill
2971
void Q3Table::paintEmptyArea(QPainter *p, int cx, int cy, int cw, int ch)
2973
// Regions work with shorts, so avoid an overflow and adjust the
2974
// table size to the visible size
2975
QSize ts(tableSize());
2976
ts.setWidth(QMIN(ts.width(), visibleWidth()));
2977
ts.setHeight(QMIN(ts.height(), visibleHeight()));
2979
// Region of the rect we should draw, calculated in viewport
2980
// coordinates, as a region can't handle bigger coordinates
2981
contentsToViewport2(cx, cy, cx, cy);
2982
QRegion reg(QRect(cx, cy, cw, ch));
2984
// Subtract the table from it
2985
reg = reg.subtract(QRect(QPoint(0, 0), ts));
2987
// And draw the rectangles (transformed inc contents coordinates as needed)
2988
Q3MemArray<QRect> r = reg.rects();
2989
for (int i = 0; i < (int)r.count(); ++i)
2990
p->fillRect(QRect(viewportToContents2(r[i].topLeft()),r[i].size()), viewport()->backgroundBrush());
2994
Returns the Q3TableItem representing the contents of the cell at \a
2997
If \a row or \a col are out of range or no content has been set
2998
for this cell, item() returns 0.
3000
If you don't use \l{Q3TableItem}s you may need to reimplement this
3001
function: see the notes on large tables.
3006
Q3TableItem *Q3Table::item(int row, int col) const
3008
if (row < 0 || col < 0 || row > numRows() - 1 ||
3009
col > numCols() - 1 || row * col >= (int)contents.size())
3012
return contents[ indexOf(row, col) ]; // contents array lookup
3016
Inserts the table item \a item into the table at row \a row,
3017
column \a col, and repaints the cell. If a table item already
3018
exists in this cell it is deleted and replaced with \a item. The
3019
table takes ownership of the table item.
3021
If you don't use \l{Q3TableItem}s you may need to reimplement this
3022
function: see the notes on large tables.
3024
\sa item() takeItem()
3027
void Q3Table::setItem(int row, int col, Q3TableItem *item)
3032
if ((int)contents.size() != numRows() * numCols())
3033
resizeData(numRows() * numCols());
3035
int orow = item->row();
3036
int ocol = item->col();
3037
clearCell(row, col);
3039
contents.insert(indexOf(row, col), item);
3043
updateCell(row, col);
3044
if (qt_update_cell_widget)
3045
item->updateEditor(orow, ocol);
3047
if (row == curRow && col == curCol && item->editType() == Q3TableItem::WhenCurrent) {
3048
if (beginEdit(row, col, false))
3049
setEditMode(Editing, row, col);
3054
Removes the Q3TableItem at \a row, \a col.
3056
If you don't use \l{Q3TableItem}s you may need to reimplement this
3057
function: see the notes on large tables.
3060
void Q3Table::clearCell(int row, int col)
3062
if ((int)contents.size() != numRows() * numCols())
3063
resizeData(numRows() * numCols());
3064
clearCellWidget(row, col);
3065
contents.setAutoDelete(true);
3066
contents.remove(indexOf(row, col));
3067
contents.setAutoDelete(false);
3071
Sets the text in the cell at \a row, \a col to \a text.
3073
If the cell does not contain a table item a Q3TableItem is created
3074
with an \link Q3TableItem::EditType EditType\endlink of \c OnTyping,
3075
otherwise the existing table item's text (if any) is replaced with
3078
\sa text() setPixmap() setItem() Q3TableItem::setText()
3081
void Q3Table::setText(int row, int col, const QString &text)
3083
Q3TableItem *itm = item(row, col);
3086
itm->updateEditor(row, col);
3087
updateCell(row, col);
3089
Q3TableItem *i = new Q3TableItem(this, Q3TableItem::OnTyping,
3091
setItem(row, col, i);
3096
Sets the pixmap in the cell at \a row, \a col to \a pix.
3098
If the cell does not contain a table item a Q3TableItem is created
3099
with an \link Q3TableItem::EditType EditType\endlink of \c OnTyping,
3100
otherwise the existing table item's pixmap (if any) is replaced
3103
Note that \l{Q3ComboTableItem}s and \l{Q3CheckTableItem}s don't show
3106
\sa pixmap() setText() setItem() Q3TableItem::setPixmap()
3109
void Q3Table::setPixmap(int row, int col, const QPixmap &pix)
3111
Q3TableItem *itm = item(row, col);
3113
itm->setPixmap(pix);
3114
updateCell(row, col);
3116
Q3TableItem *i = new Q3TableItem(this, Q3TableItem::OnTyping,
3118
setItem(row, col, i);
3123
Returns the text in the cell at \a row, \a col, or an empty string
3124
if the relevant item does not exist or has no text.
3126
\sa setText() setPixmap()
3129
QString Q3Table::text(int row, int col) const
3131
Q3TableItem *itm = item(row, col);
3138
Returns the pixmap set for the cell at \a row, \a col, or a
3139
null-pixmap if the cell contains no pixmap.
3144
QPixmap Q3Table::pixmap(int row, int col) const
3146
Q3TableItem *itm = item(row, col);
3148
return itm->pixmap();
3153
Moves the focus to the cell at \a row, \a col.
3155
\sa currentRow() currentColumn()
3158
void Q3Table::setCurrentCell(int row, int col)
3160
setCurrentCell(row, col, true, true);
3163
// need to use a define, as leftMargin() is protected
3164
#define VERTICALMARGIN \
3165
(QApplication::reverseLayout() ? \
3174
QVariant Q3Table::inputMethodQuery(Qt::InputMethodQuery query) const
3176
if (query == Qt::ImMicroFocus)
3177
return QRect(columnPos(curCol) + leftMargin() - contentsX(), rowPos(curRow) + topMargin() - contentsY(),
3178
columnWidth(curCol), rowHeight(curRow));
3179
return QWidget::inputMethodQuery(query);
3185
void Q3Table::setCurrentCell(int row, int col, bool updateSelections, bool ensureVisible)
3187
Q3TableItem *oldItem = item(curRow, curCol);
3189
if (row > numRows() - 1)
3190
row = numRows() - 1;
3191
if (col > numCols() - 1)
3192
col = numCols() - 1;
3194
if (curRow == row && curCol == col)
3198
Q3TableItem *itm = oldItem;
3199
if (itm && itm->editType() != Q3TableItem::Always && itm->editType() != Q3TableItem::Never)
3200
endEdit(curRow, curCol, true, false);
3201
int oldRow = curRow;
3202
int oldCol = curCol;
3205
repaintCell(oldRow, oldCol);
3206
repaintCell(curRow, curCol);
3208
ensureCellVisible(curRow, curCol);
3209
emit currentChanged(row, col);
3211
if (oldCol != curCol) {
3212
if (!isColumnSelected(oldCol))
3213
topHeader->setSectionState(oldCol, Q3TableHeader::Normal);
3214
else if (isRowSelection(selectionMode()))
3215
topHeader->setSectionState(oldCol, Q3TableHeader::Selected);
3216
topHeader->setSectionState(curCol, isColumnSelected(curCol, true) ?
3217
Q3TableHeader::Selected : Q3TableHeader::Bold);
3220
if (oldRow != curRow) {
3221
if (!isRowSelected(oldRow))
3222
leftHeader->setSectionState(oldRow, Q3TableHeader::Normal);
3223
leftHeader->setSectionState(curRow, isRowSelected(curRow, true) ?
3224
Q3TableHeader::Selected : Q3TableHeader::Bold);
3227
itm = item(curRow, curCol);
3230
if (cellWidget(oldRow, oldCol) &&
3231
cellWidget(oldRow, oldCol)->hasFocus())
3232
viewport()->setFocus();
3234
if (itm && itm->editType() == Q3TableItem::WhenCurrent) {
3235
if (beginEdit(curRow, curCol, false))
3236
setEditMode(Editing, row, col);
3237
} else if (itm && itm->editType() == Q3TableItem::Always) {
3238
if (cellWidget(itm->row(), itm->col()))
3239
cellWidget(itm->row(), itm->col())->setFocus();
3242
if (updateSelections && isRowSelection(selectionMode()) &&
3243
!isSelected(curRow, curCol, false)) {
3244
if (selectionMode() == Q3Table::SingleRow)
3246
currentSel = new Q3TableSelection();
3247
selections.append(currentSel);
3248
currentSel->init(curRow, 0);
3249
currentSel->expandTo(curRow, numCols() - 1);
3250
repaintSelections(0, currentSel);
3255
Scrolls the table until the cell at \a row, \a col becomes
3259
void Q3Table::ensureCellVisible(int row, int col)
3261
if (!updatesEnabled() || !viewport()->updatesEnabled())
3263
int cw = columnWidth(col);
3264
int rh = rowHeight(row);
3265
if (cw < visibleWidth())
3266
ensureVisible(columnPos(col) + cw / 2, rowPos(row) + rh / 2, cw / 2, rh / 2);
3268
ensureVisible(columnPos(col), rowPos(row) + rh / 2, 0, rh / 2);
3272
Returns true if the cell at \a row, \a col is selected; otherwise
3275
\sa isRowSelected() isColumnSelected()
3278
bool Q3Table::isSelected(int row, int col) const
3280
return isSelected(row, col, true);
3285
bool Q3Table::isSelected(int row, int col, bool includeCurrent) const
3287
Q3PtrListIterator<Q3TableSelection> it(selections);
3288
Q3TableSelection *s;
3289
while ((s = it.current()) != 0) {
3291
if (s->isActive() &&
3292
row >= s->topRow() &&
3293
row <= s->bottomRow() &&
3294
col >= s->leftCol() &&
3295
col <= s->rightCol())
3297
if (includeCurrent && row == currentRow() && col == currentColumn())
3304
Returns true if row \a row is selected; otherwise returns false.
3306
If \a full is false (the default), 'row is selected' means that at
3307
least one cell in the row is selected. If \a full is true, then 'row
3308
is selected' means every cell in the row is selected.
3310
\sa isColumnSelected() isSelected()
3313
bool Q3Table::isRowSelected(int row, bool full) const
3316
Q3PtrListIterator<Q3TableSelection> it(selections);
3317
Q3TableSelection *s;
3318
while ((s = it.current()) != 0) {
3320
if (s->isActive() &&
3321
row >= s->topRow() &&
3322
row <= s->bottomRow())
3324
if (row == currentRow())
3328
Q3PtrListIterator<Q3TableSelection> it(selections);
3329
Q3TableSelection *s;
3330
while ((s = it.current()) != 0) {
3332
if (s->isActive() &&
3333
row >= s->topRow() &&
3334
row <= s->bottomRow() &&
3335
s->leftCol() == 0 &&
3336
s->rightCol() == numCols() - 1)
3344
Returns true if column \a col is selected; otherwise returns false.
3346
If \a full is false (the default), 'column is selected' means that
3347
at least one cell in the column is selected. If \a full is true,
3348
then 'column is selected' means every cell in the column is
3351
\sa isRowSelected() isSelected()
3354
bool Q3Table::isColumnSelected(int col, bool full) const
3357
Q3PtrListIterator<Q3TableSelection> it(selections);
3358
Q3TableSelection *s;
3359
while ((s = it.current()) != 0) {
3361
if (s->isActive() &&
3362
col >= s->leftCol() &&
3363
col <= s->rightCol())
3365
if (col == currentColumn())
3369
Q3PtrListIterator<Q3TableSelection> it(selections);
3370
Q3TableSelection *s;
3371
while ((s = it.current()) != 0) {
3373
if (s->isActive() &&
3374
col >= s->leftCol() &&
3375
col <= s->rightCol() &&
3377
s->bottomRow() == numRows() - 1)
3385
\property Q3Table::numSelections
3386
\brief The number of selections.
3388
\sa currentSelection()
3391
int Q3Table::numSelections() const
3393
return selections.count();
3397
Returns selection number \a num, or an inactive Q3TableSelection if \a
3398
num is out of range (see Q3TableSelection::isActive()).
3401
Q3TableSelection Q3Table::selection(int num) const
3403
if (num < 0 || num >= (int)selections.count())
3404
return Q3TableSelection();
3406
Q3TableSelection *s = ((Q3Table*)this)->selections.at(num);
3411
Adds a selection described by \a s to the table and returns its
3412
number or -1 if the selection is invalid.
3414
Remember to call Q3TableSelection::init() and
3415
Q3TableSelection::expandTo() to make the selection valid (see also
3416
Q3TableSelection::isActive(), or use the
3417
Q3TableSelection(int,int,int,int) constructor).
3419
\sa numSelections() removeSelection() clearSelection()
3422
int Q3Table::addSelection(const Q3TableSelection &s)
3427
const int maxr = numRows()-1;
3428
const int maxc = numCols()-1;
3429
currentSel = new Q3TableSelection(QMIN(s.anchorRow(), maxr), QMIN(s.anchorCol(), maxc),
3430
QMIN(s.bottomRow(), maxr), QMIN(s.rightCol(), maxc));
3432
selections.append(currentSel);
3434
repaintSelections(0, currentSel, true, true);
3436
emit selectionChanged();
3438
return selections.count() - 1;
3442
If the table has a selection, \a s, this selection is removed from
3445
\sa addSelection() numSelections()
3448
void Q3Table::removeSelection(const Q3TableSelection &s)
3450
selections.setAutoDelete(false);
3451
for (Q3TableSelection *sel = selections.first(); sel; sel = selections.next()) {
3453
selections.removeRef(sel);
3454
repaintSelections(sel, 0, true, true);
3455
if (sel == currentSel)
3460
selections.setAutoDelete(true);
3461
emit selectionChanged();
3467
Removes selection number \a num from the table.
3469
\sa numSelections() addSelection() clearSelection()
3472
void Q3Table::removeSelection(int num)
3474
if (num < 0 || num >= (int)selections.count())
3477
Q3TableSelection *s = selections.at(num);
3478
if (s == currentSel)
3480
selections.removeRef(s);
3481
repaintContents(false);
3485
Returns the number of the current selection or -1 if there is no
3491
int Q3Table::currentSelection() const
3495
return ((Q3Table*)this)->selections.findRef(currentSel);
3498
/*! Selects the range starting at \a start_row and \a start_col and
3499
ending at \a end_row and \a end_col.
3501
\sa Q3TableSelection
3504
void Q3Table::selectCells(int start_row, int start_col, int end_row, int end_col)
3506
const int maxr = numRows()-1;
3507
const int maxc = numCols()-1;
3509
start_row = QMIN(maxr, QMAX(0, start_row));
3510
start_col = QMIN(maxc, QMAX(0, start_col));
3511
end_row = QMIN(maxr, end_row);
3512
end_col = QMIN(maxc, end_col);
3513
Q3TableSelection sel(start_row, start_col, end_row, end_col);
3517
/*! Selects the row \a row.
3519
\sa Q3TableSelection
3522
void Q3Table::selectRow(int row)
3524
row = QMIN(numRows()-1, row);
3527
Q3TableSelection sel(row, 0, row, numCols() - 1);
3531
/*! Selects the column \a col.
3533
\sa Q3TableSelection
3536
void Q3Table::selectColumn(int col)
3538
col = QMIN(numCols()-1, col);
3541
Q3TableSelection sel(0, col, numRows() - 1, col);
3547
void Q3Table::contentsMousePressEvent(QMouseEvent* e)
3549
contentsMousePressEventEx(e);
3552
void Q3Table::contentsMousePressEventEx(QMouseEvent* e)
3554
shouldClearSelection = false;
3556
if (!cellGeometry(editRow, editCol).contains(e->pos())) {
3557
endEdit(editRow, editCol, true, edMode != Editing);
3564
d->redirectMouseEvent = false;
3566
int tmpRow = rowAt(e->pos().y());
3567
int tmpCol = columnAt(e->pos().x());
3568
pressedRow = tmpRow;
3569
pressedCol = tmpCol;
3570
fixRow(tmpRow, e->pos().y());
3571
fixCol(tmpCol, e->pos().x());
3575
if (isSelected(tmpRow, tmpCol)) {
3576
startDragCol = tmpCol;
3577
startDragRow = tmpRow;
3578
dragStartPos = e->pos();
3581
Q3TableItem *itm = item(pressedRow, pressedCol);
3582
if (itm && !itm->isEnabled()) {
3583
emit pressed(tmpRow, tmpCol, e->button(), e->pos());
3587
if ((e->state() & ShiftButton) == ShiftButton) {
3588
int oldRow = curRow;
3589
int oldCol = curCol;
3590
setCurrentCell(tmpRow, tmpCol, selMode == SingleRow, true);
3591
if (selMode != NoSelection && selMode != SingleRow) {
3593
currentSel = new Q3TableSelection();
3594
selections.append(currentSel);
3595
if (!isRowSelection(selectionMode()))
3596
currentSel->init(oldRow, oldCol);
3598
currentSel->init(oldRow, 0);
3600
Q3TableSelection oldSelection = *currentSel;
3601
if (!isRowSelection(selectionMode()))
3602
currentSel->expandTo(tmpRow, tmpCol);
3604
currentSel->expandTo(tmpRow, numCols() - 1);
3605
repaintSelections(&oldSelection, currentSel);
3606
emit selectionChanged();
3608
} else if ((e->state() & ControlButton) == ControlButton) {
3609
setCurrentCell(tmpRow, tmpCol, false, true);
3610
if (selMode != NoSelection) {
3611
if (selMode == Single || selMode == SingleRow && !isSelected(tmpRow, tmpCol, false))
3613
if (!(selMode == SingleRow && isSelected(tmpRow, tmpCol, false))) {
3614
currentSel = new Q3TableSelection();
3615
selections.append(currentSel);
3616
if (!isRowSelection(selectionMode())) {
3617
currentSel->init(tmpRow, tmpCol);
3618
currentSel->expandTo(tmpRow, tmpCol);
3620
currentSel->init(tmpRow, 0);
3621
currentSel->expandTo(tmpRow, numCols() - 1);
3622
repaintSelections(0, currentSel);
3624
emit selectionChanged();
3628
setCurrentCell(tmpRow, tmpCol, false, true);
3629
Q3TableItem *itm = item(tmpRow, tmpCol);
3630
if (itm && itm->editType() == Q3TableItem::WhenCurrent) {
3631
QWidget *w = cellWidget(tmpRow, tmpCol);
3632
if (::qobject_cast<QComboBox*>(w) || ::qobject_cast<QAbstractButton*>(w)) {
3633
QMouseEvent ev(e->type(), w->mapFromGlobal(e->globalPos()),
3634
e->globalPos(), e->button(), e->state());
3635
QApplication::sendPostedEvents(w, 0);
3636
QApplication::sendEvent(w, &ev);
3637
d->redirectMouseEvent = true;
3640
if (isSelected(tmpRow, tmpCol, false)) {
3641
shouldClearSelection = true;
3643
bool b = signalsBlocked();
3644
if (selMode != NoSelection)
3648
if (selMode != NoSelection) {
3649
currentSel = new Q3TableSelection();
3650
selections.append(currentSel);
3651
if (!isRowSelection(selectionMode())) {
3652
currentSel->init(tmpRow, tmpCol);
3653
currentSel->expandTo(tmpRow, tmpCol);
3655
currentSel->init(tmpRow, 0);
3656
currentSel->expandTo(tmpRow, numCols() - 1);
3657
repaintSelections(0, currentSel);
3659
emit selectionChanged();
3664
emit pressed(tmpRow, tmpCol, e->button(), e->pos());
3670
void Q3Table::contentsMouseDoubleClickEvent(QMouseEvent *e)
3672
if (e->button() != LeftButton)
3674
if (!isRowSelection(selectionMode()))
3676
int tmpRow = rowAt(e->pos().y());
3677
int tmpCol = columnAt(e->pos().x());
3678
Q3TableItem *itm = item(tmpRow, tmpCol);
3679
if (itm && !itm->isEnabled())
3681
if (tmpRow != -1 && tmpCol != -1) {
3682
if (beginEdit(tmpRow, tmpCol, false))
3683
setEditMode(Editing, tmpRow, tmpCol);
3686
emit doubleClicked(tmpRow, tmpCol, e->button(), e->pos());
3690
Sets the current edit mode to \a mode, the current edit row to \a
3691
row and the current edit column to \a col.
3696
void Q3Table::setEditMode(EditMode mode, int row, int col)
3707
void Q3Table::contentsMouseMoveEvent(QMouseEvent *e)
3709
if ((e->state() & MouseButtonMask) == NoButton)
3711
int tmpRow = rowAt(e->pos().y());
3712
int tmpCol = columnAt(e->pos().x());
3713
fixRow(tmpRow, e->pos().y());
3714
fixCol(tmpCol, e->pos().x());
3716
#ifndef QT_NO_DRAGANDDROP
3717
if (dragEnabled() && startDragRow != -1 && startDragCol != -1) {
3718
if (QPoint(dragStartPos - e->pos()).manhattanLength() > QApplication::startDragDistance())
3723
if (selectionMode() == MultiRow && (e->state() & ControlButton) == ControlButton)
3724
shouldClearSelection = false;
3726
if (shouldClearSelection) {
3728
if (selMode != NoSelection) {
3729
currentSel = new Q3TableSelection();
3730
selections.append(currentSel);
3731
if (!isRowSelection(selectionMode()))
3732
currentSel->init(tmpRow, tmpCol);
3734
currentSel->init(tmpRow, 0);
3735
emit selectionChanged();
3737
shouldClearSelection = false;
3740
QPoint pos = mapFromGlobal(e->globalPos());
3741
pos -= QPoint(leftHeader->width(), topHeader->height());
3742
autoScrollTimer->stop();
3744
if (pos.x() < 0 || pos.x() > visibleWidth() || pos.y() < 0 || pos.y() > visibleHeight())
3745
autoScrollTimer->start(100, true);
3751
void Q3Table::doValueChanged()
3753
emit valueChanged(editRow, editCol);
3759
void Q3Table::doAutoScroll()
3761
QPoint pos = QCursor::pos();
3762
pos = mapFromGlobal(pos);
3763
pos -= QPoint(leftHeader->width(), topHeader->height());
3765
int tmpRow = curRow;
3766
int tmpCol = curCol;
3769
else if (pos.y() > visibleHeight())
3773
else if (pos.x() > visibleWidth())
3776
pos += QPoint(contentsX(), contentsY());
3777
if (tmpRow == curRow)
3778
tmpRow = rowAt(pos.y());
3779
if (tmpCol == curCol)
3780
tmpCol = columnAt(pos.x());
3781
pos -= QPoint(contentsX(), contentsY());
3783
fixRow(tmpRow, pos.y());
3784
fixCol(tmpCol, pos.x());
3786
if (tmpRow < 0 || tmpRow > numRows() - 1)
3787
tmpRow = currentRow();
3788
if (tmpCol < 0 || tmpCol > numCols() - 1)
3789
tmpCol = currentColumn();
3791
ensureCellVisible(tmpRow, tmpCol);
3793
if (currentSel && selMode != NoSelection) {
3794
Q3TableSelection oldSelection = *currentSel;
3796
if (selMode != SingleRow) {
3797
if (!isRowSelection(selectionMode())) {
3798
currentSel->expandTo(tmpRow, tmpCol);
3800
currentSel->expandTo(tmpRow, numCols() - 1);
3803
bool currentInSelection = tmpRow == curRow && isSelected(tmpRow, tmpCol);
3804
if (!currentInSelection) {
3807
currentSel = new Q3TableSelection();
3808
selections.append(currentSel);
3809
currentSel->init(tmpRow, 0);
3810
currentSel->expandTo(tmpRow, numCols() - 1);
3811
repaintSelections(0, currentSel);
3813
currentSel->expandTo(tmpRow, numCols() - 1);
3816
setCurrentCell(tmpRow, tmpCol, false, true);
3817
repaintSelections(useOld ? &oldSelection : 0, currentSel);
3818
if (currentSel && oldSelection != *currentSel)
3819
emit selectionChanged();
3821
setCurrentCell(tmpRow, tmpCol, false, true);
3824
if (pos.x() < 0 || pos.x() > visibleWidth() || pos.y() < 0 || pos.y() > visibleHeight())
3825
autoScrollTimer->start(100, true);
3831
void Q3Table::contentsMouseReleaseEvent(QMouseEvent *e)
3833
if (pressedRow == curRow && pressedCol == curCol)
3834
emit clicked(curRow, curCol, e->button(), e->pos());
3836
if (e->button() != LeftButton)
3838
if (shouldClearSelection) {
3839
int tmpRow = rowAt(e->pos().y());
3840
int tmpCol = columnAt(e->pos().x());
3841
fixRow(tmpRow, e->pos().y());
3842
fixCol(tmpCol, e->pos().x());
3844
if (selMode != NoSelection) {
3845
currentSel = new Q3TableSelection();
3846
selections.append(currentSel);
3847
if (!isRowSelection(selectionMode())) {
3848
currentSel->init(tmpRow, tmpCol);
3850
currentSel->init(tmpRow, 0);
3851
currentSel->expandTo(tmpRow, numCols() - 1);
3852
repaintSelections(0, currentSel);
3854
emit selectionChanged();
3856
shouldClearSelection = false;
3858
autoScrollTimer->stop();
3860
if (d->redirectMouseEvent && pressedRow == curRow && pressedCol == curCol &&
3861
item(pressedRow, pressedCol) && item(pressedRow, pressedCol)->editType() ==
3862
Q3TableItem::WhenCurrent) {
3863
QWidget *w = cellWidget(pressedRow, pressedCol);
3865
QMouseEvent ev(e->type(), w->mapFromGlobal(e->globalPos()),
3866
e->globalPos(), e->button(), e->state());
3867
QApplication::sendPostedEvents(w, 0);
3868
QApplication::sendEvent(w, &ev);
3877
void Q3Table::contentsContextMenuEvent(QContextMenuEvent *e)
3879
if (!receivers(SIGNAL(contextMenuRequested(int,int,const QPoint&)))) {
3883
if (e->reason() == QContextMenuEvent::Keyboard) {
3884
QRect r = cellGeometry(curRow, curCol);
3885
emit contextMenuRequested(curRow, curCol, viewport()->mapToGlobal(contentsToViewport(r.center())));
3887
int tmpRow = rowAt(e->pos().y());
3888
int tmpCol = columnAt(e->pos().x());
3889
emit contextMenuRequested(tmpRow, tmpCol, e->globalPos());
3897
bool Q3Table::eventFilter(QObject *o, QEvent *e)
3899
switch (e->type()) {
3900
case QEvent::KeyPress: {
3901
Q3TableItem *itm = item(curRow, curCol);
3902
QWidget *editorWidget = cellWidget(editRow, editCol);
3904
if (isEditing() && editorWidget && o == editorWidget) {
3905
itm = item(editRow, editCol);
3906
QKeyEvent *ke = (QKeyEvent*)e;
3907
if (ke->key() == Key_Escape) {
3908
if (!itm || itm->editType() == Q3TableItem::OnTyping)
3909
endEdit(editRow, editCol, false, edMode != Editing);
3913
if ((ke->state() == NoButton || ke->state() == Keypad)
3914
&& (ke->key() == Key_Return || ke->key() == Key_Enter)) {
3915
if (!itm || itm->editType() == Q3TableItem::OnTyping)
3916
endEdit(editRow, editCol, true, edMode != Editing);
3921
if (ke->key() == Key_Tab || ke->key() == Key_BackTab) {
3922
if (ke->state() & Qt::ControlButton)
3924
if (!itm || itm->editType() == Q3TableItem::OnTyping)
3925
endEdit(editRow, editCol, true, edMode != Editing);
3926
if ((ke->key() == Key_Tab) && !(ke->state() & ShiftButton)) {
3927
if (currentColumn() >= numCols() - 1)
3929
int cc = QMIN(numCols() - 1, currentColumn() + 1);
3930
while (cc < numCols()) {
3931
Q3TableItem *i = item(currentRow(), cc);
3932
if (!d->hiddenCols.find(cc) && !isColumnReadOnly(cc) && (!i || i->isEnabled()))
3936
setCurrentCell(currentRow(), cc);
3937
} else { // Key_BackTab
3938
if (currentColumn() == 0)
3940
int cc = QMAX(0, currentColumn() - 1);
3942
Q3TableItem *i = item(currentRow(), cc);
3943
if (!d->hiddenCols.find(cc) && !isColumnReadOnly(cc) && (!i || i->isEnabled()))
3947
setCurrentCell(currentRow(), cc);
3949
itm = item(curRow, curCol);
3950
if (beginEdit(curRow, curCol, false))
3951
setEditMode(Editing, curRow, curCol);
3955
if ((edMode == Replacing ||
3956
itm && itm->editType() == Q3TableItem::WhenCurrent) &&
3957
(ke->key() == Key_Up || ke->key() == Key_Prior ||
3958
ke->key() == Key_Home || ke->key() == Key_Down ||
3959
ke->key() == Key_Next || ke->key() == Key_End ||
3960
ke->key() == Key_Left || ke->key() == Key_Right)) {
3961
if (!itm || itm->editType() == Q3TableItem::OnTyping) {
3962
endEdit(editRow, editCol, true, edMode != Editing);
3968
QObjectList l = viewport()->queryList("QWidget");
3969
if (l.contains(o)) {
3970
QKeyEvent *ke = (QKeyEvent*)e;
3971
if ((ke->state() & ControlButton) == ControlButton ||
3972
(ke->key() != Key_Left && ke->key() != Key_Right &&
3973
ke->key() != Key_Up && ke->key() != Key_Down &&
3974
ke->key() != Key_Prior && ke->key() != Key_Next &&
3975
ke->key() != Key_Home && ke->key() != Key_End))
3977
keyPressEvent((QKeyEvent*)e);
3983
case QEvent::FocusOut: {
3984
QWidget *editorWidget = cellWidget(editRow, editCol);
3985
if (isEditing() && editorWidget && o == editorWidget && ((QFocusEvent*)e)->reason() != Qt::PopupFocusReason) {
3986
Q3TableItem *itm = item(editRow, editCol);
3987
if (!itm || itm->editType() == Q3TableItem::OnTyping) {
3988
endEdit(editRow, editCol, true, edMode != Editing);
3994
#ifndef QT_NO_WHEELEVENT
3996
if (o == this || o == viewport()) {
3997
QWheelEvent* we = (QWheelEvent*)e;
3998
scrollBy(0, -we->delta());
4007
return Q3ScrollView::eventFilter(o, e);
4010
void Q3Table::fixCell(int &row, int &col, int key)
4012
if (rowHeight(row) > 0 && columnWidth(col) > 0)
4014
if (rowHeight(row) <= 0) {
4015
if (key == Key_Down ||
4018
while (row < numRows() && rowHeight(row) <= 0)
4020
if (rowHeight(row) <= 0)
4022
} else if (key == Key_Up ||
4025
while (row >= 0 && rowHeight(row) <= 0)
4027
if (rowHeight(row) <= 0)
4029
} else if (columnWidth(col) <= 0) {
4030
if (key == Key_Left) {
4031
while (col >= 0 && columnWidth(col) <= 0)
4033
if (columnWidth(col) <= 0)
4035
} else if (key == Key_Right) {
4036
while (col < numCols() && columnWidth(col) <= 0)
4038
if (columnWidth(col) <= 0)
4047
void Q3Table::keyPressEvent(QKeyEvent* e)
4049
if (isEditing() && item(editRow, editCol) &&
4050
item(editRow, editCol)->editType() == Q3TableItem::OnTyping)
4053
int tmpRow = curRow;
4054
int tmpCol = curCol;
4055
int oldRow = tmpRow;
4056
int oldCol = tmpCol;
4058
bool navigationKey = false;
4062
tmpCol = QMAX(0, tmpCol - 1);
4063
navigationKey = true;
4066
tmpCol = QMIN(numCols() - 1, tmpCol + 1);
4067
navigationKey = true;
4070
tmpRow = QMAX(0, tmpRow - 1);
4071
navigationKey = true;
4074
tmpRow = QMIN(numRows() - 1, tmpRow + 1);
4075
navigationKey = true;
4078
r = QMAX(0, rowAt(rowPos(tmpRow) - visibleHeight()));
4079
if (r < tmpRow || tmpRow < 0)
4081
navigationKey = true;
4084
r = QMIN(numRows() - 1, rowAt(rowPos(tmpRow) + visibleHeight()));
4088
tmpRow = numRows() - 1;
4089
navigationKey = true;
4093
navigationKey = true;
4096
tmpRow = numRows() - 1;
4097
navigationKey = true;
4100
if (beginEdit(tmpRow, tmpCol, false))
4101
setEditMode(Editing, tmpRow, tmpCol);
4103
case Key_Enter: case Key_Return:
4106
case Key_Tab: case Key_BackTab:
4107
if ((e->key() == Key_Tab) && !(e->state() & ShiftButton)) {
4108
if (currentColumn() >= numCols() - 1)
4110
int cc = QMIN(numCols() - 1, currentColumn() + 1);
4111
while (cc < numCols()) {
4112
Q3TableItem *i = item(currentRow(), cc);
4113
if (!d->hiddenCols.find(cc) && !isColumnReadOnly(cc) && (!i || i->isEnabled()))
4117
setCurrentCell(currentRow(), cc);
4118
} else { // Key_BackTab
4119
if (currentColumn() == 0)
4121
int cc = QMAX(0, currentColumn() - 1);
4123
Q3TableItem *i = item(currentRow(), cc);
4124
if (!d->hiddenCols.find(cc) && !isColumnReadOnly(cc) && (!i || i->isEnabled()))
4128
setCurrentCell(currentRow(), cc);
4134
default: // ... or start in-place editing
4135
if (e->text()[ 0 ].isPrint()) {
4136
Q3TableItem *itm = item(tmpRow, tmpCol);
4137
if (!itm || itm->editType() == Q3TableItem::OnTyping) {
4138
QWidget *w = beginEdit(tmpRow, tmpCol,
4139
itm ? itm->isReplaceable() : true);
4141
setEditMode((!itm || itm && itm->isReplaceable()
4142
? Replacing : Editing), tmpRow, tmpCol);
4143
QApplication::sendEvent(w, e);
4152
if (navigationKey) {
4153
fixCell(tmpRow, tmpCol, e->key());
4154
if ((e->state() & ShiftButton) == ShiftButton &&
4155
selMode != NoSelection && selMode != SingleRow) {
4156
bool justCreated = false;
4157
setCurrentCell(tmpRow, tmpCol, false, true);
4160
currentSel = new Q3TableSelection();
4161
selections.append(currentSel);
4162
if (!isRowSelection(selectionMode()))
4163
currentSel->init(oldRow, oldCol);
4165
currentSel->init(oldRow < 0 ? 0 : oldRow, 0);
4167
Q3TableSelection oldSelection = *currentSel;
4168
if (!isRowSelection(selectionMode()))
4169
currentSel->expandTo(tmpRow, tmpCol);
4171
currentSel->expandTo(tmpRow, numCols() - 1);
4172
repaintSelections(justCreated ? 0 : &oldSelection, currentSel);
4173
emit selectionChanged();
4175
setCurrentCell(tmpRow, tmpCol, false, true);
4176
if (!isRowSelection(selectionMode())) {
4179
bool currentInSelection = tmpRow == oldRow && isSelected(tmpRow, tmpCol, false);
4180
if (!currentInSelection) {
4181
bool hasOldSel = false;
4182
Q3TableSelection oldSelection;
4183
if (selectionMode() == MultiRow) {
4184
bool b = signalsBlocked();
4190
oldSelection = *currentSel;
4192
selections.removeRef(currentSel);
4193
leftHeader->setSectionState(oldSelection.topRow(), Q3TableHeader::Normal);
4196
currentSel = new Q3TableSelection();
4197
selections.append(currentSel);
4198
currentSel->init(tmpRow, 0);
4199
currentSel->expandTo(tmpRow, numCols() - 1);
4200
repaintSelections(hasOldSel ? &oldSelection : 0, currentSel, !hasOldSel);
4201
emit selectionChanged();
4206
setCurrentCell(tmpRow, tmpCol, false, true);
4213
void Q3Table::focusInEvent(QFocusEvent*)
4215
d->inMenuMode = false;
4216
QWidget *editorWidget = cellWidget(editRow, editCol);
4217
updateCell(curRow, curCol);
4218
if (style()->styleHint(QStyle::SH_ItemView_ChangeHighlightOnFocus, 0, this))
4219
repaintSelections();
4220
if (isEditing() && editorWidget)
4221
editorWidget->setFocus();
4229
void Q3Table::focusOutEvent(QFocusEvent *e)
4231
updateCell(curRow, curCol);
4232
if (style()->styleHint(QStyle::SH_ItemView_ChangeHighlightOnFocus, 0, this)) {
4234
e->reason() == Qt::PopupFocusReason ||
4235
(qApp->focusWidget() && qApp->focusWidget()->inherits("QMenuBar"));
4237
repaintSelections();
4244
QSize Q3Table::sizeHint() const
4246
if (cachedSizeHint().isValid())
4247
return cachedSizeHint();
4251
QSize s = tableSize();
4253
if (s.width() < 500 && s.height() < 500) {
4254
sh = QSize(tableSize().width() + VERTICALMARGIN + 5,
4255
tableSize().height() + topMargin() + 5);
4257
sh = Q3ScrollView::sizeHint();
4258
if (!topHeader->isHidden())
4259
sh.setHeight(sh.height() + topHeader->height());
4260
if (!leftHeader->isHidden())
4261
sh.setWidth(sh.width() + leftHeader->width());
4263
setCachedSizeHint(sh);
4270
void Q3Table::viewportResizeEvent(QResizeEvent *e)
4272
Q3ScrollView::viewportResizeEvent(e);
4279
void Q3Table::showEvent(QShowEvent *e)
4281
Q3ScrollView::showEvent(e);
4282
QRect r(cellGeometry(numRows() - 1, numCols() - 1));
4283
resizeContents(r.right() + 1, r.bottom() + 1);
4290
void Q3Table::paintEvent(QPaintEvent *e)
4292
QRect topLeftCorner = QStyle::visualRect(layoutDirection(), rect(), QRect(frameWidth(), frameWidth(), VERTICALMARGIN, topMargin()));
4293
erase(topLeftCorner); // erase instead of widget on top
4294
Q3ScrollView::paintEvent(e);
4298
p.drawLine(topLeftCorner.bottomLeft(), topLeftCorner.bottomRight());
4299
p.drawLine(topLeftCorner.bottomRight(), topLeftCorner.topRight());
4303
static bool inUpdateCell = false;
4306
Repaints the cell at \a row, \a col.
4309
void Q3Table::updateCell(int row, int col)
4311
if (inUpdateCell || row < 0 || col < 0)
4313
inUpdateCell = true;
4314
QRect cg = cellGeometry(row, col);
4315
QRect r(contentsToViewport(QPoint(cg.x() - 2, cg.y() - 2)),
4316
QSize(cg.width() + 4, cg.height() + 4));
4317
viewport()->update(r);
4318
inUpdateCell = false;
4321
void Q3Table::repaintCell(int row, int col)
4323
if (row == -1 || col == -1)
4325
QRect cg = cellGeometry(row, col);
4326
QRect r(QPoint(cg.x() - 2, cg.y() - 2),
4327
QSize(cg.width() + 4, cg.height() + 4));
4328
repaintContents(r, false);
4331
void Q3Table::contentsToViewport2(int x, int y, int& vx, int& vy)
4333
const QPoint v = contentsToViewport2(QPoint(x, y));
4338
QPoint Q3Table::contentsToViewport2(const QPoint &p)
4340
return QPoint(p.x() - contentsX(),
4341
p.y() - contentsY());
4344
QPoint Q3Table::viewportToContents2(const QPoint& vp)
4346
return QPoint(vp.x() + contentsX(),
4347
vp.y() + contentsY());
4350
void Q3Table::viewportToContents2(int vx, int vy, int& x, int& y)
4352
const QPoint c = viewportToContents2(QPoint(vx, vy));
4358
This function should be called whenever the column width of \a col
4359
has been changed. It updates the geometry of any affected columns
4360
and repaints the table to reflect the changes it has made.
4363
void Q3Table::columnWidthChanged(int col)
4365
int p = columnPos(col);
4368
updateContents(p, contentsY(), contentsWidth(), visibleHeight());
4369
QSize s(tableSize());
4370
int w = contentsWidth();
4371
resizeContents(s.width(), s.height());
4372
if (contentsWidth() < w)
4373
repaintContents(s.width(), contentsY(),
4374
w - s.width() + 1, visibleHeight(), true);
4376
repaintContents(w, contentsY(),
4377
s.width() - w + 1, visibleHeight(), false);
4379
// update widgets that are affected by this change
4381
for (int c = col; c <= d->lastVisCol; ++c)
4382
updateColWidgets(c);
4383
delayedUpdateGeometries();
4387
This function should be called whenever the row height of \a row
4388
has been changed. It updates the geometry of any affected rows and
4389
repaints the table to reflect the changes it has made.
4392
void Q3Table::rowHeightChanged(int row)
4394
int p = rowPos(row);
4397
updateContents(contentsX(), p, visibleWidth(), contentsHeight());
4398
QSize s(tableSize());
4399
int h = contentsHeight();
4400
resizeContents(s.width(), s.height());
4401
if (contentsHeight() < h) {
4402
repaintContents(contentsX(), contentsHeight(),
4403
visibleWidth(), h - s.height() + 1, true);
4405
repaintContents(contentsX(), h,
4406
visibleWidth(), s.height() - h + 1, false);
4409
// update widgets that are affected by this change
4410
if (widgets.size()) {
4411
d->lastVisRow = rowAt(contentsY() + visibleHeight() + (s.height() - h + 1));
4412
for (int r = row; r <= d->lastVisRow; ++r)
4413
updateRowWidgets(r);
4415
delayedUpdateGeometries();
4420
void Q3Table::updateRowWidgets(int row)
4422
for (int i = 0; i < numCols(); ++i) {
4423
QWidget *w = cellWidget(row, i);
4426
moveChild(w, columnPos(i), rowPos(row));
4427
w->resize(columnWidth(i) - 1, rowHeight(row) - 1);
4433
void Q3Table::updateColWidgets(int col)
4435
for (int i = 0; i < numRows(); ++i) {
4436
QWidget *w = cellWidget(i, col);
4439
moveChild(w, columnPos(col), rowPos(i));
4440
w->resize(columnWidth(col) - 1, rowHeight(i) - 1);
4445
This function is called when column order is to be changed, i.e.
4446
when the user moved the column header \a section from \a fromIndex
4449
If you want to change the column order programmatically, call
4450
swapRows() or swapColumns();
4452
\sa Q3Header::indexChange() rowIndexChanged()
4455
void Q3Table::columnIndexChanged(int, int fromIndex, int toIndex)
4457
if (doSort && lastSortCol == fromIndex && topHeader)
4458
topHeader->setSortIndicator(toIndex, topHeader->sortIndicatorOrder());
4459
repaintContents(contentsX(), contentsY(),
4460
visibleWidth(), visibleHeight(), false);
4464
This function is called when the order of the rows is to be
4465
changed, i.e. the user moved the row header section \a section
4466
from \a fromIndex to \a toIndex.
4468
If you want to change the order programmatically, call swapRows()
4471
\sa Q3Header::indexChange() columnIndexChanged()
4474
void Q3Table::rowIndexChanged(int, int, int)
4476
repaintContents(contentsX(), contentsY(),
4477
visibleWidth(), visibleHeight(), false);
4481
This function is called when the column \a col has been clicked.
4482
The default implementation sorts this column if sorting() is true.
4485
void Q3Table::columnClicked(int col)
4490
if (col == lastSortCol) {
4496
sortColumn(lastSortCol, asc);
4500
\property Q3Table::sorting
4501
\brief whether a click on the header of a column sorts that column
4506
void Q3Table::setSorting(bool b)
4510
topHeader->setSortIndicator(b ? lastSortCol : -1);
4513
bool Q3Table::sorting() const
4518
static bool inUpdateGeometries = false;
4520
void Q3Table::delayedUpdateGeometries()
4522
d->geomTimer->start(0, true);
4525
void Q3Table::updateGeometriesSlot()
4531
This function updates the geometries of the left and top header.
4532
You do not normally need to call this function.
4535
void Q3Table::updateGeometries()
4537
if (inUpdateGeometries)
4539
inUpdateGeometries = true;
4540
QSize ts = tableSize();
4541
if (topHeader->offset() &&
4542
ts.width() < topHeader->offset() + topHeader->width())
4543
horizontalScrollBar()->setValue(ts.width() - topHeader->width());
4544
if (leftHeader->offset() &&
4545
ts.height() < leftHeader->offset() + leftHeader->height())
4546
verticalScrollBar()->setValue(ts.height() - leftHeader->height());
4548
leftHeader->setGeometry(QStyle::visualRect(layoutDirection(), rect(), QRect(frameWidth(), topMargin() + frameWidth(),
4549
VERTICALMARGIN, visibleHeight())));
4550
topHeader->setGeometry(QStyle::visualRect(layoutDirection(), rect(), QRect(VERTICALMARGIN + frameWidth(), frameWidth(),
4551
visibleWidth(), topMargin())));
4552
horizontalScrollBar()->raise();
4553
verticalScrollBar()->raise();
4554
topHeader->updateStretches();
4555
leftHeader->updateStretches();
4556
inUpdateGeometries = false;
4560
Returns the width of column \a col.
4562
\sa setColumnWidth() rowHeight()
4565
int Q3Table::columnWidth(int col) const
4567
return topHeader->sectionSize(col);
4571
Returns the height of row \a row.
4573
\sa setRowHeight() columnWidth()
4576
int Q3Table::rowHeight(int row) const
4578
return leftHeader->sectionSize(row);
4582
Returns the x-coordinate of the column \a col in content
4585
\sa columnAt() rowPos()
4588
int Q3Table::columnPos(int col) const
4590
return topHeader->sectionPos(col);
4594
Returns the y-coordinate of the row \a row in content coordinates.
4596
\sa rowAt() columnPos()
4599
int Q3Table::rowPos(int row) const
4601
return leftHeader->sectionPos(row);
4605
Returns the number of the column at position \a x. \a x must be
4606
given in content coordinates.
4608
\sa columnPos() rowAt()
4611
int Q3Table::columnAt(int x) const
4613
return topHeader->sectionAt(x);
4617
Returns the number of the row at position \a y. \a y must be given
4618
in content coordinates.
4620
\sa rowPos() columnAt()
4623
int Q3Table::rowAt(int y) const
4625
return leftHeader->sectionAt(y);
4629
Returns the bounding rectangle of the cell at \a row, \a col in
4630
content coordinates.
4633
QRect Q3Table::cellGeometry(int row, int col) const
4635
Q3TableItem *itm = item(row, col);
4637
if (!itm || itm->rowSpan() == 1 && itm->colSpan() == 1)
4638
return QRect(columnPos(col), rowPos(row),
4639
columnWidth(col), rowHeight(row));
4641
while (row != itm->row())
4643
while (col != itm->col())
4646
QRect rect(columnPos(col), rowPos(row),
4647
columnWidth(col), rowHeight(row));
4649
for (int r = 1; r < itm->rowSpan(); ++r)
4650
rect.setHeight(rect.height() + rowHeight(r + row));
4652
for (int c = 1; c < itm->colSpan(); ++c)
4653
rect.setWidth(rect.width() + columnWidth(c + col));
4659
Returns the size of the table.
4661
This is the same as the coordinates of the bottom-right edge of
4662
the last table cell.
4665
QSize Q3Table::tableSize() const
4667
return QSize(columnPos(numCols() - 1) + columnWidth(numCols() - 1),
4668
rowPos(numRows() - 1) + rowHeight(numRows() - 1));
4672
\property Q3Table::numRows
4673
\brief The number of rows in the table
4678
int Q3Table::numRows() const
4680
return leftHeader->count();
4684
\property Q3Table::numCols
4685
\brief The number of columns in the table
4690
int Q3Table::numCols() const
4692
return topHeader->count();
4695
void Q3Table::saveContents(Q3PtrVector<Q3TableItem> &tmp,
4696
Q3PtrVector<Q3Table::TableWidget> &tmp2)
4698
int nCols = numCols();
4699
if (editRow != -1 && editCol != -1)
4700
endEdit(editRow, editCol, false, edMode != Editing);
4701
tmp.resize(contents.size());
4702
tmp2.resize(widgets.size());
4704
for (i = 0; i < (int)tmp.size(); ++i) {
4705
Q3TableItem *item = contents[ i ];
4706
if (item && (item->row() * nCols) + item->col() == i)
4707
tmp.insert(i, item);
4711
for (i = 0; i < (int)tmp2.size(); ++i) {
4712
QWidget *w = widgets[ i ];
4714
tmp2.insert(i, new TableWidget(w, i / nCols, i % nCols));
4720
void Q3Table::updateHeaderAndResizeContents(Q3TableHeader *header,
4721
int num, int rowCol,
4722
int width, bool &updateBefore)
4724
updateBefore = rowCol < num;
4726
header->Q3Header::resizeArrays(rowCol);
4727
header->Q3TableHeader::resizeArrays(rowCol);
4729
clearSelection(false);
4731
for (i = old; i < rowCol; ++i)
4732
header->addLabel(QString(), width);
4734
clearSelection(false);
4735
if (header == leftHeader) {
4736
while (numRows() > rowCol)
4737
header->removeLabel(numRows() - 1);
4739
while (numCols() > rowCol)
4740
header->removeLabel(numCols() - 1);
4744
contents.setAutoDelete(false);
4746
contents.setAutoDelete(true);
4747
widgets.setAutoDelete(false);
4749
widgets.setAutoDelete(true);
4750
resizeData(numRows() * numCols());
4752
// keep numStretches in sync
4754
for (uint i = 0; i < header->stretchable.size(); i++)
4755
n += (header->stretchable.at(i) & 1); // avoid cmp
4756
header->numStretches = n;
4759
void Q3Table::restoreContents(Q3PtrVector<Q3TableItem> &tmp,
4760
Q3PtrVector<Q3Table::TableWidget> &tmp2)
4763
int nCols = numCols();
4764
for (i = 0; i < (int)tmp.size(); ++i) {
4765
Q3TableItem *it = tmp[ i ];
4767
int idx = (it->row() * nCols) + it->col();
4768
if ((uint)idx < contents.size() &&
4769
it->row() == idx / nCols && it->col() == idx % nCols) {
4770
contents.insert(idx, it);
4771
if (it->rowSpan() > 1 || it->colSpan() > 1) {
4773
for (int irow = 0; irow < it->rowSpan(); irow++) {
4774
ridx = idx + irow * nCols;
4775
for (int icol = 0; icol < it->colSpan(); icol++) {
4777
if (idx != iidx && (uint)iidx < contents.size())
4778
contents.insert(iidx, it);
4788
for (i = 0; i < (int)tmp2.size(); ++i) {
4789
TableWidget *w = tmp2[ i ];
4791
int idx = (w->row * nCols) + w->col;
4792
if ((uint)idx < widgets.size() &&
4793
w->row == idx / nCols && w->col == idx % nCols)
4794
widgets.insert(idx, w->wid);
4802
void Q3Table::finishContentsResze(bool updateBefore)
4804
QRect r(cellGeometry(numRows() - 1, numCols() - 1));
4805
resizeContents(r.right() + 1, r.bottom() + 1);
4808
repaintContents(contentsX(), contentsY(),
4809
visibleWidth(), visibleHeight(), true);
4811
repaintContents(contentsX(), contentsY(),
4812
visibleWidth(), visibleHeight(), false);
4814
if (isRowSelection(selectionMode())) {
4817
setCurrentCell(r, curCol);
4821
void Q3Table::setNumRows(int r)
4826
if (r < numRows()) {
4827
// Removed rows are no longer hidden, and should thus be removed from "hiddenRows"
4828
for (int rr = numRows()-1; rr >= r; --rr) {
4829
if (d->hiddenRows.find(rr))
4830
d->hiddenRows.remove(rr);
4834
fontChange(font()); // invalidate the sizeHintCache
4836
Q3PtrVector<Q3TableItem> tmp;
4837
Q3PtrVector<TableWidget> tmp2;
4838
saveContents(tmp, tmp2);
4840
bool updatesEnabled = leftHeader->updatesEnabled();
4842
leftHeader->setUpdatesEnabled(false);
4845
updateHeaderAndResizeContents(leftHeader, numRows(), r, 20, updateBefore);
4847
int w = fontMetrics().width(QString::number(r) + "W");
4848
if (VERTICALMARGIN > 0 && w > VERTICALMARGIN)
4851
restoreContents(tmp, tmp2);
4853
leftHeader->calculatePositions();
4854
finishContentsResze(updateBefore);
4855
if (updatesEnabled) {
4856
leftHeader->setUpdatesEnabled(true);
4857
leftHeader->update();
4859
leftHeader->updateCache();
4860
if (curRow >= numRows()) {
4861
curRow = numRows() - 1;
4865
repaintCell(curRow, curCol);
4868
if (curRow > numRows())
4872
void Q3Table::setNumCols(int c)
4877
if (c < numCols()) {
4878
// Removed columns are no longer hidden, and should thus be removed from "hiddenCols"
4879
for (int cc = numCols()-1; cc >= c; --cc) {
4880
if (d->hiddenCols.find(cc))
4881
d->hiddenCols.remove(cc);
4885
fontChange(font()); // invalidate the sizeHintCache
4887
Q3PtrVector<Q3TableItem> tmp;
4888
Q3PtrVector<TableWidget> tmp2;
4889
saveContents(tmp, tmp2);
4891
bool updatesEnabled = topHeader->updatesEnabled();
4893
topHeader->setUpdatesEnabled(false);
4896
updateHeaderAndResizeContents(topHeader, numCols(), c, 100, updateBefore);
4898
restoreContents(tmp, tmp2);
4900
topHeader->calculatePositions();
4901
finishContentsResze(updateBefore);
4902
if (updatesEnabled) {
4903
topHeader->setUpdatesEnabled(true);
4904
topHeader->update();
4906
topHeader->updateCache();
4907
if (curCol >= numCols()) {
4908
curCol = numCols() - 1;
4912
repaintCell(curRow, curCol);
4916
/*! Sets the section labels of the verticalHeader() to \a labels */
4918
void Q3Table::setRowLabels(const QStringList &labels)
4920
leftHeader->setLabels(labels);
4923
/*! Sets the section labels of the horizontalHeader() to \a labels */
4925
void Q3Table::setColumnLabels(const QStringList &labels)
4927
topHeader->setLabels(labels);
4931
This function returns the widget which should be used as an editor
4932
for the contents of the cell at \a row, \a col.
4934
If \a initFromCell is true, the editor is used to edit the current
4935
contents of the cell (so the editor widget should be initialized
4936
with this content). If \a initFromCell is false, the content of
4937
the cell is replaced with the new content which the user entered
4938
into the widget created by this function.
4940
The default functionality is as follows: if \a initFromCell is
4941
true or the cell has a Q3TableItem and the table item's
4942
Q3TableItem::isReplaceable() is false then the cell is asked to
4943
create an appropriate editor (using Q3TableItem::createEditor()).
4944
Otherwise a QLineEdit is used as the editor.
4946
If you want to create your own editor for certain cells, implement
4947
a custom Q3TableItem subclass and reimplement
4948
Q3TableItem::createEditor().
4950
If you are not using \l{Q3TableItem}s and you don't want to use a
4951
QLineEdit as the default editor, subclass Q3Table and reimplement
4952
this function with code like this:
4954
Q3TableItem *i = item(row, col);
4955
if (initFromCell || (i && !i->isReplaceable()))
4956
// If we had a Q3TableItem ask the base class to create the editor
4957
return Q3Table::createEditor(row, col, initFromCell);
4959
return ...(create your own editor)
4961
Ownership of the editor widget is transferred to the caller.
4963
If you reimplement this function return 0 for read-only cells. You
4964
will need to reimplement setCellContentFromEditor() to retrieve
4965
the data the user entered.
4967
\sa Q3TableItem::createEditor()
4970
QWidget *Q3Table::createEditor(int row, int col, bool initFromCell) const
4972
if (isReadOnly() || isRowReadOnly(row) || isColumnReadOnly(col))
4977
// the current item in the cell should be edited if possible
4978
Q3TableItem *i = item(row, col);
4979
if (initFromCell || (i && !i->isReplaceable())) {
4981
if (i->editType() == Q3TableItem::Never)
4984
e = i->createEditor();
4990
// no contents in the cell yet, so open the default editor
4992
e = new QLineEdit(viewport(), "qt_lineeditor");
4993
((QLineEdit*)e)->setFrame(false);
5000
This function is called to start in-place editing of the cell at
5001
\a row, \a col. Editing is achieved by creating an editor
5002
(createEditor() is called) and setting the cell's editor with
5003
setCellWidget() to the newly created editor. (After editing is
5004
complete endEdit() will be called to replace the cell's content
5005
with the editor's content.) If \a replace is true the editor will
5006
start empty; otherwise it will be initialized with the cell's
5007
content (if any), i.e. the user will be modifying the original
5013
QWidget *Q3Table::beginEdit(int row, int col, bool replace)
5015
if (isReadOnly() || isRowReadOnly(row) || isColumnReadOnly(col))
5017
Q3TableItem *itm = item(row, col);
5018
if (itm && !itm->isEnabled())
5020
if (cellWidget(row, col))
5022
ensureCellVisible(row, col);
5023
QWidget *e = createEditor(row, col, !replace);
5026
setCellWidget(row, col, e);
5027
e->setActiveWindow();
5029
updateCell(row, col);
5034
This function is called when in-place editing of the cell at \a
5035
row, \a col is requested to stop.
5037
If the cell is not being edited or \a accept is false the function
5038
returns and the cell's contents are left unchanged.
5040
If \a accept is true the content of the editor must be transferred
5041
to the relevant cell. If \a replace is true the current content of
5042
this cell should be replaced by the content of the editor (this
5043
means removing the current Q3TableItem of the cell and creating a
5044
new one for the cell). Otherwise (if possible) the content of the
5045
editor should just be set to the existing Q3TableItem of this cell.
5047
setCellContentFromEditor() is called to replace the contents of
5048
the cell with the contents of the cell's editor.
5050
Finally clearCellWidget() is called to remove the editor widget.
5052
\sa setCellContentFromEditor(), beginEdit()
5055
void Q3Table::endEdit(int row, int col, bool accept, bool replace)
5057
QWidget *editor = cellWidget(row, col);
5062
if (row == editRow && col == editCol)
5063
setEditMode(NotEditing, -1, -1);
5064
clearCellWidget(row, col);
5065
updateCell(row, col);
5066
viewport()->setFocus();
5067
updateCell(row, col);
5071
Q3TableItem *i = item(row, col);
5074
oldContent = i->text();
5076
if (!i || replace) {
5077
setCellContentFromEditor(row, col);
5080
i->setContentFromEditor(editor);
5083
if (row == editRow && col == editCol)
5084
setEditMode(NotEditing, -1, -1);
5086
viewport()->setFocus();
5087
updateCell(row, col);
5089
if (!i || (oldContent != i->text()))
5090
emit valueChanged(row, col);
5092
clearCellWidget(row, col);
5096
This function is called to replace the contents of the cell at \a
5097
row, \a col with the contents of the cell's editor.
5099
If there already exists a Q3TableItem for the cell,
5100
it calls Q3TableItem::setContentFromEditor() on this Q3TableItem.
5102
If, for example, you want to create different \l{Q3TableItem}s
5103
depending on the contents of the editor, you might reimplement
5106
If you want to work without \l{Q3TableItem}s, you will need to
5107
reimplement this function to save the data the user entered into
5108
your data structure. (See the notes on large tables.)
5110
\sa Q3TableItem::setContentFromEditor() createEditor()
5113
void Q3Table::setCellContentFromEditor(int row, int col)
5115
QWidget *editor = cellWidget(row, col);
5119
Q3TableItem *i = item(row, col);
5121
i->setContentFromEditor(editor);
5123
QLineEdit *le = ::qobject_cast<QLineEdit*>(editor);
5125
setText(row, col, le->text());
5130
Returns true if the \l EditMode is \c Editing or \c Replacing;
5131
otherwise (i.e. the \l EditMode is \c NotEditing) returns false.
5133
\sa Q3Table::EditMode
5136
bool Q3Table::isEditing() const
5138
return edMode != NotEditing;
5142
Returns the current edit mode
5144
\sa Q3Table::EditMode
5147
Q3Table::EditMode Q3Table::editMode() const
5153
Returns the current edited row
5156
int Q3Table::currEditRow() const
5162
Returns the current edited column
5165
int Q3Table::currEditCol() const
5171
Returns a single integer which identifies a particular \a row and \a
5172
col by mapping the 2D table to a 1D array.
5174
This is useful, for example, if you have a sparse table and want to
5175
use a Q3IntDict to map integers to the cells that are used.
5178
int Q3Table::indexOf(int row, int col) const
5180
return (row * numCols()) + col;
5186
void Q3Table::repaintSelections(Q3TableSelection *oldSelection,
5187
Q3TableSelection *newSelection,
5188
bool updateVertical, bool updateHorizontal)
5190
if (!oldSelection && !newSelection)
5192
if (oldSelection && newSelection && *oldSelection == *newSelection)
5194
if (oldSelection && !oldSelection->isActive())
5197
bool optimizeOld = false;
5198
bool optimizeNew = false;
5202
old = rangeGeometry(oldSelection->topRow(),
5203
oldSelection->leftCol(),
5204
oldSelection->bottomRow(),
5205
oldSelection->rightCol(),
5208
old = QRect(0, 0, 0, 0);
5212
cur = rangeGeometry(newSelection->topRow(),
5213
newSelection->leftCol(),
5214
newSelection->bottomRow(),
5215
newSelection->rightCol(),
5218
cur = QRect(0, 0, 0, 0);
5221
if (!optimizeOld || !optimizeNew ||
5222
old.width() > SHRT_MAX || old.height() > SHRT_MAX ||
5223
cur.width() > SHRT_MAX || cur.height() > SHRT_MAX) {
5224
QRect rr = cur.unite(old);
5225
repaintContents(rr, false);
5227
old = QRect(contentsToViewport2(old.topLeft()), old.size());
5228
cur = QRect(contentsToViewport2(cur.topLeft()), cur.size());
5231
QRegion r3 = r1.subtract(r2);
5232
QRegion r4 = r2.subtract(r1);
5234
for (i = 0; i < (int)r3.rects().count(); ++i) {
5235
QRect r(r3.rects()[ i ]);
5236
r = QRect(viewportToContents2(r.topLeft()), r.size());
5237
repaintContents(r, false);
5239
for (i = 0; i < (int)r4.rects().count(); ++i) {
5240
QRect r(r4.rects()[ i ]);
5241
r = QRect(viewportToContents2(r.topLeft()), r.size());
5242
repaintContents(r, false);
5246
int top, left, bottom, right;
5247
top = QMIN(oldSelection ? oldSelection->topRow() : newSelection->topRow(),
5248
newSelection ? newSelection->topRow() :oldSelection->topRow());
5249
left = QMIN(oldSelection ? oldSelection->leftCol() : newSelection->leftCol(),
5250
newSelection ? newSelection->leftCol() : oldSelection->leftCol());
5251
bottom = QMAX(oldSelection ? oldSelection->bottomRow() : newSelection->bottomRow(),
5252
newSelection ? newSelection->bottomRow() : oldSelection->bottomRow());
5253
right = QMAX(oldSelection ? oldSelection->rightCol() : newSelection->rightCol(),
5254
newSelection ? newSelection->rightCol() : oldSelection->rightCol());
5256
if (updateHorizontal && numCols() > 0 && left >= 0 && !isRowSelection(selectionMode())) {
5257
register int *s = &topHeader->states.data()[left];
5258
for (i = left; i <= right; ++i) {
5259
if (!isColumnSelected(i))
5260
*s = Q3TableHeader::Normal;
5261
else if (isColumnSelected(i, true))
5262
*s = Q3TableHeader::Selected;
5264
*s = Q3TableHeader::Bold;
5267
topHeader->repaint(false);
5270
if (updateVertical && numRows() > 0 && top >= 0) {
5271
register int *s = &leftHeader->states.data()[top];
5272
for (i = top; i <= bottom; ++i) {
5273
if (!isRowSelected(i))
5274
*s = Q3TableHeader::Normal;
5275
else if (isRowSelected(i, true))
5276
*s = Q3TableHeader::Selected;
5278
*s = Q3TableHeader::Bold;
5281
leftHeader->repaint(false);
5286
Repaints all selections
5289
void Q3Table::repaintSelections()
5291
if (selections.isEmpty())
5295
for (Q3TableSelection *s = selections.first(); s; s = selections.next()) {
5297
r = r.unite(rangeGeometry(s->topRow(),
5303
repaintContents(r, false);
5307
Clears all selections and repaints the appropriate regions if \a
5310
\sa removeSelection()
5313
void Q3Table::clearSelection(bool repaint)
5315
if (selections.isEmpty())
5317
bool needRepaint = !selections.isEmpty();
5320
for (Q3TableSelection *s = selections.first(); s; s = selections.next()) {
5322
r = r.unite(rangeGeometry(s->topRow(),
5331
if (needRepaint && repaint)
5332
repaintContents(r, false);
5334
leftHeader->setSectionStateToAll(Q3TableHeader::Normal);
5335
leftHeader->repaint(false);
5336
if (!isRowSelection(selectionMode())) {
5337
topHeader->setSectionStateToAll(Q3TableHeader::Normal);
5338
topHeader->repaint(false);
5340
topHeader->setSectionState(curCol, Q3TableHeader::Bold);
5341
leftHeader->setSectionState(curRow, Q3TableHeader::Bold);
5342
emit selectionChanged();
5348
QRect Q3Table::rangeGeometry(int topRow, int leftCol,
5349
int bottomRow, int rightCol, bool &optimize)
5351
topRow = QMAX(topRow, rowAt(contentsY()));
5352
leftCol = QMAX(leftCol, columnAt(contentsX()));
5353
int ra = rowAt(contentsY() + visibleHeight());
5355
bottomRow = QMIN(bottomRow, ra);
5356
int ca = columnAt(contentsX() + visibleWidth());
5358
rightCol = QMIN(rightCol, ca);
5361
for (int r = topRow; r <= bottomRow; ++r) {
5362
for (int c = leftCol; c <= rightCol; ++c) {
5363
rect = rect.unite(cellGeometry(r, c));
5364
Q3TableItem *i = item(r, c);
5365
if (i && (i->rowSpan() > 1 || i->colSpan() > 1))
5373
This function is called to activate the next cell if in-place
5374
editing was finished by pressing the Enter key.
5376
The default behaviour is to move from top to bottom, i.e. move to
5377
the cell beneath the cell being edited. Reimplement this function
5378
if you want different behaviour, e.g. moving from left to right.
5381
void Q3Table::activateNextCell()
5384
while (d->hiddenRows.find(firstRow))
5387
while (d->hiddenCols.find(firstCol))
5389
int nextRow = curRow;
5390
int nextCol = curCol;
5391
while (d->hiddenRows.find(++nextRow));
5392
if (nextRow >= numRows()) {
5394
while (d->hiddenCols.find(++nextCol));
5395
if (nextCol >= numCols())
5399
if (!currentSel || !currentSel->isActive() ||
5400
(currentSel->leftCol() == currentSel->rightCol() &&
5401
currentSel->topRow() == currentSel->bottomRow())) {
5403
setCurrentCell(nextRow, nextCol);
5405
if (curRow < currentSel->bottomRow())
5406
setCurrentCell(nextRow, curCol);
5407
else if (curCol < currentSel->rightCol())
5408
setCurrentCell(currentSel->topRow(), nextCol);
5410
setCurrentCell(currentSel->topRow(), currentSel->leftCol());
5418
void Q3Table::fixRow(int &row, int y)
5424
row = numRows() - 1;
5431
void Q3Table::fixCol(int &col, int x)
5437
col = numCols() - 1;
5441
struct SortableTableItem
5446
#if defined(Q_C_CALLBACKS)
5451
static int _cdecl cmpTableItems(const void *n1, const void *n2)
5453
static int cmpTableItems(const void *n1, const void *n2)
5459
SortableTableItem *i1 = (SortableTableItem *)n1;
5460
SortableTableItem *i2 = (SortableTableItem *)n2;
5462
return i1->item->key().localeAwareCompare(i2->item->key());
5465
#if defined(Q_C_CALLBACKS)
5470
Sorts column \a col. If \a ascending is true the sort is in
5471
ascending order, otherwise the sort is in descending order.
5473
If \a wholeRows is true, entire rows are sorted using swapRows();
5474
otherwise only cells in the column are sorted using swapCells().
5476
Note that if you are not using Q3TableItems you will need to
5477
reimplement swapRows() and swapCells(). (See the notes on large
5483
void Q3Table::sortColumn(int col, bool ascending, bool wholeRows)
5485
int filledRows = 0, i;
5486
for (i = 0; i < numRows(); ++i) {
5487
Q3TableItem *itm = item(i, col);
5495
SortableTableItem *items = new SortableTableItem[ filledRows ];
5497
for (i = 0; i < numRows(); ++i) {
5498
Q3TableItem *itm = item(i, col);
5501
items[ j++ ].item = itm;
5504
qsort(items, filledRows, sizeof(SortableTableItem), cmpTableItems);
5506
bool updatesWereEnabled = updatesEnabled();
5507
if (updatesWereEnabled)
5508
setUpdatesEnabled(false);
5509
for (i = 0; i < numRows(); ++i) {
5510
if (i < filledRows) {
5512
if (items[ i ].item->row() == i)
5515
swapRows(items[ i ].item->row(), i);
5517
swapCells(items[ i ].item->row(), col, i, col);
5519
if (items[ i ].item->row() == filledRows - i - 1)
5522
swapRows(items[ i ].item->row(), filledRows - i - 1);
5524
swapCells(items[ i ].item->row(), col,
5525
filledRows - i - 1, col);
5529
if (updatesWereEnabled)
5530
setUpdatesEnabled(true);
5532
topHeader->setSortIndicator(col, ascending ? Qt::Ascending : Qt::Descending);
5535
repaintContents(columnPos(col), contentsY(),
5536
columnWidth(col), visibleHeight(), false);
5538
repaintContents(contentsX(), contentsY(),
5539
visibleWidth(), visibleHeight(), false);
5547
\sa showRow() hideColumn()
5550
void Q3Table::hideRow(int row)
5552
if (d->hiddenRows.find(row))
5554
d->hiddenRows.replace(row, new int(leftHeader->sectionSize(row)));
5555
leftHeader->resizeSection(row, 0);
5556
leftHeader->setResizeEnabled(false, row);
5557
if (isRowStretchable(row))
5558
leftHeader->numStretches--;
5559
rowHeightChanged(row);
5560
if (curRow == row) {
5563
int k = (r >= numRows() - 1 ? Key_Up : Key_Down);
5566
setCurrentCell(r, c);
5571
Hides column \a col.
5573
\sa showColumn() hideRow()
5576
void Q3Table::hideColumn(int col)
5578
if (!numCols() || d->hiddenCols.find(col))
5580
d->hiddenCols.replace(col, new int(topHeader->sectionSize(col)));
5581
topHeader->resizeSection(col, 0);
5582
topHeader->setResizeEnabled(false, col);
5583
if (isColumnStretchable(col))
5584
topHeader->numStretches--;
5585
columnWidthChanged(col);
5586
if (curCol == col) {
5589
int k = (c >= numCols() - 1 ? Key_Left : Key_Right);
5592
setCurrentCell(r, c);
5599
\sa hideRow() showColumn()
5602
void Q3Table::showRow(int row)
5604
int *h = d->hiddenRows.find(row);
5607
d->hiddenRows.remove(row);
5608
setRowHeight(row, rh);
5609
if (isRowStretchable(row))
5610
leftHeader->numStretches++;
5611
} else if (rowHeight(row) == 0) {
5612
setRowHeight(row, 20);
5614
leftHeader->setResizeEnabled(true, row);
5618
Shows column \a col.
5620
\sa hideColumn() showRow()
5623
void Q3Table::showColumn(int col)
5625
int *w = d->hiddenCols.find(col);
5628
d->hiddenCols.remove(col);
5629
setColumnWidth(col, cw);
5630
if (isColumnStretchable(col))
5631
topHeader->numStretches++;
5632
} else if (columnWidth(col) == 0) {
5633
setColumnWidth(col, 20);
5635
topHeader->setResizeEnabled(true, col);
5639
Returns true if row \a row is hidden; otherwise returns
5642
\sa hideRow(), isColumnHidden()
5644
bool Q3Table::isRowHidden(int row) const
5646
return d->hiddenRows.find(row);
5650
Returns true if column \a col is hidden; otherwise returns
5653
\sa hideColumn(), isRowHidden()
5655
bool Q3Table::isColumnHidden(int col) const
5657
return d->hiddenCols.find(col);
5661
Resizes column \a col to be \a w pixels wide.
5663
\sa columnWidth() setRowHeight()
5666
void Q3Table::setColumnWidth(int col, int w)
5668
int *ow = d->hiddenCols.find(col);
5670
d->hiddenCols.replace(col, new int(w));
5672
topHeader->resizeSection(col, w);
5673
columnWidthChanged(col);
5678
Resizes row \a row to be \a h pixels high.
5680
\sa rowHeight() setColumnWidth()
5683
void Q3Table::setRowHeight(int row, int h)
5685
int *oh = d->hiddenRows.find(row);
5687
d->hiddenRows.replace(row, new int(h));
5689
leftHeader->resizeSection(row, h);
5690
rowHeightChanged(row);
5695
Resizes column \a col so that the column width is wide enough to
5696
display the widest item the column contains.
5701
void Q3Table::adjustColumn(int col)
5703
int w = topHeader->sectionSizeHint(col, fontMetrics()).width();
5704
if (topHeader->iconSet(col))
5705
w += topHeader->iconSet(col)->pixmap().width();
5707
for (int i = 0; i < numRows(); ++i) {
5708
Q3TableItem *itm = item(i, col);
5710
QWidget *widget = cellWidget(i, col);
5712
w = QMAX(w, widget->sizeHint().width());
5714
if (itm->colSpan() > 1)
5715
w = QMAX(w, itm->sizeHint().width() / itm->colSpan());
5717
w = QMAX(w, itm->sizeHint().width());
5720
w = QMAX(w, QApplication::globalStrut().width());
5721
setColumnWidth(col, w);
5725
Resizes row \a row so that the row height is tall enough to
5726
display the tallest item the row contains.
5731
void Q3Table::adjustRow(int row)
5734
h = QMAX(h, leftHeader->sectionSizeHint(row, leftHeader->fontMetrics()).height());
5735
if (leftHeader->iconSet(row))
5736
h = QMAX(h, leftHeader->iconSet(row)->pixmap().height());
5737
for (int i = 0; i < numCols(); ++i) {
5738
Q3TableItem *itm = item(row, i);
5740
QWidget *widget = cellWidget(row, i);
5742
h = QMAX(h, widget->sizeHint().height());
5744
if (itm->rowSpan() > 1)
5745
h = QMAX(h, itm->sizeHint().height() / itm->rowSpan());
5747
h = QMAX(h, itm->sizeHint().height());
5750
h = QMAX(h, QApplication::globalStrut().height());
5751
setRowHeight(row, h);
5755
If \a stretch is true, column \a col is set to be stretchable;
5756
otherwise column \a col is set to be unstretchable.
5758
If the table widget's width decreases or increases stretchable
5759
columns will grow narrower or wider to fit the space available as
5760
completely as possible. The user cannot manually resize stretchable
5763
\sa isColumnStretchable() setRowStretchable() adjustColumn()
5766
void Q3Table::setColumnStretchable(int col, bool stretch)
5768
topHeader->setSectionStretchable(col, stretch);
5770
if (stretch && d->hiddenCols.find(col))
5771
topHeader->numStretches--;
5775
If \a stretch is true, row \a row is set to be stretchable;
5776
otherwise row \a row is set to be unstretchable.
5778
If the table widget's height decreases or increases stretchable
5779
rows will grow shorter or taller to fit the space available as
5780
completely as possible. The user cannot manually resize
5783
\sa isRowStretchable() setColumnStretchable()
5786
void Q3Table::setRowStretchable(int row, bool stretch)
5788
leftHeader->setSectionStretchable(row, stretch);
5790
if (stretch && d->hiddenRows.find(row))
5791
leftHeader->numStretches--;
5795
Returns true if column \a col is stretchable; otherwise returns
5798
\sa setColumnStretchable() isRowStretchable()
5801
bool Q3Table::isColumnStretchable(int col) const
5803
return topHeader->isSectionStretchable(col);
5807
Returns true if row \a row is stretchable; otherwise returns
5810
\sa setRowStretchable() isColumnStretchable()
5813
bool Q3Table::isRowStretchable(int row) const
5815
return leftHeader->isSectionStretchable(row);
5819
Takes the table item \a i out of the table. This function does \e
5820
not delete the table item. You must either delete the table item
5821
yourself or put it into a table (using setItem()) which will then
5822
take ownership of it.
5824
Use this function if you want to move an item from one cell in a
5825
table to another, or to move an item from one table to another,
5826
reinserting the item with setItem().
5828
If you want to exchange two cells use swapCells().
5831
void Q3Table::takeItem(Q3TableItem *i)
5835
QRect rect = cellGeometry(i->row(), i->col());
5836
contents.setAutoDelete(false);
5837
int bottom = i->row() + i->rowSpan();
5838
if (bottom > numRows())
5840
int right = i->col() + i->colSpan();
5841
if (right > numCols())
5843
for (int r = i->row(); r < bottom; ++r) {
5844
for (int c = i->col(); c < right; ++c)
5845
contents.remove(indexOf(r, c));
5847
contents.setAutoDelete(true);
5848
repaintContents(rect, false);
5849
int orow = i->row();
5850
int ocol = i->col();
5853
i->updateEditor(orow, ocol);
5858
Sets the widget \a e to the cell at \a row, \a col and takes care of
5859
placing and resizing the widget when the cell geometry changes.
5861
By default widgets are inserted into a vector with numRows() *
5862
numCols() elements. In very large tables you will probably want to
5863
store the widgets in a data structure that consumes less memory (see
5864
the notes on large tables). To support the use of your own data
5865
structure this function calls insertWidget() to add the widget to
5866
the internal data structure. To use your own data structure
5867
reimplement insertWidget(), cellWidget() and clearCellWidget().
5869
Cell widgets are created dynamically with the \c new operator. The
5870
cell widgets are destroyed automatically once the table is
5871
destroyed; the table takes ownership of the widget when using
5876
void Q3Table::setCellWidget(int row, int col, QWidget *e)
5878
if (!e || row >= numRows() || col >= numCols())
5881
QWidget *w = cellWidget(row, col);
5882
if (w && row == editRow && col == editCol)
5883
endEdit(editRow, editCol, false, edMode != Editing);
5885
e->installEventFilter(this);
5886
clearCellWidget(row, col);
5887
if (e->parent() != viewport())
5888
e->reparent(viewport(), QPoint(0,0));
5889
insertWidget(row, col, e);
5890
QRect cr = cellGeometry(row, col);
5891
e->resize(cr.size());
5892
moveChild(e, cr.x(), cr.y());
5897
Inserts widget \a w at \a row, \a col into the internal
5898
data structure. See the documentation of setCellWidget() for
5901
If you don't use \l{Q3TableItem}s you may need to reimplement this
5902
function: see the notes on large tables.
5905
void Q3Table::insertWidget(int row, int col, QWidget *w)
5907
if (row < 0 || col < 0 || row > numRows() - 1 || col > numCols() - 1)
5910
if ((int)widgets.size() != numRows() * numCols())
5911
widgets.resize(numRows() * numCols());
5913
widgets.insert(indexOf(row, col), w);
5917
Returns the widget that has been set for the cell at \a row, \a
5918
col, or 0 if no widget has been set.
5920
If you don't use \l{Q3TableItem}s you may need to reimplement this
5921
function: see the notes on large tables.
5923
\sa clearCellWidget() setCellWidget()
5926
QWidget *Q3Table::cellWidget(int row, int col) const
5928
if (row < 0 || col < 0 || row > numRows() - 1 || col > numCols() - 1)
5931
if ((int)widgets.size() != numRows() * numCols())
5932
((Q3Table*)this)->widgets.resize(numRows() * numCols());
5934
return widgets[ indexOf(row, col) ];
5938
Removes the widget (if there is one) set for the cell at \a row,
5941
If you don't use \l{Q3TableItem}s you may need to reimplement this
5942
function: see the notes on large tables.
5944
This function deletes the widget at \a row, \a col. Note that the
5945
widget is not deleted immediately; instead QObject::deleteLater()
5946
is called on the widget to avoid problems with timing issues.
5948
\sa cellWidget() setCellWidget()
5951
void Q3Table::clearCellWidget(int row, int col)
5953
if (row < 0 || col < 0 || row > numRows() - 1 || col > numCols() - 1)
5956
if ((int)widgets.size() != numRows() * numCols())
5957
widgets.resize(numRows() * numCols());
5959
QWidget *w = cellWidget(row, col);
5961
w->removeEventFilter(this);
5964
widgets.setAutoDelete(false);
5965
widgets.remove(indexOf(row, col));
5966
widgets.setAutoDelete(true);
5970
\fn void Q3Table::dropped (QDropEvent * e)
5972
This signal is emitted when a drop event occurred on the table.
5974
\a e contains information about the drop.
5978
If \a b is true, the table starts a drag (see dragObject()) when
5979
the user presses and moves the mouse on a selected cell.
5982
void Q3Table::setDragEnabled(bool b)
5988
If this function returns true, the table supports dragging.
5990
\sa setDragEnabled()
5993
bool Q3Table::dragEnabled() const
5999
Inserts \a count empty rows at row \a row. Also clears the selection(s).
6001
\sa insertColumns() removeRow()
6004
void Q3Table::insertRows(int row, int count)
6006
// special case, so a call like insertRow(currentRow(), 1) also
6007
// works, when we have 0 rows and currentRow() is -1
6008
if (row == -1 && curRow == -1)
6010
if (row < 0 || count <= 0)
6013
if (curRow >= row && curRow < row + count)
6014
curRow = row + count;
6017
if (row >= numRows())
6020
bool updatesWereEnabled = updatesEnabled();
6021
if (updatesWereEnabled)
6022
setUpdatesEnabled(false);
6023
bool leftHeaderUpdatesEnabled = leftHeader->updatesEnabled();
6024
if (leftHeaderUpdatesEnabled)
6025
leftHeader->setUpdatesEnabled(false);
6026
int oldLeftMargin = leftMargin();
6028
setNumRows(numRows() + count);
6030
for (int i = numRows() - count - 1; i > row; --i)
6031
leftHeader->swapSections(i, i + count);
6033
if (leftHeaderUpdatesEnabled)
6034
leftHeader->setUpdatesEnabled(leftHeaderUpdatesEnabled);
6036
if (updatesWereEnabled)
6037
setUpdatesEnabled(true);
6039
int cr = QMAX(0, currentRow());
6040
int cc = QMAX(0, currentColumn());
6042
curRow -= count; // this is where curRow was
6043
setCurrentCell(cr, cc, true, false); // without ensureCellVisible
6045
// Repaint the header
6046
if (leftHeaderUpdatesEnabled) {
6047
int y = rowPos(row) - contentsY();
6048
if (leftMargin() != oldLeftMargin || d->hasRowSpan)
6049
y = 0; // full repaint
6050
QRect rect(0, y, leftHeader->width(), contentsHeight());
6051
leftHeader->update(rect);
6054
if (updatesWereEnabled) {
6055
int p = rowPos(row);
6058
updateContents(contentsX(), p, visibleWidth(), contentsHeight() + 1);
6063
Inserts \a count empty columns at column \a col. Also clears the selection(s).
6065
\sa insertRows() removeColumn()
6068
void Q3Table::insertColumns(int col, int count)
6070
// see comment in insertRows()
6071
if (col == -1 && curCol == -1)
6073
if (col < 0 || count <= 0)
6076
if (curCol >= col && curCol < col + count)
6077
curCol = col + count;
6080
if (col >= numCols())
6083
bool updatesWereEnabled = updatesEnabled();
6084
if (updatesWereEnabled)
6085
setUpdatesEnabled(false);
6086
bool topHeaderUpdatesEnabled = topHeader->updatesEnabled();
6087
if (topHeaderUpdatesEnabled)
6088
topHeader->setUpdatesEnabled(false);
6089
int oldTopMargin = topMargin();
6091
setNumCols(numCols() + count);
6093
for (int i = numCols() - count - 1; i > col; --i)
6094
topHeader->swapSections(i, i + count);
6096
if (topHeaderUpdatesEnabled)
6097
topHeader->setUpdatesEnabled(true);
6098
if (updatesWereEnabled)
6099
setUpdatesEnabled(true);
6101
int cr = QMAX(0, currentRow());
6102
int cc = QMAX(0, currentColumn());
6104
curCol -= count; // this is where curCol was
6105
setCurrentCell(cr, cc, true, false); // without ensureCellVisible
6107
// Repaint the header
6108
if (topHeaderUpdatesEnabled) {
6109
int x = columnPos(col) - contentsX();
6110
if (topMargin() != oldTopMargin || d->hasColSpan)
6111
x = 0; // full repaint
6112
QRect rect(x, 0, contentsWidth(), topHeader->height());
6113
topHeader->update(rect);
6116
if (updatesWereEnabled) {
6117
int p = columnPos(col);
6120
updateContents(p, contentsY(), contentsWidth() + 1, visibleHeight());
6125
Removes row \a row, and deletes all its cells including any table
6126
items and widgets the cells may contain. Also clears the selection(s).
6128
\sa hideRow() insertRows() removeColumn() removeRows()
6131
void Q3Table::removeRow(int row)
6133
if (row < 0 || row >= numRows())
6135
if (row < numRows() - 1) {
6136
if (d->hiddenRows.find(row))
6137
d->hiddenRows.remove(row);
6139
for (int i = row; i < numRows() - 1; ++i)
6140
((Q3TableHeader*)verticalHeader())->swapSections(i, i + 1);
6142
setNumRows(numRows() - 1);
6146
Removes the rows listed in the array \a rows, and deletes all their
6147
cells including any table items and widgets the cells may contain.
6149
The array passed in must only contain valid rows (in the range
6150
from 0 to numRows() - 1) with no duplicates, and must be sorted in
6151
ascending order. Also clears the selection(s).
6153
\sa removeRow() insertRows() removeColumns()
6156
void Q3Table::removeRows(const Q3MemArray<int> &rows)
6158
if (rows.count() == 0)
6161
for (i = 0; i < (int)rows.count() - 1; ++i) {
6162
for (int j = rows[i] - i; j < rows[i + 1] - i - 1; j++) {
6163
((Q3TableHeader*)verticalHeader())->swapSections(j, j + i + 1);
6167
for (int j = rows[i] - i; j < numRows() - (int)rows.size(); j++)
6168
((Q3TableHeader*)verticalHeader())->swapSections(j, j + rows.count());
6170
setNumRows(numRows() - rows.count());
6174
Removes column \a col, and deletes all its cells including any
6175
table items and widgets the cells may contain. Also clears the
6178
\sa removeColumns() hideColumn() insertColumns() removeRow()
6181
void Q3Table::removeColumn(int col)
6183
if (col < 0 || col >= numCols())
6185
if (col < numCols() - 1) {
6186
if (d->hiddenCols.find(col))
6187
d->hiddenCols.remove(col);
6189
for (int i = col; i < numCols() - 1; ++i)
6190
((Q3TableHeader*)horizontalHeader())->swapSections(i, i + 1);
6192
setNumCols(numCols() - 1);
6196
Removes the columns listed in the array \a cols, and deletes all
6197
their cells including any table items and widgets the cells may
6200
The array passed in must only contain valid columns (in the range
6201
from 0 to numCols() - 1) with no duplicates, and must be sorted in
6202
ascending order. Also clears the selection(s).
6204
\sa removeColumn() insertColumns() removeRows()
6207
void Q3Table::removeColumns(const Q3MemArray<int> &cols)
6209
if (cols.count() == 0)
6212
for (i = 0; i < (int)cols.count() - 1; ++i) {
6213
for (int j = cols[i] - i; j < cols[i + 1] - i - 1; j++) {
6214
((Q3TableHeader*)horizontalHeader())->swapSections(j, j + i + 1);
6218
for (int j = cols[i] - i; j < numCols() - (int)cols.size(); j++)
6219
((Q3TableHeader*)horizontalHeader())->swapSections(j, j + cols.count());
6221
setNumCols(numCols() - cols.count());
6225
Starts editing the cell at \a row, \a col.
6227
If \a replace is true the content of this cell will be replaced by
6228
the content of the editor when editing is finished, i.e. the user
6229
will be entering new data; otherwise the current content of the
6230
cell (if any) will be modified in the editor.
6235
void Q3Table::editCell(int row, int col, bool replace)
6237
if (row < 0 || col < 0 || row > numRows() - 1 || col > numCols() - 1)
6240
if (beginEdit(row, col, replace)) {
6247
#ifndef QT_NO_DRAGANDDROP
6250
This event handler is called whenever a Q3Table object receives a
6251
\l QDragEnterEvent \a e, i.e. when the user pressed the mouse
6252
button to drag something.
6254
The focus is moved to the cell where the QDragEnterEvent occurred.
6257
void Q3Table::contentsDragEnterEvent(QDragEnterEvent *e)
6259
oldCurrentRow = curRow;
6260
oldCurrentCol = curCol;
6261
int tmpRow = rowAt(e->pos().y());
6262
int tmpCol = columnAt(e->pos().x());
6263
fixRow(tmpRow, e->pos().y());
6264
fixCol(tmpCol, e->pos().x());
6265
if (e->source() != (QObject*)cellWidget(currentRow(), currentColumn()))
6266
setCurrentCell(tmpRow, tmpCol, false, true);
6271
This event handler is called whenever a Q3Table object receives a
6272
\l QDragMoveEvent \a e, i.e. when the user actually drags the
6275
The focus is moved to the cell where the QDragMoveEvent occurred.
6278
void Q3Table::contentsDragMoveEvent(QDragMoveEvent *e)
6280
int tmpRow = rowAt(e->pos().y());
6281
int tmpCol = columnAt(e->pos().x());
6282
fixRow(tmpRow, e->pos().y());
6283
fixCol(tmpCol, e->pos().x());
6284
if (e->source() != (QObject*)cellWidget(currentRow(), currentColumn()))
6285
setCurrentCell(tmpRow, tmpCol, false, true);
6290
This event handler is called when a drag activity leaves \e this
6291
Q3Table object with event \a e.
6294
void Q3Table::contentsDragLeaveEvent(QDragLeaveEvent *)
6296
setCurrentCell(oldCurrentRow, oldCurrentCol, false, true);
6300
This event handler is called when the user ends a drag and drop by
6301
dropping something onto \e this Q3Table and thus triggers the drop
6305
void Q3Table::contentsDropEvent(QDropEvent *e)
6307
setCurrentCell(oldCurrentRow, oldCurrentCol, false, true);
6312
If the user presses the mouse on a selected cell, starts moving
6313
(i.e. dragging), and dragEnabled() is true, this function is
6314
called to obtain a drag object. A drag using this object begins
6315
immediately unless dragObject() returns 0.
6317
By default this function returns 0. You might reimplement it and
6318
create a Q3DragObject depending on the selected items.
6323
Q3DragObject *Q3Table::dragObject()
6331
Usually you don't need to call or reimplement this function yourself.
6336
void Q3Table::startDrag()
6338
if (startDragRow == -1 || startDragCol == -1)
6341
startDragRow = startDragCol = -1;
6343
Q3DragObject *drag = dragObject();
6353
void Q3Table::windowActivationChange(bool oldActive)
6355
if (oldActive && autoScrollTimer)
6356
autoScrollTimer->stop();
6361
if (palette().active() != palette().inactive())
6368
void Q3Table::setEnabled(bool 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);
6375
Q3ScrollView::setEnabled(b);
6380
\class Q3TableHeader
6381
\brief The Q3TableHeader class allows for creation and manipulation
6386
Q3Table uses this subclass of Q3Header for its headers. Q3Table has a
6387
horizontalHeader() for displaying column labels, and a
6388
verticalHeader() for displaying row labels.
6393
\enum Q3TableHeader::SectionState
6395
This enum type denotes the state of the header's text
6397
\value Normal the default
6399
\value Selected typically represented by showing the section "sunken"
6404
Creates a new table header called \a name with \a i sections. It
6405
is a child of widget \a parent and attached to table \a t.
6408
Q3TableHeader::Q3TableHeader(int i, Q3Table *t,
6409
QWidget *parent, const char *name)
6410
: Q3Header(i, parent, name), mousePressed(false), startPos(-1),
6411
table(t), caching(false), resizedSection(-1),
6414
setIsATableHeader(true);
6417
stretchable.resize(i);
6418
states.fill(Normal, -1);
6419
stretchable.fill(false, -1);
6420
autoScrollTimer = new QTimer(this);
6421
connect(autoScrollTimer, SIGNAL(timeout()),
6422
this, SLOT(doAutoScroll()));
6423
#ifndef NO_LINE_WIDGET
6424
line1 = new QWidget(table->viewport(), "qt_line1");
6426
line1->setBackgroundMode(PaletteText);
6427
table->addChild(line1);
6428
line2 = new QWidget(table->viewport(), "qt_line2");
6430
line2->setBackgroundMode(PaletteText);
6431
table->addChild(line2);
6433
d = new Q3TableHeaderPrivate;
6434
d->oldLinePos = -1; //outside, in contents coords
6436
connect(this, SIGNAL(sizeChange(int,int,int)),
6437
this, SLOT(sectionWidthChanged(int,int,int)));
6438
connect(this, SIGNAL(indexChange(int,int,int)),
6439
this, SLOT(indexChanged(int,int,int)));
6441
stretchTimer = new QTimer(this);
6442
widgetStretchTimer = new QTimer(this);
6443
connect(stretchTimer, SIGNAL(timeout()),
6444
this, SLOT(updateStretches()));
6445
connect(widgetStretchTimer, SIGNAL(timeout()),
6446
this, SLOT(updateWidgetStretches()));
6451
Adds a new section, \a size pixels wide (or high for vertical
6452
headers) with the label \a s. If \a size is negative the section's
6453
size is calculated based on the width (or height) of the label's
6457
void Q3TableHeader::addLabel(const QString &s , int size)
6459
Q3Header::addLabel(s, size);
6460
if (count() > (int)states.size()) {
6461
int s = states.size();
6462
states.resize(count());
6463
stretchable.resize(count());
6464
for (; s < count(); ++s) {
6465
states[ s ] = Normal;
6466
stretchable[ s ] = false;
6471
void Q3TableHeader::removeLabel(int section)
6473
Q3Header::removeLabel(section);
6474
if (section == (int)states.size() - 1) {
6475
states.resize(states.size() - 1);
6476
stretchable.resize(stretchable.size() - 1);
6480
void Q3TableHeader::resizeArrays(int n)
6482
int old = states.size();
6484
stretchable.resize(n);
6486
for (int i = old; i < n; ++i) {
6487
stretchable[ i ] = false;
6488
states[ i ] = Normal;
6493
void Q3TableHeader::setLabel(int section, const QString & s, int size)
6495
Q3Header::setLabel(section, s, size);
6496
sectionLabelChanged(section);
6499
void Q3TableHeader::setLabel(int section, const QIconSet & iconset,
6500
const QString & s, int size)
6502
Q3Header::setLabel(section, iconset, s, size);
6503
sectionLabelChanged(section);
6507
Sets the SectionState of section \a s to \a astate.
6512
void Q3TableHeader::setSectionState(int s, SectionState astate)
6514
if (s < 0 || s >= (int)states.count())
6516
if (states.data()[ s ] == astate)
6518
if (isRowSelection(table->selectionMode()) && orientation() == Horizontal)
6521
states.data()[ s ] = astate;
6522
if (updatesEnabled()) {
6523
if (orientation() == Horizontal)
6524
repaint(sectionPos(s) - offset(), 0, sectionSize(s), height(), false);
6526
repaint(0, sectionPos(s) - offset(), width(), sectionSize(s), false);
6530
void Q3TableHeader::setSectionStateToAll(SectionState state)
6532
if (isRowSelection(table->selectionMode()) && orientation() == Horizontal)
6535
register int *d = (int *) states.data();
6559
Returns the SectionState of section \a s.
6561
\sa setSectionState()
6564
Q3TableHeader::SectionState Q3TableHeader::sectionState(int s) const
6566
return (s < 0 || s >= (int)states.count() ? Normal : (Q3TableHeader::SectionState)states[s]);
6572
void Q3TableHeader::paintEvent(QPaintEvent *e)
6575
p.setPen(colorGroup().buttonText());
6576
int pos = orientation() == Horizontal
6579
int id = mapToIndex(sectionAt(pos + offset()));
6587
QRegion reg = e->region();
6588
for (int i = id; i < count(); i++) {
6592
if (!(orientation() == Horizontal && isRowSelection(table->selectionMode())) &&
6593
(sectionState(i) == Bold || sectionState(i) == Selected)) {
6598
paintSection(&p, i, r);
6600
if (orientation() == Horizontal && r. right() >= e->rect().right() ||
6601
orientation() == Vertical && r. bottom() >= e->rect().bottom())
6611
Paints the header section with index \a index into the rectangular
6612
region \a fr on the painter \a p.
6615
void Q3TableHeader::paintSection(QPainter *p, int index, const QRect& fr)
6617
int section = mapToSection(index);
6618
if (section < 0 || cellSize(section) <= 0)
6621
if (sectionState(index) != Selected ||
6622
orientation() == Horizontal && isRowSelection(table->selectionMode())) {
6623
Q3Header::paintSection(p, index, fr);
6625
QStyleOptionHeader opt;
6626
opt.palette = palette();
6628
opt.state = QStyle::State_Off | (orient == Qt::Horizontal ? QStyle::State_Horizontal
6629
: QStyle::State_None);
6631
opt.state |= QStyle::State_Enabled;
6632
if (isClickEnabled()) {
6633
if (sectionState(index) == Selected) {
6634
opt.state |= QStyle::State_Sunken;
6636
opt.state |= QStyle::State_On;
6639
if (!(opt.state & QStyle::State_Sunken))
6640
opt.state |= QStyle::State_Raised;
6641
style()->drawControl(QStyle::CE_HeaderSection, &opt, p, this);
6642
paintSectionLabel(p, index, fr);
6646
static int real_pos(const QPoint &p, Qt::Orientation o)
6648
if (o == Qt::Horizontal)
6656
void Q3TableHeader::mousePressEvent(QMouseEvent *e)
6658
if (e->button() != LeftButton)
6660
Q3Header::mousePressEvent(e);
6661
mousePressed = true;
6662
pressPos = real_pos(e->pos(), orientation());
6663
if (!table->currentSel || (e->state() & ShiftButton) != ShiftButton)
6666
resizedSection = -1;
6670
isResizing = cursor().shape() != ArrowCursor;
6671
if (!isResizing && sectionAt(pressPos) != -1)
6679
void Q3TableHeader::mouseMoveEvent(QMouseEvent *e)
6681
if ((e->state() & MouseButtonMask) != LeftButton // Using LeftButton simulates old behavior.
6682
#ifndef QT_NO_CURSOR
6683
|| cursor().shape() != ArrowCursor
6685
|| ((e->state() & ControlButton) == ControlButton &&
6686
(orientation() == Horizontal
6687
? table->columnMovingEnabled() : table->rowMovingEnabled()))) {
6688
Q3Header::mouseMoveEvent(e);
6692
if (!doSelection(e))
6693
Q3Header::mouseMoveEvent(e);
6696
bool Q3TableHeader::doSelection(QMouseEvent *e)
6698
int p = real_pos(e->pos(), orientation()) + offset();
6700
if (isRowSelection(table->selectionMode())) {
6701
if (orientation() == Horizontal)
6703
if (table->selectionMode() == Q3Table::SingleRow) {
6704
int secAt = sectionAt(p);
6707
table->setCurrentCell(secAt, table->currentColumn());
6712
if (startPos == -1) {
6713
int secAt = sectionAt(p);
6714
if ((e->state() & ControlButton) != ControlButton &&
6715
(e->state() & ShiftButton) != ShiftButton ||
6716
table->selectionMode() == Q3Table::Single ||
6717
table->selectionMode() == Q3Table::SingleRow) {
6719
bool b = table->signalsBlocked();
6720
table->blockSignals(true);
6721
table->clearSelection();
6722
table->blockSignals(b);
6726
if (table->selectionMode() != Q3Table::NoSelection) {
6728
Q3TableSelection *oldSelection = table->currentSel;
6730
if (orientation() == Vertical) {
6731
if (!table->isRowSelected(secAt, true)) {
6732
table->currentSel = new Q3TableSelection();
6733
table->selections.append(table->currentSel);
6734
table->currentSel->init(secAt, 0);
6735
table->currentSel->expandTo(secAt, table->numCols() - 1);
6736
emit table->selectionChanged();
6738
table->setCurrentCell(secAt, 0);
6739
} else { // orientation == Horizontal
6740
if (!table->isColumnSelected(secAt, true)) {
6741
table->currentSel = new Q3TableSelection();
6742
table->selections.append(table->currentSel);
6743
table->currentSel->init(0, secAt);
6744
table->currentSel->expandTo(table->numRows() - 1, secAt);
6745
emit table->selectionChanged();
6747
table->setCurrentCell(0, secAt);
6750
if (orientation() == Horizontal && table->isColumnSelected(secAt) ||
6751
orientation() == Vertical && table->isRowSelected(secAt)) {
6752
setSectionState(secAt, Selected);
6755
table->repaintSelections(oldSelection, table->currentSel,
6756
orientation() == Horizontal,
6757
orientation() == Vertical);
6758
if (sectionAt(p) != -1)
6765
if (sectionAt(p) != -1)
6767
if (startPos != -1) {
6770
if (orientation() == Horizontal && (p < 0 || p > width())) {
6772
autoScrollTimer->start(100, true);
6773
} else if (orientation() == Vertical && (p < 0 || p > height())) {
6775
autoScrollTimer->start(100, true);
6779
return table->selectionMode() == Q3Table::NoSelection;
6782
static inline bool mayOverwriteMargin(int before, int after)
6785
0 is the only user value that we always respect. We also never
6786
shrink a margin, in case the user wanted it that way.
6788
return before != 0 && before < after;
6791
void Q3TableHeader::sectionLabelChanged(int section)
6793
emit sectionSizeChanged(section);
6795
// this does not really belong here
6796
if (orientation() == Horizontal) {
6797
int h = sizeHint().height();
6798
if (h != height() && mayOverwriteMargin(table->topMargin(), h))
6799
table->setTopMargin(h);
6801
int w = sizeHint().width();
6802
if (w != width() && mayOverwriteMargin((QApplication::reverseLayout() ? table->rightMargin() : table->leftMargin()), w))
6803
table->setLeftMargin(w);
6808
void Q3TableHeader::mouseReleaseEvent(QMouseEvent *e)
6810
if (e->button() != LeftButton)
6812
autoScrollTimer->stop();
6813
mousePressed = false;
6815
Q3Header::mouseReleaseEvent(e);
6816
#ifndef NO_LINE_WIDGET
6820
if (d->oldLinePos >= 0)
6821
if (orientation() == Horizontal)
6822
table->updateContents(d->oldLinePos, table->contentsY(),
6823
1, table->visibleHeight());
6825
table->updateContents( table->contentsX(), d->oldLinePos,
6826
table->visibleWidth(), 1);
6829
if (resizedSection != -1) {
6830
emit sectionSizeChanged(resizedSection);
6834
//Make sure all newly selected sections are painted one last time
6835
QRect selectedRects;
6836
for (int i = 0; i < count(); i++) {
6837
if(sectionState(i) == Selected)
6838
selectedRects |= sRect(i);
6840
if(!selectedRects.isNull())
6841
repaint(selectedRects);
6847
void Q3TableHeader::mouseDoubleClickEvent(QMouseEvent *e)
6849
if (e->button() != LeftButton)
6852
int p = real_pos(e->pos(), orientation()) + offset();
6853
int section = sectionAt(p);
6857
if (p >= sectionPos(count() - 1) + sectionSize(count() - 1))
6859
while (sectionSize(section) == 0)
6863
int oldSize = sectionSize(section);
6864
if (orientation() == Horizontal) {
6865
table->adjustColumn(section);
6866
int newSize = sectionSize(section);
6867
if (oldSize != newSize)
6868
emit sizeChange(section, oldSize, newSize);
6869
for (int i = 0; i < table->numCols(); ++i) {
6870
if (table->isColumnSelected(i) && sectionSize(i) != 0)
6871
table->adjustColumn(i);
6874
table->adjustRow(section);
6875
int newSize = sectionSize(section);
6876
if (oldSize != newSize)
6877
emit sizeChange(section, oldSize, newSize);
6878
for (int i = 0; i < table->numRows(); ++i) {
6879
if (table->isRowSelected(i) && sectionSize(i) != 0)
6880
table->adjustRow(i);
6889
void Q3TableHeader::resizeEvent(QResizeEvent *e)
6891
stretchTimer->stop();
6892
widgetStretchTimer->stop();
6893
Q3Header::resizeEvent(e);
6894
if (numStretches == 0)
6896
stretchTimer->start(0, true);
6899
void Q3TableHeader::updateStretches()
6901
if (numStretches == 0)
6904
int dim = orientation() == Horizontal ? width() : height();
6905
if (sectionPos(count() - 1) + sectionSize(count() - 1) == dim)
6908
int pd = dim - (sectionPos(count() - 1)
6909
+ sectionSize(count() - 1));
6910
bool block = signalsBlocked();
6912
for (i = 0; i < (int)stretchable.count(); ++i) {
6913
if (!stretchable[i] ||
6914
(stretchable[i] && table->d->hiddenCols[i]))
6916
pd += sectionSize(i);
6919
for (i = 0; i < (int)stretchable.count(); ++i) {
6920
if (!stretchable[i] ||
6921
(stretchable[i] && table->d->hiddenCols[i]))
6923
if (i == (int)stretchable.count() - 1 &&
6924
sectionPos(i) + pd < dim)
6925
pd = dim - sectionPos(i);
6926
resizeSection(i, QMAX(20, pd));
6928
blockSignals(block);
6929
table->repaintContents(false);
6930
widgetStretchTimer->start(100, true);
6933
void Q3TableHeader::updateWidgetStretches()
6935
QSize s = table->tableSize();
6936
table->resizeContents(s.width(), s.height());
6937
for (int i = 0; i < table->numCols(); ++i)
6938
table->updateColWidgets(i);
6941
void Q3TableHeader::updateSelections()
6943
if (table->selectionMode() == Q3Table::NoSelection ||
6944
(isRowSelection(table->selectionMode()) && orientation() != Vertical ))
6946
int a = sectionAt(startPos);
6947
int b = sectionAt(endPos);
6948
int start = QMIN(a, b);
6949
int end = QMAX(a, b);
6950
register int *s = states.data();
6951
for (int i = 0; i < count(); ++i) {
6952
if (i < start || i > end)
6953
*s = oldStates.data()[ i ];
6960
if (table->currentSel) {
6961
Q3TableSelection oldSelection = *table->currentSel;
6962
if (orientation() == Vertical)
6963
table->currentSel->expandTo(b, table->horizontalHeader()->count() - 1);
6965
table->currentSel->expandTo(table->verticalHeader()->count() - 1, b);
6966
table->repaintSelections(&oldSelection, table->currentSel,
6967
orientation() == Horizontal,
6968
orientation() == Vertical);
6970
emit table->selectionChanged();
6973
void Q3TableHeader::saveStates()
6975
oldStates.resize(count());
6976
register int *s = states.data();
6977
register int *s2 = oldStates.data();
6978
for (int i = 0; i < count(); ++i) {
6985
void Q3TableHeader::doAutoScroll()
6987
QPoint pos = mapFromGlobal(QCursor::pos());
6988
int p = real_pos(pos, orientation()) + offset();
6989
if (sectionAt(p) != -1)
6991
if (orientation() == Horizontal)
6992
table->ensureVisible(endPos, table->contentsY());
6994
table->ensureVisible(table->contentsX(), endPos);
6996
autoScrollTimer->start(100, true);
6999
void Q3TableHeader::sectionWidthChanged(int col, int, int)
7001
resizedSection = col;
7002
if (orientation() == Horizontal) {
7003
#ifndef NO_LINE_WIDGET
7004
table->moveChild(line1, Q3Header::sectionPos(col) - 1,
7005
table->contentsY());
7006
line1->resize(1, table->visibleHeight());
7009
table->moveChild(line2,
7010
Q3Header::sectionPos(col) + Q3Header::sectionSize(col) - 1,
7011
table->contentsY());
7012
line2->resize(1, table->visibleHeight());
7016
QPainter p(table->viewport());
7017
int lx = Q3Header::sectionPos(col) + Q3Header::sectionSize(col) - 1;
7018
int ly = table->contentsY();
7020
if (lx != d->oldLinePos) {
7021
QPoint pt = table->contentsToViewport(QPoint(lx, ly));
7022
p.drawLine(pt.x(), pt.y()+1,
7023
pt.x(), pt.y()+ table->visibleHeight());
7024
if (d->oldLinePos >= 0)
7025
table->repaintContents(d->oldLinePos, table->contentsY(),
7026
1, table->visibleHeight());
7032
#ifndef NO_LINE_WIDGET
7033
table->moveChild(line1, table->contentsX(),
7034
Q3Header::sectionPos(col) - 1);
7035
line1->resize(table->visibleWidth(), 1);
7038
table->moveChild(line2, table->contentsX(),
7039
Q3Header::sectionPos(col) + Q3Header::sectionSize(col) - 1);
7040
line2->resize(table->visibleWidth(), 1);
7045
QPainter p(table->viewport());
7046
int lx = table->contentsX();
7047
int ly = Q3Header::sectionPos(col) + Q3Header::sectionSize(col) - 1;
7049
if (ly != d->oldLinePos) {
7050
QPoint pt = table->contentsToViewport(QPoint(lx, ly));
7051
p.drawLine(pt.x()+1, pt.y(),
7052
pt.x() + table->visibleWidth(), pt.y());
7053
if (d->oldLinePos >= 0)
7054
table->repaintContents( table->contentsX(), d->oldLinePos,
7055
table->visibleWidth(), 1);
7066
Returns the size of section \a section in pixels or -1 if \a
7067
section is out of range.
7070
int Q3TableHeader::sectionSize(int section) const
7072
if (count() <= 0 || section < 0 || section >= count())
7074
if (caching && section < (int)sectionSizes.count())
7075
return sectionSizes[ section ];
7076
return Q3Header::sectionSize(section);
7082
Returns the start position of section \a section in pixels or -1
7083
if \a section is out of range.
7088
int Q3TableHeader::sectionPos(int section) const
7090
if (count() <= 0 || section < 0 || section >= count())
7092
if (caching && section < (int)sectionPoses.count())
7093
return sectionPoses[ section ];
7094
return Q3Header::sectionPos(section);
7100
Returns the number of the section at index position \a pos or -1
7101
if there is no section at the position given.
7106
int Q3TableHeader::sectionAt(int pos) const
7108
if (!caching || sectionSizes.count() <= 0 || sectionPoses.count() <= 0)
7109
return Q3Header::sectionAt(pos);
7110
if (count() <= 0 || pos > sectionPoses[ count() - 1 ] + sectionSizes[ count() - 1 ])
7113
int r = count() - 1;
7114
int i = ((l+r+1) / 2);
7116
if (sectionPoses[i] > pos)
7122
if (sectionPoses[i] <= pos &&
7123
pos <= sectionPoses[i] + sectionSizes[ mapToSection(i) ])
7124
return mapToSection(i);
7128
void Q3TableHeader::updateCache()
7130
sectionPoses.resize(count());
7131
sectionSizes.resize(count());
7134
for (int i = 0; i < count(); ++i) {
7135
sectionSizes[ i ] = Q3Header::sectionSize(i);
7136
sectionPoses[ i ] = Q3Header::sectionPos(i);
7140
void Q3TableHeader::setCaching(bool b)
7145
sectionPoses.resize(count());
7146
sectionSizes.resize(count());
7148
for (int i = 0; i < count(); ++i) {
7149
sectionSizes[ i ] = Q3Header::sectionSize(i);
7150
sectionPoses[ i ] = Q3Header::sectionPos(i);
7156
If \a b is true, section \a s is stretchable; otherwise the
7157
section is not stretchable.
7159
\sa isSectionStretchable()
7162
void Q3TableHeader::setSectionStretchable(int s, bool b)
7164
if (stretchable[ s ] == b)
7166
stretchable[ s ] = b;
7174
Returns true if section \a s is stretcheable; otherwise returns
7177
\sa setSectionStretchable()
7180
bool Q3TableHeader::isSectionStretchable(int s) const
7182
return stretchable[ s ];
7185
void Q3TableHeader::swapSections(int oldIdx, int newIdx, bool swapTable)
7187
extern bool qt_qheader_label_return_null_strings; // qheader.cpp
7188
qt_qheader_label_return_null_strings = true;
7190
QIconSet oldIconSet, newIconSet;
7191
if (iconSet(oldIdx))
7192
oldIconSet = *iconSet(oldIdx);
7193
if (iconSet(newIdx))
7194
newIconSet = *iconSet(newIdx);
7195
QString oldLabel = label(oldIdx);
7196
QString newLabel = label(newIdx);
7197
bool sectionsHasContent = !(oldIconSet.isNull() && newIconSet.isNull()
7198
&& oldLabel.isNull() && newLabel.isNull());
7199
if (sectionsHasContent) {
7200
setLabel(oldIdx, newIconSet, newLabel);
7201
setLabel(newIdx, oldIconSet, oldLabel);
7204
qt_qheader_label_return_null_strings = false;
7206
int w1 = sectionSize(oldIdx);
7207
int w2 = sectionSize(newIdx);
7209
resizeSection(oldIdx, w2);
7210
resizeSection(newIdx, w1);
7215
if (orientation() == Horizontal)
7216
table->swapColumns(oldIdx, newIdx);
7218
table->swapRows(oldIdx, newIdx);
7221
void Q3TableHeader::indexChanged(int sec, int oldIdx, int newIdx)
7223
newIdx = mapToIndex(sec);
7224
if (oldIdx > newIdx)
7225
moveSection(sec, oldIdx + 1);
7227
moveSection(sec, oldIdx);
7229
if (oldIdx < newIdx) {
7230
while (oldIdx < newIdx) {
7231
swapSections(oldIdx, oldIdx + 1);
7235
while (oldIdx > newIdx) {
7236
swapSections(oldIdx - 1, oldIdx);
7241
table->repaintContents(table->contentsX(), table->contentsY(),
7242
table->visibleWidth(), table->visibleHeight());
7245
void Q3TableHeader::setLabels(const QStringList & labels)
7248
const int c = QMIN(count(), (int)labels.count());
7249
bool updates = updatesEnabled();
7251
setUpdatesEnabled(false);
7252
for (QStringList::ConstIterator it = labels.begin(); i < c; ++i, ++it) {
7255
setUpdatesEnabled(true);
7258
Q3Header::setLabel(i, *it);
7259
emit sectionSizeChanged(i);
7264
#include "q3table.moc"