src/qt3support/itemviews/q3listbox.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
--- /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