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 "qglobal.h"
43 #if defined(Q_CC_BOR)
44 // needed for qsort() because of a std namespace problem on Borland
45 #include "qplatformdefs.h"
46 #endif
47 
48 #include "q3listbox.h"
49 #ifndef QT_NO_LISTBOX
50 #include "qapplication.h"
51 #include "qevent.h"
52 #include "qfontmetrics.h"
53 #include "qpainter.h"
54 #include "qpixmap.h"
55 #include "qstringlist.h"
56 #include "qstyle.h"
57 #include "qstyleoption.h"
58 #include "qtimer.h"
59 #include "qvector.h"
60 #include "qpointer.h"
61 #ifndef QT_NO_ACCESSIBILITY
62 #include "qaccessible.h"
63 #endif
64 
65 #include <stdlib.h>
66 
67 QT_BEGIN_NAMESPACE
68 
69 class Q3ListBoxPrivate
70 {
71 public:
Q3ListBoxPrivate(Q3ListBox * lb)72     Q3ListBoxPrivate(Q3ListBox *lb):
73         head(0), last(0), cache(0), cacheIndex(-1), current(0),
74         highlighted(0), tmpCurrent(0), columnPos(1), rowPos(1), rowPosCache(0),
75         columnPosOne(0), rowMode(Q3ListBox::FixedNumber),
76         columnMode(Q3ListBox::FixedNumber), numRows(1), numColumns(1),
77         currentRow(0), currentColumn(0),
78         mousePressRow(-1), mousePressColumn(-1),
79         mouseMoveRow(-1), mouseMoveColumn(-1), mouseInternalPress(false),
80         scrollTimer(0), updateTimer(0), visibleTimer(0),
81         selectionMode(Q3ListBox::Single),
82         count(0),
83         listBox(lb), currInputString(QString()),
84         rowModeWins(false),
85         ignoreMoves(false),
86         layoutDirty(true),
87         mustPaintAll(true),
88         dragging(false),
89         dirtyDrag (false),
90         variableHeight(true /* !!! ### false */),
91         variableWidth(false),
92         inMenuMode(false)
93     {}
94     int findItemByName(int item, const QString &text);
95     ~Q3ListBoxPrivate();
96 
97     Q3ListBoxItem * head, *last, *cache;
98     int cacheIndex;
99     Q3ListBoxItem * current, *highlighted, *tmpCurrent;
100 
101     QVector<int> columnPos;
102     QVector<int> rowPos;
103     int rowPosCache;
104     int columnPosOne;
105 
106     Q3ListBox::LayoutMode rowMode;
107     Q3ListBox::LayoutMode columnMode;
108     int numRows;
109     int numColumns;
110 
111     int currentRow;
112     int currentColumn;
113     int mousePressRow;
114     int mousePressColumn;
115     int mouseMoveRow;
116     int mouseMoveColumn;
117     bool mouseInternalPress;
118 
119     QTimer * scrollTimer;
120     QTimer * updateTimer;
121     QTimer * visibleTimer;
122     QTimer * resizeTimer;
123 
124     QPoint scrollPos;
125 
126     Q3ListBox::SelectionMode selectionMode;
127 
128     int count;
129 
130 
131     Q3ListBox *listBox;
132     QString currInputString;
133     QTimer *inputTimer;
134 
135     Q3ListBoxItem *pressedItem, *selectAnchor;
136 
137     uint select :1;
138     uint pressedSelected :1;
139     uint rowModeWins :1;
140     uint ignoreMoves :1;
141     uint clearing :1;
142     uint layoutDirty :1;
143     uint mustPaintAll :1;
144     uint dragging :1;
145     uint dirtyDrag :1;
146     uint variableHeight :1;
147     uint variableWidth :1;
148     uint inMenuMode :1;
149 
150     QRect *rubber;
151 
152     struct SortableItem {
153         Q3ListBoxItem *item;
154     };
155 };
156 
157 
~Q3ListBoxPrivate()158 Q3ListBoxPrivate::~Q3ListBoxPrivate()
159 {
160     Q_ASSERT(!head);
161 }
162 
163 
164 /*!
165     \class Q3ListBoxItem
166     \brief The Q3ListBoxItem class is the base class of all list box items.
167 
168     \compat
169 
170     This class is an abstract base class used for all list box items.
171     If you need to insert customized items into a Q3ListBox you must
172     inherit this class and reimplement paint(), height() and width().
173 
174     \sa Q3ListBox
175 */
176 
177 /*!
178     Constructs an empty list box item in the list box \a listbox.
179 */
180 
Q3ListBoxItem(Q3ListBox * listbox)181 Q3ListBoxItem::Q3ListBoxItem(Q3ListBox* listbox)
182 {
183     lbox = listbox;
184     s = false;
185     dirty = true;
186     custom_highlight = false;
187     selectable = true;
188     p = n = 0;
189 
190     if (listbox)
191         listbox->insertItem(this);
192 }
193 
194 /*!
195     Constructs an empty list box item in the list box \a listbox and
196     inserts it after the item \a after or at the beginning if \a after
197     is 0.
198 */
199 
Q3ListBoxItem(Q3ListBox * listbox,Q3ListBoxItem * after)200 Q3ListBoxItem::Q3ListBoxItem(Q3ListBox* listbox, Q3ListBoxItem *after)
201 {
202     lbox = listbox;
203     s = false;
204     dirty = true;
205     custom_highlight = false;
206     selectable = true;
207     p = n = 0;
208 
209     if (listbox)
210         listbox->insertItem(this, after);
211 }
212 
213 
214 /*!
215     Destroys the list box item.
216 */
217 
~Q3ListBoxItem()218 Q3ListBoxItem::~Q3ListBoxItem()
219 {
220     if (lbox)
221         lbox->takeItem(this);
222 }
223 
224 
225 /*!
226     Defines whether the list box item is responsible for drawing
227     itself in a highlighted state when being selected.
228 
229     If \a b is false (the default), the list box will draw some
230     default highlight indicator before calling paint().
231 
232     \sa isSelected(), paint()
233 */
setCustomHighlighting(bool b)234 void Q3ListBoxItem::setCustomHighlighting(bool b)
235 {
236     custom_highlight = b;
237 }
238 
239 /*!
240     \fn void Q3ListBoxItem::paint(QPainter *p)
241 
242     Implement this function to draw your item. The painter, \a p, is
243     already open for painting.
244 
245     \sa height(), width()
246 */
247 
248 /*!
249     \fn int Q3ListBoxItem::width(const Q3ListBox* lb) const
250 
251     Reimplement this function to return the width of your item. The \a
252     lb parameter is the same as listBox() and is provided for
253     convenience and compatibility.
254 
255     The default implementation returns
256     \l{QApplication::globalStrut()}'s width.
257 
258     \sa paint(), height()
259 */
width(const Q3ListBox *) const260 int Q3ListBoxItem::width(const Q3ListBox*)  const
261 {
262     return QApplication::globalStrut().width();
263 }
264 
265 /*!
266     \fn int Q3ListBoxItem::height(const Q3ListBox* lb) const
267 
268     Implement this function to return the height of your item. The \a
269     lb parameter is the same as listBox() and is provided for
270     convenience and compatibility.
271 
272     The default implementation returns
273     \l{QApplication::globalStrut()}'s height.
274 
275     \sa paint(), width()
276 */
height(const Q3ListBox *) const277 int Q3ListBoxItem::height(const Q3ListBox*)  const
278 {
279     return QApplication::globalStrut().height();
280 }
281 
282 
283 /*!
284     Returns the text of the item. This text is also used for sorting.
285 
286     \sa setText()
287 */
text() const288 QString Q3ListBoxItem::text() const
289 {
290     return txt;
291 }
292 
293 /*!
294     Returns the pixmap associated with the item, or 0 if there isn't
295     one.
296 
297     The default implementation returns 0.
298 */
pixmap() const299 const QPixmap *Q3ListBoxItem::pixmap() const
300 {
301     return 0;
302 }
303 
304 /*! \fn void Q3ListBoxItem::setSelectable(bool b)
305 
306     If \a b is true (the default) then this item can be selected by
307     the user; otherwise this item cannot be selected by the user.
308 
309     \sa isSelectable()
310 */
311 
312 /*! \fn bool Q3ListBoxItem::isSelectable() const
313 
314     Returns true if this item is selectable (the default); otherwise
315     returns false.
316 
317     \sa setSelectable()
318 */
319 
320 
321 /*!
322     \fn void Q3ListBoxItem::setText(const QString &text)
323 
324     Sets the text of the Q3ListBoxItem to \a text. This \a text is also
325     used for sorting. The text is not shown unless explicitly drawn in
326     paint().
327 
328     \sa text()
329 */
330 
331 
332 /*!
333     \class Q3ListBoxText
334     \brief The Q3ListBoxText class provides list box items that display text.
335 
336     \compat
337 
338     The text is drawn in the widget's current font. If you need
339     several different fonts, you must implement your own subclass of
340     Q3ListBoxItem.
341 
342     \sa Q3ListBox, Q3ListBoxItem
343 */
344 
345 
346 /*!
347     Constructs a list box item in list box \a listbox showing the text
348     \a text.
349 */
Q3ListBoxText(Q3ListBox * listbox,const QString & text)350 Q3ListBoxText::Q3ListBoxText(Q3ListBox *listbox, const QString &text)
351     :Q3ListBoxItem(listbox)
352 {
353     setText(text);
354 }
355 
356 /*!
357     Constructs a list box item showing the text \a text.
358 */
359 
Q3ListBoxText(const QString & text)360 Q3ListBoxText::Q3ListBoxText(const QString &text)
361     :Q3ListBoxItem()
362 {
363     setText(text);
364 }
365 
366 /*!
367     Constructs a list box item in list box \a listbox showing the text
368     \a text. The item is inserted after the item \a after, or at the
369     beginning if \a after is 0.
370 */
371 
Q3ListBoxText(Q3ListBox * listbox,const QString & text,Q3ListBoxItem * after)372 Q3ListBoxText::Q3ListBoxText(Q3ListBox* listbox, const QString &text, Q3ListBoxItem *after)
373     : Q3ListBoxItem(listbox, after)
374 {
375     setText(text);
376 }
377 
378 /*!
379     Destroys the item.
380 */
381 
~Q3ListBoxText()382 Q3ListBoxText::~Q3ListBoxText()
383 {
384 }
385 
386 /*!
387     Draws the text using \a painter.
388 */
389 
paint(QPainter * painter)390 void Q3ListBoxText::paint(QPainter *painter)
391 {
392     int itemHeight = height(listBox());
393     QFontMetrics fm = painter->fontMetrics();
394     int yPos = ((itemHeight - fm.height()) / 2) + fm.ascent();
395     painter->drawText(3, yPos, text());
396 }
397 
398 /*!
399     Returns the height of a line of text in list box \a lb.
400 
401     \sa paint(), width()
402 */
403 
height(const Q3ListBox * lb) const404 int Q3ListBoxText::height(const Q3ListBox* lb) const
405 {
406     int h = lb ? lb->fontMetrics().lineSpacing() + 2 : 0;
407     return qMax(h, QApplication::globalStrut().height());
408 }
409 
410 /*!
411     Returns the width of this line in list box \a lb.
412 
413     \sa paint(), height()
414 */
415 
width(const Q3ListBox * lb) const416 int Q3ListBoxText::width(const Q3ListBox* lb) const
417 {
418     int w = lb ? lb->fontMetrics().width(text()) + 6 : 0;
419     return qMax(w, QApplication::globalStrut().width());
420 }
421 
422 /*!
423     \fn int Q3ListBoxText::rtti() const
424 
425     \reimp
426 
427     Returns 1.
428 
429     Make your derived classes return their own values for rtti(), and
430     you can distinguish between listbox items. You should use values
431     greater than 1000 preferably a large random number, to allow for
432     extensions to this class.
433 */
434 
rtti() const435 int Q3ListBoxText::rtti() const
436 {
437     return RTTI;
438 }
439 
440 /*!
441     \class Q3ListBoxPixmap
442     \brief The Q3ListBoxPixmap class provides list box items with a
443     pixmap and optional text.
444 
445     \compat
446 
447     Items of this class are drawn with the pixmap on the left with the
448     optional text to the right of the pixmap.
449 
450     \sa Q3ListBox, Q3ListBoxItem
451 */
452 
453 
454 /*!
455     Constructs a new list box item in list box \a listbox showing the
456     pixmap \a pixmap.
457 */
458 
Q3ListBoxPixmap(Q3ListBox * listbox,const QPixmap & pixmap)459 Q3ListBoxPixmap::Q3ListBoxPixmap(Q3ListBox* listbox, const QPixmap &pixmap)
460     : Q3ListBoxItem(listbox)
461 {
462     pm = pixmap;
463 }
464 
465 /*!
466     Constructs a new list box item showing the pixmap \a pixmap.
467 */
468 
Q3ListBoxPixmap(const QPixmap & pixmap)469 Q3ListBoxPixmap::Q3ListBoxPixmap(const QPixmap &pixmap)
470     : Q3ListBoxItem()
471 {
472     pm = pixmap;
473 }
474 
475 /*!
476     Constructs a new list box item in list box \a listbox showing the
477     pixmap \a pixmap. The item gets inserted after the item \a after,
478     or at the beginning if \a after is 0.
479 */
480 
Q3ListBoxPixmap(Q3ListBox * listbox,const QPixmap & pixmap,Q3ListBoxItem * after)481 Q3ListBoxPixmap::Q3ListBoxPixmap(Q3ListBox* listbox, const QPixmap &pixmap, Q3ListBoxItem *after)
482     : Q3ListBoxItem(listbox, after)
483 {
484     pm = pixmap;
485 }
486 
487 
488 /*!
489     Destroys the item.
490 */
491 
~Q3ListBoxPixmap()492 Q3ListBoxPixmap::~Q3ListBoxPixmap()
493 {
494 }
495 
496 
497 /*!
498     Constructs a new list box item in list box \a listbox showing the
499     pixmap \a pix and the text \a text.
500 */
Q3ListBoxPixmap(Q3ListBox * listbox,const QPixmap & pix,const QString & text)501 Q3ListBoxPixmap::Q3ListBoxPixmap(Q3ListBox* listbox, const QPixmap &pix, const QString& text)
502     : Q3ListBoxItem(listbox)
503 {
504     pm = pix;
505     setText(text);
506 }
507 
508 /*!
509     Constructs a new list box item showing the pixmap \a pix and the
510     text to \a text.
511 */
Q3ListBoxPixmap(const QPixmap & pix,const QString & text)512 Q3ListBoxPixmap::Q3ListBoxPixmap(const QPixmap & pix, const QString& text)
513     : Q3ListBoxItem()
514 {
515     pm = pix;
516     setText(text);
517 }
518 
519 /*!
520     Constructs a new list box item in list box \a listbox showing the
521     pixmap \a pix and the string \a text. The item gets inserted after
522     the item \a after, or at the beginning if \a after is 0.
523 */
Q3ListBoxPixmap(Q3ListBox * listbox,const QPixmap & pix,const QString & text,Q3ListBoxItem * after)524 Q3ListBoxPixmap::Q3ListBoxPixmap(Q3ListBox* listbox, const QPixmap & pix, const QString& text,
525                                 Q3ListBoxItem *after)
526     : Q3ListBoxItem(listbox, after)
527 {
528     pm = pix;
529     setText(text);
530 }
531 
532 /*!
533     \fn const QPixmap *Q3ListBoxPixmap::pixmap() const
534 
535     Returns the pixmap associated with the item.
536 */
537 
538 
539 /*!
540     Draws the pixmap using \a painter.
541 */
542 
paint(QPainter * painter)543 void Q3ListBoxPixmap::paint(QPainter *painter)
544 {
545     int itemHeight = height(listBox());
546     int yPos;
547 
548     const QPixmap *pm = pixmap();
549     if (pm && ! pm->isNull()) {
550         yPos = (itemHeight - pm->height()) / 2;
551         painter->drawPixmap(3, yPos, *pm);
552     }
553 
554     if (!text().isEmpty()) {
555         QFontMetrics fm = painter->fontMetrics();
556         yPos = ((itemHeight - fm.height()) / 2) + fm.ascent();
557         painter->drawText(pm->width() + 5, yPos, text());
558     }
559 }
560 
561 /*!
562     Returns the height of the pixmap in list box \a lb.
563 
564     \sa paint(), width()
565 */
566 
height(const Q3ListBox * lb) const567 int Q3ListBoxPixmap::height(const Q3ListBox* lb) const
568 {
569     int h;
570     if (text().isEmpty())
571         h = pm.height();
572     else
573         h = qMax(pm.height(), lb->fontMetrics().lineSpacing() + 2);
574     return qMax(h, QApplication::globalStrut().height());
575 }
576 
577 /*!
578     Returns the width of the pixmap plus some margin in list box \a lb.
579 
580     \sa paint(), height()
581 */
582 
width(const Q3ListBox * lb) const583 int Q3ListBoxPixmap::width(const Q3ListBox* lb) const
584 {
585     if (text().isEmpty())
586         return qMax(pm.width() + 6, QApplication::globalStrut().width());
587     return qMax(pm.width() + lb->fontMetrics().width(text()) + 6,
588             QApplication::globalStrut().width());
589 }
590 
591 /*!
592     \fn int Q3ListBoxPixmap::rtti() const
593 
594     \reimp
595 
596     Returns 2.
597 
598     Make your derived classes return their own values for rtti(), and
599     you can distinguish between listbox items. You should use values
600     greater than 1000 preferably a large random number, to allow for
601     extensions to this class.
602 */
603 
rtti() const604 int Q3ListBoxPixmap::rtti() const
605 {
606     return RTTI;
607 }
608 
609 /*!
610     \class Q3ListBox
611     \brief The Q3ListBox widget provides a list of selectable, read-only items.
612 
613     \compat
614 
615     This is typically a single-column list in which either no item or
616     one item is selected, but it can also be used in many other ways.
617 
618     Q3ListBox will add scroll bars as necessary, but it isn't intended
619     for \e really big lists. If you want more than a few thousand
620     items, it's probably better to use a different widget mainly
621     because the scroll bars won't provide very good navigation, but
622     also because Q3ListBox may become slow with huge lists. (See
623     Q3ListView and Q3Table for possible alternatives.)
624 
625     There are a variety of selection modes described in the
626     Q3ListBox::SelectionMode documentation. The default is \l Single
627     selection mode, but you can change it using setSelectionMode().
628     (setMultiSelection() is still provided for compatibility with Qt
629     1.x. We recommend using setSelectionMode() in all code.)
630 
631     Because Q3ListBox offers multiple selection it must display
632     keyboard focus and selection state separately. Therefore there are
633     functions both to set the selection state of an item, i.e.
634     setSelected(), and to set which item displays keyboard focus, i.e.
635     setCurrentItem().
636 
637     The list box normally arranges its items in a single column and
638     adds a vertical scroll bar if required. It is possible to have a
639     different fixed number of columns (setColumnMode()), or as many
640     columns as will fit in the list box's assigned screen space
641     (setColumnMode(FitToWidth)), or to have a fixed number of rows
642     (setRowMode()) or as many rows as will fit in the list box's
643     assigned screen space (setRowMode(FitToHeight)). In all these
644     cases Q3ListBox will add scroll bars, as appropriate, in at least
645     one direction.
646 
647     If multiple rows are used, each row can be as high as necessary
648     (the normal setting), or you can request that all items will have
649     the same height by calling setVariableHeight(false). The same
650     applies to a column's width, see setVariableWidth().
651 
652     The Q3ListBox's items are Q3ListBoxItem objects. Q3ListBox provides
653     methods to insert new items as strings, as pixmaps, and as
654     Q3ListBoxItem * (insertItem() with various arguments), and to
655     replace an existing item with a new string, pixmap or Q3ListBoxItem
656     (changeItem() with various arguments). You can also remove items
657     singly with removeItem() or clear() the entire list box. Note that
658     if you create a Q3ListBoxItem yourself and insert it, Q3ListBox
659     takes ownership of the item.
660 
661     You can also create a Q3ListBoxItem, such as Q3ListBoxText or
662     Q3ListBoxPixmap, with the list box as first parameter. The item
663     will then append itself. When you delete an item it is
664     automatically removed from the list box.
665 
666     The list of items can be arbitrarily large; Q3ListBox will add
667     scroll bars if necessary. Q3ListBox can display a single-column
668     (the common case) or multiple-columns, and offers both single and
669     multiple selection. Q3ListBox does not support multiple-column
670     items (but Q3ListView and Q3Table do), or tree hierarchies (but
671     Q3ListView does).
672 
673     The list box items can be accessed both as Q3ListBoxItem objects
674     (recommended) and using integer indexes (the original Q3ListBox
675     implementation used an array of strings internally, and the API
676     still supports this mode of operation). Everything can be done
677     using the new objects, and most things can be done using indexes.
678 
679     Each item in a Q3ListBox contains a Q3ListBoxItem. One of the items
680     can be the current item. The currentChanged() signal and the
681     highlighted() signal are emitted when a new item becomes current,
682     e.g. because the user clicks on it or Q3ListBox::setCurrentItem()
683     is called. The selected() signal is emitted when the user
684     double-clicks on an item or presses Enter on the current item.
685 
686     If the user does not select anything, no signals are emitted and
687     currentItem() returns -1.
688 
689     A list box has Qt::WheelFocus as a default focusPolicy(), i.e. it
690     can get keyboard focus by tabbing, clicking and through the use of
691     the mouse wheel.
692 
693     New items can be inserted using insertItem(), insertStrList() or
694     insertStringList().
695 
696     By default, vertical and horizontal scroll bars are added and
697     removed as necessary. setHScrollBarMode() and setVScrollBarMode()
698     can be used to change this policy.
699 
700     If you need to insert types other than strings and pixmaps, you
701     must define new classes which inherit Q3ListBoxItem.
702 
703     \warning The list box assumes ownership of all list box items and
704     will delete them when it does not need them any more.
705 
706     \inlineimage qlistbox-m.png Screenshot in Motif style
707     \inlineimage qlistbox-w.png Screenshot in Windows style
708 
709     \sa Q3ListView, QComboBox, QButtonGroup
710 */
711 
712 /*!
713     \enum Q3ListBox::SelectionMode
714 
715     This enumerated type is used by Q3ListBox to indicate how it reacts
716     to selection by the user.
717 
718     \value Single  When the user selects an item, any already-selected
719     item becomes unselected and the user cannot unselect the selected
720     item. This means that the user can never clear the selection, even
721     though the selection may be cleared by the application programmer
722     using Q3ListBox::clearSelection().
723 
724     \value Multi  When the user selects an item the selection status
725     of that item is toggled and the other items are left alone.
726 
727     \value Extended When the user selects an item the selection is
728     cleared and the new item selected. However, if the user presses
729     the Ctrl key when clicking on an item, the clicked item gets
730     toggled and all other items are left untouched. And if the user
731     presses the Shift key while clicking on an item, all items between
732     the current item and the clicked item get selected or unselected,
733     depending on the state of the clicked item. Also, multiple items
734     can be selected by dragging the mouse while the left mouse button
735     is kept pressed.
736 
737     \value NoSelection  Items cannot be selected.
738 
739     In other words, \c Single is a real single-selection list box, \c
740     Multi is a real multi-selection list box, \c Extended is a list
741     box in which users can select multiple items but usually want to
742     select either just one or a range of contiguous items, and \c
743     NoSelection is for a list box where the user can look but not
744     touch.
745 */
746 
747 
748 /*!
749     \enum Q3ListBox::LayoutMode
750 
751     This enum type is used to specify how Q3ListBox lays out its rows
752     and columns.
753 
754     \value FixedNumber  There is a fixed number of rows (or columns).
755 
756     \value FitToWidth   There are as many columns as will fit
757     on-screen.
758 
759     \value FitToHeight  There are as many rows as will fit on-screen.
760 
761     \value Variable  There are as many rows as are required by the
762     column mode. (Or as many columns as required by the row mode.)
763 
764     Example: When you call setRowMode(FitToHeight), columnMode()
765     automatically becomes \c Variable to accommodate the row mode
766     you've set.
767 */
768 
769 /*!
770     \fn void  Q3ListBox::onItem(Q3ListBoxItem *i)
771 
772     This signal is emitted when the user moves the mouse cursor onto
773     an item, similar to the QWidget::enterEvent() function. \a i is
774     the Q3ListBoxItem that the mouse has moved on.
775 */
776 
777 // ### bug here too? enter/leave event may noit considered. move the
778 // mouse out of the window and back in, to the same item - does it
779 // work?
780 
781 /*!
782     \fn void  Q3ListBox::onViewport()
783 
784     This signal is emitted when the user moves the mouse cursor from
785     an item to an empty part of the list box.
786 */
787 
788 
789 /*!
790     Constructs a new empty list box called \a name and with parent \a
791     parent and widget attributes \a f.
792 
793     This constructor sets the Qt::WA_StaticContent and the
794     Qt::WA_NoBackground attributes to boost performance when drawing
795     Q3ListBoxItems. This may be unsuitable for custom Q3ListBoxItem
796     classes, in which case Qt::WA_StaticContents and Qt::WA_NoBackground
797     should be cleared on the viewport() after construction.
798 */
799 
Q3ListBox(QWidget * parent,const char * name,Qt::WindowFlags f)800 Q3ListBox::Q3ListBox(QWidget *parent, const char *name, Qt::WindowFlags f)
801     : Q3ScrollView(parent, name, f | Qt::WStaticContents | Qt::WNoAutoErase)
802 {
803     d = new Q3ListBoxPrivate(this);
804     d->updateTimer = new QTimer(this, "listbox update timer");
805     d->visibleTimer = new QTimer(this, "listbox visible timer");
806     d->inputTimer = new QTimer(this, "listbox input timer");
807     d->resizeTimer = new QTimer(this, "listbox resize timer");
808     d->clearing = false;
809     d->pressedItem = 0;
810     d->selectAnchor = 0;
811     d->select = false;
812     d->rubber = 0;
813 
814     setMouseTracking(true);
815     viewport()->setMouseTracking(true);
816 
817     connect(d->updateTimer, SIGNAL(timeout()),
818              this, SLOT(refreshSlot()));
819     connect(d->visibleTimer, SIGNAL(timeout()),
820              this, SLOT(ensureCurrentVisible()));
821     connect(d->resizeTimer, SIGNAL(timeout()),
822              this, SLOT(adjustItems()));
823     viewport()->setBackgroundRole(QPalette::Base);
824     viewport()->setFocusProxy(this);
825     viewport()->setFocusPolicy(Qt::WheelFocus);
826     setFocusPolicy(Qt::WheelFocus);
827     setAttribute(Qt::WA_MacShowFocusRect);
828 }
829 
830 
831 Q3ListBox * Q3ListBox::changedListBox = 0;
832 
833 /*!
834     Destroys the list box. Deletes all list box items.
835 */
836 
~Q3ListBox()837 Q3ListBox::~Q3ListBox()
838 {
839     if (changedListBox == this)
840         changedListBox = 0;
841     clear();
842     delete d;
843     d = 0;
844 }
845 
846 /*!
847     \fn void Q3ListBox::pressed(Q3ListBoxItem *item)
848 
849     This signal is emitted when the user presses any mouse button. If
850     \a item is not 0, the cursor is on \a item. If \a item is 0, the
851     mouse cursor isn't on any item.
852 
853     Note that you must not delete any Q3ListBoxItem objects in slots
854     connected to this signal.
855 */
856 
857 /*!
858     \fn void Q3ListBox::pressed(Q3ListBoxItem *item, const QPoint &pnt)
859     \overload
860 
861     This signal is emitted when the user presses any mouse button. If
862     \a item is not 0, the cursor is on \a item. If \a item is 0, the
863     mouse cursor isn't on any item.
864 
865     \a pnt is the position of the mouse cursor in the global
866     coordinate system (QMouseEvent::globalPos()).
867 
868     Note that you must not delete any Q3ListBoxItem objects in slots
869     connected to this signal.
870 
871     \sa mouseButtonPressed() rightButtonPressed() clicked()
872 */
873 
874 /*!
875     \fn void Q3ListBox::clicked(Q3ListBoxItem *item)
876 
877     This signal is emitted when the user clicks any mouse button. If
878     \a item is not 0, the cursor is on \a item. If \a item is 0, the
879     mouse cursor isn't on any item.
880 
881     Note that you must not delete any Q3ListBoxItem objects in slots
882     connected to this signal.
883 */
884 
885 /*!
886     \fn void Q3ListBox::clicked(Q3ListBoxItem *item, const QPoint &pnt)
887     \overload
888 
889     This signal is emitted when the user clicks any mouse button. If
890     \a item is not 0, the cursor is on \a item. If \a item is 0, the
891     mouse cursor isn't on any item.
892 
893     \a pnt is the position of the mouse cursor in the global
894     coordinate system (QMouseEvent::globalPos()). (If the click's
895     press and release differs by a pixel or two, \a pnt is the
896     position at release time.)
897 
898     Note that you must not delete any Q3ListBoxItem objects in slots
899     connected to this signal.
900 */
901 
902 /*!
903     \fn void Q3ListBox::mouseButtonClicked (int button, Q3ListBoxItem * item, const QPoint & pos)
904 
905     This signal is emitted when the user clicks mouse button \a
906     button. If \a item is not 0, the cursor is on \a item. If \a item
907     is 0, the mouse cursor isn't on any item.
908 
909     \a pos is the position of the mouse cursor in the global
910     coordinate system (QMouseEvent::globalPos()). (If the click's
911     press and release differs by a pixel or two, \a pos is the
912     position at release time.)
913 
914     Note that you must not delete any Q3ListBoxItem objects in slots
915     connected to this signal.
916 */
917 
918 /*!
919     \fn void Q3ListBox::mouseButtonPressed (int button, Q3ListBoxItem * item, const QPoint & pos)
920 
921     This signal is emitted when the user presses mouse button \a
922     button. If \a item is not 0, the cursor is on \a item. If \a item
923     is 0, the mouse cursor isn't on any item.
924 
925     \a pos is the position of the mouse cursor in the global
926     coordinate system (QMouseEvent::globalPos()).
927 
928     Note that you must not delete any Q3ListBoxItem objects in slots
929     connected to this signal.
930 */
931 
932 /*!
933     \fn void Q3ListBox::doubleClicked(Q3ListBoxItem *item)
934 
935     This signal is emitted whenever an item is double-clicked. It's
936     emitted on the second button press, not the second button release.
937     If \a item is not 0, the cursor is on \a item. If \a item is 0,
938     the mouse cursor isn't on any item.
939 */
940 
941 
942 /*!
943     \fn void Q3ListBox::returnPressed(Q3ListBoxItem *item)
944 
945     This signal is emitted when Enter or Return is pressed. The
946     \a item passed in the argument is currentItem().
947 */
948 
949 /*!
950     \fn void Q3ListBox::rightButtonClicked(Q3ListBoxItem *item, const QPoint& point)
951 
952     This signal is emitted when the right button is clicked. The \a
953     item is the item that the button was clicked on (which could be
954     0 if no item was clicked on), and the \a point is where the
955     click took place in global coordinates.
956 */
957 
958 
959 /*!
960     \fn void Q3ListBox::rightButtonPressed (Q3ListBoxItem *item, const QPoint &point)
961 
962     This signal is emitted when the right button is pressed. The \a
963     item is the item that the button was pressed over (which could be
964     0 if no item was pressed over), and the \a point is where the
965     press took place in global coordinates.
966 */
967 
968 /*!
969     \fn void Q3ListBox::contextMenuRequested(Q3ListBoxItem *item, const QPoint & pos)
970 
971     This signal is emitted when the user invokes a context menu with
972     the right mouse button or with special system keys, with \a item
973     being the item under the mouse cursor or the current item,
974     respectively.
975 
976     \a pos is the position for the context menu in the global
977     coordinate system.
978 */
979 
980 /*!
981     \fn void Q3ListBox::selectionChanged()
982 
983     This signal is emitted when the selection set of a list box
984     changes. This signal is emitted in each selection mode. If the
985     user selects five items by drag-selecting, Q3ListBox tries to emit
986     just one selectionChanged() signal so the signal can be connected
987     to computationally expensive slots.
988 
989     \sa selected() currentItem()
990 */
991 
992 /*!
993     \fn void Q3ListBox::selectionChanged(Q3ListBoxItem *item)
994     \overload
995 
996     This signal is emitted when the selection in a \l Single selection
997     list box changes. \a item is the newly selected list box item.
998 
999     \sa selected() currentItem()
1000 */
1001 
1002 /*!
1003     \fn void Q3ListBox::currentChanged(Q3ListBoxItem *item)
1004 
1005     This signal is emitted when the user makes a new item the current
1006     item. \a item is the new current list box item.
1007 
1008     \sa setCurrentItem() currentItem()
1009 */
1010 
1011 /*!
1012     \fn void Q3ListBox::highlighted(int index)
1013 
1014     This signal is emitted when the user makes a new item the current
1015     item. \a index is the index of the new current item.
1016 
1017     \sa currentChanged() selected() currentItem() selectionChanged()
1018 */
1019 
1020 /*!
1021     \fn void Q3ListBox::highlighted(Q3ListBoxItem *item)
1022 
1023     \overload
1024 
1025     This signal is emitted when the user makes a new \a item the current
1026     \a item.
1027 
1028     \sa currentChanged() selected() currentItem() selectionChanged()
1029 */
1030 
1031 /*!
1032     \fn void Q3ListBox::highlighted(const QString & text)
1033 
1034     \overload
1035 
1036     This signal is emitted when the user makes a new item the current
1037     item and the item is (or has) as string. The argument is the new
1038     current item's \a text.
1039 
1040     \sa currentChanged() selected() currentItem() selectionChanged()
1041 */
1042 
1043 /*!
1044     \fn void Q3ListBox::selected(int index)
1045 
1046     This signal is emitted when the user double-clicks on an item or
1047     presses Enter on the current item. \a index is the index of the
1048     selected item.
1049 
1050     \sa currentChanged() highlighted() selectionChanged()
1051 */
1052 
1053 /*!
1054     \fn void Q3ListBox::selected(Q3ListBoxItem *item)
1055 
1056     \overload
1057 
1058     This signal is emitted when the user double-clicks on an \a item or
1059     presses Enter on the current \a item.
1060 
1061     \sa currentChanged() highlighted() selectionChanged()
1062 */
1063 
1064 /*!
1065     \fn void Q3ListBox::selected(const QString &text)
1066 
1067     \overload
1068 
1069     This signal is emitted when the user double-clicks on an item or
1070     presses Enter on the current item, and the item is (or has) a
1071     string. The argument is the \a text of the selected item.
1072 
1073     \sa currentChanged() highlighted() selectionChanged()
1074 */
1075 
1076 /*!
1077     \property Q3ListBox::count
1078     \brief the number of items in the list box
1079 */
1080 
count() const1081 uint Q3ListBox::count() const
1082 {
1083     return d->count;
1084 }
1085 
1086 #if 0
1087 /*!
1088     Inserts the string list \a list into the list at position \a
1089     index.
1090 
1091     If \a index is negative, \a list is inserted at the end of the
1092     list. If \a index is too large, the operation is ignored.
1093 
1094     \warning This function uses \c{const char *} rather than QString,
1095     so we recommend against using it. It is provided so that legacy
1096     code will continue to work, and so that programs that certainly
1097     will not need to handle code outside a single 8-bit locale can use
1098     it. See insertStringList() which uses real QStrings.
1099 
1100     \warning This function is never significantly faster than a loop
1101     around insertItem().
1102 
1103     \sa insertItem(), insertStringList()
1104 */
1105 
1106 void Q3ListBox::insertStrList(const QStrList *list, int index)
1107 {
1108     if (!list) {
1109         Q_ASSERT(list != 0);
1110         return;
1111     }
1112     insertStrList(*list, index);
1113 }
1114 #endif
1115 
1116 
1117 /*!
1118     Inserts the string list \a list into the list at position \a
1119     index.
1120 
1121     If \a index is negative, \a list is inserted at the end of the
1122     list. If \a index is too large, the operation is ignored.
1123 
1124     \warning This function is never significantly faster than a loop
1125     around insertItem().
1126 
1127     \sa insertItem(), insertStrList()
1128 */
1129 
insertStringList(const QStringList & list,int index)1130 void Q3ListBox::insertStringList(const QStringList & list, int index)
1131 {
1132     if (index < 0)
1133         index = count();
1134     for (QStringList::ConstIterator it = list.begin(); it != list.end(); ++it)
1135         insertItem(new Q3ListBoxText(*it), index++);
1136 }
1137 
1138 
1139 #if 0
1140 /*!
1141     \overload
1142 
1143     Inserts the string list \a list into the list at position \a
1144     index.
1145 
1146     If \a index is negative, \a list is inserted at the end of the
1147     list. If \a index is too large, the operation is ignored.
1148 
1149     \warning This function uses \c{const char *} rather than QString,
1150     so we recommend against using it. It is provided so that legacy
1151     code will continue to work, and so that programs that certainly
1152     will not need to handle code outside a single 8-bit locale can use
1153     it. See insertStringList() which uses real QStrings.
1154 
1155     \warning This function is never significantly faster than a loop
1156     around insertItem().
1157 
1158     \sa insertItem(), insertStringList()
1159 */
1160 void Q3ListBox::insertStrList(const QStrList & list, int index)
1161 {
1162     QStrListIterator it(list);
1163     const char* txt;
1164     if (index < 0)
1165         index = count();
1166     while ((txt=it.current())) {
1167         ++it;
1168         insertItem(new Q3ListBoxText(QString::fromLatin1(txt)),
1169                     index++);
1170     }
1171     if (hasFocus() && !d->current)
1172         setCurrentItem(d->head);
1173 }
1174 #endif
1175 
1176 
1177 /*!
1178     Inserts the \a numStrings strings of the array \a strings into the
1179     list at position \a index.
1180 
1181     If \a index is negative, insertStrList() inserts \a strings at the
1182     end of the list. If \a index is too large, the operation is
1183     ignored.
1184 
1185     \warning This function uses \c{const char *} rather than QString,
1186     so we recommend against using it. It is provided so that legacy
1187     code will continue to work, and so that programs that certainly
1188     will not need to handle code outside a single 8-bit locale can use
1189     it. See insertStringList() which uses real QStrings.
1190 
1191     \warning This function is never significantly faster than a loop
1192     around insertItem().
1193 
1194     \sa insertItem(), insertStringList()
1195 */
1196 
insertStrList(const char ** strings,int numStrings,int index)1197 void Q3ListBox::insertStrList(const char **strings, int numStrings, int index)
1198 {
1199     if (!strings) {
1200         Q_ASSERT(strings != 0);
1201         return;
1202     }
1203     if (index < 0)
1204         index = count();
1205     int i = 0;
1206     while ((numStrings<0 && strings[i]!=0) || i<numStrings) {
1207         insertItem(new Q3ListBoxText(QString::fromLatin1(strings[i])),
1208                     index + i);
1209         i++;
1210     }
1211     if (hasFocus() && !d->current)
1212         setCurrentItem(d->head);
1213 }
1214 
1215 /*!
1216     Inserts the item \a lbi into the list at position \a index.
1217 
1218     If \a index is negative or larger than the number of items in the
1219     list box, \a lbi is inserted at the end of the list.
1220 
1221     \sa insertStrList()
1222 */
1223 
insertItem(const Q3ListBoxItem * lbi,int index)1224 void Q3ListBox::insertItem(const Q3ListBoxItem *lbi, int index)
1225 {
1226     if (!lbi)
1227         return;
1228 
1229     if (index < 0)
1230         index = d->count;
1231 
1232     if (index >= d->count) {
1233         insertItem(lbi, d->last);
1234         return;
1235     }
1236 
1237     Q3ListBoxItem * item = (Q3ListBoxItem *)lbi;
1238     d->count++;
1239     d->cache = 0;
1240 
1241     item->lbox = this;
1242     if (!d->head || index == 0) {
1243         item->n = d->head;
1244         item->p = 0;
1245         d->head = item;
1246         item->dirty = true;
1247         if (item->n)
1248             item->n->p = item;
1249     } else {
1250         Q3ListBoxItem * i = d->head;
1251         while (i->n && index > 1) {
1252             i = i->n;
1253             index--;
1254         }
1255         if (i->n) {
1256             item->n = i->n;
1257             item->p = i;
1258             item->n->p = item;
1259             item->p->n = item;
1260         } else {
1261             i->n = item;
1262             item->p = i;
1263             item->n = 0;
1264         }
1265     }
1266 
1267     if (hasFocus() && !d->current) {
1268         d->current = d->head;
1269         updateItem(d->current);
1270         emit highlighted(d->current);
1271         emit highlighted(d->current->text());
1272         emit highlighted(index);
1273     }
1274 
1275     triggerUpdate(true);
1276 }
1277 
1278 /*!
1279     \overload
1280 
1281     Inserts the item \a lbi into the list after the item \a after, or
1282     at the beginning if \a after is 0.
1283 
1284     \sa insertStrList()
1285 */
1286 
insertItem(const Q3ListBoxItem * lbi,const Q3ListBoxItem * after)1287 void Q3ListBox::insertItem(const Q3ListBoxItem *lbi, const Q3ListBoxItem *after)
1288 {
1289     if (!lbi)
1290         return;
1291 
1292     Q3ListBoxItem * item = (Q3ListBoxItem*)lbi;
1293     d->count++;
1294     d->cache = 0;
1295 
1296     item->lbox = this;
1297     if (!d->head || !after) {
1298         item->n = d->head;
1299         item->p = 0;
1300         d->head = item;
1301         item->dirty = true;
1302         if (item->n)
1303             item->n->p = item;
1304     } else {
1305         Q3ListBoxItem * i = (Q3ListBoxItem*) after;
1306         if (i) {
1307             item->n = i->n;
1308             item->p = i;
1309             if (item->n)
1310                 item->n->p = item;
1311             if (item->p)
1312                 item->p->n = item;
1313         }
1314     }
1315 
1316     if (after == d->last)
1317         d->last = (Q3ListBoxItem*) lbi;
1318 
1319     if (hasFocus() && !d->current) {
1320         d->current = d->head;
1321         updateItem(d->current);
1322         emit highlighted(d->current);
1323         emit highlighted(d->current->text());
1324         emit highlighted(index(d->current));
1325     }
1326 
1327     triggerUpdate(true);
1328 }
1329 
1330 /*!
1331     \overload
1332 
1333     Inserts a new list box text item with the text \a text into the
1334     list at position \a index.
1335 
1336     If \a index is negative, \a text is inserted at the end of the
1337     list.
1338 
1339     \sa insertStrList()
1340 */
1341 
insertItem(const QString & text,int index)1342 void Q3ListBox::insertItem(const QString &text, int index)
1343 {
1344     insertItem(new Q3ListBoxText(text), index);
1345 }
1346 
1347 /*!
1348     \overload
1349 
1350     Inserts a new list box pixmap item with the pixmap \a pixmap into
1351     the list at position \a index.
1352 
1353     If \a index is negative, \a pixmap is inserted at the end of the
1354     list.
1355 
1356     \sa insertStrList()
1357 */
1358 
insertItem(const QPixmap & pixmap,int index)1359 void Q3ListBox::insertItem(const QPixmap &pixmap, int index)
1360 {
1361     insertItem(new Q3ListBoxPixmap(pixmap), index);
1362 }
1363 
1364 /*!
1365     \overload
1366 
1367     Inserts a new list box pixmap item with the pixmap \a pixmap and
1368     the text \a text into the list at position \a index.
1369 
1370     If \a index is negative, \a pixmap is inserted at the end of the
1371     list.
1372 
1373     \sa insertStrList()
1374 */
1375 
insertItem(const QPixmap & pixmap,const QString & text,int index)1376 void Q3ListBox::insertItem(const QPixmap &pixmap, const QString &text, int index)
1377 {
1378     insertItem(new Q3ListBoxPixmap(pixmap, text), index);
1379 }
1380 
1381 /*!
1382     Removes and deletes the item at position \a index. If \a index is
1383     equal to currentItem(), a new item becomes current and the
1384     currentChanged() and highlighted() signals are emitted.
1385 
1386     \sa insertItem(), clear()
1387 */
1388 
removeItem(int index)1389 void Q3ListBox::removeItem(int index)
1390 {
1391     bool wasVisible = itemVisible(currentItem());
1392     delete item(index);
1393     triggerUpdate(true);
1394     if (wasVisible)
1395         ensureCurrentVisible();
1396 }
1397 
1398 
1399 /*!
1400     Deletes all the items in the list.
1401 
1402     \sa removeItem()
1403 */
1404 
clear()1405 void Q3ListBox::clear()
1406 {
1407     setContentsPos(0, 0);
1408     bool blocked = signalsBlocked();
1409     blockSignals(true);
1410     d->clearing = true;
1411     d->current = 0;
1412     d->tmpCurrent = 0;
1413     Q3ListBoxItem * i = d->head;
1414     d->head = 0;
1415     while (i) {
1416         Q3ListBoxItem * n = i->n;
1417         i->n = i->p = 0;
1418         delete i;
1419         i = n;
1420     }
1421     d->count = 0;
1422     d->numRows = 1;
1423     d->numColumns = 1;
1424     d->currentRow = 0;
1425     d->currentColumn = 0;
1426     d->mousePressRow = -1;
1427     d->mousePressColumn = -1;
1428     d->mouseMoveRow = -1;
1429     d->mouseMoveColumn = -1;
1430     clearSelection();
1431     d->selectAnchor = 0;
1432     blockSignals(blocked);
1433     triggerUpdate(true);
1434     d->last = 0;
1435     d->clearing = false;
1436 }
1437 
1438 
1439 /*!
1440     Returns the text at position \a index, or an empty string if there
1441     is no text at that position.
1442 
1443     \sa pixmap()
1444 */
1445 
text(int index) const1446 QString Q3ListBox::text(int index) const
1447 {
1448     Q3ListBoxItem * i = item(index);
1449     if (i)
1450         return i->text();
1451     return QString();
1452 }
1453 
1454 
1455 /*!
1456     Returns a pointer to the pixmap at position \a index, or 0 if
1457     there is no pixmap there.
1458 
1459     \sa text()
1460 */
1461 
pixmap(int index) const1462 const QPixmap *Q3ListBox::pixmap(int index) const
1463 {
1464     Q3ListBoxItem * i = item(index);
1465     if (i)
1466         return i->pixmap();
1467     return 0;
1468 }
1469 
1470 /*!
1471     \overload
1472 
1473     Replaces the item at position \a index with a new list box text
1474     item with text \a text.
1475 
1476     The operation is ignored if \a index is out of range.
1477 
1478     \sa insertItem(), removeItem()
1479 */
1480 
changeItem(const QString & text,int index)1481 void Q3ListBox::changeItem(const QString &text, int index)
1482 {
1483     if(index >= 0 && index < (int)count())
1484         changeItem(new Q3ListBoxText(text), index);
1485 }
1486 
1487 /*!
1488     \overload
1489 
1490     Replaces the item at position \a index with a new list box pixmap
1491     item with pixmap \a pixmap.
1492 
1493     The operation is ignored if \a index is out of range.
1494 
1495     \sa insertItem(), removeItem()
1496 */
1497 
changeItem(const QPixmap & pixmap,int index)1498 void Q3ListBox::changeItem(const QPixmap &pixmap, int index)
1499 {
1500     if(index >= 0 && index < (int)count())
1501         changeItem(new Q3ListBoxPixmap(pixmap), index);
1502 }
1503 
1504 /*!
1505     \overload
1506 
1507     Replaces the item at position \a index with a new list box pixmap
1508     item with pixmap \a pixmap and text \a text.
1509 
1510     The operation is ignored if \a index is out of range.
1511 
1512     \sa insertItem(), removeItem()
1513 */
1514 
changeItem(const QPixmap & pixmap,const QString & text,int index)1515 void Q3ListBox::changeItem(const QPixmap &pixmap, const QString &text, int index)
1516 {
1517     if(index >= 0 && index < (int)count())
1518         changeItem(new Q3ListBoxPixmap(pixmap, text), index);
1519 }
1520 
1521 
1522 
1523 /*!
1524     Replaces the item at position \a index with \a lbi.        If \a index is
1525     negative or too large, changeItem() does nothing.
1526 
1527     The item that has been changed will become selected.
1528 
1529     \sa insertItem(), removeItem()
1530 */
1531 
changeItem(const Q3ListBoxItem * lbi,int index)1532 void Q3ListBox::changeItem(const Q3ListBoxItem *lbi, int index)
1533 {
1534     if (!lbi || index < 0 || index >= (int)count())
1535         return;
1536 
1537     removeItem(index);
1538     insertItem(lbi, index);
1539     setCurrentItem(index);
1540 }
1541 
1542 
1543 /*!
1544     \property Q3ListBox::numItemsVisible
1545     \brief the number of visible items.
1546 
1547     Both partially and entirely visible items are counted.
1548 */
1549 
numItemsVisible() const1550 int Q3ListBox::numItemsVisible() const
1551 {
1552     doLayout();
1553 
1554     int columns = 0;
1555 
1556     int x = contentsX();
1557     int i=0;
1558     while (i < (int)d->columnPos.size()-1 &&
1559            d->columnPos[i] < x)
1560         i++;
1561     if (i < (int)d->columnPos.size()-1 &&
1562          d->columnPos[i] > x)
1563         columns++;
1564     x += visibleWidth();
1565     while (i < (int)d->columnPos.size()-1 &&
1566            d->columnPos[i] < x) {
1567         i++;
1568         columns++;
1569     }
1570 
1571     int y = contentsY();
1572     int rows = 0;
1573     while (i < (int)d->rowPos.size()-1 &&
1574            d->rowPos[i] < y)
1575         i++;
1576     if (i < (int)d->rowPos.size()-1 &&
1577          d->rowPos[i] > y)
1578         rows++;
1579     y += visibleHeight();
1580     while (i < (int)d->rowPos.size()-1 &&
1581            d->rowPos[i] < y) {
1582         i++;
1583         rows++;
1584     }
1585 
1586     return rows*columns;
1587 }
1588 
currentItem() const1589 int Q3ListBox::currentItem() const
1590 {
1591     if (!d->current || !d->head)
1592         return -1;
1593 
1594     return index(d->current);
1595 }
1596 
1597 
1598 /*!
1599     \property Q3ListBox::currentText
1600     \brief the text of the current item.
1601 
1602     This is equivalent to text(currentItem()).
1603 */
1604 
1605 
1606 /*!
1607     \property Q3ListBox::currentItem
1608     \brief the current highlighted item
1609 
1610     When setting this property, the highlighting is moved to the item
1611     and the list box scrolled as necessary.
1612 
1613     If no item is current, currentItem() returns -1.
1614 */
1615 
setCurrentItem(int index)1616 void Q3ListBox::setCurrentItem(int index)
1617 {
1618     setCurrentItem(item(index));
1619 }
1620 
1621 /*!
1622     \reimp
1623 */
inputMethodQuery(Qt::InputMethodQuery query) const1624 QVariant Q3ListBox::inputMethodQuery(Qt::InputMethodQuery query) const
1625 {
1626     if (query == Qt::ImMicroFocus)
1627         return d->current ? itemRect(d->current) : QRect();
1628     return QWidget::inputMethodQuery(query);
1629 }
1630 
1631 /*!
1632     \overload
1633 
1634     Sets the current item to the Q3ListBoxItem \a i.
1635 */
setCurrentItem(Q3ListBoxItem * i)1636 void Q3ListBox::setCurrentItem(Q3ListBoxItem * i)
1637 {
1638     if (!i || d->current == i)
1639         return;
1640 
1641     Q3ListBoxItem * o = d->current;
1642     d->current = i;
1643     int ind = index(i);
1644 
1645     if (i && selectionMode() == Single) {
1646         bool changed = false;
1647         if (o && o->s) {
1648             changed = true;
1649             o->s = false;
1650         }
1651         if (i && !i->s && d->selectionMode != NoSelection && i->isSelectable()) {
1652             i->s = true;
1653             changed = true;
1654             emit selectionChanged(i);
1655 #ifndef QT_NO_ACCESSIBILITY
1656             QAccessible::updateAccessibility(viewport(), ind+1, QAccessible::StateChanged);
1657 #endif
1658         }
1659         if (changed) {
1660             emit selectionChanged();
1661 #ifndef QT_NO_ACCESSIBILITY
1662             QAccessible::updateAccessibility(viewport(), 0, QAccessible::Selection);
1663 #endif
1664         }
1665     }
1666 
1667     d->currentColumn = ind / numRows();
1668     d->currentRow = ind % numRows();
1669     if (o)
1670         updateItem(o);
1671     if (i)
1672         updateItem(i);
1673     // scroll after the items are redrawn
1674     d->visibleTimer->start(1, true);
1675 
1676     QString tmp;
1677     if (i)
1678         tmp = i->text();
1679     emit highlighted(i);
1680     if (!tmp.isNull())
1681         emit highlighted(tmp);
1682     emit highlighted(ind);
1683     emit currentChanged(i);
1684 
1685 #ifndef QT_NO_ACCESSIBILITY
1686     QAccessible::updateAccessibility(viewport(), ind+1, QAccessible::Focus);
1687 #endif
1688 }
1689 
1690 
1691 /*!
1692     Returns a pointer to the item at position \a index, or 0 if \a
1693     index is out of bounds.
1694 
1695     \sa index()
1696 */
1697 
item(int index) const1698 Q3ListBoxItem *Q3ListBox::item(int index) const
1699 {
1700     if (index < 0 || index > d->count -1)
1701         return 0;
1702 
1703     Q3ListBoxItem * i = d->head;
1704 
1705     if (d->cache && index > 0) {
1706         i = d->cache;
1707         int idx = d->cacheIndex;
1708         while (i && idx < index) {
1709             idx++;
1710             i = i->n;
1711         }
1712         while (i && idx > index) {
1713             idx--;
1714             i = i->p;
1715         }
1716     } else {
1717         int idx = index;
1718         while (i && idx > 0) {
1719             idx--;
1720             i = i->n;
1721         }
1722     }
1723 
1724     if (index > 0) {
1725         d->cache = i;
1726         d->cacheIndex = index;
1727     }
1728 
1729     return i;
1730 }
1731 
1732 
1733 /*!
1734     Returns the index of \a lbi, or -1 if the item is not in this list
1735     box or \a lbi is 0.
1736 
1737     \sa item()
1738 */
1739 
index(const Q3ListBoxItem * lbi) const1740 int Q3ListBox::index(const Q3ListBoxItem * lbi) const
1741 {
1742     if (!lbi)
1743         return -1;
1744     Q3ListBoxItem * i_n = d->head;
1745     int c_n = 0;
1746     if (d->cache) {
1747         i_n = d->cache;
1748         c_n = d->cacheIndex;
1749     }
1750     Q3ListBoxItem* i_p = i_n;
1751     int c_p = c_n;
1752     while ((i_n != 0 || i_p != 0) && i_n != lbi && i_p != lbi) {
1753         if (i_n) {
1754             c_n++;
1755             i_n = i_n->n;
1756         }
1757         if (i_p) {
1758             c_p--;
1759             i_p = i_p->p;
1760         }
1761     }
1762     if (i_p == lbi)
1763         return c_p;
1764     if (i_n == lbi)
1765         return c_n;
1766     return -1;
1767 }
1768 
1769 
1770 
1771 /*!
1772     Returns true if the item at position \a index is at least partly
1773     visible; otherwise returns false.
1774 */
1775 
itemVisible(int index)1776 bool Q3ListBox::itemVisible(int index)
1777 {
1778     Q3ListBoxItem * i = item(index);
1779     return i ? itemVisible(i) : false;
1780 }
1781 
1782 
1783 /*!
1784     \overload
1785 
1786     Returns true if \a item is at least partly visible; otherwise
1787     returns false.
1788 */
1789 
itemVisible(const Q3ListBoxItem * item)1790 bool Q3ListBox::itemVisible(const Q3ListBoxItem * item)
1791 {
1792     if (d->layoutDirty)
1793         doLayout();
1794 
1795     int i = index(item);
1796     int col = i / numRows();
1797     int row = i % numRows();
1798     return (d->columnPos[col] < contentsX()+visibleWidth() &&
1799              d->rowPos[row] < contentsY()+visibleHeight() &&
1800              d->columnPos[col+1] > contentsX() &&
1801              d->rowPos[row+1] > contentsY());
1802 }
1803 
1804 
1805 /*! \reimp */
1806 
mousePressEvent(QMouseEvent * e)1807 void Q3ListBox::mousePressEvent(QMouseEvent *e)
1808 {
1809     mousePressEventEx(e);
1810 }
1811 
mousePressEventEx(QMouseEvent * e)1812 void Q3ListBox::mousePressEventEx(QMouseEvent *e)
1813 {
1814     d->mouseInternalPress = true;
1815     Q3ListBoxItem * i = itemAt(e->pos());
1816 
1817     if (!i && !d->current && d->head) {
1818         d->current = d->head;
1819         updateItem(d->head);
1820     }
1821 
1822     if (!i && (d->selectionMode != Single || e->button() == Qt::RightButton)
1823          && !(e->state() & Qt::ControlButton))
1824         clearSelection();
1825 
1826     d->select = d->selectionMode == Multi ? (i ? !i->isSelected() : false) : true;
1827     d->pressedSelected = i && i->s;
1828 
1829     if (i)
1830         d->selectAnchor = i;
1831     if (i) {
1832         switch(selectionMode()) {
1833         default:
1834         case Single:
1835             if (!i->s || i != d->current) {
1836                 if (i->isSelectable())
1837                     setSelected(i, true);
1838                 else
1839                     setCurrentItem(i);
1840             }
1841             break;
1842         case Extended:
1843             if (i) {
1844                 bool shouldBlock = false;
1845                 if (!(e->state() & Qt::ShiftButton) &&
1846                     !(e->state() & Qt::ControlButton)) {
1847                     if (!i->isSelected()) {
1848                         bool b = signalsBlocked();
1849                         blockSignals(true);
1850                         clearSelection();
1851                         blockSignals(b);
1852                     }
1853                     setSelected(i, true);
1854                     d->dragging = true; // always assume dragging
1855                     shouldBlock = true;
1856                 } else if (e->state() & Qt::ShiftButton) {
1857                     d->pressedSelected = false;
1858                     Q3ListBoxItem *oldCurrent = item(currentItem());
1859                     bool down = index(oldCurrent) < index(i);
1860 
1861                     Q3ListBoxItem *lit = down ? oldCurrent : i;
1862                     bool select = d->select;
1863                     bool blocked = signalsBlocked();
1864                     blockSignals(true);
1865                     for (;; lit = lit->n) {
1866                         if (!lit) {
1867                             triggerUpdate(false);
1868                             break;
1869                         }
1870                         if (down && lit == i) {
1871                             setSelected(i, select);
1872                             triggerUpdate(false);
1873                             break;
1874                         }
1875                         if (!down && lit == oldCurrent) {
1876                             setSelected(oldCurrent, select);
1877                             triggerUpdate(false);
1878                             break;
1879                         }
1880                         setSelected(lit, select);
1881                     }
1882                     blockSignals(blocked);
1883                     emit selectionChanged();
1884                 } else if (e->state() & Qt::ControlButton) {
1885                     setSelected(i, !i->isSelected());
1886                     shouldBlock = true;
1887                     d->pressedSelected = false;
1888                 }
1889                 bool blocked = signalsBlocked();
1890                 blockSignals(shouldBlock);
1891                 setCurrentItem(i);
1892                 blockSignals(blocked);
1893             }
1894             break;
1895         case Multi:
1896 	    {
1897                 setSelected(i, !i->s);
1898                 bool b = signalsBlocked();
1899                 blockSignals(true);
1900                 setCurrentItem(i);
1901                 blockSignals(b);
1902                 break;
1903 	    }
1904         case NoSelection:
1905             setCurrentItem(i);
1906             break;
1907         }
1908     } else {
1909         bool unselect = true;
1910         if (e->button() == Qt::LeftButton) {
1911             if (d->selectionMode == Multi ||
1912                  d->selectionMode == Extended) {
1913                 d->tmpCurrent = d->current;
1914                 d->current = 0;
1915                 updateItem(d->tmpCurrent);
1916                 if (d->rubber)
1917                     delete d->rubber;
1918                 d->rubber = 0;
1919                 d->rubber = new QRect(e->x(), e->y(), 0, 0);
1920 
1921                 if (d->selectionMode == Extended && !(e->state() & Qt::ControlButton))
1922                     selectAll(false);
1923                 unselect = false;
1924             }
1925             if (unselect && (e->button() == Qt::RightButton ||
1926                                (selectionMode() == Multi || selectionMode() == Extended)))
1927                 clearSelection();
1928         }
1929     }
1930 
1931     // for sanity, in case people are event-filtering or whatnot
1932     delete d->scrollTimer;
1933     d->scrollTimer = 0;
1934     if (i) {
1935         d->mousePressColumn = d->currentColumn;
1936         d->mousePressRow = d->currentRow;
1937     } else {
1938         d->mousePressColumn = -1;
1939         d->mousePressRow = -1;
1940     }
1941     d->ignoreMoves = false;
1942 
1943     d->pressedItem = i;
1944 
1945     emit pressed(i);
1946     emit pressed(i, e->globalPos());
1947     emit mouseButtonPressed(e->button(), i, e->globalPos());
1948     if (e->button() == Qt::RightButton)
1949         emit rightButtonPressed(i, e->globalPos());
1950 }
1951 
1952 
1953 /*! \reimp */
1954 
mouseReleaseEvent(QMouseEvent * e)1955 void Q3ListBox::mouseReleaseEvent(QMouseEvent *e)
1956 {
1957     if (d->selectionMode == Extended &&
1958         d->dragging) {
1959         d->dragging = false;
1960         if (d->current != d->pressedItem) {
1961             updateSelection(); // when we drag, we get an update after we release
1962         }
1963     }
1964 
1965     if (d->rubber) {
1966         drawRubber();
1967         delete d->rubber;
1968         d->rubber = 0;
1969         d->current = d->tmpCurrent;
1970         updateItem(d->current);
1971     }
1972     if (d->scrollTimer)
1973         mouseMoveEvent(e);
1974     delete d->scrollTimer;
1975     d->scrollTimer = 0;
1976     d->ignoreMoves = false;
1977 
1978     if (d->selectionMode == Extended &&
1979          d->current == d->pressedItem &&
1980          d->pressedSelected && d->current) {
1981         bool block = signalsBlocked();
1982         blockSignals(true);
1983         clearSelection();
1984         blockSignals(block);
1985         d->current->s = true;
1986         emit selectionChanged();
1987     }
1988 
1989     Q3ListBoxItem * i = itemAt(e->pos());
1990     bool emitClicked = (d->mousePressColumn != -1 && d->mousePressRow != -1) || !d->pressedItem;
1991     emitClicked = emitClicked && d->pressedItem == i;
1992     d->pressedItem = 0;
1993     d->mousePressRow = -1;
1994     d->mousePressColumn = -1;
1995     d->mouseInternalPress = false;
1996     if (emitClicked) {
1997         emit clicked(i);
1998         emit clicked(i, e->globalPos());
1999         emit mouseButtonClicked(e->button(), i, e->globalPos());
2000         if (e->button() == Qt::RightButton)
2001             emit rightButtonClicked(i, e->globalPos());
2002     }
2003 }
2004 
2005 
2006 /*! \reimp */
2007 
mouseDoubleClickEvent(QMouseEvent * e)2008 void Q3ListBox::mouseDoubleClickEvent(QMouseEvent *e)
2009 {
2010     bool ok = true;
2011     Q3ListBoxItem *i = itemAt(e->pos());
2012     if (!i || selectionMode() == NoSelection)
2013         ok = false;
2014 
2015     d->ignoreMoves = true;
2016 
2017     if (d->current && ok) {
2018         Q3ListBoxItem * i = d->current;
2019         QString tmp = d->current->text();
2020         emit selected(currentItem());
2021         emit selected(i);
2022         if (!tmp.isNull())
2023             emit selected(tmp);
2024         emit doubleClicked(i);
2025     }
2026 }
2027 
2028 
2029 /*! \reimp */
2030 
mouseMoveEvent(QMouseEvent * e)2031 void Q3ListBox::mouseMoveEvent(QMouseEvent *e)
2032 {
2033     Q3ListBoxItem * i = itemAt(e->pos());
2034     if (i != d->highlighted) {
2035         if (i) {
2036             emit onItem(i);
2037         } else {
2038             emit onViewport();
2039         }
2040         d->highlighted = i;
2041     }
2042 
2043     if (d->rubber) {
2044         QRect r = d->rubber->normalized();
2045         drawRubber();
2046         d->rubber->setCoords(d->rubber->x(), d->rubber->y(), e->x(), e->y());
2047         doRubberSelection(r, d->rubber->normalized());
2048         drawRubber();
2049         return;
2050     }
2051 
2052     if (((e->state() & (Qt::RightButton | Qt::LeftButton | Qt::MidButton)) == 0) ||
2053          d->ignoreMoves)
2054         return;
2055 
2056     // hack to keep the combo (and what else?) working: if we get a
2057     // move outside the listbox without having seen a press, discard
2058     // it.
2059     if (!QRect(0, 0, visibleWidth(), visibleHeight()).contains(e->pos()) &&
2060          ((d->mousePressColumn < 0 && d->mousePressRow < 0)
2061           || (e->state() == Qt::NoButton && !d->pressedItem)))
2062         return;
2063 
2064     // figure out in what direction to drag-select and perhaps scroll
2065     int dx = 0;
2066     int x = e->x();
2067     if (x >= visibleWidth()) {
2068         x = visibleWidth()-1;
2069         dx = 1;
2070     } else if (x < 0) {
2071         x = 0;
2072         dx = -1;
2073     }
2074     d->mouseMoveColumn = columnAt(x + contentsX());
2075 
2076     // sanitize mousePressColumn, if we got here without a mouse press event
2077     if (d->mousePressColumn < 0 && d->mouseMoveColumn >= 0)
2078         d->mousePressColumn = d->mouseMoveColumn;
2079     if (d->mousePressColumn < 0 && d->currentColumn >= 0)
2080         d->mousePressColumn = d->currentColumn;
2081 
2082     // if it's beyond the last column, use the last one
2083     if (d->mouseMoveColumn < 0)
2084         d->mouseMoveColumn = dx >= 0 ? numColumns()-1 : 0;
2085 
2086     // repeat for y
2087     int dy = 0;
2088     int y = e->y();
2089     if (y >= visibleHeight()) {
2090         y = visibleHeight()-1;
2091         dy = 1;
2092     } else if (y < 0) {
2093         y = 0;
2094         dy = -1;
2095     }
2096     d->mouseMoveRow = rowAt(y + contentsY());
2097 
2098     if (d->mousePressRow < 0 && d->mouseMoveRow >= 0)
2099         d->mousePressRow = d->mouseMoveRow;
2100     if (d->mousePressRow < 0 && d->currentRow >= 0)
2101         d->mousePressRow = d->currentRow;
2102 
2103     if (d->mousePressRow < 0)
2104         d->mousePressRow = rowAt(x + contentsX());
2105 
2106     d->scrollPos = QPoint(dx, dy);
2107 
2108     if ((dx || dy) && !d->scrollTimer && e->state() == Qt::LeftButton && e->button() != Qt::LeftButton) {
2109         // start autoscrolling if necessary
2110         d->scrollTimer = new QTimer(this);
2111         connect(d->scrollTimer, SIGNAL(timeout()),
2112                  this, SLOT(doAutoScroll()));
2113         d->scrollTimer->start(100, false);
2114         doAutoScroll();
2115     } else if (!d->scrollTimer) {
2116         // or just select the required bits
2117         updateSelection();
2118     }
2119 }
2120 
2121 
2122 
updateSelection()2123 void Q3ListBox::updateSelection()
2124 {
2125     if (d->mouseMoveColumn >= 0 && d->mouseMoveRow >= 0 &&
2126          d->mousePressColumn >= 0 && d->mousePressRow >= 0) {
2127         Q3ListBoxItem * i = item(d->mouseMoveColumn * numRows() +
2128                                  d->mouseMoveRow);
2129 #ifndef QT_NO_ACCESSIBILITY
2130         int ind = index(i);
2131 #endif
2132         if (selectionMode() == Single || selectionMode() == NoSelection) {
2133             if (i && (d->mouseInternalPress || (windowType() == Qt::Popup)))
2134                 setCurrentItem(i);
2135         } else {
2136             if (d->selectionMode == Extended && (
2137                  (d->current == d->pressedItem && d->pressedSelected) ||
2138                 (d->dirtyDrag && !d->dragging))) {
2139                 if (d->dirtyDrag && !d->dragging) // emit after dragging stops
2140                     d->dirtyDrag = false;
2141                 else
2142                     clearSelection(); // don't reset drag-selected items
2143                 d->pressedItem = 0;
2144                 if (i && i->isSelectable()) {
2145                     bool block = signalsBlocked();
2146                     blockSignals(true);
2147                     i->s = true;
2148                     blockSignals(block);
2149                     emit selectionChanged();
2150 #ifndef QT_NO_ACCESSIBILITY
2151                     QAccessible::updateAccessibility(viewport(), ind+1, QAccessible::StateChanged);
2152                     QAccessible::updateAccessibility(viewport(), 0, QAccessible::Selection);
2153                     QAccessible::updateAccessibility(viewport(), ind+1, QAccessible::SelectionAdd);
2154 #endif
2155                 }
2156                 triggerUpdate(false);
2157             } else {
2158                 int c = qMin(d->mouseMoveColumn, d->mousePressColumn);
2159                 int r = qMin(d->mouseMoveRow, d->mousePressRow);
2160                 int c2 = qMax(d->mouseMoveColumn, d->mousePressColumn);
2161                 int r2 = qMax(d->mouseMoveRow, d->mousePressRow);
2162                 bool changed = false;
2163                 while(c <= c2) {
2164                     Q3ListBoxItem * i = item(c*numRows()+r);
2165                     int rtmp = r;
2166                     while(i && rtmp <= r2) {
2167                         if ((bool)i->s != (bool)d->select && i->isSelectable()) {
2168                             i->s = d->select;
2169 #ifndef QT_NO_ACCESSIBILITY
2170                             QAccessible::updateAccessibility(viewport(), ind+1, QAccessible::StateChanged);
2171                             QAccessible::updateAccessibility(viewport(), ind+1, d->select ? QAccessible::SelectionAdd : QAccessible::SelectionRemove);
2172 #endif
2173                             i->dirty = true;
2174                             d->dirtyDrag = changed = true;
2175                         }
2176                         i = i->n;
2177                         rtmp++;
2178                     }
2179                     c++;
2180                 }
2181                 if (changed) {
2182                     if (!d->dragging) // emit after dragging stops instead
2183                         emit selectionChanged();
2184 #ifndef QT_NO_ACCESSIBILITY
2185                     QAccessible::updateAccessibility(viewport(), 0, QAccessible::Selection);
2186 #endif
2187                     triggerUpdate(false);
2188                 }
2189             }
2190             if (i)
2191                 setCurrentItem(i);
2192         }
2193     }
2194 }
2195 
repaintSelection()2196 void Q3ListBox::repaintSelection()
2197 {
2198     if (d->numColumns == 1) {
2199         for (uint i = topItem(); itemVisible(i) && i < count(); ++i) {
2200             Q3ListBoxItem *it = item(i);
2201             if (!it)
2202                 break;
2203             if (it->isSelected())
2204                 updateItem(it);
2205         }
2206     } else {
2207         for (uint i = 0; i < count(); ++i) {
2208             Q3ListBoxItem *it = item(i);
2209             if (!it)
2210                 break;
2211             if (it->isSelected())
2212                 updateItem(it);
2213         }
2214     }
2215 }
2216 
2217 /*! \reimp
2218 */
2219 
contentsContextMenuEvent(QContextMenuEvent * e)2220 void Q3ListBox::contentsContextMenuEvent(QContextMenuEvent *e)
2221 {
2222     if (!receivers(SIGNAL(contextMenuRequested(Q3ListBoxItem*,QPoint)))) {
2223         e->ignore();
2224         return;
2225     }
2226     if (e->reason() == QContextMenuEvent::Keyboard) {
2227         Q3ListBoxItem *i = item(currentItem());
2228         if (i) {
2229             QRect r = itemRect(i);
2230             emit contextMenuRequested(i, mapToGlobal(r.topLeft() + QPoint(width() / 2, r.height() / 2)));
2231         }
2232     } else {
2233         Q3ListBoxItem * i = itemAt(contentsToViewport(e->pos()));
2234         emit contextMenuRequested(i, e->globalPos());
2235     }
2236 }
2237 
2238 /*!\reimp
2239 */
keyPressEvent(QKeyEvent * e)2240 void Q3ListBox::keyPressEvent(QKeyEvent *e)
2241 {
2242     if ((e->key() == Qt::Key_Tab || e->key() == Qt::Key_Backtab)
2243          && e->state() & Qt::ControlButton)
2244         e->ignore();
2245 
2246     if (count() == 0) {
2247         e->ignore();
2248         return;
2249     }
2250 
2251     QPointer<Q3ListBox> selfCheck = this;
2252 
2253     Q3ListBoxItem *old = d->current;
2254     if (!old) {
2255         setCurrentItem(d->head);
2256         if (d->selectionMode == Single)
2257             setSelected(d->head, true);
2258         e->ignore();
2259         return;
2260     }
2261 
2262     bool selectCurrent = false;
2263     switch (e->key()) {
2264         case Qt::Key_Up:
2265             {
2266                 d->currInputString.clear();
2267                 if (currentItem() > 0) {
2268                     setCurrentItem(currentItem() - 1);
2269                     handleItemChange(old, e->state() & Qt::ShiftButton, e->state() & Qt::ControlButton);
2270                 }
2271                 if (!(e->state() & Qt::ShiftButton) || !d->selectAnchor)
2272                     d->selectAnchor = d->current;
2273             }
2274             break;
2275         case Qt::Key_Down:
2276             {
2277                 d->currInputString.clear();
2278                 if (currentItem() < (int)count() - 1) {
2279                     setCurrentItem(currentItem() + 1);
2280                     handleItemChange(old, e->state() & Qt::ShiftButton, e->state() & Qt::ControlButton);
2281                 }
2282                 if (!(e->state() & Qt::ShiftButton) || !d->selectAnchor)
2283                     d->selectAnchor = d->current;
2284             }
2285             break;
2286         case Qt::Key_Left:
2287             {
2288                 d->currInputString.clear();
2289                 if (currentColumn() > 0) {
2290                     setCurrentItem(currentItem() - numRows());
2291                     handleItemChange(old, e->state() & Qt::ShiftButton, e->state() & Qt::ControlButton);
2292                 } else if (numColumns() > 1 && currentItem() > 0) {
2293                     int row = currentRow();
2294                     setCurrentItem(currentRow() - 1 + (numColumns() - 1) * numRows());
2295 
2296                     if (currentItem() == -1)
2297                         setCurrentItem(row - 1 + (numColumns() - 2) * numRows());
2298 
2299                     handleItemChange(old, e->state() & Qt::ShiftButton, e->state() & Qt::ControlButton);
2300                 } else {
2301                     QApplication::sendEvent(horizontalScrollBar(), e);
2302                 }
2303                 if (!(e->state() & Qt::ShiftButton) || !d->selectAnchor)
2304                     d->selectAnchor = d->current;
2305             }
2306             break;
2307         case Qt::Key_Right:
2308             {
2309                 d->currInputString.clear();
2310                 if (currentColumn() < numColumns()-1) {
2311                     int row = currentRow();
2312                     int i = currentItem();
2313                     Q3ListBoxItem *it = item(i + numRows());
2314                     if (!it)
2315                         it = item(count()-1);
2316                     setCurrentItem(it);
2317 
2318                     if (currentItem() == -1) {
2319                         if (row < numRows() - 1)
2320                             setCurrentItem(row + 1);
2321                         else
2322                             setCurrentItem(i);
2323                     }
2324 
2325                     handleItemChange(old, e->state() & Qt::ShiftButton, e->state() & Qt::ControlButton);
2326                 } else if (numColumns() > 1 && currentRow() < numRows()) {
2327                     if (currentRow() + 1 < numRows()) {
2328                         setCurrentItem(currentRow() + 1);
2329                         handleItemChange(old, e->state() & Qt::ShiftButton, e->state() & Qt::ControlButton);
2330                     }
2331                 } else {
2332                     QApplication::sendEvent(horizontalScrollBar(), e);
2333                 }
2334                 if (!(e->state() & Qt::ShiftButton) || !d->selectAnchor)
2335                     d->selectAnchor = d->current;
2336             }
2337             break;
2338         case Qt::Key_Next:
2339             {
2340                 d->currInputString.clear();
2341                 int i = 0;
2342                 if (numColumns() == 1) {
2343                     i = currentItem() + numItemsVisible();
2344                     i = i > (int)count() - 1 ? (int)count() - 1 : i;
2345                     setCurrentItem(i);
2346                     setBottomItem(i);
2347                 } else {
2348                     // I'm not sure about this behavior...
2349                     if (currentRow() == numRows() - 1)
2350                         i = currentItem() + numRows();
2351                     else
2352                         i = currentItem() + numRows() - currentRow() - 1;
2353                     i = i > (int)count() - 1 ? (int)count() - 1 : i;
2354                     setCurrentItem(i);
2355                 }
2356                 handleItemChange(old, e->state() & Qt::ShiftButton, e->state() & Qt::ControlButton);
2357                 if (!(e->state() & Qt::ShiftButton) || !d->selectAnchor)
2358                     d->selectAnchor = d->current;
2359             }
2360             break;
2361         case Qt::Key_Prior:
2362             {
2363                 selectCurrent = true;
2364                 d->currInputString.clear();
2365                 int i;
2366                 if (numColumns() == 1) {
2367                     i = currentItem() - numItemsVisible();
2368                     i = i < 0 ? 0 : i;
2369                     setCurrentItem(i);
2370                     setTopItem(i);
2371                 } else {
2372                     // I'm not sure about this behavior...
2373                     if (currentRow() == 0)
2374                         i = currentItem() - numRows();
2375                     else
2376                         i = currentItem() - currentRow();
2377                     i = i < 0 ? 0 : i;
2378                     setCurrentItem(i);
2379                 }
2380                 handleItemChange(old, e->state() & Qt::ShiftButton, e->state() & Qt::ControlButton);
2381                 if (!(e->state() & Qt::ShiftButton) || !d->selectAnchor)
2382                     d->selectAnchor = d->current;
2383             }
2384             break;
2385         case Qt::Key_Space:
2386             {
2387                 selectCurrent = true;
2388                 d->currInputString.clear();
2389                 toggleCurrentItem();
2390                 if (selectionMode() == Extended && d->current->isSelected())
2391                     emit highlighted(currentItem());
2392                 if (selfCheck && (!(e->state() & Qt::ShiftButton) || !d->selectAnchor))
2393                     d->selectAnchor = d->current;
2394             }
2395             break;
2396         case Qt::Key_Return:
2397         case Qt::Key_Enter:
2398             {
2399                 selectCurrent = true;
2400                 d->currInputString.clear();
2401                 if (currentItem() >= 0 && selectionMode() != NoSelection) {
2402                     QString tmp = item(currentItem())->text();
2403                     emit selected(currentItem());
2404                     emit selected(item(currentItem()));
2405                     if (!tmp.isEmpty())
2406                         emit selected(tmp);
2407                     emit returnPressed(item(currentItem()));
2408                 }
2409                 if (selfCheck && (!(e->state() & Qt::ShiftButton) || !d->selectAnchor))
2410                     d->selectAnchor = d->current;
2411             }
2412             break;
2413         case Qt::Key_Home:
2414             {
2415                 selectCurrent = true;
2416                 d->currInputString.clear();
2417                 setCurrentItem(0);
2418                 handleItemChange(old, e->state() & Qt::ShiftButton, e->state() & Qt::ControlButton);
2419                 if (!(e->state() & Qt::ShiftButton) || !d->selectAnchor)
2420                     d->selectAnchor = d->current;
2421             }
2422             break;
2423         case Qt::Key_End:
2424             {
2425                 selectCurrent = true;
2426                 d->currInputString.clear();
2427                 int i = (int)count() - 1;
2428                 setCurrentItem(i);
2429                 handleItemChange(old, e->state() & Qt::ShiftButton, e->state() & Qt::ControlButton);
2430                 if (!(e->state() & Qt::ShiftButton) || !d->selectAnchor)
2431                     d->selectAnchor = d->current;
2432             }
2433             break;
2434         default:
2435             {
2436                 if (!e->text().isEmpty() && e->text()[0].isPrint() && count()) {
2437                     int curItem = currentItem();
2438                     if (curItem == -1)
2439                         curItem = 0;
2440                     if (!d->inputTimer->isActive()) {
2441                         d->currInputString = e->text();
2442                         curItem = d->findItemByName(++curItem, d->currInputString);
2443                     } else {
2444                         d->inputTimer->stop();
2445                         d->currInputString += e->text();
2446                         int oldCurItem = curItem;
2447                         curItem = d->findItemByName(curItem, d->currInputString);
2448                         if (curItem < 0) {
2449                             curItem = d->findItemByName(++oldCurItem, e->text());
2450                             d->currInputString = e->text();
2451                         }
2452                     }
2453                     if (curItem >= 0)
2454                         setCurrentItem(curItem);
2455                     if (curItem >= 0 && selectionMode() == Q3ListBox::Extended) {
2456                         bool changed = false;
2457                         bool block = signalsBlocked();
2458                         blockSignals(true);
2459                         selectAll(false);
2460                         blockSignals(block);
2461                         Q3ListBoxItem *i = item(curItem);
2462                         if (!i->s && i->isSelectable()) {
2463                             changed = true;
2464                             i->s = true;
2465                             updateItem(i);
2466                         }
2467                         if (changed)
2468                             emit selectionChanged();
2469                     }
2470                     d->inputTimer->start(400, true);
2471                 } else {
2472                     d->currInputString.clear();
2473                     if (e->state() & Qt::ControlButton) {
2474                         switch (e->key()) {
2475                             case Qt::Key_A:
2476                                 selectAll(true);
2477                                 break;
2478                         }
2479                     } else {
2480                         e->ignore();
2481                     }
2482                 }
2483             }
2484     }
2485 
2486     if (selfCheck && selectCurrent && selectionMode() == Single &&
2487         d->current && !d->current->s) {
2488             updateItem(d->current);
2489             setSelected(d->current, true);
2490         }
2491 }
2492 
2493 
2494 /*!\reimp
2495 */
focusInEvent(QFocusEvent * e)2496 void Q3ListBox::focusInEvent(QFocusEvent *e)
2497 {
2498     d->mousePressRow = -1;
2499     d->mousePressColumn = -1;
2500     d->inMenuMode = false;
2501     if (e->reason() != Qt::MouseFocusReason && !d->current && d->head) {
2502         d->current = d->head;
2503         Q3ListBoxItem *i = d->current;
2504         QString tmp;
2505         if (i)
2506             tmp = i->text();
2507         int tmp2 = index(i);
2508         emit highlighted(i);
2509         if (!tmp.isNull())
2510             emit highlighted(tmp);
2511         emit highlighted(tmp2);
2512         emit currentChanged(i);
2513     }
2514     if (style()->styleHint(QStyle::SH_ItemView_ChangeHighlightOnFocus, 0, this))
2515         repaintSelection();
2516 
2517     if (d->current)
2518         updateItem(currentItem());
2519 }
2520 
2521 
2522 /*!\reimp
2523 */
focusOutEvent(QFocusEvent * e)2524 void Q3ListBox::focusOutEvent(QFocusEvent *e)
2525 {
2526     if (style()->styleHint(QStyle::SH_ItemView_ChangeHighlightOnFocus, 0, this)) {
2527         d->inMenuMode =
2528             e->reason() == Qt::PopupFocusReason ||
2529             (qApp->focusWidget() && qApp->focusWidget()->inherits("QMenuBar"));
2530         if (!d->inMenuMode)
2531             repaintSelection();
2532     }
2533 
2534     if (d->current)
2535         updateItem(currentItem());
2536 }
2537 
2538 /*!\reimp
2539 */
eventFilter(QObject * o,QEvent * e)2540 bool Q3ListBox::eventFilter(QObject *o, QEvent *e)
2541 {
2542     return Q3ScrollView::eventFilter(o, e);
2543 }
2544 
2545 /*!
2546     Repaints the item at position \a index in the list.
2547 */
2548 
updateItem(int index)2549 void Q3ListBox::updateItem(int index)
2550 {
2551     if (index >= 0)
2552         updateItem(item(index));
2553 }
2554 
2555 
2556 /*!
2557     \overload
2558 
2559     Repaints the Q3ListBoxItem \a i.
2560 */
2561 
updateItem(Q3ListBoxItem * i)2562 void Q3ListBox::updateItem(Q3ListBoxItem * i)
2563 {
2564     if (!i)
2565         return;
2566     i->dirty = true;
2567     d->updateTimer->start(0, true);
2568 }
2569 
2570 
2571 /*!
2572     \property Q3ListBox::selectionMode
2573     \brief the selection mode of the list box
2574 
2575     Sets the list box's selection mode, which may be one of \c Single
2576     (the default), \c Extended, \c Multi or \c NoSelection.
2577 
2578     \sa SelectionMode
2579 */
2580 
setSelectionMode(SelectionMode mode)2581 void Q3ListBox::setSelectionMode(SelectionMode mode)
2582 {
2583     if (d->selectionMode == mode)
2584         return;
2585 
2586     if ((selectionMode() == Multi || selectionMode() == Extended)
2587          && (mode == Q3ListBox::Single || mode == Q3ListBox::NoSelection)){
2588         clearSelection();
2589         if ((mode == Q3ListBox::Single) && currentItem())
2590             setSelected(currentItem(), true);
2591     }
2592 
2593     d->selectionMode = mode;
2594     triggerUpdate(true);
2595 }
2596 
2597 
selectionMode() const2598 Q3ListBox::SelectionMode Q3ListBox::selectionMode() const
2599 {
2600     return d->selectionMode;
2601 }
2602 
2603 
2604 /*!
2605   \property Q3ListBox::multiSelection
2606   \brief whether or not the list box is in Multi selection mode
2607 
2608   Consider using the \l Q3ListBox::selectionMode property instead of
2609   this property.
2610 
2611   When setting this property, Multi selection mode is used if set to true and
2612   to Single selection mode if set to false.
2613 
2614   When getting this property, true is returned if the list box is in
2615   Multi selection mode or Extended selection mode, and false if it is
2616   in Single selection mode or NoSelection mode.
2617 
2618   \sa selectionMode
2619 */
2620 
isMultiSelection() const2621 bool Q3ListBox::isMultiSelection() const
2622 {
2623     return selectionMode() == Multi || selectionMode() == Extended;
2624 }
2625 
setMultiSelection(bool enable)2626 void Q3ListBox::setMultiSelection(bool enable)
2627 {
2628     setSelectionMode(enable ? Multi : Single);
2629 }
2630 
2631 
2632 /*!
2633     Toggles the selection status of currentItem() and repaints if the
2634     list box is a \c Multi selection list box.
2635 
2636     \sa setMultiSelection()
2637 */
2638 
toggleCurrentItem()2639 void Q3ListBox::toggleCurrentItem()
2640 {
2641     if (selectionMode() == Single ||
2642          selectionMode() == NoSelection ||
2643          !d->current)
2644         return;
2645 
2646     if (d->current->s || d->current->isSelectable()) {
2647         d->current->s = !d->current->s;
2648         emit selectionChanged();
2649 #ifndef QT_NO_ACCESSIBILITY
2650         int ind = index(d->current);
2651         QAccessible::updateAccessibility(viewport(), 0, QAccessible::Selection);
2652         QAccessible::updateAccessibility(viewport(), ind+1, QAccessible::StateChanged);
2653         QAccessible::updateAccessibility(viewport(), ind+1, d->current->s ? QAccessible::SelectionAdd : QAccessible::SelectionRemove);
2654 #endif
2655     }
2656     updateItem(d->current);
2657 }
2658 
2659 
2660 /*!
2661     \overload
2662 
2663     If \a select is true the item at position \a index is selected;
2664     otherwise the item is deselected.
2665 */
2666 
setSelected(int index,bool select)2667 void Q3ListBox::setSelected(int index, bool select)
2668 {
2669     setSelected(item(index), select);
2670 }
2671 
2672 
2673 /*!
2674     Selects \a item if \a select is true or unselects it if \a select
2675     is false, and repaints the item appropriately.
2676 
2677     If the list box is a \c Single selection list box and \a select is
2678     true, setSelected() calls setCurrentItem().
2679 
2680     If the list box is a \c Single selection list box, \a select is
2681     false, setSelected() calls clearSelection().
2682 
2683     \sa setMultiSelection(), setCurrentItem(), clearSelection(), currentItem()
2684 */
2685 
setSelected(Q3ListBoxItem * item,bool select)2686 void Q3ListBox::setSelected(Q3ListBoxItem * item, bool select)
2687 {
2688     if (!item || !item->isSelectable() ||
2689         (bool)item->s == select || d->selectionMode == NoSelection)
2690         return;
2691 
2692     int ind = index(item);
2693     bool emitHighlighted = (d->current != item) || ( select && (item->s != (uint) select) );
2694     if (selectionMode() == Single) {
2695         if (d->current != item) {
2696             Q3ListBoxItem *o = d->current;
2697             if (d->current && d->current->s)
2698                 d->current->s = false;
2699             d->current = item;
2700 #ifndef QT_NO_ACCESSIBILITY
2701             QAccessible::updateAccessibility(viewport(), ind+1, QAccessible::Focus);
2702 #endif
2703             d->currentColumn = ind / numRows();
2704             d->currentRow = ind % numRows();
2705 
2706             if (o)
2707                 updateItem(o);
2708         }
2709     }
2710 
2711     item->s = (uint)select;
2712     updateItem(item);
2713 
2714     if (d->selectionMode == Single && select) {
2715         emit selectionChanged(item);
2716 #ifndef QT_NO_ACCESSIBILITY
2717         QAccessible::updateAccessibility(viewport(), ind+1, QAccessible::StateChanged);
2718 #endif
2719     }
2720     emit selectionChanged();
2721 #ifndef QT_NO_ACCESSIBILITY
2722     QAccessible::updateAccessibility(viewport(), 0, QAccessible::Selection);
2723     if (d->selectionMode != Single)
2724         QAccessible::updateAccessibility(viewport(), ind+1, select ? QAccessible::SelectionAdd : QAccessible::SelectionRemove);
2725 #endif
2726 
2727     if (emitHighlighted) {
2728         QString tmp;
2729         if (item)
2730             tmp = item->text();
2731         int tmp2 = index(item);
2732         emit highlighted(item);
2733         if (!tmp.isNull())
2734             emit highlighted(tmp);
2735         emit highlighted(tmp2);
2736         emit currentChanged(item);
2737     }
2738 }
2739 
2740 
2741 /*!
2742     Returns true if item \a i is selected; otherwise returns false.
2743 */
2744 
isSelected(int i) const2745 bool Q3ListBox::isSelected(int i) const
2746 {
2747     if (selectionMode() == Single && i != currentItem())
2748         return false;
2749 
2750     Q3ListBoxItem * lbi = item(i);
2751     if (!lbi)
2752         return false; // should not happen
2753     return lbi->s;
2754 }
2755 
2756 
2757 /*!
2758     \overload
2759 
2760     Returns true if item \a i is selected; otherwise returns false.
2761 */
2762 
isSelected(const Q3ListBoxItem * i) const2763 bool Q3ListBox::isSelected(const Q3ListBoxItem * i) const
2764 {
2765     if (!i)
2766         return false;
2767 
2768     return i->s;
2769 }
2770 
2771 /*!  Returns the selected item if the list box is in
2772 single-selection mode and an item is selected.
2773 
2774 If no items are selected or the list box is in another selection mode
2775 this function returns 0.
2776 
2777 \sa setSelected() setMultiSelection()
2778 */
2779 
selectedItem() const2780 Q3ListBoxItem* Q3ListBox::selectedItem() const
2781 {
2782     if (d->selectionMode != Single)
2783         return 0;
2784     if (isSelected(currentItem()))
2785         return  d->current;
2786     return 0;
2787 }
2788 
2789 
2790 /*!
2791     Deselects all items, if possible.
2792 
2793     Note that a \c Single selection list box will automatically select
2794     an item if it has keyboard focus.
2795 */
2796 
clearSelection()2797 void Q3ListBox::clearSelection()
2798 {
2799     selectAll(false);
2800 }
2801 
2802 /*!
2803     In \c Multi and \c Extended modes, this function sets all items to
2804     be selected if \a select is true, and to be unselected if \a
2805     select is false.
2806 
2807     In \c Single and \c NoSelection modes, this function only changes
2808     the selection status of currentItem().
2809 */
2810 
selectAll(bool select)2811 void Q3ListBox::selectAll(bool select)
2812 {
2813     if (selectionMode() == Multi || selectionMode() == Extended) {
2814         bool b = signalsBlocked();
2815         blockSignals(true);
2816         for (int i = 0; i < (int)count(); i++)
2817             setSelected(i, select);
2818         blockSignals(b);
2819         emit selectionChanged();
2820     } else if (d->current) {
2821         Q3ListBoxItem * i = d->current;
2822         setSelected(i, select);
2823     }
2824 }
2825 
2826 /*!
2827     Inverts the selection. Only works in \c Multi and \c Extended
2828     selection mode.
2829 */
2830 
invertSelection()2831 void Q3ListBox::invertSelection()
2832 {
2833     if (d->selectionMode == Single ||
2834          d->selectionMode == NoSelection)
2835         return;
2836 
2837     bool b = signalsBlocked();
2838     blockSignals(true);
2839     for (int i = 0; i < (int)count(); i++)
2840         setSelected(i, !item(i)->isSelected());
2841     blockSignals(b);
2842     emit selectionChanged();
2843 }
2844 
2845 
2846 /*!
2847   Not used anymore; provided for compatibility.
2848 */
2849 
emitChangedSignal(bool)2850 void Q3ListBox::emitChangedSignal(bool)
2851 {
2852 }
2853 
2854 
2855 /*! \reimp */
2856 
sizeHint() const2857 QSize Q3ListBox::sizeHint() const
2858 {
2859     if (cachedSizeHint().isValid())
2860         return cachedSizeHint();
2861 
2862     ensurePolished();
2863     doLayout();
2864 
2865     int i=0;
2866     while(i < 10 &&
2867            i < (int)d->columnPos.size()-1 &&
2868            d->columnPos[i] < 200)
2869         i++;
2870     int x;
2871     x = qMin(200, d->columnPos[i] +
2872               2 * style()->pixelMetric(QStyle::PM_DefaultFrameWidth));
2873     x = qMax(40, x);
2874 
2875     i = 0;
2876     while(i < 10 &&
2877            i < (int)d->rowPos.size()-1 &&
2878            d->rowPos[i] < 200)
2879         i++;
2880     int y;
2881     y = qMin(200, d->rowPos[i] +
2882               2 * style()->pixelMetric(QStyle::PM_DefaultFrameWidth));
2883     y = qMax(40, y);
2884 
2885     QSize s(x, y);
2886     setCachedSizeHint(s);
2887     return s;
2888 }
2889 
2890 /*!
2891   \reimp
2892 */
2893 
minimumSizeHint() const2894 QSize Q3ListBox::minimumSizeHint() const
2895 {
2896     return Q3ScrollView::minimumSizeHint();
2897 }
2898 
2899 
2900 /*!
2901     Ensures that a single paint event will occur at the end of the
2902     current event loop iteration. If \a doLayout is true, the layout
2903     is also redone.
2904 */
2905 
triggerUpdate(bool doLayout)2906 void Q3ListBox::triggerUpdate(bool doLayout)
2907 {
2908     if (doLayout)
2909         d->layoutDirty = d->mustPaintAll = true;
2910     d->updateTimer->start(0, true);
2911 }
2912 
2913 
setColumnMode(LayoutMode mode)2914 void Q3ListBox::setColumnMode(LayoutMode mode)
2915 {
2916     if (mode == Variable)
2917         return;
2918     d->rowModeWins = false;
2919     d->columnMode = mode;
2920     triggerUpdate(true);
2921 }
2922 
2923 
setColumnMode(int columns)2924 void Q3ListBox::setColumnMode(int columns)
2925 {
2926     if (columns < 1)
2927         columns = 1;
2928     d->columnMode = FixedNumber;
2929     d->numColumns = columns;
2930     d->rowModeWins = false;
2931     triggerUpdate(true);
2932 }
2933 
setRowMode(LayoutMode mode)2934 void Q3ListBox::setRowMode(LayoutMode mode)
2935 {
2936     if (mode == Variable)
2937         return;
2938     d->rowModeWins = true;
2939     d->rowMode = mode;
2940     triggerUpdate(true);
2941 }
2942 
2943 
setRowMode(int rows)2944 void Q3ListBox::setRowMode(int rows)
2945 {
2946     if (rows < 1)
2947         rows = 1;
2948     d->rowMode = FixedNumber;
2949     d->numRows = rows;
2950     d->rowModeWins = true;
2951     triggerUpdate(true);
2952 }
2953 
2954 /*!
2955     \property Q3ListBox::columnMode
2956     \brief the column layout mode for this list box.
2957 
2958     setColumnMode() sets the layout mode and adjusts the number of
2959     displayed columns. The row layout mode automatically becomes \c
2960     Variable, unless the column mode is \c Variable.
2961 
2962     \sa setRowMode() rowMode numColumns
2963 */
2964 
2965 
columnMode() const2966 Q3ListBox::LayoutMode Q3ListBox::columnMode() const
2967 {
2968     if (d->rowModeWins)
2969         return Variable;
2970     else
2971         return d->columnMode;
2972 }
2973 
2974 
2975 /*!
2976     \property Q3ListBox::rowMode
2977     \brief the row layout mode for this list box
2978 
2979     This property is normally \c Variable.
2980 
2981     setRowMode() sets the layout mode and adjusts the number of
2982     displayed rows. The column layout mode automatically becomes \c
2983     Variable, unless the row mode is \c Variable.
2984 
2985     \sa columnMode
2986 */
2987 
2988 
rowMode() const2989 Q3ListBox::LayoutMode Q3ListBox::rowMode() const
2990 {
2991     if (d->rowModeWins)
2992         return d->rowMode;
2993     else
2994         return Variable;
2995 }
2996 
2997 
2998 /*!
2999     \property Q3ListBox::numColumns
3000     \brief the number of columns in the list box
3001 
3002     This is normally 1, but can be different if \l
3003     Q3ListBox::columnMode or \l Q3ListBox::rowMode has been set.
3004 
3005     \sa columnMode rowMode numRows
3006 */
3007 
numColumns() const3008 int Q3ListBox::numColumns() const
3009 {
3010     if (count() == 0)
3011         return 0;
3012     if (!d->rowModeWins && d->columnMode == FixedNumber)
3013         return d->numColumns;
3014     doLayout();
3015     return d->columnPos.size()-1;
3016 }
3017 
3018 
3019 /*!
3020     \property Q3ListBox::numRows
3021     \brief the number of rows in the list box.
3022 
3023     This is equal to the number of items in the default single-column
3024     layout, but can be different.
3025 
3026     \sa columnMode rowMode numColumns
3027 */
3028 
numRows() const3029 int Q3ListBox::numRows() const
3030 {
3031     if (count() == 0)
3032         return 0;
3033     if (d->rowModeWins && d->rowMode == FixedNumber)
3034         return d->numRows;
3035     doLayout();
3036     return d->rowPos.size()-1;
3037 }
3038 
3039 
3040 /*!
3041     This function does the hard layout work. You should never need to
3042     call it.
3043 */
3044 
doLayout() const3045 void Q3ListBox::doLayout() const
3046 {
3047     if (!d->layoutDirty || d->resizeTimer->isActive())
3048         return;
3049     ensurePolished();
3050     int c = count();
3051     switch(rowMode()) {
3052     case FixedNumber:
3053         // columnMode() is known to be Variable
3054         tryGeometry(d->numRows, (c+d->numRows-1)/d->numRows);
3055         break;
3056     case FitToHeight:
3057         // columnMode() is known to be Variable
3058         if (d->head) {
3059             // this is basically the FitToWidth code, but edited to use rows.
3060             int maxh = 0;
3061             Q3ListBoxItem * i = d->head;
3062             while (i) {
3063                 int h = i->height(this);
3064                 if (maxh < h)
3065                     maxh = h;
3066                 i = i->n;
3067             }
3068             int vh = viewportSize(1, 1).height();
3069             do {
3070                 int rows = vh / maxh;
3071                 if (rows > c)
3072                     rows = c;
3073                 if (rows < 1)
3074                     rows = 1;
3075                 if (variableHeight() && rows < c) {
3076                     do {
3077                         ++rows;
3078                         tryGeometry(rows, (c+rows-1)/rows);
3079                     } while (rows <= c &&
3080                               d->rowPos[(int)d->rowPos.size()-1] <= vh);
3081                     --rows;
3082                 }
3083                 tryGeometry(rows, (c+rows-1)/rows);
3084                 int nvh = viewportSize(d->columnPos[(int)d->columnPos.size()-1],
3085                                         d->rowPos[(int)d->rowPos.size()-1]).height();
3086                 if (nvh < vh)
3087                     vh = nvh;
3088             } while (d->rowPos.size() > 2 &&
3089                       vh < d->rowPos[(int)d->rowPos.size()-1]);
3090         } else {
3091             tryGeometry(1, 1);
3092         }
3093         break;
3094     case Variable:
3095         if (columnMode() == FixedNumber) {
3096             tryGeometry((count()+d->numColumns-1)/d->numColumns,
3097                          d->numColumns);
3098         } else if (d->head) { // FitToWidth, at least one item
3099             int maxw = 0;
3100             Q3ListBoxItem * i = d->head;
3101             while (i) {
3102                 int w = i->width(this);
3103                 if (maxw < w)
3104                     maxw = w;
3105                 i = i->n;
3106             }
3107             int vw = viewportSize(1, 1).width();
3108             do {
3109                 int cols = vw / maxw;
3110                 if (cols > c)
3111                     cols = c;
3112                 if (cols < 1)
3113                     cols = 1;
3114                 if (variableWidth() && cols < c) {
3115                     do {
3116                         ++cols;
3117                         tryGeometry((c+cols-1)/cols, cols);
3118                     } while (cols <= c &&
3119                               d->columnPos[(int)d->columnPos.size()-1] <= vw);
3120                     --cols;
3121                 }
3122                 tryGeometry((c+cols-1)/cols, cols);
3123                 int nvw = viewportSize(d->columnPos[(int)d->columnPos.size()-1],
3124                                         d->rowPos[(int)d->rowPos.size()-1]).width();
3125                 if (nvw < vw)
3126                     vw = nvw;
3127             } while (d->columnPos.size() > 2 &&
3128                       vw < d->columnPos[(int)d->columnPos.size()-1]);
3129         } else {
3130             tryGeometry(1, 1);
3131         }
3132         break;
3133     }
3134 
3135     d->layoutDirty = false;
3136     int w = d->columnPos[(int)d->columnPos.size()-1];
3137     int h = d->rowPos[(int)d->rowPos.size()-1];
3138     QSize s(viewportSize(w, h));
3139     w = qMax(w, s.width());
3140 
3141     d->columnPosOne = d->columnPos[1];
3142     // extend the column for simple single-column listboxes
3143     if (columnMode() == FixedNumber && d->numColumns == 1 &&
3144          d->columnPos[1] < w)
3145         d->columnPos[1] = w;
3146     ((Q3ListBox *)this)->resizeContents(w, h);
3147 }
3148 
3149 
3150 /*!
3151     Lay the items out in a \a columns by \a rows array. The array may
3152     be too big: doLayout() is expected to call this with the right
3153     values.
3154 */
3155 
tryGeometry(int rows,int columns) const3156 void Q3ListBox::tryGeometry(int rows, int columns) const
3157 {
3158     if (columns < 1)
3159         columns = 1;
3160     d->columnPos.resize(columns+1);
3161 
3162     if (rows < 1)
3163         rows = 1;
3164     d->rowPos.resize(rows+1);
3165 
3166     // funky hack I: dump the height/width of each column/row in
3167     // {column,row}Pos for later conversion to positions.
3168     int c;
3169     for(c=0; c<=columns; c++)
3170         d->columnPos[c] = 0;
3171     int r;
3172     for(r=0; r<=rows; r++)
3173         d->rowPos[r] = 0;
3174     r = c = 0;
3175     Q3ListBoxItem * i = d->head;
3176     while (i && c < columns) {
3177         if (i == d->current) {
3178             d->currentRow = r;
3179             d->currentColumn = c;
3180         }
3181 
3182         int w = i->width(this);
3183         if (d->columnPos[c] < w)
3184             d->columnPos[c] = w;
3185         int h = i->height(this);
3186         if (d->rowPos[r] < h)
3187             d->rowPos[r] = h;
3188         i = i->n;
3189         r++;
3190         if (r == rows) {
3191             r = 0;
3192             c++;
3193         }
3194     }
3195     // funky hack II: if not variable {width,height}, unvariablify it.
3196     if (!variableWidth()) {
3197         int w = 0;
3198         for(c=0; c<columns; c++)
3199             if (w < d->columnPos[c])
3200                 w = d->columnPos[c];
3201         for(c=0; c<columns; c++)
3202             d->columnPos[c] = w;
3203     }
3204     if (!variableHeight()) {
3205         int h = 0;
3206         for(r=0; r<rows; r++)
3207             if (h < d->rowPos[r])
3208                 h = d->rowPos[r];
3209         for(r=0; r<rows; r++)
3210             d->rowPos[r] = h;
3211     }
3212     // repair the hacking.
3213     int x = 0;
3214     for(c=0; c<=columns; c++) {
3215         int w = d->columnPos[c];
3216         d->columnPos[c] = x;
3217         x += w;
3218     }
3219     int y = 0;
3220     for(r=0; r<=rows; r++) {
3221         int h = d->rowPos[r];
3222         d->rowPos[r] = y;
3223         y += h;
3224     }
3225 }
3226 
3227 
3228 /*!
3229     Returns the row index of the current item, or -1 if no item is the
3230     current item.
3231 */
3232 
currentRow() const3233 int Q3ListBox::currentRow() const
3234 {
3235     if (!d->current)
3236         return -1;
3237     if (d->currentRow < 0)
3238         d->layoutDirty = true;
3239     if (d->layoutDirty)
3240         doLayout();
3241     return d->currentRow;
3242 }
3243 
3244 
3245 /*!
3246     Returns the column index of the current item, or -1 if no item is
3247     the current item.
3248 */
3249 
currentColumn() const3250 int Q3ListBox::currentColumn() const
3251 {
3252     if (!d->current)
3253         return -1;
3254     if (d->currentColumn < 0)
3255         d->layoutDirty = true;
3256     if (d->layoutDirty)
3257         doLayout();
3258     return d->currentColumn;
3259 }
3260 
3261 
setTopItem(int index)3262 void Q3ListBox::setTopItem(int index)
3263 {
3264     if (index >= (int)count() || count() == 0)
3265         return;
3266     int col = index / numRows();
3267     int y = d->rowPos[index-col*numRows()];
3268     if (d->columnPos[col] >= contentsX() &&
3269          d->columnPos[col+1] <= contentsX() + visibleWidth())
3270         setContentsPos(contentsX(), y);
3271     else
3272         setContentsPos(d->columnPos[col], y);
3273 }
3274 
3275 /*!
3276     Scrolls the list box so the item at position \a index in the list
3277     is displayed in the bottom row of the list box.
3278 
3279     \sa setTopItem()
3280 */
3281 
setBottomItem(int index)3282 void Q3ListBox::setBottomItem(int index)
3283 {
3284     if (index >= (int)count() || count() == 0)
3285         return;
3286     int col = index / numRows();
3287     int y = d->rowPos[1+index-col*numRows()] - visibleHeight();
3288     if (y < 0)
3289         y = 0;
3290     if (d->columnPos[col] >= contentsX() &&
3291          d->columnPos[col+1] <= contentsX() + visibleWidth())
3292         setContentsPos(contentsX(), y);
3293     else
3294         setContentsPos(d->columnPos[col], y);
3295 }
3296 
3297 
3298 /*!
3299     Returns the item at point \a p, specified in viewport coordinates,
3300     or a 0 if there is no item at \a p.
3301 
3302     Use contentsToViewport() to convert between widget coordinates and
3303     viewport coordinates.
3304 */
3305 
itemAt(const QPoint & p) const3306 Q3ListBoxItem * Q3ListBox::itemAt(const QPoint& p) const
3307 {
3308     if (d->layoutDirty)
3309         doLayout();
3310     QPoint np = p;
3311 
3312     np -= viewport()->pos();
3313     if (!viewport()->rect().contains(np))
3314         return 0;
3315 
3316     // take into account contents position
3317     np = viewportToContents(np);
3318 
3319     int x = np.x();
3320     int y = np.y();
3321 
3322     // return 0 when y is below the last row
3323     if (y > d->rowPos[numRows()])
3324         return 0;
3325 
3326     int col = columnAt(x);
3327     int row = rowAt(y);
3328 
3329     Q3ListBoxItem *i = item(col * numRows()  + row);
3330     if (i && numColumns() > 1) {
3331         if (d->columnPos[col] + i->width(this) >= x)
3332             return i;
3333     } else {
3334         if (d->columnPos[col + 1] >= x)
3335             return i;
3336     }
3337     return 0;
3338 }
3339 
3340 
3341 /*!
3342     Ensures that the current item is visible.
3343 */
3344 
ensureCurrentVisible()3345 void Q3ListBox::ensureCurrentVisible()
3346 {
3347     if (!d->current)
3348         return;
3349 
3350     doLayout();
3351 
3352     int row = currentRow();
3353     int column = currentColumn();
3354     int w = (d->columnPos[column+1] - d->columnPos[column]) / 2;
3355     int h = (d->rowPos[row+1] - d->rowPos[row]) / 2;
3356     // next four lines are Bad.  they mean that for pure left-to-right
3357     // languages, textual list box items are displayed better than
3358     // before when there is little space.  for non-textual items, or
3359     // other languages, it means... that you really should have enough
3360     // space in the first place :)
3361     if (numColumns() == 1)
3362         w = 0;
3363     if (w*2 > viewport()->width())
3364         w = viewport()->width()/2;
3365 
3366     ensureVisible(d->columnPos[column] + w, d->rowPos[row] + h, w, h);
3367 }
3368 
3369 
3370 /*! \internal */
3371 
doAutoScroll()3372 void Q3ListBox::doAutoScroll()
3373 {
3374     if (d->scrollPos.x() < 0) {
3375         // scroll left
3376         int x = contentsX() - horizontalScrollBar()->singleStep();
3377         if (x < 0)
3378             x = 0;
3379         if (x != contentsX()) {
3380             d->mouseMoveColumn = columnAt(x);
3381             updateSelection();
3382             if (x < contentsX())
3383                 setContentsPos(x, contentsY());
3384         }
3385     } else if (d->scrollPos.x() > 0) {
3386         // scroll right
3387         int x = contentsX() + horizontalScrollBar()->singleStep();
3388         if (x + visibleWidth() > contentsWidth())
3389             x = contentsWidth() - visibleWidth();
3390         if (x != contentsX()) {
3391             d->mouseMoveColumn = columnAt(x + visibleWidth() - 1);
3392             updateSelection();
3393             if (x > contentsX())
3394                 setContentsPos(x, contentsY());
3395         }
3396     }
3397 
3398     if (d->scrollPos.y() < 0) {
3399         // scroll up
3400         int y = contentsY() - verticalScrollBar()->singleStep();
3401         if (y < 0)
3402             y = 0;
3403         if (y != contentsY()) {
3404             y = contentsY() - verticalScrollBar()->singleStep();
3405             d->mouseMoveRow = rowAt(y);
3406             updateSelection();
3407         }
3408     } else if (d->scrollPos.y() > 0) {
3409         // scroll down
3410         int y = contentsY() + verticalScrollBar()->singleStep();
3411         if (y + visibleHeight() > contentsHeight())
3412             y = contentsHeight() - visibleHeight();
3413         if (y != contentsY()) {
3414             y = contentsY() + verticalScrollBar()->singleStep();
3415             d->mouseMoveRow = rowAt(y + visibleHeight() - 1);
3416             updateSelection();
3417         }
3418     }
3419 
3420     if (d->scrollPos == QPoint(0, 0)) {
3421         delete d->scrollTimer;
3422         d->scrollTimer = 0;
3423     }
3424 }
3425 
3426 
3427 /*!
3428     \property Q3ListBox::topItem
3429     \brief the index of an item at the top of the screen.
3430 
3431     When getting this property and the listbox has multiple columns,
3432     an arbitrary item is selected and returned.
3433 
3434     When setting this property, the list box is scrolled so the item
3435     at position \e index in the list is displayed in the top row of
3436     the list box.
3437 */
3438 
topItem() const3439 int Q3ListBox::topItem() const
3440 {
3441     doLayout();
3442 
3443     // move rightwards to the best column
3444     int col = columnAt(contentsX());
3445     int row = rowAt(contentsY());
3446     return col * numRows() + row;
3447 }
3448 
3449 
3450 /*!
3451     \property Q3ListBox::variableHeight
3452     \brief whether this list box has variable-height rows
3453 
3454     When the list box has variable-height rows (the default), each row
3455     is as high as the highest item in that row. When it has same-sized
3456     rows, all rows are as high as the highest item in the list box.
3457 
3458     \sa variableWidth
3459 */
3460 
variableHeight() const3461 bool Q3ListBox::variableHeight() const
3462 {
3463     return d->variableHeight;
3464 }
3465 
3466 
setVariableHeight(bool enable)3467 void Q3ListBox::setVariableHeight(bool enable)
3468 {
3469     if ((bool)d->variableHeight == enable)
3470         return;
3471 
3472     d->variableHeight = enable;
3473     triggerUpdate(true);
3474 }
3475 
3476 
3477 /*!
3478     \property Q3ListBox::variableWidth
3479     \brief whether this list box has variable-width columns
3480 
3481     When the list box has variable-width columns, each column is as
3482     wide as the widest item in that column. When it has same-sized
3483     columns (the default), all columns are as wide as the widest item
3484     in the list box.
3485 
3486     \sa variableHeight
3487 */
3488 
variableWidth() const3489 bool Q3ListBox::variableWidth() const
3490 {
3491     return d->variableWidth;
3492 }
3493 
3494 
setVariableWidth(bool enable)3495 void Q3ListBox::setVariableWidth(bool enable)
3496 {
3497     if ((bool)d->variableWidth == enable)
3498         return;
3499 
3500     d->variableWidth = enable;
3501     triggerUpdate(true);
3502 }
3503 
3504 
3505 /*!
3506     Repaints only what really needs to be repainted.
3507 */
refreshSlot()3508 void Q3ListBox::refreshSlot()
3509 {
3510     if (d->mustPaintAll ||
3511          d->layoutDirty) {
3512         d->mustPaintAll = false;
3513         bool currentItemVisible = itemVisible(currentItem());
3514         doLayout();
3515         if (hasFocus() &&
3516              currentItemVisible &&
3517              d->currentColumn >= 0 &&
3518              d->currentRow >= 0 &&
3519              (d->columnPos[d->currentColumn] < contentsX() ||
3520                d->columnPos[d->currentColumn+1]>contentsX()+visibleWidth() ||
3521                d->rowPos[d->currentRow] < contentsY() ||
3522                d->rowPos[d->currentRow+1] > contentsY()+visibleHeight()))
3523             ensureCurrentVisible();
3524         viewport()->repaint();
3525         return;
3526     }
3527 
3528     QRegion r;
3529     int x = contentsX();
3530     int y = contentsY();
3531     int col = columnAt(x);
3532     int row = rowAt(y);
3533     int top = row;
3534     while(col+1 < (int)d->columnPos.size() && d->columnPos[col+1] < x)
3535         col++;
3536     while(top+1 < (int)d->rowPos.size() && d->rowPos[top+1] < y)
3537         top++;
3538     Q3ListBoxItem * i = item(col * numRows() + row);
3539 
3540     while (i && (int)col < numColumns() &&
3541             d->columnPos[col] < x + visibleWidth() ) {
3542         int cw = d->columnPos[col+1] - d->columnPos[col];
3543         while (i && row < numRows() && d->rowPos[row] <
3544                 y + visibleHeight()) {
3545             if (i->dirty)
3546                 r = r.united(QRect(d->columnPos[col] - x, d->rowPos[row] - y,
3547                                    cw, d->rowPos[row+1] - d->rowPos[row]));
3548             row++;
3549             i = i->n;
3550         }
3551         col++;
3552         if (numColumns() > 1) {
3553             row = top;
3554             i = item(col *  numRows() + row);
3555         }
3556     }
3557 
3558     if (r.isEmpty())
3559         viewport()->repaint();
3560     else
3561         viewport()->repaint(r);
3562 }
3563 
3564 
3565 /*! \reimp */
3566 
viewportPaintEvent(QPaintEvent * e)3567 void Q3ListBox::viewportPaintEvent(QPaintEvent * e)
3568 {
3569     doLayout();
3570     QWidget* vp = viewport();
3571     QPainter p(vp);
3572     QRegion r = e->region();
3573 
3574 #if 0
3575     {
3576         // this stuff has been useful enough times that from now I'm
3577         //  leaving it in the source.
3578         uint i = 0;
3579         qDebug("%s/%s: %i rects", className(), name(), r.rects().size());
3580         while(i < r.rects().size()) {
3581             qDebug("rect %d: %d, %d, %d, %d", i,
3582                    r.rects()[i].left(), r.rects()[i].top(),
3583                    r.rects()[i].width(), r.rects()[i].height());
3584             i++;
3585         }
3586         qDebug("");
3587     }
3588 #endif
3589 
3590     int x = contentsX();
3591     int y = contentsY();
3592     int w = vp->width();
3593     int h = vp->height();
3594 
3595     int col = columnAt(x);
3596     int top = rowAt(y);
3597     int row = top;
3598 
3599     Q3ListBoxItem * i = item(col*numRows() + row);
3600 
3601     const QPalette &pal = palette();
3602     p.setPen(pal.text().color());
3603     p.setBackground(palette().brush(backgroundRole()).color());
3604     while (i && (int)col < numColumns() && d->columnPos[col] < x + w) {
3605         int cw = d->columnPos[col+1] - d->columnPos[col];
3606         while (i && (int)row < numRows() && d->rowPos[row] < y + h) {
3607             int ch = d->rowPos[row+1] - d->rowPos[row];
3608             QRect itemRect(d->columnPos[col]-x, d->rowPos[row]-y, cw, ch);
3609             QRegion tempRegion(itemRect);
3610             QRegion itemPaintRegion(tempRegion.intersected(r ));
3611             if (!itemPaintRegion.isEmpty()) {
3612                 p.save();
3613                 p.setClipRegion(itemPaintRegion);
3614                 p.translate(d->columnPos[col]-x, d->rowPos[row]-y);
3615                 paintCell(&p, row, col);
3616                 p.restore();
3617                 r = r.subtracted(itemPaintRegion);
3618             }
3619             row++;
3620             if (i->dirty) {
3621                 // reset dirty flag only if the entire item was painted
3622                 if (itemPaintRegion == QRegion(itemRect))
3623                     i->dirty = false;
3624             }
3625             i = i->n;
3626         }
3627         col++;
3628         if (numColumns() > 1) {
3629             row = top;
3630             i = item(col *  numRows() + row);
3631         }
3632     }
3633 
3634     if (r.isEmpty())
3635         return;
3636     p.setClipRegion(r);
3637     p.fillRect(0, 0, w, h, viewport()->palette().brush(viewport()->backgroundRole()));
3638 
3639     if(d->rubber && d->rubber->width() && d->rubber->height()) {
3640         p.save();
3641         p.setClipping(false);
3642         // p.setRasterOp(NotROP); // ### fix - use qrubberband instead
3643         QStyleOptionRubberBand opt;
3644         opt.rect = d->rubber->normalized();
3645         opt.palette = palette();
3646         opt.shape = QRubberBand::Rectangle;
3647         opt.opaque = false;
3648         style()->drawControl(QStyle::CE_RubberBand, &opt, &p, this);
3649         p.restore();
3650     }
3651 }
3652 
3653 
3654 /*!
3655     Returns the height in pixels of the item with index \a index. \a
3656     index defaults to 0.
3657 
3658     If \a index is too large, this function returns 0.
3659 */
3660 
itemHeight(int index) const3661 int Q3ListBox::itemHeight(int index) const
3662 {
3663     if (index >= (int)count() || index < 0)
3664         return 0;
3665     int r = index % numRows();
3666     return d->rowPos[r+1] - d->rowPos[r];
3667 }
3668 
3669 
3670 /*!
3671     Returns the index of the column at \a x, which is in the listbox's
3672     coordinates, not in on-screen coordinates.
3673 
3674     If there is no column that spans \a x, columnAt() returns -1.
3675 */
3676 
columnAt(int x) const3677 int Q3ListBox::columnAt(int x) const
3678 {
3679     if (x < 0)
3680         return -1;
3681     if (!d->columnPos.size())
3682         return -1;
3683     if (x >= d->columnPos[(int)d->columnPos.size()-1])
3684         return numColumns() - 1;
3685 
3686     int col = 0;
3687     while(col+1 < (int)d->columnPos.size() && d->columnPos[col+1] < x)
3688         col++;
3689     return col;
3690 }
3691 
3692 
3693 /*!
3694     Returns the index of the row at \a y, which is in the listbox's
3695     coordinates, not in on-screen coordinates.
3696 
3697     If there is no row that spans \a y, rowAt() returns -1.
3698 */
3699 
rowAt(int y) const3700 int Q3ListBox::rowAt(int y) const
3701 {
3702     if (y < 0)
3703         return -1;
3704 
3705     // find the top item, use bsearch for speed
3706     int l = 0;
3707     int r = d->rowPos.size() - 2;
3708     if (r < 0)
3709         return -1;
3710     if (l <= d->rowPosCache && d->rowPosCache <= r) {
3711         if (d->rowPos[qMax(l, d->rowPosCache - 10)] <= y
3712              && y <= d->rowPos[qMin(r, d->rowPosCache + 10)]) {
3713             l = qMax(l, d->rowPosCache - 10);
3714             r = qMin(r, d->rowPosCache + 10);
3715         }
3716     }
3717     int i = ((l+r+1) / 2);
3718     while (r - l) {
3719         if (d->rowPos[i] > y)
3720             r = i -1;
3721         else
3722             l = i;
3723         i = ((l+r+1) / 2);
3724     }
3725     d->rowPosCache = i;
3726     if (d->rowPos[i] <= y && y <= d->rowPos[i+1] )
3727         return  i;
3728 
3729     return d->count - 1;
3730 }
3731 
3732 
3733 /*!
3734     Returns the rectangle on the screen that \a item occupies in
3735     viewport()'s coordinates, or an invalid rectangle if \a item is 0
3736     or is not currently visible.
3737 */
3738 
itemRect(Q3ListBoxItem * item) const3739 QRect Q3ListBox::itemRect(Q3ListBoxItem *item) const
3740 {
3741     if (d->resizeTimer->isActive())
3742         return QRect(0, 0, -1, -1);
3743     if (!item)
3744         return QRect(0, 0, -1, -1);
3745 
3746     int i = index(item);
3747     if (i == -1)
3748         return QRect(0, 0, -1, -1);
3749 
3750     int col = i / numRows();
3751     int row = i % numRows();
3752 
3753     int x = d->columnPos[col] - contentsX();
3754     int y = d->rowPos[row] - contentsY();
3755 
3756     QRect r(x, y, d->columnPos[col + 1] - d->columnPos[col],
3757                   d->rowPos[row + 1] - d->rowPos[row]);
3758     if (r.intersects(QRect(0, 0, visibleWidth(), visibleHeight())))
3759         return r;
3760     return QRect(0, 0, -1, -1);
3761 }
3762 
3763 
3764 /*!
3765   Using this method is quite inefficient. We suggest to use insertItem()
3766   for inserting and sort() afterwards.
3767 
3768   Inserts \a lbi at its sorted position in the list box and returns the
3769   position.
3770 
3771   All items must be inserted with inSort() to maintain the sorting
3772   order. inSort() treats any pixmap (or user-defined type) as
3773   lexicographically less than any string.
3774 
3775   \sa insertItem(), sort()
3776 */
inSort(const Q3ListBoxItem * lbi)3777 int Q3ListBox::inSort(const Q3ListBoxItem * lbi)
3778 {
3779     if (!lbi)
3780         return -1;
3781 
3782     Q3ListBoxItem * i = d->head;
3783     int c = 0;
3784 
3785     while(i && i->text() < lbi->text()) {
3786         i = i->n;
3787         c++;
3788     }
3789     insertItem(lbi, c);
3790     return c;
3791 }
3792 
3793 /*!
3794   \overload
3795   Using this method is quite inefficient. We suggest to use insertItem()
3796   for inserting and sort() afterwards.
3797 
3798   Inserts a new item of \a text at its sorted position in the list box and
3799   returns the position.
3800 
3801   All items must be inserted with inSort() to maintain the sorting
3802   order. inSort() treats any pixmap (or user-defined type) as
3803   lexicographically less than any string.
3804 
3805   \sa insertItem(), sort()
3806 */
inSort(const QString & text)3807 int Q3ListBox::inSort(const QString& text)
3808 {
3809     Q3ListBoxItem *lbi = new Q3ListBoxText(text);
3810 
3811     Q3ListBoxItem * i = d->head;
3812     int c = 0;
3813 
3814     while(i && i->text() < lbi->text()) {
3815         i = i->n;
3816         c++;
3817     }
3818     insertItem(lbi, c);
3819     return c;
3820 }
3821 
3822 
3823 /*! \reimp */
3824 
resizeEvent(QResizeEvent * e)3825 void Q3ListBox::resizeEvent(QResizeEvent *e)
3826 {
3827     d->layoutDirty = (d->layoutDirty ||
3828                        rowMode() == FitToHeight ||
3829                        columnMode() == FitToWidth);
3830 
3831     if (!d->layoutDirty && columnMode() == FixedNumber &&
3832          d->numColumns == 1) {
3833         int w = d->columnPosOne;
3834         QSize s(viewportSize(w, contentsHeight()));
3835         w = qMax(w, s.width());
3836         d->columnPos[1] = qMax(w, d->columnPosOne);
3837         resizeContents(d->columnPos[1], contentsHeight());
3838     }
3839 
3840     if (d->resizeTimer->isActive())
3841         d->resizeTimer->stop();
3842     if (d->rowMode == FixedNumber && d->columnMode == FixedNumber) {
3843         bool currentItemVisible = itemVisible(currentItem());
3844         doLayout();
3845         Q3ScrollView::resizeEvent(e);
3846         if (currentItemVisible)
3847             ensureCurrentVisible();
3848         if (d->current)
3849             viewport()->repaint(itemRect(d->current));
3850     } else if ((d->columnMode == FitToWidth || d->rowMode == FitToHeight) && !(isVisible())) {
3851         Q3ScrollView::resizeEvent(e);
3852     } else if (d->layoutDirty) {
3853         d->resizeTimer->start(100, true);
3854         resizeContents(contentsWidth() - (e->oldSize().width() - e->size().width()),
3855                         contentsHeight() - (e->oldSize().height() - e->size().height()));
3856         Q3ScrollView::resizeEvent(e);
3857     } else {
3858         Q3ScrollView::resizeEvent(e);
3859     }
3860 }
3861 
3862 /*!
3863   \internal
3864 */
3865 
adjustItems()3866 void Q3ListBox::adjustItems()
3867 {
3868     triggerUpdate(true);
3869     ensureCurrentVisible();
3870 }
3871 
3872 
3873 /*!
3874     Provided for compatibility with the old Q3ListBox. We recommend
3875     using Q3ListBoxItem::paint() instead.
3876 
3877     Repaints the cell at \a row, \a col using painter \a p.
3878 */
3879 
paintCell(QPainter * p,int row,int col)3880 void Q3ListBox::paintCell(QPainter * p, int row, int col)
3881 {
3882     bool drawActiveSelection = hasFocus() || d->inMenuMode ||
3883         !style()->styleHint(QStyle::SH_ItemView_ChangeHighlightOnFocus, 0, this);
3884     QPalette pal = palette();
3885     if(!drawActiveSelection)
3886         pal.setCurrentColorGroup(QPalette::Inactive);
3887 
3888     int cw = d->columnPos[col+1] - d->columnPos[col];
3889     int ch = d->rowPos[row+1] - d->rowPos[row];
3890     Q3ListBoxItem * i = item(col*numRows()+row);
3891     p->save();
3892     if (i->s) {
3893         if (i->custom_highlight) {
3894             p->fillRect(0, 0, cw, ch, pal.brush(viewport()->foregroundRole()));
3895             p->setPen(pal.highlightedText().color());
3896             p->setBackground(pal.highlight());
3897         } else if (numColumns()  == 1) {
3898             p->fillRect(0, 0, cw, ch, pal.brush(QPalette::Highlight));
3899             p->setPen(pal.highlightedText().color());
3900             p->setBackground(pal.highlight());
3901         } else {
3902             int iw = i->width(this);
3903             p->fillRect(0, 0, iw, ch, pal.brush(QPalette::Highlight));
3904             p->fillRect(iw, 0, cw - iw + 1, ch, viewport()->palette().brush(viewport()->backgroundRole()));
3905             p->setPen(pal.highlightedText().color());
3906             p->setBackground(pal.highlight());
3907         }
3908     } else {
3909         p->fillRect(0, 0, cw, ch, viewport()->palette().brush(viewport()->backgroundRole()));
3910     }
3911 
3912     i->paint(p);
3913 
3914     if (d->current == i && hasFocus() && !i->custom_highlight) {
3915         if (numColumns() > 1)
3916             cw = i->width(this);
3917         QStyleOptionFocusRect opt;
3918         opt.rect.setRect(0, 0, cw, ch);
3919         opt.palette = pal;
3920         opt.state = QStyle::State_FocusAtBorder;
3921         if (i->isSelected())
3922             opt.backgroundColor = pal.highlight().color();
3923         else
3924             opt.backgroundColor = pal.base().color();
3925         style()->drawPrimitive(QStyle::PE_FrameFocusRect, &opt, p, this);
3926     }
3927 
3928     p->restore();
3929 }
3930 
3931 /*!
3932     Returns the width of the widest item in the list box.
3933 */
3934 
maxItemWidth() const3935 long Q3ListBox::maxItemWidth() const
3936 {
3937     if (d->layoutDirty)
3938         doLayout();
3939     long m = 0;
3940     int i = d->columnPos.size();
3941     while(i--)
3942         if (m < d->columnPos[i])
3943             m = d->columnPos[i];
3944     return m;
3945 }
3946 
3947 
3948 /*! \reimp */
3949 
showEvent(QShowEvent *)3950 void Q3ListBox::showEvent(QShowEvent *)
3951 {
3952     d->ignoreMoves = false;
3953     d->mousePressRow = -1;
3954     d->mousePressColumn = -1;
3955     d->mustPaintAll = false;
3956     ensureCurrentVisible();
3957 }
3958 
3959 /*!
3960     \fn bool Q3ListBoxItem::isSelected() const
3961 
3962     Returns true if the item is selected; otherwise returns false.
3963 
3964     \sa Q3ListBox::isSelected(), isCurrent()
3965 */
3966 
3967 /*!
3968     Returns true if the item is the current item; otherwise returns
3969     false.
3970 
3971     \sa Q3ListBox::currentItem(), Q3ListBox::item(), isSelected()
3972 */
isCurrent() const3973 bool Q3ListBoxItem::isCurrent() const
3974 {
3975     return listBox() && listBox()->hasFocus() &&
3976         listBox()->item(listBox()->currentItem()) == this;
3977 }
3978 
3979 /*!
3980     \fn void Q3ListBox::centerCurrentItem()
3981 
3982     If there is a current item, the list box is scrolled so that this
3983     item is displayed centered.
3984 
3985     \sa Q3ListBox::ensureCurrentVisible()
3986 */
3987 
3988 /*!
3989     Returns a pointer to the list box containing this item.
3990 */
3991 
listBox() const3992 Q3ListBox * Q3ListBoxItem::listBox() const
3993 {
3994     return lbox;
3995 }
3996 
3997 
3998 /*!
3999     Removes \a item from the list box and causes an update of the
4000     screen display. The item is not deleted. You should normally not
4001     need to call this function because Q3ListBoxItem::~Q3ListBoxItem()
4002     calls it. The normal way to delete an item is with \c delete.
4003 
4004     \sa Q3ListBox::insertItem()
4005 */
takeItem(const Q3ListBoxItem * item)4006 void Q3ListBox::takeItem(const Q3ListBoxItem * item)
4007 {
4008     if (!item || d->clearing)
4009         return;
4010     d->cache = 0;
4011     d->count--;
4012     if (item == d->last)
4013         d->last = d->last->p;
4014     if (item->p && item->p->n == item)
4015         item->p->n = item->n;
4016     if (item->n && item->n->p == item)
4017         item->n->p = item->p;
4018     if (d->head == item) {
4019         d->head = item->n;
4020         d->currentColumn = d->currentRow = -1;
4021     }
4022 
4023     if (d->current == item) {
4024         d->current = item->n ? item->n : item->p;
4025         Q3ListBoxItem *i = d->current;
4026         QString tmp;
4027         if (i)
4028             tmp = i->text();
4029         int tmp2 = index(i);
4030         emit highlighted(i);
4031         if (!tmp.isNull())
4032             emit highlighted(tmp);
4033         emit highlighted(tmp2);
4034         emit currentChanged(i);
4035     }
4036     if (d->tmpCurrent == item)
4037         d->tmpCurrent = d->current;
4038     if (d->selectAnchor == item)
4039         d->selectAnchor = d->current;
4040 
4041     if (item->s)
4042         emit selectionChanged();
4043     ((Q3ListBoxItem *)item)->lbox = 0;
4044     triggerUpdate(true);
4045 }
4046 
4047 /*!
4048   \internal
4049   Finds the next item after start beginning with \a text.
4050 */
4051 
findItemByName(int start,const QString & text)4052 int Q3ListBoxPrivate::findItemByName(int start, const QString &text)
4053 {
4054     if (start < 0 || (uint)start >= listBox->count())
4055         start = 0;
4056     QString match = text.toLower();
4057     if (match.length() < 1)
4058         return start;
4059     QString curText;
4060     int item = start;
4061     do {
4062         curText = listBox->text(item).toLower();
4063         if (curText.startsWith(match))
4064             return item;
4065         item++;
4066         if ((uint)item == listBox->count())
4067             item = 0;
4068     } while (item != start);
4069     return -1;
4070 }
4071 
4072 /*!
4073   \internal
4074 */
4075 
clearInputString()4076 void Q3ListBox::clearInputString()
4077 {
4078     d->currInputString.clear();
4079 }
4080 
4081 /*!
4082     Finds the first list box item that has the text \a text and
4083     returns it, or returns 0 of no such item could be found. If \c
4084     ComparisonFlags are specified in \a compare then these flags
4085     are used, otherwise the default is a case-insensitive, "begins
4086     with" search.
4087 */
4088 
findItem(const QString & text,ComparisonFlags compare) const4089 Q3ListBoxItem *Q3ListBox::findItem(const QString &text, ComparisonFlags compare) const
4090 {
4091     if (text.isEmpty())
4092         return 0;
4093 
4094     if (compare == CaseSensitive || compare == 0)
4095         compare |= ExactMatch;
4096 
4097     QString itmtxt;
4098     QString comtxt = text;
4099     if (!(compare & CaseSensitive))
4100         comtxt = text.toLower();
4101 
4102     Q3ListBoxItem *item;
4103     if (d->current)
4104         item = d->current;
4105     else
4106         item = d->head;
4107 
4108     Q3ListBoxItem *beginsWithItem = 0;
4109     Q3ListBoxItem *endsWithItem = 0;
4110     Q3ListBoxItem *containsItem = 0;
4111 
4112     if (item) {
4113         for (; item; item = item->n) {
4114             if (!(compare & CaseSensitive))
4115                 itmtxt = item->text().toLower();
4116             else
4117                 itmtxt = item->text();
4118 
4119             if ((compare & ExactMatch)==ExactMatch && itmtxt == comtxt)
4120                 return item;
4121             if (compare & BeginsWith && !beginsWithItem && itmtxt.startsWith(comtxt))
4122                 beginsWithItem = containsItem = item;
4123             if (compare & EndsWith && !endsWithItem && itmtxt.endsWith(comtxt))
4124                 endsWithItem = containsItem = item;
4125             if ((compare & ExactMatch)==0 && !containsItem && itmtxt.contains(comtxt))
4126                 containsItem = item;
4127         }
4128 
4129         if (d->current && d->head) {
4130             item = d->head;
4131             for (; item && item != d->current; item = item->n) {
4132                 if (!(compare & CaseSensitive))
4133                     itmtxt = item->text().toLower();
4134                 else
4135                     itmtxt = item->text();
4136 
4137                 if ((compare & ExactMatch)==ExactMatch && itmtxt == comtxt)
4138                     return item;
4139                 if (compare & BeginsWith && !beginsWithItem && itmtxt.startsWith(comtxt))
4140                     beginsWithItem = containsItem = item;
4141                 if (compare & EndsWith && !endsWithItem && itmtxt.endsWith(comtxt))
4142                     endsWithItem = containsItem = item;
4143                 if ((compare & ExactMatch)==0 && !containsItem && itmtxt.contains(comtxt))
4144                     containsItem = item;
4145             }
4146         }
4147     }
4148 
4149     // Obey the priorities
4150     if (beginsWithItem)
4151         return beginsWithItem;
4152     else if (endsWithItem)
4153         return endsWithItem;
4154     else if (containsItem)
4155         return containsItem;
4156     return 0;
4157 }
4158 
4159 /*!
4160   \internal
4161 */
4162 
drawRubber()4163 void Q3ListBox::drawRubber()
4164 {
4165     if (!d->rubber)
4166         return;
4167     if (!d->rubber->width() && !d->rubber->height())
4168         return;
4169     update();
4170 }
4171 
4172 /*!
4173   \internal
4174 */
4175 
doRubberSelection(const QRect & old,const QRect & rubber)4176 void Q3ListBox::doRubberSelection(const QRect &old, const QRect &rubber)
4177 {
4178     Q3ListBoxItem *i = d->head;
4179     QRect ir, pr;
4180     bool changed = false;
4181     for (; i; i = i->n) {
4182         ir = itemRect(i);
4183         if (ir == QRect(0, 0, -1, -1))
4184             continue;
4185         if (i->isSelected() && !ir.intersects(rubber) && ir.intersects(old)) {
4186             i->s = false;
4187             pr = pr.united(ir);
4188             changed = true;
4189         } else if (!i->isSelected() && ir.intersects(rubber)) {
4190             if (i->isSelectable()) {
4191                 i->s = true;
4192                 pr = pr.united(ir);
4193                 changed = true;
4194             }
4195         }
4196     }
4197     if (changed) {
4198         emit selectionChanged();
4199 #ifndef QT_NO_ACCESSIBILITY
4200         QAccessible::updateAccessibility(viewport(), 0, QAccessible::Selection);
4201 #endif
4202     }
4203     viewport()->repaint(pr);
4204 }
4205 
4206 
4207 /*!
4208     Returns true if the user is selecting items using a rubber band
4209     rectangle; otherwise returns false.
4210 */
4211 
isRubberSelecting() const4212 bool Q3ListBox::isRubberSelecting() const
4213 {
4214     return d->rubber != 0;
4215 }
4216 
4217 
4218 /*!
4219     Returns the item that comes after this in the list box. If this is
4220     the last item, 0 is returned.
4221 
4222     \sa prev()
4223 */
4224 
next() const4225 Q3ListBoxItem *Q3ListBoxItem::next() const
4226 {
4227     return n;
4228 }
4229 
4230 /*!
4231     Returns the item which comes before this in the list box. If this
4232     is the first item, 0 is returned.
4233 
4234     \sa next()
4235 */
4236 
prev() const4237 Q3ListBoxItem *Q3ListBoxItem::prev() const
4238 {
4239     return p;
4240 }
4241 
4242 /*!
4243     Returns the first item in this list box. If the list box is empty,
4244     returns 0.
4245 */
4246 
firstItem() const4247 Q3ListBoxItem *Q3ListBox::firstItem() const
4248 {
4249     return d->head;
4250 }
4251 
4252 #if defined(Q_C_CALLBACKS)
4253 extern "C" {
4254 #endif
4255 
4256 #ifdef Q_OS_WINCE
cmpListBoxItems(const void * n1,const void * n2)4257 static int _cdecl cmpListBoxItems(const void *n1, const void *n2)
4258 #else
4259 static int cmpListBoxItems(const void *n1, const void *n2)
4260 #endif
4261 {
4262     if (!n1 || !n2)
4263         return 0;
4264 
4265     Q3ListBoxPrivate::SortableItem *i1 = (Q3ListBoxPrivate::SortableItem *)n1;
4266     Q3ListBoxPrivate::SortableItem *i2 = (Q3ListBoxPrivate::SortableItem *)n2;
4267 
4268     return i1->item->text().localeAwareCompare(i2->item->text());
4269 }
4270 
4271 #if defined(Q_C_CALLBACKS)
4272 }
4273 #endif
4274 
4275 /*!
4276     If \a ascending is true sorts the items in ascending order;
4277     otherwise sorts in descending order.
4278 
4279     To compare the items, the text (Q3ListBoxItem::text()) of the items
4280     is used.
4281 */
4282 
sort(bool ascending)4283 void Q3ListBox::sort(bool ascending)
4284 {
4285     if (count() == 0)
4286         return;
4287 
4288     d->cache = 0;
4289 
4290     Q3ListBoxPrivate::SortableItem *items = new Q3ListBoxPrivate::SortableItem[count()];
4291 
4292     Q3ListBoxItem *item = d->head;
4293     int i = 0;
4294     for (; item; item = item->n)
4295         items[i++].item = item;
4296 
4297     qsort(items, count(), sizeof(Q3ListBoxPrivate::SortableItem), cmpListBoxItems);
4298 
4299     Q3ListBoxItem *prev = 0;
4300     item = 0;
4301     if (ascending) {
4302         for (i = 0; i < (int)count(); ++i) {
4303             item = items[i].item;
4304             if (item) {
4305                 item->p = prev;
4306                 item->dirty = true;
4307                 if (item->p)
4308                     item->p->n = item;
4309                 item->n = 0;
4310             }
4311             if (i == 0)
4312                 d->head = item;
4313             prev = item;
4314         }
4315     } else {
4316         for (i = (int)count() - 1; i >= 0 ; --i) {
4317             item = items[i].item;
4318             if (item) {
4319                 item->p = prev;
4320                 item->dirty = true;
4321                 if (item->p)
4322                     item->p->n = item;
4323                 item->n = 0;
4324             }
4325             if (i == (int)count() - 1)
4326                 d->head = item;
4327             prev = item;
4328         }
4329     }
4330     d->last = item;
4331 
4332     delete [] items;
4333 
4334     // We have to update explicitly in case the current "vieport" overlaps the
4335     // new viewport we set (starting at (0,0)).
4336     bool haveToUpdate = contentsX() < visibleWidth() || contentsY() < visibleHeight();
4337     setContentsPos(0, 0);
4338     if (haveToUpdate)
4339         updateContents(0, 0, visibleWidth(), visibleHeight());
4340 }
4341 
handleItemChange(Q3ListBoxItem * old,bool shift,bool control)4342 void Q3ListBox::handleItemChange(Q3ListBoxItem *old, bool shift, bool control)
4343 {
4344     if (d->selectionMode == Single) {
4345         // nothing
4346     } else if (d->selectionMode == Extended) {
4347         if (shift) {
4348             selectRange(d->selectAnchor ? d->selectAnchor : old,
4349                          d->current, false, true, (d->selectAnchor && !control) ? true : false);
4350         } else if (!control) {
4351             bool block = signalsBlocked();
4352             blockSignals(true);
4353             selectAll(false);
4354             blockSignals(block);
4355             setSelected(d->current, true);
4356         }
4357     } else if (d->selectionMode == Multi) {
4358         if (shift)
4359             selectRange(old, d->current, true, false);
4360     }
4361 }
4362 
selectRange(Q3ListBoxItem * from,Q3ListBoxItem * to,bool invert,bool includeFirst,bool clearSel)4363 void Q3ListBox::selectRange(Q3ListBoxItem *from, Q3ListBoxItem *to, bool invert, bool includeFirst, bool clearSel)
4364 {
4365     if (!from || !to)
4366         return;
4367     if (from == to && !includeFirst)
4368         return;
4369     Q3ListBoxItem *i = 0;
4370     int index =0;
4371     int f_idx = -1, t_idx = -1;
4372     for (i = d->head; i; i = i->n, index++) {
4373         if (i == from)
4374             f_idx = index;
4375         if (i == to)
4376             t_idx = index;
4377         if (f_idx != -1 && t_idx != -1)
4378             break;
4379     }
4380     if (f_idx > t_idx) {
4381         i = from;
4382         from = to;
4383         to = i;
4384         if (!includeFirst)
4385             to = to->prev();
4386     } else {
4387         if (!includeFirst)
4388             from = from->next();
4389     }
4390 
4391     bool changed = false;
4392     if (clearSel) {
4393         for (i = d->head; i && i != from; i = i->n) {
4394             if (i->s) {
4395                 i->s = false;
4396                 changed = true;
4397                 updateItem(i);
4398             }
4399         }
4400         for (i = to->n; i; i = i->n) {
4401             if (i->s) {
4402                 i->s = false;
4403                 changed = true;
4404                 updateItem(i);
4405             }
4406         }
4407     }
4408 
4409     for (i = from; i; i = i->next()) {
4410         if (!invert) {
4411             if (!i->s && i->isSelectable()) {
4412                 i->s = true;
4413                 changed = true;
4414                 updateItem(i);
4415             }
4416         } else {
4417             bool sel = !i->s;
4418             if (((bool)i->s != sel && sel && i->isSelectable()) || !sel) {
4419                 i->s = sel;
4420                 changed = true;
4421                 updateItem(i);
4422             }
4423         }
4424         if (i == to)
4425             break;
4426     }
4427     if (changed) {
4428         emit selectionChanged();
4429 #ifndef QT_NO_ACCESSIBILITY
4430         QAccessible::updateAccessibility(viewport(), 0, QAccessible::Selection);
4431 #endif
4432     }
4433 }
4434 
4435 /*! \reimp */
changeEvent(QEvent * ev)4436 void Q3ListBox::changeEvent(QEvent *ev)
4437 {
4438     if (ev->type() == QEvent::ActivationChange) {
4439         if (!isActiveWindow() && d->scrollTimer)
4440             d->scrollTimer->stop();
4441         if (!palette().isEqual(QPalette::Active, QPalette::Inactive))
4442             viewport()->update();
4443     }
4444     Q3ScrollView::changeEvent(ev);
4445 
4446     if (ev->type() == QEvent::ApplicationFontChange || ev->type() == QEvent::FontChange)
4447         triggerUpdate(true);
4448 }
4449 
4450 /*!
4451     Returns 0.
4452 
4453     Make your derived classes return their own values for rtti(), and
4454     you can distinguish between listbox items. You should use values
4455     greater than 1000 preferably a large random number, to allow for
4456     extensions to this class.
4457 */
4458 
rtti() const4459 int Q3ListBoxItem::rtti() const
4460 {
4461     return RTTI;
4462 }
4463 
4464 /*!
4465     \fn bool Q3ListBox::dragSelect() const
4466 
4467     Returns true. Dragging always selects.
4468 */
4469 
4470 /*!
4471     \fn void Q3ListBox::setDragSelect(bool b)
4472 
4473     Does nothing. Dragging always selects. The \a b parameter is ignored.
4474 */
4475 
4476 /*!
4477     \fn bool Q3ListBox::autoScroll() const
4478 
4479     Use dragAutoScroll() instead. This function always returns true.
4480 */
4481 
4482 /*!
4483     \fn void Q3ListBox::setAutoScroll(bool b)
4484 
4485     Use setDragAutoScroll(\a b) instead.
4486 */
4487 
4488 /*!
4489     \fn bool Q3ListBox::autoScrollBar() const
4490 
4491     Use vScrollBarMode() instead. Returns true if the vertical
4492     scrollbar mode is \c Auto.
4493 */
4494 
4495 /*!
4496     \fn void Q3ListBox::setAutoScrollBar(bool enable)
4497 
4498     Use setVScrollBarMode() instead.
4499 
4500     If \a enable is true, pass \c Auto as the argument to
4501     setVScrollBarMode(); otherwise, pass \c AlwaysOff.
4502 */
4503 
4504 /*!
4505     \fn bool Q3ListBox::scrollBar() const
4506 
4507     Use vScrollBarMode() instead. Returns true if the vertical
4508     scrollbar mode is not \c AlwaysOff.
4509 */
4510 
4511 /*!
4512     \fn void Q3ListBox::setScrollBar(bool enable)
4513 
4514     Use setVScrollBarMode() instead.
4515 
4516     If \a enable is true, pass \c AlwaysOn as the argument to
4517     setVScrollBarMode(); otherwise, pass \c AlwaysOff.
4518 */
4519 
4520 /*!
4521     \fn bool Q3ListBox::autoBottomScrollBar() const
4522 
4523     Use hScrollBarMode() instead. Returns true if the horizontal
4524     scrollbar mode is set to \c Auto.
4525 */
4526 
4527 /*!
4528     \fn void Q3ListBox::setAutoBottomScrollBar(bool enable)
4529 
4530     Use setHScrollBarMode() instead.
4531 
4532     If \a enable is true, pass \c Auto as the argument to
4533     setHScrollBarMode(); otherwise, pass \c AlwaysOff.
4534 */
4535 
4536 /*!
4537     \fn bool Q3ListBox::bottomScrollBar() const
4538 
4539     Use hScrollBarMode() instead. Returns true if the horizontal
4540     scrollbar mode is not \c AlwaysOff.
4541 */
4542 
4543 /*!
4544     \fn void Q3ListBox::setBottomScrollBar(bool enable)
4545 
4546     Use setHScrollBarMode() instead.
4547 
4548     If \a enable is true, pass \c AlwaysOn as the argument to
4549     setHScrollBarMode(); otherwise, pass \c AlwaysOff.
4550 */
4551 
4552 /*!
4553     \fn bool Q3ListBox::smoothScrolling() const
4554 
4555     Returns false. Qt always scrolls smoothly.
4556 */
4557 
4558 /*!
4559     \fn void Q3ListBox::setSmoothScrolling(bool b)
4560 
4561     Does nothing. Qt always scrolls smoothly. The \a b parameter is
4562     ignored.
4563 */
4564 
4565 /*!
4566     \fn bool Q3ListBox::autoUpdate() const
4567 
4568     Returns true. Qt always updates automatically.
4569 */
4570 
4571 /*!
4572     \fn void Q3ListBox::setAutoUpdate(bool b)
4573 
4574     Does nothing. Qt always updates automatically. The \a b parameter
4575     is ignored.
4576 */
4577 
4578 /*!
4579     \fn void Q3ListBox::setFixedVisibleLines(int lines)
4580 
4581     Use setRowMode(\a lines) instead.
4582 */
4583 
4584 /*!
4585     \fn int Q3ListBox::cellHeight(int i) const
4586 
4587     Use itemHeight(\a i) instead.
4588 */
4589 
4590 /*!
4591     \fn int  Q3ListBox::cellHeight() const
4592 
4593     Use itemHeight() instead.
4594 */
4595 
4596 /*!
4597     \fn int  Q3ListBox::cellWidth() const
4598 
4599     Use maxItemWidth() instead.
4600 */
4601 
4602 /*!
4603     \fn int  Q3ListBox::cellWidth(int i) const
4604 
4605     Use maxItemWidth(\a i) instead.
4606 */
4607 
4608 /*!
4609     \fn int  Q3ListBox::numCols() const
4610 
4611     Use numColumns() instead.
4612 */
4613 
4614 /*!
4615     \fn void Q3ListBox::updateCellWidth()
4616 
4617     Does nothing. Qt automatically updates.
4618 */
4619 
4620 /*!
4621     \fn int  Q3ListBox::totalWidth() const
4622 
4623     Use contentsWidth() instead.
4624 */
4625 
4626 /*!
4627     \fn int  Q3ListBox::totalHeight() const
4628 
4629     Use contentsHeight() instead.
4630 */
4631 
4632 /*!
4633     \fn int  Q3ListBox::findItem(int yPos) const
4634 
4635     Use index(itemAt(\a yPos)) instead.
4636 */
4637 
4638 /*!
4639     \fn bool Q3ListBoxItem::selected() const
4640 
4641     Use isSelected() instead. Returns true if isSelected()
4642     returns true.
4643 */
4644 
4645 /*!
4646     \fn bool Q3ListBoxItem::current() const
4647 
4648     Use isCurrent() instead. Returns true if isCurrent()
4649     returns true.
4650 */
4651 
4652 /*!
4653     \enum Q3ListBox::StringComparisonMode
4654 
4655     This enum type is used to set the string comparison mode when
4656     searching for an item. We'll refer to the string being searched
4657     as the 'target' string.
4658 
4659     \value CaseSensitive The strings must match case sensitively.
4660     \value ExactMatch The target and search strings must match exactly.
4661     \value BeginsWith The target string begins with the search string.
4662     \value EndsWith The target string ends with the search string.
4663     \value Contains The target string contains the search string.
4664 
4665     If you OR these flags together (excluding \c CaseSensitive), the
4666     search criteria be applied in the following order: \c ExactMatch,
4667     \c BeginsWith, \c EndsWith, \c Contains.
4668 
4669     Matching is case-insensitive unless \c CaseSensitive is set. \c
4670     CaseSensitive can be OR-ed with any combination of the other
4671     flags.
4672 
4673     \sa ComparisonFlags
4674 */
4675 
4676 /*!
4677     \typedef Q3ListBox::ComparisonFlags
4678 
4679     This typedef is used in Q3IconView's API for values that are OR'd
4680     combinations of \l StringComparisonMode values.
4681 
4682     \sa StringComparisonMode
4683 */
4684 
4685 QT_END_NAMESPACE
4686 
4687 #endif // QT_NO_LISTBOX
4688