File indexing completed on 2024-11-24 04:48:16
0001 /* 0002 This file is part of KOrganizer. 0003 0004 SPDX-FileCopyrightText: 2001 Cornelius Schumacher <schumacher@kde.org> 0005 SPDX-FileCopyrightText: 2004 Reinhold Kainhofer <reinhold@kainhofer.com> 0006 SPDX-FileCopyrightText: 2005 Thomas Zander <zander@kde.org> 0007 0008 SPDX-License-Identifier: GPL-2.0-or-later WITH Qt-Commercial-exception-1.0 0009 */ 0010 0011 #include "filtereditdialog.h" 0012 #include "korganizer_debug.h" 0013 #include <KStatefulBrush> 0014 0015 #include <KCalendarCore/CalFilter> 0016 0017 #include <KLineEditEventHandler> 0018 0019 #include <Akonadi/TagSelectionDialog> 0020 0021 #include <PimCommon/PimUtil> 0022 0023 #include <KColorScheme> 0024 #include <KMessageBox> 0025 0026 #include <QDialogButtonBox> 0027 0028 FilterEditDialog::FilterEditDialog(QList<KCalendarCore::CalFilter *> *filters, QWidget *parent) 0029 : QDialog(parent) 0030 { 0031 setWindowTitle(i18nc("@title::window", "Edit Calendar Filters")); 0032 auto mainLayout = new QVBoxLayout(this); 0033 0034 auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel | QDialogButtonBox::Apply, this); 0035 mOkButton = buttonBox->button(QDialogButtonBox::Ok); 0036 mApplyButton = buttonBox->button(QDialogButtonBox::Apply); 0037 mOkButton->setDefault(true); 0038 mOkButton->setShortcut(Qt::CTRL | Qt::Key_Return); 0039 connect(buttonBox, &QDialogButtonBox::accepted, this, &FilterEditDialog::slotOk); 0040 connect(buttonBox, &QDialogButtonBox::rejected, this, &FilterEditDialog::reject); 0041 mainLayout->addWidget(mFilterEdit = new FilterEdit(filters, this)); 0042 mainLayout->addWidget(buttonBox); 0043 0044 connect(mFilterEdit, &FilterEdit::dataConsistent, this, &FilterEditDialog::setDialogConsistent); 0045 updateFilterList(); 0046 connect(mFilterEdit, &FilterEdit::editCategories, this, &FilterEditDialog::editCategories); 0047 connect(mFilterEdit, &FilterEdit::filterChanged, this, &FilterEditDialog::filterChanged); 0048 connect(buttonBox->button(QDialogButtonBox::Apply), &QPushButton::clicked, this, &FilterEditDialog::slotApply); 0049 } 0050 0051 FilterEditDialog::~FilterEditDialog() 0052 { 0053 delete mFilterEdit; 0054 mFilterEdit = nullptr; 0055 } 0056 0057 void FilterEditDialog::updateFilterList() 0058 { 0059 mFilterEdit->updateFilterList(); 0060 } 0061 0062 void FilterEditDialog::slotApply() 0063 { 0064 mFilterEdit->saveChanges(); 0065 } 0066 0067 void FilterEditDialog::slotOk() 0068 { 0069 slotApply(); 0070 accept(); 0071 } 0072 0073 void FilterEditDialog::setDialogConsistent(bool consistent) 0074 { 0075 mOkButton->setEnabled(consistent); 0076 mApplyButton->setEnabled(consistent); 0077 } 0078 0079 FilterEdit::FilterEdit(QList<KCalendarCore::CalFilter *> *filters, QWidget *parent) 0080 : QWidget(parent) 0081 { 0082 setupUi(this); 0083 searchline->setListWidget(mRulesList); 0084 KLineEditEventHandler::catchReturnKey(mNameLineEdit); 0085 mDetailsFrame->setEnabled(false); 0086 mFilters = filters; 0087 mNewButton->setWhatsThis(i18nc("@info:whatsthis", "Press this button to define a new filter.")); 0088 mDeleteButton->setWhatsThis(i18nc("@info:whatsthis", "Press this button to remove the currently active filter.")); 0089 0090 connect(mRulesList, &QListWidget::itemSelectionChanged, this, qOverload<>(&FilterEdit::filterSelected)); 0091 0092 connect(mNewButton, &QPushButton::clicked, this, &FilterEdit::bNewPressed); 0093 connect(mDeleteButton, &QPushButton::clicked, this, &FilterEdit::bDeletePressed); 0094 connect(mNameLineEdit, &QLineEdit::textChanged, this, &FilterEdit::updateSelectedName); 0095 connect(mCatEditButton, &QPushButton::clicked, this, &FilterEdit::editCategorySelection); 0096 connect(mCompletedCheck, &QCheckBox::toggled, mCompletedTimeSpanLabel, &QLabel::setEnabled); 0097 connect(mCompletedCheck, &QCheckBox::toggled, mCompletedTimeSpan, &QSpinBox::setEnabled); 0098 } 0099 0100 FilterEdit::~FilterEdit() = default; 0101 0102 void FilterEdit::updateFilterList() 0103 { 0104 mRulesList->clear(); 0105 if (!mFilters || mFilters->empty()) { 0106 mDetailsFrame->setEnabled(false); 0107 Q_EMIT dataConsistent(false); 0108 } else { 0109 QList<KCalendarCore::CalFilter *>::iterator i; 0110 QList<KCalendarCore::CalFilter *>::iterator end(mFilters->end()); 0111 for (i = mFilters->begin(); i != end; ++i) { 0112 if (*i) { 0113 mRulesList->addItem((*i)->name()); 0114 } 0115 } 0116 if (mRulesList->currentRow() != -1) { 0117 KCalendarCore::CalFilter *f = mFilters->at(mRulesList->currentRow()); 0118 if (f) { 0119 filterSelected(f); 0120 } 0121 } 0122 Q_EMIT dataConsistent(true); 0123 } 0124 if (mFilters && !mFilters->isEmpty() && !mCurrent) { 0125 filterSelected(mFilters->at(0)); 0126 } 0127 if (mFilters) { 0128 mDeleteButton->setEnabled(!mFilters->isEmpty()); 0129 } 0130 } 0131 0132 void FilterEdit::saveChanges() 0133 { 0134 if (!mCurrent) { 0135 return; 0136 } 0137 0138 mCurrent->setName(mNameLineEdit->text()); 0139 int criteria = 0; 0140 if (mCompletedCheck->isChecked()) { 0141 criteria |= KCalendarCore::CalFilter::HideCompletedTodos; 0142 } 0143 if (mRecurringCheck->isChecked()) { 0144 criteria |= KCalendarCore::CalFilter::HideRecurring; 0145 } 0146 if (mCatShowCheck->isChecked()) { 0147 criteria |= KCalendarCore::CalFilter::ShowCategories; 0148 } 0149 if (mHideInactiveTodosCheck->isChecked()) { 0150 criteria |= KCalendarCore::CalFilter::HideInactiveTodos; 0151 } 0152 if (mHideTodosNotAssignedToMeCheck->isChecked()) { 0153 criteria |= KCalendarCore::CalFilter::HideNoMatchingAttendeeTodos; 0154 } 0155 mCurrent->setCriteria(criteria); 0156 mCurrent->setCompletedTimeSpan(mCompletedTimeSpan->value()); 0157 0158 QStringList categoryList; 0159 const int numberOfCat(mCatList->count()); 0160 categoryList.reserve(numberOfCat); 0161 for (int i = 0; i < numberOfCat; ++i) { 0162 QListWidgetItem *item = mCatList->item(i); 0163 if (item) { 0164 categoryList.append(item->text()); 0165 } 0166 } 0167 mCurrent->setCategoryList(categoryList); 0168 Q_EMIT filterChanged(); 0169 } 0170 0171 void FilterEdit::filterSelected() 0172 { 0173 if (mRulesList->currentRow() < mFilters->count()) { 0174 mDetailsFrame->setEnabled(true); 0175 filterSelected(mFilters->at(mRulesList->currentRow())); 0176 } 0177 } 0178 0179 void FilterEdit::filterSelected(KCalendarCore::CalFilter *filter) 0180 { 0181 if (!filter || filter == mCurrent) { 0182 return; 0183 } 0184 qCDebug(KORGANIZER_LOG) << "Selected filter" << filter->name(); 0185 saveChanges(); 0186 0187 mCurrent = filter; 0188 mNameLineEdit->blockSignals(true); 0189 mNameLineEdit->setText(mCurrent->name()); 0190 mNameLineEdit->blockSignals(false); 0191 mDetailsFrame->setEnabled(true); 0192 mCompletedCheck->setChecked(mCurrent->criteria() & KCalendarCore::CalFilter::HideCompletedTodos); 0193 mCompletedTimeSpan->setValue(mCurrent->completedTimeSpan()); 0194 mRecurringCheck->setChecked(mCurrent->criteria() & KCalendarCore::CalFilter::HideRecurring); 0195 mHideInactiveTodosCheck->setChecked(mCurrent->criteria() & KCalendarCore::CalFilter::HideInactiveTodos); 0196 mHideTodosNotAssignedToMeCheck->setChecked(mCurrent->criteria() & KCalendarCore::CalFilter::HideNoMatchingAttendeeTodos); 0197 0198 if (mCurrent->criteria() & KCalendarCore::CalFilter::ShowCategories) { 0199 mCatShowCheck->setChecked(true); 0200 } else { 0201 mCatHideCheck->setChecked(true); 0202 } 0203 mCatList->clear(); 0204 mCatList->addItems(mCurrent->categoryList()); 0205 } 0206 0207 void FilterEdit::bNewPressed() 0208 { 0209 mDetailsFrame->setEnabled(true); 0210 saveChanges(); 0211 QStringList filterNames; 0212 const int numRules = mRulesList->count(); 0213 filterNames.reserve(numRules); 0214 for (int i = 0; i < numRules; ++i) { 0215 filterNames << mRulesList->item(i)->text(); 0216 } 0217 QString newFilterName; 0218 for (int i = 1;; ++i) { 0219 newFilterName = i18nc("@label default filter name", "New Filter %1", i); 0220 if (!filterNames.contains(newFilterName)) { 0221 break; 0222 } 0223 } 0224 0225 auto newFilter = new KCalendarCore::CalFilter(newFilterName); 0226 mFilters->append(newFilter); 0227 updateFilterList(); 0228 mRulesList->setCurrentRow(mRulesList->count() - 1); 0229 Q_EMIT filterChanged(); 0230 } 0231 0232 void FilterEdit::bDeletePressed() 0233 { 0234 if (!mRulesList->currentItem()) { // nothing selected 0235 return; 0236 } 0237 if (mFilters->isEmpty()) { // We need at least a default filter object. 0238 return; 0239 } 0240 0241 if (KMessageBox::warningContinueCancel(this, 0242 i18nc("@info", "Do you really want to permanently remove the filter \"%1\"?", mCurrent->name()), 0243 i18nc("@title:window", "Delete Filter?"), 0244 KStandardGuiItem::del()) 0245 == KMessageBox::Cancel) { 0246 return; 0247 } 0248 0249 int selected = mRulesList->currentRow(); 0250 KCalendarCore::CalFilter *filter = mFilters->at(selected); 0251 mFilters->removeAll(filter); 0252 delete filter; 0253 mCurrent = nullptr; 0254 updateFilterList(); 0255 mRulesList->setCurrentRow(qMin(mRulesList->count() - 1, selected)); 0256 Q_EMIT filterChanged(); 0257 } 0258 0259 void FilterEdit::updateSelectedName(const QString &newText) 0260 { 0261 mRulesList->blockSignals(true); 0262 QListWidgetItem *item = mRulesList->currentItem(); 0263 if (item) { 0264 item->setText(newText); 0265 } 0266 mRulesList->blockSignals(false); 0267 if (correctName(newText)) { 0268 Q_EMIT dataConsistent(false); 0269 return; 0270 } 0271 bool allOk = true; 0272 0273 for (KCalendarCore::CalFilter *i : std::as_const(*mFilters)) { 0274 if (i && i->name().isEmpty()) { 0275 allOk = false; 0276 } 0277 } 0278 0279 Q_EMIT dataConsistent(allOk); 0280 } 0281 0282 bool FilterEdit::correctName(const QString &newText) 0283 { 0284 bool negative = false; 0285 #ifndef QT_NO_STYLE_STYLESHEET 0286 QString styleSheet; 0287 if (mNegativeBackground.isEmpty()) { 0288 const KStatefulBrush bgBrush = KStatefulBrush(KColorScheme::View, KColorScheme::NegativeBackground); 0289 mNegativeBackground = QStringLiteral("QLineEdit{ background-color:%1 }").arg(bgBrush.brush(mNameLineEdit->palette()).color().name()); 0290 } 0291 if (!newText.isEmpty()) { 0292 const int val = mRulesList->count(); 0293 for (int i = 0; i < val; ++i) { 0294 QListWidgetItem *item = mRulesList->item(i); 0295 if (item && (mRulesList->currentItem() != item)) { 0296 if (newText == item->text()) { 0297 negative = true; 0298 break; 0299 } 0300 } 0301 } 0302 } else { 0303 negative = true; 0304 } 0305 if (negative) { 0306 styleSheet = mNegativeBackground; 0307 } 0308 mNameLineEdit->setStyleSheet(styleSheet); 0309 #endif 0310 return negative; 0311 } 0312 0313 void FilterEdit::editCategorySelection() 0314 { 0315 if (!mCurrent) { 0316 return; 0317 } 0318 0319 if (!mCategorySelectDialog) { 0320 mCategorySelectDialog = new Akonadi::TagSelectionDialog(this); 0321 QDialogButtonBox *buttons = mCategorySelectDialog->buttons(); 0322 if (buttons) { 0323 buttons->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel | QDialogButtonBox::Help); 0324 connect(mCategorySelectDialog, &Akonadi::TagSelectionDialog::accepted, this, &FilterEdit::updateCategorySelection); 0325 connect(buttons->button(QDialogButtonBox::Help), &QPushButton::clicked, this, &FilterEdit::slotHelp); 0326 } 0327 } 0328 Akonadi::Tag::List tags; 0329 const auto names = mCurrent->categoryList(); 0330 tags.resize(names.size()); 0331 std::transform(names.cbegin(), names.cend(), std::back_inserter(tags), [](const QString &name) { 0332 return Akonadi::Tag{name}; 0333 }); 0334 mCategorySelectDialog->setSelection(tags); 0335 0336 mCategorySelectDialog->show(); 0337 } 0338 0339 void FilterEdit::slotHelp() 0340 { 0341 PimCommon::Util::invokeHelp(QStringLiteral("korganizer/filters-view.html")); 0342 } 0343 0344 void FilterEdit::updateCategorySelection() 0345 { 0346 const auto tags = mCategorySelectDialog->selection(); 0347 QStringList categories; 0348 categories.reserve(tags.size()); 0349 std::transform(tags.cbegin(), tags.cend(), std::back_inserter(categories), std::bind(&Akonadi::Tag::name, std::placeholders::_1)); 0350 mCatList->clear(); 0351 mCatList->addItems(categories); 0352 mCurrent->setCategoryList(categories); 0353 } 0354 0355 #include "moc_filtereditdialog.cpp"