KWidgetsAddons

kactionselector.cpp
1/*
2 This file is part of the KDE project
3 SPDX-FileCopyrightText: 2002 Anders Lund <anders.lund@lund.tdcadsl.dk>
4
5 SPDX-License-Identifier: LGPL-2.0-only
6*/
7
8#include "kactionselector.h"
9
10#include <QApplication>
11#include <QHBoxLayout>
12#include <QKeyEvent>
13#include <QLabel>
14#include <QListWidget>
15#include <QToolButton>
16#include <QVBoxLayout>
17
18class KActionSelectorPrivate
19{
20public:
21 KActionSelectorPrivate(KActionSelector *qq)
22 : q(qq)
23 {
24 }
25
26 KActionSelector *const q = nullptr;
27 QListWidget *availableListWidget = nullptr;
28 QListWidget *selectedListWidget = nullptr;
29 QToolButton *btnAdd = nullptr;
30 QToolButton *btnRemove = nullptr;
31 QToolButton *btnUp = nullptr;
32 QToolButton *btnDown = nullptr;
33 QLabel *lAvailable = nullptr;
34 QLabel *lSelected = nullptr;
35 bool moveOnDoubleClick : 1;
36 bool keyboardEnabled : 1;
37 bool showUpDownButtons : 1;
38 QString addIcon, removeIcon, upIcon, downIcon;
39 KActionSelector::InsertionPolicy availableInsertionPolicy, selectedInsertionPolicy;
40
41 /**
42 Move item @p item to the other listbox
43 */
44 void moveItem(QListWidgetItem *item);
45
46 /**
47 loads the icons for the move buttons.
48 */
49 void loadIcons();
50
51 /**
52 @return the index to insert an item into listbox @p lb,
53 given InsertionPolicy @p policy.
54
55 Note that if policy is Sorted, this will return -1.
56 Sort the listbox after inserting the item in that case.
57 */
58 int insertionIndex(QListWidget *lb, KActionSelector::InsertionPolicy policy);
59
60 /**
61 @return the index of the first selected item in listbox @p lb.
62 If no item is selected, it will return -1.
63 */
64 int selectedRowIndex(QListWidget *lb);
65
66 void buttonAddClicked();
67 void buttonRemoveClicked();
68 void buttonUpClicked();
69 void buttonDownClicked();
70 void itemDoubleClicked(QListWidgetItem *item);
71 void slotCurrentChanged(QListWidgetItem *)
72 {
73 q->setButtonsEnabled();
74 }
75};
76
77// BEGIN Constructor/destructor
78
79KActionSelector::KActionSelector(QWidget *parent)
80 : QWidget(parent)
81 , d(new KActionSelectorPrivate(this))
82{
83 d->moveOnDoubleClick = true;
84 d->keyboardEnabled = true;
85 d->addIcon = QLatin1String(QApplication::isRightToLeft() ? "go-previous" : "go-next");
86 d->removeIcon = QLatin1String(QApplication::isRightToLeft() ? "go-next" : "go-previous");
87 d->upIcon = QStringLiteral("go-up");
88 d->downIcon = QStringLiteral("go-down");
89 d->availableInsertionPolicy = Sorted;
90 d->selectedInsertionPolicy = BelowCurrent;
91 d->showUpDownButtons = true;
92
93 QHBoxLayout *lo = new QHBoxLayout(this);
94 lo->setContentsMargins(0, 0, 0, 0);
95
96 QVBoxLayout *loAv = new QVBoxLayout();
97 lo->addLayout(loAv);
98 d->lAvailable = new QLabel(tr("&Available:", "@label:listbox"), this);
99 loAv->addWidget(d->lAvailable);
100 d->availableListWidget = new QListWidget(this);
101 loAv->addWidget(d->availableListWidget);
102 d->lAvailable->setBuddy(d->availableListWidget);
103
104 QVBoxLayout *loHBtns = new QVBoxLayout();
105 lo->addLayout(loHBtns);
106 loHBtns->addStretch(1);
107 d->btnAdd = new QToolButton(this);
108 loHBtns->addWidget(d->btnAdd);
109 d->btnRemove = new QToolButton(this);
110 loHBtns->addWidget(d->btnRemove);
111 loHBtns->addStretch(1);
112
113 QVBoxLayout *loS = new QVBoxLayout();
114 lo->addLayout(loS);
115 d->lSelected = new QLabel(tr("&Selected:", "@label:listbox"), this);
116 loS->addWidget(d->lSelected);
117 d->selectedListWidget = new QListWidget(this);
118 loS->addWidget(d->selectedListWidget);
119 d->lSelected->setBuddy(d->selectedListWidget);
120
121 QVBoxLayout *loVBtns = new QVBoxLayout();
122 lo->addLayout(loVBtns);
123 loVBtns->addStretch(1);
124 d->btnUp = new QToolButton(this);
125 d->btnUp->setAutoRepeat(true);
126 loVBtns->addWidget(d->btnUp);
127 d->btnDown = new QToolButton(this);
128 d->btnDown->setAutoRepeat(true);
129 loVBtns->addWidget(d->btnDown);
130 loVBtns->addStretch(1);
131
132 d->loadIcons();
133
134 connect(d->btnAdd, &QToolButton::clicked, this, [this]() {
135 d->buttonAddClicked();
136 });
137 connect(d->btnRemove, &QToolButton::clicked, this, [this]() {
138 d->buttonRemoveClicked();
139 });
140 connect(d->btnUp, &QToolButton::clicked, this, [this]() {
141 d->buttonUpClicked();
142 });
143 connect(d->btnDown, &QToolButton::clicked, this, [this]() {
144 d->buttonDownClicked();
145 });
146 connect(d->availableListWidget, &QListWidget::itemDoubleClicked, this, [this](QListWidgetItem *item) {
147 d->itemDoubleClicked(item);
148 });
149 connect(d->selectedListWidget, &QListWidget::itemDoubleClicked, this, [this](QListWidgetItem *item) {
150 d->itemDoubleClicked(item);
151 });
154
155 d->availableListWidget->installEventFilter(this);
156 d->selectedListWidget->installEventFilter(this);
157 setButtonsEnabled();
158}
159
160KActionSelector::~KActionSelector() = default;
161
162// END Constructor/destroctor
163
164// BEGIN Public Methods
165
167{
168 return d->availableListWidget;
169}
170
172{
173 return d->selectedListWidget;
174}
175
177{
178 switch (button) {
179 case ButtonAdd:
180 d->addIcon = icon;
181 d->btnAdd->setIcon(QIcon::fromTheme(icon));
182 break;
183 case ButtonRemove:
184 d->removeIcon = icon;
185 d->btnRemove->setIcon(QIcon::fromTheme(icon));
186 break;
187 case ButtonUp:
188 d->upIcon = icon;
189 d->btnUp->setIcon(QIcon::fromTheme(icon));
190 break;
191 case ButtonDown:
192 d->downIcon = icon;
193 d->btnDown->setIcon(QIcon::fromTheme(icon));
194 break;
195 default:
196 // qCDebug(KWidgetsAddonsLog)<<"KActionSelector::setButtonIcon: DAINBREAD!";
197 break;
198 }
199}
200
202{
203 switch (button) {
204 case ButtonAdd:
205 d->btnAdd->setIcon(iconset);
206 break;
207 case ButtonRemove:
208 d->btnRemove->setIcon(iconset);
209 break;
210 case ButtonUp:
211 d->btnUp->setIcon(iconset);
212 break;
213 case ButtonDown:
214 d->btnDown->setIcon(iconset);
215 break;
216 default:
217 // qCDebug(KWidgetsAddonsLog)<<"KActionSelector::setButtonIconSet: DAINBREAD!";
218 break;
219 }
220}
221
223{
224 switch (button) {
225 case ButtonAdd:
226 d->btnAdd->setText(tip);
227 d->btnAdd->setToolTip(tip);
228 break;
229 case ButtonRemove:
230 d->btnRemove->setText(tip);
231 d->btnRemove->setToolTip(tip);
232 break;
233 case ButtonUp:
234 d->btnUp->setText(tip);
235 d->btnUp->setToolTip(tip);
236 break;
237 case ButtonDown:
238 d->btnDown->setText(tip);
239 d->btnDown->setToolTip(tip);
240 break;
241 default:
242 // qCDebug(KWidgetsAddonsLog)<<"KActionSelector::setButtonToolTip: DAINBREAD!";
243 break;
244 }
245}
246
248{
249 switch (button) {
250 case ButtonAdd:
251 d->btnAdd->setWhatsThis(text);
252 break;
253 case ButtonRemove:
254 d->btnRemove->setWhatsThis(text);
255 break;
256 case ButtonUp:
257 d->btnUp->setWhatsThis(text);
258 break;
259 case ButtonDown:
260 d->btnDown->setWhatsThis(text);
261 break;
262 default:
263 // qCDebug(KWidgetsAddonsLog)<<"KActionSelector::setButtonWhatsThis: DAINBREAD!";
264 break;
265 }
266}
267
268// END Public Methods
269
270// BEGIN Properties
271
272bool KActionSelector::moveOnDoubleClick() const
273{
274 return d->moveOnDoubleClick;
275}
276
278{
279 d->moveOnDoubleClick = b;
280}
281
282bool KActionSelector::keyboardEnabled() const
283{
284 return d->keyboardEnabled;
285}
286
288{
289 d->keyboardEnabled = b;
290}
291
292QString KActionSelector::availableLabel() const
293{
294 return d->lAvailable->text();
295}
296
298{
299 d->lAvailable->setText(text);
300}
301
302QString KActionSelector::selectedLabel() const
303{
304 return d->lSelected->text();
305}
306
308{
309 d->lSelected->setText(text);
310}
311
312KActionSelector::InsertionPolicy KActionSelector::availableInsertionPolicy() const
313{
314 return d->availableInsertionPolicy;
315}
316
318{
319 d->availableInsertionPolicy = p;
320}
321
322KActionSelector::InsertionPolicy KActionSelector::selectedInsertionPolicy() const
323{
324 return d->selectedInsertionPolicy;
325}
326
328{
329 d->selectedInsertionPolicy = p;
330}
331
332bool KActionSelector::showUpDownButtons() const
333{
334 return d->showUpDownButtons;
335}
336
338{
339 d->showUpDownButtons = show;
340 if (show) {
341 d->btnUp->show();
342 d->btnDown->show();
343 } else {
344 d->btnUp->hide();
345 d->btnDown->hide();
346 }
347}
348
349// END Properties
350
351// BEGIN Public Slots
352
354{
355 d->btnAdd->setEnabled(d->selectedRowIndex(d->availableListWidget) > -1);
356 d->btnRemove->setEnabled(d->selectedRowIndex(d->selectedListWidget) > -1);
357 d->btnUp->setEnabled(d->selectedRowIndex(d->selectedListWidget) > 0);
358 d->btnDown->setEnabled(d->selectedRowIndex(d->selectedListWidget) > -1 //
359 && d->selectedRowIndex(d->selectedListWidget) < d->selectedListWidget->count() - 1);
360}
361
362// END Public Slots
363
364// BEGIN Protected
366{
367 if (!d->keyboardEnabled) {
368 return;
369 }
370 if ((e->modifiers() & Qt::ControlModifier)) {
371 switch (e->key()) {
372 case Qt::Key_Right:
373 d->buttonAddClicked();
374 break;
375 case Qt::Key_Left:
376 d->buttonRemoveClicked();
377 break;
378 case Qt::Key_Up:
379 d->buttonUpClicked();
380 break;
381 case Qt::Key_Down:
382 d->buttonDownClicked();
383 break;
384 default:
385 e->ignore();
386 return;
387 }
388 }
389}
390
392{
393 if (d->keyboardEnabled && e->type() == QEvent::KeyPress) {
394 if ((((QKeyEvent *)e)->modifiers() & Qt::ControlModifier)) {
395 switch (((QKeyEvent *)e)->key()) {
396 case Qt::Key_Right:
397 d->buttonAddClicked();
398 break;
399 case Qt::Key_Left:
400 d->buttonRemoveClicked();
401 break;
402 case Qt::Key_Up:
403 d->buttonUpClicked();
404 break;
405 case Qt::Key_Down:
406 d->buttonDownClicked();
407 break;
408 default:
409 return QWidget::eventFilter(o, e);
410 }
411 return true;
412 } else if (QListWidget *lb = qobject_cast<QListWidget *>(o)) {
413 switch (((QKeyEvent *)e)->key()) {
414 case Qt::Key_Return:
415 case Qt::Key_Enter:
416 int index = lb->currentRow();
417 if (index < 0) {
418 break;
419 }
420 d->moveItem(lb->item(index));
421 return true;
422 }
423 }
424 }
425 return QWidget::eventFilter(o, e);
426}
427
428// END Protected
429
430// BEGIN Private Slots
431
432void KActionSelectorPrivate::buttonAddClicked()
433{
434 // move all selected items from available to selected listbox
435 const QList<QListWidgetItem *> list = availableListWidget->selectedItems();
436 for (QListWidgetItem *item : list) {
437 availableListWidget->takeItem(availableListWidget->row(item));
438 selectedListWidget->insertItem(insertionIndex(selectedListWidget, selectedInsertionPolicy), item);
439 selectedListWidget->setCurrentItem(item);
440 Q_EMIT q->added(item);
441 }
442 if (selectedInsertionPolicy == KActionSelector::Sorted) {
443 selectedListWidget->sortItems();
444 }
445 selectedListWidget->setFocus();
446}
447
448void KActionSelectorPrivate::buttonRemoveClicked()
449{
450 // move all selected items from selected to available listbox
451 const QList<QListWidgetItem *> list = selectedListWidget->selectedItems();
452 for (QListWidgetItem *item : list) {
453 selectedListWidget->takeItem(selectedListWidget->row(item));
454 availableListWidget->insertItem(insertionIndex(availableListWidget, availableInsertionPolicy), item);
455 availableListWidget->setCurrentItem(item);
456 Q_EMIT q->removed(item);
457 }
458 if (availableInsertionPolicy == KActionSelector::Sorted) {
459 availableListWidget->sortItems();
460 }
461 availableListWidget->setFocus();
462}
463
464void KActionSelectorPrivate::buttonUpClicked()
465{
466 int c = selectedRowIndex(selectedListWidget);
467 if (c < 1) {
468 return;
469 }
470 QListWidgetItem *item = selectedListWidget->item(c);
471 selectedListWidget->takeItem(c);
472 selectedListWidget->insertItem(c - 1, item);
473 selectedListWidget->setCurrentItem(item);
474 Q_EMIT q->movedUp(item);
475}
476
477void KActionSelectorPrivate::buttonDownClicked()
478{
479 int c = selectedRowIndex(selectedListWidget);
480 if (c < 0 || c == selectedListWidget->count() - 1) {
481 return;
482 }
483 QListWidgetItem *item = selectedListWidget->item(c);
484 selectedListWidget->takeItem(c);
485 selectedListWidget->insertItem(c + 1, item);
486 selectedListWidget->setCurrentItem(item);
487 Q_EMIT q->movedDown(item);
488}
489
490void KActionSelectorPrivate::itemDoubleClicked(QListWidgetItem *item)
491{
492 if (moveOnDoubleClick) {
493 moveItem(item);
494 }
495}
496
497// END Private Slots
498
499// BEGIN Private Methods
500
501void KActionSelectorPrivate::loadIcons()
502{
503 btnAdd->setIcon(QIcon::fromTheme(addIcon));
504 btnRemove->setIcon(QIcon::fromTheme(removeIcon));
505 btnUp->setIcon(QIcon::fromTheme(upIcon));
506 btnDown->setIcon(QIcon::fromTheme(downIcon));
507}
508
509void KActionSelectorPrivate::moveItem(QListWidgetItem *item)
510{
511 QListWidget *lbFrom = item->listWidget();
512 QListWidget *lbTo;
513 if (lbFrom == availableListWidget) {
514 lbTo = selectedListWidget;
515 } else if (lbFrom == selectedListWidget) {
516 lbTo = availableListWidget;
517 } else { //?! somewhat unlikely...
518 return;
519 }
520
521 KActionSelector::InsertionPolicy p = (lbTo == availableListWidget) ? availableInsertionPolicy : selectedInsertionPolicy;
522
523 lbFrom->takeItem(lbFrom->row(item));
524 lbTo->insertItem(insertionIndex(lbTo, p), item);
525 lbTo->setFocus();
526 lbTo->setCurrentItem(item);
527
528 if (p == KActionSelector::Sorted) {
529 lbTo->sortItems();
530 }
531 if (lbTo == selectedListWidget) {
532 Q_EMIT q->added(item);
533 } else {
534 Q_EMIT q->removed(item);
535 }
536}
537
538int KActionSelectorPrivate::insertionIndex(QListWidget *lb, KActionSelector::InsertionPolicy policy)
539{
540 int index;
541 switch (policy) {
543 index = lb->currentRow();
544 if (index > -1) {
545 index += 1;
546 }
547 break;
549 index = 0;
550 break;
552 index = lb->count();
553 break;
554 default:
555 index = -1;
556 }
557 return index;
558}
559
560int KActionSelectorPrivate::selectedRowIndex(QListWidget *lb)
561{
562 QList<QListWidgetItem *> list = lb->selectedItems();
563 if (list.isEmpty()) {
564 return -1;
565 }
566 return lb->row(list.at(0));
567}
568
569// END Private Methods
570#include "moc_kactionselector.cpp"
bool eventFilter(QObject *, QEvent *) override
Reimplemented for internal reasons.
void setShowUpDownButtons(bool show)
Sets whether the Up and Down buttons should be displayed according to show.
InsertionPolicy
This enum defines policies for where to insert moved items in a listbox.
@ AtBottom
The item is inserted at the end of the listbox.
@ Sorted
The listbox is sort()ed after one or more items are inserted.
@ AtTop
The item is inserted at index 0 in the listbox.
@ BelowCurrent
The item is inserted below the listbox' currentItem() or at the end if there is no current item.
MoveButton
This enum identifies the moving buttons.
void setSelectedLabel(const QString &text)
Sets the label for the selected items listbox to text.
void setSelectedInsertionPolicy(InsertionPolicy policy)
Sets the insertion policy for the selected listbox.
void setButtonIconSet(const QIcon &iconset, MoveButton button)
Sets the iconset for button button to iconset.
void setMoveOnDoubleClick(bool enable)
Sets moveOnDoubleClick to enable.
void setAvailableLabel(const QString &text)
Sets the label for the available items listbox to text.
QListWidget * selectedListWidget() const
void setButtonTooltip(const QString &tip, MoveButton button)
Sets the tooltip for the button button to tip.
void setButtonWhatsThis(const QString &text, MoveButton button)
Sets the whatsthis help for button button to text.
void keyPressEvent(QKeyEvent *) override
Reimplemented for internal reasons.
void added(QListWidgetItem *item)
Emitted when an item is moved to the "selected" listbox.
void setButtonIcon(const QString &icon, MoveButton button)
Sets the pixmap of the button button to icon.
void setKeyboardEnabled(bool enable)
Sets the keyboard enabled depending on enable.
void setButtonsEnabled()
Emitted when an item is moved to the "selected" listbox.
QListWidget * availableListWidget() const
void setAvailableInsertionPolicy(InsertionPolicy policy)
Sets the insertion policy for the available listbox.
KIOCORE_EXPORT QStringList list(const QString &fileClass)
void clicked(bool checked)
void addLayout(QLayout *layout, int stretch)
void addStretch(int stretch)
void addWidget(QWidget *widget, int stretch, Qt::Alignment alignment)
void ignore()
Type type() const const
bool isRightToLeft()
QIcon fromTheme(const QString &name)
int key() const const
Qt::KeyboardModifiers modifiers() const const
void setContentsMargins(const QMargins &margins)
const_reference at(qsizetype i) const const
bool isEmpty() const const
void insertItem(int row, QListWidgetItem *item)
void itemDoubleClicked(QListWidgetItem *item)
void itemSelectionChanged()
int row(const QListWidgetItem *item) const const
QList< QListWidgetItem * > selectedItems() const const
void setCurrentItem(QListWidgetItem *item)
void sortItems(Qt::SortOrder order)
QListWidgetItem * takeItem(int row)
QListWidget * listWidget() const const
void setIcon(const QIcon &icon)
QObject(QObject *parent)
virtual bool eventFilter(QObject *watched, QEvent *event)
T qobject_cast(QObject *object)
Key_Right
ControlModifier
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
void setFocus()
void show()
This file is part of the KDE documentation.
Documentation copyright © 1996-2025 The KDE developers.
Generated on Fri Feb 28 2025 12:02:04 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.