"QMenu")); 115 QVariant value = index.data(arole: Qt::ForegroundRole); 116 if (value.canConvert<QBrush>()) { 117 resolvedpalette.setBrush(acr: QPalette::WindowText, abrush: qvariant_cast<QBrush>(v: value)); 118 resolvedpalette.setBrush(acr: QPalette::ButtonText, abrush: qvariant_cast<QBrush>(v: value)); 119 resolvedpalette.setBrush(acr: QPalette::Text, abrush: qvariant_cast<QBrush>(v: value)); 120 } 121 menuOption.palette = resolvedpalette; 122 menuOption.state = QStyle::State_None; 123 if (mCombo->window()->isActiveWindow()) 124 menuOption.state = QStyle::State_Active; 125 if ((option.state & QStyle::State_Enabled) && (index.model()->flags(index) & Qt::ItemIsEnabled)) 126 menuOption.state |= QStyle::State_Enabled; 127 else 128 menuOption.palette.setCurrentColorGroup(QPalette::Disabled); 129 if (option.state & QStyle::State_Selected) 130 menuOption.state |= QStyle::State_Selected; 131 menuOption.checkType = QStyleOptionMenuItem::NonExclusive; 132 // a valid checkstate means that the model has checkable items 133 const QVariant checkState = index.data(arole: Qt::CheckStateRole); 134 if (!checkState.isValid()) { 135 menuOption.checked = mCombo->currentIndex() == index.row(); 136 } else { 137 menuOption.checked = qvariant_cast<int>(v: checkState) == Qt::Checked; 138 menuOption.state |= qvariant_cast<int>(v: checkState) == Qt::Checked 139 ? QStyle::State_On : QStyle::State_Off; 140 } 141 if (QComboBoxDelegate::isSeparator(index)) 142 menuOption.menuItemType = QStyleOptionMenuItem::Separator; 143 else 144 menuOption.menuItemType = QStyleOptionMenuItem::Normal; 145 146 QVariant variant = index.model()->data(index, role: Qt::DecorationRole); 147 switch (variant.userType()) { 148 case QMetaType::QIcon: 149 menuOption.icon = qvariant_cast<QIcon>(v: variant); 150 break; 151 case QMetaType::QColor: { 152 static QPixmap pixmap(option.decorationSize); 153 pixmap.fill(fillColor: qvariant_cast<QColor>(v: variant)); 154 menuOption.icon = pixmap; 155 break; } 156 default: 157 menuOption.icon = qvariant_cast<QPixmap>(v: variant); 158 break; 159 } 160 if (index.data(arole: Qt::BackgroundRole).canConvert<QBrush>()) { 161 menuOption.palette.setBrush(cg: QPalette::All, cr: QPalette::Window, 162 brush: qvariant_cast<QBrush>(v: index.data(arole: Qt::BackgroundRole))); 163 } 164 menuOption.text = index.model()->data(index, role: Qt::DisplayRole).toString() 165 .replace(c: QLatin1Char('&'), after: QLatin1String(
"&&")); 166 menuOption.tabWidth = 0; 167 menuOption.maxIconWidth = option.decorationSize.width() + 4; 168 menuOption.menuRect = option.rect; 169 menuOption.rect = option.rect; 170 171 // Make sure fonts set on the model or on the combo box, in 172 // that order, also override the font for the popup menu. 173 QVariant fontRoleData = index.data(arole: Qt::FontRole); 174 if (fontRoleData.isValid()) { 175 menuOption.font = qvariant_cast<QFont>(v: fontRoleData); 176 } else if (mCombo->testAttribute(attribute: Qt::WA_SetFont) 177 || mCombo->testAttribute(attribute: Qt::WA_MacSmallSize) 178 || mCombo->testAttribute(attribute: Qt::WA_MacMiniSize) 179 || mCombo->font() != qt_app_fonts_hash()->value(akey:
"QComboBox", adefaultValue: QFont())) { 180 menuOption.font = mCombo->font(); 181 } else { 182 menuOption.font = qt_app_fonts_hash()->value(akey:
"QComboMenuItem", adefaultValue: mCombo->font()); 183 } 184 185 menuOption.fontMetrics = QFontMetrics(menuOption.font); 186 187 return menuOption; 188 } 189 190 bool QComboMenuDelegate::(QEvent *event, QAbstractItemModel *model, 191 const QStyleOptionViewItem &option, const QModelIndex &index) 192 { 193 Q_ASSERT(event); 194 Q_ASSERT(model); 195 196 // make sure that the item is checkable 197 Qt::ItemFlags flags = model->flags(index); 198 if (!(flags & Qt::ItemIsUserCheckable) || !(option.state & QStyle::State_Enabled) 199 || !(flags & Qt::ItemIsEnabled)) 200 return false; 201 202 // make sure that we have a check state 203 const QVariant checkState = index.data(arole: Qt::CheckStateRole); 204 if (!checkState.isValid()) 205 return false; 206 207 // make sure that we have the right event type 208 if ((event->type() == QEvent::MouseButtonRelease) 209 || (event->type() == QEvent::MouseButtonDblClick) 210 || (event->type() == QEvent::MouseButtonPress)) { 211 QMouseEvent *me = static_cast<QMouseEvent*>(event); 212 if (me->button() != Qt::LeftButton) 213 return false; 214 215 if ((event->type() == QEvent::MouseButtonPress) 216 || (event->type() == QEvent::MouseButtonDblClick)) { 217 pressedIndex = index.row(); 218 return false; 219 } 220 221 if (index.row() != pressedIndex) 222 return false; 223 pressedIndex = -1; 224 225 } else if (event->type() == QEvent::KeyPress) { 226 if (static_cast<QKeyEvent*>(event)->key() != Qt::Key_Space 227 && static_cast<QKeyEvent*>(event)->key() != Qt::Key_Select) 228 return false; 229 } else { 230 return false; 231 } 232 233 // we don't support user-tristate items in QComboBox (not implemented in any style) 234 Qt::CheckState newState = (static_cast<Qt::CheckState>(checkState.toInt()) == Qt::Checked) 235 ? Qt::Unchecked : Qt::Checked; 236 return model->setData(index, value: newState, role: Qt::CheckStateRole); 237 } 238 239 #if QT_CONFIG(completer) 240 void QComboBoxPrivate::_q_completerActivated(const QModelIndex &index) 241 { 242 Q_Q(QComboBox); 243 #if QT_CONFIG(proxymodel) 244 if (index.isValid() && q->completer()) { 245 QAbstractProxyModel *proxy = qobject_cast<QAbstractProxyModel *>(object: q->completer()->completionModel()); 246 if (proxy) { 247 const QModelIndex &completerIndex = proxy->mapToSource(proxyIndex: index); 248 int row = -1; 249 if (completerIndex.model() == model) { 250 row = completerIndex.row(); 251 } else { 252 // if QCompleter uses a proxy model to host widget's one - map again 253 QAbstractProxyModel *completerProxy = qobject_cast<QAbstractProxyModel *>(object: q->completer()->model()); 254 if (completerProxy && completerProxy->sourceModel() == model) { 255 row = completerProxy->mapToSource(proxyIndex: completerIndex).row(); 256 } else { 257 QString match = q->completer()->model()->data(index: completerIndex).toString(); 258 row = q->findText(text: match, flags: matchFlags()); 259 } 260 } 261 q->setCurrentIndex(row); 262 emitActivated(index: currentIndex); 263 } 264 } 265 #endif 266 267 # ifdef QT_KEYPAD_NAVIGATION 268 if ( QApplicationPrivate::keypadNavigationEnabled() 269 && q->isEditable() 270 && q->completer() 271 && q->completer()->completionMode() == QCompleter::UnfilteredPopupCompletion ) { 272 q->setEditFocus(false); 273 } 274 # endif // QT_KEYPAD_NAVIGATION 275 } 276 #endif // QT_CONFIG(completer) 277 278 void QComboBoxPrivate::updateArrow(QStyle::StateFlag state) 279 { 280 Q_Q(QComboBox); 281 if (arrowState == state) 282 return; 283 arrowState = state; 284 QStyleOptionComboBox opt; 285 q->initStyleOption(option: &opt); 286 q->update(q->rect()); 287 } 288 289 void QComboBoxPrivate::_q_modelReset() 290 { 291 Q_Q(QComboBox); 292 if (lineEdit) { 293 lineEdit->setText(QString()); 294 updateLineEditGeometry(); 295 } 296 trySetValidIndex(); 297 modelChanged(); 298 q->update(); 299 } 300 301 void QComboBoxPrivate::_q_modelDestroyed() 302 { 303 model = QAbstractItemModelPrivate::staticEmptyModel(); 304 } 305 306 void QComboBoxPrivate::trySetValidIndex() 307 { 308 Q_Q(QComboBox); 309 bool currentReset = false; 310 311 const int rowCount = q->count(); 312 for (int pos = 0; pos < rowCount; ++pos) { 313 const QModelIndex idx(model->index(row: pos, column: modelColumn, parent: root)); 314 if (idx.flags() & Qt::ItemIsEnabled) { 315 setCurrentIndex(idx); 316 currentReset = true; 317 break; 318 } 319 } 320 321 if (!currentReset) 322 setCurrentIndex(QModelIndex()); 323 } 324 325 QRect QComboBoxPrivate::(int screen) const 326 { 327 return QStylePrivate::useFullScreenForPopup() 328 ? QDesktopWidgetPrivate::screenGeometry(screen) 329 : QDesktopWidgetPrivate::availableGeometry(screen); 330 } 331 332 bool QComboBoxPrivate::updateHoverControl(const QPoint &pos) 333 { 334 335 Q_Q(QComboBox); 336 QRect lastHoverRect = hoverRect; 337 QStyle::SubControl lastHoverControl = hoverControl; 338 bool doesHover = q->testAttribute(attribute: Qt::WA_Hover); 339 if (lastHoverControl != newHoverControl(pos) && doesHover) { 340 q->update(lastHoverRect); 341 q->update(hoverRect); 342 return true; 343 } 344 return !doesHover; 345 } 346 347 QStyle::SubControl QComboBoxPrivate::newHoverControl(const QPoint &pos) 348 { 349 Q_Q(QComboBox); 350 QStyleOptionComboBox opt; 351 q->initStyleOption(option: &opt); 352 opt.subControls = QStyle::SC_All; 353 hoverControl = q->style()->hitTestComplexControl(cc: QStyle::CC_ComboBox, opt: &opt, pt: pos, widget: q); 354 hoverRect = (hoverControl != QStyle::SC_None) 355 ? q->style()->subControlRect(cc: QStyle::CC_ComboBox, opt: &opt, sc: hoverControl, widget: q) 356 : QRect(); 357 return hoverControl; 358 } 359 360 /* 361 Computes a size hint based on the maximum width 362 for the items in the combobox. 363 */ 364 int QComboBoxPrivate::computeWidthHint() const 365 { 366 Q_Q(const QComboBox); 367 368 int width = 0; 369 const int count = q->count(); 370 const int iconWidth = q->iconSize().width() + 4; 371 const QFontMetrics &fontMetrics = q->fontMetrics(); 372 373 for (int i = 0; i < count; ++i) { 374 const int textWidth = fontMetrics.horizontalAdvance(q->itemText(index: i)); 375 if (q->itemIcon(index: i).isNull()) 376 width = (qMax(a: width, b: textWidth)); 377 else 378 width = (qMax(a: width, b: textWidth + iconWidth)); 379 } 380 381 QStyleOptionComboBox opt; 382 q->initStyleOption(option: &opt); 383 QSize tmp(width, 0); 384 tmp = q->style()->sizeFromContents(ct: QStyle::CT_ComboBox, opt: &opt, contentsSize: tmp, w: q); 385 return tmp.width(); 386 } 387 388 #if QT_DEPRECATED_SINCE(5, 15) 389 QT_WARNING_PUSH 390 QT_WARNING_DISABLE_DEPRECATED 391 static constexpr QComboBox::SizeAdjustPolicy deprecatedAdjustToMinimumContentsLength() 392 { 393 return QComboBox::AdjustToMinimumContentsLength; 394 } 395 QT_WARNING_POP 396 #endif 397 398 QSize QComboBoxPrivate::recomputeSizeHint(QSize &sh) const 399 { 400 Q_Q(const QComboBox); 401 if (!sh.isValid()) { 402 bool hasIcon = sizeAdjustPolicy == QComboBox::AdjustToMinimumContentsLengthWithIcon; 403 int count = q->count(); 404 QSize iconSize = q->iconSize(); 405 const QFontMetrics &fm = q->fontMetrics(); 406 407 // text width 408 if (&sh == &sizeHint || minimumContentsLength == 0) { 409 switch (sizeAdjustPolicy) { 410 case QComboBox::AdjustToContents: 411 case QComboBox::AdjustToContentsOnFirstShow: 412 if (count == 0) { 413 sh.rwidth() = 7 * fm.horizontalAdvance(QLatin1Char('x')); 414 } else { 415 for (int i = 0; i < count; ++i) { 416 if (!q->itemIcon(index: i).isNull()) { 417 hasIcon = true; 418 sh.setWidth(qMax(a: sh.width(), b: fm.boundingRect(text: q->itemText(index: i)).width() + iconSize.width() + 4)); 419 } else { 420 sh.setWidth(qMax(a: sh.width(), b: fm.boundingRect(text: q->itemText(index: i)).width())); 421 } 422 } 423 } 424 break; 425 case deprecatedAdjustToMinimumContentsLength(): 426 for (int i = 0; i < count && !hasIcon; ++i) 427 hasIcon = !q->itemIcon(index: i).isNull(); 428 break; 429 case QComboBox::AdjustToMinimumContentsLengthWithIcon: 430 ; 431 } 432 } else { 433 for (int i = 0; i < count && !hasIcon; ++i) 434 hasIcon = !q->itemIcon(index: i).isNull(); 435 } 436 if (minimumContentsLength > 0) 437 sh.setWidth(qMax(a: sh.width(), b: minimumContentsLength * fm.horizontalAdvance(QLatin1Char('X')) + (hasIcon ? iconSize.width() + 4 : 0))); 438 if (!placeholderText.isEmpty()) 439 sh.setWidth(qMax(a: sh.width(), b: fm.boundingRect(text: placeholderText).width())); 440 441 442 // height 443 sh.setHeight(qMax(a: qCeil(v: QFontMetricsF(fm).height()), b: 14) + 2); 444 if (hasIcon) { 445 sh.setHeight(qMax(a: sh.height(), b: iconSize.height() + 2)); 446 } 447 448 // add style and strut values 449 QStyleOptionComboBox opt; 450 q->initStyleOption(option: &opt); 451 sh = q->style()->sizeFromContents(ct: QStyle::CT_ComboBox, opt: &opt, contentsSize: sh, w: q); 452 } 453 return sh.expandedTo(otherSize: QApplication::globalStrut()); 454 } 455 456 void QComboBoxPrivate::adjustComboBoxSize() 457 { 458 viewContainer()->adjustSizeTimer.start(msec: 20, obj: container); 459 } 460 461 void QComboBoxPrivate::updateLayoutDirection() 462 { 463 Q_Q(const QComboBox); 464 QStyleOptionComboBox opt; 465 q->initStyleOption(option: &opt); 466 Qt::LayoutDirection dir = Qt::LayoutDirection( 467 q->style()->styleHint(stylehint: QStyle::SH_ComboBox_LayoutDirection, opt: &opt, widget: q)); 468 if (lineEdit) 469 lineEdit->setLayoutDirection(dir); 470 if (container) 471 container->setLayoutDirection(dir); 472 } 473 474 475 void QComboBoxPrivateContainer::timerEvent(QTimerEvent *timerEvent) 476 { 477 if (timerEvent->timerId() == adjustSizeTimer.timerId()) { 478 adjustSizeTimer.stop(); 479 if (combo->sizeAdjustPolicy() == QComboBox::AdjustToContents) { 480 combo->updateGeometry(); 481 combo->adjustSize(); 482 combo->update(); 483 } 484 } 485 } 486 487 void QComboBoxPrivateContainer::resizeEvent(QResizeEvent *e) 488 { 489 QStyleOptionComboBox opt = comboStyleOption(); 490 if (combo->style()->styleHint(stylehint: QStyle::SH_ComboBox_Popup, opt: &opt, widget: combo)) { 491 QStyleOption myOpt; 492 myOpt.initFrom(w: this); 493 QStyleHintReturnMask mask; 494 if (combo->style()->styleHint(stylehint: QStyle::SH_Menu_Mask, opt: &myOpt, widget: this, returnData: &mask)) { 495 setMask(mask.region); 496 } 497 } else { 498 clearMask(); 499 } 500 QFrame::resizeEvent(event: e); 501 } 502 503 void QComboBoxPrivateContainer::paintEvent(QPaintEvent *e) 504 { 505 QStyleOptionComboBox cbOpt = comboStyleOption(); 506 if (combo->style()->styleHint(stylehint: QStyle::SH_ComboBox_Popup, opt: &cbOpt, widget: combo) 507 && mask().isEmpty()) { 508 QStyleOption opt; 509 opt.initFrom(w: this); 510 QPainter p(this); 511 style()->drawPrimitive(pe: QStyle::PE_PanelMenu, opt: &opt, p: &p, w: this); 512 } 513 514 QFrame::paintEvent(e); 515 } 516 517 QComboBoxPrivateContainer::QComboBoxPrivateContainer(QAbstractItemView *itemView, QComboBox *parent) 518 : QFrame(parent, Qt::Popup), combo(parent) 519 { 520 // we need the combobox and itemview 521 Q_ASSERT(parent); 522 Q_ASSERT(itemView); 523 524 setAttribute(Qt::WA_WindowPropagation); 525 setAttribute(Qt::WA_X11NetWmWindowTypeCombo); 526 527 // setup container 528 blockMouseReleaseTimer.setSingleShot(true); 529 530 // we need a vertical layout 531 QBoxLayout *layout = new QBoxLayout(QBoxLayout::TopToBottom, this); 532 layout->setSpacing(0); 533 layout->setContentsMargins(QMargins()); 534 535 // set item view 536 setItemView(itemView); 537 538 // add scroller arrows if style needs them 539 QStyleOptionComboBox opt = comboStyleOption(); 540 const bool = combo->style()->styleHint(stylehint: QStyle::SH_ComboBox_Popup, opt: &opt, widget: combo); 541 if (usePopup) { 542 top = new QComboBoxPrivateScroller(QAbstractSlider::SliderSingleStepSub, this); 543 bottom = new QComboBoxPrivateScroller(QAbstractSlider::SliderSingleStepAdd, this); 544 top->hide(); 545 bottom->hide(); 546 } else { 547 setLineWidth(1); 548 } 549 550 if (top) { 551 layout->insertWidget(index: 0, widget: top); 552 connect(sender: top, SIGNAL(doScroll(int)), receiver: this, SLOT(scrollItemView(int))); 553 } 554 if (bottom) { 555 layout->addWidget(bottom); 556 connect(sender: bottom, SIGNAL(doScroll(int)), receiver: this, SLOT(scrollItemView(int))); 557 } 558 559 // Some styles (Mac) have a margin at the top and bottom of the popup. 560 layout->insertSpacing(index: 0, size: 0); 561 layout->addSpacing(size: 0); 562 updateStyleSettings(); 563 } 564 565 void QComboBoxPrivateContainer::scrollItemView(int action) 566 { 567 #if QT_CONFIG(scrollbar) 568 if (view->verticalScrollBar()) 569 view->verticalScrollBar()->triggerAction(action: static_cast<QAbstractSlider::SliderAction>(action)); 570 #endif 571 } 572 573 void QComboBoxPrivateContainer::hideScrollers() 574 { 575 if (top) 576 top->hide(); 577 if (bottom) 578 bottom->hide(); 579 } 580 581 /* 582 Hides or shows the scrollers when we emulate a popupmenu 583 */ 584 void QComboBoxPrivateContainer::updateScrollers() 585 { 586 #if QT_CONFIG(scrollbar) 587 if (!top || !bottom) 588 return; 589 590 if (isVisible() == false) 591 return; 592 593 QStyleOptionComboBox opt = comboStyleOption(); 594 if (combo->style()->styleHint(stylehint: QStyle::SH_ComboBox_Popup, opt: &opt, widget: combo) && 595 view->verticalScrollBar()->minimum() < view->verticalScrollBar()->maximum()) { 596 597 bool needTop = view->verticalScrollBar()->value() 598 > (view->verticalScrollBar()->minimum() + topMargin()); 599 bool needBottom = view->verticalScrollBar()->value() 600 < (view->verticalScrollBar()->maximum() - bottomMargin() - topMargin()); 601 if (needTop) 602 top->show(); 603 else 604 top->hide(); 605 if (needBottom) 606 bottom->show(); 607 else 608 bottom->hide(); 609 } else { 610 top->hide(); 611 bottom->hide(); 612 } 613 #endif // QT_CONFIG(scrollbar) 614 } 615 616 /* 617 Cleans up when the view is destroyed. 618 */ 619 void QComboBoxPrivateContainer::viewDestroyed() 620 { 621 view = nullptr; 622 setItemView(new QComboBoxListView()); 623 } 624 625 /* 626 Returns the item view used for the combobox popup. 627 */ 628 QAbstractItemView *QComboBoxPrivateContainer::itemView() const 629 { 630 return view; 631 } 632 633 /*! 634 Sets the item view to be used for the combobox popup. 635 */ 636 void QComboBoxPrivateContainer::setItemView(QAbstractItemView *itemView) 637 { 638 Q_ASSERT(itemView); 639 640 // clean up old one 641 if (view) { 642 view->removeEventFilter(obj: this); 643 view->viewport()->removeEventFilter(obj: this); 644 #if QT_CONFIG(scrollbar) 645 disconnect(sender: view->verticalScrollBar(), SIGNAL(valueChanged(int)), 646 receiver: this, SLOT(updateScrollers())); 647 disconnect(sender: view->verticalScrollBar(), SIGNAL(rangeChanged(int,int)), 648 receiver: this, SLOT(updateScrollers())); 649 #endif 650 disconnect(sender: view, SIGNAL(destroyed()), 651 receiver: this, SLOT(viewDestroyed())); 652 653 if (isAncestorOf(child: view)) 654 delete view; 655 view = nullptr; 656 } 657 658 // setup the item view 659 view = itemView; 660 view->setParent(this); 661 view->setAttribute(Qt::WA_MacShowFocusRect, on: false); 662 qobject_cast<QBoxLayout*>(object: layout())->insertWidget(index: top ? 2 : 0, widget: view); 663 view->setSizePolicy(hor: QSizePolicy::Ignored, ver: QSizePolicy::Ignored); 664 view->installEventFilter(filterObj: this); 665 view->viewport()->installEventFilter(filterObj: this); 666 view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 667 QStyleOptionComboBox opt = comboStyleOption(); 668 const bool = combo->style()->styleHint(stylehint: QStyle::SH_ComboBox_Popup, opt: &opt, widget: combo); 669 #if QT_CONFIG(scrollbar) 670 if (usePopup) 671 view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 672 #endif 673 if (combo->style()->styleHint(stylehint: QStyle::SH_ComboBox_ListMouseTracking, opt: &opt, widget: combo) || 674 usePopup) { 675 view->setMouseTracking(true); 676 } 677 view->setSelectionMode(QAbstractItemView::SingleSelection); 678 view->setFrameStyle(QFrame::NoFrame); 679 view->setLineWidth(0); 680 view->setEditTriggers(QAbstractItemView::NoEditTriggers); 681 #if QT_CONFIG(scrollbar) 682 connect(sender: view->verticalScrollBar(), SIGNAL(valueChanged(int)), 683 receiver: this, SLOT(updateScrollers())); 684 connect(sender: view->verticalScrollBar(), SIGNAL(rangeChanged(int,int)), 685 receiver: this, SLOT(updateScrollers())); 686 #endif 687 connect(sender: view, SIGNAL(destroyed()), 688 receiver: this, SLOT(viewDestroyed())); 689 } 690 691 /*! 692 Returns the top/bottom vertical margin of the view. 693 */ 694 int QComboBoxPrivateContainer::topMargin() const 695 { 696 if (const QListView *lview = qobject_cast<const QListView*>(object: view)) 697 return lview->spacing(); 698 #if QT_CONFIG(tableview) 699 if (const QTableView *tview = qobject_cast<const QTableView*>(object: view)) 700 return tview->showGrid() ? 1 : 0; 701 #endif 702 return 0; 703 } 704 705 /*! 706 Returns the spacing between the items in the view. 707 */ 708 int QComboBoxPrivateContainer::spacing() const 709 { 710 QListView *lview = qobject_cast<QListView*>(object: view); 711 if (lview) 712 return 2 * lview->spacing(); // QListView::spacing is the padding around the item. 713 #if QT_CONFIG(tableview) 714 QTableView *tview = qobject_cast<QTableView*>(object: view); 715 if (tview) 716 return tview->showGrid() ? 1 : 0; 717 #endif 718 return 0; 719 } 720 721 void QComboBoxPrivateContainer::updateTopBottomMargin() 722 { 723 if (!layout() || layout()->count() < 1) 724 return; 725 726 QBoxLayout *boxLayout = qobject_cast<QBoxLayout *>(object: layout()); 727 if (!boxLayout) 728 return; 729 730 const QStyleOptionComboBox opt = comboStyleOption(); 731 const bool = combo->style()->styleHint(stylehint: QStyle::SH_ComboBox_Popup, opt: &opt, widget: combo); 732 const int margin = usePopup ? combo->style()->pixelMetric(metric: QStyle::PM_MenuVMargin, option: &opt, widget: combo) : 0; 733 734 QSpacerItem *topSpacer = boxLayout->itemAt(0)->spacerItem(); 735 if (topSpacer) 736 topSpacer->changeSize(w: 0, h: margin, hData: QSizePolicy::Minimum, vData: QSizePolicy::Fixed); 737 738 QSpacerItem *bottomSpacer = boxLayout->itemAt(boxLayout->count() - 1)->spacerItem(); 739 if (bottomSpacer && bottomSpacer != topSpacer) 740 bottomSpacer->changeSize(w: 0, h: margin, hData: QSizePolicy::Minimum, vData: QSizePolicy::Fixed); 741 742 boxLayout->invalidate(); 743 } 744 745 void QComboBoxPrivateContainer::updateStyleSettings() 746 { 747 // add scroller arrows if style needs them 748 QStyleOptionComboBox opt = comboStyleOption(); 749 view->setMouseTracking(combo->style()->styleHint(stylehint: QStyle::SH_ComboBox_ListMouseTracking, opt: &opt, widget: combo) || 750 combo->style()->styleHint(stylehint: QStyle::SH_ComboBox_Popup, opt: &opt, widget: combo)); 751 setFrameStyle(combo->style()->styleHint(stylehint: QStyle::SH_ComboBox_PopupFrameStyle, opt: &opt, widget: combo)); 752 updateTopBottomMargin(); 753 } 754 755 void QComboBoxPrivateContainer::changeEvent(QEvent *e) 756 { 757 if (e->type() == QEvent::StyleChange) 758 updateStyleSettings(); 759 760 QFrame::changeEvent(e); 761 } 762 763 764 bool QComboBoxPrivateContainer::eventFilter(QObject *o, QEvent *e) 765 { 766 switch (e->type()) { 767 case QEvent::ShortcutOverride: { 768 QKeyEvent *keyEvent = static_cast<QKeyEvent*>(e); 769 switch (keyEvent->key()) { 770 case Qt::Key_Enter: 771 case Qt::Key_Return: 772 #ifdef QT_KEYPAD_NAVIGATION 773 case Qt::Key_Select: 774 #endif 775 if (view->currentIndex().isValid() && (view->currentIndex().flags() & Qt::ItemIsEnabled) ) { 776 combo->hidePopup(); 777 emit itemSelected(view->currentIndex()); 778 } 779 return true; 780 case Qt::Key_Down: 781 if (!(keyEvent->modifiers() & Qt::AltModifier)) 782 break; 783 Q_FALLTHROUGH(); 784 case Qt::Key_F4: 785 combo->hidePopup(); 786 return true; 787 default: 788 #if QT_CONFIG(shortcut) 789 if (keyEvent->matches(key: QKeySequence::Cancel)) { 790 combo->hidePopup(); 791 return true; 792 } 793 #endif 794 break; 795 } 796 break; 797 } 798 case QEvent::MouseMove: 799 if (isVisible()) { 800 QMouseEvent *m = static_cast<QMouseEvent *>(e); 801 QWidget *widget = static_cast<QWidget *>(o); 802 QPoint vector = widget->mapToGlobal(m->pos()) - initialClickPosition; 803 if (vector.manhattanLength() > 9 && blockMouseReleaseTimer.isActive()) 804 blockMouseReleaseTimer.stop(); 805 QModelIndex indexUnderMouse = view->indexAt(point: m->pos()); 806 if (indexUnderMouse.isValid() 807 && !QComboBoxDelegate::isSeparator(index: indexUnderMouse)) { 808 view->setCurrentIndex(indexUnderMouse); 809 } 810 } 811 break; 812 case QEvent::MouseButtonPress: 813 maybeIgnoreMouseButtonRelease = false; 814 break; 815 case QEvent::MouseButtonRelease: { 816 bool ignoreEvent = maybeIgnoreMouseButtonRelease && popupTimer.elapsed() < QApplication::doubleClickInterval(); 817 818 QMouseEvent *m = static_cast<QMouseEvent *>(e); 819 if (isVisible() && view->rect().contains(p: m->pos()) && view->currentIndex().isValid() 820 && !blockMouseReleaseTimer.isActive() && !ignoreEvent 821 && (view->currentIndex().flags() & Qt::ItemIsEnabled) 822 && (view->currentIndex().flags() & Qt::ItemIsSelectable)) { 823 combo->hidePopup(); 824 emit itemSelected(view->currentIndex()); 825 return true; 826 } 827 break; 828 } 829 default: 830 break; 831 } 832 return QFrame::eventFilter(watched: o, event: e); 833 } 834 835 void QComboBoxPrivateContainer::showEvent(QShowEvent *) 836 { 837 combo->update(); 838 } 839 840 void QComboBoxPrivateContainer::hideEvent(QHideEvent *) 841 { 842 emit resetButton(); 843 combo->update(); 844 #if QT_CONFIG(graphicsview) 845 // QGraphicsScenePrivate::removePopup closes the combo box popup, it hides it non-explicitly. 846 // Hiding/showing the QComboBox after this will unexpectedly show the popup as well. 847 // Re-hiding the popup container makes sure it is explicitly hidden. 848 if (QGraphicsProxyWidget *proxy = graphicsProxyWidget()) 849 proxy->hide(); 850 #endif 851 } 852 853 void QComboBoxPrivateContainer::mousePressEvent(QMouseEvent *e) 854 { 855 856 QStyleOptionComboBox opt = comboStyleOption(); 857 opt.subControls = QStyle::SC_All; 858 opt.activeSubControls = QStyle::SC_ComboBoxArrow; 859 QStyle::SubControl sc = combo->style()->hitTestComplexControl(cc: QStyle::CC_ComboBox, opt: &opt, 860 pt: combo->mapFromGlobal(e->globalPos()), 861 widget: combo); 862 if ((combo->isEditable() && sc == QStyle::SC_ComboBoxArrow) 863 || (!combo->isEditable() && sc != QStyle::SC_None)) 864 setAttribute(Qt::WA_NoMouseReplay); 865 combo->hidePopup(); 866 } 867 868 void QComboBoxPrivateContainer::mouseReleaseEvent(QMouseEvent *e) 869 { 870 Q_UNUSED(e); 871 if (!blockMouseReleaseTimer.isActive()){ 872 combo->hidePopup(); 873 emit resetButton(); 874 } 875 } 876 877 QStyleOptionComboBox QComboBoxPrivateContainer::comboStyleOption() const 878 { 879 // ### This should use QComboBox's initStyleOption(), but it's protected 880 // perhaps, we could cheat by having the QCombo private instead? 881 QStyleOptionComboBox opt; 882 opt.initFrom(w: combo); 883 opt.subControls = QStyle::SC_All; 884 opt.activeSubControls = QStyle::SC_None; 885 opt.editable = combo->isEditable(); 886 return opt; 887 } 888 889 /*! 890 \enum QComboBox::InsertPolicy 891 892 This enum specifies what the QComboBox should do when a new string is 893 entered by the user. 894 895 \value NoInsert The string will not be inserted into the combobox. 896 \value InsertAtTop The string will be inserted as the first item in the combobox. 897 \value InsertAtCurrent The current item will be \e replaced by the string. 898 \value InsertAtBottom The string will be inserted after the last item in the combobox. 899 \value InsertAfterCurrent The string is inserted after the current item in the combobox. 900 \value InsertBeforeCurrent The string is inserted before the current item in the combobox. 901 \value InsertAlphabetically The string is inserted in the alphabetic order in the combobox. 902 */ 903 904 /*! 905 \enum QComboBox::SizeAdjustPolicy 906 907 This enum specifies how the size hint of the QComboBox should 908 adjust when new content is added or content changes. 909 910 \value AdjustToContents The combobox will always adjust to the contents 911 \value AdjustToContentsOnFirstShow The combobox will adjust to its contents the first time it is shown. 912 \omitvalue AdjustToMinimumContentsLength 913 \value AdjustToMinimumContentsLengthWithIcon The combobox will adjust to \l minimumContentsLength plus space for an icon. For performance reasons use this policy on large models. 914 */ 915 916 /*! 917 \fn void QComboBox::activated(int index) 918 919 This signal is sent when the user chooses an item in the combobox. 920 The item's \a index is passed. Note that this signal is sent even 921 when the choice is not changed. If you need to know when the 922 choice actually changes, use signal currentIndexChanged() or 923 currentTextChanged(). 924 925 */ 926 927 /*! 928 \fn void QComboBox::activated(const QString &text) 929 930 This signal is sent when the user chooses an item in the combobox. 931 The item's \a text is passed. Note that this signal is sent even 932 when the choice is not changed. If you need to know when the 933 choice actually changes, use signal currentIndexChanged() or 934 currentTextChanged(). 935 936 \obsolete Use QComboBox::textActivated() instead 937 */ 938 /*! 939 \fn void QComboBox::textActivated(const QString &text) 940 \since 5.14 941 942 This signal is sent when the user chooses an item in the combobox. 943 The item's \a text is passed. Note that this signal is sent even 944 when the choice is not changed. If you need to know when the 945 choice actually changes, use signal currentIndexChanged() or 946 currentTextChanged(). 947 */ 948 949 /*! 950 \fn void QComboBox::highlighted(int index) 951 952 This signal is sent when an item in the combobox popup list is 953 highlighted by the user. The item's \a index is passed. 954 */ 955 956 /*! 957 \fn void QComboBox::highlighted(const QString &text) 958 959 This signal is sent when an item in the combobox popup list is 960 highlighted by the user. The item's \a text is passed. 961 962 \obsolete Use textHighlighted() instead 963 */ 964 /*! 965 \fn void QComboBox::textHighlighted(const QString &text) 966 \since 5.14 967 968 This signal is sent when an item in the combobox popup list is 969 highlighted by the user. The item's \a text is passed. 970 */ 971 972 /*! 973 \fn void QComboBox::currentIndexChanged(int index) 974 \since 4.1 975 976 This signal is sent whenever the currentIndex in the combobox 977 changes either through user interaction or programmatically. The 978 item's \a index is passed or -1 if the combobox becomes empty or the 979 currentIndex was reset. 980 */ 981 982 /*! 983 \fn void QComboBox::currentIndexChanged(const QString &text) 984 \since 4.1 985 986 This signal is sent whenever the currentIndex in the combobox 987 changes either through user interaction or programmatically. The 988 item's \a text is passed. 989 990 \obsolete Use currentIndexChanged(int) and get the text from 991 the itemText(int) method. 992 */ 993 994 /*! 995 \fn void QComboBox::currentTextChanged(const QString &text) 996 \since 5.0 997 998 This signal is sent whenever currentText changes. The new value 999 is passed as \a text. 1000 */ 1001 1002 /*! 1003 Constructs a combobox with the given \a parent, using the default 1004 model QStandardItemModel. 1005 */ 1006 QComboBox::QComboBox(QWidget *parent) 1007 : QWidget(*new QComboBoxPrivate(), parent, { }) 1008 { 1009 Q_D(QComboBox); 1010 d->init(); 1011 } 1012 1013 /*! 1014 \internal 1015 */ 1016 QComboBox::QComboBox(QComboBoxPrivate &dd, QWidget *parent) 1017 : QWidget(dd, parent, { }) 1018 { 1019 Q_D(QComboBox); 1020 d->init(); 1021 } 1022 1023 /*! 1024 \class QComboBox 1025 \brief The QComboBox widget is a combined button and popup list. 1026 1027 \ingroup basicwidgets 1028 \inmodule QtWidgets 1029 1030 \image windows-combobox.png 1031 1032 A QComboBox provides a means of presenting a list of options to the user 1033 in a way that takes up the minimum amount of screen space. 1034 1035 A combobox is a selection widget that displays the current item, 1036 and can pop up a list of selectable items. A combobox may be editable, 1037 allowing the user to modify each item in the list. 1038 1039 Comboboxes can contain pixmaps as well as strings; the 1040 insertItem() and setItemText() functions are suitably overloaded. 1041 For editable comboboxes, the function clearEditText() is provided, 1042 to clear the displayed string without changing the combobox's 1043 contents. 1044 1045 There are three signals emitted if the current item of a combobox 1046 changes, currentIndexChanged(), currentTextChanged() and activated(). 1047 currentIndexChanged() and currentTextChanged() are always emitted 1048 regardless if the change 1049 was done programmatically or by user interaction, while 1050 activated() is only emitted when the change is caused by user 1051 interaction. The highlighted() signal is emitted when the user 1052 highlights an item in the combobox popup list. All three signals 1053 exist in two versions, one with a QString argument and one with an 1054 \c int argument. If the user selects or highlights a pixmap, only 1055 the \c int signals are emitted. Whenever the text of an editable 1056 combobox is changed the editTextChanged() signal is emitted. 1057 1058 When the user enters a new string in an editable combobox, the 1059 widget may or may not insert it, and it can insert it in several 1060 locations. The default policy is \l InsertAtBottom but you can change 1061 this using setInsertPolicy(). 1062 1063 It is possible to constrain the input to an editable combobox 1064 using QValidator; see setValidator(). By default, any input is 1065 accepted. 1066 1067 A combobox can be populated using the insert functions, 1068 insertItem() and insertItems() for example. Items can be 1069 changed with setItemText(). An item can be removed with 1070 removeItem() and all items can be removed with clear(). The text 1071 of the current item is returned by currentText(), and the text of 1072 a numbered item is returned with text(). The current item can be 1073 set with setCurrentIndex(). The number of items in the combobox is 1074 returned by count(); the maximum number of items can be set with 1075 setMaxCount(). You can allow editing using setEditable(). For 1076 editable comboboxes you can set auto-completion using 1077 setCompleter() and whether or not the user can add duplicates 1078 is set with setDuplicatesEnabled(). 1079 1080 QComboBox uses the \l{Model/View Programming}{model/view 1081 framework} for its popup list and to store its items. By default 1082 a QStandardItemModel stores the items and a QListView subclass 1083 displays the popuplist. You can access the model and view directly 1084 (with model() and view()), but QComboBox also provides functions 1085 to set and get item data (e.g., setItemData() and itemText()). You 1086 can also set a new model and view (with setModel() and setView()). 1087 For the text and icon in the combobox label, the data in the model 1088 that has the Qt::DisplayRole and Qt::DecorationRole is used. Note 1089 that you cannot alter the \l{QAbstractItemView::}{SelectionMode} 1090 of the view(), e.g., by using 1091 \l{QAbstractItemView::}{setSelectionMode()}. 1092 1093 \sa QLineEdit, QSpinBox, QRadioButton, QButtonGroup, 1094 {fowler}{GUI Design Handbook: Combo Box, Drop-Down List Box} 1095 */ 1096 1097 void QComboBoxPrivate::init() 1098 { 1099 Q_Q(QComboBox); 1100 #ifdef Q_OS_MACOS 1101 // On OS X, only line edits and list views always get tab focus. It's only 1102 // when we enable full keyboard access that other controls can get tab focus. 1103 // When it's not editable, a combobox looks like a button, and it behaves as 1104 // such in this respect. 1105 if (!q->isEditable()) 1106 q->setFocusPolicy(Qt::TabFocus); 1107 else 1108 #endif 1109 q->setFocusPolicy(Qt::WheelFocus); 1110 1111 q->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed, 1112 QSizePolicy::ComboBox)); 1113 setLayoutItemMargins(element: QStyle::SE_ComboBoxLayoutItem); 1114 q->setModel(new QStandardItemModel(0, 1, q)); 1115 if (!q->isEditable()) 1116 q->setAttribute(Qt::WA_InputMethodEnabled, on: false); 1117 else 1118 q->setAttribute(Qt::WA_InputMethodEnabled); 1119 } 1120 1121 QComboBoxPrivateContainer* QComboBoxPrivate::viewContainer() 1122 { 1123 if (container) 1124 return container; 1125 1126 Q_Q(QComboBox); 1127 container = new QComboBoxPrivateContainer(new QComboBoxListView(q), q); 1128 container->itemView()->setModel(model); 1129 container->itemView()->setTextElideMode(Qt::ElideMiddle); 1130 updateDelegate(force: true); 1131 updateLayoutDirection(); 1132 updateViewContainerPaletteAndOpacity(); 1133 QObject::connect(sender: container, SIGNAL(itemSelected(QModelIndex)), 1134 receiver: q, SLOT(_q_itemSelected(QModelIndex))); 1135 QObject::connect(sender: container->itemView()->selectionModel(), 1136 SIGNAL(currentChanged(QModelIndex,QModelIndex)), 1137 receiver: q, SLOT(_q_emitHighlighted(QModelIndex))); 1138 QObject::connect(sender: container, SIGNAL(resetButton()), receiver: q, SLOT(_q_resetButton())); 1139 return container; 1140 } 1141 1142 1143 void QComboBoxPrivate::_q_resetButton() 1144 { 1145 updateArrow(state: QStyle::State_None); 1146 } 1147 1148 void QComboBoxPrivate::_q_dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) 1149 { 1150 Q_Q(QComboBox); 1151 if (inserting || topLeft.parent() != root) 1152 return; 1153 1154 if (sizeAdjustPolicy == QComboBox::AdjustToContents) { 1155 sizeHint = QSize(); 1156 adjustComboBoxSize(); 1157 q->updateGeometry(); 1158 } 1159 1160 if (currentIndex.row() >= topLeft.row() && currentIndex.row() <= bottomRight.row()) { 1161 const QString text = q->itemText(index: currentIndex.row()); 1162 if (lineEdit) { 1163 lineEdit->setText(text); 1164 updateLineEditGeometry(); 1165 } else { 1166 emit q->currentTextChanged(text); 1167 } 1168 q->update(); 1169 #ifndef QT_NO_ACCESSIBILITY 1170 QAccessibleValueChangeEvent event(q, text); 1171 QAccessible::updateAccessibility(event: &event); 1172 #endif 1173 } 1174 } 1175 1176 void QComboBoxPrivate::_q_rowsInserted(const QModelIndex &parent, int start, int end) 1177 { 1178 Q_Q(QComboBox); 1179 if (inserting || parent != root) 1180 return; 1181 1182 if (sizeAdjustPolicy == QComboBox::AdjustToContents) { 1183 sizeHint = QSize(); 1184 adjustComboBoxSize(); 1185 q->updateGeometry(); 1186 } 1187 1188 // set current index if combo was previously empty and there is no placeholderText 1189 if (start == 0 && (end - start + 1) == q->count() && !currentIndex.isValid() && 1190 placeholderText.isEmpty()) { 1191 q->setCurrentIndex(0); 1192 // need to emit changed if model updated index "silently" 1193 } else if (currentIndex.row() != indexBeforeChange) { 1194 q->update(); 1195 _q_emitCurrentIndexChanged(index: currentIndex); 1196 } 1197 } 1198 1199 void QComboBoxPrivate::_q_updateIndexBeforeChange() 1200 { 1201 indexBeforeChange = currentIndex.row(); 1202 } 1203 1204 void QComboBoxPrivate::_q_rowsRemoved(const QModelIndex &parent, int /*start*/, int /*end*/) 1205 { 1206 Q_Q(QComboBox); 1207 if (parent != root) 1208 return; 1209 1210 if (sizeAdjustPolicy == QComboBox::AdjustToContents) { 1211 sizeHint = QSize(); 1212 adjustComboBoxSize(); 1213 q->updateGeometry(); 1214 } 1215 1216 // model has changed the currentIndex 1217 if (currentIndex.row() != indexBeforeChange) { 1218 if (!currentIndex.isValid() && q->count()) { 1219 q->setCurrentIndex(qMin(a: q->count() - 1, b: qMax(a: indexBeforeChange, b: 0))); 1220 return; 1221 } 1222 if (lineEdit) { 1223 lineEdit->setText(q->itemText(index: currentIndex.row())); 1224 updateLineEditGeometry(); 1225 } 1226 q->update(); 1227 _q_emitCurrentIndexChanged(index: currentIndex); 1228 } 1229 } 1230 1231 1232 void QComboBoxPrivate::updateViewContainerPaletteAndOpacity() 1233 { 1234 if (!container) 1235 return; 1236 Q_Q(QComboBox); 1237 QStyleOptionComboBox opt; 1238 q->initStyleOption(option: &opt); 1239 #if QT_CONFIG(menu) 1240 if (q->style()->styleHint(stylehint: QStyle::SH_ComboBox_Popup, opt: &opt, widget: q)) { 1241 QMenu ; 1242 menu.ensurePolished(); 1243 container->setPalette(menu.palette()); 1244 container->setWindowOpacity(menu.windowOpacity()); 1245 } else 1246 #endif 1247 { 1248 container->setPalette(q->palette()); 1249 container->setWindowOpacity(1.0); 1250 } 1251 if (lineEdit) 1252 lineEdit->setPalette(q->palette()); 1253 } 1254 1255 void QComboBoxPrivate::updateFocusPolicy() 1256 { 1257 #ifdef Q_OS_MACOS 1258 Q_Q(QComboBox); 1259 1260 // See comment in QComboBoxPrivate::init() 1261 if (q->isEditable()) 1262 q->setFocusPolicy(Qt::WheelFocus); 1263 else 1264 q->setFocusPolicy(Qt::TabFocus); 1265 #endif 1266 } 1267 1268 /*! 1269 Initialize \a option with the values from this QComboBox. This method 1270 is useful for subclasses when they need a QStyleOptionComboBox, but don't want 1271 to fill in all the information themselves. 1272 1273 \sa QStyleOption::initFrom() 1274 */ 1275 void QComboBox::initStyleOption(QStyleOptionComboBox *option) const 1276 { 1277 if (!option) 1278 return; 1279 1280 Q_D(const QComboBox); 1281 option->initFrom(w: this); 1282 option->editable = isEditable(); 1283 option->frame = d->frame; 1284 if (hasFocus() && !option->editable) 1285 option->state |= QStyle::State_Selected; 1286 option->subControls = QStyle::SC_All; 1287 if (d->arrowState == QStyle::State_Sunken) { 1288 option->activeSubControls = QStyle::SC_ComboBoxArrow; 1289 option->state |= d->arrowState; 1290 } else { 1291 option->activeSubControls = d->hoverControl; 1292 } 1293 option->currentText = currentText(); 1294 if (d->currentIndex.isValid()) 1295 option->currentIcon = d->itemIcon(index: d->currentIndex); 1296 option->iconSize = iconSize(); 1297 if (d->container && d->container->isVisible()) 1298 option->state |= QStyle::State_On; 1299 } 1300 1301 void QComboBoxPrivate::() 1302 { 1303 if (!lineEdit) 1304 return; 1305 1306 Q_Q(QComboBox); 1307 QStyleOptionComboBox opt; 1308 q->initStyleOption(option: &opt); 1309 QRect editRect = q->style()->subControlRect(cc: QStyle::CC_ComboBox, opt: &opt, 1310 sc: QStyle::SC_ComboBoxEditField, widget: q); 1311 if (!q->itemIcon(index: q->currentIndex()).isNull()) { 1312 QRect comboRect(editRect); 1313 editRect.setWidth(editRect.width() - q->iconSize().width() - 4); 1314 editRect = QStyle::alignedRect(direction: q->layoutDirection(), alignment: Qt::AlignRight, 1315 size: editRect.size(), rectangle: comboRect); 1316 } 1317 lineEdit->setGeometry(editRect); 1318 } 1319 1320 Qt::MatchFlags QComboBoxPrivate::matchFlags() const 1321 { 1322 // Base how duplicates are determined on the autocompletion case sensitivity 1323 Qt::MatchFlags flags = Qt::MatchFixedString; 1324 #if QT_CONFIG(completer) 1325 if (!lineEdit->completer() || lineEdit->completer()->caseSensitivity() == Qt::CaseSensitive) 1326 #endif 1327 flags |= Qt::MatchCaseSensitive; 1328 return flags; 1329 } 1330 1331 1332 void QComboBoxPrivate::_q_editingFinished() 1333 { 1334 Q_Q(QComboBox); 1335 if (!lineEdit) 1336 return; 1337 const auto leText = lineEdit->text(); 1338 if (!leText.isEmpty() && itemText(index: currentIndex) != leText) { 1339 #if QT_CONFIG(completer) 1340 const auto *leCompleter = lineEdit->completer(); 1341 const auto * = leCompleter ? QCompleterPrivate::get(o: leCompleter)->popup : nullptr; 1342 if (popup && popup->isVisible()) { 1343 // QLineEdit::editingFinished() will be emitted before the code flow returns 1344 // to QCompleter::eventFilter(), where QCompleter::activated() may be emitted. 1345 // We know that the completer popup will still be visible at this point, and 1346 // that any selection should be valid. 1347 const QItemSelectionModel *selModel = popup->selectionModel(); 1348 const QModelIndex curIndex = popup->currentIndex(); 1349 const bool completerIsActive = selModel && selModel->selectedIndexes().contains(t: curIndex); 1350 1351 if (completerIsActive) 1352 return; 1353 } 1354 #endif 1355 const int index = q_func()->findText(text: leText, flags: matchFlags()); 1356 if (index != -1) { 1357 q->setCurrentIndex(index); 1358 emitActivated(index: currentIndex); 1359 } 1360 } 1361 1362 } 1363 1364 void QComboBoxPrivate::_q_returnPressed() 1365 { 1366 Q_Q(QComboBox); 1367 1368 // The insertion code below does not apply when the policy is QComboBox::NoInsert. 1369 // In case a completer is installed, item activation via the completer is handled 1370 // in _q_completerActivated(). Otherwise _q_editingFinished() updates the current 1371 // index as appropriate. 1372 if (insertPolicy == QComboBox::NoInsert) 1373 return; 1374 1375 if (lineEdit && !lineEdit->text().isEmpty()) { 1376 if (q->count() >= maxCount && !(this->insertPolicy == QComboBox::InsertAtCurrent)) 1377 return; 1378 lineEdit->deselect(); 1379 lineEdit->end(mark: false); 1380 QString text = lineEdit->text(); 1381 // check for duplicates (if not enabled) and quit 1382 int index = -1; 1383 if (!duplicatesEnabled) { 1384 index = q->findText(text, flags: matchFlags()); 1385 if (index != -1) { 1386 q->setCurrentIndex(index); 1387 emitActivated(index: currentIndex); 1388 return; 1389 } 1390 } 1391 switch (insertPolicy) { 1392 case QComboBox::InsertAtTop: 1393 index = 0; 1394 break; 1395 case QComboBox::InsertAtBottom: 1396 index = q->count(); 1397 break; 1398 case QComboBox::InsertAtCurrent: 1399 case QComboBox::InsertAfterCurrent: 1400 case QComboBox::InsertBeforeCurrent: 1401 if (!q->count() || !currentIndex.isValid()) 1402 index = 0; 1403 else if (insertPolicy == QComboBox::InsertAtCurrent) 1404 q->setItemText(index: q->currentIndex(), text); 1405 else if (insertPolicy == QComboBox::InsertAfterCurrent) 1406 index = q->currentIndex() + 1; 1407 else if (insertPolicy == QComboBox::InsertBeforeCurrent) 1408 index = q->currentIndex(); 1409 break; 1410 case QComboBox::InsertAlphabetically: 1411 index = 0; 1412 for (int i=0; i< q->count(); i++, index++ ) { 1413 if (text.toLower() < q->itemText(index: i).toLower()) 1414 break; 1415 } 1416 break; 1417 default: 1418 break; 1419 } 1420 if (index >= 0) { 1421 q->insertItem(aindex: index, atext: text); 1422 q->setCurrentIndex(index); 1423 emitActivated(index: currentIndex); 1424 } 1425 } 1426 } 1427 1428 void QComboBoxPrivate::_q_itemSelected(const QModelIndex &item) 1429 { 1430 Q_Q(QComboBox); 1431 if (item != currentIndex) { 1432 setCurrentIndex(item); 1433 } else if (lineEdit) { 1434 lineEdit->selectAll(); 1435 lineEdit->setText(q->itemText(index: currentIndex.row())); 1436 } 1437 emitActivated(index: currentIndex); 1438 } 1439 1440 void QComboBoxPrivate::emitActivated(const QModelIndex &index) 1441 { 1442 Q_Q(QComboBox); 1443 if (!index.isValid()) 1444 return; 1445 QString text(itemText(index)); 1446 emit q->activated(index: index.row()); 1447 emit q->textActivated(text); 1448 #if QT_DEPRECATED_SINCE(5, 15) 1449 QT_WARNING_PUSH 1450 QT_WARNING_DISABLE_DEPRECATED 1451 emit q->activated(text); 1452 QT_WARNING_POP 1453 #endif 1454 } 1455 1456 void QComboBoxPrivate::_q_emitHighlighted(const QModelIndex &index) 1457 { 1458 Q_Q(QComboBox); 1459 if (!index.isValid()) 1460 return; 1461 QString text(itemText(index)); 1462 emit q->highlighted(index: index.row()); 1463 emit q->textHighlighted(text); 1464 #if QT_DEPRECATED_SINCE(5, 15) 1465 QT_WARNING_PUSH 1466 QT_WARNING_DISABLE_DEPRECATED 1467 emit q->highlighted(text); 1468 QT_WARNING_POP 1469 #endif 1470 } 1471 1472 void QComboBoxPrivate::_q_emitCurrentIndexChanged(const QModelIndex &index) 1473 { 1474 Q_Q(QComboBox); 1475 const QString text = itemText(index); 1476 emit q->currentIndexChanged(index: index.row()); 1477 #if QT_DEPRECATED_SINCE(5, 13) 1478 QT_WARNING_PUSH 1479 QT_WARNING_DISABLE_DEPRECATED 1480 emit q->currentIndexChanged(text); 1481 QT_WARNING_POP 1482 #endif 1483 // signal lineEdit.textChanged already connected to signal currentTextChanged, so don't emit double here 1484 if (!lineEdit) 1485 emit q->currentTextChanged(text); 1486 #ifndef QT_NO_ACCESSIBILITY 1487 QAccessibleValueChangeEvent event(q, text); 1488 QAccessible::updateAccessibility(event: &event); 1489 #endif 1490 } 1491 1492 QString QComboBoxPrivate::itemText(const QModelIndex &index) const 1493 { 1494 return index.isValid() ? model->data(index, role: itemRole()).toString() : QString(); 1495 } 1496 1497 int QComboBoxPrivate::itemRole() const 1498 { 1499 return q_func()->isEditable() ? Qt::EditRole : Qt::DisplayRole; 1500 } 1501 1502 /*! 1503 Destroys the combobox. 1504 */ 1505 QComboBox::~QComboBox() 1506 { 1507 // ### check delegateparent and delete delegate if us? 1508 Q_D(QComboBox); 1509 1510 QT_TRY { 1511 disconnect(sender: d->model, SIGNAL(destroyed()), 1512 receiver: this, SLOT(_q_modelDestroyed())); 1513 } QT_CATCH(...) { 1514 ; // objects can't throw in destructor 1515 } 1516 } 1517 1518 /*! 1519 \property QComboBox::maxVisibleItems 1520 \brief the maximum allowed size on screen of the combo box, measured in items 1521 1522 By default, this property has a value of 10. 1523 1524 \note This property is ignored for non-editable comboboxes in styles that returns 1525 true for QStyle::SH_ComboBox_Popup such as the Mac style or the Gtk+ Style. 1526 */ 1527 int QComboBox::maxVisibleItems() const 1528 { 1529 Q_D(const QComboBox); 1530 return d->maxVisibleItems; 1531 } 1532 1533 void QComboBox::setMaxVisibleItems(int maxItems) 1534 { 1535 Q_D(QComboBox); 1536 if (Q_UNLIKELY(maxItems < 0)) { 1537 qWarning(msg:
"QComboBox::setMaxVisibleItems: "1538
"Invalid max visible items (%d) must be >= 0", maxItems); 1539 return; 1540 } 1541 d->maxVisibleItems = maxItems; 1542 } 1543 1544 /*! 1545 \property QComboBox::count 1546 \brief the number of items in the combobox 1547 1548 By default, for an empty combo box, this property has a value of 0. 1549 */ 1550 int QComboBox::count() const 1551 { 1552 Q_D(const QComboBox); 1553 return d->model->rowCount(parent: d->root); 1554 } 1555 1556 /*! 1557 \property QComboBox::maxCount 1558 \brief the maximum number of items allowed in the combobox 1559 1560 \note If you set the maximum number to be less then the current 1561 amount of items in the combobox, the extra items will be 1562 truncated. This also applies if you have set an external model on 1563 the combobox. 1564 1565 By default, this property's value is derived from the highest 1566 signed integer available (typically 2147483647). 1567 */ 1568 void QComboBox::setMaxCount(int max) 1569 { 1570 Q_D(QComboBox); 1571 if (Q_UNLIKELY(max < 0)) { 1572 qWarning(msg:
"QComboBox::setMaxCount: Invalid count (%d) must be >= 0", max); 1573 return; 1574 } 1575 1576 const int rowCount = count(); 1577 if (rowCount > max) 1578 d->model->removeRows(row: max, count: rowCount - max, parent: d->root); 1579 1580 d->maxCount = max; 1581 } 1582 1583 int QComboBox::maxCount() const 1584 { 1585 Q_D(const QComboBox); 1586 return d->maxCount; 1587 } 1588 1589 #if QT_CONFIG(completer) 1590 #if QT_DEPRECATED_SINCE(5, 13) 1591 1592 /*! 1593 \property QComboBox::autoCompletion 1594 \brief whether the combobox provides auto-completion for editable items 1595 \since 4.1 1596 \obsolete 1597 1598 Use setCompleter() instead. 1599 1600 By default, this property is \c true. 1601 1602 \sa editable 1603 */ 1604 1605 /*! 1606 \obsolete 1607 1608 Use completer() instead. 1609 */ 1610 bool QComboBox::autoCompletion() const 1611 { 1612 Q_D(const QComboBox); 1613 return d->autoCompletion; 1614 } 1615 1616 /*! 1617 \obsolete 1618 1619 Use setCompleter() instead. 1620 */ 1621 void QComboBox::setAutoCompletion(bool enable) 1622 { 1623 Q_D(QComboBox); 1624 1625 #ifdef QT_KEYPAD_NAVIGATION 1626 if (Q_UNLIKELY(QApplicationPrivate::keypadNavigationEnabled() && !enable && isEditable())) 1627 qWarning(
"QComboBox::setAutoCompletion: auto completion is mandatory when combo box editable"); 1628 #endif 1629 1630 d->autoCompletion = enable; 1631 if (!d->lineEdit) 1632 return; 1633 if (enable) { 1634 if (d->lineEdit->completer()) 1635 return; 1636 d->completer = new QCompleter(d->model, d->lineEdit); 1637 connect(sender: d->completer, SIGNAL(activated(QModelIndex)), receiver: this, SLOT(_q_completerActivated(QModelIndex))); 1638 d->completer->setCaseSensitivity(d->autoCompletionCaseSensitivity); 1639 d->completer->setCompletionMode(QCompleter::InlineCompletion); 1640 d->completer->setCompletionColumn(d->modelColumn); 1641 d->lineEdit->setCompleter(d->completer); 1642 d->completer->setWidget(this); 1643 } else { 1644 d->lineEdit->setCompleter(nullptr); 1645 } 1646 } 1647 1648 /*! 1649 \property QComboBox::autoCompletionCaseSensitivity 1650 \brief whether string comparisons are case-sensitive or case-insensitive for auto-completion 1651 \obsolete 1652 1653 By default, this property is Qt::CaseInsensitive. 1654 1655 Use setCompleter() instead. Case sensitivity of the auto completion can be 1656 changed using QCompleter::setCaseSensitivity(). 1657 1658 \sa autoCompletion 1659 */ 1660 1661 /*! 1662 \obsolete 1663 1664 Use setCompleter() and QCompleter::setCaseSensitivity() instead. 1665 */ 1666 Qt::CaseSensitivity QComboBox::autoCompletionCaseSensitivity() const 1667 { 1668 Q_D(const QComboBox); 1669 return d->autoCompletionCaseSensitivity; 1670 } 1671 1672 /*! 1673 \obsolete 1674 1675 Use setCompleter() and QCompleter::setCaseSensitivity() instead. 1676 */ 1677 void QComboBox::setAutoCompletionCaseSensitivity(Qt::CaseSensitivity sensitivity) 1678 { 1679 Q_D(QComboBox); 1680 d->autoCompletionCaseSensitivity = sensitivity; 1681 if (d->lineEdit && d->lineEdit->completer()) 1682 d->lineEdit->completer()->setCaseSensitivity(sensitivity); 1683 } 1684 #endif // QT_DEPRECATED_SINCE(5, 13) 1685 1686 #endif // QT_CONFIG(completer) 1687 1688 /*! 1689 \property QComboBox::duplicatesEnabled 1690 \brief whether the user can enter duplicate items into the combobox 1691 1692 Note that it is always possible to programmatically insert duplicate items into the 1693 combobox. 1694 1695 By default, this property is \c false (duplicates are not allowed). 1696 */ 1697 bool QComboBox::duplicatesEnabled() const 1698 { 1699 Q_D(const QComboBox); 1700 return d->duplicatesEnabled; 1701 } 1702 1703 void QComboBox::setDuplicatesEnabled(bool enable) 1704 { 1705 Q_D(QComboBox); 1706 d->duplicatesEnabled = enable; 1707 } 1708 1709 /*! \fn int QComboBox::findText(const QString &text, Qt::MatchFlags flags = Qt::MatchExactly|Qt::MatchCaseSensitive) const 1710 1711 Returns the index of the item containing the given \a text; otherwise 1712 returns -1. 1713 1714 The \a flags specify how the items in the combobox are searched. 1715 */ 1716 1717 /*! 1718 Returns the index of the item containing the given \a data for the 1719 given \a role; otherwise returns -1. 1720 1721 The \a flags specify how the items in the combobox are searched. 1722 */ 1723 int QComboBox::findData(const QVariant &data, int role, Qt::MatchFlags flags) const 1724 { 1725 Q_D(const QComboBox); 1726 QModelIndex start = d->model->index(row: 0, column: d->modelColumn, parent: d->root); 1727 const QModelIndexList result = d->model->match(start, role, value: data, hits: 1, flags); 1728 if (result.isEmpty()) 1729 return -1; 1730 return result.first().row(); 1731 } 1732 1733 /*! 1734 \property QComboBox::insertPolicy 1735 \brief the policy used to determine where user-inserted items should 1736 appear in the combobox 1737 1738 The default value is \l InsertAtBottom, indicating that new items will appear 1739 at the bottom of the list of items. 1740 1741 \sa InsertPolicy 1742 */ 1743 1744 QComboBox::InsertPolicy QComboBox::insertPolicy() const 1745 { 1746 Q_D(const QComboBox); 1747 return d->insertPolicy; 1748 } 1749 1750 void QComboBox::setInsertPolicy(InsertPolicy policy) 1751 { 1752 Q_D(QComboBox); 1753 d->insertPolicy = policy; 1754 } 1755 1756 /*! 1757 \property QComboBox::sizeAdjustPolicy 1758 \brief the policy describing how the size of the combobox changes 1759 when the content changes 1760 1761 The default value is \l AdjustToContentsOnFirstShow. 1762 1763 \sa SizeAdjustPolicy 1764 */ 1765 1766 QComboBox::SizeAdjustPolicy QComboBox::sizeAdjustPolicy() const 1767 { 1768 Q_D(const QComboBox); 1769 return d->sizeAdjustPolicy; 1770 } 1771 1772 void QComboBox::setSizeAdjustPolicy(QComboBox::SizeAdjustPolicy policy) 1773 { 1774 Q_D(QComboBox); 1775 if (policy == d->sizeAdjustPolicy) 1776 return; 1777 1778 d->sizeAdjustPolicy = policy; 1779 d->sizeHint = QSize(); 1780 d->adjustComboBoxSize(); 1781 updateGeometry(); 1782 } 1783 1784 /*! 1785 \property QComboBox::minimumContentsLength 1786 \brief the minimum number of characters that should fit into the combobox. 1787 1788 The default value is 0. 1789 1790 If this property is set to a positive value, the 1791 minimumSizeHint() and sizeHint() take it into account. 1792 1793 \sa sizeAdjustPolicy 1794 */ 1795 int QComboBox::minimumContentsLength() const 1796 { 1797 Q_D(const QComboBox); 1798 return d->minimumContentsLength; 1799 } 1800 1801 void QComboBox::setMinimumContentsLength(int characters) 1802 { 1803 Q_D(QComboBox); 1804 if (characters == d->minimumContentsLength || characters < 0) 1805 return; 1806 1807 d->minimumContentsLength = characters; 1808 1809 if (d->sizeAdjustPolicy == AdjustToContents 1810 || d->sizeAdjustPolicy == deprecatedAdjustToMinimumContentsLength() 1811 || d->sizeAdjustPolicy == AdjustToMinimumContentsLengthWithIcon) { 1812 d->sizeHint = QSize(); 1813 d->adjustComboBoxSize(); 1814 updateGeometry(); 1815 } 1816 } 1817 1818 /*! 1819 \property QComboBox::iconSize 1820 \brief the size of the icons shown in the combobox. 1821 1822 Unless explicitly set this returns the default value of the 1823 current style. This size is the maximum size that icons can have; 1824 icons of smaller size are not scaled up. 1825 */ 1826 1827 QSize QComboBox::iconSize() const 1828 { 1829 Q_D(const QComboBox); 1830 if (d->iconSize.isValid()) 1831 return d->iconSize; 1832 1833 int iconWidth = style()->pixelMetric(metric: QStyle::PM_SmallIconSize, option: nullptr, widget: this); 1834 return QSize(iconWidth, iconWidth); 1835 } 1836 1837 void QComboBox::setIconSize(const QSize &size) 1838 { 1839 Q_D(QComboBox); 1840 if (size == d->iconSize) 1841 return; 1842 1843 view()->setIconSize(size); 1844 d->iconSize = size; 1845 d->sizeHint = QSize(); 1846 updateGeometry(); 1847 } 1848 1849 /*! 1850 \property QComboBox::placeholderText 1851 \brief Sets a \a placeholderText text shown when no valid index is set 1852 1853 The \a placeholderText will be shown when an invalid index is set. The 1854 text is not accessible in the dropdown list. When this function is called 1855 before items are added the placeholder text will be shown, otherwise you 1856 have to call setCurrentIndex(-1) programmatically if you want to show the 1857 placeholder text. 1858 Set an empty placeholder text to reset the setting. 1859 1860 When the QComboBox is editable, use QLineEdit::setPlaceholderText() 1861 instead. 1862 1863 \since 5.15 1864 */ 1865 void QComboBox::setPlaceholderText(const QString &placeholderText) 1866 { 1867 Q_D(QComboBox); 1868 if (placeholderText == d->placeholderText) 1869 return; 1870 1871 d->placeholderText = placeholderText; 1872 if (currentIndex() == -1) { 1873 if (d->placeholderText.isEmpty() && currentIndex() == -1) 1874 setCurrentIndex(0); 1875 else 1876 update(); 1877 } else { 1878 updateGeometry(); 1879 } 1880 } 1881 1882 QString QComboBox::placeholderText() const 1883 { 1884 Q_D(const QComboBox); 1885 return d->placeholderText; 1886 } 1887 1888 /*! 1889 \property QComboBox::editable 1890 \brief whether the combo box can be edited by the user 1891 1892 By default, this property is \c false. The effect of editing depends 1893 on the insert policy. 1894 1895 \note When disabling the \a editable state, the validator and 1896 completer are removed. 1897 1898 \sa InsertPolicy 1899 */ 1900 bool QComboBox::isEditable() const 1901 { 1902 Q_D(const QComboBox); 1903 return d->lineEdit != nullptr; 1904 } 1905 1906 /*! \internal 1907 update the default delegate 1908 depending on the style's SH_ComboBox_Popup hint, we use a different default delegate. 1909 1910 but we do not change the delegate is the combobox use a custom delegate, 1911 unless \a force is set to true. 1912 */ 1913 void QComboBoxPrivate::updateDelegate(bool force) 1914 { 1915 Q_Q(QComboBox); 1916 QStyleOptionComboBox opt; 1917 q->initStyleOption(option: &opt); 1918 if (q->style()->styleHint(stylehint: QStyle::SH_ComboBox_Popup, opt: &opt, widget: q)) { 1919 if (force || qobject_cast<QComboBoxDelegate *>(object: q->itemDelegate())) 1920 q->setItemDelegate(new QComboMenuDelegate(q->view(), q)); 1921 } else { 1922 if (force || qobject_cast<QComboMenuDelegate *>(object: q->itemDelegate())) 1923 q->setItemDelegate(new QComboBoxDelegate(q->view(), q)); 1924 } 1925 } 1926 1927 QIcon QComboBoxPrivate::itemIcon(const QModelIndex &index) const 1928 { 1929 QVariant decoration = model->data(index, role: Qt::DecorationRole); 1930 if (decoration.userType() == QMetaType::QPixmap) 1931 return QIcon(qvariant_cast<QPixmap>(v: decoration)); 1932 else 1933 return qvariant_cast<QIcon>(v: decoration); 1934 } 1935 1936 void QComboBox::setEditable(bool editable) 1937 { 1938 Q_D(QComboBox); 1939 if (isEditable() == editable) 1940 return; 1941 1942 QStyleOptionComboBox opt; 1943 initStyleOption(option: &opt); 1944 if (editable) { 1945 if (style()->styleHint(stylehint: QStyle::SH_ComboBox_Popup, opt: &opt, widget: this)) { 1946 d->viewContainer()->updateScrollers(); 1947 view()->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); 1948 } 1949 QLineEdit *le = new QLineEdit(this); 1950 le->setPalette(palette()); 1951 setLineEdit(le); 1952 } else { 1953 if (style()->styleHint(stylehint: QStyle::SH_ComboBox_Popup, opt: &opt, widget: this)) { 1954 d->viewContainer()->updateScrollers(); 1955 view()->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 1956 } 1957 setAttribute(Qt::WA_InputMethodEnabled, on: false); 1958 d->lineEdit->hide(); 1959 d->lineEdit->deleteLater(); 1960 d->lineEdit = nullptr; 1961 } 1962 1963 d->updateDelegate(); 1964 d->updateFocusPolicy(); 1965 1966 d->viewContainer()->updateTopBottomMargin(); 1967 if (!testAttribute(attribute: Qt::WA_Resized)) 1968 adjustSize(); 1969 } 1970 1971 /*! 1972 Sets the line \a edit to use instead of the current line edit widget. 1973 1974 The combo box takes ownership of the line edit. 1975 */ 1976 void QComboBox::setLineEdit(QLineEdit *edit) 1977 { 1978 Q_D(QComboBox); 1979 if (Q_UNLIKELY(!edit)) { 1980 qWarning(msg:
"QComboBox::setLineEdit: cannot set a 0 line edit"); 1981 return; 1982 } 1983 1984 if (edit == d->lineEdit) 1985 return; 1986 1987 edit->setText(currentText()); 1988 delete d->lineEdit; 1989 1990 d->lineEdit = edit; 1991 #ifndef QT_NO_IM 1992 qt_widget_private(widget: d->lineEdit)->inheritsInputMethodHints = 1; 1993 #endif 1994 if (d->lineEdit->parent() != this) 1995 d->lineEdit->setParent(this); 1996 connect(sender: d->lineEdit, SIGNAL(returnPressed()), receiver: this, SLOT(_q_returnPressed())); 1997 connect(sender: d->lineEdit, SIGNAL(editingFinished()), receiver: this, SLOT(_q_editingFinished())); 1998 connect(sender: d->lineEdit, SIGNAL(textChanged(QString)), receiver: this, SIGNAL(editTextChanged(QString))); 1999 connect(sender: d->lineEdit, SIGNAL(textChanged(QString)), receiver: this, SIGNAL(currentTextChanged(QString))); 2000 connect(sender: d->lineEdit, SIGNAL(cursorPositionChanged(int,int)), receiver: this, SLOT(updateMicroFocus())); 2001 connect(sender: d->lineEdit, SIGNAL(selectionChanged()), receiver: this, SLOT(updateMicroFocus())); 2002 connect(sender: d->lineEdit->d_func()->control, SIGNAL(updateMicroFocus()), receiver: this, SLOT(updateMicroFocus())); 2003 d->lineEdit->setFrame(false); 2004 d->lineEdit->setContextMenuPolicy(Qt::NoContextMenu); 2005 d->updateFocusPolicy(); 2006 d->lineEdit->setFocusProxy(this); 2007 d->lineEdit->setAttribute(Qt::WA_MacShowFocusRect, on: false); 2008 #if QT_DEPRECATED_SINCE(5, 13) 2009 QT_WARNING_PUSH 2010 QT_WARNING_DISABLE_DEPRECATED 2011 #if QT_CONFIG(completer) 2012 setAutoCompletion(d->autoCompletion); 2013 2014 #ifdef QT_KEYPAD_NAVIGATION 2015 if (QApplicationPrivate::keypadNavigationEnabled()) { 2016 // Editable combo boxes will have a completer that is set to UnfilteredPopupCompletion. 2017 // This means that when the user enters edit mode they are immediately presented with a 2018 // list of possible completions. 2019 setAutoCompletion(true); 2020 if (d->completer) { 2021 d->completer->setCompletionMode(QCompleter::UnfilteredPopupCompletion); 2022 connect(d->completer, SIGNAL(activated(QModelIndex)), this, SLOT(_q_completerActivated())); 2023 } 2024 } 2025 #endif 2026 #endif 2027 QT_WARNING_POP 2028 #endif 2029 2030 setAttribute(Qt::WA_InputMethodEnabled); 2031 d->updateLayoutDirection(); 2032 d->updateLineEditGeometry(); 2033 if (isVisible()) 2034 d->lineEdit->show(); 2035 2036 update(); 2037 } 2038 2039 /*! 2040 Returns the line edit used to edit items in the combobox, or 2041 \nullptr if there is no line edit. 2042 2043 Only editable combo boxes have a line edit. 2044 */ 2045 QLineEdit *QComboBox::lineEdit() const 2046 { 2047 Q_D(const QComboBox); 2048 return d->lineEdit; 2049 } 2050 2051 #ifndef QT_NO_VALIDATOR 2052 /*! 2053 \fn void QComboBox::setValidator(const QValidator *validator) 2054 2055 Sets the \a validator to use instead of the current validator. 2056 2057 \note The validator is removed when the \l editable property becomes \c false. 2058 */ 2059 2060 void QComboBox::setValidator(const QValidator *v) 2061 { 2062 Q_D(QComboBox); 2063 if (d->lineEdit) 2064 d->lineEdit->setValidator(v); 2065 } 2066 2067 /*! 2068 Returns the validator that is used to constrain text input for the 2069 combobox. 2070 2071 \sa editable 2072 */ 2073 const QValidator *QComboBox::validator() const 2074 { 2075 Q_D(const QComboBox); 2076 return d->lineEdit ? d->lineEdit->validator() : nullptr; 2077 } 2078 #endif // QT_NO_VALIDATOR 2079 2080 #if QT_CONFIG(completer) 2081 2082 /*! 2083 \fn void QComboBox::setCompleter(QCompleter *completer) 2084 \since 4.2 2085 2086 Sets the \a completer to use instead of the current completer. 2087 If \a completer is \nullptr, auto completion is disabled. 2088 2089 By default, for an editable combo box, a QCompleter that 2090 performs case insensitive inline completion is automatically created. 2091 2092 \note The completer is removed when the \l editable property becomes \c false. 2093 Setting a completer on a QComboBox that is not editable will be ignored. 2094 */ 2095 void QComboBox::setCompleter(QCompleter *c) 2096 { 2097 Q_D(QComboBox); 2098 if (!d->lineEdit) { 2099 qWarning(msg:
"Setting a QCompleter on non-editable QComboBox is not allowed."); 2100 return; 2101 } 2102 d->lineEdit->setCompleter(c); 2103 if (c) { 2104 connect(sender: c, SIGNAL(activated(QModelIndex)), receiver: this, SLOT(_q_completerActivated(QModelIndex))); 2105 c->setWidget(this); 2106 } 2107 } 2108 2109 /*! 2110 \since 4.2 2111 2112 Returns the completer that is used to auto complete text input for the 2113 combobox. 2114 2115 \sa editable 2116 */ 2117 QCompleter *QComboBox::completer() const 2118 { 2119 Q_D(const QComboBox); 2120 return d->lineEdit ? d->lineEdit->completer() : nullptr; 2121 } 2122 2123 #endif // QT_CONFIG(completer) 2124 2125 /*! 2126 Returns the item delegate used by the popup list view. 2127 2128 \sa setItemDelegate() 2129 */ 2130 QAbstractItemDelegate *QComboBox::itemDelegate() const 2131 { 2132 return view()->itemDelegate(); 2133 } 2134 2135 /*! 2136 Sets the item \a delegate for the popup list view. 2137 The combobox takes ownership of the delegate. 2138 2139 \warning You should not share the same instance of a delegate between comboboxes, 2140 widget mappers or views. Doing so can cause incorrect or unintuitive editing behavior 2141 since each view connected to a given delegate may receive the 2142 \l{QAbstractItemDelegate::}{closeEditor()} signal, and attempt to access, modify or 2143 close an editor that has already been closed. 2144 2145 \sa itemDelegate() 2146 */ 2147 void QComboBox::setItemDelegate(QAbstractItemDelegate *delegate) 2148 { 2149 if (Q_UNLIKELY(!delegate)) { 2150 qWarning(msg:
"QComboBox::setItemDelegate: cannot set a 0 delegate"); 2151 return; 2152 } 2153 delete view()->itemDelegate(); 2154 view()->setItemDelegate(delegate); 2155 } 2156 2157 /*! 2158 Returns the model used by the combobox. 2159 */ 2160 2161 QAbstractItemModel *QComboBox::model() const 2162 { 2163 Q_D(const QComboBox); 2164 if (d->model == QAbstractItemModelPrivate::staticEmptyModel()) { 2165 QComboBox *that = const_cast<QComboBox*>(this); 2166 that->setModel(new QStandardItemModel(0, 1, that)); 2167 } 2168 return d->model; 2169 } 2170 2171 /*! 2172 Sets the model to be \a model. \a model must not be \nullptr. 2173 If you want to clear the contents of a model, call clear(). 2174 2175 \sa clear() 2176 */ 2177 void QComboBox::setModel(QAbstractItemModel *model) 2178 { 2179 Q_D(QComboBox); 2180 2181 if (Q_UNLIKELY(!model)) { 2182 qWarning(msg:
"QComboBox::setModel: cannot set a 0 model"); 2183 return; 2184 } 2185 2186 if (model == d->model) 2187 return; 2188 2189 #if QT_CONFIG(completer) 2190 if (d->lineEdit && d->lineEdit->completer() 2191 && d->lineEdit->completer() == d->completer) 2192 d->lineEdit->completer()->setModel(model); 2193 #endif 2194 if (d->model) { 2195 disconnect(sender: d->model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), 2196 receiver: this, SLOT(_q_dataChanged(QModelIndex,QModelIndex))); 2197 disconnect(sender: d->model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)), 2198 receiver: this, SLOT(_q_updateIndexBeforeChange())); 2199 disconnect(sender: d->model, SIGNAL(rowsInserted(QModelIndex,int,int)), 2200 receiver: this, SLOT(_q_rowsInserted(QModelIndex,int,int))); 2201 disconnect(sender: d->model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), 2202 receiver: this, SLOT(_q_updateIndexBeforeChange())); 2203 disconnect(sender: d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)), 2204 receiver: this, SLOT(_q_rowsRemoved(QModelIndex,int,int))); 2205 disconnect(sender: d->model, SIGNAL(destroyed()), 2206 receiver: this, SLOT(_q_modelDestroyed())); 2207 disconnect(sender: d->model, SIGNAL(modelAboutToBeReset()), 2208 receiver: this, SLOT(_q_updateIndexBeforeChange())); 2209 disconnect(sender: d->model, SIGNAL(modelReset()), 2210 receiver: this, SLOT(_q_modelReset())); 2211 if (d->model->QObject::parent() == this) 2212 delete d->model; 2213 } 2214 2215 d->model = model; 2216 2217 connect(sender: model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), 2218 receiver: this, SLOT(_q_dataChanged(QModelIndex,QModelIndex))); 2219 connect(sender: model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)), 2220 receiver: this, SLOT(_q_updateIndexBeforeChange())); 2221 connect(sender: model, SIGNAL(rowsInserted(QModelIndex,int,int)), 2222 receiver: this, SLOT(_q_rowsInserted(QModelIndex,int,int))); 2223 connect(sender: model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), 2224 receiver: this, SLOT(_q_updateIndexBeforeChange())); 2225 connect(sender: model, SIGNAL(rowsRemoved(QModelIndex,int,int)), 2226 receiver: this, SLOT(_q_rowsRemoved(QModelIndex,int,int))); 2227 connect(sender: model, SIGNAL(destroyed()), 2228 receiver: this, SLOT(_q_modelDestroyed())); 2229 connect(sender: model, SIGNAL(modelAboutToBeReset()), 2230 receiver: this, SLOT(_q_updateIndexBeforeChange())); 2231 connect(sender: model, SIGNAL(modelReset()), 2232 receiver: this, SLOT(_q_modelReset())); 2233 2234 if (d->container) { 2235 d->container->itemView()->setModel(model); 2236 connect(sender: d->container->itemView()->selectionModel(), 2237 SIGNAL(currentChanged(QModelIndex,QModelIndex)), 2238 receiver: this, SLOT(_q_emitHighlighted(QModelIndex)), Qt::UniqueConnection); 2239 } 2240 2241 setRootModelIndex(QModelIndex()); 2242 2243 d->trySetValidIndex(); 2244 d->modelChanged(); 2245 } 2246 2247 /*! 2248 Returns the root model item index for the items in the combobox. 2249 2250 \sa setRootModelIndex() 2251 */ 2252 2253 QModelIndex QComboBox::rootModelIndex() const 2254 { 2255 Q_D(const QComboBox); 2256 return QModelIndex(d->root); 2257 } 2258 2259 /*! 2260 Sets the root model item \a index for the items in the combobox. 2261 2262 \sa rootModelIndex() 2263 */ 2264 void QComboBox::setRootModelIndex(const QModelIndex &index) 2265 { 2266 Q_D(QComboBox); 2267 if (d->root == index) 2268 return; 2269 d->root = QPersistentModelIndex(index); 2270 view()->setRootIndex(index); 2271 update(); 2272 } 2273 2274 /*! 2275 \property QComboBox::currentIndex 2276 \brief the index of the current item in the combobox. 2277 2278 The current index can change when inserting or removing items. 2279 2280 By default, for an empty combo box or a combo box in which no current 2281 item is set, this property has a value of -1. 2282 */ 2283 int QComboBox::currentIndex() const 2284 { 2285 Q_D(const QComboBox); 2286 return d->currentIndex.row(); 2287 } 2288 2289 void QComboBox::setCurrentIndex(int index) 2290 { 2291 Q_D(QComboBox); 2292 QModelIndex mi = d->model->index(row: index, column: d->modelColumn, parent: d->root); 2293 d->setCurrentIndex(mi); 2294 } 2295 2296 void QComboBox::setCurrentText(const QString &text) 2297 { 2298 if (isEditable()) { 2299 setEditText(text); 2300 } else { 2301 const int i = findText(text); 2302 if (i > -1) 2303 setCurrentIndex(i); 2304 } 2305 } 2306 2307 void QComboBoxPrivate::setCurrentIndex(const QModelIndex &mi) 2308 { 2309 Q_Q(QComboBox); 2310 2311 QModelIndex normalized = mi.sibling(arow: mi.row(), acolumn: modelColumn); // no-op if mi.column() == modelColumn 2312 if (!normalized.isValid()) 2313 normalized = mi; // Fallback to passed index. 2314 2315 bool indexChanged = (normalized != currentIndex); 2316 if (indexChanged) 2317 currentIndex = QPersistentModelIndex(normalized); 2318 if (lineEdit) { 2319 const QString newText = itemText(index: normalized); 2320 if (lineEdit->text() != newText) { 2321 lineEdit->setText(newText); // may cause lineEdit -> nullptr (QTBUG-54191) 2322 #if QT_CONFIG(completer) 2323 if (lineEdit && lineEdit->completer()) 2324 lineEdit->completer()->setCompletionPrefix(newText); 2325 #endif 2326 } 2327 updateLineEditGeometry(); 2328 } 2329 if (indexChanged) { 2330 q->update(); 2331 _q_emitCurrentIndexChanged(index: currentIndex); 2332 } 2333 } 2334 2335 /*! 2336 \property QComboBox::currentText 2337 \brief the current text 2338 2339 If the combo box is editable, the current text is the value displayed 2340 by the line edit. Otherwise, it is the value of the current item or 2341 an empty string if the combo box is empty or no current item is set. 2342 2343 The setter setCurrentText() simply calls setEditText() if the combo box is editable. 2344 Otherwise, if there is a matching text in the list, currentIndex is set to the 2345 corresponding index. 2346 2347 \sa editable, setEditText() 2348 */ 2349 QString QComboBox::currentText() const 2350 { 2351 Q_D(const QComboBox); 2352 if (d->lineEdit) 2353 return d->lineEdit->text(); 2354 if (d->currentIndex.isValid()) 2355 return d->itemText(index: d->currentIndex); 2356 return {}; 2357 } 2358 2359 /*! 2360 \property QComboBox::currentData 2361 \brief the data for the current item 2362 \since 5.2 2363 2364 By default, for an empty combo box or a combo box in which no current 2365 item is set, this property contains an invalid QVariant. 2366 */ 2367 QVariant QComboBox::currentData(int role) const 2368 { 2369 Q_D(const QComboBox); 2370 return d->currentIndex.data(role); 2371 } 2372 2373 /*! 2374 Returns the text for the given \a index in the combobox. 2375 */ 2376 QString QComboBox::itemText(int index) const 2377 { 2378 Q_D(const QComboBox); 2379 QModelIndex mi = d->model->index(row: index, column: d->modelColumn, parent: d->root); 2380 return d->itemText(index: mi); 2381 } 2382 2383 /*! 2384 Returns the icon for the given \a index in the combobox. 2385 */ 2386 QIcon QComboBox::itemIcon(int index) const 2387 { 2388 Q_D(const QComboBox); 2389 QModelIndex mi = d->model->index(row: index, column: d->modelColumn, parent: d->root); 2390 return d->itemIcon(index: mi); 2391 } 2392 2393 /*! 2394 Returns the data for the given \a role in the given \a index in the 2395 combobox, or QVariant::Invalid if there is no data for this role. 2396 */ 2397 QVariant QComboBox::itemData(int index, int role) const 2398 { 2399 Q_D(const QComboBox); 2400 QModelIndex mi = d->model->index(row: index, column: d->modelColumn, parent: d->root); 2401 return d->model->data(index: mi, role); 2402 } 2403 2404 /*! 2405 \fn void QComboBox::insertItem(int index, const QString &text, const QVariant &userData) 2406 2407 Inserts the \a text and \a userData (stored in the Qt::UserRole) 2408 into the combobox at the given \a index. 2409 2410 If the index is equal to or higher than the total number of items, 2411 the new item is appended to the list of existing items. If the 2412 index is zero or negative, the new item is prepended to the list 2413 of existing items. 2414 2415 \sa insertItems() 2416 */ 2417 2418 /*! 2419 2420 Inserts the \a icon, \a text and \a userData (stored in the 2421 Qt::UserRole) into the combobox at the given \a index. 2422 2423 If the index is equal to or higher than the total number of items, 2424 the new item is appended to the list of existing items. If the 2425 index is zero or negative, the new item is prepended to the list 2426 of existing items. 2427 2428 \sa insertItems() 2429 */ 2430 void QComboBox::insertItem(int index, const QIcon &icon, const QString &text, const QVariant &userData) 2431 { 2432 Q_D(QComboBox); 2433 int itemCount = count(); 2434 index = qBound(min: 0, val: index, max: itemCount); 2435 if (index >= d->maxCount) 2436 return; 2437 2438 // For the common case where we are using the built in QStandardItemModel 2439 // construct a QStandardItem, reducing the number of expensive signals from the model 2440 if (QStandardItemModel *m = qobject_cast<QStandardItemModel*>(object: d->model)) { 2441 QStandardItem *item = new QStandardItem(text); 2442 if (!icon.isNull()) item->setData(value: icon, role: Qt::DecorationRole); 2443 if (userData.isValid()) item->setData(value: userData, role: Qt::UserRole); 2444 m->insertRow(arow: index, aitem: item); 2445 ++itemCount; 2446 } else { 2447 d->inserting = true; 2448 if (d->model->insertRows(row: index, count: 1, parent: d->root)) { 2449 QModelIndex item = d->model->index(row: index, column: d->modelColumn, parent: d->root); 2450 if (icon.isNull() && !userData.isValid()) { 2451 d->model->setData(index: item, value: text, role: Qt::EditRole); 2452 } else { 2453 QMap<int, QVariant> values; 2454 if (!text.isNull()) values.insert(akey: Qt::EditRole, avalue: text); 2455 if (!icon.isNull()) values.insert(akey: Qt::DecorationRole, avalue: icon); 2456 if (userData.isValid()) values.insert(akey: Qt::UserRole, avalue: userData); 2457 if (!values.isEmpty()) d->model->setItemData(index: item, roles: values); 2458 } 2459 d->inserting = false; 2460 d->_q_rowsInserted(parent: d->root, start: index, end: index); 2461 ++itemCount; 2462 } else { 2463 d->inserting = false; 2464 } 2465 } 2466 2467 if (itemCount > d->maxCount) 2468 d->model->removeRows(row: itemCount - 1, count: itemCount - d->maxCount, parent: d->root); 2469 } 2470 2471 /*! 2472 Inserts the strings from the \a list into the combobox as separate items, 2473 starting at the \a index specified. 2474 2475 If the index is equal to or higher than the total number of items, the new items 2476 are appended to the list of existing items. If the index is zero or negative, the 2477 new items are prepended to the list of existing items. 2478 2479 \sa insertItem() 2480 */ 2481 void QComboBox::insertItems(int index, const QStringList &list) 2482 { 2483 Q_D(QComboBox); 2484 if (list.isEmpty()) 2485 return; 2486 index = qBound(min: 0, val: index, max: count()); 2487 int insertCount = qMin(a: d->maxCount - index, b: list.count()); 2488 if (insertCount <= 0) 2489 return; 2490 // For the common case where we are using the built in QStandardItemModel 2491 // construct a QStandardItem, reducing the number of expensive signals from the model 2492 if (QStandardItemModel *m = qobject_cast<QStandardItemModel*>(object: d->model)) { 2493 QList<QStandardItem *> items; 2494 items.reserve(alloc: insertCount); 2495 QStandardItem *hiddenRoot = m->invisibleRootItem(); 2496 for (int i = 0; i < insertCount; ++i) 2497 items.append(t: new QStandardItem(list.at(i))); 2498 hiddenRoot->insertRows(row: index, items); 2499 } else { 2500 d->inserting = true; 2501 if (d->model->insertRows(row: index, count: insertCount, parent: d->root)) { 2502 QModelIndex item; 2503 for (int i = 0; i < insertCount; ++i) { 2504 item = d->model->index(row: i+index, column: d->modelColumn, parent: d->root); 2505 d->model->setData(index: item, value: list.at(i), role: Qt::EditRole); 2506 } 2507 d->inserting = false; 2508 d->_q_rowsInserted(parent: d->root, start: index, end: index + insertCount - 1); 2509 } else { 2510 d->inserting = false; 2511 } 2512 } 2513 2514 int mc = count(); 2515 if (mc > d->maxCount) 2516 d->model->removeRows(row: d->maxCount, count: mc - d->maxCount, parent: d->root); 2517 } 2518 2519 /*! 2520 \since 4.4 2521 2522 Inserts a separator item into the combobox at the given \a index. 2523 2524 If the index is equal to or higher than the total number of items, the new item 2525 is appended to the list of existing items. If the index is zero or negative, the 2526 new item is prepended to the list of existing items. 2527 2528 \sa insertItem() 2529 */ 2530 void QComboBox::insertSeparator(int index) 2531 { 2532 Q_D(QComboBox); 2533 int itemCount = count(); 2534 index = qBound(min: 0, val: index, max: itemCount); 2535 if (index >= d->maxCount) 2536 return; 2537 insertItem(index, icon: QIcon(), text: QString()); 2538 QComboBoxDelegate::setSeparator(model: d->model, index: d->model->index(row: index, column: 0, parent: d->root)); 2539 } 2540 2541 /*! 2542 Removes the item at the given \a index from the combobox. 2543 This will update the current index if the index is removed. 2544 2545 This function does nothing if \a index is out of range. 2546 */ 2547 void QComboBox::removeItem(int index) 2548 { 2549 Q_D(QComboBox); 2550 if (index < 0 || index >= count()) 2551 return; 2552 d->model->removeRows(row: index, count: 1, parent: d->root); 2553 } 2554 2555 /*! 2556 Sets the \a text for the item on the given \a index in the combobox. 2557 */ 2558 void QComboBox::setItemText(int index, const QString &text) 2559 { 2560 Q_D(const QComboBox); 2561 QModelIndex item = d->model->index(row: index, column: d->modelColumn, parent: d->root); 2562 if (item.isValid()) { 2563 d->model->setData(index: item, value: text, role: Qt::EditRole); 2564 } 2565 } 2566 2567 /*! 2568 Sets the \a icon for the item on the given \a index in the combobox. 2569 */ 2570 void QComboBox::setItemIcon(int index, const QIcon &icon) 2571 { 2572 Q_D(const QComboBox); 2573 QModelIndex item = d->model->index(row: index, column: d->modelColumn, parent: d->root); 2574 if (item.isValid()) { 2575 d->model->setData(index: item, value: icon, role: Qt::DecorationRole); 2576 } 2577 } 2578 2579 /*! 2580 Sets the data \a role for the item on the given \a index in the combobox 2581 to the specified \a value. 2582 */ 2583 void QComboBox::setItemData(int index, const QVariant &value, int role) 2584 { 2585 Q_D(const QComboBox); 2586 QModelIndex item = d->model->index(row: index, column: d->modelColumn, parent: d->root); 2587 if (item.isValid()) { 2588 d->model->setData(index: item, value, role); 2589 } 2590 } 2591 2592 /*! 2593 Returns the list view used for the combobox popup. 2594 */ 2595 QAbstractItemView *QComboBox::view() const 2596 { 2597 Q_D(const QComboBox); 2598 return const_cast<QComboBoxPrivate*>(d)->viewContainer()->itemView(); 2599 } 2600 2601 /*! 2602 Sets the view to be used in the combobox popup to the given \a 2603 itemView. The combobox takes ownership of the view. 2604 2605 Note: If you want to use the convenience views (like QListWidget, 2606 QTableWidget or QTreeWidget), make sure to call setModel() on the 2607 combobox with the convenience widgets model before calling this 2608 function. 2609 */ 2610 void QComboBox::setView(QAbstractItemView *itemView) 2611 { 2612 Q_D(QComboBox); 2613 if (Q_UNLIKELY(!itemView)) { 2614 qWarning(msg:
"QComboBox::setView: cannot set a 0 view"); 2615 return; 2616 } 2617 2618 if (itemView->model() != d->model) 2619 itemView->setModel(d->model); 2620 d->viewContainer()->setItemView(itemView); 2621 } 2622 2623 /*! 2624 \reimp 2625 */ 2626 QSize QComboBox::minimumSizeHint() const 2627 { 2628 Q_D(const QComboBox); 2629 return d->recomputeSizeHint(sh&: d->minimumSizeHint); 2630 } 2631 2632 /*! 2633 \reimp 2634 2635 This implementation caches the size hint to avoid resizing when 2636 the contents change dynamically. To invalidate the cached value 2637 change the \l sizeAdjustPolicy. 2638 */ 2639 QSize QComboBox::sizeHint() const 2640 { 2641 Q_D(const QComboBox); 2642 return d->recomputeSizeHint(sh&: d->sizeHint); 2643 } 2644 2645 #ifdef Q_OS_MAC 2646 void QComboBoxPrivate::cleanupNativePopup() 2647 { 2648 if (!m_platformMenu) 2649 return; 2650 2651 int count = int(m_platformMenu->tag()); 2652 for (int i = 0; i < count; ++i) 2653 m_platformMenu->menuItemAt(i)->deleteLater(); 2654 2655 delete m_platformMenu; 2656 m_platformMenu = 0; 2657 } 2658 2659 /*! 2660 * \internal 2661 * 2662 * Tries to show a native popup. Returns true if it could, false otherwise. 2663 * 2664 */ 2665 bool QComboBoxPrivate::showNativePopup() 2666 { 2667 Q_Q(QComboBox); 2668 2669 cleanupNativePopup(); 2670 2671 QPlatformTheme *theme = QGuiApplicationPrivate::instance()->platformTheme(); 2672 m_platformMenu = theme->createPlatformMenu(); 2673 if (!m_platformMenu) 2674 return false; 2675 2676 int itemsCount = q->count(); 2677 m_platformMenu->setTag(quintptr(itemsCount)); 2678 2679 QPlatformMenuItem *currentItem = 0; 2680 int currentIndex = q->currentIndex(); 2681 2682 for (int i = 0; i < itemsCount; ++i) { 2683 QPlatformMenuItem *item = theme->createPlatformMenuItem(); 2684 QModelIndex rowIndex = model->index(i, modelColumn, root); 2685 QVariant textVariant = model->data(rowIndex, Qt::EditRole); 2686 item->setText(textVariant.toString()); 2687 QVariant iconVariant = model->data(rowIndex, Qt::DecorationRole); 2688 if (iconVariant.canConvert<QIcon>()) 2689 item->setIcon(iconVariant.value<QIcon>()); 2690 item->setCheckable(true); 2691 item->setChecked(i == currentIndex); 2692 if (!currentItem || i == currentIndex) 2693 currentItem = item; 2694 2695 IndexSetter setter = { i, q }; 2696 QObject::connect(item, &QPlatformMenuItem::activated, setter); 2697 2698 m_platformMenu->insertMenuItem(item, 0); 2699 m_platformMenu->syncMenuItem(item); 2700 } 2701 2702 QWindow *tlw = q->window()->windowHandle(); 2703 m_platformMenu->setFont(q->font()); 2704 m_platformMenu->setMinimumWidth(q->rect().width()); 2705 QPoint offset = QPoint(0, 7); 2706 if (q->testAttribute(Qt::WA_MacSmallSize)) 2707 offset = QPoint(-1, 7); 2708 else if (q->testAttribute(Qt::WA_MacMiniSize)) 2709 offset = QPoint(-2, 6); 2710 2711 const QRect targetRect = QRect(tlw->mapFromGlobal(q->mapToGlobal(offset)), QSize()); 2712 m_platformMenu->showPopup(tlw, QHighDpi::toNativePixels(targetRect, tlw), currentItem); 2713 2714 #ifdef Q_OS_MACOS 2715 // The Cocoa popup will swallow any mouse release event. 2716 // We need to fake one here to un-press the button. 2717 QMouseEvent mouseReleased(QEvent::MouseButtonRelease, q->pos(), Qt::LeftButton, 2718 Qt::MouseButtons(Qt::LeftButton), Qt::KeyboardModifiers()); 2719 QCoreApplication::sendEvent(q, &mouseReleased); 2720 #endif 2721 2722 return true; 2723 } 2724 2725 #endif // Q_OS_MAC 2726 2727 /*! 2728 Displays the list of items in the combobox. If the list is empty 2729 then no items will be shown. 2730 2731 If you reimplement this function to show a custom pop-up, make 2732 sure you call hidePopup() to reset the internal state. 2733 2734 \sa hidePopup() 2735 */ 2736 void QComboBox::() 2737 { 2738 Q_D(QComboBox); 2739 if (count() <= 0) 2740 return; 2741 2742 QStyle * const style = this->style(); 2743 QStyleOptionComboBox opt; 2744 initStyleOption(option: &opt); 2745 const bool = style->styleHint(stylehint: QStyle::SH_ComboBox_Popup, opt: &opt, widget: this); 2746 2747 #ifdef Q_OS_MAC 2748 if (usePopup 2749 && (!d->container 2750 || (view()->metaObject()->className() == QByteArray(
"QComboBoxListView") 2751 && view()->itemDelegate()->metaObject()->className() == QByteArray(
"QComboMenuDelegate"))) 2752 && style->styleHint(QStyle::SH_ComboBox_UseNativePopup, &opt, this) 2753 && d->showNativePopup()) 2754 return; 2755 #endif // Q_OS_MAC 2756 2757 #ifdef QT_KEYPAD_NAVIGATION 2758 #if QT_CONFIG(completer) 2759 if (QApplicationPrivate::keypadNavigationEnabled() && d->completer) { 2760 // editable combo box is line edit plus completer 2761 setEditFocus(true); 2762 d->completer->complete(); // show popup 2763 return; 2764 } 2765 #endif 2766 #endif 2767 2768 // set current item and select it 2769 QItemSelectionModel::SelectionFlags selectionMode = QItemSelectionModel::ClearAndSelect; 2770 if (view()->selectionBehavior() == QAbstractItemView::SelectRows) 2771 selectionMode.setFlag(flag: QItemSelectionModel::Rows); 2772 view()->selectionModel()->setCurrentIndex(index: d->currentIndex, command: selectionMode); 2773 QComboBoxPrivateContainer* container = d->viewContainer(); 2774 QRect listRect(style->subControlRect(cc: QStyle::CC_ComboBox, opt: &opt, 2775 sc: QStyle::SC_ComboBoxListBoxPopup, widget: this)); 2776 QRect screen = d->popupGeometry(screen: QDesktopWidgetPrivate::screenNumber(widget: this)); 2777 2778 QPoint below = mapToGlobal(listRect.bottomLeft()); 2779 int belowHeight = screen.bottom() - below.y(); 2780 QPoint above = mapToGlobal(listRect.topLeft()); 2781 int aboveHeight = above.y() - screen.y(); 2782 bool boundToScreen = !window()->testAttribute(attribute: Qt::WA_DontShowOnScreen); 2783 2784 { 2785 int listHeight = 0; 2786 int count = 0; 2787 QStack<QModelIndex> toCheck; 2788 toCheck.push(t: view()->rootIndex()); 2789 #if QT_CONFIG(treeview) 2790 QTreeView *treeView = qobject_cast<QTreeView*>(object: view()); 2791 if (treeView && treeView->header() && !treeView->header()->isHidden()) 2792 listHeight += treeView->header()->height(); 2793 #endif 2794 while (!toCheck.isEmpty()) { 2795 QModelIndex parent = toCheck.pop(); 2796 for (int i = 0, end = d->model->rowCount(parent); i < end; ++i) { 2797 QModelIndex idx = d->model->index(row: i, column: d->modelColumn, parent); 2798 if (!idx.isValid()) 2799 continue; 2800 listHeight += view()->visualRect(index: idx).height(); 2801 #if QT_CONFIG(treeview) 2802 if (d->model->hasChildren(parent: idx) && treeView && treeView->isExpanded(index: idx)) 2803 toCheck.push(t: idx); 2804 #endif 2805 ++count; 2806 if (!usePopup && count >= d->maxVisibleItems) { 2807 toCheck.clear(); 2808 break; 2809 } 2810 } 2811 } 2812 if (count > 1) 2813 listHeight += (count - 1) * container->spacing(); 2814 listRect.setHeight(listHeight); 2815 } 2816 2817 { 2818 // add the spacing for the grid on the top and the bottom; 2819 int heightMargin = container->topMargin() + container->bottomMargin(); 2820 2821 // add the frame of the container 2822 const QMargins cm = container->contentsMargins(); 2823 heightMargin += cm.top() + cm.bottom(); 2824 2825 //add the frame of the view 2826 const QMargins vm = view()->contentsMargins(); 2827 heightMargin += vm.top() + vm.bottom(); 2828 heightMargin += static_cast<QAbstractScrollAreaPrivate *>(QObjectPrivate::get(o: view()))->top; 2829 heightMargin += static_cast<QAbstractScrollAreaPrivate *>(QObjectPrivate::get(o: view()))->bottom; 2830 2831 listRect.setHeight(listRect.height() + heightMargin); 2832 } 2833 2834 // Add space for margin at top and bottom if the style wants it. 2835 if (usePopup) 2836 listRect.setHeight(listRect.height() + style->pixelMetric(metric: QStyle::PM_MenuVMargin, option: &opt, widget: this) * 2); 2837 2838 // Make sure the popup is wide enough to display its contents. 2839 if (usePopup) { 2840 const int diff = d->computeWidthHint() - width(); 2841 if (diff > 0) 2842 listRect.setWidth(listRect.width() + diff); 2843 } 2844 2845 //we need to activate the layout to make sure the min/maximum size are set when the widget was not yet show 2846 container->layout()->activate(); 2847 //takes account of the minimum/maximum size of the container 2848 listRect.setSize( listRect.size().expandedTo(otherSize: container->minimumSize()) 2849 .boundedTo(otherSize: container->maximumSize())); 2850 2851 // make sure the widget fits on screen 2852 if (boundToScreen) { 2853 if (listRect.width() > screen.width() ) 2854 listRect.setWidth(screen.width()); 2855 if (mapToGlobal(listRect.bottomRight()).x() > screen.right()) { 2856 below.setX(screen.x() + screen.width() - listRect.width()); 2857 above.setX(screen.x() + screen.width() - listRect.width()); 2858 } 2859 if (mapToGlobal(listRect.topLeft()).x() < screen.x() ) { 2860 below.setX(screen.x()); 2861 above.setX(screen.x()); 2862 } 2863 } 2864 2865 if (usePopup) { 2866 // Position horizontally. 2867 listRect.moveLeft(pos: above.x()); 2868 2869 // Position vertically so the curently selected item lines up 2870 // with the combo box. 2871 const QRect currentItemRect = view()->visualRect(index: view()->currentIndex()); 2872 const int offset = listRect.top() - currentItemRect.top(); 2873 listRect.moveTop(pos: above.y() + offset - listRect.top()); 2874 2875 // Clamp the listRect height and vertical position so we don't expand outside the 2876 // available screen geometry.This may override the vertical position, but it is more 2877 // important to show as much as possible of the popup. 2878 const int height = !boundToScreen ? listRect.height() : qMin(a: listRect.height(), b: screen.height()); 2879 listRect.setHeight(height); 2880 2881 if (boundToScreen) { 2882 if (listRect.top() < screen.top()) 2883 listRect.moveTop(pos: screen.top()); 2884 if (listRect.bottom() > screen.bottom()) 2885 listRect.moveBottom(pos: screen.bottom()); 2886 } 2887 } else if (!boundToScreen || listRect.height() <= belowHeight) { 2888 listRect.moveTopLeft(p: below); 2889 } else if (listRect.height() <= aboveHeight) { 2890 listRect.moveBottomLeft(p: above); 2891 } else if (belowHeight >= aboveHeight) { 2892 listRect.setHeight(belowHeight); 2893 listRect.moveTopLeft(p: below); 2894 } else { 2895 listRect.setHeight(aboveHeight); 2896 listRect.moveBottomLeft(p: above); 2897 } 2898 2899 if (qApp) { 2900 QGuiApplication::inputMethod()->reset(); 2901 } 2902 2903 const QScrollBar *sb = view()->horizontalScrollBar(); 2904 const auto needHorizontalScrollBar = [this, sb]{ 2905 const Qt::ScrollBarPolicy policy = view()->horizontalScrollBarPolicy(); 2906 return (policy == Qt::ScrollBarAsNeeded || policy == Qt::ScrollBarAlwaysOn) 2907 && sb->minimum() < sb->maximum(); 2908 }; 2909 const bool neededHorizontalScrollBar = needHorizontalScrollBar(); 2910 if (neededHorizontalScrollBar) 2911 listRect.adjust(dx1: 0, dy1: 0, dx2: 0, dy2: sb->height()); 2912 2913 // Hide the scrollers here, so that the listrect gets the full height of the container 2914 // If the scrollers are truly needed, the later call to container->updateScrollers() 2915 // will make them visible again. 2916 container->hideScrollers(); 2917 container->setGeometry(listRect); 2918 2919 #ifndef Q_OS_MAC 2920 const bool updatesEnabled = container->updatesEnabled(); 2921 #endif 2922 2923 #if QT_CONFIG(effects) 2924 bool scrollDown = (listRect.topLeft() == below); 2925 if (QApplication::isEffectEnabled(Qt::UI_AnimateCombo) 2926 && !style->styleHint(stylehint: QStyle::SH_ComboBox_Popup, opt: &opt, widget: this) && !window()->testAttribute(attribute: Qt::WA_DontShowOnScreen)) 2927 qScrollEffect(container, dir: scrollDown ? QEffects::DownScroll : QEffects::UpScroll, time: 150); 2928 #endif 2929 2930 // Don't disable updates on OS X. Windows are displayed immediately on this platform, 2931 // which means that the window will be visible before the call to container->show() returns. 2932 // If updates are disabled at this point we'll miss our chance at painting the popup 2933 // menu before it's shown, causing flicker since the window then displays the standard gray 2934 // background. 2935 #ifndef Q_OS_MAC 2936 container->setUpdatesEnabled(false); 2937 #endif 2938 2939 bool startTimer = !container->isVisible(); 2940 container->raise(); 2941 container->create(); 2942 if (QWindow *containerWindow = qt_widget_private(widget: container)->windowHandle(mode: QWidgetPrivate::WindowHandleMode::TopLevel)) { 2943 QScreen *currentScreen = d->associatedScreen(); 2944 if (currentScreen && !currentScreen->virtualSiblings().contains(t: containerWindow->screen())) { 2945 containerWindow->setScreen(currentScreen); 2946 2947 // This seems to workaround an issue in xcb+multi GPU+multiscreen 2948 // environment where the window might not always show up when screen 2949 // is changed. 2950 container->hide(); 2951 } 2952 } 2953 container->show(); 2954 if (!neededHorizontalScrollBar && needHorizontalScrollBar()) { 2955 listRect.adjust(dx1: 0, dy1: 0, dx2: 0, dy2: sb->height()); 2956 container->setGeometry(listRect); 2957 } 2958 2959 container->updateScrollers(); 2960 view()->setFocus(); 2961 2962 view()->scrollTo(index: view()->currentIndex(), 2963 hint: style->styleHint(stylehint: QStyle::SH_ComboBox_Popup, opt: &opt, widget: this) 2964 ? QAbstractItemView::PositionAtCenter 2965 : QAbstractItemView::EnsureVisible); 2966 2967 #ifndef Q_OS_MAC 2968 container->setUpdatesEnabled(updatesEnabled); 2969 #endif 2970 2971 container->update(); 2972 #ifdef QT_KEYPAD_NAVIGATION 2973 if (QApplicationPrivate::keypadNavigationEnabled()) 2974 view()->setEditFocus(true); 2975 #endif 2976 if (startTimer) { 2977 container->popupTimer.start(); 2978 container->maybeIgnoreMouseButtonRelease = true; 2979 } 2980 } 2981 2982 /*! 2983 Hides the list of items in the combobox if it is currently visible 2984 and resets the internal state, so that if the custom pop-up was 2985 shown inside the reimplemented showPopup(), then you also need to 2986 reimplement the hidePopup() function to hide your custom pop-up 2987 and call the base class implementation to reset the internal state 2988 whenever your custom pop-up widget is hidden. 2989 2990 \sa showPopup() 2991 */ 2992 void QComboBox::() 2993 { 2994 Q_D(QComboBox); 2995 if (d->container && d->container->isVisible()) { 2996 #if QT_CONFIG(effects) 2997 QSignalBlocker modelBlocker(d->model); 2998 QSignalBlocker viewBlocker(d->container->itemView()); 2999 QSignalBlocker containerBlocker(d->container); 3000 // Flash selected/triggered item (if any). 3001 if (style()->styleHint(stylehint: QStyle::SH_Menu_FlashTriggeredItem)) { 3002 QItemSelectionModel *selectionModel = view() ? view()->selectionModel() : nullptr; 3003 if (selectionModel && selectionModel->hasSelection()) { 3004 QEventLoop eventLoop; 3005 const QItemSelection selection = selectionModel->selection(); 3006 3007 // Deselect item and wait 60 ms. 3008 selectionModel->select(selection, command: QItemSelectionModel::Toggle); 3009 QTimer::singleShot(msec: 60, receiver: &eventLoop, SLOT(quit())); 3010 eventLoop.exec(); 3011 3012 // Select item and wait 20 ms. 3013 selectionModel->select(selection, command: QItemSelectionModel::Toggle); 3014 QTimer::singleShot(msec: 20, receiver: &eventLoop, SLOT(quit())); 3015 eventLoop.exec(); 3016 } 3017 } 3018 3019 // Fade out. 3020 bool needFade = style()->styleHint(stylehint: QStyle::SH_Menu_FadeOutOnHide); 3021 bool didFade = false; 3022 if (needFade) { 3023 #if defined(Q_OS_MAC) 3024 QPlatformNativeInterface *platformNativeInterface = QGuiApplication::platformNativeInterface(); 3025 int at = platformNativeInterface->metaObject()->indexOfMethod(
"fadeWindow()"); 3026 if (at != -1) { 3027 QMetaMethod windowFade = platformNativeInterface->metaObject()->method(at); 3028 windowFade.invoke(platformNativeInterface, Q_ARG(QWindow *, d->container->windowHandle())); 3029 didFade = true; 3030 } 3031 3032 #endif // Q_OS_MAC 3033 // Other platform implementations welcome :-) 3034 } 3035 containerBlocker.unblock(); 3036 viewBlocker.unblock(); 3037 modelBlocker.unblock(); 3038 3039 if (!didFade) 3040 #endif // QT_CONFIG(effects) 3041 // Fade should implicitly hide as well ;-) 3042 d->container->hide(); 3043 } 3044 #ifdef QT_KEYPAD_NAVIGATION 3045 if (QApplicationPrivate::keypadNavigationEnabled() && isEditable() && hasFocus()) 3046 setEditFocus(true); 3047 #endif 3048 d->_q_resetButton(); 3049 } 3050 3051 /*! 3052 Clears the combobox, removing all items. 3053 3054 Note: If you have set an external model on the combobox this model 3055 will still be cleared when calling this function. 3056 */ 3057 void QComboBox::clear() 3058 { 3059 Q_D(QComboBox); 3060 d->model->removeRows(row: 0, count: d->model->rowCount(parent: d->root), parent: d->root); 3061 #ifndef QT_NO_ACCESSIBILITY 3062 QAccessibleValueChangeEvent event(this, QString()); 3063 QAccessible::updateAccessibility(event: &event); 3064 #endif 3065 } 3066 3067 /*! 3068 Clears the contents of the line edit used for editing in the combobox. 3069 */ 3070 void QComboBox::clearEditText() 3071 { 3072 Q_D(QComboBox); 3073 if (d->lineEdit) 3074 d->lineEdit->clear(); 3075 #ifndef QT_NO_ACCESSIBILITY 3076 QAccessibleValueChangeEvent event(this, QString()); 3077 QAccessible::updateAccessibility(event: &event); 3078 #endif 3079 } 3080 3081 /*! 3082 Sets the \a text in the combobox's text edit. 3083 */ 3084 void QComboBox::setEditText(const QString &text) 3085 { 3086 Q_D(QComboBox); 3087 if (d->lineEdit) 3088 d->lineEdit->setText(text); 3089 #ifndef QT_NO_ACCESSIBILITY 3090 QAccessibleValueChangeEvent event(this, text); 3091 QAccessible::updateAccessibility(event: &event); 3092 #endif 3093 } 3094 3095 /*! 3096 \reimp 3097 */ 3098 void QComboBox::focusInEvent(QFocusEvent *e) 3099 { 3100 Q_D(QComboBox); 3101 update(); 3102 if (d->lineEdit) { 3103 d->lineEdit->event(e); 3104 #if QT_CONFIG(completer) 3105 if (d->lineEdit->completer()) 3106 d->lineEdit->completer()->setWidget(this); 3107 #endif 3108 } 3109 } 3110 3111 /*! 3112 \reimp 3113 */ 3114 void QComboBox::focusOutEvent(QFocusEvent *e) 3115 { 3116 Q_D(QComboBox); 3117 update(); 3118 if (d->lineEdit) 3119 d->lineEdit->event(e); 3120 } 3121 3122 /*! \reimp */ 3123 void QComboBox::changeEvent(QEvent *e) 3124 { 3125 Q_D(QComboBox); 3126 switch (e->type()) { 3127 case QEvent::StyleChange: 3128 if (d->container) 3129 d->container->updateStyleSettings(); 3130 d->updateDelegate(); 3131 #ifdef Q_OS_MAC 3132 case QEvent::MacSizeChange: 3133 #endif 3134 d->sizeHint = QSize(); // invalidate size hint 3135 d->minimumSizeHint = QSize(); 3136 d->updateLayoutDirection(); 3137 if (d->lineEdit) 3138 d->updateLineEditGeometry(); 3139 d->setLayoutItemMargins(element: QStyle::SE_ComboBoxLayoutItem); 3140 3141 if (e->type() == QEvent::MacSizeChange){ 3142 QPlatformTheme::Font f = QPlatformTheme::SystemFont; 3143 if (testAttribute(attribute: Qt::WA_MacSmallSize)) 3144 f = QPlatformTheme::SmallFont; 3145 else if (testAttribute(attribute: Qt::WA_MacMiniSize)) 3146 f = QPlatformTheme::MiniFont; 3147 if (const QFont *platformFont = QApplicationPrivate::platformTheme()->font(type: f)) { 3148 QFont f = font(); 3149 f.setPointSizeF(platformFont->pointSizeF()); 3150 setFont(f); 3151 } 3152 } 3153 // ### need to update scrollers etc. as well here 3154 break; 3155 case QEvent::EnabledChange: 3156 if (!isEnabled()) 3157 hidePopup(); 3158 break; 3159 case QEvent::PaletteChange: { 3160 d->updateViewContainerPaletteAndOpacity(); 3161 break; 3162 } 3163 case QEvent::FontChange: { 3164 d->sizeHint = QSize(); // invalidate size hint 3165 d->viewContainer()->setFont(font()); 3166 d->viewContainer()->itemView()->doItemsLayout(); 3167 if (d->lineEdit) 3168 d->updateLineEditGeometry(); 3169 break; 3170 } 3171 default: 3172 break; 3173 } 3174 QWidget::changeEvent(e); 3175 } 3176 3177 /*! 3178 \reimp 3179 */ 3180 void QComboBox::resizeEvent(QResizeEvent *) 3181 { 3182 Q_D(QComboBox); 3183 d->updateLineEditGeometry(); 3184 } 3185 3186 /*! 3187 \reimp 3188 */ 3189 void QComboBox::paintEvent(QPaintEvent *) 3190 { 3191 QStylePainter painter(this); 3192 painter.setPen(palette().color(cr: QPalette::Text)); 3193 3194 // draw the combobox frame, focusrect and selected etc. 3195 QStyleOptionComboBox opt; 3196 initStyleOption(option: &opt); 3197 painter.drawComplexControl(cc: QStyle::CC_ComboBox, opt); 3198 3199 if (currentIndex() < 0 && !placeholderText().isEmpty()) { 3200 opt.palette.setBrush(acr: QPalette::ButtonText, abrush: opt.palette.placeholderText()); 3201 opt.currentText = placeholderText(); 3202 } 3203 3204 // draw the icon and text 3205 painter.drawControl(ce: QStyle::CE_ComboBoxLabel, opt); 3206 } 3207 3208 /*! 3209 \reimp 3210 */ 3211 void QComboBox::showEvent(QShowEvent *e) 3212 { 3213 Q_D(QComboBox); 3214 if (!d->shownOnce && d->sizeAdjustPolicy == QComboBox::AdjustToContentsOnFirstShow) { 3215 d->sizeHint = QSize(); 3216 updateGeometry(); 3217 } 3218 d->shownOnce = true; 3219 QWidget::showEvent(event: e); 3220 } 3221 3222 /*! 3223 \reimp 3224 */ 3225 void QComboBox::hideEvent(QHideEvent *) 3226 { 3227 hidePopup(); 3228 } 3229 3230 /*! 3231 \reimp 3232 */ 3233 bool QComboBox::event(QEvent *event) 3234 { 3235 Q_D(QComboBox); 3236 switch(event->type()) { 3237 case QEvent::LayoutDirectionChange: 3238 case QEvent::ApplicationLayoutDirectionChange: 3239 d->updateLayoutDirection(); 3240 d->updateLineEditGeometry(); 3241 break; 3242 case QEvent::HoverEnter: 3243 case QEvent::HoverLeave: 3244 case QEvent::HoverMove: 3245 if (const QHoverEvent *he = static_cast<const QHoverEvent *>(event)) 3246 d->updateHoverControl(pos: he->pos()); 3247 break; 3248 case QEvent::ShortcutOverride: 3249 if (d->lineEdit) 3250 return d->lineEdit->event(event); 3251 break; 3252 #ifdef QT_KEYPAD_NAVIGATION 3253 case QEvent::EnterEditFocus: 3254 if (!d->lineEdit) 3255 setEditFocus(false); // We never want edit focus if we are not editable 3256 else 3257 d->lineEdit->event(event); //so cursor starts 3258 break; 3259 case QEvent::LeaveEditFocus: 3260 if (d->lineEdit) 3261 d->lineEdit->event(event); //so cursor stops 3262 break; 3263 #endif 3264 default: 3265 break; 3266 } 3267 return QWidget::event(event); 3268 } 3269 3270 /*! 3271 \reimp 3272 */ 3273 void QComboBox::mousePressEvent(QMouseEvent *e) 3274 { 3275 Q_D(QComboBox); 3276 if (!QGuiApplication::styleHints()->setFocusOnTouchRelease()) 3277 d->showPopupFromMouseEvent(e); 3278 } 3279 3280 void QComboBoxPrivate::(QMouseEvent *e) 3281 { 3282 Q_Q(QComboBox); 3283 QStyleOptionComboBox opt; 3284 q->initStyleOption(option: &opt); 3285 QStyle::SubControl sc = q->style()->hitTestComplexControl(cc: QStyle::CC_ComboBox, opt: &opt, pt: e->pos(), widget: q); 3286 3287 if (e->button() == Qt::LeftButton 3288 && !(sc == QStyle::SC_None && e->type() == QEvent::MouseButtonRelease) 3289 && (sc == QStyle::SC_ComboBoxArrow || !q->isEditable()) 3290 && !viewContainer()->isVisible()) { 3291 if (sc == QStyle::SC_ComboBoxArrow) 3292 updateArrow(state: QStyle::State_Sunken); 3293 #ifdef QT_KEYPAD_NAVIGATION 3294 //if the container already exists, then d->viewContainer() is safe to call 3295 if (container) { 3296 #else 3297 if (true) { 3298 #endif 3299 // We've restricted the next couple of lines, because by not calling 3300 // viewContainer(), we avoid creating the QComboBoxPrivateContainer. 3301 viewContainer()->initialClickPosition = q->mapToGlobal(e->pos()); 3302 } 3303 q->showPopup(); 3304 // The code below ensures that regular mousepress and pick item still works 3305 // If it was not called the viewContainer would ignore event since it didn't have 3306 // a mousePressEvent first. 3307 if (viewContainer()) { 3308 viewContainer()->blockMouseReleaseTimer.start(msec: QApplication::doubleClickInterval()); 3309 viewContainer()->maybeIgnoreMouseButtonRelease = false; 3310 } 3311 } else { 3312 #ifdef QT_KEYPAD_NAVIGATION 3313 if (QApplicationPrivate::keypadNavigationEnabled() && sc == QStyle::SC_ComboBoxEditField && lineEdit) { 3314 lineEdit->event(e); //so lineedit can move cursor, etc 3315 return; 3316 } 3317 #endif 3318 e->ignore(); 3319 } 3320 } 3321 3322 /*! 3323 \reimp 3324 */ 3325 void QComboBox::mouseReleaseEvent(QMouseEvent *e) 3326 { 3327 Q_D(QComboBox); 3328 d->updateArrow(state: QStyle::State_None); 3329 if (QGuiApplication::styleHints()->setFocusOnTouchRelease() && hasFocus()) 3330 d->showPopupFromMouseEvent(e); 3331 } 3332 3333 /*! 3334 \reimp 3335 */ 3336 void QComboBox::keyPressEvent(QKeyEvent *e) 3337 { 3338 Q_D(QComboBox); 3339 3340 #if QT_CONFIG(completer) 3341 if (const auto *cmpltr = completer()) { 3342 const auto * = QCompleterPrivate::get(o: cmpltr)->popup; 3343 if (popup && popup->isVisible()) { 3344 // provide same autocompletion support as line edit 3345 d->lineEdit->event(e); 3346 return; 3347 } 3348 } 3349 #endif 3350 3351 enum Move { NoMove=0 , MoveUp , MoveDown , MoveFirst , MoveLast}; 3352 3353 Move move = NoMove; 3354 int newIndex = currentIndex(); 3355 switch (e->key()) { 3356 case Qt::Key_Up: 3357 if (e->modifiers() & Qt::ControlModifier) 3358 break; // pass to line edit for auto completion 3359 Q_FALLTHROUGH(); 3360 case Qt::Key_PageUp: 3361 #ifdef QT_KEYPAD_NAVIGATION 3362 if (QApplicationPrivate::keypadNavigationEnabled()) 3363 e->ignore(); 3364 else 3365 #endif 3366 move = MoveUp; 3367 break; 3368 case Qt::Key_Down: 3369 if (e->modifiers() & Qt::AltModifier) { 3370 showPopup(); 3371 return; 3372 } else if (e->modifiers() & Qt::ControlModifier) 3373 break; // pass to line edit for auto completion 3374 Q_FALLTHROUGH(); 3375 case Qt::Key_PageDown: 3376 #ifdef QT_KEYPAD_NAVIGATION 3377 if (QApplicationPrivate::keypadNavigationEnabled()) 3378 e->ignore(); 3379 else 3380 #endif 3381 move = MoveDown; 3382 break; 3383 case Qt::Key_Home: 3384 if (!d->lineEdit) 3385 move = MoveFirst; 3386 break; 3387 case Qt::Key_End: 3388 if (!d->lineEdit) 3389 move = MoveLast; 3390 break; 3391 case Qt::Key_F4: 3392 if (!e->modifiers()) { 3393 showPopup(); 3394 return; 3395 } 3396 break; 3397 case Qt::Key_Space: 3398 if (!d->lineEdit) { 3399 showPopup(); 3400 return; 3401 } 3402 break; 3403 case Qt::Key_Enter: 3404 case Qt::Key_Return: 3405 case Qt::Key_Escape: 3406 if (!d->lineEdit) 3407 e->ignore(); 3408 break; 3409 #ifdef QT_KEYPAD_NAVIGATION 3410 case Qt::Key_Select: 3411 if (QApplicationPrivate::keypadNavigationEnabled() 3412 && (!hasEditFocus() || !d->lineEdit)) { 3413 showPopup(); 3414 return; 3415 } 3416 break; 3417 case Qt::Key_Left: 3418 case Qt::Key_Right: 3419 if (QApplicationPrivate::keypadNavigationEnabled() && !hasEditFocus()) 3420 e->ignore(); 3421 break; 3422 case Qt::Key_Back: 3423 if (QApplicationPrivate::keypadNavigationEnabled()) { 3424 if (!hasEditFocus() || !d->lineEdit) 3425 e->ignore(); 3426 } else { 3427 e->ignore(); // let the surounding dialog have it 3428 } 3429 break; 3430 #endif 3431 default: 3432 if (!d->lineEdit) { 3433 if (!e->text().isEmpty()) 3434 d->keyboardSearchString(text: e->text()); 3435 else 3436 e->ignore(); 3437 } 3438 } 3439 3440 const int rowCount = count(); 3441 3442 if (move != NoMove) { 3443 e->accept(); 3444 switch (move) { 3445 case MoveFirst: 3446 newIndex = -1; 3447 Q_FALLTHROUGH(); 3448 case MoveDown: 3449 newIndex++; 3450 while (newIndex < rowCount && !(d->model->index(row: newIndex, column: d->modelColumn, parent: d->root).flags() & Qt::ItemIsEnabled)) 3451 newIndex++; 3452 break; 3453 case MoveLast: 3454 newIndex = rowCount; 3455 Q_FALLTHROUGH(); 3456 case MoveUp: 3457 newIndex--; 3458 while ((newIndex >= 0) && !(d->model->flags(index: d->model->index(row: newIndex,column: d->modelColumn,parent: d->root)) & Qt::ItemIsEnabled)) 3459 newIndex--; 3460 break; 3461 default: 3462 e->ignore(); 3463 break; 3464 } 3465 3466 if (newIndex >= 0 && newIndex < rowCount && newIndex != currentIndex()) { 3467 setCurrentIndex(newIndex); 3468 d->emitActivated(index: d->currentIndex); 3469 } 3470 } else if (d->lineEdit) { 3471 d->lineEdit->event(e); 3472 } 3473 } 3474 3475 3476 /*! 3477 \reimp 3478 */ 3479 void QComboBox::keyReleaseEvent(QKeyEvent *e) 3480 { 3481 Q_D(QComboBox); 3482 if (d->lineEdit) 3483 d->lineEdit->event(e); 3484 else 3485 QWidget::keyReleaseEvent(event: e); 3486 } 3487 3488 /*! 3489 \reimp 3490 */ 3491 #if QT_CONFIG(wheelevent) 3492 void QComboBox::wheelEvent(QWheelEvent *e) 3493 { 3494 Q_D(QComboBox); 3495 QStyleOptionComboBox opt; 3496 initStyleOption(option: &opt); 3497 if (style()->styleHint(stylehint: QStyle::SH_ComboBox_AllowWheelScrolling, opt: &opt, widget: this) && 3498 !d->viewContainer()->isVisible()) { 3499 const int rowCount = count(); 3500 int newIndex = currentIndex(); 3501 int delta = e->angleDelta().y(); 3502 3503 if (delta > 0) { 3504 newIndex--; 3505 while ((newIndex >= 0) && !(d->model->flags(index: d->model->index(row: newIndex,column: d->modelColumn,parent: d->root)) & Qt::ItemIsEnabled)) 3506 newIndex--; 3507 } else if (delta < 0) { 3508 newIndex++; 3509 while (newIndex < rowCount && !(d->model->index(row: newIndex, column: d->modelColumn, parent: d->root).flags() & Qt::ItemIsEnabled)) 3510 newIndex++; 3511 } 3512 3513 if (newIndex >= 0 && newIndex < rowCount && newIndex != currentIndex()) { 3514 setCurrentIndex(newIndex); 3515 d->emitActivated(index: d->currentIndex); 3516 } 3517 e->accept(); 3518 } 3519 } 3520 #endif 3521 3522 #ifndef QT_NO_CONTEXTMENU 3523 /*! 3524 \reimp 3525 */ 3526 void QComboBox::(QContextMenuEvent *e) 3527 { 3528 Q_D(QComboBox); 3529 if (d->lineEdit) { 3530 Qt::ContextMenuPolicy p = d->lineEdit->contextMenuPolicy(); 3531 d->lineEdit->setContextMenuPolicy(Qt::DefaultContextMenu); 3532 d->lineEdit->event(e); 3533 d->lineEdit->setContextMenuPolicy(p); 3534 } 3535 } 3536 #endif // QT_NO_CONTEXTMENU 3537 3538 void QComboBoxPrivate::keyboardSearchString(const QString &text) 3539 { 3540 // use keyboardSearch from the listView so we do not duplicate code 3541 QAbstractItemView *view = viewContainer()->itemView(); 3542 view->setCurrentIndex(currentIndex); 3543 int currentRow = view->currentIndex().row(); 3544 view->keyboardSearch(search: text); 3545 if (currentRow != view->currentIndex().row()) { 3546 setCurrentIndex(view->currentIndex()); 3547 emitActivated(index: currentIndex); 3548 } 3549 } 3550 3551 void QComboBoxPrivate::modelChanged() 3552 { 3553 Q_Q(QComboBox); 3554 3555 if (sizeAdjustPolicy == QComboBox::AdjustToContents) { 3556 sizeHint = QSize(); 3557 adjustComboBoxSize(); 3558 q->updateGeometry(); 3559 } 3560 } 3561 3562 /*! 3563 \reimp 3564 */ 3565 void QComboBox::inputMethodEvent(QInputMethodEvent *e) 3566 { 3567 Q_D(QComboBox); 3568 if (d->lineEdit) { 3569 d->lineEdit->event(e); 3570 } else { 3571 if (!e->commitString().isEmpty()) 3572 d->keyboardSearchString(text: e->commitString()); 3573 else 3574 e->ignore(); 3575 } 3576 } 3577 3578 /*! 3579 \reimp 3580 */ 3581 QVariant QComboBox::inputMethodQuery(Qt::InputMethodQuery query) const 3582 { 3583 Q_D(const QComboBox); 3584 if (d->lineEdit) 3585 return d->lineEdit->inputMethodQuery(query); 3586 return QWidget::inputMethodQuery(query); 3587 } 3588 3589 /*!\internal 3590 */ 3591 QVariant QComboBox::inputMethodQuery(Qt::InputMethodQuery query, const QVariant &argument) const 3592 { 3593 Q_D(const QComboBox); 3594 if (d->lineEdit) 3595 return d->lineEdit->inputMethodQuery(property: query, argument); 3596 return QWidget::inputMethodQuery(query); 3597 } 3598 3599 /*! 3600 \fn void QComboBox::addItem(const QString &text, const QVariant &userData) 3601 3602 Adds an item to the combobox with the given \a text, and 3603 containing the specified \a userData (stored in the Qt::UserRole). 3604 The item is appended to the list of existing items. 3605 */ 3606 3607 /*! 3608 \fn void QComboBox::addItem(const QIcon &icon, const QString &text, 3609 const QVariant &userData) 3610 3611 Adds an item to the combobox with the given \a icon and \a text, 3612 and containing the specified \a userData (stored in the 3613 Qt::UserRole). The item is appended to the list of existing items. 3614 */ 3615 3616 /*! 3617 \fn void QComboBox::addItems(const QStringList &texts) 3618 3619 Adds each of the strings in the given \a texts to the combobox. Each item 3620 is appended to the list of existing items in turn. 3621 */ 3622 3623 /*! 3624 \fn void QComboBox::editTextChanged(const QString &text) 3625 3626 This signal is emitted when the text in the combobox's line edit 3627 widget is changed. The new text is specified by \a text. 3628 */ 3629 3630 /*! 3631 \property QComboBox::frame 3632 \brief whether the combo box draws itself with a frame 3633 3634 3635 If enabled (the default) the combo box draws itself inside a 3636 frame, otherwise the combo box draws itself without any frame. 3637 */ 3638 bool QComboBox::hasFrame() const 3639 { 3640 Q_D(const QComboBox); 3641 return d->frame; 3642 } 3643 3644 3645 void QComboBox::setFrame(bool enable) 3646 { 3647 Q_D(QComboBox); 3648 d->frame = enable; 3649 update(); 3650 updateGeometry(); 3651 } 3652 3653 /*! 3654 \property QComboBox::modelColumn 3655 \brief the column in the model that is visible. 3656 3657 If set prior to populating the combo box, the pop-up view will 3658 not be affected and will show the first column (using this property's 3659 default value). 3660 3661 By default, this property has a value of 0. 3662 */ 3663 int QComboBox::modelColumn() const 3664 { 3665 Q_D(const QComboBox); 3666 return d->modelColumn; 3667 } 3668 3669 void QComboBox::setModelColumn(int visibleColumn) 3670 { 3671 Q_D(QComboBox); 3672 d->modelColumn = visibleColumn; 3673 QListView *lv = qobject_cast<QListView *>(object: d->viewContainer()->itemView()); 3674 if (lv) 3675 lv->setModelColumn(visibleColumn); 3676 #if QT_CONFIG(completer) 3677 if (d->lineEdit && d->lineEdit->completer() 3678 && d->lineEdit->completer() == d->completer) 3679 d->lineEdit->completer()->setCompletionColumn(visibleColumn); 3680 #endif 3681 setCurrentIndex(currentIndex()); //update the text to the text of the new column; 3682 } 3683 3684 QT_END_NAMESPACE 3685 3686 #include "moc_qcombobox.cpp" 3687 #include "moc_qcombobox_p.cpp" 3688
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4