Mailcommon

filteractionwidget.cpp
1 /*
2  SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <[email protected]>
3  SPDX-FileCopyrightText: 2010 Andras Mantia <[email protected]>
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 
23 using namespace MailCommon;
24 
25 //=============================================================================
26 //
27 // class FilterActionWidget
28 //
29 //=============================================================================
30 
31 class Q_DECL_HIDDEN FilterActionWidget::FilterActionWidgetPrivate
32 {
33 public:
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 
60 void 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 
73 void FilterActionWidget::FilterActionWidgetPrivate::slotAddWidget()
74 {
75  Q_EMIT q->addFilterWidget(q);
76  Q_EMIT q->filterModified();
77 }
78 
79 void FilterActionWidget::FilterActionWidgetPrivate::slotRemoveWidget()
80 {
81  Q_EMIT q->removeFilterWidget(q);
82  Q_EMIT q->filterModified();
83 }
84 
85 void FilterActionWidget::FilterActionWidgetPrivate::slotFilterTypeChanged(int index)
86 {
87  setFilterAction(index < mActionList.count() ? mActionList.at(index)->createParamWidget(q) : nullptr);
88 }
89 
91  : QWidget(parent)
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));
149  updateGeometry();
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 
175 void 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 
240 class FilterActionWidgetLister::FilterActionWidgetListerPrivate
241 {
242 public:
243  FilterActionWidgetListerPrivate(FilterActionWidgetLister *qq)
244  : q(qq)
245  {
246  }
247 
248  void regenerateActionListFromWidgets();
249 
250  FilterActionWidgetLister *const q;
251  QList<MailCommon::FilterAction *> *mActionList = nullptr;
252 };
253 
254 void 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());
317  QList<QWidget *>::ConstIterator wIt = widgetList.constBegin();
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 
326 void 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 
336 void FilterActionWidgetLister::slotAddWidget(QWidget *w)
337 {
339  updateAddRemoveButton();
340 }
341 
342 void FilterActionWidgetLister::slotRemoveWidget(QWidget *w)
343 {
344  removeWidget(w);
345  updateAddRemoveButton();
346 }
347 
348 void 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  }
364  QList<QWidget *>::ConstIterator wIt = widgetList.constBegin();
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 
389 void 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"
QLayoutItem * itemAtPosition(int row, int column) const const
QWidget(QWidget *parent, Qt::WindowFlags f)
virtual void setParamWidgetValue(QWidget *paramWidget) const
The filter action shall set it's widget's contents from it's parameter.
void setAction(const MailCommon::FilterAction *action)
Sets the filter action.
void setSizePolicy(QSizePolicy)
void setActionList(QList< FilterAction * > *list)
Sets the list of filter actions, the lister will create FilterActionWidgets for.
int count(const T &value) const const
FilterActionWidgetLister(QWidget *parent=nullptr)
Creates a new filter action widget lister.
void clicked(bool checked)
QIcon fromTheme(const QString &name)
void setFocusProxy(QWidget *w)
A container widget for a list of FilterActionWidgets.
QList::const_iterator constBegin() const const
A widget to edit a single MailCommon::FilterAction.
The MailFilter class.
Definition: mailfilter.h:28
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
virtual QWidget * widget()
~FilterActionWidget() override
Destroys the filter action widget.
QList< QWidget * > widgets() const
void reset()
Resets the action widgets.
QString name() const
Returns identifier name, ie.
Abstract base class for mail filter actions.
Definition: filteraction.h:38
QString i18n(const char *text, const TYPE &arg...)
void filterActionModified()
Called to notify that the current FilterAction has had some value modification.
MailCommon::FilterAction * action() const
Returns the filter action.
UniqueConnection
bool isEmpty() const const
void updateActionList()
Updates the action list according to the current action widget values.
virtual void removeWidget(QWidget *widget)
void setEnabled(bool)
const MAILCOMMON_EXPORT QList< FilterActionDesc * > & list() const
Provides read-only access to a list of all known filter actions.
virtual void applyParamWidgetValue(QWidget *paramWidget)
The filter action shall set it's parameter from the widget's contents.
void updateGeometry()
static FilterActionDict * filterActionDict()
Returns the global filter action dictionary.
QList::const_iterator constEnd() const const
int widgetsMinimum() const
void clear()
~FilterActionWidgetLister() override
Destroys the filter action widget lister.
int widgetsMaximum() const
FilterActionWidget(QWidget *parent=nullptr)
Creates a filter action widget with no type selected.
Auxiliary struct for FilterActionDict.
void activated(int index)
virtual void setNumberOfShownWidgetsTo(int count)
QObject * parent() const const
The filter dialog.
virtual void addWidgetAfterThisWidget(QWidget *currentWidget, QWidget *widget=nullptr)
QWidget * createWidget(QWidget *) override
virtual void slotClear()
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Fri Dec 8 2023 04:02:07 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.