Mailcommon

filteractionwidget.cpp
1/*
2 SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
3 SPDX-FileCopyrightText: 2010 Andras Mantia <andras@kdab.com>
4
5 SPDX-License-Identifier: GPL-2.0-or-later
6*/
7
8#include "filteractionwidget.h"
9#include "filter/filteractions/filteraction.h"
10#include "filter/filteractions/filteractiondict.h"
11#include "filter/filtermanager.h"
12#include "filter/mailfilter.h"
13#include "mailcommon_debug.h"
14
15#include <KLocalizedString>
16#include <QComboBox>
17#include <QIcon>
18#include <QPushButton>
19
20#include <QGridLayout>
21#include <QLabel>
22
23using namespace MailCommon;
24
25//=============================================================================
26//
27// class FilterActionWidget
28//
29//=============================================================================
30
31class Q_DECL_HIDDEN FilterActionWidget::FilterActionWidgetPrivate
32{
33public:
34 FilterActionWidgetPrivate(FilterActionWidget *qq)
35 : q(qq)
36 {
37 }
38
39 ~FilterActionWidgetPrivate()
40 {
41 qDeleteAll(mActionList);
42 mActionList.clear();
43 }
44
45 void setFilterAction(QWidget *widget = nullptr);
46
47 void slotFilterTypeChanged(int index);
48 void slotAddWidget();
49 void slotRemoveWidget();
50
51 FilterActionWidget *const q;
53 QComboBox *mComboBox = nullptr;
54 QPushButton *mAdd = nullptr;
55 QPushButton *mRemove = nullptr;
56
57 QGridLayout *mLayout = nullptr;
58};
59
60void FilterActionWidget::FilterActionWidgetPrivate::setFilterAction(QWidget *widget)
61{
62 if (mLayout->itemAtPosition(1, 2)) {
63 delete mLayout->itemAtPosition(1, 2)->widget();
64 }
65
66 if (widget) {
67 mLayout->addWidget(widget, 1, 2);
68 } else {
69 mLayout->addWidget(new QLabel(i18n("Please select an action."), q), 1, 2);
70 }
71}
72
73void FilterActionWidget::FilterActionWidgetPrivate::slotAddWidget()
74{
75 Q_EMIT q->addFilterWidget(q);
76 Q_EMIT q->filterModified();
77}
78
79void FilterActionWidget::FilterActionWidgetPrivate::slotRemoveWidget()
80{
81 Q_EMIT q->removeFilterWidget(q);
82 Q_EMIT q->filterModified();
83}
84
85void FilterActionWidget::FilterActionWidgetPrivate::slotFilterTypeChanged(int index)
86{
87 setFilterAction(index < mActionList.count() ? mActionList.at(index)->createParamWidget(q) : nullptr);
88}
89
92 , d(new FilterActionWidgetPrivate(this))
93{
94 auto mainLayout = new QHBoxLayout(this);
95 mainLayout->setContentsMargins({});
96 auto widget = new QWidget(this);
97 mainLayout->addWidget(widget);
98
99 d->mLayout = new QGridLayout(widget);
100 d->mLayout->setContentsMargins({});
101
102 d->mComboBox = new QComboBox(widget);
103 d->mComboBox->setMinimumWidth(50);
104 d->mComboBox->setEditable(false);
105 Q_ASSERT(d->mComboBox);
106 d->mLayout->addWidget(d->mComboBox, 1, 1);
107 d->mAdd = new QPushButton(widget);
108 d->mAdd->setIcon(QIcon::fromTheme(QStringLiteral("list-add")));
109 d->mAdd->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
110
111 d->mRemove = new QPushButton(widget);
112 d->mRemove->setIcon(QIcon::fromTheme(QStringLiteral("list-remove")));
113 d->mRemove->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
114
115 mainLayout->setSpacing(4);
116
117 int index;
121 for (index = 0, it = list.constBegin(); it != end; ++it, ++index) {
122 // create an instance:
123 FilterAction *action = (*it)->create();
124
125 // append to the list of actions:
126 d->mActionList.append(action);
127
128 // add (i18n-ized) name to combo box
129 d->mComboBox->addItem((*it)->label, (*it)->name);
130
131 // Register the FilterAction modification signal
132 connect(action, &FilterAction::filterActionModified, this, &FilterActionWidget::filterModified);
133 }
134
135 // widget for the case where no action is selected.
136 d->mComboBox->addItem(QStringLiteral(" "));
137 d->mComboBox->setCurrentIndex(index);
138
139 // don't show scroll bars.
140 d->mComboBox->setMaxCount(d->mComboBox->count());
141
142 // layout management:
143 // o the combo box is not to be made larger than it's sizeHint(),
144 // the parameter widget should grow instead.
145 // o the whole widget takes all space horizontally, but is fixed vertically.
146 d->mComboBox->adjustSize();
147 d->mComboBox->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed));
150
151 // redirect focus to the filter action combo box
152 setFocusProxy(d->mComboBox);
153
154 // now connect the combo box and the widget stack
155 connect(d->mComboBox, &QComboBox::activated, this, [this](int index) {
156 d->slotFilterTypeChanged(index);
157 });
158
159 connect(d->mComboBox, &QComboBox::activated, this, &FilterActionWidget::filterModified);
160
161 connect(d->mAdd, &QPushButton::clicked, this, [this]() {
162 d->slotAddWidget();
163 });
164 connect(d->mRemove, &QPushButton::clicked, this, [this]() {
165 d->slotRemoveWidget();
166 });
167
168 d->setFilterAction();
169 d->mLayout->addWidget(d->mAdd, 1, 3);
170 d->mLayout->addWidget(d->mRemove, 1, 4);
171}
172
174
175void FilterActionWidget::updateAddRemoveButton(bool addButtonEnabled, bool removeButtonEnabled)
176{
177 d->mAdd->setEnabled(addButtonEnabled);
178 d->mRemove->setEnabled(removeButtonEnabled);
179}
180
182{
183 bool found = false;
184 const int count = d->mComboBox->count() - 1; // last entry is the empty one
185
186 const QString name = action ? action->name() : QString();
187
188 // find the index of typeOf(action) in mComboBox
189 // and clear the other widgets on the way.
190 for (int i = 0; i < count; ++i) {
191 if (action && d->mComboBox->itemData(i) == name) {
192 d->setFilterAction(d->mActionList.at(i)->createParamWidget(this));
193
194 //...set the parameter widget to the settings
195 // of aAction...
196 action->setParamWidgetValue(d->mLayout->itemAtPosition(1, 2)->widget());
197
198 //...and show the correct entry of
199 // the combo box
200 d->mComboBox->setCurrentIndex(i); // (mm) also raise the widget, but doesn't
201 found = true;
202 }
203 }
204
205 if (found) {
206 return;
207 }
208
209 // not found, so set the empty widget
210 d->setFilterAction();
211
212 d->mComboBox->setCurrentIndex(count); // last item
213}
214
216{
217 // look up the action description via the label
218 // returned by KComboBox::currentText()...
219 FilterActionDesc *description = MailCommon::FilterManager::filterActionDict()->value(d->mComboBox->itemData(d->mComboBox->currentIndex()).toString());
220
221 if (description) {
222 // ...create an instance...
223 FilterAction *action = description->create();
224 if (action) {
225 // ...and apply the setting of the parameter widget.
226 action->applyParamWidgetValue(d->mLayout->itemAtPosition(1, 2)->widget());
227 return action;
228 }
229 }
230
231 return nullptr;
232}
233
234//=============================================================================
235//
236// class FilterActionWidgetLister (the filter action editor)
237//
238//=============================================================================
239
240class FilterActionWidgetLister::FilterActionWidgetListerPrivate
241{
242public:
243 FilterActionWidgetListerPrivate(FilterActionWidgetLister *qq)
244 : q(qq)
245 {
246 }
247
248 void regenerateActionListFromWidgets();
249
251 QList<MailCommon::FilterAction *> *mActionList = nullptr;
252};
253
254void FilterActionWidgetLister::FilterActionWidgetListerPrivate::regenerateActionListFromWidgets()
255{
256 if (!mActionList) {
257 return;
258 }
259
260 mActionList->clear();
261
262 const auto lst = q->widgets();
263 for (const QWidget *widget : lst) {
264 FilterAction *action = qobject_cast<const FilterActionWidget *>(widget)->action();
265 if (action) {
266 mActionList->append(action);
267 }
268 }
269 q->updateAddRemoveButton();
270}
271
273 : KWidgetLister(false, 1, MailFilter::filterActionsMaximumSize(), parent)
274 , d(new FilterActionWidgetListerPrivate(this))
275{
276}
277
279
281{
282 Q_ASSERT(list);
283 if (d->mActionList && d->mActionList != list) {
284 d->regenerateActionListFromWidgets();
285 }
286
287 d->mActionList = list;
288
289 static_cast<QWidget *>(parent())->setEnabled(true);
290
291 if (!widgets().isEmpty()) { // move this below next 'if'?
292 widgets().constFirst()->blockSignals(true);
293 }
294
295 if (list->isEmpty()) {
296 slotClear();
297 connectWidget(widgets().constFirst(), nullptr);
298 widgets().constFirst()->blockSignals(false);
299 return;
300 }
301
302 int superfluousItems = (int)d->mActionList->count() - widgetsMaximum();
303 if (superfluousItems > 0) {
304 qCDebug(MAILCOMMON_LOG) << "FilterActionWidgetLister: Clipping action list to" << widgetsMaximum() << "items!";
305
306 for (; superfluousItems; superfluousItems--) {
307 d->mActionList->removeLast();
308 }
309 }
310
311 // set the right number of widgets
312 setNumberOfShownWidgetsTo(d->mActionList->count());
313
314 // load the actions into the widgets
315 QList<QWidget *> widgetList = widgets();
316 QList<FilterAction *>::const_iterator aEnd(d->mActionList->constEnd());
318 QList<QWidget *>::ConstIterator wEnd = widgetList.constEnd();
319 for (QList<FilterAction *>::const_iterator aIt = d->mActionList->constBegin(); (aIt != aEnd && wIt != wEnd); ++aIt, ++wIt) {
320 connectWidget((*wIt), (*aIt));
321 }
322 widgets().constFirst()->blockSignals(false);
323 updateAddRemoveButton();
324}
325
326void FilterActionWidgetLister::connectWidget(QWidget *widget, FilterAction *filterAction)
327{
328 auto w = qobject_cast<FilterActionWidget *>(widget);
329 if (filterAction) {
330 w->setAction(filterAction);
331 }
332 connect(w, &FilterActionWidget::filterModified, this, &FilterActionWidgetLister::filterModified, Qt::UniqueConnection);
333 reconnectWidget(w);
334}
335
336void FilterActionWidgetLister::slotAddWidget(QWidget *w)
337{
339 updateAddRemoveButton();
340}
341
342void FilterActionWidgetLister::slotRemoveWidget(QWidget *w)
343{
344 removeWidget(w);
345 updateAddRemoveButton();
346}
347
348void FilterActionWidgetLister::updateAddRemoveButton()
349{
350 QList<QWidget *> widgetList = widgets();
351 const int numberOfWidget(widgetList.count());
352 bool addButtonEnabled = false;
353 bool removeButtonEnabled = false;
354 if (numberOfWidget <= widgetsMinimum()) {
355 addButtonEnabled = true;
356 removeButtonEnabled = false;
357 } else if (numberOfWidget >= widgetsMaximum()) {
358 addButtonEnabled = false;
359 removeButtonEnabled = true;
360 } else {
361 addButtonEnabled = true;
362 removeButtonEnabled = true;
363 }
365 QList<QWidget *>::ConstIterator wEnd = widgetList.constEnd();
366 for (; wIt != wEnd; ++wIt) {
367 auto w = qobject_cast<FilterActionWidget *>(*wIt);
368 w->updateAddRemoveButton(addButtonEnabled, removeButtonEnabled);
369 }
370}
371
373{
374 d->regenerateActionListFromWidgets();
375}
376
378{
379 if (d->mActionList) {
380 d->regenerateActionListFromWidgets();
381 }
382
383 d->mActionList = nullptr;
384 slotClear();
385
386 static_cast<QWidget *>(parent())->setEnabled(false);
387}
388
389void FilterActionWidgetLister::reconnectWidget(FilterActionWidget *w)
390{
391 connect(w, &FilterActionWidget::addFilterWidget, this, &FilterActionWidgetLister::slotAddWidget, Qt::UniqueConnection);
392
393 connect(w, &FilterActionWidget::removeFilterWidget, this, &FilterActionWidgetLister::slotRemoveWidget, Qt::UniqueConnection);
394}
395
397{
398 auto w = new FilterActionWidget(parent);
399 reconnectWidget(w);
400 return w;
401}
402
404{
405 if (widget) {
406 auto w = static_cast<FilterActionWidget *>(widget);
407 w->setAction(nullptr);
408 w->disconnect(this);
409 reconnectWidget(w);
410 updateAddRemoveButton();
411 }
412}
413
414#include "moc_filteractionwidget.cpp"
virtual void addWidgetAfterThisWidget(QWidget *currentWidget, QWidget *widget=nullptr)
virtual void slotClear()
virtual void removeWidget(QWidget *widget)
int widgetsMaximum() const
virtual void setNumberOfShownWidgetsTo(int count)
QList< QWidget * > widgets() const
KWidgetLister(bool fewerMoreButton, int minWidgets=1, int maxWidgets=8, QWidget *parent=nullptr)
int widgetsMinimum() const
MAILCOMMON_EXPORT const QList< FilterActionDesc * > & list() const
Provides read-only access to a list of all known filter actions.
A container widget for a list of FilterActionWidgets.
void setActionList(QList< FilterAction * > *list)
Sets the list of filter actions, the lister will create FilterActionWidgets for.
void reset()
Resets the action widgets.
void updateActionList()
Updates the action list according to the current action widget values.
QWidget * createWidget(QWidget *) override
~FilterActionWidgetLister() override
Destroys the filter action widget lister.
FilterActionWidgetLister(QWidget *parent=nullptr)
Creates a new filter action widget lister.
A widget to edit a single MailCommon::FilterAction.
~FilterActionWidget() override
Destroys the filter action widget.
void setAction(const MailCommon::FilterAction *action)
Sets the filter action.
FilterActionWidget(QWidget *parent=nullptr)
Creates a filter action widget with no type selected.
MailCommon::FilterAction * action() const
Returns the filter action.
Abstract base class for mail filter actions.
QString name() const
Returns identifier name, ie.
virtual void applyParamWidgetValue(QWidget *paramWidget)
The filter action shall set it's parameter from the widget's contents.
void filterActionModified()
Called to notify that the current FilterAction has had some value modification.
virtual void setParamWidgetValue(QWidget *paramWidget) const
The filter action shall set it's widget's contents from it's parameter.
static FilterActionDict * filterActionDict()
Returns the global filter action dictionary.
The MailFilter class.
Definition mailfilter.h:29
QString i18n(const char *text, const TYPE &arg...)
The filter dialog.
void clicked(bool checked)
void activated(int index)
void addWidget(QWidget *widget, int fromRow, int fromColumn, int rowSpan, int columnSpan, Qt::Alignment alignment)
QLayoutItem * itemAtPosition(int row, int column) const const
QIcon fromTheme(const QString &name)
virtual QWidget * widget() const const
void append(QList< T > &&value)
void clear()
const_iterator constBegin() const const
const_iterator constEnd() const const
qsizetype count() const const
bool isEmpty() const const
T value(const Key &key) const const
Q_EMITQ_EMIT
bool blockSignals(bool block)
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QObject * parent() const const
UniqueConnection
QWidget(QWidget *parent, Qt::WindowFlags f)
void setEnabled(bool)
void setFocusProxy(QWidget *w)
void setSizePolicy(QSizePolicy)
void updateGeometry()
Auxiliary struct for FilterActionDict.
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:14:00 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.