src/qt3support/widgets/q3combobox.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the Qt3Support module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "q3combobox.h"
       
    43 #ifndef QT_NO_COMBOBOX
       
    44 #include "qpainter.h"
       
    45 #include "qdrawutil.h"
       
    46 #include "qpixmap.h"
       
    47 #include "qtimer.h"
       
    48 #include "qapplication.h"
       
    49 #include "qlineedit.h"
       
    50 #include "qbitmap.h"
       
    51 #include "qstringlist.h"
       
    52 #include "qstyle.h"
       
    53 #include "qevent.h"
       
    54 #include "qmenu.h"
       
    55 #include "qmenudata.h"
       
    56 #include "qstyleoption.h"
       
    57 #include "qdesktopwidget.h"
       
    58 #include "q3popupmenu.h"
       
    59 #include "q3listbox.h"
       
    60 #include "q3strlist.h"
       
    61 #include "q3frame.h"
       
    62 #include <limits.h>
       
    63 #include <qdebug.h>
       
    64 #ifndef QT_NO_EFFECTS
       
    65 # include <private/qeffects_p.h>
       
    66 #endif
       
    67 #if defined(QT_ACCESSIBILITY_SUPPORT)
       
    68 #include "qaccessible.h"
       
    69 #endif
       
    70 
       
    71 QT_BEGIN_NAMESPACE
       
    72 
       
    73 /*!
       
    74     \class Q3ComboBox
       
    75     \brief The Q3ComboBox widget is a combined button and popup list.
       
    76     \since 4.1
       
    77     \compat
       
    78 
       
    79     A combobox is a selection widget which displays the current item
       
    80     and can pop up a list of items. A combobox may be editable in
       
    81     which case the user can enter arbitrary strings.
       
    82 
       
    83     Comboboxes provide a means of showing the user's current choice
       
    84     out of a list of options in a way that takes up the minimum amount
       
    85     of screen space.
       
    86 
       
    87     Q3ComboBox supports three different display styles: Aqua/Motif 1.x,
       
    88     Motif 2.0 and Windows. In Motif 1.x, a combobox was called
       
    89     XmOptionMenu. In Motif 2.0, OSF introduced an improved combobox
       
    90     and named that XmComboBox. Q3ComboBox provides both.
       
    91 
       
    92     Q3ComboBox provides two different constructors. The simplest
       
    93     constructor creates an "old-style" combobox in Motif (or Aqua)
       
    94     style:
       
    95     \snippet doc/src/snippets/code/src_qt3support_widgets_q3combobox.cpp 0
       
    96 
       
    97     The other constructor creates a new-style combobox in Motif style,
       
    98     and can create both read-only and editable comboboxes:
       
    99     \snippet doc/src/snippets/code/src_qt3support_widgets_q3combobox.cpp 1
       
   100 
       
   101     New-style comboboxes use a list box in both Motif and Windows
       
   102     styles, and both the content size and the on-screen size of the
       
   103     list box can be limited with sizeLimit() and setMaxCount()
       
   104     respectively. Old-style comboboxes use a popup in Aqua and Motif
       
   105     style, and that popup will happily grow larger than the desktop if
       
   106     you put enough data into it.
       
   107 
       
   108     The two constructors create identical-looking comboboxes in
       
   109     Windows style.
       
   110 
       
   111     Comboboxes can contain pixmaps as well as strings; the
       
   112     insertItem() and changeItem() functions are suitably overloaded.
       
   113     For editable comboboxes, the function clearEdit() is provided,
       
   114     to clear the displayed string without changing the combobox's
       
   115     contents.
       
   116 
       
   117     A combobox emits two signals, activated() and highlighted(), when
       
   118     a new item has been activated (selected) or highlighted (made
       
   119     current). Both signals exist in two versions, one with a \c
       
   120     QString argument and one with an \c int argument. If the user
       
   121     highlights or activates a pixmap, only the \c int signals are
       
   122     emitted. Whenever the text of an editable combobox is changed the
       
   123     textChanged() signal is emitted.
       
   124 
       
   125     When the user enters a new string in an editable combobox, the
       
   126     widget may or may not insert it, and it can insert it in several
       
   127     locations. The default policy is is \c AtBottom but you can change
       
   128     this using setInsertionPolicy().
       
   129 
       
   130     It is possible to constrain the input to an editable combobox
       
   131     using QValidator; see setValidator(). By default, any input is
       
   132     accepted.
       
   133 
       
   134     If the combobox is not editable then it has a default
       
   135     focusPolicy() of \c TabFocus, i.e. it will not grab focus if
       
   136     clicked. This differs from both Windows and Motif. If the combobox
       
   137     is editable then it has a default focusPolicy() of \c StrongFocus,
       
   138     i.e. it will grab focus if clicked.
       
   139 
       
   140     A combobox can be populated using the insert functions,
       
   141     insertStringList() and insertItem() for example. Items can be
       
   142     changed with changeItem(). An item can be removed with
       
   143     removeItem() and all items can be removed with clear(). The text
       
   144     of the current item is returned by currentText(), and the text of
       
   145     a numbered item is returned with text(). The current item can be
       
   146     set with setCurrentItem() or setCurrentText(). The number of items
       
   147     in the combobox is returned by count(); the maximum number of
       
   148     items can be set with setMaxCount(). You can allow editing using
       
   149     setEditable(). For editable comboboxes you can set auto-completion
       
   150     using setAutoCompletion() and whether or not the user can add
       
   151     duplicates is set with setDuplicatesEnabled().
       
   152 
       
   153     Depending on the style, Q3ComboBox will use a list box or a
       
   154     popup menu to display the list of items. See setListBox() for
       
   155     more information.
       
   156 
       
   157     \sa QComboBox, QLineEdit, QSpinBox
       
   158         {GUI Design Handbook}{GUI Design Handbook: Combo Box, Drop-Down List Box}
       
   159 */
       
   160 
       
   161 
       
   162 /*!
       
   163     \enum Q3ComboBox::Policy
       
   164 
       
   165     This enum specifies what the Q3ComboBox should do when a new string
       
   166     is entered by the user.
       
   167 
       
   168     \value NoInsertion the string will not be inserted into the
       
   169     combobox.
       
   170 
       
   171     \value AtTop insert the string as the first item in the combobox.
       
   172 
       
   173     \value AtCurrent replace the previously selected item with the
       
   174     string the user has entered.
       
   175 
       
   176     \value AtBottom insert the string as the last item in the
       
   177     combobox.
       
   178 
       
   179     \value AfterCurrent insert the string after the previously
       
   180     selected item.
       
   181 
       
   182     \value BeforeCurrent insert the string before the previously
       
   183     selected item.
       
   184 
       
   185     activated() is always emitted when the string is entered.
       
   186 
       
   187     If inserting the new string would cause the combobox to breach its
       
   188     content size limit, the item at the other end of the list is
       
   189     deleted. The definition of "other end" is
       
   190     implementation-dependent.
       
   191 
       
   192     \omitvalue NoInsert
       
   193     \omitvalue InsertAtTop
       
   194     \omitvalue InsertAtCurrent
       
   195     \omitvalue InsertAtBottom
       
   196     \omitvalue InsertAfterCurrent
       
   197     \omitvalue InsertBeforeCurrent
       
   198 */
       
   199 
       
   200 
       
   201 /*!
       
   202     \fn void Q3ComboBox::activated( int index )
       
   203 
       
   204     This signal is emitted when a new item has been activated
       
   205     (selected). The \a index is the position of the item in the
       
   206     combobox.
       
   207 
       
   208     This signal is not emitted if the item is changed
       
   209     programmatically, e.g. using setCurrentItem().
       
   210 */
       
   211 
       
   212 /*!
       
   213     \overload
       
   214     \fn void Q3ComboBox::activated( const QString &string )
       
   215 
       
   216     This signal is emitted when a new item has been activated
       
   217     (selected). \a string is the selected string.
       
   218 
       
   219     You can also use the activated(int) signal, but be aware that its
       
   220     argument is meaningful only for selected strings, not for user
       
   221     entered strings.
       
   222 */
       
   223 
       
   224 /*!
       
   225     \fn void Q3ComboBox::highlighted( int index )
       
   226 
       
   227     This signal is emitted when a new item has been set to be the
       
   228     current item. The \a index is the position of the item in the
       
   229     combobox.
       
   230 
       
   231     This signal is not emitted if the item is changed
       
   232     programmatically, e.g. using setCurrentItem().
       
   233 */
       
   234 
       
   235 /*!
       
   236     \overload
       
   237     \fn void Q3ComboBox::highlighted( const QString &string )
       
   238 
       
   239     This signal is emitted when a new item has been set to be the
       
   240     current item. \a string is the item's text.
       
   241 
       
   242     You can also use the highlighted(int) signal.
       
   243 */
       
   244 
       
   245 /*!
       
   246     \fn void Q3ComboBox::textChanged( const QString &string )
       
   247 
       
   248     This signal is used for editable comboboxes. It is emitted
       
   249     whenever the contents of the text entry field changes. \a string
       
   250     contains the new text.
       
   251 */
       
   252 
       
   253 /*!
       
   254     \property Q3ComboBox::autoCompletion
       
   255     \brief whether auto-completion is enabled
       
   256 
       
   257     This property can only be set for editable comboboxes, for
       
   258     non-editable comboboxes it has no effect. It is false by default.
       
   259 */
       
   260 
       
   261 /*!
       
   262     \property Q3ComboBox::autoResize
       
   263     \brief whether auto-resize is enabled
       
   264     \obsolete
       
   265 
       
   266     If this property is set to true then the combobox will resize
       
   267     itself whenever its contents change. The default is false.
       
   268 */
       
   269 
       
   270 /*!
       
   271     \property Q3ComboBox::count
       
   272     \brief the number of items in the combobox
       
   273 */
       
   274 
       
   275 /*!
       
   276     \property Q3ComboBox::currentItem
       
   277     \brief the index of the current item in the combobox
       
   278 
       
   279     Note that the activated() and highlighted() signals are only
       
   280     emitted when the user changes the current item, not when it is
       
   281     changed programmatically.
       
   282 */
       
   283 
       
   284 /*!
       
   285     \property Q3ComboBox::currentText
       
   286     \brief the text of the combobox's current item
       
   287 */
       
   288 
       
   289 /*!
       
   290     \property Q3ComboBox::duplicatesEnabled
       
   291     \brief whether duplicates are allowed
       
   292 
       
   293     If the combobox is editable and the user enters some text in the
       
   294     combobox's lineedit and presses Enter (and the insertionPolicy()
       
   295     is not \c NoInsertion), then what happens is this:
       
   296     \list
       
   297     \i If the text is not already in the list, the text is inserted.
       
   298     \i If the text is in the list and this property is true (the
       
   299     default), the text is inserted.
       
   300     \i If the text is in the list and this property is false, the text
       
   301     is \e not inserted; instead the item which has matching text becomes
       
   302     the current item.
       
   303     \endlist
       
   304 
       
   305     This property only affects user-interaction. You can use
       
   306     insertItem() to insert duplicates if you wish regardless of this
       
   307     setting.
       
   308 */
       
   309 
       
   310 /*!
       
   311     \property Q3ComboBox::editable
       
   312     \brief whether the combobox is editable
       
   313 
       
   314     This property's default is false. Note that the combobox will be
       
   315     cleared if this property is set to true for a 1.x Motif style
       
   316     combobox. To avoid this, use setEditable() before inserting any
       
   317     items. Also note that the 1.x version of Motif didn't have any
       
   318     editable comboboxes, so the combobox will change its appearance
       
   319     to a 2.0 style Motif combobox is it is set to be editable.
       
   320 */
       
   321 
       
   322 /*!
       
   323     \property Q3ComboBox::insertionPolicy
       
   324     \brief the position of the items inserted by the user
       
   325 
       
   326     The default insertion policy is \c AtBottom. See \l Policy.
       
   327 */
       
   328 
       
   329 /*!
       
   330     \property Q3ComboBox::maxCount
       
   331     \brief the maximum number of items allowed in the combobox
       
   332 */
       
   333 
       
   334 /*!
       
   335     \property Q3ComboBox::sizeLimit
       
   336     \brief the maximum on-screen size of the combobox.
       
   337 
       
   338     This property is ignored for both Motif 1.x style and non-editable
       
   339     comboboxes in Mac style. The default limit is ten
       
   340     lines. If the number of items in the combobox is or grows larger
       
   341     than lines, a scroll bar is added.
       
   342 */
       
   343 
       
   344 class Q3ComboBoxPopup : public Q3PopupMenu
       
   345 {
       
   346 public:
       
   347     Q3ComboBoxPopup( QWidget *parent=0, const char *name=0 )
       
   348 	: Q3PopupMenu( parent, name )
       
   349     {
       
   350     }
       
   351 
       
   352     int itemHeight( int index )
       
   353     {
       
   354 	return Q3PopupMenu::itemHeight( index );
       
   355     }
       
   356 };
       
   357 
       
   358 static inline QString escapedComboString(const QString &str)
       
   359 {
       
   360     QString stringToReturn = str;
       
   361     return stringToReturn.replace(QLatin1Char('&'), QLatin1String("&&"));
       
   362 }
       
   363 
       
   364 class Q3ComboBoxPopupItem : public QMenuItem
       
   365 {
       
   366     Q3ListBoxItem *li;
       
   367     QSize sc; // Size cache optimization
       
   368 public:
       
   369     Q3ComboBoxPopupItem(Q3ListBoxItem *i) : QMenuItem(), li(i), sc(0, 0) {  }
       
   370     virtual bool fullSpan() const { return true; }
       
   371     virtual void paint( QPainter*, const QColorGroup&, bool, bool, int, int, int, int);
       
   372     virtual QSize sizeHint() { if (sc.isNull()) sc = QSize(li->width(li->listBox()), QMAX(25, li->height(li->listBox()))); return sc; }
       
   373 };
       
   374 void Q3ComboBoxPopupItem::paint( QPainter* p, const QColorGroup&, bool,
       
   375 				bool, int x, int y, int, int)
       
   376 {
       
   377     p->save();
       
   378     p->translate(x, y + ((sizeHint().height() / 2) - (li->height(li->listBox()) / 2)));
       
   379     li->paint(p);
       
   380     p->restore();
       
   381 }
       
   382 
       
   383 
       
   384 class Q3ComboBoxData
       
   385 {
       
   386 public:
       
   387     Q3ComboBoxData( Q3ComboBox *cb ): current( 0 ), arrowDown(false), ed( 0 ), usingLBox( false ), pop( 0 ), lBox( 0 ), combo( cb )
       
   388     {
       
   389 	duplicatesEnabled = true;
       
   390 	cb->setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed ) );
       
   391     }
       
   392 
       
   393     inline bool usingListBox()  { return usingLBox; }
       
   394     inline Q3ListBox * listBox() { return lBox; }
       
   395     inline Q3ComboBoxPopup * popup() { return pop; }
       
   396     void updateLinedGeometry();
       
   397 
       
   398     void setListBox( Q3ListBox *l ) { lBox = l ; usingLBox = true;
       
   399 				l->setMouseTracking( true );}
       
   400 
       
   401     void setPopupMenu( Q3ComboBoxPopup * pm, bool isPopup=true )
       
   402 	{ pop = pm; if(isPopup) usingLBox = false; }
       
   403 
       
   404     QStyleOptionComboBox getStyleOption() const
       
   405         {
       
   406             QStyleOptionComboBox opt;
       
   407             opt.init(combo);
       
   408             if (!combo->editable() && combo->hasFocus())
       
   409                 opt.state |= QStyle::State_Selected;
       
   410             opt.subControls = QStyle::SC_All;
       
   411             if (arrowDown) {
       
   412                 opt.activeSubControls = QStyle::SC_ComboBoxArrow;
       
   413                 opt.state |= QStyle::State_Sunken;
       
   414             }
       
   415             opt.editable = combo->editable();
       
   416             opt.frame = 1; // ### get from style?
       
   417             if (current > -1 && current < combo->count()) {
       
   418                 opt.currentText = combo->text(current);
       
   419                 if (combo->pixmap(current))
       
   420                     opt.currentIcon = QIcon(*combo->pixmap(current));
       
   421             }
       
   422             opt.iconSize = QSize(22, 22); // ### need a sane value here
       
   423 //             if (container && container->isVisible())
       
   424 //                 opt.state |= QStyle::State_On;
       
   425             return opt;
       
   426         }
       
   427 
       
   428     int		current;
       
   429     int		maxCount;
       
   430     int		sizeLimit;
       
   431     Q3ComboBox::Policy p;
       
   432     bool	autoresize;
       
   433     bool	poppedUp;
       
   434     bool	mouseWasInsidePopup;
       
   435     bool	arrowPressed;
       
   436     bool	arrowDown;
       
   437     bool	discardNextMousePress;
       
   438     bool	shortClick;
       
   439     bool	useCompletion;
       
   440     bool	completeNow;
       
   441     int		completeAt;
       
   442     bool duplicatesEnabled;
       
   443     int fullHeight, currHeight;
       
   444 
       
   445     QLineEdit * ed;  // /bin/ed rules!
       
   446     QTimer *completionTimer;
       
   447 
       
   448     QSize sizeHint;
       
   449     QHash<int, QPixmap> popupPixmaps;
       
   450 
       
   451 private:
       
   452     bool	usingLBox;
       
   453     Q3ComboBoxPopup *pop;
       
   454     Q3ListBox   *lBox;
       
   455     Q3ComboBox *combo;
       
   456 };
       
   457 
       
   458 void Q3ComboBoxData::updateLinedGeometry()
       
   459 {
       
   460     if ( !ed || !combo )
       
   461 	return;
       
   462 
       
   463     QStyleOptionComboBox opt = getStyleOption();
       
   464     QRect r = combo->style()->subControlRect(
       
   465         QStyle::CC_ComboBox, &opt, QStyle::SC_ComboBoxEditField, combo);
       
   466 
       
   467     const QPixmap *pix = current < combo->count() ? combo->pixmap( current ) : 0;
       
   468     if ( pix && pix->width() < r.width() )
       
   469 	r.setLeft( r.left() + pix->width() + 4 );
       
   470     if ( r != ed->geometry() )
       
   471 	ed->setGeometry( r );
       
   472 }
       
   473 
       
   474 static inline bool checkInsertIndex( const char *method, const char * name,
       
   475 				     int count, int *index)
       
   476 {
       
   477     bool range_err = (*index > count);
       
   478 #if defined(QT_CHECK_RANGE)
       
   479     if ( range_err )
       
   480 	qWarning( "Q3ComboBox::%s: (%s) Index %d out of range",
       
   481 		 method, name ? name : "<no name>", *index );
       
   482 #else
       
   483     Q_UNUSED( method )
       
   484     Q_UNUSED( name )
       
   485 #endif
       
   486     if ( *index < 0 )				// append
       
   487 	*index = count;
       
   488     return !range_err;
       
   489 }
       
   490 
       
   491 
       
   492 static inline bool checkIndex( const char *method, const char * name,
       
   493 			       int count, int index )
       
   494 {
       
   495     bool range_err = (index >= count);
       
   496 #if defined(QT_CHECK_RANGE)
       
   497     if ( range_err )
       
   498 	qWarning( "Q3ComboBox::%s: (%s) Index %i out of range",
       
   499 		 method, name ? name : "<no name>", index );
       
   500 #else
       
   501     Q_UNUSED( method )
       
   502     Q_UNUSED( name )
       
   503 #endif
       
   504     return !range_err;
       
   505 }
       
   506 
       
   507 
       
   508 
       
   509 /*!
       
   510     Constructs a combobox widget with parent \a parent called \a name.
       
   511 
       
   512     This constructor creates a popup list if the program uses Motif
       
   513     (or Aqua) look and feel; this is compatible with Motif 1.x and
       
   514     Aqua.
       
   515 
       
   516     Note: If you use this constructor to create your Q3ComboBox, then
       
   517     the pixmap() function will always return 0. To workaround this,
       
   518     use the other constructor.
       
   519 
       
   520 */
       
   521 
       
   522 
       
   523 
       
   524 Q3ComboBox::Q3ComboBox( QWidget *parent, const char *name )
       
   525     : QWidget( parent, name, Qt::WNoAutoErase )
       
   526 {
       
   527     d = new Q3ComboBoxData( this );
       
   528     QStyleOptionComboBox opt;
       
   529     opt.init(this);
       
   530     if ( style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, this) ||
       
   531 	 style()->styleHint(QStyle::SH_GUIStyle, &opt, this) == Qt::MotifStyle ) {
       
   532 	d->setPopupMenu( new Q3ComboBoxPopup( this, "in-combo" ) );
       
   533 	d->popup()->setFont( font() );
       
   534 	connect( d->popup(), SIGNAL(activated(int)),
       
   535 			     SLOT(internalActivate(int)) );
       
   536 	connect( d->popup(), SIGNAL(highlighted(int)),
       
   537 			     SLOT(internalHighlight(int)) );
       
   538     } else {
       
   539 	setUpListBox();
       
   540     }
       
   541     d->ed                    = 0;
       
   542     d->current               = 0;
       
   543     d->maxCount              = INT_MAX;
       
   544     d->sizeLimit	     = 10;
       
   545     d->p                     = AtBottom;
       
   546     d->autoresize            = false;
       
   547     d->poppedUp              = false;
       
   548     d->arrowDown             = false;
       
   549     d->arrowPressed          = false;
       
   550     d->discardNextMousePress = false;
       
   551     d->shortClick            = false;
       
   552     d->useCompletion         = false;
       
   553     d->completeAt            = 0;
       
   554     d->completeNow           = false;
       
   555     d->completionTimer       = new QTimer( this );
       
   556 
       
   557     setFocusPolicy( Qt::TabFocus );
       
   558     setBackgroundMode( Qt::PaletteButton );
       
   559 }
       
   560 
       
   561 
       
   562 /*!
       
   563     Constructs a combobox with a maximum size and either Motif 2.0 or
       
   564     Windows look and feel.
       
   565 
       
   566     The input field can be edited if \a rw is true, otherwise the user
       
   567     may only choose one of the items in the combobox.
       
   568 
       
   569     The \a parent and \a name arguments are passed on to the QWidget
       
   570     constructor.
       
   571 */
       
   572 
       
   573 
       
   574 Q3ComboBox::Q3ComboBox( bool rw, QWidget *parent, const char *name )
       
   575     : QWidget( parent, name, Qt::WNoAutoErase )
       
   576 {
       
   577     d = new Q3ComboBoxData( this );
       
   578     setUpListBox();
       
   579 
       
   580     QStyleOptionComboBox opt = d->getStyleOption();
       
   581     if(d->popup() && style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, this))
       
   582 	d->popup()->setItemChecked(d->current, false);
       
   583     d->maxCount = INT_MAX;
       
   584     setSizeLimit(10);
       
   585     d->p = AtBottom;
       
   586     d->autoresize = false;
       
   587     d->poppedUp = false;
       
   588     d->arrowDown = false;
       
   589     d->discardNextMousePress = false;
       
   590     d->shortClick = false;
       
   591     d->useCompletion = false;
       
   592     d->completeAt = 0;
       
   593     d->completeNow = false;
       
   594     d->completionTimer = new QTimer( this );
       
   595 
       
   596     setFocusPolicy( Qt::StrongFocus );
       
   597 
       
   598     d->ed = 0;
       
   599     if ( rw )
       
   600 	setUpLineEdit();
       
   601     setBackgroundMode( Qt::PaletteButton, Qt::PaletteBase );
       
   602 }
       
   603 
       
   604 
       
   605 
       
   606 /*!
       
   607     Destroys the combobox.
       
   608 */
       
   609 
       
   610 Q3ComboBox::~Q3ComboBox()
       
   611 {
       
   612     delete d;
       
   613 }
       
   614 
       
   615 void Q3ComboBox::setDuplicatesEnabled( bool enable )
       
   616 {
       
   617    d->duplicatesEnabled = enable;
       
   618 }
       
   619 
       
   620 bool Q3ComboBox::duplicatesEnabled() const
       
   621 {
       
   622     return d->duplicatesEnabled;
       
   623 }
       
   624 
       
   625 int Q3ComboBox::count() const
       
   626 {
       
   627     if ( d->usingListBox() )
       
   628 	return d->listBox()->count();
       
   629     else if (d->popup())
       
   630 	return d->popup()->count();
       
   631     else
       
   632         return 0;
       
   633 }
       
   634 
       
   635 
       
   636 /*!
       
   637     \overload
       
   638 
       
   639     Inserts the \a list of strings at position \a index in the
       
   640     combobox.
       
   641 
       
   642     This is only for compatibility since it does not support Unicode
       
   643     strings. See insertStringList().
       
   644 */
       
   645 
       
   646 void Q3ComboBox::insertStrList( const Q3StrList &list, int index )
       
   647 {
       
   648     insertStrList( &list, index );
       
   649 }
       
   650 
       
   651 /*!
       
   652     \overload
       
   653 
       
   654     Inserts the \a list of strings at position \a index in the
       
   655     combobox.
       
   656 
       
   657     This is only for compatibility since it does not support Unicode
       
   658     strings. See insertStringList().
       
   659 */
       
   660 
       
   661 void Q3ComboBox::insertStrList( const Q3StrList *list, int index )
       
   662 {
       
   663     if ( !list ) {
       
   664 #if defined(QT_CHECK_NULL)
       
   665 	Q_ASSERT( list != 0 );
       
   666 #endif
       
   667 	return;
       
   668     }
       
   669     Q3StrListIterator it( *list );
       
   670     const char* tmp;
       
   671     if ( index < 0 )
       
   672 	index = count();
       
   673     while ( (tmp=it.current()) ) {
       
   674 	++it;
       
   675 	if ( d->usingListBox() )
       
   676 	    d->listBox()->insertItem( QString::fromLatin1(tmp), index );
       
   677 	else
       
   678 	    d->popup()->insertItem( escapedComboString(QString::fromLatin1(tmp)), index, index );
       
   679 	if ( index++ == d->current && d->current < count() ) {
       
   680 	    if ( d->ed ) {
       
   681 		d->ed->setText( text( d->current ) );
       
   682 		d->updateLinedGeometry();
       
   683 	    } else
       
   684 		update();
       
   685 	    currentChanged();
       
   686 	}
       
   687     }
       
   688     if ( index != count() )
       
   689 	reIndex();
       
   690 }
       
   691 
       
   692 /*!
       
   693     Inserts the \a list of strings at position \a index in the
       
   694     combobox.
       
   695 */
       
   696 
       
   697 void Q3ComboBox::insertStringList( const QStringList &list, int index )
       
   698 {
       
   699     QStringList::ConstIterator it = list.begin();
       
   700     if ( index < 0 )
       
   701 	index = count();
       
   702     while ( it != list.end() ) {
       
   703 	if ( d->usingListBox() )
       
   704 	    d->listBox()->insertItem( *it, index );
       
   705 	else
       
   706 	    d->popup()->insertItem( escapedComboString(*it), index, index );
       
   707 	if ( index++ == d->current && d->current < count() ) {
       
   708 	    if ( d->ed ) {
       
   709 		d->ed->setText( text( d->current ) );
       
   710 		d->updateLinedGeometry();
       
   711 	    } else
       
   712 		update();
       
   713 	    currentChanged();
       
   714 	}
       
   715 	++it;
       
   716     }
       
   717     if ( index != count() )
       
   718 	reIndex();
       
   719 }
       
   720 
       
   721 /*!
       
   722     Inserts the array of char * \a strings at position \a index in the
       
   723     combobox.
       
   724 
       
   725     The \a numStrings argument is the number of strings. If \a
       
   726     numStrings is -1 (default), the \a strings array must be
       
   727     terminated with 0.
       
   728 
       
   729     Example:
       
   730     \snippet doc/src/snippets/code/src_qt3support_widgets_q3combobox.cpp 2
       
   731 
       
   732     \sa insertStringList()
       
   733 */
       
   734 
       
   735 void Q3ComboBox::insertStrList( const char **strings, int numStrings, int index)
       
   736 {
       
   737     if ( !strings ) {
       
   738 #if defined(QT_CHECK_NULL)
       
   739 	Q_ASSERT( strings != 0 );
       
   740 #endif
       
   741 	return;
       
   742     }
       
   743     if ( index < 0 )
       
   744 	index = count();
       
   745     int i = 0;
       
   746     while ( (numStrings<0 && strings[i]!=0) || i<numStrings ) {
       
   747 	if ( d->usingListBox() )
       
   748 	    d->listBox()->insertItem( QString::fromLatin1(strings[i]), index );
       
   749 	else
       
   750 	    d->popup()->insertItem( escapedComboString(QString::fromLatin1(strings[i])), index, index );
       
   751 	i++;
       
   752 	if ( index++ == d->current && d->current < count()  ) {
       
   753 	    if ( d->ed ) {
       
   754 		d->ed->setText( text( d->current ) );
       
   755 		d->updateLinedGeometry();
       
   756 	    } else
       
   757 		update();
       
   758 	    currentChanged();
       
   759 	}
       
   760     }
       
   761     if ( index != count() )
       
   762 	reIndex();
       
   763 }
       
   764 
       
   765 
       
   766 /*!
       
   767     Inserts a text item with text \a t, at position \a index. The item
       
   768     will be appended if \a index is negative.
       
   769 */
       
   770 
       
   771 void Q3ComboBox::insertItem( const QString &t, int index )
       
   772 {
       
   773     int cnt = count();
       
   774     if ( !checkInsertIndex( "insertItem", name(), cnt, &index ) )
       
   775 	return;
       
   776     if ( d->usingListBox() )
       
   777 	d->listBox()->insertItem( t, index );
       
   778     else
       
   779 	d->popup()->insertItem( escapedComboString(t), index, index );
       
   780     if ( index != cnt )
       
   781 	reIndex();
       
   782     if ( index == d->current && d->current < count()  ) {
       
   783 	if ( d->ed ) {
       
   784 	    d->ed->setText( text( d->current ) );
       
   785 	    d->updateLinedGeometry();
       
   786 	} else
       
   787 	    update();
       
   788     }
       
   789     if ( index == d->current )
       
   790 	currentChanged();
       
   791 }
       
   792 
       
   793 /*!
       
   794     \overload
       
   795 
       
   796     Inserts a \a pixmap item at position \a index. The item will be
       
   797     appended if \a index is negative.
       
   798 */
       
   799 
       
   800 void Q3ComboBox::insertItem( const QPixmap &pixmap, int index )
       
   801 {
       
   802     int cnt = count();
       
   803     if ( !checkInsertIndex( "insertItem", name(), cnt, &index ) )
       
   804 	return;
       
   805     if ( d->usingListBox() )
       
   806 	d->listBox()->insertItem( pixmap, index );
       
   807     else
       
   808 	d->popup()->insertItem( pixmap, index, index );
       
   809     if ( index != cnt )
       
   810 	reIndex();
       
   811     if ( index == d->current && d->current < count()  ) {
       
   812 	if ( d->ed ) {
       
   813 	    d->ed->setText( text( d->current ) );
       
   814 	    d->updateLinedGeometry();
       
   815 	} else
       
   816 	    update();
       
   817     }
       
   818     if ( index == d->current )
       
   819 	currentChanged();
       
   820 }
       
   821 
       
   822 /*!
       
   823     \overload
       
   824 
       
   825     Inserts a \a pixmap item with additional text \a text at position
       
   826     \a index. The item will be appended if \a index is negative.
       
   827 */
       
   828 
       
   829 void Q3ComboBox::insertItem( const QPixmap &pixmap, const QString& text, int index )
       
   830 {
       
   831     int cnt = count();
       
   832     if ( !checkInsertIndex( "insertItem", name(), cnt, &index ) )
       
   833 	return;
       
   834     if ( d->usingListBox() )
       
   835 	d->listBox()->insertItem( pixmap, text, index );
       
   836     else
       
   837 	d->popup()->insertItem( pixmap, escapedComboString(text), index, index );
       
   838     if ( index != cnt )
       
   839 	reIndex();
       
   840     if ( index == d->current && d->current < count()  ) {
       
   841 	if ( d->ed ) {
       
   842 	    d->ed->setText( this->text( d->current ) );
       
   843 	    d->updateLinedGeometry();
       
   844 	} else
       
   845 	    update();
       
   846     }
       
   847     if ( index == d->current )
       
   848 	currentChanged();
       
   849 }
       
   850 
       
   851 
       
   852 /*!
       
   853     Removes the item at position \a index.
       
   854 */
       
   855 
       
   856 void Q3ComboBox::removeItem( int index )
       
   857 {
       
   858     int cnt = count();
       
   859     if ( !checkIndex( "removeItem", name(), cnt, index ) )
       
   860 	return;
       
   861     if ( d->usingListBox() ) {
       
   862         QStyleOptionComboBox opt = d->getStyleOption();
       
   863 	if ( style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, this) && d->popup() )
       
   864 	    d->popup()->removeItemAt( index );
       
   865 	d->listBox()->removeItem( index );
       
   866     } else {
       
   867 	d->popup()->removeItemAt( index );
       
   868     }
       
   869     if ( index != cnt-1 )
       
   870 	reIndex();
       
   871     if ( index == d->current ) {
       
   872 	if ( d->ed ) {
       
   873 	    QString s = QString::fromLatin1("");
       
   874 	    if (d->current < cnt - 1)
       
   875 		s = text( d->current );
       
   876 	    d->ed->setText( s );
       
   877 	    d->updateLinedGeometry();
       
   878 	}
       
   879 	else {
       
   880 	    if ( d->usingListBox() ) {
       
   881 		d->current = d->listBox()->currentItem();
       
   882 	    } else {
       
   883 		if (d->current > count()-1 && d->current > 0)
       
   884 		    d->current--;
       
   885 	    }
       
   886 	    update();
       
   887 	}
       
   888 	currentChanged();
       
   889     }
       
   890     else {
       
   891 	if ( !d->ed ) {
       
   892 	    if (d->current < cnt - 1)
       
   893 		setCurrentItem( d->current );
       
   894 	    else
       
   895 		setCurrentItem( d->current - 1 );
       
   896 	}
       
   897     }
       
   898 
       
   899 }
       
   900 
       
   901 
       
   902 /*!
       
   903     Removes all combobox items.
       
   904 */
       
   905 
       
   906 void Q3ComboBox::clear()
       
   907 {
       
   908     QStyleOptionComboBox opt = d->getStyleOption();
       
   909     if ( d->usingListBox() ) {
       
   910 	if ( style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, this) && d->popup() )
       
   911 	    d->popup()->clear();
       
   912 	d->listBox()->resize( 0, 0 );
       
   913 	d->listBox()->clear();
       
   914     } else {
       
   915 	d->popup()->clear();
       
   916     }
       
   917 
       
   918     if(d->popup() && style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, this))
       
   919 	d->popup()->setItemChecked(d->current, false);
       
   920     d->current = 0;
       
   921     if ( d->ed ) {
       
   922 	d->ed->setText( QString::fromLatin1("") );
       
   923 	d->updateLinedGeometry();
       
   924     }
       
   925     currentChanged();
       
   926 }
       
   927 
       
   928 
       
   929 QString Q3ComboBox::currentText() const
       
   930 {
       
   931     if ( d->ed )
       
   932 	return d->ed->text();
       
   933     else if ( d->current < count() )
       
   934 	return text( currentItem() );
       
   935     else
       
   936 	return QString::null;
       
   937 }
       
   938 
       
   939 void Q3ComboBox::setCurrentText( const QString& txt )
       
   940 {
       
   941     int i;
       
   942     for ( i = 0; i < count(); i++)
       
   943 	if ( text( i ) == txt )
       
   944 	    break;
       
   945     if ( i < count() )
       
   946 	setCurrentItem( i );
       
   947     else if ( d->ed )
       
   948 	d->ed->setText( txt );
       
   949     else
       
   950 	changeItem( txt, currentItem() );
       
   951 }
       
   952 
       
   953 
       
   954 /*!
       
   955     Returns the text item at position \a index, or QString::null if
       
   956     the item is not a string.
       
   957 
       
   958     \sa currentText()
       
   959 */
       
   960 
       
   961 QString Q3ComboBox::text( int index ) const
       
   962 {
       
   963     if ( !checkIndex( "text", name(), count(), index ) )
       
   964 	return QString::null;
       
   965     if ( d->usingListBox() ) {
       
   966 	return d->listBox()->text( index );
       
   967     } else {
       
   968         QString retText = d->popup()->text(index);
       
   969         retText.replace(QLatin1String("&&"), QString(QLatin1Char('&')));
       
   970 	return retText;
       
   971     }
       
   972 }
       
   973 
       
   974 /*!
       
   975     Returns the pixmap item at position \a index, or 0 if the item is
       
   976     not a pixmap.
       
   977 */
       
   978 
       
   979 const QPixmap *Q3ComboBox::pixmap( int index ) const
       
   980 {
       
   981     if ( !checkIndex( "pixmap", name(), count(), index ) )
       
   982 	return 0;
       
   983 
       
   984     if (d->usingListBox()) {
       
   985         return d->listBox()->pixmap( index );
       
   986     } else {
       
   987         d->popupPixmaps[index] = d->popup()->pixmap(index);
       
   988         return d->popupPixmaps[index].isNull() ? 0 : &d->popupPixmaps[index];
       
   989     }
       
   990 }
       
   991 
       
   992 /*!
       
   993     Replaces the item at position \a index with the text \a t.
       
   994 */
       
   995 
       
   996 void Q3ComboBox::changeItem( const QString &t, int index )
       
   997 {
       
   998     if ( !checkIndex( "changeItem", name(), count(), index ) )
       
   999 	return;
       
  1000     if ( d->usingListBox() )
       
  1001 	d->listBox()->changeItem( t, index );
       
  1002     else
       
  1003 	d->popup()->changeItem(index, t);
       
  1004     if ( index == d->current ) {
       
  1005 	if ( d->ed ) {
       
  1006 	    d->ed->setText( text( d->current ) );
       
  1007 	    d->updateLinedGeometry();
       
  1008 	} else
       
  1009 	    update();
       
  1010     }
       
  1011 }
       
  1012 
       
  1013 /*!
       
  1014     \overload
       
  1015 
       
  1016     Replaces the item at position \a index with the pixmap \a im,
       
  1017     unless the combobox is editable.
       
  1018 
       
  1019     \sa insertItem()
       
  1020 */
       
  1021 
       
  1022 void Q3ComboBox::changeItem( const QPixmap &im, int index )
       
  1023 {
       
  1024     if ( !checkIndex( "changeItem", name(), count(), index ) )
       
  1025 	return;
       
  1026     if ( d->usingListBox() )
       
  1027 	d->listBox()->changeItem( im, index );
       
  1028     else
       
  1029 	d->popup()->changeItem(index, im);
       
  1030     if ( index == d->current )
       
  1031 	update();
       
  1032 }
       
  1033 
       
  1034 /*!
       
  1035     \overload
       
  1036 
       
  1037     Replaces the item at position \a index with the pixmap \a im and
       
  1038     the text \a t.
       
  1039 
       
  1040     \sa insertItem()
       
  1041 */
       
  1042 
       
  1043 void Q3ComboBox::changeItem( const QPixmap &im, const QString &t, int index )
       
  1044 {
       
  1045     if ( !checkIndex( "changeItem", name(), count(), index ) )
       
  1046 	return;
       
  1047     if ( d->usingListBox() )
       
  1048 	d->listBox()->changeItem( im, t, index );
       
  1049     else
       
  1050 	d->popup()->changeItem(index, im, t);
       
  1051     if ( index == d->current )
       
  1052 	update();
       
  1053 }
       
  1054 
       
  1055 
       
  1056 int Q3ComboBox::currentItem() const
       
  1057 {
       
  1058     return d->current;
       
  1059 }
       
  1060 
       
  1061 void Q3ComboBox::setCurrentItem( int index )
       
  1062 {
       
  1063     if ( index == d->current && !d->ed ) {
       
  1064 	return;
       
  1065     }
       
  1066     if ( !checkIndex( "setCurrentItem", name(), count(), index ) ) {
       
  1067 	return;
       
  1068     }
       
  1069 
       
  1070     if ( d->usingListBox() && !( listBox()->item(index) && listBox()->item(index)->isSelectable() ) )
       
  1071 	return;
       
  1072 
       
  1073     QStyleOptionComboBox opt = d->getStyleOption();
       
  1074     if(d->popup() && style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, this))
       
  1075 	d->popup()->setItemChecked(d->current, false);
       
  1076     d->current = index;
       
  1077     d->completeAt = 0;
       
  1078     if ( d->ed ) {
       
  1079 	d->ed->setText( text( index ) );
       
  1080 	d->updateLinedGeometry();
       
  1081     }
       
  1082     // ### We want to keep ListBox's currentItem in sync, even if NOT popuped...
       
  1083     if ( d->usingListBox() && d->listBox() ) {
       
  1084 	d->listBox()->setCurrentItem( index );
       
  1085     } else {
       
  1086 	internalHighlight( index );
       
  1087 	// internalActivate( index ); ### this leads to weird behavior, as in 3.0.1
       
  1088     }
       
  1089 
       
  1090     currentChanged();
       
  1091 }
       
  1092 
       
  1093 /*!
       
  1094     Returns true if auto-resize is enabled; otherwise returns false.
       
  1095 
       
  1096     \sa autoResize
       
  1097 */
       
  1098 
       
  1099 bool Q3ComboBox::autoResize() const
       
  1100 {
       
  1101     return d->autoresize;
       
  1102 }
       
  1103 
       
  1104 /*!
       
  1105     If \a enable is true, enable auto-resize; disable it otherwise.
       
  1106 
       
  1107     \sa autoResize
       
  1108 */
       
  1109 
       
  1110 void Q3ComboBox::setAutoResize( bool enable )
       
  1111 {
       
  1112     if ( (bool)d->autoresize != enable ) {
       
  1113 	d->autoresize = enable;
       
  1114 	if ( enable )
       
  1115 	    adjustSize();
       
  1116     }
       
  1117 }
       
  1118 
       
  1119 
       
  1120 /*!
       
  1121     \reimp
       
  1122 
       
  1123     This implementation caches the size hint to avoid resizing when
       
  1124     the contents change dynamically. To invalidate the cached value
       
  1125     call setFont().
       
  1126 */
       
  1127 QSize Q3ComboBox::sizeHint() const
       
  1128 {
       
  1129     if ( isVisible() && d->sizeHint.isValid() )
       
  1130 	return d->sizeHint;
       
  1131 
       
  1132     constPolish();
       
  1133     int i, w;
       
  1134     QFontMetrics fm = fontMetrics();
       
  1135 
       
  1136     int maxW = count() ? 18 : 7 * fm.width(QLatin1Char('x')) + 18;
       
  1137     int maxH = QMAX( fm.lineSpacing(), 14 ) + 2;
       
  1138 
       
  1139     if ( !d->usingListBox() ) {
       
  1140 	w = d->popup()->sizeHint().width() - 2* d->popup()->frameWidth();
       
  1141 	if ( w > maxW )
       
  1142 	    maxW = w;
       
  1143     } else {
       
  1144 	for( i = 0; i < count(); i++ ) {
       
  1145 	    w = d->listBox()->item( i )->width( d->listBox() );
       
  1146 	    if ( w > maxW )
       
  1147 		maxW = w;
       
  1148 	}
       
  1149     }
       
  1150 
       
  1151     QStyleOptionComboBox opt = d->getStyleOption();
       
  1152     d->sizeHint = (style()->sizeFromContents(QStyle::CT_ComboBox, &opt, QSize(maxW, maxH), this).
       
  1153                    expandedTo(QApplication::globalStrut()));
       
  1154 
       
  1155     return d->sizeHint;
       
  1156 }
       
  1157 
       
  1158 
       
  1159 /*!
       
  1160   \internal
       
  1161   Receives activated signals from an internal popup list and emits
       
  1162   the activated() signal.
       
  1163 */
       
  1164 
       
  1165 void Q3ComboBox::internalActivate( int index )
       
  1166 {
       
  1167     QStyleOptionComboBox opt = d->getStyleOption();
       
  1168     if ( d->current != index ) {
       
  1169 	if ( !d->usingListBox() || listBox()->item( index )->isSelectable() ) {
       
  1170 	    if (d->popup() && style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, this))
       
  1171 		d->popup()->setItemChecked(d->current, false);
       
  1172 	    d->current = index;
       
  1173 	    currentChanged();
       
  1174 	}
       
  1175     }
       
  1176     if ( d->usingListBox() )
       
  1177 	popDownListBox();
       
  1178     else
       
  1179 	d->popup()->removeEventFilter( this );
       
  1180     d->poppedUp = false;
       
  1181 
       
  1182     QString t( text( index ) );
       
  1183     if ( d->ed ) {
       
  1184 	d->ed->setText( t );
       
  1185 	d->updateLinedGeometry();
       
  1186     }
       
  1187     emit activated( index );
       
  1188     emit activated( t );
       
  1189 }
       
  1190 
       
  1191 /*!
       
  1192   \internal
       
  1193   Receives highlighted signals from an internal popup list and emits
       
  1194   the highlighted() signal.
       
  1195 */
       
  1196 
       
  1197 void Q3ComboBox::internalHighlight( int index )
       
  1198 {
       
  1199     emit highlighted( index );
       
  1200     QString t = text( index );
       
  1201     if ( !t.isNull() )
       
  1202 	emit highlighted( t );
       
  1203 }
       
  1204 
       
  1205 /*!
       
  1206   \internal
       
  1207   Receives timeouts after a click. Used to decide if a Motif style
       
  1208   popup should stay up or not after a click.
       
  1209 */
       
  1210 void Q3ComboBox::internalClickTimeout()
       
  1211 {
       
  1212     d->shortClick = false;
       
  1213 }
       
  1214 
       
  1215 /*!
       
  1216     Sets the palette for both the combobox button and the combobox
       
  1217     popup list to \a palette.
       
  1218 */
       
  1219 
       
  1220 void Q3ComboBox::setPalette( const QPalette &palette )
       
  1221 {
       
  1222     QWidget::setPalette( palette );
       
  1223     if ( d->listBox() )
       
  1224 	d->listBox()->setPalette( palette );
       
  1225     if ( d->popup() )
       
  1226 	d->popup()->setPalette( palette );
       
  1227 }
       
  1228 
       
  1229 /*!
       
  1230     Sets the font for both the combobox button and the combobox popup
       
  1231     list to \a font.
       
  1232 */
       
  1233 
       
  1234 void Q3ComboBox::setFont( const QFont &font )
       
  1235 {
       
  1236     d->sizeHint = QSize();		// invalidate size hint
       
  1237     QWidget::setFont( font );
       
  1238     if ( d->usingListBox() )
       
  1239 	d->listBox()->setFont( font );
       
  1240     else
       
  1241 	d->popup()->setFont( font );
       
  1242     if (d->ed)
       
  1243 	d->ed->setFont( font );
       
  1244     if ( d->autoresize )
       
  1245 	adjustSize();
       
  1246 }
       
  1247 
       
  1248 
       
  1249 /*!\reimp
       
  1250 */
       
  1251 
       
  1252 void Q3ComboBox::resizeEvent( QResizeEvent * e )
       
  1253 {
       
  1254     if ( d->ed )
       
  1255 	d->updateLinedGeometry();
       
  1256     if ( d->listBox() )
       
  1257 	d->listBox()->resize( width(), d->listBox()->height() );
       
  1258     QWidget::resizeEvent( e );
       
  1259 }
       
  1260 
       
  1261 /*!\reimp
       
  1262 */
       
  1263 
       
  1264 void Q3ComboBox::paintEvent( QPaintEvent * )
       
  1265 {
       
  1266     QPainter p( this );
       
  1267     const QColorGroup & g = colorGroup();
       
  1268     p.setPen(g.text());
       
  1269 
       
  1270     if ( width() < 5 || height() < 5 ) {
       
  1271 	qDrawShadePanel( &p, rect(), g, false, 2,
       
  1272 			 &g.brush( QColorGroup::Button ) );
       
  1273 	return;
       
  1274     }
       
  1275 
       
  1276     QStyleOptionComboBox opt = d->getStyleOption();
       
  1277     bool reverse = QApplication::reverseLayout();
       
  1278     if ( !d->usingListBox() &&
       
  1279 	 style()->styleHint(QStyle::SH_GUIStyle) == Qt::MotifStyle) {			// motif 1.x style
       
  1280 	int dist, buttonH, buttonW;
       
  1281 	dist     = 8;
       
  1282 	buttonH  = 7;
       
  1283 	buttonW  = 11;
       
  1284 	int xPos;
       
  1285 	int x0;
       
  1286 	int w = width() - dist - buttonW - 1;
       
  1287 	if ( reverse ) {
       
  1288 	    xPos = dist + 1;
       
  1289 	    x0 = xPos + 4;
       
  1290 	} else {
       
  1291 	    xPos = w;
       
  1292 	    x0 = 4;
       
  1293 	}
       
  1294 	qDrawShadePanel( &p, rect(), g, false,
       
  1295 			 style()->pixelMetric(QStyle::PM_DefaultFrameWidth, &opt, this),
       
  1296 			 &g.brush( QColorGroup::Button ) );
       
  1297 	qDrawShadePanel( &p, xPos, (height() - buttonH)/2,
       
  1298 			 buttonW, buttonH, g, false,
       
  1299 			 style()->pixelMetric(QStyle::PM_DefaultFrameWidth, &opt, this) );
       
  1300 	QRect clip( x0, 2, w - 2 - 4 - 5, height() - 4 );
       
  1301 	QString str = d->popup()->text( this->d->current );
       
  1302 	if ( !str.isNull() ) {
       
  1303 	    p.drawText( clip, Qt::AlignCenter | Qt::TextSingleLine, str );
       
  1304 	}
       
  1305 
       
  1306 	QPixmap pix = d->popup()->pixmap( this->d->current );
       
  1307 	QIcon iconSet = d->popup()->iconSet( this->d->current );
       
  1308 	if (!pix.isNull() || !iconSet.isNull()) {
       
  1309 	    QPixmap pm = ( !pix.isNull() ? pix : iconSet.pixmap() );
       
  1310 	    p.setClipRect( clip );
       
  1311 	    p.drawPixmap( 4, (height()-pm.height())/2, pm );
       
  1312 	    p.setClipping( false );
       
  1313 	}
       
  1314 
       
  1315 	if ( hasFocus() )
       
  1316 	    p.drawRect( xPos - 5, 4, width() - xPos + 1 , height() - 8 );
       
  1317     } else if(!d->usingListBox()) {
       
  1318 	style()->drawComplexControl(QStyle::CC_ComboBox, &opt, &p, this);
       
  1319         QRect re = style()->subControlRect(QStyle::CC_ComboBox, &opt,
       
  1320                                            QStyle::SC_ComboBoxEditField, this);
       
  1321 	p.setClipRect( re );
       
  1322 
       
  1323 	QString str = d->popup()->text( this->d->current );
       
  1324 	QPixmap pix = d->popup()->pixmap( this->d->current );
       
  1325 	if ( !str.isNull() ) {
       
  1326 	    p.save();
       
  1327 	    p.setFont(font());
       
  1328 	    QFontMetrics fm(font());
       
  1329 	    int x = re.x(), y = re.y() + fm.ascent();
       
  1330             x += pix.width() + 5;
       
  1331 	    p.drawText( x, y, str );
       
  1332 	    p.restore();
       
  1333 	}
       
  1334 	if (!pix.isNull()) {
       
  1335 	    p.fillRect(re.x(), re.y(), pix.width() + 4, re.height(),
       
  1336                         colorGroup().brush(QColorGroup::Base));
       
  1337 	    p.drawPixmap(re.x() + 2, re.y() + (re.height() - pix.height()) / 2, pix);
       
  1338 	}
       
  1339     } else {
       
  1340 	style()->drawComplexControl(QStyle::CC_ComboBox, &opt, &p, this);
       
  1341 	QRect re = style()->subControlRect(QStyle::CC_ComboBox, &opt,
       
  1342                                             QStyle::SC_ComboBoxEditField, this);
       
  1343 	p.setClipRect(re);
       
  1344 
       
  1345 	if ( !d->ed ) {
       
  1346 	    Q3ListBoxItem * item = d->listBox()->item( d->current );
       
  1347 	    if ( item ) {
       
  1348 		int itemh = item->height( d->listBox() );
       
  1349 		p.translate( re.x(), re.y() + (re.height() - itemh)/2  );
       
  1350 		item->paint( &p );
       
  1351 	    }
       
  1352 	} else if ( d->listBox() && d->listBox()->item( d->current ) ) {
       
  1353 	    Q3ListBoxItem * item = d->listBox()->item( d->current );
       
  1354 	    const QPixmap *pix = item->pixmap();
       
  1355 	    if ( pix ) {
       
  1356 		p.fillRect( re.x(), re.y(), pix->width() + 4, re.height(),
       
  1357 			    colorGroup().brush( QColorGroup::Base ) );
       
  1358 		p.drawPixmap( re.x() + 2, re.y() +
       
  1359 			      ( re.height() - pix->height() ) / 2, *pix );
       
  1360 	    }
       
  1361 	}
       
  1362 	p.setClipping( false );
       
  1363     }
       
  1364 }
       
  1365 
       
  1366 
       
  1367 /*!\reimp
       
  1368 */
       
  1369 
       
  1370 void Q3ComboBox::mousePressEvent( QMouseEvent *e )
       
  1371 {
       
  1372     if ( e->button() != Qt::LeftButton )
       
  1373 	return;
       
  1374     if ( d->discardNextMousePress ) {
       
  1375 	d->discardNextMousePress = false;
       
  1376 	return;
       
  1377     }
       
  1378 
       
  1379     QStyleOptionComboBox opt = d->getStyleOption();
       
  1380     QRect arrowRect = style()->subControlRect(QStyle::CC_ComboBox, &opt, QStyle::SC_ComboBoxArrow
       
  1381                                                , this);
       
  1382 
       
  1383     // Correction for motif style, where arrow is smaller
       
  1384     // and thus has a rect that doesn't fit the button.
       
  1385     arrowRect.setHeight( QMAX(  height() - (2 * arrowRect.y()), arrowRect.height() ) );
       
  1386 
       
  1387     if ( count() && ( !editable() || arrowRect.contains( e->pos() ) ) ) {
       
  1388 	d->arrowPressed = false;
       
  1389 
       
  1390 	if ( d->usingListBox() ) {
       
  1391 	    listBox()->blockSignals( true );
       
  1392 	    qApp->sendEvent( listBox(), e ); // trigger the listbox's autoscroll
       
  1393 	    listBox()->setCurrentItem(d->current);
       
  1394 	    listBox()->blockSignals( false );
       
  1395 	    popup();
       
  1396 	    if ( arrowRect.contains( e->pos() ) ) {
       
  1397 		d->arrowPressed = true;
       
  1398 		d->arrowDown    = true;
       
  1399 		repaint( false );
       
  1400 	    }
       
  1401 	} else {
       
  1402 	    popup();
       
  1403 	}
       
  1404 	QTimer::singleShot( 200, this, SLOT(internalClickTimeout()));
       
  1405 	d->shortClick = true;
       
  1406     }
       
  1407 }
       
  1408 
       
  1409 /*!\reimp
       
  1410 */
       
  1411 
       
  1412 void Q3ComboBox::mouseMoveEvent( QMouseEvent * )
       
  1413 {
       
  1414 }
       
  1415 
       
  1416 /*!\reimp
       
  1417 */
       
  1418 
       
  1419 void Q3ComboBox::mouseReleaseEvent( QMouseEvent * )
       
  1420 {
       
  1421 }
       
  1422 
       
  1423 /*!\reimp
       
  1424 */
       
  1425 
       
  1426 void Q3ComboBox::mouseDoubleClickEvent( QMouseEvent *e )
       
  1427 {
       
  1428     mousePressEvent( e );
       
  1429 }
       
  1430 
       
  1431 
       
  1432 /*!\reimp
       
  1433 */
       
  1434 
       
  1435 void Q3ComboBox::keyPressEvent( QKeyEvent *e )
       
  1436 {
       
  1437     bool handleEventHere = d->usingListBox() || !d->poppedUp;
       
  1438 
       
  1439     int c = currentItem();
       
  1440     if ( ( e->key() == Qt::Key_F4 && e->state() == 0 ) ||
       
  1441 	 ( e->key() == Qt::Key_Down && (e->state() & Qt::AltModifier) ) ||
       
  1442 	 ( !d->ed && e->key() == Qt::Key_Space ) ) {
       
  1443 	if ( count() ) {
       
  1444 	    if ( !d->usingListBox() )
       
  1445 		d->popup()->setActiveItem( this->d->current );
       
  1446 	    popup();
       
  1447 	}
       
  1448 	return;
       
  1449     } else if ( handleEventHere && e->key() == Qt::Key_Up ) {
       
  1450 	if ( c > 0 )
       
  1451 	    setCurrentItem( c-1 );
       
  1452     } else if ( handleEventHere && e->key() == Qt::Key_Down ) {
       
  1453 	if ( ++c < count() )
       
  1454 	    setCurrentItem( c );
       
  1455     } else if ( handleEventHere && e->key() == Qt::Key_Home && ( !d->ed || !d->ed->hasFocus() ) ) {
       
  1456 	setCurrentItem( 0 );
       
  1457     } else if ( handleEventHere && e->key() == Qt::Key_End && ( !d->ed || !d->ed->hasFocus() ) ) {
       
  1458 	setCurrentItem( count()-1 );
       
  1459     } else if ( !d->ed && e->ascii() >= 32 && !e->text().isEmpty() ) {
       
  1460 	if ( !d->completionTimer->isActive() ) {
       
  1461 	    d->completeAt = 0;
       
  1462 	    c = completionIndex( e->text(), ++c );
       
  1463 	    if ( c >= 0 ) {
       
  1464 		setCurrentItem( c );
       
  1465 		d->completeAt = e->text().length();
       
  1466 	    }
       
  1467 	} else {
       
  1468 	    d->completionTimer->stop();
       
  1469 	    QString ct = currentText().left( d->completeAt ) + e->text();
       
  1470 	    c = completionIndex( ct, c );
       
  1471 	    if ( c < 0 && d->completeAt > 0 ) {
       
  1472 		c = completionIndex( e->text(), 0 );
       
  1473 		ct = e->text();
       
  1474 	    }
       
  1475 	    d->completeAt = 0;
       
  1476 	    if ( c >= 0 ) {
       
  1477 		setCurrentItem( c );
       
  1478 		d->completeAt = ct.length();
       
  1479 	    }
       
  1480 	}
       
  1481 	d->completionTimer->start( 400, true );
       
  1482     } else {
       
  1483 	e->ignore();
       
  1484 	return;
       
  1485     }
       
  1486 
       
  1487     c = currentItem();
       
  1488     if ( count() && !text( c ).isNull() )
       
  1489 	emit activated( text( c ) );
       
  1490     emit activated( c );
       
  1491 }
       
  1492 
       
  1493 
       
  1494 /*!\reimp
       
  1495 */
       
  1496 
       
  1497 void Q3ComboBox::focusInEvent( QFocusEvent * e )
       
  1498 {
       
  1499     QWidget::focusInEvent( e );
       
  1500     d->completeNow = false;
       
  1501     d->completeAt = 0;
       
  1502 }
       
  1503 
       
  1504 /*!\reimp
       
  1505 */
       
  1506 
       
  1507 void Q3ComboBox::focusOutEvent( QFocusEvent * e )
       
  1508 {
       
  1509     QWidget::focusOutEvent( e );
       
  1510     d->completeNow = false;
       
  1511     d->completeAt = 0;
       
  1512 }
       
  1513 
       
  1514 /*!\reimp
       
  1515 */
       
  1516 #ifndef QT_NO_WHEELEVENT
       
  1517 void Q3ComboBox::wheelEvent( QWheelEvent *e )
       
  1518 {
       
  1519     if ( d->poppedUp ) {
       
  1520 	if ( d->usingListBox() ) {
       
  1521 	    QApplication::sendEvent( d->listBox(), e );
       
  1522 	}
       
  1523     } else {
       
  1524 	if ( e->delta() > 0 ) {
       
  1525 	    int c = currentItem();
       
  1526 	    if ( c > 0 ) {
       
  1527 		setCurrentItem( c-1 );
       
  1528 		emit activated( currentItem() );
       
  1529 		emit activated( currentText() );
       
  1530 	    }
       
  1531 	} else {
       
  1532 	    int c = currentItem();
       
  1533 	    if ( ++c < count() ) {
       
  1534 		setCurrentItem( c );
       
  1535 		emit activated( currentItem() );
       
  1536 		emit activated( currentText() );
       
  1537 	    }
       
  1538 	}
       
  1539 	e->accept();
       
  1540     }
       
  1541 }
       
  1542 #endif
       
  1543 
       
  1544 /*!
       
  1545   \internal
       
  1546    Calculates the listbox height needed to contain all items, or as
       
  1547    many as the list box is supposed to contain.
       
  1548 */
       
  1549 static int listHeight( Q3ListBox *l, int sl )
       
  1550 {
       
  1551     if ( l->count() > 0 )
       
  1552 	return QMIN( l->count(), (uint)sl) * l->item( 0 )->height(l);
       
  1553     else
       
  1554 	return l->sizeHint().height();
       
  1555 }
       
  1556 
       
  1557 
       
  1558 /*!
       
  1559     Pops up the combobox popup list.
       
  1560 
       
  1561     If the list is empty, no items appear.
       
  1562 */
       
  1563 
       
  1564 void Q3ComboBox::popup()
       
  1565 {
       
  1566     if ( !count() || d->poppedUp )
       
  1567 	return;
       
  1568 
       
  1569     QStyleOptionComboBox opt = d->getStyleOption();
       
  1570     if( !d->usingListBox() || style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, this) ) {
       
  1571 	if(d->usingListBox()) {
       
  1572 	    if(!d->popup()) {
       
  1573 		Q3ComboBoxPopup *p = new Q3ComboBoxPopup( this, "in-combo" );
       
  1574 		d->setPopupMenu( p, false );
       
  1575 		p->setFont( font() );
       
  1576 		connect( p, SIGNAL(activated(int)), SLOT(internalActivate(int)) );
       
  1577 		connect( p, SIGNAL(highlighted(int)), SLOT(internalHighlight(int)) );
       
  1578 	    }
       
  1579 	    d->popup()->clear();
       
  1580 	    for(unsigned int i = 0; i < d->listBox()->count(); i++) {
       
  1581 		Q3ListBoxItem *item = d->listBox()->item(i);
       
  1582 		if(item->rtti() == Q3ListBoxText::RTTI) {
       
  1583 		    d->popup()->insertItem(escapedComboString(item->text()), i, i);
       
  1584 		} else if(item->rtti() == Q3ListBoxPixmap::RTTI) {
       
  1585 		    if(item->pixmap())
       
  1586 			d->popup()->insertItem(QIcon(*item->pixmap()), escapedComboString(item->text()), i, i);
       
  1587 		    else
       
  1588 			d->popup()->insertItem(escapedComboString(item->text()), i, i);
       
  1589 		} else {
       
  1590 		    d->popup()->insertItem(new Q3ComboBoxPopupItem(item), i, i);
       
  1591 		}
       
  1592 	    }
       
  1593 	}
       
  1594 	d->popup()->installEventFilter( this );
       
  1595 	if(d->popup() && style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, this))
       
  1596 	    d->popup()->setItemChecked(this->d->current, true);
       
  1597 	d->popup()->popup( mapToGlobal( QPoint(0,0) ), this->d->current );
       
  1598 	update();
       
  1599     } else {
       
  1600 	// Send all listbox events to eventFilter():
       
  1601 	Q3ListBox* lb = d->listBox();
       
  1602 	lb->triggerUpdate( true );
       
  1603 	lb->installEventFilter( this );
       
  1604 	d->mouseWasInsidePopup = false;
       
  1605 	int w = lb->variableWidth() ? lb->sizeHint().width() : width();
       
  1606 	int h = listHeight( lb, d->sizeLimit ) + 2;
       
  1607 	QRect screen = QApplication::desktop()->availableGeometry( this );
       
  1608 
       
  1609 	int sx = screen.x();				// screen pos
       
  1610 	int sy = screen.y();
       
  1611 	int sw = screen.width();			// screen width
       
  1612 	int sh = screen.height();			// screen height
       
  1613 	QPoint pos = mapToGlobal( QPoint(0,height()) );
       
  1614 	// ## Similar code is in QPopupMenu
       
  1615 	int x = pos.x();
       
  1616 	int y = pos.y();
       
  1617 
       
  1618 	// the complete widget must be visible
       
  1619 	if ( x + w > sx + sw )
       
  1620 	    x = sx+sw - w;
       
  1621 	if ( x < sx )
       
  1622 	    x = sx;
       
  1623 	if (y + h > sy+sh && y - h - height() >= 0 )
       
  1624 	    y = y - h - height();
       
  1625 
       
  1626         opt.rect = QRect(x, y, w, h);
       
  1627        	QRect rect = style()->subControlRect(QStyle::CC_ComboBox, &opt,
       
  1628                                              QStyle::SC_ComboBoxListBoxPopup, this);
       
  1629 
       
  1630 	// work around older styles that don't implement the combobox
       
  1631 	// listbox popup subcontrol
       
  1632 	if ( rect.isNull() )
       
  1633 	    rect.setRect( x, y, w, h );
       
  1634 	lb->setGeometry( rect );
       
  1635 
       
  1636 	lb->raise();
       
  1637 	bool block = lb->signalsBlocked();
       
  1638 	lb->blockSignals( true );
       
  1639 	Q3ListBoxItem* currentLBItem = 0;
       
  1640 	if ( editable() && currentText() != text( currentItem() ) )
       
  1641 	    currentLBItem = lb->findItem( currentText() );
       
  1642 
       
  1643 	currentLBItem = currentLBItem ? currentLBItem : lb->item( d->current );
       
  1644 
       
  1645 	lb->setCurrentItem( currentLBItem );
       
  1646 	lb->setContentsPos( lb->contentsX(),
       
  1647 			    lb->viewportToContents( lb->itemRect( currentLBItem ).topLeft() ).y() );
       
  1648 
       
  1649 	// set the current item to also be the selected item if it isn't already
       
  1650 	if ( currentLBItem && currentLBItem->isSelectable() && !currentLBItem->isSelected() )
       
  1651 	    lb->setSelected( currentLBItem, true );
       
  1652 	lb->blockSignals( block );
       
  1653 	lb->setVScrollBarMode(Q3ScrollView::Auto);
       
  1654 
       
  1655 #ifndef QT_NO_EFFECTS
       
  1656 	if ( QApplication::isEffectEnabled( Qt::UI_AnimateCombo ) ) {
       
  1657 	    if ( lb->y() < mapToGlobal(QPoint(0,0)).y() )
       
  1658 		qScrollEffect( lb, QEffects::UpScroll );
       
  1659 	    else
       
  1660 		qScrollEffect( lb );
       
  1661 	} else
       
  1662 #endif
       
  1663 	    lb->show();
       
  1664     }
       
  1665     d->poppedUp = true;
       
  1666 }
       
  1667 
       
  1668 
       
  1669 /*!
       
  1670   Updates the widget mask.
       
  1671 
       
  1672   \sa QWidget::setMask()
       
  1673 */
       
  1674 void Q3ComboBox::updateMask()
       
  1675 {
       
  1676     QBitmap bm( size() );
       
  1677     bm.fill( Qt::color0 );
       
  1678 
       
  1679     QStyleOptionComboBox opt = d->getStyleOption();
       
  1680     {
       
  1681 	QPainter p(&bm);
       
  1682         p.initFrom(this);
       
  1683         p.fillRect(opt.rect, Qt::color1); // qcommonstyle old drawComplexControl implementation
       
  1684     }
       
  1685 
       
  1686     setMask( bm );
       
  1687 }
       
  1688 
       
  1689 /*!
       
  1690   \internal
       
  1691   Pops down (removes) the combobox popup list box.
       
  1692 */
       
  1693 void Q3ComboBox::popDownListBox()
       
  1694 {
       
  1695     Q_ASSERT( d->usingListBox() );
       
  1696     d->listBox()->removeEventFilter( this );
       
  1697     d->listBox()->viewport()->removeEventFilter( this );
       
  1698     d->listBox()->hide();
       
  1699     d->listBox()->setCurrentItem( d->current );
       
  1700     if ( d->arrowDown ) {
       
  1701 	d->arrowDown = false;
       
  1702 	repaint( false );
       
  1703     }
       
  1704     d->poppedUp = false;
       
  1705 }
       
  1706 
       
  1707 
       
  1708 /*!
       
  1709   \internal
       
  1710   Re-indexes the identifiers in the popup list.
       
  1711 */
       
  1712 
       
  1713 void Q3ComboBox::reIndex()
       
  1714 {
       
  1715     if ( !d->usingListBox() ) {
       
  1716 	int cnt = count();
       
  1717 	while ( cnt-- )
       
  1718 	    d->popup()->setId( cnt, cnt );
       
  1719     }
       
  1720 }
       
  1721 
       
  1722 /*!
       
  1723   \internal
       
  1724   Repaints the combobox.
       
  1725 */
       
  1726 
       
  1727 void Q3ComboBox::currentChanged()
       
  1728 {
       
  1729     if ( d->autoresize )
       
  1730 	adjustSize();
       
  1731     update();
       
  1732 
       
  1733 #if defined(QT_ACCESSIBILITY_SUPPORT)
       
  1734     QAccessible::updateAccessibility( this, 0, QAccessible::ValueChanged );
       
  1735 #endif
       
  1736 }
       
  1737 
       
  1738 /*! \reimp
       
  1739 
       
  1740   \internal
       
  1741 
       
  1742   The event filter steals events from the popup or listbox when they
       
  1743   are popped up. It makes the popup stay up after a short click in
       
  1744   motif style. In windows style it toggles the arrow button of the
       
  1745   combobox field, and activates an item and takes down the listbox
       
  1746   when the mouse button is released.
       
  1747 */
       
  1748 
       
  1749 bool Q3ComboBox::eventFilter( QObject *object, QEvent *event )
       
  1750 {
       
  1751     QStyleOptionComboBox opt = d->getStyleOption();
       
  1752     if ( !event )
       
  1753 	return true;
       
  1754     else if ( object == d->ed ) {
       
  1755 	if ( event->type() == QEvent::KeyPress ) {
       
  1756 	    bool isAccepted = ( (QKeyEvent*)event )->isAccepted();
       
  1757 	    keyPressEvent( (QKeyEvent *)event );
       
  1758 	    if ( ((QKeyEvent *)event)->isAccepted() ) {
       
  1759 		d->completeNow = false;
       
  1760 		return true;
       
  1761 	    } else if ( ((QKeyEvent *)event)->key() != Qt::Key_End ) {
       
  1762 		d->completeNow = true;
       
  1763 		d->completeAt = d->ed->cursorPosition();
       
  1764 	    }
       
  1765 	    if ( isAccepted )
       
  1766 		( (QKeyEvent*)event )->accept();
       
  1767 	    else
       
  1768 		( (QKeyEvent*)event )->ignore();
       
  1769 	} else if ( event->type() == QEvent::KeyRelease ) {
       
  1770 	    keyReleaseEvent( (QKeyEvent *)event );
       
  1771 	    return ((QKeyEvent *)event)->isAccepted();
       
  1772 	} else if ( event->type() == QEvent::FocusIn ) {
       
  1773 	    focusInEvent( (QFocusEvent *)event );
       
  1774 	} else if ( event->type() == QEvent::FocusOut ) {
       
  1775 	    focusOutEvent( (QFocusEvent *)event );
       
  1776 	} else if ( d->useCompletion && d->completeNow ) {
       
  1777 	    d->completeNow = false;
       
  1778 	    if ( !d->ed->text().isNull() &&
       
  1779 		 d->ed->cursorPosition() > d->completeAt &&
       
  1780 		 d->ed->cursorPosition() == (int)d->ed->text().length() ) {
       
  1781 		QString ct( d->ed->text() );
       
  1782 		int i = completionIndex( ct, currentItem() );
       
  1783 		if ( i > -1 ) {
       
  1784 		    QString it = text( i );
       
  1785 		    d->ed->validateAndSet( it, ct.length(),
       
  1786 					   ct.length(), it.length() );
       
  1787 		    d->current = i;
       
  1788                     // ### sets current item without emitting signals. This is to
       
  1789 		    // make sure the right item is current if you change current with
       
  1790 		    // wheel/up/down. While typing current is not valid anyway. Fix properly
       
  1791 		    // in 4.0.
       
  1792 		}
       
  1793 	    }
       
  1794 	}
       
  1795     } else if ( d->usingListBox() && ( object == d->listBox() ||
       
  1796                                        object == d->listBox()->viewport() )) {
       
  1797 	QMouseEvent *e = (QMouseEvent*)event;
       
  1798 	switch( event->type() ) {
       
  1799 	case QEvent::MouseMove:
       
  1800 	    if ( !d->mouseWasInsidePopup  ) {
       
  1801 		QPoint pos = e->pos();
       
  1802 		if ( d->listBox()->rect().contains( pos ) )
       
  1803 		    d->mouseWasInsidePopup = true;
       
  1804 		// Check if arrow button should toggle
       
  1805 		if ( d->arrowPressed ) {
       
  1806 		    QPoint comboPos;
       
  1807 		    comboPos = mapFromGlobal( d->listBox()->mapToGlobal(pos) );
       
  1808 		    QRect arrowRect = style()->subControlRect(QStyle::CC_ComboBox, &opt,
       
  1809                                                               QStyle::SC_ComboBoxArrow, this);
       
  1810 		    if ( arrowRect.contains( comboPos ) ) {
       
  1811 			if ( !d->arrowDown  ) {
       
  1812 			    d->arrowDown = true;
       
  1813 			    repaint( false );
       
  1814 			}
       
  1815 		    } else {
       
  1816 			if ( d->arrowDown  ) {
       
  1817 			    d->arrowDown = false;
       
  1818 			    repaint( false );
       
  1819 			}
       
  1820 		    }
       
  1821 		}
       
  1822 	    } else if ((e->state() & ( Qt::RightButton | Qt::LeftButton | Qt::MidButton ) ) == 0 &&
       
  1823 		       style()->styleHint(QStyle::SH_ComboBox_ListMouseTracking, &opt, this)) {
       
  1824 		QWidget *mouseW = QApplication::widgetAt( e->globalPos(), true );
       
  1825 		if ( mouseW == d->listBox()->viewport() ) { //###
       
  1826 		    QMouseEvent m( QEvent::MouseMove, e->pos(), e->globalPos(),
       
  1827 				   Qt::NoButton, Qt::LeftButton );
       
  1828 		    QApplication::sendEvent( object, &m ); //### Evil
       
  1829 		    return true;
       
  1830 		}
       
  1831 	    }
       
  1832 
       
  1833 	    break;
       
  1834 	case QEvent::MouseButtonRelease:
       
  1835 	    if ( d->listBox()->rect().contains( e->pos() ) ) {
       
  1836 		QMouseEvent tmp( QEvent::MouseButtonDblClick,
       
  1837 				 e->pos(), e->button(), e->state() ) ;
       
  1838 		// will hide popup
       
  1839 		QApplication::sendEvent( object, &tmp );
       
  1840 		return true;
       
  1841 	    } else {
       
  1842 		if ( d->mouseWasInsidePopup ) {
       
  1843 		    popDownListBox();
       
  1844 		} else {
       
  1845 		    d->arrowPressed = false;
       
  1846 		    if ( d->arrowDown  ) {
       
  1847 			d->arrowDown = false;
       
  1848 			repaint( false );
       
  1849 		    }
       
  1850 		}
       
  1851 	    }
       
  1852 	    break;
       
  1853 	case QEvent::MouseButtonDblClick:
       
  1854 	case QEvent::MouseButtonPress:
       
  1855 	    if ( !d->listBox()->rect().contains( e->pos() ) ) {
       
  1856 		QPoint globalPos = d->listBox()->mapToGlobal(e->pos());
       
  1857 		if ( QApplication::widgetAt( globalPos, true ) == this ) {
       
  1858 		    d->discardNextMousePress = true;
       
  1859 		    // avoid popping up again
       
  1860 		}
       
  1861 		popDownListBox();
       
  1862 		return true;
       
  1863 	    }
       
  1864 	    break;
       
  1865 	case QEvent::KeyPress:
       
  1866 	    switch( ((QKeyEvent *)event)->key() ) {
       
  1867 	    case Qt::Key_Up:
       
  1868 	    case Qt::Key_Down:
       
  1869 		if ( !(((QKeyEvent *)event)->state() & Qt::AltModifier) )
       
  1870 		    break;
       
  1871 	    case Qt::Key_F4:
       
  1872 	    case Qt::Key_Escape:
       
  1873 		if ( d->poppedUp ) {
       
  1874 		    popDownListBox();
       
  1875 		    return true;
       
  1876 		}
       
  1877 		break;
       
  1878 	    case Qt::Key_Enter:
       
  1879 	    case Qt::Key_Return:
       
  1880 		// work around QDialog's enter handling
       
  1881 		return false;
       
  1882 	    default:
       
  1883 		break;
       
  1884 	    }
       
  1885 	    break;
       
  1886 	case QEvent::Hide:
       
  1887 	    popDownListBox();
       
  1888 	    break;
       
  1889 	default:
       
  1890 	    break;
       
  1891 	}
       
  1892     } else if ( (!d->usingListBox() || style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, this)) &&
       
  1893 		object == d->popup() ) {
       
  1894 	QMouseEvent *e = (QMouseEvent*)event;
       
  1895 	switch ( event->type() ) {
       
  1896 	case QEvent::MouseButtonRelease:
       
  1897 	    if ( d->shortClick ) {
       
  1898 		QMouseEvent tmp( QEvent::MouseMove,
       
  1899 				 e->pos(), e->button(), e->state() ) ;
       
  1900 		// highlight item, but don't pop down:
       
  1901 		QApplication::sendEvent( object, &tmp );
       
  1902 		return true;
       
  1903 	    }
       
  1904 	    break;
       
  1905 	case QEvent::MouseButtonDblClick:
       
  1906 	case QEvent::MouseButtonPress:
       
  1907 	    if ( !d->popup()->rect().contains( e->pos() ) ) {
       
  1908                 d->poppedUp = false;
       
  1909                 d->arrowDown = false;
       
  1910 		// remove filter, event will take down popup:
       
  1911 		d->popup()->removeEventFilter( this );
       
  1912 		// ### uglehack!
       
  1913 		// call internalHighlight so the highlighed signal
       
  1914 		// will be emitted at least as often as necessary.
       
  1915 		// it may be called more often than necessary
       
  1916 		internalHighlight( d->current );
       
  1917 	    }
       
  1918 	    break;
       
  1919 	case QEvent::Hide:
       
  1920 	    d->poppedUp = false;
       
  1921 	    break;
       
  1922 	default:
       
  1923 	    break;
       
  1924 	}
       
  1925     }
       
  1926     return QWidget::eventFilter( object, event );
       
  1927 }
       
  1928 
       
  1929 
       
  1930 /*!
       
  1931     Returns the index of the first item \e after \a startingAt of
       
  1932     which \a prefix is a case-insensitive prefix. Returns -1 if no
       
  1933     items start with \a prefix.
       
  1934 */
       
  1935 
       
  1936 int Q3ComboBox::completionIndex( const QString & prefix,
       
  1937 				int startingAt = 0 ) const
       
  1938 {
       
  1939     int start = startingAt;
       
  1940     if ( start < 0 || start >= count() )
       
  1941 	start = 0;
       
  1942     if ( start >= count() )
       
  1943 	return -1;
       
  1944     QString match = prefix.lower();
       
  1945     if ( match.length() < 1 )
       
  1946 	return start;
       
  1947 
       
  1948     QString current;
       
  1949     int i = start;
       
  1950     do {
       
  1951 	current = text( i ).lower();
       
  1952 	if ( current.startsWith( match ) )
       
  1953 	    return i;
       
  1954 	i++;
       
  1955 	if ( i == count() )
       
  1956 	    i = 0;
       
  1957     } while ( i != start );
       
  1958     return -1;
       
  1959 }
       
  1960 
       
  1961 int Q3ComboBox::sizeLimit() const
       
  1962 {
       
  1963     return d ? d->sizeLimit : INT_MAX;
       
  1964 }
       
  1965 
       
  1966 void Q3ComboBox::setSizeLimit( int lines )
       
  1967 {
       
  1968     d->sizeLimit = lines;
       
  1969 }
       
  1970 
       
  1971 
       
  1972 int Q3ComboBox::maxCount() const
       
  1973 {
       
  1974     return d ? d->maxCount : INT_MAX;
       
  1975 }
       
  1976 
       
  1977 void Q3ComboBox::setMaxCount( int count )
       
  1978 {
       
  1979     int l = this->count();
       
  1980     while( --l > count )
       
  1981 	removeItem( l );
       
  1982     d->maxCount = count;
       
  1983 }
       
  1984 
       
  1985 Q3ComboBox::Policy Q3ComboBox::insertionPolicy() const
       
  1986 {
       
  1987     return d->p;
       
  1988 }
       
  1989 
       
  1990 void Q3ComboBox::setInsertionPolicy( Policy policy )
       
  1991 {
       
  1992     d->p = policy;
       
  1993 }
       
  1994 
       
  1995 
       
  1996 
       
  1997 /*!
       
  1998   Internal slot to keep the line editor up to date.
       
  1999 */
       
  2000 
       
  2001 void Q3ComboBox::returnPressed()
       
  2002 {
       
  2003     QString s( d->ed->text() );
       
  2004 
       
  2005     if ( s.isEmpty() )
       
  2006 	return;
       
  2007 
       
  2008     int c = 0;
       
  2009     bool doInsert = true;
       
  2010     if ( !d->duplicatesEnabled ) {
       
  2011 	for ( int i = 0; i < count(); ++i ) {
       
  2012 	    if ( s == text( i ) ) {
       
  2013 		doInsert = false;
       
  2014 		c = i;
       
  2015 		break;
       
  2016 	    }
       
  2017 	}
       
  2018     }
       
  2019 
       
  2020     if ( doInsert ) {
       
  2021 	if ( insertionPolicy() != NoInsert ) {
       
  2022 	    int cnt = count();
       
  2023 	    while ( cnt >= d->maxCount ) {
       
  2024 		removeItem( --cnt );
       
  2025 	    }
       
  2026 	}
       
  2027 
       
  2028 	switch ( insertionPolicy() ) {
       
  2029 	case InsertAtCurrent:
       
  2030 	    if (count() == 0)
       
  2031 		insertItem(s);
       
  2032 	    else if ( s != text( currentItem() ) )
       
  2033 		changeItem( s, currentItem() );
       
  2034 	    emit activated( currentItem() );
       
  2035 	    emit activated( s );
       
  2036 	    return;
       
  2037 	case NoInsert:
       
  2038 	    emit activated( s );
       
  2039 	    return;
       
  2040 	case InsertAtTop:
       
  2041 	    c = 0;
       
  2042 	    break;
       
  2043 	case InsertAtBottom:
       
  2044 	    c = count();
       
  2045 	    break;
       
  2046 	case InsertBeforeCurrent:
       
  2047 	    c = currentItem();
       
  2048 	    break;
       
  2049 	case InsertAfterCurrent:
       
  2050 	    c = count() == 0 ? 0 : currentItem() + 1;
       
  2051 	    break;
       
  2052 	}
       
  2053 	insertItem( s, c );
       
  2054     }
       
  2055 
       
  2056     setCurrentItem( c );
       
  2057     emit activated( c );
       
  2058     emit activated( s );
       
  2059 }
       
  2060 
       
  2061 
       
  2062 /*!
       
  2063   Enables the combobox if \a enable is true; otherwise disables it.
       
  2064 
       
  2065   \sa QWidget::enabled
       
  2066 */
       
  2067 
       
  2068 void Q3ComboBox::setEnabled( bool enable )
       
  2069 {
       
  2070     if ( !enable ) {
       
  2071 	if ( d->usingListBox() ) {
       
  2072 	    popDownListBox();
       
  2073 	} else {
       
  2074 	    d->popup()->removeEventFilter( this );
       
  2075 	    d->popup()->close();
       
  2076 	    d->poppedUp = false;
       
  2077 	}
       
  2078     }
       
  2079     QWidget::setEnabled( enable );
       
  2080 }
       
  2081 
       
  2082 
       
  2083 
       
  2084 /*!
       
  2085     Applies the validator \a v to the combobox so that only text which
       
  2086     is valid according to \a v is accepted.
       
  2087 
       
  2088     This function does nothing if the combobox is not editable.
       
  2089 
       
  2090     \sa validator() clearValidator() QValidator
       
  2091 */
       
  2092 
       
  2093 void Q3ComboBox::setValidator( const QValidator * v )
       
  2094 {
       
  2095     if ( d && d->ed )
       
  2096 	d->ed->setValidator( v );
       
  2097 }
       
  2098 
       
  2099 
       
  2100 /*!
       
  2101     Returns the validator which constrains editing for this combobox
       
  2102     if there is one; otherwise returns 0.
       
  2103 
       
  2104     \sa setValidator() clearValidator() QValidator
       
  2105 */
       
  2106 
       
  2107 const QValidator * Q3ComboBox::validator() const
       
  2108 {
       
  2109     return d && d->ed ? d->ed->validator() : 0;
       
  2110 }
       
  2111 
       
  2112 
       
  2113 /*!
       
  2114     This slot is equivalent to setValidator( 0 ).
       
  2115 */
       
  2116 
       
  2117 void Q3ComboBox::clearValidator()
       
  2118 {
       
  2119     if ( d && d->ed )
       
  2120 	d->ed->setValidator( 0 );
       
  2121 }
       
  2122 
       
  2123 
       
  2124 /*!
       
  2125     Sets the combobox to use \a newListBox instead of the current list
       
  2126     box or popup. As a side effect, it clears the combobox of its
       
  2127     current contents.
       
  2128 
       
  2129     \warning Q3ComboBox assumes that newListBox->text(n) returns
       
  2130     non-null for 0 \<= n \< newListbox->count(). This assumption is
       
  2131     necessary because of the line edit in Q3ComboBox.
       
  2132 */
       
  2133 
       
  2134 void Q3ComboBox::setListBox( Q3ListBox * newListBox )
       
  2135 {
       
  2136     clear();
       
  2137 
       
  2138     if ( d->usingListBox() ) {
       
  2139 	delete d->listBox();
       
  2140     } else {
       
  2141 	delete d->popup();
       
  2142         d->setPopupMenu(0, false);
       
  2143     }
       
  2144 
       
  2145     newListBox->reparent( this, Qt::WType_Popup, QPoint(0,0), false );
       
  2146     d->setListBox( newListBox );
       
  2147     d->listBox()->setFont( font() );
       
  2148     d->listBox()->setPalette( palette() );
       
  2149     d->listBox()->setVScrollBarMode(Q3ScrollView::AlwaysOff);
       
  2150     d->listBox()->setHScrollBarMode(Q3ScrollView::AlwaysOff);
       
  2151     d->listBox()->setFrameStyle( Q3Frame::Box | Q3Frame::Plain );
       
  2152     d->listBox()->setLineWidth( 1 );
       
  2153     d->listBox()->resize( 100, 10 );
       
  2154 
       
  2155     connect( d->listBox(), SIGNAL(selected(int)),
       
  2156 	     SLOT(internalActivate(int)) );
       
  2157     connect( d->listBox(), SIGNAL(highlighted(int)),
       
  2158 	     SLOT(internalHighlight(int)));
       
  2159 }
       
  2160 
       
  2161 
       
  2162 /*!
       
  2163     Returns the current list box, or 0 if there is no list box.
       
  2164     (Q3ComboBox can use QPopupMenu instead of QListBox.) Provided to
       
  2165     match setListBox().
       
  2166 
       
  2167     \sa setListBox()
       
  2168 */
       
  2169 
       
  2170 Q3ListBox * Q3ComboBox::listBox() const
       
  2171 {
       
  2172     return d && d->usingListBox() ? d->listBox() : 0;
       
  2173 }
       
  2174 
       
  2175 /*!
       
  2176     Returns the line edit, or 0 if there is no line edit.
       
  2177 
       
  2178     Only editable listboxes have a line editor.
       
  2179 */
       
  2180 QLineEdit* Q3ComboBox::lineEdit() const
       
  2181 {
       
  2182     return d->ed;
       
  2183 }
       
  2184 
       
  2185 
       
  2186 
       
  2187 /*!
       
  2188     Clears the line edit without changing the combobox's contents.
       
  2189     Does nothing if the combobox isn't editable.
       
  2190 
       
  2191     This is particularly useful when using a combobox as a line edit
       
  2192     with history. For example you can connect the combobox's
       
  2193     activated() signal to clearEdit() in order to present the user
       
  2194     with a new, empty line as soon as Enter is pressed.
       
  2195 
       
  2196     \sa setEditText()
       
  2197 */
       
  2198 
       
  2199 void Q3ComboBox::clearEdit()
       
  2200 {
       
  2201     if ( d && d->ed )
       
  2202 	d->ed->clear();
       
  2203 }
       
  2204 
       
  2205 
       
  2206 /*!
       
  2207     Sets the text in the line edit to \a newText without changing the
       
  2208     combobox's contents. Does nothing if the combobox isn't editable.
       
  2209 
       
  2210     This is useful e.g. for providing a good starting point for the
       
  2211     user's editing and entering the change in the combobox only when
       
  2212     the user presses Enter.
       
  2213 
       
  2214     \sa clearEdit() insertItem()
       
  2215 */
       
  2216 
       
  2217 void Q3ComboBox::setEditText( const QString &newText )
       
  2218 {
       
  2219     if ( d && d->ed ) {
       
  2220 	d->updateLinedGeometry();
       
  2221 	d->ed->setText( newText );
       
  2222     }
       
  2223 }
       
  2224 
       
  2225 void Q3ComboBox::setAutoCompletion( bool enable )
       
  2226 {
       
  2227     d->useCompletion = enable;
       
  2228     d->completeNow = false;
       
  2229 }
       
  2230 
       
  2231 
       
  2232 bool Q3ComboBox::autoCompletion() const
       
  2233 {
       
  2234     return d->useCompletion;
       
  2235 }
       
  2236 
       
  2237 /*!
       
  2238   \internal
       
  2239  */
       
  2240 void Q3ComboBox::styleChange( QStyle& s )
       
  2241 {
       
  2242     d->sizeHint = QSize();		// invalidate size hint...
       
  2243     if ( d->ed )
       
  2244 	d->updateLinedGeometry();
       
  2245     QWidget::styleChange( s );
       
  2246 }
       
  2247 
       
  2248 bool Q3ComboBox::editable() const
       
  2249 {
       
  2250     return d->ed != 0;
       
  2251 }
       
  2252 
       
  2253 void Q3ComboBox::setEditable( bool y )
       
  2254 {
       
  2255     if ( y == editable() )
       
  2256 	return;
       
  2257     if ( y ) {
       
  2258 	if ( !d->usingListBox() )
       
  2259 	    setUpListBox();
       
  2260 	setUpLineEdit();
       
  2261 	d->ed->show();
       
  2262 	if ( currentItem() )
       
  2263 	    setEditText( currentText() );
       
  2264     } else {
       
  2265 	delete d->ed;
       
  2266 	d->ed = 0;
       
  2267     }
       
  2268 
       
  2269     setFocusPolicy(Qt::StrongFocus);
       
  2270     updateGeometry();
       
  2271     update();
       
  2272 }
       
  2273 
       
  2274 
       
  2275 void Q3ComboBox::setUpListBox()
       
  2276 {
       
  2277     d->setListBox( new Q3ListBox( this, "in-combo", Qt::WType_Popup ) );
       
  2278     d->listBox()->setFont( font() );
       
  2279     d->listBox()->setPalette( palette() );
       
  2280     d->listBox()->setVScrollBarMode( Q3ListBox::AlwaysOff );
       
  2281     d->listBox()->setHScrollBarMode( Q3ListBox::AlwaysOff );
       
  2282     d->listBox()->setFrameStyle( Q3Frame::Box | Q3Frame::Plain );
       
  2283     d->listBox()->setLineWidth( 1 );
       
  2284     d->listBox()->resize( 100, 10 );
       
  2285 
       
  2286     connect( d->listBox(), SIGNAL(selected(int)),
       
  2287 	     SLOT(internalActivate(int)) );
       
  2288     connect( d->listBox(), SIGNAL(highlighted(int)),
       
  2289 	     SLOT(internalHighlight(int)));
       
  2290 }
       
  2291 
       
  2292 
       
  2293 void Q3ComboBox::setUpLineEdit()
       
  2294 {
       
  2295     if ( !d->ed )
       
  2296 	setLineEdit( new QLineEdit( this, "combo edit" ) );
       
  2297 }
       
  2298 
       
  2299 /*!
       
  2300     Sets the line edit to use \a edit instead of the current line edit.
       
  2301 */
       
  2302 
       
  2303 void Q3ComboBox::setLineEdit( QLineEdit *edit )
       
  2304 {
       
  2305     if ( !edit ) {
       
  2306 #if defined(QT_CHECK_NULL)
       
  2307 	Q_ASSERT( edit != 0 );
       
  2308 #endif
       
  2309 	return;
       
  2310     }
       
  2311 
       
  2312     edit->setText( currentText() );
       
  2313     delete d->ed;
       
  2314     d->ed = edit;
       
  2315 
       
  2316     if ( edit->parent() != this )
       
  2317 	edit->reparent( this, QPoint(0,0), false );
       
  2318 
       
  2319     connect (edit, SIGNAL(textChanged(QString)),
       
  2320 	     this, SIGNAL(textChanged(QString)) );
       
  2321     connect( edit, SIGNAL(returnPressed()), SLOT(returnPressed()) );
       
  2322 
       
  2323     edit->setFrame( false );
       
  2324     d->updateLinedGeometry();
       
  2325     edit->installEventFilter( this );
       
  2326     setFocusProxy( edit );
       
  2327     setFocusPolicy(Qt::StrongFocus);
       
  2328     setInputMethodEnabled( true );
       
  2329 
       
  2330     if ( !d->usingListBox() )
       
  2331 	setUpListBox();
       
  2332 
       
  2333     if ( isVisible() )
       
  2334 	edit->show();
       
  2335 
       
  2336     updateGeometry();
       
  2337     update();
       
  2338 }
       
  2339 
       
  2340 /*!
       
  2341   Hides the combobox.
       
  2342 
       
  2343   \sa QWidget::hide()
       
  2344 */
       
  2345 void Q3ComboBox::hide()
       
  2346 {
       
  2347     QWidget::hide();
       
  2348 
       
  2349     if (listBox())
       
  2350 	listBox()->hide();
       
  2351     else if (d->popup())
       
  2352 	d->popup()->hide();
       
  2353 }
       
  2354 
       
  2355 QT_END_NAMESPACE
       
  2356 
       
  2357 #endif // QT_NO_COMBOBOX