summaryrefslogtreecommitdiffstats
path: root/src/widgets/widgets/qcombobox.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/widgets/widgets/qcombobox.cpp')
-rw-r--r--src/widgets/widgets/qcombobox.cpp169
1 files changed, 125 insertions, 44 deletions
diff --git a/src/widgets/widgets/qcombobox.cpp b/src/widgets/widgets/qcombobox.cpp
index 9a0e969e1c..d786c7ff83 100644
--- a/src/widgets/widgets/qcombobox.cpp
+++ b/src/widgets/widgets/qcombobox.cpp
@@ -91,30 +91,11 @@ QT_BEGIN_NAMESPACE
QComboBoxPrivate::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)
-#ifdef Q_OS_MAC
- , m_platformMenu(0)
-#endif
-#if QT_CONFIG(completer)
- , completer(0)
-#endif
+ inserting(false)
{
}
@@ -148,7 +129,15 @@ QStyleOptionMenuItem QComboMenuDelegate::getStyleOption(const QStyleOptionViewIt
if (option.state & QStyle::State_Selected)
menuOption.state |= QStyle::State_Selected;
menuOption.checkType = QStyleOptionMenuItem::NonExclusive;
- menuOption.checked = mCombo->currentIndex() == index.row();
+ // a valid checkstate means that the model has checkable items
+ const QVariant checkState = index.data(Qt::CheckStateRole);
+ if (!checkState.isValid()) {
+ menuOption.checked = mCombo->currentIndex() == index.row();
+ } else {
+ menuOption.checked = qvariant_cast<int>(checkState) == Qt::Checked;
+ menuOption.state |= qvariant_cast<int>(checkState) == Qt::Checked
+ ? QStyle::State_On : QStyle::State_Off;
+ }
if (QComboBoxDelegate::isSeparator(index))
menuOption.menuItemType = QStyleOptionMenuItem::Separator;
else
@@ -183,7 +172,7 @@ QStyleOptionMenuItem QComboMenuDelegate::getStyleOption(const QStyleOptionViewIt
// that order, also override the font for the popup menu.
QVariant fontRoleData = index.data(Qt::FontRole);
if (fontRoleData.isValid()) {
- menuOption.font = fontRoleData.value<QFont>();
+ menuOption.font = qvariant_cast<QFont>(fontRoleData);
} else if (mCombo->testAttribute(Qt::WA_SetFont)
|| mCombo->testAttribute(Qt::WA_MacSmallSize)
|| mCombo->testAttribute(Qt::WA_MacMiniSize)
@@ -198,6 +187,55 @@ QStyleOptionMenuItem QComboMenuDelegate::getStyleOption(const QStyleOptionViewIt
return menuOption;
}
+bool QComboMenuDelegate::editorEvent(QEvent *event, QAbstractItemModel *model,
+ const QStyleOptionViewItem &option, const QModelIndex &index)
+{
+ Q_ASSERT(event);
+ Q_ASSERT(model);
+
+ // make sure that the item is checkable
+ Qt::ItemFlags flags = model->flags(index);
+ if (!(flags & Qt::ItemIsUserCheckable) || !(option.state & QStyle::State_Enabled)
+ || !(flags & Qt::ItemIsEnabled))
+ return false;
+
+ // make sure that we have a check state
+ const QVariant checkState = index.data(Qt::CheckStateRole);
+ if (!checkState.isValid())
+ return false;
+
+ // make sure that we have the right event type
+ if ((event->type() == QEvent::MouseButtonRelease)
+ || (event->type() == QEvent::MouseButtonDblClick)
+ || (event->type() == QEvent::MouseButtonPress)) {
+ QMouseEvent *me = static_cast<QMouseEvent*>(event);
+ if (me->button() != Qt::LeftButton)
+ return false;
+
+ if ((event->type() == QEvent::MouseButtonPress)
+ || (event->type() == QEvent::MouseButtonDblClick)) {
+ pressedIndex = index.row();
+ return false;
+ }
+
+ if (index.row() != pressedIndex)
+ return false;
+ pressedIndex = -1;
+
+ } else if (event->type() == QEvent::KeyPress) {
+ if (static_cast<QKeyEvent*>(event)->key() != Qt::Key_Space
+ && static_cast<QKeyEvent*>(event)->key() != Qt::Key_Select)
+ return false;
+ } else {
+ return false;
+ }
+
+ // we don't support user-tristate items in QComboBox (not implemented in any style)
+ Qt::CheckState newState = (static_cast<Qt::CheckState>(checkState.toInt()) == Qt::Checked)
+ ? Qt::Unchecked : Qt::Checked;
+ return model->setData(index, newState, Qt::CheckStateRole);
+}
+
#if QT_CONFIG(completer)
void QComboBoxPrivate::_q_completerActivated(const QModelIndex &index)
{
@@ -368,6 +406,8 @@ QSize QComboBoxPrivate::recomputeSizeHint(QSize &sh) const
}
if (minimumContentsLength > 0)
sh.setWidth(qMax(sh.width(), minimumContentsLength * fm.horizontalAdvance(QLatin1Char('X')) + (hasIcon ? iconSize.width() + 4 : 0)));
+ if (!placeholderText.isEmpty())
+ sh.setWidth(qMax(sh.width(), fm.boundingRect(placeholderText).width()));
// height
@@ -445,12 +485,8 @@ void QComboBoxPrivateContainer::paintEvent(QPaintEvent *e)
QFrame::paintEvent(e);
}
-void QComboBoxPrivateContainer::leaveEvent(QEvent *)
-{
-}
-
QComboBoxPrivateContainer::QComboBoxPrivateContainer(QAbstractItemView *itemView, QComboBox *parent)
- : QFrame(parent, Qt::Popup), combo(parent), view(0), top(0), bottom(0), maybeIgnoreMouseButtonRelease(false)
+ : QFrame(parent, Qt::Popup), combo(parent)
{
// we need the combobox and itemview
Q_ASSERT(parent);
@@ -555,7 +591,7 @@ void QComboBoxPrivateContainer::updateScrollers()
*/
void QComboBoxPrivateContainer::viewDestroyed()
{
- view = 0;
+ view = nullptr;
setItemView(new QComboBoxListView());
}
@@ -589,7 +625,7 @@ void QComboBoxPrivateContainer::setItemView(QAbstractItemView *itemView)
if (isAncestorOf(view))
delete view;
- view = 0;
+ view = nullptr;
}
// setup the item view
@@ -929,7 +965,7 @@ QStyleOptionComboBox QComboBoxPrivateContainer::comboStyleOption() const
model QStandardItemModel.
*/
QComboBox::QComboBox(QWidget *parent)
- : QWidget(*new QComboBoxPrivate(), parent, 0)
+ : QWidget(*new QComboBoxPrivate(), parent, { })
{
Q_D(QComboBox);
d->init();
@@ -939,7 +975,7 @@ QComboBox::QComboBox(QWidget *parent)
\internal
*/
QComboBox::QComboBox(QComboBoxPrivate &dd, QWidget *parent)
- : QWidget(dd, parent, 0)
+ : QWidget(dd, parent, { })
{
Q_D(QComboBox);
d->init();
@@ -1110,8 +1146,9 @@ void QComboBoxPrivate::_q_rowsInserted(const QModelIndex &parent, int start, int
q->updateGeometry();
}
- // set current index if combo was previously empty
- if (start == 0 && (end - start + 1) == q->count() && !currentIndex.isValid()) {
+ // set current index if combo was previously empty and there is no placeholderText
+ if (start == 0 && (end - start + 1) == q->count() && !currentIndex.isValid() &&
+ placeholderText.isEmpty()) {
q->setCurrentIndex(0);
// need to emit changed if model updated index "silently"
} else if (currentIndex.row() != indexBeforeChange) {
@@ -1214,10 +1251,9 @@ void QComboBox::initStyleOption(QStyleOptionComboBox *option) const
} else {
option->activeSubControls = d->hoverControl;
}
- if (d->currentIndex.isValid()) {
- option->currentText = currentText();
+ option->currentText = currentText();
+ if (d->currentIndex.isValid())
option->currentIcon = d->itemIcon(d->currentIndex);
- }
option->iconSize = iconSize();
if (d->container && d->container->isVisible())
option->state |= QStyle::State_On;
@@ -1566,7 +1602,7 @@ void QComboBox::setAutoCompletion(bool enable)
d->lineEdit->setCompleter(d->completer);
d->completer->setWidget(this);
} else {
- d->lineEdit->setCompleter(0);
+ d->lineEdit->setCompleter(nullptr);
}
}
@@ -1755,7 +1791,7 @@ QSize QComboBox::iconSize() const
if (d->iconSize.isValid())
return d->iconSize;
- int iconWidth = style()->pixelMetric(QStyle::PM_SmallIconSize, 0, this);
+ int iconWidth = style()->pixelMetric(QStyle::PM_SmallIconSize, nullptr, this);
return QSize(iconWidth, iconWidth);
}
@@ -1772,6 +1808,45 @@ void QComboBox::setIconSize(const QSize &size)
}
/*!
+ \property QComboBox::placeholderText
+ \brief Sets a \a placeholderText text shown when no valid index is set
+
+ The \a placeholderText will be shown when an invalid index is set. The
+ text is not accessible in the dropdown list. When this function is called
+ before items are added the placeholder text will be shown, otherwise you
+ have to call setCurrentIndex(-1) programmatically if you want to show the
+ placeholder text.
+ Set an empty placeholder text to reset the setting.
+
+ When the QComboBox is editable, use QLineEdit::setPlaceholderText()
+ instead.
+
+ \since 5.15
+*/
+void QComboBox::setPlaceholderText(const QString &placeholderText)
+{
+ Q_D(QComboBox);
+ if (placeholderText == d->placeholderText)
+ return;
+
+ d->placeholderText = placeholderText;
+ if (currentIndex() == -1) {
+ if (d->placeholderText.isEmpty() && currentIndex() == -1)
+ setCurrentIndex(0);
+ else
+ update();
+ } else {
+ updateGeometry();
+ }
+}
+
+QString QComboBox::placeholderText() const
+{
+ Q_D(const QComboBox);
+ return d->placeholderText;
+}
+
+/*!
\property QComboBox::editable
\brief whether the combo box can be edited by the user
@@ -1786,7 +1861,7 @@ void QComboBox::setIconSize(const QSize &size)
bool QComboBox::isEditable() const
{
Q_D(const QComboBox);
- return d->lineEdit != 0;
+ return d->lineEdit != nullptr;
}
/*! \internal
@@ -1842,7 +1917,7 @@ void QComboBox::setEditable(bool editable)
setAttribute(Qt::WA_InputMethodEnabled, false);
d->lineEdit->hide();
d->lineEdit->deleteLater();
- d->lineEdit = 0;
+ d->lineEdit = nullptr;
}
d->updateDelegate();
@@ -1891,6 +1966,8 @@ void QComboBox::setLineEdit(QLineEdit *edit)
d->lineEdit->setFocusProxy(this);
d->lineEdit->setAttribute(Qt::WA_MacShowFocusRect, false);
#if QT_DEPRECATED_SINCE(5, 13)
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
#if QT_CONFIG(completer)
setAutoCompletion(d->autoCompletion);
@@ -1907,6 +1984,7 @@ void QComboBox::setLineEdit(QLineEdit *edit)
}
#endif
#endif
+QT_WARNING_POP
#endif
setAttribute(Qt::WA_InputMethodEnabled);
@@ -1955,7 +2033,7 @@ void QComboBox::setValidator(const QValidator *v)
const QValidator *QComboBox::validator() const
{
Q_D(const QComboBox);
- return d->lineEdit ? d->lineEdit->validator() : 0;
+ return d->lineEdit ? d->lineEdit->validator() : nullptr;
}
#endif // QT_NO_VALIDATOR
@@ -1999,7 +2077,7 @@ void QComboBox::setCompleter(QCompleter *c)
QCompleter *QComboBox::completer() const
{
Q_D(const QComboBox);
- return d->lineEdit ? d->lineEdit->completer() : 0;
+ return d->lineEdit ? d->lineEdit->completer() : nullptr;
}
#endif // QT_CONFIG(completer)
@@ -2249,7 +2327,7 @@ QString QComboBox::currentText() const
else if (d->currentIndex.isValid())
return d->itemText(d->currentIndex);
else
- return QString();
+ return d->placeholderText;
}
/*!
@@ -2886,7 +2964,7 @@ void QComboBox::hidePopup()
QSignalBlocker containerBlocker(d->container);
// Flash selected/triggered item (if any).
if (style()->styleHint(QStyle::SH_Menu_FlashTriggeredItem)) {
- QItemSelectionModel *selectionModel = view() ? view()->selectionModel() : 0;
+ QItemSelectionModel *selectionModel = view() ? view()->selectionModel() : nullptr;
if (selectionModel && selectionModel->hasSelection()) {
QEventLoop eventLoop;
const QItemSelection selection = selectionModel->selection();
@@ -3079,6 +3157,9 @@ void QComboBox::paintEvent(QPaintEvent *)
initStyleOption(&opt);
painter.drawComplexControl(QStyle::CC_ComboBox, opt);
+ if (currentIndex() < 0)
+ opt.palette.setBrush(QPalette::ButtonText, opt.palette.brush(QPalette::ButtonText).color().lighter());
+
// draw the icon and text
painter.drawControl(QStyle::CE_ComboBoxLabel, opt);
}