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