summaryrefslogtreecommitdiffstats
path: root/src/widgets/qcombobox.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/widgets/qcombobox.cpp')
-rw-r--r--src/widgets/qcombobox.cpp2334
1 files changed, 2334 insertions, 0 deletions
diff --git a/src/widgets/qcombobox.cpp b/src/widgets/qcombobox.cpp
new file mode 100644
index 000000000..8923192af
--- /dev/null
+++ b/src/widgets/qcombobox.cpp
@@ -0,0 +1,2334 @@
+/**********************************************************************
+**
+** Implementation of TQComboBox widget class
+**
+** Created : 940426
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the TQt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free TQt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing retquirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.TQPL
+** included in the packaging of this file. Licensees holding valid TQt
+** Commercial licenses may use this file in accordance with the TQt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qcombobox.h"
+#ifndef QT_NO_COMBOBOX
+#include "qpopupmenu.h"
+#include "qlistbox.h"
+#include "qpainter.h"
+#include "qdrawutil.h"
+#include "qstrlist.h"
+#include "qpixmap.h"
+#include "qtimer.h"
+#include "qapplication.h"
+#include "qlineedit.h"
+#include "qbitmap.h"
+#include "qeffects_p.h"
+#include "qstringlist.h"
+#include "qcombobox.h"
+#include "qstyle.h"
+#include <limits.h>
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+#include "qaccessible.h"
+#endif
+
+/*!
+ \class TQComboBox qcombobox.h
+ \brief The TQComboBox widget is a combined button and popup list.
+
+ \ingroup basic
+ \mainclass
+
+ 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.
+
+ TQComboBox 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. TQComboBox provides both.
+
+ TQComboBox provides two different constructors. The simplest
+ constructor creates an "old-style" combobox in Motif (or Aqua)
+ style:
+ \code
+ TQComboBox *c = new TQComboBox( this, "read-only combobox" );
+ \endcode
+
+ The other constructor creates a new-style combobox in Motif style,
+ and can create both read-only and editable comboboxes:
+ \code
+ TQComboBox *c1 = new TQComboBox( FALSE, this, "read-only combobox" );
+ TQComboBox *c2 = new TQComboBox( TRUE, this, "editable combobox" );
+ \endcode
+
+ 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
+ TQString 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 TQValidator; 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().
+
+ <img src="qcombo1-m.png">(Motif 1, read-only)<br clear=all>
+ <img src="qcombo2-m.png">(Motif 2, editable)<br clear=all>
+ <img src="qcombo3-m.png">(Motif 2, read-only)<br clear=all>
+ <img src="qcombo1-w.png">(Windows style)
+
+ Depending on the style, TQComboBox will use a TQListBox or a
+ TQPopupMenu to display the list of items. See setListBox() for
+ more information.
+
+ \sa TQLineEdit TQListBox TQSpinBox TQRadioButton TQButtonGroup
+ \link guibooks.html#fowler GUI Design Handbook: Combo Box,\endlink
+ \link guibooks.html#fowler GUI Design Handbook: Drop-Down List Box.\endlink
+*/
+
+
+/*!
+ \enum TQComboBox::Policy
+
+ This enum specifies what the TQComboBox 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.
+*/
+
+
+/*!
+ \fn void TQComboBox::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 void TQComboBox::activated( const TQString &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 TQComboBox::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 void TQComboBox::highlighted( const TQString &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 TQComboBox::textChanged( const TQString &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 TQComboBox::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 TQComboBox::autoMask
+ \brief whether the combobox is automatically masked
+
+ \sa TQWidget::setAutoMask()
+*/
+
+/*! \property TQComboBox::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 TQComboBox::count
+ \brief the number of items in the combobox
+*/
+
+/*!
+ \property TQComboBox::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 TQComboBox::currentText
+ \brief the text of the combobox's current item
+*/
+
+/*!
+ \property TQComboBox::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 TQComboBox::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 it's appearance
+ to a 2.0 style Motif combobox is it is set to be editable.
+*/
+
+/*!
+ \property TQComboBox::insertionPolicy
+ \brief the position of the items inserted by the user
+
+ The default insertion policy is \c AtBottom. See \l Policy.
+*/
+
+/*!
+ \property TQComboBox::maxCount
+ \brief the maximum number of items allowed in the combobox
+*/
+
+/*!
+ \property TQComboBox::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 scrollbar is added.
+*/
+
+class TQComboBoxPopup : public TQPopupMenu
+{
+public:
+ TQComboBoxPopup( TQWidget *parent=0, const char *name=0 )
+ : TQPopupMenu( parent, name )
+ {
+ }
+
+ int itemHeight( int index )
+ {
+ return TQPopupMenu::itemHeight( index );
+ }
+};
+
+static inline TQString escapedComboString(const TQString &str)
+{
+ TQString stringToReturn = str;
+ return stringToReturn.replace('&', "&&");
+}
+
+class TQComboBoxPopupItem : public TQCustomMenuItem
+{
+ TQListBoxItem *li;
+ TQSize sc; // Size cache optimization
+public:
+ TQComboBoxPopupItem(TQListBoxItem *i) : TQCustomMenuItem(), li(i), sc(0, 0) { }
+ virtual bool fullSpan() const { return TRUE; }
+ virtual void paint( TQPainter*, const TQColorGroup&, bool, bool, int, int, int, int);
+ virtual TQSize sizeHint() { if (sc.isNull()) sc = TQSize(li->width(li->listBox()), TQMAX(25, li->height(li->listBox()))); return sc; }
+};
+void TQComboBoxPopupItem::paint( TQPainter* p, const TQColorGroup&, 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 TQComboBoxData
+{
+public:
+ TQComboBoxData( TQComboBox *cb ): ed( 0 ), usingLBox( FALSE ), pop( 0 ), lBox( 0 ), combo( cb )
+ {
+ duplicatesEnabled = TRUE;
+ cb->setSizePolicy( TQSizePolicy( TQSizePolicy::Minimum, TQSizePolicy::Fixed ) );
+ }
+
+ inline bool usingListBox() { return usingLBox; }
+ inline TQListBox * listBox() { return lBox; }
+ inline TQComboBoxPopup * popup() { return pop; }
+ void updateLinedGeometry();
+ void setListBox( TQListBox *l );
+ void setPopupMenu( TQComboBoxPopup * pm, bool isPopup=TRUE );
+
+ int current;
+ int maxCount;
+ int sizeLimit;
+ TQComboBox::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;
+
+ TQLineEdit * ed; // /bin/ed rules!
+ TQTimer *completionTimer;
+
+ TQSize sizeHint;
+
+private:
+ bool usingLBox;
+ TQComboBoxPopup *pop;
+ TQListBox *lBox;
+ TQComboBox *combo;
+
+};
+
+void TQComboBoxData::updateLinedGeometry()
+{
+ if ( !ed || !combo )
+ return;
+ TQRect r = TQStyle::visualRect( combo->style().querySubControlMetrics(TQStyle::CC_ComboBox, combo,
+ TQStyle::SC_ComboBoxEditField), combo );
+
+ const TQPixmap *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 );
+}
+
+void TQComboBoxData::setListBox( TQListBox *l )
+{
+ lBox = l;
+ usingLBox = TRUE;
+ l->setMouseTracking( TRUE );
+#ifdef Q_WS_X11
+ l->x11SetWindowType( TQWidget::X11WindowTypeCombo );
+ l->x11SetWindowTransient( combo->topLevelWidget());
+#endif
+}
+
+void TQComboBoxData::setPopupMenu( TQComboBoxPopup * pm, bool isPopup )
+{
+ pop = pm;
+ if(isPopup)
+ usingLBox = FALSE;
+#ifdef Q_WS_X11
+ if( pm ) {
+ pm->x11SetWindowType( TQWidget::X11WindowTypeCombo );
+ pm->x11SetWindowTransient( combo->topLevelWidget());
+ }
+#endif
+}
+
+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( "TQComboBox::%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( "TQComboBox::%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 TQComboBox, then
+ the pixmap() function will always return 0. To workaround this,
+ use the other constructor.
+
+*/
+
+
+
+TQComboBox::TQComboBox( TQWidget *parent, const char *name )
+ : TQWidget( parent, name, WNoAutoErase )
+{
+ d = new TQComboBoxData( this );
+ if ( style().styleHint(TQStyle::SH_ComboBox_Popup, this) ||
+ style().styleHint(TQStyle::SH_GUIStyle) == TQt::MotifStyle ) {
+ d->setPopupMenu( new TQComboBoxPopup( 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 TQTimer( this );
+
+ setFocusPolicy( TabFocus );
+ setBackgroundMode( 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 TQWidget
+ constructor.
+*/
+
+
+TQComboBox::TQComboBox( bool rw, TQWidget *parent, const char *name )
+ : TQWidget( parent, name, WNoAutoErase )
+{
+ d = new TQComboBoxData( this );
+ setUpListBox();
+
+ if(d->popup() && style().styleHint(TQStyle::SH_ComboBox_Popup, this))
+ d->popup()->setItemChecked(d->current, FALSE);
+ d->current = 0;
+ 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 TQTimer( this );
+
+ setFocusPolicy( StrongFocus );
+
+ d->ed = 0;
+ if ( rw )
+ setUpLineEdit();
+ setBackgroundMode( PaletteButton, PaletteBase );
+}
+
+
+
+/*!
+ Destroys the combobox.
+*/
+
+TQComboBox::~TQComboBox()
+{
+ delete d;
+}
+
+void TQComboBox::setDuplicatesEnabled( bool enable )
+{
+ d->duplicatesEnabled = enable;
+}
+
+bool TQComboBox::duplicatesEnabled() const
+{
+ return d->duplicatesEnabled;
+}
+
+int TQComboBox::count() const
+{
+ if ( d->usingListBox() )
+ return d->listBox()->count();
+ else
+ return d->popup()->count();
+}
+
+
+/*!
+ \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 TQComboBox::insertStrList( const TQStrList &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 TQComboBox::insertStrList( const TQStrList *list, int index )
+{
+ if ( !list ) {
+#if defined(QT_CHECK_NULL)
+ Q_ASSERT( list != 0 );
+#endif
+ return;
+ }
+ TQStrListIterator it( *list );
+ const char* tmp;
+ if ( index < 0 )
+ index = count();
+ while ( (tmp=it.current()) ) {
+ ++it;
+ if ( d->usingListBox() )
+ d->listBox()->insertItem( TQString::fromLatin1(tmp), index );
+ else
+ d->popup()->insertItem( escapedComboString(TQString::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 TQComboBox::insertStringList( const TQStringList &list, int index )
+{
+ TQStringList::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:
+ \code
+ static const char* items[] = { "red", "green", "blue", 0 };
+ combo->insertStrList( items );
+ \endcode
+
+ \sa insertStringList()
+*/
+
+void TQComboBox::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( TQString::fromLatin1(strings[i]), index );
+ else
+ d->popup()->insertItem( escapedComboString(TQString::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 TQComboBox::insertItem( const TQString &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 TQComboBox::insertItem( const TQPixmap &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 TQComboBox::insertItem( const TQPixmap &pixmap, const TQString& 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 TQComboBox::removeItem( int index )
+{
+ int cnt = count();
+ if ( !checkIndex( "removeItem", name(), cnt, index ) )
+ return;
+ if ( d->usingListBox() ) {
+ if ( style().styleHint(TQStyle::SH_ComboBox_Popup, 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 ) {
+ TQString s = TQString::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 TQComboBox::clear()
+{
+ if ( d->usingListBox() ) {
+ if ( style().styleHint(TQStyle::SH_ComboBox_Popup, this) && d->popup() )
+ d->popup()->clear();
+ d->listBox()->resize( 0, 0 );
+ d->listBox()->clear();
+ } else {
+ d->popup()->clear();
+ }
+
+ if(d->popup() && style().styleHint(TQStyle::SH_ComboBox_Popup, this))
+ d->popup()->setItemChecked(d->current, FALSE);
+ d->current = 0;
+ if ( d->ed ) {
+ d->ed->setText( TQString::fromLatin1("") );
+ d->updateLinedGeometry();
+ }
+ currentChanged();
+}
+
+
+TQString TQComboBox::currentText() const
+{
+ if ( d->ed )
+ return d->ed->text();
+ else if ( d->current < count() )
+ return text( currentItem() );
+ else
+ return TQString::null;
+}
+
+void TQComboBox::setCurrentText( const TQString& 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 TQString::null if
+ the item is not a string.
+
+ \sa currentText()
+*/
+
+TQString TQComboBox::text( int index ) const
+{
+ if ( !checkIndex( "text", name(), count(), index ) )
+ return TQString::null;
+ if ( d->usingListBox() ) {
+ return d->listBox()->text( index );
+ } else {
+ TQString retText = d->popup()->text(index);
+ retText.replace("&&", "&");
+ return retText;
+ }
+}
+
+/*!
+ Returns the pixmap item at position \a index, or 0 if the item is
+ not a pixmap.
+*/
+
+const TQPixmap *TQComboBox::pixmap( int index ) const
+{
+ if ( !checkIndex( "pixmap", name(), count(), index ) )
+ return 0;
+ if ( d->usingListBox() )
+ return d->listBox()->pixmap( index );
+ else
+ return d->popup()->pixmap( index );
+}
+
+/*!
+ Replaces the item at position \a index with the text \a t.
+*/
+
+void TQComboBox::changeItem( const TQString &t, int index )
+{
+ if ( !checkIndex( "changeItem", name(), count(), index ) )
+ return;
+ if ( d->usingListBox() )
+ d->listBox()->changeItem( t, index );
+ else
+ d->popup()->changeItem( t, index );
+ 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 TQComboBox::changeItem( const TQPixmap &im, int index )
+{
+ if ( !checkIndex( "changeItem", name(), count(), index ) )
+ return;
+ if ( d->usingListBox() )
+ d->listBox()->changeItem( im, index );
+ else
+ d->popup()->changeItem( im, index );
+ 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 TQComboBox::changeItem( const TQPixmap &im, const TQString &t, int index )
+{
+ if ( !checkIndex( "changeItem", name(), count(), index ) )
+ return;
+ if ( d->usingListBox() )
+ d->listBox()->changeItem( im, t, index );
+ else
+ d->popup()->changeItem( im, t, index );
+ if ( index == d->current )
+ update();
+}
+
+
+int TQComboBox::currentItem() const
+{
+ return d->current;
+}
+
+void TQComboBox::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;
+
+ if(d->popup() && style().styleHint(TQStyle::SH_ComboBox_Popup, 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();
+}
+
+bool TQComboBox::autoResize() const
+{
+ return d->autoresize;
+}
+
+void TQComboBox::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().
+*/
+TQSize TQComboBox::sizeHint() const
+{
+ if ( isVisible() && d->sizeHint.isValid() )
+ return d->sizeHint;
+
+ constPolish();
+ int i, w;
+ TQFontMetrics fm = fontMetrics();
+
+ int maxW = count() ? 18 : 7 * fm.width(TQChar('x')) + 18;
+ int maxH = TQMAX( 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;
+ }
+ }
+
+ d->sizeHint = (style().sizeFromContents(TQStyle::CT_ComboBox, this,
+ TQSize(maxW, maxH)).
+ expandedTo(TQApplication::globalStrut()));
+
+ return d->sizeHint;
+}
+
+
+/*!
+ \internal
+ Receives activated signals from an internal popup list and emits
+ the activated() signal.
+*/
+
+void TQComboBox::internalActivate( int index )
+{
+ if ( d->current != index ) {
+ if ( !d->usingListBox() || listBox()->item( index )->isSelectable() ) {
+ if(d->popup() && style().styleHint(TQStyle::SH_ComboBox_Popup, this))
+ d->popup()->setItemChecked(d->current, FALSE);
+ d->current = index;
+ currentChanged();
+ }
+ }
+ if ( d->usingListBox() )
+ popDownListBox();
+ else
+ d->popup()->removeEventFilter( this );
+ d->poppedUp = FALSE;
+
+ TQString 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 TQComboBox::internalHighlight( int index )
+{
+ emit highlighted( index );
+ TQString 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 TQComboBox::internalClickTimeout()
+{
+ d->shortClick = FALSE;
+}
+
+/*!
+ Sets the palette for both the combobox button and the combobox
+ popup list to \a palette.
+*/
+
+void TQComboBox::setPalette( const TQPalette &palette )
+{
+ TQWidget::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 TQComboBox::setFont( const TQFont &font )
+{
+ d->sizeHint = TQSize(); // invalidate size hint
+ TQWidget::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 TQComboBox::resizeEvent( TQResizeEvent * e )
+{
+ if ( d->ed )
+ d->updateLinedGeometry();
+ if ( d->listBox() )
+ d->listBox()->resize( width(), d->listBox()->height() );
+ TQWidget::resizeEvent( e );
+}
+
+/*!\reimp
+*/
+
+void TQComboBox::paintEvent( TQPaintEvent * )
+{
+ TQPainter p( this );
+ const TQColorGroup & g = colorGroup();
+ p.setPen(g.text());
+
+ TQStyle::SFlags flags = TQStyle::Style_Default;
+ if (isEnabled())
+ flags |= TQStyle::Style_Enabled;
+ if (hasFocus())
+ flags |= TQStyle::Style_HasFocus;
+
+ if ( width() < 5 || height() < 5 ) {
+ qDrawShadePanel( &p, rect(), g, FALSE, 2,
+ &g.brush( TQColorGroup::Button ) );
+ return;
+ }
+
+ bool reverse = TQApplication::reverseLayout();
+ if ( !d->usingListBox() &&
+ style().styleHint(TQStyle::SH_GUIStyle) == TQt::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(TQStyle::PM_DefaultFrameWidth, this),
+ &g.brush( TQColorGroup::Button ) );
+ qDrawShadePanel( &p, xPos, (height() - buttonH)/2,
+ buttonW, buttonH, g, FALSE,
+ style().pixelMetric(TQStyle::PM_DefaultFrameWidth, this) );
+ TQRect clip( x0, 2, w - 2 - 4 - 5, height() - 4 );
+ TQString str = d->popup()->text( this->d->current );
+ if ( !str.isNull() ) {
+ p.drawText( clip, AlignCenter | SingleLine, str );
+ }
+
+ TQPixmap *pix = d->popup()->pixmap( this->d->current );
+ TQIconSet *iconSet = d->popup()->iconSet( this->d->current );
+ if (pix || iconSet) {
+ TQPixmap pm = ( pix ? *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( TQStyle::CC_ComboBox, &p, this, rect(), g,
+ flags, (uint)TQStyle::SC_All,
+ (d->arrowDown ?
+ TQStyle::SC_ComboBoxArrow :
+ TQStyle::SC_None ));
+
+ TQRect re = style().querySubControlMetrics( TQStyle::CC_ComboBox, this,
+ TQStyle::SC_ComboBoxEditField );
+ re = TQStyle::visualRect(re, this);
+ p.setClipRect( re );
+
+ TQString str = d->popup()->text( this->d->current );
+ TQPixmap *pix = d->popup()->pixmap( this->d->current );
+ if ( !str.isNull() ) {
+ p.save();
+ p.setFont(font());
+ TQFontMetrics fm(font());
+ int x = re.x(), y = re.y() + fm.ascent();
+ if( pix )
+ x += pix->width() + 5;
+ p.drawText( x, y, str );
+ p.restore();
+ }
+ if ( pix ) {
+ p.fillRect( re.x(), re.y(), pix->width() + 4, re.height(),
+ colorGroup().brush( TQColorGroup::Base ) );
+ p.drawPixmap( re.x() + 2, re.y() +
+ ( re.height() - pix->height() ) / 2, *pix );
+ }
+ } else {
+ style().drawComplexControl( TQStyle::CC_ComboBox, &p, this, rect(), g,
+ flags, (uint)TQStyle::SC_All,
+ (d->arrowDown ?
+ TQStyle::SC_ComboBoxArrow :
+ TQStyle::SC_None ));
+
+ TQRect re = style().querySubControlMetrics( TQStyle::CC_ComboBox, this,
+ TQStyle::SC_ComboBoxEditField );
+ re = TQStyle::visualRect(re, this);
+ p.setClipRect( re );
+
+ if ( !d->ed ) {
+ TQListBoxItem * 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 ) ) {
+ TQListBoxItem * item = d->listBox()->item( d->current );
+ const TQPixmap *pix = item->pixmap();
+ if ( pix ) {
+ p.fillRect( re.x(), re.y(), pix->width() + 4, re.height(),
+ colorGroup().brush( TQColorGroup::Base ) );
+ p.drawPixmap( re.x() + 2, re.y() +
+ ( re.height() - pix->height() ) / 2, *pix );
+ }
+ }
+ p.setClipping( FALSE );
+ }
+}
+
+
+/*!\reimp
+*/
+
+void TQComboBox::mousePressEvent( TQMouseEvent *e )
+{
+ if ( e->button() != LeftButton )
+ return;
+ if ( d->discardNextMousePress ) {
+ d->discardNextMousePress = FALSE;
+ return;
+ }
+ TQRect arrowRect = style().querySubControlMetrics( TQStyle::CC_ComboBox, this,
+ TQStyle::SC_ComboBoxArrow);
+ arrowRect = TQStyle::visualRect(arrowRect, this);
+
+ // Correction for motif style, where arrow is smaller
+ // and thus has a rect that doesn't fit the button.
+ arrowRect.setHeight( TQMAX( 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();
+ }
+ TQTimer::singleShot( 200, this, SLOT(internalClickTimeout()));
+ d->shortClick = TRUE;
+ }
+}
+
+/*!\reimp
+*/
+
+void TQComboBox::mouseMoveEvent( TQMouseEvent * )
+{
+}
+
+/*!\reimp
+*/
+
+void TQComboBox::mouseReleaseEvent( TQMouseEvent * )
+{
+}
+
+/*!\reimp
+*/
+
+void TQComboBox::mouseDoubleClickEvent( TQMouseEvent *e )
+{
+ mousePressEvent( e );
+}
+
+
+/*!\reimp
+*/
+
+void TQComboBox::keyPressEvent( TQKeyEvent *e )
+{
+ int c = currentItem();
+ if ( ( e->key() == Key_F4 && e->state() == 0 ) ||
+ ( e->key() == Key_Down && (e->state() & AltButton) ) ||
+ ( !d->ed && e->key() == Key_Space ) ) {
+ if ( count() ) {
+ if ( !d->usingListBox() )
+ d->popup()->setActiveItem( this->d->current );
+ popup();
+ }
+ return;
+ } else if ( d->usingListBox() && e->key() == Key_Up ) {
+ if ( c > 0 )
+ setCurrentItem( c-1 );
+ } else if ( d->usingListBox() && e->key() == Key_Down ) {
+ if ( ++c < count() )
+ setCurrentItem( c );
+ } else if ( d->usingListBox() && e->key() == Key_Home && ( !d->ed || !d->ed->hasFocus() ) ) {
+ setCurrentItem( 0 );
+ } else if ( d->usingListBox() && e->key() == 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();
+ TQString 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 TQComboBox::focusInEvent( TQFocusEvent * e )
+{
+ TQWidget::focusInEvent( e );
+ d->completeNow = FALSE;
+ d->completeAt = 0;
+}
+
+/*!\reimp
+*/
+
+void TQComboBox::focusOutEvent( TQFocusEvent * e )
+{
+ TQWidget::focusOutEvent( e );
+ d->completeNow = FALSE;
+ d->completeAt = 0;
+}
+
+/*!\reimp
+*/
+#ifndef QT_NO_WHEELEVENT
+void TQComboBox::wheelEvent( TQWheelEvent *e )
+{
+ if ( d->poppedUp ) {
+ if ( d->usingListBox() ) {
+ TQApplication::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( TQListBox *l, int sl )
+{
+ if ( l->count() > 0 )
+ return TQMIN( 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 TQComboBox::popup()
+{
+ if ( !count() || d->poppedUp )
+ return;
+
+ if( !d->usingListBox() || style().styleHint(TQStyle::SH_ComboBox_Popup, this) ) {
+ if(d->usingListBox()) {
+ if(!d->popup()) {
+ TQComboBoxPopup *p = new TQComboBoxPopup( 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++) {
+ TQListBoxItem *item = d->listBox()->item(i);
+ if(item->rtti() == TQListBoxText::RTTI) {
+ d->popup()->insertItem(escapedComboString(item->text()), i, i);
+ } else if(item->rtti() == TQListBoxPixmap::RTTI) {
+ if(item->pixmap())
+ d->popup()->insertItem(TQIconSet(*item->pixmap()), escapedComboString(item->text()), i, i);
+ else
+ d->popup()->insertItem(escapedComboString(item->text()), i, i);
+ } else {
+ d->popup()->insertItem(new TQComboBoxPopupItem(item), i, i);
+ }
+ }
+ }
+ d->popup()->installEventFilter( this );
+ if(d->popup() && style().styleHint(TQStyle::SH_ComboBox_Popup, this))
+ d->popup()->setItemChecked(this->d->current, TRUE);
+ d->popup()->popup( mapToGlobal( TQPoint(0,0) ), this->d->current );
+ update();
+ } else {
+ // Send all listbox events to eventFilter():
+ TQListBox* 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;
+ TQRect screen = TQApplication::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
+ TQPoint pos = mapToGlobal( TQPoint(0,height()) );
+ // ## Similar code is in TQPopupMenu
+ 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();
+
+ TQRect rect =
+ style().querySubControlMetrics( TQStyle::CC_ComboBox, this,
+ TQStyle::SC_ComboBoxListBoxPopup,
+ TQStyleOption( x, y, w, h ) );
+ // 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 );
+ TQListBoxItem* 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(TQScrollView::Auto);
+
+#ifndef QT_NO_EFFECTS
+ if ( TQApplication::isEffectEnabled( UI_AnimateCombo ) ) {
+ if ( lb->y() < mapToGlobal(TQPoint(0,0)).y() )
+ qScrollEffect( lb, TQEffects::UpScroll );
+ else
+ qScrollEffect( lb );
+ } else
+#endif
+ lb->show();
+ }
+ d->poppedUp = TRUE;
+}
+
+
+/*!
+ \reimp
+*/
+void TQComboBox::updateMask()
+{
+ TQBitmap bm( size() );
+ bm.fill( color0 );
+
+ {
+ TQPainter p( &bm, this );
+ style().drawComplexControlMask(TQStyle::CC_ComboBox, &p, this, rect());
+ }
+
+ setMask( bm );
+}
+
+/*!
+ \internal
+ Pops down (removes) the combobox popup list box.
+*/
+void TQComboBox::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 TQComboBox::reIndex()
+{
+ if ( !d->usingListBox() ) {
+ int cnt = count();
+ while ( cnt-- )
+ d->popup()->setId( cnt, cnt );
+ }
+}
+
+/*!
+ \internal
+ Repaints the combobox.
+*/
+
+void TQComboBox::currentChanged()
+{
+ if ( d->autoresize )
+ adjustSize();
+ update();
+
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ TQAccessible::updateAccessibility( this, 0, TQAccessible::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 TQComboBox::eventFilter( TQObject *object, TQEvent *event )
+{
+ if ( !event )
+ return TRUE;
+ else if ( object == d->ed ) {
+ if ( event->type() == TQEvent::KeyPress ) {
+ bool isAccepted = ( (TQKeyEvent*)event )->isAccepted();
+ keyPressEvent( (TQKeyEvent *)event );
+ if ( ((TQKeyEvent *)event)->isAccepted() ) {
+ d->completeNow = FALSE;
+ return TRUE;
+ } else if ( ((TQKeyEvent *)event)->key() != Key_End ) {
+ d->completeNow = TRUE;
+ d->completeAt = d->ed->cursorPosition();
+ }
+ if ( isAccepted )
+ ( (TQKeyEvent*)event )->accept();
+ else
+ ( (TQKeyEvent*)event )->ignore();
+ } else if ( event->type() == TQEvent::KeyRelease ) {
+ keyReleaseEvent( (TQKeyEvent *)event );
+ return ((TQKeyEvent *)event)->isAccepted();
+ } else if ( event->type() == TQEvent::FocusIn ) {
+ focusInEvent( (TQFocusEvent *)event );
+ } else if ( event->type() == TQEvent::FocusOut ) {
+ focusOutEvent( (TQFocusEvent *)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() ) {
+ TQString ct( d->ed->text() );
+ int i = completionIndex( ct, currentItem() );
+ if ( i > -1 ) {
+ TQString 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() )) {
+ TQMouseEvent *e = (TQMouseEvent*)event;
+ switch( event->type() ) {
+ case TQEvent::MouseMove:
+ if ( !d->mouseWasInsidePopup ) {
+ TQPoint pos = e->pos();
+ if ( d->listBox()->rect().contains( pos ) )
+ d->mouseWasInsidePopup = TRUE;
+ // Check if arrow button should toggle
+ if ( d->arrowPressed ) {
+ TQPoint comboPos;
+ comboPos = mapFromGlobal( d->listBox()->mapToGlobal(pos) );
+ TQRect arrowRect =
+ style().querySubControlMetrics( TQStyle::CC_ComboBox, this,
+ TQStyle::SC_ComboBoxArrow);
+ arrowRect = TQStyle::visualRect(arrowRect, 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() & ( RightButton | LeftButton | MidButton ) ) == 0 &&
+ style().styleHint(TQStyle::SH_ComboBox_ListMouseTracking, this)) {
+ TQWidget *mouseW = TQApplication::widgetAt( e->globalPos(), TRUE );
+ if ( mouseW == d->listBox()->viewport() ) { //###
+ TQMouseEvent m( TQEvent::MouseMove, e->pos(), e->globalPos(),
+ LeftButton, LeftButton );
+ TQApplication::sendEvent( object, &m ); //### Evil
+ return TRUE;
+ }
+ }
+
+ break;
+ case TQEvent::MouseButtonRelease:
+ if ( d->listBox()->rect().contains( e->pos() ) ) {
+ TQMouseEvent tmp( TQEvent::MouseButtonDblClick,
+ e->pos(), e->button(), e->state() ) ;
+ // will hide popup
+ TQApplication::sendEvent( object, &tmp );
+ return TRUE;
+ } else {
+ if ( d->mouseWasInsidePopup ) {
+ popDownListBox();
+ } else {
+ d->arrowPressed = FALSE;
+ if ( d->arrowDown ) {
+ d->arrowDown = FALSE;
+ repaint( FALSE );
+ }
+ }
+ }
+ break;
+ case TQEvent::MouseButtonDblClick:
+ case TQEvent::MouseButtonPress:
+ if ( !d->listBox()->rect().contains( e->pos() ) ) {
+ TQPoint globalPos = d->listBox()->mapToGlobal(e->pos());
+ if ( TQApplication::widgetAt( globalPos, TRUE ) == this ) {
+ d->discardNextMousePress = TRUE;
+ // avoid popping up again
+ }
+ popDownListBox();
+ return TRUE;
+ }
+ break;
+ case TQEvent::KeyPress:
+ switch( ((TQKeyEvent *)event)->key() ) {
+ case Key_Up:
+ case Key_Down:
+ if ( !(((TQKeyEvent *)event)->state() & AltButton) )
+ break;
+ case Key_F4:
+ case Key_Escape:
+ if ( d->poppedUp ) {
+ popDownListBox();
+ return TRUE;
+ }
+ break;
+ case Key_Enter:
+ case Key_Return:
+ // work around TQDialog's enter handling
+ return FALSE;
+ default:
+ break;
+ }
+ break;
+ case TQEvent::Hide:
+ popDownListBox();
+ break;
+ default:
+ break;
+ }
+ } else if ( (!d->usingListBox() || style().styleHint(TQStyle::SH_ComboBox_Popup, this)) &&
+ object == d->popup() ) {
+ TQMouseEvent *e = (TQMouseEvent*)event;
+ switch ( event->type() ) {
+ case TQEvent::MouseButtonRelease:
+ if ( d->shortClick ) {
+ TQMouseEvent tmp( TQEvent::MouseMove,
+ e->pos(), e->button(), e->state() ) ;
+ // highlight item, but don't pop down:
+ TQApplication::sendEvent( object, &tmp );
+ return TRUE;
+ }
+ break;
+ case TQEvent::MouseButtonDblClick:
+ case TQEvent::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 TQEvent::Hide:
+ d->poppedUp = FALSE;
+ break;
+ default:
+ break;
+ }
+ }
+ return TQWidget::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 TQComboBox::completionIndex( const TQString & prefix,
+ int startingAt = 0 ) const
+{
+ int start = startingAt;
+ if ( start < 0 || start >= count() )
+ start = 0;
+ if ( start >= count() )
+ return -1;
+ TQString match = prefix.lower();
+ if ( match.length() < 1 )
+ return start;
+
+ TQString 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 TQComboBox::sizeLimit() const
+{
+ return d ? d->sizeLimit : INT_MAX;
+}
+
+void TQComboBox::setSizeLimit( int lines )
+{
+ d->sizeLimit = lines;
+}
+
+
+int TQComboBox::maxCount() const
+{
+ return d ? d->maxCount : INT_MAX;
+}
+
+void TQComboBox::setMaxCount( int count )
+{
+ int l = this->count();
+ while( --l > count )
+ removeItem( l );
+ d->maxCount = count;
+}
+
+TQComboBox::Policy TQComboBox::insertionPolicy() const
+{
+ return d->p;
+}
+
+void TQComboBox::setInsertionPolicy( Policy policy )
+{
+ d->p = policy;
+}
+
+
+
+/*!
+ Internal slot to keep the line editor up to date.
+*/
+
+void TQComboBox::returnPressed()
+{
+ TQString 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() != NoInsertion ) {
+ int cnt = count();
+ while ( cnt >= d->maxCount ) {
+ removeItem( --cnt );
+ }
+ }
+
+ switch ( insertionPolicy() ) {
+ case AtCurrent:
+ if (count() == 0)
+ insertItem(s);
+ else if ( s != text( currentItem() ) )
+ changeItem( s, currentItem() );
+ emit activated( currentItem() );
+ emit activated( s );
+ return;
+ case NoInsertion:
+ emit activated( s );
+ return;
+ case AtTop:
+ c = 0;
+ break;
+ case AtBottom:
+ c = count();
+ break;
+ case BeforeCurrent:
+ c = currentItem();
+ break;
+ case AfterCurrent:
+ c = count() == 0 ? 0 : currentItem() + 1;
+ break;
+ }
+ insertItem( s, c );
+ }
+
+ setCurrentItem( c );
+ emit activated( c );
+ emit activated( s );
+}
+
+
+/*! \reimp
+*/
+
+void TQComboBox::setEnabled( bool enable )
+{
+ if ( !enable ) {
+ if ( d->usingListBox() ) {
+ popDownListBox();
+ } else {
+ d->popup()->removeEventFilter( this );
+ d->popup()->close();
+ d->poppedUp = FALSE;
+ }
+ }
+ TQWidget::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() TQValidator
+*/
+
+void TQComboBox::setValidator( const TQValidator * 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() TQValidator
+*/
+
+const TQValidator * TQComboBox::validator() const
+{
+ return d && d->ed ? d->ed->validator() : 0;
+}
+
+
+/*!
+ This slot is equivalent to setValidator( 0 ).
+*/
+
+void TQComboBox::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 TQComboBox assumes that newListBox->text(n) returns
+ non-null for 0 \<= n \< newListbox->count(). This assumption is
+ necessary because of the line edit in TQComboBox.
+*/
+
+void TQComboBox::setListBox( TQListBox * newListBox )
+{
+ clear();
+
+ if ( d->usingListBox() ) {
+ delete d->listBox();
+ } else {
+ delete d->popup();
+ d->setPopupMenu(0, FALSE);
+ }
+
+ newListBox->reparent( this, WType_Popup, TQPoint(0,0), FALSE );
+ d->setListBox( newListBox );
+ d->listBox()->setFont( font() );
+ d->listBox()->setPalette( palette() );
+ d->listBox()->setVScrollBarMode(TQScrollView::AlwaysOff);
+ d->listBox()->setHScrollBarMode(TQScrollView::AlwaysOff);
+ d->listBox()->setFrameStyle( TQFrame::Box | TQFrame::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.
+ (TQComboBox can use TQPopupMenu instead of TQListBox.) Provided to
+ match setListBox().
+
+ \sa setListBox()
+*/
+
+TQListBox * TQComboBox::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.
+*/
+TQLineEdit* TQComboBox::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 TQComboBox::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 TQComboBox::setEditText( const TQString &newText )
+{
+ if ( d && d->ed ) {
+ d->updateLinedGeometry();
+ d->ed->setText( newText );
+ }
+}
+
+void TQComboBox::setAutoCompletion( bool enable )
+{
+ d->useCompletion = enable;
+ d->completeNow = FALSE;
+}
+
+
+bool TQComboBox::autoCompletion() const
+{
+ return d->useCompletion;
+}
+
+/*!\reimp
+ */
+void TQComboBox::styleChange( TQStyle& s )
+{
+ d->sizeHint = TQSize(); // invalidate size hint...
+ if ( d->ed )
+ d->updateLinedGeometry();
+ TQWidget::styleChange( s );
+}
+
+bool TQComboBox::editable() const
+{
+ return d->ed != 0;
+}
+
+void TQComboBox::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( StrongFocus );
+ updateGeometry();
+ update();
+}
+
+
+void TQComboBox::setUpListBox()
+{
+ d->setListBox( new TQListBox( this, "in-combo", WType_Popup ) );
+ d->listBox()->setFont( font() );
+ d->listBox()->setPalette( palette() );
+ d->listBox()->setVScrollBarMode( TQListBox::AlwaysOff );
+ d->listBox()->setHScrollBarMode( TQListBox::AlwaysOff );
+ d->listBox()->setFrameStyle( TQFrame::Box | TQFrame::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 TQComboBox::setUpLineEdit()
+{
+ if ( !d->ed )
+ setLineEdit( new TQLineEdit( this, "combo edit" ) );
+}
+
+/*!
+ Sets the line edit to use \a edit instead of the current line edit.
+*/
+
+void TQComboBox::setLineEdit( TQLineEdit *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, TQPoint(0,0), FALSE );
+
+ connect (edit, SIGNAL( textChanged(const TQString&) ),
+ this, SIGNAL( textChanged(const TQString&) ) );
+ connect( edit, SIGNAL(returnPressed()), SLOT(returnPressed()) );
+
+ edit->setFrame( FALSE );
+ d->updateLinedGeometry();
+ edit->installEventFilter( this );
+ setFocusProxy( edit );
+ setFocusPolicy( StrongFocus );
+ setInputMethodEnabled( TRUE );
+
+ if ( !d->usingListBox() )
+ setUpListBox();
+
+ if ( isVisible() )
+ edit->show();
+
+ updateGeometry();
+ update();
+}
+
+/*!
+ \reimp
+*/
+void TQComboBox::hide()
+{
+ TQWidget::hide();
+
+ if (listBox())
+ listBox()->hide();
+ else if (d->popup())
+ d->popup()->hide();
+}
+
+#endif // QT_NO_COMBOBOX