diff --git a/src/filter/kmfilterlistbox.cpp b/src/filter/kmfilterlistbox.cpp index d0a266d..399f77c 100644 --- a/src/filter/kmfilterlistbox.cpp +++ b/src/filter/kmfilterlistbox.cpp @@ -1,888 +1,879 @@ /* Copyright (c) 2014-2019 Montel Laurent This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "kmfilterlistbox.h" #include "mailfilter.h" #include "filtermanager.h" #include "filteractions/filteractiondict.h" #include #include "invalidfilters/invalidfilterinfo.h" #include "invalidfilters/invalidfilterdialog.h" #include #include #include #include #include #include #include #include -#include #include "mailcommon_debug.h" #include #include // What's this help texts const char _wt_filterlist[] = I18N_NOOP("

This is the list of defined filters. " "They are processed top-to-bottom.

" "

Click on any filter to edit it " "using the controls in the right-hand half " "of the dialog.

"); const char _wt_filterlist_new[] = I18N_NOOP("

Click this button to create a new filter.

" "

The filter will be inserted just before the currently-" "selected one, but you can always change that " "later on.

" "

If you have clicked this button accidentally, you can undo this " "by clicking on the Delete button.

"); const char _wt_filterlist_copy[] = I18N_NOOP("

Click this button to copy a filter.

" "

If you have clicked this button accidentally, you can undo this " "by clicking on the Delete button.

"); const char _wt_filterlist_delete[] = I18N_NOOP("

Click this button to delete the currently-" "selected filter from the list above.

" "

There is no way to get the filter back once " "it is deleted, but you can always leave the " "dialog by clicking Cancel to discard the " "changes made.

"); const char _wt_filterlist_up[] = I18N_NOOP("

Click this button to move the currently-" "selected filter up one in the list above.

" "

This is useful since the order of the filters in the list " "determines the order in which they are tried on messages: " "The topmost filter gets tried first.

" "

If you have clicked this button accidentally, you can undo this " "by clicking on the Down button.

"); const char _wt_filterlist_down[] = I18N_NOOP("

Click this button to move the currently-" "selected filter down one in the list above.

" "

This is useful since the order of the filters in the list " "determines the order in which they are tried on messages: " "The topmost filter gets tried first.

" "

If you have clicked this button accidentally, you can undo this " "by clicking on the Up button.

"); const char _wt_filterlist_top[] = I18N_NOOP("

Click this button to move the currently-" "selected filter to top of list.

" "

This is useful since the order of the filters in the list " "determines the order in which they are tried on messages: " "The topmost filter gets tried first.

"); const char _wt_filterlist_bottom[] = I18N_NOOP("

Click this button to move the currently-" "selected filter to bottom of list.

" "

This is useful since the order of the filters in the list " "determines the order in which they are tried on messages: " "The topmost filter gets tried first.

"); const char _wt_filterlist_rename[] = I18N_NOOP("

Click this button to rename the currently-selected filter.

" "

Filters are named automatically, as long as they start with " "\"<\".

" "

If you have renamed a filter accidentally and want automatic " "naming back, click this button and select Clear followed " "by OK in the appearing dialog.

"); //============================================================================= // // class KMFilterListBox (the filter list manipulator) // //============================================================================= using namespace MailCommon; KMFilterListBox::KMFilterListBox(const QString &title, QWidget *parent) : QGroupBox(title, parent) { QVBoxLayout *layout = new QVBoxLayout(); //----------- the list box mListWidget = new QListWidget(this); mListWidget->setMinimumWidth(150); mListWidget->setWhatsThis(i18n(_wt_filterlist)); mListWidget->setDragDropMode(QAbstractItemView::InternalMove); mListWidget->setSelectionMode(QAbstractItemView::ExtendedSelection); connect(mListWidget->model(), &QAbstractItemModel::rowsMoved, this, &KMFilterListBox::slotRowsMoved); mSearchListWidget = new KListWidgetSearchLine(this, mListWidget); mSearchListWidget->setPlaceholderText( i18nc("@info Displayed grayed-out inside the textbox, verb to search", "Search")); mSearchListWidget->installEventFilter(this); layout->addWidget(mSearchListWidget); layout->addWidget(mListWidget); //----------- the first row of buttons QWidget *hb = new QWidget(this); QHBoxLayout *hbHBoxLayout = new QHBoxLayout(hb); hbHBoxLayout->setContentsMargins(0, 0, 0, 0); hbHBoxLayout->setSpacing(4); mBtnTop = new QPushButton(QString(), hb); hbHBoxLayout->addWidget(mBtnTop); mBtnTop->setIcon(QIcon::fromTheme(QStringLiteral("go-top"))); - mBtnTop->setIconSize(QSize(KIconLoader::SizeSmall, KIconLoader::SizeSmall)); mBtnTop->setMinimumSize(mBtnTop->sizeHint() * 1.2); mBtnUp = new QPushButton(QString(), hb); hbHBoxLayout->addWidget(mBtnUp); mBtnUp->setAutoRepeat(true); mBtnUp->setIcon(QIcon::fromTheme(QStringLiteral("go-up"))); - mBtnUp->setIconSize(QSize(KIconLoader::SizeSmall, KIconLoader::SizeSmall)); mBtnUp->setMinimumSize(mBtnUp->sizeHint() * 1.2); mBtnDown = new QPushButton(QString(), hb); hbHBoxLayout->addWidget(mBtnDown); mBtnDown->setAutoRepeat(true); mBtnDown->setIcon(QIcon::fromTheme(QStringLiteral("go-down"))); - mBtnDown->setIconSize(QSize(KIconLoader::SizeSmall, KIconLoader::SizeSmall)); mBtnDown->setMinimumSize(mBtnDown->sizeHint() * 1.2); mBtnBottom = new QPushButton(QString(), hb); hbHBoxLayout->addWidget(mBtnBottom); mBtnBottom->setIcon(QIcon::fromTheme(QStringLiteral("go-bottom"))); - mBtnBottom->setIconSize(QSize(KIconLoader::SizeSmall, KIconLoader::SizeSmall)); mBtnBottom->setMinimumSize(mBtnBottom->sizeHint() * 1.2); mBtnUp->setToolTip(i18nc("Move selected filter up.", "Up")); mBtnDown->setToolTip(i18nc("Move selected filter down.", "Down")); mBtnTop->setToolTip(i18nc("Move selected filter to the top.", "Top")); mBtnBottom->setToolTip(i18nc("Move selected filter to the bottom.", "Bottom")); mBtnUp->setWhatsThis(i18n(_wt_filterlist_up)); mBtnDown->setWhatsThis(i18n(_wt_filterlist_down)); mBtnBottom->setWhatsThis(i18n(_wt_filterlist_bottom)); mBtnTop->setWhatsThis(i18n(_wt_filterlist_top)); layout->addWidget(hb); //----------- the second row of buttons hb = new QWidget(this); hbHBoxLayout = new QHBoxLayout(hb); hbHBoxLayout->setContentsMargins(0, 0, 0, 0); hbHBoxLayout->setSpacing(4); mBtnNew = new QPushButton(hb); hbHBoxLayout->addWidget(mBtnNew); mBtnNew->setIcon(QIcon::fromTheme(QStringLiteral("document-new"))); - mBtnNew->setIconSize(QSize(KIconLoader::SizeSmall, KIconLoader::SizeSmall)); mBtnNew->setMinimumSize(mBtnNew->sizeHint() * 1.2); mBtnCopy = new QPushButton(hb); hbHBoxLayout->addWidget(mBtnCopy); mBtnCopy->setIcon(QIcon::fromTheme(QStringLiteral("edit-copy"))); - mBtnCopy->setIconSize(QSize(KIconLoader::SizeSmall, KIconLoader::SizeSmall)); mBtnCopy->setMinimumSize(mBtnCopy->sizeHint() * 1.2); mBtnDelete = new QPushButton(hb); hbHBoxLayout->addWidget(mBtnDelete); mBtnDelete->setIcon(QIcon::fromTheme(QStringLiteral("edit-delete"))); - mBtnDelete->setIconSize(QSize(KIconLoader::SizeSmall, KIconLoader::SizeSmall)); mBtnDelete->setMinimumSize(mBtnDelete->sizeHint() * 1.2); mBtnRename = new QPushButton(hb); mBtnRename->setIcon(QIcon::fromTheme(QStringLiteral("edit-rename"))); - mBtnRename->setIconSize(QSize(KIconLoader::SizeSmall, KIconLoader::SizeSmall)); mBtnRename->setMinimumSize(mBtnDelete->sizeHint() * 1.2); hbHBoxLayout->addWidget(mBtnRename); mBtnNew->setToolTip(i18nc("@action:button in filter list manipulator", "New")); mBtnCopy->setToolTip(i18n("Copy")); mBtnDelete->setToolTip(i18n("Delete")); mBtnRename->setToolTip(i18n("Rename")); mBtnNew->setWhatsThis(i18n(_wt_filterlist_new)); mBtnCopy->setWhatsThis(i18n(_wt_filterlist_copy)); mBtnDelete->setWhatsThis(i18n(_wt_filterlist_delete)); mBtnRename->setWhatsThis(i18n(_wt_filterlist_rename)); layout->addWidget(hb); setLayout(layout); QShortcut *shortcut = new QShortcut(this); shortcut->setKey(Qt::Key_Delete); connect(shortcut, &QShortcut::activated, this, &KMFilterListBox::slotDelete); //----------- now connect everything connect(mListWidget, &QListWidget::currentRowChanged, this, &KMFilterListBox::slotSelected); connect(mListWidget, &QListWidget::itemDoubleClicked, this, &KMFilterListBox::slotRename); connect(mListWidget, &QListWidget::itemChanged, this, &KMFilterListBox::slotFilterEnabledChanged); connect(mListWidget, &QListWidget::itemSelectionChanged, this, &KMFilterListBox::slotSelectionChanged); connect(mBtnUp, &QPushButton::clicked, this, &KMFilterListBox::slotUp); connect(mBtnDown, &QPushButton::clicked, this, &KMFilterListBox::slotDown); connect(mBtnTop, &QPushButton::clicked, this, &KMFilterListBox::slotTop); connect(mBtnBottom, &QPushButton::clicked, this, &KMFilterListBox::slotBottom); connect(mBtnNew, &QPushButton::clicked, this, &KMFilterListBox::slotNew); connect(mBtnCopy, &QPushButton::clicked, this, &KMFilterListBox::slotCopy); connect(mBtnDelete, &QPushButton::clicked, this, &KMFilterListBox::slotDelete); connect(mBtnRename, &QPushButton::clicked, this, &KMFilterListBox::slotRename); // the dialog should call loadFilterList() // when all signals are connected. enableControls(); } KMFilterListBox::~KMFilterListBox() { } bool KMFilterListBox::eventFilter(QObject *obj, QEvent *event) { if (event->type() == QEvent::KeyPress && obj == mSearchListWidget) { QKeyEvent *key = static_cast(event); if ((key->key() == Qt::Key_Enter) || (key->key() == Qt::Key_Return)) { event->accept(); return true; } } return QGroupBox::eventFilter(obj, event); } bool KMFilterListBox::itemIsValid(QListWidgetItem *item) const { if (!item) { qCDebug(MAILCOMMON_LOG) << "Called while no filter is selected, ignoring."; return false; } if (item->isHidden()) { return false; } return true; } void KMFilterListBox::slotFilterEnabledChanged(QListWidgetItem *item) { if (!item) { qCDebug(MAILCOMMON_LOG) << "Called while no filter is selected, ignoring."; return; } QListWidgetFilterItem *itemFilter = static_cast(item); MailCommon::MailFilter *filter = itemFilter->filter(); filter->setEnabled((item->checkState() == Qt::Checked)); Q_EMIT filterUpdated(filter); } void KMFilterListBox::slotRowsMoved(const QModelIndex &, int sourcestart, int sourceEnd, const QModelIndex &, int destinationRow) { Q_UNUSED(sourceEnd); Q_UNUSED(sourcestart); Q_UNUSED(destinationRow); enableControls(); Q_EMIT filterOrderAltered(); } void KMFilterListBox::createFilter(const QByteArray &field, const QString &value) { SearchRule::Ptr newRule = SearchRule::createInstance(field, SearchRule::FuncContains, value); MailFilter *newFilter = new MailFilter(); newFilter->pattern()->append(newRule); newFilter->pattern()->setName(QStringLiteral("<%1>: %2"). arg(QString::fromLatin1(field)). arg(value)); FilterActionDesc *desc = MailCommon::FilterManager::filterActionDict()->value(QStringLiteral("transfer")); if (desc) { newFilter->actions()->append(desc->create()); } insertFilter(newFilter); enableControls(); } void KMFilterListBox::slotUpdateFilterName() { QListWidgetItem *item = mListWidget->currentItem(); if (!item) { qCDebug(MAILCOMMON_LOG) << "Called while no filter is selected, ignoring."; return; } QListWidgetFilterItem *itemFilter = static_cast(item); MailCommon::MailFilter *filter = itemFilter->filter(); SearchPattern *p = filter->pattern(); if (!p) { return; } QString shouldBeName = p->name(); QString displayedName = itemFilter->text(); if (shouldBeName.trimmed().isEmpty()) { filter->setAutoNaming(true); } if (filter->isAutoNaming()) { // auto-naming of patterns if (!p->isEmpty() && p->first() && !p->first()->field().trimmed().isEmpty()) { shouldBeName = QStringLiteral("<%1>: %2"). arg(QString::fromLatin1(p->first()->field())). arg(p->first()->contents()); } else { shouldBeName = QLatin1Char('<') + i18n("unnamed") + QLatin1Char('>'); } p->setName(shouldBeName); } if (displayedName == shouldBeName) { return; } filter->setToolbarName(shouldBeName); mListWidget->blockSignals(true); itemFilter->setText(shouldBeName); mListWidget->blockSignals(false); } void KMFilterListBox::slotAccepted() { applyFilterChanged(true); } void KMFilterListBox::slotApplied() { applyFilterChanged(false); } void KMFilterListBox::applyFilterChanged(bool closeAfterSaving) { if (mListWidget->currentItem()) { Q_EMIT applyWidgets(); slotSelected(mListWidget->currentRow()); } // by now all edit widgets should have written back // their widget's data into our filter list. bool wasCanceled = false; const QVector newFilters = filtersForSaving(closeAfterSaving, wasCanceled); if (!wasCanceled) { MailCommon::FilterManager::instance()->setFilters(newFilters); } } QVector KMFilterListBox::filtersForSaving(bool closeAfterSaving, bool &wasCanceled) const { Q_EMIT const_cast(this)->applyWidgets(); // signals aren't const QVector filters; QStringList emptyFilters; QVector listInvalidFilters; const int numberOfFilter(mListWidget->count()); for (int i = 0; i < numberOfFilter; ++i) { QListWidgetFilterItem *itemFilter = static_cast(mListWidget->item(i)); MailFilter *f = new MailFilter(*itemFilter->filter()); // deep copy const QString information = f->purify(); if (!f->isEmpty() && information.isEmpty()) { // the filter is valid: filters.append(f); } else { // the filter is invalid: emptyFilters << f->name(); listInvalidFilters.append(MailCommon::InvalidFilterInfo(f->name(), information)); delete f; } } // report on invalid filters: if (!emptyFilters.empty()) { QPointer dlg = new MailCommon::InvalidFilterDialog(nullptr); dlg->setInvalidFilters(listInvalidFilters); if (!dlg->exec()) { if (closeAfterSaving) { Q_EMIT abortClosing(); } wasCanceled = true; } delete dlg; } return filters; } void KMFilterListBox::slotSelectionChanged() { if (mListWidget->selectedItems().count() > 1) { Q_EMIT resetWidgets(); } enableControls(); } void KMFilterListBox::slotSelected(int aIdx) { if (aIdx >= 0 && aIdx < mListWidget->count()) { QListWidgetFilterItem *itemFilter = static_cast(mListWidget->item(aIdx)); MailFilter *f = itemFilter->filter(); if (f) { Q_EMIT filterSelected(f); } else { Q_EMIT resetWidgets(); } } else { Q_EMIT resetWidgets(); } enableControls(); } void KMFilterListBox::slotNew() { QListWidgetItem *item = mListWidget->currentItem(); if (item && item->isHidden()) { return; } // just insert a new filter. insertFilter(new MailFilter()); enableControls(); } void KMFilterListBox::slotCopy() { QListWidgetItem *item = mListWidget->currentItem(); if (!itemIsValid(item)) { return; } // make sure that all changes are written to the filter before we copy it Q_EMIT applyWidgets(); QListWidgetFilterItem *itemFilter = static_cast(item); MailFilter *filter = itemFilter->filter(); // enableControls should make sure this method is // never called when no filter is selected. Q_ASSERT(filter); // inserts a copy of the current filter. MailFilter *copyFilter = new MailFilter(*filter); copyFilter->generateRandomIdentifier(); copyFilter->setShortcut(QKeySequence()); insertFilter(copyFilter); enableControls(); } void KMFilterListBox::slotDelete() { QListWidgetItem *itemFirst = mListWidget->currentItem(); if (!itemIsValid(itemFirst)) { return; } const bool uniqFilterSelected = (mListWidget->selectedItems().count() == 1); QListWidgetFilterItem *itemFilter = static_cast(itemFirst); MailCommon::MailFilter *filter = itemFilter->filter(); const QString filterName = filter->pattern()->name(); if (uniqFilterSelected) { if (KMessageBox::questionYesNo( this, i18n("Do you want to remove the filter \"%1\"?", filterName), i18n("Remove Filter")) == KMessageBox::No) { return; } } else { if (KMessageBox::questionYesNo( this, i18n("Do you want to remove selected filters?"), i18n("Remove Filters")) == KMessageBox::No) { return; } } const int oIdxSelItem = mListWidget->currentRow(); QVector lst; Q_EMIT resetWidgets(); const QList lstItems = mListWidget->selectedItems(); for (QListWidgetItem *item : lstItems) { QListWidgetFilterItem *itemFilter = static_cast(item); MailCommon::MailFilter *filter = itemFilter->filter(); lst << filter; // remove the filter from both the listbox QListWidgetItem *item2 = mListWidget->takeItem(mListWidget->row(item)); delete item2; } const int count = mListWidget->count(); // and set the new current item. if (count > oIdxSelItem) { // oIdxItem is still a valid index mListWidget->setCurrentRow(oIdxSelItem); } else if (count) { // oIdxSelIdx is no longer valid, but the // list box isn't empty mListWidget->setCurrentRow(count - 1); } // work around a problem when deleting the first item in a QListWidget: // after takeItem, slotSelectionChanged is emitted with 1, but the row 0 // remains selected and another selectCurrentRow(0) does not trigger the // selectionChanged signal // (qt-copy as of 2006-12-22 / gungl) if (oIdxSelItem == 0) { slotSelected(0); } enableControls(); Q_EMIT filterRemoved(lst); } void KMFilterListBox::slotTop() { QList listWidgetItem = selectedFilter(); if (listWidgetItem.isEmpty()) { return; } const int numberOfItem(listWidgetItem.count()); if ((numberOfItem == 1) && (mListWidget->currentRow() == 0)) { qCDebug(MAILCOMMON_LOG) << "Called while the _topmost_ filter is selected, ignoring."; return; } QListWidgetItem *item = nullptr; bool wasMoved = false; for (int i = 0; i < numberOfItem; ++i) { const int posItem = mListWidget->row(listWidgetItem.at(i)); if (posItem == i) { continue; } item = mListWidget->takeItem(mListWidget->row(listWidgetItem.at(i))); mListWidget->insertItem(i, item); wasMoved = true; } if (wasMoved) { enableControls(); Q_EMIT filterOrderAltered(); } } QList KMFilterListBox::selectedFilter() { QList listWidgetItem; const int numberOfFilters = mListWidget->count(); for (int i = 0; i < numberOfFilters; ++i) { if (mListWidget->item(i)->isSelected() && !mListWidget->item(i)->isHidden()) { listWidgetItem << mListWidget->item(i); } } return listWidgetItem; } QStringList KMFilterListBox::selectedFilterId(SearchRule::RequiredPart &requiredPart, const QString &resource) const { QStringList listFilterId; requiredPart = SearchRule::Envelope; const int numberOfFilters = mListWidget->count(); for (int i = 0; i < numberOfFilters; ++i) { if (mListWidget->item(i)->isSelected() && !mListWidget->item(i)->isHidden()) { MailFilter *filter = static_cast(mListWidget->item(i))->filter(); if (!filter->isEmpty()) { const QString id = filter->identifier(); listFilterId << id; requiredPart = qMax(requiredPart, static_cast(mListWidget->item(i))->filter()->requiredPart(resource)); } } } return listFilterId; } void KMFilterListBox::slotBottom() { const QList listWidgetItem = selectedFilter(); if (listWidgetItem.isEmpty()) { return; } const int numberOfElement(mListWidget->count()); const int numberOfItem(listWidgetItem.count()); if ((numberOfItem == 1) && (mListWidget->currentRow() == numberOfElement - 1)) { qCDebug(MAILCOMMON_LOG) << "Called while the _last_ filter is selected, ignoring."; return; } QListWidgetItem *item = nullptr; int j = 0; bool wasMoved = false; for (int i = numberOfItem - 1; i >= 0; --i, j++) { const int posItem = mListWidget->row(listWidgetItem.at(i)); if (posItem == (numberOfElement - 1 - j)) { continue; } item = mListWidget->takeItem(mListWidget->row(listWidgetItem.at(i))); mListWidget->insertItem(numberOfElement - j, item); wasMoved = true; } if (wasMoved) { enableControls(); Q_EMIT filterOrderAltered(); } } void KMFilterListBox::slotUp() { const QList listWidgetItem = selectedFilter(); if (listWidgetItem.isEmpty()) { return; } const int numberOfItem(listWidgetItem.count()); if ((numberOfItem == 1) && (mListWidget->currentRow() == 0)) { qCDebug(MAILCOMMON_LOG) << "Called while the _topmost_ filter is selected, ignoring."; return; } bool wasMoved = false; for (int i = 0; i < numberOfItem; ++i) { const int posItem = mListWidget->row(listWidgetItem.at(i)); if (posItem == i) { continue; } swapNeighbouringFilters(posItem, posItem - 1); wasMoved = true; } if (wasMoved) { enableControls(); Q_EMIT filterOrderAltered(); } } void KMFilterListBox::slotDown() { const QList listWidgetItem = selectedFilter(); if (listWidgetItem.isEmpty()) { return; } const int numberOfElement(mListWidget->count()); const int numberOfItem(listWidgetItem.count()); if ((numberOfItem == 1) && (mListWidget->currentRow() == numberOfElement - 1)) { qCDebug(MAILCOMMON_LOG) << "Called while the _last_ filter is selected, ignoring."; return; } int j = 0; bool wasMoved = false; for (int i = numberOfItem - 1; i >= 0; --i, j++) { const int posItem = mListWidget->row(listWidgetItem.at(i)); if (posItem == (numberOfElement - 1 - j)) { continue; } swapNeighbouringFilters(posItem, posItem + 1); wasMoved = true; } if (wasMoved) { enableControls(); Q_EMIT filterOrderAltered(); } } void KMFilterListBox::slotRename() { QListWidgetItem *item = mListWidget->currentItem(); if (!itemIsValid(item)) { return; } QListWidgetFilterItem *itemFilter = static_cast(item); bool okPressed = false; MailFilter *filter = itemFilter->filter(); // enableControls should make sure this method is // never called when no filter is selected. Q_ASSERT(filter); // allow empty names - those will turn auto-naming on again QString newName = QInputDialog::getText(window(), i18n("Rename Filter"), i18n("Rename filter \"%1\" to:\n(leave the field empty for automatic naming)", filter->pattern()->name()), /*label*/ QLineEdit::Normal, filter->pattern()->name(), /* initial value */ &okPressed); if (!okPressed) { return; } if (newName.isEmpty()) { // bait for slotUpdateFilterName to // use automatic naming again. filter->pattern()->setName(QStringLiteral("<>")); filter->setAutoNaming(true); } else { filter->pattern()->setName(newName); filter->setAutoNaming(false); } slotUpdateFilterName(); Q_EMIT filterUpdated(filter); } void KMFilterListBox::enableControls() { const int currentIndex = mListWidget->currentRow(); const bool theFirst = (currentIndex == 0); const int numberOfElement(mListWidget->count()); const bool theLast = (currentIndex >= numberOfElement - 1); const bool aFilterIsSelected = (currentIndex >= 0); const int numberOfSelectedItem(mListWidget->selectedItems().count()); const bool uniqFilterSelected = (numberOfSelectedItem == 1); const bool allItemSelected = (numberOfSelectedItem == numberOfElement); mBtnUp->setEnabled(aFilterIsSelected && ((uniqFilterSelected && !theFirst) || (!uniqFilterSelected)) && !allItemSelected); mBtnDown->setEnabled(aFilterIsSelected && ((uniqFilterSelected && !theLast) || (!uniqFilterSelected)) && !allItemSelected); mBtnCopy->setEnabled(aFilterIsSelected && uniqFilterSelected); mBtnDelete->setEnabled(aFilterIsSelected); mBtnRename->setEnabled(aFilterIsSelected && uniqFilterSelected); mBtnTop->setEnabled(aFilterIsSelected && ((uniqFilterSelected && !theFirst) || (!uniqFilterSelected)) && !allItemSelected); mBtnBottom->setEnabled(aFilterIsSelected && ((uniqFilterSelected && !theLast) || (!uniqFilterSelected)) && !allItemSelected); if (aFilterIsSelected) { mListWidget->scrollToItem(mListWidget->currentItem()); } } void KMFilterListBox::loadFilterList(bool createDummyFilter) { Q_ASSERT(mListWidget); setEnabled(false); Q_EMIT resetWidgets(); // we don't want the insertion to // cause flicker in the edit widgets. blockSignals(true); // clear both lists mListWidget->clear(); const QVector filters = MailCommon::FilterManager::instance()->filters(); for (MailFilter *filter : filters) { QListWidgetFilterItem *item = new QListWidgetFilterItem(filter->pattern()->name(), mListWidget); item->setFilter(new MailFilter(*filter)); mListWidget->addItem(item); } blockSignals(false); setEnabled(true); // create an empty filter when there's none, to avoid a completely // disabled dialog (usability tests indicated that the new-filter // button is too hard to find that way): const int numberOfItem(mListWidget->count()); if (numberOfItem == 0) { if (createDummyFilter) { slotNew(); } } else { mListWidget->setCurrentRow(0); } enableControls(); } void KMFilterListBox::insertFilter(MailFilter *aFilter) { // must be really a filter... Q_ASSERT(aFilter); const int currentIndex = mListWidget->currentRow(); // if mIdxSelItem < 0, QListBox::insertItem will append. QListWidgetFilterItem *item = new QListWidgetFilterItem(aFilter->pattern()->name()); item->setFilter(aFilter); mListWidget->insertItem(currentIndex, item); mListWidget->clearSelection(); if (currentIndex < 0) { mListWidget->setCurrentRow(mListWidget->count() - 1); } else { // insert just before selected mListWidget->setCurrentRow(currentIndex); } Q_EMIT filterCreated(); Q_EMIT filterOrderAltered(); } void KMFilterListBox::appendFilter(MailFilter *aFilter) { QListWidgetFilterItem *item = new QListWidgetFilterItem(aFilter->pattern()->name(), mListWidget); item->setFilter(aFilter); mListWidget->addItem(item); Q_EMIT filterCreated(); } void KMFilterListBox::swapNeighbouringFilters(int untouchedOne, int movedOne) { // must be neighbours... Q_ASSERT(untouchedOne - movedOne == 1 || movedOne - untouchedOne == 1); // untouchedOne is at idx. to move it down(up), // remove item at idx+(-)1 w/o deleting it. QListWidgetItem *item = mListWidget->takeItem(movedOne); // now selected item is at idx(idx-1), so // insert the other item at idx, ie. above(below). mListWidget->insertItem(untouchedOne, item); } QListWidgetFilterItem::QListWidgetFilterItem(const QString &text, QListWidget *parent) : QListWidgetItem(text, parent) , mFilter(nullptr) { } QListWidgetFilterItem::~QListWidgetFilterItem() { delete mFilter; } void QListWidgetFilterItem::setFilter(MailCommon::MailFilter *filter) { mFilter = filter; setCheckState(filter->isEnabled() ? Qt::Checked : Qt::Unchecked); } MailCommon::MailFilter *QListWidgetFilterItem::filter() { return mFilter; } diff --git a/src/filter/soundtestwidget.cpp b/src/filter/soundtestwidget.cpp index 189af27..4aa1ba9 100644 --- a/src/filter/soundtestwidget.cpp +++ b/src/filter/soundtestwidget.cpp @@ -1,134 +1,132 @@ /* Copyright (c) 2001 Marc Mutz This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "soundtestwidget.h" -#include #include #include #include #include #include #include #include #include #include using namespace MailCommon; SoundTestWidget::SoundTestWidget(QWidget *parent) : QWidget(parent) { QHBoxLayout *layout = new QHBoxLayout(this); layout->setContentsMargins(0, 0, 0, 0); m_playButton = new QPushButton(this); m_playButton->setIcon(QIcon::fromTheme(QStringLiteral("arrow-right"))); - m_playButton->setIconSize(QSize(KIconLoader::SizeSmall, KIconLoader::SizeSmall)); m_playButton->setToolTip(i18n("Play")); layout->addWidget(m_playButton); m_urlRequester = new KUrlRequester(this); layout->addWidget(m_urlRequester); connect(m_playButton, &QPushButton::clicked, this, &SoundTestWidget::playSound); connect(m_urlRequester, &KUrlRequester::openFileDialog, this, &SoundTestWidget::openSoundDialog); connect(m_urlRequester->lineEdit(), &QLineEdit::textChanged, this, &SoundTestWidget::slotUrlChanged); slotUrlChanged(m_urlRequester->lineEdit()->text()); } SoundTestWidget::~SoundTestWidget() { } void SoundTestWidget::slotUrlChanged(const QString &url) { m_playButton->setEnabled(!url.isEmpty()); Q_EMIT textChanged(url); } void SoundTestWidget::openSoundDialog(KUrlRequester *) { static bool init = true; if (!init) { return; } init = false; QFileDialog *fileDialog = m_urlRequester->fileDialog(); fileDialog->setWindowTitle(i18n("Select Sound File")); QStringList filters; filters << QStringLiteral("audio/x-wav") << QStringLiteral("audio/mpeg") << QStringLiteral("application/ogg") << QStringLiteral("audio/x-adpcm"); fileDialog->setMimeTypeFilters(filters); const QStringList soundDirs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("sound/"), QStandardPaths::LocateDirectory); if (!soundDirs.isEmpty()) { QUrl soundURL; QDir dir; dir.setFilter(QDir::Files | QDir::Readable); for (const QString &soundDir : soundDirs) { dir = soundDir; if (dir.isReadable() && dir.count() > 2) { soundURL.setPath(soundDir); fileDialog->setDirectoryUrl(soundURL); break; } } } } void SoundTestWidget::playSound() { const QString parameter = m_urlRequester->lineEdit()->text(); if (parameter.isEmpty()) { return; } const QString file = QStringLiteral("file:"); const QString play = (parameter.startsWith(file) ? parameter.mid(file.length()) : parameter); Phonon::MediaObject *player = Phonon::createPlayer(Phonon::NotificationCategory, QUrl::fromLocalFile(play)); player->play(); connect(player, &Phonon::MediaObject::finished, player, &Phonon::MediaObject::deleteLater); } QString SoundTestWidget::url() const { return m_urlRequester->lineEdit()->text(); } void SoundTestWidget::setUrl(const QString &url) { m_urlRequester->lineEdit()->setText(url); } void SoundTestWidget::clear() { m_urlRequester->lineEdit()->clear(); } diff --git a/src/folder/folderrequester.cpp b/src/folder/folderrequester.cpp index aad5bd7..19c57ac 100644 --- a/src/folder/folderrequester.cpp +++ b/src/folder/folderrequester.cpp @@ -1,205 +1,203 @@ /* * Copyright (c) 2004 Carsten Burghardt * Copyright (c) 2009-2019 Montel Laurent * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 of the License * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of this program with any edition of * the Qt library by Trolltech AS, Norway (or with modified versions * of Qt that use the same license as Qt), and distribute linked * combinations including the two. You must obey the GNU General * Public License in all respects for all of the code used other than * Qt. If you modify this file, you may extend this exception to * your version of the file, but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from * your version. */ #include "folderrequester.h" #include "folderselectiondialog.h" #include "util/mailutil.h" #include "kernel/mailkernel.h" #include -#include #include #include #include #include #include #include namespace MailCommon { class FolderRequesterPrivate { public: FolderRequesterPrivate() { } Akonadi::Collection mCollection; KLineEdit *mEdit = nullptr; bool mMustBeReadWrite = false; bool mShowOutbox = false; bool mNotCreateNewFolder = false; }; FolderRequester::FolderRequester(QWidget *parent) : QWidget(parent) , d(new MailCommon::FolderRequesterPrivate) { QHBoxLayout *hlay = new QHBoxLayout(this); hlay->setContentsMargins(0, 0, 0, 0); d->mEdit = new KLineEdit(this); d->mEdit->setPlaceholderText(i18n("Select Folder")); d->mEdit->setTrapReturnKey(true); d->mEdit->setReadOnly(true); hlay->addWidget(d->mEdit); QToolButton *button = new QToolButton(this); button->setIcon(QIcon::fromTheme(QStringLiteral("folder"))); - button->setIconSize(QSize(KIconLoader::SizeSmall, KIconLoader::SizeSmall)); hlay->addWidget(button); connect(button, &QToolButton::clicked, this, &FolderRequester::slotOpenDialog); setSizePolicy(QSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed)); setFocusPolicy(Qt::StrongFocus); } //----------------------------------------------------------------------------- void FolderRequester::slotOpenDialog() { FolderSelectionDialog::SelectionFolderOptions options = FolderSelectionDialog::EnableCheck; options |= FolderSelectionDialog::HideVirtualFolder; options |= FolderSelectionDialog::NotUseGlobalSettings; if (d->mNotCreateNewFolder) { options |= FolderSelectionDialog::NotAllowToCreateNewFolder; } if (!d->mShowOutbox) { options |= FolderSelectionDialog::HideOutboxFolder; } QPointer dlg(new FolderSelectionDialog(this, options)); dlg->setWindowTitle(i18n("Select Folder")); dlg->setModal(false); dlg->setSelectedCollection(d->mCollection); if (dlg->exec() && dlg) { setCollection(dlg->selectedCollection(), false); } delete dlg; } //----------------------------------------------------------------------------- FolderRequester::~FolderRequester() { delete d; } Akonadi::Collection FolderRequester::collection() const { return d->mCollection; } void FolderRequester::setCollectionFullPath(const Akonadi::Collection &col) { if (KernelIf->collectionModel()) { d->mEdit->setText(Util::fullCollectionPath(col)); } else { d->mEdit->clear(); } } //----------------------------------------------------------------------------- void FolderRequester::setCollection(const Akonadi::Collection &collection, bool fetchCollection) { d->mCollection = collection; if (d->mCollection.isValid()) { if (fetchCollection) { Akonadi::CollectionFetchJob *job = new Akonadi::CollectionFetchJob(d->mCollection, Akonadi::CollectionFetchJob::Base, this); connect(job, &Akonadi::CollectionFetchJob::result, this, &FolderRequester::slotCollectionsReceived); } else { setCollectionFullPath(d->mCollection); } } else if (!d->mMustBeReadWrite) { // the Local Folders root node was selected d->mEdit->setText(i18n("Local Folders")); } Q_EMIT folderChanged(d->mCollection); } void FolderRequester::slotCollectionsReceived(KJob *job) { if (job->error()) { d->mCollection = Akonadi::Collection(); d->mEdit->setText(i18n("Please select a folder")); Q_EMIT invalidFolder(); return; } const Akonadi::CollectionFetchJob *fetchJob = qobject_cast(job); const Akonadi::Collection::List collections = fetchJob->collections(); if (!collections.isEmpty()) { const Akonadi::Collection collection = collections.first(); // in case this is still the collection we are interested in, update if (collection.id() == d->mCollection.id()) { d->mCollection = collection; setCollectionFullPath(collection); } } else { // the requested collection doesn't exists anymore d->mCollection = Akonadi::Collection(); d->mEdit->setText(i18n("Please select a folder")); Q_EMIT invalidFolder(); } } bool FolderRequester::hasCollection() const { return d->mCollection.isValid(); } //----------------------------------------------------------------------------- void FolderRequester::keyPressEvent(QKeyEvent *e) { if (e->key() == Qt::Key_Space) { slotOpenDialog(); } else { e->ignore(); } } void FolderRequester::setMustBeReadWrite(bool readwrite) { d->mMustBeReadWrite = readwrite; } void FolderRequester::setShowOutbox(bool show) { d->mShowOutbox = show; } void FolderRequester::setNotAllowToCreateNewFolder(bool notCreateNewFolder) { d->mNotCreateNewFolder = notCreateNewFolder; } } // namespace MailCommon diff --git a/src/widgets/redirectwidget.cpp b/src/widgets/redirectwidget.cpp index d443f32..445c7e9 100644 --- a/src/widgets/redirectwidget.cpp +++ b/src/widgets/redirectwidget.cpp @@ -1,106 +1,104 @@ /* Copyright (c) 2015-2019 Montel Laurent This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "redirectwidget.h" #include "kernel/mailkernel.h" #include -#include #include #include #include #include #include #include using namespace MailCommon; RedirectWidget::RedirectWidget(QWidget *parent) : QWidget(parent) { QHBoxLayout *hbox = new QHBoxLayout(this); hbox->setSpacing(0); hbox->setContentsMargins(0, 0, 0, 0); hbox->setAlignment(Qt::AlignRight); mEdit = new MessageComposer::ComposerLineEdit(true); mEdit->setRecentAddressConfig(KernelIf->config().data()); mEdit->setMinimumWidth(300); mEdit->setClearButtonEnabled(true); hbox->addWidget(mEdit); QPushButton *BtnTo = new QPushButton(this); BtnTo->setIcon(QIcon::fromTheme(QStringLiteral("help-contents"))); - BtnTo->setIconSize(QSize(KIconLoader::SizeSmall, KIconLoader::SizeSmall)); BtnTo->setToolTip(i18n("Use the Address-Selection Dialog")); BtnTo->setWhatsThis(i18n("This button opens a separate dialog " "where you can select recipients out " "of all available addresses.")); hbox->addWidget(BtnTo); connect(BtnTo, &QAbstractButton::clicked, this, &RedirectWidget::slotAddressSelection); connect(mEdit, &QLineEdit::textChanged, this, &RedirectWidget::addressChanged); setFocusPolicy(Qt::StrongFocus); setFocusProxy(mEdit); } RedirectWidget::~RedirectWidget() { } QString RedirectWidget::resend() { mResendStr = mEdit->text(); return mResendStr; } void RedirectWidget::setFocus() { mEdit->setFocus(); } void RedirectWidget::slotAddressSelection() { std::unique_ptr dlg( new Akonadi::EmailAddressSelectionDialog(this)); dlg->view()->view()->setSelectionMode(QAbstractItemView::MultiSelection); mResendStr = mEdit->text(); if (dlg->exec() != QDialog::Rejected && dlg) { QStringList addresses; const Akonadi::EmailAddressSelection::List lstAddress = dlg->selectedAddresses(); addresses.reserve(lstAddress.count()); for (const Akonadi::EmailAddressSelection &selection : lstAddress) { addresses << selection.quotedEmail(); } if (!mResendStr.isEmpty()) { addresses.prepend(mResendStr); } mEdit->setText(addresses.join(QLatin1String(", "))); mEdit->setModified(true); } }