source: trunk/src/gui/widgets/qcombobox_p.h@ 603

Last change on this file since 603 was 561, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.1 sources.

File size: 13.5 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtGui module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
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** 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 have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#ifndef QCOMBOBOX_P_H
43#define QCOMBOBOX_P_H
44
45//
46// W A R N I N G
47// -------------
48//
49// This file is not part of the Qt API. It exists purely as an
50// implementation detail. This header file may change from version to
51// version without notice, or even be removed.
52//
53// We mean it.
54//
55
56#include "QtGui/qcombobox.h"
57
58#ifndef QT_NO_COMBOBOX
59#include "QtGui/qabstractslider.h"
60#include "QtGui/qapplication.h"
61#include "QtGui/qitemdelegate.h"
62#include "QtGui/qstandarditemmodel.h"
63#include "QtGui/qlineedit.h"
64#include "QtGui/qlistview.h"
65#include "QtGui/qpainter.h"
66#include "QtGui/qstyle.h"
67#include "QtGui/qstyleoption.h"
68#include "QtCore/qhash.h"
69#include "QtCore/qpair.h"
70#include "QtCore/qtimer.h"
71#include "private/qwidget_p.h"
72#include "QtCore/qpointer.h"
73#include "QtGui/qcompleter.h"
74#include "QtGui/qevent.h"
75#include "QtCore/qdebug.h"
76
77#include <limits.h>
78
79QT_BEGIN_NAMESPACE
80
81class QAction;
82
83class QComboBoxListView : public QListView
84{
85 Q_OBJECT
86public:
87 QComboBoxListView(QComboBox *cmb = 0) : combo(cmb) {}
88
89protected:
90 void resizeEvent(QResizeEvent *event)
91 {
92 resizeContents(viewport()->width(), contentsSize().height());
93 QListView::resizeEvent(event);
94 }
95
96 QStyleOptionViewItem viewOptions() const
97 {
98 QStyleOptionViewItem option = QListView::viewOptions();
99 option.showDecorationSelected = true;
100 if (combo)
101 option.font = combo->font();
102 return option;
103 }
104
105 void paintEvent(QPaintEvent *e)
106 {
107 if (combo) {
108 QStyleOptionComboBox opt;
109 opt.initFrom(combo);
110 opt.editable = combo->isEditable();
111 if (combo->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, combo)) {
112 //we paint the empty menu area to avoid having blank space that can happen when scrolling
113 QStyleOptionMenuItem menuOpt;
114 menuOpt.initFrom(this);
115 menuOpt.palette = palette();
116 menuOpt.state = QStyle::State_None;
117 menuOpt.checkType = QStyleOptionMenuItem::NotCheckable;
118 menuOpt.menuRect = e->rect();
119 menuOpt.maxIconWidth = 0;
120 menuOpt.tabWidth = 0;
121 QPainter p(viewport());
122 combo->style()->drawControl(QStyle::CE_MenuEmptyArea, &menuOpt, &p, this);
123 }
124 }
125 QListView::paintEvent(e);
126 }
127
128private:
129 QComboBox *combo;
130};
131
132
133class QStandardItemModel;
134
135class Q_AUTOTEST_EXPORT QComboBoxPrivateScroller : public QWidget
136{
137 Q_OBJECT
138
139public:
140 QComboBoxPrivateScroller(QAbstractSlider::SliderAction action, QWidget *parent)
141 : QWidget(parent), sliderAction(action)
142 {
143 setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
144 setAttribute(Qt::WA_NoMousePropagation);
145 }
146 QSize sizeHint() const {
147 return QSize(20, style()->pixelMetric(QStyle::PM_MenuScrollerHeight));
148 }
149
150protected:
151 inline void stopTimer() {
152 timer.stop();
153 }
154
155 inline void startTimer() {
156 timer.start(100, this);
157 fast = false;
158 }
159
160 void enterEvent(QEvent *) {
161 startTimer();
162 }
163
164 void leaveEvent(QEvent *) {
165 stopTimer();
166 }
167 void timerEvent(QTimerEvent *e) {
168 if (e->timerId() == timer.timerId()) {
169 emit doScroll(sliderAction);
170 if (fast) {
171 emit doScroll(sliderAction);
172 emit doScroll(sliderAction);
173 }
174 }
175 }
176 void hideEvent(QHideEvent *) {
177 stopTimer();
178 }
179
180 void mouseMoveEvent(QMouseEvent *e)
181 {
182 // Enable fast scrolling if the cursor is directly above or below the popup.
183 const int mouseX = e->pos().x();
184 const int mouseY = e->pos().y();
185 const bool horizontallyInside = pos().x() < mouseX && mouseX < rect().right() + 1;
186 const bool verticallyOutside = (sliderAction == QAbstractSlider::SliderSingleStepAdd) ?
187 rect().bottom() + 1 < mouseY : mouseY < pos().y();
188
189 fast = horizontallyInside && verticallyOutside;
190 }
191
192 void paintEvent(QPaintEvent *) {
193 QPainter p(this);
194 QStyleOptionMenuItem menuOpt;
195 menuOpt.init(this);
196 menuOpt.checkType = QStyleOptionMenuItem::NotCheckable;
197 menuOpt.menuRect = rect();
198 menuOpt.maxIconWidth = 0;
199 menuOpt.tabWidth = 0;
200 menuOpt.menuItemType = QStyleOptionMenuItem::Scroller;
201 if (sliderAction == QAbstractSlider::SliderSingleStepAdd)
202 menuOpt.state |= QStyle::State_DownArrow;
203 p.eraseRect(rect());
204 style()->drawControl(QStyle::CE_MenuScroller, &menuOpt, &p);
205 }
206
207Q_SIGNALS:
208 void doScroll(int action);
209
210private:
211 QAbstractSlider::SliderAction sliderAction;
212 QBasicTimer timer;
213 bool fast;
214};
215
216class Q_AUTOTEST_EXPORT QComboBoxPrivateContainer : public QFrame
217{
218 Q_OBJECT
219
220public:
221 QComboBoxPrivateContainer(QAbstractItemView *itemView, QComboBox *parent);
222 QAbstractItemView *itemView() const;
223 void setItemView(QAbstractItemView *itemView);
224 int spacing() const;
225 void updateTopBottomMargin();
226
227 QTimer blockMouseReleaseTimer;
228 QBasicTimer adjustSizeTimer;
229 QPoint initialClickPosition;
230
231public Q_SLOTS:
232 void scrollItemView(int action);
233 void updateScrollers();
234 void viewDestroyed();
235
236protected:
237 void changeEvent(QEvent *e);
238 bool eventFilter(QObject *o, QEvent *e);
239 void mousePressEvent(QMouseEvent *e);
240 void mouseReleaseEvent(QMouseEvent *e);
241 void showEvent(QShowEvent *e);
242 void hideEvent(QHideEvent *e);
243 void timerEvent(QTimerEvent *timerEvent);
244 void leaveEvent(QEvent *e);
245 void resizeEvent(QResizeEvent *e);
246 QStyleOptionComboBox comboStyleOption() const;
247
248Q_SIGNALS:
249 void itemSelected(const QModelIndex &);
250 void resetButton();
251
252private:
253 QComboBox *combo;
254 QAbstractItemView *view;
255 QComboBoxPrivateScroller *top;
256 QComboBoxPrivateScroller *bottom;
257#ifdef QT_SOFTKEYS_ENABLED
258 QAction *selectAction;
259 QAction *cancelAction;
260#endif
261};
262
263class QComboMenuDelegate : public QAbstractItemDelegate
264{ Q_OBJECT
265public:
266 QComboMenuDelegate(QObject *parent, QComboBox *cmb) : QAbstractItemDelegate(parent), mCombo(cmb) {}
267
268protected:
269 void paint(QPainter *painter,
270 const QStyleOptionViewItem &option,
271 const QModelIndex &index) const {
272 QStyleOptionMenuItem opt = getStyleOption(option, index);
273 painter->fillRect(option.rect, opt.palette.background());
274 mCombo->style()->drawControl(QStyle::CE_MenuItem, &opt, painter, mCombo);
275 }
276 QSize sizeHint(const QStyleOptionViewItem &option,
277 const QModelIndex &index) const {
278 QStyleOptionMenuItem opt = getStyleOption(option, index);
279 return mCombo->style()->sizeFromContents(
280 QStyle::CT_MenuItem, &opt, option.rect.size(), mCombo);
281 }
282
283private:
284 QStyleOptionMenuItem getStyleOption(const QStyleOptionViewItem &option,
285 const QModelIndex &index) const;
286 QComboBox *mCombo;
287};
288
289// Note that this class is intentionally not using QStyledItemDelegate
290// Vista does not use the new theme for combo boxes and there might
291// be other side effects from using the new class
292class QComboBoxDelegate : public QItemDelegate
293{ Q_OBJECT
294public:
295 QComboBoxDelegate(QObject *parent, QComboBox *cmb) : QItemDelegate(parent), mCombo(cmb) {}
296
297 static bool isSeparator(const QModelIndex &index) {
298 return index.data(Qt::AccessibleDescriptionRole).toString() == QLatin1String("separator");
299 }
300 static void setSeparator(QAbstractItemModel *model, const QModelIndex &index) {
301 model->setData(index, QString::fromLatin1("separator"), Qt::AccessibleDescriptionRole);
302 if (QStandardItemModel *m = qobject_cast<QStandardItemModel*>(model))
303 if (QStandardItem *item = m->itemFromIndex(index))
304 item->setFlags(item->flags() & ~(Qt::ItemIsSelectable|Qt::ItemIsEnabled));
305 }
306
307protected:
308 void paint(QPainter *painter,
309 const QStyleOptionViewItem &option,
310 const QModelIndex &index) const {
311 if (isSeparator(index)) {
312 QRect rect = option.rect;
313 if (const QStyleOptionViewItemV3 *v3 = qstyleoption_cast<const QStyleOptionViewItemV3*>(&option))
314 if (const QAbstractItemView *view = qobject_cast<const QAbstractItemView*>(v3->widget))
315 rect.setWidth(view->viewport()->width());
316 QStyleOption opt;
317 opt.rect = rect;
318 mCombo->style()->drawPrimitive(QStyle::PE_IndicatorToolBarSeparator, &opt, painter, mCombo);
319 } else {
320 QItemDelegate::paint(painter, option, index);
321 }
322 }
323
324 QSize sizeHint(const QStyleOptionViewItem &option,
325 const QModelIndex &index) const {
326 if (isSeparator(index)) {
327 int pm = mCombo->style()->pixelMetric(QStyle::PM_DefaultFrameWidth, 0, mCombo);
328 return QSize(pm, pm);
329 }
330 return QItemDelegate::sizeHint(option, index);
331 }
332private:
333 QComboBox *mCombo;
334};
335
336class QComboBoxPrivate : public QWidgetPrivate
337{
338 Q_DECLARE_PUBLIC(QComboBox)
339public:
340 QComboBoxPrivate();
341 ~QComboBoxPrivate() {}
342 void init();
343 QComboBoxPrivateContainer* viewContainer();
344 void updateLineEditGeometry();
345 Qt::MatchFlags matchFlags() const;
346 void _q_editingFinished();
347 void _q_returnPressed();
348 void _q_complete();
349 void _q_itemSelected(const QModelIndex &item);
350 bool contains(const QString &text, int role);
351 void emitActivated(const QModelIndex&);
352 void _q_emitHighlighted(const QModelIndex&);
353 void _q_emitCurrentIndexChanged(const QModelIndex &index);
354 void _q_modelDestroyed();
355 void _q_modelReset();
356#ifdef QT_KEYPAD_NAVIGATION
357 void _q_completerActivated();
358#endif
359 void _q_resetButton();
360 void _q_dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight);
361 void _q_updateIndexBeforeChange();
362 void _q_rowsInserted(const QModelIndex & parent, int start, int end);
363 void _q_rowsRemoved(const QModelIndex & parent, int start, int end);
364 void updateArrow(QStyle::StateFlag state);
365 bool updateHoverControl(const QPoint &pos);
366 QRect popupGeometry(int screen = -1) const;
367 QStyle::SubControl newHoverControl(const QPoint &pos);
368 int computeWidthHint() const;
369 QSize recomputeSizeHint(QSize &sh) const;
370 void adjustComboBoxSize();
371 QString itemText(const QModelIndex &index) const;
372 QIcon itemIcon(const QModelIndex &index) const;
373 int itemRole() const;
374 void updateLayoutDirection();
375 void setCurrentIndex(const QModelIndex &index);
376 void updateDelegate(bool force = false);
377 void keyboardSearchString(const QString &text);
378 void modelChanged();
379 void updateViewContainerPaletteAndOpacity();
380
381 QAbstractItemModel *model;
382 QLineEdit *lineEdit;
383 QComboBoxPrivateContainer *container;
384 QComboBox::InsertPolicy insertPolicy;
385 QComboBox::SizeAdjustPolicy sizeAdjustPolicy;
386 int minimumContentsLength;
387 QSize iconSize;
388 uint shownOnce : 1;
389 uint autoCompletion : 1;
390 uint duplicatesEnabled : 1;
391 uint frame : 1;
392 uint padding : 26;
393 int maxVisibleItems;
394 int maxCount;
395 int modelColumn;
396 bool inserting;
397 mutable QSize minimumSizeHint;
398 mutable QSize sizeHint;
399 QStyle::StateFlag arrowState;
400 QStyle::SubControl hoverControl;
401 QRect hoverRect;
402 QPersistentModelIndex currentIndex;
403 QPersistentModelIndex root;
404 Qt::CaseSensitivity autoCompletionCaseSensitivity;
405 int indexBeforeChange;
406#ifndef QT_NO_COMPLETER
407 QPointer<QCompleter> completer;
408#endif
409 static QPalette viewContainerPalette(QComboBox *cmb)
410 { return cmb->d_func()->viewContainer()->palette(); }
411};
412
413QT_END_NAMESPACE
414
415#endif // QT_NO_COMBOBOX
416
417#endif // QCOMBOBOX_P_H
Note: See TracBrowser for help on using the repository browser.