1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the Qt3Support module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file. Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include <qplatformdefs.h>
43 #include "q3listview.h"
44 #ifndef QT_NO_LISTVIEW
45 #include "q3tl.h"
46 #include "qapplication.h"
47 #include "qbitmap.h"
48 #include "q3cleanuphandler.h"
49 #include "qcursor.h"
50 #include "qdatetime.h"
51 #include "q3dragobject.h"
52 #include "qevent.h"
53 #include "qhash.h"
54 #include "q3header.h"
55 #include "qicon.h"
56 #include "qlineedit.h"
57 #include "qpainter.h"
58 #include "qpixmapcache.h"
59 #include "qstack.h"
60 #include "qstyle.h"
61 #include "qstyleoption.h"
62 #include "qtimer.h"
63 #include "qtooltip.h"
64 #include "qdebug.h"
65 #ifndef QT_NO_ACCESSIBILITY
66 #include "qaccessible.h"
67 #endif
68
69 QT_BEGIN_NAMESPACE
70
71 const int Unsorted = 16383;
72
73 struct Q3ListViewPrivate
74 {
75 // classes that are here to avoid polluting the global name space
76
77 // the magical hidden mother of all items
78 class Root: public Q3ListViewItem {
79 public:
80 Root(Q3ListView * parent);
81
82 void setHeight(int);
83 void invalidateHeight();
84 void setup();
85 Q3ListView * theListView() const;
86
87 Q3ListView * lv;
88 };
89
90 // to remember what's on screen
91 class DrawableItem {
92 public:
DrawableItem()93 DrawableItem() {}
DrawableItem(int level,int ypos,Q3ListViewItem * item)94 DrawableItem(int level, int ypos, Q3ListViewItem * item)
95 : l(level), y(ypos), i(item) {};
96 int l;
97 int y;
98 Q3ListViewItem * i;
99 };
100
101 // for sorting
102 class SortableItem {
103 public:
104 /*
105 We could be smarter and keep a pointer to the Q3ListView
106 item instead of numCols, col and asc. This would then allow
107 us to use the physical ordering of columns rather than the
108 logical. Microsoft uses the logical ordering, so there is
109 some virtue in doing so, although it prevents the user from
110 choosing the secondary key.
111 */
112 Q3ListViewItem * item;
113 int numCols;
114 int col;
115 bool asc;
116
cmp(const SortableItem & i) const117 int cmp(const SortableItem& i) const {
118 int diff = item->compare(i.item, col, asc);
119 if (diff == 0 && numCols != 1) {
120 for (int j = 0; j < numCols; j++) {
121 if (j != col) {
122 diff = item->compare(i.item, j, asc);
123 if (diff != 0)
124 break;
125 }
126 }
127 }
128 return diff;
129 }
operator <(const SortableItem & i) const130 bool operator<(const SortableItem& i) const { return cmp(i) < 0; }
operator <=(const SortableItem & i) const131 bool operator<=(const SortableItem& i) const { return cmp(i) <= 0; }
operator >(const SortableItem & i) const132 bool operator>(const SortableItem& i) const { return cmp(i) > 0; }
133 };
134
135 class ItemColumnInfo {
136 public:
ItemColumnInfo()137 ItemColumnInfo(): pm(0), next(0), truncated(false), dirty(false), allow_rename(false), width(0) {}
~ItemColumnInfo()138 ~ItemColumnInfo() { delete pm; delete next; }
139 QString text, tmpText;
140 QPixmap * pm;
141 ItemColumnInfo * next;
142 uint truncated : 1;
143 uint dirty : 1;
144 uint allow_rename : 1;
145 int width;
146 };
147
148 class ViewColumnInfo {
149 public:
ViewColumnInfo()150 ViewColumnInfo(): align(Qt::AlignAuto), sortable(true), next(0) {}
~ViewColumnInfo()151 ~ViewColumnInfo() { delete next; }
152 int align;
153 bool sortable;
154 ViewColumnInfo * next;
155 };
156
157 // private variables used in Q3ListView
158 ViewColumnInfo * vci;
159 Q3Header * h;
160 Root * r;
161 uint rootIsExpandable : 1;
162 int margin;
163
164 Q3ListViewItem * focusItem, *highlighted, *oldFocusItem;
165
166 QTimer * timer;
167 QTimer * dirtyItemTimer;
168 QTimer * visibleTimer;
169 int levelWidth;
170
171 // the list of drawables, and the range drawables covers entirely
172 // (it may also include a few items above topPixel)
173 QList<DrawableItem> drawables;
174 int topPixel;
175 int bottomPixel;
176
177 QList<const Q3ListViewItem *> dirtyItems;
178
179 Q3ListView::SelectionMode selectionMode;
180
181 // Per-column structure for information not in the Q3Header
182 struct Column {
183 Q3ListView::WidthMode wmode;
184 };
185 QVector<Column> column;
186
187 // suggested height for the items
188 int fontMetricsHeight;
189 int minLeftBearing, minRightBearing;
190 int ellipsisWidth;
191
192 // currently typed prefix for the keyboard interface, and the time
193 // of the last key-press
194 QString currentPrefix;
195 QTime currentPrefixTime;
196
197 // holds a list of iterators
198 QList<Q3ListViewItemIterator *> iterators;
199 Q3ListViewItem *pressedItem, *selectAnchor;
200
201 QTimer *scrollTimer;
202 QTimer *renameTimer;
203 QTimer *autoopenTimer;
204
205 // sort column and order #### may need to move to Q3Header [subclass]
206 int sortcolumn;
207 bool ascending :1;
208 bool sortIndicator :1;
209 // whether to select or deselect during this mouse press.
210 bool allColumnsShowFocus :1;
211 bool select :1;
212
213 // true if the widget should take notice of mouseReleaseEvent
214 bool buttonDown :1;
215 // true if the widget should ignore a double-click
216 bool ignoreDoubleClick :1;
217
218 bool clearing :1;
219 bool pressedSelected :1;
220 bool pressedEmptyArea :1;
221
222 bool toolTips :1;
223 bool fullRepaintOnComlumnChange:1;
224 bool updateHeader :1;
225
226 bool startEdit : 1;
227 bool ignoreEditAfterFocus : 1;
228 bool inMenuMode :1;
229
230 Q3ListView::RenameAction defRenameAction;
231
232 Q3ListViewItem *startDragItem;
233 QPoint dragStartPos;
234 int pressedColumn;
235 Q3ListView::ResizeMode resizeMode;
236 };
237
238 Q_DECLARE_TYPEINFO(Q3ListViewPrivate::DrawableItem, Q_PRIMITIVE_TYPE);
239
240 // these should probably be in Q3ListViewPrivate, for future thread safety
241 static bool activatedByClick;
242 static QPoint activatedP;
243
244 #ifndef QT_NO_ACCESSIBILITY
indexOfItem(Q3ListViewItem * item)245 static int indexOfItem(Q3ListViewItem *item)
246 {
247 if (!QAccessible::isActive())
248 return 0;
249
250 static Q3ListViewItem *lastItem = 0;
251 static int lastIndex = 0;
252
253 if (!item || !item->listView())
254 return 0;
255
256 if (item == lastItem)
257 return lastIndex;
258
259 lastItem = item;
260 int index = 1;
261
262 Q3ListViewItemIterator it(item->listView());
263 while (it.current()) {
264 if (it.current() == item) {
265 lastIndex = index;
266 return index;
267 }
268 ++it;
269 ++index;
270 }
271 lastIndex = 0;
272 return 0;
273 }
274 #endif
275
276 /*!
277 Creates a string with ... like "Trollte..." or "...olltech", depending on the alignment.
278 */
qEllipsisText(const QString & org,const QFontMetrics & fm,int width,int align)279 static QString qEllipsisText(const QString &org, const QFontMetrics &fm, int width, int align)
280 {
281 int ellWidth = fm.width(QLatin1String("..."));
282 QString text = QString::fromLatin1("");
283 int i = 0;
284 int len = org.length();
285 int offset = (align & Qt::AlignRight) ? (len-1) - i : i;
286 while (i < len && fm.width(text + org[offset]) + ellWidth < width) {
287 if (align & Qt::AlignRight)
288 text.prepend(org[offset]);
289 else
290 text += org[offset];
291 offset = (align & Qt::AlignRight) ? (len-1) - ++i : ++i;
292 }
293 if (text.isEmpty())
294 text = (align & Qt::AlignRight) ? org.right(1) : text = org.left(1);
295 if (align & Qt::AlignRight)
296 text.prepend(QLatin1String("..."));
297 else
298 text += QLatin1String("...");
299 return text;
300 }
301
302 /*!
303 \class Q3ListViewItem
304 \brief The Q3ListViewItem class implements a list view item.
305
306 \compat
307
308 A list view item is a multi-column object capable of displaying
309 itself in a Q3ListView.
310
311 The easiest way to use Q3ListViewItem is to construct one with a
312 few constant strings, and either a Q3ListView or another
313 Q3ListViewItem as parent.
314 \snippet doc/src/snippets/code/src_qt3support_itemviews_q3listview.cpp 0
315 We've discarded the pointers to the items since we can still access
316 them via their parent \e listView. By default, Q3ListView sorts its
317 items; this can be switched off with Q3ListView::setSorting(-1).
318
319 The parent must be another Q3ListViewItem or a Q3ListView. If the
320 parent is a Q3ListView, the item becomes a top-level item within
321 that Q3ListView. If the parent is another Q3ListViewItem, the item
322 becomes a child of that list view item.
323
324 If you keep the pointer, you can set or change the texts using
325 setText(), add pixmaps using setPixmap(), change its mode using
326 setSelectable(), setSelected(), setOpen() and setExpandable().
327 You'll also be able to change its height using setHeight(), and
328 traverse its sub-items. You don't have to keep the pointer since
329 you can get a pointer to any Q3ListViewItem in a Q3ListView using
330 Q3ListView::selectedItem(), Q3ListView::currentItem(),
331 Q3ListView::firstChild(), Q3ListView::lastItem() and
332 Q3ListView::findItem().
333
334 If you call \c delete on a list view item, it will be deleted as
335 expected, and as usual for \l{QObject}s, if it has any child items
336 (to any depth), all these will be deleted too.
337
338 \l{Q3CheckListItem}s are list view items that have a checkbox or
339 radio button and can be used in place of plain Q3ListViewItems.
340
341 You can traverse the tree as if it were a doubly-linked list using
342 itemAbove() and itemBelow(); they return pointers to the items
343 directly above and below this item on the screen (even if none of
344 them are actually visible at the moment).
345
346 Here's how to traverse all of an item's children (but not its
347 children's children, etc.):
348 Example:
349 \snippet doc/src/snippets/code/src_qt3support_itemviews_q3listview.cpp 1
350
351 If you want to iterate over every item, to any level of depth use
352 an iterator. To iterate over the entire tree, initialize the
353 iterator with the list view itself; to iterate over an item's
354 children (and children's children to any depth), initialize the
355 iterator with the item:
356 \snippet doc/src/snippets/code/src_qt3support_itemviews_q3listview.cpp 2
357
358 Note that the order of the children will change when the sorting
359 order changes and is undefined if the items are not visible. You
360 can, however, call enforceSortOrder() at any time; Q3ListView will
361 always call it before it needs to show an item.
362
363 Many programs will need to reimplement Q3ListViewItem. The most
364 commonly reimplemented functions are:
365 \table
366 \header \i Function \i Description
367 \row \i \l text()
368 \i Returns the text in a column. Many subclasses will compute
369 this on the fly.
370 \row \i \l key()
371 \i Used for sorting. The default key() simply calls
372 text(), but judicious use of key() can give you fine
373 control over sorting; for example, QFileDialog
374 reimplements key() to sort by date.
375 \row \i \l setup()
376 \i Called before showing the item and whenever the list
377 view's font changes, for example.
378 \row \i \l activate()
379 \i Called whenever the user clicks on the item or presses
380 Space when the item is the current item.
381 \endtable
382
383 Some subclasses call setExpandable(true) even when they have no
384 children, and populate themselves when setup() or setOpen(true) is
385 called. The \c dirview/dirview.cpp example program uses this
386 technique to start up quickly: The files and subdirectories in a
387 directory aren't inserted into the tree until they're actually
388 needed.
389
390 \img qlistviewitems.png List View Items
391
392 \sa Q3CheckListItem Q3ListView
393 */
394
395 /*!
396 \fn int Q3CheckListItem::rtti() const
397
398 Returns 1.
399
400 Make your derived classes return their own values for rtti(), and
401 you can distinguish between list view items. You should use values
402 greater than 1000, to allow for extensions to this class.
403 */
404
405 /*!
406 Constructs a new top-level list view item in the Q3ListView \a
407 parent.
408 */
409
Q3ListViewItem(Q3ListView * parent)410 Q3ListViewItem::Q3ListViewItem(Q3ListView * parent)
411 {
412 init();
413 parent->insertItem(this);
414 }
415
416
417 /*!
418 Constructs a new list view item that is a child of \a parent and
419 first in the parent's list of children.
420 */
421
Q3ListViewItem(Q3ListViewItem * parent)422 Q3ListViewItem::Q3ListViewItem(Q3ListViewItem * parent)
423 {
424 init();
425 parent->insertItem(this);
426 }
427
428
429
430
431 /*!
432 Constructs an empty list view item that is a child of \a parent
433 and is after item \a after in the parent's list of children. Since
434 \a parent is a Q3ListView the item will be a top-level item.
435 */
436
Q3ListViewItem(Q3ListView * parent,Q3ListViewItem * after)437 Q3ListViewItem::Q3ListViewItem(Q3ListView * parent, Q3ListViewItem * after)
438 {
439 init();
440 parent->insertItem(this);
441 moveToJustAfter(after);
442 }
443
444
445 /*!
446 Constructs an empty list view item that is a child of \a parent
447 and is after item \a after in the parent's list of children.
448 */
449
Q3ListViewItem(Q3ListViewItem * parent,Q3ListViewItem * after)450 Q3ListViewItem::Q3ListViewItem(Q3ListViewItem * parent, Q3ListViewItem * after)
451 {
452 init();
453 parent->insertItem(this);
454 moveToJustAfter(after);
455 }
456
457
458
459 /*!
460 Constructs a new top-level list view item in the Q3ListView \a
461 parent, with up to eight constant strings, \a label1, \a label2, \a
462 label3, \a label4, \a label5, \a label6, \a label7 and \a label8
463 defining its columns' contents.
464
465 \sa setText()
466 */
467
Q3ListViewItem(Q3ListView * parent,const QString & label1,const QString & label2,const QString & label3,const QString & label4,const QString & label5,const QString & label6,const QString & label7,const QString & label8)468 Q3ListViewItem::Q3ListViewItem(Q3ListView * parent,
469 const QString &label1,
470 const QString &label2,
471 const QString &label3,
472 const QString &label4,
473 const QString &label5,
474 const QString &label6,
475 const QString &label7,
476 const QString &label8)
477 {
478 init();
479 parent->insertItem(this);
480
481 setText(0, label1);
482 setText(1, label2);
483 setText(2, label3);
484 setText(3, label4);
485 setText(4, label5);
486 setText(5, label6);
487 setText(6, label7);
488 setText(7, label8);
489 }
490
491
492 /*!
493 Constructs a new list view item as a child of the Q3ListViewItem \a
494 parent with up to eight constant strings, \a label1, \a label2, \a
495 label3, \a label4, \a label5, \a label6, \a label7 and \a label8
496 as columns' contents.
497
498 \sa setText()
499 */
500
Q3ListViewItem(Q3ListViewItem * parent,const QString & label1,const QString & label2,const QString & label3,const QString & label4,const QString & label5,const QString & label6,const QString & label7,const QString & label8)501 Q3ListViewItem::Q3ListViewItem(Q3ListViewItem * parent,
502 const QString &label1,
503 const QString &label2,
504 const QString &label3,
505 const QString &label4,
506 const QString &label5,
507 const QString &label6,
508 const QString &label7,
509 const QString &label8)
510 {
511 init();
512 parent->insertItem(this);
513
514 setText(0, label1);
515 setText(1, label2);
516 setText(2, label3);
517 setText(3, label4);
518 setText(4, label5);
519 setText(5, label6);
520 setText(6, label7);
521 setText(7, label8);
522 }
523
524 /*!
525 Constructs a new list view item in the Q3ListView \a parent that is
526 included after item \a after and that has up to eight column
527 texts, \a label1, \a label2, \a label3, \a label4, \a label5, \a
528 label6, \a label7 and\a label8.
529
530 Note that the order is changed according to Q3ListViewItem::key()
531 unless the list view's sorting is disabled using
532 Q3ListView::setSorting(-1).
533
534 \sa setText()
535 */
536
Q3ListViewItem(Q3ListView * parent,Q3ListViewItem * after,const QString & label1,const QString & label2,const QString & label3,const QString & label4,const QString & label5,const QString & label6,const QString & label7,const QString & label8)537 Q3ListViewItem::Q3ListViewItem(Q3ListView * parent, Q3ListViewItem * after,
538 const QString &label1,
539 const QString &label2,
540 const QString &label3,
541 const QString &label4,
542 const QString &label5,
543 const QString &label6,
544 const QString &label7,
545 const QString &label8)
546 {
547 init();
548 parent->insertItem(this);
549 moveToJustAfter(after);
550
551 setText(0, label1);
552 setText(1, label2);
553 setText(2, label3);
554 setText(3, label4);
555 setText(4, label5);
556 setText(5, label6);
557 setText(6, label7);
558 setText(7, label8);
559 }
560
561
562 /*!
563 Constructs a new list view item as a child of the Q3ListViewItem \a
564 parent. It is inserted after item \a after and may contain up to
565 eight strings, \a label1, \a label2, \a label3, \a label4, \a
566 label5, \a label6, \a label7 and \a label8 as column entries.
567
568 Note that the order is changed according to Q3ListViewItem::key()
569 unless the list view's sorting is disabled using
570 Q3ListView::setSorting(-1).
571
572 \sa setText()
573 */
574
Q3ListViewItem(Q3ListViewItem * parent,Q3ListViewItem * after,const QString & label1,const QString & label2,const QString & label3,const QString & label4,const QString & label5,const QString & label6,const QString & label7,const QString & label8)575 Q3ListViewItem::Q3ListViewItem(Q3ListViewItem * parent, Q3ListViewItem * after,
576 const QString &label1,
577 const QString &label2,
578 const QString &label3,
579 const QString &label4,
580 const QString &label5,
581 const QString &label6,
582 const QString &label7,
583 const QString &label8)
584 {
585 init();
586 parent->insertItem(this);
587 moveToJustAfter(after);
588
589 setText(0, label1);
590 setText(1, label2);
591 setText(2, label3);
592 setText(3, label4);
593 setText(4, label5);
594 setText(5, label6);
595 setText(6, label7);
596 setText(7, label8);
597 }
598
599 /*!
600 Sorts all this item's child items using the current sorting
601 configuration (sort column and direction).
602
603 \sa enforceSortOrder()
604 */
605
sort()606 void Q3ListViewItem::sort()
607 {
608 if (!listView())
609 return;
610 lsc = Unsorted;
611 enforceSortOrder();
612 listView()->triggerUpdate();
613 }
614
615 /*!
616 Returns 0.
617
618 Make your derived classes return their own values for rtti(), so
619 that you can distinguish between different kinds of list view
620 items. You should use values greater than 1000 to allow for
621 extensions to this class.
622 */
623
rtti() const624 int Q3ListViewItem::rtti() const
625 {
626 return RTTI;
627 }
628
629 /*
630 Performs the initializations that's common to the constructors.
631 */
632
init()633 void Q3ListViewItem::init()
634 {
635 ownHeight = 0;
636 maybeTotalHeight = -1;
637 open = false;
638
639 nChildren = 0;
640 parentItem = 0;
641 siblingItem = childItem = 0;
642
643 columns = 0;
644
645 selected = 0;
646 selectable = true;
647
648 lsc = Unsorted;
649 lso = true; // unsorted in ascending order :)
650 configured = false;
651 expandable = false;
652 selectable = true;
653 is_root = false;
654 allow_drag = false;
655 allow_drop = false;
656 visible = true;
657 renameBox = 0;
658 enabled = true;
659 mlenabled = false;
660 }
661
662 /*!
663 If \a b is true, the item is made visible; otherwise it is hidden.
664
665 If the item is not visible, itemAbove() and itemBelow() will never
666 return this item, although you still can reach it by using e.g.
667 Q3ListViewItemIterator.
668 */
669
setVisible(bool b)670 void Q3ListViewItem::setVisible(bool b)
671 {
672 if (b == (bool)visible)
673 return;
674 Q3ListView *lv = listView();
675 if (!lv)
676 return;
677 if (b && parent() && !parent()->isVisible())
678 return;
679 visible = b;
680 configured = false;
681 setHeight(0);
682 invalidateHeight();
683 if (parent())
684 parent()->invalidateHeight();
685 else
686 lv->d->r->invalidateHeight();
687 for (Q3ListViewItem *i = childItem; i; i = i->siblingItem)
688 i->setVisible(b);
689 if (lv)
690 lv->triggerUpdate();
691 }
692
693 /*!
694 Returns true if the item is visible; otherwise returns false.
695
696 \sa setVisible()
697 */
698
isVisible() const699 bool Q3ListViewItem::isVisible() const
700 {
701 return (bool)visible;
702 }
703
704 /*!
705 If \a b is true, this item can be in-place renamed in the column
706 \a col by the user; otherwise it cannot be renamed in-place.
707 */
708
setRenameEnabled(int col,bool b)709 void Q3ListViewItem::setRenameEnabled(int col, bool b)
710 {
711 Q3ListViewPrivate::ItemColumnInfo * l = (Q3ListViewPrivate::ItemColumnInfo*)columns;
712 if (!l) {
713 l = new Q3ListViewPrivate::ItemColumnInfo;
714 columns = (void*)l;
715 }
716 for(int c = 0; c < col; c++) {
717 if (!l->next)
718 l->next = new Q3ListViewPrivate::ItemColumnInfo;
719 l = l->next;
720 }
721
722 if (!l)
723 return;
724 l->allow_rename = b;
725 }
726
727 /*!
728 Returns true if this item can be in-place renamed in column \a
729 col; otherwise returns false.
730 */
731
renameEnabled(int col) const732 bool Q3ListViewItem::renameEnabled(int col) const
733 {
734 Q3ListViewPrivate::ItemColumnInfo * l = (Q3ListViewPrivate::ItemColumnInfo*)columns;
735 if (!l)
736 return false;
737
738 while(col && l) {
739 l = l->next;
740 col--;
741 }
742
743 if (!l)
744 return false;
745 return (bool)l->allow_rename;
746 }
747
748 /*!
749 If \a b is true the item is enabled; otherwise it is disabled.
750 Disabled items are drawn differently (e.g. grayed-out) and are not
751 accessible by the user.
752 */
753
setEnabled(bool b)754 void Q3ListViewItem::setEnabled(bool b)
755 {
756 if ((bool)enabled == b)
757 return;
758 enabled = b;
759 if (!enabled)
760 selected = false;
761 Q3ListView *lv = listView();
762 if (lv) {
763 lv->triggerUpdate();
764
765 #ifndef QT_NO_ACCESSIBILITY
766 QAccessible::updateAccessibility(lv->viewport(), indexOfItem(this), QAccessible::StateChanged);
767 #endif
768 }
769 }
770
771 /*!
772 Returns true if this item is enabled; otherwise returns false.
773
774 \sa setEnabled()
775 */
776
isEnabled() const777 bool Q3ListViewItem::isEnabled() const
778 {
779 return (bool)enabled;
780 }
781
782 /*!
783 If in-place renaming of this item is enabled (see
784 renameEnabled()), this function starts renaming the item in column
785 \a col, by creating and initializing an edit box.
786 */
787
startRename(int col)788 void Q3ListViewItem::startRename(int col)
789 {
790 if (!renameEnabled(col))
791 return;
792 if (renameBox)
793 cancelRename(col);
794 Q3ListView *lv = listView();
795 if (!lv)
796 return;
797
798 if (lv->d->renameTimer)
799 lv->d->renameTimer->stop();
800
801 lv->ensureItemVisible(this);
802
803 if (lv->d->timer->isActive()) {
804 // make sure that pending calculations get finished
805 lv->d->timer->stop();
806 lv->updateContents();
807 }
808
809 if (lv->currentItem() && lv->currentItem()->renameBox) {
810 if (lv->d->defRenameAction == Q3ListView::Reject)
811 lv->currentItem()->cancelRename(lv->currentItem()->renameCol);
812 else
813 lv->currentItem()->okRename(lv->currentItem()->renameCol);
814 }
815
816 if (this != lv->currentItem())
817 lv->setCurrentItem(this);
818
819 QRect r = lv->itemRect(this);
820 r = QRect(lv->viewportToContents(r.topLeft()), r.size());
821 r.setLeft(lv->header()->sectionPos(col));
822 r.setWidth(qMin(lv->header()->sectionSize(col) - 1,
823 lv->contentsX() + lv->visibleWidth() - r.left()));
824 if (col == 0)
825 r.setLeft(r.left() + lv->itemMargin() + (depth() + (lv->rootIsDecorated() ? 1 : 0)) * lv->treeStepSize() - 1);
826 if (pixmap(col))
827 r.setLeft(r.left() + pixmap(col)->width());
828 if (r.x() - lv->contentsX() < 0) {
829 lv->scrollBy(r.x() - lv->contentsX(), 0);
830 r.setX(lv->contentsX());
831 } else if ((lv->contentsX() + lv->visibleWidth()) < (r.x() + r.width())) {
832 lv->scrollBy((r.x() + r.width()) - (lv->contentsX() + lv->visibleWidth()), 0);
833 }
834 if (r.width() > lv->visibleWidth())
835 r.setWidth(lv->visibleWidth());
836 renameBox = new QLineEdit(lv->viewport(), "qt_renamebox");
837 renameBox->setFrame(false);
838 renameBox->setText(text(col));
839 renameBox->selectAll();
840 renameBox->installEventFilter(lv);
841 lv->addChild(renameBox, r.x(), r.y());
842 renameBox->resize(r.size());
843 lv->viewport()->setFocusProxy(renameBox);
844 renameBox->setFocus();
845 renameBox->show();
846 renameCol = col;
847 }
848
849 /*!
850 This function removes the rename box.
851 */
852
removeRenameBox()853 void Q3ListViewItem::removeRenameBox()
854 {
855 // Sanity, it should be checked by the functions calling this first anyway
856 Q3ListView *lv = listView();
857 if (!lv || !renameBox)
858 return;
859 const bool resetFocus = lv->viewport()->focusProxy() == renameBox;
860 delete renameBox;
861 renameBox = 0;
862 if (resetFocus) {
863 lv->viewport()->setFocusProxy(lv);
864 lv->setFocus();
865 }
866 }
867
868 /*!
869 This function is called if the user presses Enter during in-place
870 renaming of the item in column \a col.
871
872 \sa cancelRename()
873 */
874
okRename(int col)875 void Q3ListViewItem::okRename(int col)
876 {
877 Q3ListView *lv = listView();
878 if (!lv || !renameBox)
879 return;
880 setText(col, renameBox->text());
881 removeRenameBox();
882
883 // we set the parent lsc to Unsorted if that column is the sorted one
884 if (parent() && (int)parent()->lsc == col)
885 parent()->lsc = Unsorted;
886
887 emit lv->itemRenamed(this, col);
888 emit lv->itemRenamed(this, col, text(col));
889 }
890
891 /*!
892 This function is called if the user cancels in-place renaming of
893 this item in column \a col (e.g. by pressing Esc).
894
895 \sa okRename()
896 */
897
cancelRename(int)898 void Q3ListViewItem::cancelRename(int)
899 {
900 Q3ListView *lv = listView();
901 if (!lv || !renameBox)
902 return;
903 removeRenameBox();
904 }
905
906 /*!
907 Destroys the item, deleting all its children and freeing up all
908 allocated resources.
909 */
910
~Q3ListViewItem()911 Q3ListViewItem::~Q3ListViewItem()
912 {
913 if (renameBox) {
914 delete renameBox;
915 renameBox = 0;
916 }
917
918 Q3ListView *lv = listView();
919
920 if (lv) {
921 if (lv->d->oldFocusItem == this)
922 lv->d->oldFocusItem = 0;
923 if (lv->d->focusItem == this)
924 lv->d->focusItem = 0;
925 if (lv->d->highlighted == this)
926 lv->d->highlighted = 0;
927 if (lv->d->pressedItem == this)
928 lv->d->pressedItem = 0;
929 if (lv->d->selectAnchor == this)
930 lv->d->selectAnchor = 0;
931 for (int j = 0; j < lv->d->iterators.size(); ++j) {
932 Q3ListViewItemIterator *i = lv->d->iterators.at(j);
933 if (i->current() == this)
934 i->currentRemoved();
935 }
936 }
937
938 if (parentItem)
939 parentItem->takeItem(this);
940 Q3ListViewItem * i = childItem;
941 childItem = 0;
942 while (i) {
943 i->parentItem = 0;
944 Q3ListViewItem * n = i->siblingItem;
945 delete i;
946 i = n;
947 }
948 delete (Q3ListViewPrivate::ItemColumnInfo *)columns;
949 }
950
951
952 /*!
953 If \a b is true each of the item's columns may contain multiple
954 lines of text; otherwise each of them may only contain a single
955 line.
956 */
957
setMultiLinesEnabled(bool b)958 void Q3ListViewItem::setMultiLinesEnabled(bool b)
959 {
960 mlenabled = b;
961 }
962
963 /*!
964 Returns true if the item can display multiple lines of text in its
965 columns; otherwise returns false.
966 */
967
multiLinesEnabled() const968 bool Q3ListViewItem::multiLinesEnabled() const
969 {
970 return mlenabled;
971 }
972
973 /*!
974 If \a allow is true, the list view starts a drag (see
975 Q3ListView::dragObject()) when the user presses and moves the mouse
976 on this item.
977 */
978
979
setDragEnabled(bool allow)980 void Q3ListViewItem::setDragEnabled(bool allow)
981 {
982 allow_drag = (uint)allow;
983 }
984
985 /*!
986 If \a allow is true, the list view accepts drops onto the item;
987 otherwise drops are not allowed.
988 */
989
setDropEnabled(bool allow)990 void Q3ListViewItem::setDropEnabled(bool allow)
991 {
992 allow_drop = (uint)allow;
993 }
994
995 /*!
996 Returns true if this item can be dragged; otherwise returns false.
997
998 \sa setDragEnabled()
999 */
1000
dragEnabled() const1001 bool Q3ListViewItem::dragEnabled() const
1002 {
1003 return (bool)allow_drag;
1004 }
1005
1006 /*!
1007 Returns true if this item accepts drops; otherwise returns false.
1008
1009 \sa setDropEnabled(), acceptDrop()
1010 */
1011
dropEnabled() const1012 bool Q3ListViewItem::dropEnabled() const
1013 {
1014 return (bool)allow_drop;
1015 }
1016
1017 /*!
1018 Returns true if the item can accept drops of type QMimeSource \a
1019 mime; otherwise returns false.
1020
1021 The default implementation does nothing and returns false. A
1022 subclass must reimplement this to accept drops.
1023 */
1024
acceptDrop(const QMimeSource *) const1025 bool Q3ListViewItem::acceptDrop(const QMimeSource *) const
1026 {
1027 return false;
1028 }
1029
1030 #ifndef QT_NO_DRAGANDDROP
1031
1032 /*!
1033 This function is called when something was dropped on the item. \a e
1034 contains all the information about the drop.
1035
1036 The default implementation does nothing, subclasses may need to
1037 reimplement this function.
1038 */
1039
dropped(QDropEvent * e)1040 void Q3ListViewItem::dropped(QDropEvent *e)
1041 {
1042 Q_UNUSED(e);
1043 }
1044
1045 #endif
1046
1047 /*!
1048 This function is called when a drag enters the item's bounding
1049 rectangle.
1050
1051 The default implementation does nothing, subclasses may need to
1052 reimplement this function.
1053 */
1054
dragEntered()1055 void Q3ListViewItem::dragEntered()
1056 {
1057 }
1058
1059 /*!
1060 This function is called when a drag leaves the item's bounding
1061 rectangle.
1062
1063 The default implementation does nothing, subclasses may need to
1064 reimplement this function.
1065 */
1066
dragLeft()1067 void Q3ListViewItem::dragLeft()
1068 {
1069 }
1070
1071 /*!
1072 Inserts \a newChild into this list view item's list of children.
1073 You should not need to call this function; it is called
1074 automatically by the constructor of \a newChild.
1075
1076 \warning If you are using \c Single selection mode, then you
1077 should only insert unselected items.
1078 */
1079
insertItem(Q3ListViewItem * newChild)1080 void Q3ListViewItem::insertItem(Q3ListViewItem * newChild)
1081 {
1082 Q3ListView *lv = listView();
1083 if (lv && lv->currentItem() && lv->currentItem()->renameBox) {
1084 if (lv->d->defRenameAction == Q3ListView::Reject)
1085 lv->currentItem()->cancelRename(lv->currentItem()->renameCol);
1086 else
1087 lv->currentItem()->okRename(lv->currentItem()->renameCol);
1088 }
1089
1090 if (!newChild || newChild->parentItem == this)
1091 return;
1092 if (newChild->parentItem)
1093 newChild->parentItem->takeItem(newChild);
1094 if (open)
1095 invalidateHeight();
1096 newChild->siblingItem = childItem;
1097 childItem = newChild;
1098 nChildren++;
1099 newChild->parentItem = this;
1100 lsc = Unsorted;
1101 newChild->ownHeight = 0;
1102 newChild->configured = false;
1103
1104 if (lv && !lv->d->focusItem) {
1105 lv->d->focusItem = lv->firstChild();
1106 lv->d->selectAnchor = lv->d->focusItem;
1107 lv->repaintItem(lv->d->focusItem);
1108 }
1109 }
1110
1111
1112 /*!
1113 \fn void Q3ListViewItem::removeItem(Q3ListViewItem *item)
1114
1115 Removes the given \a item. Use takeItem() instead.
1116 */
1117
1118
1119 /*!
1120 Removes \a item from this object's list of children and causes an
1121 update of the screen display. The item is not deleted. You should
1122 not normally need to call this function because
1123 Q3ListViewItem::~Q3ListViewItem() calls it.
1124
1125 The normal way to delete an item is to use \c delete.
1126
1127 If you need to move an item from one place in the hierarchy to
1128 another you can use takeItem() to remove the item from the list
1129 view and then insertItem() to put the item back in its new
1130 position.
1131
1132 If a taken item is part of a selection in \c Single selection
1133 mode, it is unselected and selectionChanged() is emitted. If a
1134 taken item is part of a selection in \c Multi or \c Extended
1135 selection mode, it remains selected.
1136
1137 \warning This function leaves \a item and its children in a state
1138 where most member functions are unsafe. Only a few functions work
1139 correctly on an item in this state, most notably insertItem(). The
1140 functions that work on taken items are explicitly documented as
1141 such.
1142
1143 \sa Q3ListViewItem::insertItem()
1144 */
1145
takeItem(Q3ListViewItem * item)1146 void Q3ListViewItem::takeItem(Q3ListViewItem * item)
1147 {
1148 if (!item)
1149 return;
1150
1151 Q3ListView *lv = listView();
1152 if (lv && lv->currentItem() && lv->currentItem()->renameBox) {
1153 if (lv->d->defRenameAction == Q3ListView::Reject)
1154 lv->currentItem()->cancelRename(lv->currentItem()->renameCol);
1155 else
1156 lv->currentItem()->okRename(lv->currentItem()->renameCol);
1157 }
1158 bool emit_changed = false;
1159 if (lv && !lv->d->clearing) {
1160 if (lv->d->oldFocusItem == this)
1161 lv->d->oldFocusItem = 0;
1162
1163 for (int j = 0; j < lv->d->iterators.size(); ++j) {
1164 Q3ListViewItemIterator *i = lv->d->iterators.at(j);
1165 if (i->current() == item)
1166 i->currentRemoved();
1167 }
1168
1169 invalidateHeight();
1170
1171 if (lv->d && !lv->d->drawables.isEmpty())
1172 lv->d->drawables.clear();
1173
1174 if (!lv->d->dirtyItems.isEmpty()) {
1175 if (item->childItem) {
1176 lv->d->dirtyItems.clear();
1177 lv->d->dirtyItemTimer->stop();
1178 lv->triggerUpdate();
1179 } else {
1180 lv->d->dirtyItems.removeAll(item);
1181 }
1182 }
1183
1184 if (lv->d->focusItem) {
1185 const Q3ListViewItem * c = lv->d->focusItem;
1186 while(c && c != item)
1187 c = c->parentItem;
1188 if (c == item) {
1189 if (lv->selectedItem()) {
1190 // for Single, setSelected(false) when selectedItem() is taken
1191 lv->selectedItem()->setSelected(false);
1192 // we don't emit selectionChanged(0)
1193 emit lv->selectionChanged();
1194 }
1195 if (item->nextSibling())
1196 lv->d->focusItem = item->nextSibling();
1197 else if (item->itemAbove())
1198 lv->d->focusItem = item->itemAbove();
1199 else
1200 lv->d->focusItem = 0;
1201 emit_changed = true;
1202 }
1203 }
1204
1205 // reset anchors etc. if they are set to this or any child
1206 // items
1207 const Q3ListViewItem *ptr = lv->d->selectAnchor;
1208 while (ptr && ptr != item)
1209 ptr = ptr->parentItem;
1210 if (ptr == item)
1211 lv->d->selectAnchor = lv->d->focusItem;
1212
1213 ptr = lv->d->startDragItem;
1214 while (ptr && ptr != item)
1215 ptr = ptr->parentItem;
1216 if (ptr == item)
1217 lv->d->startDragItem = 0;
1218
1219 ptr = lv->d->pressedItem;
1220 while (ptr && ptr != item)
1221 ptr = ptr->parentItem;
1222 if (ptr == item)
1223 lv->d->pressedItem = 0;
1224
1225 ptr = lv->d->highlighted;
1226 while (ptr && ptr != item)
1227 ptr = ptr->parentItem;
1228 if (ptr == item)
1229 lv->d->highlighted = 0;
1230 }
1231
1232 nChildren--;
1233
1234 Q3ListViewItem ** nextChild = &childItem;
1235 while(nextChild && *nextChild && item != *nextChild)
1236 nextChild = &((*nextChild)->siblingItem);
1237
1238 if (nextChild && item == *nextChild)
1239 *nextChild = (*nextChild)->siblingItem;
1240 item->parentItem = 0;
1241 item->siblingItem = 0;
1242 item->ownHeight = 0;
1243 item->maybeTotalHeight = -1;
1244 item->configured = false;
1245
1246 if (emit_changed) {
1247 emit lv->currentChanged(lv->d->focusItem);
1248 #ifndef QT_NO_ACCESSIBILITY
1249 QAccessible::updateAccessibility(lv->viewport(), 0, QAccessible::Focus);
1250 #endif
1251 }
1252 }
1253
1254
1255 /*!
1256 \fn QString Q3ListViewItem::key(int column, bool ascending) const
1257
1258 Returns a key that can be used for sorting by column \a column.
1259 The default implementation returns text(). Derived classes may
1260 also incorporate the order indicated by \a ascending into this
1261 key, although this is not recommended.
1262
1263 If you want to sort on non-alphabetical data, e.g. dates, numbers,
1264 etc., it is more efficient to reimplement compare().
1265
1266 \sa compare(), sortChildItems()
1267 */
1268
key(int column,bool) const1269 QString Q3ListViewItem::key(int column, bool) const
1270 {
1271 return text(column);
1272 }
1273
1274
1275 /*!
1276 Compares this list view item to \a i using the column \a col in \a
1277 ascending order. Returns \< 0 if this item is less than \a i, 0 if
1278 they are equal and \> 0 if this item is greater than \a i.
1279
1280 This function is used for sorting.
1281
1282 The default implementation compares the item keys (key()) using
1283 QString::localeAwareCompare(). A reimplementation can use
1284 different values and a different comparison function. Here is a
1285 reimplementation that uses plain Unicode comparison:
1286
1287 \snippet doc/src/snippets/code/src_qt3support_itemviews_q3listview.cpp 3
1288 We don't recommend using \a ascending so your code can safely
1289 ignore it.
1290
1291 \sa key() QString::localeAwareCompare() QString::compare()
1292 */
1293
compare(Q3ListViewItem * i,int col,bool ascending) const1294 int Q3ListViewItem::compare(Q3ListViewItem *i, int col, bool ascending) const
1295 {
1296 return key(col, ascending).localeAwareCompare(i->key(col, ascending));
1297 }
1298
1299 /*!
1300 Sorts this item's children using column \a column. This is done in
1301 ascending order if \a ascending is true and in descending order if
1302 \a ascending is false.
1303
1304 Asks some of the children to sort their children. (Q3ListView and
1305 Q3ListViewItem ensure that all on-screen objects are properly
1306 sorted but may avoid or defer sorting other objects in order to be
1307 more responsive.)
1308
1309 \sa key() compare()
1310 */
1311
sortChildItems(int column,bool ascending)1312 void Q3ListViewItem::sortChildItems(int column, bool ascending)
1313 {
1314 // we try HARD not to sort. if we're already sorted, don't.
1315 if (column == (int)lsc && ascending == (bool)lso)
1316 return;
1317
1318 if (column < 0)
1319 return;
1320
1321 lsc = column;
1322 lso = ascending;
1323
1324 const int nColumns = (listView() ? listView()->columns() : 0);
1325
1326 // and don't sort if we already have the right sorting order
1327 if (column > nColumns || childItem == 0)
1328 return;
1329
1330 // If there is just one child, just sort its children
1331 if (childItem->siblingItem == 0) {
1332 if (childItem->isOpen())
1333 childItem->sortChildItems(column, ascending);
1334 return;
1335 }
1336
1337 // make an array for qHeapSort()
1338 Q3ListViewPrivate::SortableItem * siblings
1339 = new Q3ListViewPrivate::SortableItem[nChildren];
1340 Q3ListViewItem * s = childItem;
1341 int i = 0;
1342 while (s && i < nChildren) {
1343 siblings[i].numCols = nColumns;
1344 siblings[i].col = column;
1345 siblings[i].asc = ascending;
1346 siblings[i].item = s;
1347 s = s->siblingItem;
1348 i++;
1349 }
1350
1351 // and sort it.
1352 qHeapSort(siblings, siblings + nChildren);
1353
1354 // build the linked list of siblings, in the appropriate
1355 // direction, and finally set this->childItem to the new top
1356 // child.
1357 if (ascending) {
1358 for(i = 0; i < nChildren - 1; i++)
1359 siblings[i].item->siblingItem = siblings[i+1].item;
1360 siblings[nChildren-1].item->siblingItem = 0;
1361 childItem = siblings[0].item;
1362 } else {
1363 for(i = nChildren - 1; i > 0; i--)
1364 siblings[i].item->siblingItem = siblings[i-1].item;
1365 siblings[0].item->siblingItem = 0;
1366 childItem = siblings[nChildren-1].item;
1367 }
1368 for (i = 0; i < nChildren; i++) {
1369 if (siblings[i].item->isOpen())
1370 siblings[i].item->sort();
1371 }
1372 delete[] siblings;
1373 }
1374
1375
1376 /*!
1377 Sets this item's height to \a height pixels. This implicitly
1378 changes totalHeight(), too.
1379
1380 Note that a font change causes this height to be overwritten
1381 unless you reimplement setup().
1382
1383 For best results in Windows style we suggest using an even number
1384 of pixels.
1385
1386 \sa height() totalHeight() isOpen()
1387 */
1388
setHeight(int height)1389 void Q3ListViewItem::setHeight(int height)
1390 {
1391 if (ownHeight != height) {
1392 if (visible)
1393 ownHeight = height;
1394 else
1395 ownHeight = 0;
1396 invalidateHeight();
1397 }
1398 }
1399
1400
1401 /*!
1402 Invalidates the cached total height of this item, including all
1403 open children.
1404
1405 \sa setHeight() height() totalHeight()
1406 */
1407
invalidateHeight()1408 void Q3ListViewItem::invalidateHeight()
1409 {
1410 if (maybeTotalHeight < 0)
1411 return;
1412 maybeTotalHeight = -1;
1413 if (parentItem && parentItem->isOpen())
1414 parentItem->invalidateHeight();
1415 }
1416
1417
1418 /*!
1419 Opens or closes an item, i.e. shows or hides an item's children.
1420
1421 If \a o is true all child items are shown initially. The user can
1422 hide them by clicking the \bold{-} icon to the left of the item.
1423 If \a o is false, the children of this item are initially hidden.
1424 The user can show them by clicking the \bold{+} icon to the left
1425 of the item.
1426
1427 \sa height() totalHeight() isOpen()
1428 */
1429
setOpen(bool o)1430 void Q3ListViewItem::setOpen(bool o)
1431 {
1432 if (o == (bool)open || !enabled)
1433 return;
1434 open = o;
1435
1436 // If no children to show simply emit signals and return
1437 if (!nChildren) {
1438 Q3ListView *lv = listView();
1439 if (lv && this != lv->d->r) {
1440 if (o)
1441 emit lv->expanded(this);
1442 else
1443 emit lv->collapsed(this);
1444 #ifndef QT_NO_ACCESSIBILITY
1445 QAccessible::updateAccessibility(lv->viewport(), indexOfItem(this), QAccessible::StateChanged);
1446 #endif
1447 }
1448 return;
1449 }
1450 invalidateHeight();
1451
1452 if (!configured) {
1453 Q3ListViewItem * l = this;
1454 QStack<Q3ListViewItem *> s;
1455 while(l) {
1456 if (l->open && l->childItem) {
1457 s.push(l->childItem);
1458 } else if (l->childItem) {
1459 // first invisible child is unconfigured
1460 Q3ListViewItem * c = l->childItem;
1461 while(c) {
1462 c->configured = false;
1463 c = c->siblingItem;
1464 }
1465 }
1466 l->configured = true;
1467 l->setup();
1468 l = (l == this) ? 0 : l->siblingItem;
1469 if (!l && !s.isEmpty())
1470 l = s.pop();
1471 }
1472 }
1473
1474 Q3ListView *lv = listView();
1475
1476 if (open && lv)
1477 enforceSortOrder();
1478
1479 if (isVisible() && lv && lv->d && !lv->d->drawables.isEmpty())
1480 lv->buildDrawableList();
1481
1482 if (lv && this != lv->d->r) {
1483 if (o)
1484 emit lv->expanded(this);
1485 else
1486 emit lv->collapsed(this);
1487 #ifndef QT_NO_ACCESSIBILITY
1488 QAccessible::updateAccessibility(lv->viewport(), indexOfItem(this), QAccessible::StateChanged);
1489 #endif
1490 }
1491 }
1492
1493
1494 /*!
1495 This virtual function is called before the first time Q3ListView
1496 needs to know the height or any other graphical attribute of this
1497 object, and whenever the font, GUI style, or colors of the list
1498 view change.
1499
1500 The default calls widthChanged() and sets the item's height to the
1501 height of a single line of text in the list view's font. (If you
1502 use icons, multi-line text, etc., you will probably need to call
1503 setHeight() yourself or reimplement it.)
1504 */
1505
setup()1506 void Q3ListViewItem::setup()
1507 {
1508 widthChanged();
1509 Q3ListView *lv = listView();
1510
1511 int ph = 0;
1512 int h = 0;
1513 if (lv) {
1514 for (int i = 0; i < lv->d->column.size(); ++i) {
1515 if (pixmap(i))
1516 ph = qMax(ph, pixmap(i)->height());
1517 }
1518
1519 if (mlenabled) {
1520 h = ph;
1521 for (int c = 0; c < lv->columns(); ++c) {
1522 int lines = text(c).count(QLatin1Char('\n')) + 1;
1523 int tmph = lv->d->fontMetricsHeight
1524 + lv->fontMetrics().lineSpacing() * (lines - 1);
1525 h = qMax(h, tmph);
1526 }
1527 h += 2*lv->itemMargin();
1528 } else {
1529 h = qMax(lv->d->fontMetricsHeight, ph) + 2*lv->itemMargin();
1530 }
1531 }
1532
1533 h = qMax(h, QApplication::globalStrut().height());
1534
1535 if (h % 2 > 0)
1536 h++;
1537 setHeight(h);
1538 }
1539
1540
1541
1542
1543 /*!
1544 This virtual function is called whenever the user presses the mouse
1545 on this item or presses Space on it.
1546
1547 \sa activatedPos()
1548 */
1549
activate()1550 void Q3ListViewItem::activate()
1551 {
1552 }
1553
1554
1555 /*!
1556 When called from a reimplementation of activate(), this function
1557 gives information on how the item was activated. Otherwise the
1558 behavior is undefined.
1559
1560 If activate() was caused by a mouse press, the function sets \a
1561 pos to where the user clicked and returns true; otherwise it
1562 returns false and does not change \a pos.
1563
1564 \a pos is relative to the top-left corner of this item.
1565
1566 \sa activate()
1567 */
1568
activatedPos(QPoint & pos)1569 bool Q3ListViewItem::activatedPos(QPoint &pos)
1570 {
1571 if (activatedByClick)
1572 pos = activatedP;
1573 return activatedByClick;
1574 }
1575
1576
1577 /*!
1578 \fn bool Q3ListViewItem::isSelectable() const
1579
1580 Returns true if the item is selectable (as it is by default);
1581 otherwise returns false
1582
1583 \sa setSelectable()
1584 */
1585
1586
1587 /*!
1588 Sets this items to be selectable if \a enable is true (the
1589 default) or not to be selectable if \a enable is false.
1590
1591 The user is not able to select a non-selectable item using either
1592 the keyboard or the mouse. The application programmer still can
1593 though, e.g. using setSelected().
1594
1595 \sa isSelectable()
1596 */
1597
setSelectable(bool enable)1598 void Q3ListViewItem::setSelectable(bool enable)
1599 {
1600 selectable = enable;
1601 }
1602
1603
1604 /*!
1605 \fn bool Q3ListViewItem::isExpandable() const
1606
1607 Returns true if this item is expandable even when it has no
1608 children; otherwise returns false.
1609 */
1610
1611 /*!
1612 Sets this item to be expandable even if it has no children if \a
1613 enable is true, and to be expandable only if it has children if \a
1614 enable is false (the default).
1615
1616 The dirview example uses this in the canonical fashion. It checks
1617 whether the directory is empty in setup() and calls
1618 setExpandable(true) if not; in setOpen() it reads the contents of
1619 the directory and inserts items accordingly. This strategy means
1620 that dirview can display the entire file system without reading
1621 very much at startup.
1622
1623 Note that root items are not expandable by the user unless
1624 Q3ListView::setRootIsDecorated() is set to true.
1625
1626 \sa setSelectable()
1627 */
1628
setExpandable(bool enable)1629 void Q3ListViewItem::setExpandable(bool enable)
1630 {
1631 expandable = enable;
1632 }
1633
1634
1635 /*!
1636 Makes sure that this object's children are sorted appropriately.
1637
1638 This only works if every item from the root item down to this item
1639 is already sorted.
1640
1641 \sa sortChildItems()
1642 */
1643
enforceSortOrder() const1644 void Q3ListViewItem::enforceSortOrder() const
1645 {
1646 Q3ListView *lv = listView();
1647 if (!lv || (lv && (lv->d->clearing || lv->d->sortcolumn == Unsorted)))
1648 return;
1649 if (parentItem &&
1650 (parentItem->lsc != lsc || parentItem->lso != lso))
1651 ((Q3ListViewItem *)this)->sortChildItems((int)parentItem->lsc,
1652 (bool)parentItem->lso);
1653 else if (!parentItem &&
1654 ((int)lsc != lv->d->sortcolumn || (bool)lso != lv->d->ascending))
1655 ((Q3ListViewItem *)this)->sortChildItems(lv->d->sortcolumn, lv->d->ascending);
1656 }
1657
1658
1659 /*!
1660 \fn bool Q3ListViewItem::isSelected() const
1661
1662 Returns true if this item is selected; otherwise returns false.
1663
1664 \sa setSelected() Q3ListView::setSelected() Q3ListView::selectionChanged()
1665 */
1666
1667
1668 /*!
1669 If \a s is true this item is selected; otherwise it is deselected.
1670
1671 This function does not maintain any invariants or repaint anything
1672 -- Q3ListView::setSelected() does that.
1673
1674 \sa height() totalHeight()
1675 */
1676
setSelected(bool s)1677 void Q3ListViewItem::setSelected(bool s)
1678 {
1679 bool old = selected;
1680
1681 Q3ListView *lv = listView();
1682 if (lv && lv->selectionMode() != Q3ListView::NoSelection) {
1683 if (s && isSelectable())
1684 selected = true;
1685 else
1686 selected = false;
1687
1688 #ifndef QT_NO_ACCESSIBILITY
1689 if (old != (bool)selected) {
1690 int ind = indexOfItem(this);
1691 QAccessible::updateAccessibility(lv->viewport(), ind, QAccessible::StateChanged);
1692 QAccessible::updateAccessibility(lv->viewport(), ind, selected ? QAccessible::SelectionAdd : QAccessible::SelectionRemove);
1693 }
1694 #else
1695 Q_UNUSED(old);
1696 #endif
1697 }
1698 }
1699
1700 /*!
1701 Returns the total height of this object, including any visible
1702 children. This height is recomputed lazily and cached for as long
1703 as possible.
1704
1705 Functions which can affect the total height are, setHeight() which
1706 is used to set an item's height, setOpen() to show or hide an
1707 item's children, and invalidateHeight() to invalidate the cached
1708 height.
1709
1710 \sa height()
1711 */
1712
totalHeight() const1713 int Q3ListViewItem::totalHeight() const
1714 {
1715 if (!visible)
1716 return 0;
1717 if (maybeTotalHeight >= 0)
1718 return maybeTotalHeight;
1719 Q3ListViewItem * that = (Q3ListViewItem *)this;
1720 if (!that->configured) {
1721 that->configured = true;
1722 that->setup(); // ### virtual non-const function called in const
1723 }
1724 that->maybeTotalHeight = that->ownHeight;
1725
1726 if (!that->isOpen() || !that->childCount())
1727 return that->ownHeight;
1728
1729 Q3ListViewItem * child = that->childItem;
1730 while (child != 0) {
1731 that->maybeTotalHeight += child->totalHeight();
1732 child = child->siblingItem;
1733 }
1734 return that->maybeTotalHeight;
1735 }
1736
1737
1738 /*!
1739 Returns the text in column \a column, or an empty string if there is
1740 no text in that column.
1741
1742 \sa key() paintCell()
1743 */
1744
text(int column) const1745 QString Q3ListViewItem::text(int column) const
1746 {
1747 Q3ListViewPrivate::ItemColumnInfo * l
1748 = (Q3ListViewPrivate::ItemColumnInfo*) columns;
1749
1750 while(column && l) {
1751 l = l->next;
1752 column--;
1753 }
1754
1755 return l ? l->text : QString();
1756 }
1757
1758
1759 /*!
1760 Sets the text in column \a column to \a text, if \a column is a
1761 valid column number and \a text is different from the existing
1762 text.
1763
1764 If the text() function has been reimplemented, this function may
1765 be a no-op.
1766
1767 \sa text() key()
1768 */
1769
setText(int column,const QString & text)1770 void Q3ListViewItem::setText(int column, const QString &text)
1771 {
1772 if (column < 0)
1773 return;
1774
1775 Q3ListViewPrivate::ItemColumnInfo * l
1776 = (Q3ListViewPrivate::ItemColumnInfo*) columns;
1777 if (!l) {
1778 l = new Q3ListViewPrivate::ItemColumnInfo;
1779 columns = (void*)l;
1780 }
1781 for(int c = 0; c < column; c++) {
1782 if (!l->next)
1783 l->next = new Q3ListViewPrivate::ItemColumnInfo;
1784 l = l->next;
1785 }
1786 if (l->text == text)
1787 return;
1788
1789 int oldLc = 0;
1790 int newLc = 0;
1791 if (mlenabled) {
1792 if (!l->text.isEmpty())
1793 oldLc = l->text.count(QLatin1Char('\n')) + 1;
1794 if (!text.isEmpty())
1795 newLc = text.count(QLatin1Char('\n')) + 1;
1796 }
1797
1798 l->dirty = true;
1799 l->text = text;
1800 if (column == (int)lsc)
1801 lsc = Unsorted;
1802
1803 if (mlenabled && oldLc != newLc)
1804 setup();
1805 else
1806 widthChanged(column);
1807
1808 Q3ListView * lv = listView();
1809 if (lv) {
1810 lv->triggerUpdate();
1811 #ifndef QT_NO_ACCESSIBILITY
1812 if (lv->isVisible())
1813 QAccessible::updateAccessibility(lv->viewport(), indexOfItem(this), QAccessible::NameChanged);
1814 #endif
1815 }
1816 }
1817
1818
1819 /*!
1820 Sets the pixmap in column \a column to \a pm, if \a pm is non-null
1821 and different from the current pixmap, and if \a column is
1822 non-negative.
1823
1824 \sa pixmap() setText()
1825 */
1826
setPixmap(int column,const QPixmap & pm)1827 void Q3ListViewItem::setPixmap(int column, const QPixmap & pm)
1828 {
1829 if (column < 0)
1830 return;
1831
1832 int oldW = 0;
1833 int oldH = 0;
1834 if (pixmap(column)) {
1835 oldW = pixmap(column)->width();
1836 oldH = pixmap(column)->height();
1837 }
1838
1839 Q3ListViewPrivate::ItemColumnInfo * l
1840 = (Q3ListViewPrivate::ItemColumnInfo*) columns;
1841 if (!l) {
1842 l = new Q3ListViewPrivate::ItemColumnInfo;
1843 columns = (void*)l;
1844 }
1845
1846 for(int c = 0; c < column; c++) {
1847 if (!l->next)
1848 l->next = new Q3ListViewPrivate::ItemColumnInfo;
1849 l = l->next;
1850 }
1851
1852 if ((pm.isNull() && (!l->pm || l->pm->isNull())) ||
1853 (l->pm && pm.serialNumber() == l->pm->serialNumber()))
1854 return;
1855
1856 if (pm.isNull()) {
1857 delete l->pm;
1858 l->pm = 0;
1859 } else {
1860 if (l->pm)
1861 *(l->pm) = pm;
1862 else
1863 l->pm = new QPixmap(pm);
1864 }
1865
1866 int newW = 0;
1867 int newH = 0;
1868 if (pixmap(column)) {
1869 newW = pixmap(column)->width();
1870 newH = pixmap(column)->height();
1871 }
1872
1873 if (oldW != newW || oldH != newH) {
1874 setup();
1875 widthChanged(column);
1876 invalidateHeight();
1877 }
1878 Q3ListView *lv = listView();
1879 if (lv) {
1880 lv->triggerUpdate();
1881 }
1882 }
1883
1884
1885 /*!
1886 Returns the pixmap for \a column, or 0 if there is no pixmap for
1887 \a column.
1888
1889 \sa setText() setPixmap()
1890 */
1891
pixmap(int column) const1892 const QPixmap * Q3ListViewItem::pixmap(int column) const
1893 {
1894 Q3ListViewPrivate::ItemColumnInfo * l
1895 = (Q3ListViewPrivate::ItemColumnInfo*) columns;
1896
1897 while(column && l) {
1898 l = l->next;
1899 column--;
1900 }
1901
1902 return (l && l->pm) ? l->pm : 0;
1903 }
1904
1905
1906 /*
1907 This function paints the contents of one column of an item
1908 and aligns it as described by \a align.
1909
1910 \a p is a QPainter open on the relevant paint device. \a p is
1911 translated so (0, 0) is the top-left pixel in the cell and \a
1912 width-1, height()-1 is the bottom-right pixel \e in the cell. The
1913 other properties of \a p (pen, brush, etc) are undefined. \a pal is
1914 the color group to use. \a column is the logical column number
1915 within the item that is to be painted; 0 is the column which may
1916 contain a tree.
1917
1918 This function may use Q3ListView::itemMargin() for readability
1919 spacing on the left and right sides of data such as text, and
1920 should honor isSelected() and Q3ListView::allColumnsShowFocus().
1921
1922 If you reimplement this function, you should also reimplement
1923 width().
1924
1925 The rectangle to be painted is in an undefined state when this
1926 function is called, so you \e must draw on all the pixels. The
1927 painter \a p has the right font on entry.
1928
1929 \sa paintBranches(), Q3ListView::drawContentsOffset()
1930 */
1931
getStyleOption(const Q3ListView * lv,const Q3ListViewItem * item,bool hierarchy=false)1932 static QStyleOptionQ3ListView getStyleOption(const Q3ListView *lv, const Q3ListViewItem *item,
1933 bool hierarchy = false)
1934 {
1935 QStyleOptionQ3ListView opt;
1936 opt.init(lv);
1937 opt.subControls = QStyle::SC_None;
1938 opt.activeSubControls = QStyle::SC_None;
1939 QWidget *vp = lv->viewport();
1940 opt.viewportPalette = vp->palette();
1941 opt.viewportBGRole = vp->backgroundRole();
1942 opt.itemMargin = lv->itemMargin();
1943 opt.sortColumn = 0;
1944 opt.treeStepSize = lv->treeStepSize();
1945 opt.rootIsDecorated = lv->rootIsDecorated();
1946 bool firstItem = true;
1947 int y = item ? item->itemPos() : 0;
1948 while (item) {
1949 QStyleOptionQ3ListViewItem lvi;
1950 lvi.height = item->height();
1951 lvi.totalHeight = item->totalHeight();
1952 lvi.itemY = y;
1953 lvi.childCount = item->childCount();
1954 lvi.features = QStyleOptionQ3ListViewItem::None;
1955 lvi.state = QStyle::State_None;
1956 if (item->isEnabled())
1957 lvi.state |= QStyle::State_Enabled;
1958 if (item->isOpen())
1959 lvi.state |= QStyle::State_Open;
1960 if (item->isExpandable())
1961 lvi.features |= QStyleOptionQ3ListViewItem::Expandable;
1962 if (item->multiLinesEnabled())
1963 lvi.features |= QStyleOptionQ3ListViewItem::MultiLine;
1964 if (item->isVisible())
1965 lvi.features |= QStyleOptionQ3ListViewItem::Visible;
1966 if (item->parent() && item->parent()->rtti() == 1
1967 && static_cast<Q3CheckListItem *>(item->parent())->type() == Q3CheckListItem::Controller)
1968 lvi.features |= QStyleOptionQ3ListViewItem::ParentControl;
1969 opt.items.append(lvi);
1970 // we only care about the children when we are painting the branches
1971 // this is only enabled by Q3ListViewItem::paintBranches
1972 if (hierarchy) {
1973 if (!firstItem) {
1974 item = item->nextSibling();
1975 } else {
1976 firstItem = false;
1977 item = item->firstChild();
1978 }
1979 y += lvi.height;
1980 } else {
1981 break;
1982 }
1983 }
1984 return opt;
1985 }
1986
1987 /*!
1988 \fn void Q3ListViewItem::paintCell(QPainter *painter, const QColorGroup & cg, int column, int width, int align)
1989
1990 This virtual function paints the contents of one column of an item
1991 and aligns it as described by \a align.
1992
1993 The \a painter is a Q3Painter open on the relevant paint
1994 device. It is translated so (0, 0) is the top-left pixel in the
1995 cell and \a width - 1, height() - 1 is the bottom-right pixel \e
1996 in the cell. The other properties of the \a painter (pen, brush, etc) are
1997 undefined. \a cg is the color group to use. \a column is the
1998 logical column number within the item that is to be painted; 0 is
1999 the column which may contain a tree.
2000
2001 This function may use Q3ListView::itemMargin() for readability
2002 spacing on the left and right sides of data such as text, and
2003 should honor \l isSelected() and
2004 Q3ListView::allColumnsShowFocus().
2005
2006 If you reimplement this function, you should also reimplement \l
2007 width().
2008
2009 The rectangle to be painted is in an undefined state when this
2010 function is called, so you \e must draw on all the pixels. The
2011 \a painter has the right font on entry.
2012
2013 \sa paintBranches(), Q3ListView::drawContentsOffset()
2014 */
paintCell(QPainter * p,const QColorGroup & cg,int column,int width,int align)2015 void Q3ListViewItem::paintCell(QPainter * p, const QColorGroup & cg,
2016 int column, int width, int align)
2017 {
2018 // Change width() if you change this.
2019
2020 QPalette pal = cg;
2021 if (!p)
2022 return;
2023
2024 Q3ListView *lv = listView();
2025 if (!lv)
2026 return;
2027 QFontMetrics fm(p->fontMetrics());
2028
2029 // had, but we _need_ the column info for the ellipsis thingy!!!
2030 if (!columns) {
2031 for (int i = 0; i < lv->d->column.size(); ++i) {
2032 setText(i, text(i));
2033 }
2034 }
2035
2036 QString t = text(column);
2037
2038 if (columns) {
2039 Q3ListViewPrivate::ItemColumnInfo *ci = 0;
2040 // try until we have a column info....
2041 while (!ci) {
2042 ci = (Q3ListViewPrivate::ItemColumnInfo*)columns;
2043 for (int i = 0; ci && (i < column); ++i)
2044 ci = ci->next;
2045
2046 if (!ci) {
2047 setText(column, t);
2048 ci = 0;
2049 }
2050 }
2051
2052 // if the column width changed and this item was not painted since this change
2053 if (ci && (ci->width != width || ci->text != t || ci->dirty)) {
2054 ci->text = t;
2055 ci->dirty = false;
2056 ci->width = width;
2057 ci->truncated = false;
2058 // if we have to do the ellipsis thingy calc the truncated text
2059 int pw = lv->itemMargin()*2 - lv->d->minLeftBearing - lv->d->minRightBearing;
2060 pw += pixmap(column) ? pixmap(column)->width() + lv->itemMargin() : 0;
2061 if (!mlenabled && fm.width(t) + pw > width) {
2062 // take care of arabic shaping in width calculation (lars)
2063 ci->truncated = true;
2064 ci->tmpText = qEllipsisText(t, fm, width - pw, align);
2065 } else if (mlenabled && fm.width(t) + pw > width) {
2066 QStringList list = t.split(QLatin1Char('\n'));
2067 for (QStringList::Iterator it = list.begin(); it != list.end(); ++it) {
2068 QString z = *it;
2069 if (fm.width(z) + pw > width) {
2070 ci->truncated = true;
2071 *it = qEllipsisText(z, fm, width - pw, align);
2072 }
2073 }
2074
2075 if (ci->truncated)
2076 ci->tmpText = list.join(QString(QLatin1Char('\n')));
2077 }
2078 }
2079
2080 // if we have to draw the ellipsis thingy, use the truncated text
2081 if (ci && ci->truncated)
2082 t = ci->tmpText;
2083 }
2084
2085 int marg = lv->itemMargin();
2086 int r = marg;
2087 const QPixmap * icon = pixmap(column);
2088
2089 const QPalette::ColorRole crole = lv->viewport()->backgroundRole();
2090 if (pal.brush(crole) != lv->palette().brush(pal.currentColorGroup(), crole))
2091 p->fillRect(0, 0, width, height(), pal.brush(crole));
2092 else
2093 lv->paintEmptyArea(p, QRect(0, 0, width, height()));
2094
2095 // (lars) what does this do???
2096 #if 0 // RS: ####
2097 if (align != Qt::AlignLeft)
2098 marg -= lv->d->minRightBearing;
2099 #endif
2100 if (isSelected() &&
2101 (column == 0 || lv->allColumnsShowFocus())) {
2102 p->fillRect(r - marg, 0, qMax(0, width - r + marg), height(),
2103 pal.brush(QPalette::Highlight));
2104 if (enabled || !lv)
2105 p->setPen(pal.highlightedText().color());
2106 else if (!enabled && lv)
2107 p->setPen(lv->palette().color(QPalette::Disabled, QPalette::HighlightedText));
2108 } else {
2109 if (enabled || !lv)
2110 p->setPen(pal.text().color());
2111 else if (!enabled && lv)
2112 p->setPen(lv->palette().color(QPalette::Disabled, QPalette::Text));
2113 }
2114
2115
2116 #if 0
2117 bool reverse = QApplication::reverseLayout();
2118 #else
2119 bool reverse = false;
2120 #endif
2121 int iconWidth = 0;
2122
2123 if (icon) {
2124 iconWidth = icon->width() + lv->itemMargin();
2125 int xo = r;
2126 // we default to Qt::AlignVCenter.
2127 int yo = (height() - icon->height()) / 2;
2128
2129 // I guess we may as well always respect vertical alignment.
2130 if (align & Qt::AlignBottom)
2131 yo = height() - icon->height();
2132 else if (align & Qt::AlignTop)
2133 yo = 0;
2134
2135 // respect horizontal alignment when there is no text for an item.
2136 if (text(column).isEmpty()) {
2137 if (align & Qt::AlignRight)
2138 xo = width - 2 * marg - iconWidth;
2139 else if (align & Qt::AlignHCenter)
2140 xo = (width - iconWidth) / 2;
2141 }
2142 if (reverse)
2143 xo = width - 2 * marg - iconWidth;
2144 p->drawPixmap(xo, yo, *icon);
2145 }
2146
2147 if (!t.isEmpty()) {
2148 if (!mlenabled) {
2149 if (!(align & Qt::AlignTop || align & Qt::AlignBottom))
2150 align |= Qt::AlignVCenter;
2151 } else {
2152 if (!(align & Qt::AlignVCenter || align & Qt::AlignBottom))
2153 align |= Qt::AlignTop;
2154 }
2155 if (!reverse)
2156 r += iconWidth;
2157
2158 if (!mlenabled) {
2159 p->drawText(r, 0, width-marg-r, height(), align, t);
2160 } else {
2161 p->drawText(r, marg, width-marg-r, height(), align, t);
2162 }
2163 }
2164
2165 if (mlenabled && column == 0 && isOpen() && childCount()) {
2166 int textheight = fm.size(align, t).height() + 2 * lv->itemMargin();
2167 textheight = qMax(textheight, QApplication::globalStrut().height());
2168 if (textheight % 2 > 0)
2169 textheight++;
2170 if (textheight < height()) {
2171 int w = lv->treeStepSize() / 2;
2172 QStyleOptionQ3ListView opt = getStyleOption(lv, this);
2173 opt.rect.setRect(0, textheight, w + 1, height() - textheight + 1);
2174 opt.palette = pal;
2175 opt.subControls = QStyle::SC_Q3ListViewExpand;
2176 opt.activeSubControls = QStyle::SC_All;
2177 lv->style()->drawComplexControl(QStyle::CC_Q3ListView, &opt, p, lv);
2178 }
2179 }
2180 }
2181
2182 /*!
2183 Returns the number of pixels of width required to draw column \a c
2184 of list view \a lv, using the metrics \a fm without cropping. The
2185 list view containing this item may use this information depending
2186 on the Q3ListView::WidthMode settings for the column.
2187
2188 The default implementation returns the width of the bounding
2189 rectangle of the text of column \a c.
2190
2191 \sa listView() widthChanged() Q3ListView::setColumnWidthMode()
2192 Q3ListView::itemMargin()
2193 */
width(const QFontMetrics & fm,const Q3ListView * lv,int c) const2194 int Q3ListViewItem::width(const QFontMetrics& fm,
2195 const Q3ListView* lv, int c) const
2196 {
2197 int w;
2198 if (mlenabled)
2199 w = fm.size(Qt::AlignVCenter, text(c)).width() + lv->itemMargin() * 2
2200 - lv->d->minLeftBearing - lv->d->minRightBearing;
2201 else
2202 w = fm.width(text(c)) + lv->itemMargin() * 2
2203 - lv->d->minLeftBearing - lv->d->minRightBearing;
2204 const QPixmap * pm = pixmap(c);
2205 if (pm)
2206 w += pm->width() + lv->itemMargin(); // ### correct margin stuff?
2207 return qMax(w, QApplication::globalStrut().width());
2208 }
2209
2210
2211 /*!
2212 Paints a focus indicator on the rectangle \a r using painter \a p
2213 and colors \a cg.
2214
2215 \a p is already clipped.
2216
2217 \sa paintCell() paintBranches() Q3ListView::setAllColumnsShowFocus()
2218 */
2219
paintFocus(QPainter * p,const QColorGroup & cg,const QRect & r)2220 void Q3ListViewItem::paintFocus(QPainter *p, const QColorGroup &cg, const QRect &r)
2221 {
2222 QPalette pal = cg;
2223 Q3ListView *lv = listView();
2224 if (lv) {
2225 QStyleOptionFocusRect opt;
2226 opt.init(lv);
2227 opt.rect = r;
2228 opt.palette = pal;
2229 opt.state |= QStyle::State_KeyboardFocusChange;
2230 if (isSelected()) {
2231 opt.state |= QStyle::State_FocusAtBorder;
2232 opt.backgroundColor = pal.highlight().color();
2233 } else {
2234 opt.state |= QStyle::State_None;
2235 opt.backgroundColor = pal.base().color();
2236 }
2237 lv->style()->drawPrimitive(QStyle::PE_FrameFocusRect, &opt, p, lv);
2238 }
2239 }
2240
2241
2242 /*!
2243 Paints a set of branches from this item to (some of) its children.
2244
2245 Painter \a p is set up with clipping and translation so that you
2246 can only draw in the rectangle that needs redrawing; \a cg is the
2247 color group to use; the update rectangle is at (0, 0) and has size
2248 width \a w by height \a h. The top of the rectangle you own is at
2249 \a y (which is never greater than 0 but can be outside the window
2250 system's allowed coordinate range).
2251
2252 The update rectangle is in an undefined state when this function
2253 is called; this function must draw on \e all of the pixels.
2254
2255 \sa paintCell(), Q3ListView::drawContentsOffset()
2256 */
2257
paintBranches(QPainter * p,const QColorGroup & cg,int w,int y,int h)2258 void Q3ListViewItem::paintBranches(QPainter * p, const QColorGroup & cg,
2259 int w, int y, int h)
2260 {
2261 Q3ListView *lv = listView();
2262 if (lv)
2263 lv->paintEmptyArea(p, QRect(0, 0, w, h));
2264 if (!visible || !lv)
2265 return;
2266 QStyleOptionQ3ListView opt = getStyleOption(lv, this, true);
2267 opt.rect.setRect(0, y, w, h);
2268 opt.palette = cg;
2269 opt.subControls = QStyle::SC_Q3ListViewBranch | QStyle::SC_Q3ListViewExpand;
2270 opt.activeSubControls = QStyle::SC_None;
2271 lv->style()->drawComplexControl(QStyle::CC_Q3ListView, &opt, p, lv);
2272 }
2273
2274
Root(Q3ListView * parent)2275 Q3ListViewPrivate::Root::Root(Q3ListView * parent)
2276 : Q3ListViewItem(parent)
2277 {
2278 lv = parent;
2279 setHeight(0);
2280 setOpen(true);
2281 }
2282
2283
setHeight(int)2284 void Q3ListViewPrivate::Root::setHeight(int)
2285 {
2286 Q3ListViewItem::setHeight(0);
2287 }
2288
2289
invalidateHeight()2290 void Q3ListViewPrivate::Root::invalidateHeight()
2291 {
2292 Q3ListViewItem::invalidateHeight();
2293 lv->triggerUpdate();
2294 }
2295
2296
theListView() const2297 Q3ListView * Q3ListViewPrivate::Root::theListView() const
2298 {
2299 return lv;
2300 }
2301
2302
setup()2303 void Q3ListViewPrivate::Root::setup()
2304 {
2305 // explicitly nothing
2306 }
2307
2308
2309
2310 /*!
2311 \internal
2312 If called after a mouse click, tells the list view to ignore a
2313 following double click. This state is reset after the next mouse click.
2314 */
2315
ignoreDoubleClick()2316 void Q3ListViewItem::ignoreDoubleClick()
2317 {
2318 Q3ListView *lv = listView();
2319 if (lv)
2320 lv->d->ignoreDoubleClick = true;
2321 }
2322
2323
2324
2325 /*!
2326 \fn void Q3ListView::onItem(Q3ListViewItem *i)
2327
2328 This signal is emitted when the user moves the mouse cursor onto
2329 item \a i, similar to the QWidget::enterEvent() function.
2330 */
2331
2332 // ### bug here too? see qiconview.cppp onItem/onViewport
2333
2334 /*!
2335 \fn void Q3ListView::onViewport()
2336
2337 This signal is emitted when the user moves the mouse cursor from
2338 an item to an empty part of the list view.
2339 */
2340
2341 /*!
2342 \enum Q3ListView::SelectionMode
2343
2344 This enumerated type is used by Q3ListView to indicate how it
2345 reacts to selection by the user.
2346
2347 \value Single When the user selects an item, any already-selected
2348 item becomes unselected, and the user cannot unselect the selected
2349 item.
2350
2351 \value Multi When the user selects an item in the usual way, the
2352 selection status of that item is toggled and the other items are
2353 left alone.
2354
2355 \value Extended When the user selects an item in the usual way,
2356 the selection is cleared and the new item selected. However, if
2357 the user presses the Ctrl key when clicking on an item, the
2358 clicked item gets toggled and all other items are left untouched.
2359 And if the user presses the Shift key while clicking on an item,
2360 all items between the current item and the clicked item get
2361 selected or unselected, depending on the state of the clicked
2362 item. Also, multiple items can be selected by dragging the mouse
2363 over them.
2364
2365 \value NoSelection Items cannot be selected.
2366
2367 In other words, \c Single is a real single-selection list view, \c
2368 Multi a real multi-selection list view, \c Extended is a list view
2369 where users can select multiple items but usually want to select
2370 either just one or a range of contiguous items, and \c NoSelection
2371 is a list view where the user can look but not touch.
2372 */
2373
2374 /*!
2375 \enum Q3ListView::ResizeMode
2376
2377 This enum describes how the list view's header adjusts to resize
2378 events which affect the width of the list view.
2379
2380 \value NoColumn The columns do not get resized in resize events.
2381
2382 \value AllColumns All columns are resized equally to fit the width
2383 of the list view.
2384
2385 \value LastColumn The last column is resized to fit the width of
2386 the list view.
2387 */
2388
2389 /*!
2390 \enum Q3ListView::RenameAction
2391
2392 This enum describes whether a rename operation is accepted if the
2393 rename editor loses focus without the user pressing Enter.
2394
2395 \value Accept Rename if Enter is pressed or focus is lost.
2396
2397 \value Reject Discard the rename operation if focus is lost (and
2398 Enter has not been pressed).
2399 */
2400
2401 /*!
2402 \class Q3ListView
2403 \brief The Q3ListView class implements a list/tree view.
2404
2405 \compat
2406
2407 It can display and control a hierarchy of multi-column items, and
2408 provides the ability to add new items at any time. The user may
2409 select one or many items (depending on the \c SelectionMode) and
2410 sort the list in increasing or decreasing order by any column.
2411
2412 The simplest pattern of use is to create a Q3ListView, add some
2413 column headers using addColumn() and create one or more
2414 Q3ListViewItem or Q3CheckListItem objects with the Q3ListView as
2415 parent.
2416
2417 Further nodes can be added to the list view object (the root of the
2418 tree) or as child nodes to Q3ListViewItems.
2419
2420 The main setup functions are:
2421 \table
2422 \header \i Function \i Action
2423 \row \i \l addColumn()
2424 \i Adds a column with a text label and perhaps width. Columns
2425 are counted from the left starting with column 0.
2426 \row \i \l setColumnWidthMode()
2427 \i Sets the column to be resized automatically or not.
2428 \row \i \l setAllColumnsShowFocus()
2429 \i Sets whether items should show keyboard focus using all
2430 columns or just column 0. The default is to show focus
2431 just using column 0.
2432 \row \i \l setRootIsDecorated()
2433 \i Sets whether root items can be opened and closed by the
2434 user and have open/close decoration to their left. The
2435 default is false.
2436 \row \i \l setTreeStepSize()
2437 \i Sets how many pixels an item's children are indented
2438 relative to their parent. The default is 20. This is
2439 mostly a matter of taste.
2440 \row \i \l setSorting()
2441 \i Sets whether the items should be sorted, whether it should
2442 be in ascending or descending order, and by what column
2443 they should be sorted. By default the list view is sorted
2444 by the first column; to switch this off call setSorting(-1).
2445 \endtable
2446
2447 There are several functions for mapping between items and
2448 coordinates. itemAt() returns the item at a position on-screen,
2449 itemRect() returns the rectangle an item occupies on the screen,
2450 and itemPos() returns the position of any item (whether it is
2451 on-screen or not). firstChild() returns the list view's first item
2452 (not necessarily visible on-screen).
2453
2454 You can iterate over visible items using
2455 Q3ListViewItem::itemBelow(); over a list view's top-level items
2456 using Q3ListViewItem::firstChild() and
2457 Q3ListViewItem::nextSibling(); or every item using a
2458 Q3ListViewItemIterator. See
2459 the Q3ListViewItem documentation for examples of traversal.
2460
2461 An item can be moved amongst its siblings using
2462 Q3ListViewItem::moveItem(). To move an item in the hierarchy use
2463 takeItem() and insertItem(). Item's (and all their child items)
2464 are deleted with \c delete; to delete all the list view's items
2465 use clear().
2466
2467 There are a variety of selection modes described in the
2468 Q3ListView::SelectionMode documentation. The default is \c Single
2469 selection, which you can change using setSelectionMode().
2470
2471 Because Q3ListView offers multiple selection it must display
2472 keyboard focus and selection state separately. Therefore there are
2473 functions both to set the selection state of an item
2474 (setSelected()) and to set which item displays keyboard focus
2475 (setCurrentItem()).
2476
2477 Q3ListView emits two groups of signals; one group signals changes
2478 in selection/focus state and one indicates selection. The first
2479 group consists of selectionChanged() (applicable to all list
2480 views), selectionChanged(Q3ListViewItem*) (applicable only to a
2481 \c Single selection list view), and currentChanged(Q3ListViewItem*).
2482 The second group consists of doubleClicked(Q3ListViewItem*),
2483 returnPressed(Q3ListViewItem*),
2484 rightButtonClicked(Q3ListViewItem*, const QPoint&, int), etc.
2485
2486 Note that changing the state of the list view in a slot connected
2487 to a list view signal may cause unexpected side effects. If you
2488 need to change the list view's state in response to a signal, use
2489 a \link QTimer::singleShot() single shot timer\endlink with a
2490 time out of 0, and connect this timer to a slot that modifies the
2491 list view's state.
2492
2493 In Motif style, Q3ListView deviates fairly strongly from the look
2494 and feel of the Motif hierarchical tree view. This is done mostly
2495 to provide a usable keyboard interface and to make the list view
2496 look better with a white background.
2497
2498 If selectionMode() is \c Single (the default) the user can select
2499 one item at a time, e.g. by clicking an item with the mouse, see
2500 \l Q3ListView::SelectionMode for details.
2501
2502 The list view can be navigated either using the mouse or the
2503 keyboard. Clicking a \bold{-} icon closes an item (hides its
2504 children) and clicking a \bold{+} icon opens an item (shows its
2505 children). The keyboard controls are these:
2506 \table
2507 \header \i Keypress \i Action
2508 \row \i Home
2509 \i Make the first item current and visible.
2510 \row \i End
2511 \i Make the last item current and visible.
2512 \row \i Page Up
2513 \i Make the item above the top visible item current and visible.
2514 \row \i Page Down
2515 \i Make the item below the bottom visible item current and visible.
2516 \row \i Up Arrow
2517 \i Make the item above the current item current and visible.
2518 \row \i Down Arrow
2519 \i Make the item below the current item current and visible.
2520 \row \i Left Arrow
2521 \i If the current item is closed (\bold{+} icon) or has no
2522 children, make its parent item current and visible. If the
2523 current item is open (\bold{-} icon) close it, i.e. hide its
2524 children. Exception: if the current item is the first item
2525 and is closed and the horizontal scroll bar is offset to
2526 the right the list view will be scrolled left.
2527 \row \i Right Arrow
2528 \i If the current item is closed (\bold{+} icon) and has
2529 children, the item is opened. If the current item is
2530 opened (\bold{-} icon) and has children the item's first
2531 child is made current and visible. If the current item has
2532 no children the list view is scrolled right.
2533 \endtable
2534
2535 If the user starts typing letters with the focus in the list view
2536 an incremental search will occur. For example if the user types
2537 'd' the current item will change to the first item that begins
2538 with the letter 'd'; if they then type 'a', the current item will
2539 change to the first item that begins with 'da', and so on. If no
2540 item begins with the letters they type the current item doesn't
2541 change.
2542
2543 Note that the list view's size hint is calculated taking into
2544 account the height \e and width to produce a nice aspect ratio.
2545 This may mean that you need to reimplement sizeHint() in some
2546 cases.
2547
2548 \warning The list view assumes ownership of all list view items
2549 and will delete them when it does not need them any more.
2550
2551 \sa Q3ListViewItem Q3CheckListItem
2552 */
2553
2554 /*!
2555 \fn void Q3ListView::itemRenamed(Q3ListViewItem * item, int col)
2556
2557 \overload
2558
2559 This signal is emitted when \a item has been renamed, e.g. by
2560 in-place renaming, in column \a col.
2561
2562 \sa Q3ListViewItem::setRenameEnabled()
2563 */
2564
2565 /*!
2566 \fn void Q3ListView::itemRenamed(Q3ListViewItem * item, int col, const QString &text)
2567
2568 This signal is emitted when \a item has been renamed to \a text,
2569 e.g. by in in-place renaming, in column \a col.
2570
2571 \sa Q3ListViewItem::setRenameEnabled()
2572 */
2573
2574 /*!
2575 Constructs a new empty list view called \a name with parent \a
2576 parent and widget attributes \a f.
2577
2578 This constructor sets the \c WA_StaticContent and the \c
2579 Qt::WA_NoBackground attributes to boost performance when drawing
2580 Q3ListViewItems. This may be unsuitable for custom Q3ListViewItem
2581 classes, in which case Qt::WA_StaticContents and Qt::WA_NoBackground
2582 should be cleared on the viewport() after construction.
2583
2584 \sa QWidget::setAttribute()
2585 */
Q3ListView(QWidget * parent,const char * name,Qt::WindowFlags f)2586 Q3ListView::Q3ListView(QWidget * parent, const char *name, Qt::WindowFlags f)
2587 : Q3ScrollView(parent, name, f | Qt::WStaticContents | Qt::WNoAutoErase)
2588 {
2589 init();
2590 }
2591
init()2592 void Q3ListView::init()
2593 {
2594 d = new Q3ListViewPrivate;
2595 d->vci = 0;
2596 d->timer = new QTimer(this);
2597 d->levelWidth = 20;
2598 d->r = 0;
2599 d->rootIsExpandable = 0;
2600 d->h = new Q3Header(this, "list view header");
2601 d->h->installEventFilter(this);
2602 d->focusItem = 0;
2603 d->oldFocusItem = 0;
2604 d->dirtyItemTimer = new QTimer(this);
2605 d->visibleTimer = new QTimer(this);
2606 d->renameTimer = new QTimer(this);
2607 d->autoopenTimer = new QTimer(this);
2608 d->margin = 1;
2609 d->selectionMode = Q3ListView::Single;
2610 d->sortcolumn = 0;
2611 d->ascending = true;
2612 d->allColumnsShowFocus = false;
2613 d->fontMetricsHeight = fontMetrics().height();
2614 d->h->setTracking(true);
2615 d->buttonDown = false;
2616 d->ignoreDoubleClick = false;
2617 d->scrollTimer = 0;
2618 d->sortIndicator = false;
2619 d->clearing = false;
2620 d->minLeftBearing = fontMetrics().minLeftBearing();
2621 d->minRightBearing = fontMetrics().minRightBearing();
2622 d->ellipsisWidth = fontMetrics().width(QLatin1String("...")) * 2;
2623 d->highlighted = 0;
2624 d->pressedItem = 0;
2625 d->selectAnchor = 0;
2626 d->select = true;
2627 d->startDragItem = 0;
2628 d->toolTips = true;
2629 d->updateHeader = false;
2630 d->fullRepaintOnComlumnChange = false;
2631 d->resizeMode = NoColumn;
2632 d->defRenameAction = Reject;
2633 d->pressedEmptyArea = false;
2634 d->startEdit = true;
2635 d->ignoreEditAfterFocus = false;
2636 d->inMenuMode = false;
2637 d->pressedSelected = false;
2638
2639 setMouseTracking(true);
2640 viewport()->setMouseTracking(true);
2641
2642 connect(d->timer, SIGNAL(timeout()),
2643 this, SLOT(updateContents()));
2644 connect(d->dirtyItemTimer, SIGNAL(timeout()),
2645 this, SLOT(updateDirtyItems()));
2646 connect(d->visibleTimer, SIGNAL(timeout()),
2647 this, SLOT(makeVisible()));
2648 connect(d->renameTimer, SIGNAL(timeout()),
2649 this, SLOT(startRename()));
2650 connect(d->autoopenTimer, SIGNAL(timeout()),
2651 this, SLOT(openFocusItem()));
2652
2653 connect(d->h, SIGNAL(sizeChange(int,int,int)),
2654 this, SLOT(handleSizeChange(int,int,int)));
2655 connect(d->h, SIGNAL(indexChange(int,int,int)),
2656 this, SLOT(handleIndexChange()));
2657 connect(d->h, SIGNAL(sectionClicked(int)),
2658 this, SLOT(changeSortColumn(int)));
2659 connect(d->h, SIGNAL(sectionHandleDoubleClicked(int)),
2660 this, SLOT(adjustColumn(int)));
2661 connect(horizontalScrollBar(), SIGNAL(sliderMoved(int)),
2662 d->h, SLOT(setOffset(int)));
2663 connect(horizontalScrollBar(), SIGNAL(valueChanged(int)),
2664 d->h, SLOT(setOffset(int)));
2665
2666 // will access d->r
2667 Q3ListViewPrivate::Root * r = new Q3ListViewPrivate::Root(this);
2668 r->is_root = true;
2669 d->r = r;
2670 d->r->setSelectable(false);
2671
2672 viewport()->setFocusProxy(this);
2673 viewport()->setFocusPolicy(Qt::WheelFocus);
2674 setFocusPolicy(Qt::WheelFocus);
2675 viewport()->setBackgroundRole(QPalette::Base);
2676 setAttribute(Qt::WA_MacShowFocusRect);
2677 }
2678
2679 /*!
2680 \property Q3ListView::showSortIndicator
2681 \brief whether the list view header should display a sort indicator.
2682
2683 If this property is true, an arrow is drawn in the header of the
2684 list view to indicate the sort order of the list view contents.
2685 The arrow will be drawn in the correct column and will point up or
2686 down, depending on the current sort direction. The default is
2687 false (don't show an indicator).
2688
2689 \sa Q3Header::setSortIndicator()
2690 */
2691
setShowSortIndicator(bool show)2692 void Q3ListView::setShowSortIndicator(bool show)
2693 {
2694 if (show == d->sortIndicator)
2695 return;
2696
2697 d->sortIndicator = show;
2698 if (d->sortcolumn != Unsorted && d->sortIndicator)
2699 d->h->setSortIndicator(d->sortcolumn, d->ascending);
2700 else
2701 d->h->setSortIndicator(-1);
2702 }
2703
showSortIndicator() const2704 bool Q3ListView::showSortIndicator() const
2705 {
2706 return d->sortIndicator;
2707 }
2708
2709 /*!
2710 \property Q3ListView::showToolTips
2711 \brief whether this list view should show tooltips for truncated column texts
2712
2713 The default is true.
2714 */
2715
setShowToolTips(bool b)2716 void Q3ListView::setShowToolTips(bool b)
2717 {
2718 d->toolTips = b;
2719 }
2720
showToolTips() const2721 bool Q3ListView::showToolTips() const
2722 {
2723 return d->toolTips;
2724 }
2725
2726 /*!
2727 \property Q3ListView::resizeMode
2728 \brief whether all, none or the only the last column should be resized
2729
2730 Specifies whether all, none or only the last column should be
2731 resized to fit the full width of the list view. The values for this
2732 property can be one of: \c NoColumn (the default), \c AllColumns
2733 or \c LastColumn.
2734
2735 \warning Setting the resize mode should be done after all necessary
2736 columns have been added to the list view, otherwise the behavior is
2737 undefined.
2738
2739 \sa Q3Header, header()
2740 */
2741
setResizeMode(ResizeMode m)2742 void Q3ListView::setResizeMode(ResizeMode m)
2743 {
2744 d->resizeMode = m;
2745 if (m == NoColumn)
2746 header()->setStretchEnabled(false);
2747 else if (m == AllColumns)
2748 header()->setStretchEnabled(true);
2749 else
2750 header()->setStretchEnabled(true, header()->count() - 1);
2751 }
2752
resizeMode() const2753 Q3ListView::ResizeMode Q3ListView::resizeMode() const
2754 {
2755 return d->resizeMode;
2756 }
2757
2758 /*!
2759 Destroys the list view, deleting all its items, and frees up all
2760 allocated resources.
2761 */
2762
~Q3ListView()2763 Q3ListView::~Q3ListView()
2764 {
2765 for (int j = 0; j < d->iterators.size(); ++j) {
2766 Q3ListViewItemIterator *i = d->iterators.at(j);
2767 i->listView = 0;
2768 }
2769
2770 d->focusItem = 0;
2771 delete d->r;
2772 d->r = 0;
2773 delete d->vci;
2774 d->vci = 0;
2775 #if 0
2776 delete d->toolTip;
2777 d->toolTip = 0;
2778 #endif
2779 delete d;
2780 d = 0;
2781 }
2782
2783
2784 /*!
2785 Calls Q3ListViewItem::paintCell() and
2786 Q3ListViewItem::paintBranches() as necessary for all list view
2787 items that require repainting in the \a cw pixels wide and \a ch
2788 pixels high bounding rectangle starting at position \a cx, \a cy
2789 with offset \a ox, \a oy. Uses the painter \a p.
2790 */
2791
drawContentsOffset(QPainter * p,int ox,int oy,int cx,int cy,int cw,int ch)2792 void Q3ListView::drawContentsOffset(QPainter * p, int ox, int oy,
2793 int cx, int cy, int cw, int ch)
2794 {
2795 if (columns() == 0) {
2796 paintEmptyArea(p, QRect(cx, cy, cw, ch));
2797 return;
2798 }
2799
2800 if (d->drawables.isEmpty() ||
2801 d->topPixel > cy ||
2802 d->bottomPixel < cy + ch - 1 ||
2803 d->r->maybeTotalHeight < 0)
2804 buildDrawableList();
2805
2806 if (!d->dirtyItems.isEmpty()) {
2807 QRect br(cx - ox, cy - oy, cw, ch);
2808 for (int i = 0; i < d->dirtyItems.size(); ++i) {
2809 const Q3ListViewItem * item = d->dirtyItems.at(i);
2810 QRect ir = itemRect(item).intersected(viewport()->visibleRect());
2811 if (ir.isEmpty() || br.contains(ir))
2812 // we're painting this one, or it needs no painting: forget it
2813 d->dirtyItems.removeAt(i);
2814 }
2815 if (d->dirtyItems.count()) {
2816 // there are still items left that need repainting
2817 d->dirtyItemTimer->start(0, true);
2818 } else {
2819 // we're painting all items that need to be painted
2820 d->dirtyItems.clear();
2821 d->dirtyItemTimer->stop();
2822 }
2823 }
2824
2825 p->setFont(font());
2826
2827 QRect r;
2828 int fx = -1, x, fc = 0, lc = 0;
2829 int tx = -1;
2830
2831 for (int i = 0; i < d->drawables.size(); ++i) {
2832 Q3ListViewPrivate::DrawableItem current = d->drawables.at(i);
2833 if (!current.i->isVisible())
2834 continue;
2835 int ih = current.i->height();
2836 int ith = current.i->totalHeight();
2837 int c;
2838 int cs;
2839
2840 // need to paint current?
2841 if (ih > 0 && current.y < cy+ch && current.y+ih > cy) {
2842 if (fx < 0) {
2843 // find first interesting column, once
2844 x = 0;
2845 c = 0;
2846 cs = d->h->cellSize(0);
2847 while (x + cs <= cx && c < d->h->count()) {
2848 x += cs;
2849 c++;
2850 if (c < d->h->count())
2851 cs = d->h->cellSize(c);
2852 }
2853 fx = x;
2854 fc = c;
2855 while(x < cx + cw && c < d->h->count()) {
2856 x += cs;
2857 c++;
2858 if (c < d->h->count())
2859 cs = d->h->cellSize(c);
2860 }
2861 lc = c;
2862 }
2863
2864 x = fx;
2865 c = fc;
2866 // draw to last interesting column
2867
2868 bool drawActiveSelection = hasFocus() || d->inMenuMode ||
2869 !style()->styleHint(QStyle::SH_ItemView_ChangeHighlightOnFocus, 0, this)
2870 || (currentItem() && currentItem()->renameBox
2871 && currentItem()->renameBox->hasFocus());
2872 QPalette pal = palette();
2873 if(!drawActiveSelection)
2874 pal.setCurrentColorGroup(QPalette::Inactive);
2875
2876 while (c < lc) {
2877 int i = d->h->mapToLogical(c);
2878 cs = d->h->cellSize(c);
2879 r.setRect(x - ox, current.y - oy, cs, ih);
2880 if (i == 0 && current.i->parentItem)
2881 r.setLeft(r.left() + current.l * treeStepSize());
2882
2883 p->save();
2884 // No need to paint if the cell isn't technically visible
2885 if (!(r.width() == 0 || r.height() == 0)) {
2886 p->translate(r.left(), r.top());
2887 int ac = d->h->mapToLogical(c);
2888 // map to Left currently. This should change once we
2889 // can really reverse the listview.
2890 int align = columnAlignment(ac);
2891 if (align == Qt::AlignAuto) align = Qt::AlignLeft;
2892 current.i->paintCell(p, pal, ac, r.width(), align);
2893 }
2894 p->restore();
2895 x += cs;
2896 c++;
2897 }
2898
2899 if (current.i == d->focusItem && hasFocus() &&
2900 !d->allColumnsShowFocus) {
2901 p->save();
2902 int cell = d->h->mapToActual(0);
2903 QRect r(d->h->cellPos(cell) - ox, current.y - oy, d->h->cellSize(cell), ih);
2904 if (current.i->parentItem)
2905 r.setLeft(r.left() + current.l * treeStepSize());
2906 if (r.left() < r.right())
2907 current.i->paintFocus(p, palette(), r);
2908 p->restore();
2909 }
2910 }
2911
2912 const int cell = d->h->mapToActual(0);
2913
2914 // does current need focus indication?
2915 if (current.i == d->focusItem && hasFocus() &&
2916 d->allColumnsShowFocus) {
2917 p->save();
2918 int x = -contentsX();
2919 int w = header()->cellPos(header()->count() - 1) +
2920 header()->cellSize(header()->count() - 1);
2921
2922 r.setRect(x, current.y - oy, w, ih);
2923 if (d->h->mapToActual(0) == 0 || (current.l == 0 && !rootIsDecorated())) {
2924 int offsetx = qMin(current.l * treeStepSize(), d->h->cellSize(cell));
2925 r.setLeft(r.left() + offsetx);
2926 current.i->paintFocus(p, palette(), r);
2927 } else {
2928 int xdepth = qMin(treeStepSize() * (current.i->depth() + (rootIsDecorated() ? 1 : 0))
2929 + itemMargin(), d->h->cellSize(cell));
2930 xdepth += d->h->cellPos(cell);
2931 QRect r1(r);
2932 r1.setRight(d->h->cellPos(cell) - 1);
2933 QRect r2(r);
2934 r2.setLeft(xdepth - 1);
2935 current.i->paintFocus(p, palette(), r1);
2936 current.i->paintFocus(p, palette(), r2);
2937 }
2938 p->restore();
2939 }
2940
2941 if (tx < 0)
2942 tx = d->h->cellPos(cell);
2943
2944 // do any children of current need to be painted?
2945 if (ih != ith &&
2946 (current.i != d->r || d->rootIsExpandable) &&
2947 current.y + ith > cy &&
2948 current.y + ih < cy + ch &&
2949 tx + current.l * treeStepSize() < cx + cw &&
2950 tx + (current.l+1) * treeStepSize() > cx) {
2951 // compute the clip rectangle the safe way
2952
2953 int rtop = current.y + ih;
2954 int rbottom = current.y + ith;
2955 int rleft = tx + current.l*treeStepSize();
2956 int rright = rleft + treeStepSize();
2957
2958 int crtop = qMax(rtop, cy);
2959 int crbottom = qMin(rbottom, cy+ch);
2960 int crleft = qMax(rleft, cx);
2961 int crright = qMin(rright, cx+cw);
2962
2963 r.setRect(crleft-ox, crtop-oy,
2964 crright-crleft, crbottom-crtop);
2965
2966 if (r.isValid()) {
2967 p->save();
2968 p->setClipRect(QRect(d->h->cellPos(cell), 0, d->h->cellSize(cell), height()));
2969 p->translate(rleft-ox, crtop-oy);
2970
2971 current.i->paintBranches(p, palette(), treeStepSize(),
2972 rtop - crtop, r.height());
2973 p->restore();
2974 }
2975 }
2976 }
2977
2978 if (d->r->totalHeight() < cy + ch)
2979 paintEmptyArea(p, QRect(cx - ox, d->r->totalHeight() - oy,
2980 cw, cy + ch - d->r->totalHeight()));
2981
2982 int c = d->h->count()-1;
2983 if (c >= 0 &&
2984 d->h->cellPos(c) + d->h->cellSize(c) < cx + cw) {
2985 c = d->h->cellPos(c) + d->h->cellSize(c);
2986 paintEmptyArea(p, QRect(c - ox, cy - oy, cx + cw - c, ch));
2987 }
2988 }
2989
2990
2991
2992 /*!
2993 Paints \a rect so that it looks like empty background using
2994 painter \a p. \a rect is in widget coordinates, ready to be fed to
2995 \a p.
2996
2997 The default function fills \a rect with the
2998 viewport()->backgroundBrush().
2999 */
3000
paintEmptyArea(QPainter * p,const QRect & rect)3001 void Q3ListView::paintEmptyArea(QPainter * p, const QRect & rect)
3002 {
3003 QStyleOptionQ3ListView opt = getStyleOption(this, 0);
3004 opt.rect = rect;
3005 opt.sortColumn = d->sortcolumn;
3006 opt.subControls = QStyle::SC_Q3ListView;
3007 style()->drawComplexControl(QStyle::CC_Q3ListView, &opt, p, this);
3008 }
3009
3010
3011 /*
3012 Rebuilds the list of drawable Q3ListViewItems. This function is
3013 const so that const functions can call it without requiring
3014 d->drawables to be mutable.
3015 */
3016
buildDrawableList() const3017 void Q3ListView::buildDrawableList() const
3018 {
3019 d->r->enforceSortOrder();
3020
3021 QStack<Q3ListViewPrivate::DrawableItem> stack;
3022 Q3ListViewPrivate::DrawableItem di(((int)d->rootIsExpandable)-1, 0, d->r);
3023 stack.push(di);
3024
3025 Q3ListView *that = const_cast<Q3ListView *>(this);
3026
3027 // could mess with cy and ch in order to speed up vertical
3028 // scrolling
3029 int cy = contentsY();
3030 int ch = that->visibleHeight();
3031 d->topPixel = cy + ch; // one below bottom
3032 d->bottomPixel = cy - 1; // one above top
3033
3034 that->d->drawables.clear();
3035
3036 while (!stack.isEmpty()) {
3037 Q3ListViewPrivate::DrawableItem cur = stack.pop();
3038
3039 int ih = cur.i->height();
3040 int ith = cur.i->totalHeight();
3041
3042 // is this item, or its branch symbol, inside the viewport?
3043 if (cur.y + ith >= cy && cur.y < cy + ch) {
3044 that->d->drawables.append(cur);
3045 // perhaps adjust topPixel up to this item? may be adjusted
3046 // down again if any children are not to be painted
3047 if (cur.y < d->topPixel)
3048 d->topPixel = cur.y;
3049 // bottompixel is easy: the bottom item drawn contains it
3050 d->bottomPixel = cur.y + ih - 1;
3051 }
3052
3053 // push younger sibling of cur on the stack?
3054 if (cur.y + ith < cy+ch && cur.i->siblingItem)
3055 stack.push(Q3ListViewPrivate::DrawableItem(cur.l, cur.y + ith, cur.i->siblingItem));
3056
3057 // do any children of cur need to be painted?
3058 if (cur.i->isOpen() && cur.i->childCount() &&
3059 cur.y + ith > cy &&
3060 cur.y + ih < cy + ch) {
3061 cur.i->enforceSortOrder();
3062
3063 Q3ListViewItem * c = cur.i->childItem;
3064 int y = cur.y + ih;
3065
3066 // if any of the children are not to be painted, skip them
3067 // and invalidate topPixel
3068 while (c && y + c->totalHeight() <= cy) {
3069 y += c->totalHeight();
3070 c = c->siblingItem;
3071 d->topPixel = cy + ch;
3072 }
3073
3074 // push one child on the stack, if there is at least one
3075 // needing to be painted
3076 if (c && y < cy+ch)
3077 stack.push(Q3ListViewPrivate::DrawableItem(cur.l + 1, y, c));
3078 }
3079 }
3080 }
3081
3082 /*!
3083 \property Q3ListView::treeStepSize
3084 \brief the number of pixels a child is offset from its parent
3085
3086 The default is 20 pixels.
3087
3088 Of course, this property is only meaningful for hierarchical list
3089 views.
3090 */
3091
treeStepSize() const3092 int Q3ListView::treeStepSize() const
3093 {
3094 return d->levelWidth;
3095 }
3096
setTreeStepSize(int size)3097 void Q3ListView::setTreeStepSize(int size)
3098 {
3099 if (size != d->levelWidth) {
3100 d->levelWidth = size;
3101 viewport()->repaint();
3102 }
3103 }
3104
3105 /*!
3106 Inserts item \a i into the list view as a top-level item. You do
3107 not need to call this unless you've called takeItem(\a i) or
3108 Q3ListViewItem::takeItem(\a i) and need to reinsert \a i elsewhere.
3109
3110 \sa Q3ListViewItem::takeItem() takeItem()
3111 */
3112
insertItem(Q3ListViewItem * i)3113 void Q3ListView::insertItem(Q3ListViewItem * i)
3114 {
3115 if (d->r) // not for d->r itself
3116 d->r->insertItem(i);
3117 }
3118
3119
3120 /*!
3121 Removes and deletes all the items in this list view and triggers
3122 an update.
3123
3124 \sa triggerUpdate()
3125 */
3126
clear()3127 void Q3ListView::clear()
3128 {
3129 bool wasUpdatesEnabled = viewport()->updatesEnabled();
3130 if (wasUpdatesEnabled)
3131 viewport()->setUpdatesEnabled(false);
3132 setContentsPos(0, 0);
3133 if (wasUpdatesEnabled)
3134 viewport()->setUpdatesEnabled(true);
3135
3136 bool block = signalsBlocked();
3137 blockSignals(true);
3138 d->clearing = true;
3139 clearSelection();
3140 for (int j = 0; j < d->iterators.size(); ++j) {
3141 Q3ListViewItemIterator *i = d->iterators.at(j);
3142 i->curr = 0;
3143 }
3144
3145 d->drawables.clear();
3146 d->dirtyItems.clear();
3147 d->dirtyItemTimer->stop();
3148
3149 d->highlighted = 0;
3150 d->focusItem = 0;
3151 d->selectAnchor = 0;
3152 d->pressedItem = 0;
3153 d->startDragItem = 0;
3154
3155 // if it's down its downness makes no sense, so undown it
3156 d->buttonDown = false;
3157
3158 Q3ListViewItem *c = (Q3ListViewItem *)d->r->firstChild();
3159 Q3ListViewItem *n;
3160 while(c) {
3161 n = (Q3ListViewItem *)c->nextSibling();
3162 delete c;
3163 c = n;
3164 }
3165 resizeContents(d->h->sizeHint().width(), contentsHeight());
3166 delete d->r;
3167 d->r = 0;
3168 Q3ListViewPrivate::Root * r = new Q3ListViewPrivate::Root(this);
3169 r->is_root = true;
3170 d->r = r;
3171 d->r->setSelectable(false);
3172 blockSignals(block);
3173 triggerUpdate();
3174 d->clearing = false;
3175 }
3176
3177 /*!
3178 \reimp
3179 */
3180
setContentsPos(int x,int y)3181 void Q3ListView::setContentsPos(int x, int y)
3182 {
3183 updateGeometries();
3184 Q3ScrollView::setContentsPos(x, y);
3185 }
3186
3187 /*!
3188 Adds a \a width pixels wide column with the column header \a label
3189 to the list view, and returns the index of the new column.
3190
3191 All columns apart from the first one are inserted to the right of
3192 the existing ones.
3193
3194 If \a width is negative, the new column's \l WidthMode is set to
3195 \c Maximum instead of \c Manual.
3196
3197 \sa setColumnText() setColumnWidth() setColumnWidthMode()
3198 */
addColumn(const QString & label,int width)3199 int Q3ListView::addColumn(const QString &label, int width)
3200 {
3201 int c = d->h->addLabel(label, width);
3202 d->column.resize(c+1);
3203 d->column[c].wmode = (width >= 0 ? Manual : Maximum);
3204 updateGeometries();
3205 updateGeometry();
3206 return c;
3207 }
3208
3209 /*!
3210 \overload
3211
3212 Adds a \a width pixels wide new column with the header \a label
3213 and the \a icon to the list view, and returns the index of the
3214 column.
3215
3216 If \a width is negative, the new column's \l WidthMode is set to
3217 \c Maximum, and to \c Manual otherwise.
3218
3219 \sa setColumnText() setColumnWidth() setColumnWidthMode()
3220 */
addColumn(const QIcon & icon,const QString & label,int width)3221 int Q3ListView::addColumn(const QIcon& icon, const QString &label, int width)
3222 {
3223 int c = d->h->addLabel(icon, label, width);
3224 d->column.resize(c+1);
3225 d->column[c].wmode = (width >= 0 ? Manual : Maximum);
3226 updateGeometries();
3227 updateGeometry();
3228 return c;
3229 }
3230
3231 /*!
3232 \property Q3ListView::columns
3233 \brief the number of columns in this list view
3234
3235 \sa addColumn(), removeColumn()
3236 */
3237
columns() const3238 int Q3ListView::columns() const
3239 {
3240 return d->column.count();
3241 }
3242
3243 /*!
3244 Removes the column at position \a index.
3245 */
3246
removeColumn(int index)3247 void Q3ListView::removeColumn(int index)
3248 {
3249 if (index < 0 || index > (int)d->column.count() - 1)
3250 return;
3251
3252 if (d->vci) {
3253 Q3ListViewPrivate::ViewColumnInfo *vi = d->vci, *prev = 0, *next = 0;
3254 for (int i = 0; i < index; ++i) {
3255 if (vi) {
3256 prev = vi;
3257 vi = vi->next;
3258 }
3259 }
3260 if (vi) {
3261 next = vi->next;
3262 if (prev)
3263 prev->next = next;
3264 vi->next = 0;
3265 delete vi;
3266 if (index == 0)
3267 d->vci = next;
3268 }
3269 }
3270
3271 Q3ListViewItemIterator it(this);
3272 for (; it.current(); ++it) {
3273 Q3ListViewPrivate::ItemColumnInfo *ci = (Q3ListViewPrivate::ItemColumnInfo*)it.current()->columns;
3274 if (ci) {
3275 Q3ListViewPrivate::ItemColumnInfo *prev = 0, *next = 0;
3276 for (int i = 0; i < index; ++i) {
3277 if (ci) {
3278 prev = ci;
3279 ci = ci->next;
3280 }
3281 }
3282 if (ci) {
3283 next = ci->next;
3284 if (prev)
3285 prev->next = next;
3286 ci->next = 0;
3287 delete ci;
3288 if (index == 0)
3289 it.current()->columns = next;
3290 }
3291 }
3292 }
3293
3294 for (int i = index; i < (int)d->column.size() - 1; ++i)
3295 d->column[i] = d->column[i + 1];
3296 d->column.resize(d->column.size() - 1);
3297
3298 d->h->removeLabel(index);
3299 if (d->resizeMode == LastColumn)
3300 d->h->setStretchEnabled(true, d->h->count() - 1);
3301
3302 updateGeometries();
3303 if (d->column.count() == 0)
3304 clear();
3305 updateGeometry();
3306 viewport()->update();
3307 }
3308
3309 /*!
3310 Sets the heading of column \a column to \a label.
3311
3312 \sa columnText()
3313 */
setColumnText(int column,const QString & label)3314 void Q3ListView::setColumnText(int column, const QString &label)
3315 {
3316 if (column < d->h->count()) {
3317 d->h->setLabel(column, label);
3318 updateGeometries();
3319 updateGeometry();
3320 }
3321 }
3322
3323 /*!
3324 \overload
3325
3326 Sets the heading of column \a column to \a icon and \a label.
3327
3328 \sa columnText()
3329 */
setColumnText(int column,const QIcon & icon,const QString & label)3330 void Q3ListView::setColumnText(int column, const QIcon& icon, const QString &label)
3331 {
3332 if (column < d->h->count()) {
3333 d->h->setLabel(column, icon, label);
3334 updateGeometries();
3335 }
3336 }
3337
3338 /*!
3339 Sets the width of column \a column to \a w pixels. Note that if
3340 the column has a \c WidthMode other than \c Manual, this width
3341 setting may be subsequently overridden.
3342
3343 \sa columnWidth()
3344 */
setColumnWidth(int column,int w)3345 void Q3ListView::setColumnWidth(int column, int w)
3346 {
3347 int oldw = d->h->sectionSize(column);
3348 if (column < d->h->count() && oldw != w) {
3349 d->h->resizeSection(column, w);
3350 disconnect(d->h, SIGNAL(sizeChange(int,int,int)),
3351 this, SLOT(handleSizeChange(int,int,int)));
3352 emit d->h->sizeChange(column, oldw, w);
3353 connect(d->h, SIGNAL(sizeChange(int,int,int)),
3354 this, SLOT(handleSizeChange(int,int,int)));
3355 viewport()->update();
3356 }
3357 }
3358
3359
3360 /*!
3361 Returns the text of column \a c.
3362
3363 \sa setColumnText()
3364 */
3365
columnText(int c) const3366 QString Q3ListView::columnText(int c) const
3367 {
3368 return d->h->label(c);
3369 }
3370
3371 /*!
3372 Returns the width of column \a c.
3373
3374 \sa setColumnWidth()
3375 */
3376
columnWidth(int c) const3377 int Q3ListView::columnWidth(int c) const
3378 {
3379 int actual = d->h->mapToActual(c);
3380 return d->h->cellSize(actual);
3381 }
3382
3383
3384 /*!
3385 \enum Q3ListView::WidthMode
3386
3387 This enum type describes how the width of a column in the view
3388 changes.
3389
3390 \value Manual the column width does not change automatically.
3391
3392 \value Maximum the column is automatically sized according to the
3393 widths of all items in the column. (Note: The column never shrinks
3394 in this case.) This means that the column is always resized to the
3395 width of the item with the largest width in the column.
3396
3397 \sa setColumnWidth() setColumnWidthMode() columnWidth()
3398 */
3399
3400
3401 /*!
3402 Sets column \a{c}'s width mode to \a mode. The default depends on
3403 the original width argument to addColumn().
3404
3405 \sa Q3ListViewItem::width()
3406 */
3407
setColumnWidthMode(int c,WidthMode mode)3408 void Q3ListView::setColumnWidthMode(int c, WidthMode mode)
3409 {
3410 if (c >= 0 && c < d->h->count())
3411 d->column[c].wmode = mode;
3412 }
3413
3414
3415 /*!
3416 Returns the \c WidthMode for column \a c.
3417
3418 \sa setColumnWidthMode()
3419 */
3420
columnWidthMode(int c) const3421 Q3ListView::WidthMode Q3ListView::columnWidthMode(int c) const
3422 {
3423 if (c >= 0 && c < d->h->count())
3424 return d->column[c].wmode;
3425 else
3426 return Manual;
3427 }
3428
3429
3430 /*!
3431 Sets column \a{column}'s alignment to \a align. The alignment is
3432 ultimately passed to Q3ListViewItem::paintCell() for each item in
3433 the list view. For horizontally aligned text with Qt::AlignLeft or
3434 Qt::AlignHCenter the ellipsis (...) will be to the right, for
3435 Qt::AlignRight the ellipsis will be to the left.
3436
3437 \sa Qt::Alignment
3438 */
3439
setColumnAlignment(int column,int align)3440 void Q3ListView::setColumnAlignment(int column, int align)
3441 {
3442 if (column < 0)
3443 return;
3444 if (!d->vci)
3445 d->vci = new Q3ListViewPrivate::ViewColumnInfo;
3446 Q3ListViewPrivate::ViewColumnInfo * l = d->vci;
3447 while(column) {
3448 if (!l->next)
3449 l->next = new Q3ListViewPrivate::ViewColumnInfo;
3450 l = l->next;
3451 column--;
3452 }
3453 if (l->align == align)
3454 return;
3455 l->align = align;
3456 triggerUpdate();
3457 }
3458
3459
3460 /*!
3461 Returns the alignment of column \a column. The default is \c
3462 Qt::AlignAuto.
3463
3464 \sa Qt::Alignment
3465 */
3466
columnAlignment(int column) const3467 int Q3ListView::columnAlignment(int column) const
3468 {
3469 if (column < 0 || !d->vci)
3470 return Qt::AlignAuto;
3471 Q3ListViewPrivate::ViewColumnInfo * l = d->vci;
3472 while(column) {
3473 if (!l->next)
3474 l->next = new Q3ListViewPrivate::ViewColumnInfo;
3475 l = l->next;
3476 column--;
3477 }
3478 return l ? l->align : Qt::AlignAuto;
3479 }
3480
3481
3482
3483 /*!
3484 \internal
3485 */
show()3486 void Q3ListView::show()
3487 {
3488 // Reimplemented to setx the correct background mode and viewed
3489 // area size.
3490 if (!isVisible()) {
3491 reconfigureItems();
3492 updateGeometries();
3493 }
3494 Q3ScrollView::show();
3495 }
3496
3497
3498 /*!
3499 Updates the sizes of the viewport, header, scroll bars and so on.
3500
3501 \warning Don't call this directly; call triggerUpdate() instead.
3502 */
3503
updateContents()3504 void Q3ListView::updateContents()
3505 {
3506 if (d->updateHeader)
3507 header()->adjustHeaderSize();
3508 d->updateHeader = false;
3509 if (!isVisible()) {
3510 // Not in response to a setText/setPixmap any more.
3511 return;
3512 }
3513 d->drawables.clear();
3514 viewport()->setUpdatesEnabled(false);
3515 updateGeometries();
3516 viewport()->setUpdatesEnabled(true);
3517 viewport()->repaint();
3518 }
3519
3520
updateGeometries()3521 void Q3ListView::updateGeometries()
3522 {
3523 int th = d->r->totalHeight();
3524 int tw = d->h->headerWidth();
3525 if (d->h->offset() &&
3526 tw < d->h->offset() + d->h->width())
3527 horizontalScrollBar()->setValue(tw - Q3ListView::d->h->width());
3528 #if 0
3529 if (QApplication::reverseLayout() && d->h->offset() != horizontalScrollBar()->value())
3530 horizontalScrollBar()->setValue(d->h->offset());
3531 #endif
3532 verticalScrollBar()->raise();
3533 resizeContents(tw, th);
3534 d->drawables.clear();
3535 if (d->h->isHidden()) {
3536 setMargins(0, 0, 0, 0);
3537 } else {
3538 QSize hs(d->h->sizeHint());
3539 setMargins(0, hs.height(), 0, 0);
3540 d->h->setGeometry(viewport()->x(), viewport()->y()-hs.height(),
3541 visibleWidth(), hs.height());
3542 }
3543 }
3544
3545
3546 /*!
3547 Updates the display when the section \a section has changed size
3548 from the old size, \a os, to the new size, \a ns.
3549 */
3550
handleSizeChange(int section,int os,int ns)3551 void Q3ListView::handleSizeChange(int section, int os, int ns)
3552 {
3553 bool upe = viewport()->updatesEnabled();
3554 if (upe)
3555 viewport()->setUpdatesEnabled(false);
3556 viewport()->setAttribute(Qt::WA_UpdatesDisabled, true);
3557 int sx = horizontalScrollBar()->value();
3558 bool sv = horizontalScrollBar()->isVisible();
3559 updateGeometries();
3560 bool fullRepaint = d->fullRepaintOnComlumnChange || sx != horizontalScrollBar()->value()
3561 || sv != horizontalScrollBar()->isVisible();
3562 d->fullRepaintOnComlumnChange = false;
3563 if (upe)
3564 viewport()->setUpdatesEnabled(true);
3565
3566 if (fullRepaint) {
3567 viewport()->repaint();
3568 return;
3569 }
3570
3571 int actual = d->h->mapToActual(section);
3572 int dx = ns - os;
3573 int left = d->h->cellPos(actual) - contentsX() + d->h->cellSize(actual);
3574 if (dx > 0)
3575 left -= dx;
3576 if (left < visibleWidth())
3577 viewport()->scroll(dx, 0, QRect(left, 0, visibleWidth() - left, visibleHeight()));
3578 viewport()->repaint(left - 4 - d->ellipsisWidth, 0, 4 + d->ellipsisWidth,
3579 visibleHeight()); // border between the items and ellipses width
3580
3581 // map auto to left for now. Need to fix this once we support
3582 // reverse layout on the listview.
3583 int align = columnAlignment(section);
3584 if (align == Qt::AlignAuto) align = Qt::AlignLeft;
3585 if (align != Qt::AlignAuto && align != Qt::AlignLeft)
3586 viewport()->repaint(d->h->cellPos(actual) - contentsX(), 0,
3587 d->h->cellSize(actual), visibleHeight());
3588
3589 if (currentItem() && currentItem()->renameBox) {
3590 QRect r = itemRect(currentItem());
3591 r = QRect(viewportToContents(r.topLeft()), r.size());
3592 r.setLeft(header()->sectionPos(currentItem()->renameCol));
3593 r.setWidth(header()->sectionSize(currentItem()->renameCol) - 1);
3594 if (currentItem()->renameCol == 0)
3595 r.setLeft(r.left() + itemMargin() + (currentItem()->depth() +
3596 (rootIsDecorated() ? 1 : 0)) * treeStepSize() - 1);
3597 if (currentItem()->pixmap(currentItem()->renameCol))
3598 r.setLeft(r.left() + currentItem()->pixmap(currentItem()->renameCol)->width());
3599 if (r.x() - contentsX() < 0)
3600 r.setX(contentsX());
3601 if (r.width() > visibleWidth())
3602 r.setWidth(visibleWidth());
3603 addChild(currentItem()->renameBox, r.x(), r.y());
3604 currentItem()->renameBox->resize(r.size());
3605 }
3606 }
3607
3608
3609 /*
3610 Very smart internal slot that repaints \e only the items that need
3611 to be repainted. Don't use this directly; call repaintItem()
3612 instead.
3613 */
3614
updateDirtyItems()3615 void Q3ListView::updateDirtyItems()
3616 {
3617 if (d->timer->isActive() || d->dirtyItems.isEmpty())
3618 return;
3619 QRect ir;
3620 for (int i = 0; i < d->dirtyItems.size(); ++i) {
3621 const Q3ListViewItem *item = d->dirtyItems.at(i);
3622 ir = ir.united(itemRect(item));
3623 }
3624 d->dirtyItems.clear();
3625 if (!ir.isEmpty()) { // rectangle to be repainted
3626 if (ir.x() < 0)
3627 ir.moveBy(-ir.x(), 0);
3628 viewport()->repaint(ir);
3629 }
3630 }
3631
3632
makeVisible()3633 void Q3ListView::makeVisible()
3634 {
3635 if (d->focusItem)
3636 ensureItemVisible(d->focusItem);
3637 }
3638
3639
3640 /*!
3641 Ensures that the header is correctly sized and positioned when the
3642 resize event \a e occurs.
3643 */
3644
resizeEvent(QResizeEvent * e)3645 void Q3ListView::resizeEvent(QResizeEvent *e)
3646 {
3647 Q3ScrollView::resizeEvent(e);
3648 d->fullRepaintOnComlumnChange = true;
3649 d->h->resize(visibleWidth(), d->h->height());
3650 d->h->adjustHeaderSize();
3651 }
3652
3653 /*! \reimp */
3654
viewportResizeEvent(QResizeEvent * e)3655 void Q3ListView::viewportResizeEvent(QResizeEvent *e)
3656 {
3657 Q3ScrollView::viewportResizeEvent(e);
3658 d->h->resize(visibleWidth(), d->h->height());
3659 if (resizeMode() != NoColumn && currentItem() && currentItem()->renameBox) {
3660 QRect r = itemRect(currentItem());
3661 r = QRect(viewportToContents(r.topLeft()), r.size());
3662 r.setLeft(header()->sectionPos(currentItem()->renameCol));
3663 r.setWidth(header()->sectionSize(currentItem()->renameCol) - 1);
3664 if (currentItem()->renameCol == 0)
3665 r.setLeft(r.left() + itemMargin() + (currentItem()->depth() +
3666 (rootIsDecorated() ? 1 : 0)) * treeStepSize() - 1);
3667 if (currentItem()->pixmap(currentItem()->renameCol))
3668 r.setLeft(r.left() + currentItem()->pixmap(currentItem()->renameCol)->width());
3669 if (r.x() - contentsX() < 0)
3670 r.setX(contentsX());
3671 if (r.width() > visibleWidth())
3672 r.setWidth(visibleWidth());
3673 addChild(currentItem()->renameBox, r.x(), r.y());
3674 currentItem()->renameBox->resize(r.size());
3675 }
3676 }
3677
3678 /*!
3679 Triggers a size, geometry and content update during the next
3680 iteration of the event loop. Ensures that there'll be just one
3681 update to avoid flicker.
3682 */
3683
triggerUpdate()3684 void Q3ListView::triggerUpdate()
3685 {
3686 if (!isVisible() || !updatesEnabled()) {
3687 // Not in response to a setText/setPixmap any more.
3688 return; // it will update when shown, or something.
3689 }
3690
3691 d->timer->start(0, true);
3692 }
3693
3694
3695 /*!
3696 Redirects the event \a e relating to object \a o, for the viewport
3697 to mousePressEvent(), keyPressEvent() and friends.
3698 */
3699
eventFilter(QObject * o,QEvent * e)3700 bool Q3ListView::eventFilter(QObject * o, QEvent * e)
3701 {
3702 if (o == d->h &&
3703 e->type() >= QEvent::MouseButtonPress &&
3704 e->type() <= QEvent::MouseMove) {
3705 QMouseEvent * me = (QMouseEvent *)e;
3706 QMouseEvent me2(me->type(),
3707 QPoint(me->pos().x(),
3708 me->pos().y() - d->h->height()),
3709 me->button(), me->state());
3710 switch(me2.type()) {
3711 case QEvent::MouseButtonDblClick:
3712 if (me2.button() == Qt::RightButton)
3713 return true;
3714 break;
3715 case QEvent::MouseMove:
3716 if (me2.state() & Qt::RightButton) {
3717 viewportMouseMoveEvent(&me2);
3718 return true;
3719 }
3720 break;
3721 default:
3722 break;
3723 }
3724 } else if (o == viewport()) {
3725 QFocusEvent * fe = (QFocusEvent *)e;
3726
3727 switch(e->type()) {
3728 case QEvent::FocusIn:
3729 focusInEvent(fe);
3730 return true;
3731 case QEvent::FocusOut:
3732 focusOutEvent(fe);
3733 return true;
3734 #ifndef QT_NO_TOOLTIP
3735 case QEvent::ToolTip:
3736 {
3737 if (!showToolTips())
3738 return false;
3739
3740 QHelpEvent *he = static_cast<QHelpEvent *>(e);
3741 Q3ListViewItem *item = itemAt(he->pos());
3742 QPoint contentsPos = viewportToContents(he->pos());
3743 if (!item || !item->columns) {
3744 QToolTip::showText(he->globalPos(), QString(), viewport());
3745 return true;
3746 }
3747 int col = header()->sectionAt(contentsPos.x());
3748 Q3ListViewPrivate::ItemColumnInfo *ci = (Q3ListViewPrivate::ItemColumnInfo*)item->columns;
3749 for (int i = 0; ci && (i < col); ++i)
3750 ci = ci->next;
3751
3752 if (!ci || !ci->truncated)
3753 QToolTip::showText(he->globalPos(), QString(), viewport());
3754 else
3755 QToolTip::showText(he->globalPos(), item->text(col), viewport());
3756 return true;
3757 }
3758 #endif
3759 default:
3760 // nothing
3761 break;
3762 }
3763 } else if (qobject_cast<QLineEdit*>(o)) {
3764 if (currentItem() && currentItem()->renameBox) {
3765 if (e->type() == QEvent::KeyPress) {
3766 QKeyEvent *ke = (QKeyEvent*)e;
3767 if (ke->key() == Qt::Key_Return ||
3768 ke->key() == Qt::Key_Enter) {
3769 currentItem()->okRename(currentItem()->renameCol);
3770 return true;
3771 } else if (ke->key() == Qt::Key_Escape) {
3772 currentItem()->cancelRename(currentItem()->renameCol);
3773 return true;
3774 }
3775 } else if (e->type() == QEvent::FocusOut) {
3776 if (((QFocusEvent*)e)->reason() != Qt::PopupFocusReason) {
3777 QCustomEvent *e = new QCustomEvent(9999);
3778 QApplication::postEvent(o, e);
3779 return true;
3780 }
3781 } else if (e->type() == 9999) {
3782 if (d->defRenameAction == Reject)
3783 currentItem()->cancelRename(currentItem()->renameCol);
3784 else
3785 currentItem()->okRename(currentItem()->renameCol);
3786 return true;
3787 }
3788 }
3789 }
3790
3791 return Q3ScrollView::eventFilter(o, e);
3792 }
3793
3794
3795 /*!
3796 Returns a pointer to the list view containing this item.
3797
3798 Note that this function traverses the items to the root to find the
3799 listview. This function will return 0 for taken items - see
3800 Q3ListViewItem::takeItem()
3801 */
3802
listView() const3803 Q3ListView * Q3ListViewItem::listView() const
3804 {
3805 const Q3ListViewItem* c = this;
3806 while (c && !c->is_root)
3807 c = c->parentItem;
3808 if (!c)
3809 return 0;
3810 return ((Q3ListViewPrivate::Root*)c)->theListView();
3811 }
3812
3813
3814 /*!
3815 Returns the depth of this item.
3816 */
depth() const3817 int Q3ListViewItem::depth() const
3818 {
3819 return parentItem ? parentItem->depth()+1 : -1; // -1 == the hidden root
3820 }
3821
3822
3823 /*!
3824 Returns a pointer to the item immediately above this item on the
3825 screen. This is usually the item's closest older sibling, but it
3826 may also be its parent or its next older sibling's youngest child,
3827 or something else if anyoftheabove->height() returns 0. Returns 0
3828 if there is no item immediately above this item.
3829
3830 This function assumes that all parents of this item are open (i.e.
3831 that this item is visible, or can be made visible by scrolling).
3832
3833 This function might be relatively slow because of the tree
3834 traversions needed to find the correct item.
3835
3836 \sa itemBelow() Q3ListView::itemRect()
3837 */
3838
itemAbove() const3839 Q3ListViewItem * Q3ListViewItem::itemAbove() const
3840 {
3841 if (!parentItem)
3842 return 0;
3843
3844 Q3ListViewItem * c = parentItem;
3845 if (c->childItem != this) {
3846 c = c->childItem;
3847 while(c && c->siblingItem != this)
3848 c = c->siblingItem;
3849 if (!c)
3850 return 0;
3851 while(c->isOpen() && c->childItem) {
3852 c = c->childItem;
3853 while(c->siblingItem)
3854 c = c->siblingItem; // assign c's sibling to c
3855 }
3856 }
3857 if (c && (!c->height() || !c->isEnabled()))
3858 return c->itemAbove();
3859 return c;
3860 }
3861
3862
3863 /*!
3864 Returns a pointer to the item immediately below this item on the
3865 screen. This is usually the item's eldest child, but it may also
3866 be its next younger sibling, its parent's next younger sibling,
3867 grandparent's, etc., or something else if anyoftheabove->height()
3868 returns 0. Returns 0 if there is no item immediately below this
3869 item.
3870
3871 This function assumes that all parents of this item are open (i.e.
3872 that this item is visible or can be made visible by scrolling).
3873
3874 \sa itemAbove() Q3ListView::itemRect()
3875 */
3876
itemBelow() const3877 Q3ListViewItem * Q3ListViewItem::itemBelow() const
3878 {
3879 Q3ListViewItem * c = 0;
3880 if (isOpen() && childItem) {
3881 c = childItem;
3882 } else if (siblingItem) {
3883 c = siblingItem;
3884 } else if (parentItem) {
3885 c = const_cast<Q3ListViewItem*>(this);
3886 do {
3887 c = c->parentItem;
3888 } while(c->parentItem && !c->siblingItem);
3889 if (c)
3890 c = c->siblingItem;
3891 }
3892 if (c && (!c->height() || !c->isEnabled()))
3893 return c->itemBelow();
3894 return c;
3895 }
3896
3897
3898 /*!
3899 \fn bool Q3ListViewItem::isOpen() const
3900
3901 Returns true if this list view item has children \e and they are
3902 not explicitly hidden; otherwise returns false.
3903
3904 \sa setOpen()
3905 */
3906
3907 /*!
3908 Returns the first (top) child of this item, or 0 if this item has
3909 no children.
3910
3911 Note that the children are not guaranteed to be sorted properly.
3912 Q3ListView and Q3ListViewItem try to postpone or avoid sorting to
3913 the greatest degree possible, in order to keep the user interface
3914 snappy.
3915
3916 \sa nextSibling() sortChildItems()
3917 */
3918
firstChild() const3919 Q3ListViewItem* Q3ListViewItem::firstChild() const
3920 {
3921 enforceSortOrder();
3922 return childItem;
3923 }
3924
3925
3926 /*!
3927 Returns the parent of this item, or 0 if this item has no parent.
3928
3929 \sa firstChild(), nextSibling()
3930 */
3931
parent() const3932 Q3ListViewItem* Q3ListViewItem::parent() const
3933 {
3934 if (!parentItem || parentItem->is_root) return 0;
3935 return parentItem;
3936 }
3937
3938
3939 /*!
3940 \fn Q3ListViewItem* Q3ListViewItem::nextSibling() const
3941
3942 Returns the sibling item below this item, or 0 if there is no
3943 sibling item after this item.
3944
3945 Note that the siblings are not guaranteed to be sorted properly.
3946 Q3ListView and Q3ListViewItem try to postpone or avoid sorting to
3947 the greatest degree possible, in order to keep the user interface
3948 snappy.
3949
3950 \sa firstChild() sortChildItems()
3951 */
3952
3953 /*!
3954 \fn int Q3ListViewItem::childCount () const
3955
3956 Returns how many children this item has. The count only includes
3957 the item's immediate children.
3958 */
3959
3960
3961 /*!
3962 Returns the height of this item in pixels. This does not include
3963 the height of any children; totalHeight() returns that.
3964 */
height() const3965 int Q3ListViewItem::height() const
3966 {
3967 Q3ListViewItem * that = (Q3ListViewItem *)this;
3968 if (!that->configured) {
3969 that->configured = true;
3970 that->setup(); // ### virtual non-const function called in const
3971 }
3972
3973 return visible ? ownHeight : 0;
3974 }
3975
3976 /*!
3977 Call this function when the value of width() may have changed for
3978 column \a c. Normally, you should call this if text(c) changes.
3979 Passing -1 for \a c indicates that all columns may have changed.
3980 It is more efficient to pass -1 if two or more columns have
3981 changed than to call widthChanged() separately for each one.
3982
3983 \sa width()
3984 */
widthChanged(int c) const3985 void Q3ListViewItem::widthChanged(int c) const
3986 {
3987 Q3ListView *lv = listView();
3988 if (lv)
3989 lv->widthChanged(this, c);
3990 }
3991
3992 /*!
3993 \fn void Q3ListView::dropped (QDropEvent * e)
3994
3995 This signal is emitted, when a drop event occurred on the
3996 viewport (not onto an item).
3997
3998 \a e provides all the information about the drop.
3999 */
4000
4001 /*!
4002 \fn void Q3ListView::selectionChanged()
4003
4004 This signal is emitted whenever the set of selected items has
4005 changed (normally before the screen update). It is available both
4006 in \c Single selection and \c Multi selection mode but is most
4007 useful in \c Multi selection mode.
4008
4009 \warning Do not delete any Q3ListViewItem objects in slots
4010 connected to this signal.
4011
4012 \sa setSelected() Q3ListViewItem::setSelected()
4013 */
4014
4015
4016 /*!
4017 \fn void Q3ListView::pressed(Q3ListViewItem *item)
4018
4019 This signal is emitted whenever the user presses the mouse button
4020 in a list view. \a item is the list view item on which the user
4021 pressed the mouse button, or 0 if the user didn't press the mouse
4022 on an item.
4023
4024 \warning Do not delete any Q3ListViewItem objects in slots
4025 connected to this signal.
4026 */
4027
4028 /*!
4029 \fn void Q3ListView::pressed(Q3ListViewItem *item, const QPoint &pnt, int c)
4030
4031 \overload
4032
4033 This signal is emitted whenever the user presses the mouse button
4034 in a list view. \a item is the list view item on which the user
4035 pressed the mouse button, or 0 if the user didn't press the mouse
4036 on an item. \a pnt is the position of the mouse cursor in global
4037 coordinates, and \a c is the column where the mouse cursor was
4038 when the user pressed the mouse button.
4039
4040 \warning Do not delete any Q3ListViewItem objects in slots
4041 connected to this signal.
4042 */
4043
4044 /*!
4045 \fn void Q3ListView::clicked(Q3ListViewItem *item)
4046
4047 This signal is emitted whenever the user clicks (mouse pressed \e
4048 and mouse released) in the list view. \a item is the clicked list
4049 view item, or 0 if the user didn't click on an item.
4050
4051 \warning Do not delete any Q3ListViewItem objects in slots
4052 connected to this signal.
4053 */
4054
4055 /*!
4056 \fn void Q3ListView::mouseButtonClicked(int button, Q3ListViewItem * item, const QPoint & pos, int c)
4057
4058 This signal is emitted whenever the user clicks (mouse pressed \e
4059 and mouse released) in the list view at position \a pos. \a button
4060 is the mouse button that the user pressed, \a item is the clicked
4061 list view item or 0 if the user didn't click on an item. If \a
4062 item is not 0, \a c is the list view column into which the user
4063 pressed; if \a item is 0 \a{c}'s value is undefined.
4064
4065 \warning Do not delete any Q3ListViewItem objects in slots
4066 connected to this signal.
4067 */
4068
4069 /*!
4070 \fn void Q3ListView::mouseButtonPressed(int button, Q3ListViewItem * item, const QPoint & pos, int c)
4071
4072 This signal is emitted whenever the user pressed the mouse button
4073 in the list view at position \a pos. \a button is the mouse button
4074 which the user pressed, \a item is the pressed list view item or 0
4075 if the user didn't press on an item. If \a item is not 0, \a c is
4076 the list view column into which the user pressed; if \a item is 0
4077 \a{c}'s value is undefined.
4078
4079 \warning Do not delete any Q3ListViewItem objects in slots
4080 connected to this signal.
4081 */
4082
4083 /*!
4084 \fn void Q3ListView::clicked(Q3ListViewItem *item, const QPoint &pnt, int c)
4085
4086 \overload
4087
4088 This signal is emitted whenever the user clicks (mouse pressed \e
4089 and mouse released) in the list view. \a item is the clicked list
4090 view item, or 0 if the user didn't click on an item. \a pnt is the
4091 position where the user has clicked in global coordinates. If \a
4092 item is not 0, \a c is the list view column into which the user
4093 pressed; if \a item is 0 \a{c}'s value is undefined.
4094
4095 \warning Do not delete any Q3ListViewItem objects in slots
4096 connected to this signal.
4097 */
4098
4099 /*!
4100 \fn void Q3ListView::selectionChanged(Q3ListViewItem *item)
4101
4102 \overload
4103
4104 This signal is emitted whenever the selected item has changed in
4105 \c Single selection mode (normally after the screen update). The
4106 argument is the newly selected \a item.
4107
4108 In \c Multi selection mode, use the no argument overload of this
4109 signal.
4110
4111 \warning Do not delete any Q3ListViewItem objects in slots
4112 connected to this signal.
4113
4114 \sa setSelected() Q3ListViewItem::setSelected() currentChanged()
4115 */
4116
4117
4118 /*!
4119 \fn void Q3ListView::currentChanged(Q3ListViewItem *item)
4120
4121 This signal is emitted whenever the current item has changed
4122 (normally after the screen update). The current item is the item
4123 responsible for indicating keyboard focus.
4124
4125 The argument is the newly current \a item, or 0 if the change made
4126 no item current. This can happen, for example, if all the items in
4127 the list view are deleted.
4128
4129 \warning Do not delete any Q3ListViewItem objects in slots
4130 connected to this signal.
4131
4132 \sa setCurrentItem() currentItem()
4133 */
4134
4135
4136 /*!
4137 \fn void Q3ListView::expanded(Q3ListViewItem *item)
4138
4139 This signal is emitted when \a item has been expanded, i.e. when
4140 the children of \a item are shown.
4141
4142 \sa setOpen() collapsed()
4143 */
4144
4145 /*!
4146 \fn void Q3ListView::collapsed(Q3ListViewItem *item)
4147
4148 This signal is emitted when the \a item has been collapsed, i.e.
4149 when the children of \a item are hidden.
4150
4151 \sa setOpen() expanded()
4152 */
4153
4154 /*!
4155 Processes the mouse press event \a e on behalf of the viewed widget.
4156 */
contentsMousePressEvent(QMouseEvent * e)4157 void Q3ListView::contentsMousePressEvent(QMouseEvent * e)
4158 {
4159 contentsMousePressEventEx(e);
4160 }
4161
contentsMousePressEventEx(QMouseEvent * e)4162 void Q3ListView::contentsMousePressEventEx(QMouseEvent * e)
4163 {
4164 if (!e)
4165 return;
4166
4167 if (!d->ignoreEditAfterFocus)
4168 d->startEdit = true;
4169 d->ignoreEditAfterFocus = false;
4170
4171 if (currentItem() && currentItem()->renameBox &&
4172 !itemRect(currentItem()).contains(e->pos())) {
4173 d->startEdit = false;
4174 if (d->defRenameAction == Reject)
4175 currentItem()->cancelRename(currentItem()->renameCol);
4176 else
4177 currentItem()->okRename(currentItem()->renameCol);
4178 }
4179
4180 d->startDragItem = 0;
4181 d->dragStartPos = e->pos();
4182 QPoint vp = contentsToViewport(e->pos());
4183
4184 d->ignoreDoubleClick = false;
4185 d->buttonDown = true;
4186
4187 Q3ListViewItem * i = itemAt(vp);
4188 d->pressedEmptyArea = e->y() > contentsHeight();
4189 if (i && !i->isEnabled())
4190 return;
4191 if (d->startEdit && (i != currentItem() || (i && !i->isSelected())))
4192 d->startEdit = false;
4193 Q3ListViewItem *oldCurrent = currentItem();
4194
4195 if (e->button() == Qt::RightButton && (e->state() & Qt::ControlButton))
4196 goto emit_signals;
4197
4198 if (!i) {
4199 if (!(e->state() & Qt::ControlButton))
4200 clearSelection();
4201 goto emit_signals;
4202 } else {
4203 // No new anchor when using shift
4204 if (!(e->state() & Qt::ShiftButton))
4205 d->selectAnchor = i;
4206 }
4207
4208 if ((i->isExpandable() || i->childCount()) &&
4209 d->h->mapToLogical(d->h->cellAt(vp.x())) == 0) {
4210 int x1 = vp.x() +
4211 d->h->offset() -
4212 d->h->cellPos(d->h->mapToActual(0));
4213 int draw = 0;
4214 for (; draw < d->drawables.size(); ++draw)
4215 if (d->drawables.at(draw).i == i)
4216 break;
4217
4218 if (draw < d->drawables.size()) {
4219 Q3ListViewPrivate::DrawableItem it = d->drawables.at(draw);
4220 QStyleOptionQ3ListView opt = getStyleOption(this, i);
4221 x1 -= treeStepSize() * (it.l - 1);
4222 QStyle::SubControl ctrl = style()->hitTestComplexControl(QStyle::CC_Q3ListView, &opt,
4223 QPoint(x1, e->pos().y()), this);
4224 if (ctrl == QStyle::SC_Q3ListViewExpand &&
4225 e->type() == style()->styleHint(QStyle::SH_Q3ListViewExpand_SelectMouseType, 0,
4226 this)) {
4227 d->buttonDown = false;
4228 if (e->button() == Qt::LeftButton) {
4229 bool close = i->isOpen();
4230 setOpen(i, !close);
4231 // ### Looks dangerous, removed because of reentrance problems
4232 // qApp->processEvents();
4233 if (!d->focusItem) {
4234 d->focusItem = i;
4235 repaintItem(d->focusItem);
4236 emit currentChanged(d->focusItem);
4237 }
4238 if (close) {
4239 bool newCurrent = false;
4240 Q3ListViewItem *ci = d->focusItem;
4241 while (ci) {
4242 if (ci->parent() && ci->parent() == i) {
4243 newCurrent = true;
4244 break;
4245 }
4246 ci = ci->parent();
4247 }
4248 if (newCurrent) {
4249 setCurrentItem(i);
4250 }
4251 }
4252 }
4253 d->ignoreDoubleClick = true;
4254 d->buttonDown = false;
4255 goto emit_signals;
4256 }
4257 }
4258 }
4259
4260 d->select = d->selectionMode == Multi ? !i->isSelected() : true;
4261
4262 {// calculate activatedP
4263 activatedByClick = true;
4264 QPoint topLeft = itemRect(i).topLeft(); //### inefficient?
4265 activatedP = vp - topLeft;
4266 int xdepth = treeStepSize() * (i->depth() + (rootIsDecorated() ? 1 : 0))
4267 + itemMargin();
4268 xdepth += d->h->sectionPos(d->h->mapToSection(0));
4269 activatedP.rx() -= xdepth;
4270 }
4271 i->activate();
4272 activatedByClick = false;
4273
4274 if (i != d->focusItem)
4275 setCurrentItem(i);
4276 else
4277 repaintItem(i);
4278
4279 d->pressedSelected = i && i->isSelected();
4280
4281 if (i->isSelectable() && selectionMode() != NoSelection) {
4282 if (selectionMode() == Single)
4283 setSelected(i, true);
4284 else if (selectionMode() == Multi)
4285 setSelected(i, d->select);
4286 else if (selectionMode() == Extended) {
4287 bool changed = false;
4288 if (!(e->state() & (Qt::ControlButton | Qt::ShiftButton))) {
4289 if (!i->isSelected()) {
4290 bool blocked = signalsBlocked();
4291 blockSignals(true);
4292 clearSelection();
4293 blockSignals(blocked);
4294 i->setSelected(true);
4295 changed = true;
4296 }
4297 } else {
4298 if (e->state() & Qt::ShiftButton)
4299 d->pressedSelected = false;
4300 if ((e->state() & Qt::ControlButton) && !(e->state() & Qt::ShiftButton) && i) {
4301 i->setSelected(!i->isSelected());
4302 changed = true;
4303 d->pressedSelected = false;
4304 } else if (!oldCurrent || !i || oldCurrent == i) {
4305 if ((bool)i->selected != d->select) {
4306 changed = true;
4307 i->setSelected(d->select);
4308 }
4309 // Shift pressed in Extended mode ---
4310 } else {
4311 changed = selectRange(i, oldCurrent, d->selectAnchor);
4312 }
4313 }
4314 if (changed) {
4315 triggerUpdate();
4316 emit selectionChanged();
4317
4318 #ifndef QT_NO_ACCESSIBILITY
4319 QAccessible::updateAccessibility(viewport(), 0, QAccessible::Selection);
4320 #endif
4321 }
4322 }
4323 }
4324
4325 emit_signals:
4326
4327 if (i && !d->buttonDown &&
4328 vp.x() + contentsX() < itemMargin() + (i->depth() + (rootIsDecorated() ? 1 : 0)) * treeStepSize())
4329 i = 0;
4330 d->pressedItem = i;
4331
4332 int c = i ? d->h->mapToLogical(d->h->cellAt(vp.x())) : -1;
4333 if (!i || (i && i->isEnabled())) {
4334 emit pressed(i);
4335 emit pressed(i, viewport()->mapToGlobal(vp), c);
4336 }
4337 emit mouseButtonPressed(e->button(), i, viewport()->mapToGlobal(vp), c);
4338
4339 if (e->button() == Qt::RightButton && i == d->pressedItem) {
4340 if (!i && !(e->state() & Qt::ControlButton))
4341 clearSelection();
4342
4343 emit rightButtonPressed(i, viewport()->mapToGlobal(vp), c);
4344 }
4345 }
4346
4347 /*!
4348 \reimp
4349 */
4350
contentsContextMenuEvent(QContextMenuEvent * e)4351 void Q3ListView::contentsContextMenuEvent(QContextMenuEvent *e)
4352 {
4353 if (!receivers(SIGNAL(contextMenuRequested(Q3ListViewItem*,QPoint,int)))) {
4354 e->ignore();
4355 return;
4356 }
4357 if (e->reason() == QContextMenuEvent::Keyboard) {
4358 Q3ListViewItem *item = currentItem();
4359 if (item) {
4360 QRect r = itemRect(item);
4361 QPoint p = r.topLeft();
4362 if (allColumnsShowFocus())
4363 p += QPoint(width() / 2, (r.height() / 2));
4364 else
4365 p += QPoint(columnWidth(0) / 2, (r.height() / 2));
4366 p.rx() = qMax(0, p.x());
4367 p.rx() = qMin(visibleWidth(), p.x());
4368 emit contextMenuRequested(item, viewport()->mapToGlobal(p), -1);
4369 }
4370 } else {
4371 QPoint vp = contentsToViewport(e->pos());
4372 Q3ListViewItem * i = itemAt(vp);
4373 int c = i ? d->h->mapToLogical(d->h->cellAt(vp.x())) : -1;
4374 emit contextMenuRequested(i, viewport()->mapToGlobal(vp), c);
4375 }
4376 }
4377
4378 /*!
4379 Processes the mouse release event \a e on behalf of the viewed widget.
4380 */
contentsMouseReleaseEvent(QMouseEvent * e)4381 void Q3ListView::contentsMouseReleaseEvent(QMouseEvent * e)
4382 {
4383 contentsMouseReleaseEventEx(e);
4384 }
4385
contentsMouseReleaseEventEx(QMouseEvent * e)4386 void Q3ListView::contentsMouseReleaseEventEx(QMouseEvent * e)
4387 {
4388 d->startDragItem = 0;
4389 bool emitClicked = !d->pressedItem || d->buttonDown;
4390 d->buttonDown = false;
4391 // delete and disconnect autoscroll timer, if we have one
4392 if (d->scrollTimer) {
4393 disconnect(d->scrollTimer, SIGNAL(timeout()),
4394 this, SLOT(doAutoScroll()));
4395 d->scrollTimer->stop();
4396 delete d->scrollTimer;
4397 d->scrollTimer = 0;
4398 }
4399
4400 if (!e)
4401 return;
4402
4403 if (d->selectionMode == Extended &&
4404 d->focusItem == d->pressedItem &&
4405 d->pressedSelected && d->focusItem &&
4406 e->button() == Qt::LeftButton) {
4407 bool block = signalsBlocked();
4408 blockSignals(true);
4409 clearSelection();
4410 blockSignals(block);
4411 d->focusItem->setSelected(true);
4412 emit selectionChanged();
4413 #ifndef QT_NO_ACCESSIBILITY
4414 QAccessible::updateAccessibility(viewport(), 0, QAccessible::Selection);
4415 #endif
4416 }
4417
4418 QPoint vp = contentsToViewport(e->pos());
4419 Q3ListViewItem *i = itemAt(vp);
4420 if (i && !i->isEnabled())
4421 return;
4422
4423 if (i && i == d->pressedItem && (i->isExpandable() || i->childCount()) &&
4424 !d->h->mapToLogical(d->h->cellAt(vp.x())) && e->button() == Qt::LeftButton &&
4425 e->type() == style()->styleHint(QStyle::SH_Q3ListViewExpand_SelectMouseType, 0, this)) {
4426 int draw = 0;
4427 for (; draw < d->drawables.size(); ++draw)
4428 if (d->drawables.at(draw).i == i)
4429 break;
4430 if (draw < d->drawables.size()) {
4431 int x1 = vp.x() + d->h->offset() - d->h->cellPos(d->h->mapToActual(0)) -
4432 (treeStepSize() * (d->drawables.at(draw).l - 1));
4433 QStyleOptionQ3ListView opt = getStyleOption(this, i);
4434 QStyle::SubControl ctrl = style()->hitTestComplexControl(QStyle::CC_Q3ListView, &opt,
4435 QPoint(x1, e->pos().y()), this);
4436 if (ctrl == QStyle::SC_Q3ListViewExpand) {
4437 bool close = i->isOpen();
4438 setOpen(i, !close);
4439 // ### Looks dangerous, removed because of reentrance problems
4440 // qApp->processEvents();
4441 if (!d->focusItem) {
4442 d->focusItem = i;
4443 repaintItem(d->focusItem);
4444 emit currentChanged(d->focusItem);
4445 }
4446 if (close) {
4447 bool newCurrent = false;
4448 Q3ListViewItem *ci = d->focusItem;
4449 while (ci) {
4450 if (ci->parent() && ci->parent() == i) {
4451 newCurrent = true;
4452 break;
4453 }
4454 ci = ci->parent();
4455 }
4456 if (newCurrent)
4457 setCurrentItem(i);
4458 d->ignoreDoubleClick = true;
4459 }
4460 }
4461 }
4462 }
4463
4464 if (i == d->pressedItem && i && i->isSelected() && e->button() == Qt::LeftButton && d->startEdit) {
4465 QRect r = itemRect(currentItem());
4466 r = QRect(viewportToContents(r.topLeft()), r.size());
4467 d->pressedColumn = header()->sectionAt( e->pos().x());
4468 r.setLeft(header()->sectionPos(d->pressedColumn));
4469 r.setWidth(header()->sectionSize(d->pressedColumn) - 1);
4470 if (d->pressedColumn == 0)
4471 r.setLeft(r.left() + itemMargin() + (currentItem()->depth() +
4472 (rootIsDecorated() ? 1 : 0)) * treeStepSize() - 1);
4473 if (r.contains(e->pos()) &&
4474 !(e->state() & (Qt::ShiftButton | Qt::ControlButton)))
4475 d->renameTimer->start(QApplication::doubleClickInterval(), true);
4476 }
4477 if (i && vp.x() + contentsX() < itemMargin() + (i->depth() + (rootIsDecorated() ? 1 : 0)) * treeStepSize())
4478 i = 0;
4479 emitClicked = emitClicked && d->pressedItem == i;
4480 d->pressedItem = 0;
4481
4482 if (emitClicked) {
4483 if (!i || (i && i->isEnabled())) {
4484 emit clicked(i);
4485 emit clicked(i, viewport()->mapToGlobal(vp), d->h->mapToLogical(d->h->cellAt(vp.x())));
4486 }
4487 emit mouseButtonClicked(e->button(), i, viewport()->mapToGlobal(vp),
4488 i ? d->h->mapToLogical(d->h->cellAt(vp.x())) : -1);
4489
4490 if (e->button() == Qt::RightButton) {
4491 if (!i) {
4492 if (!(e->state() & Qt::ControlButton))
4493 clearSelection();
4494 emit rightButtonClicked(0, viewport()->mapToGlobal(vp), -1);
4495 return;
4496 }
4497
4498 int c = d->h->mapToLogical(d->h->cellAt(vp.x()));
4499 emit rightButtonClicked(i, viewport()->mapToGlobal(vp), c);
4500 }
4501 }
4502 }
4503
4504
4505 /*!
4506 Processes the mouse double-click event \a e on behalf of the viewed widget.
4507 */
contentsMouseDoubleClickEvent(QMouseEvent * e)4508 void Q3ListView::contentsMouseDoubleClickEvent(QMouseEvent * e)
4509 {
4510 d->renameTimer->stop();
4511 d->startEdit = false;
4512 if (!e || e->button() != Qt::LeftButton)
4513 return;
4514
4515 // ensure that the following mouse moves and eventual release is
4516 // ignored.
4517 d->buttonDown = false;
4518
4519 if (d->ignoreDoubleClick) {
4520 d->ignoreDoubleClick = false;
4521 return;
4522 }
4523
4524 QPoint vp = contentsToViewport(e->pos());
4525
4526 Q3ListViewItem * i = itemAt(vp);
4527
4528 // we emit doubleClicked when the item is null (or enabled) to be consistent with
4529 // rightButtonClicked etc.
4530 if (!i || i->isEnabled()) {
4531 int c = d->h->mapToLogical(d->h->cellAt(vp.x()));
4532 emit doubleClicked(i, viewport()->mapToGlobal(vp), c);
4533 }
4534
4535 if (!i || !i->isEnabled())
4536 return;
4537
4538 if (!i->isOpen()) {
4539 if (i->isExpandable() || i->childCount())
4540 setOpen(i, true);
4541 } else {
4542 setOpen(i, false);
4543 }
4544
4545 // we emit the 'old' obsolete doubleClicked only if the item is not null and enabled
4546 emit doubleClicked(i);
4547 }
4548
4549
4550 /*!
4551 Processes the mouse move event \a e on behalf of the viewed widget.
4552 */
contentsMouseMoveEvent(QMouseEvent * e)4553 void Q3ListView::contentsMouseMoveEvent(QMouseEvent * e)
4554 {
4555 if (!e)
4556 return;
4557
4558 bool needAutoScroll = false;
4559
4560 QPoint vp = contentsToViewport(e->pos());
4561
4562 Q3ListViewItem * i = itemAt(vp);
4563 if (i && !i->isEnabled())
4564 return;
4565 if (i != d->highlighted &&
4566 !(d->pressedItem &&
4567 (d->pressedItem->isSelected() || d->selectionMode == NoSelection) &&
4568 d->pressedItem->dragEnabled())) {
4569
4570 if (i) {
4571 emit onItem(i);
4572 } else {
4573 emit onViewport();
4574 }
4575 d->highlighted = i;
4576 }
4577
4578 if (d->startDragItem)
4579 i = d->startDragItem;
4580
4581 if (!d->buttonDown ||
4582 ((e->state() & Qt::LeftButton) != Qt::LeftButton &&
4583 (e->state() & Qt::MidButton) != Qt::MidButton &&
4584 (e->state() & Qt::RightButton) != Qt::RightButton))
4585 return;
4586
4587 if (d->pressedItem &&
4588 (d->pressedItem->isSelected() || d->selectionMode == NoSelection) &&
4589 d->pressedItem->dragEnabled()) {
4590
4591 if (!d->startDragItem) {
4592 setSelected(d->pressedItem, true);
4593 d->startDragItem = d->pressedItem;
4594 }
4595 if ((d->dragStartPos - e->pos()).manhattanLength() > QApplication::startDragDistance()) {
4596 d->buttonDown = false;
4597 #ifndef QT_NO_DRAGANDDROP
4598 startDrag();
4599 #endif
4600 }
4601 return;
4602 }
4603
4604 // check, if we need to scroll
4605 if (vp.y() > visibleHeight() || vp.y() < 0)
4606 needAutoScroll = true;
4607
4608 // if we need to scroll and no autoscroll timer is started,
4609 // connect the timer
4610 if (needAutoScroll && !d->scrollTimer) {
4611 d->scrollTimer = new QTimer(this);
4612 connect(d->scrollTimer, SIGNAL(timeout()),
4613 this, SLOT(doAutoScroll()));
4614 d->scrollTimer->start(100, false);
4615 // call it once manually
4616 doAutoScroll(vp);
4617 }
4618
4619 // if we don't need to autoscroll
4620 if (!needAutoScroll) {
4621 // if there is a autoscroll timer, delete it
4622 if (d->scrollTimer) {
4623 disconnect(d->scrollTimer, SIGNAL(timeout()),
4624 this, SLOT(doAutoScroll()));
4625 d->scrollTimer->stop();
4626 delete d->scrollTimer;
4627 d->scrollTimer = 0;
4628 }
4629 // call this to select an item (using the pos from the event)
4630 doAutoScroll(vp);
4631 }
4632 }
4633
4634
4635 /*!
4636 This slot handles auto-scrolling when the mouse button is pressed
4637 and the mouse is outside the widget.
4638 */
doAutoScroll()4639 void Q3ListView::doAutoScroll()
4640 {
4641 doAutoScroll(QPoint());
4642 }
4643
4644 /*
4645 Handles auto-scrolling when the mouse button is pressed
4646 and the mouse is outside the widget.
4647
4648 If cursorPos is (0,0) (isNull == true) it uses the current QCursor::pos, otherwise it uses cursorPos
4649 */
doAutoScroll(const QPoint & cursorPos)4650 void Q3ListView::doAutoScroll(const QPoint &cursorPos)
4651 {
4652 QPoint pos = cursorPos.isNull() ? viewport()->mapFromGlobal(QCursor::pos()) : cursorPos;
4653 if (!d->focusItem || (d->pressedEmptyArea && pos.y() > contentsHeight()))
4654 return;
4655
4656 bool down = pos.y() > itemRect(d->focusItem).y();
4657
4658 int g = pos.y() + contentsY();
4659
4660 if (down && pos.y() > height() )
4661 g = height() + contentsY();
4662 else if (pos.y() < 0)
4663 g = contentsY();
4664
4665 Q3ListViewItem *c = d->focusItem, *old = 0;
4666 Q3ListViewItem *oldCurrent = c;
4667 if (down) {
4668 int y = itemRect(d->focusItem).y() + contentsY();
4669 while(c && y + c->height() <= g) {
4670 y += c->height();
4671 old = c;
4672 c = c->itemBelow();
4673 }
4674 if (!c && old)
4675 c = old;
4676 } else {
4677 int y = itemRect(d->focusItem).y() + contentsY();
4678 while(c && y >= g) {
4679 old = c;
4680 c = c->itemAbove();
4681 if (c)
4682 y -= c->height();
4683 }
4684 if (!c && old)
4685 c = old;
4686 }
4687
4688 if (!c || c == d->focusItem)
4689 return;
4690
4691 if (d->focusItem) {
4692 if (d->selectionMode == Multi) {
4693 // also (de)select the ones in between
4694 Q3ListViewItem * b = d->focusItem;
4695 bool down = (itemPos(c) > itemPos(b));
4696 while(b && b != c) {
4697 if (b->isSelectable())
4698 setSelected(b, d->select);
4699 b = down ? b->itemBelow() : b->itemAbove();
4700 }
4701 if (c->isSelectable())
4702 setSelected(c, d->select);
4703 } else if (d->selectionMode == Extended) {
4704 if (selectRange(c, oldCurrent, d->selectAnchor)) {
4705 triggerUpdate();
4706 emit selectionChanged();
4707 }
4708 }
4709 }
4710
4711 setCurrentItem(c);
4712 d->visibleTimer->start(1, true);
4713 }
4714
4715 /*!
4716 \reimp
4717 */
4718
focusInEvent(QFocusEvent * e)4719 void Q3ListView::focusInEvent(QFocusEvent *e)
4720 {
4721 d->inMenuMode = false;
4722 if (d->focusItem) {
4723 repaintItem(d->focusItem);
4724 } else if (firstChild() && e->reason() != Qt::MouseFocusReason) {
4725 d->focusItem = firstChild();
4726 emit currentChanged(d->focusItem);
4727 repaintItem(d->focusItem);
4728 }
4729 if (e->reason() == Qt::MouseFocusReason) {
4730 d->ignoreEditAfterFocus = true;
4731 d->startEdit = false;
4732 }
4733 if (style()->styleHint(QStyle::SH_ItemView_ChangeHighlightOnFocus, 0, this)) {
4734 viewport()->repaint();
4735 }
4736 }
4737
4738 /*!
4739 \reimp
4740 */
inputMethodQuery(Qt::InputMethodQuery query) const4741 QVariant Q3ListView::inputMethodQuery(Qt::InputMethodQuery query) const
4742 {
4743 if (query == Qt::ImMicroFocus) {
4744 QRect mfrect = itemRect(d->focusItem);
4745 if (mfrect.isValid() && header() && header()->isVisible())
4746 mfrect.moveBy(0, header()->height());
4747 return mfrect;
4748 }
4749 return QWidget::inputMethodQuery(query);
4750 }
4751
4752 /*!
4753 \reimp
4754 */
4755
focusOutEvent(QFocusEvent * e)4756 void Q3ListView::focusOutEvent(QFocusEvent *e)
4757 {
4758 if (e->reason() == Qt::PopupFocusReason && d->buttonDown)
4759 d->buttonDown = false;
4760 if (style()->styleHint(QStyle::SH_ItemView_ChangeHighlightOnFocus, 0, this)) {
4761 d->inMenuMode =
4762 e->reason() == Qt::PopupFocusReason
4763 || (qApp->focusWidget() && qApp->focusWidget()->inherits("QMenuBar"));
4764 if (!d->inMenuMode) {
4765 viewport()->repaint();
4766 }
4767 }
4768
4769 if (d->focusItem)
4770 repaintItem(d->focusItem);
4771 }
4772
4773
4774 /*!
4775 \reimp
4776 */
4777
keyPressEvent(QKeyEvent * e)4778 void Q3ListView::keyPressEvent(QKeyEvent * e)
4779 {
4780 if (currentItem() && currentItem()->renameBox)
4781 return;
4782 if (!firstChild()) {
4783 e->ignore();
4784 return; // subclass bug
4785 }
4786
4787 Q3ListViewItem* oldCurrent = currentItem();
4788 if (!oldCurrent) {
4789 setCurrentItem(firstChild());
4790 if (d->selectionMode == Single)
4791 setSelected(firstChild(), true);
4792 return;
4793 }
4794
4795 Q3ListViewItem * i = currentItem();
4796 Q3ListViewItem *old = i;
4797
4798 QRect r(itemRect(i));
4799 Q3ListViewItem * i2;
4800
4801 bool singleStep = false;
4802 bool selectCurrent = true;
4803 bool wasNavigation = true;
4804
4805 switch(e->key()) {
4806 case Qt::Key_Backspace:
4807 case Qt::Key_Delete:
4808 d->currentPrefix.truncate(0);
4809 break;
4810 case Qt::Key_Enter:
4811 case Qt::Key_Return:
4812 d->currentPrefix.truncate(0);
4813 if (i && !i->isSelectable() && i->isEnabled() &&
4814 (i->childCount() || i->isExpandable() || i->isOpen())) {
4815 i->setOpen(!i->isOpen());
4816 return;
4817 }
4818 e->ignore();
4819 if (currentItem() && !currentItem()->isEnabled())
4820 break;
4821 emit returnPressed(currentItem());
4822 // do NOT accept. QDialog.
4823 return;
4824 case Qt::Key_Down:
4825 selectCurrent = false;
4826 i = i->itemBelow();
4827 d->currentPrefix.truncate(0);
4828 singleStep = true;
4829 break;
4830 case Qt::Key_Up:
4831 selectCurrent = false;
4832 i = i->itemAbove();
4833 d->currentPrefix.truncate(0);
4834 singleStep = true;
4835 break;
4836 case Qt::Key_Home:
4837 selectCurrent = false;
4838 i = firstChild();
4839 if (!i->height() || !i->isEnabled())
4840 i = i->itemBelow();
4841 d->currentPrefix.truncate(0);
4842 break;
4843 case Qt::Key_End:
4844 selectCurrent = false;
4845 i = firstChild();
4846 while (i->nextSibling() && i->nextSibling()->height() && i->nextSibling()->isEnabled())
4847 i = i->nextSibling();
4848 while (i->itemBelow())
4849 i = i->itemBelow();
4850 d->currentPrefix.truncate(0);
4851 break;
4852 case Qt::Key_Next:
4853 selectCurrent = false;
4854 i2 = itemAt(QPoint(0, visibleHeight()-1));
4855 if (i2 == i || !r.isValid() ||
4856 visibleHeight() <= itemRect(i).bottom()) {
4857 if (i2)
4858 i = i2;
4859 int left = visibleHeight();
4860 while((i2 = i->itemBelow()) != 0 && left > i2->height()) {
4861 left -= i2->height();
4862 i = i2;
4863 }
4864 } else {
4865 if (!i2) {
4866 // list is shorter than the view, goto last item
4867 while((i2 = i->itemBelow()) != 0)
4868 i = i2;
4869 } else {
4870 i = i2;
4871 }
4872 }
4873 d->currentPrefix.truncate(0);
4874 break;
4875 case Qt::Key_Prior:
4876 selectCurrent = false;
4877 i2 = itemAt(QPoint(0, 0));
4878 if (i == i2 || !r.isValid() || r.top() <= 0) {
4879 if (i2)
4880 i = i2;
4881 int left = visibleHeight();
4882 while((i2 = i->itemAbove()) != 0 && left > i2->height()) {
4883 left -= i2->height();
4884 i = i2;
4885 }
4886 } else {
4887 i = i2;
4888 }
4889 d->currentPrefix.truncate(0);
4890 break;
4891 case Qt::Key_Plus:
4892 d->currentPrefix.truncate(0);
4893 if ( !i->isOpen() && (i->isExpandable() || i->childCount()))
4894 setOpen(i, true);
4895 else
4896 return;
4897 break;
4898 case Qt::Key_Right:
4899 d->currentPrefix.truncate(0);
4900 if (i->isOpen() && i->childItem) {
4901 i = i->childItem;
4902 } else if (!i->isOpen() && (i->isExpandable() || i->childCount())) {
4903 setOpen(i, true);
4904 } else if (contentsX() + visibleWidth() < contentsWidth()) {
4905 horizontalScrollBar()->triggerAction(QScrollBar::SliderSingleStepAdd);
4906 return;
4907 } else {
4908 return;
4909 }
4910 break;
4911 case Qt::Key_Minus:
4912 d->currentPrefix.truncate(0);
4913 if (i->isOpen())
4914 setOpen(i, false);
4915 else
4916 return;
4917 break;
4918 case Qt::Key_Left:
4919 d->currentPrefix.truncate(0);
4920 if (i->isOpen()) {
4921 setOpen(i, false);
4922 } else if (i->parentItem && i->parentItem != d->r) {
4923 i = i->parentItem;
4924 } else if (contentsX()) {
4925 horizontalScrollBar()->triggerAction(QScrollBar::SliderSingleStepSub);
4926 return;
4927 } else {
4928 return;
4929 }
4930 break;
4931 case Qt::Key_Space:
4932 activatedByClick = false;
4933 d->currentPrefix.truncate(0);
4934 if (currentItem() && !currentItem()->isEnabled())
4935 break;
4936 i->activate();
4937 if (i->isSelectable() && (d->selectionMode == Multi || d->selectionMode == Extended)) {
4938 setSelected(i, !i->isSelected());
4939 d->currentPrefix.truncate(0);
4940 }
4941 emit spacePressed(currentItem());
4942 break;
4943 case Qt::Key_Escape:
4944 e->ignore(); // For QDialog
4945 return;
4946 case Qt::Key_F2:
4947 if (currentItem() && currentItem()->renameEnabled(0))
4948 currentItem()->startRename(0);
4949 default:
4950 if (e->text().length() > 0 && e->text()[0].isPrint()) {
4951 selectCurrent = false;
4952 wasNavigation = false;
4953 QString input(d->currentPrefix);
4954 Q3ListViewItem * keyItem = i;
4955 QTime now(QTime::currentTime());
4956 bool tryFirst = true;
4957 while(keyItem) {
4958 // try twice, first with the previous string and this char
4959 if (d->currentPrefixTime.msecsTo(now) <= 400)
4960 input = input + e->text().toLower();
4961 else
4962 input = e->text().toLower();
4963 if (input.length() == e->text().length()) {
4964 if (keyItem->itemBelow()) {
4965 keyItem = keyItem->itemBelow();
4966 tryFirst = true;
4967 } else {
4968 keyItem = firstChild();
4969 tryFirst = false;
4970 }
4971 }
4972 QString keyItemKey;
4973 QString prefix;
4974 while(keyItem) {
4975 keyItemKey = QString::null;
4976 // Look first in the sort column, then left to right
4977 if (d->sortcolumn != Unsorted)
4978 keyItemKey = keyItem->text(d->sortcolumn);
4979 for (int col = 0; col < d->h->count() && keyItemKey.isNull(); ++col)
4980 keyItemKey = keyItem->text(d->h->mapToSection(col));
4981 if (!keyItemKey.isEmpty()) {
4982 prefix = keyItemKey;
4983 prefix.truncate(input.length());
4984 prefix = prefix.toLower();
4985 if (prefix == input) {
4986 d->currentPrefix = input;
4987 d->currentPrefixTime = now;
4988 i = keyItem;
4989 // nonoptimal double-break...
4990 keyItem = 0;
4991 input.truncate(0);
4992 tryFirst = false;
4993 }
4994 }
4995 if (keyItem)
4996 keyItem = keyItem->itemBelow();
4997 if (!keyItem && tryFirst) {
4998 keyItem = firstChild();
4999 tryFirst = false;
5000 }
5001 }
5002 // then, if appropriate, with just this character
5003 if (input.length() > e->text().length()) {
5004 input.truncate(0);
5005 keyItem = i;
5006 }
5007 }
5008 } else {
5009 d->currentPrefix.truncate(0);
5010 if (e->state() & Qt::ControlButton) {
5011 d->currentPrefix.clear();
5012 switch (e->key()) {
5013 case Qt::Key_A:
5014 selectAll(true);
5015 break;
5016 }
5017 }
5018 e->ignore();
5019 return;
5020 }
5021 }
5022
5023 if (!i)
5024 return;
5025
5026 if (!(e->state() & Qt::ShiftButton) || !d->selectAnchor)
5027 d->selectAnchor = i;
5028
5029 setCurrentItem(i);
5030 if (i->isSelectable())
5031 handleItemChange(old, wasNavigation && (e->state() & Qt::ShiftButton),
5032 wasNavigation && (e->state() & Qt::ControlButton));
5033
5034 if (d->focusItem && !d->focusItem->isSelected() && d->selectionMode == Single && selectCurrent)
5035 setSelected(d->focusItem, true);
5036
5037 if (singleStep)
5038 d->visibleTimer->start(1, true);
5039 else
5040 ensureItemVisible(i);
5041 }
5042
5043
5044 /*!
5045 Returns the list view item at \a viewPos. Note that \a viewPos is
5046 in the viewport()'s coordinate system, not in the list view's own,
5047 much larger, coordinate system.
5048
5049 itemAt() returns 0 if there is no such item.
5050
5051 Note that you also get the pointer to the item if \a viewPos
5052 points to the root decoration (see setRootIsDecorated()) of the
5053 item. To check whether or not \a viewPos is on the root decoration
5054 of the item, you can do something like this:
5055
5056 \snippet doc/src/snippets/code/src_qt3support_itemviews_q3listview.cpp 4
5057
5058 This might be interesting if you use this function to find out
5059 where the user clicked and if you want to start a drag (which you
5060 do not want to do if the user clicked onto the root decoration of
5061 an item).
5062
5063 \sa itemPos() itemRect() viewportToContents()
5064 */
5065
itemAt(const QPoint & viewPos) const5066 Q3ListViewItem * Q3ListView::itemAt(const QPoint & viewPos) const
5067 {
5068 if (viewPos.x() > contentsWidth() - contentsX())
5069 return 0;
5070
5071 if (d->drawables.isEmpty())
5072 buildDrawableList();
5073
5074 int g = viewPos.y() + contentsY();
5075
5076 for (int i = 0; i < d->drawables.size(); ++i) {
5077 Q3ListViewPrivate::DrawableItem c = d->drawables.at(i);
5078 if (c.y + c.i->height() > g
5079 && c.i->isVisible() && (!c.i->parent() || c.i->parent()->isVisible()))
5080 return c.y <= g ? c.i : 0;
5081 }
5082 return 0;
5083 }
5084
5085
5086 /*!
5087 Returns the y-coordinate of \a item in the list view's coordinate
5088 system. This function is normally much slower than itemAt() but it
5089 works for all items, whereas itemAt() normally works only for
5090 items on the screen.
5091
5092 This is a thin wrapper around Q3ListViewItem::itemPos().
5093
5094 \sa itemAt() itemRect()
5095 */
5096
itemPos(const Q3ListViewItem * item)5097 int Q3ListView::itemPos(const Q3ListViewItem * item)
5098 {
5099 return item ? item->itemPos() : 0;
5100 }
5101
5102
5103 /*!
5104 \property Q3ListView::multiSelection
5105 \brief whether the list view is in multi-selection or extended-selection mode
5106
5107 If you enable multi-selection, \c Multi, mode, it is possible to
5108 specify whether or not this mode should be extended. \c Extended
5109 means that the user can select multiple items only when pressing
5110 the Shift or Ctrl key at the same time.
5111
5112 The default selection mode is \c Single.
5113
5114 \sa selectionMode()
5115 */
5116
setMultiSelection(bool enable)5117 void Q3ListView::setMultiSelection(bool enable)
5118 {
5119 if (!enable)
5120 d->selectionMode = Q3ListView::Single;
5121 else if ( d->selectionMode != Multi && d->selectionMode != Extended)
5122 d->selectionMode = Q3ListView::Multi;
5123 }
5124
isMultiSelection() const5125 bool Q3ListView::isMultiSelection() const
5126 {
5127 return d->selectionMode == Q3ListView::Extended || d->selectionMode == Q3ListView::Multi;
5128 }
5129
5130 /*!
5131 \property Q3ListView::selectionMode
5132 \brief the list view's selection mode
5133
5134 The mode can be \c Single (the default), \c Extended, \c Multi or
5135 \c NoSelection.
5136
5137 \sa multiSelection
5138 */
5139
setSelectionMode(SelectionMode mode)5140 void Q3ListView::setSelectionMode(SelectionMode mode)
5141 {
5142 if (d->selectionMode == mode)
5143 return;
5144
5145 if ((d->selectionMode == Multi || d->selectionMode == Extended) &&
5146 (mode == Q3ListView::Single || mode == Q3ListView::NoSelection)){
5147 clearSelection();
5148 if ((mode == Q3ListView::Single) && currentItem())
5149 currentItem()->selected = true;
5150 }
5151
5152 d->selectionMode = mode;
5153 }
5154
selectionMode() const5155 Q3ListView::SelectionMode Q3ListView::selectionMode() const
5156 {
5157 return d->selectionMode;
5158 }
5159
5160
5161 /*!
5162 If \a selected is true the \a item is selected; otherwise it is
5163 unselected.
5164
5165 If the list view is in \c Single selection mode and \a selected is
5166 true, the currently selected item is unselected and \a item is
5167 made current. Unlike Q3ListViewItem::setSelected(), this function
5168 updates the list view as necessary and emits the
5169 selectionChanged() signals.
5170
5171 \sa isSelected() setMultiSelection() isMultiSelection()
5172 setCurrentItem(), setSelectionAnchor()
5173 */
5174
setSelected(Q3ListViewItem * item,bool selected)5175 void Q3ListView::setSelected(Q3ListViewItem * item, bool selected)
5176 {
5177 if (!item || item->isSelected() == selected ||
5178 !item->isSelectable() || selectionMode() == NoSelection)
5179 return;
5180
5181 bool emitHighlighted = false;
5182 if (selectionMode() == Single && d->focusItem != item) {
5183 Q3ListViewItem *o = d->focusItem;
5184 if (d->focusItem && d->focusItem->selected)
5185 d->focusItem->setSelected(false);
5186 d->focusItem = item;
5187 if (o)
5188 repaintItem(o);
5189 emitHighlighted = true;
5190 }
5191
5192 item->setSelected(selected);
5193
5194 repaintItem(item);
5195
5196 if (d->selectionMode == Single && selected)
5197 emit selectionChanged(item);
5198 emit selectionChanged();
5199
5200 if (emitHighlighted)
5201 emit currentChanged(d->focusItem);
5202 }
5203
5204 /*!
5205 Sets the selection anchor to \a item, if \a item is selectable.
5206
5207 The selection anchor is the item that remains selected when
5208 Shift-selecting with either mouse or keyboard in \c Extended
5209 selection mode.
5210
5211 \sa setSelected()
5212 */
5213
setSelectionAnchor(Q3ListViewItem * item)5214 void Q3ListView::setSelectionAnchor(Q3ListViewItem *item)
5215 {
5216 if (item && item->isSelectable())
5217 d->selectAnchor = item;
5218 }
5219
5220 /*!
5221 Sets all the items to be not selected, updates the list view as
5222 necessary, and emits the selectionChanged() signals. Note that for
5223 \c Multi selection list views this function needs to iterate over
5224 \e all items.
5225
5226 \sa setSelected(), setMultiSelection()
5227 */
5228
clearSelection()5229 void Q3ListView::clearSelection()
5230 {
5231 selectAll(false);
5232 }
5233
5234 /*!
5235 If \a select is true, all the items get selected; otherwise all
5236 the items get unselected. This only works in the selection modes \c
5237 Multi and \c Extended. In \c Single and \c NoSelection mode the
5238 selection of the current item is just set to \a select.
5239 */
5240
selectAll(bool select)5241 void Q3ListView::selectAll(bool select)
5242 {
5243 if (d->selectionMode == Multi || d->selectionMode == Extended) {
5244 bool b = signalsBlocked();
5245 blockSignals(true);
5246 bool anything = false;
5247 Q3ListViewItemIterator it(this);
5248 while (it.current()) {
5249 Q3ListViewItem *i = it.current();
5250 if ((bool)i->selected != select) {
5251 i->setSelected(select);
5252 anything = true;
5253 }
5254 ++it;
5255 }
5256 blockSignals(b);
5257 if (anything) {
5258 emit selectionChanged();
5259 triggerUpdate();
5260 }
5261 } else if (d->focusItem) {
5262 Q3ListViewItem * i = d->focusItem;
5263 setSelected(i, select);
5264 }
5265 }
5266
5267 /*!
5268 Inverts the selection. Only works in \c Multi and \c Extended
5269 selection modes.
5270 */
5271
invertSelection()5272 void Q3ListView::invertSelection()
5273 {
5274 if (d->selectionMode == Single ||
5275 d->selectionMode == NoSelection)
5276 return;
5277
5278 bool b = signalsBlocked();
5279 blockSignals(true);
5280 Q3ListViewItemIterator it(this);
5281 for (; it.current(); ++it)
5282 it.current()->setSelected(!it.current()->isSelected());
5283 blockSignals(b);
5284 emit selectionChanged();
5285 triggerUpdate();
5286 }
5287
5288
5289 /*!
5290 Returns true if the list view item \a i is selected; otherwise
5291 returns false.
5292
5293 \sa Q3ListViewItem::isSelected()
5294 */
5295
isSelected(const Q3ListViewItem * i) const5296 bool Q3ListView::isSelected(const Q3ListViewItem * i) const
5297 {
5298 return i ? i->isSelected() : false;
5299 }
5300
5301
5302 /*!
5303 Returns the selected item if the list view is in \c Single
5304 selection mode and an item is selected.
5305
5306 If no items are selected or the list view is not in \c Single
5307 selection mode this function returns 0.
5308
5309 \sa setSelected() setMultiSelection()
5310 */
5311
selectedItem() const5312 Q3ListViewItem * Q3ListView::selectedItem() const
5313 {
5314 if (d->selectionMode != Single)
5315 return 0;
5316 if (d->focusItem && d->focusItem->isSelected())
5317 return d->focusItem;
5318 return 0;
5319 }
5320
5321
5322 /*!
5323 Sets item \a i to be the current item and repaints appropriately
5324 (i.e. highlights the item). The current item is used for keyboard
5325 navigation and focus indication; it is independent of any selected
5326 items, although a selected item can also be the current item.
5327
5328 \sa currentItem() setSelected()
5329 */
5330
setCurrentItem(Q3ListViewItem * i)5331 void Q3ListView::setCurrentItem(Q3ListViewItem * i)
5332 {
5333 if (!i || d->focusItem == i || !i->isEnabled())
5334 return;
5335
5336 if (currentItem() && currentItem()->renameBox) {
5337 if (d->defRenameAction == Reject)
5338 currentItem()->cancelRename(currentItem()->renameCol);
5339 else
5340 currentItem()->okRename(currentItem()->renameCol);
5341 }
5342
5343 Q3ListViewItem * prev = d->focusItem;
5344 d->focusItem = i;
5345
5346 if (i != prev) {
5347 if (i && d->selectionMode == Single) {
5348 bool changed = false;
5349 if (prev && prev->selected) {
5350 changed = true;
5351 prev->setSelected(false);
5352 }
5353 if (i && !i->selected && d->selectionMode != NoSelection && i->isSelectable()) {
5354 i->setSelected(true);
5355 changed = true;
5356 emit selectionChanged(i);
5357 }
5358 if (changed)
5359 emit selectionChanged();
5360 }
5361
5362 if (i)
5363 repaintItem(i);
5364 if (prev)
5365 repaintItem(prev);
5366 emit currentChanged(i);
5367
5368 #ifndef QT_NO_ACCESSIBILITY
5369 QAccessible::updateAccessibility(viewport(), indexOfItem(i), QAccessible::Focus);
5370 #endif
5371 }
5372 }
5373
5374
5375 /*!
5376 Returns the current item, or 0 if there isn't one.
5377
5378 \sa setCurrentItem()
5379 */
5380
currentItem() const5381 Q3ListViewItem * Q3ListView::currentItem() const
5382 {
5383 return d->focusItem;
5384 }
5385
5386
5387 /*!
5388 Returns the rectangle on the screen that item \a item occupies in
5389 viewport()'s coordinates, or an invalid rectangle if \a item is 0 or
5390 is not currently visible.
5391
5392 The rectangle returned does not include any children of the
5393 rectangle (i.e. it uses Q3ListViewItem::height(), rather than
5394 Q3ListViewItem::totalHeight()). If you want the rectangle to
5395 include children you can use something like this:
5396
5397 \snippet doc/src/snippets/code/src_qt3support_itemviews_q3listview.cpp 5
5398
5399 Note the way it avoids too-high rectangles. totalHeight() can be
5400 much larger than the window system's coordinate system allows.
5401
5402 itemRect() is comparatively slow. It's best to call it only for
5403 items that are probably on-screen.
5404 */
5405
itemRect(const Q3ListViewItem * item) const5406 QRect Q3ListView::itemRect(const Q3ListViewItem * item) const
5407 {
5408 if (d->drawables.isEmpty())
5409 buildDrawableList();
5410
5411 for (int i = 0; i < d->drawables.size(); ++i) {
5412 const Q3ListViewPrivate::DrawableItem &c = d->drawables.at(i);
5413 if (c.i == item) {
5414 int y = c.y - contentsY();
5415 if (y + c.i->height() >= 0 && y < ((Q3ListView *)this)->visibleHeight()) {
5416 return QRect(-contentsX(), y, d->h->width(), c.i->height());;
5417 }
5418 }
5419 }
5420
5421 return QRect(0, 0, -1, -1);
5422 }
5423
5424
5425 /*!
5426 \fn void Q3ListView::doubleClicked(Q3ListViewItem *item)
5427
5428 This signal is emitted whenever an item is double-clicked. It's
5429 emitted on the second button press, not the second button release.
5430 \a item is the list view item on which the user did the
5431 double-click.
5432 */
5433
5434 /*!
5435 \fn void Q3ListView::doubleClicked(Q3ListViewItem *item, const
5436 QPoint& point, int column)
5437
5438 This signal is emitted when a double-click occurs. It's emitted on
5439 the second button press, not the second button release. The \a
5440 item is the Q3ListViewItem the button was double-clicked on (which
5441 could be 0 if it wasn't double-clicked on an item). The \a point
5442 where the double-click occurred is given in global coordinates. If
5443 an item was double-clicked on, \a column is the column within the
5444 item that was double-clicked; otherwise \a column is -1.
5445
5446 \warning Do not delete any Q3ListViewItem objects in slots
5447 connected to this signal.
5448 */
5449
5450
5451 /*!
5452 \fn void Q3ListView::returnPressed(Q3ListViewItem *item)
5453
5454 This signal is emitted when Enter or Return is pressed. The
5455 \a item parameter is the currentItem().
5456 */
5457
5458 /*!
5459 \fn void Q3ListView::spacePressed(Q3ListViewItem *item)
5460
5461 This signal is emitted when Space is pressed. The \a item
5462 parameter is the currentItem().
5463 */
5464
5465
5466 /*!
5467 Sets the list view to be sorted by column \a column in ascending
5468 order if \a ascending is true or descending order if it is false.
5469
5470 If \a column is -1, sorting is disabled and the user cannot sort
5471 columns by clicking on the column headers. If \a column is larger
5472 than the number of columns the user must click on a column
5473 header to sort the list view.
5474 */
5475
setSorting(int column,bool ascending)5476 void Q3ListView::setSorting(int column, bool ascending)
5477 {
5478 if (column == -1)
5479 column = Unsorted;
5480
5481 if (d->sortcolumn == column && d->ascending == ascending)
5482 return;
5483
5484 d->ascending = ascending;
5485 d->sortcolumn = column;
5486 if (d->sortcolumn != Unsorted && d->sortIndicator)
5487 d->h->setSortIndicator(d->sortcolumn, d->ascending);
5488 else
5489 d->h->setSortIndicator(-1);
5490
5491 triggerUpdate();
5492
5493 #ifndef QT_NO_ACCESSIBILITY
5494 QAccessible::updateAccessibility(viewport(), 0, QAccessible::ObjectReorder);
5495 #endif
5496 }
5497
5498 /*!
5499 Sets the \a column the list view is sorted by.
5500
5501 Sorting is triggered by choosing a header section.
5502 */
5503
changeSortColumn(int column)5504 void Q3ListView::changeSortColumn(int column)
5505 {
5506 if (isRenaming()) {
5507 if (d->defRenameAction == Q3ListView::Reject) {
5508 currentItem()->cancelRename(currentItem()->renameCol);
5509 } else {
5510 currentItem()->okRename(currentItem()->renameCol);
5511 }
5512 }
5513 if (d->sortcolumn != Unsorted) {
5514 int lcol = d->h->mapToLogical(column);
5515 setSorting(lcol, d->sortcolumn == lcol ? !d->ascending : true);
5516 }
5517 }
5518
5519 /*!
5520 \internal
5521 Handles renaming when sections are being swapped by the user.
5522 */
5523
handleIndexChange()5524 void Q3ListView::handleIndexChange()
5525 {
5526 if (isRenaming()) {
5527 if (d->defRenameAction == Q3ListView::Reject) {
5528 currentItem()->cancelRename(currentItem()->renameCol);
5529 } else {
5530 currentItem()->okRename(currentItem()->renameCol);
5531 }
5532 }
5533 triggerUpdate();
5534 }
5535
5536 /*!
5537 Returns the column by which the list view is sorted, or -1 if
5538 sorting is disabled.
5539
5540 \sa sortOrder()
5541 */
5542
sortColumn() const5543 int Q3ListView::sortColumn() const
5544 {
5545 return d->sortcolumn;
5546 }
5547
5548 /*!
5549 Sets the sorting column for the list view.
5550
5551 If \a column is -1, sorting is disabled and the user cannot sort
5552 columns by clicking on the column headers. If \a column is larger
5553 than the number of columns the user must click on a column header
5554 to sort the list view.
5555
5556 \sa setSorting()
5557 */
setSortColumn(int column)5558 void Q3ListView::setSortColumn(int column)
5559 {
5560 setSorting(column, d->ascending);
5561 }
5562
5563 /*!
5564 Returns the sorting order of the list view items.
5565
5566 \sa sortColumn()
5567 */
sortOrder() const5568 Qt::SortOrder Q3ListView::sortOrder() const
5569 {
5570 if (d->ascending)
5571 return Qt::AscendingOrder;
5572 return Qt::DescendingOrder;
5573 }
5574
5575 /*!
5576 Sets the sort order for the items in the list view to \a order.
5577
5578 \sa setSorting()
5579 */
setSortOrder(Qt::SortOrder order)5580 void Q3ListView::setSortOrder(Qt::SortOrder order)
5581 {
5582 setSorting(d->sortcolumn, order == Qt::AscendingOrder ? true : false);
5583 }
5584
5585 /*!
5586 Sorts the list view using the last sorting configuration (sort
5587 column and ascending/descending).
5588 */
5589
sort()5590 void Q3ListView::sort()
5591 {
5592 if (d->r)
5593 d->r->sort();
5594 }
5595
5596 /*!
5597 \property Q3ListView::itemMargin
5598 \brief the advisory item margin that list items may use
5599
5600 The item margin defaults to one pixel and is the margin between
5601 the item's edges and the area where it draws its contents.
5602 Q3ListViewItem::paintFocus() draws in the margin.
5603
5604 \sa Q3ListViewItem::paintCell()
5605 */
5606
setItemMargin(int m)5607 void Q3ListView::setItemMargin(int m)
5608 {
5609 if (d->margin == m)
5610 return;
5611 d->margin = m;
5612 if (isVisible()) {
5613 d->drawables.clear();
5614 triggerUpdate();
5615 }
5616 }
5617
itemMargin() const5618 int Q3ListView::itemMargin() const
5619 {
5620 return d->margin;
5621 }
5622
5623
5624 /*!
5625 \fn void Q3ListView::rightButtonClicked(Q3ListViewItem *item,
5626 const QPoint& point, int column)
5627
5628 This signal is emitted when the right button is clicked. The \a
5629 item is the Q3ListViewItem the button was clicked on (which could
5630 be 0 if it wasn't clicked on an item). The \a point where the
5631 click occurred is given in global coordinates. If an item was
5632 clicked on, \a column is the column within the item that was
5633 clicked; otherwise \a column is -1.
5634 */
5635
5636
5637 /*!
5638 \fn void Q3ListView::rightButtonPressed (Q3ListViewItem *item,
5639 const QPoint &point, int column)
5640
5641 This signal is emitted when the right button is pressed. The \a
5642 item is the Q3ListViewItem the button was pressed on (which could
5643 be 0 if it wasn't pressed on an item). The \a point where the
5644 press occurred is given in global coordinates. If an item was
5645 pressed on, \a column is the column within the item that was
5646 pressed; otherwise \a column is -1.
5647 */
5648
5649 /*!
5650 \fn void Q3ListView::contextMenuRequested(Q3ListViewItem *item, const QPoint & pos, int col)
5651
5652 This signal is emitted when the user invokes a context menu with
5653 the right mouse button or with special system keys. If the
5654 keyboard was used \a item is the current item; if the mouse was
5655 used, \a item is the item under the mouse pointer or 0 if there is
5656 no item under the mouse pointer. If no item is clicked, the column
5657 index emitted is -1.
5658
5659 \a pos is the position for the context menu in the global
5660 coordinate system.
5661
5662 \a col is the column on which the user pressed, or -1 if the
5663 signal was triggered by a key event.
5664 */
5665
5666 /*!
5667 \reimp
5668 */
changeEvent(QEvent * ev)5669 void Q3ListView::changeEvent(QEvent *ev)
5670 {
5671 if(ev->type() == QEvent::StyleChange) {
5672 reconfigureItems();
5673 } else if(ev->type() == QEvent::ActivationChange) {
5674 if (!isActiveWindow() && d->scrollTimer)
5675 d->scrollTimer->stop();
5676 if (!palette().isEqual(QPalette::Active, QPalette::Inactive))
5677 viewport()->update();
5678 }
5679 Q3ScrollView::changeEvent(ev);
5680
5681 if (ev->type() == QEvent::ApplicationFontChange || ev->type() == QEvent::FontChange
5682 || ev->type() == QEvent::ApplicationPaletteChange || ev->type() == QEvent::PaletteChange)
5683 reconfigureItems();
5684 }
5685
5686 /*!
5687 Ensures that setup() is called for all currently visible items,
5688 and that it will be called for currently invisible items as soon
5689 as their parents are opened.
5690
5691 (A visible item, here, is an item whose parents are all open. The
5692 item may happen to be off-screen.)
5693
5694 \sa Q3ListViewItem::setup()
5695 */
5696
reconfigureItems()5697 void Q3ListView::reconfigureItems()
5698 {
5699 d->fontMetricsHeight = fontMetrics().height();
5700 d->minLeftBearing = fontMetrics().minLeftBearing();
5701 d->minRightBearing = fontMetrics().minRightBearing();
5702 d->ellipsisWidth = fontMetrics().width(QLatin1String("...")) * 2;
5703 d->r->setOpen(false);
5704 d->r->configured = false;
5705 d->r->setOpen(true);
5706 }
5707
5708 /*!
5709 Ensures that the width mode of column \a c is updated according to
5710 the width of \a item.
5711 */
5712
widthChanged(const Q3ListViewItem * item,int c)5713 void Q3ListView::widthChanged(const Q3ListViewItem* item, int c)
5714 {
5715 if (c >= d->h->count())
5716 return;
5717
5718
5719 QFontMetrics fm = fontMetrics();
5720 int col = c < 0 ? 0 : c;
5721 while (col == c || (c < 0 && col < d->h->count())) {
5722 if (d->column[col].wmode == Maximum) {
5723 int w = item->width(fm, this, col);
5724 if (showSortIndicator()) {
5725 int tw = d->h->sectionSizeHint( col, fm ).width();
5726 tw += 40; //add space for the sort indicator
5727 w = qMax(w, tw);
5728 }
5729 if (col == 0) {
5730 int indent = treeStepSize() * item->depth();
5731 if (rootIsDecorated())
5732 indent += treeStepSize();
5733 w += indent;
5734 }
5735 if (w > columnWidth(col) && !d->h->isStretchEnabled() && !d->h->isStretchEnabled(col)) {
5736 d->updateHeader = true;
5737 setColumnWidth(col, w);
5738 }
5739 }
5740 col++;
5741 }
5742 }
5743
5744 /*!
5745 \property Q3ListView::allColumnsShowFocus
5746 \brief whether items should show keyboard focus using all columns
5747
5748 If this property is true all columns will show focus and selection
5749 states, otherwise only column 0 will show focus.
5750
5751 The default is false.
5752
5753 Setting this to true if it's not necessary may cause noticeable
5754 flicker.
5755 */
5756
setAllColumnsShowFocus(bool enable)5757 void Q3ListView::setAllColumnsShowFocus(bool enable)
5758 {
5759 d->allColumnsShowFocus = enable;
5760 }
5761
allColumnsShowFocus() const5762 bool Q3ListView::allColumnsShowFocus() const
5763 {
5764 return d->allColumnsShowFocus;
5765 }
5766
5767
5768 /*!
5769 Returns the first item in this Q3ListView. Returns 0 if there is no
5770 first item.
5771
5772 A list view's items can be traversed using firstChild()
5773 and nextSibling() or using a Q3ListViewItemIterator.
5774
5775 \sa itemAt() Q3ListViewItem::itemBelow() Q3ListViewItem::itemAbove()
5776 */
5777
firstChild() const5778 Q3ListViewItem * Q3ListView::firstChild() const
5779 {
5780 if (!d->r)
5781 return 0;
5782
5783 d->r->enforceSortOrder();
5784 return d->r->childItem;
5785 }
5786
5787 /*!
5788 Returns the last item in the list view tree. Returns 0 if there
5789 are no items in the Q3ListView.
5790
5791 This function is slow because it traverses the entire tree to find
5792 the last item.
5793 */
5794
lastItem() const5795 Q3ListViewItem* Q3ListView::lastItem() const
5796 {
5797 Q3ListViewItem* item = firstChild();
5798 if (item) {
5799 while (item->nextSibling() || item->firstChild()) {
5800 if (item->nextSibling())
5801 item = item->nextSibling();
5802 else
5803 item = item->firstChild();
5804 }
5805 }
5806 return item;
5807 }
5808
5809 /*!
5810 Repaints this item on the screen if it is currently visible.
5811 */
5812
repaint() const5813 void Q3ListViewItem::repaint() const
5814 {
5815 Q3ListView *lv = listView();
5816 if (lv)
5817 lv->repaintItem(this);
5818 }
5819
5820
5821 /*!
5822 Repaints \a item on the screen if \a item is currently visible.
5823 Takes care to avoid multiple repaints.
5824 */
5825
repaintItem(const Q3ListViewItem * item) const5826 void Q3ListView::repaintItem(const Q3ListViewItem * item) const
5827 {
5828 if (!item)
5829 return;
5830 d->dirtyItemTimer->start(0, true);
5831 d->dirtyItems.append(item);
5832 }
5833
5834
5835 struct Q3CheckListItemPrivate
5836 {
Q3CheckListItemPrivateQ3CheckListItemPrivate5837 Q3CheckListItemPrivate():
5838 exclusive(0),
5839 currentState(Q3CheckListItem::Off),
5840 tristate(false) {}
5841
5842 Q3CheckListItem *exclusive;
5843 Q3CheckListItem::ToggleState currentState;
5844 QHash<Q3CheckListItem *, Q3CheckListItem::ToggleState> statesDict;
5845 bool tristate;
5846 };
5847
5848
5849 /*!
5850 \class Q3CheckListItem
5851 \brief The Q3CheckListItem class provides checkable list view items.
5852
5853 \compat
5854
5855 Q3CheckListItems are used in \l{Q3ListView}s to provide
5856 \l{Q3ListViewItem}s that are checkboxes, radio buttons or
5857 controllers.
5858
5859 Checkbox and controller check list items may be inserted at any
5860 level in a list view. Radio button check list items must be
5861 children of a controller check list item.
5862
5863 The item can be checked or unchecked with setOn(). Its type can be
5864 retrieved with type() and its text retrieved with text().
5865
5866 \img qlistviewitems.png List View Items
5867
5868 \sa Q3ListViewItem Q3ListView
5869 */
5870
5871 /*!
5872 \enum Q3CheckListItem::Type
5873
5874 This enum type specifies a Q3CheckListItem's type:
5875
5876 \value RadioButton
5877 \value CheckBox
5878 \value RadioButtonController
5879 \value CheckBoxController
5880 \omitvalue Controller
5881 */
5882
5883 /*!
5884 \enum Q3CheckListItem::ToggleState
5885
5886 This enum specifies a Q3CheckListItem's toggle state.
5887
5888 \value Off
5889 \value NoChange
5890 \value On
5891 */
5892
5893
5894 /*!
5895 Constructs a checkable item with parent \a parent, text \a text
5896 and of type \a tt. Note that a \c RadioButton must be the child of a
5897 \c RadioButtonController, otherwise it will not toggle.
5898 */
Q3CheckListItem(Q3CheckListItem * parent,const QString & text,Type tt)5899 Q3CheckListItem::Q3CheckListItem(Q3CheckListItem *parent, const QString &text,
5900 Type tt)
5901 : Q3ListViewItem(parent, text, QString())
5902 {
5903 myType = tt;
5904 init();
5905 if (myType == RadioButton) {
5906 if (parent->type() != RadioButtonController)
5907 qWarning("Q3CheckListItem::Q3CheckListItem(), radio button must be "
5908 "child of a controller");
5909 else
5910 d->exclusive = parent;
5911 }
5912 }
5913
5914 /*!
5915 Constructs a checkable item with parent \a parent, which is after
5916 \a after in the parent's list of children, and with text \a text
5917 and of type \a tt. Note that a \c RadioButton must be the child of
5918 a \c RadioButtonController, otherwise it will not toggle.
5919 */
Q3CheckListItem(Q3CheckListItem * parent,Q3ListViewItem * after,const QString & text,Type tt)5920 Q3CheckListItem::Q3CheckListItem(Q3CheckListItem *parent, Q3ListViewItem *after,
5921 const QString &text, Type tt)
5922 : Q3ListViewItem(parent, after, text)
5923 {
5924 myType = tt;
5925 init();
5926 if (myType == RadioButton) {
5927 if (parent->type() != RadioButtonController)
5928 qWarning("Q3CheckListItem::Q3CheckListItem(), radio button must be "
5929 "child of a controller");
5930 else
5931 d->exclusive = parent;
5932 }
5933 }
5934
5935 /*!
5936 Constructs a checkable item with parent \a parent, text \a text
5937 and of type \a tt. Note that this item must \e not be a \c
5938 RadioButton. Radio buttons must be children of a \c
5939 RadioButtonController.
5940 */
Q3CheckListItem(Q3ListViewItem * parent,const QString & text,Type tt)5941 Q3CheckListItem::Q3CheckListItem(Q3ListViewItem *parent, const QString &text,
5942 Type tt)
5943 : Q3ListViewItem(parent, text, QString())
5944 {
5945 myType = tt;
5946 if (myType == RadioButton) {
5947 qWarning("Q3CheckListItem::Q3CheckListItem(), radio button must be "
5948 "child of a Q3CheckListItem");
5949 }
5950 init();
5951 }
5952
5953 /*!
5954 Constructs a checkable item with parent \a parent, which is after
5955 \a after in the parent's list of children, with text \a text and
5956 of type \a tt. Note that this item must \e not be a \c
5957 RadioButton. Radio buttons must be children of a \c
5958 RadioButtonController.
5959 */
Q3CheckListItem(Q3ListViewItem * parent,Q3ListViewItem * after,const QString & text,Type tt)5960 Q3CheckListItem::Q3CheckListItem(Q3ListViewItem *parent, Q3ListViewItem *after,
5961 const QString &text, Type tt)
5962 : Q3ListViewItem(parent, after, text)
5963 {
5964 myType = tt;
5965 if (myType == RadioButton) {
5966 qWarning("Q3CheckListItem::Q3CheckListItem(), radio button must be "
5967 "child of a Q3CheckListItem");
5968 }
5969 init();
5970 }
5971
5972
5973 /*!
5974 Constructs a checkable item with parent \a parent, text \a text
5975 and of type \a tt. Note that \a tt must \e not be \c RadioButton.
5976 Radio buttons must be children of a \c RadioButtonController.
5977 */
Q3CheckListItem(Q3ListView * parent,const QString & text,Type tt)5978 Q3CheckListItem::Q3CheckListItem(Q3ListView *parent, const QString &text,
5979 Type tt)
5980 : Q3ListViewItem(parent, text)
5981 {
5982 myType = tt;
5983 if (tt == RadioButton)
5984 qWarning("Q3CheckListItem::Q3CheckListItem(), radio button must be "
5985 "child of a Q3CheckListItem");
5986 init();
5987 }
5988
5989 /*!
5990 Constructs a checkable item with parent \a parent, which is after
5991 \a after in the parent's list of children, with text \a text and
5992 of type \a tt. Note that \a tt must \e not be \c RadioButton.
5993 Radio buttons must be children of a \c RadioButtonController.
5994 */
Q3CheckListItem(Q3ListView * parent,Q3ListViewItem * after,const QString & text,Type tt)5995 Q3CheckListItem::Q3CheckListItem(Q3ListView *parent, Q3ListViewItem *after,
5996 const QString &text, Type tt)
5997 : Q3ListViewItem(parent, after, text)
5998 {
5999 myType = tt;
6000 if (tt == RadioButton)
6001 qWarning("Q3CheckListItem::Q3CheckListItem(), radio button must be "
6002 "child of a Q3CheckListItem");
6003 init();
6004 }
6005
6006
6007 /* \reimp */
6008
rtti() const6009 int Q3CheckListItem::rtti() const
6010 {
6011 return RTTI;
6012 }
6013
6014 /*!
6015 Constructs a \c RadioButtonController item with parent \a parent,
6016 text \a text and pixmap \a p.
6017 */
Q3CheckListItem(Q3ListView * parent,const QString & text,const QPixmap & p)6018 Q3CheckListItem::Q3CheckListItem(Q3ListView *parent, const QString &text,
6019 const QPixmap & p)
6020 : Q3ListViewItem(parent, text)
6021 {
6022 myType = RadioButtonController;
6023 setPixmap(0, p);
6024 init();
6025 }
6026
6027 /*!
6028 Constructs a \c RadioButtonController item with parent \a parent,
6029 text \a text and pixmap \a p.
6030 */
Q3CheckListItem(Q3ListViewItem * parent,const QString & text,const QPixmap & p)6031 Q3CheckListItem::Q3CheckListItem(Q3ListViewItem *parent, const QString &text,
6032 const QPixmap & p)
6033 : Q3ListViewItem(parent, text)
6034 {
6035 myType = RadioButtonController;
6036 setPixmap(0, p);
6037 init();
6038 }
6039
init()6040 void Q3CheckListItem::init()
6041 {
6042 d = new Q3CheckListItemPrivate();
6043 on = false;
6044 // CheckBoxControllers by default have tristate set to true
6045 if (myType == CheckBoxController)
6046 setTristate(true);
6047 }
6048
6049 /*!
6050 Destroys the item, and all its children to any depth, freeing up
6051 all allocated resources.
6052 */
~Q3CheckListItem()6053 Q3CheckListItem::~Q3CheckListItem()
6054 {
6055 if (myType == RadioButton
6056 && d->exclusive && d->exclusive->d
6057 && d->exclusive->d->exclusive == this)
6058 d->exclusive->turnOffChild();
6059 d->exclusive = 0; // so the children won't try to access us.
6060 delete d;
6061 d = 0;
6062 }
6063
6064 /*!
6065 \fn Q3CheckListItem::Type Q3CheckListItem::type() const
6066
6067 Returns the type of this item.
6068 */
6069
6070 /*!
6071 \fn bool Q3CheckListItem::isOn() const
6072
6073 Returns true if the item is toggled on; otherwise returns false.
6074 */
6075
6076 /*!
6077 Sets tristate to \a b if the \c Type is either a \c CheckBoxController or
6078 a \c CheckBox.
6079
6080 \c CheckBoxControllers are tristate by default.
6081
6082 \sa state() isTristate()
6083 */
setTristate(bool b)6084 void Q3CheckListItem::setTristate(bool b)
6085 {
6086 if ((myType != CheckBoxController) && (myType != CheckBox)) {
6087 qWarning("Q3CheckListItem::setTristate(), has no effect on RadioButton "
6088 "or RadioButtonController.");
6089 return;
6090 }
6091 d->tristate = b;
6092 }
6093
6094 /*!
6095 Returns true if the item is tristate; otherwise returns false.
6096
6097 \sa setTristate()
6098 */
isTristate() const6099 bool Q3CheckListItem::isTristate() const
6100 {
6101 return d->tristate;
6102 }
6103
6104 /*!
6105 Returns the state of the item.
6106
6107 \sa Q3CheckListItem::ToggleState
6108 */
state() const6109 Q3CheckListItem::ToggleState Q3CheckListItem::state() const
6110 {
6111 if (!isTristate() && internalState() == NoChange)
6112 return Off;
6113 else
6114 return d->currentState;
6115 }
6116
6117 /*
6118 Same as the public state() except this one does not mask NoChange into Off
6119 when tristate is disabled.
6120 */
internalState() const6121 Q3CheckListItem::ToggleState Q3CheckListItem::internalState() const
6122 {
6123 return d->currentState;
6124 }
6125
6126
6127
6128
6129 /*!
6130 Sets the toggle state of the checklistitem to \a s. \a s can be
6131 \c Off, \c NoChange or \c On.
6132
6133 Tristate can only be enabled for \c CheckBox or \c CheckBoxController,
6134 therefore the \c NoChange only applies to them.
6135
6136 Setting the state to \c On or \c Off on a \c CheckBoxController
6137 will recursivly set the states of its children to the same state.
6138
6139 Setting the state to \c NoChange on a \c CheckBoxController will
6140 make it recursivly recall the previous stored state of its
6141 children. If there was no previous stored state the children are
6142 all set to \c On.
6143 */
setState(ToggleState s)6144 void Q3CheckListItem::setState(ToggleState s)
6145 {
6146 if (myType == CheckBoxController && state() == NoChange)
6147 updateStoredState(this);
6148 setState(s, true, true);
6149 }
6150
6151 /*
6152 Sets the toggle state of the checklistitems. \a update tells if the
6153 controller / parent controller should be aware of these changes, \a store
6154 tells if the parent should store its children if certain conditions arise
6155 */
setState(ToggleState s,bool update,bool store)6156 void Q3CheckListItem::setState(ToggleState s, bool update, bool store)
6157 {
6158
6159 if (s == internalState())
6160 return;
6161
6162 if (myType == CheckBox) {
6163 setCurrentState(s);
6164 stateChange(state());
6165 if (update && parent() && parent()->rtti() == 1
6166 && ((Q3CheckListItem*)parent())->type() == CheckBoxController)
6167 ((Q3CheckListItem*)parent())->updateController(update, store);
6168 } else if (myType == CheckBoxController) {
6169 if (s == NoChange && childCount()) {
6170 restoreState(this);
6171 } else {
6172 Q3ListViewItem *item = firstChild();
6173 int childCount = 0;
6174 while(item) {
6175 if (item->rtti() == 1 &&
6176 (((Q3CheckListItem*)item)->type() == CheckBox ||
6177 ((Q3CheckListItem*)item)->type() == CheckBoxController)) {
6178 Q3CheckListItem *checkItem = (Q3CheckListItem*)item;
6179 checkItem->setState(s, false, false);
6180 childCount++;
6181 }
6182 item = item->nextSibling();
6183 }
6184 if (update) {
6185 if (childCount > 0) {
6186 ToggleState oldState = internalState();
6187 updateController(false, false);
6188 if (oldState != internalState() &&
6189 parent() && parent()->rtti() == 1 &&
6190 ((Q3CheckListItem*)parent())->type() == CheckBoxController)
6191 ((Q3CheckListItem*)parent())->updateController(update, store);
6192
6193 updateController(update, store);
6194 } else {
6195 // if there are no children we simply set the CheckBoxController and update its parent
6196 setCurrentState(s);
6197 stateChange(state());
6198 if (parent() && parent()->rtti() == 1
6199 && ((Q3CheckListItem*)parent())->type() == CheckBoxController)
6200 ((Q3CheckListItem*)parent())->updateController(update, store);
6201 }
6202 } else {
6203 setCurrentState(s);
6204 stateChange(state());
6205 }
6206
6207 }
6208 } else if (myType == RadioButton) {
6209 if (s == On) {
6210 if (d->exclusive && d->exclusive->d->exclusive != this)
6211 d->exclusive->turnOffChild();
6212 setCurrentState(s);
6213 if (d->exclusive)
6214 d->exclusive->d->exclusive = this;
6215 } else {
6216 if (d->exclusive && d->exclusive->d->exclusive == this)
6217 d->exclusive->d->exclusive = 0;
6218 setCurrentState(Off);
6219 }
6220 stateChange(state());
6221 }
6222 repaint();
6223 }
6224
6225 /*
6226 this function is needed because we need to update "on" every time we
6227 update d->currentState. In order to retain binary compatibility the
6228 inline function isOn() needs the "on" bool ### should be changed in
6229 ver 4
6230 */
setCurrentState(ToggleState s)6231 void Q3CheckListItem::setCurrentState(ToggleState s)
6232 {
6233 ToggleState old = d->currentState;
6234 d->currentState = s;
6235 if (d->currentState == On)
6236 on = true;
6237 else
6238 on = false;
6239
6240 #ifndef QT_NO_ACCESSIBILITY
6241 if (old != d->currentState && listView())
6242 QAccessible::updateAccessibility(listView()->viewport(), indexOfItem(this), QAccessible::StateChanged);
6243 #else
6244 Q_UNUSED(old);
6245 #endif
6246 }
6247
6248
6249
6250 /*
6251 updates the internally stored state of this item for the parent (key)
6252 */
setStoredState(ToggleState newState,Q3CheckListItem * key)6253 void Q3CheckListItem::setStoredState(ToggleState newState, Q3CheckListItem *key)
6254 {
6255 if (myType == CheckBox || myType == CheckBoxController)
6256 d->statesDict[key] = newState;
6257 }
6258
6259 /*
6260 Returns the stored state for this item for the given key.
6261 If the key is not found it returns Off.
6262 */
storedState(Q3CheckListItem * key) const6263 Q3CheckListItem::ToggleState Q3CheckListItem::storedState(Q3CheckListItem *key) const
6264 {
6265 QHash<Q3CheckListItem *, Q3CheckListItem::ToggleState>::Iterator it = d->statesDict.find(key);
6266 if (it != d->statesDict.end())
6267 return it.value();
6268 else
6269 return Off;
6270 }
6271
6272
6273 /*!
6274 \fn QString Q3CheckListItem::text() const
6275
6276 Returns the item's text.
6277 */
6278
6279
6280 /*!
6281 If this is a \c RadioButtonController that has \c RadioButton
6282 children, turn off the child that is on.
6283 */
turnOffChild()6284 void Q3CheckListItem::turnOffChild()
6285 {
6286 if (myType == RadioButtonController && d->exclusive)
6287 d->exclusive->setOn(false);
6288 }
6289
6290 /*!
6291 Toggle check box or set radio button to on.
6292 */
activate()6293 void Q3CheckListItem::activate()
6294 {
6295 Q3ListView * lv = listView();
6296
6297 if ((lv && !lv->isEnabled()) || !isEnabled())
6298 return;
6299
6300 QPoint pos;
6301 int boxsize = lv->style()->pixelMetric(QStyle::PM_CheckListButtonSize, 0, lv);
6302 if (activatedPos(pos)) {
6303 bool parentControl = false;
6304 if (parent() && parent()->rtti() == 1 &&
6305 ((Q3CheckListItem*) parent())->type() == RadioButtonController)
6306 parentControl = true;
6307
6308 int x = parentControl ? 0 : 3;
6309 int align = lv->columnAlignment(0);
6310 int marg = lv->itemMargin();
6311 int y = 0;
6312
6313 if (align & Qt::AlignVCenter)
6314 y = ((height() - boxsize) / 2) + marg;
6315 else
6316 y = (lv->fontMetrics().height() + 2 + marg - boxsize) / 2;
6317
6318 QRect r(x, y, boxsize-3, boxsize-3);
6319 // columns might have been swapped
6320 r.moveBy(lv->header()->sectionPos(0), 0);
6321 if (!r.contains(pos))
6322 return;
6323 }
6324 if ((myType == CheckBox) || (myType == CheckBoxController)) {
6325 lv->d->startEdit = FALSE;
6326 switch (internalState()) {
6327 case On:
6328 setState(Off);
6329 break;
6330 case Off:
6331 if ( (!isTristate() && myType == CheckBox) ||
6332 (myType == CheckBoxController && !childCount()) ) {
6333 setState(On);
6334 } else {
6335 setState(NoChange);
6336 if (myType == CheckBoxController && internalState() != NoChange)
6337 setState(On);
6338 }
6339 break;
6340 case NoChange:
6341 setState(On);
6342 break;
6343 }
6344 ignoreDoubleClick();
6345 } else if (myType == RadioButton) {
6346 setOn(true);
6347 ignoreDoubleClick();
6348 }
6349 }
6350
6351 /*!
6352 Sets the button on if \a b is true, otherwise sets it off.
6353 Maintains radio button exclusivity.
6354 */
setOn(bool b)6355 void Q3CheckListItem::setOn(bool b )
6356 {
6357 if (b)
6358 setState(On , true, true);
6359 else
6360 setState(Off , true, true);
6361 }
6362
6363
6364 /*!
6365 \fn void Q3CheckListItem::stateChange(bool b)
6366
6367 This virtual function is called when the item changes its state.
6368 \a b is true if the state is \c On; otherwise the state is \c Off.
6369 \c NoChange (if tristate is enabled and the type is either \c
6370 CheckBox or \c CheckBoxController) reports the same as \c Off, so
6371 use state() to determine if the state is actually \c Off or \c
6372 NoChange.
6373 */
stateChange(bool)6374 void Q3CheckListItem::stateChange(bool)
6375 {
6376 }
6377
6378 /*
6379 Calls the public virtual function if the state is changed to either On, NoChange or Off.
6380 NoChange reports the same as Off - ### should be fixed in ver4
6381 */
stateChange(ToggleState s)6382 void Q3CheckListItem::stateChange(ToggleState s)
6383 {
6384 stateChange(s == On);
6385 }
6386
6387 /*
6388 sets the state of the CheckBox and CheckBoxController back to
6389 previous stored state
6390 */
restoreState(Q3CheckListItem * key,int depth)6391 void Q3CheckListItem::restoreState(Q3CheckListItem *key, int depth)
6392 {
6393 switch (type()) {
6394 case CheckBox:
6395 setCurrentState(storedState(key));
6396 stateChange(state());
6397 repaint();
6398 break;
6399 case CheckBoxController: {
6400 Q3ListViewItem *item = firstChild();
6401 int childCount = 0;
6402 while (item) {
6403 // recursively calling restoreState for children of type CheckBox and CheckBoxController
6404 if (item->rtti() == 1 &&
6405 (((Q3CheckListItem*)item)->type() == CheckBox ||
6406 ((Q3CheckListItem*)item)->type() == CheckBoxController)) {
6407 ((Q3CheckListItem*)item)->restoreState(key , depth+1);
6408 childCount++;
6409 }
6410 item = item->nextSibling();
6411 }
6412 if (childCount > 0) {
6413 if (depth == 0)
6414 updateController(true);
6415 else
6416 updateController(false);
6417 } else {
6418 // if there are no children we retrieve the CheckBoxController state directly.
6419 setState(storedState(key), true, false);
6420 }
6421 }
6422 break;
6423 default:
6424 break;
6425 }
6426 }
6427
6428
6429 /*
6430 Checks the childrens state and updates the controllers state
6431 if necessary. If the controllers state change, then his parent again is
6432 called to update itself.
6433 */
updateController(bool update,bool store)6434 void Q3CheckListItem::updateController(bool update , bool store)
6435 {
6436 if (myType != CheckBoxController)
6437 return;
6438
6439 Q3CheckListItem *controller = 0;
6440 // checks if this CheckBoxController has another CheckBoxController as parent
6441 if (parent() && parent()->rtti() == 1
6442 && ((Q3CheckListItem*)parent())->type() == CheckBoxController)
6443 controller = (Q3CheckListItem*)parent();
6444
6445 ToggleState theState = Off;
6446 bool first = true;
6447 Q3ListViewItem *item = firstChild();
6448 while(item && theState != NoChange) {
6449 if (item->rtti() == 1 &&
6450 (((Q3CheckListItem*)item)->type() == CheckBox ||
6451 ((Q3CheckListItem*)item)->type() == CheckBoxController)) {
6452 Q3CheckListItem *checkItem = (Q3CheckListItem*)item;
6453 if (first) {
6454 theState = checkItem->internalState();
6455 first = false;
6456 } else {
6457 if (checkItem->internalState() == NoChange ||
6458 theState != checkItem->internalState())
6459 theState = NoChange;
6460 else
6461 theState = checkItem->internalState();
6462 }
6463 }
6464 item = item->nextSibling();
6465 }
6466 if (internalState() != theState) {
6467 setCurrentState(theState);
6468 if (store && (internalState() == On || internalState() == Off))
6469 updateStoredState(this);
6470 stateChange(state());
6471 if (update && controller) {
6472 controller->updateController(update, store);
6473 }
6474 repaint();
6475 }
6476 }
6477
6478
6479 /*
6480 Makes all the children CheckBoxes update their storedState
6481 */
updateStoredState(Q3CheckListItem * key)6482 void Q3CheckListItem::updateStoredState(Q3CheckListItem *key)
6483 {
6484 if (myType != CheckBoxController)
6485 return;
6486
6487 Q3ListViewItem *item = firstChild();
6488 while(item) {
6489 if (item->rtti() == 1) {
6490 Q3CheckListItem *checkItem = (Q3CheckListItem*)item;
6491 if (checkItem->type() == CheckBox)
6492 checkItem->setStoredState(checkItem->internalState(), key);
6493 else if (checkItem->type() == CheckBoxController)
6494 checkItem->updateStoredState(key);
6495 }
6496 item = item->nextSibling();
6497 }
6498 // this state is only needed if the CheckBoxController has no CheckBox / CheckBoxController children.
6499 setStoredState(internalState() , key);
6500 }
6501
6502
6503 /*!
6504 \reimp
6505 */
setup()6506 void Q3CheckListItem::setup()
6507 {
6508 Q3ListViewItem::setup();
6509 int h = height();
6510 Q3ListView *lv = listView();
6511 if (lv)
6512 h = qMax(lv->style()->pixelMetric(QStyle::PM_CheckListButtonSize, 0, lv),
6513 h);
6514 h = qMax(h, QApplication::globalStrut().height());
6515 setHeight(h);
6516 }
6517
6518 /*!
6519 \reimp
6520 */
6521
width(const QFontMetrics & fm,const Q3ListView * lv,int column) const6522 int Q3CheckListItem::width(const QFontMetrics& fm, const Q3ListView* lv, int column) const
6523 {
6524 int r = Q3ListViewItem::width(fm, lv, column);
6525 if (column == 0) {
6526 r += lv->itemMargin();
6527 if (myType == RadioButtonController && pixmap(0)) {
6528 // r += 0;
6529 } else {
6530 r += lv->style()->pixelMetric(QStyle::PM_CheckListButtonSize, 0, lv) + 4;
6531 }
6532 }
6533 return qMax(r, QApplication::globalStrut().width());
6534 }
6535
6536 /*!
6537 Paints the item using the painter \a p and the color group \a cg.
6538 The item is in column \a column, has width \a width and has
6539 alignment \a align. (See \l Qt::Alignment for valid alignments.)
6540 */
paintCell(QPainter * p,const QColorGroup & cg,int column,int width,int align)6541 void Q3CheckListItem::paintCell(QPainter * p, const QColorGroup & cg,
6542 int column, int width, int align)
6543 {
6544 if (!p)
6545 return;
6546
6547 Q3ListView *lv = listView();
6548 if (!lv)
6549 return;
6550
6551 const QPalette::ColorRole crole = lv->backgroundRole();
6552 if (cg.brush(crole) != lv->palette().brush(cg.currentColorGroup(), crole))
6553 p->fillRect(0, 0, width, height(), cg.brush(crole));
6554 else
6555 lv->paintEmptyArea(p, QRect(0, 0, width, height()));
6556
6557 if (column != 0) {
6558 // The rest is text, or for subclasses to change.
6559 Q3ListViewItem::paintCell(p, cg, column, width, align);
6560 return;
6561 }
6562
6563 bool parentControl = false;
6564 if (parent() && parent()->rtti() == 1 &&
6565 ((Q3CheckListItem*) parent())->type() == RadioButtonController)
6566 parentControl = true;
6567
6568 QFontMetrics fm(lv->fontMetrics());
6569 int boxsize = lv->style()->pixelMetric(myType == RadioButtonController ? QStyle::PM_CheckListControllerSize :
6570 QStyle::PM_CheckListButtonSize, 0, lv);
6571 int marg = lv->itemMargin();
6572 int r = marg;
6573
6574 // Draw controller / check box / radio button ---------------------
6575 QStyle::State styleflags = QStyle::State_None;
6576 if (internalState() == On) {
6577 styleflags |= QStyle::State_On;
6578 } else if (internalState() == NoChange) {
6579 if (myType == CheckBoxController && !isTristate())
6580 styleflags |= QStyle::State_Off;
6581 else
6582 styleflags |= QStyle::State_NoChange;
6583 } else {
6584 styleflags |= QStyle::State_Off;
6585 }
6586 if (isSelected())
6587 styleflags |= QStyle::State_Selected;
6588 if (isEnabled() && lv->isEnabled())
6589 styleflags |= QStyle::State_Enabled;
6590 if (lv->window()->isActiveWindow())
6591 styleflags |= QStyle::State_Active;
6592
6593 if (myType == RadioButtonController) {
6594 int x = 0;
6595 if(!parentControl)
6596 x += 3;
6597 if (!pixmap(0)) {
6598 QStyleOptionQ3ListView opt = getStyleOption(lv, this);
6599 opt.rect.setRect(x, 0, boxsize, fm.height() + 2 + marg);
6600 opt.palette = cg;
6601 opt.state = styleflags;
6602 lv->style()->drawPrimitive(QStyle::PE_Q3CheckListController, &opt, p, lv);
6603 r += boxsize + 4;
6604 }
6605 } else {
6606 Q_ASSERT(lv); //###
6607 int x = 0;
6608 int y = 0;
6609 if (!parentControl)
6610 x += 3;
6611 if (align & Qt::AlignVCenter)
6612 y = ((height() - boxsize) / 2) + marg;
6613 else
6614 y = (fm.height() + 2 + marg - boxsize) / 2;
6615
6616 QStyleOptionQ3ListView opt = getStyleOption(lv, this);
6617 opt.rect.setRect(x, y, boxsize, fm.height() + 2 + marg);
6618 opt.palette = cg;
6619 opt.state = styleflags;
6620 lv->style()->drawPrimitive((myType == CheckBox || myType == CheckBoxController)
6621 ? QStyle::PE_Q3CheckListIndicator
6622 : QStyle::PE_Q3CheckListExclusiveIndicator, &opt, p, lv);
6623 r += boxsize + 4;
6624 }
6625
6626 // Draw text ----------------------------------------------------
6627 p->translate(r, 0);
6628 p->setPen(QPen(cg.text()));
6629 Q3ListViewItem::paintCell(p, cg, column, width - r, align);
6630 }
6631
6632 /*!
6633 Draws the focus rectangle \a r using the color group \a cg on the
6634 painter \a p.
6635 */
paintFocus(QPainter * p,const QColorGroup & cg,const QRect & r)6636 void Q3CheckListItem::paintFocus(QPainter *p, const QColorGroup & cg,
6637 const QRect & r)
6638 {
6639 bool intersect = true;
6640 Q3ListView *lv = listView();
6641 if (lv && lv->header()->mapToActual(0) != 0) {
6642 int xdepth = lv->treeStepSize() * (depth() + (lv->rootIsDecorated() ? 1 : 0)) + lv->itemMargin();
6643 int p = lv->header()->cellPos(lv->header()->mapToActual(0));
6644 xdepth += p;
6645 intersect = r.intersects(QRect(p, r.y(), xdepth - p + 1, r.height()));
6646 }
6647 bool parentControl = false;
6648 if (parent() && parent()->rtti() == 1 &&
6649 ((Q3CheckListItem*) parent())->type() == RadioButtonController)
6650 parentControl = true;
6651 if (myType != RadioButtonController && intersect &&
6652 (lv->rootIsDecorated() || myType == RadioButton ||
6653 (myType == CheckBox && parentControl))) {
6654 QRect rect;
6655 int boxsize = lv->style()->pixelMetric(QStyle::PM_CheckListButtonSize, 0, lv);
6656 if (lv->columnAlignment(0) == Qt::AlignCenter) {
6657 QFontMetrics fm(lv->font());
6658 int bx = (lv->columnWidth(0) - (boxsize + fm.width(text())))/2 + boxsize;
6659 if (bx < 0) bx = 0;
6660 rect.setRect(r.x() + bx + 5, r.y(), r.width() - bx - 5,
6661 r.height());
6662 } else
6663 rect.setRect(r.x() + boxsize + 5, r.y(), r.width() - boxsize - 5,
6664 r.height());
6665 Q3ListViewItem::paintFocus(p, cg, rect);
6666 } else {
6667 Q3ListViewItem::paintFocus(p, cg, r);
6668 }
6669 }
6670
6671 /*!
6672 \reimp
6673 */
sizeHint() const6674 QSize Q3ListView::sizeHint() const
6675 {
6676 if (cachedSizeHint().isValid())
6677 return cachedSizeHint();
6678
6679 ensurePolished();
6680
6681 if (!isVisible() && d->drawables.isEmpty())
6682 // force the column widths to sanity, if possible
6683 buildDrawableList();
6684
6685 QSize s(d->h->sizeHint());
6686 if (verticalScrollBar()->isVisible())
6687 s.setWidth(s.width() + style()->pixelMetric(QStyle::PM_ScrollBarExtent));
6688 s += QSize(frameWidth()*2,frameWidth()*2);
6689 Q3ListViewItem * l = d->r;
6690 while(l && !l->height())
6691 l = l->childItem ? l->childItem : l->siblingItem;
6692
6693 if (l && l->height())
6694 s.setHeight(s.height() + 10 * l->height());
6695 else
6696 s.setHeight(s.height() + 140);
6697
6698 if (s.width() > s.height() * 3)
6699 s.setHeight(s.width() / 3);
6700 else if (s.width() *3 < s.height())
6701 s.setHeight(s.width() * 3);
6702
6703 setCachedSizeHint(s);
6704
6705 return s;
6706 }
6707
6708
6709 /*!
6710 \reimp
6711 */
6712
minimumSizeHint() const6713 QSize Q3ListView::minimumSizeHint() const
6714 {
6715 return Q3ScrollView::minimumSizeHint();
6716 }
6717
6718
6719 /*!
6720 Sets \a item to be open if \a open is true and \a item is
6721 expandable, and to be closed if \a open is false. Repaints
6722 accordingly.
6723
6724 \sa Q3ListViewItem::setOpen() Q3ListViewItem::setExpandable()
6725 */
6726
setOpen(Q3ListViewItem * item,bool open)6727 void Q3ListView::setOpen(Q3ListViewItem * item, bool open)
6728 {
6729 if (!item ||
6730 item->isOpen() == open ||
6731 (open && !item->childCount() && !item->isExpandable()))
6732 return;
6733
6734 Q3ListViewItem* nextParent = 0;
6735 if (open)
6736 nextParent = item->itemBelow();
6737
6738 item->setOpen(open);
6739
6740 if (open) {
6741 Q3ListViewItem* lastChild = item;
6742 Q3ListViewItem* tmp;
6743 while (true) {
6744 tmp = lastChild->itemBelow();
6745 if (!tmp || tmp == nextParent)
6746 break;
6747 lastChild = tmp;
6748 }
6749 ensureItemVisible(lastChild);
6750 ensureItemVisible(item);
6751 }
6752 buildDrawableList();
6753
6754 int i = 0;
6755 for (; i < d->drawables.size(); ++i) {
6756 const Q3ListViewPrivate::DrawableItem &c = d->drawables.at(i);
6757 if(c.i == item)
6758 break;
6759 }
6760
6761 if (i < d->drawables.size()) {
6762 d->dirtyItemTimer->start(0, true);
6763 for (; i < d->drawables.size(); ++i) {
6764 const Q3ListViewPrivate::DrawableItem &c = d->drawables.at(i);
6765 d->dirtyItems.append(c.i);
6766 }
6767 }
6768 }
6769
6770
6771 /*!
6772 Returns true if this list view item has children \e and they are
6773 not explicitly hidden; otherwise returns false.
6774
6775 Identical to \a{item}->isOpen(). Provided for completeness.
6776
6777 \sa setOpen()
6778 */
6779
isOpen(const Q3ListViewItem * item) const6780 bool Q3ListView::isOpen(const Q3ListViewItem * item) const
6781 {
6782 return item->isOpen();
6783 }
6784
6785
6786 /*!
6787 \property Q3ListView::rootIsDecorated
6788 \brief whether the list view shows open/close signs on root items
6789
6790 Open/close signs are small \bold{+} or \bold{-} symbols in windows
6791 style, or arrows in Motif style. The default is false.
6792 */
6793
setRootIsDecorated(bool enable)6794 void Q3ListView::setRootIsDecorated(bool enable)
6795 {
6796 if (enable != (bool)d->rootIsExpandable) {
6797 d->rootIsExpandable = enable;
6798 if (isVisible())
6799 triggerUpdate();
6800 }
6801 }
6802
rootIsDecorated() const6803 bool Q3ListView::rootIsDecorated() const
6804 {
6805 return d->rootIsExpandable;
6806 }
6807
6808
6809 /*!
6810 Ensures that item \a i is visible, scrolling the list view
6811 vertically if necessary and opening (expanding) any parent items
6812 if this is required to show the item.
6813
6814 \sa itemRect() Q3ScrollView::ensureVisible()
6815 */
6816
ensureItemVisible(const Q3ListViewItem * i)6817 void Q3ListView::ensureItemVisible(const Q3ListViewItem * i)
6818 {
6819 if (!i || !i->isVisible())
6820 return;
6821
6822 Q3ListViewItem *parent = i->parent();
6823 while (parent) {
6824 if (!parent->isOpen())
6825 parent->setOpen(true);
6826 parent = parent->parent();
6827 }
6828
6829 if (d->r->maybeTotalHeight < 0)
6830 updateGeometries();
6831 int y = itemPos(i);
6832 int h = i->height();
6833 if (isVisible() && y + h > contentsY() + visibleHeight())
6834 setContentsPos(contentsX(), y - visibleHeight() + h);
6835 else if (!isVisible() || y < contentsY())
6836 setContentsPos(contentsX(), y);
6837 }
6838
6839
6840 /*!
6841 \fn QString Q3CheckListItem::text(int n) const
6842
6843 \reimp
6844 */
6845
6846 /*!
6847 Returns the Q3Header object that manages this list view's columns.
6848 Please don't modify the header behind the list view's back.
6849
6850 You may safely call Q3Header::setClickEnabled(),
6851 Q3Header::setResizeEnabled(), Q3Header::setMovingEnabled(),
6852 Q3Header::hide() and all the const Q3Header functions.
6853 */
6854
header() const6855 Q3Header * Q3ListView::header() const
6856 {
6857 return d->h;
6858 }
6859
6860
6861 /*!
6862 \property Q3ListView::childCount
6863 \brief the number of parentless (top-level) Q3ListViewItem objects in this Q3ListView
6864
6865 Holds the current number of parentless (top-level) Q3ListViewItem
6866 objects in this Q3ListView.
6867
6868 \sa Q3ListViewItem::childCount()
6869 */
6870
childCount() const6871 int Q3ListView::childCount() const
6872 {
6873 if (d->r)
6874 return d->r->childCount();
6875 return 0;
6876 }
6877
6878
6879 /*
6880 Moves this item to just after \a olderSibling. \a olderSibling and
6881 this object must have the same parent.
6882
6883 If you need to move an item in the hierarchy use takeItem() and
6884 insertItem().
6885 */
6886
moveToJustAfter(Q3ListViewItem * olderSibling)6887 void Q3ListViewItem::moveToJustAfter(Q3ListViewItem * olderSibling)
6888 {
6889 if (parentItem && olderSibling &&
6890 olderSibling->parentItem == parentItem && olderSibling != this) {
6891 if (parentItem->childItem == this) {
6892 parentItem->childItem = siblingItem;
6893 } else {
6894 Q3ListViewItem * i = parentItem->childItem;
6895 while(i && i->siblingItem != this)
6896 i = i->siblingItem;
6897 if (i)
6898 i->siblingItem = siblingItem;
6899 }
6900 siblingItem = olderSibling->siblingItem;
6901 olderSibling->siblingItem = this;
6902 parentItem->lsc = Unsorted;
6903 }
6904 }
6905
6906 /*!
6907 Move the item to be after item \a after, which must be one of the
6908 item's siblings. To move an item in the hierarchy, use takeItem()
6909 and insertItem().
6910
6911 Note that this function will have no effect if sorting is enabled
6912 in the list view.
6913 */
6914
moveItem(Q3ListViewItem * after)6915 void Q3ListViewItem::moveItem(Q3ListViewItem *after)
6916 {
6917 if (!after || after == this)
6918 return;
6919 if (parent() != after->parent()) {
6920 if (parentItem)
6921 parentItem->takeItem(this);
6922 if (after->parentItem) {
6923 int tmpLsc = after->parentItem->lsc;
6924 after->parentItem->insertItem(this);
6925 after->parentItem->lsc = tmpLsc;
6926 }
6927 }
6928 moveToJustAfter(after);
6929 Q3ListView *lv = listView();
6930 if (lv)
6931 lv->triggerUpdate();
6932 }
6933
6934 /*
6935 Recursively sorts items, from the root to this item.
6936 (enforceSortOrder() won't work the other way around, as
6937 documented.)
6938 */
enforceSortOrderBackToRoot()6939 void Q3ListViewItem::enforceSortOrderBackToRoot()
6940 {
6941 if (parentItem) {
6942 parentItem->enforceSortOrderBackToRoot();
6943 parentItem->enforceSortOrder();
6944 }
6945 }
6946
6947 /*!
6948 \reimp
6949 */
showEvent(QShowEvent *)6950 void Q3ListView::showEvent(QShowEvent *)
6951 {
6952 d->drawables.clear();
6953 d->dirtyItems.clear();
6954 d->dirtyItemTimer->stop();
6955 d->fullRepaintOnComlumnChange = true;
6956
6957 updateGeometries();
6958 }
6959
6960
6961 /*!
6962 Returns the y coordinate of this item in the list view's
6963 coordinate system. This function is normally much slower than
6964 Q3ListView::itemAt(), but it works for all items whereas
6965 Q3ListView::itemAt() normally only works for items on the screen.
6966
6967 \sa Q3ListView::itemAt() Q3ListView::itemRect() Q3ListView::itemPos()
6968 */
6969
itemPos() const6970 int Q3ListViewItem::itemPos() const
6971 {
6972 QStack<Q3ListViewItem *> s;
6973 Q3ListViewItem * i = (Q3ListViewItem *)this;
6974 while(i) {
6975 s.push(i);
6976 i = i->parentItem;
6977 }
6978
6979 int a = 0;
6980 Q3ListViewItem * p = 0;
6981 while(s.count()) {
6982 i = s.pop();
6983 if (p) {
6984 if (!p->configured) {
6985 p->configured = true;
6986 p->setup(); // ### virtual non-const function called in const
6987 }
6988 a += p->height();
6989 Q3ListViewItem * s = p->firstChild();
6990 while(s && s != i) {
6991 a += s->totalHeight();
6992 s = s->nextSibling();
6993 }
6994 }
6995 p = i;
6996 }
6997 return a;
6998 }
6999
7000
7001 /*!
7002 \fn void Q3ListView::removeItem(Q3ListViewItem *item)
7003
7004 Removes the given \a item. Use takeItem() instead.
7005 */
7006
7007 /*!
7008 Removes item \a i from the list view; \a i must be a top-level
7009 item. The warnings regarding Q3ListViewItem::takeItem() apply to
7010 this function, too.
7011
7012 \sa insertItem()
7013 */
takeItem(Q3ListViewItem * i)7014 void Q3ListView::takeItem(Q3ListViewItem * i)
7015 {
7016 if (d->r)
7017 d->r->takeItem(i);
7018 }
7019
7020
openFocusItem()7021 void Q3ListView::openFocusItem()
7022 {
7023 d->autoopenTimer->stop();
7024 if (d->focusItem && !d->focusItem->isOpen()) {
7025 d->focusItem->setOpen(true);
7026 d->focusItem->repaint();
7027 }
7028 }
7029
7030 static const int autoopenTime = 750;
7031
7032 #ifndef QT_NO_DRAGANDDROP
7033
7034 /*! \reimp */
7035
contentsDragEnterEvent(QDragEnterEvent * e)7036 void Q3ListView::contentsDragEnterEvent(QDragEnterEvent *e)
7037 {
7038 d->oldFocusItem = d->focusItem;
7039 Q3ListViewItem *i = d->focusItem;
7040 d->focusItem = itemAt(contentsToViewport(e->pos()));
7041 if (i)
7042 i->repaint();
7043 if (d->focusItem) {
7044 d->autoopenTimer->start(autoopenTime);
7045 d->focusItem->dragEntered();
7046 d->focusItem->repaint();
7047 }
7048 e->accept();
7049 }
7050
7051 /*! \reimp */
7052
contentsDragMoveEvent(QDragMoveEvent * e)7053 void Q3ListView::contentsDragMoveEvent(QDragMoveEvent *e)
7054 {
7055 Q3ListViewItem *i = d->focusItem;
7056 d->focusItem = itemAt(contentsToViewport(e->pos()));
7057 if (i) {
7058 if (i != d->focusItem)
7059 i->dragLeft();
7060 i->repaint();
7061 }
7062 if (d->focusItem) {
7063 if (i != d->focusItem) {
7064 d->focusItem->dragEntered();
7065 d->autoopenTimer->stop();
7066 d->autoopenTimer->start(autoopenTime);
7067 }
7068 d->focusItem->repaint();
7069 } else {
7070 d->autoopenTimer->stop();
7071 }
7072 if ((i && i->dropEnabled() && i->acceptDrop(e)) || acceptDrops())
7073 e->accept();
7074 else
7075 e->ignore();
7076 }
7077
7078 /*! \reimp */
7079
contentsDragLeaveEvent(QDragLeaveEvent *)7080 void Q3ListView::contentsDragLeaveEvent(QDragLeaveEvent *)
7081 {
7082 d->autoopenTimer->stop();
7083
7084 if (d->focusItem)
7085 d->focusItem->dragLeft();
7086
7087 setCurrentItem(d->oldFocusItem);
7088 d->oldFocusItem = 0;
7089 }
7090
7091 /*! \reimp */
7092
contentsDropEvent(QDropEvent * e)7093 void Q3ListView::contentsDropEvent(QDropEvent *e)
7094 {
7095 d->autoopenTimer->stop();
7096
7097 setCurrentItem(d->oldFocusItem);
7098 Q3ListViewItem *i = itemAt(contentsToViewport(e->pos()));
7099 if (i && i->dropEnabled() && i->acceptDrop(e)) {
7100 i->dropped(e);
7101 e->accept();
7102 } else if (acceptDrops()) {
7103 emit dropped(e);
7104 e->accept();
7105 }
7106 }
7107
7108 /*!
7109 If the user presses the mouse on an item and starts moving the
7110 mouse, and the item allow dragging (see
7111 Q3ListViewItem::setDragEnabled()), this function is called to get a
7112 drag object and a drag is started unless dragObject() returns 0.
7113
7114 By default this function returns 0. You should reimplement it and
7115 create a Q3DragObject depending on the selected items.
7116 */
7117
dragObject()7118 Q3DragObject *Q3ListView::dragObject()
7119 {
7120 return 0;
7121 }
7122
7123 /*!
7124 Starts a drag.
7125 */
7126
startDrag()7127 void Q3ListView::startDrag()
7128 {
7129 if (!d->startDragItem)
7130 return;
7131
7132 d->startDragItem = 0;
7133 d->buttonDown = false;
7134
7135 Q3DragObject *drag = dragObject();
7136 if (!drag)
7137 return;
7138
7139 drag->drag();
7140 }
7141
7142 #endif // QT_NO_DRAGANDDROP
7143
7144 /*!
7145 \property Q3ListView::defaultRenameAction
7146 \brief What action to perform when the editor loses focus during renaming
7147
7148 If this property is \c Accept, and the user renames an item and
7149 the editor loses focus (without the user pressing Enter), the
7150 item will still be renamed. If the property's value is \c Reject,
7151 the item will not be renamed unless the user presses Enter. The
7152 default is \c Reject.
7153 */
7154
setDefaultRenameAction(RenameAction a)7155 void Q3ListView::setDefaultRenameAction(RenameAction a)
7156 {
7157 d->defRenameAction = a;
7158 }
7159
defaultRenameAction() const7160 Q3ListView::RenameAction Q3ListView::defaultRenameAction() const
7161 {
7162 return d->defRenameAction;
7163 }
7164
7165 /*!
7166 Returns true if an item is being renamed; otherwise returns false.
7167 */
7168
isRenaming() const7169 bool Q3ListView::isRenaming() const
7170 {
7171 return currentItem() && currentItem()->renameBox;
7172 }
7173
7174 /**********************************************************************
7175 *
7176 * Class Q3ListViewItemIterator
7177 *
7178 **********************************************************************/
7179
7180
7181 /*!
7182 \class Q3ListViewItemIterator
7183 \brief The Q3ListViewItemIterator class provides an iterator for collections of Q3ListViewItems.
7184
7185 \compat
7186
7187 Construct an instance of a Q3ListViewItemIterator, with either a
7188 Q3ListView* or a Q3ListViewItem* as argument, to operate on the tree
7189 of Q3ListViewItems, starting from the argument.
7190
7191 A Q3ListViewItemIterator iterates over all the items from its
7192 starting point. This means that it always makes the first child of
7193 the current item the new current item. If there is no child, the
7194 next sibling becomes the new current item; and if there is no next
7195 sibling, the next sibling of the parent becomes current.
7196
7197 The following example creates a list of all the items that have
7198 been selected by the user, storing pointers to the items in a
7199 QList:
7200 \snippet doc/src/snippets/code/src_qt3support_itemviews_q3listview.cpp 6
7201
7202 An alternative approach is to use an \c IteratorFlag:
7203 \snippet doc/src/snippets/code/src_qt3support_itemviews_q3listview.cpp 7
7204
7205 A Q3ListViewItemIterator provides a convenient and easy way to
7206 traverse a hierarchical Q3ListView.
7207
7208 Multiple Q3ListViewItemIterators can operate on the tree of
7209 Q3ListViewItems. A Q3ListView knows about all iterators operating on
7210 its Q3ListViewItems. So when a Q3ListViewItem gets removed all
7211 iterators that point to this item are updated and point to the
7212 following item if possible, otherwise to a valid item before the
7213 current one or to 0. Note however that deleting the parent item of
7214 an item that an iterator points to is not safe.
7215
7216 \sa Q3ListView, Q3ListViewItem
7217 */
7218
7219 /*!
7220 \enum Q3ListViewItemIterator::IteratorFlag
7221
7222 These flags can be passed to a Q3ListViewItemIterator constructor
7223 (OR-ed together if more than one is used), so that the iterator
7224 will only iterate over items that match the given flags.
7225
7226 \value Visible
7227 \value Invisible
7228 \value Selected
7229 \value Unselected
7230 \value Selectable
7231 \value NotSelectable
7232 \value DragEnabled
7233 \value DragDisabled
7234 \value DropEnabled
7235 \value DropDisabled
7236 \value Expandable
7237 \value NotExpandable
7238 \value Checked
7239 \value NotChecked
7240 */
7241
7242 /*!
7243 Constructs an empty iterator.
7244 */
7245
Q3ListViewItemIterator()7246 Q3ListViewItemIterator::Q3ListViewItemIterator()
7247 : curr(0), listView(0), flags(0)
7248 {
7249 }
7250
7251 /*!
7252 Constructs an iterator for the Q3ListView that contains the \a
7253 item. The current iterator item is set to point to the \a item.
7254 */
7255
Q3ListViewItemIterator(Q3ListViewItem * item)7256 Q3ListViewItemIterator::Q3ListViewItemIterator(Q3ListViewItem *item)
7257 : curr(item), listView(0), flags(0)
7258 {
7259 if (item) {
7260 item->enforceSortOrderBackToRoot();
7261 listView = item->listView();
7262 }
7263 if (listView)
7264 listView->d->iterators.append(this);
7265 }
7266
7267 /*!
7268 Constructs an iterator for the Q3ListView that contains the \a item
7269 using the flags \a iteratorFlags. The current iterator item is set
7270 to point to \a item or the next matching item if \a item doesn't
7271 match the flags.
7272
7273 \sa Q3ListViewItemIterator::IteratorFlag
7274 */
7275
Q3ListViewItemIterator(Q3ListViewItem * item,int iteratorFlags)7276 Q3ListViewItemIterator::Q3ListViewItemIterator(Q3ListViewItem *item, int iteratorFlags)
7277 : curr(item), listView(0), flags(iteratorFlags)
7278 {
7279 // go to next matching item if the current don't match
7280 if (curr && !matchesFlags(curr))
7281 ++(*this);
7282
7283 if (curr) {
7284 curr->enforceSortOrderBackToRoot();
7285 listView = curr->listView();
7286 }
7287 if (listView)
7288 listView->d->iterators.append(this);
7289 }
7290
7291
7292 /*!
7293 Constructs an iterator for the same Q3ListView as \a it. The
7294 current iterator item is set to point on the current item of \a
7295 it.
7296 */
7297
Q3ListViewItemIterator(const Q3ListViewItemIterator & it)7298 Q3ListViewItemIterator::Q3ListViewItemIterator(const Q3ListViewItemIterator& it)
7299 : curr(it.curr), listView(it.listView), flags(it.flags)
7300 {
7301 if (listView)
7302 listView->d->iterators.append(this);
7303 }
7304
7305 /*!
7306 Constructs an iterator for the Q3ListView \a lv. The current
7307 iterator item is set to point on the first child (Q3ListViewItem)
7308 of \a lv.
7309 */
7310
Q3ListViewItemIterator(Q3ListView * lv)7311 Q3ListViewItemIterator::Q3ListViewItemIterator(Q3ListView *lv)
7312 : curr(lv->firstChild()), listView(lv), flags(0)
7313 {
7314 if (listView)
7315 listView->d->iterators.append(this);
7316 }
7317
7318 /*!
7319 Constructs an iterator for the Q3ListView \a lv with the flags \a
7320 iteratorFlags. The current iterator item is set to point on the
7321 first child (Q3ListViewItem) of \a lv that matches the flags.
7322
7323 \sa Q3ListViewItemIterator::IteratorFlag
7324 */
7325
Q3ListViewItemIterator(Q3ListView * lv,int iteratorFlags)7326 Q3ListViewItemIterator::Q3ListViewItemIterator(Q3ListView *lv, int iteratorFlags)
7327 : curr (lv->firstChild()), listView(lv), flags(iteratorFlags)
7328 {
7329 if (listView)
7330 listView->d->iterators.append(this);
7331 if (!matchesFlags(curr))
7332 ++(*this);
7333 }
7334
7335
7336
7337 /*!
7338 Assignment. Makes a copy of \a it and returns a reference to its
7339 iterator.
7340 */
7341
operator =(const Q3ListViewItemIterator & it)7342 Q3ListViewItemIterator &Q3ListViewItemIterator::operator=(const Q3ListViewItemIterator &it)
7343 {
7344 if (listView)
7345 listView->d->iterators.removeAll(this);
7346
7347 listView = it.listView;
7348 curr = it.curr;
7349 flags = it.flags;
7350 if (listView)
7351 listView->d->iterators.append(this);
7352
7353 // go to next matching item if the current don't match
7354 if (curr && !matchesFlags(curr))
7355 ++(*this);
7356
7357 return *this;
7358 }
7359
7360 /*!
7361 Destroys the iterator.
7362 */
7363
~Q3ListViewItemIterator()7364 Q3ListViewItemIterator::~Q3ListViewItemIterator()
7365 {
7366 if (listView)
7367 listView->d->iterators.removeAll(this);
7368 }
7369
7370 /*!
7371 Prefix ++. Makes the next item the new current item and returns
7372 it. Returns 0 if the current item is the last item or the
7373 Q3ListView is 0.
7374 */
7375
operator ++()7376 Q3ListViewItemIterator &Q3ListViewItemIterator::operator++()
7377 {
7378 if (!curr)
7379 return *this;
7380
7381 Q3ListViewItem *item = curr->firstChild();
7382 if (!item) {
7383 while ((item = curr->nextSibling()) == 0 ) {
7384 curr = curr->parent();
7385 if (curr == 0)
7386 break;
7387 }
7388 }
7389 curr = item;
7390 // if the next one doesn't match the flags we try one more ahead
7391 if (curr && !matchesFlags(curr))
7392 ++(*this);
7393 return *this;
7394 }
7395
7396 /*!
7397 \overload
7398
7399 Postfix ++. Makes the next item the new current item and returns
7400 the item that \e was the current item.
7401 */
7402
operator ++(int)7403 const Q3ListViewItemIterator Q3ListViewItemIterator::operator++(int)
7404 {
7405 Q3ListViewItemIterator oldValue = *this;
7406 ++(*this);
7407 return oldValue;
7408 }
7409
7410 /*!
7411 Sets the current item to the item \a j positions after the current
7412 item. If that item is beyond the last item, the current item is
7413 set to 0. Returns the current item.
7414 */
7415
operator +=(int j)7416 Q3ListViewItemIterator &Q3ListViewItemIterator::operator+=(int j)
7417 {
7418 while (curr && j--)
7419 ++(*this);
7420
7421 return *this;
7422 }
7423
7424 /*!
7425 Prefix --. Makes the previous item the new current item and
7426 returns it. Returns 0 if the current item is the first item or the
7427 Q3ListView is 0.
7428 */
7429
operator --()7430 Q3ListViewItemIterator &Q3ListViewItemIterator::operator--()
7431 {
7432 if (!curr)
7433 return *this;
7434
7435 if (!curr->parent()) {
7436 // we are in the first depth
7437 if (curr->listView()) {
7438 if (curr->listView()->firstChild() != curr) {
7439 // go the previous sibling
7440 Q3ListViewItem *i = curr->listView()->firstChild();
7441 while (i && i->siblingItem != curr)
7442 i = i->siblingItem;
7443
7444 curr = i;
7445
7446 if (i && i->firstChild()) {
7447 // go to the last child of this item
7448 Q3ListViewItemIterator it(curr->firstChild());
7449 for (; it.current() && it.current()->parent(); ++it)
7450 curr = it.current();
7451 }
7452
7453 if (curr && !matchesFlags(curr))
7454 --(*this);
7455
7456 return *this;
7457 } else {
7458 //we are already the first child of the list view, so it's over
7459 curr = 0;
7460 return *this;
7461 }
7462 } else
7463 return *this;
7464 } else {
7465 Q3ListViewItem *parent = curr->parent();
7466
7467 if (curr != parent->firstChild()) {
7468 // go to the previous sibling
7469 Q3ListViewItem *i = parent->firstChild();
7470 while (i && i->siblingItem != curr)
7471 i = i->siblingItem;
7472
7473 curr = i;
7474
7475 if (i && i->firstChild()) {
7476 // go to the last child of this item
7477 Q3ListViewItemIterator it(curr->firstChild());
7478 for (; it.current() && it.current()->parent() != parent; ++it)
7479 curr = it.current();
7480 }
7481
7482 if (curr && !matchesFlags(curr))
7483 --(*this);
7484
7485 return *this;
7486 } else {
7487 // make our parent the current item
7488 curr = parent;
7489
7490 if (curr && !matchesFlags(curr))
7491 --(*this);
7492
7493 return *this;
7494 }
7495 }
7496 }
7497
7498 /*!
7499 \overload
7500
7501 Postfix --. Makes the previous item the new current item and
7502 returns the item that \e was the current item.
7503 */
7504
operator --(int)7505 const Q3ListViewItemIterator Q3ListViewItemIterator::operator--(int)
7506 {
7507 Q3ListViewItemIterator oldValue = *this;
7508 --(*this);
7509 return oldValue;
7510 }
7511
7512 /*!
7513 Sets the current item to the item \a j positions before the
7514 current item. If that item is before the first item, the current
7515 item is set to 0. Returns the current item.
7516 */
7517
operator -=(int j)7518 Q3ListViewItemIterator &Q3ListViewItemIterator::operator-=(int j)
7519 {
7520 while (curr && j--)
7521 --(*this);
7522
7523 return *this;
7524 }
7525
7526 /*!
7527 Dereference operator. Returns a reference to the current item. The
7528 same as current().
7529 */
7530
operator *()7531 Q3ListViewItem* Q3ListViewItemIterator::operator*()
7532 {
7533 if (curr != 0 && !matchesFlags(curr))
7534 qWarning("Q3ListViewItemIterator::operator*() curr out of sync");
7535 return curr;
7536 }
7537
7538 /*!
7539 Returns iterator's current item.
7540 */
7541
current() const7542 Q3ListViewItem *Q3ListViewItemIterator::current() const
7543 {
7544 if (curr != 0 && !matchesFlags(curr))
7545 qWarning("Q3ListViewItemIterator::current() curr out of sync");
7546 return curr;
7547 }
7548
7549 /*
7550 This function is called to notify the iterator that the current
7551 item has been deleted, and sets the current item point to another
7552 (valid) item or 0.
7553 */
7554
currentRemoved()7555 void Q3ListViewItemIterator::currentRemoved()
7556 {
7557 if (!curr) return;
7558
7559 if (curr->parent())
7560 curr = curr->parent();
7561 else if (curr->nextSibling())
7562 curr = curr->nextSibling();
7563 else if (listView && listView->firstChild() &&
7564 listView->firstChild() != curr)
7565 curr = listView->firstChild();
7566 else
7567 curr = 0;
7568 }
7569
7570 /*
7571 returns true if the item \a item matches all of the flags set for the iterator
7572 */
matchesFlags(const Q3ListViewItem * item) const7573 bool Q3ListViewItemIterator::matchesFlags(const Q3ListViewItem *item) const
7574 {
7575 if (!item)
7576 return false;
7577
7578 if (flags == 0)
7579 return true;
7580
7581 if (flags & Visible && !item->isVisible())
7582 return false;
7583 if (flags & Invisible && item->isVisible())
7584 return false;
7585 if (flags & Selected && !item->isSelected())
7586 return false;
7587 if (flags & Unselected && item->isSelected())
7588 return false;
7589 if (flags & Selectable && !item->isSelectable())
7590 return false;
7591 if (flags & NotSelectable && item->isSelectable())
7592 return false;
7593 if (flags & DragEnabled && !item->dragEnabled())
7594 return false;
7595 if (flags & DragDisabled && item->dragEnabled())
7596 return false;
7597 if (flags & DropEnabled && !item->dropEnabled())
7598 return false;
7599 if (flags & DropDisabled && item->dropEnabled())
7600 return false;
7601 if (flags & Expandable && !item->isExpandable())
7602 return false;
7603 if (flags & NotExpandable && item->isExpandable())
7604 return false;
7605 if (flags & Checked && !isChecked(item))
7606 return false;
7607 if (flags & NotChecked && isChecked(item))
7608 return false;
7609
7610 return true;
7611 }
7612
7613 /*
7614 we want the iterator to check Q3CheckListItems as well, so we provide this convenience function
7615 that checks if the rtti() is 1 which means Q3CheckListItem and if isOn is true, returns false otherwise.
7616 */
isChecked(const Q3ListViewItem * item) const7617 bool Q3ListViewItemIterator::isChecked(const Q3ListViewItem *item) const
7618 {
7619 if (item->rtti() == 1)
7620 return ((const Q3CheckListItem*)item)->isOn();
7621 else return false;
7622 }
7623
handleItemChange(Q3ListViewItem * old,bool shift,bool control)7624 void Q3ListView::handleItemChange(Q3ListViewItem *old, bool shift, bool control)
7625 {
7626 if (d->selectionMode == Single) {
7627 // nothing
7628 } else if (d->selectionMode == Extended) {
7629 if (shift) {
7630 selectRange(d->selectAnchor ? d->selectAnchor : old,
7631 d->focusItem, false, true, (d->selectAnchor && !control) ? true : false);
7632 } else if (!control) {
7633 bool block = signalsBlocked();
7634 blockSignals(true);
7635 selectAll(false);
7636 blockSignals(block);
7637 setSelected(d->focusItem, true);
7638 }
7639 } else if (d->selectionMode == Multi) {
7640 if (shift)
7641 selectRange(old, d->focusItem, true, false);
7642 }
7643 }
7644
startRename()7645 void Q3ListView::startRename()
7646 {
7647 if (!currentItem())
7648 return;
7649 currentItem()->startRename(d->pressedColumn);
7650 d->buttonDown = false;
7651 }
7652
7653 /* unselects items from to, including children, returns true if any items were unselected */
clearRange(Q3ListViewItem * from,Q3ListViewItem * to,bool includeFirst)7654 bool Q3ListView::clearRange(Q3ListViewItem *from, Q3ListViewItem *to, bool includeFirst)
7655 {
7656 if (!from || !to)
7657 return false;
7658
7659 // Swap
7660 if (from->itemPos() > to->itemPos()) {
7661 Q3ListViewItem *temp = from;
7662 from = to;
7663 to = temp;
7664 }
7665
7666 // Start on second?
7667 if (!includeFirst) {
7668 Q3ListViewItem *below = (from == to) ? from : from->itemBelow();
7669 if (below)
7670 from = below;
7671 }
7672
7673 // Clear items <from, to>
7674 bool changed = false;
7675
7676 Q3ListViewItemIterator it(from);
7677 while (it.current()) {
7678 if (it.current()->isSelected()) {
7679 it.current()->setSelected(false);
7680 changed = true;
7681 }
7682 if (it.current() == to)
7683 break;
7684 ++it;
7685 }
7686
7687 // NOTE! This function does _not_ emit
7688 // any signals about selection changed
7689 return changed;
7690 }
7691
selectRange(Q3ListViewItem * from,Q3ListViewItem * to,bool invert,bool includeFirst,bool clearSel)7692 void Q3ListView::selectRange(Q3ListViewItem *from, Q3ListViewItem *to, bool invert, bool includeFirst, bool clearSel)
7693 {
7694 if (!from || !to)
7695 return;
7696 if (from == to && !includeFirst)
7697 return;
7698 bool swap = false;
7699 if (to == from->itemAbove())
7700 swap = true;
7701 if (!swap && from != to && from != to->itemAbove()) {
7702 Q3ListViewItemIterator it(from);
7703 bool found = false;
7704 for (; it.current(); ++it) {
7705 if (it.current() == to) {
7706 found = true;
7707 break;
7708 }
7709 }
7710 if (!found)
7711 swap = true;
7712 }
7713 if (swap) {
7714 Q3ListViewItem *i = from;
7715 from = to;
7716 to = i;
7717 if (!includeFirst)
7718 to = to->itemAbove();
7719 } else {
7720 if (!includeFirst)
7721 from = from->itemBelow();
7722 }
7723
7724 bool changed = false;
7725 if (clearSel) {
7726 Q3ListViewItemIterator it(firstChild());
7727 for (; it.current(); ++it) {
7728 if (it.current()->selected) {
7729 it.current()->setSelected(false);
7730 changed = true;
7731 }
7732 }
7733 it = Q3ListViewItemIterator(to);
7734 for (; it.current(); ++it) {
7735 if (it.current()->selected) {
7736 it.current()->setSelected(false);
7737 changed = true;
7738 }
7739 }
7740 }
7741
7742 for (Q3ListViewItem *i = from; i; i = i->itemBelow()) {
7743 if (!invert) {
7744 if (!i->selected && i->isSelectable()) {
7745 i->setSelected(true);
7746 changed = true;
7747 }
7748 } else {
7749 bool sel = !i->selected;
7750 if (((bool)i->selected != sel && sel && i->isSelectable()) || !sel) {
7751 i->setSelected(sel);
7752 changed = true;
7753 }
7754 }
7755 if (i == to)
7756 break;
7757 }
7758 if (changed) {
7759 triggerUpdate();
7760 emit selectionChanged();
7761 }
7762 }
7763
7764 /* clears selection from anchor to old, selects from anchor to new, does not emit selectionChanged on change */
selectRange(Q3ListViewItem * newItem,Q3ListViewItem * oldItem,Q3ListViewItem * anchorItem)7765 bool Q3ListView::selectRange(Q3ListViewItem *newItem, Q3ListViewItem *oldItem, Q3ListViewItem *anchorItem)
7766 {
7767 if (!newItem || !oldItem || !anchorItem)
7768 return false;
7769
7770 int anchorPos = anchorItem ? anchorItem->itemPos() : 0,
7771 oldPos = oldItem ? oldItem->itemPos() : 0,
7772 newPos = newItem->itemPos();
7773 Q3ListViewItem *top=0, *bottom=0;
7774 if (anchorPos > newPos) {
7775 top = newItem;
7776 bottom = anchorItem;
7777 } else {
7778 top = anchorItem;
7779 bottom = newItem;
7780 }
7781
7782 // removes the subControls of the old selection that will no longer be selected
7783 bool changed = false;
7784 int topPos = top ? top->itemPos() : 0,
7785 bottomPos = bottom ? bottom->itemPos() : 0;
7786 if (!(oldPos > topPos && oldPos < bottomPos)) {
7787 if (oldPos < topPos)
7788 changed = clearRange(oldItem, top);
7789 else
7790 changed = clearRange(bottom, oldItem);
7791 }
7792
7793 // selects the new (not already selected) items
7794 Q3ListViewItemIterator lit(top);
7795 for (; lit.current(); ++lit) {
7796 if ((bool)lit.current()->selected != d->select) {
7797 lit.current()->setSelected(d->select);
7798 changed = true;
7799 }
7800 // Include bottom, then break
7801 if (lit.current() == bottom)
7802 break;
7803 }
7804
7805 return changed;
7806 }
7807
7808
7809 /*!
7810 Finds the first list view item in column \a column, that matches
7811 \a text and returns the item, or returns 0 of no such item could
7812 be found. Pass OR-ed together \l ComparisonFlags values
7813 in the \a compare flag, to control how the matching is performed.
7814 The default comparison mode is case-sensitive, exact match.
7815 */
7816
findItem(const QString & text,int column,ComparisonFlags compare) const7817 Q3ListViewItem *Q3ListView::findItem(const QString& text, int column,
7818 ComparisonFlags compare) const
7819 {
7820 if (text.isEmpty() && !(compare & ExactMatch))
7821 return 0;
7822
7823 if (compare == Qt::CaseSensitive || compare == 0)
7824 compare |= ExactMatch;
7825
7826 QString itmtxt;
7827 QString comtxt = text;
7828 if (!(compare & Qt::CaseSensitive))
7829 comtxt = comtxt.toLower();
7830
7831 Q3ListViewItemIterator it(d->focusItem ? d->focusItem : firstChild());
7832 Q3ListViewItem *sentinel = 0;
7833 Q3ListViewItem *item;
7834 Q3ListViewItem *beginsWithItem = 0;
7835 Q3ListViewItem *endsWithItem = 0;
7836 Q3ListViewItem *containsItem = 0;
7837
7838 for (int pass = 0; pass < 2; pass++) {
7839 while ((item = it.current()) != sentinel) {
7840 itmtxt = item->text(column);
7841 if (!(compare & CaseSensitive))
7842 itmtxt = itmtxt.toLower();
7843
7844 if ((compare & ExactMatch)==ExactMatch && itmtxt == comtxt)
7845 return item;
7846 if (compare & BeginsWith && !beginsWithItem && itmtxt.startsWith(comtxt))
7847 beginsWithItem = containsItem = item;
7848 if (compare & EndsWith && !endsWithItem && itmtxt.endsWith(comtxt))
7849 endsWithItem = containsItem = item;
7850 if ((compare & ExactMatch)==0 && !containsItem && itmtxt.contains(comtxt))
7851 containsItem = item;
7852 ++it;
7853 }
7854
7855 it = Q3ListViewItemIterator(firstChild());
7856 sentinel = d->focusItem ? d->focusItem : firstChild();
7857 }
7858
7859 // Obey the priorities
7860 if (beginsWithItem)
7861 return beginsWithItem;
7862 else if (endsWithItem)
7863 return endsWithItem;
7864 else if (containsItem)
7865 return containsItem;
7866 return 0;
7867 }
7868
7869 /*!
7870 Hides the column specified at \a column. This is a convenience
7871 function that calls setColumnWidth(column, 0).
7872
7873 Note: The user may still be able to resize the hidden column using
7874 the header handles. To prevent this, call setResizeEnabled(false,
7875 \a column) on the list views header.
7876
7877 \sa setColumnWidth()
7878 */
7879
hideColumn(int column)7880 void Q3ListView::hideColumn(int column)
7881 {
7882 setColumnWidth(column, 0);
7883 }
7884
7885 /*! Adjusts the column \a col to its preferred width */
7886
adjustColumn(int col)7887 void Q3ListView::adjustColumn(int col)
7888 {
7889 if (col < 0 || col > (int)d->column.count() - 1 || d->h->isStretchEnabled(col))
7890 return;
7891
7892 int oldw = d->h->sectionSize(col);
7893
7894 int w = d->h->sectionSizeHint(col, fontMetrics()).width();
7895 if (d->h->iconSet(col))
7896 w += d->h->iconSet(col)->pixmap().width();
7897 w = qMax(w, 20);
7898 QFontMetrics fm(fontMetrics());
7899 Q3ListViewItem* item = firstChild();
7900 int rootDepth = rootIsDecorated() ? treeStepSize() : 0;
7901 while (item) {
7902 int iw = item->width(fm, this, col);
7903 if (0 == col)
7904 iw += itemMargin() + rootDepth + item->depth()*treeStepSize() - 1;
7905 w = qMax(w, iw);
7906 item = item->itemBelow();
7907 }
7908 w = qMax(w, QApplication::globalStrut().width());
7909
7910 d->h->adjustHeaderSize(oldw - w);
7911 if (oldw != w) {
7912 d->fullRepaintOnComlumnChange = true;
7913 d->h->resizeSection(col, w);
7914 emit d->h->sizeChange(col, oldw, w);
7915 }
7916 }
7917
7918 /*!
7919 \enum Q3ListView::StringComparisonMode
7920
7921 This enum type is used to set the string comparison mode when
7922 searching for an item. We'll refer to the string being searched
7923 as the 'target' string.
7924
7925 \value CaseSensitive The strings must match case sensitively.
7926 \value ExactMatch The target and search strings must match exactly.
7927 \value BeginsWith The target string begins with the search string.
7928 \value EndsWith The target string ends with the search string.
7929 \value Contains The target string contains the search string.
7930
7931 If you OR these flags together (excluding \c CaseSensitive), the
7932 search criteria be applied in the following order: \c ExactMatch,
7933 \c BeginsWith, \c EndsWith, \c Contains.
7934
7935 Matching is case-insensitive unless \c CaseSensitive is set. \c
7936 CaseSensitive can be OR-ed with any combination of the other
7937 flags.
7938
7939 \sa ComparisonFlags
7940 */
7941
7942 /*!
7943 \typedef Q3ListView::ComparisonFlags
7944
7945 This typedef is used in Q3ListView's API for values that are OR'd
7946 combinations of \l StringComparisonMode values.
7947
7948 \sa StringComparisonMode
7949 */
7950
7951 QT_END_NAMESPACE
7952
7953 #endif // QT_NO_LISTVIEW
7954