1/*
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: 1999 Reginald Stadlbauer <reggie@kde.org>
4 SPDX-FileCopyrightText: 1999 Simon Hausmann <hausmann@kde.org>
5 SPDX-FileCopyrightText: 2000 Nicolas Hadacek <haadcek@kde.org>
6 SPDX-FileCopyrightText: 2000 Kurt Granroth <granroth@kde.org>
7 SPDX-FileCopyrightText: 2000 Michael Koch <koch@kde.org>
8 SPDX-FileCopyrightText: 2001 Holger Freyther <freyther@kde.org>
9 SPDX-FileCopyrightText: 2002 Ellis Whitehead <ellis@kde.org>
10 SPDX-FileCopyrightText: 2002 Joseph Wenninger <jowenn@kde.org>
11 SPDX-FileCopyrightText: 2003 Andras Mantia <amantia@kde.org>
12 SPDX-FileCopyrightText: 2005-2006 Hamish Rodda <rodda@kde.org>
13 SPDX-FileCopyrightText: 2006 Albert Astals Cid <aacid@kde.org>
14 SPDX-FileCopyrightText: 2006 Clarence Dang <dang@kde.org>
15 SPDX-FileCopyrightText: 2006 Michel Hermier <michel.hermier@gmail.com>
16 SPDX-FileCopyrightText: 2007 Nick Shaforostoff <shafff@ukr.net>
17
18 SPDX-License-Identifier: LGPL-2.0-only
19*/
20
21#include "kselectaction.h"
22#include "kselectaction_p.h"
23
24#include "loggingcategory.h"
25
26#include <QActionEvent>
27#include <QEvent>
28#include <QMenu>
29#include <QStandardItem>
30#include <QToolBar>
31
32// QAction::setText("Hi") and then KPopupAccelManager exec'ing, causes
33// QAction::text() to return "&Hi" :( Comboboxes don't have accels and
34// display ampersands literally.
35static QString DropAmpersands(const QString &text)
36{
37 QString label = text;
38
39 int p = label.indexOf(c: QLatin1Char('&'));
40 while (p >= 0 && p < label.length() - 1) {
41 if (label[p + 1].isLetterOrNumber() // Valid accelerator.
42 || label[p + 1] == QLatin1Char('&')) { // Escaped accelerator marker.
43 label.remove(i: p, len: 1);
44 }
45
46 p = label.indexOf(c: QLatin1Char('&'), from: p + 1);
47 }
48
49 return label;
50}
51
52KSelectAction::KSelectAction(QObject *parent)
53 : KSelectAction(*new KSelectActionPrivate(this), parent)
54{
55}
56
57KSelectAction::KSelectAction(const QString &text, QObject *parent)
58 : KSelectAction(*new KSelectActionPrivate(this), parent)
59{
60 setText(text);
61}
62
63KSelectAction::KSelectAction(const QIcon &icon, const QString &text, QObject *parent)
64 : KSelectAction(*new KSelectActionPrivate(this), parent)
65{
66 setIcon(icon);
67 setText(text);
68}
69
70KSelectAction::KSelectAction(KSelectActionPrivate &dd, QObject *parent)
71 : QWidgetAction(parent)
72 , d_ptr(&dd)
73{
74 Q_D(KSelectAction);
75 d->init();
76}
77
78KSelectAction::~KSelectAction()
79{
80 menu()->deleteLater();
81}
82
83void KSelectActionPrivate::init()
84{
85 QObject::connect(sender: q_ptr->selectableActionGroup(), signal: &QActionGroup::triggered, context: q_ptr, slot: &KSelectAction::slotActionTriggered);
86 QObject::connect(sender: q_ptr, signal: &QAction::toggled, context: q_ptr, slot: &KSelectAction::slotToggled);
87 q_ptr->setMenu(new QMenu());
88 q_ptr->setEnabled(false);
89}
90
91QActionGroup *KSelectAction::selectableActionGroup() const
92{
93 Q_D(const KSelectAction);
94 return d->m_actionGroup;
95}
96
97QList<QAction *> KSelectAction::actions() const
98{
99 return selectableActionGroup()->actions();
100}
101
102QAction *KSelectAction::currentAction() const
103{
104 return selectableActionGroup()->checkedAction();
105}
106
107int KSelectAction::currentItem() const
108{
109 return selectableActionGroup()->actions().indexOf(t: currentAction());
110}
111
112QString KSelectAction::currentText() const
113{
114 if (QAction *a = currentAction()) {
115 return ::DropAmpersands(text: a->text());
116 }
117
118 return QString();
119}
120
121bool KSelectAction::setCurrentAction(QAction *action)
122{
123 // qCDebug(KWidgetsAddonsLog) << "KSelectAction::setCurrentAction(" << action << ")";
124 if (action) {
125 if (actions().contains(t: action)) {
126 if (action->isVisible() && action->isEnabled() && action->isCheckable()) {
127 action->setChecked(true);
128 if (isCheckable()) {
129 setChecked(true);
130 }
131 return true;
132 } else {
133 qCWarning(KWidgetsAddonsLog) << "Action does not have the correct properties to be current:" << action->text();
134 }
135 } else {
136 qCWarning(KWidgetsAddonsLog) << "Action does not belong to group:" << action->text();
137 }
138 return false;
139 }
140
141 if (currentAction()) {
142 currentAction()->setChecked(false);
143 }
144
145 return false;
146}
147
148bool KSelectAction::setCurrentItem(int index)
149{
150 // qCDebug(KWidgetsAddonsLog) << "KSelectAction::setCurrentIndex(" << index << ")";
151 return setCurrentAction(action(index));
152}
153
154QAction *KSelectAction::action(int index) const
155{
156 if (index >= 0 && index < selectableActionGroup()->actions().count()) {
157 return selectableActionGroup()->actions().at(i: index);
158 }
159
160 return nullptr;
161}
162
163QAction *KSelectAction::action(const QString &text, Qt::CaseSensitivity cs) const
164{
165 QString compare;
166 if (cs == Qt::CaseSensitive) {
167 compare = text;
168 } else {
169 compare = text.toLower();
170 }
171
172 const auto selectableActions = selectableActionGroup()->actions();
173 for (QAction *action : selectableActions) {
174 const QString text = ::DropAmpersands(text: action->text());
175 if (cs == Qt::CaseSensitive) {
176 if (text == compare) {
177 return action;
178 }
179
180 } else if (cs == Qt::CaseInsensitive) {
181 if (text.toLower() == compare) {
182 return action;
183 }
184 }
185 }
186
187 return nullptr;
188}
189
190bool KSelectAction::setCurrentAction(const QString &text, Qt::CaseSensitivity cs)
191{
192 // qCDebug(KWidgetsAddonsLog) << "KSelectAction::setCurrentAction(" << text << ",cs=" << cs << ")";
193 return setCurrentAction(action(text, cs));
194}
195
196void KSelectAction::setComboWidth(int width)
197{
198 Q_D(KSelectAction);
199 if (width < 0) {
200 return;
201 }
202
203 d->m_comboWidth = width;
204
205 for (QComboBox *box : std::as_const(t&: d->m_comboBoxes)) {
206 box->setMaximumWidth(d->m_comboWidth);
207 }
208
209 Q_EMIT changed();
210}
211
212void KSelectAction::setMaxComboViewCount(int n)
213{
214 Q_D(KSelectAction);
215 d->m_maxComboViewCount = n;
216
217 for (QComboBox *box : std::as_const(t&: d->m_comboBoxes)) {
218 if (d->m_maxComboViewCount != -1) {
219 box->setMaxVisibleItems(d->m_maxComboViewCount);
220 } else
221 // hardcoded qt default
222 {
223 box->setMaxVisibleItems(10);
224 }
225 }
226
227 Q_EMIT changed();
228}
229
230void KSelectAction::addAction(QAction *action)
231{
232 insertAction(before: nullptr, action);
233}
234
235QAction *KSelectAction::addAction(const QString &text)
236{
237 Q_D(KSelectAction);
238 QAction *newAction = new QAction(parent());
239 newAction->setText(text);
240 newAction->setCheckable(true);
241 newAction->setProperty(name: "isShortcutConfigurable", value: false);
242
243 if (!d->m_menuAccelsEnabled) {
244 newAction->setText(text);
245 newAction->setShortcut(QKeySequence());
246 }
247
248 addAction(action: newAction);
249 return newAction;
250}
251
252QAction *KSelectAction::addAction(const QIcon &icon, const QString &text)
253{
254 QAction *newAction = addAction(text);
255 newAction->setIcon(icon);
256 return newAction;
257}
258
259QAction *KSelectAction::removeAction(QAction *action)
260{
261 Q_D(KSelectAction);
262 // qCDebug(KWidgetsAddonsLog) << "KSelectAction::removeAction(" << action << ")";
263 // int index = selectableActionGroup()->actions().indexOf(action);
264 // qCDebug(KWidgetsAddonsLog) << "\tindex=" << index;
265
266 // Removes the action from the group and sets its parent to null.
267 d->m_actionGroup->removeAction(a: action);
268
269 // Disable when no action is in the group
270 bool hasActions = selectableActionGroup()->actions().isEmpty();
271 setEnabled(!hasActions);
272
273 for (QToolButton *button : std::as_const(t&: d->m_buttons)) {
274 button->setEnabled(!hasActions);
275 button->removeAction(action);
276 }
277
278 for (QComboBox *comboBox : std::as_const(t&: d->m_comboBoxes)) {
279 comboBox->setEnabled(!hasActions);
280 comboBox->removeAction(action);
281 }
282
283 menu()->removeAction(action);
284
285 return action;
286}
287
288void KSelectAction::insertAction(QAction *before, QAction *action)
289{
290 Q_D(KSelectAction);
291 action->setActionGroup(selectableActionGroup());
292
293 // Re-Enable when an action is added
294 setEnabled(true);
295
296 // Keep in sync with createToolBarWidget()
297 for (QToolButton *button : std::as_const(t&: d->m_buttons)) {
298 button->setEnabled(true);
299 button->insertAction(before, action);
300 }
301
302 for (QComboBox *comboBox : std::as_const(t&: d->m_comboBoxes)) {
303 comboBox->setEnabled(true);
304 comboBox->insertAction(before, action);
305 }
306
307 menu()->insertAction(before, action);
308}
309
310void KSelectAction::slotActionTriggered(QAction *action)
311{
312 // cache values so we don't need access to members in the action
313 // after we've done an emit()
314 const QString text = ::DropAmpersands(text: action->text());
315 const int index = selectableActionGroup()->actions().indexOf(t: action);
316 // qCDebug(KWidgetsAddonsLog) << "KSelectAction::slotActionTriggered(" << action << ") text=" << text
317 // << " index=" << index << " emitting triggered()" << endl;
318
319 if (isCheckable()) { // if this is subsidiary of other KSelectAction-derived class
320 trigger(); // then imitate usual QAction behaviour so that other submenus (and their items) become unchecked
321 }
322
323 Q_EMIT actionTriggered(action);
324 Q_EMIT indexTriggered(index);
325 Q_EMIT textTriggered(text);
326}
327
328QStringList KSelectAction::items() const
329{
330 Q_D(const KSelectAction);
331 QStringList ret;
332
333 const auto actions = d->m_actionGroup->actions();
334 ret.reserve(asize: actions.size());
335 for (QAction *action : actions) {
336 ret << ::DropAmpersands(text: action->text());
337 }
338
339 return ret;
340}
341
342void KSelectAction::changeItem(int index, const QString &text)
343{
344 Q_D(KSelectAction);
345 if (index < 0 || index >= actions().count()) {
346 qCWarning(KWidgetsAddonsLog) << "KSelectAction::changeItem Index out of scope";
347 return;
348 }
349
350 actions()[index]->setText(d->makeMenuText(text: text));
351}
352
353void KSelectAction::setItems(const QStringList &lst)
354{
355 Q_D(KSelectAction);
356 // qCDebug(KWidgetsAddonsLog) << "KSelectAction::setItems(" << lst << ")";
357
358 clear();
359
360 for (const QString &string : lst) {
361 if (!string.isEmpty()) {
362 addAction(text: string);
363 } else {
364 QAction *action = new QAction(this);
365 action->setSeparator(true);
366 addAction(action);
367 }
368 }
369
370 // Disable if empty and not editable
371 setEnabled(lst.count() > 0 || d->m_edit);
372}
373
374int KSelectAction::comboWidth() const
375{
376 Q_D(const KSelectAction);
377 return d->m_comboWidth;
378}
379
380void KSelectAction::clear()
381{
382 Q_D(KSelectAction);
383 // qCDebug(KWidgetsAddonsLog) << "KSelectAction::clear()";
384
385 // we need to delete the actions later since we may get a call to clear()
386 // from a method called due to a triggered(...) signal
387 const QList<QAction *> actions = d->m_actionGroup->actions();
388 for (int i = 0; i < actions.count(); ++i) {
389 // deleteLater() only removes us from the actions() list (among
390 // other things) on the next entry into the event loop. Until then,
391 // e.g. action() and setCurrentItem() will be working on items
392 // that are supposed to have been deleted. So detach the action to
393 // prevent this from happening.
394 removeAction(action: actions[i]);
395
396 actions[i]->deleteLater();
397 }
398}
399
400void KSelectAction::removeAllActions()
401{
402 Q_D(KSelectAction);
403 while (d->m_actionGroup->actions().count()) {
404 removeAction(action: d->m_actionGroup->actions().first());
405 }
406}
407
408void KSelectAction::setEditable(bool edit)
409{
410 Q_D(KSelectAction);
411 d->m_edit = edit;
412
413 for (QComboBox *comboBox : std::as_const(t&: d->m_comboBoxes)) {
414 comboBox->setEditable(edit);
415 }
416
417 Q_EMIT changed();
418}
419
420bool KSelectAction::isEditable() const
421{
422 Q_D(const KSelectAction);
423 return d->m_edit;
424}
425
426void KSelectAction::slotToggled(bool checked)
427{
428 // if (checked && selectableActionGroup()->checkedAction())
429 if (!checked && currentAction()) { // other's submenu item has been selected
430 currentAction()->setChecked(false);
431 }
432}
433
434KSelectAction::ToolBarMode KSelectAction::toolBarMode() const
435{
436 Q_D(const KSelectAction);
437 return d->m_toolBarMode;
438}
439
440void KSelectAction::setToolBarMode(ToolBarMode mode)
441{
442 Q_D(KSelectAction);
443 d->m_toolBarMode = mode;
444}
445
446QToolButton::ToolButtonPopupMode KSelectAction::toolButtonPopupMode() const
447{
448 Q_D(const KSelectAction);
449 return d->m_toolButtonPopupMode;
450}
451
452void KSelectAction::setToolButtonPopupMode(QToolButton::ToolButtonPopupMode mode)
453{
454 Q_D(KSelectAction);
455 d->m_toolButtonPopupMode = mode;
456}
457
458void KSelectActionPrivate::comboBoxDeleted(QComboBox *combo)
459{
460 m_comboBoxes.removeAll(t: combo);
461}
462
463void KSelectActionPrivate::comboBoxCurrentIndexChanged(int index)
464{
465 Q_Q(KSelectAction);
466 // qCDebug(KWidgetsAddonsLog) << "KSelectActionPrivate::comboBoxCurrentIndexChanged(" << index << ")";
467
468 QComboBox *triggeringCombo = qobject_cast<QComboBox *>(object: q->sender());
469
470 QAction *a = q->action(index);
471 // qCDebug(KWidgetsAddonsLog) << "\ta=" << a;
472 if (a) {
473 // qCDebug(KWidgetsAddonsLog) << "\t\tsetting as current action";
474 a->trigger();
475
476 } else if (q->isEditable() && triggeringCombo && triggeringCombo->count() > 0 && index == triggeringCombo->count() - 1) {
477 // User must have added a new item by typing and pressing enter.
478 const QString newItemText = triggeringCombo->currentText();
479 // qCDebug(KWidgetsAddonsLog) << "\t\tuser typed new item '" << newItemText << "'";
480
481 // Only 1 combobox contains this and it's not a proper action.
482 bool blocked = triggeringCombo->blockSignals(b: true);
483 triggeringCombo->removeItem(index);
484 triggeringCombo->blockSignals(b: blocked);
485
486 QAction *newAction = q->addAction(text: newItemText);
487
488 newAction->trigger();
489 } else {
490 if (q->selectableActionGroup()->checkedAction()) {
491 q->selectableActionGroup()->checkedAction()->setChecked(false);
492 }
493 }
494}
495
496// TODO: DropAmpersands() certainly makes sure this doesn't work. But I don't
497// think it did anyway esp. in the presence KCheckAccelerator - Clarence.
498void KSelectAction::setMenuAccelsEnabled(bool b)
499{
500 Q_D(KSelectAction);
501 d->m_menuAccelsEnabled = b;
502}
503
504bool KSelectAction::menuAccelsEnabled() const
505{
506 Q_D(const KSelectAction);
507 return d->m_menuAccelsEnabled;
508}
509
510QWidget *KSelectAction::createWidget(QWidget *parent)
511{
512 Q_D(KSelectAction);
513 QMenu *menu = qobject_cast<QMenu *>(object: parent);
514 if (menu) { // If used in a menu want to return 0 and use only the text, not a widget
515 return nullptr;
516 }
517 ToolBarMode mode = toolBarMode();
518 QToolBar *toolBar = qobject_cast<QToolBar *>(object: parent);
519 if (!toolBar && mode != ComboBoxMode) { // we can return a combobox just fine.
520 return nullptr;
521 }
522 switch (mode) {
523 case MenuMode: {
524 QToolButton *button = new QToolButton(toolBar);
525 button->setToolTip(toolTip());
526 button->setWhatsThis(whatsThis());
527 button->setStatusTip(statusTip());
528 button->setAutoRaise(true);
529 button->setFocusPolicy(Qt::NoFocus);
530 button->setIconSize(toolBar->iconSize());
531 button->setToolButtonStyle(toolBar->toolButtonStyle());
532 QObject::connect(sender: toolBar, signal: &QToolBar::iconSizeChanged, context: button, slot: &QAbstractButton::setIconSize);
533 QObject::connect(sender: toolBar, signal: &QToolBar::toolButtonStyleChanged, context: button, slot: &QToolButton::setToolButtonStyle);
534 button->setDefaultAction(this);
535 QObject::connect(sender: button, signal: &QToolButton::triggered, context: toolBar, slot: &QToolBar::actionTriggered);
536
537 button->setPopupMode(toolButtonPopupMode());
538
539 button->addActions(actions: selectableActionGroup()->actions());
540
541 d->m_buttons.append(t: button);
542 return button;
543 }
544
545 case ComboBoxMode: {
546 QComboBox *comboBox = new QComboBox(parent);
547 comboBox->installEventFilter(filterObj: this);
548
549 if (d->m_maxComboViewCount != -1) {
550 comboBox->setMaxVisibleItems(d->m_maxComboViewCount);
551 }
552
553 if (d->m_comboWidth > 0) {
554 comboBox->setMaximumWidth(d->m_comboWidth);
555 }
556
557 comboBox->setEditable(isEditable());
558 comboBox->setToolTip(toolTip());
559 comboBox->setWhatsThis(whatsThis());
560 comboBox->setStatusTip(statusTip());
561
562 const auto selectableActions = selectableActionGroup()->actions();
563 for (QAction *action : selectableActions) {
564 comboBox->addAction(action);
565 }
566
567 if (selectableActions.isEmpty()) {
568 comboBox->setEnabled(false);
569 }
570
571 connect(sender: comboBox, signal: &QComboBox::destroyed, context: this, slot: [d, comboBox]() {
572 d->comboBoxDeleted(combo: comboBox);
573 });
574
575 connect(sender: comboBox, signal: &QComboBox::currentIndexChanged, context: this, slot: [d](int value) {
576 d->comboBoxCurrentIndexChanged(index: value);
577 });
578
579 d->m_comboBoxes.append(t: comboBox);
580
581 return comboBox;
582 }
583 }
584
585 return nullptr;
586}
587
588void KSelectAction::deleteWidget(QWidget *widget)
589{
590 Q_D(KSelectAction);
591 if (QToolButton *toolButton = qobject_cast<QToolButton *>(object: widget)) {
592 d->m_buttons.removeAll(t: toolButton);
593 } else if (QComboBox *comboBox = qobject_cast<QComboBox *>(object: widget)) {
594 d->m_comboBoxes.removeAll(t: comboBox);
595 }
596 QWidgetAction::deleteWidget(widget);
597}
598
599bool KSelectAction::event(QEvent *event)
600{
601 Q_D(KSelectAction);
602 if (event->type() == QEvent::ActionChanged) {
603 for (QComboBox *comboBox : std::as_const(t&: d->m_comboBoxes)) {
604 comboBox->setToolTip(toolTip());
605 comboBox->setWhatsThis(whatsThis());
606 comboBox->setStatusTip(statusTip());
607 }
608 for (QToolButton *toolButton : std::as_const(t&: d->m_buttons)) {
609 toolButton->setToolTip(toolTip());
610 toolButton->setWhatsThis(whatsThis());
611 toolButton->setStatusTip(statusTip());
612 }
613 }
614 return QWidgetAction::event(event);
615}
616
617// KSelectAction::eventFilter() is called before action->setChecked()
618// invokes the signal to update QActionGroup so KSelectAction::currentItem()
619// returns an old value. There are 3 possibilities, where n actions will
620// report QAction::isChecked() where n is:
621//
622// 0: the checked action was unchecked
623// 1: the checked action did not change
624// 2: another action was checked but QActionGroup has not been invoked yet
625// to uncheck the one that was checked before
626//
627// TODO: we might want to cache this since QEvent::ActionChanged is fired
628// often.
629static int TrueCurrentItem(KSelectAction *sa)
630{
631 QAction *curAction = sa->currentAction();
632 // qCDebug(KWidgetsAddonsLog) << "\tTrueCurrentItem(" << sa << ") curAction=" << curAction;
633
634 const auto actions = sa->actions();
635 int i = 0;
636 for (QAction *action : actions) {
637 if (action->isChecked()) {
638 // qCDebug(KWidgetsAddonsLog) << "\t\taction " << action << " (text=" << action->text () << ") isChecked";
639
640 // 2 actions checked case?
641 if (action != curAction) {
642 // qCDebug(KWidgetsAddonsLog) << "\t\t\tmust be newly selected one";
643 return i;
644 }
645 }
646 ++i;
647 }
648
649 // qCDebug(KWidgetsAddonsLog) << "\t\tcurrent action still selected? " << (curAction && curAction->isChecked ());
650 // 1 or 0 actions checked case (in that order)?
651 return (curAction && curAction->isChecked()) ? sa->actions().indexOf(t: curAction) : -1;
652}
653
654bool KSelectAction::eventFilter(QObject *watched, QEvent *event)
655{
656 QComboBox *comboBox = qobject_cast<QComboBox *>(object: watched);
657 if (!comboBox) {
658 return false /*propagate event*/;
659 }
660
661 // If focus is lost, replace any edited text with the currently selected
662 // item.
663 if (event->type() == QEvent::FocusOut) {
664 QFocusEvent *const e = static_cast<QFocusEvent *>(event);
665 // qCDebug(KWidgetsAddonsLog) << "KSelectAction::eventFilter(FocusOut)"
666 // << " comboBox: ptr=" << comboBox
667 // << " reason=" << e->reason ()
668 // << endl;
669
670 if (e->reason() != Qt::ActiveWindowFocusReason // switch window
671 && e->reason() != Qt::PopupFocusReason // menu
672 && e->reason() != Qt::OtherFocusReason // inconsistently reproduceable actions...
673 ) {
674 // qCDebug(KWidgetsAddonsLog) << "\tkilling text";
675 comboBox->setEditText(comboBox->itemText(index: comboBox->currentIndex()));
676 }
677
678 return false /*propagate event*/;
679 }
680
681 bool blocked = comboBox->blockSignals(b: true);
682
683 if (event->type() == QEvent::ActionAdded) {
684 QActionEvent *const e = static_cast<QActionEvent *>(event);
685
686 const int index = e->before() ? comboBox->findData(data: QVariant::fromValue(value: e->before())) : comboBox->count();
687 const int newItem = ::TrueCurrentItem(sa: this);
688 // qCDebug(KWidgetsAddonsLog) << "KSelectAction::eventFilter(ActionAdded)"
689 // << " comboBox: ptr=" << comboBox
690 // << " currentItem=" << comboBox->currentIndex ()
691 // << " add index=" << index
692 // << " action new: e->before=" << e->before ()
693 // << " ptr=" << e->action ()
694 // << " icon=" << e->action ()->icon ()
695 // << " text=" << e->action ()->text ()
696 // << " currentItem=" << newItem
697 // << endl;
698 comboBox->insertItem(index, icon: e->action()->icon(), text: ::DropAmpersands(text: e->action()->text()), userData: QVariant::fromValue(value: e->action()));
699 if (QStandardItemModel *model = qobject_cast<QStandardItemModel *>(object: comboBox->model())) {
700 QStandardItem *item = model->item(row: index);
701 item->setEnabled(e->action()->isEnabled());
702 }
703
704 // Inserting an item into a combobox can change the current item so
705 // make sure the item corresponding to the checked action is selected.
706 comboBox->setCurrentIndex(newItem);
707 } else if (event->type() == QEvent::ActionChanged) {
708 QActionEvent *const e = static_cast<QActionEvent *>(event);
709
710 const int index = comboBox->findData(data: QVariant::fromValue(value: e->action()));
711 const int newItem = ::TrueCurrentItem(sa: this);
712 // qCDebug(KWidgetsAddonsLog) << "KSelectAction::eventFilter(ActionChanged)"
713 // << " comboBox: ptr=" << comboBox
714 // << " currentItem=" << comboBox->currentIndex ()
715 // << " changed action's index=" << index
716 // << " action new: ptr=" << e->action ()
717 // << " icon=" << e->action ()->icon ()
718 // << " text=" << e->action ()->text ()
719 // << " currentItem=" << newItem
720 // << endl;
721 comboBox->setItemIcon(index, icon: e->action()->icon());
722 comboBox->setItemText(index, text: ::DropAmpersands(text: e->action()->text()));
723 if (QStandardItemModel *model = qobject_cast<QStandardItemModel *>(object: comboBox->model())) {
724 QStandardItem *item = model->item(row: index);
725 item->setEnabled(e->action()->isEnabled());
726 }
727
728 // The checked action may have become unchecked so
729 // make sure the item corresponding to the checked action is selected.
730 comboBox->setCurrentIndex(newItem);
731 } else if (event->type() == QEvent::ActionRemoved) {
732 QActionEvent *const e = static_cast<QActionEvent *>(event);
733
734 const int index = comboBox->findData(data: QVariant::fromValue(value: e->action()));
735 const int newItem = ::TrueCurrentItem(sa: this);
736 // qCDebug(KWidgetsAddonsLog) << "KSelectAction::eventFilter(ActionRemoved)"
737 // << " comboBox: ptr=" << comboBox
738 // << " currentItem=" << comboBox->currentIndex ()
739 // << " delete action index=" << index
740 // << " new: currentItem=" << newItem
741 // << endl;
742 comboBox->removeItem(index);
743
744 // Removing an item from a combobox can change the current item so
745 // make sure the item corresponding to the checked action is selected.
746 comboBox->setCurrentIndex(newItem);
747 }
748
749 comboBox->blockSignals(b: blocked);
750
751 return false /*propagate event*/;
752}
753
754// END
755
756#include "moc_kselectaction.cpp"
757

source code of kwidgetsaddons/src/kselectaction.cpp