source: trunk/src/gui/itemviews/qheaderview.cpp@ 138

Last change on this file since 138 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

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