File indexing completed on 2024-04-28 03:59:13
0001 /* 0002 This file is part of the KDE libraries 0003 SPDX-FileCopyrightText: 1999 Reginald Stadlbauer <reggie@kde.org> 0004 SPDX-FileCopyrightText: 1999 Simon Hausmann <hausmann@kde.org> 0005 SPDX-FileCopyrightText: 2000 Nicolas Hadacek <haadcek@kde.org> 0006 SPDX-FileCopyrightText: 2000 Kurt Granroth <granroth@kde.org> 0007 SPDX-FileCopyrightText: 2000 Michael Koch <koch@kde.org> 0008 SPDX-FileCopyrightText: 2001 Holger Freyther <freyther@kde.org> 0009 SPDX-FileCopyrightText: 2002 Ellis Whitehead <ellis@kde.org> 0010 SPDX-FileCopyrightText: 2002 Joseph Wenninger <jowenn@kde.org> 0011 SPDX-FileCopyrightText: 2003 Andras Mantia <amantia@kde.org> 0012 SPDX-FileCopyrightText: 2005-2006 Hamish Rodda <rodda@kde.org> 0013 SPDX-FileCopyrightText: 2006 Albert Astals Cid <aacid@kde.org> 0014 SPDX-FileCopyrightText: 2006 Clarence Dang <dang@kde.org> 0015 SPDX-FileCopyrightText: 2006 Michel Hermier <michel.hermier@gmail.com> 0016 SPDX-FileCopyrightText: 2007 Nick Shaforostoff <shafff@ukr.net> 0017 0018 SPDX-License-Identifier: LGPL-2.0-only 0019 */ 0020 0021 #include "kselectaction.h" 0022 #include "kselectaction_p.h" 0023 0024 #include "loggingcategory.h" 0025 0026 #include <QActionEvent> 0027 #include <QEvent> 0028 #include <QMenu> 0029 #include <QStandardItem> 0030 #include <QToolBar> 0031 0032 // QAction::setText("Hi") and then KPopupAccelManager exec'ing, causes 0033 // QAction::text() to return "&Hi" :( Comboboxes don't have accels and 0034 // display ampersands literally. 0035 static QString DropAmpersands(const QString &text) 0036 { 0037 QString label = text; 0038 0039 int p = label.indexOf(QLatin1Char('&')); 0040 while (p >= 0 && p < label.length() - 1) { 0041 if (label[p + 1].isLetterOrNumber() // Valid accelerator. 0042 || label[p + 1] == QLatin1Char('&')) { // Escaped accelerator marker. 0043 label.remove(p, 1); 0044 } 0045 0046 p = label.indexOf(QLatin1Char('&'), p + 1); 0047 } 0048 0049 return label; 0050 } 0051 0052 KSelectAction::KSelectAction(QObject *parent) 0053 : KSelectAction(*new KSelectActionPrivate(this), parent) 0054 { 0055 } 0056 0057 KSelectAction::KSelectAction(const QString &text, QObject *parent) 0058 : KSelectAction(*new KSelectActionPrivate(this), parent) 0059 { 0060 setText(text); 0061 } 0062 0063 KSelectAction::KSelectAction(const QIcon &icon, const QString &text, QObject *parent) 0064 : KSelectAction(*new KSelectActionPrivate(this), parent) 0065 { 0066 setIcon(icon); 0067 setText(text); 0068 } 0069 0070 KSelectAction::KSelectAction(KSelectActionPrivate &dd, QObject *parent) 0071 : QWidgetAction(parent) 0072 , d_ptr(&dd) 0073 { 0074 Q_D(KSelectAction); 0075 d->init(); 0076 } 0077 0078 KSelectAction::~KSelectAction() 0079 { 0080 menu()->deleteLater(); 0081 } 0082 0083 void KSelectActionPrivate::init() 0084 { 0085 QObject::connect(q_ptr->selectableActionGroup(), &QActionGroup::triggered, q_ptr, &KSelectAction::slotActionTriggered); 0086 QObject::connect(q_ptr, &QAction::toggled, q_ptr, &KSelectAction::slotToggled); 0087 q_ptr->setMenu(new QMenu()); 0088 q_ptr->setEnabled(false); 0089 } 0090 0091 QActionGroup *KSelectAction::selectableActionGroup() const 0092 { 0093 Q_D(const KSelectAction); 0094 return d->m_actionGroup; 0095 } 0096 0097 QList<QAction *> KSelectAction::actions() const 0098 { 0099 return selectableActionGroup()->actions(); 0100 } 0101 0102 QAction *KSelectAction::currentAction() const 0103 { 0104 return selectableActionGroup()->checkedAction(); 0105 } 0106 0107 int KSelectAction::currentItem() const 0108 { 0109 return selectableActionGroup()->actions().indexOf(currentAction()); 0110 } 0111 0112 QString KSelectAction::currentText() const 0113 { 0114 if (QAction *a = currentAction()) { 0115 return ::DropAmpersands(a->text()); 0116 } 0117 0118 return QString(); 0119 } 0120 0121 bool KSelectAction::setCurrentAction(QAction *action) 0122 { 0123 // qCDebug(KWidgetsAddonsLog) << "KSelectAction::setCurrentAction(" << action << ")"; 0124 if (action) { 0125 if (actions().contains(action)) { 0126 if (action->isVisible() && action->isEnabled() && action->isCheckable()) { 0127 action->setChecked(true); 0128 if (isCheckable()) { 0129 setChecked(true); 0130 } 0131 return true; 0132 } else { 0133 qCWarning(KWidgetsAddonsLog) << "Action does not have the correct properties to be current:" << action->text(); 0134 } 0135 } else { 0136 qCWarning(KWidgetsAddonsLog) << "Action does not belong to group:" << action->text(); 0137 } 0138 return false; 0139 } 0140 0141 if (currentAction()) { 0142 currentAction()->setChecked(false); 0143 } 0144 0145 return false; 0146 } 0147 0148 bool KSelectAction::setCurrentItem(int index) 0149 { 0150 // qCDebug(KWidgetsAddonsLog) << "KSelectAction::setCurrentIndex(" << index << ")"; 0151 return setCurrentAction(action(index)); 0152 } 0153 0154 QAction *KSelectAction::action(int index) const 0155 { 0156 if (index >= 0 && index < selectableActionGroup()->actions().count()) { 0157 return selectableActionGroup()->actions().at(index); 0158 } 0159 0160 return nullptr; 0161 } 0162 0163 QAction *KSelectAction::action(const QString &text, Qt::CaseSensitivity cs) const 0164 { 0165 QString compare; 0166 if (cs == Qt::CaseSensitive) { 0167 compare = text; 0168 } else { 0169 compare = text.toLower(); 0170 } 0171 0172 const auto selectableActions = selectableActionGroup()->actions(); 0173 for (QAction *action : selectableActions) { 0174 const QString text = ::DropAmpersands(action->text()); 0175 if (cs == Qt::CaseSensitive) { 0176 if (text == compare) { 0177 return action; 0178 } 0179 0180 } else if (cs == Qt::CaseInsensitive) { 0181 if (text.toLower() == compare) { 0182 return action; 0183 } 0184 } 0185 } 0186 0187 return nullptr; 0188 } 0189 0190 bool KSelectAction::setCurrentAction(const QString &text, Qt::CaseSensitivity cs) 0191 { 0192 // qCDebug(KWidgetsAddonsLog) << "KSelectAction::setCurrentAction(" << text << ",cs=" << cs << ")"; 0193 return setCurrentAction(action(text, cs)); 0194 } 0195 0196 void KSelectAction::setComboWidth(int width) 0197 { 0198 Q_D(KSelectAction); 0199 if (width < 0) { 0200 return; 0201 } 0202 0203 d->m_comboWidth = width; 0204 0205 for (QComboBox *box : std::as_const(d->m_comboBoxes)) { 0206 box->setMaximumWidth(d->m_comboWidth); 0207 } 0208 0209 Q_EMIT changed(); 0210 } 0211 0212 void KSelectAction::setMaxComboViewCount(int n) 0213 { 0214 Q_D(KSelectAction); 0215 d->m_maxComboViewCount = n; 0216 0217 for (QComboBox *box : std::as_const(d->m_comboBoxes)) { 0218 if (d->m_maxComboViewCount != -1) { 0219 box->setMaxVisibleItems(d->m_maxComboViewCount); 0220 } else 0221 // hardcoded qt default 0222 { 0223 box->setMaxVisibleItems(10); 0224 } 0225 } 0226 0227 Q_EMIT changed(); 0228 } 0229 0230 void KSelectAction::addAction(QAction *action) 0231 { 0232 insertAction(nullptr, action); 0233 } 0234 0235 QAction *KSelectAction::addAction(const QString &text) 0236 { 0237 Q_D(KSelectAction); 0238 QAction *newAction = new QAction(parent()); 0239 newAction->setText(text); 0240 newAction->setCheckable(true); 0241 newAction->setProperty("isShortcutConfigurable", false); 0242 0243 if (!d->m_menuAccelsEnabled) { 0244 newAction->setText(text); 0245 newAction->setShortcut(QKeySequence()); 0246 } 0247 0248 addAction(newAction); 0249 return newAction; 0250 } 0251 0252 QAction *KSelectAction::addAction(const QIcon &icon, const QString &text) 0253 { 0254 QAction *newAction = addAction(text); 0255 newAction->setIcon(icon); 0256 return newAction; 0257 } 0258 0259 QAction *KSelectAction::removeAction(QAction *action) 0260 { 0261 Q_D(KSelectAction); 0262 // qCDebug(KWidgetsAddonsLog) << "KSelectAction::removeAction(" << action << ")"; 0263 // int index = selectableActionGroup()->actions().indexOf(action); 0264 // qCDebug(KWidgetsAddonsLog) << "\tindex=" << index; 0265 0266 // Removes the action from the group and sets its parent to null. 0267 d->m_actionGroup->removeAction(action); 0268 0269 // Disable when no action is in the group 0270 bool hasActions = selectableActionGroup()->actions().isEmpty(); 0271 setEnabled(!hasActions); 0272 0273 for (QToolButton *button : std::as_const(d->m_buttons)) { 0274 button->setEnabled(!hasActions); 0275 button->removeAction(action); 0276 } 0277 0278 for (QComboBox *comboBox : std::as_const(d->m_comboBoxes)) { 0279 comboBox->setEnabled(!hasActions); 0280 comboBox->removeAction(action); 0281 } 0282 0283 menu()->removeAction(action); 0284 0285 return action; 0286 } 0287 0288 void KSelectAction::insertAction(QAction *before, QAction *action) 0289 { 0290 Q_D(KSelectAction); 0291 action->setActionGroup(selectableActionGroup()); 0292 0293 // Re-Enable when an action is added 0294 setEnabled(true); 0295 0296 // Keep in sync with createToolBarWidget() 0297 for (QToolButton *button : std::as_const(d->m_buttons)) { 0298 button->setEnabled(true); 0299 button->insertAction(before, action); 0300 } 0301 0302 for (QComboBox *comboBox : std::as_const(d->m_comboBoxes)) { 0303 comboBox->setEnabled(true); 0304 comboBox->insertAction(before, action); 0305 } 0306 0307 menu()->insertAction(before, action); 0308 } 0309 0310 void KSelectAction::slotActionTriggered(QAction *action) 0311 { 0312 // cache values so we don't need access to members in the action 0313 // after we've done an emit() 0314 const QString text = ::DropAmpersands(action->text()); 0315 const int index = selectableActionGroup()->actions().indexOf(action); 0316 // qCDebug(KWidgetsAddonsLog) << "KSelectAction::slotActionTriggered(" << action << ") text=" << text 0317 // << " index=" << index << " emitting triggered()" << endl; 0318 0319 if (isCheckable()) { // if this is subsidiary of other KSelectAction-derived class 0320 trigger(); // then imitate usual QAction behaviour so that other submenus (and their items) become unchecked 0321 } 0322 0323 Q_EMIT actionTriggered(action); 0324 Q_EMIT indexTriggered(index); 0325 Q_EMIT textTriggered(text); 0326 } 0327 0328 QStringList KSelectAction::items() const 0329 { 0330 Q_D(const KSelectAction); 0331 QStringList ret; 0332 0333 const auto actions = d->m_actionGroup->actions(); 0334 ret.reserve(actions.size()); 0335 for (QAction *action : actions) { 0336 ret << ::DropAmpersands(action->text()); 0337 } 0338 0339 return ret; 0340 } 0341 0342 void KSelectAction::changeItem(int index, const QString &text) 0343 { 0344 Q_D(KSelectAction); 0345 if (index < 0 || index >= actions().count()) { 0346 qCWarning(KWidgetsAddonsLog) << "KSelectAction::changeItem Index out of scope"; 0347 return; 0348 } 0349 0350 actions()[index]->setText(d->makeMenuText(text)); 0351 } 0352 0353 void KSelectAction::setItems(const QStringList &lst) 0354 { 0355 Q_D(KSelectAction); 0356 // qCDebug(KWidgetsAddonsLog) << "KSelectAction::setItems(" << lst << ")"; 0357 0358 clear(); 0359 0360 for (const QString &string : lst) { 0361 if (!string.isEmpty()) { 0362 addAction(string); 0363 } else { 0364 QAction *action = new QAction(this); 0365 action->setSeparator(true); 0366 addAction(action); 0367 } 0368 } 0369 0370 // Disable if empty and not editable 0371 setEnabled(lst.count() > 0 || d->m_edit); 0372 } 0373 0374 int KSelectAction::comboWidth() const 0375 { 0376 Q_D(const KSelectAction); 0377 return d->m_comboWidth; 0378 } 0379 0380 void KSelectAction::clear() 0381 { 0382 Q_D(KSelectAction); 0383 // qCDebug(KWidgetsAddonsLog) << "KSelectAction::clear()"; 0384 0385 // we need to delete the actions later since we may get a call to clear() 0386 // from a method called due to a triggered(...) signal 0387 const QList<QAction *> actions = d->m_actionGroup->actions(); 0388 for (int i = 0; i < actions.count(); ++i) { 0389 // deleteLater() only removes us from the actions() list (among 0390 // other things) on the next entry into the event loop. Until then, 0391 // e.g. action() and setCurrentItem() will be working on items 0392 // that are supposed to have been deleted. So detach the action to 0393 // prevent this from happening. 0394 removeAction(actions[i]); 0395 0396 actions[i]->deleteLater(); 0397 } 0398 } 0399 0400 void KSelectAction::removeAllActions() 0401 { 0402 Q_D(KSelectAction); 0403 while (d->m_actionGroup->actions().count()) { 0404 removeAction(d->m_actionGroup->actions().first()); 0405 } 0406 } 0407 0408 void KSelectAction::setEditable(bool edit) 0409 { 0410 Q_D(KSelectAction); 0411 d->m_edit = edit; 0412 0413 for (QComboBox *comboBox : std::as_const(d->m_comboBoxes)) { 0414 comboBox->setEditable(edit); 0415 } 0416 0417 Q_EMIT changed(); 0418 } 0419 0420 bool KSelectAction::isEditable() const 0421 { 0422 Q_D(const KSelectAction); 0423 return d->m_edit; 0424 } 0425 0426 void KSelectAction::slotToggled(bool checked) 0427 { 0428 // if (checked && selectableActionGroup()->checkedAction()) 0429 if (!checked && currentAction()) { // other's submenu item has been selected 0430 currentAction()->setChecked(false); 0431 } 0432 } 0433 0434 KSelectAction::ToolBarMode KSelectAction::toolBarMode() const 0435 { 0436 Q_D(const KSelectAction); 0437 return d->m_toolBarMode; 0438 } 0439 0440 void KSelectAction::setToolBarMode(ToolBarMode mode) 0441 { 0442 Q_D(KSelectAction); 0443 d->m_toolBarMode = mode; 0444 } 0445 0446 QToolButton::ToolButtonPopupMode KSelectAction::toolButtonPopupMode() const 0447 { 0448 Q_D(const KSelectAction); 0449 return d->m_toolButtonPopupMode; 0450 } 0451 0452 void KSelectAction::setToolButtonPopupMode(QToolButton::ToolButtonPopupMode mode) 0453 { 0454 Q_D(KSelectAction); 0455 d->m_toolButtonPopupMode = mode; 0456 } 0457 0458 void KSelectActionPrivate::comboBoxDeleted(QComboBox *combo) 0459 { 0460 m_comboBoxes.removeAll(combo); 0461 } 0462 0463 void KSelectActionPrivate::comboBoxCurrentIndexChanged(int index) 0464 { 0465 Q_Q(KSelectAction); 0466 // qCDebug(KWidgetsAddonsLog) << "KSelectActionPrivate::comboBoxCurrentIndexChanged(" << index << ")"; 0467 0468 QComboBox *triggeringCombo = qobject_cast<QComboBox *>(q->sender()); 0469 0470 QAction *a = q->action(index); 0471 // qCDebug(KWidgetsAddonsLog) << "\ta=" << a; 0472 if (a) { 0473 // qCDebug(KWidgetsAddonsLog) << "\t\tsetting as current action"; 0474 a->trigger(); 0475 0476 } else if (q->isEditable() && triggeringCombo && triggeringCombo->count() > 0 && index == triggeringCombo->count() - 1) { 0477 // User must have added a new item by typing and pressing enter. 0478 const QString newItemText = triggeringCombo->currentText(); 0479 // qCDebug(KWidgetsAddonsLog) << "\t\tuser typed new item '" << newItemText << "'"; 0480 0481 // Only 1 combobox contains this and it's not a proper action. 0482 bool blocked = triggeringCombo->blockSignals(true); 0483 triggeringCombo->removeItem(index); 0484 triggeringCombo->blockSignals(blocked); 0485 0486 QAction *newAction = q->addAction(newItemText); 0487 0488 newAction->trigger(); 0489 } else { 0490 if (q->selectableActionGroup()->checkedAction()) { 0491 q->selectableActionGroup()->checkedAction()->setChecked(false); 0492 } 0493 } 0494 } 0495 0496 // TODO: DropAmpersands() certainly makes sure this doesn't work. But I don't 0497 // think it did anyway esp. in the presence KCheckAccelerator - Clarence. 0498 void KSelectAction::setMenuAccelsEnabled(bool b) 0499 { 0500 Q_D(KSelectAction); 0501 d->m_menuAccelsEnabled = b; 0502 } 0503 0504 bool KSelectAction::menuAccelsEnabled() const 0505 { 0506 Q_D(const KSelectAction); 0507 return d->m_menuAccelsEnabled; 0508 } 0509 0510 QWidget *KSelectAction::createWidget(QWidget *parent) 0511 { 0512 Q_D(KSelectAction); 0513 QMenu *menu = qobject_cast<QMenu *>(parent); 0514 if (menu) { // If used in a menu want to return 0 and use only the text, not a widget 0515 return nullptr; 0516 } 0517 ToolBarMode mode = toolBarMode(); 0518 QToolBar *toolBar = qobject_cast<QToolBar *>(parent); 0519 if (!toolBar && mode != ComboBoxMode) { // we can return a combobox just fine. 0520 return nullptr; 0521 } 0522 switch (mode) { 0523 case MenuMode: { 0524 QToolButton *button = new QToolButton(toolBar); 0525 button->setToolTip(toolTip()); 0526 button->setWhatsThis(whatsThis()); 0527 button->setStatusTip(statusTip()); 0528 button->setAutoRaise(true); 0529 button->setFocusPolicy(Qt::NoFocus); 0530 button->setIconSize(toolBar->iconSize()); 0531 button->setToolButtonStyle(toolBar->toolButtonStyle()); 0532 QObject::connect(toolBar, &QToolBar::iconSizeChanged, button, &QAbstractButton::setIconSize); 0533 QObject::connect(toolBar, &QToolBar::toolButtonStyleChanged, button, &QToolButton::setToolButtonStyle); 0534 button->setDefaultAction(this); 0535 QObject::connect(button, &QToolButton::triggered, toolBar, &QToolBar::actionTriggered); 0536 0537 button->setPopupMode(toolButtonPopupMode()); 0538 0539 button->addActions(selectableActionGroup()->actions()); 0540 0541 d->m_buttons.append(button); 0542 return button; 0543 } 0544 0545 case ComboBoxMode: { 0546 QComboBox *comboBox = new QComboBox(parent); 0547 comboBox->installEventFilter(this); 0548 0549 if (d->m_maxComboViewCount != -1) { 0550 comboBox->setMaxVisibleItems(d->m_maxComboViewCount); 0551 } 0552 0553 if (d->m_comboWidth > 0) { 0554 comboBox->setMaximumWidth(d->m_comboWidth); 0555 } 0556 0557 comboBox->setEditable(isEditable()); 0558 comboBox->setToolTip(toolTip()); 0559 comboBox->setWhatsThis(whatsThis()); 0560 comboBox->setStatusTip(statusTip()); 0561 0562 const auto selectableActions = selectableActionGroup()->actions(); 0563 for (QAction *action : selectableActions) { 0564 comboBox->addAction(action); 0565 } 0566 0567 if (selectableActions.isEmpty()) { 0568 comboBox->setEnabled(false); 0569 } 0570 0571 connect(comboBox, &QComboBox::destroyed, this, [d, comboBox]() { 0572 d->comboBoxDeleted(comboBox); 0573 }); 0574 0575 connect(comboBox, &QComboBox::currentIndexChanged, this, [d](int value) { 0576 d->comboBoxCurrentIndexChanged(value); 0577 }); 0578 0579 d->m_comboBoxes.append(comboBox); 0580 0581 return comboBox; 0582 } 0583 } 0584 0585 return nullptr; 0586 } 0587 0588 void KSelectAction::deleteWidget(QWidget *widget) 0589 { 0590 Q_D(KSelectAction); 0591 if (QToolButton *toolButton = qobject_cast<QToolButton *>(widget)) { 0592 d->m_buttons.removeAll(toolButton); 0593 } else if (QComboBox *comboBox = qobject_cast<QComboBox *>(widget)) { 0594 d->m_comboBoxes.removeAll(comboBox); 0595 } 0596 QWidgetAction::deleteWidget(widget); 0597 } 0598 0599 bool KSelectAction::event(QEvent *event) 0600 { 0601 Q_D(KSelectAction); 0602 if (event->type() == QEvent::ActionChanged) { 0603 for (QComboBox *comboBox : std::as_const(d->m_comboBoxes)) { 0604 comboBox->setToolTip(toolTip()); 0605 comboBox->setWhatsThis(whatsThis()); 0606 comboBox->setStatusTip(statusTip()); 0607 } 0608 for (QToolButton *toolButton : std::as_const(d->m_buttons)) { 0609 toolButton->setToolTip(toolTip()); 0610 toolButton->setWhatsThis(whatsThis()); 0611 toolButton->setStatusTip(statusTip()); 0612 } 0613 } 0614 return QWidgetAction::event(event); 0615 } 0616 0617 // KSelectAction::eventFilter() is called before action->setChecked() 0618 // invokes the signal to update QActionGroup so KSelectAction::currentItem() 0619 // returns an old value. There are 3 possibilities, where n actions will 0620 // report QAction::isChecked() where n is: 0621 // 0622 // 0: the checked action was unchecked 0623 // 1: the checked action did not change 0624 // 2: another action was checked but QActionGroup has not been invoked yet 0625 // to uncheck the one that was checked before 0626 // 0627 // TODO: we might want to cache this since QEvent::ActionChanged is fired 0628 // often. 0629 static int TrueCurrentItem(KSelectAction *sa) 0630 { 0631 QAction *curAction = sa->currentAction(); 0632 // qCDebug(KWidgetsAddonsLog) << "\tTrueCurrentItem(" << sa << ") curAction=" << curAction; 0633 0634 const auto actions = sa->actions(); 0635 int i = 0; 0636 for (QAction *action : actions) { 0637 if (action->isChecked()) { 0638 // qCDebug(KWidgetsAddonsLog) << "\t\taction " << action << " (text=" << action->text () << ") isChecked"; 0639 0640 // 2 actions checked case? 0641 if (action != curAction) { 0642 // qCDebug(KWidgetsAddonsLog) << "\t\t\tmust be newly selected one"; 0643 return i; 0644 } 0645 } 0646 ++i; 0647 } 0648 0649 // qCDebug(KWidgetsAddonsLog) << "\t\tcurrent action still selected? " << (curAction && curAction->isChecked ()); 0650 // 1 or 0 actions checked case (in that order)? 0651 return (curAction && curAction->isChecked()) ? sa->actions().indexOf(curAction) : -1; 0652 } 0653 0654 bool KSelectAction::eventFilter(QObject *watched, QEvent *event) 0655 { 0656 QComboBox *comboBox = qobject_cast<QComboBox *>(watched); 0657 if (!comboBox) { 0658 return false /*propagate event*/; 0659 } 0660 0661 // If focus is lost, replace any edited text with the currently selected 0662 // item. 0663 if (event->type() == QEvent::FocusOut) { 0664 QFocusEvent *const e = static_cast<QFocusEvent *>(event); 0665 // qCDebug(KWidgetsAddonsLog) << "KSelectAction::eventFilter(FocusOut)" 0666 // << " comboBox: ptr=" << comboBox 0667 // << " reason=" << e->reason () 0668 // << endl; 0669 0670 if (e->reason() != Qt::ActiveWindowFocusReason // switch window 0671 && e->reason() != Qt::PopupFocusReason // menu 0672 && e->reason() != Qt::OtherFocusReason // inconsistently reproduceable actions... 0673 ) { 0674 // qCDebug(KWidgetsAddonsLog) << "\tkilling text"; 0675 comboBox->setEditText(comboBox->itemText(comboBox->currentIndex())); 0676 } 0677 0678 return false /*propagate event*/; 0679 } 0680 0681 bool blocked = comboBox->blockSignals(true); 0682 0683 if (event->type() == QEvent::ActionAdded) { 0684 QActionEvent *const e = static_cast<QActionEvent *>(event); 0685 0686 const int index = e->before() ? comboBox->findData(QVariant::fromValue(e->before())) : comboBox->count(); 0687 const int newItem = ::TrueCurrentItem(this); 0688 // qCDebug(KWidgetsAddonsLog) << "KSelectAction::eventFilter(ActionAdded)" 0689 // << " comboBox: ptr=" << comboBox 0690 // << " currentItem=" << comboBox->currentIndex () 0691 // << " add index=" << index 0692 // << " action new: e->before=" << e->before () 0693 // << " ptr=" << e->action () 0694 // << " icon=" << e->action ()->icon () 0695 // << " text=" << e->action ()->text () 0696 // << " currentItem=" << newItem 0697 // << endl; 0698 comboBox->insertItem(index, e->action()->icon(), ::DropAmpersands(e->action()->text()), QVariant::fromValue(e->action())); 0699 if (QStandardItemModel *model = qobject_cast<QStandardItemModel *>(comboBox->model())) { 0700 QStandardItem *item = model->item(index); 0701 item->setEnabled(e->action()->isEnabled()); 0702 } 0703 0704 // Inserting an item into a combobox can change the current item so 0705 // make sure the item corresponding to the checked action is selected. 0706 comboBox->setCurrentIndex(newItem); 0707 } else if (event->type() == QEvent::ActionChanged) { 0708 QActionEvent *const e = static_cast<QActionEvent *>(event); 0709 0710 const int index = comboBox->findData(QVariant::fromValue(e->action())); 0711 const int newItem = ::TrueCurrentItem(this); 0712 // qCDebug(KWidgetsAddonsLog) << "KSelectAction::eventFilter(ActionChanged)" 0713 // << " comboBox: ptr=" << comboBox 0714 // << " currentItem=" << comboBox->currentIndex () 0715 // << " changed action's index=" << index 0716 // << " action new: ptr=" << e->action () 0717 // << " icon=" << e->action ()->icon () 0718 // << " text=" << e->action ()->text () 0719 // << " currentItem=" << newItem 0720 // << endl; 0721 comboBox->setItemIcon(index, e->action()->icon()); 0722 comboBox->setItemText(index, ::DropAmpersands(e->action()->text())); 0723 if (QStandardItemModel *model = qobject_cast<QStandardItemModel *>(comboBox->model())) { 0724 QStandardItem *item = model->item(index); 0725 item->setEnabled(e->action()->isEnabled()); 0726 } 0727 0728 // The checked action may have become unchecked so 0729 // make sure the item corresponding to the checked action is selected. 0730 comboBox->setCurrentIndex(newItem); 0731 } else if (event->type() == QEvent::ActionRemoved) { 0732 QActionEvent *const e = static_cast<QActionEvent *>(event); 0733 0734 const int index = comboBox->findData(QVariant::fromValue(e->action())); 0735 const int newItem = ::TrueCurrentItem(this); 0736 // qCDebug(KWidgetsAddonsLog) << "KSelectAction::eventFilter(ActionRemoved)" 0737 // << " comboBox: ptr=" << comboBox 0738 // << " currentItem=" << comboBox->currentIndex () 0739 // << " delete action index=" << index 0740 // << " new: currentItem=" << newItem 0741 // << endl; 0742 comboBox->removeItem(index); 0743 0744 // Removing an item from a combobox can change the current item so 0745 // make sure the item corresponding to the checked action is selected. 0746 comboBox->setCurrentIndex(newItem); 0747 } 0748 0749 comboBox->blockSignals(blocked); 0750 0751 return false /*propagate event*/; 0752 } 0753 0754 // END 0755 0756 #include "moc_kselectaction.cpp"