File indexing completed on 2024-11-10 04:50:04
0001 /* 0002 SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com> 0003 SPDX-FileCopyrightText: 2010 Andras Mantia <andras@kdab.com> 0004 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #include "filteractionwidget.h" 0009 #include "filter/filteractions/filteraction.h" 0010 #include "filter/filteractions/filteractiondict.h" 0011 #include "filter/filtermanager.h" 0012 #include "filter/mailfilter.h" 0013 #include "mailcommon_debug.h" 0014 0015 #include <KLocalizedString> 0016 #include <QComboBox> 0017 #include <QIcon> 0018 #include <QPushButton> 0019 0020 #include <QGridLayout> 0021 #include <QLabel> 0022 0023 using namespace MailCommon; 0024 0025 //============================================================================= 0026 // 0027 // class FilterActionWidget 0028 // 0029 //============================================================================= 0030 0031 class Q_DECL_HIDDEN FilterActionWidget::FilterActionWidgetPrivate 0032 { 0033 public: 0034 FilterActionWidgetPrivate(FilterActionWidget *qq) 0035 : q(qq) 0036 { 0037 } 0038 0039 ~FilterActionWidgetPrivate() 0040 { 0041 qDeleteAll(mActionList); 0042 mActionList.clear(); 0043 } 0044 0045 void setFilterAction(QWidget *widget = nullptr); 0046 0047 void slotFilterTypeChanged(int index); 0048 void slotAddWidget(); 0049 void slotRemoveWidget(); 0050 0051 FilterActionWidget *const q; 0052 QList<MailCommon::FilterAction *> mActionList; 0053 QComboBox *mComboBox = nullptr; 0054 QPushButton *mAdd = nullptr; 0055 QPushButton *mRemove = nullptr; 0056 0057 QGridLayout *mLayout = nullptr; 0058 }; 0059 0060 void FilterActionWidget::FilterActionWidgetPrivate::setFilterAction(QWidget *widget) 0061 { 0062 if (mLayout->itemAtPosition(1, 2)) { 0063 delete mLayout->itemAtPosition(1, 2)->widget(); 0064 } 0065 0066 if (widget) { 0067 mLayout->addWidget(widget, 1, 2); 0068 } else { 0069 mLayout->addWidget(new QLabel(i18n("Please select an action."), q), 1, 2); 0070 } 0071 } 0072 0073 void FilterActionWidget::FilterActionWidgetPrivate::slotAddWidget() 0074 { 0075 Q_EMIT q->addFilterWidget(q); 0076 Q_EMIT q->filterModified(); 0077 } 0078 0079 void FilterActionWidget::FilterActionWidgetPrivate::slotRemoveWidget() 0080 { 0081 Q_EMIT q->removeFilterWidget(q); 0082 Q_EMIT q->filterModified(); 0083 } 0084 0085 void FilterActionWidget::FilterActionWidgetPrivate::slotFilterTypeChanged(int index) 0086 { 0087 setFilterAction(index < mActionList.count() ? mActionList.at(index)->createParamWidget(q) : nullptr); 0088 } 0089 0090 FilterActionWidget::FilterActionWidget(QWidget *parent) 0091 : QWidget(parent) 0092 , d(new FilterActionWidgetPrivate(this)) 0093 { 0094 auto mainLayout = new QHBoxLayout(this); 0095 mainLayout->setContentsMargins({}); 0096 auto widget = new QWidget(this); 0097 mainLayout->addWidget(widget); 0098 0099 d->mLayout = new QGridLayout(widget); 0100 d->mLayout->setContentsMargins({}); 0101 0102 d->mComboBox = new QComboBox(widget); 0103 d->mComboBox->setMinimumWidth(50); 0104 d->mComboBox->setEditable(false); 0105 Q_ASSERT(d->mComboBox); 0106 d->mLayout->addWidget(d->mComboBox, 1, 1); 0107 d->mAdd = new QPushButton(widget); 0108 d->mAdd->setIcon(QIcon::fromTheme(QStringLiteral("list-add"))); 0109 d->mAdd->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); 0110 0111 d->mRemove = new QPushButton(widget); 0112 d->mRemove->setIcon(QIcon::fromTheme(QStringLiteral("list-remove"))); 0113 d->mRemove->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); 0114 0115 mainLayout->setSpacing(4); 0116 0117 int index; 0118 QList<FilterActionDesc *> list = MailCommon::FilterManager::filterActionDict()->list(); 0119 QList<FilterActionDesc *>::const_iterator it; 0120 QList<FilterActionDesc *>::const_iterator end(list.constEnd()); 0121 for (index = 0, it = list.constBegin(); it != end; ++it, ++index) { 0122 // create an instance: 0123 FilterAction *action = (*it)->create(); 0124 0125 // append to the list of actions: 0126 d->mActionList.append(action); 0127 0128 // add (i18n-ized) name to combo box 0129 d->mComboBox->addItem((*it)->label, (*it)->name); 0130 0131 // Register the FilterAction modification signal 0132 connect(action, &FilterAction::filterActionModified, this, &FilterActionWidget::filterModified); 0133 } 0134 0135 // widget for the case where no action is selected. 0136 d->mComboBox->addItem(QStringLiteral(" ")); 0137 d->mComboBox->setCurrentIndex(index); 0138 0139 // don't show scroll bars. 0140 d->mComboBox->setMaxCount(d->mComboBox->count()); 0141 0142 // layout management: 0143 // o the combo box is not to be made larger than it's sizeHint(), 0144 // the parameter widget should grow instead. 0145 // o the whole widget takes all space horizontally, but is fixed vertically. 0146 d->mComboBox->adjustSize(); 0147 d->mComboBox->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed)); 0148 setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed)); 0149 updateGeometry(); 0150 0151 // redirect focus to the filter action combo box 0152 setFocusProxy(d->mComboBox); 0153 0154 // now connect the combo box and the widget stack 0155 connect(d->mComboBox, &QComboBox::activated, this, [this](int index) { 0156 d->slotFilterTypeChanged(index); 0157 }); 0158 0159 connect(d->mComboBox, &QComboBox::activated, this, &FilterActionWidget::filterModified); 0160 0161 connect(d->mAdd, &QPushButton::clicked, this, [this]() { 0162 d->slotAddWidget(); 0163 }); 0164 connect(d->mRemove, &QPushButton::clicked, this, [this]() { 0165 d->slotRemoveWidget(); 0166 }); 0167 0168 d->setFilterAction(); 0169 d->mLayout->addWidget(d->mAdd, 1, 3); 0170 d->mLayout->addWidget(d->mRemove, 1, 4); 0171 } 0172 0173 FilterActionWidget::~FilterActionWidget() = default; 0174 0175 void FilterActionWidget::updateAddRemoveButton(bool addButtonEnabled, bool removeButtonEnabled) 0176 { 0177 d->mAdd->setEnabled(addButtonEnabled); 0178 d->mRemove->setEnabled(removeButtonEnabled); 0179 } 0180 0181 void FilterActionWidget::setAction(const FilterAction *action) 0182 { 0183 bool found = false; 0184 const int count = d->mComboBox->count() - 1; // last entry is the empty one 0185 0186 const QString name = action ? action->name() : QString(); 0187 0188 // find the index of typeOf(action) in mComboBox 0189 // and clear the other widgets on the way. 0190 for (int i = 0; i < count; ++i) { 0191 if (action && d->mComboBox->itemData(i) == name) { 0192 d->setFilterAction(d->mActionList.at(i)->createParamWidget(this)); 0193 0194 //...set the parameter widget to the settings 0195 // of aAction... 0196 action->setParamWidgetValue(d->mLayout->itemAtPosition(1, 2)->widget()); 0197 0198 //...and show the correct entry of 0199 // the combo box 0200 d->mComboBox->setCurrentIndex(i); // (mm) also raise the widget, but doesn't 0201 found = true; 0202 } 0203 } 0204 0205 if (found) { 0206 return; 0207 } 0208 0209 // not found, so set the empty widget 0210 d->setFilterAction(); 0211 0212 d->mComboBox->setCurrentIndex(count); // last item 0213 } 0214 0215 FilterAction *FilterActionWidget::action() const 0216 { 0217 // look up the action description via the label 0218 // returned by KComboBox::currentText()... 0219 FilterActionDesc *description = MailCommon::FilterManager::filterActionDict()->value(d->mComboBox->itemData(d->mComboBox->currentIndex()).toString()); 0220 0221 if (description) { 0222 // ...create an instance... 0223 FilterAction *action = description->create(); 0224 if (action) { 0225 // ...and apply the setting of the parameter widget. 0226 action->applyParamWidgetValue(d->mLayout->itemAtPosition(1, 2)->widget()); 0227 return action; 0228 } 0229 } 0230 0231 return nullptr; 0232 } 0233 0234 //============================================================================= 0235 // 0236 // class FilterActionWidgetLister (the filter action editor) 0237 // 0238 //============================================================================= 0239 0240 class FilterActionWidgetLister::FilterActionWidgetListerPrivate 0241 { 0242 public: 0243 FilterActionWidgetListerPrivate(FilterActionWidgetLister *qq) 0244 : q(qq) 0245 { 0246 } 0247 0248 void regenerateActionListFromWidgets(); 0249 0250 FilterActionWidgetLister *const q; 0251 QList<MailCommon::FilterAction *> *mActionList = nullptr; 0252 }; 0253 0254 void FilterActionWidgetLister::FilterActionWidgetListerPrivate::regenerateActionListFromWidgets() 0255 { 0256 if (!mActionList) { 0257 return; 0258 } 0259 0260 mActionList->clear(); 0261 0262 const auto lst = q->widgets(); 0263 for (const QWidget *widget : lst) { 0264 FilterAction *action = qobject_cast<const FilterActionWidget *>(widget)->action(); 0265 if (action) { 0266 mActionList->append(action); 0267 } 0268 } 0269 q->updateAddRemoveButton(); 0270 } 0271 0272 FilterActionWidgetLister::FilterActionWidgetLister(QWidget *parent) 0273 : KWidgetLister(false, 1, MailFilter::filterActionsMaximumSize(), parent) 0274 , d(new FilterActionWidgetListerPrivate(this)) 0275 { 0276 } 0277 0278 FilterActionWidgetLister::~FilterActionWidgetLister() = default; 0279 0280 void FilterActionWidgetLister::setActionList(QList<FilterAction *> *list) 0281 { 0282 Q_ASSERT(list); 0283 if (d->mActionList && d->mActionList != list) { 0284 d->regenerateActionListFromWidgets(); 0285 } 0286 0287 d->mActionList = list; 0288 0289 static_cast<QWidget *>(parent())->setEnabled(true); 0290 0291 if (!widgets().isEmpty()) { // move this below next 'if'? 0292 widgets().constFirst()->blockSignals(true); 0293 } 0294 0295 if (list->isEmpty()) { 0296 slotClear(); 0297 connectWidget(widgets().constFirst(), nullptr); 0298 widgets().constFirst()->blockSignals(false); 0299 return; 0300 } 0301 0302 int superfluousItems = (int)d->mActionList->count() - widgetsMaximum(); 0303 if (superfluousItems > 0) { 0304 qCDebug(MAILCOMMON_LOG) << "FilterActionWidgetLister: Clipping action list to" << widgetsMaximum() << "items!"; 0305 0306 for (; superfluousItems; superfluousItems--) { 0307 d->mActionList->removeLast(); 0308 } 0309 } 0310 0311 // set the right number of widgets 0312 setNumberOfShownWidgetsTo(d->mActionList->count()); 0313 0314 // load the actions into the widgets 0315 QList<QWidget *> widgetList = widgets(); 0316 QList<FilterAction *>::const_iterator aEnd(d->mActionList->constEnd()); 0317 QList<QWidget *>::ConstIterator wIt = widgetList.constBegin(); 0318 QList<QWidget *>::ConstIterator wEnd = widgetList.constEnd(); 0319 for (QList<FilterAction *>::const_iterator aIt = d->mActionList->constBegin(); (aIt != aEnd && wIt != wEnd); ++aIt, ++wIt) { 0320 connectWidget((*wIt), (*aIt)); 0321 } 0322 widgets().constFirst()->blockSignals(false); 0323 updateAddRemoveButton(); 0324 } 0325 0326 void FilterActionWidgetLister::connectWidget(QWidget *widget, FilterAction *filterAction) 0327 { 0328 auto w = qobject_cast<FilterActionWidget *>(widget); 0329 if (filterAction) { 0330 w->setAction(filterAction); 0331 } 0332 connect(w, &FilterActionWidget::filterModified, this, &FilterActionWidgetLister::filterModified, Qt::UniqueConnection); 0333 reconnectWidget(w); 0334 } 0335 0336 void FilterActionWidgetLister::slotAddWidget(QWidget *w) 0337 { 0338 addWidgetAfterThisWidget(w); 0339 updateAddRemoveButton(); 0340 } 0341 0342 void FilterActionWidgetLister::slotRemoveWidget(QWidget *w) 0343 { 0344 removeWidget(w); 0345 updateAddRemoveButton(); 0346 } 0347 0348 void FilterActionWidgetLister::updateAddRemoveButton() 0349 { 0350 QList<QWidget *> widgetList = widgets(); 0351 const int numberOfWidget(widgetList.count()); 0352 bool addButtonEnabled = false; 0353 bool removeButtonEnabled = false; 0354 if (numberOfWidget <= widgetsMinimum()) { 0355 addButtonEnabled = true; 0356 removeButtonEnabled = false; 0357 } else if (numberOfWidget >= widgetsMaximum()) { 0358 addButtonEnabled = false; 0359 removeButtonEnabled = true; 0360 } else { 0361 addButtonEnabled = true; 0362 removeButtonEnabled = true; 0363 } 0364 QList<QWidget *>::ConstIterator wIt = widgetList.constBegin(); 0365 QList<QWidget *>::ConstIterator wEnd = widgetList.constEnd(); 0366 for (; wIt != wEnd; ++wIt) { 0367 auto w = qobject_cast<FilterActionWidget *>(*wIt); 0368 w->updateAddRemoveButton(addButtonEnabled, removeButtonEnabled); 0369 } 0370 } 0371 0372 void FilterActionWidgetLister::updateActionList() 0373 { 0374 d->regenerateActionListFromWidgets(); 0375 } 0376 0377 void FilterActionWidgetLister::reset() 0378 { 0379 if (d->mActionList) { 0380 d->regenerateActionListFromWidgets(); 0381 } 0382 0383 d->mActionList = nullptr; 0384 slotClear(); 0385 0386 static_cast<QWidget *>(parent())->setEnabled(false); 0387 } 0388 0389 void FilterActionWidgetLister::reconnectWidget(FilterActionWidget *w) 0390 { 0391 connect(w, &FilterActionWidget::addFilterWidget, this, &FilterActionWidgetLister::slotAddWidget, Qt::UniqueConnection); 0392 0393 connect(w, &FilterActionWidget::removeFilterWidget, this, &FilterActionWidgetLister::slotRemoveWidget, Qt::UniqueConnection); 0394 } 0395 0396 QWidget *FilterActionWidgetLister::createWidget(QWidget *parent) 0397 { 0398 auto w = new FilterActionWidget(parent); 0399 reconnectWidget(w); 0400 return w; 0401 } 0402 0403 void FilterActionWidgetLister::clearWidget(QWidget *widget) 0404 { 0405 if (widget) { 0406 auto w = static_cast<FilterActionWidget *>(widget); 0407 w->setAction(nullptr); 0408 w->disconnect(this); 0409 reconnectWidget(w); 0410 updateAddRemoveButton(); 0411 } 0412 } 0413 0414 #include "moc_filteractionwidget.cpp"