~oif-team/ubuntu/natty/qt4-x11/xi2.1

« back to all changes in this revision

Viewing changes to src/qt3support/itemviews/q3table.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Adam Conrad
  • Date: 2005-08-24 04:09:09 UTC
  • Revision ID: james.westby@ubuntu.com-20050824040909-xmxe9jfr4a0w5671
Tags: upstream-4.0.0
ImportĀ upstreamĀ versionĀ 4.0.0

Show diffs side-by-side

added added

removed removed

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