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