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