source: trunk/src/qt3support/widgets/q3combobox.cpp@ 5

Last change on this file since 5 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 60.5 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the Qt3Support module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
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
71QT_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
344class Q3ComboBoxPopup : public Q3PopupMenu
345{
346public:
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
358static inline QString escapedComboString(const QString &str)
359{
360 QString stringToReturn = str;
361 return stringToReturn.replace(QLatin1Char('&'), QLatin1String("&&"));
362}
363
364class Q3ComboBoxPopupItem : public QMenuItem
365{
366 Q3ListBoxItem *li;
367 QSize sc; // Size cache optimization
368public:
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};
374void 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
384class Q3ComboBoxData
385{
386public:
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
451private:
452 bool usingLBox;
453 Q3ComboBoxPopup *pop;
454 Q3ListBox *lBox;
455 Q3ComboBox *combo;
456};
457
458void 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
474static 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
492static 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
524Q3ComboBox::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
574Q3ComboBox::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
610Q3ComboBox::~Q3ComboBox()
611{
612 delete d;
613}
614
615void Q3ComboBox::setDuplicatesEnabled( bool enable )
616{
617 d->duplicatesEnabled = enable;
618}
619
620bool Q3ComboBox::duplicatesEnabled() const
621{
622 return d->duplicatesEnabled;
623}
624
625int 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
646void 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
661void 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
697void 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
735void Q3ComboBox::insertStrList( const char **strings, int numStrings, int index)
736{