📄 qcombobox.cpp
字号:
/******************************************************************************** Copyright (C) 1992-2007 Trolltech ASA. All rights reserved.**** This file is part of the QtGui module of the Qt Toolkit.**** This file may be used under the terms of the GNU General Public** License version 2.0 as published by the Free Software Foundation** and appearing in the file LICENSE.GPL included in the packaging of** this file. Please review the following information to ensure GNU** General Public Licensing requirements will be met:** http://trolltech.com/products/qt/licenses/licensing/opensource/**** If you are unsure which license is appropriate for your use, please** review the following information:** http://trolltech.com/products/qt/licenses/licensing/licensingoverview** or contact the sales department at sales@trolltech.com.**** In addition, as a special exception, Trolltech gives you certain** additional rights. These rights are described in the Trolltech GPL** Exception version 1.0, which can be found at** http://www.trolltech.com/products/qt/gplexception/ and in the file** GPL_EXCEPTION.txt in this package.**** In addition, as a special exception, Trolltech, as the sole copyright** holder for Qt Designer, grants users of the Qt/Eclipse Integration** plug-in the right for the Qt/Eclipse Integration to link to** functionality provided by Qt Designer and its related libraries.**** Trolltech reserves all rights not expressly granted herein.**** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.******************************************************************************/#include "qcombobox.h"#ifndef QT_NO_COMBOBOX#include <qstylepainter.h>#include <qlineedit.h>#include <qapplication.h>#include <qdesktopwidget.h>#include <qlistview.h>#include <qitemdelegate.h>#include <qstandarditemmodel.h>#include <qmap.h>#include <qmenu.h>#include <qevent.h>#include <qlayout.h>#include <qscrollbar.h>#ifndef QT_NO_IM#include "qinputcontext.h"#endif#include <private/qcombobox_p.h>#include <private/qabstractitemmodel_p.h>#include <qdebug.h>#ifdef Q_WS_X11#include <private/qt_x11_p.h>#endifQComboBoxPrivate::QComboBoxPrivate() : QWidgetPrivate(), model(0), lineEdit(0), container(0), insertPolicy(QComboBox::InsertAtBottom), sizeAdjustPolicy(QComboBox::AdjustToContentsOnFirstShow), minimumContentsLength(0), shownOnce(false), autoCompletion(true), duplicatesEnabled(false), frame(true), maxVisibleItems(10), maxCount(INT_MAX), modelColumn(0), inserting(false), arrowState(QStyle::State_None), hoverControl(QStyle::SC_None), autoCompletionCaseSensitivity(Qt::CaseInsensitive), indexBeforeChange(-1)#ifndef QT_NO_COMPLETER , completer(0)#endif{}QStyleOptionMenuItem QComboMenuDelegate::getStyleOption(const QStyleOptionViewItem &option, const QModelIndex &index) const{ QStyleOptionMenuItem menuOption; menuOption.palette = QApplication::palette("QMenu"); menuOption.state = QStyle::State_None; if (mCombo->window()->isActiveWindow()) menuOption.state = QStyle::State_Active; if ((option.state & QStyle::State_Enabled) && (index.model()->flags(index) & Qt::ItemIsEnabled)) menuOption.state |= QStyle::State_Enabled; else menuOption.palette.setCurrentColorGroup(QPalette::Disabled); if (option.state & QStyle::State_Selected) menuOption.state |= QStyle::State_Selected; menuOption.checkType = QStyleOptionMenuItem::NonExclusive; menuOption.checked = mCombo->currentIndex() == index.row(); menuOption.menuItemType = QStyleOptionMenuItem::Normal; QVariant variant = index.model()->data(index, Qt::DecorationRole); switch (variant.type()) { case QVariant::Icon: menuOption.icon = qvariant_cast<QIcon>(variant); break; case QVariant::Color: { static QPixmap pixmap(option.decorationSize); pixmap.fill(qvariant_cast<QColor>(variant)); menuOption.icon = pixmap; break; } default: menuOption.icon = qvariant_cast<QPixmap>(variant); break; } menuOption.text = index.model()->data(index, Qt::DisplayRole).toString() .replace(QLatin1Char('&'), QLatin1String("&&")); menuOption.tabWidth = 0; menuOption.maxIconWidth = option.decorationSize.width() + 4; menuOption.menuRect = option.rect; menuOption.rect = option.rect; extern QHash<QByteArray, QFont> *qt_app_fonts_hash(); // Make sure fonts set on the combo box also overrides the font for the popup menu. if (mCombo->testAttribute(Qt::WA_SetFont)) menuOption.font = mCombo->font(); else menuOption.font = qt_app_fonts_hash()->value("QComboMenuItem", mCombo->font()); menuOption.fontMetrics = QFontMetrics(menuOption.font); return menuOption;}#ifdef QT_KEYPAD_NAVIGATIONvoid QComboBoxPrivate::_q_completerActivated(){ Q_Q(QComboBox); if ( QApplication::keypadNavigationEnabled() && q->isEditable() && q->completer() && q->completer()->completionMode() == QCompleter::UnfilteredPopupCompletion ) { q->setEditFocus(false); }}#endifvoid QComboBoxPrivate::updateArrow(QStyle::StateFlag state){ Q_Q(QComboBox); if (arrowState == state) return; arrowState = state; QStyleOptionComboBox opt; q->initStyleOption(&opt); q->update(q->style()->subControlRect(QStyle::CC_ComboBox, &opt, QStyle::SC_ComboBoxArrow, q));}void QComboBoxPrivate::_q_modelReset(){ Q_Q(QComboBox); if (lineEdit) { lineEdit->setText(QString()); updateLineEditGeometry(); } q->update();}void QComboBoxPrivate::_q_modelDestroyed(){ model = QAbstractItemModelPrivate::staticEmptyModel();}//Windows and KDE allows menus to cover the taskbar, while GNOME and Mac don'tQRect QComboBoxPrivate::popupGeometry(int screen) const{#ifdef Q_WS_WIN return QApplication::desktop()->screenGeometry(screen);#elif defined Q_WS_X11 if (X11->desktopEnvironment == DE_KDE) return QApplication::desktop()->screenGeometry(screen); else return QApplication::desktop()->availableGeometry(screen);#else return QApplication::desktop()->availableGeometry(screen);#endif}bool QComboBoxPrivate::updateHoverControl(const QPoint &pos){ Q_Q(QComboBox); QRect lastHoverRect = hoverRect; QStyle::SubControl lastHoverControl = hoverControl; bool doesHover = q->testAttribute(Qt::WA_Hover); if (lastHoverControl != newHoverControl(pos) && doesHover) { q->update(lastHoverRect); q->update(hoverRect); return true; } return !doesHover;}QStyle::SubControl QComboBoxPrivate::newHoverControl(const QPoint &pos){ Q_Q(QComboBox); QStyleOptionComboBox opt; q->initStyleOption(&opt); opt.subControls = QStyle::SC_All; hoverControl = q->style()->hitTestComplexControl(QStyle::CC_ComboBox, &opt, pos, q); hoverRect = (hoverControl != QStyle::SC_None) ? q->style()->subControlRect(QStyle::CC_ComboBox, &opt, hoverControl, q) : QRect(); return hoverControl;}/* Computes a size hint based on the maximum width for the items in the combobox.*/int QComboBoxPrivate::computeWidthHint() const{ Q_Q(const QComboBox); int width = 0; const int count = q->count(); const int iconWidth = q->iconSize().width() + 4; const QFontMetrics &fontMetrics = q->fontMetrics(); for (int i = 0; i < count; ++i) { const int textWidth = fontMetrics.width(q->itemText(i)); if (q->itemIcon(i).isNull()) width = (qMax(width, textWidth)); else width = (qMax(width, textWidth + iconWidth)); } QStyleOptionComboBox opt; q->initStyleOption(&opt); QSize tmp(width, 0); tmp = q->style()->sizeFromContents(QStyle::CT_ComboBox, &opt, tmp, q); return tmp.width();}QSize QComboBoxPrivate::recomputeSizeHint(QSize &sh) const{ Q_Q(const QComboBox); if (!sh.isValid()) { bool hasIcon = sizeAdjustPolicy == QComboBox::AdjustToMinimumContentsLengthWithIcon ? true : false; int count = q->count(); QSize iconSize = q->iconSize(); const QFontMetrics &fm = q->fontMetrics(); // text width if (&sh == &sizeHint || minimumContentsLength == 0) { switch (sizeAdjustPolicy) { case QComboBox::AdjustToContents: case QComboBox::AdjustToContentsOnFirstShow: if (count == 0) { sh.rwidth() = 7 * fm.width(QLatin1Char('x')); } else { for (int i = 0; i < count; ++i) { if (!q->itemIcon(i).isNull()) { hasIcon = true; sh.setWidth(qMax(sh.width(), fm.width(q->itemText(i)) + iconSize.width() + 4)); } else { sh.setWidth(qMax(sh.width(), fm.width(q->itemText(i)))); } } } break; case QComboBox::AdjustToMinimumContentsLength: for (int i = 0; i < count && !hasIcon; ++i) hasIcon = !q->itemIcon(i).isNull(); default: ; } } else { for (int i = 0; i < count && !hasIcon; ++i) hasIcon = !q->itemIcon(i).isNull(); } if (minimumContentsLength > 0) sh.setWidth(qMax(sh.width(), minimumContentsLength * fm.width(QLatin1Char('X')) + (hasIcon ? iconSize.width() + 4 : 0))); // height sh.setHeight(qMax(fm.lineSpacing(), 14) + 2); if (hasIcon) { sh.setHeight(qMax(sh.height(), iconSize.height() + 2)); } // add style and strut values QStyleOptionComboBox opt; q->initStyleOption(&opt); sh = q->style()->sizeFromContents(QStyle::CT_ComboBox, &opt, sh, q); } return sh.expandedTo(QApplication::globalStrut());}void QComboBoxPrivate::adjustComboBoxSize(){ viewContainer()->adjustSizeTimer.start(20, container);}void QComboBoxPrivate::updateLayoutDirection(){ Q_Q(const QComboBox); QStyleOptionComboBox opt; q->initStyleOption(&opt); Qt::LayoutDirection dir = Qt::LayoutDirection( q->style()->styleHint(QStyle::SH_ComboBox_LayoutDirection, &opt, q)); if (lineEdit) lineEdit->setLayoutDirection(dir); if (container) container->setLayoutDirection(dir);}void QComboBoxPrivateContainer::timerEvent(QTimerEvent *timerEvent){ if (timerEvent->timerId() == adjustSizeTimer.timerId()) { adjustSizeTimer.stop(); if (combo->sizeAdjustPolicy() == QComboBox::AdjustToContents) { combo->adjustSize(); combo->update(); } }}void QComboBoxPrivateContainer::resizeEvent(QResizeEvent *e){ QStyleOptionComboBox opt = comboStyleOption(); if (combo->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, combo)) { QStyleOption myOpt; myOpt.initFrom(this); QStyleHintReturnMask mask; if (combo->style()->styleHint(QStyle::SH_Menu_Mask, &myOpt, this, &mask)) { setMask(mask.region); } } else { clearMask(); } QFrame::resizeEvent(e);}void QComboBoxPrivateContainer::leaveEvent(QEvent *){// On Mac using the Mac style we want to clear the selection// when the mouse moves outside the popup.#ifdef Q_WS_MAC QStyleOptionComboBox opt = comboStyleOption(); if (combo->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, combo)) view->clearSelection();#endif}QComboBoxPrivateContainer::QComboBoxPrivateContainer(QAbstractItemView *itemView, QComboBox *parent) : QFrame(parent, Qt::Popup), combo(parent), view(0), top(0), bottom(0){ // we need the combobox and itemview Q_ASSERT(parent); Q_ASSERT(itemView); setAttribute(Qt::WA_WindowPropagation); // setup container blockMouseReleaseTimer.setSingleShot(true); // we need a vertical layout QBoxLayout *layout = new QBoxLayout(QBoxLayout::TopToBottom, this); layout->setSpacing(0); layout->setMargin(0); // set item view setItemView(itemView); // add scroller arrows if style needs them QStyleOptionComboBox opt = comboStyleOption(); const bool usePopup = combo->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, combo); if (usePopup) { top = new QComboBoxPrivateScroller(QAbstractSlider::SliderSingleStepSub, this); bottom = new QComboBoxPrivateScroller(QAbstractSlider::SliderSingleStepAdd, this); top->hide(); bottom->hide(); } else { setLineWidth(1); } setFrameStyle(combo->style()->styleHint(QStyle::SH_ComboBox_PopupFrameStyle, &opt, combo)); if (top) { layout->insertWidget(0, top); connect(top, SIGNAL(doScroll(int)), this, SLOT(scrollItemView(int))); } if (bottom) { layout->addWidget(bottom); connect(bottom, SIGNAL(doScroll(int)), this, SLOT(scrollItemView(int))); } // Some styles (Mac) have a margin at the top and bottom of the popup. layout->insertSpacing(0, 0); layout->addSpacing(0); updateTopBottomMargin();}void QComboBoxPrivateContainer::scrollItemView(int action){#ifndef QT_NO_SCROLLBAR if (view->verticalScrollBar()) view->verticalScrollBar()->triggerAction(static_cast<QAbstractSlider::SliderAction>(action));#endif}/* Hides or shows the scrollers when we emulate a popupmenu*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -