~gabriel1984sibiu/minitube/qt5.6

« back to all changes in this revision

Viewing changes to src/widgets/itemviews/qheaderview.cpp

  • Committer: Grevutiu Gabriel
  • Date: 2017-06-13 08:43:17 UTC
  • Revision ID: gabriel1984sibiu@gmail.com-20170613084317-ek0zqe0u9g3ocvi8
OriginalĀ upstreamĀ code

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
**
 
3
** Copyright (C) 2016 The Qt Company Ltd.
 
4
** Contact: https://www.qt.io/licensing/
 
5
**
 
6
** This file is part of the QtWidgets module of the Qt Toolkit.
 
7
**
 
8
** $QT_BEGIN_LICENSE:LGPL$
 
9
** Commercial License Usage
 
10
** Licensees holding valid commercial Qt licenses may use this file in
 
11
** accordance with the commercial license agreement provided with the
 
12
** Software or, alternatively, in accordance with the terms contained in
 
13
** a written agreement between you and The Qt Company. For licensing terms
 
14
** and conditions see https://www.qt.io/terms-conditions. For further
 
15
** information use the contact form at https://www.qt.io/contact-us.
 
16
**
 
17
** GNU Lesser General Public License Usage
 
18
** Alternatively, this file may be used under the terms of the GNU Lesser
 
19
** General Public License version 3 as published by the Free Software
 
20
** Foundation and appearing in the file LICENSE.LGPL3 included in the
 
21
** packaging of this file. Please review the following information to
 
22
** ensure the GNU Lesser General Public License version 3 requirements
 
23
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
 
24
**
 
25
** GNU General Public License Usage
 
26
** Alternatively, this file may be used under the terms of the GNU
 
27
** General Public License version 2.0 or (at your option) the GNU General
 
28
** Public license version 3 or any later version approved by the KDE Free
 
29
** Qt Foundation. The licenses are as published by the Free Software
 
30
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
 
31
** included in the packaging of this file. Please review the following
 
32
** information to ensure the GNU General Public License requirements will
 
33
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
 
34
** https://www.gnu.org/licenses/gpl-3.0.html.
 
35
**
 
36
** $QT_END_LICENSE$
 
37
**
 
38
****************************************************************************/
 
39
 
 
40
#include "qheaderview.h"
 
41
 
 
42
#ifndef QT_NO_ITEMVIEWS
 
43
#include <qbitarray.h>
 
44
#include <qbrush.h>
 
45
#include <qdebug.h>
 
46
#include <qevent.h>
 
47
#include <qpainter.h>
 
48
#include <qscrollbar.h>
 
49
#include <qtooltip.h>
 
50
#include <qwhatsthis.h>
 
51
#include <qstyle.h>
 
52
#include <qstyleoption.h>
 
53
#include <qvector.h>
 
54
#include <qapplication.h>
 
55
#include <qvarlengtharray.h>
 
56
#include <qabstractitemdelegate.h>
 
57
#include <qvariant.h>
 
58
#include <private/qheaderview_p.h>
 
59
#include <private/qabstractitemmodel_p.h>
 
60
 
 
61
#ifndef QT_NO_DATASTREAM
 
62
#include <qdatastream.h>
 
63
#endif
 
64
 
 
65
QT_BEGIN_NAMESPACE
 
66
 
 
67
#ifndef QT_NO_DATASTREAM
 
68
QDataStream &operator<<(QDataStream &out, const QHeaderViewPrivate::SectionItem &section)
 
69
{
 
70
    section.write(out);
 
71
    return out;
 
72
}
 
73
 
 
74
QDataStream &operator>>(QDataStream &in, QHeaderViewPrivate::SectionItem &section)
 
75
{
 
76
    section.read(in);
 
77
    return in;
 
78
}
 
79
#endif // QT_NO_DATASTREAM
 
80
 
 
81
static const int maxSizeSection = 1048575; // since section size is in a bitfield (uint 20). See qheaderview_p.h
 
82
                                           // if this is changed then the docs in maximumSectionSize should be changed.
 
83
 
 
84
/*!
 
85
    \class QHeaderView
 
86
 
 
87
    \brief The QHeaderView class provides a header row or header column for
 
88
    item views.
 
89
 
 
90
    \ingroup model-view
 
91
    \inmodule QtWidgets
 
92
 
 
93
    A QHeaderView displays the headers used in item views such as the
 
94
    QTableView and QTreeView classes. It takes the place of Qt3's \c QHeader
 
95
    class previously used for the same purpose, but uses the Qt's model/view
 
96
    architecture for consistency with the item view classes.
 
97
 
 
98
    The QHeaderView class is one of the \l{Model/View Classes} and is part of
 
99
    Qt's \l{Model/View Programming}{model/view framework}.
 
100
 
 
101
    The header gets the data for each section from the model using the
 
102
    QAbstractItemModel::headerData() function. You can set the data by using
 
103
    QAbstractItemModel::setHeaderData().
 
104
 
 
105
    Each header has an orientation() and a number of sections, given by the
 
106
    count() function. A section refers to a part of the header - either a row
 
107
    or a column, depending on the orientation.
 
108
 
 
109
    Sections can be moved and resized using moveSection() and resizeSection();
 
110
    they can also be hidden and shown with hideSection() and showSection().
 
111
 
 
112
    Each section of a header is described by a section ID, specified by its
 
113
    section(), and can be located at a particular visualIndex() in the header.
 
114
    A section can have a sort indicator set with setSortIndicator(); this
 
115
    indicates whether the items in the associated item view will be sorted in
 
116
    the order given by the section.
 
117
 
 
118
    For a horizontal header the section is equivalent to a column in the model,
 
119
    and for a vertical header the section is equivalent to a row in the model.
 
120
 
 
121
    \section1 Moving Header Sections
 
122
 
 
123
    A header can be fixed in place, or made movable with setSectionsMovable(). It can
 
124
    be made clickable with setSectionsClickable(), and has resizing behavior in
 
125
    accordance with setSectionResizeMode().
 
126
 
 
127
    \note Double-clicking on a header to resize a section only applies for
 
128
    visible rows.
 
129
 
 
130
    A header will emit sectionMoved() if the user moves a section,
 
131
    sectionResized() if the user resizes a section, and sectionClicked() as
 
132
    well as sectionHandleDoubleClicked() in response to mouse clicks. A header
 
133
    will also emit sectionCountChanged().
 
134
 
 
135
    You can identify a section using the logicalIndex() and logicalIndexAt()
 
136
    functions, or by its index position, using the visualIndex() and
 
137
    visualIndexAt() functions. The visual index will change if a section is
 
138
    moved, but the logical index will not change.
 
139
 
 
140
    \section1 Appearance
 
141
 
 
142
    QTableWidget and QTableView create default headers. If you want
 
143
    the headers to be visible, you can use \l{QFrame::}{setVisible()}.
 
144
 
 
145
    Not all \l{Qt::}{ItemDataRole}s will have an effect on a
 
146
    QHeaderView. If you need to draw other roles, you can subclass
 
147
    QHeaderView and reimplement \l{QHeaderView::}{paintEvent()}.
 
148
    QHeaderView respects the following item data roles:
 
149
    \l{Qt::}{TextAlignmentRole}, \l{Qt::}{DisplayRole},
 
150
    \l{Qt::}{FontRole}, \l{Qt::}{DecorationRole},
 
151
    \l{Qt::}{ForegroundRole}, and \l{Qt::}{BackgroundRole}.
 
152
 
 
153
    \note Each header renders the data for each section itself, and does not
 
154
    rely on a delegate. As a result, calling a header's setItemDelegate()
 
155
    function will have no effect.
 
156
 
 
157
    \sa {Model/View Programming}, QListView, QTableView, QTreeView
 
158
*/
 
159
 
 
160
/*!
 
161
    \enum QHeaderView::ResizeMode
 
162
 
 
163
    The resize mode specifies the behavior of the header sections. It can be
 
164
    set on the entire header view or on individual sections using
 
165
    setSectionResizeMode().
 
166
 
 
167
    \value Interactive The user can resize the section. The section can also be
 
168
           resized programmatically using resizeSection().  The section size
 
169
           defaults to \l defaultSectionSize. (See also
 
170
           \l cascadingSectionResizes.)
 
171
 
 
172
    \value Fixed The user cannot resize the section. The section can only be
 
173
           resized programmatically using resizeSection(). The section size
 
174
           defaults to \l defaultSectionSize.
 
175
 
 
176
    \value Stretch QHeaderView will automatically resize the section to fill
 
177
           the available space. The size cannot be changed by the user or
 
178
           programmatically.
 
179
 
 
180
    \value ResizeToContents QHeaderView will automatically resize the section
 
181
           to its optimal size based on the contents of the entire column or
 
182
           row. The size cannot be changed by the user or programmatically.
 
183
           (This value was introduced in 4.2)
 
184
 
 
185
    The following values are obsolete:
 
186
    \value Custom Use Fixed instead.
 
187
 
 
188
    \sa setResizeMode(), setSectionResizeMode(), stretchLastSection, minimumSectionSize
 
189
*/
 
190
 
 
191
/*!
 
192
    \fn void QHeaderView::sectionMoved(int logicalIndex, int oldVisualIndex,
 
193
    int newVisualIndex)
 
194
 
 
195
    This signal is emitted when a section is moved. The section's logical index
 
196
    is specified by \a logicalIndex, the old index by \a oldVisualIndex, and
 
197
    the new index position by \a newVisualIndex.
 
198
 
 
199
    \sa moveSection()
 
200
*/
 
201
 
 
202
/*!
 
203
    \fn void QHeaderView::sectionResized(int logicalIndex, int oldSize,
 
204
    int newSize)
 
205
 
 
206
    This signal is emitted when a section is resized. The section's logical
 
207
    number is specified by \a logicalIndex, the old size by \a oldSize, and the
 
208
    new size by \a newSize.
 
209
 
 
210
    \sa resizeSection()
 
211
*/
 
212
 
 
213
/*!
 
214
    \fn void QHeaderView::sectionPressed(int logicalIndex)
 
215
 
 
216
    This signal is emitted when a section is pressed. The section's logical
 
217
    index is specified by \a logicalIndex.
 
218
 
 
219
    \sa setSectionsClickable()
 
220
*/
 
221
 
 
222
/*!
 
223
    \fn void QHeaderView::sectionClicked(int logicalIndex)
 
224
 
 
225
    This signal is emitted when a section is clicked. The section's logical
 
226
    index is specified by \a logicalIndex.
 
227
 
 
228
    Note that the sectionPressed signal will also be emitted.
 
229
 
 
230
    \sa setSectionsClickable(), sectionPressed()
 
231
*/
 
232
 
 
233
/*!
 
234
    \fn void QHeaderView::sectionEntered(int logicalIndex)
 
235
    \since 4.3
 
236
 
 
237
    This signal is emitted when the cursor moves over the section and the left
 
238
    mouse button is pressed. The section's logical index is specified by
 
239
    \a logicalIndex.
 
240
 
 
241
    \sa setSectionsClickable(), sectionPressed()
 
242
*/
 
243
 
 
244
/*!
 
245
    \fn void QHeaderView::sectionDoubleClicked(int logicalIndex)
 
246
 
 
247
    This signal is emitted when a section is double-clicked. The section's
 
248
    logical index is specified by \a logicalIndex.
 
249
 
 
250
    \sa setSectionsClickable()
 
251
*/
 
252
 
 
253
/*!
 
254
    \fn void QHeaderView::sectionCountChanged(int oldCount, int newCount)
 
255
 
 
256
    This signal is emitted when the number of sections changes, i.e., when
 
257
    sections are added or deleted. The original count is specified by
 
258
    \a oldCount, and the new count by \a newCount.
 
259
 
 
260
    \sa count(), length(), headerDataChanged()
 
261
*/
 
262
 
 
263
/*!
 
264
    \fn void QHeaderView::sectionHandleDoubleClicked(int logicalIndex)
 
265
 
 
266
    This signal is emitted when a section is double-clicked. The section's
 
267
    logical index is specified by \a logicalIndex.
 
268
 
 
269
    \sa setSectionsClickable()
 
270
*/
 
271
 
 
272
/*!
 
273
    \fn void QHeaderView::sortIndicatorChanged(int logicalIndex,
 
274
    Qt::SortOrder order)
 
275
    \since 4.3
 
276
 
 
277
    This signal is emitted when the section containing the sort indicator or
 
278
    the order indicated is changed. The section's logical index is specified
 
279
    by \a logicalIndex and the sort order is specified by \a order.
 
280
 
 
281
    \sa setSortIndicator()
 
282
*/
 
283
 
 
284
/*!
 
285
    \fn void QHeaderView::geometriesChanged()
 
286
    \since 4.2
 
287
 
 
288
    This signal is emitted when the header's geometries have changed.
 
289
*/
 
290
 
 
291
/*!
 
292
    \property QHeaderView::highlightSections
 
293
    \brief whether the sections containing selected items are highlighted
 
294
 
 
295
    By default, this property is \c false.
 
296
*/
 
297
 
 
298
/*!
 
299
    Creates a new generic header with the given \a orientation and \a parent.
 
300
*/
 
301
QHeaderView::QHeaderView(Qt::Orientation orientation, QWidget *parent)
 
302
    : QAbstractItemView(*new QHeaderViewPrivate, parent)
 
303
{
 
304
    Q_D(QHeaderView);
 
305
    d->setDefaultValues(orientation);
 
306
    initialize();
 
307
}
 
308
 
 
309
/*!
 
310
  \internal
 
311
*/
 
312
QHeaderView::QHeaderView(QHeaderViewPrivate &dd,
 
313
                         Qt::Orientation orientation, QWidget *parent)
 
314
    : QAbstractItemView(dd, parent)
 
315
{
 
316
    Q_D(QHeaderView);
 
317
    d->setDefaultValues(orientation);
 
318
    initialize();
 
319
}
 
320
 
 
321
/*!
 
322
  Destroys the header.
 
323
*/
 
324
 
 
325
QHeaderView::~QHeaderView()
 
326
{
 
327
}
 
328
 
 
329
/*!
 
330
  \internal
 
331
*/
 
332
void QHeaderView::initialize()
 
333
{
 
334
    Q_D(QHeaderView);
 
335
    setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
 
336
    setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
 
337
    setFrameStyle(NoFrame);
 
338
    setFocusPolicy(Qt::NoFocus);
 
339
    d->viewport->setMouseTracking(true);
 
340
    d->viewport->setBackgroundRole(QPalette::Button);
 
341
    d->textElideMode = Qt::ElideNone;
 
342
    delete d->itemDelegate;
 
343
}
 
344
 
 
345
/*!
 
346
  \reimp
 
347
*/
 
348
void QHeaderView::setModel(QAbstractItemModel *model)
 
349
{
 
350
    if (model == this->model())
 
351
        return;
 
352
    Q_D(QHeaderView);
 
353
    d->persistentHiddenSections.clear();
 
354
    if (d->model && d->model != QAbstractItemModelPrivate::staticEmptyModel()) {
 
355
    if (d->orientation == Qt::Horizontal) {
 
356
        QObject::disconnect(d->model, SIGNAL(columnsInserted(QModelIndex,int,int)),
 
357
                            this, SLOT(sectionsInserted(QModelIndex,int,int)));
 
358
        QObject::disconnect(d->model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
 
359
                            this, SLOT(sectionsAboutToBeRemoved(QModelIndex,int,int)));
 
360
        QObject::disconnect(d->model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
 
361
                            this, SLOT(_q_sectionsRemoved(QModelIndex,int,int)));
 
362
        QObject::disconnect(d->model, SIGNAL(columnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
 
363
                            this, SLOT(_q_layoutAboutToBeChanged()));
 
364
    } else {
 
365
        QObject::disconnect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)),
 
366
                            this, SLOT(sectionsInserted(QModelIndex,int,int)));
 
367
        QObject::disconnect(d->model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
 
368
                            this, SLOT(sectionsAboutToBeRemoved(QModelIndex,int,int)));
 
369
        QObject::disconnect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
 
370
                            this, SLOT(_q_sectionsRemoved(QModelIndex,int,int)));
 
371
        QObject::disconnect(d->model, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
 
372
                            this, SLOT(_q_layoutAboutToBeChanged()));
 
373
    }
 
374
    QObject::disconnect(d->model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)),
 
375
                        this, SLOT(headerDataChanged(Qt::Orientation,int,int)));
 
376
    QObject::disconnect(d->model, SIGNAL(layoutAboutToBeChanged()),
 
377
                        this, SLOT(_q_layoutAboutToBeChanged()));
 
378
    }
 
379
 
 
380
    if (model && model != QAbstractItemModelPrivate::staticEmptyModel()) {
 
381
        if (d->orientation == Qt::Horizontal) {
 
382
            QObject::connect(model, SIGNAL(columnsInserted(QModelIndex,int,int)),
 
383
                             this, SLOT(sectionsInserted(QModelIndex,int,int)));
 
384
            QObject::connect(model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
 
385
                             this, SLOT(sectionsAboutToBeRemoved(QModelIndex,int,int)));
 
386
            QObject::connect(model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
 
387
                             this, SLOT(_q_sectionsRemoved(QModelIndex,int,int)));
 
388
            QObject::connect(model, SIGNAL(columnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
 
389
                             this, SLOT(_q_layoutAboutToBeChanged()));
 
390
        } else {
 
391
            QObject::connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)),
 
392
                             this, SLOT(sectionsInserted(QModelIndex,int,int)));
 
393
            QObject::connect(model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
 
394
                             this, SLOT(sectionsAboutToBeRemoved(QModelIndex,int,int)));
 
395
            QObject::connect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
 
396
                             this, SLOT(_q_sectionsRemoved(QModelIndex,int,int)));
 
397
            QObject::connect(model, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
 
398
                             this, SLOT(_q_layoutAboutToBeChanged()));
 
399
        }
 
400
        QObject::connect(model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)),
 
401
                         this, SLOT(headerDataChanged(Qt::Orientation,int,int)));
 
402
        QObject::connect(model, SIGNAL(layoutAboutToBeChanged()),
 
403
                         this, SLOT(_q_layoutAboutToBeChanged()));
 
404
    }
 
405
 
 
406
    d->state = QHeaderViewPrivate::NoClear;
 
407
    QAbstractItemView::setModel(model);
 
408
    d->state = QHeaderViewPrivate::NoState;
 
409
 
 
410
    // Users want to set sizes and modes before the widget is shown.
 
411
    // Thus, we have to initialize when the model is set,
 
412
    // and not lazily like we do in the other views.
 
413
    initializeSections();
 
414
}
 
415
 
 
416
/*!
 
417
    Returns the orientation of the header.
 
418
 
 
419
    \sa Qt::Orientation
 
420
*/
 
421
 
 
422
Qt::Orientation QHeaderView::orientation() const
 
423
{
 
424
    Q_D(const QHeaderView);
 
425
    return d->orientation;
 
426
}
 
427
 
 
428
/*!
 
429
    Returns the offset of the header: this is the header's left-most (or
 
430
    top-most for vertical headers) visible pixel.
 
431
 
 
432
    \sa setOffset()
 
433
*/
 
434
 
 
435
int QHeaderView::offset() const
 
436
{
 
437
    Q_D(const QHeaderView);
 
438
    return d->offset;
 
439
}
 
440
 
 
441
/*!
 
442
    \fn void QHeaderView::setOffset(int offset)
 
443
 
 
444
    Sets the header's offset to \a offset.
 
445
 
 
446
    \sa offset(), length()
 
447
*/
 
448
 
 
449
void QHeaderView::setOffset(int newOffset)
 
450
{
 
451
    Q_D(QHeaderView);
 
452
    if (d->offset == (int)newOffset)
 
453
        return;
 
454
    int ndelta = d->offset - newOffset;
 
455
    d->offset = newOffset;
 
456
    if (d->orientation == Qt::Horizontal)
 
457
        d->viewport->scroll(isRightToLeft() ? -ndelta : ndelta, 0);
 
458
    else
 
459
        d->viewport->scroll(0, ndelta);
 
460
    if (d->state == QHeaderViewPrivate::ResizeSection && !d->preventCursorChangeInSetOffset) {
 
461
        QPoint cursorPos = QCursor::pos();
 
462
        if (d->orientation == Qt::Horizontal)
 
463
            QCursor::setPos(cursorPos.x() + ndelta, cursorPos.y());
 
464
        else
 
465
            QCursor::setPos(cursorPos.x(), cursorPos.y() + ndelta);
 
466
        d->firstPos += ndelta;
 
467
        d->lastPos += ndelta;
 
468
    }
 
469
}
 
470
 
 
471
/*!
 
472
    \since 4.2
 
473
    Sets the offset to the start of the section at the given \a visualSectionNumber.
 
474
    \a visualSectionNumber is the actual visible section when hiddenSections are
 
475
    not considered. That is not always the same as visualIndex().
 
476
 
 
477
    \sa setOffset(), sectionPosition()
 
478
*/
 
479
void QHeaderView::setOffsetToSectionPosition(int visualSectionNumber)
 
480
{
 
481
    Q_D(QHeaderView);
 
482
    if (visualSectionNumber > -1 && visualSectionNumber < d->sectionCount()) {
 
483
        int position = d->headerSectionPosition(d->adjustedVisualIndex(visualSectionNumber));
 
484
        setOffset(position);
 
485
    }
 
486
}
 
487
 
 
488
/*!
 
489
    \since 4.2
 
490
    Sets the offset to make the last section visible.
 
491
 
 
492
    \sa setOffset(), sectionPosition(), setOffsetToSectionPosition()
 
493
*/
 
494
void QHeaderView::setOffsetToLastSection()
 
495
{
 
496
    Q_D(const QHeaderView);
 
497
    int size = (d->orientation == Qt::Horizontal ? viewport()->width() : viewport()->height());
 
498
    int position = length() - size;
 
499
    setOffset(position);
 
500
}
 
501
 
 
502
/*!
 
503
    Returns the length along the orientation of the header.
 
504
 
 
505
    \sa sizeHint(), setSectionResizeMode(), offset()
 
506
*/
 
507
 
 
508
int QHeaderView::length() const
 
509
{
 
510
    Q_D(const QHeaderView);
 
511
    d->executePostedLayout();
 
512
    d->executePostedResize();
 
513
    //Q_ASSERT(d->headerLength() == d->length);
 
514
    return d->length;
 
515
}
 
516
 
 
517
/*!
 
518
    Returns a suitable size hint for this header.
 
519
 
 
520
    \sa sectionSizeHint()
 
521
*/
 
522
 
 
523
QSize QHeaderView::sizeHint() const
 
524
{
 
525
    Q_D(const QHeaderView);
 
526
    if (d->cachedSizeHint.isValid())
 
527
        return d->cachedSizeHint;
 
528
    d->cachedSizeHint = QSize(0, 0); //reinitialize the cached size hint
 
529
    const int sectionCount = count();
 
530
 
 
531
    // get size hint for the first n sections
 
532
    int i = 0;
 
533
    for (int checked = 0; checked < 100 && i < sectionCount; ++i) {
 
534
        if (isSectionHidden(i))
 
535
            continue;
 
536
        checked++;
 
537
        QSize hint = sectionSizeFromContents(i);
 
538
        d->cachedSizeHint = d->cachedSizeHint.expandedTo(hint);
 
539
    }
 
540
    // get size hint for the last n sections
 
541
    i = qMax(i, sectionCount - 100 );
 
542
    for (int j = sectionCount - 1, checked = 0; j >= i && checked < 100; --j) {
 
543
        if (isSectionHidden(j))
 
544
            continue;
 
545
        checked++;
 
546
        QSize hint = sectionSizeFromContents(j);
 
547
        d->cachedSizeHint = d->cachedSizeHint.expandedTo(hint);
 
548
    }
 
549
    return d->cachedSizeHint;
 
550
}
 
551
 
 
552
/*!
 
553
    \reimp
 
554
*/
 
555
 
 
556
void QHeaderView::setVisible(bool v)
 
557
{
 
558
    bool actualChange = (v != isVisible());
 
559
    QAbstractItemView::setVisible(v);
 
560
    if (actualChange) {
 
561
        QAbstractScrollArea *parent = qobject_cast<QAbstractScrollArea*>(parentWidget());
 
562
        if (parent)
 
563
            parent->updateGeometry();
 
564
    }
 
565
}
 
566
 
 
567
 
 
568
/*!
 
569
    Returns a suitable size hint for the section specified by \a logicalIndex.
 
570
 
 
571
    \sa sizeHint(), defaultSectionSize(), minimumSectionSize(), maximumSectionSize()
 
572
    Qt::SizeHintRole
 
573
*/
 
574
 
 
575
int QHeaderView::sectionSizeHint(int logicalIndex) const
 
576
{
 
577
    Q_D(const QHeaderView);
 
578
    if (isSectionHidden(logicalIndex))
 
579
        return 0;
 
580
    if (logicalIndex < 0 || logicalIndex >= count())
 
581
        return -1;
 
582
    QSize size;
 
583
    QVariant value = d->model->headerData(logicalIndex, d->orientation, Qt::SizeHintRole);
 
584
    if (value.isValid())
 
585
        size = qvariant_cast<QSize>(value);
 
586
    else
 
587
        size = sectionSizeFromContents(logicalIndex);
 
588
    int hint = d->orientation == Qt::Horizontal ? size.width() : size.height();
 
589
    return qBound(minimumSectionSize(), hint, maximumSectionSize());
 
590
}
 
591
 
 
592
/*!
 
593
    Returns the visual index of the section that covers the given \a position
 
594
    in the viewport.
 
595
 
 
596
    \sa logicalIndexAt()
 
597
*/
 
598
 
 
599
int QHeaderView::visualIndexAt(int position) const
 
600
{
 
601
    Q_D(const QHeaderView);
 
602
    int vposition = position;
 
603
    d->executePostedLayout();
 
604
    d->executePostedResize();
 
605
    const int count = d->sectionCount();
 
606
    if (count < 1)
 
607
        return -1;
 
608
 
 
609
    if (d->reverse())
 
610
        vposition = d->viewport->width() - vposition;
 
611
    vposition += d->offset;
 
612
 
 
613
    if (vposition > d->length)
 
614
        return -1;
 
615
    int visual = d->headerVisualIndexAt(vposition);
 
616
    if (visual < 0)
 
617
        return -1;
 
618
 
 
619
    while (d->isVisualIndexHidden(visual)){
 
620
        ++visual;
 
621
        if (visual >= count)
 
622
            return -1;
 
623
    }
 
624
    return visual;
 
625
}
 
626
 
 
627
/*!
 
628
    Returns the section that covers the given \a position in the viewport.
 
629
 
 
630
    \sa visualIndexAt(), isSectionHidden()
 
631
*/
 
632
 
 
633
int QHeaderView::logicalIndexAt(int position) const
 
634
{
 
635
    const int visual = visualIndexAt(position);
 
636
    if (visual > -1)
 
637
        return logicalIndex(visual);
 
638
    return -1;
 
639
}
 
640
 
 
641
/*!
 
642
    Returns the width (or height for vertical headers) of the given
 
643
    \a logicalIndex.
 
644
 
 
645
    \sa length(), setSectionResizeMode(), defaultSectionSize()
 
646
*/
 
647
 
 
648
int QHeaderView::sectionSize(int logicalIndex) const
 
649
{
 
650
    Q_D(const QHeaderView);
 
651
    if (isSectionHidden(logicalIndex))
 
652
        return 0;
 
653
    if (logicalIndex < 0 || logicalIndex >= count())
 
654
        return 0;
 
655
    int visual = visualIndex(logicalIndex);
 
656
    if (visual == -1)
 
657
        return 0;
 
658
    d->executePostedResize();
 
659
    return d->headerSectionSize(visual);
 
660
}
 
661
 
 
662
/*!
 
663
 
 
664
    Returns the section position of the given \a logicalIndex, or -1
 
665
    if the section is hidden. The position is measured in pixels from
 
666
    the first visible item's top-left corner to the top-left corner of
 
667
    the item with \a logicalIndex. The measurement is along the x-axis
 
668
    for horizontal headers and along the y-axis for vertical headers.
 
669
 
 
670
    \sa sectionViewportPosition()
 
671
*/
 
672
 
 
673
int QHeaderView::sectionPosition(int logicalIndex) const
 
674
{
 
675
    Q_D(const QHeaderView);
 
676
    int visual = visualIndex(logicalIndex);
 
677
    // in some cases users may change the selections
 
678
    // before we have a chance to do the layout
 
679
    if (visual == -1)
 
680
        return -1;
 
681
    d->executePostedResize();
 
682
    return d->headerSectionPosition(visual);
 
683
}
 
684
 
 
685
/*!
 
686
    Returns the section viewport position of the given \a logicalIndex.
 
687
 
 
688
    If the section is hidden, the return value is undefined.
 
689
 
 
690
    \sa sectionPosition(), isSectionHidden()
 
691
*/
 
692
 
 
693
int QHeaderView::sectionViewportPosition(int logicalIndex) const
 
694
{
 
695
    Q_D(const QHeaderView);
 
696
    if (logicalIndex >= count())
 
697
        return -1;
 
698
    int position = sectionPosition(logicalIndex);
 
699
    if (position < 0)
 
700
        return position; // the section was hidden
 
701
    int offsetPosition = position - d->offset;
 
702
    if (d->reverse())
 
703
        return d->viewport->width() - (offsetPosition + sectionSize(logicalIndex));
 
704
    return offsetPosition;
 
705
}
 
706
 
 
707
/*!
 
708
    \fn int QHeaderView::logicalIndexAt(int x, int y) const
 
709
 
 
710
    Returns the logical index of the section at the given coordinate. If the
 
711
    header is horizontal \a x will be used, otherwise \a y will be used to
 
712
    find the logical index.
 
713
*/
 
714
 
 
715
/*!
 
716
    \fn int QHeaderView::logicalIndexAt(const QPoint &pos) const
 
717
 
 
718
    Returns the logical index of the section at the position given in \a pos.
 
719
    If the header is horizontal the x-coordinate will be used, otherwise the
 
720
    y-coordinate will be used to find the logical index.
 
721
 
 
722
    \sa sectionPosition()
 
723
*/
 
724
 
 
725
template<typename Container>
 
726
static void qMoveRange(Container& c,
 
727
               typename Container::size_type rangeStart,
 
728
               typename Container::size_type rangeEnd,
 
729
               typename Container::size_type targetPosition)
 
730
{
 
731
    Q_ASSERT(targetPosition <= c.size());
 
732
    Q_ASSERT(targetPosition < rangeStart || targetPosition >= rangeEnd);
 
733
 
 
734
    const bool forwardMove = targetPosition > rangeStart;
 
735
    typename Container::size_type first = std::min(rangeStart, targetPosition);
 
736
    typename Container::size_type mid = forwardMove ? rangeEnd : rangeStart;
 
737
    typename Container::size_type last = forwardMove ? targetPosition + 1 : rangeEnd;
 
738
    std::rotate(c.begin() + first, c.begin() + mid, c.begin() + last);
 
739
}
 
740
 
 
741
/*!
 
742
    Moves the section at visual index \a from to occupy visual index \a to.
 
743
 
 
744
    \sa sectionsMoved()
 
745
*/
 
746
 
 
747
void QHeaderView::moveSection(int from, int to)
 
748
{
 
749
    Q_D(QHeaderView);
 
750
 
 
751
    d->executePostedLayout();
 
752
    if (from < 0 || from >= d->sectionCount() || to < 0 || to >= d->sectionCount())
 
753
        return;
 
754
 
 
755
    if (from == to) {
 
756
        int logical = logicalIndex(from);
 
757
        Q_ASSERT(logical != -1);
 
758
        updateSection(logical);
 
759
        return;
 
760
    }
 
761
 
 
762
    d->initializeIndexMapping();
 
763
 
 
764
    int *visualIndices = d->visualIndices.data();
 
765
    int *logicalIndices = d->logicalIndices.data();
 
766
    int logical = logicalIndices[from];
 
767
    int visual = from;
 
768
 
 
769
    if (to > from) {
 
770
        while (visual < to) {
 
771
            visualIndices[logicalIndices[visual + 1]] = visual;
 
772
            logicalIndices[visual] = logicalIndices[visual + 1];
 
773
            ++visual;
 
774
        }
 
775
    } else {
 
776
        while (visual > to) {
 
777
            visualIndices[logicalIndices[visual - 1]] = visual;
 
778
            logicalIndices[visual] = logicalIndices[visual - 1];
 
779
            --visual;
 
780
        }
 
781
    }
 
782
    visualIndices[logical] = to;
 
783
    logicalIndices[to] = logical;
 
784
 
 
785
    qMoveRange(d->sectionItems, from, from + 1, to);
 
786
 
 
787
    d->sectionStartposRecalc = true;
 
788
 
 
789
    if (d->hasAutoResizeSections())
 
790
        d->doDelayedResizeSections();
 
791
    d->viewport->update();
 
792
 
 
793
    emit sectionMoved(logical, from, to);
 
794
 
 
795
    if (stretchLastSection()) {
 
796
        const int lastSectionVisualIdx = visualIndex(d->lastSectionLogicalIdx);
 
797
        if (from >= lastSectionVisualIdx || to >= lastSectionVisualIdx)
 
798
            d->maybeRestorePrevLastSectionAndStretchLast();
 
799
    }
 
800
}
 
801
 
 
802
/*!
 
803
    \since 4.2
 
804
    Swaps the section at visual index \a first with the section at visual
 
805
    index \a second.
 
806
 
 
807
    \sa moveSection()
 
808
*/
 
809
void QHeaderView::swapSections(int first, int second)
 
810
{
 
811
    Q_D(QHeaderView);
 
812
 
 
813
    if (first == second)
 
814
        return;
 
815
    d->executePostedLayout();
 
816
    if (first < 0 || first >= d->sectionCount() || second < 0 || second >= d->sectionCount())
 
817
        return;
 
818
 
 
819
    int firstSize = d->headerSectionSize(first);
 
820
    ResizeMode firstMode = d->headerSectionResizeMode(first);
 
821
    int firstLogical = d->logicalIndex(first);
 
822
 
 
823
    int secondSize = d->headerSectionSize(second);
 
824
    ResizeMode secondMode = d->headerSectionResizeMode(second);
 
825
    int secondLogical = d->logicalIndex(second);
 
826
 
 
827
    if (d->state == QHeaderViewPrivate::ResizeSection)
 
828
        d->preventCursorChangeInSetOffset = true;
 
829
 
 
830
    d->createSectionItems(second, second, firstSize, firstMode);
 
831
    d->createSectionItems(first, first, secondSize, secondMode);
 
832
 
 
833
    d->initializeIndexMapping();
 
834
 
 
835
    d->visualIndices[firstLogical] = second;
 
836
    d->logicalIndices[second] = firstLogical;
 
837
 
 
838
    d->visualIndices[secondLogical] = first;
 
839
    d->logicalIndices[first] = secondLogical;
 
840
 
 
841
    if (!d->hiddenSectionSize.isEmpty()) {
 
842
        bool firstHidden = d->isVisualIndexHidden(first);
 
843
        bool secondHidden = d->isVisualIndexHidden(second);
 
844
        d->setVisualIndexHidden(first, secondHidden);
 
845
        d->setVisualIndexHidden(second, firstHidden);
 
846
    }
 
847
 
 
848
    d->viewport->update();
 
849
    emit sectionMoved(firstLogical, first, second);
 
850
    emit sectionMoved(secondLogical, second, first);
 
851
 
 
852
    if (stretchLastSection()) {
 
853
        const int lastSectionVisualIdx = visualIndex(d->lastSectionLogicalIdx);
 
854
        if (first >= lastSectionVisualIdx || second >= lastSectionVisualIdx)
 
855
            d->maybeRestorePrevLastSectionAndStretchLast();
 
856
    }
 
857
}
 
858
 
 
859
/*!
 
860
    \fn void QHeaderView::resizeSection(int logicalIndex, int size)
 
861
 
 
862
    Resizes the section specified by \a logicalIndex to \a size measured in
 
863
    pixels. The size parameter must be a value larger or equal to zero. A
 
864
    size equal to zero is however not recommended. In that situation hideSection
 
865
    should be used instead.
 
866
 
 
867
    \sa sectionResized(), resizeMode(), sectionSize(), hideSection()
 
868
*/
 
869
 
 
870
void QHeaderView::resizeSection(int logical, int size)
 
871
{
 
872
    Q_D(QHeaderView);
 
873
    if (logical < 0 || logical >= count() || size < 0 || size > maxSizeSection)
 
874
        return;
 
875
 
 
876
    if (isSectionHidden(logical)) {
 
877
        d->hiddenSectionSize.insert(logical, size);
 
878
        return;
 
879
    }
 
880
 
 
881
    int visual = visualIndex(logical);
 
882
    if (visual == -1)
 
883
        return;
 
884
 
 
885
    if (d->state == QHeaderViewPrivate::ResizeSection && !d->cascadingResizing && logical != d->section)
 
886
        d->preventCursorChangeInSetOffset = true;
 
887
 
 
888
    int oldSize = d->headerSectionSize(visual);
 
889
    if (oldSize == size)
 
890
        return;
 
891
 
 
892
    d->executePostedLayout();
 
893
    d->invalidateCachedSizeHint();
 
894
 
 
895
    if (stretchLastSection() && logical == d->lastSectionLogicalIdx)
 
896
        d->lastSectionSize = size;
 
897
 
 
898
    d->createSectionItems(visual, visual, size, d->headerSectionResizeMode(visual));
 
899
 
 
900
    if (!updatesEnabled()) {
 
901
        if (d->hasAutoResizeSections())
 
902
            d->doDelayedResizeSections();
 
903
        emit sectionResized(logical, oldSize, size);
 
904
        return;
 
905
    }
 
906
 
 
907
    int w = d->viewport->width();
 
908
    int h = d->viewport->height();
 
909
    int pos = sectionViewportPosition(logical);
 
910
    QRect r;
 
911
    if (d->orientation == Qt::Horizontal)
 
912
        if (isRightToLeft())
 
913
            r.setRect(0, 0, pos + size, h);
 
914
        else
 
915
            r.setRect(pos, 0, w - pos, h);
 
916
    else
 
917
        r.setRect(0, pos, w, h - pos);
 
918
 
 
919
    if (d->hasAutoResizeSections()) {
 
920
        d->doDelayedResizeSections();
 
921
        r = d->viewport->rect();
 
922
    }
 
923
 
 
924
    // If the parent is a QAbstractScrollArea with QAbstractScrollArea::AdjustToContents
 
925
    // then we want to change the geometry on that widget. Not doing it at once can/will
 
926
    // cause scrollbars flicker as they would be shown at first but then removed.
 
927
    // In the same situation it will also allow shrinking the whole view when stretchLastSection is set
 
928
    // (It is default on QTreeViews - and it wouldn't shrink since the last stretch was made before the
 
929
    // viewport was resized)
 
930
 
 
931
    QAbstractScrollArea *parent = qobject_cast<QAbstractScrollArea *>(parentWidget());
 
932
    if (parent && parent->sizeAdjustPolicy() == QAbstractScrollArea::AdjustToContents)
 
933
        parent->updateGeometry();
 
934
 
 
935
    d->viewport->update(r.normalized());
 
936
    emit sectionResized(logical, oldSize, size);
 
937
}
 
938
 
 
939
/*!
 
940
    Resizes the sections according to the given \a mode, ignoring the current
 
941
    resize mode.
 
942
 
 
943
    \sa resizeMode(), sectionResized()
 
944
*/
 
945
 
 
946
void QHeaderView::resizeSections(QHeaderView::ResizeMode mode)
 
947
{
 
948
    Q_D(QHeaderView);
 
949
    d->resizeSections(mode, true);
 
950
}
 
951
 
 
952
/*!
 
953
    \fn void QHeaderView::hideSection(int logicalIndex)
 
954
    Hides the section specified by \a logicalIndex.
 
955
 
 
956
    \sa showSection(), isSectionHidden(), hiddenSectionCount(),
 
957
    setSectionHidden()
 
958
*/
 
959
 
 
960
/*!
 
961
    \fn void QHeaderView::showSection(int logicalIndex)
 
962
    Shows the section specified by \a logicalIndex.
 
963
 
 
964
    \sa hideSection(), isSectionHidden(), hiddenSectionCount(),
 
965
    setSectionHidden()
 
966
*/
 
967
 
 
968
/*!
 
969
    Returns \c true if the section specified by \a logicalIndex is explicitly
 
970
    hidden from the user; otherwise returns \c false.
 
971
 
 
972
    \sa hideSection(), showSection(), setSectionHidden(), hiddenSectionCount()
 
973
*/
 
974
 
 
975
bool QHeaderView::isSectionHidden(int logicalIndex) const
 
976
{
 
977
    Q_D(const QHeaderView);
 
978
    d->executePostedLayout();
 
979
    if (d->hiddenSectionSize.isEmpty() || logicalIndex < 0 || logicalIndex >= d->sectionCount())
 
980
        return false;
 
981
    int visual = visualIndex(logicalIndex);
 
982
    Q_ASSERT(visual != -1);
 
983
    return d->isVisualIndexHidden(visual);
 
984
}
 
985
 
 
986
/*!
 
987
    \since 4.1
 
988
 
 
989
    Returns the number of sections in the header that has been hidden.
 
990
 
 
991
    \sa setSectionHidden(), isSectionHidden()
 
992
*/
 
993
int QHeaderView::hiddenSectionCount() const
 
994
{
 
995
    Q_D(const QHeaderView);
 
996
    return d->hiddenSectionSize.count();
 
997
}
 
998
 
 
999
/*!
 
1000
  If \a hide is true the section specified by \a logicalIndex is hidden;
 
1001
  otherwise the section is shown.
 
1002
 
 
1003
  \sa isSectionHidden(), hiddenSectionCount()
 
1004
*/
 
1005
 
 
1006
void QHeaderView::setSectionHidden(int logicalIndex, bool hide)
 
1007
{
 
1008
    Q_D(QHeaderView);
 
1009
    if (logicalIndex < 0 || logicalIndex >= count())
 
1010
        return;
 
1011
 
 
1012
    d->executePostedLayout();
 
1013
    int visual = visualIndex(logicalIndex);
 
1014
    Q_ASSERT(visual != -1);
 
1015
    if (hide == d->isVisualIndexHidden(visual))
 
1016
        return;
 
1017
    if (hide) {
 
1018
        const bool isHidingLastSection = (stretchLastSection() && logicalIndex == d->lastSectionLogicalIdx);
 
1019
        if (isHidingLastSection)
 
1020
            d->restoreSizeOnPrevLastSection(); // Restore here/now to get the right restore size.
 
1021
        int size = d->headerSectionSize(visual);
 
1022
        if (!d->hasAutoResizeSections())
 
1023
            resizeSection(logicalIndex, 0);
 
1024
        d->hiddenSectionSize.insert(logicalIndex, size);
 
1025
        d->setVisualIndexHidden(visual, true);
 
1026
        if (isHidingLastSection)
 
1027
            d->setNewLastSection(d->lastVisibleVisualIndex());
 
1028
        if (d->hasAutoResizeSections())
 
1029
            d->doDelayedResizeSections();
 
1030
    } else {
 
1031
        int size = d->hiddenSectionSize.value(logicalIndex, d->defaultSectionSize);
 
1032
        d->hiddenSectionSize.remove(logicalIndex);
 
1033
        d->setVisualIndexHidden(visual, false);
 
1034
        resizeSection(logicalIndex, size);
 
1035
 
 
1036
        const bool newLastSection = (stretchLastSection() && visual > visualIndex(d->lastSectionLogicalIdx));
 
1037
        if (newLastSection) {
 
1038
            d->restoreSizeOnPrevLastSection();
 
1039
            d->setNewLastSection(visual);
 
1040
        }
 
1041
    }
 
1042
}
 
1043
 
 
1044
/*!
 
1045
    Returns the number of sections in the header.
 
1046
 
 
1047
    \sa sectionCountChanged(), length()
 
1048
*/
 
1049
 
 
1050
int QHeaderView::count() const
 
1051
{
 
1052
    Q_D(const QHeaderView);
 
1053
    //Q_ASSERT(d->sectionCount == d->headerSectionCount());
 
1054
    // ### this may affect the lazy layout
 
1055
    d->executePostedLayout();
 
1056
    return d->sectionCount();
 
1057
}
 
1058
 
 
1059
/*!
 
1060
    Returns the visual index position of the section specified by the given
 
1061
    \a logicalIndex, or -1 otherwise.
 
1062
 
 
1063
    Hidden sections still have valid visual indexes.
 
1064
 
 
1065
    \sa logicalIndex()
 
1066
*/
 
1067
 
 
1068
int QHeaderView::visualIndex(int logicalIndex) const
 
1069
{
 
1070
    Q_D(const QHeaderView);
 
1071
    if (logicalIndex < 0)
 
1072
        return -1;
 
1073
    d->executePostedLayout();
 
1074
    if (d->visualIndices.isEmpty()) { // nothing has been moved, so we have no mapping
 
1075
        if (logicalIndex < d->sectionCount())
 
1076
            return logicalIndex;
 
1077
    } else if (logicalIndex < d->visualIndices.count()) {
 
1078
        int visual = d->visualIndices.at(logicalIndex);
 
1079
        Q_ASSERT(visual < d->sectionCount());
 
1080
        return visual;
 
1081
    }
 
1082
    return -1;
 
1083
}
 
1084
 
 
1085
/*!
 
1086
    Returns the logicalIndex for the section at the given \a visualIndex
 
1087
    position, or -1 if visualIndex < 0 or visualIndex >= QHeaderView::count().
 
1088
 
 
1089
    Note that the visualIndex is not affected by hidden sections.
 
1090
 
 
1091
    \sa visualIndex(), sectionPosition()
 
1092
*/
 
1093
 
 
1094
int QHeaderView::logicalIndex(int visualIndex) const
 
1095
{
 
1096
    Q_D(const QHeaderView);
 
1097
    if (visualIndex < 0 || visualIndex >= d->sectionCount())
 
1098
        return -1;
 
1099
    return d->logicalIndex(visualIndex);
 
1100
}
 
1101
 
 
1102
/*!
 
1103
    \since 5.0
 
1104
 
 
1105
    If \a movable is true, the header may be moved by the user; otherwise it
 
1106
    is fixed in place.
 
1107
 
 
1108
    \sa sectionsMovable(), sectionMoved()
 
1109
*/
 
1110
 
 
1111
void QHeaderView::setSectionsMovable(bool movable)
 
1112
{
 
1113
    Q_D(QHeaderView);
 
1114
    d->movableSections = movable;
 
1115
}
 
1116
 
 
1117
// ### Qt 6 - remove this obsolete function
 
1118
/*!
 
1119
    \obsolete
 
1120
    \fn void QHeaderView::setMovable(bool movable)
 
1121
 
 
1122
    Use setSectionsMovable instead.
 
1123
 
 
1124
    \sa setSectionsMovable()
 
1125
*/
 
1126
 
 
1127
/*!
 
1128
    \since 5.0
 
1129
 
 
1130
    Returns \c true if the header can be moved by the user; otherwise returns
 
1131
    false.
 
1132
 
 
1133
    \sa setSectionsMovable()
 
1134
*/
 
1135
 
 
1136
bool QHeaderView::sectionsMovable() const
 
1137
{
 
1138
    Q_D(const QHeaderView);
 
1139
    return d->movableSections;
 
1140
}
 
1141
 
 
1142
// ### Qt 6 - remove this obsolete function
 
1143
/*!
 
1144
    \obsolete
 
1145
    \fn bool QHeaderView::isMovable() const
 
1146
 
 
1147
    Use sectionsMovable instead.
 
1148
 
 
1149
    \sa sectionsMovable()
 
1150
*/
 
1151
 
 
1152
/*!
 
1153
    \since 5.0
 
1154
 
 
1155
    If \a clickable is true, the header will respond to single clicks.
 
1156
 
 
1157
    \sa sectionsClickable(), sectionClicked(), sectionPressed(),
 
1158
    setSortIndicatorShown()
 
1159
*/
 
1160
 
 
1161
void QHeaderView::setSectionsClickable(bool clickable)
 
1162
{
 
1163
    Q_D(QHeaderView);
 
1164
    d->clickableSections = clickable;
 
1165
}
 
1166
 
 
1167
// ### Qt 6 - remove this obsolete function
 
1168
/*!
 
1169
    \obsolete
 
1170
    \fn void QHeaderView::setClickable(bool clickable)
 
1171
 
 
1172
    Use setSectionsClickable instead.
 
1173
 
 
1174
    \sa setSectionsClickable()
 
1175
*/
 
1176
 
 
1177
/*!
 
1178
    \since 5.0
 
1179
 
 
1180
    Returns \c true if the header is clickable; otherwise returns \c false. A
 
1181
    clickable header could be set up to allow the user to change the
 
1182
    representation of the data in the view related to the header.
 
1183
 
 
1184
    \sa setSectionsClickable()
 
1185
*/
 
1186
 
 
1187
bool QHeaderView::sectionsClickable() const
 
1188
{
 
1189
    Q_D(const QHeaderView);
 
1190
    return d->clickableSections;
 
1191
}
 
1192
 
 
1193
// ### Qt 6 - remove this obsolete function
 
1194
/*!
 
1195
    \obsolete
 
1196
    \fn bool QHeaderView::isClickable() const
 
1197
 
 
1198
    Use sectionsClickable instead.
 
1199
 
 
1200
    \sa sectionsClickable()
 
1201
*/
 
1202
 
 
1203
void QHeaderView::setHighlightSections(bool highlight)
 
1204
{
 
1205
    Q_D(QHeaderView);
 
1206
    d->highlightSelected = highlight;
 
1207
}
 
1208
 
 
1209
bool QHeaderView::highlightSections() const
 
1210
{
 
1211
    Q_D(const QHeaderView);
 
1212
    return d->highlightSelected;
 
1213
}
 
1214
 
 
1215
/*!
 
1216
    \since 5.0
 
1217
 
 
1218
    Sets the constraints on how the header can be resized to those described
 
1219
    by the given \a mode.
 
1220
 
 
1221
    \sa resizeMode(), length(), sectionResized()
 
1222
*/
 
1223
 
 
1224
void QHeaderView::setSectionResizeMode(ResizeMode mode)
 
1225
{
 
1226
    Q_D(QHeaderView);
 
1227
    initializeSections();
 
1228
    d->stretchSections = (mode == Stretch ? count() : 0);
 
1229
    d->contentsSections =  (mode == ResizeToContents ? count() : 0);
 
1230
    d->setGlobalHeaderResizeMode(mode);
 
1231
    if (d->hasAutoResizeSections())
 
1232
        d->doDelayedResizeSections(); // section sizes may change as a result of the new mode
 
1233
}
 
1234
 
 
1235
/*!
 
1236
    \since 5.0
 
1237
 
 
1238
    Sets the constraints on how the section specified by \a logicalIndex in
 
1239
    the header can be resized to those described by the given \a mode. The logical
 
1240
    index should exist at the time this function is called.
 
1241
 
 
1242
    \note This setting will be ignored for the last section if the stretchLastSection
 
1243
    property is set to true. This is the default for the horizontal headers provided
 
1244
    by QTreeView.
 
1245
 
 
1246
    \sa setStretchLastSection(), resizeContentsPrecision()
 
1247
*/
 
1248
 
 
1249
void QHeaderView::setSectionResizeMode(int logicalIndex, ResizeMode mode)
 
1250
{
 
1251
    Q_D(QHeaderView);
 
1252
    int visual = visualIndex(logicalIndex);
 
1253
    Q_ASSERT(visual != -1);
 
1254
 
 
1255
    ResizeMode old = d->headerSectionResizeMode(visual);
 
1256
    d->setHeaderSectionResizeMode(visual, mode);
 
1257
 
 
1258
    if (mode == Stretch && old != Stretch)
 
1259
        ++d->stretchSections;
 
1260
    else if (mode == ResizeToContents && old != ResizeToContents)
 
1261
        ++d->contentsSections;
 
1262
    else if (mode != Stretch && old == Stretch)
 
1263
        --d->stretchSections;
 
1264
    else if (mode != ResizeToContents && old == ResizeToContents)
 
1265
        --d->contentsSections;
 
1266
 
 
1267
    if (d->hasAutoResizeSections() && d->state == QHeaderViewPrivate::NoState)
 
1268
        d->doDelayedResizeSections(); // section sizes may change as a result of the new mode
 
1269
}
 
1270
 
 
1271
// ### Qt 6 - remove this obsolete function
 
1272
/*!
 
1273
    \overload
 
1274
    \obsolete
 
1275
    \fn void QHeaderView::setResizeMode(int logicalIndex, ResizeMode mode)
 
1276
 
 
1277
    Use setSectionResizeMode instead.
 
1278
 
 
1279
    \sa setSectionResizeMode()
 
1280
*/
 
1281
 
 
1282
/*!
 
1283
    \obsolete
 
1284
    \fn void QHeaderView::setResizeMode(ResizeMode mode)
 
1285
 
 
1286
    Use setSectionResizeMode instead.
 
1287
 
 
1288
    \sa setSectionResizeMode()
 
1289
*/
 
1290
 
 
1291
/*!
 
1292
    \since 5.0
 
1293
 
 
1294
    Returns the resize mode that applies to the section specified by the given
 
1295
    \a logicalIndex.
 
1296
 
 
1297
    \sa setSectionResizeMode()
 
1298
*/
 
1299
 
 
1300
QHeaderView::ResizeMode QHeaderView::sectionResizeMode(int logicalIndex) const
 
1301
{
 
1302
    Q_D(const QHeaderView);
 
1303
    int visual = visualIndex(logicalIndex);
 
1304
    if (visual == -1)
 
1305
        return Fixed; //the default value
 
1306
    return d->headerSectionResizeMode(visual);
 
1307
}
 
1308
 
 
1309
/*!
 
1310
   \since 5.2
 
1311
   Sets how precise QHeaderView should calculate the size when ResizeToContents is used.
 
1312
   A low value will provide a less accurate but fast auto resize while a higher
 
1313
   value will provide a more accurate resize that however can be slow.
 
1314
 
 
1315
   The number \a precision specifies how many sections that should be consider
 
1316
   when calculating the preferred size.
 
1317
 
 
1318
   The default value is 1000 meaning that a horizontal column with auto-resize will look
 
1319
   at maximum 1000 rows on calculating when doing an auto resize.
 
1320
 
 
1321
   Special value 0 means that it will look at only the visible area.
 
1322
   Special value -1 will imply looking at all elements.
 
1323
 
 
1324
   This value is used in QTableView::sizeHintForColumn(), QTableView::sizeHintForRow()
 
1325
   and QTreeView::sizeHintForColumn(). Reimplementing these functions can make this
 
1326
   function not having an effect.
 
1327
 
 
1328
    \sa resizeContentsPrecision(), setSectionResizeMode(), resizeSections(), QTableView::sizeHintForColumn(), QTableView::sizeHintForRow(), QTreeView::sizeHintForColumn()
 
1329
*/
 
1330
 
 
1331
void QHeaderView::setResizeContentsPrecision(int precision)
 
1332
{
 
1333
    Q_D(QHeaderView);
 
1334
    d->resizeContentsPrecision = precision;
 
1335
}
 
1336
 
 
1337
/*!
 
1338
  \since 5.2
 
1339
  Returns how precise QHeaderView will calculate on ResizeToContents.
 
1340
 
 
1341
  \sa setResizeContentsPrecision(), setSectionResizeMode()
 
1342
 
 
1343
*/
 
1344
 
 
1345
int QHeaderView::resizeContentsPrecision() const
 
1346
{
 
1347
    Q_D(const QHeaderView);
 
1348
    return d->resizeContentsPrecision;
 
1349
}
 
1350
 
 
1351
// ### Qt 6 - remove this obsolete function
 
1352
/*!
 
1353
    \obsolete
 
1354
    \fn QHeaderView::ResizeMode QHeaderView::resizeMode(int logicalIndex) const
 
1355
 
 
1356
    Use sectionResizeMode instead.
 
1357
 
 
1358
    \sa sectionResizeMode()
 
1359
*/
 
1360
 
 
1361
/*!
 
1362
    \since 4.1
 
1363
 
 
1364
    Returns the number of sections that are set to resize mode stretch. In
 
1365
    views, this can be used to see if the headerview needs to resize the
 
1366
    sections when the view's geometry changes.
 
1367
 
 
1368
    \sa stretchLastSection, resizeMode()
 
1369
*/
 
1370
 
 
1371
int QHeaderView::stretchSectionCount() const
 
1372
{
 
1373
    Q_D(const QHeaderView);
 
1374
    return d->stretchSections;
 
1375
}
 
1376
 
 
1377
/*!
 
1378
  \property QHeaderView::showSortIndicator
 
1379
  \brief whether the sort indicator is shown
 
1380
 
 
1381
  By default, this property is \c false.
 
1382
 
 
1383
  \sa setSectionsClickable()
 
1384
*/
 
1385
 
 
1386
void QHeaderView::setSortIndicatorShown(bool show)
 
1387
{
 
1388
    Q_D(QHeaderView);
 
1389
    if (d->sortIndicatorShown == show)
 
1390
        return;
 
1391
 
 
1392
    d->sortIndicatorShown = show;
 
1393
 
 
1394
    if (sortIndicatorSection() < 0 || sortIndicatorSection() > count())
 
1395
        return;
 
1396
 
 
1397
    if (d->headerSectionResizeMode(sortIndicatorSection()) == ResizeToContents)
 
1398
        resizeSections();
 
1399
 
 
1400
    d->viewport->update();
 
1401
}
 
1402
 
 
1403
bool QHeaderView::isSortIndicatorShown() const
 
1404
{
 
1405
    Q_D(const QHeaderView);
 
1406
    return d->sortIndicatorShown;
 
1407
}
 
1408
 
 
1409
/*!
 
1410
    Sets the sort indicator for the section specified by the given
 
1411
    \a logicalIndex in the direction specified by \a order, and removes the
 
1412
    sort indicator from any other section that was showing it.
 
1413
 
 
1414
    \a logicalIndex may be -1, in which case no sort indicator will be shown
 
1415
    and the model will return to its natural, unsorted order. Note that not
 
1416
    all models support this and may even crash in this case.
 
1417
 
 
1418
    \sa sortIndicatorSection(), sortIndicatorOrder()
 
1419
*/
 
1420
 
 
1421
void QHeaderView::setSortIndicator(int logicalIndex, Qt::SortOrder order)
 
1422
{
 
1423
    Q_D(QHeaderView);
 
1424
 
 
1425
    // This is so that people can set the position of the sort indicator before the fill the model
 
1426
    int old = d->sortIndicatorSection;
 
1427
    if (old == logicalIndex && order == d->sortIndicatorOrder)
 
1428
        return;
 
1429
    d->sortIndicatorSection = logicalIndex;
 
1430
    d->sortIndicatorOrder = order;
 
1431
 
 
1432
    if (logicalIndex >= d->sectionCount()) {
 
1433
        emit sortIndicatorChanged(logicalIndex, order);
 
1434
        return; // nothing to do
 
1435
    }
 
1436
 
 
1437
    if (old != logicalIndex
 
1438
        && ((logicalIndex >= 0 && sectionResizeMode(logicalIndex) == ResizeToContents)
 
1439
            || old >= d->sectionCount() || (old >= 0 && sectionResizeMode(old) == ResizeToContents))) {
 
1440
        resizeSections();
 
1441
        d->viewport->update();
 
1442
    } else {
 
1443
        if (old >= 0 && old != logicalIndex)
 
1444
            updateSection(old);
 
1445
        if (logicalIndex >= 0)
 
1446
            updateSection(logicalIndex);
 
1447
    }
 
1448
 
 
1449
    emit sortIndicatorChanged(logicalIndex, order);
 
1450
}
 
1451
 
 
1452
/*!
 
1453
    Returns the logical index of the section that has a sort indicator.
 
1454
    By default this is section 0.
 
1455
 
 
1456
    \sa setSortIndicator(), sortIndicatorOrder(), setSortIndicatorShown()
 
1457
*/
 
1458
 
 
1459
int QHeaderView::sortIndicatorSection() const
 
1460
{
 
1461
    Q_D(const QHeaderView);
 
1462
    return d->sortIndicatorSection;
 
1463
}
 
1464
 
 
1465
/*!
 
1466
    Returns the order for the sort indicator. If no section has a sort
 
1467
    indicator the return value of this function is undefined.
 
1468
 
 
1469
    \sa setSortIndicator(), sortIndicatorSection()
 
1470
*/
 
1471
 
 
1472
Qt::SortOrder QHeaderView::sortIndicatorOrder() const
 
1473
{
 
1474
    Q_D(const QHeaderView);
 
1475
    return d->sortIndicatorOrder;
 
1476
}
 
1477
 
 
1478
/*!
 
1479
    \property QHeaderView::stretchLastSection
 
1480
    \brief whether the last visible section in the header takes up all the
 
1481
    available space
 
1482
 
 
1483
    The default value is false.
 
1484
 
 
1485
    \note The horizontal headers provided by QTreeView are configured with this
 
1486
    property set to true, ensuring that the view does not waste any of the
 
1487
    space assigned to it for its header. If this value is set to true, this
 
1488
    property will override the resize mode set on the last section in the
 
1489
    header.
 
1490
 
 
1491
    \sa setSectionResizeMode()
 
1492
*/
 
1493
bool QHeaderView::stretchLastSection() const
 
1494
{
 
1495
    Q_D(const QHeaderView);
 
1496
    return d->stretchLastSection;
 
1497
}
 
1498
 
 
1499
void QHeaderView::setStretchLastSection(bool stretch)
 
1500
{
 
1501
    Q_D(QHeaderView);
 
1502
    if (d->stretchLastSection == stretch)
 
1503
        return;
 
1504
    d->stretchLastSection = stretch;
 
1505
    if (d->state != QHeaderViewPrivate::NoState)
 
1506
        return;
 
1507
    if (stretch) {
 
1508
        d->setNewLastSection(d->lastVisibleVisualIndex());
 
1509
        resizeSections();
 
1510
    } else {
 
1511
        d->restoreSizeOnPrevLastSection();
 
1512
    }
 
1513
}
 
1514
 
 
1515
/*!
 
1516
    \since 4.2
 
1517
    \property QHeaderView::cascadingSectionResizes
 
1518
    \brief whether interactive resizing will be cascaded to the following
 
1519
    sections once the section being resized by the user has reached its
 
1520
    minimum size
 
1521
 
 
1522
    This property only affects sections that have \l Interactive as their
 
1523
    resize mode.
 
1524
 
 
1525
    The default value is false.
 
1526
 
 
1527
    \sa setSectionResizeMode()
 
1528
*/
 
1529
bool QHeaderView::cascadingSectionResizes() const
 
1530
{
 
1531
    Q_D(const QHeaderView);
 
1532
    return d->cascadingResizing;
 
1533
}
 
1534
 
 
1535
void QHeaderView::setCascadingSectionResizes(bool enable)
 
1536
{
 
1537
    Q_D(QHeaderView);
 
1538
    d->cascadingResizing = enable;
 
1539
}
 
1540
 
 
1541
/*!
 
1542
    \property QHeaderView::defaultSectionSize
 
1543
    \brief the default size of the header sections before resizing.
 
1544
 
 
1545
    This property only affects sections that have \l Interactive or \l Fixed
 
1546
    as their resize mode.
 
1547
 
 
1548
    By default, the value of this property is style dependent.
 
1549
    Thus, when the style changes, this property updates from it.
 
1550
    Calling setDefaultSectionSize() stops the updates, calling
 
1551
    resetDefaultSectionSize() will restore default behavior.
 
1552
 
 
1553
    \sa setSectionResizeMode(), minimumSectionSize
 
1554
*/
 
1555
int QHeaderView::defaultSectionSize() const
 
1556
{
 
1557
    Q_D(const QHeaderView);
 
1558
    return d->defaultSectionSize;
 
1559
}
 
1560
 
 
1561
void QHeaderView::setDefaultSectionSize(int size)
 
1562
{
 
1563
    Q_D(QHeaderView);
 
1564
    if (size < 0 || size > maxSizeSection)
 
1565
        return;
 
1566
    d->setDefaultSectionSize(size);
 
1567
}
 
1568
 
 
1569
void QHeaderView::resetDefaultSectionSize()
 
1570
{
 
1571
    Q_D(QHeaderView);
 
1572
    if (d->customDefaultSectionSize) {
 
1573
        d->updateDefaultSectionSizeFromStyle();
 
1574
        d->customDefaultSectionSize = false;
 
1575
    }
 
1576
}
 
1577
 
 
1578
/*!
 
1579
    \since 4.2
 
1580
    \property QHeaderView::minimumSectionSize
 
1581
    \brief the minimum size of the header sections.
 
1582
 
 
1583
    The minimum section size is the smallest section size allowed. If the
 
1584
    minimum section size is set to -1, QHeaderView will use the maximum of
 
1585
    the \l{QApplication::globalStrut()}{global strut} or the
 
1586
    \l{fontMetrics()}{font metrics} size.
 
1587
 
 
1588
    This property is honored by all \l{ResizeMode}{resize modes}.
 
1589
 
 
1590
    \sa setSectionResizeMode(), defaultSectionSize
 
1591
*/
 
1592
int QHeaderView::minimumSectionSize() const
 
1593
{
 
1594
    Q_D(const QHeaderView);
 
1595
    if (d->minimumSectionSize == -1) {
 
1596
        QSize strut = QApplication::globalStrut();
 
1597
        int margin = 2 * style()->pixelMetric(QStyle::PM_HeaderMargin, 0, this);
 
1598
        if (d->orientation == Qt::Horizontal)
 
1599
            return qMax(strut.width(), (fontMetrics().maxWidth() + margin));
 
1600
        return qMax(strut.height(), (fontMetrics().height() + margin));
 
1601
    }
 
1602
    return d->minimumSectionSize;
 
1603
}
 
1604
 
 
1605
void QHeaderView::setMinimumSectionSize(int size)
 
1606
{
 
1607
    Q_D(QHeaderView);
 
1608
    if (size < -1 || size > maxSizeSection)
 
1609
        return;
 
1610
    d->minimumSectionSize = size;
 
1611
    if (d->minimumSectionSize > maximumSectionSize())
 
1612
        d->maximumSectionSize = size;
 
1613
}
 
1614
 
 
1615
/*!
 
1616
    \since 5.2
 
1617
    \property QHeaderView::maximumSectionSize
 
1618
    \brief the maximum size of the header sections.
 
1619
 
 
1620
    The maximum section size is the largest section size allowed.
 
1621
    The default value for this property is 1048575, which is also the largest
 
1622
    possible size for a section. Setting maximum to -1 will reset the value to
 
1623
    the largest section size.
 
1624
 
 
1625
    With exception of stretch this property is honored by all \l{ResizeMode}{resize modes}
 
1626
 
 
1627
    \sa setSectionResizeMode(), defaultSectionSize
 
1628
*/
 
1629
int QHeaderView::maximumSectionSize() const
 
1630
{
 
1631
    Q_D(const QHeaderView);
 
1632
    if (d->maximumSectionSize == -1)
 
1633
        return maxSizeSection;
 
1634
    return d->maximumSectionSize;
 
1635
}
 
1636
 
 
1637
void QHeaderView::setMaximumSectionSize(int size)
 
1638
{
 
1639
    Q_D(QHeaderView);
 
1640
    if (size == -1) {
 
1641
        d->maximumSectionSize = maxSizeSection;
 
1642
        return;
 
1643
    }
 
1644
    if (size < 0 || size > maxSizeSection)
 
1645
        return;
 
1646
    if (minimumSectionSize() > size)
 
1647
        d->minimumSectionSize = size;
 
1648
 
 
1649
    d->maximumSectionSize = size;
 
1650
}
 
1651
 
 
1652
 
 
1653
/*!
 
1654
    \since 4.1
 
1655
    \property QHeaderView::defaultAlignment
 
1656
    \brief the default alignment of the text in each header section
 
1657
*/
 
1658
 
 
1659
Qt::Alignment QHeaderView::defaultAlignment() const
 
1660
{
 
1661
    Q_D(const QHeaderView);
 
1662
    return d->defaultAlignment;
 
1663
}
 
1664
 
 
1665
void QHeaderView::setDefaultAlignment(Qt::Alignment alignment)
 
1666
{
 
1667
    Q_D(QHeaderView);
 
1668
    if (d->defaultAlignment == alignment)
 
1669
        return;
 
1670
 
 
1671
    d->defaultAlignment = alignment;
 
1672
    d->viewport->update();
 
1673
}
 
1674
 
 
1675
/*!
 
1676
    \internal
 
1677
*/
 
1678
void QHeaderView::doItemsLayout()
 
1679
{
 
1680
    initializeSections();
 
1681
    QAbstractItemView::doItemsLayout();
 
1682
}
 
1683
 
 
1684
/*!
 
1685
    Returns \c true if sections in the header has been moved; otherwise returns
 
1686
    false;
 
1687
 
 
1688
    \sa moveSection()
 
1689
*/
 
1690
bool QHeaderView::sectionsMoved() const
 
1691
{
 
1692
    Q_D(const QHeaderView);
 
1693
    return !d->visualIndices.isEmpty();
 
1694
}
 
1695
 
 
1696
/*!
 
1697
    \since 4.1
 
1698
 
 
1699
    Returns \c true if sections in the header has been hidden; otherwise returns
 
1700
    false;
 
1701
 
 
1702
    \sa setSectionHidden()
 
1703
*/
 
1704
bool QHeaderView::sectionsHidden() const
 
1705
{
 
1706
    Q_D(const QHeaderView);
 
1707
    return !d->hiddenSectionSize.isEmpty();
 
1708
}
 
1709
 
 
1710
#ifndef QT_NO_DATASTREAM
 
1711
/*!
 
1712
    \since 4.3
 
1713
 
 
1714
    Saves the current state of this header view.
 
1715
 
 
1716
    To restore the saved state, pass the return value to restoreState().
 
1717
 
 
1718
    \sa restoreState()
 
1719
*/
 
1720
QByteArray QHeaderView::saveState() const
 
1721
{
 
1722
    Q_D(const QHeaderView);
 
1723
    QByteArray data;
 
1724
    QDataStream stream(&data, QIODevice::WriteOnly);
 
1725
    stream << QHeaderViewPrivate::VersionMarker;
 
1726
    stream << 0; // current version is 0
 
1727
    d->write(stream);
 
1728
    return data;
 
1729
}
 
1730
 
 
1731
/*!
 
1732
    \since 4.3
 
1733
    Restores the \a state of this header view.
 
1734
    This function returns \c true if the state was restored; otherwise returns
 
1735
    false.
 
1736
 
 
1737
    \sa saveState()
 
1738
*/
 
1739
bool QHeaderView::restoreState(const QByteArray &state)
 
1740
{
 
1741
    Q_D(QHeaderView);
 
1742
    if (state.isEmpty())
 
1743
        return false;
 
1744
    QByteArray data = state;
 
1745
    QDataStream stream(&data, QIODevice::ReadOnly);
 
1746
    int marker;
 
1747
    int ver;
 
1748
    stream >> marker;
 
1749
    stream >> ver;
 
1750
    if (stream.status() != QDataStream::Ok
 
1751
        || marker != QHeaderViewPrivate::VersionMarker
 
1752
        || ver != 0) // current version is 0
 
1753
        return false;
 
1754
 
 
1755
    if (d->read(stream)) {
 
1756
        emit sortIndicatorChanged(d->sortIndicatorSection, d->sortIndicatorOrder );
 
1757
        d->viewport->update();
 
1758
        return true;
 
1759
    }
 
1760
    return false;
 
1761
}
 
1762
#endif // QT_NO_DATASTREAM
 
1763
 
 
1764
/*!
 
1765
  \reimp
 
1766
*/
 
1767
void QHeaderView::reset()
 
1768
{
 
1769
    QAbstractItemView::reset();
 
1770
    // it would be correct to call clear, but some apps rely
 
1771
    // on the header keeping the sections, even after calling reset
 
1772
    //d->clear();
 
1773
    initializeSections();
 
1774
}
 
1775
 
 
1776
/*!
 
1777
    Updates the changed header sections with the given \a orientation, from
 
1778
    \a logicalFirst to \a logicalLast inclusive.
 
1779
*/
 
1780
void QHeaderView::headerDataChanged(Qt::Orientation orientation, int logicalFirst, int logicalLast)
 
1781
{
 
1782
    Q_D(QHeaderView);
 
1783
    if (d->orientation != orientation)
 
1784
        return;
 
1785
 
 
1786
    if (logicalFirst < 0 || logicalLast < 0 || logicalFirst >= count() || logicalLast >= count())
 
1787
        return;
 
1788
 
 
1789
    d->invalidateCachedSizeHint();
 
1790
 
 
1791
    int firstVisualIndex = INT_MAX, lastVisualIndex = -1;
 
1792
 
 
1793
    for (int section = logicalFirst; section <= logicalLast; ++section) {
 
1794
        const int visual = visualIndex(section);
 
1795
        firstVisualIndex = qMin(firstVisualIndex, visual);
 
1796
        lastVisualIndex =  qMax(lastVisualIndex,  visual);
 
1797
    }
 
1798
 
 
1799
    d->executePostedResize();
 
1800
    const int first = d->headerSectionPosition(firstVisualIndex),
 
1801
              last = d->headerSectionPosition(lastVisualIndex)
 
1802
                        + d->headerSectionSize(lastVisualIndex);
 
1803
 
 
1804
    if (orientation == Qt::Horizontal) {
 
1805
        d->viewport->update(first, 0, last - first, d->viewport->height());
 
1806
    } else {
 
1807
        d->viewport->update(0, first, d->viewport->width(), last - first);
 
1808
    }
 
1809
}
 
1810
 
 
1811
/*!
 
1812
    \internal
 
1813
    \since 4.2
 
1814
 
 
1815
    Updates the section specified by the given \a logicalIndex.
 
1816
*/
 
1817
 
 
1818
void QHeaderView::updateSection(int logicalIndex)
 
1819
{
 
1820
    Q_D(QHeaderView);
 
1821
    if (d->orientation == Qt::Horizontal)
 
1822
        d->viewport->update(QRect(sectionViewportPosition(logicalIndex),
 
1823
                                  0, sectionSize(logicalIndex), d->viewport->height()));
 
1824
    else
 
1825
        d->viewport->update(QRect(0, sectionViewportPosition(logicalIndex),
 
1826
                                  d->viewport->width(), sectionSize(logicalIndex)));
 
1827
}
 
1828
 
 
1829
/*!
 
1830
    Resizes the sections according to their size hints. Normally, you do not
 
1831
    have to call this function.
 
1832
*/
 
1833
 
 
1834
void QHeaderView::resizeSections()
 
1835
{
 
1836
    Q_D(QHeaderView);
 
1837
    if (d->hasAutoResizeSections())
 
1838
        d->resizeSections(Interactive, false); // no global resize mode
 
1839
}
 
1840
 
 
1841
/*!
 
1842
    This slot is called when sections are inserted into the \a parent.
 
1843
    \a logicalFirst and \a logicalLast indices signify where the new sections
 
1844
    were inserted.
 
1845
 
 
1846
    If only one section is inserted, \a logicalFirst and \a logicalLast will
 
1847
    be the same.
 
1848
*/
 
1849
 
 
1850
void QHeaderView::sectionsInserted(const QModelIndex &parent,
 
1851
                                   int logicalFirst, int logicalLast)
 
1852
{
 
1853
    Q_D(QHeaderView);
 
1854
    if (parent != d->root)
 
1855
        return; // we only handle changes in the root level
 
1856
    int oldCount = d->sectionCount();
 
1857
 
 
1858
    d->invalidateCachedSizeHint();
 
1859
 
 
1860
    if (d->state == QHeaderViewPrivate::ResizeSection)
 
1861
        d->preventCursorChangeInSetOffset = true;
 
1862
 
 
1863
    // add the new sections
 
1864
    int insertAt = logicalFirst;
 
1865
    int insertCount = logicalLast - logicalFirst + 1;
 
1866
 
 
1867
    bool lastSectionActualChange = false;
 
1868
    if (stretchLastSection()) {
 
1869
 
 
1870
        int visualIndexForStretch = d->lastSectionLogicalIdx;
 
1871
        if (d->lastSectionLogicalIdx >= 0 && d->lastSectionLogicalIdx < d->visualIndices.size())
 
1872
            visualIndexForStretch = d->visualIndices[d->lastSectionLogicalIdx]; // We cannot call visualIndex since it executes executePostedLayout()
 
1873
                                                                                // and it is likely to bypass initializeSections() and we may end up here again. Doing the insert twice.
 
1874
 
 
1875
        if (d->lastSectionLogicalIdx < 0 || insertAt >= visualIndexForStretch)
 
1876
            lastSectionActualChange = true;
 
1877
 
 
1878
        if (d->lastSectionLogicalIdx >= logicalFirst)
 
1879
            d->lastSectionLogicalIdx += insertCount; // We do not want to emit resize before we have fixed the count
 
1880
    }
 
1881
 
 
1882
    QHeaderViewPrivate::SectionItem section(d->defaultSectionSize, d->globalResizeMode);
 
1883
    d->sectionStartposRecalc = true;
 
1884
 
 
1885
    if (d->sectionItems.isEmpty() || insertAt >= d->sectionItems.count()) {
 
1886
        int insertLength = d->defaultSectionSize * insertCount;
 
1887
        d->length += insertLength;
 
1888
        d->sectionItems.insert(d->sectionItems.count(), insertCount, section); // append
 
1889
    } else {
 
1890
        // separate them out into their own sections
 
1891
        int insertLength = d->defaultSectionSize * insertCount;
 
1892
        d->length += insertLength;
 
1893
        d->sectionItems.insert(insertAt, insertCount, section);
 
1894
    }
 
1895
 
 
1896
    // update sorting column
 
1897
    if (d->sortIndicatorSection >= logicalFirst)
 
1898
        d->sortIndicatorSection += insertCount;
 
1899
 
 
1900
    // update resize mode section counts
 
1901
    if (d->globalResizeMode == Stretch)
 
1902
        d->stretchSections = d->sectionCount();
 
1903
    else if (d->globalResizeMode == ResizeToContents)
 
1904
        d->contentsSections = d->sectionCount();
 
1905
 
 
1906
    // clear selection cache
 
1907
    d->sectionSelected.clear();
 
1908
 
 
1909
    // update mapping
 
1910
    if (!d->visualIndices.isEmpty() && !d->logicalIndices.isEmpty()) {
 
1911
        Q_ASSERT(d->visualIndices.count() == d->logicalIndices.count());
 
1912
        int mappingCount = d->visualIndices.count();
 
1913
        for (int i = 0; i < mappingCount; ++i) {
 
1914
            if (d->visualIndices.at(i) >= logicalFirst)
 
1915
               d->visualIndices[i] += insertCount;
 
1916
            if (d->logicalIndices.at(i) >= logicalFirst)
 
1917
                d->logicalIndices[i] += insertCount;
 
1918
        }
 
1919
        for (int j = logicalFirst; j <= logicalLast; ++j) {
 
1920
            d->visualIndices.insert(j, j);
 
1921
            d->logicalIndices.insert(j, j);
 
1922
        }
 
1923
    }
 
1924
 
 
1925
    // insert sections into hiddenSectionSize
 
1926
    QHash<int, int> newHiddenSectionSize; // from logical index to section size
 
1927
    for (QHash<int, int>::const_iterator it = d->hiddenSectionSize.cbegin(),
 
1928
         end = d->hiddenSectionSize.cend(); it != end; ++it) {
 
1929
        const int oldIndex = it.key();
 
1930
        const int newIndex = (oldIndex < logicalFirst) ? oldIndex : oldIndex + insertCount;
 
1931
        newHiddenSectionSize[newIndex] = it.value();
 
1932
    }
 
1933
    d->hiddenSectionSize.swap(newHiddenSectionSize);
 
1934
 
 
1935
    d->doDelayedResizeSections();
 
1936
    emit sectionCountChanged(oldCount, count());
 
1937
 
 
1938
    if (lastSectionActualChange)
 
1939
        d->maybeRestorePrevLastSectionAndStretchLast();
 
1940
 
 
1941
    // if the new sections were not updated by resizing, we need to update now
 
1942
    if (!d->hasAutoResizeSections())
 
1943
        d->viewport->update();
 
1944
}
 
1945
 
 
1946
/*!
 
1947
    This slot is called when sections are removed from the \a parent.
 
1948
    \a logicalFirst and \a logicalLast signify where the sections were removed.
 
1949
 
 
1950
    If only one section is removed, \a logicalFirst and \a logicalLast will
 
1951
    be the same.
 
1952
*/
 
1953
 
 
1954
void QHeaderView::sectionsAboutToBeRemoved(const QModelIndex &parent,
 
1955
                                           int logicalFirst, int logicalLast)
 
1956
{
 
1957
    Q_UNUSED(parent);
 
1958
    Q_UNUSED(logicalFirst);
 
1959
    Q_UNUSED(logicalLast);
 
1960
}
 
1961
 
 
1962
void QHeaderViewPrivate::updateHiddenSections(int logicalFirst, int logicalLast)
 
1963
{
 
1964
    Q_Q(QHeaderView);
 
1965
    const int changeCount = logicalLast - logicalFirst + 1;
 
1966
 
 
1967
    // remove sections from hiddenSectionSize
 
1968
    QHash<int, int> newHiddenSectionSize; // from logical index to section size
 
1969
    for (int i = 0; i < logicalFirst; ++i)
 
1970
        if (q->isSectionHidden(i))
 
1971
            newHiddenSectionSize[i] = hiddenSectionSize[i];
 
1972
    for (int j = logicalLast + 1; j < sectionCount(); ++j)
 
1973
        if (q->isSectionHidden(j))
 
1974
            newHiddenSectionSize[j - changeCount] = hiddenSectionSize[j];
 
1975
    hiddenSectionSize = newHiddenSectionSize;
 
1976
}
 
1977
 
 
1978
void QHeaderViewPrivate::_q_sectionsRemoved(const QModelIndex &parent,
 
1979
                                            int logicalFirst, int logicalLast)
 
1980
{
 
1981
    Q_Q(QHeaderView);
 
1982
    if (parent != root)
 
1983
        return; // we only handle changes in the root level
 
1984
    if (qMin(logicalFirst, logicalLast) < 0
 
1985
        || qMax(logicalLast, logicalFirst) >= sectionCount())
 
1986
        return;
 
1987
    int oldCount = q->count();
 
1988
    int changeCount = logicalLast - logicalFirst + 1;
 
1989
 
 
1990
    if (state == QHeaderViewPrivate::ResizeSection)
 
1991
        preventCursorChangeInSetOffset = true;
 
1992
 
 
1993
    updateHiddenSections(logicalFirst, logicalLast);
 
1994
 
 
1995
    if (visualIndices.isEmpty() && logicalIndices.isEmpty()) {
 
1996
        //Q_ASSERT(headerSectionCount() == sectionCount);
 
1997
        removeSectionsFromSectionItems(logicalFirst, logicalLast);
 
1998
    } else {
 
1999
        if (logicalFirst == logicalLast) { // Remove just one index.
 
2000
            int l = logicalFirst;
 
2001
            int visual = visualIndices.at(l);
 
2002
            Q_ASSERT(sectionCount() == logicalIndices.count());
 
2003
            for (int v = 0; v < sectionCount(); ++v) {
 
2004
                if (v > visual) {
 
2005
                    int logical = logicalIndices.at(v);
 
2006
                    --(visualIndices[logical]);
 
2007
                }
 
2008
                if (logicalIndex(v) > l) // no need to move the positions before l
 
2009
                    --(logicalIndices[v]);
 
2010
            }
 
2011
            logicalIndices.remove(visual);
 
2012
            visualIndices.remove(l);
 
2013
            //Q_ASSERT(headerSectionCount() == sectionCount);
 
2014
            removeSectionsFromSectionItems(visual, visual);
 
2015
        } else {
 
2016
            sectionStartposRecalc = true; // We will need to recalc positions after removing items
 
2017
            for (int u = 0; u < sectionItems.count(); ++u)  // Store section info
 
2018
                sectionItems.at(u).tmpLogIdx = logicalIndices.at(u);
 
2019
            for (int v = sectionItems.count() - 1; v >= 0; --v) {  // Remove the sections
 
2020
                if (logicalFirst <= sectionItems.at(v).tmpLogIdx && sectionItems.at(v).tmpLogIdx <= logicalLast)
 
2021
                    removeSectionsFromSectionItems(v, v);
 
2022
            }
 
2023
            visualIndices.resize(sectionItems.count());
 
2024
            logicalIndices.resize(sectionItems.count());
 
2025
            int* visual_data = visualIndices.data();
 
2026
            int* logical_data = logicalIndices.data();
 
2027
            for (int w = 0; w < sectionItems.count(); ++w) { // Restore visual and logical indexes
 
2028
                int logindex = sectionItems.at(w).tmpLogIdx;
 
2029
                if (logindex > logicalFirst)
 
2030
                    logindex -= changeCount;
 
2031
                visual_data[logindex] = w;
 
2032
                logical_data[w] = logindex;
 
2033
            }
 
2034
        }
 
2035
        // ### handle sectionSelection (sectionHidden is handled by updateHiddenSections)
 
2036
    }
 
2037
 
 
2038
    // update sorting column
 
2039
    if (sortIndicatorSection >= logicalFirst) {
 
2040
        if (sortIndicatorSection <= logicalLast)
 
2041
            sortIndicatorSection = -1;
 
2042
        else
 
2043
            sortIndicatorSection -= changeCount;
 
2044
    }
 
2045
 
 
2046
    // if we only have the last section (the "end" position) left, the header is empty
 
2047
    if (sectionCount() <= 0)
 
2048
        clear();
 
2049
    invalidateCachedSizeHint();
 
2050
    emit q->sectionCountChanged(oldCount, q->count());
 
2051
 
 
2052
    if (q->stretchLastSection()) {
 
2053
        const bool lastSectionRemoved = lastSectionLogicalIdx >= logicalFirst && lastSectionLogicalIdx <= logicalLast;
 
2054
        if (lastSectionRemoved)
 
2055
            setNewLastSection(lastVisibleVisualIndex());
 
2056
        else
 
2057
            lastSectionLogicalIdx = logicalIndex(lastVisibleVisualIndex()); // Just update the last log index.
 
2058
        doDelayedResizeSections();
 
2059
    }
 
2060
 
 
2061
    viewport->update();
 
2062
}
 
2063
 
 
2064
void QHeaderViewPrivate::_q_layoutAboutToBeChanged()
 
2065
{
 
2066
    //if there is no row/column we can't have mapping for columns
 
2067
    //because no QModelIndex in the model would be valid
 
2068
    // ### this is far from being bullet-proof and we would need a real system to
 
2069
    // ### map columns or rows persistently
 
2070
    if ((orientation == Qt::Horizontal && model->rowCount(root) == 0)
 
2071
        || model->columnCount(root) == 0)
 
2072
        return;
 
2073
 
 
2074
    if (hiddenSectionSize.count() == 0)
 
2075
        return;
 
2076
 
 
2077
    for (int i = 0; i < sectionItems.count(); ++i)
 
2078
        if (isVisualIndexHidden(i)) // ### note that we are using column or row 0
 
2079
            persistentHiddenSections.append(orientation == Qt::Horizontal
 
2080
                                            ? model->index(0, logicalIndex(i), root)
 
2081
                                            : model->index(logicalIndex(i), 0, root));
 
2082
}
 
2083
 
 
2084
void QHeaderViewPrivate::_q_layoutChanged()
 
2085
{
 
2086
    Q_Q(QHeaderView);
 
2087
    viewport->update();
 
2088
    if (persistentHiddenSections.isEmpty() || modelIsEmpty()) {
 
2089
        if (modelSectionCount() != sectionCount())
 
2090
            q->initializeSections();
 
2091
        persistentHiddenSections.clear();
 
2092
        return;
 
2093
    }
 
2094
 
 
2095
    QBitArray oldSectionHidden = sectionsHiddenToBitVector();
 
2096
    oldSectionHidden.resize(sectionItems.size());
 
2097
    bool sectionCountChanged = false;
 
2098
 
 
2099
    for (int i = 0; i < persistentHiddenSections.count(); ++i) {
 
2100
        QModelIndex index = persistentHiddenSections.at(i);
 
2101
        if (index.isValid()) {
 
2102
            const int logical = (orientation == Qt::Horizontal
 
2103
                                 ? index.column()
 
2104
                                 : index.row());
 
2105
            q->setSectionHidden(logical, true);
 
2106
            oldSectionHidden.setBit(logical, false);
 
2107
        } else if (!sectionCountChanged && (modelSectionCount() != sectionCount())) {
 
2108
            sectionCountChanged = true;
 
2109
            break;
 
2110
        }
 
2111
    }
 
2112
    persistentHiddenSections.clear();
 
2113
 
 
2114
    for (int i = 0; i < oldSectionHidden.count(); ++i) {
 
2115
        if (oldSectionHidden.testBit(i))
 
2116
            q->setSectionHidden(i, false);
 
2117
    }
 
2118
 
 
2119
    // the number of sections changed; we need to reread the state of the model
 
2120
    if (sectionCountChanged)
 
2121
        q->initializeSections();
 
2122
}
 
2123
 
 
2124
/*!
 
2125
  \internal
 
2126
*/
 
2127
 
 
2128
void QHeaderView::initializeSections()
 
2129
{
 
2130
    Q_D(QHeaderView);
 
2131
    const int oldCount = d->sectionCount();
 
2132
    const int newCount = d->modelSectionCount();
 
2133
    if (newCount <= 0) {
 
2134
            d->clear();
 
2135
            emit sectionCountChanged(oldCount, 0);
 
2136
    } else if (newCount != oldCount) {
 
2137
        const int min = qBound(0, oldCount, newCount - 1);
 
2138
        initializeSections(min, newCount - 1);
 
2139
        if (stretchLastSection())   // we've already gotten the size hint
 
2140
            d->maybeRestorePrevLastSectionAndStretchLast();
 
2141
 
 
2142
        //make sure we update the hidden sections
 
2143
        if (newCount < oldCount)
 
2144
            d->updateHiddenSections(0, newCount-1);
 
2145
    }
 
2146
}
 
2147
 
 
2148
/*!
 
2149
    \internal
 
2150
*/
 
2151
 
 
2152
void QHeaderView::initializeSections(int start, int end)
 
2153
{
 
2154
    Q_D(QHeaderView);
 
2155
 
 
2156
    Q_ASSERT(start >= 0);
 
2157
    Q_ASSERT(end >= 0);
 
2158
 
 
2159
    d->invalidateCachedSizeHint();
 
2160
    int oldCount = d->sectionCount();
 
2161
 
 
2162
    if (end + 1 < d->sectionCount()) {
 
2163
        int newCount = end + 1;
 
2164
        d->removeSectionsFromSectionItems(newCount, d->sectionCount() - 1);
 
2165
        if (!d->hiddenSectionSize.isEmpty()) {
 
2166
            if (oldCount - newCount > d->hiddenSectionSize.count()) {
 
2167
                for (int i = end + 1; i < d->sectionCount(); ++i)
 
2168
                    d->hiddenSectionSize.remove(i);
 
2169
            } else {
 
2170
                QHash<int, int>::iterator it = d->hiddenSectionSize.begin();
 
2171
                while (it != d->hiddenSectionSize.end()) {
 
2172
                    if (it.key() > end)
 
2173
                        it = d->hiddenSectionSize.erase(it);
 
2174
                    else
 
2175
                        ++it;
 
2176
                }
 
2177
            }
 
2178
        }
 
2179
    }
 
2180
 
 
2181
    int newSectionCount = end + 1;
 
2182
 
 
2183
    if (!d->logicalIndices.isEmpty()) {
 
2184
        if (oldCount <= newSectionCount) {
 
2185
            d->logicalIndices.resize(newSectionCount);
 
2186
            d->visualIndices.resize(newSectionCount);
 
2187
            for (int i = oldCount; i < newSectionCount; ++i) {
 
2188
                d->logicalIndices[i] = i;
 
2189
                d->visualIndices[i] = i;
 
2190
            }
 
2191
        } else {
 
2192
            int j = 0;
 
2193
            for (int i = 0; i < oldCount; ++i) {
 
2194
                int v = d->logicalIndices.at(i);
 
2195
                if (v < newSectionCount) {
 
2196
                    d->logicalIndices[j] = v;
 
2197
                    d->visualIndices[v] = j;
 
2198
                    j++;
 
2199
                }
 
2200
            }
 
2201
            d->logicalIndices.resize(newSectionCount);
 
2202
            d->visualIndices.resize(newSectionCount);
 
2203
        }
 
2204
    }
 
2205
 
 
2206
    if (d->globalResizeMode == Stretch)
 
2207
        d->stretchSections = newSectionCount;
 
2208
    else if (d->globalResizeMode == ResizeToContents)
 
2209
         d->contentsSections = newSectionCount;
 
2210
 
 
2211
    if (newSectionCount > oldCount)
 
2212
        d->createSectionItems(start, end, (end - start + 1) * d->defaultSectionSize, d->globalResizeMode);
 
2213
    //Q_ASSERT(d->headerLength() == d->length);
 
2214
 
 
2215
    if (d->sectionCount() != oldCount)
 
2216
        emit sectionCountChanged(oldCount,  d->sectionCount());
 
2217
    d->viewport->update();
 
2218
}
 
2219
 
 
2220
/*!
 
2221
  \reimp
 
2222
*/
 
2223
 
 
2224
void QHeaderView::currentChanged(const QModelIndex &current, const QModelIndex &old)
 
2225
{
 
2226
    Q_D(QHeaderView);
 
2227
 
 
2228
    if (d->orientation == Qt::Horizontal && current.column() != old.column()) {
 
2229
        if (old.isValid() && old.parent() == d->root)
 
2230
            d->viewport->update(QRect(sectionViewportPosition(old.column()), 0,
 
2231
                                    sectionSize(old.column()), d->viewport->height()));
 
2232
        if (current.isValid() && current.parent() == d->root)
 
2233
            d->viewport->update(QRect(sectionViewportPosition(current.column()), 0,
 
2234
                                    sectionSize(current.column()), d->viewport->height()));
 
2235
    } else if (d->orientation == Qt::Vertical && current.row() != old.row()) {
 
2236
        if (old.isValid() && old.parent() == d->root)
 
2237
            d->viewport->update(QRect(0, sectionViewportPosition(old.row()),
 
2238
                                    d->viewport->width(), sectionSize(old.row())));
 
2239
        if (current.isValid() && current.parent() == d->root)
 
2240
            d->viewport->update(QRect(0, sectionViewportPosition(current.row()),
 
2241
                                    d->viewport->width(), sectionSize(current.row())));
 
2242
    }
 
2243
}
 
2244
 
 
2245
 
 
2246
/*!
 
2247
  \reimp
 
2248
*/
 
2249
 
 
2250
bool QHeaderView::event(QEvent *e)
 
2251
{
 
2252
    Q_D(QHeaderView);
 
2253
    switch (e->type()) {
 
2254
    case QEvent::HoverEnter: {
 
2255
        QHoverEvent *he = static_cast<QHoverEvent*>(e);
 
2256
        d->hover = logicalIndexAt(he->pos());
 
2257
        if (d->hover != -1)
 
2258
            updateSection(d->hover);
 
2259
        break; }
 
2260
    case QEvent::Leave:
 
2261
    case QEvent::HoverLeave: {
 
2262
        if (d->hover != -1)
 
2263
            updateSection(d->hover);
 
2264
        d->hover = -1;
 
2265
        break; }
 
2266
    case QEvent::HoverMove: {
 
2267
        QHoverEvent *he = static_cast<QHoverEvent*>(e);
 
2268
        int oldHover = d->hover;
 
2269
        d->hover = logicalIndexAt(he->pos());
 
2270
        if (d->hover != oldHover) {
 
2271
            if (oldHover != -1)
 
2272
                updateSection(oldHover);
 
2273
            if (d->hover != -1)
 
2274
                updateSection(d->hover);
 
2275
        }
 
2276
        break; }
 
2277
    case QEvent::Timer: {
 
2278
        QTimerEvent *te = static_cast<QTimerEvent*>(e);
 
2279
        if (te->timerId() == d->delayedResize.timerId()) {
 
2280
            d->delayedResize.stop();
 
2281
            resizeSections();
 
2282
        }
 
2283
        break; }
 
2284
    case QEvent::StyleChange:
 
2285
        if (!d->customDefaultSectionSize)
 
2286
            d->updateDefaultSectionSizeFromStyle();
 
2287
        break;
 
2288
    default:
 
2289
        break;
 
2290
    }
 
2291
    return QAbstractItemView::event(e);
 
2292
}
 
2293
 
 
2294
/*!
 
2295
  \reimp
 
2296
*/
 
2297
 
 
2298
void QHeaderView::paintEvent(QPaintEvent *e)
 
2299
{
 
2300
    Q_D(QHeaderView);
 
2301
 
 
2302
    if (count() == 0)
 
2303
        return;
 
2304
 
 
2305
    QPainter painter(d->viewport);
 
2306
    const QPoint offset = d->scrollDelayOffset;
 
2307
    QRect translatedEventRect = e->rect();
 
2308
    translatedEventRect.translate(offset);
 
2309
 
 
2310
    int start = -1;
 
2311
    int end = -1;
 
2312
    if (d->orientation == Qt::Horizontal) {
 
2313
        start = visualIndexAt(translatedEventRect.left());
 
2314
        end = visualIndexAt(translatedEventRect.right());
 
2315
    } else {
 
2316
        start = visualIndexAt(translatedEventRect.top());
 
2317
        end = visualIndexAt(translatedEventRect.bottom());
 
2318
    }
 
2319
 
 
2320
    if (d->reverse()) {
 
2321
        start = (start == -1 ? count() - 1 : start);
 
2322
        end = (end == -1 ? 0 : end);
 
2323
    } else {
 
2324
        start = (start == -1 ? 0 : start);
 
2325
        end = (end == -1 ? count() - 1 : end);
 
2326
    }
 
2327
 
 
2328
    int tmp = start;
 
2329
    start = qMin(start, end);
 
2330
    end = qMax(tmp, end);
 
2331
 
 
2332
    d->prepareSectionSelected(); // clear and resize the bit array
 
2333
 
 
2334
    QRect currentSectionRect;
 
2335
    int logical;
 
2336
    const int width = d->viewport->width();
 
2337
    const int height = d->viewport->height();
 
2338
    for (int i = start; i <= end; ++i) {
 
2339
        if (d->isVisualIndexHidden(i))
 
2340
            continue;
 
2341
        painter.save();
 
2342
        logical = logicalIndex(i);
 
2343
        if (d->orientation == Qt::Horizontal) {
 
2344
            currentSectionRect.setRect(sectionViewportPosition(logical), 0, sectionSize(logical), height);
 
2345
        } else {
 
2346
            currentSectionRect.setRect(0, sectionViewportPosition(logical), width, sectionSize(logical));
 
2347
        }
 
2348
        currentSectionRect.translate(offset);
 
2349
 
 
2350
        QVariant variant = d->model->headerData(logical, d->orientation,
 
2351
                                                Qt::FontRole);
 
2352
        if (variant.isValid() && variant.canConvert<QFont>()) {
 
2353
            QFont sectionFont = qvariant_cast<QFont>(variant);
 
2354
            painter.setFont(sectionFont);
 
2355
        }
 
2356
        paintSection(&painter, currentSectionRect, logical);
 
2357
        painter.restore();
 
2358
    }
 
2359
 
 
2360
    QStyleOption opt;
 
2361
    opt.init(this);
 
2362
    // Paint the area beyond where there are indexes
 
2363
    if (d->reverse()) {
 
2364
        opt.state |= QStyle::State_Horizontal;
 
2365
        if (currentSectionRect.left() > translatedEventRect.left()) {
 
2366
            opt.rect = QRect(translatedEventRect.left(), 0,
 
2367
                             currentSectionRect.left() - translatedEventRect.left(), height);
 
2368
            style()->drawControl(QStyle::CE_HeaderEmptyArea, &opt, &painter, this);
 
2369
        }
 
2370
    } else if (currentSectionRect.right() < translatedEventRect.right()) {
 
2371
        // paint to the right
 
2372
        opt.state |= QStyle::State_Horizontal;
 
2373
        opt.rect = QRect(currentSectionRect.right() + 1, 0,
 
2374
                         translatedEventRect.right() - currentSectionRect.right(), height);
 
2375
        style()->drawControl(QStyle::CE_HeaderEmptyArea, &opt, &painter, this);
 
2376
    } else if (currentSectionRect.bottom() < translatedEventRect.bottom()) {
 
2377
        // paint the bottom section
 
2378
        opt.state &= ~QStyle::State_Horizontal;
 
2379
        opt.rect = QRect(0, currentSectionRect.bottom() + 1,
 
2380
                         width, height - currentSectionRect.bottom() - 1);
 
2381
        style()->drawControl(QStyle::CE_HeaderEmptyArea, &opt, &painter, this);
 
2382
    }
 
2383
 
 
2384
#if 0
 
2385
    // ### visualize sections
 
2386
    for (int a = 0, i = 0; i < d->sectionItems.count(); ++i) {
 
2387
        QColor color((i & 4 ? 255 : 0), (i & 2 ? 255 : 0), (i & 1 ? 255 : 0));
 
2388
        if (d->orientation == Qt::Horizontal)
 
2389
            painter.fillRect(a - d->offset, 0, d->sectionItems.at(i).size, 4, color);
 
2390
        else
 
2391
            painter.fillRect(0, a - d->offset, 4, d->sectionItems.at(i).size, color);
 
2392
        a += d->sectionItems.at(i).size;
 
2393
    }
 
2394
 
 
2395
#endif
 
2396
}
 
2397
 
 
2398
/*!
 
2399
  \reimp
 
2400
*/
 
2401
 
 
2402
void QHeaderView::mousePressEvent(QMouseEvent *e)
 
2403
{
 
2404
    Q_D(QHeaderView);
 
2405
    if (d->state != QHeaderViewPrivate::NoState || e->button() != Qt::LeftButton)
 
2406
        return;
 
2407
    int pos = d->orientation == Qt::Horizontal ? e->x() : e->y();
 
2408
    int handle = d->sectionHandleAt(pos);
 
2409
    d->originalSize = -1; // clear the stored original size
 
2410
    if (handle == -1) {
 
2411
        d->pressed = logicalIndexAt(pos);
 
2412
        if (d->clickableSections)
 
2413
            emit sectionPressed(d->pressed);
 
2414
 
 
2415
        bool acceptMoveSection = d->movableSections;
 
2416
        if (acceptMoveSection && d->pressed == 0 && !d->allowUserMoveOfSection0)
 
2417
            acceptMoveSection = false; // Do not allow moving the tree nod
 
2418
 
 
2419
        if (acceptMoveSection) {
 
2420
            d->section = d->target = d->pressed;
 
2421
            if (d->section == -1)
 
2422
                return;
 
2423
            d->state = QHeaderViewPrivate::MoveSection;
 
2424
            d->setupSectionIndicator(d->section, pos);
 
2425
        } else if (d->clickableSections && d->pressed != -1) {
 
2426
            updateSection(d->pressed);
 
2427
            d->state = QHeaderViewPrivate::SelectSections;
 
2428
        }
 
2429
    } else if (sectionResizeMode(handle) == Interactive) {
 
2430
        d->originalSize = sectionSize(handle);
 
2431
        d->state = QHeaderViewPrivate::ResizeSection;
 
2432
        d->section = handle;
 
2433
        d->preventCursorChangeInSetOffset = false;
 
2434
    }
 
2435
 
 
2436
    d->firstPos = pos;
 
2437
    d->lastPos = pos;
 
2438
 
 
2439
    d->clearCascadingSections();
 
2440
}
 
2441
 
 
2442
/*!
 
2443
  \reimp
 
2444
*/
 
2445
 
 
2446
void QHeaderView::mouseMoveEvent(QMouseEvent *e)
 
2447
{
 
2448
    Q_D(QHeaderView);
 
2449
    int pos = d->orientation == Qt::Horizontal ? e->x() : e->y();
 
2450
    if (pos < 0 && d->state != QHeaderViewPrivate::SelectSections)
 
2451
        return;
 
2452
    if (e->buttons() == Qt::NoButton) {
 
2453
#if !defined(Q_DEAD_CODE_FROM_QT4_MAC)
 
2454
        // Under Cocoa, when the mouse button is released, may include an extra
 
2455
        // simulated mouse moved event. The state of the buttons when this event
 
2456
        // is generated is already "no button" and the code below gets executed
 
2457
        // just before the mouseReleaseEvent and resets the state. This prevents
 
2458
        // column dragging from working. So this code is disabled under Cocoa.
 
2459
        d->state = QHeaderViewPrivate::NoState;
 
2460
        d->pressed = -1;
 
2461
#endif
 
2462
    }
 
2463
    switch (d->state) {
 
2464
        case QHeaderViewPrivate::ResizeSection: {
 
2465
            Q_ASSERT(d->originalSize != -1);
 
2466
            if (d->cascadingResizing) {
 
2467
                int delta = d->reverse() ? d->lastPos - pos : pos - d->lastPos;
 
2468
                int visual = visualIndex(d->section);
 
2469
                d->cascadingResize(visual, d->headerSectionSize(visual) + delta);
 
2470
            } else {
 
2471
                int delta = d->reverse() ? d->firstPos - pos : pos - d->firstPos;
 
2472
                int newsize = qBound(minimumSectionSize(), d->originalSize + delta, maximumSectionSize());
 
2473
                resizeSection(d->section, newsize);
 
2474
            }
 
2475
            d->lastPos = pos;
 
2476
            return;
 
2477
        }
 
2478
        case QHeaderViewPrivate::MoveSection: {
 
2479
            if (d->shouldAutoScroll(e->pos()))
 
2480
                d->startAutoScroll();
 
2481
            if (qAbs(pos - d->firstPos) >= QApplication::startDragDistance()
 
2482
                || !d->sectionIndicator->isHidden()) {
 
2483
                int visual = visualIndexAt(pos);
 
2484
                if (visual == -1)
 
2485
                    return;
 
2486
                if (visual == 0 && logicalIndex(0) == 0 && !d->allowUserMoveOfSection0)
 
2487
                    return;
 
2488
 
 
2489
                int posThreshold = d->headerSectionPosition(visual) - d->offset + d->headerSectionSize(visual) / 2;
 
2490
                int moving = visualIndex(d->section);
 
2491
                if (visual < moving) {
 
2492
                    if (pos < posThreshold)
 
2493
                        d->target = d->logicalIndex(visual);
 
2494
                    else
 
2495
                        d->target = d->logicalIndex(visual + 1);
 
2496
                } else if (visual > moving) {
 
2497
                    if (pos > posThreshold)
 
2498
                        d->target = d->logicalIndex(visual);
 
2499
                    else
 
2500
                        d->target = d->logicalIndex(visual - 1);
 
2501
                } else {
 
2502
                    d->target = d->section;
 
2503
                }
 
2504
                d->updateSectionIndicator(d->section, pos);
 
2505
            }
 
2506
            return;
 
2507
        }
 
2508
        case QHeaderViewPrivate::SelectSections: {
 
2509
            int logical = logicalIndexAt(qMax(-d->offset, pos));
 
2510
            if (logical == -1 && pos > 0)
 
2511
                logical = logicalIndex(d->lastVisibleVisualIndex());
 
2512
            if (logical == d->pressed)
 
2513
                return; // nothing to do
 
2514
            else if (d->pressed != -1)
 
2515
                updateSection(d->pressed);
 
2516
            d->pressed = logical;
 
2517
            if (d->clickableSections && logical != -1) {
 
2518
                emit sectionEntered(d->pressed);
 
2519
                updateSection(d->pressed);
 
2520
            }
 
2521
            return;
 
2522
        }
 
2523
        case QHeaderViewPrivate::NoState: {
 
2524
#ifndef QT_NO_CURSOR
 
2525
            int handle = d->sectionHandleAt(pos);
 
2526
            bool hasCursor = testAttribute(Qt::WA_SetCursor);
 
2527
            if (handle != -1 && (sectionResizeMode(handle) == Interactive)) {
 
2528
                if (!hasCursor)
 
2529
                    setCursor(d->orientation == Qt::Horizontal ? Qt::SplitHCursor : Qt::SplitVCursor);
 
2530
            } else if (hasCursor) {
 
2531
                unsetCursor();
 
2532
            }
 
2533
#endif
 
2534
            return;
 
2535
        }
 
2536
        default:
 
2537
            break;
 
2538
    }
 
2539
}
 
2540
 
 
2541
/*!
 
2542
  \reimp
 
2543
*/
 
2544
 
 
2545
void QHeaderView::mouseReleaseEvent(QMouseEvent *e)
 
2546
{
 
2547
    Q_D(QHeaderView);
 
2548
    int pos = d->orientation == Qt::Horizontal ? e->x() : e->y();
 
2549
    switch (d->state) {
 
2550
    case QHeaderViewPrivate::MoveSection:
 
2551
        if (!d->sectionIndicator->isHidden()) { // moving
 
2552
            int from = visualIndex(d->section);
 
2553
            Q_ASSERT(from != -1);
 
2554
            int to = visualIndex(d->target);
 
2555
            Q_ASSERT(to != -1);
 
2556
            moveSection(from, to);
 
2557
            d->section = d->target = -1;
 
2558
            d->updateSectionIndicator(d->section, pos);
 
2559
            break;
 
2560
        } // not moving
 
2561
    case QHeaderViewPrivate::SelectSections:
 
2562
        if (!d->clickableSections) {
 
2563
            int section = logicalIndexAt(pos);
 
2564
            updateSection(section);
 
2565
        }
 
2566
        // fall through
 
2567
    case QHeaderViewPrivate::NoState:
 
2568
        if (d->clickableSections) {
 
2569
            int section = logicalIndexAt(pos);
 
2570
            if (section != -1 && section == d->pressed) {
 
2571
                d->flipSortIndicator(section);
 
2572
                emit sectionClicked(section);
 
2573
            }
 
2574
            if (d->pressed != -1)
 
2575
                updateSection(d->pressed);
 
2576
        }
 
2577
        break;
 
2578
    case QHeaderViewPrivate::ResizeSection:
 
2579
        d->originalSize = -1;
 
2580
        d->clearCascadingSections();
 
2581
        break;
 
2582
    default:
 
2583
        break;
 
2584
    }
 
2585
    d->state = QHeaderViewPrivate::NoState;
 
2586
    d->pressed = -1;
 
2587
}
 
2588
 
 
2589
/*!
 
2590
  \reimp
 
2591
*/
 
2592
 
 
2593
void QHeaderView::mouseDoubleClickEvent(QMouseEvent *e)
 
2594
{
 
2595
    Q_D(QHeaderView);
 
2596
    int pos = d->orientation == Qt::Horizontal ? e->x() : e->y();
 
2597
    int handle = d->sectionHandleAt(pos);
 
2598
    if (handle > -1 && sectionResizeMode(handle) == Interactive) {
 
2599
        emit sectionHandleDoubleClicked(handle);
 
2600
#ifndef QT_NO_CURSOR
 
2601
        Qt::CursorShape splitCursor = (d->orientation == Qt::Horizontal)
 
2602
                                      ? Qt::SplitHCursor : Qt::SplitVCursor;
 
2603
        if (cursor().shape() == splitCursor) {
 
2604
            // signal handlers may have changed the section size
 
2605
            handle = d->sectionHandleAt(pos);
 
2606
            if (!(handle > -1 && sectionResizeMode(handle) == Interactive))
 
2607
                setCursor(Qt::ArrowCursor);
 
2608
        }
 
2609
#endif
 
2610
    } else {
 
2611
        emit sectionDoubleClicked(logicalIndexAt(e->pos()));
 
2612
    }
 
2613
}
 
2614
 
 
2615
/*!
 
2616
  \reimp
 
2617
*/
 
2618
 
 
2619
bool QHeaderView::viewportEvent(QEvent *e)
 
2620
{
 
2621
    Q_D(QHeaderView);
 
2622
    switch (e->type()) {
 
2623
#ifndef QT_NO_TOOLTIP
 
2624
    case QEvent::ToolTip: {
 
2625
        QHelpEvent *he = static_cast<QHelpEvent*>(e);
 
2626
        int logical = logicalIndexAt(he->pos());
 
2627
        if (logical != -1) {
 
2628
            QVariant variant = d->model->headerData(logical, d->orientation, Qt::ToolTipRole);
 
2629
            if (variant.isValid()) {
 
2630
                QToolTip::showText(he->globalPos(), variant.toString(), this);
 
2631
                return true;
 
2632
            }
 
2633
        }
 
2634
        break; }
 
2635
#endif
 
2636
#ifndef QT_NO_WHATSTHIS
 
2637
    case QEvent::QueryWhatsThis: {
 
2638
        QHelpEvent *he = static_cast<QHelpEvent*>(e);
 
2639
        int logical = logicalIndexAt(he->pos());
 
2640
        if (logical != -1
 
2641
            && d->model->headerData(logical, d->orientation, Qt::WhatsThisRole).isValid())
 
2642
            return true;
 
2643
        break; }
 
2644
    case QEvent::WhatsThis: {
 
2645
        QHelpEvent *he = static_cast<QHelpEvent*>(e);
 
2646
        int logical = logicalIndexAt(he->pos());
 
2647
        if (logical != -1) {
 
2648
             QVariant whatsthis = d->model->headerData(logical, d->orientation,
 
2649
                                                      Qt::WhatsThisRole);
 
2650
             if (whatsthis.isValid()) {
 
2651
                 QWhatsThis::showText(he->globalPos(), whatsthis.toString(), this);
 
2652
                 return true;
 
2653
             }
 
2654
        }
 
2655
        break; }
 
2656
#endif // QT_NO_WHATSTHIS
 
2657
#ifndef QT_NO_STATUSTIP
 
2658
    case QEvent::StatusTip: {
 
2659
        QHelpEvent *he = static_cast<QHelpEvent*>(e);
 
2660
        int logical = logicalIndexAt(he->pos());
 
2661
        if (logical != -1) {
 
2662
            QString statustip = d->model->headerData(logical, d->orientation,
 
2663
                                                    Qt::StatusTipRole).toString();
 
2664
            if (!statustip.isEmpty())
 
2665
                setStatusTip(statustip);
 
2666
        }
 
2667
        return true; }
 
2668
#endif // QT_NO_STATUSTIP
 
2669
    case QEvent::FontChange:
 
2670
    case QEvent::StyleChange:
 
2671
        d->invalidateCachedSizeHint();
 
2672
        // Fall through
 
2673
    case QEvent::Hide:
 
2674
    case QEvent::Show: {
 
2675
        QAbstractScrollArea *parent = qobject_cast<QAbstractScrollArea *>(parentWidget());
 
2676
        if (parent && parent->isVisible()) // Only resize if we have a visible parent
 
2677
            resizeSections();
 
2678
        emit geometriesChanged();
 
2679
        break;}
 
2680
    case QEvent::ContextMenu: {
 
2681
        d->state = QHeaderViewPrivate::NoState;
 
2682
        d->pressed = d->section = d->target = -1;
 
2683
        d->updateSectionIndicator(d->section, -1);
 
2684
        break; }
 
2685
    case QEvent::Wheel: {
 
2686
        QAbstractScrollArea *asa = qobject_cast<QAbstractScrollArea *>(parentWidget());
 
2687
        if (asa)
 
2688
            return QApplication::sendEvent(asa->viewport(), e);
 
2689
        break; }
 
2690
    default:
 
2691
        break;
 
2692
    }
 
2693
    return QAbstractItemView::viewportEvent(e);
 
2694
}
 
2695
 
 
2696
/*!
 
2697
    Paints the section specified by the given \a logicalIndex, using the given
 
2698
    \a painter and \a rect.
 
2699
 
 
2700
    Normally, you do not have to call this function.
 
2701
*/
 
2702
 
 
2703
void QHeaderView::paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const
 
2704
{
 
2705
    Q_D(const QHeaderView);
 
2706
    if (!rect.isValid())
 
2707
        return;
 
2708
    // get the state of the section
 
2709
    QStyleOptionHeader opt;
 
2710
    initStyleOption(&opt);
 
2711
    QStyle::State state = QStyle::State_None;
 
2712
    if (isEnabled())
 
2713
        state |= QStyle::State_Enabled;
 
2714
    if (window()->isActiveWindow())
 
2715
        state |= QStyle::State_Active;
 
2716
    if (d->clickableSections) {
 
2717
        if (logicalIndex == d->hover)
 
2718
            state |= QStyle::State_MouseOver;
 
2719
        if (logicalIndex == d->pressed)
 
2720
            state |= QStyle::State_Sunken;
 
2721
        else if (d->highlightSelected) {
 
2722
            if (d->sectionIntersectsSelection(logicalIndex))
 
2723
                state |= QStyle::State_On;
 
2724
            if (d->isSectionSelected(logicalIndex))
 
2725
                state |= QStyle::State_Sunken;
 
2726
        }
 
2727
 
 
2728
    }
 
2729
    if (isSortIndicatorShown() && sortIndicatorSection() == logicalIndex)
 
2730
        opt.sortIndicator = (sortIndicatorOrder() == Qt::AscendingOrder)
 
2731
                            ? QStyleOptionHeader::SortDown : QStyleOptionHeader::SortUp;
 
2732
 
 
2733
    // setup the style options structure
 
2734
    QVariant textAlignment = d->model->headerData(logicalIndex, d->orientation,
 
2735
                                                  Qt::TextAlignmentRole);
 
2736
    opt.rect = rect;
 
2737
    opt.section = logicalIndex;
 
2738
    opt.state |= state;
 
2739
    opt.textAlignment = Qt::Alignment(textAlignment.isValid()
 
2740
                                      ? Qt::Alignment(textAlignment.toInt())
 
2741
                                      : d->defaultAlignment);
 
2742
 
 
2743
    opt.iconAlignment = Qt::AlignVCenter;
 
2744
    opt.text = d->model->headerData(logicalIndex, d->orientation,
 
2745
                                    Qt::DisplayRole).toString();
 
2746
 
 
2747
    int margin = 2 * style()->pixelMetric(QStyle::PM_HeaderMargin, 0, this);
 
2748
 
 
2749
    const Qt::Alignment headerArrowAlignment = static_cast<Qt::Alignment>(style()->styleHint(QStyle::SH_Header_ArrowAlignment, 0, this));
 
2750
    const bool isHeaderArrowOnTheSide = headerArrowAlignment & Qt::AlignVCenter;
 
2751
    if (isSortIndicatorShown() && sortIndicatorSection() == logicalIndex && isHeaderArrowOnTheSide)
 
2752
        margin += style()->pixelMetric(QStyle::PM_HeaderMarkSize, 0, this);
 
2753
 
 
2754
    if (d->textElideMode != Qt::ElideNone)
 
2755
        opt.text = opt.fontMetrics.elidedText(opt.text, d->textElideMode , rect.width() - margin);
 
2756
 
 
2757
    QVariant variant = d->model->headerData(logicalIndex, d->orientation,
 
2758
                                    Qt::DecorationRole);
 
2759
    opt.icon = qvariant_cast<QIcon>(variant);
 
2760
    if (opt.icon.isNull())
 
2761
        opt.icon = qvariant_cast<QPixmap>(variant);
 
2762
    QVariant foregroundBrush = d->model->headerData(logicalIndex, d->orientation,
 
2763
                                                    Qt::ForegroundRole);
 
2764
    if (foregroundBrush.canConvert<QBrush>())
 
2765
        opt.palette.setBrush(QPalette::ButtonText, qvariant_cast<QBrush>(foregroundBrush));
 
2766
 
 
2767
    QPointF oldBO = painter->brushOrigin();
 
2768
    QVariant backgroundBrush = d->model->headerData(logicalIndex, d->orientation,
 
2769
                                                    Qt::BackgroundRole);
 
2770
    if (backgroundBrush.canConvert<QBrush>()) {
 
2771
        opt.palette.setBrush(QPalette::Button, qvariant_cast<QBrush>(backgroundBrush));
 
2772
        opt.palette.setBrush(QPalette::Window, qvariant_cast<QBrush>(backgroundBrush));
 
2773
        painter->setBrushOrigin(opt.rect.topLeft());
 
2774
    }
 
2775
 
 
2776
    // the section position
 
2777
    int visual = visualIndex(logicalIndex);
 
2778
    Q_ASSERT(visual != -1);
 
2779
    bool first = d->isFirstVisibleSection(visual);
 
2780
    bool last = d->isLastVisibleSection(visual);
 
2781
    if (first && last)
 
2782
        opt.position = QStyleOptionHeader::OnlyOneSection;
 
2783
    else if (first)
 
2784
        opt.position = QStyleOptionHeader::Beginning;
 
2785
    else if (last)
 
2786
        opt.position = QStyleOptionHeader::End;
 
2787
    else
 
2788
        opt.position = QStyleOptionHeader::Middle;
 
2789
    opt.orientation = d->orientation;
 
2790
    // the selected position
 
2791
    bool previousSelected = d->isSectionSelected(this->logicalIndex(visual - 1));
 
2792
    bool nextSelected =  d->isSectionSelected(this->logicalIndex(visual + 1));
 
2793
    if (previousSelected && nextSelected)
 
2794
        opt.selectedPosition = QStyleOptionHeader::NextAndPreviousAreSelected;
 
2795
    else if (previousSelected)
 
2796
        opt.selectedPosition = QStyleOptionHeader::PreviousIsSelected;
 
2797
    else if (nextSelected)
 
2798
        opt.selectedPosition = QStyleOptionHeader::NextIsSelected;
 
2799
    else
 
2800
        opt.selectedPosition = QStyleOptionHeader::NotAdjacent;
 
2801
    // draw the section
 
2802
    style()->drawControl(QStyle::CE_Header, &opt, painter, this);
 
2803
 
 
2804
    painter->setBrushOrigin(oldBO);
 
2805
}
 
2806
 
 
2807
/*!
 
2808
    Returns the size of the contents of the section specified by the given
 
2809
    \a logicalIndex.
 
2810
 
 
2811
    \sa defaultSectionSize()
 
2812
*/
 
2813
 
 
2814
QSize QHeaderView::sectionSizeFromContents(int logicalIndex) const
 
2815
{
 
2816
    Q_D(const QHeaderView);
 
2817
    Q_ASSERT(logicalIndex >= 0);
 
2818
 
 
2819
    ensurePolished();
 
2820
 
 
2821
    // use SizeHintRole
 
2822
    QVariant variant = d->model->headerData(logicalIndex, d->orientation, Qt::SizeHintRole);
 
2823
    if (variant.isValid())
 
2824
        return qvariant_cast<QSize>(variant);
 
2825
 
 
2826
    // otherwise use the contents
 
2827
    QStyleOptionHeader opt;
 
2828
    initStyleOption(&opt);
 
2829
    opt.section = logicalIndex;
 
2830
    QVariant var = d->model->headerData(logicalIndex, d->orientation,
 
2831
                                            Qt::FontRole);
 
2832
    QFont fnt;
 
2833
    if (var.isValid() && var.canConvert<QFont>())
 
2834
        fnt = qvariant_cast<QFont>(var);
 
2835
    else
 
2836
        fnt = font();
 
2837
    fnt.setBold(true);
 
2838
    opt.fontMetrics = QFontMetrics(fnt);
 
2839
    opt.text = d->model->headerData(logicalIndex, d->orientation,
 
2840
                                    Qt::DisplayRole).toString();
 
2841
    variant = d->model->headerData(logicalIndex, d->orientation, Qt::DecorationRole);
 
2842
    opt.icon = qvariant_cast<QIcon>(variant);
 
2843
    if (opt.icon.isNull())
 
2844
        opt.icon = qvariant_cast<QPixmap>(variant);
 
2845
    if (isSortIndicatorShown())
 
2846
        opt.sortIndicator = QStyleOptionHeader::SortDown;
 
2847
    return style()->sizeFromContents(QStyle::CT_HeaderSection, &opt, QSize(), this);
 
2848
}
 
2849
 
 
2850
/*!
 
2851
    Returns the horizontal offset of the header. This is 0 for vertical
 
2852
    headers.
 
2853
 
 
2854
    \sa offset()
 
2855
*/
 
2856
 
 
2857
int QHeaderView::horizontalOffset() const
 
2858
{
 
2859
    Q_D(const QHeaderView);
 
2860
    if (d->orientation == Qt::Horizontal)
 
2861
        return d->offset;
 
2862
    return 0;
 
2863
}
 
2864
 
 
2865
/*!
 
2866
    Returns the vertical offset of the header. This is 0 for horizontal
 
2867
    headers.
 
2868
 
 
2869
    \sa offset()
 
2870
*/
 
2871
 
 
2872
int QHeaderView::verticalOffset() const
 
2873
{
 
2874
    Q_D(const QHeaderView);
 
2875
    if (d->orientation == Qt::Vertical)
 
2876
        return d->offset;
 
2877
    return 0;
 
2878
}
 
2879
 
 
2880
/*!
 
2881
    \reimp
 
2882
    \internal
 
2883
*/
 
2884
 
 
2885
void QHeaderView::updateGeometries()
 
2886
{
 
2887
    Q_D(QHeaderView);
 
2888
    d->layoutChildren();
 
2889
    if (d->hasAutoResizeSections())
 
2890
        d->doDelayedResizeSections();
 
2891
}
 
2892
 
 
2893
/*!
 
2894
    \reimp
 
2895
    \internal
 
2896
*/
 
2897
 
 
2898
void QHeaderView::scrollContentsBy(int dx, int dy)
 
2899
{
 
2900
    Q_D(QHeaderView);
 
2901
    d->scrollDirtyRegion(dx, dy);
 
2902
}
 
2903
 
 
2904
/*!
 
2905
    \reimp
 
2906
    \internal
 
2907
*/
 
2908
void QHeaderView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &)
 
2909
{
 
2910
    Q_D(QHeaderView);
 
2911
    d->invalidateCachedSizeHint();
 
2912
    if (d->hasAutoResizeSections()) {
 
2913
        bool resizeRequired = d->globalResizeMode == ResizeToContents;
 
2914
        int first = orientation() == Qt::Horizontal ? topLeft.column() : topLeft.row();
 
2915
        int last = orientation() == Qt::Horizontal ? bottomRight.column() : bottomRight.row();
 
2916
        for (int i = first; i <= last && !resizeRequired; ++i)
 
2917
            resizeRequired = (sectionResizeMode(i) == ResizeToContents);
 
2918
        if (resizeRequired)
 
2919
            d->doDelayedResizeSections();
 
2920
    }
 
2921
}
 
2922
 
 
2923
/*!
 
2924
    \reimp
 
2925
    \internal
 
2926
 
 
2927
    Empty implementation because the header doesn't show QModelIndex items.
 
2928
*/
 
2929
void QHeaderView::rowsInserted(const QModelIndex &, int, int)
 
2930
{
 
2931
    // do nothing
 
2932
}
 
2933
 
 
2934
/*!
 
2935
    \reimp
 
2936
    \internal
 
2937
 
 
2938
    Empty implementation because the header doesn't show QModelIndex items.
 
2939
*/
 
2940
 
 
2941
QRect QHeaderView::visualRect(const QModelIndex &) const
 
2942
{
 
2943
    return QRect();
 
2944
}
 
2945
 
 
2946
/*!
 
2947
    \reimp
 
2948
    \internal
 
2949
 
 
2950
    Empty implementation because the header doesn't show QModelIndex items.
 
2951
*/
 
2952
 
 
2953
void QHeaderView::scrollTo(const QModelIndex &, ScrollHint)
 
2954
{
 
2955
    // do nothing - the header only displays sections
 
2956
}
 
2957
 
 
2958
/*!
 
2959
    \reimp
 
2960
    \internal
 
2961
 
 
2962
    Empty implementation because the header doesn't show QModelIndex items.
 
2963
*/
 
2964
 
 
2965
QModelIndex QHeaderView::indexAt(const QPoint &) const
 
2966
{
 
2967
    return QModelIndex();
 
2968
}
 
2969
 
 
2970
/*!
 
2971
    \reimp
 
2972
    \internal
 
2973
 
 
2974
    Empty implementation because the header doesn't show QModelIndex items.
 
2975
*/
 
2976
 
 
2977
bool QHeaderView::isIndexHidden(const QModelIndex &) const
 
2978
{
 
2979
    return true; // the header view has no items, just sections
 
2980
}
 
2981
 
 
2982
/*!
 
2983
    \reimp
 
2984
    \internal
 
2985
 
 
2986
    Empty implementation because the header doesn't show QModelIndex items.
 
2987
*/
 
2988
 
 
2989
QModelIndex QHeaderView::moveCursor(CursorAction, Qt::KeyboardModifiers)
 
2990
{
 
2991
    return QModelIndex();
 
2992
}
 
2993
 
 
2994
/*!
 
2995
    \reimp
 
2996
 
 
2997
    Selects the items in the given \a rect according to the specified
 
2998
    \a flags.
 
2999
 
 
3000
    The base class implementation does nothing.
 
3001
*/
 
3002
 
 
3003
void QHeaderView::setSelection(const QRect&, QItemSelectionModel::SelectionFlags)
 
3004
{
 
3005
    // do nothing
 
3006
}
 
3007
 
 
3008
/*!
 
3009
    \internal
 
3010
*/
 
3011
 
 
3012
QRegion QHeaderView::visualRegionForSelection(const QItemSelection &selection) const
 
3013
{
 
3014
    Q_D(const QHeaderView);
 
3015
    const int max = d->modelSectionCount();
 
3016
 
 
3017
    if (d->orientation == Qt::Horizontal) {
 
3018
        int logicalLeft = max;
 
3019
        int logicalRight = 0;
 
3020
 
 
3021
        if (d->visualIndices.empty()) {
 
3022
            // If no reordered sections, skip redundant visual-to-logical transformations
 
3023
            for (const auto &r : selection) {
 
3024
                if (r.parent().isValid() || !r.isValid())
 
3025
                    continue; // we only know about toplevel items and we don't want invalid ranges
 
3026
                if (r.left() < logicalLeft)
 
3027
                    logicalLeft = r.left();
 
3028
                if (r.right() > logicalRight)
 
3029
                    logicalRight = r.right();
 
3030
            }
 
3031
        } else {
 
3032
            int left = max;
 
3033
            int right = 0;
 
3034
            for (const auto &r : selection) {
 
3035
                if (r.parent().isValid() || !r.isValid())
 
3036
                    continue; // we only know about toplevel items and we don't want invalid ranges
 
3037
                for (int k = r.left(); k <= r.right(); ++k) {
 
3038
                    int visual = visualIndex(k);
 
3039
                    if (visual == -1)   // in some cases users may change the selections
 
3040
                        continue;       // before we have a chance to do the layout
 
3041
                    if (visual < left)
 
3042
                        left = visual;
 
3043
                    if (visual > right)
 
3044
                        right = visual;
 
3045
                }
 
3046
            }
 
3047
            logicalLeft = logicalIndex(left);
 
3048
            logicalRight = logicalIndex(right);
 
3049
        }
 
3050
 
 
3051
        if (logicalLeft < 0  || logicalLeft >= count() ||
 
3052
            logicalRight < 0 || logicalRight >= count())
 
3053
            return QRegion();
 
3054
 
 
3055
        int leftPos = sectionViewportPosition(logicalLeft);
 
3056
        int rightPos = sectionViewportPosition(logicalRight);
 
3057
        rightPos += sectionSize(logicalRight);
 
3058
        return QRect(leftPos, 0, rightPos - leftPos, height());
 
3059
    }
 
3060
    // orientation() == Qt::Vertical
 
3061
    int logicalTop = max;
 
3062
    int logicalBottom = 0;
 
3063
 
 
3064
    if (d->visualIndices.empty()) {
 
3065
        // If no reordered sections, skip redundant visual-to-logical transformations
 
3066
        for (const auto &r : selection) {
 
3067
            if (r.parent().isValid() || !r.isValid())
 
3068
                continue; // we only know about toplevel items and we don't want invalid ranges
 
3069
            if (r.top() < logicalTop)
 
3070
                logicalTop = r.top();
 
3071
            if (r.bottom() > logicalBottom)
 
3072
                logicalBottom = r.bottom();
 
3073
        }
 
3074
    } else {
 
3075
        int top = max;
 
3076
        int bottom = 0;
 
3077
 
 
3078
        for (const auto &r : selection) {
 
3079
            if (r.parent().isValid() || !r.isValid())
 
3080
                continue; // we only know about toplevel items and we don't want invalid ranges
 
3081
            for (int k = r.top(); k <= r.bottom(); ++k) {
 
3082
                int visual = visualIndex(k);
 
3083
                if (visual == -1)   // in some cases users may change the selections
 
3084
                    continue;       // before we have a chance to do the layout
 
3085
                if (visual < top)
 
3086
                    top = visual;
 
3087
                if (visual > bottom)
 
3088
                    bottom = visual;
 
3089
            }
 
3090
        }
 
3091
 
 
3092
        logicalTop = logicalIndex(top);
 
3093
        logicalBottom = logicalIndex(bottom);
 
3094
    }
 
3095
 
 
3096
    if (logicalTop < 0 || logicalTop >= count() ||
 
3097
        logicalBottom < 0 || logicalBottom >= count())
 
3098
        return QRegion();
 
3099
 
 
3100
    int topPos = sectionViewportPosition(logicalTop);
 
3101
    int bottomPos = sectionViewportPosition(logicalBottom) + sectionSize(logicalBottom);
 
3102
 
 
3103
    return QRect(0, topPos, width(), bottomPos - topPos);
 
3104
}
 
3105
 
 
3106
 
 
3107
// private implementation
 
3108
 
 
3109
int QHeaderViewPrivate::sectionHandleAt(int position)
 
3110
{
 
3111
    Q_Q(QHeaderView);
 
3112
    int visual = q->visualIndexAt(position);
 
3113
    if (visual == -1)
 
3114
        return -1;
 
3115
    int log = logicalIndex(visual);
 
3116
    int pos = q->sectionViewportPosition(log);
 
3117
    int grip = q->style()->pixelMetric(QStyle::PM_HeaderGripMargin, 0, q);
 
3118
 
 
3119
    bool atLeft = position < pos + grip;
 
3120
    bool atRight = (position > pos + q->sectionSize(log) - grip);
 
3121
    if (reverse())
 
3122
        qSwap(atLeft, atRight);
 
3123
 
 
3124
    if (atLeft) {
 
3125
        //grip at the beginning of the section
 
3126
        while(visual > -1) {
 
3127
            int logical = q->logicalIndex(--visual);
 
3128
            if (!q->isSectionHidden(logical))
 
3129
                return logical;
 
3130
        }
 
3131
    } else if (atRight) {
 
3132
        //grip at the end of the section
 
3133
        return log;
 
3134
    }
 
3135
    return -1;
 
3136
}
 
3137
 
 
3138
void QHeaderViewPrivate::setupSectionIndicator(int section, int position)
 
3139
{
 
3140
    Q_Q(QHeaderView);
 
3141
    if (!sectionIndicator) {
 
3142
        sectionIndicator = new QLabel(viewport);
 
3143
    }
 
3144
 
 
3145
    int w, h;
 
3146
    int p = q->sectionViewportPosition(section);
 
3147
    if (orientation == Qt::Horizontal) {
 
3148
        w = q->sectionSize(section);
 
3149
        h = viewport->height();
 
3150
    } else {
 
3151
        w = viewport->width();
 
3152
        h = q->sectionSize(section);
 
3153
    }
 
3154
    sectionIndicator->resize(w, h);
 
3155
 
 
3156
    QPixmap pm(w, h);
 
3157
    pm.fill(QColor(0, 0, 0, 45));
 
3158
    QRect rect(0, 0, w, h);
 
3159
 
 
3160
    QPainter painter(&pm);
 
3161
    painter.setOpacity(0.75);
 
3162
    q->paintSection(&painter, rect, section);
 
3163
    painter.end();
 
3164
 
 
3165
    sectionIndicator->setPixmap(pm);
 
3166
    sectionIndicatorOffset = position - qMax(p, 0);
 
3167
}
 
3168
 
 
3169
void QHeaderViewPrivate::updateSectionIndicator(int section, int position)
 
3170
{
 
3171
    if (!sectionIndicator)
 
3172
        return;
 
3173
 
 
3174
    if (section == -1 || target == -1) {
 
3175
        sectionIndicator->hide();
 
3176
        return;
 
3177
    }
 
3178
 
 
3179
    if (orientation == Qt::Horizontal)
 
3180
        sectionIndicator->move(position - sectionIndicatorOffset, 0);
 
3181
    else
 
3182
        sectionIndicator->move(0, position - sectionIndicatorOffset);
 
3183
 
 
3184
    sectionIndicator->show();
 
3185
}
 
3186
 
 
3187
/*!
 
3188
    Initialize \a option with the values from this QHeaderView. This method is
 
3189
    useful for subclasses when they need a QStyleOptionHeader, but do not want
 
3190
    to fill in all the information themselves.
 
3191
 
 
3192
    \sa QStyleOption::initFrom()
 
3193
*/
 
3194
void QHeaderView::initStyleOption(QStyleOptionHeader *option) const
 
3195
{
 
3196
    Q_D(const QHeaderView);
 
3197
    option->initFrom(this);
 
3198
    option->state = QStyle::State_None | QStyle::State_Raised;
 
3199
    option->orientation = d->orientation;
 
3200
    if (d->orientation == Qt::Horizontal)
 
3201
        option->state |= QStyle::State_Horizontal;
 
3202
    if (isEnabled())
 
3203
        option->state |= QStyle::State_Enabled;
 
3204
    option->section = 0;
 
3205
}
 
3206
 
 
3207
bool QHeaderViewPrivate::isSectionSelected(int section) const
 
3208
{
 
3209
    int i = section * 2;
 
3210
    if (i < 0 || i >= sectionSelected.count())
 
3211
        return false;
 
3212
    if (sectionSelected.testBit(i)) // if the value was cached
 
3213
        return sectionSelected.testBit(i + 1);
 
3214
    bool s = false;
 
3215
    if (orientation == Qt::Horizontal)
 
3216
        s = isColumnSelected(section);
 
3217
    else
 
3218
        s = isRowSelected(section);
 
3219
    sectionSelected.setBit(i + 1, s); // selection state
 
3220
    sectionSelected.setBit(i, true); // cache state
 
3221
    return s;
 
3222
}
 
3223
 
 
3224
bool QHeaderViewPrivate::isFirstVisibleSection(int section) const
 
3225
{
 
3226
    if (sectionStartposRecalc)
 
3227
        recalcSectionStartPos();
 
3228
    const SectionItem &item = sectionItems.at(section);
 
3229
    return item.size > 0 && item.calculated_startpos == 0;
 
3230
}
 
3231
 
 
3232
bool QHeaderViewPrivate::isLastVisibleSection(int section) const
 
3233
{
 
3234
    if (sectionStartposRecalc)
 
3235
        recalcSectionStartPos();
 
3236
    const SectionItem &item = sectionItems.at(section);
 
3237
    return item.size > 0 && item.calculatedEndPos() == length;
 
3238
}
 
3239
 
 
3240
/*!
 
3241
    \internal
 
3242
    Returns the last visible (ie. not hidden) visual index
 
3243
*/
 
3244
int QHeaderViewPrivate::lastVisibleVisualIndex() const
 
3245
{
 
3246
    Q_Q(const QHeaderView);
 
3247
    for (int visual = q->count()-1; visual >= 0; --visual) {
 
3248
        if (!q->isSectionHidden(q->logicalIndex(visual)))
 
3249
            return visual;
 
3250
    }
 
3251
 
 
3252
    //default value if no section is actually visible
 
3253
    return -1;
 
3254
}
 
3255
 
 
3256
void QHeaderViewPrivate::restoreSizeOnPrevLastSection()
 
3257
{
 
3258
    Q_Q(QHeaderView);
 
3259
    if (lastSectionLogicalIdx < 0)
 
3260
        return;
 
3261
    int resizeLogIdx = lastSectionLogicalIdx;
 
3262
    lastSectionLogicalIdx = -1; // We do not want resize to catch it as the last section.
 
3263
    q->resizeSection(resizeLogIdx, lastSectionSize);
 
3264
}
 
3265
 
 
3266
void QHeaderViewPrivate::setNewLastSection(int visualIndexForLastSection)
 
3267
{
 
3268
    Q_Q(QHeaderView);
 
3269
    lastSectionSize = -1;
 
3270
    lastSectionLogicalIdx = q->logicalIndex(visualIndexForLastSection);
 
3271
    lastSectionSize = headerSectionSize(visualIndexForLastSection); // pick size directly since ...
 
3272
    //  q->sectionSize(lastSectionLogicalIdx) may do delayed resize and stretch it before we get the value.
 
3273
}
 
3274
 
 
3275
void QHeaderViewPrivate::maybeRestorePrevLastSectionAndStretchLast()
 
3276
{
 
3277
    Q_Q(const QHeaderView);
 
3278
    if (!q->stretchLastSection())
 
3279
        return;
 
3280
 
 
3281
    int nowLastVisualSection = lastVisibleVisualIndex();
 
3282
    if (lastSectionLogicalIdx == q->logicalIndex(nowLastVisualSection))
 
3283
        return;
 
3284
 
 
3285
    // restore old last section.
 
3286
    restoreSizeOnPrevLastSection();
 
3287
    setNewLastSection(nowLastVisualSection);
 
3288
    doDelayedResizeSections(); // Do stretch of last section soon (but not now).
 
3289
}
 
3290
 
 
3291
 
 
3292
/*!
 
3293
    \internal
 
3294
    Go through and resize all of the sections applying stretchLastSection,
 
3295
    manual stretches, sizes, and useGlobalMode.
 
3296
 
 
3297
    The different resize modes are:
 
3298
    Interactive - the user decides the size
 
3299
    Stretch - take up whatever space is left
 
3300
    Fixed - the size is set programmatically outside the header
 
3301
    ResizeToContentes - the size is set based on the contents of the row or column in the parent view
 
3302
 
 
3303
    The resize mode will not affect the last section if stretchLastSection is true.
 
3304
*/
 
3305
void QHeaderViewPrivate::resizeSections(QHeaderView::ResizeMode globalMode, bool useGlobalMode)
 
3306
{
 
3307
    Q_Q(QHeaderView);
 
3308
    //stop the timer in case it is delayed
 
3309
    delayedResize.stop();
 
3310
 
 
3311
    executePostedLayout();
 
3312
    if (sectionCount() == 0)
 
3313
        return;
 
3314
 
 
3315
    if (resizeRecursionBlock)
 
3316
        return;
 
3317
    resizeRecursionBlock = true;
 
3318
 
 
3319
    invalidateCachedSizeHint();
 
3320
    const int lastSectionVisualIdx = q->visualIndex(lastSectionLogicalIdx);
 
3321
 
 
3322
    // find stretchLastSection if we have it
 
3323
    int stretchSection = -1;
 
3324
    if (stretchLastSection && !useGlobalMode)
 
3325
        stretchSection = lastSectionVisualIdx;
 
3326
 
 
3327
    // count up the number of stretched sections and how much space left for them
 
3328
    int lengthToStretch = (orientation == Qt::Horizontal ? viewport->width() : viewport->height());
 
3329
    int numberOfStretchedSections = 0;
 
3330
    QList<int> section_sizes;
 
3331
    for (int i = 0; i < sectionCount(); ++i) {
 
3332
        if (isVisualIndexHidden(i))
 
3333
            continue;
 
3334
 
 
3335
        QHeaderView::ResizeMode resizeMode;
 
3336
        if (useGlobalMode && (i != stretchSection))
 
3337
            resizeMode = globalMode;
 
3338
        else
 
3339
            resizeMode = (i == stretchSection ? QHeaderView::Stretch : headerSectionResizeMode(i));
 
3340
 
 
3341
        if (resizeMode == QHeaderView::Stretch) {
 
3342
            ++numberOfStretchedSections;
 
3343
            section_sizes.append(headerSectionSize(i));
 
3344
            continue;
 
3345
        }
 
3346
 
 
3347
        // because it isn't stretch, determine its width and remove that from lengthToStretch
 
3348
        int sectionSize = 0;
 
3349
        if (resizeMode == QHeaderView::Interactive || resizeMode == QHeaderView::Fixed) {
 
3350
            sectionSize = headerSectionSize(i);
 
3351
        } else { // resizeMode == QHeaderView::ResizeToContents
 
3352
            int logicalIndex = q->logicalIndex(i);
 
3353
            sectionSize = qMax(viewSectionSizeHint(logicalIndex),
 
3354
                               q->sectionSizeHint(logicalIndex));
 
3355
            if (sectionSize > q->maximumSectionSize())
 
3356
                sectionSize = q->maximumSectionSize();
 
3357
        }
 
3358
        section_sizes.append(sectionSize);
 
3359
        lengthToStretch -= sectionSize;
 
3360
    }
 
3361
 
 
3362
    // calculate the new length for all of the stretched sections
 
3363
    int stretchSectionLength = -1;
 
3364
    int pixelReminder = 0;
 
3365
    if (numberOfStretchedSections > 0 && lengthToStretch > 0) { // we have room to stretch in
 
3366
        int hintLengthForEveryStretchedSection = lengthToStretch / numberOfStretchedSections;
 
3367
        stretchSectionLength = qMax(hintLengthForEveryStretchedSection, q->minimumSectionSize());
 
3368
        pixelReminder = lengthToStretch % numberOfStretchedSections;
 
3369
    }
 
3370
 
 
3371
    // ### The code below would be nicer if it was cleaned up a bit (since spans has been replaced with items)
 
3372
    int spanStartSection = 0;
 
3373
    int previousSectionLength = 0;
 
3374
 
 
3375
    QHeaderView::ResizeMode previousSectionResizeMode = QHeaderView::Interactive;
 
3376
 
 
3377
    // resize each section along the total length
 
3378
    for (int i = 0; i < sectionCount(); ++i) {
 
3379
        int oldSectionLength = headerSectionSize(i);
 
3380
        int newSectionLength = -1;
 
3381
        QHeaderView::ResizeMode newSectionResizeMode = headerSectionResizeMode(i);
 
3382
 
 
3383
        if (isVisualIndexHidden(i)) {
 
3384
            newSectionLength = 0;
 
3385
        } else {
 
3386
            QHeaderView::ResizeMode resizeMode;
 
3387
            if (useGlobalMode)
 
3388
                resizeMode = globalMode;
 
3389
            else
 
3390
                resizeMode = (i == stretchSection
 
3391
                              ? QHeaderView::Stretch
 
3392
                              : newSectionResizeMode);
 
3393
            if (resizeMode == QHeaderView::Stretch && stretchSectionLength != -1) {
 
3394
                if (i == lastSectionVisualIdx)
 
3395
                    newSectionLength = qMax(stretchSectionLength, lastSectionSize);
 
3396
                else
 
3397
                    newSectionLength = stretchSectionLength;
 
3398
                if (pixelReminder > 0) {
 
3399
                    newSectionLength += 1;
 
3400
                    --pixelReminder;
 
3401
                }
 
3402
                section_sizes.removeFirst();
 
3403
            } else {
 
3404
                newSectionLength = section_sizes.takeFirst();
 
3405
            }
 
3406
        }
 
3407
 
 
3408
        //Q_ASSERT(newSectionLength > 0);
 
3409
        if ((previousSectionResizeMode != newSectionResizeMode
 
3410
            || previousSectionLength != newSectionLength) && i > 0) {
 
3411
            int spanLength = (i - spanStartSection) * previousSectionLength;
 
3412
            createSectionItems(spanStartSection, i - 1, spanLength, previousSectionResizeMode);
 
3413
            //Q_ASSERT(headerLength() == length);
 
3414
            spanStartSection = i;
 
3415
        }
 
3416
 
 
3417
        if (newSectionLength != oldSectionLength)
 
3418
            emit q->sectionResized(logicalIndex(i), oldSectionLength, newSectionLength);
 
3419
 
 
3420
        previousSectionLength = newSectionLength;
 
3421
        previousSectionResizeMode = newSectionResizeMode;
 
3422
    }
 
3423
 
 
3424
    createSectionItems(spanStartSection, sectionCount() - 1,
 
3425
                      (sectionCount() - spanStartSection) * previousSectionLength,
 
3426
                      previousSectionResizeMode);
 
3427
    //Q_ASSERT(headerLength() == length);
 
3428
    resizeRecursionBlock = false;
 
3429
    viewport->update();
 
3430
}
 
3431
 
 
3432
void QHeaderViewPrivate::createSectionItems(int start, int end, int size, QHeaderView::ResizeMode mode)
 
3433
{
 
3434
    int sizePerSection = size / (end - start + 1);
 
3435
    if (end >= sectionItems.count()) {
 
3436
        sectionItems.resize(end + 1);
 
3437
        sectionStartposRecalc = true;
 
3438
    }
 
3439
    SectionItem *sectiondata = sectionItems.data();
 
3440
    for (int i = start; i <= end; ++i) {
 
3441
        length += (sizePerSection - sectiondata[i].size);
 
3442
        sectionStartposRecalc |= (sectiondata[i].size != sizePerSection);
 
3443
        sectiondata[i].size = sizePerSection;
 
3444
        sectiondata[i].resizeMode = mode;
 
3445
    }
 
3446
}
 
3447
 
 
3448
void QHeaderViewPrivate::removeSectionsFromSectionItems(int start, int end)
 
3449
{
 
3450
    // remove sections
 
3451
    sectionStartposRecalc |= (end != sectionItems.count() - 1);
 
3452
    int removedlength = 0;
 
3453
    for (int u = start; u <= end; ++u)
 
3454
        removedlength += sectionItems.at(u).size;
 
3455
    length -= removedlength;
 
3456
    sectionItems.remove(start, end - start + 1);
 
3457
}
 
3458
 
 
3459
void QHeaderViewPrivate::clear()
 
3460
{
 
3461
    if (state != NoClear) {
 
3462
    length = 0;
 
3463
    visualIndices.clear();
 
3464
    logicalIndices.clear();
 
3465
    sectionSelected.clear();
 
3466
    hiddenSectionSize.clear();
 
3467
    sectionItems.clear();
 
3468
    lastSectionLogicalIdx = -1;
 
3469
    invalidateCachedSizeHint();
 
3470
    }
 
3471
}
 
3472
 
 
3473
void QHeaderViewPrivate::flipSortIndicator(int section)
 
3474
{
 
3475
    Q_Q(QHeaderView);
 
3476
    Qt::SortOrder sortOrder;
 
3477
    if (sortIndicatorSection == section) {
 
3478
        sortOrder = (sortIndicatorOrder == Qt::DescendingOrder) ? Qt::AscendingOrder : Qt::DescendingOrder;
 
3479
    } else {
 
3480
        const QVariant value = model->headerData(section, orientation, Qt::InitialSortOrderRole);
 
3481
        if (value.canConvert(QVariant::Int))
 
3482
            sortOrder = static_cast<Qt::SortOrder>(value.toInt());
 
3483
        else
 
3484
            sortOrder = Qt::AscendingOrder;
 
3485
    }
 
3486
    q->setSortIndicator(section, sortOrder);
 
3487
}
 
3488
 
 
3489
void QHeaderViewPrivate::cascadingResize(int visual, int newSize)
 
3490
{
 
3491
    Q_Q(QHeaderView);
 
3492
    const int minimumSize = q->minimumSectionSize();
 
3493
    const int oldSize = headerSectionSize(visual);
 
3494
    int delta = newSize - oldSize;
 
3495
 
 
3496
    if (delta > 0) { // larger
 
3497
        bool sectionResized = false;
 
3498
 
 
3499
        // restore old section sizes
 
3500
        for (int i = firstCascadingSection; i < visual; ++i) {
 
3501
            if (cascadingSectionSize.contains(i)) {
 
3502
                int currentSectionSize = headerSectionSize(i);
 
3503
                int originalSectionSize = cascadingSectionSize.value(i);
 
3504
                if (currentSectionSize < originalSectionSize) {
 
3505
                    int newSectionSize = currentSectionSize + delta;
 
3506
                    resizeSectionItem(i, currentSectionSize, newSectionSize);
 
3507
                    if (newSectionSize >= originalSectionSize && false)
 
3508
                        cascadingSectionSize.remove(i); // the section is now restored
 
3509
                    sectionResized = true;
 
3510
                    break;
 
3511
                }
 
3512
            }
 
3513
 
 
3514
        }
 
3515
 
 
3516
        // resize the section
 
3517
        if (!sectionResized) {
 
3518
            newSize = qMax(newSize, minimumSize);
 
3519
            if (oldSize != newSize)
 
3520
                resizeSectionItem(visual, oldSize, newSize);
 
3521
        }
 
3522
 
 
3523
        // cascade the section size change
 
3524
        for (int i = visual + 1; i < sectionCount(); ++i) {
 
3525
            if (!sectionIsCascadable(i))
 
3526
                continue;
 
3527
            int currentSectionSize = headerSectionSize(i);
 
3528
            if (currentSectionSize <= minimumSize)
 
3529
                continue;
 
3530
            int newSectionSize = qMax(currentSectionSize - delta, minimumSize);
 
3531
            //qDebug() << "### cascading to" << i << newSectionSize - currentSectionSize << delta;
 
3532
            resizeSectionItem(i, currentSectionSize, newSectionSize);
 
3533
            saveCascadingSectionSize(i, currentSectionSize);
 
3534
            delta = delta - (currentSectionSize - newSectionSize);
 
3535
            //qDebug() << "new delta" << delta;
 
3536
            //if (newSectionSize != minimumSize)
 
3537
            if (delta <= 0)
 
3538
                break;
 
3539
        }
 
3540
    } else { // smaller
 
3541
        bool sectionResized = false;
 
3542
 
 
3543
        // restore old section sizes
 
3544
        for (int i = lastCascadingSection; i > visual; --i) {
 
3545
            if (!cascadingSectionSize.contains(i))
 
3546
                continue;
 
3547
            int currentSectionSize = headerSectionSize(i);
 
3548
            int originalSectionSize = cascadingSectionSize.value(i);
 
3549
            if (currentSectionSize >= originalSectionSize)
 
3550
                continue;
 
3551
            int newSectionSize = currentSectionSize - delta;
 
3552
            resizeSectionItem(i, currentSectionSize, newSectionSize);
 
3553
            if (newSectionSize >= originalSectionSize && false) {
 
3554
                //qDebug() << "section" << i << "restored to" << originalSectionSize;
 
3555
                cascadingSectionSize.remove(i); // the section is now restored
 
3556
            }
 
3557
            sectionResized = true;
 
3558
            break;
 
3559
        }
 
3560
 
 
3561
        // resize the section
 
3562
        resizeSectionItem(visual, oldSize, qMax(newSize, minimumSize));
 
3563
 
 
3564
        // cascade the section size change
 
3565
        if (delta < 0 && newSize < minimumSize) {
 
3566
            for (int i = visual - 1; i >= 0; --i) {
 
3567
                if (!sectionIsCascadable(i))
 
3568
                    continue;
 
3569
                int sectionSize = headerSectionSize(i);
 
3570
                if (sectionSize <= minimumSize)
 
3571
                    continue;
 
3572
                resizeSectionItem(i, sectionSize, qMax(sectionSize + delta, minimumSize));
 
3573
                saveCascadingSectionSize(i, sectionSize);
 
3574
                break;
 
3575
            }
 
3576
        }
 
3577
 
 
3578
        // let the next section get the space from the resized section
 
3579
        if (!sectionResized) {
 
3580
            for (int i = visual + 1; i < sectionCount(); ++i) {
 
3581
                if (!sectionIsCascadable(i))
 
3582
                    continue;
 
3583
                int currentSectionSize = headerSectionSize(i);
 
3584
                int newSectionSize = qMax(currentSectionSize - delta, minimumSize);
 
3585
                resizeSectionItem(i, currentSectionSize, newSectionSize);
 
3586
                break;
 
3587
            }
 
3588
        }
 
3589
    }
 
3590
 
 
3591
    if (hasAutoResizeSections())
 
3592
        doDelayedResizeSections();
 
3593
 
 
3594
    viewport->update();
 
3595
}
 
3596
 
 
3597
void QHeaderViewPrivate::setDefaultSectionSize(int size)
 
3598
{
 
3599
    Q_Q(QHeaderView);
 
3600
    executePostedLayout();
 
3601
    invalidateCachedSizeHint();
 
3602
    defaultSectionSize = size;
 
3603
    customDefaultSectionSize = true;
 
3604
    if (state == QHeaderViewPrivate::ResizeSection)
 
3605
        preventCursorChangeInSetOffset = true;
 
3606
    for (int i = 0; i < sectionItems.count(); ++i) {
 
3607
        QHeaderViewPrivate::SectionItem &section = sectionItems[i];
 
3608
        if (hiddenSectionSize.isEmpty() || !isVisualIndexHidden(i)) { // resize on not hidden.
 
3609
            const int newSize = size;
 
3610
            if (newSize != section.size) {
 
3611
                length += newSize - section.size; //the whole length is changed
 
3612
                const int oldSectionSize = section.sectionSize();
 
3613
                section.size = size;
 
3614
                emit q->sectionResized(logicalIndex(i), oldSectionSize, size);
 
3615
            }
 
3616
        }
 
3617
    }
 
3618
    sectionStartposRecalc = true;
 
3619
    if (hasAutoResizeSections())
 
3620
        doDelayedResizeSections();
 
3621
    viewport->update();
 
3622
}
 
3623
 
 
3624
void QHeaderViewPrivate::updateDefaultSectionSizeFromStyle()
 
3625
{
 
3626
    Q_Q(QHeaderView);
 
3627
    if (orientation == Qt::Horizontal) {
 
3628
        defaultSectionSize = q->style()->pixelMetric(QStyle::PM_HeaderDefaultSectionSizeHorizontal, 0, q);
 
3629
    } else {
 
3630
        defaultSectionSize = qMax(q->minimumSectionSize(),
 
3631
                                  q->style()->pixelMetric(QStyle::PM_HeaderDefaultSectionSizeVertical, 0, q));
 
3632
    }
 
3633
}
 
3634
 
 
3635
void QHeaderViewPrivate::recalcSectionStartPos() const // linear (but fast)
 
3636
{
 
3637
    int pixelpos = 0;
 
3638
    for (QVector<SectionItem>::const_iterator i = sectionItems.constBegin(); i != sectionItems.constEnd(); ++i) {
 
3639
        i->calculated_startpos = pixelpos; // write into const mutable
 
3640
        pixelpos += i->size;
 
3641
    }
 
3642
    sectionStartposRecalc = false;
 
3643
}
 
3644
 
 
3645
void QHeaderViewPrivate::resizeSectionItem(int visualIndex, int oldSize, int newSize)
 
3646
{
 
3647
    Q_Q(QHeaderView);
 
3648
    QHeaderView::ResizeMode mode = headerSectionResizeMode(visualIndex);
 
3649
    createSectionItems(visualIndex, visualIndex, newSize, mode);
 
3650
    emit q->sectionResized(logicalIndex(visualIndex), oldSize, newSize);
 
3651
}
 
3652
 
 
3653
int QHeaderViewPrivate::headerSectionSize(int visual) const
 
3654
{
 
3655
    if (visual < sectionCount() && visual >= 0)
 
3656
        return sectionItems.at(visual).sectionSize();
 
3657
    return -1;
 
3658
}
 
3659
 
 
3660
int QHeaderViewPrivate::headerSectionPosition(int visual) const
 
3661
{
 
3662
    if (visual < sectionCount() && visual >= 0) {
 
3663
        if (sectionStartposRecalc)
 
3664
            recalcSectionStartPos();
 
3665
        return sectionItems.at(visual).calculated_startpos;
 
3666
    }
 
3667
    return -1;
 
3668
}
 
3669
 
 
3670
int QHeaderViewPrivate::headerVisualIndexAt(int position) const
 
3671
{
 
3672
    if (sectionStartposRecalc)
 
3673
        recalcSectionStartPos();
 
3674
    int startidx = 0;
 
3675
    int endidx = sectionItems.count() - 1;
 
3676
    while (startidx <= endidx) {
 
3677
        int middle = (endidx + startidx) / 2;
 
3678
        if (sectionItems.at(middle).calculated_startpos > position) {
 
3679
            endidx = middle - 1;
 
3680
        } else {
 
3681
            if (sectionItems.at(middle).calculatedEndPos() <= position)
 
3682
                startidx = middle + 1;
 
3683
            else // we found it.
 
3684
                return middle;
 
3685
        }
 
3686
    }
 
3687
    return -1;
 
3688
}
 
3689
 
 
3690
void QHeaderViewPrivate::setHeaderSectionResizeMode(int visual, QHeaderView::ResizeMode mode)
 
3691
{
 
3692
    int size = headerSectionSize(visual);
 
3693
    createSectionItems(visual, visual, size, mode);
 
3694
}
 
3695
 
 
3696
QHeaderView::ResizeMode QHeaderViewPrivate::headerSectionResizeMode(int visual) const
 
3697
{
 
3698
    if (visual < 0 || visual >= sectionItems.count())
 
3699
        return globalResizeMode;
 
3700
    return static_cast<QHeaderView::ResizeMode>(sectionItems.at(visual).resizeMode);
 
3701
}
 
3702
 
 
3703
void QHeaderViewPrivate::setGlobalHeaderResizeMode(QHeaderView::ResizeMode mode)
 
3704
{
 
3705
    globalResizeMode = mode;
 
3706
    for (int i = 0; i < sectionItems.count(); ++i)
 
3707
        sectionItems[i].resizeMode = mode;
 
3708
}
 
3709
 
 
3710
int QHeaderViewPrivate::viewSectionSizeHint(int logical) const
 
3711
{
 
3712
    if (QAbstractItemView *view = qobject_cast<QAbstractItemView*>(parent)) {
 
3713
        return (orientation == Qt::Horizontal
 
3714
                ? view->sizeHintForColumn(logical)
 
3715
                : view->sizeHintForRow(logical));
 
3716
    }
 
3717
    return 0;
 
3718
}
 
3719
 
 
3720
int QHeaderViewPrivate::adjustedVisualIndex(int visualIndex) const
 
3721
{
 
3722
    if (!hiddenSectionSize.isEmpty()) {
 
3723
        int adjustedVisualIndex = visualIndex;
 
3724
        int currentVisualIndex = 0;
 
3725
        for (int i = 0; i < sectionItems.count(); ++i) {
 
3726
            if (isVisualIndexHidden(i))
 
3727
                ++adjustedVisualIndex;
 
3728
            else
 
3729
                ++currentVisualIndex;
 
3730
            if (currentVisualIndex >= visualIndex)
 
3731
                break;
 
3732
        }
 
3733
        visualIndex = adjustedVisualIndex;
 
3734
    }
 
3735
    return visualIndex;
 
3736
}
 
3737
 
 
3738
void QHeaderViewPrivate::setScrollOffset(const QScrollBar *scrollBar, QAbstractItemView::ScrollMode scrollMode)
 
3739
{
 
3740
    Q_Q(QHeaderView);
 
3741
    if (scrollMode == QAbstractItemView::ScrollPerItem) {
 
3742
        if (scrollBar->maximum() > 0 && scrollBar->value() == scrollBar->maximum())
 
3743
            q->setOffsetToLastSection();
 
3744
        else
 
3745
            q->setOffsetToSectionPosition(scrollBar->value());
 
3746
    } else {
 
3747
        q->setOffset(scrollBar->value());
 
3748
    }
 
3749
}
 
3750
 
 
3751
#ifndef QT_NO_DATASTREAM
 
3752
void QHeaderViewPrivate::write(QDataStream &out) const
 
3753
{
 
3754
    out << int(orientation);
 
3755
    out << int(sortIndicatorOrder);
 
3756
    out << sortIndicatorSection;
 
3757
    out << sortIndicatorShown;
 
3758
 
 
3759
    out << visualIndices;
 
3760
    out << logicalIndices;
 
3761
 
 
3762
    out << sectionsHiddenToBitVector();
 
3763
    out << hiddenSectionSize;
 
3764
 
 
3765
    out << length;
 
3766
    out << sectionCount();
 
3767
    out << movableSections;
 
3768
    out << clickableSections;
 
3769
    out << highlightSelected;
 
3770
    out << stretchLastSection;
 
3771
    out << cascadingResizing;
 
3772
    out << stretchSections;
 
3773
    out << contentsSections;
 
3774
    out << defaultSectionSize;
 
3775
    out << minimumSectionSize;
 
3776
 
 
3777
    out << int(defaultAlignment);
 
3778
    out << int(globalResizeMode);
 
3779
 
 
3780
    out << sectionItems;
 
3781
    out << resizeContentsPrecision;
 
3782
    out << customDefaultSectionSize;
 
3783
    out << lastSectionSize;
 
3784
}
 
3785
 
 
3786
bool QHeaderViewPrivate::read(QDataStream &in)
 
3787
{
 
3788
    Q_Q(QHeaderView);
 
3789
    int orient, order, align, global;
 
3790
    int sortIndicatorSectionIn;
 
3791
    bool sortIndicatorShownIn;
 
3792
    int lengthIn;
 
3793
    QVector<int> visualIndicesIn;
 
3794
    QVector<int> logicalIndicesIn;
 
3795
    QHash<int, int> hiddenSectionSizeIn;
 
3796
    bool movableSectionsIn;
 
3797
    bool clickableSectionsIn;
 
3798
    bool highlightSelectedIn;
 
3799
    bool stretchLastSectionIn;
 
3800
    bool cascadingResizingIn;
 
3801
    int stretchSectionsIn;
 
3802
    int contentsSectionsIn;
 
3803
    int defaultSectionSizeIn;
 
3804
    int minimumSectionSizeIn;
 
3805
    QVector<SectionItem> sectionItemsIn;
 
3806
 
 
3807
    in >> orient;
 
3808
    in >> order;
 
3809
 
 
3810
    in >> sortIndicatorSectionIn;
 
3811
    in >> sortIndicatorShownIn;
 
3812
 
 
3813
    in >> visualIndicesIn;
 
3814
    in >> logicalIndicesIn;
 
3815
 
 
3816
    QBitArray sectionHidden;
 
3817
    in >> sectionHidden;
 
3818
    in >> hiddenSectionSizeIn;
 
3819
    in >> lengthIn;
 
3820
 
 
3821
    int unusedSectionCount; // For compatibility
 
3822
    in >> unusedSectionCount;
 
3823
 
 
3824
    if (in.status() != QDataStream::Ok || lengthIn < 0)
 
3825
        return false;
 
3826
 
 
3827
    in >> movableSectionsIn;
 
3828
    in >> clickableSectionsIn;
 
3829
    in >> highlightSelectedIn;
 
3830
    in >> stretchLastSectionIn;
 
3831
    in >> cascadingResizingIn;
 
3832
    in >> stretchSectionsIn;
 
3833
    in >> contentsSectionsIn;
 
3834
    in >> defaultSectionSizeIn;
 
3835
    in >> minimumSectionSizeIn;
 
3836
 
 
3837
    in >> align;
 
3838
 
 
3839
    in >> global;
 
3840
 
 
3841
    in >> sectionItemsIn;
 
3842
    // In Qt4 we had a vector of spans where one span could hold information on more sections.
 
3843
    // Now we have an itemvector where one items contains information about one section
 
3844
    // For backward compatibility with Qt4 we do the following
 
3845
    QVector<SectionItem> newSectionItems;
 
3846
    for (int u = 0; u < sectionItemsIn.count(); ++u) {
 
3847
        int count = sectionItemsIn.at(u).tmpDataStreamSectionCount;
 
3848
        if (count > 0)
 
3849
            sectionItemsIn[u].size /= count;
 
3850
        for (int n = 0; n < count; ++n)
 
3851
            newSectionItems.append(sectionItemsIn[u]);
 
3852
    }
 
3853
 
 
3854
    int sectionItemsLengthTotal = 0;
 
3855
    foreach (const SectionItem &section, newSectionItems)
 
3856
        sectionItemsLengthTotal += section.size;
 
3857
    if (sectionItemsLengthTotal != lengthIn)
 
3858
        return false;
 
3859
 
 
3860
    orientation = static_cast<Qt::Orientation>(orient);
 
3861
    sortIndicatorOrder = static_cast<Qt::SortOrder>(order);
 
3862
    sortIndicatorSection = sortIndicatorSectionIn;
 
3863
    sortIndicatorShown = sortIndicatorShownIn;
 
3864
    visualIndices = visualIndicesIn;
 
3865
    logicalIndices = logicalIndicesIn;
 
3866
    hiddenSectionSize = hiddenSectionSizeIn;
 
3867
    length = lengthIn;
 
3868
 
 
3869
    movableSections = movableSectionsIn;
 
3870
    clickableSections = clickableSectionsIn;
 
3871
    highlightSelected = highlightSelectedIn;
 
3872
    stretchLastSection = stretchLastSectionIn;
 
3873
    cascadingResizing = cascadingResizingIn;
 
3874
    stretchSections = stretchSectionsIn;
 
3875
    contentsSections = contentsSectionsIn;
 
3876
    defaultSectionSize = defaultSectionSizeIn;
 
3877
    minimumSectionSize = minimumSectionSizeIn;
 
3878
 
 
3879
    defaultAlignment = Qt::Alignment(align);
 
3880
    globalResizeMode = static_cast<QHeaderView::ResizeMode>(global);
 
3881
 
 
3882
    sectionItems = newSectionItems;
 
3883
    setHiddenSectionsFromBitVector(sectionHidden);
 
3884
    recalcSectionStartPos();
 
3885
 
 
3886
    int tmpint;
 
3887
    in >> tmpint;
 
3888
    if (in.status() == QDataStream::Ok)  // we haven't read past end
 
3889
        resizeContentsPrecision = tmpint;
 
3890
 
 
3891
    bool tmpbool;
 
3892
    in >> tmpbool;
 
3893
    if (in.status() == QDataStream::Ok) {  // we haven't read past end
 
3894
        customDefaultSectionSize = tmpbool;
 
3895
        if (!customDefaultSectionSize)
 
3896
            updateDefaultSectionSizeFromStyle();
 
3897
    }
 
3898
 
 
3899
    lastSectionSize = -1;
 
3900
    int inLastSectionSize;
 
3901
    in >> inLastSectionSize;
 
3902
    if (in.status() == QDataStream::Ok)
 
3903
        lastSectionSize = inLastSectionSize;
 
3904
 
 
3905
    lastSectionLogicalIdx = -1;
 
3906
    if (stretchLastSection) {
 
3907
        lastSectionLogicalIdx = q->logicalIndex(lastVisibleVisualIndex());
 
3908
        doDelayedResizeSections();
 
3909
    }
 
3910
 
 
3911
    return true;
 
3912
}
 
3913
 
 
3914
#endif // QT_NO_DATASTREAM
 
3915
 
 
3916
QT_END_NAMESPACE
 
3917
 
 
3918
#endif // QT_NO_ITEMVIEWS
 
3919
 
 
3920
#include "moc_qheaderview.cpp"