itemviews/qtreeview.cpp

Source codeSwitch to Preprocessed file
LineSource CodeCoverage
1/****************************************************************************-
**
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/****************************************************************************
2** -
3** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -
4** Contact: http://www.qt-project.org/legal -
5** -
6** This file is part of the QtGui module of the Qt Toolkit. -
7** -
8** $QT_BEGIN_LICENSE:LGPL$ -
9** Commercial License Usage -
10** Licensees holding valid commercial Qt licenses may use this file in -
11** accordance with the commercial license agreement provided with the -
12** Software or, alternatively, in accordance with the terms contained in -
13** a written agreement between you and Digia. For licensing terms and -
14** conditions see http://qt.digia.com/licensing. For further information -
15** use the contact form at http://qt.digia.com/contact-us. -
16** -
17** GNU Lesser General Public License Usage -
18** Alternatively, this file may be used under the terms of the GNU Lesser -
19** General Public License version 2.1 as published by the Free Software -
20** Foundation and appearing in the file LICENSE.LGPL included in the -
21** packaging of this file. Please review the following information to -
22** ensure the GNU Lesser General Public License version 2.1 requirements -
23** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -
24** -
25** In addition, as a special exception, Digia gives you certain additional -
26** rights. These rights are described in the Digia Qt LGPL Exception -
27** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -
28** -
29** GNU General Public License Usage -
30** Alternatively, this file may be used under the terms of the GNU -
31** General Public License version 3.0 as published by the Free Software -
32** Foundation and appearing in the file LICENSE.GPL included in the -
33** packaging of this file. Please review the following information to -
34** ensure the GNU General Public License version 3.0 requirements will be -
35** met: http://www.gnu.org/copyleft/gpl.html. -
36** -
37** -
38** $QT_END_LICENSE$ -
39** -
40****************************************************************************/ -
41#include "qtreeview.h" -
42 -
43#ifndef QT_NO_TREEVIEW -
44#include <qheaderview.h> -
45#include <qitemdelegate.h> -
46#include <qapplication.h> -
47#include <qscrollbar.h> -
48#include <qpainter.h> -
49#include <qstack.h> -
50#include <qstyle.h> -
51#include <qstyleoption.h> -
52#include <qevent.h> -
53#include <qpen.h> -
54#include <qdebug.h> -
55#ifndef QT_NO_ACCESSIBILITY -
56#include <qaccessible.h> -
57#include <qaccessible2.h> -
58#endif -
59 -
60#include <private/qtreeview_p.h> -
61#include <private/qheaderview_p.h> -
62 -
63QT_BEGIN_NAMESPACE -
64 -
65/*! -
66 \class QTreeView -
67 \brief The QTreeView class provides a default model/view implementation of a tree view. -
68 -
69 \ingroup model-view -
70 \ingroup advanced -
71 \inmodule QtWidgets -
72 -
73 A QTreeView implements a tree representation of items from a -
74 model. This class is used to provide standard hierarchical lists that -
75 were previously provided by the \c QListView class, but using the more -
76 flexible approach provided by Qt's model/view architecture. -
77 -
78 The QTreeView class is one of the \l{Model/View Classes} and is part of -
79 Qt's \l{Model/View Programming}{model/view framework}. -
80 -
81 QTreeView implements the interfaces defined by the -
82 QAbstractItemView class to allow it to display data provided by -
83 models derived from the QAbstractItemModel class. -
84 -
85 It is simple to construct a tree view displaying data from a -
86 model. In the following example, the contents of a directory are -
87 supplied by a QFileSystemModel and displayed as a tree: -
88 -
89 \snippet shareddirmodel/main.cpp 3 -
90 \snippet shareddirmodel/main.cpp 6 -
91 -
92 The model/view architecture ensures that the contents of the tree view -
93 are updated as the model changes. -
94 -
95 Items that have children can be in an expanded (children are -
96 visible) or collapsed (children are hidden) state. When this state -
97 changes a collapsed() or expanded() signal is emitted with the -
98 model index of the relevant item. -
99 -
100 The amount of indentation used to indicate levels of hierarchy is -
101 controlled by the \l indentation property. -
102 -
103 Headers in tree views are constructed using the QHeaderView class and can -
104 be hidden using \c{header()->hide()}. Note that each header is configured -
105 with its \l{QHeaderView::}{stretchLastSection} property set to true, -
106 ensuring that the view does not waste any of the space assigned to it for -
107 its header. If this value is set to true, this property will override the -
108 resize mode set on the last section in the header. -
109 -
110 -
111 \section1 Key Bindings -
112 -
113 QTreeView supports a set of key bindings that enable the user to -
114 navigate in the view and interact with the contents of items: -
115 -
116 \table -
117 \header \li Key \li Action -
118 \row \li Up \li Moves the cursor to the item in the same column on -
119 the previous row. If the parent of the current item has no more rows to -
120 navigate to, the cursor moves to the relevant item in the last row -
121 of the sibling that precedes the parent. -
122 \row \li Down \li Moves the cursor to the item in the same column on -
123 the next row. If the parent of the current item has no more rows to -
124 navigate to, the cursor moves to the relevant item in the first row -
125 of the sibling that follows the parent. -
126 \row \li Left \li Hides the children of the current item (if present) -
127 by collapsing a branch. -
128 \row \li Minus \li Same as LeftArrow. -
129 \row \li Right \li Reveals the children of the current item (if present) -
130 by expanding a branch. -
131 \row \li Plus \li Same as RightArrow. -
132 \row \li Asterisk \li Expands all children of the current item (if present). -
133 \row \li PageUp \li Moves the cursor up one page. -
134 \row \li PageDown \li Moves the cursor down one page. -
135 \row \li Home \li Moves the cursor to an item in the same column of the first -
136 row of the first top-level item in the model. -
137 \row \li End \li Moves the cursor to an item in the same column of the last -
138 row of the last top-level item in the model. -
139 \row \li F2 \li In editable models, this opens the current item for editing. -
140 The Escape key can be used to cancel the editing process and revert -
141 any changes to the data displayed. -
142 \endtable -
143 -
144 \omit -
145 Describe the expanding/collapsing concept if not covered elsewhere. -
146 \endomit -
147 -
148 \table 100% -
149 \row \li \inlineimage windowsvista-treeview.png Screenshot of a Windows Vista style tree view -
150 \li \inlineimage macintosh-treeview.png Screenshot of a Macintosh style tree view -
151 \li \inlineimage fusion-treeview.png Screenshot of a Fusion style tree view -
152 \row \li A \l{Windows Vista Style Widget Gallery}{Windows Vista style} tree view. -
153 \li A \l{Macintosh Style Widget Gallery}{Macintosh style} tree view. -
154 \li A \l{Fusion Style Widget Gallery}{Fusion style} tree view. -
155 \endtable -
156 -
157 \section1 Improving Performance -
158 -
159 It is possible to give the view hints about the data it is handling in order -
160 to improve its performance when displaying large numbers of items. One approach -
161 that can be taken for views that are intended to display items with equal heights -
162 is to set the \l uniformRowHeights property to true. -
163 -
164 \sa QListView, QTreeWidget, {View Classes}, QAbstractItemModel, QAbstractItemView, -
165 {Dir View Example} -
166*/ -
167 -
168 -
169/*! -
170 \fn void QTreeView::expanded(const QModelIndex &index) -
171 -
172 This signal is emitted when the item specified by \a index is expanded. -
173*/ -
174 -
175 -
176/*! -
177 \fn void QTreeView::collapsed(const QModelIndex &index) -
178 -
179 This signal is emitted when the item specified by \a index is collapsed. -
180*/ -
181 -
182/*! -
183 Constructs a tree view with a \a parent to represent a model's -
184 data. Use setModel() to set the model. -
185 -
186 \sa QAbstractItemModel -
187*/ -
188QTreeView::QTreeView(QWidget *parent) -
189 : QAbstractItemView(*new QTreeViewPrivate, parent) -
190{ -
191 Q_D(QTreeView); -
192 d->initialize(); -
193} -
194 -
195/*! -
196 \internal -
197*/ -
198QTreeView::QTreeView(QTreeViewPrivate &dd, QWidget *parent) -
199 : QAbstractItemView(dd, parent) -
200{ -
201 Q_D(QTreeView); -
202 d->initialize(); -
203} -
204 -
205/*! -
206 Destroys the tree view. -
207*/ -
208QTreeView::~QTreeView() -
209{ -
210} -
211 -
212/*! -
213 \reimp -
214*/ -
215void QTreeView::setModel(QAbstractItemModel *model) -
216{ -
217 Q_D(QTreeView); -
218 if (model == d->model) -
219 return; -
220 if (d->model && d->model != QAbstractItemModelPrivate::staticEmptyModel()) { -
221 disconnect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)), -
222 this, SLOT(rowsRemoved(QModelIndex,int,int))); -
223 -
224 disconnect(d->model, SIGNAL(modelAboutToBeReset()), this, SLOT(_q_modelAboutToBeReset())); -
225 } -
226 -
227 if (d->selectionModel) { // support row editing -
228 disconnect(d->selectionModel, SIGNAL(currentRowChanged(QModelIndex,QModelIndex)), -
229 d->model, SLOT(submit())); -
230 disconnect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)), -
231 this, SLOT(rowsRemoved(QModelIndex,int,int))); -
232 disconnect(d->model, SIGNAL(modelAboutToBeReset()), this, SLOT(_q_modelAboutToBeReset())); -
233 } -
234 d->viewItems.clear(); -
235 d->expandedIndexes.clear(); -
236 d->hiddenIndexes.clear(); -
237 d->header->setModel(model); -
238 QAbstractItemView::setModel(model); -
239 -
240 // QAbstractItemView connects to a private slot -
241 disconnect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)), -
242 this, SLOT(_q_rowsRemoved(QModelIndex,int,int))); -
243 // do header layout after the tree -
244 disconnect(d->model, SIGNAL(layoutChanged()), -
245 d->header, SLOT(_q_layoutChanged())); -
246 // QTreeView has a public slot for this -
247 connect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)), -
248 this, SLOT(rowsRemoved(QModelIndex,int,int))); -
249 -
250 connect(d->model, SIGNAL(modelAboutToBeReset()), SLOT(_q_modelAboutToBeReset())); -
251 -
252 if (d->sortingEnabled) -
253 d->_q_sortIndicatorChanged(header()->sortIndicatorSection(), header()->sortIndicatorOrder()); -
254} -
255 -
256/*! -
257 \reimp -
258*/ -
259void QTreeView::setRootIndex(const QModelIndex &index) -
260{ -
261 Q_D(QTreeView); -
262 d->header->setRootIndex(index); -
263 QAbstractItemView::setRootIndex(index); -
264} -
265 -
266/*! -
267 \reimp -
268*/ -
269void QTreeView::setSelectionModel(QItemSelectionModel *selectionModel) -
270{ -
271 Q_D(QTreeView); -
272 Q_ASSERT(selectionModel); -
273 if (d->selectionModel) { -
274 // support row editing -
275 disconnect(d->selectionModel, SIGNAL(currentRowChanged(QModelIndex,QModelIndex)), -
276 d->model, SLOT(submit())); -
277 } -
278 -
279 d->header->setSelectionModel(selectionModel); -
280 QAbstractItemView::setSelectionModel(selectionModel); -
281 -
282 if (d->selectionModel) { -
283 // support row editing -
284 connect(d->selectionModel, SIGNAL(currentRowChanged(QModelIndex,QModelIndex)), -
285 d->model, SLOT(submit())); -
286 } -
287} -
288 -
289/*! -
290 Returns the header for the tree view. -
291 -
292 \sa QAbstractItemModel::headerData() -
293*/ -
294QHeaderView *QTreeView::header() const -
295{ -
296 Q_D(const QTreeView); -
297 return d->header; -
298} -
299 -
300/*! -
301 Sets the header for the tree view, to the given \a header. -
302 -
303 The view takes ownership over the given \a header and deletes it -
304 when a new header is set. -
305 -
306 \sa QAbstractItemModel::headerData() -
307*/ -
308void QTreeView::setHeader(QHeaderView *header) -
309{ -
310 Q_D(QTreeView); -
311 if (header == d->header || !header) -
312 return; -
313 if (d->header && d->header->parent() == this) -
314 delete d->header; -
315 d->header = header; -
316 d->header->setParent(this); -
317 d->header->d_func()->setAllowUserMoveOfSection0(false); -
318 -
319 if (!d->header->model()) { -
320 d->header->setModel(d->model); -
321 if (d->selectionModel) -
322 d->header->setSelectionModel(d->selectionModel); -
323 } -
324 -
325 connect(d->header, SIGNAL(sectionResized(int,int,int)), -
326 this, SLOT(columnResized(int,int,int))); -
327 connect(d->header, SIGNAL(sectionMoved(int,int,int)), -
328 this, SLOT(columnMoved())); -
329 connect(d->header, SIGNAL(sectionCountChanged(int,int)), -
330 this, SLOT(columnCountChanged(int,int))); -
331 connect(d->header, SIGNAL(sectionHandleDoubleClicked(int)), -
332 this, SLOT(resizeColumnToContents(int))); -
333 connect(d->header, SIGNAL(geometriesChanged()), -
334 this, SLOT(updateGeometries())); -
335 -
336 setSortingEnabled(d->sortingEnabled); -
337} -
338 -
339/*! -
340 \property QTreeView::autoExpandDelay -
341 \brief The delay time before items in a tree are opened during a drag and drop operation. -
342 \since 4.3 -
343 -
344 This property holds the amount of time in milliseconds that the user must wait over -
345 a node before that node will automatically open or close. If the time is -
346 set to less then 0 then it will not be activated. -
347 -
348 By default, this property has a value of -1, meaning that auto-expansion is disabled. -
349*/ -
350int QTreeView::autoExpandDelay() const -
351{ -
352 Q_D(const QTreeView); -
353 return d->autoExpandDelay; -
354} -
355 -
356void QTreeView::setAutoExpandDelay(int delay) -
357{ -
358 Q_D(QTreeView); -
359 d->autoExpandDelay = delay; -
360} -
361 -
362/*! -
363 \property QTreeView::indentation -
364 \brief indentation of the items in the tree view. -
365 -
366 This property holds the indentation measured in pixels of the items for each -
367 level in the tree view. For top-level items, the indentation specifies the -
368 horizontal distance from the viewport edge to the items in the first column; -
369 for child items, it specifies their indentation from their parent items. -
370 -
371 By default, this property has a value of 20. -
372*/ -
373int QTreeView::indentation() const -
374{ -
375 Q_D(const QTreeView); -
376 return d->indent; -
377} -
378 -
379void QTreeView::setIndentation(int i) -
380{ -
381 Q_D(QTreeView); -
382 if (i != d->indent) { -
383 d->indent = i; -
384 d->viewport->update(); -
385 } -
386} -
387 -
388/*! -
389 \property QTreeView::rootIsDecorated -
390 \brief whether to show controls for expanding and collapsing top-level items -
391 -
392 Items with children are typically shown with controls to expand and collapse -
393 them, allowing their children to be shown or hidden. If this property is -
394 false, these controls are not shown for top-level items. This can be used to -
395 make a single level tree structure appear like a simple list of items. -
396 -
397 By default, this property is true. -
398*/ -
399bool QTreeView::rootIsDecorated() const -
400{ -
401 Q_D(const QTreeView); -
402 return d->rootDecoration; -
403} -
404 -
405void QTreeView::setRootIsDecorated(bool show) -
406{ -
407 Q_D(QTreeView); -
408 if (show != d->rootDecoration) { -
409 d->rootDecoration = show; -
410 d->viewport->update(); -
411 } -
412} -
413 -
414/*! -
415 \property QTreeView::uniformRowHeights -
416 \brief whether all items in the treeview have the same height -
417 -
418 This property should only be set to true if it is guaranteed that all items -
419 in the view has the same height. This enables the view to do some -
420 optimizations. -
421 -
422 The height is obtained from the first item in the view. It is updated -
423 when the data changes on that item. -
424 -
425 By default, this property is false. -
426*/ -
427bool QTreeView::uniformRowHeights() const -
428{ -
429 Q_D(const QTreeView); -
430 return d->uniformRowHeights; -
431} -
432 -
433void QTreeView::setUniformRowHeights(bool uniform) -
434{ -
435 Q_D(QTreeView); -
436 d->uniformRowHeights = uniform; -
437} -
438 -
439/*! -
440 \property QTreeView::itemsExpandable -
441 \brief whether the items are expandable by the user. -
442 -
443 This property holds whether the user can expand and collapse items -
444 interactively. -
445 -
446 By default, this property is true. -
447 -
448*/ -
449bool QTreeView::itemsExpandable() const -
450{ -
451 Q_D(const QTreeView); -
452 return d->itemsExpandable; -
453} -
454 -
455void QTreeView::setItemsExpandable(bool enable) -
456{ -
457 Q_D(QTreeView); -
458 d->itemsExpandable = enable; -
459} -
460 -
461/*! -
462 \property QTreeView::expandsOnDoubleClick -
463 \since 4.4 -
464 \brief whether the items can be expanded by double-clicking. -
465 -
466 This property holds whether the user can expand and collapse items -
467 by double-clicking. The default value is true. -
468 -
469 \sa itemsExpandable -
470*/ -
471bool QTreeView::expandsOnDoubleClick() const -
472{ -
473 Q_D(const QTreeView); -
474 return d->expandsOnDoubleClick; -
475} -
476 -
477void QTreeView::setExpandsOnDoubleClick(bool enable) -
478{ -
479 Q_D(QTreeView); -
480 d->expandsOnDoubleClick = enable; -
481} -
482 -
483/*! -
484 Returns the horizontal position of the \a column in the viewport. -
485*/ -
486int QTreeView::columnViewportPosition(int column) const -
487{ -
488 Q_D(const QTreeView); -
489 return d->header->sectionViewportPosition(column); -
490} -
491 -
492/*! -
493 Returns the width of the \a column. -
494 -
495 \sa resizeColumnToContents(), setColumnWidth() -
496*/ -
497int QTreeView::columnWidth(int column) const -
498{ -
499 Q_D(const QTreeView); -
500 return d->header->sectionSize(column); -
501} -
502 -
503/*! -
504 \since 4.2 -
505 -
506 Sets the width of the given \a column to the \a width specified. -
507 -
508 \sa columnWidth(), resizeColumnToContents() -
509*/ -
510void QTreeView::setColumnWidth(int column, int width) -
511{ -
512 Q_D(QTreeView); -
513 d->header->resizeSection(column, width); -
514} -
515 -
516/*! -
517 Returns the column in the tree view whose header covers the \a x -
518 coordinate given. -
519*/ -
520int QTreeView::columnAt(int x) const -
521{ -
522 Q_D(const QTreeView); -
523 return d->header->logicalIndexAt(x); -
524} -
525 -
526/*! -
527 Returns true if the \a column is hidden; otherwise returns false. -
528 -
529 \sa hideColumn(), isRowHidden() -
530*/ -
531bool QTreeView::isColumnHidden(int column) const -
532{ -
533 Q_D(const QTreeView); -
534 return d->header->isSectionHidden(column); -
535} -
536 -
537/*! -
538 If \a hide is true the \a column is hidden, otherwise the \a column is shown. -
539 -
540 \sa hideColumn(), setRowHidden() -
541*/ -
542void QTreeView::setColumnHidden(int column, bool hide) -
543{ -
544 Q_D(QTreeView); -
545 if (column < 0 || column >= d->header->count()) -
546 return; -
547 d->header->setSectionHidden(column, hide); -
548} -
549 -
550/*! -
551 \property QTreeView::headerHidden -
552 \brief whether the header is shown or not. -
553 \since 4.4 -
554 -
555 If this property is true, the header is not shown otherwise it is. -
556 The default value is false. -
557 -
558 \sa header() -
559*/ -
560bool QTreeView::isHeaderHidden() const -
561{ -
562 Q_D(const QTreeView); -
563 return d->header->isHidden(); -
564} -
565 -
566void QTreeView::setHeaderHidden(bool hide) -
567{ -
568 Q_D(QTreeView); -
569 d->header->setHidden(hide); -
570} -
571 -
572/*! -
573 Returns true if the item in the given \a row of the \a parent is hidden; -
574 otherwise returns false. -
575 -
576 \sa setRowHidden(), isColumnHidden() -
577*/ -
578bool QTreeView::isRowHidden(int row, const QModelIndex &parent) const -
579{ -
580 Q_D(const QTreeView); -
581 if (!d->model) -
582 return false; -
583 return d->isRowHidden(d->model->index(row, 0, parent)); -
584} -
585 -
586/*! -
587 If \a hide is true the \a row with the given \a parent is hidden, otherwise the \a row is shown. -
588 -
589 \sa isRowHidden(), setColumnHidden() -
590*/ -
591void QTreeView::setRowHidden(int row, const QModelIndex &parent, bool hide) -
592{ -
593 Q_D(QTreeView); -
594 if (!d->model) -
595 return; -
596 QModelIndex index = d->model->index(row, 0, parent); -
597 if (!index.isValid()) -
598 return; -
599 -
600 if (hide) { -
601 d->hiddenIndexes.insert(index); -
602 } else if(d->isPersistent(index)) { //if the index is not persistent, it cannot be in the set -
603 d->hiddenIndexes.remove(index); -
604 } -
605 -
606 d->doDelayedItemsLayout(); -
607} -
608 -
609/*! -
610 \since 4.3 -
611 -
612 Returns true if the item in first column in the given \a row -
613 of the \a parent is spanning all the columns; otherwise returns false. -
614 -
615 \sa setFirstColumnSpanned() -
616*/ -
617bool QTreeView::isFirstColumnSpanned(int row, const QModelIndex &parent) const -
618{ -
619 Q_D(const QTreeView); -
620 if (d->spanningIndexes.isEmpty() || !d->model) -
621 return false; -
622 QModelIndex index = d->model->index(row, 0, parent); -
623 for (int i = 0; i < d->spanningIndexes.count(); ++i) -
624 if (d->spanningIndexes.at(i) == index) -
625 return true; -
626 return false; -
627} -
628 -
629/*! -
630 \since 4.3 -
631 -
632 If \a span is true the item in the first column in the \a row -
633 with the given \a parent is set to span all columns, otherwise all items -
634 on the \a row are shown. -
635 -
636 \sa isFirstColumnSpanned() -
637*/ -
638void QTreeView::setFirstColumnSpanned(int row, const QModelIndex &parent, bool span) -
639{ -
640 Q_D(QTreeView); -
641 if (!d->model) -
642 return; -
643 QModelIndex index = d->model->index(row, 0, parent); -
644 if (!index.isValid()) -
645 return; -
646 -
647 if (span) { -
648 QPersistentModelIndex persistent(index); -
649 if (!d->spanningIndexes.contains(persistent)) -
650 d->spanningIndexes.append(persistent); -
651 } else { -
652 QPersistentModelIndex persistent(index); -
653 int i = d->spanningIndexes.indexOf(persistent); -
654 if (i >= 0) -
655 d->spanningIndexes.remove(i); -
656 } -
657 -
658 d->executePostedLayout(); -
659 int i = d->viewIndex(index); -
660 if (i >= 0) -
661 d->viewItems[i].spanning = span; -
662 -
663 d->viewport->update(); -
664} -
665 -
666/*! -
667 \reimp -
668*/ -
669void QTreeView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles) -
670{ -
671 Q_D(QTreeView); -
672 -
673 // if we are going to do a complete relayout anyway, there is no need to update -
674 if (d->delayedPendingLayout) -
675 return; -
676 -
677 // refresh the height cache here; we don't really lose anything by getting the size hint, -
678 // since QAbstractItemView::dataChanged() will get the visualRect for the items anyway -
679 -
680 bool sizeChanged = false; -
681 int topViewIndex = d->viewIndex(topLeft); -
682 if (topViewIndex == 0) { -
683 int newDefaultItemHeight = indexRowSizeHint(topLeft); -
684 sizeChanged = d->defaultItemHeight != newDefaultItemHeight; -
685 d->defaultItemHeight = newDefaultItemHeight; -
686 } -
687 -
688 if (topViewIndex != -1) { -
689 if (topLeft.row() == bottomRight.row()) { -
690 int oldHeight = d->itemHeight(topViewIndex); -
691 d->invalidateHeightCache(topViewIndex); -
692 sizeChanged |= (oldHeight != d->itemHeight(topViewIndex)); -
693 if (topLeft.column() == 0) -
694 d->viewItems[topViewIndex].hasChildren = d->hasVisibleChildren(topLeft); -
695 } else { -
696 int bottomViewIndex = d->viewIndex(bottomRight); -
697 for (int i = topViewIndex; i <= bottomViewIndex; ++i) { -
698 int oldHeight = d->itemHeight(i); -
699 d->invalidateHeightCache(i); -
700 sizeChanged |= (oldHeight != d->itemHeight(i)); -
701 if (topLeft.column() == 0) -
702 d->viewItems[i].hasChildren = d->hasVisibleChildren(d->viewItems.at(i).index); -
703 } -
704 } -
705 } -
706 -
707 if (sizeChanged) { -
708 d->updateScrollBars(); -
709 d->viewport->update(); -
710 } -
711 QAbstractItemView::dataChanged(topLeft, bottomRight, roles); -
712} -
713 -
714/*! -
715 Hides the \a column given. -
716 -
717 \note This function should only be called after the model has been -
718 initialized, as the view needs to know the number of columns in order to -
719 hide \a column. -
720 -
721 \sa showColumn(), setColumnHidden() -
722*/ -
723void QTreeView::hideColumn(int column) -
724{ -
725 Q_D(QTreeView); -
726 d->header->hideSection(column); -
727} -
728 -
729/*! -
730 Shows the given \a column in the tree view. -
731 -
732 \sa hideColumn(), setColumnHidden() -
733*/ -
734void QTreeView::showColumn(int column) -
735{ -
736 Q_D(QTreeView); -
737 d->header->showSection(column); -
738} -
739 -
740/*! -
741 \fn void QTreeView::expand(const QModelIndex &index) -
742 -
743 Expands the model item specified by the \a index. -
744 -
745 \sa expanded() -
746*/ -
747void QTreeView::expand(const QModelIndex &index) -
748{ -
749 Q_D(QTreeView); -
750 if (!d->isIndexValid(index)) -
751 return; -
752 if (d->delayedPendingLayout) { -
753 //A complete relayout is going to be performed, just store the expanded index, no need to layout. -
754 if (d->storeExpanded(index)) -
755 emit expanded(index); -
756 return; -
757 } -
758 -
759 int i = d->viewIndex(index); -
760 if (i != -1) { // is visible -
761 d->expand(i, true); -
762 if (!d->isAnimating()) { -
763 updateGeometries(); -
764 d->viewport->update(); -
765 } -
766 } else if (d->storeExpanded(index)) { -
767 emit expanded(index); -
768 } -
769} -
770 -
771/*! -
772 \fn void QTreeView::collapse(const QModelIndex &index) -
773 -
774 Collapses the model item specified by the \a index. -
775 -
776 \sa collapsed() -
777*/ -
778void QTreeView::collapse(const QModelIndex &index) -
779{ -
780 Q_D(QTreeView); -
781 if (!d->isIndexValid(index)) -
782 return; -
783 //if the current item is now invisible, the autoscroll will expand the tree to see it, so disable the autoscroll -
784 d->delayedAutoScroll.stop(); -
785 -
786 if (d->delayedPendingLayout) { -
787 //A complete relayout is going to be performed, just un-store the expanded index, no need to layout. -
788 if (d->isPersistent(index) && d->expandedIndexes.remove(index)) -
789 emit collapsed(index); -
790 return; -
791 } -
792 int i = d->viewIndex(index); -
793 if (i != -1) { // is visible -
794 d->collapse(i, true); -
795 if (!d->isAnimating()) { -
796 updateGeometries(); -
797 viewport()->update(); -
798 } -
799 } else { -
800 if (d->isPersistent(index) && d->expandedIndexes.remove(index)) -
801 emit collapsed(index); -
802 } -
803} -
804 -
805/*! -
806 \fn bool QTreeView::isExpanded(const QModelIndex &index) const -
807 -
808 Returns true if the model item \a index is expanded; otherwise returns -
809 false. -
810 -
811 \sa expand(), expanded(), setExpanded() -
812*/ -
813bool QTreeView::isExpanded(const QModelIndex &index) const -
814{ -
815 Q_D(const QTreeView); -
816 return d->isIndexExpanded(index); -
817} -
818 -
819/*! -
820 Sets the item referred to by \a index to either collapse or expanded, -
821 depending on the value of \a expanded. -
822 -
823 \sa expanded(), expand(), isExpanded() -
824*/ -
825void QTreeView::setExpanded(const QModelIndex &index, bool expanded) -
826{ -
827 if (expanded) -
828 this->expand(index); -
829 else -
830 this->collapse(index); -
831} -
832 -
833/*! -
834 \since 4.2 -
835 \property QTreeView::sortingEnabled -
836 \brief whether sorting is enabled -
837 -
838 If this property is true, sorting is enabled for the tree; if the property -
839 is false, sorting is not enabled. The default value is false. -
840 -
841 \note In order to avoid performance issues, it is recommended that -
842 sorting is enabled \e after inserting the items into the tree. -
843 Alternatively, you could also insert the items into a list before inserting -
844 the items into the tree. -
845 -
846 \sa sortByColumn() -
847*/ -
848 -
849void QTreeView::setSortingEnabled(bool enable) -
850{ -
851 Q_D(QTreeView); -
852 header()->setSortIndicatorShown(enable); -
853 header()->setSectionsClickable(enable); -
854 if (enable) { -
855 //sortByColumn has to be called before we connect or set the sortingEnabled flag -
856 // because otherwise it will not call sort on the model. -
857 sortByColumn(header()->sortIndicatorSection(), header()->sortIndicatorOrder()); -
858 connect(header(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), -
859 this, SLOT(_q_sortIndicatorChanged(int,Qt::SortOrder)), Qt::UniqueConnection); -
860 } else { -
861 disconnect(header(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), -
862 this, SLOT(_q_sortIndicatorChanged(int,Qt::SortOrder))); -
863 } -
864 d->sortingEnabled = enable; -
865} -
866 -
867bool QTreeView::isSortingEnabled() const -
868{ -
869 Q_D(const QTreeView); -
870 return d->sortingEnabled; -
871} -
872 -
873/*! -
874 \since 4.2 -
875 \property QTreeView::animated -
876 \brief whether animations are enabled -
877 -
878 If this property is true the treeview will animate expandsion -
879 and collapsing of branches. If this property is false, the treeview -
880 will expand or collapse branches immediately without showing -
881 the animation. -
882 -
883 By default, this property is false. -
884*/ -
885 -
886void QTreeView::setAnimated(bool animate) -
887{ -
888 Q_D(QTreeView); -
889 d->animationsEnabled = animate; -
890} -
891 -
892bool QTreeView::isAnimated() const -
893{ -
894 Q_D(const QTreeView); -
895 return d->animationsEnabled; -
896} -
897 -
898/*! -
899 \since 4.2 -
900 \property QTreeView::allColumnsShowFocus -
901 \brief whether items should show keyboard focus using all columns -
902 -
903 If this property is true all columns will show focus, otherwise only -
904 one column will show focus. -
905 -
906 The default is false. -
907*/ -
908 -
909void QTreeView::setAllColumnsShowFocus(bool enable) -
910{ -
911 Q_D(QTreeView); -
912 if (d->allColumnsShowFocus == enable) -
913 return; -
914 d->allColumnsShowFocus = enable; -
915 d->viewport->update(); -
916} -
917 -
918bool QTreeView::allColumnsShowFocus() const -
919{ -
920 Q_D(const QTreeView); -
921 return d->allColumnsShowFocus; -
922} -
923 -
924/*! -
925 \property QTreeView::wordWrap -
926 \brief the item text word-wrapping policy -
927 \since 4.3 -
928 -
929 If this property is true then the item text is wrapped where -
930 necessary at word-breaks; otherwise it is not wrapped at all. -
931 This property is false by default. -
932 -
933 Note that even if wrapping is enabled, the cell will not be -
934 expanded to fit all text. Ellipsis will be inserted according to -
935 the current \l{QAbstractItemView::}{textElideMode}. -
936*/ -
937void QTreeView::setWordWrap(bool on) -
938{ -
939 Q_D(QTreeView); -
940 if (d->wrapItemText == on) -
941 return; -
942 d->wrapItemText = on; -
943 d->doDelayedItemsLayout(); -
944} -
945 -
946bool QTreeView::wordWrap() const -
947{ -
948 Q_D(const QTreeView); -
949 return d->wrapItemText; -
950} -
951 -
952 -
953/*! -
954 \reimp -
955 */ -
956void QTreeView::keyboardSearch(const QString &search) -
957{ -
958 Q_D(QTreeView); -
959 if (!d->model->rowCount(d->root) || !d->model->columnCount(d->root)) -
960 return; -
961 -
962 QModelIndex start; -
963 if (currentIndex().isValid()) -
964 start = currentIndex(); -
965 else -
966 start = d->model->index(0, 0, d->root); -
967 -
968 bool skipRow = false; -
969 bool keyboardTimeWasValid = d->keyboardInputTime.isValid(); -
970 qint64 keyboardInputTimeElapsed = d->keyboardInputTime.restart(); -
971 if (search.isEmpty() || !keyboardTimeWasValid -
972 || keyboardInputTimeElapsed > QApplication::keyboardInputInterval()) { -
973 d->keyboardInput = search; -
974 skipRow = currentIndex().isValid(); //if it is not valid we should really start at QModelIndex(0,0) -
975 } else { -
976 d->keyboardInput += search; -
977 } -
978 -
979 // special case for searches with same key like 'aaaaa' -
980 bool sameKey = false; -
981 if (d->keyboardInput.length() > 1) { -
982 int c = d->keyboardInput.count(d->keyboardInput.at(d->keyboardInput.length() - 1)); -
983 sameKey = (c == d->keyboardInput.length()); -
984 if (sameKey) -
985 skipRow = true; -
986 } -
987 -
988 // skip if we are searching for the same key or a new search started -
989 if (skipRow) { -
990 if (indexBelow(start).isValid()) -
991 start = indexBelow(start); -
992 else -
993 start = d->model->index(0, start.column(), d->root); -
994 } -
995 -
996 d->executePostedLayout(); -
997 int startIndex = d->viewIndex(start); -
998 if (startIndex <= -1) -
999 return; -
1000 -
1001 int previousLevel = -1; -
1002 int bestAbove = -1; -
1003 int bestBelow = -1; -
1004 QString searchString = sameKey ? QString(d->keyboardInput.at(0)) : d->keyboardInput; -
1005 for (int i = 0; i < d->viewItems.count(); ++i) { -
1006 if ((int)d->viewItems.at(i).level > previousLevel) { -
1007 QModelIndex searchFrom = d->viewItems.at(i).index; -
1008 if (start.column() > 0) -
1009 searchFrom = searchFrom.sibling(searchFrom.row(), start.column()); -
1010 if (searchFrom.parent() == start.parent()) -
1011 searchFrom = start; -
1012 QModelIndexList match = d->model->match(searchFrom, Qt::DisplayRole, searchString); -
1013 if (match.count()) { -
1014 int hitIndex = d->viewIndex(match.at(0)); -
1015 if (hitIndex >= 0 && hitIndex < startIndex) -
1016 bestAbove = bestAbove == -1 ? hitIndex : qMin(hitIndex, bestAbove); -
1017 else if (hitIndex >= startIndex) -
1018 bestBelow = bestBelow == -1 ? hitIndex : qMin(hitIndex, bestBelow); -
1019 } -
1020 } -
1021 previousLevel = d->viewItems.at(i).level; -
1022 } -
1023 -
1024 QModelIndex index; -
1025 if (bestBelow > -1) -
1026 index = d->viewItems.at(bestBelow).index; -
1027 else if (bestAbove > -1) -
1028 index = d->viewItems.at(bestAbove).index; -
1029 -
1030 if (start.column() > 0) -
1031 index = index.sibling(index.row(), start.column()); -
1032 -
1033 if (index.isValid()) { -
1034 QItemSelectionModel::SelectionFlags flags = (d->selectionMode == SingleSelection -
1035 ? QItemSelectionModel::SelectionFlags( -
1036 QItemSelectionModel::ClearAndSelect -
1037 |d->selectionBehaviorFlags()) -
1038 : QItemSelectionModel::SelectionFlags( -
1039 QItemSelectionModel::NoUpdate)); -
1040 selectionModel()->setCurrentIndex(index, flags); -
1041 } -
1042} -
1043 -
1044/*! -
1045 Returns the rectangle on the viewport occupied by the item at \a index. -
1046 If the index is not visible or explicitly hidden, the returned rectangle is invalid. -
1047*/ -
1048QRect QTreeView::visualRect(const QModelIndex &index) const -
1049{ -
1050 Q_D(const QTreeView); -
1051 -
1052 if (!d->isIndexValid(index) || isIndexHidden(index)) -
1053 return QRect(); -
1054 -
1055 d->executePostedLayout(); -
1056 -
1057 int vi = d->viewIndex(index); -
1058 if (vi < 0) -
1059 return QRect(); -
1060 -
1061 bool spanning = d->viewItems.at(vi).spanning; -
1062 -
1063 // if we have a spanning item, make the selection stretch from left to right -
1064 int x = (spanning ? 0 : columnViewportPosition(index.column())); -
1065 int w = (spanning ? d->header->length() : columnWidth(index.column())); -
1066 // handle indentation -
1067 if (index.column() == 0) { -
1068 int i = d->indentationForItem(vi); -
1069 w -= i; -
1070 if (!isRightToLeft()) -
1071 x += i; -
1072 } -
1073 -
1074 int y = d->coordinateForItem(vi); -
1075 int h = d->itemHeight(vi); -
1076 -
1077 return QRect(x, y, w, h); -
1078} -
1079 -
1080/*! -
1081 Scroll the contents of the tree view until the given model item -
1082 \a index is visible. The \a hint parameter specifies more -
1083 precisely where the item should be located after the -
1084 operation. -
1085 If any of the parents of the model item are collapsed, they will -
1086 be expanded to ensure that the model item is visible. -
1087*/ -
1088void QTreeView::scrollTo(const QModelIndex &index, ScrollHint hint) -
1089{ -
1090 Q_D(QTreeView);
executed (the execution status of this line is deduced): QTreeViewPrivate * const d = d_func();
-
1091 -
1092 if (!d->isIndexValid(index))
evaluated: !d->isIndexValid(index)
TRUEFALSE
yes
Evaluation Count:30
yes
Evaluation Count:5635
30-5635
1093 return;
executed: return;
Execution Count:30
30
1094 -
1095 d->executePostedLayout();
executed (the execution status of this line is deduced): d->executePostedLayout();
-
1096 d->updateScrollBars();
executed (the execution status of this line is deduced): d->updateScrollBars();
-
1097 -
1098 // Expand all parents if the parent(s) of the node are not expanded. -
1099 QModelIndex parent = index.parent();
executed (the execution status of this line is deduced): QModelIndex parent = index.parent();
-
1100 while (parent != d->root && parent.isValid() && state() == NoState && d->itemsExpandable) {
evaluated: parent != d->root
TRUEFALSE
yes
Evaluation Count:56
yes
Evaluation Count:5635
partially evaluated: parent.isValid()
TRUEFALSE
yes
Evaluation Count:56
no
Evaluation Count:0
partially evaluated: state() == NoState
TRUEFALSE
yes
Evaluation Count:56
no
Evaluation Count:0
partially evaluated: d->itemsExpandable
TRUEFALSE
yes
Evaluation Count:56
no
Evaluation Count:0
0-5635
1101 if (!isExpanded(parent))
evaluated: !isExpanded(parent)
TRUEFALSE
yes
Evaluation Count:7
yes
Evaluation Count:49
7-49
1102 expand(parent);
executed: expand(parent);
Execution Count:7
7
1103 parent = d->model->parent(parent);
executed (the execution status of this line is deduced): parent = d->model->parent(parent);
-
1104 }
executed: }
Execution Count:56
56
1105 -
1106 int item = d->viewIndex(index);
executed (the execution status of this line is deduced): int item = d->viewIndex(index);
-
1107 if (item < 0)
partially evaluated: item < 0
TRUEFALSE
no
Evaluation Count:0
yes
Evaluation Count:5635
0-5635
1108 return;
never executed: return;
0
1109 -
1110 QRect area = d->viewport->rect();
executed (the execution status of this line is deduced): QRect area = d->viewport->rect();
-
1111 -
1112 // vertical -
1113 if (verticalScrollMode() == QAbstractItemView::ScrollPerItem) {
evaluated: verticalScrollMode() == QAbstractItemView::ScrollPerItem
TRUEFALSE
yes
Evaluation Count:2897
yes
Evaluation Count:2738
2738-2897
1114 int top = verticalScrollBar()->value();
executed (the execution status of this line is deduced): int top = verticalScrollBar()->value();
-
1115 int bottom = top + verticalScrollBar()->pageStep();
executed (the execution status of this line is deduced): int bottom = top + verticalScrollBar()->pageStep();
-
1116 if (hint == EnsureVisible && item >= top && item < bottom) {
evaluated: hint == EnsureVisible
TRUEFALSE
yes
Evaluation Count:2889
yes
Evaluation Count:8
evaluated: item >= top
TRUEFALSE
yes
Evaluation Count:2882
yes
Evaluation Count:7
evaluated: item < bottom
TRUEFALSE
yes
Evaluation Count:2842
yes
Evaluation Count:40
7-2889
1117 // nothing to do -
1118 } else if (hint == PositionAtTop || (hint == EnsureVisible && item < top)) {
executed: }
Execution Count:2842
evaluated: hint == PositionAtTop
TRUEFALSE
yes
Evaluation Count:7
yes
Evaluation Count:48
evaluated: hint == EnsureVisible
TRUEFALSE
yes
Evaluation Count:47
yes
Evaluation Count:1
evaluated: item < top
TRUEFALSE
yes
Evaluation Count:7
yes
Evaluation Count:40
1-2842
1119 verticalScrollBar()->setValue(item);
executed (the execution status of this line is deduced): verticalScrollBar()->setValue(item);
-
1120 } else { // PositionAtBottom or PositionAtCenter
executed: }
Execution Count:14
14
1121 const int currentItemHeight = d->itemHeight(item);
executed (the execution status of this line is deduced): const int currentItemHeight = d->itemHeight(item);
-
1122 int y = (hint == PositionAtCenter
partially evaluated: hint == PositionAtCenter
TRUEFALSE
no
Evaluation Count:0
yes
Evaluation Count:41
0-41
1123 //we center on the current item with a preference to the top item (ie. -1)
executed (the execution status of this line is deduced):
-
1124 ? area.height() / 2 + currentItemHeight - 1
executed (the execution status of this line is deduced): ? area.height() / 2 + currentItemHeight - 1
-
1125 //otherwise we simply take the whole space
executed (the execution status of this line is deduced):
-
1126 : area.height());
executed (the execution status of this line is deduced): : area.height());
-
1127 if (y > currentItemHeight) {
partially evaluated: y > currentItemHeight
TRUEFALSE
yes
Evaluation Count:41
no
Evaluation Count:0
0-41
1128 while (item >= 0) {
evaluated: item >= 0
TRUEFALSE
yes
Evaluation Count:357
yes
Evaluation Count:1
1-357
1129 y -= d->itemHeight(item);
executed (the execution status of this line is deduced): y -= d->itemHeight(item);
-
1130 if (y < 0) { //there is no more space left
evaluated: y < 0
TRUEFALSE
yes
Evaluation Count:40
yes
Evaluation Count:317
40-317
1131 item++;
executed (the execution status of this line is deduced): item++;
-
1132 break;
executed: break;
Execution Count:40
40
1133 } -
1134 item--;
executed (the execution status of this line is deduced): item--;
-
1135 }
executed: }
Execution Count:317
317
1136 }
executed: }
Execution Count:41
41
1137 verticalScrollBar()->setValue(item);
executed (the execution status of this line is deduced): verticalScrollBar()->setValue(item);
-
1138 }
executed: }
Execution Count:41
41
1139 } else { // ScrollPerPixel -
1140 QRect rect(columnViewportPosition(index.column()),
executed (the execution status of this line is deduced): QRect rect(columnViewportPosition(index.column()),
-
1141 d->coordinateForItem(item), // ### slow for items outside the view
executed (the execution status of this line is deduced): d->coordinateForItem(item),
-
1142 columnWidth(index.column()),
executed (the execution status of this line is deduced): columnWidth(index.column()),
-
1143 d->itemHeight(item));
executed (the execution status of this line is deduced): d->itemHeight(item));
-
1144 -
1145 if (rect.isEmpty()) {
partially evaluated: rect.isEmpty()
TRUEFALSE
no
Evaluation Count:0
yes
Evaluation Count:2738
0-2738
1146 // nothing to do -
1147 } else if (hint == EnsureVisible && area.contains(rect)) {
never executed: }
evaluated: hint == EnsureVisible
TRUEFALSE
yes
Evaluation Count:2736
yes
Evaluation Count:2
evaluated: area.contains(rect)
TRUEFALSE
yes
Evaluation Count:461
yes
Evaluation Count:2275
0-2736
1148 d->viewport->update(rect);
executed (the execution status of this line is deduced): d->viewport->update(rect);
-
1149 // nothing to do -
1150 } else {
executed: }
Execution Count:461
461
1151 bool above = (hint == EnsureVisible
evaluated: hint == EnsureVisible
TRUEFALSE
yes
Evaluation Count:2275
yes
Evaluation Count:2
2-2275
1152 && (rect.top() < area.top()
evaluated: rect.top() < area.top()
TRUEFALSE
yes
Evaluation Count:4
yes
Evaluation Count:2271
4-2271
1153 || area.height() < rect.height()));
partially evaluated: area.height() < rect.height()
TRUEFALSE
no
Evaluation Count:0
yes
Evaluation Count:2271
0-2271
1154 bool below = (hint == EnsureVisible
evaluated: hint == EnsureVisible
TRUEFALSE
yes
Evaluation Count:2275
yes
Evaluation Count:2
2-2275
1155 && rect.bottom() > area.bottom()
evaluated: rect.bottom() > area.bottom()
TRUEFALSE
yes
Evaluation Count:1873
yes
Evaluation Count:402
402-1873
1156 && rect.height() < area.height());
partially evaluated: rect.height() < area.height()
TRUEFALSE
yes
Evaluation Count:1873
no
Evaluation Count:0
0-1873
1157 -
1158 int verticalValue = verticalScrollBar()->value();
executed (the execution status of this line is deduced): int verticalValue = verticalScrollBar()->value();
-
1159 if (hint == PositionAtTop || above)
evaluated: hint == PositionAtTop
TRUEFALSE
yes
Evaluation Count:2
yes
Evaluation Count:2275
evaluated: above
TRUEFALSE
yes
Evaluation Count:4
yes
Evaluation Count:2271
2-2275
1160 verticalValue += rect.top();
executed: verticalValue += rect.top();
Execution Count:6
6
1161 else if (hint == PositionAtBottom || below)
partially evaluated: hint == PositionAtBottom
TRUEFALSE
no
Evaluation Count:0
yes
Evaluation Count:2271
evaluated: below
TRUEFALSE
yes
Evaluation Count:1873
yes
Evaluation Count:398
0-2271
1162 verticalValue += rect.bottom() - area.height();
executed: verticalValue += rect.bottom() - area.height();
Execution Count:1873
1873
1163 else if (hint == PositionAtCenter)
partially evaluated: hint == PositionAtCenter
TRUEFALSE
no
Evaluation Count:0
yes
Evaluation Count:398
0-398
1164 verticalValue += rect.top() - ((area.height() - rect.height()) / 2);
never executed: verticalValue += rect.top() - ((area.height() - rect.height()) / 2);
0
1165 verticalScrollBar()->setValue(verticalValue);
executed (the execution status of this line is deduced): verticalScrollBar()->setValue(verticalValue);
-
1166 }
executed: }
Execution Count:2277
2277
1167 } -
1168 // horizontal -
1169 int viewportWidth = d->viewport->width();
executed (the execution status of this line is deduced): int viewportWidth = d->viewport->width();
-
1170 int horizontalOffset = d->header->offset();
executed (the execution status of this line is deduced): int horizontalOffset = d->header->offset();
-
1171 int horizontalPosition = d->header->sectionPosition(index.column());
executed (the execution status of this line is deduced): int horizontalPosition = d->header->sectionPosition(index.column());
-
1172 int cellWidth = d->header->sectionSize(index.column());
executed (the execution status of this line is deduced): int cellWidth = d->header->sectionSize(index.column());
-
1173 -
1174 if (hint == PositionAtCenter) {
partially evaluated: hint == PositionAtCenter
TRUEFALSE
no
Evaluation Count:0
yes
Evaluation Count:5635
0-5635
1175 horizontalScrollBar()->setValue(horizontalPosition - ((viewportWidth - cellWidth) / 2));
never executed (the execution status of this line is deduced): horizontalScrollBar()->setValue(horizontalPosition - ((viewportWidth - cellWidth) / 2));
-
1176 } else {
never executed: }
0
1177 if (horizontalPosition - horizontalOffset < 0 || cellWidth > viewportWidth)
evaluated: horizontalPosition - horizontalOffset < 0
TRUEFALSE
yes
Evaluation Count:2355
yes
Evaluation Count:3280
evaluated: cellWidth > viewportWidth
TRUEFALSE
yes
Evaluation Count:25
yes
Evaluation Count:3255
25-3280
1178 horizontalScrollBar()->setValue(horizontalPosition);
executed: horizontalScrollBar()->setValue(horizontalPosition);
Execution Count:2380
2380
1179 else if (horizontalPosition - horizontalOffset + cellWidth > viewportWidth)
evaluated: horizontalPosition - horizontalOffset + cellWidth > viewportWidth
TRUEFALSE
yes
Evaluation Count:1317
yes
Evaluation Count:1938
1317-1938
1180 horizontalScrollBar()->setValue(horizontalPosition - viewportWidth + cellWidth);
executed: horizontalScrollBar()->setValue(horizontalPosition - viewportWidth + cellWidth);
Execution Count:1317
1317
1181 } -
1182} -
1183 -
1184/*! -
1185 \reimp -
1186*/ -
1187void QTreeView::timerEvent(QTimerEvent *event) -
1188{ -
1189 Q_D(QTreeView); -
1190 if (event->timerId() == d->columnResizeTimerID) { -
1191 updateGeometries(); -
1192 killTimer(d->columnResizeTimerID); -
1193 d->columnResizeTimerID = 0; -
1194 QRect rect; -
1195 int viewportHeight = d->viewport->height(); -
1196 int viewportWidth = d->viewport->width(); -
1197 for (int i = d->columnsToUpdate.size() - 1; i >= 0; --i) { -
1198 int column = d->columnsToUpdate.at(i); -
1199 int x = columnViewportPosition(column); -
1200 if (isRightToLeft()) -
1201 rect |= QRect(0, 0, x + columnWidth(column), viewportHeight); -
1202 else -
1203 rect |= QRect(x, 0, viewportWidth - x, viewportHeight); -
1204 } -
1205 d->viewport->update(rect.normalized()); -
1206 d->columnsToUpdate.clear(); -
1207 } else if (event->timerId() == d->openTimer.timerId()) { -
1208 QPoint pos = d->viewport->mapFromGlobal(QCursor::pos()); -
1209 if (state() == QAbstractItemView::DraggingState -
1210 && d->viewport->rect().contains(pos)) { -
1211 QModelIndex index = indexAt(pos); -
1212 setExpanded(index, !isExpanded(index)); -
1213 } -
1214 d->openTimer.stop(); -
1215 } -
1216 -
1217 QAbstractItemView::timerEvent(event); -
1218} -
1219 -
1220/*! -
1221 \reimp -
1222*/ -
1223#ifndef QT_NO_DRAGANDDROP -
1224void QTreeView::dragMoveEvent(QDragMoveEvent *event) -
1225{ -
1226 Q_D(QTreeView); -
1227 if (d->autoExpandDelay >= 0) -
1228 d->openTimer.start(d->autoExpandDelay, this); -
1229 QAbstractItemView::dragMoveEvent(event); -
1230} -
1231#endif -
1232 -
1233/*! -
1234 \reimp -
1235*/ -
1236bool QTreeView::viewportEvent(QEvent *event) -
1237{ -
1238 Q_D(QTreeView); -
1239 switch (event->type()) { -
1240 case QEvent::HoverEnter: -
1241 case QEvent::HoverLeave: -
1242 case QEvent::HoverMove: { -
1243 QHoverEvent *he = static_cast<QHoverEvent*>(event); -
1244 int oldBranch = d->hoverBranch; -
1245 d->hoverBranch = d->itemDecorationAt(he->pos()); -
1246 QModelIndex newIndex = indexAt(he->pos()); -
1247 if (d->hover != newIndex || d->hoverBranch != oldBranch) { -
1248 // Update the whole hovered over row. No need to update the old hovered -
1249 // row, that is taken care in superclass hover handling. -
1250 QRect rect = visualRect(newIndex); -
1251 rect.setX(0); -
1252 rect.setWidth(viewport()->width()); -
1253 viewport()->update(rect); -
1254 } -
1255 break; } -
1256 default: -
1257 break; -
1258 } -
1259 return QAbstractItemView::viewportEvent(event); -
1260} -
1261 -
1262/*! -
1263 \reimp -
1264*/ -
1265void QTreeView::paintEvent(QPaintEvent *event) -
1266{ -
1267 Q_D(QTreeView); -
1268 d->executePostedLayout(); -
1269 QPainter painter(viewport()); -
1270#ifndef QT_NO_ANIMATION -
1271 if (d->isAnimating()) { -
1272 drawTree(&painter, event->region() - d->animatedOperation.rect()); -
1273 d->drawAnimatedOperation(&painter); -
1274 } else -
1275#endif //QT_NO_ANIMATION -
1276 { -
1277 drawTree(&painter, event->region()); -
1278#ifndef QT_NO_DRAGANDDROP -
1279 d->paintDropIndicator(&painter); -
1280#endif -
1281 } -
1282} -
1283 -
1284void QTreeViewPrivate::paintAlternatingRowColors(QPainter *painter, QStyleOptionViewItem *option, int y, int bottom) const -
1285{ -
1286 Q_Q(const QTreeView); -
1287 if (!alternatingColors || !q->style()->styleHint(QStyle::SH_ItemView_PaintAlternatingRowColorsForEmptyArea, option, q)) -
1288 return; -
1289 int rowHeight = defaultItemHeight; -
1290 if (rowHeight <= 0) { -
1291 rowHeight = itemDelegate->sizeHint(*option, QModelIndex()).height(); -
1292 if (rowHeight <= 0) -
1293 return; -
1294 } -
1295 while (y <= bottom) { -
1296 option->rect.setRect(0, y, viewport->width(), rowHeight); -
1297 if (current & 1) { -
1298 option->features |= QStyleOptionViewItem::Alternate; -
1299 } else { -
1300 option->features &= ~QStyleOptionViewItem::Alternate; -
1301 } -
1302 ++current; -
1303 q->style()->drawPrimitive(QStyle::PE_PanelItemViewRow, option, painter, q); -
1304 y += rowHeight; -
1305 } -
1306} -
1307 -
1308bool QTreeViewPrivate::expandOrCollapseItemAtPos(const QPoint &pos) -
1309{ -
1310 Q_Q(QTreeView); -
1311 // we want to handle mousePress in EditingState (persistent editors) -
1312 if ((state != QAbstractItemView::NoState -
1313 && state != QAbstractItemView::EditingState) -
1314 || !viewport->rect().contains(pos)) -
1315 return true; -
1316 -
1317 int i = itemDecorationAt(pos); -
1318 if ((i != -1) && itemsExpandable && hasVisibleChildren(viewItems.at(i).index)) { -
1319 if (viewItems.at(i).expanded) -
1320 collapse(i, true); -
1321 else -
1322 expand(i, true); -
1323 if (!isAnimating()) { -
1324 q->updateGeometries(); -
1325 viewport->update(); -
1326 } -
1327 return true; -
1328 } -
1329 return false; -
1330} -
1331 -
1332void QTreeViewPrivate::_q_modelDestroyed() -
1333{ -
1334 //we need to clear the viewItems because it contains QModelIndexes to -
1335 //the model currently being destroyed -
1336 viewItems.clear(); -
1337 QAbstractItemViewPrivate::_q_modelDestroyed(); -
1338} -
1339 -
1340/*! -
1341 \reimp -
1342 -
1343 We have a QTreeView way of knowing what elements are on the viewport -
1344*/ -
1345QItemViewPaintPairs QTreeViewPrivate::draggablePaintPairs(const QModelIndexList &indexes, QRect *r) const -
1346{ -
1347 Q_ASSERT(r); -
1348 Q_Q(const QTreeView); -
1349 if (spanningIndexes.isEmpty()) -
1350 return QAbstractItemViewPrivate::draggablePaintPairs(indexes, r); -
1351 QModelIndexList list; -
1352 foreach (const QModelIndex &idx, indexes) { -
1353 if (idx.column() > 0 && q->isFirstColumnSpanned(idx.row(), idx.parent())) -
1354 continue; -
1355 list << idx; -
1356 } -
1357 return QAbstractItemViewPrivate::draggablePaintPairs(list, r); -
1358} -
1359 -
1360void QTreeViewPrivate::adjustViewOptionsForIndex(QStyleOptionViewItem *option, const QModelIndex &current) const -
1361{ -
1362 const int row = viewIndex(current); // get the index in viewItems[] -
1363 option->state = option->state | (viewItems.at(row).expanded ? QStyle::State_Open : QStyle::State_None) -
1364 | (viewItems.at(row).hasChildren ? QStyle::State_Children : QStyle::State_None) -
1365 | (viewItems.at(row).hasMoreSiblings ? QStyle::State_Sibling : QStyle::State_None); -
1366 -
1367 option->showDecorationSelected = (selectionBehavior & QTreeView::SelectRows) -
1368 || option->showDecorationSelected; -
1369 -
1370 QVector<int> logicalIndices; // index = visual index of visible columns only. data = logical index. -
1371 QVector<QStyleOptionViewItem::ViewItemPosition> viewItemPosList; // vector of left/middle/end for each logicalIndex, visible columns only. -
1372 const bool spanning = viewItems.at(row).spanning; -
1373 const int left = (spanning ? header->visualIndex(0) : 0); -
1374 const int right = (spanning ? header->visualIndex(0) : header->count() - 1 ); -
1375 calcLogicalIndices(&logicalIndices, &viewItemPosList, left, right); -
1376 -
1377 int columnIndex = 0; -
1378 for (int visualIndex = 0; visualIndex < current.column(); ++visualIndex) { -
1379 int logicalIndex = header->logicalIndex(visualIndex); -
1380 if (!header->isSectionHidden(logicalIndex)) { -
1381 ++columnIndex; -
1382 } -
1383 } -
1384 -
1385 option->viewItemPosition = viewItemPosList.at(columnIndex); -
1386} -
1387 -
1388 -
1389/*! -
1390 \since 4.2 -
1391 Draws the part of the tree intersecting the given \a region using the specified -
1392 \a painter. -
1393 -
1394 \sa paintEvent() -
1395*/ -
1396void QTreeView::drawTree(QPainter *painter, const QRegion &region) const -
1397{ -
1398 Q_D(const QTreeView); -
1399 const QVector<QTreeViewItem> viewItems = d->viewItems; -
1400 -
1401 QStyleOptionViewItem option = d->viewOptions(); -
1402 const QStyle::State state = option.state; -
1403 d->current = 0; -
1404 -
1405 if (viewItems.count() == 0 || d->header->count() == 0 || !d->itemDelegate) { -
1406 d->paintAlternatingRowColors(painter, &option, 0, region.boundingRect().bottom()+1); -
1407 return; -
1408 } -
1409 -
1410 int firstVisibleItemOffset = 0; -
1411 const int firstVisibleItem = d->firstVisibleItem(&firstVisibleItemOffset); -
1412 if (firstVisibleItem < 0) { -
1413 d->paintAlternatingRowColors(painter, &option, 0, region.boundingRect().bottom()+1); -
1414 return; -
1415 } -
1416 -
1417 const int viewportWidth = d->viewport->width(); -
1418 -
1419 QPoint hoverPos = d->viewport->mapFromGlobal(QCursor::pos()); -
1420 d->hoverBranch = d->itemDecorationAt(hoverPos); -
1421 -
1422 QVector<QRect> rects = region.rects(); -
1423 QVector<int> drawn; -
1424 bool multipleRects = (rects.size() > 1); -
1425 for (int a = 0; a < rects.size(); ++a) { -
1426 const QRect area = (multipleRects -
1427 ? QRect(0, rects.at(a).y(), viewportWidth, rects.at(a).height()) -
1428 : rects.at(a)); -
1429 d->leftAndRight = d->startAndEndColumns(area); -
1430 -
1431 int i = firstVisibleItem; // the first item at the top of the viewport -
1432 int y = firstVisibleItemOffset; // we may only see part of the first item -
1433 -
1434 // start at the top of the viewport and iterate down to the update area -
1435 for (; i < viewItems.count(); ++i) { -
1436 const int itemHeight = d->itemHeight(i); -
1437 if (y + itemHeight > area.top()) -
1438 break; -
1439 y += itemHeight; -
1440 } -
1441 -
1442 // paint the visible rows -
1443 for (; i < viewItems.count() && y <= area.bottom(); ++i) { -
1444 const int itemHeight = d->itemHeight(i); -
1445 option.rect.setRect(0, y, viewportWidth, itemHeight); -
1446 option.state = state | (viewItems.at(i).expanded ? QStyle::State_Open : QStyle::State_None) -
1447 | (viewItems.at(i).hasChildren ? QStyle::State_Children : QStyle::State_None) -
1448 | (viewItems.at(i).hasMoreSiblings ? QStyle::State_Sibling : QStyle::State_None); -
1449 d->current = i; -
1450 d->spanning = viewItems.at(i).spanning; -
1451 if (!multipleRects || !drawn.contains(i)) { -
1452 drawRow(painter, option, viewItems.at(i).index); -
1453 if (multipleRects) // even if the rect only intersects the item, -
1454 drawn.append(i); // the entire item will be painted -
1455 } -
1456 y += itemHeight; -
1457 } -
1458 -
1459 if (y <= area.bottom()) { -
1460 d->current = i; -
1461 d->paintAlternatingRowColors(painter, &option, y, area.bottom()); -
1462 } -
1463 } -
1464} -
1465 -
1466/// ### move to QObject :) -
1467static inline bool ancestorOf(QObject *widget, QObject *other) -
1468{ -
1469 for (QObject *parent = other; parent != 0; parent = parent->parent()) { -
1470 if (parent == widget) -
1471 return true; -
1472 } -
1473 return false; -
1474} -
1475 -
1476void QTreeViewPrivate::calcLogicalIndices(QVector<int> *logicalIndices, QVector<QStyleOptionViewItem::ViewItemPosition> *itemPositions, int left, int right) const -
1477{ -
1478 const int columnCount = header->count(); -
1479 /* 'left' and 'right' are the left-most and right-most visible visual indices. -
1480 Compute the first visible logical indices before and after the left and right. -
1481 We will use these values to determine the QStyleOptionViewItem::viewItemPosition. */ -
1482 int logicalIndexBeforeLeft = -1, logicalIndexAfterRight = -1; -
1483 for (int visualIndex = left - 1; visualIndex >= 0; --visualIndex) { -
1484 int logicalIndex = header->logicalIndex(visualIndex); -
1485 if (!header->isSectionHidden(logicalIndex)) { -
1486 logicalIndexBeforeLeft = logicalIndex; -
1487 break; -
1488 } -
1489 } -
1490 -
1491 for (int visualIndex = left; visualIndex < columnCount; ++visualIndex) { -
1492 int logicalIndex = header->logicalIndex(visualIndex); -
1493 if (!header->isSectionHidden(logicalIndex)) { -
1494 if (visualIndex > right) { -
1495 logicalIndexAfterRight = logicalIndex; -
1496 break; -
1497 } -
1498 logicalIndices->append(logicalIndex); -
1499 } -
1500 } -
1501 -
1502 itemPositions->resize(logicalIndices->count()); -
1503 for (int currentLogicalSection = 0; currentLogicalSection < logicalIndices->count(); ++currentLogicalSection) { -
1504 const int headerSection = logicalIndices->at(currentLogicalSection); -
1505 // determine the viewItemPosition depending on the position of column 0 -
1506 int nextLogicalSection = currentLogicalSection + 1 >= logicalIndices->count() -
1507 ? logicalIndexAfterRight -
1508 : logicalIndices->at(currentLogicalSection + 1); -
1509 int prevLogicalSection = currentLogicalSection - 1 < 0 -
1510 ? logicalIndexBeforeLeft -
1511 : logicalIndices->at(currentLogicalSection - 1); -
1512 QStyleOptionViewItem::ViewItemPosition pos; -
1513 if (columnCount == 1 || (nextLogicalSection == 0 && prevLogicalSection == -1) -
1514 || (headerSection == 0 && nextLogicalSection == -1) || spanning) -
1515 pos = QStyleOptionViewItem::OnlyOne; -
1516 else if (headerSection == 0 || (nextLogicalSection != 0 && prevLogicalSection == -1)) -
1517 pos = QStyleOptionViewItem::Beginning; -
1518 else if (nextLogicalSection == 0 || nextLogicalSection == -1) -
1519 pos = QStyleOptionViewItem::End; -
1520 else -
1521 pos = QStyleOptionViewItem::Middle; -
1522 (*itemPositions)[currentLogicalSection] = pos; -
1523 } -
1524} -
1525 -
1526 -
1527/*! -
1528 Draws the row in the tree view that contains the model item \a index, -
1529 using the \a painter given. The \a option control how the item is -
1530 displayed. -
1531 -
1532 \sa setAlternatingRowColors() -
1533*/ -
1534void QTreeView::drawRow(QPainter *painter, const QStyleOptionViewItem &option, -
1535 const QModelIndex &index) const -
1536{ -
1537 Q_D(const QTreeView); -
1538 QStyleOptionViewItem opt = option; -
1539 const QPoint offset = d->scrollDelayOffset; -
1540 const int y = option.rect.y() + offset.y(); -
1541 const QModelIndex parent = index.parent(); -
1542 const QHeaderView *header = d->header; -
1543 const QModelIndex current = currentIndex(); -
1544 const QModelIndex hover = d->hover; -
1545 const bool reverse = isRightToLeft(); -
1546 const QStyle::State state = opt.state; -
1547 const bool spanning = d->spanning; -
1548 const int left = (spanning ? header->visualIndex(0) : d->leftAndRight.first); -
1549 const int right = (spanning ? header->visualIndex(0) : d->leftAndRight.second); -
1550 const bool alternate = d->alternatingColors; -
1551 const bool enabled = (state & QStyle::State_Enabled) != 0; -
1552 const bool allColumnsShowFocus = d->allColumnsShowFocus; -
1553 -
1554 -
1555 // when the row contains an index widget which has focus, -
1556 // we want to paint the entire row as active -
1557 bool indexWidgetHasFocus = false; -
1558 if ((current.row() == index.row()) && !d->editorIndexHash.isEmpty()) { -
1559 const int r = index.row(); -
1560 QWidget *fw = QApplication::focusWidget(); -
1561 for (int c = 0; c < header->count(); ++c) { -
1562 QModelIndex idx = d->model->index(r, c, parent); -
1563 if (QWidget *editor = indexWidget(idx)) { -
1564 if (ancestorOf(editor, fw)) { -
1565 indexWidgetHasFocus = true; -
1566 break; -
1567 } -
1568 } -
1569 } -
1570 } -
1571 -
1572 const bool widgetHasFocus = hasFocus(); -
1573 bool currentRowHasFocus = false; -
1574 if (allColumnsShowFocus && widgetHasFocus && current.isValid()) { -
1575 // check if the focus index is before or after the visible columns -
1576 const int r = index.row(); -
1577 for (int c = 0; c < left && !currentRowHasFocus; ++c) { -
1578 QModelIndex idx = d->model->index(r, c, parent); -
1579 currentRowHasFocus = (idx == current); -
1580 } -
1581 QModelIndex parent = d->model->parent(index); -
1582 for (int c = right; c < header->count() && !currentRowHasFocus; ++c) { -
1583 currentRowHasFocus = (d->model->index(r, c, parent) == current); -
1584 } -
1585 } -
1586 -
1587 // ### special case: treeviews with multiple columns draw -
1588 // the selections differently than with only one column -
1589 opt.showDecorationSelected = (d->selectionBehavior & SelectRows) -
1590 || option.showDecorationSelected; -
1591 -
1592 int width, height = option.rect.height(); -
1593 int position; -
1594 QModelIndex modelIndex; -
1595 const bool hoverRow = selectionBehavior() == QAbstractItemView::SelectRows -
1596 && index.parent() == hover.parent() -
1597 && index.row() == hover.row(); -
1598 -
1599 QVector<int> logicalIndices; -
1600 QVector<QStyleOptionViewItem::ViewItemPosition> viewItemPosList; // vector of left/middle/end for each logicalIndex -
1601 d->calcLogicalIndices(&logicalIndices, &viewItemPosList, left, right); -
1602 -
1603 for (int currentLogicalSection = 0; currentLogicalSection < logicalIndices.count(); ++currentLogicalSection) { -
1604 int headerSection = logicalIndices.at(currentLogicalSection); -
1605 position = columnViewportPosition(headerSection) + offset.x(); -
1606 width = header->sectionSize(headerSection); -
1607 -
1608 if (spanning) { -
1609 int lastSection = header->logicalIndex(header->count() - 1); -
1610 if (!reverse) { -
1611 width = columnViewportPosition(lastSection) + header->sectionSize(lastSection) - position; -
1612 } else { -
1613 width += position - columnViewportPosition(lastSection); -
1614 position = columnViewportPosition(lastSection); -
1615 } -
1616 } -
1617 -
1618 modelIndex = d->model->index(index.row(), headerSection, parent); -
1619 if (!modelIndex.isValid()) -
1620 continue; -
1621 opt.state = state; -
1622 -
1623 opt.viewItemPosition = viewItemPosList.at(currentLogicalSection); -
1624 -
1625 // fake activeness when row editor has focus -
1626 if (indexWidgetHasFocus) -
1627 opt.state |= QStyle::State_Active; -
1628 -
1629 if (d->selectionModel->isSelected(modelIndex)) -
1630 opt.state |= QStyle::State_Selected; -
1631 if (widgetHasFocus && (current == modelIndex)) { -
1632 if (allColumnsShowFocus) -
1633 currentRowHasFocus = true; -
1634 else -
1635 opt.state |= QStyle::State_HasFocus; -
1636 } -
1637 if ((hoverRow || modelIndex == hover) -
1638 && (option.showDecorationSelected || (d->hoverBranch == -1))) -
1639 opt.state |= QStyle::State_MouseOver; -
1640 else -
1641 opt.state &= ~QStyle::State_MouseOver; -
1642 -
1643 if (enabled) { -
1644 QPalette::ColorGroup cg; -
1645 if ((d->model->flags(modelIndex) & Qt::ItemIsEnabled) == 0) { -
1646 opt.state &= ~QStyle::State_Enabled; -
1647 cg = QPalette::Disabled; -
1648 } else if (opt.state & QStyle::State_Active) { -
1649 cg = QPalette::Active; -
1650 } else { -
1651 cg = QPalette::Inactive; -
1652 } -
1653 opt.palette.setCurrentColorGroup(cg); -
1654 } -
1655 -
1656 if (alternate) { -
1657 if (d->current & 1) { -
1658 opt.features |= QStyleOptionViewItem::Alternate; -
1659 } else { -
1660 opt.features &= ~QStyleOptionViewItem::Alternate; -
1661 } -
1662 } -
1663 -
1664 /* Prior to Qt 4.3, the background of the branch (in selected state and -
1665 alternate row color was provided by the view. For backward compatibility, -
1666 this is now delegated to the style using PE_PanelViewItemRow which -
1667 does the appropriate fill */ -
1668 if (headerSection == 0) { -
1669 const int i = d->indentationForItem(d->current); -
1670 QRect branches(reverse ? position + width - i : position, y, i, height); -
1671 const bool setClipRect = branches.width() > width; -
1672 if (setClipRect) { -
1673 painter->save(); -
1674 painter->setClipRect(QRect(position, y, width, height)); -
1675 } -
1676 // draw background for the branch (selection + alternate row) -
1677 opt.rect = branches; -
1678 style()->drawPrimitive(QStyle::PE_PanelItemViewRow, &opt, painter, this); -
1679 -
1680 // draw background of the item (only alternate row). rest of the background -
1681 // is provided by the delegate -
1682 QStyle::State oldState = opt.state; -
1683 opt.state &= ~QStyle::State_Selected; -
1684 opt.rect.setRect(reverse ? position : i + position, y, width - i, height); -
1685 style()->drawPrimitive(QStyle::PE_PanelItemViewRow, &opt, painter, this); -
1686 opt.state = oldState; -
1687 -
1688 if (d->indent != 0) -
1689 drawBranches(painter, branches, index); -
1690 if (setClipRect) -
1691 painter->restore(); -
1692 } else { -
1693 QStyle::State oldState = opt.state; -
1694 opt.state &= ~QStyle::State_Selected; -
1695 opt.rect.setRect(position, y, width, height); -
1696 style()->drawPrimitive(QStyle::PE_PanelItemViewRow, &opt, painter, this); -
1697 opt.state = oldState; -
1698 } -
1699 -
1700 d->delegateForIndex(modelIndex)->paint(painter, opt, modelIndex); -
1701 } -
1702 -
1703 if (currentRowHasFocus) { -
1704 QStyleOptionFocusRect o; -
1705 o.QStyleOption::operator=(option); -
1706 o.state |= QStyle::State_KeyboardFocusChange; -
1707 QPalette::ColorGroup cg = (option.state & QStyle::State_Enabled) -
1708 ? QPalette::Normal : QPalette::Disabled; -
1709 o.backgroundColor = option.palette.color(cg, d->selectionModel->isSelected(index) -
1710 ? QPalette::Highlight : QPalette::Background); -
1711 int x = 0; -
1712 if (!option.showDecorationSelected) -
1713 x = header->sectionPosition(0) + d->indentationForItem(d->current); -
1714 QRect focusRect(x - header->offset(), y, header->length() - x, height); -
1715 o.rect = style()->visualRect(layoutDirection(), d->viewport->rect(), focusRect); -
1716 style()->drawPrimitive(QStyle::PE_FrameFocusRect, &o, painter); -
1717 // if we show focus on all columns and the first section is moved, -
1718 // we have to split the focus rect into two rects -
1719 if (allColumnsShowFocus && !option.showDecorationSelected -
1720 && header->sectionsMoved() && (header->visualIndex(0) != 0)) { -
1721 QRect sectionRect(0, y, header->sectionPosition(0), height); -
1722 o.rect = style()->visualRect(layoutDirection(), d->viewport->rect(), sectionRect); -
1723 style()->drawPrimitive(QStyle::PE_FrameFocusRect, &o, painter); -
1724 } -
1725 } -
1726} -
1727 -
1728/*! -
1729 Draws the branches in the tree view on the same row as the model item -
1730 \a index, using the \a painter given. The branches are drawn in the -
1731 rectangle specified by \a rect. -
1732*/ -
1733void QTreeView::drawBranches(QPainter *painter, const QRect &rect, -
1734 const QModelIndex &index) const -
1735{ -
1736 Q_D(const QTreeView); -
1737 const bool reverse = isRightToLeft(); -
1738 const int indent = d->indent; -
1739 const int outer = d->rootDecoration ? 0 : 1; -
1740 const int item = d->current; -
1741 const QTreeViewItem &viewItem = d->viewItems.at(item); -
1742 int level = viewItem.level; -
1743 QRect primitive(reverse ? rect.left() : rect.right() + 1, rect.top(), indent, rect.height()); -
1744 -
1745 QModelIndex parent = index.parent(); -
1746 QModelIndex current = parent; -
1747 QModelIndex ancestor = current.parent(); -
1748 -
1749 QStyleOptionViewItem opt = viewOptions(); -
1750 QStyle::State extraFlags = QStyle::State_None; -
1751 if (isEnabled()) -
1752 extraFlags |= QStyle::State_Enabled; -
1753 if (window()->isActiveWindow()) -
1754 extraFlags |= QStyle::State_Active; -
1755 QPoint oldBO = painter->brushOrigin(); -
1756 if (verticalScrollMode() == QAbstractItemView::ScrollPerPixel) -
1757 painter->setBrushOrigin(QPoint(0, verticalOffset())); -
1758 -
1759 if (d->alternatingColors) { -
1760 if (d->current & 1) { -
1761 opt.features |= QStyleOptionViewItem::Alternate; -
1762 } else { -
1763 opt.features &= ~QStyleOptionViewItem::Alternate; -
1764 } -
1765 } -
1766 -
1767 // When hovering over a row, pass State_Hover for painting the branch -
1768 // indicators if it has the decoration (aka branch) selected. -
1769 bool hoverRow = selectionBehavior() == QAbstractItemView::SelectRows -
1770 && opt.showDecorationSelected -
1771 && index.parent() == d->hover.parent() -
1772 && index.row() == d->hover.row(); -
1773 -
1774 if (d->selectionModel->isSelected(index)) -
1775 extraFlags |= QStyle::State_Selected; -
1776 -
1777 if (level >= outer) { -
1778 // start with the innermost branch -
1779 primitive.moveLeft(reverse ? primitive.left() : primitive.left() - indent); -
1780 opt.rect = primitive; -
1781 -
1782 const bool expanded = viewItem.expanded; -
1783 const bool children = viewItem.hasChildren; -
1784 bool moreSiblings = viewItem.hasMoreSiblings; -
1785 -
1786 opt.state = QStyle::State_Item | extraFlags -
1787 | (moreSiblings ? QStyle::State_Sibling : QStyle::State_None) -
1788 | (children ? QStyle::State_Children : QStyle::State_None) -
1789 | (expanded ? QStyle::State_Open : QStyle::State_None); -
1790 if (hoverRow || item == d->hoverBranch) -
1791 opt.state |= QStyle::State_MouseOver; -
1792 else -
1793 opt.state &= ~QStyle::State_MouseOver; -
1794 style()->drawPrimitive(QStyle::PE_IndicatorBranch, &opt, painter, this); -
1795 } -
1796 // then go out level by level -
1797 for (--level; level >= outer; --level) { // we have already drawn the innermost branch -
1798 primitive.moveLeft(reverse ? primitive.left() + indent : primitive.left() - indent); -
1799 opt.rect = primitive; -
1800 opt.state = extraFlags; -
1801 bool moreSiblings = false; -
1802 if (d->hiddenIndexes.isEmpty()) { -
1803 moreSiblings = (d->model->rowCount(ancestor) - 1 > current.row()); -
1804 } else { -
1805 int successor = item + viewItem.total + 1; -
1806 while (successor < d->viewItems.size() -
1807 && d->viewItems.at(successor).level >= uint(level)) { -
1808 const QTreeViewItem &successorItem = d->viewItems.at(successor); -
1809 if (successorItem.level == uint(level)) { -
1810 moreSiblings = true; -
1811 break; -
1812 } -
1813 successor += successorItem.total + 1; -
1814 } -
1815 } -
1816 if (moreSiblings) -
1817 opt.state |= QStyle::State_Sibling; -
1818 if (hoverRow || item == d->hoverBranch) -
1819 opt.state |= QStyle::State_MouseOver; -
1820 else -
1821 opt.state &= ~QStyle::State_MouseOver; -
1822 style()->drawPrimitive(QStyle::PE_IndicatorBranch, &opt, painter, this); -
1823 current = ancestor; -
1824 ancestor = current.parent(); -
1825 } -
1826 painter->setBrushOrigin(oldBO); -
1827} -
1828 -
1829/*! -
1830 \reimp -
1831*/ -
1832void QTreeView::mousePressEvent(QMouseEvent *event) -
1833{ -
1834 Q_D(QTreeView); -
1835 bool handled = false; -
1836 if (style()->styleHint(QStyle::SH_ListViewExpand_SelectMouseType, 0, this) == QEvent::MouseButtonPress) -
1837 handled = d->expandOrCollapseItemAtPos(event->pos()); -
1838 if (!handled && d->itemDecorationAt(event->pos()) == -1) -
1839 QAbstractItemView::mousePressEvent(event); -
1840} -
1841 -
1842/*! -
1843 \reimp -
1844*/ -
1845void QTreeView::mouseReleaseEvent(QMouseEvent *event) -
1846{ -
1847 Q_D(QTreeView); -
1848 if (d->itemDecorationAt(event->pos()) == -1) { -
1849 QAbstractItemView::mouseReleaseEvent(event); -
1850 } else { -
1851 if (state() == QAbstractItemView::DragSelectingState) -
1852 setState(QAbstractItemView::NoState); -
1853 if (style()->styleHint(QStyle::SH_ListViewExpand_SelectMouseType, 0, this) == QEvent::MouseButtonRelease) -
1854 d->expandOrCollapseItemAtPos(event->pos()); -
1855 } -
1856} -
1857 -
1858/*! -
1859 \reimp -
1860*/ -
1861void QTreeView::mouseDoubleClickEvent(QMouseEvent *event) -
1862{ -
1863 Q_D(QTreeView); -
1864 if (state() != NoState || !d->viewport->rect().contains(event->pos())) -
1865 return; -
1866 -
1867 int i = d->itemDecorationAt(event->pos()); -
1868 if (i == -1) { -
1869 i = d->itemAtCoordinate(event->y()); -
1870 if (i == -1) -
1871 return; // user clicked outside the items -
1872 -
1873 const QPersistentModelIndex firstColumnIndex = d->viewItems.at(i).index; -
1874 const QPersistentModelIndex persistent = indexAt(event->pos()); -
1875 -
1876 if (d->pressedIndex != persistent) { -
1877 mousePressEvent(event); -
1878 return; -
1879 } -
1880 -
1881 // signal handlers may change the model -
1882 emit doubleClicked(persistent); -
1883 -
1884 if (!persistent.isValid()) -
1885 return; -
1886 -
1887 if (edit(persistent, DoubleClicked, event) || state() != NoState) -
1888 return; // the double click triggered editing -
1889 -
1890 if (!style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, 0, this)) -
1891 emit activated(persistent); -
1892 -
1893 d->executePostedLayout(); // we need to make sure viewItems is updated -
1894 if (d->itemsExpandable -
1895 && d->expandsOnDoubleClick -
1896 && d->hasVisibleChildren(persistent)) { -
1897 if (!((i < d->viewItems.count()) && (d->viewItems.at(i).index == firstColumnIndex))) { -
1898 // find the new index of the item -
1899 for (i = 0; i < d->viewItems.count(); ++i) { -
1900 if (d->viewItems.at(i).index == firstColumnIndex) -
1901 break; -
1902 } -
1903 if (i == d->viewItems.count()) -
1904 return; -
1905 } -
1906 if (d->viewItems.at(i).expanded) -
1907 d->collapse(i, true); -
1908 else -
1909 d->expand(i, true); -
1910 updateGeometries(); -
1911 viewport()->update(); -
1912 } -
1913 } -
1914} -
1915 -
1916/*! -
1917 \reimp -
1918*/ -
1919void QTreeView::mouseMoveEvent(QMouseEvent *event) -
1920{ -
1921 Q_D(QTreeView); -
1922 if (d->itemDecorationAt(event->pos()) == -1) // ### what about expanding/collapsing state ? -
1923 QAbstractItemView::mouseMoveEvent(event); -
1924} -
1925 -
1926/*! -
1927 \reimp -
1928*/ -
1929void QTreeView::keyPressEvent(QKeyEvent *event) -
1930{ -
1931 Q_D(QTreeView); -
1932 QModelIndex current = currentIndex(); -
1933 //this is the management of the expansion -
1934 if (d->isIndexValid(current) && d->model && d->itemsExpandable) { -
1935 switch (event->key()) { -
1936 case Qt::Key_Asterisk: { -
1937 QStack<QModelIndex> parents; -
1938 parents.push(current); -
1939 while (!parents.isEmpty()) { -
1940 QModelIndex parent = parents.pop(); -
1941 for (int row = 0; row < d->model->rowCount(parent); ++row) { -
1942 QModelIndex child = d->model->index(row, 0, parent); -
1943 if (!d->isIndexValid(child)) -
1944 break; -
1945 parents.push(child); -
1946 expand(child); -
1947 } -
1948 } -
1949 expand(current); -
1950 break; } -
1951 case Qt::Key_Plus: -
1952 expand(current); -
1953 break; -
1954 case Qt::Key_Minus: -
1955 collapse(current); -
1956 break; -
1957 } -
1958 } -
1959 -
1960 QAbstractItemView::keyPressEvent(event); -
1961} -
1962 -
1963/*! -
1964 \reimp -
1965*/ -
1966QModelIndex QTreeView::indexAt(const QPoint &point) const -
1967{ -
1968 Q_D(const QTreeView); -
1969 d->executePostedLayout(); -
1970 -
1971 int visualIndex = d->itemAtCoordinate(point.y()); -
1972 QModelIndex idx = d->modelIndex(visualIndex); -
1973 if (!idx.isValid()) -
1974 return QModelIndex(); -
1975 -
1976 if (d->viewItems.at(visualIndex).spanning) -
1977 return idx; -
1978 -
1979 int column = d->columnAt(point.x()); -
1980 if (column == idx.column()) -
1981 return idx; -
1982 if (column < 0) -
1983 return QModelIndex(); -
1984 return idx.sibling(idx.row(), column); -
1985} -
1986 -
1987/*! -
1988 Returns the model index of the item above \a index. -
1989*/ -
1990QModelIndex QTreeView::indexAbove(const QModelIndex &index) const -
1991{ -
1992 Q_D(const QTreeView); -
1993 if (!d->isIndexValid(index)) -
1994 return QModelIndex(); -
1995 d->executePostedLayout(); -
1996 int i = d->viewIndex(index); -
1997 if (--i < 0) -
1998 return QModelIndex(); -
1999 const QModelIndex firstColumnIndex = d->viewItems.at(i).index; -
2000 return firstColumnIndex.sibling(firstColumnIndex.row(), index.column()); -
2001} -
2002 -
2003/*! -
2004 Returns the model index of the item below \a index. -
2005*/ -
2006QModelIndex QTreeView::indexBelow(const QModelIndex &index) const -
2007{ -
2008 Q_D(const QTreeView); -
2009 if (!d->isIndexValid(index)) -
2010 return QModelIndex(); -
2011 d->executePostedLayout(); -
2012 int i = d->viewIndex(index); -
2013 if (++i >= d->viewItems.count()) -
2014 return QModelIndex(); -
2015 const QModelIndex firstColumnIndex = d->viewItems.at(i).index; -
2016 return firstColumnIndex.sibling(firstColumnIndex.row(), index.column()); -
2017} -
2018 -
2019/*! -
2020 \internal -
2021 -
2022 Lays out the items in the tree view. -
2023*/ -
2024void QTreeView::doItemsLayout() -
2025{ -
2026 Q_D(QTreeView); -
2027 if (d->hasRemovedItems) { -
2028 //clean the QSet that may contains old (and this invalid) indexes -
2029 d->hasRemovedItems = false; -
2030 QSet<QPersistentModelIndex>::iterator it = d->expandedIndexes.begin(); -
2031 while (it != d->expandedIndexes.end()) { -
2032 if (!it->isValid()) -
2033 it = d->expandedIndexes.erase(it); -
2034 else -
2035 ++it; -
2036 } -
2037 it = d->hiddenIndexes.begin(); -
2038 while (it != d->hiddenIndexes.end()) { -
2039 if (!it->isValid()) -
2040 it = d->hiddenIndexes.erase(it); -
2041 else -
2042 ++it; -
2043 } -
2044 } -
2045 d->viewItems.clear(); // prepare for new layout -
2046 QModelIndex parent = d->root; -
2047 if (d->model->hasChildren(parent)) { -
2048 d->layout(-1); -
2049 } -
2050 QAbstractItemView::doItemsLayout(); -
2051 d->header->doItemsLayout(); -
2052} -
2053 -
2054/*! -
2055 \reimp -
2056*/ -
2057void QTreeView::reset() -
2058{ -
2059 Q_D(QTreeView); -
2060 d->expandedIndexes.clear(); -
2061 d->hiddenIndexes.clear(); -
2062 d->spanningIndexes.clear(); -
2063 d->viewItems.clear(); -
2064 QAbstractItemView::reset(); -
2065} -
2066 -
2067/*! -
2068 Returns the horizontal offset of the items in the treeview. -
2069 -
2070 Note that the tree view uses the horizontal header section -
2071 positions to determine the positions of columns in the view. -
2072 -
2073 \sa verticalOffset() -
2074*/ -
2075int QTreeView::horizontalOffset() const -
2076{ -
2077 Q_D(const QTreeView); -
2078 return d->header->offset(); -
2079} -
2080 -
2081/*! -
2082 Returns the vertical offset of the items in the tree view. -
2083 -
2084 \sa horizontalOffset() -
2085*/ -
2086int QTreeView::verticalOffset() const -
2087{ -
2088 Q_D(const QTreeView); -
2089 if (d->verticalScrollMode == QAbstractItemView::ScrollPerItem) { -
2090 if (d->uniformRowHeights) -
2091 return verticalScrollBar()->value() * d->defaultItemHeight; -
2092 // If we are scrolling per item and have non-uniform row heights, -
2093 // finding the vertical offset in pixels is going to be relatively slow. -
2094 // ### find a faster way to do this -
2095 d->executePostedLayout(); -
2096 int offset = 0; -
2097 for (int i = 0; i < d->viewItems.count(); ++i) { -
2098 if (i == verticalScrollBar()->value()) -
2099 return offset; -
2100 offset += d->itemHeight(i); -
2101 } -
2102 return 0; -
2103 } -
2104 // scroll per pixel -
2105 return verticalScrollBar()->value(); -
2106} -
2107 -
2108/*! -
2109 Move the cursor in the way described by \a cursorAction, using the -
2110 information provided by the button \a modifiers. -
2111*/ -
2112QModelIndex QTreeView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers) -
2113{ -
2114 Q_D(QTreeView); -
2115 Q_UNUSED(modifiers); -
2116 -
2117 d->executePostedLayout(); -
2118 -
2119 QModelIndex current = currentIndex(); -
2120 if (!current.isValid()) { -
2121 int i = d->below(-1); -
2122 int c = 0; -
2123 while (c < d->header->count() && d->header->isSectionHidden(c)) -
2124 ++c; -
2125 if (i < d->viewItems.count() && c < d->header->count()) { -
2126 return d->modelIndex(i, c); -
2127 } -
2128 return QModelIndex(); -
2129 } -
2130 int vi = -1; -
2131#if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC) -
2132 // Selection behavior is slightly different on the Mac. -
2133 if (d->selectionMode == QAbstractItemView::ExtendedSelection -
2134 && d->selectionModel -
2135 && d->selectionModel->hasSelection()) { -
2136 -
2137 const bool moveUpDown = (cursorAction == MoveUp || cursorAction == MoveDown); -
2138 const bool moveNextPrev = (cursorAction == MoveNext || cursorAction == MovePrevious); -
2139 const bool contiguousSelection = moveUpDown && (modifiers & Qt::ShiftModifier); -
2140 -
2141 // Use the outermost index in the selection as the current index -
2142 if (!contiguousSelection && (moveUpDown || moveNextPrev)) { -
2143 -
2144 // Find outermost index. -
2145 const bool useTopIndex = (cursorAction == MoveUp || cursorAction == MovePrevious); -
2146 int index = useTopIndex ? INT_MAX : INT_MIN; -
2147 const QItemSelection selection = d->selectionModel->selection(); -
2148 for (int i = 0; i < selection.count(); ++i) { -
2149 const QItemSelectionRange &range = selection.at(i); -
2150 int candidate = d->viewIndex(useTopIndex ? range.topLeft() : range.bottomRight()); -
2151 if (candidate >= 0) -
2152 index = useTopIndex ? qMin(index, candidate) : qMax(index, candidate); -
2153 } -
2154 -
2155 if (index >= 0 && index < INT_MAX) -
2156 vi = index; -
2157 } -
2158 } -
2159#endif -
2160 if (vi < 0) -
2161 vi = qMax(0, d->viewIndex(current)); -
2162 -
2163 if (isRightToLeft()) { -
2164 if (cursorAction == MoveRight) -
2165 cursorAction = MoveLeft; -
2166 else if (cursorAction == MoveLeft) -
2167 cursorAction = MoveRight; -
2168 } -
2169 switch (cursorAction) { -
2170 case MoveNext: -
2171 case MoveDown: -
2172#ifdef QT_KEYPAD_NAVIGATION -
2173 if (vi == d->viewItems.count()-1 && QApplication::keypadNavigationEnabled()) -
2174 return d->model->index(0, current.column(), d->root); -
2175#endif -
2176 return d->modelIndex(d->below(vi), current.column()); -
2177 case MovePrevious: -
2178 case MoveUp: -
2179#ifdef QT_KEYPAD_NAVIGATION -
2180 if (vi == 0 && QApplication::keypadNavigationEnabled()) -
2181 return d->modelIndex(d->viewItems.count() - 1, current.column()); -
2182#endif -
2183 return d->modelIndex(d->above(vi), current.column()); -
2184 case MoveLeft: { -
2185 QScrollBar *sb = horizontalScrollBar(); -
2186 if (vi < d->viewItems.count() && d->viewItems.at(vi).expanded && d->itemsExpandable && sb->value() == sb->minimum()) { -
2187 d->collapse(vi, true); -
2188 d->moveCursorUpdatedView = true; -
2189 } else { -
2190 bool descend = style()->styleHint(QStyle::SH_ItemView_ArrowKeysNavigateIntoChildren, 0, this); -
2191 if (descend) { -
2192 QModelIndex par = current.parent(); -
2193 if (par.isValid() && par != rootIndex()) -
2194 return par; -
2195 else -
2196 descend = false; -
2197 } -
2198 if (!descend) { -
2199 if (d->selectionBehavior == SelectItems || d->selectionBehavior == SelectColumns) { -
2200 int visualColumn = d->header->visualIndex(current.column()) - 1; -
2201 while (visualColumn >= 0 && isColumnHidden(d->header->logicalIndex(visualColumn))) -
2202 visualColumn--; -
2203 int newColumn = d->header->logicalIndex(visualColumn); -
2204 QModelIndex next = current.sibling(current.row(), newColumn); -
2205 if (next.isValid()) -
2206 return next; -
2207 } -
2208 -
2209 int oldValue = sb->value(); -
2210 sb->setValue(sb->value() - sb->singleStep()); -
2211 if (oldValue != sb->value()) -
2212 d->moveCursorUpdatedView = true; -
2213 } -
2214 -
2215 } -
2216 updateGeometries(); -
2217 viewport()->update(); -
2218 break; -
2219 } -
2220 case MoveRight: -
2221 if (vi < d->viewItems.count() && !d->viewItems.at(vi).expanded && d->itemsExpandable -
2222 && d->hasVisibleChildren(d->viewItems.at(vi).index)) { -
2223 d->expand(vi, true); -
2224 d->moveCursorUpdatedView = true; -
2225 } else { -
2226 bool descend = style()->styleHint(QStyle::SH_ItemView_ArrowKeysNavigateIntoChildren, 0, this); -
2227 if (descend) { -
2228 QModelIndex idx = d->modelIndex(d->below(vi)); -
2229 if (idx.parent() == current) -
2230 return idx; -
2231 else -
2232 descend = false; -
2233 } -
2234 if (!descend) { -
2235 if (d->selectionBehavior == SelectItems || d->selectionBehavior == SelectColumns) { -
2236 int visualColumn = d->header->visualIndex(current.column()) + 1; -
2237 while (visualColumn < d->model->columnCount(current.parent()) && isColumnHidden(d->header->logicalIndex(visualColumn))) -
2238 visualColumn++; -
2239 -
2240 QModelIndex next = current.sibling(current.row(), visualColumn); -
2241 if (next.isValid()) -
2242 return next; -
2243 } -
2244 -
2245 //last restort: we change the scrollbar value -
2246 QScrollBar *sb = horizontalScrollBar(); -
2247 int oldValue = sb->value(); -
2248 sb->setValue(sb->value() + sb->singleStep()); -
2249 if (oldValue != sb->value()) -
2250 d->moveCursorUpdatedView = true; -
2251 } -
2252 } -
2253 updateGeometries(); -
2254 viewport()->update(); -
2255 break; -
2256 case MovePageUp: -
2257 return d->modelIndex(d->pageUp(vi), current.column()); -
2258 case MovePageDown: -
2259 return d->modelIndex(d->pageDown(vi), current.column()); -
2260 case MoveHome: -
2261 return d->model->index(0, current.column(), d->root); -
2262 case MoveEnd: -
2263 return d->modelIndex(d->viewItems.count() - 1, current.column()); -
2264 } -
2265 return current; -
2266} -
2267 -
2268/*! -
2269 Applies the selection \a command to the items in or touched by the -
2270 rectangle, \a rect. -
2271 -
2272 \sa selectionCommand() -
2273*/ -
2274void QTreeView::setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags command) -
2275{ -
2276 Q_D(QTreeView); -
2277 if (!selectionModel() || rect.isNull()) -
2278 return; -
2279 -
2280 d->executePostedLayout(); -
2281 QPoint tl(isRightToLeft() ? qMax(rect.left(), rect.right()) -
2282 : qMin(rect.left(), rect.right()), qMin(rect.top(), rect.bottom())); -
2283 QPoint br(isRightToLeft() ? qMin(rect.left(), rect.right()) : -
2284 qMax(rect.left(), rect.right()), qMax(rect.top(), rect.bottom())); -
2285 QModelIndex topLeft = indexAt(tl); -
2286 QModelIndex bottomRight = indexAt(br); -
2287 if (!topLeft.isValid() && !bottomRight.isValid()) { -
2288 if (command & QItemSelectionModel::Clear) -
2289 selectionModel()->clear(); -
2290 return; -
2291 } -
2292 if (!topLeft.isValid() && !d->viewItems.isEmpty()) -
2293 topLeft = d->viewItems.first().index; -
2294 if (!bottomRight.isValid() && !d->viewItems.isEmpty()) { -
2295 const int column = d->header->logicalIndex(d->header->count() - 1); -
2296 const QModelIndex index = d->viewItems.last().index; -
2297 bottomRight = index.sibling(index.row(), column); -
2298 } -
2299 -
2300 if (!d->isIndexEnabled(topLeft) || !d->isIndexEnabled(bottomRight)) -
2301 return; -
2302 -
2303 d->select(topLeft, bottomRight, command); -
2304} -
2305 -
2306/*! -
2307 Returns the rectangle from the viewport of the items in the given -
2308 \a selection. -
2309 -
2310 Since 4.7, the returned region only contains rectangles intersecting -
2311 (or included in) the viewport. -
2312*/ -
2313QRegion QTreeView::visualRegionForSelection(const QItemSelection &selection) const -
2314{ -
2315 Q_D(const QTreeView); -
2316 if (selection.isEmpty()) -
2317 return QRegion(); -
2318 -
2319 QRegion selectionRegion; -
2320 const QRect &viewportRect = d->viewport->rect(); -
2321 for (int i = 0; i < selection.count(); ++i) { -
2322 QItemSelectionRange range = selection.at(i); -
2323 if (!range.isValid()) -
2324 continue; -
2325 QModelIndex parent = range.parent(); -
2326 QModelIndex leftIndex = range.topLeft(); -
2327 int columnCount = d->model->columnCount(parent); -
2328 while (leftIndex.isValid() && isIndexHidden(leftIndex)) { -
2329 if (leftIndex.column() + 1 < columnCount) -
2330 leftIndex = d->model->index(leftIndex.row(), leftIndex.column() + 1, parent); -
2331 else -
2332 leftIndex = QModelIndex(); -
2333 } -
2334 if (!leftIndex.isValid()) -
2335 continue; -
2336 const QRect leftRect = visualRect(leftIndex); -
2337 int top = leftRect.top(); -
2338 QModelIndex rightIndex = range.bottomRight(); -
2339 while (rightIndex.isValid() && isIndexHidden(rightIndex)) { -
2340 if (rightIndex.column() - 1 >= 0) -
2341 rightIndex = d->model->index(rightIndex.row(), rightIndex.column() - 1, parent); -
2342 else -
2343 rightIndex = QModelIndex(); -
2344 } -
2345 if (!rightIndex.isValid()) -
2346 continue; -
2347 const QRect rightRect = visualRect(rightIndex); -
2348 int bottom = rightRect.bottom(); -
2349 if (top > bottom) -
2350 qSwap<int>(top, bottom); -
2351 int height = bottom - top + 1; -
2352 if (d->header->sectionsMoved()) { -
2353 for (int c = range.left(); c <= range.right(); ++c) { -
2354 const QRect rangeRect(columnViewportPosition(c), top, columnWidth(c), height); -
2355 if (viewportRect.intersects(rangeRect)) -
2356 selectionRegion += rangeRect; -
2357 } -
2358 } else { -
2359 QRect combined = leftRect|rightRect; -
2360 combined.setX(columnViewportPosition(isRightToLeft() ? range.right() : range.left())); -
2361 if (viewportRect.intersects(combined)) -
2362 selectionRegion += combined; -
2363 } -
2364 } -
2365 return selectionRegion; -
2366} -
2367 -
2368/*! -
2369 \reimp -
2370*/ -
2371QModelIndexList QTreeView::selectedIndexes() const -
2372{ -
2373 QModelIndexList viewSelected; -
2374 QModelIndexList modelSelected; -
2375 if (selectionModel()) -
2376 modelSelected = selectionModel()->selectedIndexes(); -
2377 for (int i = 0; i < modelSelected.count(); ++i) { -
2378 // check that neither the parents nor the index is hidden before we add -
2379 QModelIndex index = modelSelected.at(i); -
2380 while (index.isValid() && !isIndexHidden(index)) -
2381 index = index.parent(); -
2382 if (index.isValid()) -
2383 continue; -
2384 viewSelected.append(modelSelected.at(i)); -
2385 } -
2386 return viewSelected; -
2387} -
2388 -
2389/*! -
2390 Scrolls the contents of the tree view by (\a dx, \a dy). -
2391*/ -
2392void QTreeView::scrollContentsBy(int dx, int dy) -
2393{ -
2394 Q_D(QTreeView); -
2395 -
2396 d->delayedAutoScroll.stop(); // auto scroll was canceled by the user scrolling -
2397 -
2398 dx = isRightToLeft() ? -dx : dx; -
2399 if (dx) { -
2400 if (horizontalScrollMode() == QAbstractItemView::ScrollPerItem) { -
2401 int oldOffset = d->header->offset(); -
2402 if (horizontalScrollBar()->value() == horizontalScrollBar()->maximum()) -
2403 d->header->setOffsetToLastSection(); -
2404 else -
2405 d->header->setOffsetToSectionPosition(horizontalScrollBar()->value()); -
2406 int newOffset = d->header->offset(); -
2407 dx = isRightToLeft() ? newOffset - oldOffset : oldOffset - newOffset; -
2408 } else { -
2409 d->header->setOffset(horizontalScrollBar()->value()); -
2410 } -
2411 } -
2412 -
2413 const int itemHeight = d->defaultItemHeight <= 0 ? sizeHintForRow(0) : d->defaultItemHeight; -
2414 if (d->viewItems.isEmpty() || itemHeight == 0) -
2415 return; -
2416 -
2417 // guestimate the number of items in the viewport -
2418 int viewCount = d->viewport->height() / itemHeight; -
2419 int maxDeltaY = qMin(d->viewItems.count(), viewCount); -
2420 // no need to do a lot of work if we are going to redraw the whole thing anyway -
2421 if (qAbs(dy) > qAbs(maxDeltaY) && d->editorIndexHash.isEmpty()) { -
2422 verticalScrollBar()->update(); -
2423 d->viewport->update(); -
2424 return; -
2425 } -
2426 -
2427 if (dy && verticalScrollMode() == QAbstractItemView::ScrollPerItem) { -
2428 int currentScrollbarValue = verticalScrollBar()->value(); -
2429 int previousScrollbarValue = currentScrollbarValue + dy; // -(-dy) -
2430 int currentViewIndex = currentScrollbarValue; // the first visible item -
2431 int previousViewIndex = previousScrollbarValue; -
2432 const QVector<QTreeViewItem> viewItems = d->viewItems; -
2433 dy = 0; -
2434 if (previousViewIndex < currentViewIndex) { // scrolling down -
2435 for (int i = previousViewIndex; i < currentViewIndex; ++i) { -
2436 if (i < d->viewItems.count()) -
2437 dy -= d->itemHeight(i); -
2438 } -
2439 } else if (previousViewIndex > currentViewIndex) { // scrolling up -
2440 for (int i = previousViewIndex - 1; i >= currentViewIndex; --i) { -
2441 if (i < d->viewItems.count()) -
2442 dy += d->itemHeight(i); -
2443 } -
2444 } -
2445 } -
2446 -
2447 d->scrollContentsBy(dx, dy); -
2448} -
2449 -
2450/*! -
2451 This slot is called whenever a column has been moved. -
2452*/ -
2453void QTreeView::columnMoved() -
2454{ -
2455 Q_D(QTreeView); -
2456 updateEditorGeometries(); -
2457 d->viewport->update(); -
2458} -
2459 -
2460/*! -
2461 \internal -
2462*/ -
2463void QTreeView::reexpand() -
2464{ -
2465 // do nothing -
2466} -
2467 -
2468/*! -
2469 Informs the view that the rows from the \a start row to the \a end row -
2470 inclusive have been inserted into the \a parent model item. -
2471*/ -
2472void QTreeView::rowsInserted(const QModelIndex &parent, int start, int end) -
2473{ -
2474 Q_D(QTreeView); -
2475 // if we are going to do a complete relayout anyway, there is no need to update -
2476 if (d->delayedPendingLayout) { -
2477 QAbstractItemView::rowsInserted(parent, start, end); -
2478 return; -
2479 } -
2480 -
2481 //don't add a hierarchy on a column != 0 -
2482 if (parent.column() != 0 && parent.isValid()) { -
2483 QAbstractItemView::rowsInserted(parent, start, end); -
2484 return; -
2485 } -
2486 -
2487 const int parentRowCount = d->model->rowCount(parent); -
2488 const int delta = end - start + 1; -
2489 if (parent != d->root && !d->isIndexExpanded(parent) && parentRowCount > delta) { -
2490 QAbstractItemView::rowsInserted(parent, start, end); -
2491 return; -
2492 } -
2493 -
2494 const int parentItem = d->viewIndex(parent); -
2495 if (((parentItem != -1) && d->viewItems.at(parentItem).expanded) -
2496 || (parent == d->root)) { -
2497 d->doDelayedItemsLayout(); -
2498 } else if (parentItem != -1 && (d->model->rowCount(parent) == end - start + 1)) { -
2499 // the parent just went from 0 children to more. update to re-paint the decoration -
2500 d->viewItems[parentItem].hasChildren = true; -
2501 viewport()->update(); -
2502 } -
2503 QAbstractItemView::rowsInserted(parent, start, end); -
2504} -
2505 -
2506/*! -
2507 Informs the view that the rows from the \a start row to the \a end row -
2508 inclusive are about to removed from the given \a parent model item. -
2509*/ -
2510void QTreeView::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) -
2511{ -
2512 Q_D(QTreeView); -
2513 QAbstractItemView::rowsAboutToBeRemoved(parent, start, end); -
2514 d->viewItems.clear(); -
2515} -
2516 -
2517/*! -
2518 \since 4.1 -
2519 -
2520 Informs the view that the rows from the \a start row to the \a end row -
2521 inclusive have been removed from the given \a parent model item. -
2522*/ -
2523void QTreeView::rowsRemoved(const QModelIndex &parent, int start, int end) -
2524{ -
2525 Q_D(QTreeView); -
2526 d->viewItems.clear(); -
2527 d->doDelayedItemsLayout(); -
2528 d->hasRemovedItems = true; -
2529 d->_q_rowsRemoved(parent, start, end); -
2530} -
2531 -
2532/*! -
2533 Informs the tree view that the number of columns in the tree view has -
2534 changed from \a oldCount to \a newCount. -
2535*/ -
2536void QTreeView::columnCountChanged(int oldCount, int newCount) -
2537{ -
2538 Q_D(QTreeView); -
2539 if (oldCount == 0 && newCount > 0) { -
2540 //if the first column has just been added we need to relayout. -
2541 d->doDelayedItemsLayout(); -
2542 } -
2543 -
2544 if (isVisible()) -
2545 updateGeometries(); -
2546 viewport()->update(); -
2547} -
2548 -
2549/*! -
2550 Resizes the \a column given to the size of its contents. -
2551 -
2552 \sa columnWidth(), setColumnWidth() -
2553*/ -
2554void QTreeView::resizeColumnToContents(int column) -
2555{ -
2556 Q_D(QTreeView); -
2557 d->executePostedLayout(); -
2558 if (column < 0 || column >= d->header->count()) -
2559 return; -
2560 int contents = sizeHintForColumn(column); -
2561 int header = d->header->isHidden() ? 0 : d->header->sectionSizeHint(column); -
2562 d->header->resizeSection(column, qMax(contents, header)); -
2563} -
2564 -
2565/*! -
2566 \obsolete -
2567 \overload -
2568 -
2569 Sorts the model by the values in the given \a column. -
2570*/ -
2571void QTreeView::sortByColumn(int column) -
2572{ -
2573 Q_D(QTreeView); -
2574 sortByColumn(column, d->header->sortIndicatorOrder()); -
2575} -
2576 -
2577/*! -
2578 \since 4.2 -
2579 -
2580 Sets the model up for sorting by the values in the given \a column and \a order. -
2581 -
2582 \a column may be -1, in which case no sort indicator will be shown -
2583 and the model will return to its natural, unsorted order. Note that not -
2584 all models support this and may even crash in this case. -
2585 -
2586 \sa sortingEnabled -
2587*/ -
2588void QTreeView::sortByColumn(int column, Qt::SortOrder order) -
2589{ -
2590 Q_D(QTreeView); -
2591 -
2592 //If sorting is enabled will emit a signal connected to _q_sortIndicatorChanged, which then actually sorts -
2593 d->header->setSortIndicator(column, order); -
2594 //If sorting is not enabled, force to sort now. -
2595 if (!d->sortingEnabled) -
2596 d->model->sort(column, order); -
2597} -
2598 -
2599/*! -
2600 \reimp -
2601*/ -
2602void QTreeView::selectAll() -
2603{ -
2604 Q_D(QTreeView); -
2605 if (!selectionModel()) -
2606 return; -
2607 SelectionMode mode = d->selectionMode; -
2608 d->executePostedLayout(); //make sure we lay out the items -
2609 if (mode != SingleSelection && mode != NoSelection && !d->viewItems.isEmpty()) { -
2610 const QModelIndex &idx = d->viewItems.last().index; -
2611 QModelIndex lastItemIndex = idx.sibling(idx.row(), d->model->columnCount(idx.parent()) - 1); -
2612 d->select(d->viewItems.first().index, lastItemIndex, -
2613 QItemSelectionModel::ClearAndSelect -
2614 |QItemSelectionModel::Rows); -
2615 } -
2616} -
2617 -
2618/*! -
2619 \since 4.2 -
2620 Expands all expandable items. -
2621 -
2622 Warning: if the model contains a large number of items, -
2623 this function will take some time to execute. -
2624 -
2625 \sa collapseAll(), expand(), collapse(), setExpanded() -
2626*/ -
2627void QTreeView::expandAll() -
2628{ -
2629 Q_D(QTreeView); -
2630 d->viewItems.clear(); -
2631 d->interruptDelayedItemsLayout(); -
2632 d->layout(-1, true); -
2633 updateGeometries(); -
2634 d->viewport->update(); -
2635} -
2636 -
2637/*! -
2638 \since 4.2 -
2639 -
2640 Collapses all expanded items. -
2641 -
2642 \sa expandAll(), expand(), collapse(), setExpanded() -
2643*/ -
2644void QTreeView::collapseAll() -
2645{ -
2646 Q_D(QTreeView); -
2647 d->expandedIndexes.clear(); -
2648 doItemsLayout(); -
2649} -
2650 -
2651/*! -
2652 \since 4.3 -
2653 Expands all expandable items to the given \a depth. -
2654 -
2655 \sa expandAll(), collapseAll(), expand(), collapse(), setExpanded() -
2656*/ -
2657void QTreeView::expandToDepth(int depth) -
2658{ -
2659 Q_D(QTreeView); -
2660 d->viewItems.clear(); -
2661 d->expandedIndexes.clear(); -
2662 d->interruptDelayedItemsLayout(); -
2663 d->layout(-1); -
2664 for (int i = 0; i < d->viewItems.count(); ++i) { -
2665 if (d->viewItems.at(i).level <= (uint)depth) { -
2666 d->viewItems[i].expanded = true; -
2667 d->layout(i); -
2668 d->storeExpanded(d->viewItems.at(i).index); -
2669 } -
2670 } -
2671 updateGeometries(); -
2672 d->viewport->update(); -
2673} -
2674 -
2675/*! -
2676 This function is called whenever \a{column}'s size is changed in -
2677 the header. \a oldSize and \a newSize give the previous size and -
2678 the new size in pixels. -
2679 -
2680 \sa setColumnWidth() -
2681*/ -
2682void QTreeView::columnResized(int column, int /* oldSize */, int /* newSize */) -
2683{ -
2684 Q_D(QTreeView); -
2685 d->columnsToUpdate.append(column); -
2686 if (d->columnResizeTimerID == 0) -
2687 d->columnResizeTimerID = startTimer(0); -
2688} -
2689 -
2690/*! -
2691 \reimp -
2692*/ -
2693void QTreeView::updateGeometries() -
2694{ -
2695 Q_D(QTreeView); -
2696 if (d->header) { -
2697 if (d->geometryRecursionBlock) -
2698 return; -
2699 d->geometryRecursionBlock = true; -
2700 QSize hint = d->header->isHidden() ? QSize(0, 0) : d->header->sizeHint(); -
2701 setViewportMargins(0, hint.height(), 0, 0); -
2702 QRect vg = d->viewport->geometry(); -
2703 QRect geometryRect(vg.left(), vg.top() - hint.height(), vg.width(), hint.height()); -
2704 d->header->setGeometry(geometryRect); -
2705 //d->header->setOffset(horizontalScrollBar()->value()); // ### bug ??? -
2706 QMetaObject::invokeMethod(d->header, "updateGeometries"); -
2707 d->updateScrollBars(); -
2708 d->geometryRecursionBlock = false; -
2709 } -
2710 QAbstractItemView::updateGeometries(); -
2711} -
2712 -
2713/*! -
2714 Returns the size hint for the \a column's width or -1 if there is no -
2715 model. -
2716 -
2717 If you need to set the width of a given column to a fixed value, call -
2718 QHeaderView::resizeSection() on the view's header. -
2719 -
2720 If you reimplement this function in a subclass, note that the value you -
2721 return is only used when resizeColumnToContents() is called. In that case, -
2722 if a larger column width is required by either the view's header or -
2723 the item delegate, that width will be used instead. -
2724 -
2725 \sa QWidget::sizeHint, header() -
2726*/ -
2727int QTreeView::sizeHintForColumn(int column) const -
2728{ -
2729 Q_D(const QTreeView); -
2730 d->executePostedLayout(); -
2731 if (d->viewItems.isEmpty()) -
2732 return -1; -
2733 ensurePolished(); -
2734 int w = 0; -
2735 QStyleOptionViewItem option = d->viewOptions(); -
2736 const QVector<QTreeViewItem> viewItems = d->viewItems; -
2737 -
2738 int start = 0; -
2739 int end = viewItems.count(); -
2740 if(end > 1000) { //if we have too many item this function would be too slow. -
2741 //we get a good approximation by only iterate over 1000 items. -
2742 start = qMax(0, d->firstVisibleItem() - 100); -
2743 end = qMin(end, start + 900); -
2744 } -
2745 -
2746 for (int i = start; i < end; ++i) { -
2747 if (viewItems.at(i).spanning) -
2748 continue; // we have no good size hint -
2749 QModelIndex index = viewItems.at(i).index; -
2750 index = index.sibling(index.row(), column); -
2751 QWidget *editor = d->editorForIndex(index).widget.data(); -
2752 if (editor && d->persistent.contains(editor)) { -
2753 w = qMax(w, editor->sizeHint().width()); -
2754 int min = editor->minimumSize().width(); -
2755 int max = editor->maximumSize().width(); -
2756 w = qBound(min, w, max); -
2757 } -
2758 int hint = d->delegateForIndex(index)->sizeHint(option, index).width(); -
2759 w = qMax(w, hint + (column == 0 ? d->indentationForItem(i) : 0)); -
2760 } -
2761 return w; -
2762} -
2763 -
2764/*! -
2765 Returns the size hint for the row indicated by \a index. -
2766 -
2767 \sa sizeHintForColumn(), uniformRowHeights() -
2768*/ -
2769int QTreeView::indexRowSizeHint(const QModelIndex &index) const -
2770{ -
2771 Q_D(const QTreeView); -
2772 if (!d->isIndexValid(index) || !d->itemDelegate) -
2773 return 0; -
2774 -
2775 int start = -1; -
2776 int end = -1; -
2777 int indexRow = index.row(); -
2778 int count = d->header->count(); -
2779 bool emptyHeader = (count == 0); -
2780 QModelIndex parent = index.parent(); -
2781 -
2782 if (count && isVisible()) { -
2783 // If the sections have moved, we end up checking too many or too few -
2784 start = d->header->visualIndexAt(0); -
2785 } else { -
2786 // If the header has not been laid out yet, we use the model directly -
2787 count = d->model->columnCount(parent); -
2788 } -
2789 -
2790 if (isRightToLeft()) { -
2791 start = (start == -1 ? count - 1 : start); -
2792 end = 0; -
2793 } else { -
2794 start = (start == -1 ? 0 : start); -
2795 end = count - 1; -
2796 } -
2797 -
2798 if (end < start) -
2799 qSwap(end, start); -
2800 -
2801 int height = -1; -
2802 QStyleOptionViewItem option = d->viewOptions(); -
2803 // ### If we want word wrapping in the items, -
2804 // ### we need to go through all the columns -
2805 // ### and set the width of the column -
2806 -
2807 // Hack to speed up the function -
2808 option.rect.setWidth(-1); -
2809 -
2810 for (int column = start; column <= end; ++column) { -
2811 int logicalColumn = emptyHeader ? column : d->header->logicalIndex(column); -
2812 if (d->header->isSectionHidden(logicalColumn)) -
2813 continue; -
2814 QModelIndex idx = d->model->index(indexRow, logicalColumn, parent); -
2815 if (idx.isValid()) { -
2816 QWidget *editor = d->editorForIndex(idx).widget.data(); -
2817 if (editor && d->persistent.contains(editor)) { -
2818 height = qMax(height, editor->sizeHint().height()); -
2819 int min = editor->minimumSize().height(); -
2820 int max = editor->maximumSize().height(); -
2821 height = qBound(min, height, max); -
2822 } -
2823 int hint = d->delegateForIndex(idx)->sizeHint(option, idx).height(); -
2824 height = qMax(height, hint); -
2825 } -
2826 } -
2827 -
2828 return height; -
2829} -
2830 -
2831/*! -
2832 \since 4.3 -
2833 Returns the height of the row indicated by the given \a index. -
2834 \sa indexRowSizeHint() -
2835*/ -
2836int QTreeView::rowHeight(const QModelIndex &index) const -
2837{ -
2838 Q_D(const QTreeView); -
2839 d->executePostedLayout(); -
2840 int i = d->viewIndex(index); -
2841 if (i == -1) -
2842 return 0; -
2843 return d->itemHeight(i); -
2844} -
2845 -
2846/*! -
2847 \internal -
2848*/ -
2849void QTreeView::horizontalScrollbarAction(int action) -
2850{ -
2851 QAbstractItemView::horizontalScrollbarAction(action); -
2852} -
2853 -
2854/*! -
2855 \reimp -
2856*/ -
2857bool QTreeView::isIndexHidden(const QModelIndex &index) const -
2858{ -
2859 return (isColumnHidden(index.column()) || isRowHidden(index.row(), index.parent())); -
2860} -
2861 -
2862/* -
2863 private implementation -
2864*/ -
2865void QTreeViewPrivate::initialize() -
2866{ -
2867 Q_Q(QTreeView); -
2868 updateStyledFrameWidths(); -
2869 q->setSelectionBehavior(QAbstractItemView::SelectRows); -
2870 q->setSelectionMode(QAbstractItemView::SingleSelection); -
2871 q->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel); -
2872 q->setAttribute(Qt::WA_MacShowFocusRect); -
2873 -
2874 QHeaderView *header = new QHeaderView(Qt::Horizontal, q); -
2875 header->setSectionsMovable(true); -
2876 header->setStretchLastSection(true); -
2877 header->setDefaultAlignment(Qt::AlignLeft|Qt::AlignVCenter); -
2878 q->setHeader(header); -
2879#ifndef QT_NO_ANIMATION -
2880 QObject::connect(&animatedOperation, SIGNAL(finished()), q, SLOT(_q_endAnimatedOperation())); -
2881#endif //QT_NO_ANIMATION -
2882} -
2883 -
2884void QTreeViewPrivate::expand(int item, bool emitSignal) -
2885{ -
2886 Q_Q(QTreeView); -
2887 -
2888 if (item == -1 || viewItems.at(item).expanded) -
2889 return; -
2890 -
2891#ifndef QT_NO_ANIMATION -
2892 if (emitSignal && animationsEnabled) -
2893 prepareAnimatedOperation(item, QVariantAnimation::Forward); -
2894#endif //QT_NO_ANIMATION -
2895 //if already animating, stateBeforeAnimation is set to the correct value -
2896 if (state != QAbstractItemView::AnimatingState) -
2897 stateBeforeAnimation = state; -
2898 q->setState(QAbstractItemView::ExpandingState); -
2899 const QModelIndex index = viewItems.at(item).index; -
2900 storeExpanded(index); -
2901 viewItems[item].expanded = true; -
2902 layout(item); -
2903 q->setState(stateBeforeAnimation); -
2904 -
2905 if (model->canFetchMore(index)) -
2906 model->fetchMore(index); -
2907 if (emitSignal) { -
2908 emit q->expanded(index); -
2909#ifndef QT_NO_ANIMATION -
2910 if (animationsEnabled) -
2911 beginAnimatedOperation(); -
2912#endif //QT_NO_ANIMATION -
2913 } -
2914} -
2915 -
2916void QTreeViewPrivate::insertViewItems(int pos, int count, const QTreeViewItem &viewItem) -
2917{ -
2918 Q_Q(QTreeView); -
2919 Q_UNUSED(q) -
2920 viewItems.insert(pos, count, viewItem); -
2921 QTreeViewItem *items = viewItems.data(); -
2922 for (int i = pos + count; i < viewItems.count(); i++) -
2923 if (items[i].parentItem >= pos) -
2924 items[i].parentItem += count; -
2925} -
2926 -
2927void QTreeViewPrivate::removeViewItems(int pos, int count) -
2928{ -
2929 Q_Q(QTreeView); -
2930 Q_UNUSED(q) -
2931 viewItems.remove(pos, count); -
2932 QTreeViewItem *items = viewItems.data(); -
2933 for (int i = pos; i < viewItems.count(); i++) -
2934 if (items[i].parentItem >= pos) -
2935 items[i].parentItem -= count; -
2936} -
2937 -
2938#if 0 -
2939bool QTreeViewPrivate::checkViewItems() const -
2940{ -
2941 for (int i = 0; i < viewItems.count(); ++i) { -
2942 const QTreeViewItem &vi = viewItems.at(i); -
2943 if (vi.parentItem == -1) { -
2944 Q_ASSERT(!vi.index.parent().isValid() || vi.index.parent() == root); -
2945 } else { -
2946 Q_ASSERT(vi.index.parent() == viewItems.at(vi.parentItem).index); -
2947 } -
2948 } -
2949 return true; -
2950} -
2951#endif -
2952 -
2953void QTreeViewPrivate::collapse(int item, bool emitSignal) -
2954{ -
2955 Q_Q(QTreeView); -
2956 -
2957 if (item == -1 || expandedIndexes.isEmpty()) -
2958 return; -
2959 -
2960 //if the current item is now invisible, the autoscroll will expand the tree to see it, so disable the autoscroll -
2961 delayedAutoScroll.stop(); -
2962 -
2963 int total = viewItems.at(item).total; -
2964 const QModelIndex &modelIndex = viewItems.at(item).index; -
2965 if (!isPersistent(modelIndex)) -
2966 return; // if the index is not persistent, no chances it is expanded -
2967 QSet<QPersistentModelIndex>::iterator it = expandedIndexes.find(modelIndex); -
2968 if (it == expandedIndexes.end() || viewItems.at(item).expanded == false) -
2969 return; // nothing to do -
2970 -
2971#ifndef QT_NO_ANIMATION -
2972 if (emitSignal && animationsEnabled) -
2973 prepareAnimatedOperation(item, QVariantAnimation::Backward); -
2974#endif //QT_NO_ANIMATION -
2975 -
2976 //if already animating, stateBeforeAnimation is set to the correct value -
2977 if (state != QAbstractItemView::AnimatingState) -
2978 stateBeforeAnimation = state; -
2979 q->setState(QAbstractItemView::CollapsingState); -
2980 expandedIndexes.erase(it); -
2981 viewItems[item].expanded = false; -
2982 int index = item; -
2983 while (index > -1) { -
2984 viewItems[index].total -= total; -
2985 index = viewItems[index].parentItem; -
2986 } -
2987 removeViewItems(item + 1, total); // collapse -
2988 q->setState(stateBeforeAnimation); -
2989 -
2990 if (emitSignal) { -
2991 emit q->collapsed(modelIndex); -
2992#ifndef QT_NO_ANIMATION -
2993 if (animationsEnabled) -
2994 beginAnimatedOperation(); -
2995#endif //QT_NO_ANIMATION -
2996 } -
2997} -
2998 -
2999#ifndef QT_NO_ANIMATION -
3000void QTreeViewPrivate::prepareAnimatedOperation(int item, QVariantAnimation::Direction direction) -
3001{ -
3002 animatedOperation.item = item; -
3003 animatedOperation.viewport = viewport; -
3004 animatedOperation.setDirection(direction); -
3005 -
3006 int top = coordinateForItem(item) + itemHeight(item); -
3007 QRect rect = viewport->rect(); -
3008 rect.setTop(top); -
3009 if (direction == QVariantAnimation::Backward) { -
3010 const int limit = rect.height() * 2; -
3011 int h = 0; -
3012 int c = item + viewItems.at(item).total + 1; -
3013 for (int i = item + 1; i < c && h < limit; ++i) -
3014 h += itemHeight(i); -
3015 rect.setHeight(h); -
3016 animatedOperation.setEndValue(top + h); -
3017 } -
3018 animatedOperation.setStartValue(top); -
3019 animatedOperation.before = renderTreeToPixmapForAnimation(rect); -
3020} -
3021 -
3022void QTreeViewPrivate::beginAnimatedOperation() -
3023{ -
3024 Q_Q(QTreeView); -
3025 -
3026 QRect rect = viewport->rect(); -
3027 rect.setTop(animatedOperation.top()); -
3028 if (animatedOperation.direction() == QVariantAnimation::Forward) { -
3029 const int limit = rect.height() * 2; -
3030 int h = 0; -
3031 int c = animatedOperation.item + viewItems.at(animatedOperation.item).total + 1; -
3032 for (int i = animatedOperation.item + 1; i < c && h < limit; ++i) -
3033 h += itemHeight(i); -
3034 rect.setHeight(h); -
3035 animatedOperation.setEndValue(animatedOperation.top() + h); -
3036 } -
3037 -
3038 if (!rect.isEmpty()) { -
3039 animatedOperation.after = renderTreeToPixmapForAnimation(rect); -
3040 -
3041 q->setState(QAbstractItemView::AnimatingState); -
3042 animatedOperation.start(); //let's start the animation -
3043 } -
3044} -
3045 -
3046void QTreeViewPrivate::drawAnimatedOperation(QPainter *painter) const -
3047{ -
3048 const int start = animatedOperation.startValue().toInt(), -
3049 end = animatedOperation.endValue().toInt(), -
3050 current = animatedOperation.currentValue().toInt(); -
3051 bool collapsing = animatedOperation.direction() == QVariantAnimation::Backward; -
3052 const QPixmap top = collapsing ? animatedOperation.before : animatedOperation.after; -
3053 painter->drawPixmap(0, start, top, 0, end - current - 1, top.width(), top.height()); -
3054 const QPixmap bottom = collapsing ? animatedOperation.after : animatedOperation.before; -
3055 painter->drawPixmap(0, current, bottom); -
3056} -
3057 -
3058QPixmap QTreeViewPrivate::renderTreeToPixmapForAnimation(const QRect &rect) const -
3059{ -
3060 Q_Q(const QTreeView); -
3061 QPixmap pixmap(rect.size()); -
3062 if (rect.size().isEmpty()) -
3063 return pixmap; -
3064 pixmap.fill(Qt::transparent); //the base might not be opaque, and we don't want uninitialized pixels. -
3065 QPainter painter(&pixmap); -
3066 painter.fillRect(QRect(QPoint(0,0), rect.size()), q->palette().base()); -
3067 painter.translate(0, -rect.top()); -
3068 q->drawTree(&painter, QRegion(rect)); -
3069 painter.end(); -
3070 -
3071 //and now let's render the editors the editors -
3072 QStyleOptionViewItem option = viewOptions(); -
3073 for (QEditorIndexHash::const_iterator it = editorIndexHash.constBegin(); it != editorIndexHash.constEnd(); ++it) { -
3074 QWidget *editor = it.key(); -
3075 const QModelIndex &index = it.value(); -
3076 option.rect = q->visualRect(index); -
3077 if (option.rect.isValid()) { -
3078 -
3079 if (QAbstractItemDelegate *delegate = delegateForIndex(index)) -
3080 delegate->updateEditorGeometry(editor, option, index); -
3081 -
3082 const QPoint pos = editor->pos(); -
3083 if (rect.contains(pos)) { -
3084 editor->render(&pixmap, pos - rect.topLeft()); -
3085 //the animation uses pixmap to display the treeview's content -
3086 //the editor is rendered on this pixmap and thus can (should) be hidden -
3087 editor->hide(); -
3088 } -
3089 } -
3090 } -
3091 -
3092 -
3093 return pixmap; -
3094} -
3095 -
3096void QTreeViewPrivate::_q_endAnimatedOperation() -
3097{ -
3098 Q_Q(QTreeView); -
3099 q->setState(stateBeforeAnimation); -
3100 q->updateGeometries(); -
3101 viewport->update(); -
3102} -
3103#endif //QT_NO_ANIMATION -
3104 -
3105void QTreeViewPrivate::_q_modelAboutToBeReset() -
3106{ -
3107 viewItems.clear(); -
3108} -
3109 -
3110void QTreeViewPrivate::_q_columnsAboutToBeRemoved(const QModelIndex &parent, int start, int end) -
3111{ -
3112 if (start <= 0 && 0 <= end) -
3113 viewItems.clear(); -
3114 QAbstractItemViewPrivate::_q_columnsAboutToBeRemoved(parent, start, end); -
3115} -
3116 -
3117void QTreeViewPrivate::_q_columnsRemoved(const QModelIndex &parent, int start, int end) -
3118{ -
3119 if (start <= 0 && 0 <= end) -
3120 doDelayedItemsLayout(); -
3121 QAbstractItemViewPrivate::_q_columnsRemoved(parent, start, end); -
3122} -
3123 -
3124/** \internal -
3125 creates and initialize the viewItem structure of the children of the element \li -
3126 -
3127 set \a recursiveExpanding if the function has to expand all the children (called from expandAll) -
3128 \a afterIsUninitialized is when we recurse from layout(-1), it means all the items after 'i' are -
3129 not yet initialized and need not to be moved -
3130 */ -
3131void QTreeViewPrivate::layout(int i, bool recursiveExpanding, bool afterIsUninitialized) -
3132{ -
3133 Q_Q(QTreeView); -
3134 QModelIndex current; -
3135 QModelIndex parent = (i < 0) ? (QModelIndex)root : modelIndex(i); -
3136 -
3137 if (i>=0 && !parent.isValid()) { -
3138 //modelIndex() should never return something invalid for the real items. -
3139 //This can happen if columncount has been set to 0. -
3140 //To avoid infinite loop we stop here. -
3141 return; -
3142 } -
3143 -
3144 int count = 0; -
3145 if (model->hasChildren(parent)) { -
3146 if (model->canFetchMore(parent)) -
3147 model->fetchMore(parent); -
3148 count = model->rowCount(parent); -
3149 } -
3150 -
3151 bool expanding = true; -
3152 if (i == -1) { -
3153 if (uniformRowHeights) { -
3154 QModelIndex index = model->index(0, 0, parent); -
3155 defaultItemHeight = q->indexRowSizeHint(index); -
3156 } -
3157 viewItems.resize(count); -
3158 afterIsUninitialized = true; -
3159 } else if (viewItems[i].total != (uint)count) { -
3160 if (!afterIsUninitialized) -
3161 insertViewItems(i + 1, count, QTreeViewItem()); // expand -
3162 else if (count > 0) -
3163 viewItems.resize(viewItems.count() + count); -
3164 } else { -
3165 expanding = false; -
3166 } -
3167 -
3168 int first = i + 1; -
3169 int level = (i >= 0 ? viewItems.at(i).level + 1 : 0); -
3170 int hidden = 0; -
3171 int last = 0; -
3172 int children = 0; -
3173 QTreeViewItem *item = 0; -
3174 for (int j = first; j < first + count; ++j) { -
3175 current = model->index(j - first, 0, parent); -
3176 if (isRowHidden(current)) { -
3177 ++hidden; -
3178 last = j - hidden + children; -
3179 } else { -
3180 last = j - hidden + children; -
3181 if (item) -
3182 item->hasMoreSiblings = true; -
3183 item = &viewItems[last]; -
3184 item->index = current; -
3185 item->parentItem = i; -
3186 item->level = level; -
3187 item->height = 0; -
3188 item->spanning = q->isFirstColumnSpanned(current.row(), parent); -
3189 item->expanded = false; -
3190 item->total = 0; -
3191 item->hasMoreSiblings = false; -
3192 if (recursiveExpanding || isIndexExpanded(current)) { -
3193 if (recursiveExpanding) -
3194 expandedIndexes.insert(current); -
3195 item->expanded = true; -
3196 layout(last, recursiveExpanding, afterIsUninitialized); -
3197 item = &viewItems[last]; -
3198 children += item->total; -
3199 item->hasChildren = item->total > 0; -
3200 last = j - hidden + children; -
3201 } else { -
3202 item->hasChildren = hasVisibleChildren(current); -
3203 } -
3204 } -
3205 } -
3206 -
3207 // remove hidden items -
3208 if (hidden > 0) { -
3209 if (!afterIsUninitialized) -
3210 removeViewItems(last + 1, hidden); -
3211 else -
3212 viewItems.resize(viewItems.size() - hidden); -
3213 } -
3214 -
3215 if (!expanding) -
3216 return; // nothing changed -
3217 -
3218 while (i > -1) { -
3219 viewItems[i].total += count - hidden; -
3220 i = viewItems[i].parentItem; -
3221 } -
3222} -
3223 -
3224int QTreeViewPrivate::pageUp(int i) const -
3225{ -
3226 int index = itemAtCoordinate(coordinateForItem(i) - viewport->height()); -
3227 while (isItemHiddenOrDisabled(index)) -
3228 index--; -
3229 return index == -1 ? 0 : index; -
3230} -
3231 -
3232int QTreeViewPrivate::pageDown(int i) const -
3233{ -
3234 int index = itemAtCoordinate(coordinateForItem(i) + viewport->height()); -
3235 while (isItemHiddenOrDisabled(index)) -
3236 index++; -
3237 return index == -1 ? viewItems.count() - 1 : index; -
3238} -
3239 -
3240int QTreeViewPrivate::indentationForItem(int item) const -
3241{ -
3242 if (item < 0 || item >= viewItems.count()) -
3243 return 0; -
3244 int level = viewItems.at(item).level; -
3245 if (rootDecoration) -
3246 ++level; -
3247 return level * indent; -
3248} -
3249 -
3250int QTreeViewPrivate::itemHeight(int item) const -
3251{ -
3252 if (uniformRowHeights) -
3253 return defaultItemHeight; -
3254 if (viewItems.isEmpty()) -
3255 return 0; -
3256 const QModelIndex &index = viewItems.at(item).index; -
3257 if (!index.isValid()) -
3258 return 0; -
3259 int height = viewItems.at(item).height; -
3260 if (height <= 0) { -
3261 height = q_func()->indexRowSizeHint(index); -
3262 viewItems[item].height = height; -
3263 } -
3264 return qMax(height, 0); -
3265} -
3266 -
3267 -
3268/*! -
3269 \internal -
3270 Returns the viewport y coordinate for \a item. -
3271*/ -
3272int QTreeViewPrivate::coordinateForItem(int item) const -
3273{ -
3274 if (verticalScrollMode == QAbstractItemView::ScrollPerPixel) { -
3275 if (uniformRowHeights) -
3276 return (item * defaultItemHeight) - vbar->value(); -
3277 // ### optimize (spans or caching) -
3278 int y = 0; -
3279 for (int i = 0; i < viewItems.count(); ++i) { -
3280 if (i == item) -
3281 return y - vbar->value(); -
3282 y += itemHeight(i); -
3283 } -
3284 } else { // ScrollPerItem -
3285 int topViewItemIndex = vbar->value(); -
3286 if (uniformRowHeights) -
3287 return defaultItemHeight * (item - topViewItemIndex); -
3288 if (item >= topViewItemIndex) { -
3289 // search in the visible area first and continue down -
3290 // ### slow if the item is not visible -
3291 int viewItemCoordinate = 0; -
3292 int viewItemIndex = topViewItemIndex; -
3293 while (viewItemIndex < viewItems.count()) { -
3294 if (viewItemIndex == item) -
3295 return viewItemCoordinate; -
3296 viewItemCoordinate += itemHeight(viewItemIndex); -
3297 ++viewItemIndex; -
3298 } -
3299 // below the last item in the view -
3300 Q_ASSERT(false); -
3301 return viewItemCoordinate; -
3302 } else { -
3303 // search the area above the viewport (used for editor widgets) -
3304 int viewItemCoordinate = 0; -
3305 for (int viewItemIndex = topViewItemIndex; viewItemIndex > 0; --viewItemIndex) { -
3306 if (viewItemIndex == item) -
3307 return viewItemCoordinate; -
3308 viewItemCoordinate -= itemHeight(viewItemIndex - 1); -
3309 } -
3310 return viewItemCoordinate; -
3311 } -
3312 } -
3313 return 0; -
3314} -
3315 -
3316/*! -
3317 \internal -
3318 Returns the index of the view item at the -
3319 given viewport \a coordinate. -
3320 -
3321 \sa modelIndex() -
3322*/ -
3323int QTreeViewPrivate::itemAtCoordinate(int coordinate) const -
3324{ -
3325 const int itemCount = viewItems.count(); -
3326 if (itemCount == 0) -
3327 return -1; -
3328 if (uniformRowHeights && defaultItemHeight <= 0) -
3329 return -1; -
3330 if (verticalScrollMode == QAbstractItemView::ScrollPerPixel) { -
3331 if (uniformRowHeights) { -
3332 const int viewItemIndex = (coordinate + vbar->value()) / defaultItemHeight; -
3333 return ((viewItemIndex >= itemCount || viewItemIndex < 0) ? -1 : viewItemIndex); -
3334 } -
3335 // ### optimize -
3336 int viewItemCoordinate = 0; -
3337 const int contentsCoordinate = coordinate + vbar->value(); -
3338 for (int viewItemIndex = 0; viewItemIndex < viewItems.count(); ++viewItemIndex) { -
3339 viewItemCoordinate += itemHeight(viewItemIndex); -
3340 if (viewItemCoordinate >= contentsCoordinate) -
3341 return (viewItemIndex >= itemCount ? -1 : viewItemIndex); -
3342 } -
3343 } else { // ScrollPerItem -
3344 int topViewItemIndex = vbar->value(); -
3345 if (uniformRowHeights) { -
3346 if (coordinate < 0) -
3347 coordinate -= defaultItemHeight - 1; -
3348 const int viewItemIndex = topViewItemIndex + (coordinate / defaultItemHeight); -
3349 return ((viewItemIndex >= itemCount || viewItemIndex < 0) ? -1 : viewItemIndex); -
3350 } -
3351 if (coordinate >= 0) { -
3352 // the coordinate is in or below the viewport -
3353 int viewItemCoordinate = 0; -
3354 for (int viewItemIndex = topViewItemIndex; viewItemIndex < viewItems.count(); ++viewItemIndex) { -
3355 viewItemCoordinate += itemHeight(viewItemIndex); -
3356 if (viewItemCoordinate > coordinate) -
3357 return (viewItemIndex >= itemCount ? -1 : viewItemIndex); -
3358 } -
3359 } else { -
3360 // the coordinate is above the viewport -
3361 int viewItemCoordinate = 0; -
3362 for (int viewItemIndex = topViewItemIndex; viewItemIndex >= 0; --viewItemIndex) { -
3363 if (viewItemCoordinate <= coordinate) -
3364 return (viewItemIndex >= itemCount ? -1 : viewItemIndex); -
3365 viewItemCoordinate -= itemHeight(viewItemIndex); -
3366 } -
3367 } -
3368 } -
3369 return -1; -
3370} -
3371 -
3372int QTreeViewPrivate::viewIndex(const QModelIndex &_index) const -
3373{ -
3374 if (!_index.isValid() || viewItems.isEmpty()) -
3375 return -1; -
3376 -
3377 const int totalCount = viewItems.count(); -
3378 const QModelIndex index = _index.sibling(_index.row(), 0); -
3379 const int row = index.row(); -
3380 const quintptr internalId = index.internalId(); -
3381 -
3382 // We start nearest to the lastViewedItem -
3383 int localCount = qMin(lastViewedItem - 1, totalCount - lastViewedItem); -
3384 for (int i = 0; i < localCount; ++i) { -
3385 const QModelIndex &idx1 = viewItems.at(lastViewedItem + i).index; -
3386 if (idx1.row() == row && idx1.internalId() == internalId) { -
3387 lastViewedItem = lastViewedItem + i; -
3388 return lastViewedItem; -
3389 } -
3390 const QModelIndex &idx2 = viewItems.at(lastViewedItem - i - 1).index; -
3391 if (idx2.row() == row && idx2.internalId() == internalId) { -
3392 lastViewedItem = lastViewedItem - i - 1; -
3393 return lastViewedItem; -
3394 } -
3395 } -
3396 -
3397 for (int j = qMax(0, lastViewedItem + localCount); j < totalCount; ++j) { -
3398 const QModelIndex &idx = viewItems.at(j).index; -
3399 if (idx.row() == row && idx.internalId() == internalId) { -
3400 lastViewedItem = j; -
3401 return j; -
3402 } -
3403 } -
3404 for (int j = qMin(totalCount, lastViewedItem - localCount) - 1; j >= 0; --j) { -
3405 const QModelIndex &idx = viewItems.at(j).index; -
3406 if (idx.row() == row && idx.internalId() == internalId) { -
3407 lastViewedItem = j; -
3408 return j; -
3409 } -
3410 } -
3411 -
3412 // nothing found -
3413 return -1; -
3414} -
3415 -
3416QModelIndex QTreeViewPrivate::modelIndex(int i, int column) const -
3417{ -
3418 if (i < 0 || i >= viewItems.count()) -
3419 return QModelIndex(); -
3420 -
3421 QModelIndex ret = viewItems.at(i).index; -
3422 if (column) -
3423 ret = ret.sibling(ret.row(), column); -
3424 return ret; -
3425} -
3426 -
3427int QTreeViewPrivate::firstVisibleItem(int *offset) const -
3428{ -
3429 const int value = vbar->value(); -
3430 if (verticalScrollMode == QAbstractItemView::ScrollPerItem) { -
3431 if (offset) -
3432 *offset = 0; -
3433 return (value < 0 || value >= viewItems.count()) ? -1 : value; -
3434 } -
3435 // ScrollMode == ScrollPerPixel -
3436 if (uniformRowHeights) { -
3437 if (!defaultItemHeight) -
3438 return -1; -
3439 -
3440 if (offset) -
3441 *offset = -(value % defaultItemHeight); -
3442 return value / defaultItemHeight; -
3443 } -
3444 int y = 0; // ### optimize (use spans ?) -
3445 for (int i = 0; i < viewItems.count(); ++i) { -
3446 y += itemHeight(i); // the height value is cached -
3447 if (y > value) { -
3448 if (offset) -
3449 *offset = y - value - itemHeight(i); -
3450 return i; -
3451 } -
3452 } -
3453 return -1; -
3454} -
3455 -
3456int QTreeViewPrivate::columnAt(int x) const -
3457{ -
3458 return header->logicalIndexAt(x); -
3459} -
3460 -
3461void QTreeViewPrivate::updateScrollBars() -
3462{ -
3463 Q_Q(QTreeView); -
3464 QSize viewportSize = viewport->size(); -
3465 if (!viewportSize.isValid()) -
3466 viewportSize = QSize(0, 0); -
3467 -
3468 if (viewItems.isEmpty()) { -
3469 q->doItemsLayout(); -
3470 } -
3471 -
3472 int itemsInViewport = 0; -
3473 if (uniformRowHeights) { -
3474 if (defaultItemHeight <= 0) -
3475 itemsInViewport = viewItems.count(); -
3476 else -
3477 itemsInViewport = viewportSize.height() / defaultItemHeight; -
3478 } else { -
3479 const int itemsCount = viewItems.count(); -
3480 const int viewportHeight = viewportSize.height(); -
3481 for (int height = 0, item = itemsCount - 1; item >= 0; --item) { -
3482 height += itemHeight(item); -
3483 if (height > viewportHeight) -
3484 break; -
3485 ++itemsInViewport; -
3486 } -
3487 } -
3488 if (verticalScrollMode == QAbstractItemView::ScrollPerItem) { -
3489 if (!viewItems.isEmpty()) -
3490 itemsInViewport = qMax(1, itemsInViewport); -
3491 vbar->setRange(0, viewItems.count() - itemsInViewport); -
3492 vbar->setPageStep(itemsInViewport); -
3493 vbar->setSingleStep(1); -
3494 } else { // scroll per pixel -
3495 int contentsHeight = 0; -
3496 if (uniformRowHeights) { -
3497 contentsHeight = defaultItemHeight * viewItems.count(); -
3498 } else { // ### optimize (spans or caching) -
3499 for (int i = 0; i < viewItems.count(); ++i) -
3500 contentsHeight += itemHeight(i); -
3501 } -
3502 vbar->setRange(0, contentsHeight - viewportSize.height()); -
3503 vbar->setPageStep(viewportSize.height()); -
3504 vbar->setSingleStep(qMax(viewportSize.height() / (itemsInViewport + 1), 2)); -
3505 } -
3506 -
3507 const int columnCount = header->count(); -
3508 const int viewportWidth = viewportSize.width(); -
3509 int columnsInViewport = 0; -
3510 for (int width = 0, column = columnCount - 1; column >= 0; --column) { -
3511 int logical = header->logicalIndex(column); -
3512 width += header->sectionSize(logical); -
3513 if (width > viewportWidth) -
3514 break; -
3515 ++columnsInViewport; -
3516 } -
3517 if (columnCount > 0) -
3518 columnsInViewport = qMax(1, columnsInViewport); -
3519 if (horizontalScrollMode == QAbstractItemView::ScrollPerItem) { -
3520 hbar->setRange(0, columnCount - columnsInViewport); -
3521 hbar->setPageStep(columnsInViewport); -
3522 hbar->setSingleStep(1); -
3523 } else { // scroll per pixel -
3524 const int horizontalLength = header->length(); -
3525 const QSize maxSize = q->maximumViewportSize(); -
3526 if (maxSize.width() >= horizontalLength && vbar->maximum() <= 0) -
3527 viewportSize = maxSize; -
3528 hbar->setPageStep(viewportSize.width()); -
3529 hbar->setRange(0, qMax(horizontalLength - viewportSize.width(), 0)); -
3530 hbar->setSingleStep(qMax(viewportSize.width() / (columnsInViewport + 1), 2)); -
3531 } -
3532} -
3533 -
3534int QTreeViewPrivate::itemDecorationAt(const QPoint &pos) const -
3535{ -
3536 executePostedLayout(); -
3537 int x = pos.x(); -
3538 int column = header->logicalIndexAt(x); -
3539 if (column != 0) -
3540 return -1; // no logical index at x -
3541 -
3542 int viewItemIndex = itemAtCoordinate(pos.y()); -
3543 QRect returning = itemDecorationRect(modelIndex(viewItemIndex)); -
3544 if (!returning.contains(pos)) -
3545 return -1; -
3546 -
3547 return viewItemIndex; -
3548} -
3549 -
3550QRect QTreeViewPrivate::itemDecorationRect(const QModelIndex &index) const -
3551{ -
3552 Q_Q(const QTreeView); -
3553 if (!rootDecoration && index.parent() == root) -
3554 return QRect(); // no decoration at root -
3555 -
3556 int viewItemIndex = viewIndex(index); -
3557 if (viewItemIndex < 0 || !hasVisibleChildren(viewItems.at(viewItemIndex).index)) -
3558 return QRect(); -
3559 -
3560 int itemIndentation = indentationForItem(viewItemIndex); -
3561 int position = header->sectionViewportPosition(0); -
3562 int size = header->sectionSize(0); -
3563 -
3564 QRect rect; -
3565 if (q->isRightToLeft()) -
3566 rect = QRect(position + size - itemIndentation, coordinateForItem(viewItemIndex), -
3567 indent, itemHeight(viewItemIndex)); -
3568 else -
3569 rect = QRect(position + itemIndentation - indent, coordinateForItem(viewItemIndex), -
3570 indent, itemHeight(viewItemIndex)); -
3571 QStyleOption opt; -
3572 opt.initFrom(q); -
3573 opt.rect = rect; -
3574 return q->style()->subElementRect(QStyle::SE_TreeViewDisclosureItem, &opt, q); -
3575} -
3576 -
3577QList<QPair<int, int> > QTreeViewPrivate::columnRanges(const QModelIndex &topIndex, -
3578 const QModelIndex &bottomIndex) const -
3579{ -
3580 const int topVisual = header->visualIndex(topIndex.column()), -
3581 bottomVisual = header->visualIndex(bottomIndex.column()); -
3582 -
3583 const int start = qMin(topVisual, bottomVisual); -
3584 const int end = qMax(topVisual, bottomVisual); -
3585 -
3586 QList<int> logicalIndexes; -
3587 -
3588 //we iterate over the visual indexes to get the logical indexes -
3589 for (int c = start; c <= end; c++) { -
3590 const int logical = header->logicalIndex(c); -
3591 if (!header->isSectionHidden(logical)) { -
3592 logicalIndexes << logical; -
3593 } -
3594 } -
3595 //let's sort the list -
3596 qSort(logicalIndexes.begin(), logicalIndexes.end()); -
3597 -
3598 QList<QPair<int, int> > ret; -
3599 QPair<int, int> current; -
3600 current.first = -2; // -1 is not enough because -1+1 = 0 -
3601 current.second = -2; -
3602 for(int i = 0; i < logicalIndexes.count(); ++i) { -
3603 const int logicalColumn = logicalIndexes.at(i); -
3604 if (current.second + 1 != logicalColumn) { -
3605 if (current.first != -2) { -
3606 //let's save the current one -
3607 ret += current; -
3608 } -
3609 //let's start a new one -
3610 current.first = current.second = logicalColumn; -
3611 } else { -
3612 current.second++; -
3613 } -
3614 } -
3615 -
3616 //let's get the last range -
3617 if (current.first != -2) { -
3618 ret += current; -
3619 } -
3620 -
3621 return ret; -
3622} -
3623 -
3624void QTreeViewPrivate::select(const QModelIndex &topIndex, const QModelIndex &bottomIndex, -
3625 QItemSelectionModel::SelectionFlags command) -
3626{ -
3627 Q_Q(QTreeView); -
3628 QItemSelection selection; -
3629 const int top = viewIndex(topIndex), -
3630 bottom = viewIndex(bottomIndex); -
3631 -
3632 const QList< QPair<int, int> > colRanges = columnRanges(topIndex, bottomIndex); -
3633 QList< QPair<int, int> >::const_iterator it; -
3634 for (it = colRanges.begin(); it != colRanges.end(); ++it) { -
3635 const int left = (*it).first, -
3636 right = (*it).second; -
3637 -
3638 QModelIndex previous; -
3639 QItemSelectionRange currentRange; -
3640 QStack<QItemSelectionRange> rangeStack; -
3641 for (int i = top; i <= bottom; ++i) { -
3642 QModelIndex index = modelIndex(i); -
3643 QModelIndex parent = index.parent(); -
3644 QModelIndex previousParent = previous.parent(); -
3645 if (previous.isValid() && parent == previousParent) { -
3646 // same parent -
3647 if (qAbs(previous.row() - index.row()) > 1) { -
3648 //a hole (hidden index inside a range) has been detected -
3649 if (currentRange.isValid()) { -
3650 selection.append(currentRange); -
3651 } -
3652 //let's start a new range -
3653 currentRange = QItemSelectionRange(index.sibling(index.row(), left), index.sibling(index.row(), right)); -
3654 } else { -
3655 QModelIndex tl = model->index(currentRange.top(), currentRange.left(), -
3656 currentRange.parent()); -
3657 currentRange = QItemSelectionRange(tl, index.sibling(index.row(), right)); -
3658 } -
3659 } else if (previous.isValid() && parent == model->index(previous.row(), 0, previousParent)) { -
3660 // item is child of previous -
3661 rangeStack.push(currentRange); -
3662 currentRange = QItemSelectionRange(index.sibling(index.row(), left), index.sibling(index.row(), right)); -
3663 } else { -
3664 if (currentRange.isValid()) -
3665 selection.append(currentRange); -
3666 if (rangeStack.isEmpty()) { -
3667 currentRange = QItemSelectionRange(index.sibling(index.row(), left), index.sibling(index.row(), right)); -
3668 } else { -
3669 currentRange = rangeStack.pop(); -
3670 index = currentRange.bottomRight(); //let's resume the range -
3671 --i; //we process again the current item -
3672 } -
3673 } -
3674 previous = index; -
3675 } -
3676 if (currentRange.isValid()) -
3677 selection.append(currentRange); -
3678 for (int i = 0; i < rangeStack.count(); ++i) -
3679 selection.append(rangeStack.at(i)); -
3680 } -
3681 q->selectionModel()->select(selection, command); -
3682} -
3683 -
3684QPair<int,int> QTreeViewPrivate::startAndEndColumns(const QRect &rect) const -
3685{ -
3686 Q_Q(const QTreeView); -
3687 int start = header->visualIndexAt(rect.left()); -
3688 int end = header->visualIndexAt(rect.right()); -
3689 if (q->isRightToLeft()) { -
3690 start = (start == -1 ? header->count() - 1 : start); -
3691 end = (end == -1 ? 0 : end); -
3692 } else { -
3693 start = (start == -1 ? 0 : start); -
3694 end = (end == -1 ? header->count() - 1 : end); -
3695 } -
3696 return qMakePair<int,int>(qMin(start, end), qMax(start, end)); -
3697} -
3698 -
3699bool QTreeViewPrivate::hasVisibleChildren(const QModelIndex& parent) const -
3700{ -
3701 Q_Q(const QTreeView); -
3702 if (model->hasChildren(parent)) { -
3703 if (hiddenIndexes.isEmpty()) -
3704 return true; -
3705 if (q->isIndexHidden(parent)) -
3706 return false; -
3707 int rowCount = model->rowCount(parent); -
3708 for (int i = 0; i < rowCount; ++i) { -
3709 if (!q->isRowHidden(i, parent)) -
3710 return true; -
3711 } -
3712 if (rowCount == 0) -
3713 return true; -
3714 } -
3715 return false; -
3716} -
3717 -
3718void QTreeViewPrivate::_q_sortIndicatorChanged(int column, Qt::SortOrder order) -
3719{ -
3720 model->sort(column, order); -
3721} -
3722 -
3723/*! -
3724 \reimp -
3725 */ -
3726void QTreeView::currentChanged(const QModelIndex &current, const QModelIndex &previous) -
3727{ -
3728 QAbstractItemView::currentChanged(current, previous); -
3729 -
3730 if (allColumnsShowFocus()) { -
3731 if (previous.isValid()) { -
3732 QRect previousRect = visualRect(previous); -
3733 previousRect.setX(0); -
3734 previousRect.setWidth(viewport()->width()); -
3735 viewport()->update(previousRect); -
3736 } -
3737 if (current.isValid()) { -
3738 QRect currentRect = visualRect(current); -
3739 currentRect.setX(0); -
3740 currentRect.setWidth(viewport()->width()); -
3741 viewport()->update(currentRect); -
3742 } -
3743 } -
3744#ifndef QT_NO_ACCESSIBILITY -
3745 if (QAccessible::isActive() && current.isValid()) { -
3746 int entry = (visualIndex(current) + (header()?1:0))*current.model()->columnCount()+current.column(); -
3747 QAccessibleEvent event(this, QAccessible::Focus); -
3748 event.setChild(entry); -
3749 QAccessible::updateAccessibility(&event); -
3750 } -
3751#endif -
3752} -
3753 -
3754/*! -
3755 \reimp -
3756 */ -
3757void QTreeView::selectionChanged(const QItemSelection &selected, -
3758 const QItemSelection &deselected) -
3759{ -
3760 QAbstractItemView::selectionChanged(selected, deselected); -
3761#ifndef QT_NO_ACCESSIBILITY -
3762 if (QAccessible::isActive()) { -
3763 // ### does not work properly for selection ranges. -
3764 QModelIndex sel = selected.indexes().value(0); -
3765 if (sel.isValid()) { -
3766 int entry = (visualIndex(sel) + (header()?1:0))*sel.model()->columnCount()+sel.column(); -
3767 Q_ASSERT(entry >= 0); -
3768 QAccessibleEvent event(this, QAccessible::Selection); -
3769 event.setChild(entry); -
3770 QAccessible::updateAccessibility(&event); -
3771 } -
3772 QModelIndex desel = deselected.indexes().value(0); -
3773 if (desel.isValid()) { -
3774 int entry = (visualIndex(desel) + (header()?1:0))*desel.model()->columnCount()+desel.column(); -
3775 Q_ASSERT(entry >= 0); -
3776 QAccessibleEvent event(this, QAccessible::SelectionRemove); -
3777 event.setChild(entry); -
3778 QAccessible::updateAccessibility(&event); -
3779 } -
3780 } -
3781#endif -
3782} -
3783 -
3784int QTreeView::visualIndex(const QModelIndex &index) const -
3785{ -
3786 Q_D(const QTreeView); -
3787 d->executePostedLayout(); -
3788 return d->viewIndex(index); -
3789} -
3790 -
3791QT_END_NAMESPACE -
3792 -
3793#include "moc_qtreeview.cpp" -
3794 -
3795#endif // QT_NO_TREEVIEW -
3796 -
Source codeSwitch to Preprocessed file

Generated by Squish Coco Non-Commercial