|
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 |