src/qt3support/widgets/q3combobox.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/qt3support/widgets/q3combobox.cpp	Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,2357 @@
+/****************************************************************************
+**
+** 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 "q3combobox.h"
+#ifndef QT_NO_COMBOBOX
+#include "qpainter.h"
+#include "qdrawutil.h"
+#include "qpixmap.h"
+#include "qtimer.h"
+#include "qapplication.h"
+#include "qlineedit.h"
+#include "qbitmap.h"
+#include "qstringlist.h"
+#include "qstyle.h"
+#include "qevent.h"
+#include "qmenu.h"
+#include "qmenudata.h"
+#include "qstyleoption.h"
+#include "qdesktopwidget.h"
+#include "q3popupmenu.h"
+#include "q3listbox.h"
+#include "q3strlist.h"
+#include "q3frame.h"
+#include <limits.h>
+#include <qdebug.h>
+#ifndef QT_NO_EFFECTS
+# include <private/qeffects_p.h>
+#endif
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+#include "qaccessible.h"
+#endif
+
+QT_BEGIN_NAMESPACE
+
+/*!
+    \class Q3ComboBox
+    \brief The Q3ComboBox widget is a combined button and popup list.
+    \since 4.1
+    \compat
+
+    A combobox is a selection widget which displays the current item
+    and can pop up a list of items. A combobox may be editable in
+    which case the user can enter arbitrary strings.
+
+    Comboboxes provide a means of showing the user's current choice
+    out of a list of options in a way that takes up the minimum amount
+    of screen space.
+
+    Q3ComboBox supports three different display styles: Aqua/Motif 1.x,
+    Motif 2.0 and Windows. In Motif 1.x, a combobox was called
+    XmOptionMenu. In Motif 2.0, OSF introduced an improved combobox
+    and named that XmComboBox. Q3ComboBox provides both.
+
+    Q3ComboBox provides two different constructors. The simplest
+    constructor creates an "old-style" combobox in Motif (or Aqua)
+    style:
+    \snippet doc/src/snippets/code/src_qt3support_widgets_q3combobox.cpp 0
+
+    The other constructor creates a new-style combobox in Motif style,
+    and can create both read-only and editable comboboxes:
+    \snippet doc/src/snippets/code/src_qt3support_widgets_q3combobox.cpp 1
+
+    New-style comboboxes use a list box in both Motif and Windows
+    styles, and both the content size and the on-screen size of the
+    list box can be limited with sizeLimit() and setMaxCount()
+    respectively. Old-style comboboxes use a popup in Aqua and Motif
+    style, and that popup will happily grow larger than the desktop if
+    you put enough data into it.
+
+    The two constructors create identical-looking comboboxes in
+    Windows style.
+
+    Comboboxes can contain pixmaps as well as strings; the
+    insertItem() and changeItem() functions are suitably overloaded.
+    For editable comboboxes, the function clearEdit() is provided,
+    to clear the displayed string without changing the combobox's
+    contents.
+
+    A combobox emits two signals, activated() and highlighted(), when
+    a new item has been activated (selected) or highlighted (made
+    current). Both signals exist in two versions, one with a \c
+    QString argument and one with an \c int argument. If the user
+    highlights or activates a pixmap, only the \c int signals are
+    emitted. Whenever the text of an editable combobox is changed the
+    textChanged() signal is emitted.
+
+    When the user enters a new string in an editable combobox, the
+    widget may or may not insert it, and it can insert it in several
+    locations. The default policy is is \c AtBottom but you can change
+    this using setInsertionPolicy().
+
+    It is possible to constrain the input to an editable combobox
+    using QValidator; see setValidator(). By default, any input is
+    accepted.
+
+    If the combobox is not editable then it has a default
+    focusPolicy() of \c TabFocus, i.e. it will not grab focus if
+    clicked. This differs from both Windows and Motif. If the combobox
+    is editable then it has a default focusPolicy() of \c StrongFocus,
+    i.e. it will grab focus if clicked.
+
+    A combobox can be populated using the insert functions,
+    insertStringList() and insertItem() for example. Items can be
+    changed with changeItem(). An item can be removed with
+    removeItem() and all items can be removed with clear(). The text
+    of the current item is returned by currentText(), and the text of
+    a numbered item is returned with text(). The current item can be
+    set with setCurrentItem() or setCurrentText(). The number of items
+    in the combobox is returned by count(); the maximum number of
+    items can be set with setMaxCount(). You can allow editing using
+    setEditable(). For editable comboboxes you can set auto-completion
+    using setAutoCompletion() and whether or not the user can add
+    duplicates is set with setDuplicatesEnabled().
+
+    Depending on the style, Q3ComboBox will use a list box or a
+    popup menu to display the list of items. See setListBox() for
+    more information.
+
+    \sa QComboBox, QLineEdit, QSpinBox
+        {GUI Design Handbook}{GUI Design Handbook: Combo Box, Drop-Down List Box}
+*/
+
+
+/*!
+    \enum Q3ComboBox::Policy
+
+    This enum specifies what the Q3ComboBox should do when a new string
+    is entered by the user.
+
+    \value NoInsertion the string will not be inserted into the
+    combobox.
+
+    \value AtTop insert the string as the first item in the combobox.
+
+    \value AtCurrent replace the previously selected item with the
+    string the user has entered.
+
+    \value AtBottom insert the string as the last item in the
+    combobox.
+
+    \value AfterCurrent insert the string after the previously
+    selected item.
+
+    \value BeforeCurrent insert the string before the previously
+    selected item.
+
+    activated() is always emitted when the string is entered.
+
+    If inserting the new string would cause the combobox to breach its
+    content size limit, the item at the other end of the list is
+    deleted. The definition of "other end" is
+    implementation-dependent.
+
+    \omitvalue NoInsert
+    \omitvalue InsertAtTop
+    \omitvalue InsertAtCurrent
+    \omitvalue InsertAtBottom
+    \omitvalue InsertAfterCurrent
+    \omitvalue InsertBeforeCurrent
+*/
+
+
+/*!
+    \fn void Q3ComboBox::activated( int index )
+
+    This signal is emitted when a new item has been activated
+    (selected). The \a index is the position of the item in the
+    combobox.
+
+    This signal is not emitted if the item is changed
+    programmatically, e.g. using setCurrentItem().
+*/
+
+/*!
+    \overload
+    \fn void Q3ComboBox::activated( const QString &string )
+
+    This signal is emitted when a new item has been activated
+    (selected). \a string is the selected string.
+
+    You can also use the activated(int) signal, but be aware that its
+    argument is meaningful only for selected strings, not for user
+    entered strings.
+*/
+
+/*!
+    \fn void Q3ComboBox::highlighted( int index )
+
+    This signal is emitted when a new item has been set to be the
+    current item. The \a index is the position of the item in the
+    combobox.
+
+    This signal is not emitted if the item is changed
+    programmatically, e.g. using setCurrentItem().
+*/
+
+/*!
+    \overload
+    \fn void Q3ComboBox::highlighted( const QString &string )
+
+    This signal is emitted when a new item has been set to be the
+    current item. \a string is the item's text.
+
+    You can also use the highlighted(int) signal.
+*/
+
+/*!
+    \fn void Q3ComboBox::textChanged( const QString &string )
+
+    This signal is used for editable comboboxes. It is emitted
+    whenever the contents of the text entry field changes. \a string
+    contains the new text.
+*/
+
+/*!
+    \property Q3ComboBox::autoCompletion
+    \brief whether auto-completion is enabled
+
+    This property can only be set for editable comboboxes, for
+    non-editable comboboxes it has no effect. It is false by default.
+*/
+
+/*!
+    \property Q3ComboBox::autoResize
+    \brief whether auto-resize is enabled
+    \obsolete
+
+    If this property is set to true then the combobox will resize
+    itself whenever its contents change. The default is false.
+*/
+
+/*!
+    \property Q3ComboBox::count
+    \brief the number of items in the combobox
+*/
+
+/*!
+    \property Q3ComboBox::currentItem
+    \brief the index of the current item in the combobox
+
+    Note that the activated() and highlighted() signals are only
+    emitted when the user changes the current item, not when it is
+    changed programmatically.
+*/
+
+/*!
+    \property Q3ComboBox::currentText
+    \brief the text of the combobox's current item
+*/
+
+/*!
+    \property Q3ComboBox::duplicatesEnabled
+    \brief whether duplicates are allowed
+
+    If the combobox is editable and the user enters some text in the
+    combobox's lineedit and presses Enter (and the insertionPolicy()
+    is not \c NoInsertion), then what happens is this:
+    \list
+    \i If the text is not already in the list, the text is inserted.
+    \i If the text is in the list and this property is true (the
+    default), the text is inserted.
+    \i If the text is in the list and this property is false, the text
+    is \e not inserted; instead the item which has matching text becomes
+    the current item.
+    \endlist
+
+    This property only affects user-interaction. You can use
+    insertItem() to insert duplicates if you wish regardless of this
+    setting.
+*/
+
+/*!
+    \property Q3ComboBox::editable
+    \brief whether the combobox is editable
+
+    This property's default is false. Note that the combobox will be
+    cleared if this property is set to true for a 1.x Motif style
+    combobox. To avoid this, use setEditable() before inserting any
+    items. Also note that the 1.x version of Motif didn't have any
+    editable comboboxes, so the combobox will change its appearance
+    to a 2.0 style Motif combobox is it is set to be editable.
+*/
+
+/*!
+    \property Q3ComboBox::insertionPolicy
+    \brief the position of the items inserted by the user
+
+    The default insertion policy is \c AtBottom. See \l Policy.
+*/
+
+/*!
+    \property Q3ComboBox::maxCount
+    \brief the maximum number of items allowed in the combobox
+*/
+
+/*!
+    \property Q3ComboBox::sizeLimit
+    \brief the maximum on-screen size of the combobox.
+
+    This property is ignored for both Motif 1.x style and non-editable
+    comboboxes in Mac style. The default limit is ten
+    lines. If the number of items in the combobox is or grows larger
+    than lines, a scroll bar is added.
+*/
+
+class Q3ComboBoxPopup : public Q3PopupMenu
+{
+public:
+    Q3ComboBoxPopup( QWidget *parent=0, const char *name=0 )
+	: Q3PopupMenu( parent, name )
+    {
+    }
+
+    int itemHeight( int index )
+    {
+	return Q3PopupMenu::itemHeight( index );
+    }
+};
+
+static inline QString escapedComboString(const QString &str)
+{
+    QString stringToReturn = str;
+    return stringToReturn.replace(QLatin1Char('&'), QLatin1String("&&"));
+}
+
+class Q3ComboBoxPopupItem : public QMenuItem
+{
+    Q3ListBoxItem *li;
+    QSize sc; // Size cache optimization
+public:
+    Q3ComboBoxPopupItem(Q3ListBoxItem *i) : QMenuItem(), li(i), sc(0, 0) {  }
+    virtual bool fullSpan() const { return true; }
+    virtual void paint( QPainter*, const QColorGroup&, bool, bool, int, int, int, int);
+    virtual QSize sizeHint() { if (sc.isNull()) sc = QSize(li->width(li->listBox()), QMAX(25, li->height(li->listBox()))); return sc; }
+};
+void Q3ComboBoxPopupItem::paint( QPainter* p, const QColorGroup&, bool,
+				bool, int x, int y, int, int)
+{
+    p->save();
+    p->translate(x, y + ((sizeHint().height() / 2) - (li->height(li->listBox()) / 2)));
+    li->paint(p);
+    p->restore();
+}
+
+
+class Q3ComboBoxData
+{
+public:
+    Q3ComboBoxData( Q3ComboBox *cb ): current( 0 ), arrowDown(false), ed( 0 ), usingLBox( false ), pop( 0 ), lBox( 0 ), combo( cb )
+    {
+	duplicatesEnabled = true;
+	cb->setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed ) );
+    }
+
+    inline bool usingListBox()  { return usingLBox; }
+    inline Q3ListBox * listBox() { return lBox; }
+    inline Q3ComboBoxPopup * popup() { return pop; }
+    void updateLinedGeometry();
+
+    void setListBox( Q3ListBox *l ) { lBox = l ; usingLBox = true;
+				l->setMouseTracking( true );}
+
+    void setPopupMenu( Q3ComboBoxPopup * pm, bool isPopup=true )
+	{ pop = pm; if(isPopup) usingLBox = false; }
+
+    QStyleOptionComboBox getStyleOption() const
+        {
+            QStyleOptionComboBox opt;
+            opt.init(combo);
+            if (!combo->editable() && combo->hasFocus())
+                opt.state |= QStyle::State_Selected;
+            opt.subControls = QStyle::SC_All;
+            if (arrowDown) {
+                opt.activeSubControls = QStyle::SC_ComboBoxArrow;
+                opt.state |= QStyle::State_Sunken;
+            }
+            opt.editable = combo->editable();
+            opt.frame = 1; // ### get from style?
+            if (current > -1 && current < combo->count()) {
+                opt.currentText = combo->text(current);
+                if (combo->pixmap(current))
+                    opt.currentIcon = QIcon(*combo->pixmap(current));
+            }
+            opt.iconSize = QSize(22, 22); // ### need a sane value here
+//             if (container && container->isVisible())
+//                 opt.state |= QStyle::State_On;
+            return opt;
+        }
+
+    int		current;
+    int		maxCount;
+    int		sizeLimit;
+    Q3ComboBox::Policy p;
+    bool	autoresize;
+    bool	poppedUp;
+    bool	mouseWasInsidePopup;
+    bool	arrowPressed;
+    bool	arrowDown;
+    bool	discardNextMousePress;
+    bool	shortClick;
+    bool	useCompletion;
+    bool	completeNow;
+    int		completeAt;
+    bool duplicatesEnabled;
+    int fullHeight, currHeight;
+
+    QLineEdit * ed;  // /bin/ed rules!
+    QTimer *completionTimer;
+
+    QSize sizeHint;
+    QHash<int, QPixmap> popupPixmaps;
+
+private:
+    bool	usingLBox;
+    Q3ComboBoxPopup *pop;
+    Q3ListBox   *lBox;
+    Q3ComboBox *combo;
+};
+
+void Q3ComboBoxData::updateLinedGeometry()
+{
+    if ( !ed || !combo )
+	return;
+
+    QStyleOptionComboBox opt = getStyleOption();
+    QRect r = combo->style()->subControlRect(
+        QStyle::CC_ComboBox, &opt, QStyle::SC_ComboBoxEditField, combo);
+
+    const QPixmap *pix = current < combo->count() ? combo->pixmap( current ) : 0;
+    if ( pix && pix->width() < r.width() )
+	r.setLeft( r.left() + pix->width() + 4 );
+    if ( r != ed->geometry() )
+	ed->setGeometry( r );
+}
+
+static inline bool checkInsertIndex( const char *method, const char * name,
+				     int count, int *index)
+{
+    bool range_err = (*index > count);
+#if defined(QT_CHECK_RANGE)
+    if ( range_err )
+	qWarning( "Q3ComboBox::%s: (%s) Index %d out of range",
+		 method, name ? name : "<no name>", *index );
+#else
+    Q_UNUSED( method )
+    Q_UNUSED( name )
+#endif
+    if ( *index < 0 )				// append
+	*index = count;
+    return !range_err;
+}
+
+
+static inline bool checkIndex( const char *method, const char * name,
+			       int count, int index )
+{
+    bool range_err = (index >= count);
+#if defined(QT_CHECK_RANGE)
+    if ( range_err )
+	qWarning( "Q3ComboBox::%s: (%s) Index %i out of range",
+		 method, name ? name : "<no name>", index );
+#else
+    Q_UNUSED( method )
+    Q_UNUSED( name )
+#endif
+    return !range_err;
+}
+
+
+
+/*!
+    Constructs a combobox widget with parent \a parent called \a name.
+
+    This constructor creates a popup list if the program uses Motif
+    (or Aqua) look and feel; this is compatible with Motif 1.x and
+    Aqua.
+
+    Note: If you use this constructor to create your Q3ComboBox, then
+    the pixmap() function will always return 0. To workaround this,
+    use the other constructor.
+
+*/
+
+
+
+Q3ComboBox::Q3ComboBox( QWidget *parent, const char *name )
+    : QWidget( parent, name, Qt::WNoAutoErase )
+{
+    d = new Q3ComboBoxData( this );
+    QStyleOptionComboBox opt;
+    opt.init(this);
+    if ( style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, this) ||
+	 style()->styleHint(QStyle::SH_GUIStyle, &opt, this) == Qt::MotifStyle ) {
+	d->setPopupMenu( new Q3ComboBoxPopup( this, "in-combo" ) );
+	d->popup()->setFont( font() );
+	connect( d->popup(), SIGNAL(activated(int)),
+			     SLOT(internalActivate(int)) );
+	connect( d->popup(), SIGNAL(highlighted(int)),
+			     SLOT(internalHighlight(int)) );
+    } else {
+	setUpListBox();
+    }
+    d->ed                    = 0;
+    d->current               = 0;
+    d->maxCount              = INT_MAX;
+    d->sizeLimit	     = 10;
+    d->p                     = AtBottom;
+    d->autoresize            = false;
+    d->poppedUp              = false;
+    d->arrowDown             = false;
+    d->arrowPressed          = false;
+    d->discardNextMousePress = false;
+    d->shortClick            = false;
+    d->useCompletion         = false;
+    d->completeAt            = 0;
+    d->completeNow           = false;
+    d->completionTimer       = new QTimer( this );
+
+    setFocusPolicy( Qt::TabFocus );
+    setBackgroundMode( Qt::PaletteButton );
+}
+
+
+/*!
+    Constructs a combobox with a maximum size and either Motif 2.0 or
+    Windows look and feel.
+
+    The input field can be edited if \a rw is true, otherwise the user
+    may only choose one of the items in the combobox.
+
+    The \a parent and \a name arguments are passed on to the QWidget
+    constructor.
+*/
+
+
+Q3ComboBox::Q3ComboBox( bool rw, QWidget *parent, const char *name )
+    : QWidget( parent, name, Qt::WNoAutoErase )
+{
+    d = new Q3ComboBoxData( this );
+    setUpListBox();
+
+    QStyleOptionComboBox opt = d->getStyleOption();
+    if(d->popup() && style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, this))
+	d->popup()->setItemChecked(d->current, false);
+    d->maxCount = INT_MAX;
+    setSizeLimit(10);
+    d->p = AtBottom;
+    d->autoresize = false;
+    d->poppedUp = false;
+    d->arrowDown = false;
+    d->discardNextMousePress = false;
+    d->shortClick = false;
+    d->useCompletion = false;
+    d->completeAt = 0;
+    d->completeNow = false;
+    d->completionTimer = new QTimer( this );
+
+    setFocusPolicy( Qt::StrongFocus );
+
+    d->ed = 0;
+    if ( rw )
+	setUpLineEdit();
+    setBackgroundMode( Qt::PaletteButton, Qt::PaletteBase );
+}
+
+
+
+/*!
+    Destroys the combobox.
+*/
+
+Q3ComboBox::~Q3ComboBox()
+{
+    delete d;
+}
+
+void Q3ComboBox::setDuplicatesEnabled( bool enable )
+{
+   d->duplicatesEnabled = enable;
+}
+
+bool Q3ComboBox::duplicatesEnabled() const
+{
+    return d->duplicatesEnabled;
+}
+
+int Q3ComboBox::count() const
+{
+    if ( d->usingListBox() )
+	return d->listBox()->count();
+    else if (d->popup())
+	return d->popup()->count();
+    else
+        return 0;
+}
+
+
+/*!
+    \overload
+
+    Inserts the \a list of strings at position \a index in the
+    combobox.
+
+    This is only for compatibility since it does not support Unicode
+    strings. See insertStringList().
+*/
+
+void Q3ComboBox::insertStrList( const Q3StrList &list, int index )
+{
+    insertStrList( &list, index );
+}
+
+/*!
+    \overload
+
+    Inserts the \a list of strings at position \a index in the
+    combobox.
+
+    This is only for compatibility since it does not support Unicode
+    strings. See insertStringList().
+*/
+
+void Q3ComboBox::insertStrList( const Q3StrList *list, int index )
+{
+    if ( !list ) {
+#if defined(QT_CHECK_NULL)
+	Q_ASSERT( list != 0 );
+#endif
+	return;
+    }
+    Q3StrListIterator it( *list );
+    const char* tmp;
+    if ( index < 0 )
+	index = count();
+    while ( (tmp=it.current()) ) {
+	++it;
+	if ( d->usingListBox() )
+	    d->listBox()->insertItem( QString::fromLatin1(tmp), index );
+	else
+	    d->popup()->insertItem( escapedComboString(QString::fromLatin1(tmp)), index, index );
+	if ( index++ == d->current && d->current < count() ) {
+	    if ( d->ed ) {
+		d->ed->setText( text( d->current ) );
+		d->updateLinedGeometry();
+	    } else
+		update();
+	    currentChanged();
+	}
+    }
+    if ( index != count() )
+	reIndex();
+}
+
+/*!
+    Inserts the \a list of strings at position \a index in the
+    combobox.
+*/
+
+void Q3ComboBox::insertStringList( const QStringList &list, int index )
+{
+    QStringList::ConstIterator it = list.begin();
+    if ( index < 0 )
+	index = count();
+    while ( it != list.end() ) {
+	if ( d->usingListBox() )
+	    d->listBox()->insertItem( *it, index );
+	else
+	    d->popup()->insertItem( escapedComboString(*it), index, index );
+	if ( index++ == d->current && d->current < count() ) {
+	    if ( d->ed ) {
+		d->ed->setText( text( d->current ) );
+		d->updateLinedGeometry();
+	    } else
+		update();
+	    currentChanged();
+	}
+	++it;
+    }
+    if ( index != count() )
+	reIndex();
+}
+
+/*!
+    Inserts the array of char * \a strings at position \a index in the
+    combobox.
+
+    The \a numStrings argument is the number of strings. If \a
+    numStrings is -1 (default), the \a strings array must be
+    terminated with 0.
+
+    Example:
+    \snippet doc/src/snippets/code/src_qt3support_widgets_q3combobox.cpp 2
+
+    \sa insertStringList()
+*/
+
+void Q3ComboBox::insertStrList( const char **strings, int numStrings, int index)
+{
+    if ( !strings ) {
+#if defined(QT_CHECK_NULL)
+	Q_ASSERT( strings != 0 );
+#endif
+	return;
+    }
+    if ( index < 0 )
+	index = count();
+    int i = 0;
+    while ( (numStrings<0 && strings[i]!=0) || i<numStrings ) {
+	if ( d->usingListBox() )
+	    d->listBox()->insertItem( QString::fromLatin1(strings[i]), index );
+	else
+	    d->popup()->insertItem( escapedComboString(QString::fromLatin1(strings[i])), index, index );
+	i++;
+	if ( index++ == d->current && d->current < count()  ) {
+	    if ( d->ed ) {
+		d->ed->setText( text( d->current ) );
+		d->updateLinedGeometry();
+	    } else
+		update();
+	    currentChanged();
+	}
+    }
+    if ( index != count() )
+	reIndex();
+}
+
+
+/*!
+    Inserts a text item with text \a t, at position \a index. The item
+    will be appended if \a index is negative.
+*/
+
+void Q3ComboBox::insertItem( const QString &t, int index )
+{
+    int cnt = count();
+    if ( !checkInsertIndex( "insertItem", name(), cnt, &index ) )
+	return;
+    if ( d->usingListBox() )
+	d->listBox()->insertItem( t, index );
+    else
+	d->popup()->insertItem( escapedComboString(t), index, index );
+    if ( index != cnt )
+	reIndex();
+    if ( index == d->current && d->current < count()  ) {
+	if ( d->ed ) {
+	    d->ed->setText( text( d->current ) );
+	    d->updateLinedGeometry();
+	} else
+	    update();
+    }
+    if ( index == d->current )
+	currentChanged();
+}
+
+/*!
+    \overload
+
+    Inserts a \a pixmap item at position \a index. The item will be
+    appended if \a index is negative.
+*/
+
+void Q3ComboBox::insertItem( const QPixmap &pixmap, int index )
+{
+    int cnt = count();
+    if ( !checkInsertIndex( "insertItem", name(), cnt, &index ) )
+	return;
+    if ( d->usingListBox() )
+	d->listBox()->insertItem( pixmap, index );
+    else
+	d->popup()->insertItem( pixmap, index, index );
+    if ( index != cnt )
+	reIndex();
+    if ( index == d->current && d->current < count()  ) {
+	if ( d->ed ) {
+	    d->ed->setText( text( d->current ) );
+	    d->updateLinedGeometry();
+	} else
+	    update();
+    }
+    if ( index == d->current )
+	currentChanged();
+}
+
+/*!
+    \overload
+
+    Inserts a \a pixmap item with additional text \a text at position
+    \a index. The item will be appended if \a index is negative.
+*/
+
+void Q3ComboBox::insertItem( const QPixmap &pixmap, const QString& text, int index )
+{
+    int cnt = count();
+    if ( !checkInsertIndex( "insertItem", name(), cnt, &index ) )
+	return;
+    if ( d->usingListBox() )
+	d->listBox()->insertItem( pixmap, text, index );
+    else
+	d->popup()->insertItem( pixmap, escapedComboString(text), index, index );
+    if ( index != cnt )
+	reIndex();
+    if ( index == d->current && d->current < count()  ) {
+	if ( d->ed ) {
+	    d->ed->setText( this->text( d->current ) );
+	    d->updateLinedGeometry();
+	} else
+	    update();
+    }
+    if ( index == d->current )
+	currentChanged();
+}
+
+
+/*!
+    Removes the item at position \a index.
+*/
+
+void Q3ComboBox::removeItem( int index )
+{
+    int cnt = count();
+    if ( !checkIndex( "removeItem", name(), cnt, index ) )
+	return;
+    if ( d->usingListBox() ) {
+        QStyleOptionComboBox opt = d->getStyleOption();
+	if ( style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, this) && d->popup() )
+	    d->popup()->removeItemAt( index );
+	d->listBox()->removeItem( index );
+    } else {
+	d->popup()->removeItemAt( index );
+    }
+    if ( index != cnt-1 )
+	reIndex();
+    if ( index == d->current ) {
+	if ( d->ed ) {
+	    QString s = QString::fromLatin1("");
+	    if (d->current < cnt - 1)
+		s = text( d->current );
+	    d->ed->setText( s );
+	    d->updateLinedGeometry();
+	}
+	else {
+	    if ( d->usingListBox() ) {
+		d->current = d->listBox()->currentItem();
+	    } else {
+		if (d->current > count()-1 && d->current > 0)
+		    d->current--;
+	    }
+	    update();
+	}
+	currentChanged();
+    }
+    else {
+	if ( !d->ed ) {
+	    if (d->current < cnt - 1)
+		setCurrentItem( d->current );
+	    else
+		setCurrentItem( d->current - 1 );
+	}
+    }
+
+}
+
+
+/*!
+    Removes all combobox items.
+*/
+
+void Q3ComboBox::clear()
+{
+    QStyleOptionComboBox opt = d->getStyleOption();
+    if ( d->usingListBox() ) {
+	if ( style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, this) && d->popup() )
+	    d->popup()->clear();
+	d->listBox()->resize( 0, 0 );
+	d->listBox()->clear();
+    } else {
+	d->popup()->clear();
+    }
+
+    if(d->popup() && style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, this))
+	d->popup()->setItemChecked(d->current, false);
+    d->current = 0;
+    if ( d->ed ) {
+	d->ed->setText( QString::fromLatin1("") );
+	d->updateLinedGeometry();
+    }
+    currentChanged();
+}
+
+
+QString Q3ComboBox::currentText() const
+{
+    if ( d->ed )
+	return d->ed->text();
+    else if ( d->current < count() )
+	return text( currentItem() );
+    else
+	return QString::null;
+}
+
+void Q3ComboBox::setCurrentText( const QString& txt )
+{
+    int i;
+    for ( i = 0; i < count(); i++)
+	if ( text( i ) == txt )
+	    break;
+    if ( i < count() )
+	setCurrentItem( i );
+    else if ( d->ed )
+	d->ed->setText( txt );
+    else
+	changeItem( txt, currentItem() );
+}
+
+
+/*!
+    Returns the text item at position \a index, or QString::null if
+    the item is not a string.
+
+    \sa currentText()
+*/
+
+QString Q3ComboBox::text( int index ) const
+{
+    if ( !checkIndex( "text", name(), count(), index ) )
+	return QString::null;
+    if ( d->usingListBox() ) {
+	return d->listBox()->text( index );
+    } else {
+        QString retText = d->popup()->text(index);
+        retText.replace(QLatin1String("&&"), QString(QLatin1Char('&')));
+	return retText;
+    }
+}
+
+/*!
+    Returns the pixmap item at position \a index, or 0 if the item is
+    not a pixmap.
+*/
+
+const QPixmap *Q3ComboBox::pixmap( int index ) const
+{
+    if ( !checkIndex( "pixmap", name(), count(), index ) )
+	return 0;
+
+    if (d->usingListBox()) {
+        return d->listBox()->pixmap( index );
+    } else {
+        d->popupPixmaps[index] = d->popup()->pixmap(index);
+        return d->popupPixmaps[index].isNull() ? 0 : &d->popupPixmaps[index];
+    }
+}
+
+/*!
+    Replaces the item at position \a index with the text \a t.
+*/
+
+void Q3ComboBox::changeItem( const QString &t, int index )
+{
+    if ( !checkIndex( "changeItem", name(), count(), index ) )
+	return;
+    if ( d->usingListBox() )
+	d->listBox()->changeItem( t, index );
+    else
+	d->popup()->changeItem(index, t);
+    if ( index == d->current ) {
+	if ( d->ed ) {
+	    d->ed->setText( text( d->current ) );
+	    d->updateLinedGeometry();
+	} else
+	    update();
+    }
+}
+
+/*!
+    \overload
+
+    Replaces the item at position \a index with the pixmap \a im,
+    unless the combobox is editable.
+
+    \sa insertItem()
+*/
+
+void Q3ComboBox::changeItem( const QPixmap &im, int index )
+{
+    if ( !checkIndex( "changeItem", name(), count(), index ) )
+	return;
+    if ( d->usingListBox() )
+	d->listBox()->changeItem( im, index );
+    else
+	d->popup()->changeItem(index, im);
+    if ( index == d->current )
+	update();
+}
+
+/*!
+    \overload
+
+    Replaces the item at position \a index with the pixmap \a im and
+    the text \a t.
+
+    \sa insertItem()
+*/
+
+void Q3ComboBox::changeItem( const QPixmap &im, const QString &t, int index )
+{
+    if ( !checkIndex( "changeItem", name(), count(), index ) )
+	return;
+    if ( d->usingListBox() )
+	d->listBox()->changeItem( im, t, index );
+    else
+	d->popup()->changeItem(index, im, t);
+    if ( index == d->current )
+	update();
+}
+
+
+int Q3ComboBox::currentItem() const
+{
+    return d->current;
+}
+
+void Q3ComboBox::setCurrentItem( int index )
+{
+    if ( index == d->current && !d->ed ) {
+	return;
+    }
+    if ( !checkIndex( "setCurrentItem", name(), count(), index ) ) {
+	return;
+    }
+
+    if ( d->usingListBox() && !( listBox()->item(index) && listBox()->item(index)->isSelectable() ) )
+	return;
+
+    QStyleOptionComboBox opt = d->getStyleOption();
+    if(d->popup() && style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, this))
+	d->popup()->setItemChecked(d->current, false);
+    d->current = index;
+    d->completeAt = 0;
+    if ( d->ed ) {
+	d->ed->setText( text( index ) );
+	d->updateLinedGeometry();
+    }
+    // ### We want to keep ListBox's currentItem in sync, even if NOT popuped...
+    if ( d->usingListBox() && d->listBox() ) {
+	d->listBox()->setCurrentItem( index );
+    } else {
+	internalHighlight( index );
+	// internalActivate( index ); ### this leads to weird behavior, as in 3.0.1
+    }
+
+    currentChanged();
+}
+
+/*!
+    Returns true if auto-resize is enabled; otherwise returns false.
+
+    \sa autoResize
+*/
+
+bool Q3ComboBox::autoResize() const
+{
+    return d->autoresize;
+}
+
+/*!
+    If \a enable is true, enable auto-resize; disable it otherwise.
+
+    \sa autoResize
+*/
+
+void Q3ComboBox::setAutoResize( bool enable )
+{
+    if ( (bool)d->autoresize != enable ) {
+	d->autoresize = enable;
+	if ( enable )
+	    adjustSize();
+    }
+}
+
+
+/*!
+    \reimp
+
+    This implementation caches the size hint to avoid resizing when
+    the contents change dynamically. To invalidate the cached value
+    call setFont().
+*/
+QSize Q3ComboBox::sizeHint() const
+{
+    if ( isVisible() && d->sizeHint.isValid() )
+	return d->sizeHint;
+
+    constPolish();
+    int i, w;
+    QFontMetrics fm = fontMetrics();
+
+    int maxW = count() ? 18 : 7 * fm.width(QLatin1Char('x')) + 18;
+    int maxH = QMAX( fm.lineSpacing(), 14 ) + 2;
+
+    if ( !d->usingListBox() ) {
+	w = d->popup()->sizeHint().width() - 2* d->popup()->frameWidth();
+	if ( w > maxW )
+	    maxW = w;
+    } else {
+	for( i = 0; i < count(); i++ ) {
+	    w = d->listBox()->item( i )->width( d->listBox() );
+	    if ( w > maxW )
+		maxW = w;
+	}
+    }
+
+    QStyleOptionComboBox opt = d->getStyleOption();
+    d->sizeHint = (style()->sizeFromContents(QStyle::CT_ComboBox, &opt, QSize(maxW, maxH), this).
+                   expandedTo(QApplication::globalStrut()));
+
+    return d->sizeHint;
+}
+
+
+/*!
+  \internal
+  Receives activated signals from an internal popup list and emits
+  the activated() signal.
+*/
+
+void Q3ComboBox::internalActivate( int index )
+{
+    QStyleOptionComboBox opt = d->getStyleOption();
+    if ( d->current != index ) {
+	if ( !d->usingListBox() || listBox()->item( index )->isSelectable() ) {
+	    if (d->popup() && style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, this))
+		d->popup()->setItemChecked(d->current, false);
+	    d->current = index;
+	    currentChanged();
+	}
+    }
+    if ( d->usingListBox() )
+	popDownListBox();
+    else
+	d->popup()->removeEventFilter( this );
+    d->poppedUp = false;
+
+    QString t( text( index ) );
+    if ( d->ed ) {
+	d->ed->setText( t );
+	d->updateLinedGeometry();
+    }
+    emit activated( index );
+    emit activated( t );
+}
+
+/*!
+  \internal
+  Receives highlighted signals from an internal popup list and emits
+  the highlighted() signal.
+*/
+
+void Q3ComboBox::internalHighlight( int index )
+{
+    emit highlighted( index );
+    QString t = text( index );
+    if ( !t.isNull() )
+	emit highlighted( t );
+}
+
+/*!
+  \internal
+  Receives timeouts after a click. Used to decide if a Motif style
+  popup should stay up or not after a click.
+*/
+void Q3ComboBox::internalClickTimeout()
+{
+    d->shortClick = false;
+}
+
+/*!
+    Sets the palette for both the combobox button and the combobox
+    popup list to \a palette.
+*/
+
+void Q3ComboBox::setPalette( const QPalette &palette )
+{
+    QWidget::setPalette( palette );
+    if ( d->listBox() )
+	d->listBox()->setPalette( palette );
+    if ( d->popup() )
+	d->popup()->setPalette( palette );
+}
+
+/*!
+    Sets the font for both the combobox button and the combobox popup
+    list to \a font.
+*/
+
+void Q3ComboBox::setFont( const QFont &font )
+{
+    d->sizeHint = QSize();		// invalidate size hint
+    QWidget::setFont( font );
+    if ( d->usingListBox() )
+	d->listBox()->setFont( font );
+    else
+	d->popup()->setFont( font );
+    if (d->ed)
+	d->ed->setFont( font );
+    if ( d->autoresize )
+	adjustSize();
+}
+
+
+/*!\reimp
+*/
+
+void Q3ComboBox::resizeEvent( QResizeEvent * e )
+{
+    if ( d->ed )
+	d->updateLinedGeometry();
+    if ( d->listBox() )
+	d->listBox()->resize( width(), d->listBox()->height() );
+    QWidget::resizeEvent( e );
+}
+
+/*!\reimp
+*/
+
+void Q3ComboBox::paintEvent( QPaintEvent * )
+{
+    QPainter p( this );
+    const QColorGroup & g = colorGroup();
+    p.setPen(g.text());
+
+    if ( width() < 5 || height() < 5 ) {
+	qDrawShadePanel( &p, rect(), g, false, 2,
+			 &g.brush( QColorGroup::Button ) );
+	return;
+    }
+
+    QStyleOptionComboBox opt = d->getStyleOption();
+    bool reverse = QApplication::reverseLayout();
+    if ( !d->usingListBox() &&
+	 style()->styleHint(QStyle::SH_GUIStyle) == Qt::MotifStyle) {			// motif 1.x style
+	int dist, buttonH, buttonW;
+	dist     = 8;
+	buttonH  = 7;
+	buttonW  = 11;
+	int xPos;
+	int x0;
+	int w = width() - dist - buttonW - 1;
+	if ( reverse ) {
+	    xPos = dist + 1;
+	    x0 = xPos + 4;
+	} else {
+	    xPos = w;
+	    x0 = 4;
+	}
+	qDrawShadePanel( &p, rect(), g, false,
+			 style()->pixelMetric(QStyle::PM_DefaultFrameWidth, &opt, this),
+			 &g.brush( QColorGroup::Button ) );
+	qDrawShadePanel( &p, xPos, (height() - buttonH)/2,
+			 buttonW, buttonH, g, false,
+			 style()->pixelMetric(QStyle::PM_DefaultFrameWidth, &opt, this) );
+	QRect clip( x0, 2, w - 2 - 4 - 5, height() - 4 );
+	QString str = d->popup()->text( this->d->current );
+	if ( !str.isNull() ) {
+	    p.drawText( clip, Qt::AlignCenter | Qt::TextSingleLine, str );
+	}
+
+	QPixmap pix = d->popup()->pixmap( this->d->current );
+	QIcon iconSet = d->popup()->iconSet( this->d->current );
+	if (!pix.isNull() || !iconSet.isNull()) {
+	    QPixmap pm = ( !pix.isNull() ? pix : iconSet.pixmap() );
+	    p.setClipRect( clip );
+	    p.drawPixmap( 4, (height()-pm.height())/2, pm );
+	    p.setClipping( false );
+	}
+
+	if ( hasFocus() )
+	    p.drawRect( xPos - 5, 4, width() - xPos + 1 , height() - 8 );
+    } else if(!d->usingListBox()) {
+	style()->drawComplexControl(QStyle::CC_ComboBox, &opt, &p, this);
+        QRect re = style()->subControlRect(QStyle::CC_ComboBox, &opt,
+                                           QStyle::SC_ComboBoxEditField, this);
+	p.setClipRect( re );
+
+	QString str = d->popup()->text( this->d->current );
+	QPixmap pix = d->popup()->pixmap( this->d->current );
+	if ( !str.isNull() ) {
+	    p.save();
+	    p.setFont(font());
+	    QFontMetrics fm(font());
+	    int x = re.x(), y = re.y() + fm.ascent();
+            x += pix.width() + 5;
+	    p.drawText( x, y, str );
+	    p.restore();
+	}
+	if (!pix.isNull()) {
+	    p.fillRect(re.x(), re.y(), pix.width() + 4, re.height(),
+                        colorGroup().brush(QColorGroup::Base));
+	    p.drawPixmap(re.x() + 2, re.y() + (re.height() - pix.height()) / 2, pix);
+	}
+    } else {
+	style()->drawComplexControl(QStyle::CC_ComboBox, &opt, &p, this);
+	QRect re = style()->subControlRect(QStyle::CC_ComboBox, &opt,
+                                            QStyle::SC_ComboBoxEditField, this);
+	p.setClipRect(re);
+
+	if ( !d->ed ) {
+	    Q3ListBoxItem * item = d->listBox()->item( d->current );
+	    if ( item ) {
+		int itemh = item->height( d->listBox() );
+		p.translate( re.x(), re.y() + (re.height() - itemh)/2  );
+		item->paint( &p );
+	    }
+	} else if ( d->listBox() && d->listBox()->item( d->current ) ) {
+	    Q3ListBoxItem * item = d->listBox()->item( d->current );
+	    const QPixmap *pix = item->pixmap();
+	    if ( pix ) {
+		p.fillRect( re.x(), re.y(), pix->width() + 4, re.height(),
+			    colorGroup().brush( QColorGroup::Base ) );
+		p.drawPixmap( re.x() + 2, re.y() +
+			      ( re.height() - pix->height() ) / 2, *pix );
+	    }
+	}
+	p.setClipping( false );
+    }
+}
+
+
+/*!\reimp
+*/
+
+void Q3ComboBox::mousePressEvent( QMouseEvent *e )
+{
+    if ( e->button() != Qt::LeftButton )
+	return;
+    if ( d->discardNextMousePress ) {
+	d->discardNextMousePress = false;
+	return;
+    }
+
+    QStyleOptionComboBox opt = d->getStyleOption();
+    QRect arrowRect = style()->subControlRect(QStyle::CC_ComboBox, &opt, QStyle::SC_ComboBoxArrow
+                                               , this);
+
+    // Correction for motif style, where arrow is smaller
+    // and thus has a rect that doesn't fit the button.
+    arrowRect.setHeight( QMAX(  height() - (2 * arrowRect.y()), arrowRect.height() ) );
+
+    if ( count() && ( !editable() || arrowRect.contains( e->pos() ) ) ) {
+	d->arrowPressed = false;
+
+	if ( d->usingListBox() ) {
+	    listBox()->blockSignals( true );
+	    qApp->sendEvent( listBox(), e ); // trigger the listbox's autoscroll
+	    listBox()->setCurrentItem(d->current);
+	    listBox()->blockSignals( false );
+	    popup();
+	    if ( arrowRect.contains( e->pos() ) ) {
+		d->arrowPressed = true;
+		d->arrowDown    = true;
+		repaint( false );
+	    }
+	} else {
+	    popup();
+	}
+	QTimer::singleShot( 200, this, SLOT(internalClickTimeout()));
+	d->shortClick = true;
+    }
+}
+
+/*!\reimp
+*/
+
+void Q3ComboBox::mouseMoveEvent( QMouseEvent * )
+{
+}
+
+/*!\reimp
+*/
+
+void Q3ComboBox::mouseReleaseEvent( QMouseEvent * )
+{
+}
+
+/*!\reimp
+*/
+
+void Q3ComboBox::mouseDoubleClickEvent( QMouseEvent *e )
+{
+    mousePressEvent( e );
+}
+
+
+/*!\reimp
+*/
+
+void Q3ComboBox::keyPressEvent( QKeyEvent *e )
+{
+    bool handleEventHere = d->usingListBox() || !d->poppedUp;
+
+    int c = currentItem();
+    if ( ( e->key() == Qt::Key_F4 && e->state() == 0 ) ||
+	 ( e->key() == Qt::Key_Down && (e->state() & Qt::AltModifier) ) ||
+	 ( !d->ed && e->key() == Qt::Key_Space ) ) {
+	if ( count() ) {
+	    if ( !d->usingListBox() )
+		d->popup()->setActiveItem( this->d->current );
+	    popup();
+	}
+	return;
+    } else if ( handleEventHere && e->key() == Qt::Key_Up ) {
+	if ( c > 0 )
+	    setCurrentItem( c-1 );
+    } else if ( handleEventHere && e->key() == Qt::Key_Down ) {
+	if ( ++c < count() )
+	    setCurrentItem( c );
+    } else if ( handleEventHere && e->key() == Qt::Key_Home && ( !d->ed || !d->ed->hasFocus() ) ) {
+	setCurrentItem( 0 );
+    } else if ( handleEventHere && e->key() == Qt::Key_End && ( !d->ed || !d->ed->hasFocus() ) ) {
+	setCurrentItem( count()-1 );
+    } else if ( !d->ed && e->ascii() >= 32 && !e->text().isEmpty() ) {
+	if ( !d->completionTimer->isActive() ) {
+	    d->completeAt = 0;
+	    c = completionIndex( e->text(), ++c );
+	    if ( c >= 0 ) {
+		setCurrentItem( c );
+		d->completeAt = e->text().length();
+	    }
+	} else {
+	    d->completionTimer->stop();
+	    QString ct = currentText().left( d->completeAt ) + e->text();
+	    c = completionIndex( ct, c );
+	    if ( c < 0 && d->completeAt > 0 ) {
+		c = completionIndex( e->text(), 0 );
+		ct = e->text();
+	    }
+	    d->completeAt = 0;
+	    if ( c >= 0 ) {
+		setCurrentItem( c );
+		d->completeAt = ct.length();
+	    }
+	}
+	d->completionTimer->start( 400, true );
+    } else {
+	e->ignore();
+	return;
+    }
+
+    c = currentItem();
+    if ( count() && !text( c ).isNull() )
+	emit activated( text( c ) );
+    emit activated( c );
+}
+
+
+/*!\reimp
+*/
+
+void Q3ComboBox::focusInEvent( QFocusEvent * e )
+{
+    QWidget::focusInEvent( e );
+    d->completeNow = false;
+    d->completeAt = 0;
+}
+
+/*!\reimp
+*/
+
+void Q3ComboBox::focusOutEvent( QFocusEvent * e )
+{
+    QWidget::focusOutEvent( e );
+    d->completeNow = false;
+    d->completeAt = 0;
+}
+
+/*!\reimp
+*/
+#ifndef QT_NO_WHEELEVENT
+void Q3ComboBox::wheelEvent( QWheelEvent *e )
+{
+    if ( d->poppedUp ) {
+	if ( d->usingListBox() ) {
+	    QApplication::sendEvent( d->listBox(), e );
+	}
+    } else {
+	if ( e->delta() > 0 ) {
+	    int c = currentItem();
+	    if ( c > 0 ) {
+		setCurrentItem( c-1 );
+		emit activated( currentItem() );
+		emit activated( currentText() );
+	    }
+	} else {
+	    int c = currentItem();
+	    if ( ++c < count() ) {
+		setCurrentItem( c );
+		emit activated( currentItem() );
+		emit activated( currentText() );
+	    }
+	}
+	e->accept();
+    }
+}
+#endif
+
+/*!
+  \internal
+   Calculates the listbox height needed to contain all items, or as
+   many as the list box is supposed to contain.
+*/
+static int listHeight( Q3ListBox *l, int sl )
+{
+    if ( l->count() > 0 )
+	return QMIN( l->count(), (uint)sl) * l->item( 0 )->height(l);
+    else
+	return l->sizeHint().height();
+}
+
+
+/*!
+    Pops up the combobox popup list.
+
+    If the list is empty, no items appear.
+*/
+
+void Q3ComboBox::popup()
+{
+    if ( !count() || d->poppedUp )
+	return;
+
+    QStyleOptionComboBox opt = d->getStyleOption();
+    if( !d->usingListBox() || style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, this) ) {
+	if(d->usingListBox()) {
+	    if(!d->popup()) {
+		Q3ComboBoxPopup *p = new Q3ComboBoxPopup( this, "in-combo" );
+		d->setPopupMenu( p, false );
+		p->setFont( font() );
+		connect( p, SIGNAL(activated(int)), SLOT(internalActivate(int)) );
+		connect( p, SIGNAL(highlighted(int)), SLOT(internalHighlight(int)) );
+	    }
+	    d->popup()->clear();
+	    for(unsigned int i = 0; i < d->listBox()->count(); i++) {
+		Q3ListBoxItem *item = d->listBox()->item(i);
+		if(item->rtti() == Q3ListBoxText::RTTI) {
+		    d->popup()->insertItem(escapedComboString(item->text()), i, i);
+		} else if(item->rtti() == Q3ListBoxPixmap::RTTI) {
+		    if(item->pixmap())
+			d->popup()->insertItem(QIcon(*item->pixmap()), escapedComboString(item->text()), i, i);
+		    else
+			d->popup()->insertItem(escapedComboString(item->text()), i, i);
+		} else {
+		    d->popup()->insertItem(new Q3ComboBoxPopupItem(item), i, i);
+		}
+	    }
+	}
+	d->popup()->installEventFilter( this );
+	if(d->popup() && style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, this))
+	    d->popup()->setItemChecked(this->d->current, true);
+	d->popup()->popup( mapToGlobal( QPoint(0,0) ), this->d->current );
+	update();
+    } else {
+	// Send all listbox events to eventFilter():
+	Q3ListBox* lb = d->listBox();
+	lb->triggerUpdate( true );
+	lb->installEventFilter( this );
+	d->mouseWasInsidePopup = false;
+	int w = lb->variableWidth() ? lb->sizeHint().width() : width();
+	int h = listHeight( lb, d->sizeLimit ) + 2;
+	QRect screen = QApplication::desktop()->availableGeometry( this );
+
+	int sx = screen.x();				// screen pos
+	int sy = screen.y();
+	int sw = screen.width();			// screen width
+	int sh = screen.height();			// screen height
+	QPoint pos = mapToGlobal( QPoint(0,height()) );
+	// ## Similar code is in QPopupMenu
+	int x = pos.x();
+	int y = pos.y();
+
+	// the complete widget must be visible
+	if ( x + w > sx + sw )
+	    x = sx+sw - w;
+	if ( x < sx )
+	    x = sx;
+	if (y + h > sy+sh && y - h - height() >= 0 )
+	    y = y - h - height();
+
+        opt.rect = QRect(x, y, w, h);
+       	QRect rect = style()->subControlRect(QStyle::CC_ComboBox, &opt,
+                                             QStyle::SC_ComboBoxListBoxPopup, this);
+
+	// work around older styles that don't implement the combobox
+	// listbox popup subcontrol
+	if ( rect.isNull() )
+	    rect.setRect( x, y, w, h );
+	lb->setGeometry( rect );
+
+	lb->raise();
+	bool block = lb->signalsBlocked();
+	lb->blockSignals( true );
+	Q3ListBoxItem* currentLBItem = 0;
+	if ( editable() && currentText() != text( currentItem() ) )
+	    currentLBItem = lb->findItem( currentText() );
+
+	currentLBItem = currentLBItem ? currentLBItem : lb->item( d->current );
+
+	lb->setCurrentItem( currentLBItem );
+	lb->setContentsPos( lb->contentsX(),
+			    lb->viewportToContents( lb->itemRect( currentLBItem ).topLeft() ).y() );
+
+	// set the current item to also be the selected item if it isn't already
+	if ( currentLBItem && currentLBItem->isSelectable() && !currentLBItem->isSelected() )
+	    lb->setSelected( currentLBItem, true );
+	lb->blockSignals( block );
+	lb->setVScrollBarMode(Q3ScrollView::Auto);
+
+#ifndef QT_NO_EFFECTS
+	if ( QApplication::isEffectEnabled( Qt::UI_AnimateCombo ) ) {
+	    if ( lb->y() < mapToGlobal(QPoint(0,0)).y() )
+		qScrollEffect( lb, QEffects::UpScroll );
+	    else
+		qScrollEffect( lb );
+	} else
+#endif
+	    lb->show();
+    }
+    d->poppedUp = true;
+}
+
+
+/*!
+  Updates the widget mask.
+
+  \sa QWidget::setMask()
+*/
+void Q3ComboBox::updateMask()
+{
+    QBitmap bm( size() );
+    bm.fill( Qt::color0 );
+
+    QStyleOptionComboBox opt = d->getStyleOption();
+    {
+	QPainter p(&bm);
+        p.initFrom(this);
+        p.fillRect(opt.rect, Qt::color1); // qcommonstyle old drawComplexControl implementation
+    }
+
+    setMask( bm );
+}
+
+/*!
+  \internal
+  Pops down (removes) the combobox popup list box.
+*/
+void Q3ComboBox::popDownListBox()
+{
+    Q_ASSERT( d->usingListBox() );
+    d->listBox()->removeEventFilter( this );
+    d->listBox()->viewport()->removeEventFilter( this );
+    d->listBox()->hide();
+    d->listBox()->setCurrentItem( d->current );
+    if ( d->arrowDown ) {
+	d->arrowDown = false;
+	repaint( false );
+    }
+    d->poppedUp = false;
+}
+
+
+/*!
+  \internal
+  Re-indexes the identifiers in the popup list.
+*/
+
+void Q3ComboBox::reIndex()
+{
+    if ( !d->usingListBox() ) {
+	int cnt = count();
+	while ( cnt-- )
+	    d->popup()->setId( cnt, cnt );
+    }
+}
+
+/*!
+  \internal
+  Repaints the combobox.
+*/
+
+void Q3ComboBox::currentChanged()
+{
+    if ( d->autoresize )
+	adjustSize();
+    update();
+
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+    QAccessible::updateAccessibility( this, 0, QAccessible::ValueChanged );
+#endif
+}
+
+/*! \reimp
+
+  \internal
+
+  The event filter steals events from the popup or listbox when they
+  are popped up. It makes the popup stay up after a short click in
+  motif style. In windows style it toggles the arrow button of the
+  combobox field, and activates an item and takes down the listbox
+  when the mouse button is released.
+*/
+
+bool Q3ComboBox::eventFilter( QObject *object, QEvent *event )
+{
+    QStyleOptionComboBox opt = d->getStyleOption();
+    if ( !event )
+	return true;
+    else if ( object == d->ed ) {
+	if ( event->type() == QEvent::KeyPress ) {
+	    bool isAccepted = ( (QKeyEvent*)event )->isAccepted();
+	    keyPressEvent( (QKeyEvent *)event );
+	    if ( ((QKeyEvent *)event)->isAccepted() ) {
+		d->completeNow = false;
+		return true;
+	    } else if ( ((QKeyEvent *)event)->key() != Qt::Key_End ) {
+		d->completeNow = true;
+		d->completeAt = d->ed->cursorPosition();
+	    }
+	    if ( isAccepted )
+		( (QKeyEvent*)event )->accept();
+	    else
+		( (QKeyEvent*)event )->ignore();
+	} else if ( event->type() == QEvent::KeyRelease ) {
+	    keyReleaseEvent( (QKeyEvent *)event );
+	    return ((QKeyEvent *)event)->isAccepted();
+	} else if ( event->type() == QEvent::FocusIn ) {
+	    focusInEvent( (QFocusEvent *)event );
+	} else if ( event->type() == QEvent::FocusOut ) {
+	    focusOutEvent( (QFocusEvent *)event );
+	} else if ( d->useCompletion && d->completeNow ) {
+	    d->completeNow = false;
+	    if ( !d->ed->text().isNull() &&
+		 d->ed->cursorPosition() > d->completeAt &&
+		 d->ed->cursorPosition() == (int)d->ed->text().length() ) {
+		QString ct( d->ed->text() );
+		int i = completionIndex( ct, currentItem() );
+		if ( i > -1 ) {
+		    QString it = text( i );
+		    d->ed->validateAndSet( it, ct.length(),
+					   ct.length(), it.length() );
+		    d->current = i;
+                    // ### sets current item without emitting signals. This is to
+		    // make sure the right item is current if you change current with
+		    // wheel/up/down. While typing current is not valid anyway. Fix properly
+		    // in 4.0.
+		}
+	    }
+	}
+    } else if ( d->usingListBox() && ( object == d->listBox() ||
+                                       object == d->listBox()->viewport() )) {
+	QMouseEvent *e = (QMouseEvent*)event;
+	switch( event->type() ) {
+	case QEvent::MouseMove:
+	    if ( !d->mouseWasInsidePopup  ) {
+		QPoint pos = e->pos();
+		if ( d->listBox()->rect().contains( pos ) )
+		    d->mouseWasInsidePopup = true;
+		// Check if arrow button should toggle
+		if ( d->arrowPressed ) {
+		    QPoint comboPos;
+		    comboPos = mapFromGlobal( d->listBox()->mapToGlobal(pos) );
+		    QRect arrowRect = style()->subControlRect(QStyle::CC_ComboBox, &opt,
+                                                              QStyle::SC_ComboBoxArrow, this);
+		    if ( arrowRect.contains( comboPos ) ) {
+			if ( !d->arrowDown  ) {
+			    d->arrowDown = true;
+			    repaint( false );
+			}
+		    } else {
+			if ( d->arrowDown  ) {
+			    d->arrowDown = false;
+			    repaint( false );
+			}
+		    }
+		}
+	    } else if ((e->state() & ( Qt::RightButton | Qt::LeftButton | Qt::MidButton ) ) == 0 &&
+		       style()->styleHint(QStyle::SH_ComboBox_ListMouseTracking, &opt, this)) {
+		QWidget *mouseW = QApplication::widgetAt( e->globalPos(), true );
+		if ( mouseW == d->listBox()->viewport() ) { //###
+		    QMouseEvent m( QEvent::MouseMove, e->pos(), e->globalPos(),
+				   Qt::NoButton, Qt::LeftButton );
+		    QApplication::sendEvent( object, &m ); //### Evil
+		    return true;
+		}
+	    }
+
+	    break;
+	case QEvent::MouseButtonRelease:
+	    if ( d->listBox()->rect().contains( e->pos() ) ) {
+		QMouseEvent tmp( QEvent::MouseButtonDblClick,
+				 e->pos(), e->button(), e->state() ) ;
+		// will hide popup
+		QApplication::sendEvent( object, &tmp );
+		return true;
+	    } else {
+		if ( d->mouseWasInsidePopup ) {
+		    popDownListBox();
+		} else {
+		    d->arrowPressed = false;
+		    if ( d->arrowDown  ) {
+			d->arrowDown = false;
+			repaint( false );
+		    }
+		}
+	    }
+	    break;
+	case QEvent::MouseButtonDblClick:
+	case QEvent::MouseButtonPress:
+	    if ( !d->listBox()->rect().contains( e->pos() ) ) {
+		QPoint globalPos = d->listBox()->mapToGlobal(e->pos());
+		if ( QApplication::widgetAt( globalPos, true ) == this ) {
+		    d->discardNextMousePress = true;
+		    // avoid popping up again
+		}
+		popDownListBox();
+		return true;
+	    }
+	    break;
+	case QEvent::KeyPress:
+	    switch( ((QKeyEvent *)event)->key() ) {
+	    case Qt::Key_Up:
+	    case Qt::Key_Down:
+		if ( !(((QKeyEvent *)event)->state() & Qt::AltModifier) )
+		    break;
+	    case Qt::Key_F4:
+	    case Qt::Key_Escape:
+		if ( d->poppedUp ) {
+		    popDownListBox();
+		    return true;
+		}
+		break;
+	    case Qt::Key_Enter:
+	    case Qt::Key_Return:
+		// work around QDialog's enter handling
+		return false;
+	    default:
+		break;
+	    }
+	    break;
+	case QEvent::Hide:
+	    popDownListBox();
+	    break;
+	default:
+	    break;
+	}
+    } else if ( (!d->usingListBox() || style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, this)) &&
+		object == d->popup() ) {
+	QMouseEvent *e = (QMouseEvent*)event;
+	switch ( event->type() ) {
+	case QEvent::MouseButtonRelease:
+	    if ( d->shortClick ) {
+		QMouseEvent tmp( QEvent::MouseMove,
+				 e->pos(), e->button(), e->state() ) ;
+		// highlight item, but don't pop down:
+		QApplication::sendEvent( object, &tmp );
+		return true;
+	    }
+	    break;
+	case QEvent::MouseButtonDblClick:
+	case QEvent::MouseButtonPress:
+	    if ( !d->popup()->rect().contains( e->pos() ) ) {
+                d->poppedUp = false;
+                d->arrowDown = false;
+		// remove filter, event will take down popup:
+		d->popup()->removeEventFilter( this );
+		// ### uglehack!
+		// call internalHighlight so the highlighed signal
+		// will be emitted at least as often as necessary.
+		// it may be called more often than necessary
+		internalHighlight( d->current );
+	    }
+	    break;
+	case QEvent::Hide:
+	    d->poppedUp = false;
+	    break;
+	default:
+	    break;
+	}
+    }
+    return QWidget::eventFilter( object, event );
+}
+
+
+/*!
+    Returns the index of the first item \e after \a startingAt of
+    which \a prefix is a case-insensitive prefix. Returns -1 if no
+    items start with \a prefix.
+*/
+
+int Q3ComboBox::completionIndex( const QString & prefix,
+				int startingAt = 0 ) const
+{
+    int start = startingAt;
+    if ( start < 0 || start >= count() )
+	start = 0;
+    if ( start >= count() )
+	return -1;
+    QString match = prefix.lower();
+    if ( match.length() < 1 )
+	return start;
+
+    QString current;
+    int i = start;
+    do {
+	current = text( i ).lower();
+	if ( current.startsWith( match ) )
+	    return i;
+	i++;
+	if ( i == count() )
+	    i = 0;
+    } while ( i != start );
+    return -1;
+}
+
+int Q3ComboBox::sizeLimit() const
+{
+    return d ? d->sizeLimit : INT_MAX;
+}
+
+void Q3ComboBox::setSizeLimit( int lines )
+{
+    d->sizeLimit = lines;
+}
+
+
+int Q3ComboBox::maxCount() const
+{
+    return d ? d->maxCount : INT_MAX;
+}
+
+void Q3ComboBox::setMaxCount( int count )
+{
+    int l = this->count();
+    while( --l > count )
+	removeItem( l );
+    d->maxCount = count;
+}
+
+Q3ComboBox::Policy Q3ComboBox::insertionPolicy() const
+{
+    return d->p;
+}
+
+void Q3ComboBox::setInsertionPolicy( Policy policy )
+{
+    d->p = policy;
+}
+
+
+
+/*!
+  Internal slot to keep the line editor up to date.
+*/
+
+void Q3ComboBox::returnPressed()
+{
+    QString s( d->ed->text() );
+
+    if ( s.isEmpty() )
+	return;
+
+    int c = 0;
+    bool doInsert = true;
+    if ( !d->duplicatesEnabled ) {
+	for ( int i = 0; i < count(); ++i ) {
+	    if ( s == text( i ) ) {
+		doInsert = false;
+		c = i;
+		break;
+	    }
+	}
+    }
+
+    if ( doInsert ) {
+	if ( insertionPolicy() != NoInsert ) {
+	    int cnt = count();
+	    while ( cnt >= d->maxCount ) {
+		removeItem( --cnt );
+	    }
+	}
+
+	switch ( insertionPolicy() ) {
+	case InsertAtCurrent:
+	    if (count() == 0)
+		insertItem(s);
+	    else if ( s != text( currentItem() ) )
+		changeItem( s, currentItem() );
+	    emit activated( currentItem() );
+	    emit activated( s );
+	    return;
+	case NoInsert:
+	    emit activated( s );
+	    return;
+	case InsertAtTop:
+	    c = 0;
+	    break;
+	case InsertAtBottom:
+	    c = count();
+	    break;
+	case InsertBeforeCurrent:
+	    c = currentItem();
+	    break;
+	case InsertAfterCurrent:
+	    c = count() == 0 ? 0 : currentItem() + 1;
+	    break;
+	}
+	insertItem( s, c );
+    }
+
+    setCurrentItem( c );
+    emit activated( c );
+    emit activated( s );
+}
+
+
+/*!
+  Enables the combobox if \a enable is true; otherwise disables it.
+
+  \sa QWidget::enabled
+*/
+
+void Q3ComboBox::setEnabled( bool enable )
+{
+    if ( !enable ) {
+	if ( d->usingListBox() ) {
+	    popDownListBox();
+	} else {
+	    d->popup()->removeEventFilter( this );
+	    d->popup()->close();
+	    d->poppedUp = false;
+	}
+    }
+    QWidget::setEnabled( enable );
+}
+
+
+
+/*!
+    Applies the validator \a v to the combobox so that only text which
+    is valid according to \a v is accepted.
+
+    This function does nothing if the combobox is not editable.
+
+    \sa validator() clearValidator() QValidator
+*/
+
+void Q3ComboBox::setValidator( const QValidator * v )
+{
+    if ( d && d->ed )
+	d->ed->setValidator( v );
+}
+
+
+/*!
+    Returns the validator which constrains editing for this combobox
+    if there is one; otherwise returns 0.
+
+    \sa setValidator() clearValidator() QValidator
+*/
+
+const QValidator * Q3ComboBox::validator() const
+{
+    return d && d->ed ? d->ed->validator() : 0;
+}
+
+
+/*!
+    This slot is equivalent to setValidator( 0 ).
+*/
+
+void Q3ComboBox::clearValidator()
+{
+    if ( d && d->ed )
+	d->ed->setValidator( 0 );
+}
+
+
+/*!
+    Sets the combobox to use \a newListBox instead of the current list
+    box or popup. As a side effect, it clears the combobox of its
+    current contents.
+
+    \warning Q3ComboBox assumes that newListBox->text(n) returns
+    non-null for 0 \<= n \< newListbox->count(). This assumption is
+    necessary because of the line edit in Q3ComboBox.
+*/
+
+void Q3ComboBox::setListBox( Q3ListBox * newListBox )
+{
+    clear();
+
+    if ( d->usingListBox() ) {
+	delete d->listBox();
+    } else {
+	delete d->popup();
+        d->setPopupMenu(0, false);
+    }
+
+    newListBox->reparent( this, Qt::WType_Popup, QPoint(0,0), false );
+    d->setListBox( newListBox );
+    d->listBox()->setFont( font() );
+    d->listBox()->setPalette( palette() );
+    d->listBox()->setVScrollBarMode(Q3ScrollView::AlwaysOff);
+    d->listBox()->setHScrollBarMode(Q3ScrollView::AlwaysOff);
+    d->listBox()->setFrameStyle( Q3Frame::Box | Q3Frame::Plain );
+    d->listBox()->setLineWidth( 1 );
+    d->listBox()->resize( 100, 10 );
+
+    connect( d->listBox(), SIGNAL(selected(int)),
+	     SLOT(internalActivate(int)) );
+    connect( d->listBox(), SIGNAL(highlighted(int)),
+	     SLOT(internalHighlight(int)));
+}
+
+
+/*!
+    Returns the current list box, or 0 if there is no list box.
+    (Q3ComboBox can use QPopupMenu instead of QListBox.) Provided to
+    match setListBox().
+
+    \sa setListBox()
+*/
+
+Q3ListBox * Q3ComboBox::listBox() const
+{
+    return d && d->usingListBox() ? d->listBox() : 0;
+}
+
+/*!
+    Returns the line edit, or 0 if there is no line edit.
+
+    Only editable listboxes have a line editor.
+*/
+QLineEdit* Q3ComboBox::lineEdit() const
+{
+    return d->ed;
+}
+
+
+
+/*!
+    Clears the line edit without changing the combobox's contents.
+    Does nothing if the combobox isn't editable.
+
+    This is particularly useful when using a combobox as a line edit
+    with history. For example you can connect the combobox's
+    activated() signal to clearEdit() in order to present the user
+    with a new, empty line as soon as Enter is pressed.
+
+    \sa setEditText()
+*/
+
+void Q3ComboBox::clearEdit()
+{
+    if ( d && d->ed )
+	d->ed->clear();
+}
+
+
+/*!
+    Sets the text in the line edit to \a newText without changing the
+    combobox's contents. Does nothing if the combobox isn't editable.
+
+    This is useful e.g. for providing a good starting point for the
+    user's editing and entering the change in the combobox only when
+    the user presses Enter.
+
+    \sa clearEdit() insertItem()
+*/
+
+void Q3ComboBox::setEditText( const QString &newText )
+{
+    if ( d && d->ed ) {
+	d->updateLinedGeometry();
+	d->ed->setText( newText );
+    }
+}
+
+void Q3ComboBox::setAutoCompletion( bool enable )
+{
+    d->useCompletion = enable;
+    d->completeNow = false;
+}
+
+
+bool Q3ComboBox::autoCompletion() const
+{
+    return d->useCompletion;
+}
+
+/*!
+  \internal
+ */
+void Q3ComboBox::styleChange( QStyle& s )
+{
+    d->sizeHint = QSize();		// invalidate size hint...
+    if ( d->ed )
+	d->updateLinedGeometry();
+    QWidget::styleChange( s );
+}
+
+bool Q3ComboBox::editable() const
+{
+    return d->ed != 0;
+}
+
+void Q3ComboBox::setEditable( bool y )
+{
+    if ( y == editable() )
+	return;
+    if ( y ) {
+	if ( !d->usingListBox() )
+	    setUpListBox();
+	setUpLineEdit();
+	d->ed->show();
+	if ( currentItem() )
+	    setEditText( currentText() );
+    } else {
+	delete d->ed;
+	d->ed = 0;
+    }
+
+    setFocusPolicy(Qt::StrongFocus);
+    updateGeometry();
+    update();
+}
+
+
+void Q3ComboBox::setUpListBox()
+{
+    d->setListBox( new Q3ListBox( this, "in-combo", Qt::WType_Popup ) );
+    d->listBox()->setFont( font() );
+    d->listBox()->setPalette( palette() );
+    d->listBox()->setVScrollBarMode( Q3ListBox::AlwaysOff );
+    d->listBox()->setHScrollBarMode( Q3ListBox::AlwaysOff );
+    d->listBox()->setFrameStyle( Q3Frame::Box | Q3Frame::Plain );
+    d->listBox()->setLineWidth( 1 );
+    d->listBox()->resize( 100, 10 );
+
+    connect( d->listBox(), SIGNAL(selected(int)),
+	     SLOT(internalActivate(int)) );
+    connect( d->listBox(), SIGNAL(highlighted(int)),
+	     SLOT(internalHighlight(int)));
+}
+
+
+void Q3ComboBox::setUpLineEdit()
+{
+    if ( !d->ed )
+	setLineEdit( new QLineEdit( this, "combo edit" ) );
+}
+
+/*!
+    Sets the line edit to use \a edit instead of the current line edit.
+*/
+
+void Q3ComboBox::setLineEdit( QLineEdit *edit )
+{
+    if ( !edit ) {
+#if defined(QT_CHECK_NULL)
+	Q_ASSERT( edit != 0 );
+#endif
+	return;
+    }
+
+    edit->setText( currentText() );
+    delete d->ed;
+    d->ed = edit;
+
+    if ( edit->parent() != this )
+	edit->reparent( this, QPoint(0,0), false );
+
+    connect (edit, SIGNAL(textChanged(QString)),
+	     this, SIGNAL(textChanged(QString)) );
+    connect( edit, SIGNAL(returnPressed()), SLOT(returnPressed()) );
+
+    edit->setFrame( false );
+    d->updateLinedGeometry();
+    edit->installEventFilter( this );
+    setFocusProxy( edit );
+    setFocusPolicy(Qt::StrongFocus);
+    setInputMethodEnabled( true );
+
+    if ( !d->usingListBox() )
+	setUpListBox();
+
+    if ( isVisible() )
+	edit->show();
+
+    updateGeometry();
+    update();
+}
+
+/*!
+  Hides the combobox.
+
+  \sa QWidget::hide()
+*/
+void Q3ComboBox::hide()
+{
+    QWidget::hide();
+
+    if (listBox())
+	listBox()->hide();
+    else if (d->popup())
+	d->popup()->hide();
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_COMBOBOX