--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/qt3support/itemviews/q3listbox.cpp Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,4687 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt3Support module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglobal.h"
+#if defined(Q_CC_BOR)
+// needed for qsort() because of a std namespace problem on Borland
+#include "qplatformdefs.h"
+#endif
+
+#include "q3listbox.h"
+#ifndef QT_NO_LISTBOX
+#include "qapplication.h"
+#include "qevent.h"
+#include "qfontmetrics.h"
+#include "qpainter.h"
+#include "qpixmap.h"
+#include "qstringlist.h"
+#include "qstyle.h"
+#include "qstyleoption.h"
+#include "qtimer.h"
+#include "qvector.h"
+#include "qpointer.h"
+#ifndef QT_NO_ACCESSIBILITY
+#include "qaccessible.h"
+#endif
+
+#include <stdlib.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q3ListBoxPrivate
+{
+public:
+ Q3ListBoxPrivate(Q3ListBox *lb):
+ head(0), last(0), cache(0), cacheIndex(-1), current(0),
+ highlighted(0), tmpCurrent(0), columnPos(1), rowPos(1), rowPosCache(0),
+ columnPosOne(0), rowMode(Q3ListBox::FixedNumber),
+ columnMode(Q3ListBox::FixedNumber), numRows(1), numColumns(1),
+ currentRow(0), currentColumn(0),
+ mousePressRow(-1), mousePressColumn(-1),
+ mouseMoveRow(-1), mouseMoveColumn(-1), mouseInternalPress(false),
+ scrollTimer(0), updateTimer(0), visibleTimer(0),
+ selectionMode(Q3ListBox::Single),
+ count(0),
+ listBox(lb), currInputString(QString()),
+ rowModeWins(false),
+ ignoreMoves(false),
+ layoutDirty(true),
+ mustPaintAll(true),
+ dragging(false),
+ dirtyDrag (false),
+ variableHeight(true /* !!! ### false */),
+ variableWidth(false),
+ inMenuMode(false)
+ {}
+ int findItemByName(int item, const QString &text);
+ ~Q3ListBoxPrivate();
+
+ Q3ListBoxItem * head, *last, *cache;
+ int cacheIndex;
+ Q3ListBoxItem * current, *highlighted, *tmpCurrent;
+
+ QVector<int> columnPos;
+ QVector<int> rowPos;
+ int rowPosCache;
+ int columnPosOne;
+
+ Q3ListBox::LayoutMode rowMode;
+ Q3ListBox::LayoutMode columnMode;
+ int numRows;
+ int numColumns;
+
+ int currentRow;
+ int currentColumn;
+ int mousePressRow;
+ int mousePressColumn;
+ int mouseMoveRow;
+ int mouseMoveColumn;
+ bool mouseInternalPress;
+
+ QTimer * scrollTimer;
+ QTimer * updateTimer;
+ QTimer * visibleTimer;
+ QTimer * resizeTimer;
+
+ QPoint scrollPos;
+
+ Q3ListBox::SelectionMode selectionMode;
+
+ int count;
+
+
+ Q3ListBox *listBox;
+ QString currInputString;
+ QTimer *inputTimer;
+
+ Q3ListBoxItem *pressedItem, *selectAnchor;
+
+ uint select :1;
+ uint pressedSelected :1;
+ uint rowModeWins :1;
+ uint ignoreMoves :1;
+ uint clearing :1;
+ uint layoutDirty :1;
+ uint mustPaintAll :1;
+ uint dragging :1;
+ uint dirtyDrag :1;
+ uint variableHeight :1;
+ uint variableWidth :1;
+ uint inMenuMode :1;
+
+ QRect *rubber;
+
+ struct SortableItem {
+ Q3ListBoxItem *item;
+ };
+};
+
+
+Q3ListBoxPrivate::~Q3ListBoxPrivate()
+{
+ Q_ASSERT(!head);
+}
+
+
+/*!
+ \class Q3ListBoxItem
+ \brief The Q3ListBoxItem class is the base class of all list box items.
+
+ \compat
+
+ This class is an abstract base class used for all list box items.
+ If you need to insert customized items into a Q3ListBox you must
+ inherit this class and reimplement paint(), height() and width().
+
+ \sa Q3ListBox
+*/
+
+/*!
+ Constructs an empty list box item in the list box \a listbox.
+*/
+
+Q3ListBoxItem::Q3ListBoxItem(Q3ListBox* listbox)
+{
+ lbox = listbox;
+ s = false;
+ dirty = true;
+ custom_highlight = false;
+ selectable = true;
+ p = n = 0;
+
+ if (listbox)
+ listbox->insertItem(this);
+}
+
+/*!
+ Constructs an empty list box item in the list box \a listbox and
+ inserts it after the item \a after or at the beginning if \a after
+ is 0.
+*/
+
+Q3ListBoxItem::Q3ListBoxItem(Q3ListBox* listbox, Q3ListBoxItem *after)
+{
+ lbox = listbox;
+ s = false;
+ dirty = true;
+ custom_highlight = false;
+ selectable = true;
+ p = n = 0;
+
+ if (listbox)
+ listbox->insertItem(this, after);
+}
+
+
+/*!
+ Destroys the list box item.
+*/
+
+Q3ListBoxItem::~Q3ListBoxItem()
+{
+ if (lbox)
+ lbox->takeItem(this);
+}
+
+
+/*!
+ Defines whether the list box item is responsible for drawing
+ itself in a highlighted state when being selected.
+
+ If \a b is false (the default), the list box will draw some
+ default highlight indicator before calling paint().
+
+ \sa isSelected(), paint()
+*/
+void Q3ListBoxItem::setCustomHighlighting(bool b)
+{
+ custom_highlight = b;
+}
+
+/*!
+ \fn void Q3ListBoxItem::paint(QPainter *p)
+
+ Implement this function to draw your item. The painter, \a p, is
+ already open for painting.
+
+ \sa height(), width()
+*/
+
+/*!
+ \fn int Q3ListBoxItem::width(const Q3ListBox* lb) const
+
+ Reimplement this function to return the width of your item. The \a
+ lb parameter is the same as listBox() and is provided for
+ convenience and compatibility.
+
+ The default implementation returns
+ \l{QApplication::globalStrut()}'s width.
+
+ \sa paint(), height()
+*/
+int Q3ListBoxItem::width(const Q3ListBox*) const
+{
+ return QApplication::globalStrut().width();
+}
+
+/*!
+ \fn int Q3ListBoxItem::height(const Q3ListBox* lb) const
+
+ Implement this function to return the height of your item. The \a
+ lb parameter is the same as listBox() and is provided for
+ convenience and compatibility.
+
+ The default implementation returns
+ \l{QApplication::globalStrut()}'s height.
+
+ \sa paint(), width()
+*/
+int Q3ListBoxItem::height(const Q3ListBox*) const
+{
+ return QApplication::globalStrut().height();
+}
+
+
+/*!
+ Returns the text of the item. This text is also used for sorting.
+
+ \sa setText()
+*/
+QString Q3ListBoxItem::text() const
+{
+ return txt;
+}
+
+/*!
+ Returns the pixmap associated with the item, or 0 if there isn't
+ one.
+
+ The default implementation returns 0.
+*/
+const QPixmap *Q3ListBoxItem::pixmap() const
+{
+ return 0;
+}
+
+/*! \fn void Q3ListBoxItem::setSelectable(bool b)
+
+ If \a b is true (the default) then this item can be selected by
+ the user; otherwise this item cannot be selected by the user.
+
+ \sa isSelectable()
+*/
+
+/*! \fn bool Q3ListBoxItem::isSelectable() const
+
+ Returns true if this item is selectable (the default); otherwise
+ returns false.
+
+ \sa setSelectable()
+*/
+
+
+/*!
+ \fn void Q3ListBoxItem::setText(const QString &text)
+
+ Sets the text of the Q3ListBoxItem to \a text. This \a text is also
+ used for sorting. The text is not shown unless explicitly drawn in
+ paint().
+
+ \sa text()
+*/
+
+
+/*!
+ \class Q3ListBoxText
+ \brief The Q3ListBoxText class provides list box items that display text.
+
+ \compat
+
+ The text is drawn in the widget's current font. If you need
+ several different fonts, you must implement your own subclass of
+ Q3ListBoxItem.
+
+ \sa Q3ListBox, Q3ListBoxItem
+*/
+
+
+/*!
+ Constructs a list box item in list box \a listbox showing the text
+ \a text.
+*/
+Q3ListBoxText::Q3ListBoxText(Q3ListBox *listbox, const QString &text)
+ :Q3ListBoxItem(listbox)
+{
+ setText(text);
+}
+
+/*!
+ Constructs a list box item showing the text \a text.
+*/
+
+Q3ListBoxText::Q3ListBoxText(const QString &text)
+ :Q3ListBoxItem()
+{
+ setText(text);
+}
+
+/*!
+ Constructs a list box item in list box \a listbox showing the text
+ \a text. The item is inserted after the item \a after, or at the
+ beginning if \a after is 0.
+*/
+
+Q3ListBoxText::Q3ListBoxText(Q3ListBox* listbox, const QString &text, Q3ListBoxItem *after)
+ : Q3ListBoxItem(listbox, after)
+{
+ setText(text);
+}
+
+/*!
+ Destroys the item.
+*/
+
+Q3ListBoxText::~Q3ListBoxText()
+{
+}
+
+/*!
+ Draws the text using \a painter.
+*/
+
+void Q3ListBoxText::paint(QPainter *painter)
+{
+ int itemHeight = height(listBox());
+ QFontMetrics fm = painter->fontMetrics();
+ int yPos = ((itemHeight - fm.height()) / 2) + fm.ascent();
+ painter->drawText(3, yPos, text());
+}
+
+/*!
+ Returns the height of a line of text in list box \a lb.
+
+ \sa paint(), width()
+*/
+
+int Q3ListBoxText::height(const Q3ListBox* lb) const
+{
+ int h = lb ? lb->fontMetrics().lineSpacing() + 2 : 0;
+ return qMax(h, QApplication::globalStrut().height());
+}
+
+/*!
+ Returns the width of this line in list box \a lb.
+
+ \sa paint(), height()
+*/
+
+int Q3ListBoxText::width(const Q3ListBox* lb) const
+{
+ int w = lb ? lb->fontMetrics().width(text()) + 6 : 0;
+ return qMax(w, QApplication::globalStrut().width());
+}
+
+/*!
+ \fn int Q3ListBoxText::rtti() const
+
+ \reimp
+
+ Returns 1.
+
+ Make your derived classes return their own values for rtti(), and
+ you can distinguish between listbox items. You should use values
+ greater than 1000 preferably a large random number, to allow for
+ extensions to this class.
+*/
+
+int Q3ListBoxText::rtti() const
+{
+ return RTTI;
+}
+
+/*!
+ \class Q3ListBoxPixmap
+ \brief The Q3ListBoxPixmap class provides list box items with a
+ pixmap and optional text.
+
+ \compat
+
+ Items of this class are drawn with the pixmap on the left with the
+ optional text to the right of the pixmap.
+
+ \sa Q3ListBox, Q3ListBoxItem
+*/
+
+
+/*!
+ Constructs a new list box item in list box \a listbox showing the
+ pixmap \a pixmap.
+*/
+
+Q3ListBoxPixmap::Q3ListBoxPixmap(Q3ListBox* listbox, const QPixmap &pixmap)
+ : Q3ListBoxItem(listbox)
+{
+ pm = pixmap;
+}
+
+/*!
+ Constructs a new list box item showing the pixmap \a pixmap.
+*/
+
+Q3ListBoxPixmap::Q3ListBoxPixmap(const QPixmap &pixmap)
+ : Q3ListBoxItem()
+{
+ pm = pixmap;
+}
+
+/*!
+ Constructs a new list box item in list box \a listbox showing the
+ pixmap \a pixmap. The item gets inserted after the item \a after,
+ or at the beginning if \a after is 0.
+*/
+
+Q3ListBoxPixmap::Q3ListBoxPixmap(Q3ListBox* listbox, const QPixmap &pixmap, Q3ListBoxItem *after)
+ : Q3ListBoxItem(listbox, after)
+{
+ pm = pixmap;
+}
+
+
+/*!
+ Destroys the item.
+*/
+
+Q3ListBoxPixmap::~Q3ListBoxPixmap()
+{
+}
+
+
+/*!
+ Constructs a new list box item in list box \a listbox showing the
+ pixmap \a pix and the text \a text.
+*/
+Q3ListBoxPixmap::Q3ListBoxPixmap(Q3ListBox* listbox, const QPixmap &pix, const QString& text)
+ : Q3ListBoxItem(listbox)
+{
+ pm = pix;
+ setText(text);
+}
+
+/*!
+ Constructs a new list box item showing the pixmap \a pix and the
+ text to \a text.
+*/
+Q3ListBoxPixmap::Q3ListBoxPixmap(const QPixmap & pix, const QString& text)
+ : Q3ListBoxItem()
+{
+ pm = pix;
+ setText(text);
+}
+
+/*!
+ Constructs a new list box item in list box \a listbox showing the
+ pixmap \a pix and the string \a text. The item gets inserted after
+ the item \a after, or at the beginning if \a after is 0.
+*/
+Q3ListBoxPixmap::Q3ListBoxPixmap(Q3ListBox* listbox, const QPixmap & pix, const QString& text,
+ Q3ListBoxItem *after)
+ : Q3ListBoxItem(listbox, after)
+{
+ pm = pix;
+ setText(text);
+}
+
+/*!
+ \fn const QPixmap *Q3ListBoxPixmap::pixmap() const
+
+ Returns the pixmap associated with the item.
+*/
+
+
+/*!
+ Draws the pixmap using \a painter.
+*/
+
+void Q3ListBoxPixmap::paint(QPainter *painter)
+{
+ int itemHeight = height(listBox());
+ int yPos;
+
+ const QPixmap *pm = pixmap();
+ if (pm && ! pm->isNull()) {
+ yPos = (itemHeight - pm->height()) / 2;
+ painter->drawPixmap(3, yPos, *pm);
+ }
+
+ if (!text().isEmpty()) {
+ QFontMetrics fm = painter->fontMetrics();
+ yPos = ((itemHeight - fm.height()) / 2) + fm.ascent();
+ painter->drawText(pm->width() + 5, yPos, text());
+ }
+}
+
+/*!
+ Returns the height of the pixmap in list box \a lb.
+
+ \sa paint(), width()
+*/
+
+int Q3ListBoxPixmap::height(const Q3ListBox* lb) const
+{
+ int h;
+ if (text().isEmpty())
+ h = pm.height();
+ else
+ h = qMax(pm.height(), lb->fontMetrics().lineSpacing() + 2);
+ return qMax(h, QApplication::globalStrut().height());
+}
+
+/*!
+ Returns the width of the pixmap plus some margin in list box \a lb.
+
+ \sa paint(), height()
+*/
+
+int Q3ListBoxPixmap::width(const Q3ListBox* lb) const
+{
+ if (text().isEmpty())
+ return qMax(pm.width() + 6, QApplication::globalStrut().width());
+ return qMax(pm.width() + lb->fontMetrics().width(text()) + 6,
+ QApplication::globalStrut().width());
+}
+
+/*!
+ \fn int Q3ListBoxPixmap::rtti() const
+
+ \reimp
+
+ Returns 2.
+
+ Make your derived classes return their own values for rtti(), and
+ you can distinguish between listbox items. You should use values
+ greater than 1000 preferably a large random number, to allow for
+ extensions to this class.
+*/
+
+int Q3ListBoxPixmap::rtti() const
+{
+ return RTTI;
+}
+
+/*!
+ \class Q3ListBox
+ \brief The Q3ListBox widget provides a list of selectable, read-only items.
+
+ \compat
+
+ This is typically a single-column list in which either no item or
+ one item is selected, but it can also be used in many other ways.
+
+ Q3ListBox will add scroll bars as necessary, but it isn't intended
+ for \e really big lists. If you want more than a few thousand
+ items, it's probably better to use a different widget mainly
+ because the scroll bars won't provide very good navigation, but
+ also because Q3ListBox may become slow with huge lists. (See
+ Q3ListView and Q3Table for possible alternatives.)
+
+ There are a variety of selection modes described in the
+ Q3ListBox::SelectionMode documentation. The default is \l Single
+ selection mode, but you can change it using setSelectionMode().
+ (setMultiSelection() is still provided for compatibility with Qt
+ 1.x. We recommend using setSelectionMode() in all code.)
+
+ Because Q3ListBox offers multiple selection it must display
+ keyboard focus and selection state separately. Therefore there are
+ functions both to set the selection state of an item, i.e.
+ setSelected(), and to set which item displays keyboard focus, i.e.
+ setCurrentItem().
+
+ The list box normally arranges its items in a single column and
+ adds a vertical scroll bar if required. It is possible to have a
+ different fixed number of columns (setColumnMode()), or as many
+ columns as will fit in the list box's assigned screen space
+ (setColumnMode(FitToWidth)), or to have a fixed number of rows
+ (setRowMode()) or as many rows as will fit in the list box's
+ assigned screen space (setRowMode(FitToHeight)). In all these
+ cases Q3ListBox will add scroll bars, as appropriate, in at least
+ one direction.
+
+ If multiple rows are used, each row can be as high as necessary
+ (the normal setting), or you can request that all items will have
+ the same height by calling setVariableHeight(false). The same
+ applies to a column's width, see setVariableWidth().
+
+ The Q3ListBox's items are Q3ListBoxItem objects. Q3ListBox provides
+ methods to insert new items as strings, as pixmaps, and as
+ Q3ListBoxItem * (insertItem() with various arguments), and to
+ replace an existing item with a new string, pixmap or Q3ListBoxItem
+ (changeItem() with various arguments). You can also remove items
+ singly with removeItem() or clear() the entire list box. Note that
+ if you create a Q3ListBoxItem yourself and insert it, Q3ListBox
+ takes ownership of the item.
+
+ You can also create a Q3ListBoxItem, such as Q3ListBoxText or
+ Q3ListBoxPixmap, with the list box as first parameter. The item
+ will then append itself. When you delete an item it is
+ automatically removed from the list box.
+
+ The list of items can be arbitrarily large; Q3ListBox will add
+ scroll bars if necessary. Q3ListBox can display a single-column
+ (the common case) or multiple-columns, and offers both single and
+ multiple selection. Q3ListBox does not support multiple-column
+ items (but Q3ListView and Q3Table do), or tree hierarchies (but
+ Q3ListView does).
+
+ The list box items can be accessed both as Q3ListBoxItem objects
+ (recommended) and using integer indexes (the original Q3ListBox
+ implementation used an array of strings internally, and the API
+ still supports this mode of operation). Everything can be done
+ using the new objects, and most things can be done using indexes.
+
+ Each item in a Q3ListBox contains a Q3ListBoxItem. One of the items
+ can be the current item. The currentChanged() signal and the
+ highlighted() signal are emitted when a new item becomes current,
+ e.g. because the user clicks on it or Q3ListBox::setCurrentItem()
+ is called. The selected() signal is emitted when the user
+ double-clicks on an item or presses Enter on the current item.
+
+ If the user does not select anything, no signals are emitted and
+ currentItem() returns -1.
+
+ A list box has Qt::WheelFocus as a default focusPolicy(), i.e. it
+ can get keyboard focus by tabbing, clicking and through the use of
+ the mouse wheel.
+
+ New items can be inserted using insertItem(), insertStrList() or
+ insertStringList().
+
+ By default, vertical and horizontal scroll bars are added and
+ removed as necessary. setHScrollBarMode() and setVScrollBarMode()
+ can be used to change this policy.
+
+ If you need to insert types other than strings and pixmaps, you
+ must define new classes which inherit Q3ListBoxItem.
+
+ \warning The list box assumes ownership of all list box items and
+ will delete them when it does not need them any more.
+
+ \inlineimage qlistbox-m.png Screenshot in Motif style
+ \inlineimage qlistbox-w.png Screenshot in Windows style
+
+ \sa Q3ListView, QComboBox, QButtonGroup
+*/
+
+/*!
+ \enum Q3ListBox::SelectionMode
+
+ This enumerated type is used by Q3ListBox to indicate how it reacts
+ to selection by the user.
+
+ \value Single When the user selects an item, any already-selected
+ item becomes unselected and the user cannot unselect the selected
+ item. This means that the user can never clear the selection, even
+ though the selection may be cleared by the application programmer
+ using Q3ListBox::clearSelection().
+
+ \value Multi When the user selects an item the selection status
+ of that item is toggled and the other items are left alone.
+
+ \value Extended When the user selects an item the selection is
+ cleared and the new item selected. However, if the user presses
+ the Ctrl key when clicking on an item, the clicked item gets
+ toggled and all other items are left untouched. And if the user
+ presses the Shift key while clicking on an item, all items between
+ the current item and the clicked item get selected or unselected,
+ depending on the state of the clicked item. Also, multiple items
+ can be selected by dragging the mouse while the left mouse button
+ is kept pressed.
+
+ \value NoSelection Items cannot be selected.
+
+ In other words, \c Single is a real single-selection list box, \c
+ Multi is a real multi-selection list box, \c Extended is a list
+ box in which users can select multiple items but usually want to
+ select either just one or a range of contiguous items, and \c
+ NoSelection is for a list box where the user can look but not
+ touch.
+*/
+
+
+/*!
+ \enum Q3ListBox::LayoutMode
+
+ This enum type is used to specify how Q3ListBox lays out its rows
+ and columns.
+
+ \value FixedNumber There is a fixed number of rows (or columns).
+
+ \value FitToWidth There are as many columns as will fit
+ on-screen.
+
+ \value FitToHeight There are as many rows as will fit on-screen.
+
+ \value Variable There are as many rows as are required by the
+ column mode. (Or as many columns as required by the row mode.)
+
+ Example: When you call setRowMode(FitToHeight), columnMode()
+ automatically becomes \c Variable to accommodate the row mode
+ you've set.
+*/
+
+/*!
+ \fn void Q3ListBox::onItem(Q3ListBoxItem *i)
+
+ This signal is emitted when the user moves the mouse cursor onto
+ an item, similar to the QWidget::enterEvent() function. \a i is
+ the Q3ListBoxItem that the mouse has moved on.
+*/
+
+// ### bug here too? enter/leave event may noit considered. move the
+// mouse out of the window and back in, to the same item - does it
+// work?
+
+/*!
+ \fn void Q3ListBox::onViewport()
+
+ This signal is emitted when the user moves the mouse cursor from
+ an item to an empty part of the list box.
+*/
+
+
+/*!
+ Constructs a new empty list box called \a name and with parent \a
+ parent and widget attributes \a f.
+
+ This constructor sets the Qt::WA_StaticContent and the
+ Qt::WA_NoBackground attributes to boost performance when drawing
+ Q3ListBoxItems. This may be unsuitable for custom Q3ListBoxItem
+ classes, in which case Qt::WA_StaticContents and Qt::WA_NoBackground
+ should be cleared on the viewport() after construction.
+*/
+
+Q3ListBox::Q3ListBox(QWidget *parent, const char *name, Qt::WindowFlags f)
+ : Q3ScrollView(parent, name, f | Qt::WStaticContents | Qt::WNoAutoErase)
+{
+ d = new Q3ListBoxPrivate(this);
+ d->updateTimer = new QTimer(this, "listbox update timer");
+ d->visibleTimer = new QTimer(this, "listbox visible timer");
+ d->inputTimer = new QTimer(this, "listbox input timer");
+ d->resizeTimer = new QTimer(this, "listbox resize timer");
+ d->clearing = false;
+ d->pressedItem = 0;
+ d->selectAnchor = 0;
+ d->select = false;
+ d->rubber = 0;
+
+ setMouseTracking(true);
+ viewport()->setMouseTracking(true);
+
+ connect(d->updateTimer, SIGNAL(timeout()),
+ this, SLOT(refreshSlot()));
+ connect(d->visibleTimer, SIGNAL(timeout()),
+ this, SLOT(ensureCurrentVisible()));
+ connect(d->resizeTimer, SIGNAL(timeout()),
+ this, SLOT(adjustItems()));
+ viewport()->setBackgroundRole(QPalette::Base);
+ viewport()->setFocusProxy(this);
+ viewport()->setFocusPolicy(Qt::WheelFocus);
+ setFocusPolicy(Qt::WheelFocus);
+ setAttribute(Qt::WA_MacShowFocusRect);
+}
+
+
+Q3ListBox * Q3ListBox::changedListBox = 0;
+
+/*!
+ Destroys the list box. Deletes all list box items.
+*/
+
+Q3ListBox::~Q3ListBox()
+{
+ if (changedListBox == this)
+ changedListBox = 0;
+ clear();
+ delete d;
+ d = 0;
+}
+
+/*!
+ \fn void Q3ListBox::pressed(Q3ListBoxItem *item)
+
+ This signal is emitted when the user presses any mouse button. If
+ \a item is not 0, the cursor is on \a item. If \a item is 0, the
+ mouse cursor isn't on any item.
+
+ Note that you must not delete any Q3ListBoxItem objects in slots
+ connected to this signal.
+*/
+
+/*!
+ \fn void Q3ListBox::pressed(Q3ListBoxItem *item, const QPoint &pnt)
+ \overload
+
+ This signal is emitted when the user presses any mouse button. If
+ \a item is not 0, the cursor is on \a item. If \a item is 0, the
+ mouse cursor isn't on any item.
+
+ \a pnt is the position of the mouse cursor in the global
+ coordinate system (QMouseEvent::globalPos()).
+
+ Note that you must not delete any Q3ListBoxItem objects in slots
+ connected to this signal.
+
+ \sa mouseButtonPressed() rightButtonPressed() clicked()
+*/
+
+/*!
+ \fn void Q3ListBox::clicked(Q3ListBoxItem *item)
+
+ This signal is emitted when the user clicks any mouse button. If
+ \a item is not 0, the cursor is on \a item. If \a item is 0, the
+ mouse cursor isn't on any item.
+
+ Note that you must not delete any Q3ListBoxItem objects in slots
+ connected to this signal.
+*/
+
+/*!
+ \fn void Q3ListBox::clicked(Q3ListBoxItem *item, const QPoint &pnt)
+ \overload
+
+ This signal is emitted when the user clicks any mouse button. If
+ \a item is not 0, the cursor is on \a item. If \a item is 0, the
+ mouse cursor isn't on any item.
+
+ \a pnt is the position of the mouse cursor in the global
+ coordinate system (QMouseEvent::globalPos()). (If the click's
+ press and release differs by a pixel or two, \a pnt is the
+ position at release time.)
+
+ Note that you must not delete any Q3ListBoxItem objects in slots
+ connected to this signal.
+*/
+
+/*!
+ \fn void Q3ListBox::mouseButtonClicked (int button, Q3ListBoxItem * item, const QPoint & pos)
+
+ This signal is emitted when the user clicks mouse button \a
+ button. If \a item is not 0, the cursor is on \a item. If \a item
+ is 0, the mouse cursor isn't on any item.
+
+ \a pos is the position of the mouse cursor in the global
+ coordinate system (QMouseEvent::globalPos()). (If the click's
+ press and release differs by a pixel or two, \a pos is the
+ position at release time.)
+
+ Note that you must not delete any Q3ListBoxItem objects in slots
+ connected to this signal.
+*/
+
+/*!
+ \fn void Q3ListBox::mouseButtonPressed (int button, Q3ListBoxItem * item, const QPoint & pos)
+
+ This signal is emitted when the user presses mouse button \a
+ button. If \a item is not 0, the cursor is on \a item. If \a item
+ is 0, the mouse cursor isn't on any item.
+
+ \a pos is the position of the mouse cursor in the global
+ coordinate system (QMouseEvent::globalPos()).
+
+ Note that you must not delete any Q3ListBoxItem objects in slots
+ connected to this signal.
+*/
+
+/*!
+ \fn void Q3ListBox::doubleClicked(Q3ListBoxItem *item)
+
+ This signal is emitted whenever an item is double-clicked. It's
+ emitted on the second button press, not the second button release.
+ If \a item is not 0, the cursor is on \a item. If \a item is 0,
+ the mouse cursor isn't on any item.
+*/
+
+
+/*!
+ \fn void Q3ListBox::returnPressed(Q3ListBoxItem *item)
+
+ This signal is emitted when Enter or Return is pressed. The
+ \a item passed in the argument is currentItem().
+*/
+
+/*!
+ \fn void Q3ListBox::rightButtonClicked(Q3ListBoxItem *item, const QPoint& point)
+
+ This signal is emitted when the right button is clicked. The \a
+ item is the item that the button was clicked on (which could be
+ 0 if no item was clicked on), and the \a point is where the
+ click took place in global coordinates.
+*/
+
+
+/*!
+ \fn void Q3ListBox::rightButtonPressed (Q3ListBoxItem *item, const QPoint &point)
+
+ This signal is emitted when the right button is pressed. The \a
+ item is the item that the button was pressed over (which could be
+ 0 if no item was pressed over), and the \a point is where the
+ press took place in global coordinates.
+*/
+
+/*!
+ \fn void Q3ListBox::contextMenuRequested(Q3ListBoxItem *item, const QPoint & pos)
+
+ This signal is emitted when the user invokes a context menu with
+ the right mouse button or with special system keys, with \a item
+ being the item under the mouse cursor or the current item,
+ respectively.
+
+ \a pos is the position for the context menu in the global
+ coordinate system.
+*/
+
+/*!
+ \fn void Q3ListBox::selectionChanged()
+
+ This signal is emitted when the selection set of a list box
+ changes. This signal is emitted in each selection mode. If the
+ user selects five items by drag-selecting, Q3ListBox tries to emit
+ just one selectionChanged() signal so the signal can be connected
+ to computationally expensive slots.
+
+ \sa selected() currentItem()
+*/
+
+/*!
+ \fn void Q3ListBox::selectionChanged(Q3ListBoxItem *item)
+ \overload
+
+ This signal is emitted when the selection in a \l Single selection
+ list box changes. \a item is the newly selected list box item.
+
+ \sa selected() currentItem()
+*/
+
+/*!
+ \fn void Q3ListBox::currentChanged(Q3ListBoxItem *item)
+
+ This signal is emitted when the user makes a new item the current
+ item. \a item is the new current list box item.
+
+ \sa setCurrentItem() currentItem()
+*/
+
+/*!
+ \fn void Q3ListBox::highlighted(int index)
+
+ This signal is emitted when the user makes a new item the current
+ item. \a index is the index of the new current item.
+
+ \sa currentChanged() selected() currentItem() selectionChanged()
+*/
+
+/*!
+ \fn void Q3ListBox::highlighted(Q3ListBoxItem *item)
+
+ \overload
+
+ This signal is emitted when the user makes a new \a item the current
+ \a item.
+
+ \sa currentChanged() selected() currentItem() selectionChanged()
+*/
+
+/*!
+ \fn void Q3ListBox::highlighted(const QString & text)
+
+ \overload
+
+ This signal is emitted when the user makes a new item the current
+ item and the item is (or has) as string. The argument is the new
+ current item's \a text.
+
+ \sa currentChanged() selected() currentItem() selectionChanged()
+*/
+
+/*!
+ \fn void Q3ListBox::selected(int index)
+
+ This signal is emitted when the user double-clicks on an item or
+ presses Enter on the current item. \a index is the index of the
+ selected item.
+
+ \sa currentChanged() highlighted() selectionChanged()
+*/
+
+/*!
+ \fn void Q3ListBox::selected(Q3ListBoxItem *item)
+
+ \overload
+
+ This signal is emitted when the user double-clicks on an \a item or
+ presses Enter on the current \a item.
+
+ \sa currentChanged() highlighted() selectionChanged()
+*/
+
+/*!
+ \fn void Q3ListBox::selected(const QString &text)
+
+ \overload
+
+ This signal is emitted when the user double-clicks on an item or
+ presses Enter on the current item, and the item is (or has) a
+ string. The argument is the \a text of the selected item.
+
+ \sa currentChanged() highlighted() selectionChanged()
+*/
+
+/*!
+ \property Q3ListBox::count
+ \brief the number of items in the list box
+*/
+
+uint Q3ListBox::count() const
+{
+ return d->count;
+}
+
+#if 0
+/*!
+ Inserts the string list \a list into the list at position \a
+ index.
+
+ If \a index is negative, \a list is inserted at the end of the
+ list. If \a index is too large, the operation is ignored.
+
+ \warning This function uses \c{const char *} rather than QString,
+ so we recommend against using it. It is provided so that legacy
+ code will continue to work, and so that programs that certainly
+ will not need to handle code outside a single 8-bit locale can use
+ it. See insertStringList() which uses real QStrings.
+
+ \warning This function is never significantly faster than a loop
+ around insertItem().
+
+ \sa insertItem(), insertStringList()
+*/
+
+void Q3ListBox::insertStrList(const QStrList *list, int index)
+{
+ if (!list) {
+ Q_ASSERT(list != 0);
+ return;
+ }
+ insertStrList(*list, index);
+}
+#endif
+
+
+/*!
+ Inserts the string list \a list into the list at position \a
+ index.
+
+ If \a index is negative, \a list is inserted at the end of the
+ list. If \a index is too large, the operation is ignored.
+
+ \warning This function is never significantly faster than a loop
+ around insertItem().
+
+ \sa insertItem(), insertStrList()
+*/
+
+void Q3ListBox::insertStringList(const QStringList & list, int index)
+{
+ if (index < 0)
+ index = count();
+ for (QStringList::ConstIterator it = list.begin(); it != list.end(); ++it)
+ insertItem(new Q3ListBoxText(*it), index++);
+}
+
+
+#if 0
+/*!
+ \overload
+
+ Inserts the string list \a list into the list at position \a
+ index.
+
+ If \a index is negative, \a list is inserted at the end of the
+ list. If \a index is too large, the operation is ignored.
+
+ \warning This function uses \c{const char *} rather than QString,
+ so we recommend against using it. It is provided so that legacy
+ code will continue to work, and so that programs that certainly
+ will not need to handle code outside a single 8-bit locale can use
+ it. See insertStringList() which uses real QStrings.
+
+ \warning This function is never significantly faster than a loop
+ around insertItem().
+
+ \sa insertItem(), insertStringList()
+*/
+void Q3ListBox::insertStrList(const QStrList & list, int index)
+{
+ QStrListIterator it(list);
+ const char* txt;
+ if (index < 0)
+ index = count();
+ while ((txt=it.current())) {
+ ++it;
+ insertItem(new Q3ListBoxText(QString::fromLatin1(txt)),
+ index++);
+ }
+ if (hasFocus() && !d->current)
+ setCurrentItem(d->head);
+}
+#endif
+
+
+/*!
+ Inserts the \a numStrings strings of the array \a strings into the
+ list at position \a index.
+
+ If \a index is negative, insertStrList() inserts \a strings at the
+ end of the list. If \a index is too large, the operation is
+ ignored.
+
+ \warning This function uses \c{const char *} rather than QString,
+ so we recommend against using it. It is provided so that legacy
+ code will continue to work, and so that programs that certainly
+ will not need to handle code outside a single 8-bit locale can use
+ it. See insertStringList() which uses real QStrings.
+
+ \warning This function is never significantly faster than a loop
+ around insertItem().
+
+ \sa insertItem(), insertStringList()
+*/
+
+void Q3ListBox::insertStrList(const char **strings, int numStrings, int index)
+{
+ if (!strings) {
+ Q_ASSERT(strings != 0);
+ return;
+ }
+ if (index < 0)
+ index = count();
+ int i = 0;
+ while ((numStrings<0 && strings[i]!=0) || i<numStrings) {
+ insertItem(new Q3ListBoxText(QString::fromLatin1(strings[i])),
+ index + i);
+ i++;
+ }
+ if (hasFocus() && !d->current)
+ setCurrentItem(d->head);
+}
+
+/*!
+ Inserts the item \a lbi into the list at position \a index.
+
+ If \a index is negative or larger than the number of items in the
+ list box, \a lbi is inserted at the end of the list.
+
+ \sa insertStrList()
+*/
+
+void Q3ListBox::insertItem(const Q3ListBoxItem *lbi, int index)
+{
+ if (!lbi)
+ return;
+
+ if (index < 0)
+ index = d->count;
+
+ if (index >= d->count) {
+ insertItem(lbi, d->last);
+ return;
+ }
+
+ Q3ListBoxItem * item = (Q3ListBoxItem *)lbi;
+ d->count++;
+ d->cache = 0;
+
+ item->lbox = this;
+ if (!d->head || index == 0) {
+ item->n = d->head;
+ item->p = 0;
+ d->head = item;
+ item->dirty = true;
+ if (item->n)
+ item->n->p = item;
+ } else {
+ Q3ListBoxItem * i = d->head;
+ while (i->n && index > 1) {
+ i = i->n;
+ index--;
+ }
+ if (i->n) {
+ item->n = i->n;
+ item->p = i;
+ item->n->p = item;
+ item->p->n = item;
+ } else {
+ i->n = item;
+ item->p = i;
+ item->n = 0;
+ }
+ }
+
+ if (hasFocus() && !d->current) {
+ d->current = d->head;
+ updateItem(d->current);
+ emit highlighted(d->current);
+ emit highlighted(d->current->text());
+ emit highlighted(index);
+ }
+
+ triggerUpdate(true);
+}
+
+/*!
+ \overload
+
+ Inserts the item \a lbi into the list after the item \a after, or
+ at the beginning if \a after is 0.
+
+ \sa insertStrList()
+*/
+
+void Q3ListBox::insertItem(const Q3ListBoxItem *lbi, const Q3ListBoxItem *after)
+{
+ if (!lbi)
+ return;
+
+ Q3ListBoxItem * item = (Q3ListBoxItem*)lbi;
+ d->count++;
+ d->cache = 0;
+
+ item->lbox = this;
+ if (!d->head || !after) {
+ item->n = d->head;
+ item->p = 0;
+ d->head = item;
+ item->dirty = true;
+ if (item->n)
+ item->n->p = item;
+ } else {
+ Q3ListBoxItem * i = (Q3ListBoxItem*) after;
+ if (i) {
+ item->n = i->n;
+ item->p = i;
+ if (item->n)
+ item->n->p = item;
+ if (item->p)
+ item->p->n = item;
+ }
+ }
+
+ if (after == d->last)
+ d->last = (Q3ListBoxItem*) lbi;
+
+ if (hasFocus() && !d->current) {
+ d->current = d->head;
+ updateItem(d->current);
+ emit highlighted(d->current);
+ emit highlighted(d->current->text());
+ emit highlighted(index(d->current));
+ }
+
+ triggerUpdate(true);
+}
+
+/*!
+ \overload
+
+ Inserts a new list box text item with the text \a text into the
+ list at position \a index.
+
+ If \a index is negative, \a text is inserted at the end of the
+ list.
+
+ \sa insertStrList()
+*/
+
+void Q3ListBox::insertItem(const QString &text, int index)
+{
+ insertItem(new Q3ListBoxText(text), index);
+}
+
+/*!
+ \overload
+
+ Inserts a new list box pixmap item with the pixmap \a pixmap into
+ the list at position \a index.
+
+ If \a index is negative, \a pixmap is inserted at the end of the
+ list.
+
+ \sa insertStrList()
+*/
+
+void Q3ListBox::insertItem(const QPixmap &pixmap, int index)
+{
+ insertItem(new Q3ListBoxPixmap(pixmap), index);
+}
+
+/*!
+ \overload
+
+ Inserts a new list box pixmap item with the pixmap \a pixmap and
+ the text \a text into the list at position \a index.
+
+ If \a index is negative, \a pixmap is inserted at the end of the
+ list.
+
+ \sa insertStrList()
+*/
+
+void Q3ListBox::insertItem(const QPixmap &pixmap, const QString &text, int index)
+{
+ insertItem(new Q3ListBoxPixmap(pixmap, text), index);
+}
+
+/*!
+ Removes and deletes the item at position \a index. If \a index is
+ equal to currentItem(), a new item becomes current and the
+ currentChanged() and highlighted() signals are emitted.
+
+ \sa insertItem(), clear()
+*/
+
+void Q3ListBox::removeItem(int index)
+{
+ bool wasVisible = itemVisible(currentItem());
+ delete item(index);
+ triggerUpdate(true);
+ if (wasVisible)
+ ensureCurrentVisible();
+}
+
+
+/*!
+ Deletes all the items in the list.
+
+ \sa removeItem()
+*/
+
+void Q3ListBox::clear()
+{
+ setContentsPos(0, 0);
+ bool blocked = signalsBlocked();
+ blockSignals(true);
+ d->clearing = true;
+ d->current = 0;
+ d->tmpCurrent = 0;
+ Q3ListBoxItem * i = d->head;
+ d->head = 0;
+ while (i) {
+ Q3ListBoxItem * n = i->n;
+ i->n = i->p = 0;
+ delete i;
+ i = n;
+ }
+ d->count = 0;
+ d->numRows = 1;
+ d->numColumns = 1;
+ d->currentRow = 0;
+ d->currentColumn = 0;
+ d->mousePressRow = -1;
+ d->mousePressColumn = -1;
+ d->mouseMoveRow = -1;
+ d->mouseMoveColumn = -1;
+ clearSelection();
+ d->selectAnchor = 0;
+ blockSignals(blocked);
+ triggerUpdate(true);
+ d->last = 0;
+ d->clearing = false;
+}
+
+
+/*!
+ Returns the text at position \a index, or an empty string if there
+ is no text at that position.
+
+ \sa pixmap()
+*/
+
+QString Q3ListBox::text(int index) const
+{
+ Q3ListBoxItem * i = item(index);
+ if (i)
+ return i->text();
+ return QString();
+}
+
+
+/*!
+ Returns a pointer to the pixmap at position \a index, or 0 if
+ there is no pixmap there.
+
+ \sa text()
+*/
+
+const QPixmap *Q3ListBox::pixmap(int index) const
+{
+ Q3ListBoxItem * i = item(index);
+ if (i)
+ return i->pixmap();
+ return 0;
+}
+
+/*!
+ \overload
+
+ Replaces the item at position \a index with a new list box text
+ item with text \a text.
+
+ The operation is ignored if \a index is out of range.
+
+ \sa insertItem(), removeItem()
+*/
+
+void Q3ListBox::changeItem(const QString &text, int index)
+{
+ if(index >= 0 && index < (int)count())
+ changeItem(new Q3ListBoxText(text), index);
+}
+
+/*!
+ \overload
+
+ Replaces the item at position \a index with a new list box pixmap
+ item with pixmap \a pixmap.
+
+ The operation is ignored if \a index is out of range.
+
+ \sa insertItem(), removeItem()
+*/
+
+void Q3ListBox::changeItem(const QPixmap &pixmap, int index)
+{
+ if(index >= 0 && index < (int)count())
+ changeItem(new Q3ListBoxPixmap(pixmap), index);
+}
+
+/*!
+ \overload
+
+ Replaces the item at position \a index with a new list box pixmap
+ item with pixmap \a pixmap and text \a text.
+
+ The operation is ignored if \a index is out of range.
+
+ \sa insertItem(), removeItem()
+*/
+
+void Q3ListBox::changeItem(const QPixmap &pixmap, const QString &text, int index)
+{
+ if(index >= 0 && index < (int)count())
+ changeItem(new Q3ListBoxPixmap(pixmap, text), index);
+}
+
+
+
+/*!
+ Replaces the item at position \a index with \a lbi. If \a index is
+ negative or too large, changeItem() does nothing.
+
+ The item that has been changed will become selected.
+
+ \sa insertItem(), removeItem()
+*/
+
+void Q3ListBox::changeItem(const Q3ListBoxItem *lbi, int index)
+{
+ if (!lbi || index < 0 || index >= (int)count())
+ return;
+
+ removeItem(index);
+ insertItem(lbi, index);
+ setCurrentItem(index);
+}
+
+
+/*!
+ \property Q3ListBox::numItemsVisible
+ \brief the number of visible items.
+
+ Both partially and entirely visible items are counted.
+*/
+
+int Q3ListBox::numItemsVisible() const
+{
+ doLayout();
+
+ int columns = 0;
+
+ int x = contentsX();
+ int i=0;
+ while (i < (int)d->columnPos.size()-1 &&
+ d->columnPos[i] < x)
+ i++;
+ if (i < (int)d->columnPos.size()-1 &&
+ d->columnPos[i] > x)
+ columns++;
+ x += visibleWidth();
+ while (i < (int)d->columnPos.size()-1 &&
+ d->columnPos[i] < x) {
+ i++;
+ columns++;
+ }
+
+ int y = contentsY();
+ int rows = 0;
+ while (i < (int)d->rowPos.size()-1 &&
+ d->rowPos[i] < y)
+ i++;
+ if (i < (int)d->rowPos.size()-1 &&
+ d->rowPos[i] > y)
+ rows++;
+ y += visibleHeight();
+ while (i < (int)d->rowPos.size()-1 &&
+ d->rowPos[i] < y) {
+ i++;
+ rows++;
+ }
+
+ return rows*columns;
+}
+
+int Q3ListBox::currentItem() const
+{
+ if (!d->current || !d->head)
+ return -1;
+
+ return index(d->current);
+}
+
+
+/*!
+ \property Q3ListBox::currentText
+ \brief the text of the current item.
+
+ This is equivalent to text(currentItem()).
+*/
+
+
+/*!
+ \property Q3ListBox::currentItem
+ \brief the current highlighted item
+
+ When setting this property, the highlighting is moved to the item
+ and the list box scrolled as necessary.
+
+ If no item is current, currentItem() returns -1.
+*/
+
+void Q3ListBox::setCurrentItem(int index)
+{
+ setCurrentItem(item(index));
+}
+
+/*!
+ \reimp
+*/
+QVariant Q3ListBox::inputMethodQuery(Qt::InputMethodQuery query) const
+{
+ if (query == Qt::ImMicroFocus)
+ return d->current ? itemRect(d->current) : QRect();
+ return QWidget::inputMethodQuery(query);
+}
+
+/*!
+ \overload
+
+ Sets the current item to the Q3ListBoxItem \a i.
+*/
+void Q3ListBox::setCurrentItem(Q3ListBoxItem * i)
+{
+ if (!i || d->current == i)
+ return;
+
+ Q3ListBoxItem * o = d->current;
+ d->current = i;
+ int ind = index(i);
+
+ if (i && selectionMode() == Single) {
+ bool changed = false;
+ if (o && o->s) {
+ changed = true;
+ o->s = false;
+ }
+ if (i && !i->s && d->selectionMode != NoSelection && i->isSelectable()) {
+ i->s = true;
+ changed = true;
+ emit selectionChanged(i);
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessible::updateAccessibility(viewport(), ind+1, QAccessible::StateChanged);
+#endif
+ }
+ if (changed) {
+ emit selectionChanged();
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessible::updateAccessibility(viewport(), 0, QAccessible::Selection);
+#endif
+ }
+ }
+
+ d->currentColumn = ind / numRows();
+ d->currentRow = ind % numRows();
+ if (o)
+ updateItem(o);
+ if (i)
+ updateItem(i);
+ // scroll after the items are redrawn
+ d->visibleTimer->start(1, true);
+
+ QString tmp;
+ if (i)
+ tmp = i->text();
+ emit highlighted(i);
+ if (!tmp.isNull())
+ emit highlighted(tmp);
+ emit highlighted(ind);
+ emit currentChanged(i);
+
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessible::updateAccessibility(viewport(), ind+1, QAccessible::Focus);
+#endif
+}
+
+
+/*!
+ Returns a pointer to the item at position \a index, or 0 if \a
+ index is out of bounds.
+
+ \sa index()
+*/
+
+Q3ListBoxItem *Q3ListBox::item(int index) const
+{
+ if (index < 0 || index > d->count -1)
+ return 0;
+
+ Q3ListBoxItem * i = d->head;
+
+ if (d->cache && index > 0) {
+ i = d->cache;
+ int idx = d->cacheIndex;
+ while (i && idx < index) {
+ idx++;
+ i = i->n;
+ }
+ while (i && idx > index) {
+ idx--;
+ i = i->p;
+ }
+ } else {
+ int idx = index;
+ while (i && idx > 0) {
+ idx--;
+ i = i->n;
+ }
+ }
+
+ if (index > 0) {
+ d->cache = i;
+ d->cacheIndex = index;
+ }
+
+ return i;
+}
+
+
+/*!
+ Returns the index of \a lbi, or -1 if the item is not in this list
+ box or \a lbi is 0.
+
+ \sa item()
+*/
+
+int Q3ListBox::index(const Q3ListBoxItem * lbi) const
+{
+ if (!lbi)
+ return -1;
+ Q3ListBoxItem * i_n = d->head;
+ int c_n = 0;
+ if (d->cache) {
+ i_n = d->cache;
+ c_n = d->cacheIndex;
+ }
+ Q3ListBoxItem* i_p = i_n;
+ int c_p = c_n;
+ while ((i_n != 0 || i_p != 0) && i_n != lbi && i_p != lbi) {
+ if (i_n) {
+ c_n++;
+ i_n = i_n->n;
+ }
+ if (i_p) {
+ c_p--;
+ i_p = i_p->p;
+ }
+ }
+ if (i_p == lbi)
+ return c_p;
+ if (i_n == lbi)
+ return c_n;
+ return -1;
+}
+
+
+
+/*!
+ Returns true if the item at position \a index is at least partly
+ visible; otherwise returns false.
+*/
+
+bool Q3ListBox::itemVisible(int index)
+{
+ Q3ListBoxItem * i = item(index);
+ return i ? itemVisible(i) : false;
+}
+
+
+/*!
+ \overload
+
+ Returns true if \a item is at least partly visible; otherwise
+ returns false.
+*/
+
+bool Q3ListBox::itemVisible(const Q3ListBoxItem * item)
+{
+ if (d->layoutDirty)
+ doLayout();
+
+ int i = index(item);
+ int col = i / numRows();
+ int row = i % numRows();
+ return (d->columnPos[col] < contentsX()+visibleWidth() &&
+ d->rowPos[row] < contentsY()+visibleHeight() &&
+ d->columnPos[col+1] > contentsX() &&
+ d->rowPos[row+1] > contentsY());
+}
+
+
+/*! \reimp */
+
+void Q3ListBox::mousePressEvent(QMouseEvent *e)
+{
+ mousePressEventEx(e);
+}
+
+void Q3ListBox::mousePressEventEx(QMouseEvent *e)
+{
+ d->mouseInternalPress = true;
+ Q3ListBoxItem * i = itemAt(e->pos());
+
+ if (!i && !d->current && d->head) {
+ d->current = d->head;
+ updateItem(d->head);
+ }
+
+ if (!i && (d->selectionMode != Single || e->button() == Qt::RightButton)
+ && !(e->state() & Qt::ControlButton))
+ clearSelection();
+
+ d->select = d->selectionMode == Multi ? (i ? !i->isSelected() : false) : true;
+ d->pressedSelected = i && i->s;
+
+ if (i)
+ d->selectAnchor = i;
+ if (i) {
+ switch(selectionMode()) {
+ default:
+ case Single:
+ if (!i->s || i != d->current) {
+ if (i->isSelectable())
+ setSelected(i, true);
+ else
+ setCurrentItem(i);
+ }
+ break;
+ case Extended:
+ if (i) {
+ bool shouldBlock = false;
+ if (!(e->state() & Qt::ShiftButton) &&
+ !(e->state() & Qt::ControlButton)) {
+ if (!i->isSelected()) {
+ bool b = signalsBlocked();
+ blockSignals(true);
+ clearSelection();
+ blockSignals(b);
+ }
+ setSelected(i, true);
+ d->dragging = true; // always assume dragging
+ shouldBlock = true;
+ } else if (e->state() & Qt::ShiftButton) {
+ d->pressedSelected = false;
+ Q3ListBoxItem *oldCurrent = item(currentItem());
+ bool down = index(oldCurrent) < index(i);
+
+ Q3ListBoxItem *lit = down ? oldCurrent : i;
+ bool select = d->select;
+ bool blocked = signalsBlocked();
+ blockSignals(true);
+ for (;; lit = lit->n) {
+ if (!lit) {
+ triggerUpdate(false);
+ break;
+ }
+ if (down && lit == i) {
+ setSelected(i, select);
+ triggerUpdate(false);
+ break;
+ }
+ if (!down && lit == oldCurrent) {
+ setSelected(oldCurrent, select);
+ triggerUpdate(false);
+ break;
+ }
+ setSelected(lit, select);
+ }
+ blockSignals(blocked);
+ emit selectionChanged();
+ } else if (e->state() & Qt::ControlButton) {
+ setSelected(i, !i->isSelected());
+ shouldBlock = true;
+ d->pressedSelected = false;
+ }
+ bool blocked = signalsBlocked();
+ blockSignals(shouldBlock);
+ setCurrentItem(i);
+ blockSignals(blocked);
+ }
+ break;
+ case Multi:
+ {
+ setSelected(i, !i->s);
+ bool b = signalsBlocked();
+ blockSignals(true);
+ setCurrentItem(i);
+ blockSignals(b);
+ break;
+ }
+ case NoSelection:
+ setCurrentItem(i);
+ break;
+ }
+ } else {
+ bool unselect = true;
+ if (e->button() == Qt::LeftButton) {
+ if (d->selectionMode == Multi ||
+ d->selectionMode == Extended) {
+ d->tmpCurrent = d->current;
+ d->current = 0;
+ updateItem(d->tmpCurrent);
+ if (d->rubber)
+ delete d->rubber;
+ d->rubber = 0;
+ d->rubber = new QRect(e->x(), e->y(), 0, 0);
+
+ if (d->selectionMode == Extended && !(e->state() & Qt::ControlButton))
+ selectAll(false);
+ unselect = false;
+ }
+ if (unselect && (e->button() == Qt::RightButton ||
+ (selectionMode() == Multi || selectionMode() == Extended)))
+ clearSelection();
+ }
+ }
+
+ // for sanity, in case people are event-filtering or whatnot
+ delete d->scrollTimer;
+ d->scrollTimer = 0;
+ if (i) {
+ d->mousePressColumn = d->currentColumn;
+ d->mousePressRow = d->currentRow;
+ } else {
+ d->mousePressColumn = -1;
+ d->mousePressRow = -1;
+ }
+ d->ignoreMoves = false;
+
+ d->pressedItem = i;
+
+ emit pressed(i);
+ emit pressed(i, e->globalPos());
+ emit mouseButtonPressed(e->button(), i, e->globalPos());
+ if (e->button() == Qt::RightButton)
+ emit rightButtonPressed(i, e->globalPos());
+}
+
+
+/*! \reimp */
+
+void Q3ListBox::mouseReleaseEvent(QMouseEvent *e)
+{
+ if (d->selectionMode == Extended &&
+ d->dragging) {
+ d->dragging = false;
+ if (d->current != d->pressedItem) {
+ updateSelection(); // when we drag, we get an update after we release
+ }
+ }
+
+ if (d->rubber) {
+ drawRubber();
+ delete d->rubber;
+ d->rubber = 0;
+ d->current = d->tmpCurrent;
+ updateItem(d->current);
+ }
+ if (d->scrollTimer)
+ mouseMoveEvent(e);
+ delete d->scrollTimer;
+ d->scrollTimer = 0;
+ d->ignoreMoves = false;
+
+ if (d->selectionMode == Extended &&
+ d->current == d->pressedItem &&
+ d->pressedSelected && d->current) {
+ bool block = signalsBlocked();
+ blockSignals(true);
+ clearSelection();
+ blockSignals(block);
+ d->current->s = true;
+ emit selectionChanged();
+ }
+
+ Q3ListBoxItem * i = itemAt(e->pos());
+ bool emitClicked = (d->mousePressColumn != -1 && d->mousePressRow != -1) || !d->pressedItem;
+ emitClicked = emitClicked && d->pressedItem == i;
+ d->pressedItem = 0;
+ d->mousePressRow = -1;
+ d->mousePressColumn = -1;
+ d->mouseInternalPress = false;
+ if (emitClicked) {
+ emit clicked(i);
+ emit clicked(i, e->globalPos());
+ emit mouseButtonClicked(e->button(), i, e->globalPos());
+ if (e->button() == Qt::RightButton)
+ emit rightButtonClicked(i, e->globalPos());
+ }
+}
+
+
+/*! \reimp */
+
+void Q3ListBox::mouseDoubleClickEvent(QMouseEvent *e)
+{
+ bool ok = true;
+ Q3ListBoxItem *i = itemAt(e->pos());
+ if (!i || selectionMode() == NoSelection)
+ ok = false;
+
+ d->ignoreMoves = true;
+
+ if (d->current && ok) {
+ Q3ListBoxItem * i = d->current;
+ QString tmp = d->current->text();
+ emit selected(currentItem());
+ emit selected(i);
+ if (!tmp.isNull())
+ emit selected(tmp);
+ emit doubleClicked(i);
+ }
+}
+
+
+/*! \reimp */
+
+void Q3ListBox::mouseMoveEvent(QMouseEvent *e)
+{
+ Q3ListBoxItem * i = itemAt(e->pos());
+ if (i != d->highlighted) {
+ if (i) {
+ emit onItem(i);
+ } else {
+ emit onViewport();
+ }
+ d->highlighted = i;
+ }
+
+ if (d->rubber) {
+ QRect r = d->rubber->normalized();
+ drawRubber();
+ d->rubber->setCoords(d->rubber->x(), d->rubber->y(), e->x(), e->y());
+ doRubberSelection(r, d->rubber->normalized());
+ drawRubber();
+ return;
+ }
+
+ if (((e->state() & (Qt::RightButton | Qt::LeftButton | Qt::MidButton)) == 0) ||
+ d->ignoreMoves)
+ return;
+
+ // hack to keep the combo (and what else?) working: if we get a
+ // move outside the listbox without having seen a press, discard
+ // it.
+ if (!QRect(0, 0, visibleWidth(), visibleHeight()).contains(e->pos()) &&
+ ((d->mousePressColumn < 0 && d->mousePressRow < 0)
+ || (e->state() == Qt::NoButton && !d->pressedItem)))
+ return;
+
+ // figure out in what direction to drag-select and perhaps scroll
+ int dx = 0;
+ int x = e->x();
+ if (x >= visibleWidth()) {
+ x = visibleWidth()-1;
+ dx = 1;
+ } else if (x < 0) {
+ x = 0;
+ dx = -1;
+ }
+ d->mouseMoveColumn = columnAt(x + contentsX());
+
+ // sanitize mousePressColumn, if we got here without a mouse press event
+ if (d->mousePressColumn < 0 && d->mouseMoveColumn >= 0)
+ d->mousePressColumn = d->mouseMoveColumn;
+ if (d->mousePressColumn < 0 && d->currentColumn >= 0)
+ d->mousePressColumn = d->currentColumn;
+
+ // if it's beyond the last column, use the last one
+ if (d->mouseMoveColumn < 0)
+ d->mouseMoveColumn = dx >= 0 ? numColumns()-1 : 0;
+
+ // repeat for y
+ int dy = 0;
+ int y = e->y();
+ if (y >= visibleHeight()) {
+ y = visibleHeight()-1;
+ dy = 1;
+ } else if (y < 0) {
+ y = 0;
+ dy = -1;
+ }
+ d->mouseMoveRow = rowAt(y + contentsY());
+
+ if (d->mousePressRow < 0 && d->mouseMoveRow >= 0)
+ d->mousePressRow = d->mouseMoveRow;
+ if (d->mousePressRow < 0 && d->currentRow >= 0)
+ d->mousePressRow = d->currentRow;
+
+ if (d->mousePressRow < 0)
+ d->mousePressRow = rowAt(x + contentsX());
+
+ d->scrollPos = QPoint(dx, dy);
+
+ if ((dx || dy) && !d->scrollTimer && e->state() == Qt::LeftButton && e->button() != Qt::LeftButton) {
+ // start autoscrolling if necessary
+ d->scrollTimer = new QTimer(this);
+ connect(d->scrollTimer, SIGNAL(timeout()),
+ this, SLOT(doAutoScroll()));
+ d->scrollTimer->start(100, false);
+ doAutoScroll();
+ } else if (!d->scrollTimer) {
+ // or just select the required bits
+ updateSelection();
+ }
+}
+
+
+
+void Q3ListBox::updateSelection()
+{
+ if (d->mouseMoveColumn >= 0 && d->mouseMoveRow >= 0 &&
+ d->mousePressColumn >= 0 && d->mousePressRow >= 0) {
+ Q3ListBoxItem * i = item(d->mouseMoveColumn * numRows() +
+ d->mouseMoveRow);
+#ifndef QT_NO_ACCESSIBILITY
+ int ind = index(i);
+#endif
+ if (selectionMode() == Single || selectionMode() == NoSelection) {
+ if (i && (d->mouseInternalPress || (windowType() == Qt::Popup)))
+ setCurrentItem(i);
+ } else {
+ if (d->selectionMode == Extended && (
+ (d->current == d->pressedItem && d->pressedSelected) ||
+ (d->dirtyDrag && !d->dragging))) {
+ if (d->dirtyDrag && !d->dragging) // emit after dragging stops
+ d->dirtyDrag = false;
+ else
+ clearSelection(); // don't reset drag-selected items
+ d->pressedItem = 0;
+ if (i && i->isSelectable()) {
+ bool block = signalsBlocked();
+ blockSignals(true);
+ i->s = true;
+ blockSignals(block);
+ emit selectionChanged();
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessible::updateAccessibility(viewport(), ind+1, QAccessible::StateChanged);
+ QAccessible::updateAccessibility(viewport(), 0, QAccessible::Selection);
+ QAccessible::updateAccessibility(viewport(), ind+1, QAccessible::SelectionAdd);
+#endif
+ }
+ triggerUpdate(false);
+ } else {
+ int c = qMin(d->mouseMoveColumn, d->mousePressColumn);
+ int r = qMin(d->mouseMoveRow, d->mousePressRow);
+ int c2 = qMax(d->mouseMoveColumn, d->mousePressColumn);
+ int r2 = qMax(d->mouseMoveRow, d->mousePressRow);
+ bool changed = false;
+ while(c <= c2) {
+ Q3ListBoxItem * i = item(c*numRows()+r);
+ int rtmp = r;
+ while(i && rtmp <= r2) {
+ if ((bool)i->s != (bool)d->select && i->isSelectable()) {
+ i->s = d->select;
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessible::updateAccessibility(viewport(), ind+1, QAccessible::StateChanged);
+ QAccessible::updateAccessibility(viewport(), ind+1, d->select ? QAccessible::SelectionAdd : QAccessible::SelectionRemove);
+#endif
+ i->dirty = true;
+ d->dirtyDrag = changed = true;
+ }
+ i = i->n;
+ rtmp++;
+ }
+ c++;
+ }
+ if (changed) {
+ if (!d->dragging) // emit after dragging stops instead
+ emit selectionChanged();
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessible::updateAccessibility(viewport(), 0, QAccessible::Selection);
+#endif
+ triggerUpdate(false);
+ }
+ }
+ if (i)
+ setCurrentItem(i);
+ }
+ }
+}
+
+void Q3ListBox::repaintSelection()
+{
+ if (d->numColumns == 1) {
+ for (uint i = topItem(); itemVisible(i) && i < count(); ++i) {
+ Q3ListBoxItem *it = item(i);
+ if (!it)
+ break;
+ if (it->isSelected())
+ updateItem(it);
+ }
+ } else {
+ for (uint i = 0; i < count(); ++i) {
+ Q3ListBoxItem *it = item(i);
+ if (!it)
+ break;
+ if (it->isSelected())
+ updateItem(it);
+ }
+ }
+}
+
+/*! \reimp
+*/
+
+void Q3ListBox::contentsContextMenuEvent(QContextMenuEvent *e)
+{
+ if (!receivers(SIGNAL(contextMenuRequested(Q3ListBoxItem*,QPoint)))) {
+ e->ignore();
+ return;
+ }
+ if (e->reason() == QContextMenuEvent::Keyboard) {
+ Q3ListBoxItem *i = item(currentItem());
+ if (i) {
+ QRect r = itemRect(i);
+ emit contextMenuRequested(i, mapToGlobal(r.topLeft() + QPoint(width() / 2, r.height() / 2)));
+ }
+ } else {
+ Q3ListBoxItem * i = itemAt(contentsToViewport(e->pos()));
+ emit contextMenuRequested(i, e->globalPos());
+ }
+}
+
+/*!\reimp
+*/
+void Q3ListBox::keyPressEvent(QKeyEvent *e)
+{
+ if ((e->key() == Qt::Key_Tab || e->key() == Qt::Key_Backtab)
+ && e->state() & Qt::ControlButton)
+ e->ignore();
+
+ if (count() == 0) {
+ e->ignore();
+ return;
+ }
+
+ QPointer<Q3ListBox> selfCheck = this;
+
+ Q3ListBoxItem *old = d->current;
+ if (!old) {
+ setCurrentItem(d->head);
+ if (d->selectionMode == Single)
+ setSelected(d->head, true);
+ e->ignore();
+ return;
+ }
+
+ bool selectCurrent = false;
+ switch (e->key()) {
+ case Qt::Key_Up:
+ {
+ d->currInputString.clear();
+ if (currentItem() > 0) {
+ setCurrentItem(currentItem() - 1);
+ handleItemChange(old, e->state() & Qt::ShiftButton, e->state() & Qt::ControlButton);
+ }
+ if (!(e->state() & Qt::ShiftButton) || !d->selectAnchor)
+ d->selectAnchor = d->current;
+ }
+ break;
+ case Qt::Key_Down:
+ {
+ d->currInputString.clear();
+ if (currentItem() < (int)count() - 1) {
+ setCurrentItem(currentItem() + 1);
+ handleItemChange(old, e->state() & Qt::ShiftButton, e->state() & Qt::ControlButton);
+ }
+ if (!(e->state() & Qt::ShiftButton) || !d->selectAnchor)
+ d->selectAnchor = d->current;
+ }
+ break;
+ case Qt::Key_Left:
+ {
+ d->currInputString.clear();
+ if (currentColumn() > 0) {
+ setCurrentItem(currentItem() - numRows());
+ handleItemChange(old, e->state() & Qt::ShiftButton, e->state() & Qt::ControlButton);
+ } else if (numColumns() > 1 && currentItem() > 0) {
+ int row = currentRow();
+ setCurrentItem(currentRow() - 1 + (numColumns() - 1) * numRows());
+
+ if (currentItem() == -1)
+ setCurrentItem(row - 1 + (numColumns() - 2) * numRows());
+
+ handleItemChange(old, e->state() & Qt::ShiftButton, e->state() & Qt::ControlButton);
+ } else {
+ QApplication::sendEvent(horizontalScrollBar(), e);
+ }
+ if (!(e->state() & Qt::ShiftButton) || !d->selectAnchor)
+ d->selectAnchor = d->current;
+ }
+ break;
+ case Qt::Key_Right:
+ {
+ d->currInputString.clear();
+ if (currentColumn() < numColumns()-1) {
+ int row = currentRow();
+ int i = currentItem();
+ Q3ListBoxItem *it = item(i + numRows());
+ if (!it)
+ it = item(count()-1);
+ setCurrentItem(it);
+
+ if (currentItem() == -1) {
+ if (row < numRows() - 1)
+ setCurrentItem(row + 1);
+ else
+ setCurrentItem(i);
+ }
+
+ handleItemChange(old, e->state() & Qt::ShiftButton, e->state() & Qt::ControlButton);
+ } else if (numColumns() > 1 && currentRow() < numRows()) {
+ if (currentRow() + 1 < numRows()) {
+ setCurrentItem(currentRow() + 1);
+ handleItemChange(old, e->state() & Qt::ShiftButton, e->state() & Qt::ControlButton);
+ }
+ } else {
+ QApplication::sendEvent(horizontalScrollBar(), e);
+ }
+ if (!(e->state() & Qt::ShiftButton) || !d->selectAnchor)
+ d->selectAnchor = d->current;
+ }
+ break;
+ case Qt::Key_Next:
+ {
+ d->currInputString.clear();
+ int i = 0;
+ if (numColumns() == 1) {
+ i = currentItem() + numItemsVisible();
+ i = i > (int)count() - 1 ? (int)count() - 1 : i;
+ setCurrentItem(i);
+ setBottomItem(i);
+ } else {
+ // I'm not sure about this behavior...
+ if (currentRow() == numRows() - 1)
+ i = currentItem() + numRows();
+ else
+ i = currentItem() + numRows() - currentRow() - 1;
+ i = i > (int)count() - 1 ? (int)count() - 1 : i;
+ setCurrentItem(i);
+ }
+ handleItemChange(old, e->state() & Qt::ShiftButton, e->state() & Qt::ControlButton);
+ if (!(e->state() & Qt::ShiftButton) || !d->selectAnchor)
+ d->selectAnchor = d->current;
+ }
+ break;
+ case Qt::Key_Prior:
+ {
+ selectCurrent = true;
+ d->currInputString.clear();
+ int i;
+ if (numColumns() == 1) {
+ i = currentItem() - numItemsVisible();
+ i = i < 0 ? 0 : i;
+ setCurrentItem(i);
+ setTopItem(i);
+ } else {
+ // I'm not sure about this behavior...
+ if (currentRow() == 0)
+ i = currentItem() - numRows();
+ else
+ i = currentItem() - currentRow();
+ i = i < 0 ? 0 : i;
+ setCurrentItem(i);
+ }
+ handleItemChange(old, e->state() & Qt::ShiftButton, e->state() & Qt::ControlButton);
+ if (!(e->state() & Qt::ShiftButton) || !d->selectAnchor)
+ d->selectAnchor = d->current;
+ }
+ break;
+ case Qt::Key_Space:
+ {
+ selectCurrent = true;
+ d->currInputString.clear();
+ toggleCurrentItem();
+ if (selectionMode() == Extended && d->current->isSelected())
+ emit highlighted(currentItem());
+ if (selfCheck && (!(e->state() & Qt::ShiftButton) || !d->selectAnchor))
+ d->selectAnchor = d->current;
+ }
+ break;
+ case Qt::Key_Return:
+ case Qt::Key_Enter:
+ {
+ selectCurrent = true;
+ d->currInputString.clear();
+ if (currentItem() >= 0 && selectionMode() != NoSelection) {
+ QString tmp = item(currentItem())->text();
+ emit selected(currentItem());
+ emit selected(item(currentItem()));
+ if (!tmp.isEmpty())
+ emit selected(tmp);
+ emit returnPressed(item(currentItem()));
+ }
+ if (selfCheck && (!(e->state() & Qt::ShiftButton) || !d->selectAnchor))
+ d->selectAnchor = d->current;
+ }
+ break;
+ case Qt::Key_Home:
+ {
+ selectCurrent = true;
+ d->currInputString.clear();
+ setCurrentItem(0);
+ handleItemChange(old, e->state() & Qt::ShiftButton, e->state() & Qt::ControlButton);
+ if (!(e->state() & Qt::ShiftButton) || !d->selectAnchor)
+ d->selectAnchor = d->current;
+ }
+ break;
+ case Qt::Key_End:
+ {
+ selectCurrent = true;
+ d->currInputString.clear();
+ int i = (int)count() - 1;
+ setCurrentItem(i);
+ handleItemChange(old, e->state() & Qt::ShiftButton, e->state() & Qt::ControlButton);
+ if (!(e->state() & Qt::ShiftButton) || !d->selectAnchor)
+ d->selectAnchor = d->current;
+ }
+ break;
+ default:
+ {
+ if (!e->text().isEmpty() && e->text()[0].isPrint() && count()) {
+ int curItem = currentItem();
+ if (curItem == -1)
+ curItem = 0;
+ if (!d->inputTimer->isActive()) {
+ d->currInputString = e->text();
+ curItem = d->findItemByName(++curItem, d->currInputString);
+ } else {
+ d->inputTimer->stop();
+ d->currInputString += e->text();
+ int oldCurItem = curItem;
+ curItem = d->findItemByName(curItem, d->currInputString);
+ if (curItem < 0) {
+ curItem = d->findItemByName(++oldCurItem, e->text());
+ d->currInputString = e->text();
+ }
+ }
+ if (curItem >= 0)
+ setCurrentItem(curItem);
+ if (curItem >= 0 && selectionMode() == Q3ListBox::Extended) {
+ bool changed = false;
+ bool block = signalsBlocked();
+ blockSignals(true);
+ selectAll(false);
+ blockSignals(block);
+ Q3ListBoxItem *i = item(curItem);
+ if (!i->s && i->isSelectable()) {
+ changed = true;
+ i->s = true;
+ updateItem(i);
+ }
+ if (changed)
+ emit selectionChanged();
+ }
+ d->inputTimer->start(400, true);
+ } else {
+ d->currInputString.clear();
+ if (e->state() & Qt::ControlButton) {
+ switch (e->key()) {
+ case Qt::Key_A:
+ selectAll(true);
+ break;
+ }
+ } else {
+ e->ignore();
+ }
+ }
+ }
+ }
+
+ if (selfCheck && selectCurrent && selectionMode() == Single &&
+ d->current && !d->current->s) {
+ updateItem(d->current);
+ setSelected(d->current, true);
+ }
+}
+
+
+/*!\reimp
+*/
+void Q3ListBox::focusInEvent(QFocusEvent *e)
+{
+ d->mousePressRow = -1;
+ d->mousePressColumn = -1;
+ d->inMenuMode = false;
+ if (e->reason() != Qt::MouseFocusReason && !d->current && d->head) {
+ d->current = d->head;
+ Q3ListBoxItem *i = d->current;
+ QString tmp;
+ if (i)
+ tmp = i->text();
+ int tmp2 = index(i);
+ emit highlighted(i);
+ if (!tmp.isNull())
+ emit highlighted(tmp);
+ emit highlighted(tmp2);
+ emit currentChanged(i);
+ }
+ if (style()->styleHint(QStyle::SH_ItemView_ChangeHighlightOnFocus, 0, this))
+ repaintSelection();
+
+ if (d->current)
+ updateItem(currentItem());
+}
+
+
+/*!\reimp
+*/
+void Q3ListBox::focusOutEvent(QFocusEvent *e)
+{
+ if (style()->styleHint(QStyle::SH_ItemView_ChangeHighlightOnFocus, 0, this)) {
+ d->inMenuMode =
+ e->reason() == Qt::PopupFocusReason ||
+ (qApp->focusWidget() && qApp->focusWidget()->inherits("QMenuBar"));
+ if (!d->inMenuMode)
+ repaintSelection();
+ }
+
+ if (d->current)
+ updateItem(currentItem());
+}
+
+/*!\reimp
+*/
+bool Q3ListBox::eventFilter(QObject *o, QEvent *e)
+{
+ return Q3ScrollView::eventFilter(o, e);
+}
+
+/*!
+ Repaints the item at position \a index in the list.
+*/
+
+void Q3ListBox::updateItem(int index)
+{
+ if (index >= 0)
+ updateItem(item(index));
+}
+
+
+/*!
+ \overload
+
+ Repaints the Q3ListBoxItem \a i.
+*/
+
+void Q3ListBox::updateItem(Q3ListBoxItem * i)
+{
+ if (!i)
+ return;
+ i->dirty = true;
+ d->updateTimer->start(0, true);
+}
+
+
+/*!
+ \property Q3ListBox::selectionMode
+ \brief the selection mode of the list box
+
+ Sets the list box's selection mode, which may be one of \c Single
+ (the default), \c Extended, \c Multi or \c NoSelection.
+
+ \sa SelectionMode
+*/
+
+void Q3ListBox::setSelectionMode(SelectionMode mode)
+{
+ if (d->selectionMode == mode)
+ return;
+
+ if ((selectionMode() == Multi || selectionMode() == Extended)
+ && (mode == Q3ListBox::Single || mode == Q3ListBox::NoSelection)){
+ clearSelection();
+ if ((mode == Q3ListBox::Single) && currentItem())
+ setSelected(currentItem(), true);
+ }
+
+ d->selectionMode = mode;
+ triggerUpdate(true);
+}
+
+
+Q3ListBox::SelectionMode Q3ListBox::selectionMode() const
+{
+ return d->selectionMode;
+}
+
+
+/*!
+ \property Q3ListBox::multiSelection
+ \brief whether or not the list box is in Multi selection mode
+
+ Consider using the \l Q3ListBox::selectionMode property instead of
+ this property.
+
+ When setting this property, Multi selection mode is used if set to true and
+ to Single selection mode if set to false.
+
+ When getting this property, true is returned if the list box is in
+ Multi selection mode or Extended selection mode, and false if it is
+ in Single selection mode or NoSelection mode.
+
+ \sa selectionMode
+*/
+
+bool Q3ListBox::isMultiSelection() const
+{
+ return selectionMode() == Multi || selectionMode() == Extended;
+}
+
+void Q3ListBox::setMultiSelection(bool enable)
+{
+ setSelectionMode(enable ? Multi : Single);
+}
+
+
+/*!
+ Toggles the selection status of currentItem() and repaints if the
+ list box is a \c Multi selection list box.
+
+ \sa setMultiSelection()
+*/
+
+void Q3ListBox::toggleCurrentItem()
+{
+ if (selectionMode() == Single ||
+ selectionMode() == NoSelection ||
+ !d->current)
+ return;
+
+ if (d->current->s || d->current->isSelectable()) {
+ d->current->s = !d->current->s;
+ emit selectionChanged();
+#ifndef QT_NO_ACCESSIBILITY
+ int ind = index(d->current);
+ QAccessible::updateAccessibility(viewport(), 0, QAccessible::Selection);
+ QAccessible::updateAccessibility(viewport(), ind+1, QAccessible::StateChanged);
+ QAccessible::updateAccessibility(viewport(), ind+1, d->current->s ? QAccessible::SelectionAdd : QAccessible::SelectionRemove);
+#endif
+ }
+ updateItem(d->current);
+}
+
+
+/*!
+ \overload
+
+ If \a select is true the item at position \a index is selected;
+ otherwise the item is deselected.
+*/
+
+void Q3ListBox::setSelected(int index, bool select)
+{
+ setSelected(item(index), select);
+}
+
+
+/*!
+ Selects \a item if \a select is true or unselects it if \a select
+ is false, and repaints the item appropriately.
+
+ If the list box is a \c Single selection list box and \a select is
+ true, setSelected() calls setCurrentItem().
+
+ If the list box is a \c Single selection list box, \a select is
+ false, setSelected() calls clearSelection().
+
+ \sa setMultiSelection(), setCurrentItem(), clearSelection(), currentItem()
+*/
+
+void Q3ListBox::setSelected(Q3ListBoxItem * item, bool select)
+{
+ if (!item || !item->isSelectable() ||
+ (bool)item->s == select || d->selectionMode == NoSelection)
+ return;
+
+ int ind = index(item);
+ bool emitHighlighted = (d->current != item) || ( select && (item->s != (uint) select) );
+ if (selectionMode() == Single) {
+ if (d->current != item) {
+ Q3ListBoxItem *o = d->current;
+ if (d->current && d->current->s)
+ d->current->s = false;
+ d->current = item;
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessible::updateAccessibility(viewport(), ind+1, QAccessible::Focus);
+#endif
+ d->currentColumn = ind / numRows();
+ d->currentRow = ind % numRows();
+
+ if (o)
+ updateItem(o);
+ }
+ }
+
+ item->s = (uint)select;
+ updateItem(item);
+
+ if (d->selectionMode == Single && select) {
+ emit selectionChanged(item);
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessible::updateAccessibility(viewport(), ind+1, QAccessible::StateChanged);
+#endif
+ }
+ emit selectionChanged();
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessible::updateAccessibility(viewport(), 0, QAccessible::Selection);
+ if (d->selectionMode != Single)
+ QAccessible::updateAccessibility(viewport(), ind+1, select ? QAccessible::SelectionAdd : QAccessible::SelectionRemove);
+#endif
+
+ if (emitHighlighted) {
+ QString tmp;
+ if (item)
+ tmp = item->text();
+ int tmp2 = index(item);
+ emit highlighted(item);
+ if (!tmp.isNull())
+ emit highlighted(tmp);
+ emit highlighted(tmp2);
+ emit currentChanged(item);
+ }
+}
+
+
+/*!
+ Returns true if item \a i is selected; otherwise returns false.
+*/
+
+bool Q3ListBox::isSelected(int i) const
+{
+ if (selectionMode() == Single && i != currentItem())
+ return false;
+
+ Q3ListBoxItem * lbi = item(i);
+ if (!lbi)
+ return false; // should not happen
+ return lbi->s;
+}
+
+
+/*!
+ \overload
+
+ Returns true if item \a i is selected; otherwise returns false.
+*/
+
+bool Q3ListBox::isSelected(const Q3ListBoxItem * i) const
+{
+ if (!i)
+ return false;
+
+ return i->s;
+}
+
+/*! Returns the selected item if the list box is in
+single-selection mode and an item is selected.
+
+If no items are selected or the list box is in another selection mode
+this function returns 0.
+
+\sa setSelected() setMultiSelection()
+*/
+
+Q3ListBoxItem* Q3ListBox::selectedItem() const
+{
+ if (d->selectionMode != Single)
+ return 0;
+ if (isSelected(currentItem()))
+ return d->current;
+ return 0;
+}
+
+
+/*!
+ Deselects all items, if possible.
+
+ Note that a \c Single selection list box will automatically select
+ an item if it has keyboard focus.
+*/
+
+void Q3ListBox::clearSelection()
+{
+ selectAll(false);
+}
+
+/*!
+ In \c Multi and \c Extended modes, this function sets all items to
+ be selected if \a select is true, and to be unselected if \a
+ select is false.
+
+ In \c Single and \c NoSelection modes, this function only changes
+ the selection status of currentItem().
+*/
+
+void Q3ListBox::selectAll(bool select)
+{
+ if (selectionMode() == Multi || selectionMode() == Extended) {
+ bool b = signalsBlocked();
+ blockSignals(true);
+ for (int i = 0; i < (int)count(); i++)
+ setSelected(i, select);
+ blockSignals(b);
+ emit selectionChanged();
+ } else if (d->current) {
+ Q3ListBoxItem * i = d->current;
+ setSelected(i, select);
+ }
+}
+
+/*!
+ Inverts the selection. Only works in \c Multi and \c Extended
+ selection mode.
+*/
+
+void Q3ListBox::invertSelection()
+{
+ if (d->selectionMode == Single ||
+ d->selectionMode == NoSelection)
+ return;
+
+ bool b = signalsBlocked();
+ blockSignals(true);
+ for (int i = 0; i < (int)count(); i++)
+ setSelected(i, !item(i)->isSelected());
+ blockSignals(b);
+ emit selectionChanged();
+}
+
+
+/*!
+ Not used anymore; provided for compatibility.
+*/
+
+void Q3ListBox::emitChangedSignal(bool)
+{
+}
+
+
+/*! \reimp */
+
+QSize Q3ListBox::sizeHint() const
+{
+ if (cachedSizeHint().isValid())
+ return cachedSizeHint();
+
+ ensurePolished();
+ doLayout();
+
+ int i=0;
+ while(i < 10 &&
+ i < (int)d->columnPos.size()-1 &&
+ d->columnPos[i] < 200)
+ i++;
+ int x;
+ x = qMin(200, d->columnPos[i] +
+ 2 * style()->pixelMetric(QStyle::PM_DefaultFrameWidth));
+ x = qMax(40, x);
+
+ i = 0;
+ while(i < 10 &&
+ i < (int)d->rowPos.size()-1 &&
+ d->rowPos[i] < 200)
+ i++;
+ int y;
+ y = qMin(200, d->rowPos[i] +
+ 2 * style()->pixelMetric(QStyle::PM_DefaultFrameWidth));
+ y = qMax(40, y);
+
+ QSize s(x, y);
+ setCachedSizeHint(s);
+ return s;
+}
+
+/*!
+ \reimp
+*/
+
+QSize Q3ListBox::minimumSizeHint() const
+{
+ return Q3ScrollView::minimumSizeHint();
+}
+
+
+/*!
+ Ensures that a single paint event will occur at the end of the
+ current event loop iteration. If \a doLayout is true, the layout
+ is also redone.
+*/
+
+void Q3ListBox::triggerUpdate(bool doLayout)
+{
+ if (doLayout)
+ d->layoutDirty = d->mustPaintAll = true;
+ d->updateTimer->start(0, true);
+}
+
+
+void Q3ListBox::setColumnMode(LayoutMode mode)
+{
+ if (mode == Variable)
+ return;
+ d->rowModeWins = false;
+ d->columnMode = mode;
+ triggerUpdate(true);
+}
+
+
+void Q3ListBox::setColumnMode(int columns)
+{
+ if (columns < 1)
+ columns = 1;
+ d->columnMode = FixedNumber;
+ d->numColumns = columns;
+ d->rowModeWins = false;
+ triggerUpdate(true);
+}
+
+void Q3ListBox::setRowMode(LayoutMode mode)
+{
+ if (mode == Variable)
+ return;
+ d->rowModeWins = true;
+ d->rowMode = mode;
+ triggerUpdate(true);
+}
+
+
+void Q3ListBox::setRowMode(int rows)
+{
+ if (rows < 1)
+ rows = 1;
+ d->rowMode = FixedNumber;
+ d->numRows = rows;
+ d->rowModeWins = true;
+ triggerUpdate(true);
+}
+
+/*!
+ \property Q3ListBox::columnMode
+ \brief the column layout mode for this list box.
+
+ setColumnMode() sets the layout mode and adjusts the number of
+ displayed columns. The row layout mode automatically becomes \c
+ Variable, unless the column mode is \c Variable.
+
+ \sa setRowMode() rowMode numColumns
+*/
+
+
+Q3ListBox::LayoutMode Q3ListBox::columnMode() const
+{
+ if (d->rowModeWins)
+ return Variable;
+ else
+ return d->columnMode;
+}
+
+
+/*!
+ \property Q3ListBox::rowMode
+ \brief the row layout mode for this list box
+
+ This property is normally \c Variable.
+
+ setRowMode() sets the layout mode and adjusts the number of
+ displayed rows. The column layout mode automatically becomes \c
+ Variable, unless the row mode is \c Variable.
+
+ \sa columnMode
+*/
+
+
+Q3ListBox::LayoutMode Q3ListBox::rowMode() const
+{
+ if (d->rowModeWins)
+ return d->rowMode;
+ else
+ return Variable;
+}
+
+
+/*!
+ \property Q3ListBox::numColumns
+ \brief the number of columns in the list box
+
+ This is normally 1, but can be different if \l
+ Q3ListBox::columnMode or \l Q3ListBox::rowMode has been set.
+
+ \sa columnMode rowMode numRows
+*/
+
+int Q3ListBox::numColumns() const
+{
+ if (count() == 0)
+ return 0;
+ if (!d->rowModeWins && d->columnMode == FixedNumber)
+ return d->numColumns;
+ doLayout();
+ return d->columnPos.size()-1;
+}
+
+
+/*!
+ \property Q3ListBox::numRows
+ \brief the number of rows in the list box.
+
+ This is equal to the number of items in the default single-column
+ layout, but can be different.
+
+ \sa columnMode rowMode numColumns
+*/
+
+int Q3ListBox::numRows() const
+{
+ if (count() == 0)
+ return 0;
+ if (d->rowModeWins && d->rowMode == FixedNumber)
+ return d->numRows;
+ doLayout();
+ return d->rowPos.size()-1;
+}
+
+
+/*!
+ This function does the hard layout work. You should never need to
+ call it.
+*/
+
+void Q3ListBox::doLayout() const
+{
+ if (!d->layoutDirty || d->resizeTimer->isActive())
+ return;
+ ensurePolished();
+ int c = count();
+ switch(rowMode()) {
+ case FixedNumber:
+ // columnMode() is known to be Variable
+ tryGeometry(d->numRows, (c+d->numRows-1)/d->numRows);
+ break;
+ case FitToHeight:
+ // columnMode() is known to be Variable
+ if (d->head) {
+ // this is basically the FitToWidth code, but edited to use rows.
+ int maxh = 0;
+ Q3ListBoxItem * i = d->head;
+ while (i) {
+ int h = i->height(this);
+ if (maxh < h)
+ maxh = h;
+ i = i->n;
+ }
+ int vh = viewportSize(1, 1).height();
+ do {
+ int rows = vh / maxh;
+ if (rows > c)
+ rows = c;
+ if (rows < 1)
+ rows = 1;
+ if (variableHeight() && rows < c) {
+ do {
+ ++rows;
+ tryGeometry(rows, (c+rows-1)/rows);
+ } while (rows <= c &&
+ d->rowPos[(int)d->rowPos.size()-1] <= vh);
+ --rows;
+ }
+ tryGeometry(rows, (c+rows-1)/rows);
+ int nvh = viewportSize(d->columnPos[(int)d->columnPos.size()-1],
+ d->rowPos[(int)d->rowPos.size()-1]).height();
+ if (nvh < vh)
+ vh = nvh;
+ } while (d->rowPos.size() > 2 &&
+ vh < d->rowPos[(int)d->rowPos.size()-1]);
+ } else {
+ tryGeometry(1, 1);
+ }
+ break;
+ case Variable:
+ if (columnMode() == FixedNumber) {
+ tryGeometry((count()+d->numColumns-1)/d->numColumns,
+ d->numColumns);
+ } else if (d->head) { // FitToWidth, at least one item
+ int maxw = 0;
+ Q3ListBoxItem * i = d->head;
+ while (i) {
+ int w = i->width(this);
+ if (maxw < w)
+ maxw = w;
+ i = i->n;
+ }
+ int vw = viewportSize(1, 1).width();
+ do {
+ int cols = vw / maxw;
+ if (cols > c)
+ cols = c;
+ if (cols < 1)
+ cols = 1;
+ if (variableWidth() && cols < c) {
+ do {
+ ++cols;
+ tryGeometry((c+cols-1)/cols, cols);
+ } while (cols <= c &&
+ d->columnPos[(int)d->columnPos.size()-1] <= vw);
+ --cols;
+ }
+ tryGeometry((c+cols-1)/cols, cols);
+ int nvw = viewportSize(d->columnPos[(int)d->columnPos.size()-1],
+ d->rowPos[(int)d->rowPos.size()-1]).width();
+ if (nvw < vw)
+ vw = nvw;
+ } while (d->columnPos.size() > 2 &&
+ vw < d->columnPos[(int)d->columnPos.size()-1]);
+ } else {
+ tryGeometry(1, 1);
+ }
+ break;
+ }
+
+ d->layoutDirty = false;
+ int w = d->columnPos[(int)d->columnPos.size()-1];
+ int h = d->rowPos[(int)d->rowPos.size()-1];
+ QSize s(viewportSize(w, h));
+ w = qMax(w, s.width());
+
+ d->columnPosOne = d->columnPos[1];
+ // extend the column for simple single-column listboxes
+ if (columnMode() == FixedNumber && d->numColumns == 1 &&
+ d->columnPos[1] < w)
+ d->columnPos[1] = w;
+ ((Q3ListBox *)this)->resizeContents(w, h);
+}
+
+
+/*!
+ Lay the items out in a \a columns by \a rows array. The array may
+ be too big: doLayout() is expected to call this with the right
+ values.
+*/
+
+void Q3ListBox::tryGeometry(int rows, int columns) const
+{
+ if (columns < 1)
+ columns = 1;
+ d->columnPos.resize(columns+1);
+
+ if (rows < 1)
+ rows = 1;
+ d->rowPos.resize(rows+1);
+
+ // funky hack I: dump the height/width of each column/row in
+ // {column,row}Pos for later conversion to positions.
+ int c;
+ for(c=0; c<=columns; c++)
+ d->columnPos[c] = 0;
+ int r;
+ for(r=0; r<=rows; r++)
+ d->rowPos[r] = 0;
+ r = c = 0;
+ Q3ListBoxItem * i = d->head;
+ while (i && c < columns) {
+ if (i == d->current) {
+ d->currentRow = r;
+ d->currentColumn = c;
+ }
+
+ int w = i->width(this);
+ if (d->columnPos[c] < w)
+ d->columnPos[c] = w;
+ int h = i->height(this);
+ if (d->rowPos[r] < h)
+ d->rowPos[r] = h;
+ i = i->n;
+ r++;
+ if (r == rows) {
+ r = 0;
+ c++;
+ }
+ }
+ // funky hack II: if not variable {width,height}, unvariablify it.
+ if (!variableWidth()) {
+ int w = 0;
+ for(c=0; c<columns; c++)
+ if (w < d->columnPos[c])
+ w = d->columnPos[c];
+ for(c=0; c<columns; c++)
+ d->columnPos[c] = w;
+ }
+ if (!variableHeight()) {
+ int h = 0;
+ for(r=0; r<rows; r++)
+ if (h < d->rowPos[r])
+ h = d->rowPos[r];
+ for(r=0; r<rows; r++)
+ d->rowPos[r] = h;
+ }
+ // repair the hacking.
+ int x = 0;
+ for(c=0; c<=columns; c++) {
+ int w = d->columnPos[c];
+ d->columnPos[c] = x;
+ x += w;
+ }
+ int y = 0;
+ for(r=0; r<=rows; r++) {
+ int h = d->rowPos[r];
+ d->rowPos[r] = y;
+ y += h;
+ }
+}
+
+
+/*!
+ Returns the row index of the current item, or -1 if no item is the
+ current item.
+*/
+
+int Q3ListBox::currentRow() const
+{
+ if (!d->current)
+ return -1;
+ if (d->currentRow < 0)
+ d->layoutDirty = true;
+ if (d->layoutDirty)
+ doLayout();
+ return d->currentRow;
+}
+
+
+/*!
+ Returns the column index of the current item, or -1 if no item is
+ the current item.
+*/
+
+int Q3ListBox::currentColumn() const
+{
+ if (!d->current)
+ return -1;
+ if (d->currentColumn < 0)
+ d->layoutDirty = true;
+ if (d->layoutDirty)
+ doLayout();
+ return d->currentColumn;
+}
+
+
+void Q3ListBox::setTopItem(int index)
+{
+ if (index >= (int)count() || count() == 0)
+ return;
+ int col = index / numRows();
+ int y = d->rowPos[index-col*numRows()];
+ if (d->columnPos[col] >= contentsX() &&
+ d->columnPos[col+1] <= contentsX() + visibleWidth())
+ setContentsPos(contentsX(), y);
+ else
+ setContentsPos(d->columnPos[col], y);
+}
+
+/*!
+ Scrolls the list box so the item at position \a index in the list
+ is displayed in the bottom row of the list box.
+
+ \sa setTopItem()
+*/
+
+void Q3ListBox::setBottomItem(int index)
+{
+ if (index >= (int)count() || count() == 0)
+ return;
+ int col = index / numRows();
+ int y = d->rowPos[1+index-col*numRows()] - visibleHeight();
+ if (y < 0)
+ y = 0;
+ if (d->columnPos[col] >= contentsX() &&
+ d->columnPos[col+1] <= contentsX() + visibleWidth())
+ setContentsPos(contentsX(), y);
+ else
+ setContentsPos(d->columnPos[col], y);
+}
+
+
+/*!
+ Returns the item at point \a p, specified in viewport coordinates,
+ or a 0 if there is no item at \a p.
+
+ Use contentsToViewport() to convert between widget coordinates and
+ viewport coordinates.
+*/
+
+Q3ListBoxItem * Q3ListBox::itemAt(const QPoint& p) const
+{
+ if (d->layoutDirty)
+ doLayout();
+ QPoint np = p;
+
+ np -= viewport()->pos();
+ if (!viewport()->rect().contains(np))
+ return 0;
+
+ // take into account contents position
+ np = viewportToContents(np);
+
+ int x = np.x();
+ int y = np.y();
+
+ // return 0 when y is below the last row
+ if (y > d->rowPos[numRows()])
+ return 0;
+
+ int col = columnAt(x);
+ int row = rowAt(y);
+
+ Q3ListBoxItem *i = item(col * numRows() + row);
+ if (i && numColumns() > 1) {
+ if (d->columnPos[col] + i->width(this) >= x)
+ return i;
+ } else {
+ if (d->columnPos[col + 1] >= x)
+ return i;
+ }
+ return 0;
+}
+
+
+/*!
+ Ensures that the current item is visible.
+*/
+
+void Q3ListBox::ensureCurrentVisible()
+{
+ if (!d->current)
+ return;
+
+ doLayout();
+
+ int row = currentRow();
+ int column = currentColumn();
+ int w = (d->columnPos[column+1] - d->columnPos[column]) / 2;
+ int h = (d->rowPos[row+1] - d->rowPos[row]) / 2;
+ // next four lines are Bad. they mean that for pure left-to-right
+ // languages, textual list box items are displayed better than
+ // before when there is little space. for non-textual items, or
+ // other languages, it means... that you really should have enough
+ // space in the first place :)
+ if (numColumns() == 1)
+ w = 0;
+ if (w*2 > viewport()->width())
+ w = viewport()->width()/2;
+
+ ensureVisible(d->columnPos[column] + w, d->rowPos[row] + h, w, h);
+}
+
+
+/*! \internal */
+
+void Q3ListBox::doAutoScroll()
+{
+ if (d->scrollPos.x() < 0) {
+ // scroll left
+ int x = contentsX() - horizontalScrollBar()->singleStep();
+ if (x < 0)
+ x = 0;
+ if (x != contentsX()) {
+ d->mouseMoveColumn = columnAt(x);
+ updateSelection();
+ if (x < contentsX())
+ setContentsPos(x, contentsY());
+ }
+ } else if (d->scrollPos.x() > 0) {
+ // scroll right
+ int x = contentsX() + horizontalScrollBar()->singleStep();
+ if (x + visibleWidth() > contentsWidth())
+ x = contentsWidth() - visibleWidth();
+ if (x != contentsX()) {
+ d->mouseMoveColumn = columnAt(x + visibleWidth() - 1);
+ updateSelection();
+ if (x > contentsX())
+ setContentsPos(x, contentsY());
+ }
+ }
+
+ if (d->scrollPos.y() < 0) {
+ // scroll up
+ int y = contentsY() - verticalScrollBar()->singleStep();
+ if (y < 0)
+ y = 0;
+ if (y != contentsY()) {
+ y = contentsY() - verticalScrollBar()->singleStep();
+ d->mouseMoveRow = rowAt(y);
+ updateSelection();
+ }
+ } else if (d->scrollPos.y() > 0) {
+ // scroll down
+ int y = contentsY() + verticalScrollBar()->singleStep();
+ if (y + visibleHeight() > contentsHeight())
+ y = contentsHeight() - visibleHeight();
+ if (y != contentsY()) {
+ y = contentsY() + verticalScrollBar()->singleStep();
+ d->mouseMoveRow = rowAt(y + visibleHeight() - 1);
+ updateSelection();
+ }
+ }
+
+ if (d->scrollPos == QPoint(0, 0)) {
+ delete d->scrollTimer;
+ d->scrollTimer = 0;
+ }
+}
+
+
+/*!
+ \property Q3ListBox::topItem
+ \brief the index of an item at the top of the screen.
+
+ When getting this property and the listbox has multiple columns,
+ an arbitrary item is selected and returned.
+
+ When setting this property, the list box is scrolled so the item
+ at position \e index in the list is displayed in the top row of
+ the list box.
+*/
+
+int Q3ListBox::topItem() const
+{
+ doLayout();
+
+ // move rightwards to the best column
+ int col = columnAt(contentsX());
+ int row = rowAt(contentsY());
+ return col * numRows() + row;
+}
+
+
+/*!
+ \property Q3ListBox::variableHeight
+ \brief whether this list box has variable-height rows
+
+ When the list box has variable-height rows (the default), each row
+ is as high as the highest item in that row. When it has same-sized
+ rows, all rows are as high as the highest item in the list box.
+
+ \sa variableWidth
+*/
+
+bool Q3ListBox::variableHeight() const
+{
+ return d->variableHeight;
+}
+
+
+void Q3ListBox::setVariableHeight(bool enable)
+{
+ if ((bool)d->variableHeight == enable)
+ return;
+
+ d->variableHeight = enable;
+ triggerUpdate(true);
+}
+
+
+/*!
+ \property Q3ListBox::variableWidth
+ \brief whether this list box has variable-width columns
+
+ When the list box has variable-width columns, each column is as
+ wide as the widest item in that column. When it has same-sized
+ columns (the default), all columns are as wide as the widest item
+ in the list box.
+
+ \sa variableHeight
+*/
+
+bool Q3ListBox::variableWidth() const
+{
+ return d->variableWidth;
+}
+
+
+void Q3ListBox::setVariableWidth(bool enable)
+{
+ if ((bool)d->variableWidth == enable)
+ return;
+
+ d->variableWidth = enable;
+ triggerUpdate(true);
+}
+
+
+/*!
+ Repaints only what really needs to be repainted.
+*/
+void Q3ListBox::refreshSlot()
+{
+ if (d->mustPaintAll ||
+ d->layoutDirty) {
+ d->mustPaintAll = false;
+ bool currentItemVisible = itemVisible(currentItem());
+ doLayout();
+ if (hasFocus() &&
+ currentItemVisible &&
+ d->currentColumn >= 0 &&
+ d->currentRow >= 0 &&
+ (d->columnPos[d->currentColumn] < contentsX() ||
+ d->columnPos[d->currentColumn+1]>contentsX()+visibleWidth() ||
+ d->rowPos[d->currentRow] < contentsY() ||
+ d->rowPos[d->currentRow+1] > contentsY()+visibleHeight()))
+ ensureCurrentVisible();
+ viewport()->repaint();
+ return;
+ }
+
+ QRegion r;
+ int x = contentsX();
+ int y = contentsY();
+ int col = columnAt(x);
+ int row = rowAt(y);
+ int top = row;
+ while(col < (int)d->columnPos.size()-1 && d->columnPos[col+1] < x)
+ col++;
+ while(top < (int)d->rowPos.size()-1 && d->rowPos[top+1] < y)
+ top++;
+ Q3ListBoxItem * i = item(col * numRows() + row);
+
+ while (i && (int)col < numColumns() &&
+ d->columnPos[col] < x + visibleWidth() ) {
+ int cw = d->columnPos[col+1] - d->columnPos[col];
+ while (i && row < numRows() && d->rowPos[row] <
+ y + visibleHeight()) {
+ if (i->dirty)
+ r = r.united(QRect(d->columnPos[col] - x, d->rowPos[row] - y,
+ cw, d->rowPos[row+1] - d->rowPos[row]));
+ row++;
+ i = i->n;
+ }
+ col++;
+ if (numColumns() > 1) {
+ row = top;
+ i = item(col * numRows() + row);
+ }
+ }
+
+ if (r.isEmpty())
+ viewport()->repaint();
+ else
+ viewport()->repaint(r);
+}
+
+
+/*! \reimp */
+
+void Q3ListBox::viewportPaintEvent(QPaintEvent * e)
+{
+ doLayout();
+ QWidget* vp = viewport();
+ QPainter p(vp);
+ QRegion r = e->region();
+
+#if 0
+ {
+ // this stuff has been useful enough times that from now I'm
+ // leaving it in the source.
+ uint i = 0;
+ qDebug("%s/%s: %i rects", className(), name(), r.rects().size());
+ while(i < r.rects().size()) {
+ qDebug("rect %d: %d, %d, %d, %d", i,
+ r.rects()[i].left(), r.rects()[i].top(),
+ r.rects()[i].width(), r.rects()[i].height());
+ i++;
+ }
+ qDebug("");
+ }
+#endif
+
+ int x = contentsX();
+ int y = contentsY();
+ int w = vp->width();
+ int h = vp->height();
+
+ int col = columnAt(x);
+ int top = rowAt(y);
+ int row = top;
+
+ Q3ListBoxItem * i = item(col*numRows() + row);
+
+ const QPalette &pal = palette();
+ p.setPen(pal.text().color());
+ p.setBackground(palette().brush(backgroundRole()).color());
+ while (i && (int)col < numColumns() && d->columnPos[col] < x + w) {
+ int cw = d->columnPos[col+1] - d->columnPos[col];
+ while (i && (int)row < numRows() && d->rowPos[row] < y + h) {
+ int ch = d->rowPos[row+1] - d->rowPos[row];
+ QRect itemRect(d->columnPos[col]-x, d->rowPos[row]-y, cw, ch);
+ QRegion tempRegion(itemRect);
+ QRegion itemPaintRegion(tempRegion.intersected(r ));
+ if (!itemPaintRegion.isEmpty()) {
+ p.save();
+ p.setClipRegion(itemPaintRegion);
+ p.translate(d->columnPos[col]-x, d->rowPos[row]-y);
+ paintCell(&p, row, col);
+ p.restore();
+ r = r.subtracted(itemPaintRegion);
+ }
+ row++;
+ if (i->dirty) {
+ // reset dirty flag only if the entire item was painted
+ if (itemPaintRegion == QRegion(itemRect))
+ i->dirty = false;
+ }
+ i = i->n;
+ }
+ col++;
+ if (numColumns() > 1) {
+ row = top;
+ i = item(col * numRows() + row);
+ }
+ }
+
+ if (r.isEmpty())
+ return;
+ p.setClipRegion(r);
+ p.fillRect(0, 0, w, h, viewport()->palette().brush(viewport()->backgroundRole()));
+
+ if(d->rubber && d->rubber->width() && d->rubber->height()) {
+ p.save();
+ p.setClipping(false);
+ // p.setRasterOp(NotROP); // ### fix - use qrubberband instead
+ QStyleOptionRubberBand opt;
+ opt.rect = d->rubber->normalized();
+ opt.palette = palette();
+ opt.shape = QRubberBand::Rectangle;
+ opt.opaque = false;
+ style()->drawControl(QStyle::CE_RubberBand, &opt, &p, this);
+ p.restore();
+ }
+}
+
+
+/*!
+ Returns the height in pixels of the item with index \a index. \a
+ index defaults to 0.
+
+ If \a index is too large, this function returns 0.
+*/
+
+int Q3ListBox::itemHeight(int index) const
+{
+ if (index >= (int)count() || index < 0)
+ return 0;
+ int r = index % numRows();
+ return d->rowPos[r+1] - d->rowPos[r];
+}
+
+
+/*!
+ Returns the index of the column at \a x, which is in the listbox's
+ coordinates, not in on-screen coordinates.
+
+ If there is no column that spans \a x, columnAt() returns -1.
+*/
+
+int Q3ListBox::columnAt(int x) const
+{
+ if (x < 0)
+ return -1;
+ if (!d->columnPos.size())
+ return -1;
+ if (x >= d->columnPos[(int)d->columnPos.size()-1])
+ return numColumns() - 1;
+
+ int col = 0;
+ while(col < (int)d->columnPos.size()-1 && d->columnPos[col+1] < x)
+ col++;
+ return col;
+}
+
+
+/*!
+ Returns the index of the row at \a y, which is in the listbox's
+ coordinates, not in on-screen coordinates.
+
+ If there is no row that spans \a y, rowAt() returns -1.
+*/
+
+int Q3ListBox::rowAt(int y) const
+{
+ if (y < 0)
+ return -1;
+
+ // find the top item, use bsearch for speed
+ int l = 0;
+ int r = d->rowPos.size() - 2;
+ if (r < 0)
+ return -1;
+ if (l <= d->rowPosCache && d->rowPosCache <= r) {
+ if (d->rowPos[qMax(l, d->rowPosCache - 10)] <= y
+ && y <= d->rowPos[qMin(r, d->rowPosCache + 10)]) {
+ l = qMax(l, d->rowPosCache - 10);
+ r = qMin(r, d->rowPosCache + 10);
+ }
+ }
+ int i = ((l+r+1) / 2);
+ while (r - l) {
+ if (d->rowPos[i] > y)
+ r = i -1;
+ else
+ l = i;
+ i = ((l+r+1) / 2);
+ }
+ d->rowPosCache = i;
+ if (d->rowPos[i] <= y && y <= d->rowPos[i+1] )
+ return i;
+
+ return d->count - 1;
+}
+
+
+/*!
+ Returns the rectangle on the screen that \a item occupies in
+ viewport()'s coordinates, or an invalid rectangle if \a item is 0
+ or is not currently visible.
+*/
+
+QRect Q3ListBox::itemRect(Q3ListBoxItem *item) const
+{
+ if (d->resizeTimer->isActive())
+ return QRect(0, 0, -1, -1);
+ if (!item)
+ return QRect(0, 0, -1, -1);
+
+ int i = index(item);
+ if (i == -1)
+ return QRect(0, 0, -1, -1);
+
+ int col = i / numRows();
+ int row = i % numRows();
+
+ int x = d->columnPos[col] - contentsX();
+ int y = d->rowPos[row] - contentsY();
+
+ QRect r(x, y, d->columnPos[col + 1] - d->columnPos[col],
+ d->rowPos[row + 1] - d->rowPos[row]);
+ if (r.intersects(QRect(0, 0, visibleWidth(), visibleHeight())))
+ return r;
+ return QRect(0, 0, -1, -1);
+}
+
+
+/*!
+ Using this method is quite inefficient. We suggest to use insertItem()
+ for inserting and sort() afterwards.
+
+ Inserts \a lbi at its sorted position in the list box and returns the
+ position.
+
+ All items must be inserted with inSort() to maintain the sorting
+ order. inSort() treats any pixmap (or user-defined type) as
+ lexicographically less than any string.
+
+ \sa insertItem(), sort()
+*/
+int Q3ListBox::inSort(const Q3ListBoxItem * lbi)
+{
+ if (!lbi)
+ return -1;
+
+ Q3ListBoxItem * i = d->head;
+ int c = 0;
+
+ while(i && i->text() < lbi->text()) {
+ i = i->n;
+ c++;
+ }
+ insertItem(lbi, c);
+ return c;
+}
+
+/*!
+ \overload
+ Using this method is quite inefficient. We suggest to use insertItem()
+ for inserting and sort() afterwards.
+
+ Inserts a new item of \a text at its sorted position in the list box and
+ returns the position.
+
+ All items must be inserted with inSort() to maintain the sorting
+ order. inSort() treats any pixmap (or user-defined type) as
+ lexicographically less than any string.
+
+ \sa insertItem(), sort()
+*/
+int Q3ListBox::inSort(const QString& text)
+{
+ Q3ListBoxItem *lbi = new Q3ListBoxText(text);
+
+ Q3ListBoxItem * i = d->head;
+ int c = 0;
+
+ while(i && i->text() < lbi->text()) {
+ i = i->n;
+ c++;
+ }
+ insertItem(lbi, c);
+ return c;
+}
+
+
+/*! \reimp */
+
+void Q3ListBox::resizeEvent(QResizeEvent *e)
+{
+ d->layoutDirty = (d->layoutDirty ||
+ rowMode() == FitToHeight ||
+ columnMode() == FitToWidth);
+
+ if (!d->layoutDirty && columnMode() == FixedNumber &&
+ d->numColumns == 1) {
+ int w = d->columnPosOne;
+ QSize s(viewportSize(w, contentsHeight()));
+ w = qMax(w, s.width());
+ d->columnPos[1] = qMax(w, d->columnPosOne);
+ resizeContents(d->columnPos[1], contentsHeight());
+ }
+
+ if (d->resizeTimer->isActive())
+ d->resizeTimer->stop();
+ if (d->rowMode == FixedNumber && d->columnMode == FixedNumber) {
+ bool currentItemVisible = itemVisible(currentItem());
+ doLayout();
+ Q3ScrollView::resizeEvent(e);
+ if (currentItemVisible)
+ ensureCurrentVisible();
+ if (d->current)
+ viewport()->repaint(itemRect(d->current));
+ } else if ((d->columnMode == FitToWidth || d->rowMode == FitToHeight) && !(isVisible())) {
+ Q3ScrollView::resizeEvent(e);
+ } else if (d->layoutDirty) {
+ d->resizeTimer->start(100, true);
+ resizeContents(contentsWidth() - (e->oldSize().width() - e->size().width()),
+ contentsHeight() - (e->oldSize().height() - e->size().height()));
+ Q3ScrollView::resizeEvent(e);
+ } else {
+ Q3ScrollView::resizeEvent(e);
+ }
+}
+
+/*!
+ \internal
+*/
+
+void Q3ListBox::adjustItems()
+{
+ triggerUpdate(true);
+ ensureCurrentVisible();
+}
+
+
+/*!
+ Provided for compatibility with the old Q3ListBox. We recommend
+ using Q3ListBoxItem::paint() instead.
+
+ Repaints the cell at \a row, \a col using painter \a p.
+*/
+
+void Q3ListBox::paintCell(QPainter * p, int row, int col)
+{
+ bool drawActiveSelection = hasFocus() || d->inMenuMode ||
+ !style()->styleHint(QStyle::SH_ItemView_ChangeHighlightOnFocus, 0, this);
+ QPalette pal = palette();
+ if(!drawActiveSelection)
+ pal.setCurrentColorGroup(QPalette::Inactive);
+
+ int cw = d->columnPos[col+1] - d->columnPos[col];
+ int ch = d->rowPos[row+1] - d->rowPos[row];
+ Q3ListBoxItem * i = item(col*numRows()+row);
+ p->save();
+ if (i->s) {
+ if (i->custom_highlight) {
+ p->fillRect(0, 0, cw, ch, pal.brush(viewport()->foregroundRole()));
+ p->setPen(pal.highlightedText().color());
+ p->setBackground(pal.highlight());
+ } else if (numColumns() == 1) {
+ p->fillRect(0, 0, cw, ch, pal.brush(QPalette::Highlight));
+ p->setPen(pal.highlightedText().color());
+ p->setBackground(pal.highlight());
+ } else {
+ int iw = i->width(this);
+ p->fillRect(0, 0, iw, ch, pal.brush(QPalette::Highlight));
+ p->fillRect(iw, 0, cw - iw + 1, ch, viewport()->palette().brush(viewport()->backgroundRole()));
+ p->setPen(pal.highlightedText().color());
+ p->setBackground(pal.highlight());
+ }
+ } else {
+ p->fillRect(0, 0, cw, ch, viewport()->palette().brush(viewport()->backgroundRole()));
+ }
+
+ i->paint(p);
+
+ if (d->current == i && hasFocus() && !i->custom_highlight) {
+ if (numColumns() > 1)
+ cw = i->width(this);
+ QStyleOptionFocusRect opt;
+ opt.rect.setRect(0, 0, cw, ch);
+ opt.palette = pal;
+ opt.state = QStyle::State_FocusAtBorder;
+ if (i->isSelected())
+ opt.backgroundColor = pal.highlight().color();
+ else
+ opt.backgroundColor = pal.base().color();
+ style()->drawPrimitive(QStyle::PE_FrameFocusRect, &opt, p, this);
+ }
+
+ p->restore();
+}
+
+/*!
+ Returns the width of the widest item in the list box.
+*/
+
+long Q3ListBox::maxItemWidth() const
+{
+ if (d->layoutDirty)
+ doLayout();
+ long m = 0;
+ int i = d->columnPos.size();
+ while(i--)
+ if (m < d->columnPos[i])
+ m = d->columnPos[i];
+ return m;
+}
+
+
+/*! \reimp */
+
+void Q3ListBox::showEvent(QShowEvent *)
+{
+ d->ignoreMoves = false;
+ d->mousePressRow = -1;
+ d->mousePressColumn = -1;
+ d->mustPaintAll = false;
+ ensureCurrentVisible();
+}
+
+/*!
+ \fn bool Q3ListBoxItem::isSelected() const
+
+ Returns true if the item is selected; otherwise returns false.
+
+ \sa Q3ListBox::isSelected(), isCurrent()
+*/
+
+/*!
+ Returns true if the item is the current item; otherwise returns
+ false.
+
+ \sa Q3ListBox::currentItem(), Q3ListBox::item(), isSelected()
+*/
+bool Q3ListBoxItem::isCurrent() const
+{
+ return listBox() && listBox()->hasFocus() &&
+ listBox()->item(listBox()->currentItem()) == this;
+}
+
+/*!
+ \fn void Q3ListBox::centerCurrentItem()
+
+ If there is a current item, the list box is scrolled so that this
+ item is displayed centered.
+
+ \sa Q3ListBox::ensureCurrentVisible()
+*/
+
+/*!
+ Returns a pointer to the list box containing this item.
+*/
+
+Q3ListBox * Q3ListBoxItem::listBox() const
+{
+ return lbox;
+}
+
+
+/*!
+ Removes \a item from the list box and causes an update of the
+ screen display. The item is not deleted. You should normally not
+ need to call this function because Q3ListBoxItem::~Q3ListBoxItem()
+ calls it. The normal way to delete an item is with \c delete.
+
+ \sa Q3ListBox::insertItem()
+*/
+void Q3ListBox::takeItem(const Q3ListBoxItem * item)
+{
+ if (!item || d->clearing)
+ return;
+ d->cache = 0;
+ d->count--;
+ if (item == d->last)
+ d->last = d->last->p;
+ if (item->p && item->p->n == item)
+ item->p->n = item->n;
+ if (item->n && item->n->p == item)
+ item->n->p = item->p;
+ if (d->head == item) {
+ d->head = item->n;
+ d->currentColumn = d->currentRow = -1;
+ }
+
+ if (d->current == item) {
+ d->current = item->n ? item->n : item->p;
+ Q3ListBoxItem *i = d->current;
+ QString tmp;
+ if (i)
+ tmp = i->text();
+ int tmp2 = index(i);
+ emit highlighted(i);
+ if (!tmp.isNull())
+ emit highlighted(tmp);
+ emit highlighted(tmp2);
+ emit currentChanged(i);
+ }
+ if (d->tmpCurrent == item)
+ d->tmpCurrent = d->current;
+ if (d->selectAnchor == item)
+ d->selectAnchor = d->current;
+
+ if (item->s)
+ emit selectionChanged();
+ ((Q3ListBoxItem *)item)->lbox = 0;
+ triggerUpdate(true);
+}
+
+/*!
+ \internal
+ Finds the next item after start beginning with \a text.
+*/
+
+int Q3ListBoxPrivate::findItemByName(int start, const QString &text)
+{
+ if (start < 0 || (uint)start >= listBox->count())
+ start = 0;
+ QString match = text.toLower();
+ if (match.length() < 1)
+ return start;
+ QString curText;
+ int item = start;
+ do {
+ curText = listBox->text(item).toLower();
+ if (curText.startsWith(match))
+ return item;
+ item++;
+ if ((uint)item == listBox->count())
+ item = 0;
+ } while (item != start);
+ return -1;
+}
+
+/*!
+ \internal
+*/
+
+void Q3ListBox::clearInputString()
+{
+ d->currInputString.clear();
+}
+
+/*!
+ Finds the first list box item that has the text \a text and
+ returns it, or returns 0 of no such item could be found. If \c
+ ComparisonFlags are specified in \a compare then these flags
+ are used, otherwise the default is a case-insensitive, "begins
+ with" search.
+*/
+
+Q3ListBoxItem *Q3ListBox::findItem(const QString &text, ComparisonFlags compare) const
+{
+ if (text.isEmpty())
+ return 0;
+
+ if (compare == CaseSensitive || compare == 0)
+ compare |= ExactMatch;
+
+ QString itmtxt;
+ QString comtxt = text;
+ if (!(compare & CaseSensitive))
+ comtxt = text.toLower();
+
+ Q3ListBoxItem *item;
+ if (d->current)
+ item = d->current;
+ else
+ item = d->head;
+
+ Q3ListBoxItem *beginsWithItem = 0;
+ Q3ListBoxItem *endsWithItem = 0;
+ Q3ListBoxItem *containsItem = 0;
+
+ if (item) {
+ for (; item; item = item->n) {
+ if (!(compare & CaseSensitive))
+ itmtxt = item->text().toLower();
+ else
+ itmtxt = item->text();
+
+ if ((compare & ExactMatch)==ExactMatch && itmtxt == comtxt)
+ return item;
+ if (compare & BeginsWith && !beginsWithItem && itmtxt.startsWith(comtxt))
+ beginsWithItem = containsItem = item;
+ if (compare & EndsWith && !endsWithItem && itmtxt.endsWith(comtxt))
+ endsWithItem = containsItem = item;
+ if ((compare & ExactMatch)==0 && !containsItem && itmtxt.contains(comtxt))
+ containsItem = item;
+ }
+
+ if (d->current && d->head) {
+ item = d->head;
+ for (; item && item != d->current; item = item->n) {
+ if (!(compare & CaseSensitive))
+ itmtxt = item->text().toLower();
+ else
+ itmtxt = item->text();
+
+ if ((compare & ExactMatch)==ExactMatch && itmtxt == comtxt)
+ return item;
+ if (compare & BeginsWith && !beginsWithItem && itmtxt.startsWith(comtxt))
+ beginsWithItem = containsItem = item;
+ if (compare & EndsWith && !endsWithItem && itmtxt.endsWith(comtxt))
+ endsWithItem = containsItem = item;
+ if ((compare & ExactMatch)==0 && !containsItem && itmtxt.contains(comtxt))
+ containsItem = item;
+ }
+ }
+ }
+
+ // Obey the priorities
+ if (beginsWithItem)
+ return beginsWithItem;
+ else if (endsWithItem)
+ return endsWithItem;
+ else if (containsItem)
+ return containsItem;
+ return 0;
+}
+
+/*!
+ \internal
+*/
+
+void Q3ListBox::drawRubber()
+{
+ if (!d->rubber)
+ return;
+ if (!d->rubber->width() && !d->rubber->height())
+ return;
+ update();
+}
+
+/*!
+ \internal
+*/
+
+void Q3ListBox::doRubberSelection(const QRect &old, const QRect &rubber)
+{
+ Q3ListBoxItem *i = d->head;
+ QRect ir, pr;
+ bool changed = false;
+ for (; i; i = i->n) {
+ ir = itemRect(i);
+ if (ir == QRect(0, 0, -1, -1))
+ continue;
+ if (i->isSelected() && !ir.intersects(rubber) && ir.intersects(old)) {
+ i->s = false;
+ pr = pr.united(ir);
+ changed = true;
+ } else if (!i->isSelected() && ir.intersects(rubber)) {
+ if (i->isSelectable()) {
+ i->s = true;
+ pr = pr.united(ir);
+ changed = true;
+ }
+ }
+ }
+ if (changed) {
+ emit selectionChanged();
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessible::updateAccessibility(viewport(), 0, QAccessible::Selection);
+#endif
+ }
+ viewport()->repaint(pr);
+}
+
+
+/*!
+ Returns true if the user is selecting items using a rubber band
+ rectangle; otherwise returns false.
+*/
+
+bool Q3ListBox::isRubberSelecting() const
+{
+ return d->rubber != 0;
+}
+
+
+/*!
+ Returns the item that comes after this in the list box. If this is
+ the last item, 0 is returned.
+
+ \sa prev()
+*/
+
+Q3ListBoxItem *Q3ListBoxItem::next() const
+{
+ return n;
+}
+
+/*!
+ Returns the item which comes before this in the list box. If this
+ is the first item, 0 is returned.
+
+ \sa next()
+*/
+
+Q3ListBoxItem *Q3ListBoxItem::prev() const
+{
+ return p;
+}
+
+/*!
+ Returns the first item in this list box. If the list box is empty,
+ returns 0.
+*/
+
+Q3ListBoxItem *Q3ListBox::firstItem() const
+{
+ return d->head;
+}
+
+#if defined(Q_C_CALLBACKS)
+extern "C" {
+#endif
+
+#ifdef Q_OS_WINCE
+static int _cdecl cmpListBoxItems(const void *n1, const void *n2)
+#else
+static int cmpListBoxItems(const void *n1, const void *n2)
+#endif
+{
+ if (!n1 || !n2)
+ return 0;
+
+ Q3ListBoxPrivate::SortableItem *i1 = (Q3ListBoxPrivate::SortableItem *)n1;
+ Q3ListBoxPrivate::SortableItem *i2 = (Q3ListBoxPrivate::SortableItem *)n2;
+
+ return i1->item->text().localeAwareCompare(i2->item->text());
+}
+
+#if defined(Q_C_CALLBACKS)
+}
+#endif
+
+/*!
+ If \a ascending is true sorts the items in ascending order;
+ otherwise sorts in descending order.
+
+ To compare the items, the text (Q3ListBoxItem::text()) of the items
+ is used.
+*/
+
+void Q3ListBox::sort(bool ascending)
+{
+ if (count() == 0)
+ return;
+
+ d->cache = 0;
+
+ Q3ListBoxPrivate::SortableItem *items = new Q3ListBoxPrivate::SortableItem[count()];
+
+ Q3ListBoxItem *item = d->head;
+ int i = 0;
+ for (; item; item = item->n)
+ items[i++].item = item;
+
+ qsort(items, count(), sizeof(Q3ListBoxPrivate::SortableItem), cmpListBoxItems);
+
+ Q3ListBoxItem *prev = 0;
+ item = 0;
+ if (ascending) {
+ for (i = 0; i < (int)count(); ++i) {
+ item = items[i].item;
+ if (item) {
+ item->p = prev;
+ item->dirty = true;
+ if (item->p)
+ item->p->n = item;
+ item->n = 0;
+ }
+ if (i == 0)
+ d->head = item;
+ prev = item;
+ }
+ } else {
+ for (i = (int)count() - 1; i >= 0 ; --i) {
+ item = items[i].item;
+ if (item) {
+ item->p = prev;
+ item->dirty = true;
+ if (item->p)
+ item->p->n = item;
+ item->n = 0;
+ }
+ if (i == (int)count() - 1)
+ d->head = item;
+ prev = item;
+ }
+ }
+ d->last = item;
+
+ delete [] items;
+
+ // We have to update explicitly in case the current "vieport" overlaps the
+ // new viewport we set (starting at (0,0)).
+ bool haveToUpdate = contentsX() < visibleWidth() || contentsY() < visibleHeight();
+ setContentsPos(0, 0);
+ if (haveToUpdate)
+ updateContents(0, 0, visibleWidth(), visibleHeight());
+}
+
+void Q3ListBox::handleItemChange(Q3ListBoxItem *old, bool shift, bool control)
+{
+ if (d->selectionMode == Single) {
+ // nothing
+ } else if (d->selectionMode == Extended) {
+ if (shift) {
+ selectRange(d->selectAnchor ? d->selectAnchor : old,
+ d->current, false, true, (d->selectAnchor && !control) ? true : false);
+ } else if (!control) {
+ bool block = signalsBlocked();
+ blockSignals(true);
+ selectAll(false);
+ blockSignals(block);
+ setSelected(d->current, true);
+ }
+ } else if (d->selectionMode == Multi) {
+ if (shift)
+ selectRange(old, d->current, true, false);
+ }
+}
+
+void Q3ListBox::selectRange(Q3ListBoxItem *from, Q3ListBoxItem *to, bool invert, bool includeFirst, bool clearSel)
+{
+ if (!from || !to)
+ return;
+ if (from == to && !includeFirst)
+ return;
+ Q3ListBoxItem *i = 0;
+ int index =0;
+ int f_idx = -1, t_idx = -1;
+ for (i = d->head; i; i = i->n, index++) {
+ if (i == from)
+ f_idx = index;
+ if (i == to)
+ t_idx = index;
+ if (f_idx != -1 && t_idx != -1)
+ break;
+ }
+ if (f_idx > t_idx) {
+ i = from;
+ from = to;
+ to = i;
+ if (!includeFirst)
+ to = to->prev();
+ } else {
+ if (!includeFirst)
+ from = from->next();
+ }
+
+ bool changed = false;
+ if (clearSel) {
+ for (i = d->head; i && i != from; i = i->n) {
+ if (i->s) {
+ i->s = false;
+ changed = true;
+ updateItem(i);
+ }
+ }
+ for (i = to->n; i; i = i->n) {
+ if (i->s) {
+ i->s = false;
+ changed = true;
+ updateItem(i);
+ }
+ }
+ }
+
+ for (i = from; i; i = i->next()) {
+ if (!invert) {
+ if (!i->s && i->isSelectable()) {
+ i->s = true;
+ changed = true;
+ updateItem(i);
+ }
+ } else {
+ bool sel = !i->s;
+ if (((bool)i->s != sel && sel && i->isSelectable()) || !sel) {
+ i->s = sel;
+ changed = true;
+ updateItem(i);
+ }
+ }
+ if (i == to)
+ break;
+ }
+ if (changed) {
+ emit selectionChanged();
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessible::updateAccessibility(viewport(), 0, QAccessible::Selection);
+#endif
+ }
+}
+
+/*! \reimp */
+void Q3ListBox::changeEvent(QEvent *ev)
+{
+ if (ev->type() == QEvent::ActivationChange) {
+ if (!isActiveWindow() && d->scrollTimer)
+ d->scrollTimer->stop();
+ if (!palette().isEqual(QPalette::Active, QPalette::Inactive))
+ viewport()->update();
+ }
+ Q3ScrollView::changeEvent(ev);
+
+ if (ev->type() == QEvent::ApplicationFontChange || ev->type() == QEvent::FontChange)
+ triggerUpdate(true);
+}
+
+/*!
+ Returns 0.
+
+ Make your derived classes return their own values for rtti(), and
+ you can distinguish between listbox items. You should use values
+ greater than 1000 preferably a large random number, to allow for
+ extensions to this class.
+*/
+
+int Q3ListBoxItem::rtti() const
+{
+ return RTTI;
+}
+
+/*!
+ \fn bool Q3ListBox::dragSelect() const
+
+ Returns true. Dragging always selects.
+*/
+
+/*!
+ \fn void Q3ListBox::setDragSelect(bool b)
+
+ Does nothing. Dragging always selects. The \a b parameter is ignored.
+*/
+
+/*!
+ \fn bool Q3ListBox::autoScroll() const
+
+ Use dragAutoScroll() instead. This function always returns true.
+*/
+
+/*!
+ \fn void Q3ListBox::setAutoScroll(bool b)
+
+ Use setDragAutoScroll(\a b) instead.
+*/
+
+/*!
+ \fn bool Q3ListBox::autoScrollBar() const
+
+ Use vScrollBarMode() instead. Returns true if the vertical
+ scrollbar mode is \c Auto.
+*/
+
+/*!
+ \fn void Q3ListBox::setAutoScrollBar(bool enable)
+
+ Use setVScrollBarMode() instead.
+
+ If \a enable is true, pass \c Auto as the argument to
+ setVScrollBarMode(); otherwise, pass \c AlwaysOff.
+*/
+
+/*!
+ \fn bool Q3ListBox::scrollBar() const
+
+ Use vScrollBarMode() instead. Returns true if the vertical
+ scrollbar mode is not \c AlwaysOff.
+*/
+
+/*!
+ \fn void Q3ListBox::setScrollBar(bool enable)
+
+ Use setVScrollBarMode() instead.
+
+ If \a enable is true, pass \c AlwaysOn as the argument to
+ setVScrollBarMode(); otherwise, pass \c AlwaysOff.
+*/
+
+/*!
+ \fn bool Q3ListBox::autoBottomScrollBar() const
+
+ Use hScrollBarMode() instead. Returns true if the horizontal
+ scrollbar mode is set to \c Auto.
+*/
+
+/*!
+ \fn void Q3ListBox::setAutoBottomScrollBar(bool enable)
+
+ Use setHScrollBarMode() instead.
+
+ If \a enable is true, pass \c Auto as the argument to
+ setHScrollBarMode(); otherwise, pass \c AlwaysOff.
+*/
+
+/*!
+ \fn bool Q3ListBox::bottomScrollBar() const
+
+ Use hScrollBarMode() instead. Returns true if the horizontal
+ scrollbar mode is not \c AlwaysOff.
+*/
+
+/*!
+ \fn void Q3ListBox::setBottomScrollBar(bool enable)
+
+ Use setHScrollBarMode() instead.
+
+ If \a enable is true, pass \c AlwaysOn as the argument to
+ setHScrollBarMode(); otherwise, pass \c AlwaysOff.
+*/
+
+/*!
+ \fn bool Q3ListBox::smoothScrolling() const
+
+ Returns false. Qt always scrolls smoothly.
+*/
+
+/*!
+ \fn void Q3ListBox::setSmoothScrolling(bool b)
+
+ Does nothing. Qt always scrolls smoothly. The \a b parameter is
+ ignored.
+*/
+
+/*!
+ \fn bool Q3ListBox::autoUpdate() const
+
+ Returns true. Qt always updates automatically.
+*/
+
+/*!
+ \fn void Q3ListBox::setAutoUpdate(bool b)
+
+ Does nothing. Qt always updates automatically. The \a b parameter
+ is ignored.
+*/
+
+/*!
+ \fn void Q3ListBox::setFixedVisibleLines(int lines)
+
+ Use setRowMode(\a lines) instead.
+*/
+
+/*!
+ \fn int Q3ListBox::cellHeight(int i) const
+
+ Use itemHeight(\a i) instead.
+*/
+
+/*!
+ \fn int Q3ListBox::cellHeight() const
+
+ Use itemHeight() instead.
+*/
+
+/*!
+ \fn int Q3ListBox::cellWidth() const
+
+ Use maxItemWidth() instead.
+*/
+
+/*!
+ \fn int Q3ListBox::cellWidth(int i) const
+
+ Use maxItemWidth(\a i) instead.
+*/
+
+/*!
+ \fn int Q3ListBox::numCols() const
+
+ Use numColumns() instead.
+*/
+
+/*!
+ \fn void Q3ListBox::updateCellWidth()
+
+ Does nothing. Qt automatically updates.
+*/
+
+/*!
+ \fn int Q3ListBox::totalWidth() const
+
+ Use contentsWidth() instead.
+*/
+
+/*!
+ \fn int Q3ListBox::totalHeight() const
+
+ Use contentsHeight() instead.
+*/
+
+/*!
+ \fn int Q3ListBox::findItem(int yPos) const
+
+ Use index(itemAt(\a yPos)) instead.
+*/
+
+/*!
+ \fn bool Q3ListBoxItem::selected() const
+
+ Use isSelected() instead. Returns true if isSelected()
+ returns true.
+*/
+
+/*!
+ \fn bool Q3ListBoxItem::current() const
+
+ Use isCurrent() instead. Returns true if isCurrent()
+ returns true.
+*/
+
+/*!
+ \enum Q3ListBox::StringComparisonMode
+
+ This enum type is used to set the string comparison mode when
+ searching for an item. We'll refer to the string being searched
+ as the 'target' string.
+
+ \value CaseSensitive The strings must match case sensitively.
+ \value ExactMatch The target and search strings must match exactly.
+ \value BeginsWith The target string begins with the search string.
+ \value EndsWith The target string ends with the search string.
+ \value Contains The target string contains the search string.
+
+ If you OR these flags together (excluding \c CaseSensitive), the
+ search criteria be applied in the following order: \c ExactMatch,
+ \c BeginsWith, \c EndsWith, \c Contains.
+
+ Matching is case-insensitive unless \c CaseSensitive is set. \c
+ CaseSensitive can be OR-ed with any combination of the other
+ flags.
+
+ \sa ComparisonFlags
+*/
+
+/*!
+ \typedef Q3ListBox::ComparisonFlags
+
+ This typedef is used in Q3IconView's API for values that are OR'd
+ combinations of \l StringComparisonMode values.
+
+ \sa StringComparisonMode
+*/
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_LISTBOX