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"