File indexing completed on 2024-05-12 16:46:05
0001 /*************************************************************************** 0002 Copyright (C) 2003-2009 Robby Stephenson <robby@periapsis.org> 0003 ***************************************************************************/ 0004 0005 /*************************************************************************** 0006 * * 0007 * This program is free software; you can redistribute it and/or * 0008 * modify it under the terms of the GNU General Public License as * 0009 * published by the Free Software Foundation; either version 2 of * 0010 * the License or (at your option) version 3 or any later version * 0011 * accepted by the membership of KDE e.V. (or its successor approved * 0012 * by the membership of KDE e.V.), which shall act as a proxy * 0013 * defined in Section 14 of version 3 of the license. * 0014 * * 0015 * This program is distributed in the hope that it will be useful, * 0016 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0018 * GNU General Public License for more details. * 0019 * * 0020 * You should have received a copy of the GNU General Public License * 0021 * along with this program. If not, see <http://www.gnu.org/licenses/>. * 0022 * * 0023 ***************************************************************************/ 0024 0025 // The layout borrows heavily from kmsearchpatternedit.cpp in kmail 0026 // which is authored by Marc Mutz <Marc@Mutz.com> under the GPL 0027 0028 #include "filterrulewidget.h" 0029 #include "combobox.h" 0030 #include "../document.h" 0031 #include "../fieldcompletion.h" 0032 #include "../tellico_debug.h" 0033 0034 #include <KLocalizedString> 0035 #include <KComboBox> 0036 #include <KLineEdit> 0037 #include <KServiceTypeTrader> 0038 #include <KRegExpEditorInterface> 0039 #include <KDateComboBox> 0040 0041 #include <QDialog> 0042 #include <QHBoxLayout> 0043 #include <QStackedWidget> 0044 #include <QPushButton> 0045 0046 using Tellico::FilterRuleWidget; 0047 0048 FilterRuleWidget::FilterRuleWidget(Tellico::FilterRule* rule_, QWidget* parent_) 0049 : QWidget(parent_), m_ruleDate(nullptr), m_editRegExp(nullptr), m_editRegExpDialog(nullptr), m_ruleType(General) { 0050 QHBoxLayout* l = new QHBoxLayout(this); 0051 l->setMargin(0); 0052 // l->setSizeConstraint(QLayout::SetFixedSize); 0053 setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); 0054 0055 initLists(); 0056 initWidget(); 0057 0058 if(rule_) { 0059 setRule(rule_); 0060 } else { 0061 reset(); 0062 } 0063 } 0064 0065 void FilterRuleWidget::initLists() { 0066 //---------- initialize list of filter fields 0067 if(m_ruleFieldList.isEmpty()) { 0068 m_ruleFieldList.append(QLatin1Char('<') + i18n("Any Field") + QLatin1Char('>')); 0069 QStringList titles = Data::Document::self()->collection()->fieldTitles(); 0070 titles.sort(); 0071 m_ruleFieldList += titles; 0072 } 0073 0074 } 0075 0076 void FilterRuleWidget::initWidget() { 0077 m_ruleField = new KComboBox(this); 0078 layout()->addWidget(m_ruleField); 0079 void (KComboBox::* activatedInt)(int) = &KComboBox::activated; 0080 connect(m_ruleField, activatedInt, this, &FilterRuleWidget::signalModified); 0081 connect(m_ruleField, activatedInt, this, &FilterRuleWidget::slotRuleFieldChanged); 0082 0083 m_ruleFunc = new GUI::ComboBox(this); 0084 layout()->addWidget(m_ruleFunc); 0085 connect(m_ruleFunc, activatedInt, this, &FilterRuleWidget::signalModified); 0086 connect(m_ruleFunc, activatedInt, this, &FilterRuleWidget::slotRuleFunctionChanged); 0087 0088 m_valueStack = new QStackedWidget(this); 0089 layout()->addWidget(m_valueStack); 0090 0091 m_ruleValue = new KLineEdit(m_valueStack); //krazy:exclude=qclasses 0092 connect(m_ruleValue, &QLineEdit::textChanged, this, &FilterRuleWidget::signalModified); 0093 m_valueStack->addWidget(m_ruleValue); 0094 0095 m_ruleDate = new KDateComboBox(m_valueStack); 0096 connect(m_ruleDate, &KDateComboBox::dateChanged, this, &FilterRuleWidget::signalModified); 0097 m_valueStack->addWidget(m_ruleDate); 0098 0099 if(!KServiceTypeTrader::self()->query(QStringLiteral("KRegExpEditor/KRegExpEditor")).isEmpty()) { 0100 m_editRegExp = new QPushButton(i18n("Edit..."), this); 0101 connect(m_editRegExp, &QAbstractButton::clicked, this, &FilterRuleWidget::slotEditRegExp); 0102 } 0103 0104 m_ruleField->addItems(m_ruleFieldList); 0105 updateFunctionList(); 0106 slotRuleFunctionChanged(m_ruleFunc->currentIndex()); 0107 } 0108 0109 void FilterRuleWidget::slotEditRegExp() { 0110 if(!m_editRegExpDialog) { 0111 m_editRegExpDialog = KServiceTypeTrader::createInstanceFromQuery<QDialog>(QStringLiteral("KRegExpEditor/KRegExpEditor"), 0112 QString(), this); //krazy:exclude=qclasses 0113 } 0114 0115 if(!m_editRegExpDialog) { 0116 myWarning() << "no dialog"; 0117 return; 0118 } 0119 0120 KRegExpEditorInterface* iface = ::qobject_cast<KRegExpEditorInterface*>(m_editRegExpDialog); 0121 if(iface) { 0122 iface->setRegExp(m_ruleValue->text()); 0123 if(m_editRegExpDialog->exec() == QDialog::Accepted) { 0124 m_ruleValue->setText(iface->regExp()); 0125 } 0126 } 0127 } 0128 0129 void FilterRuleWidget::slotRuleFieldChanged(int which_) { 0130 Q_UNUSED(which_); 0131 m_ruleType = General; 0132 QString fieldTitle = m_ruleField->currentText(); 0133 if(fieldTitle.isEmpty() || fieldTitle[0] == QLatin1Char('<')) { 0134 m_ruleValue->setCompletionObject(nullptr); 0135 updateFunctionList(); 0136 return; 0137 } 0138 Data::FieldPtr field = Data::Document::self()->collection()->fieldByTitle(fieldTitle); 0139 if(field && field->hasFlag(Data::Field::AllowCompletion)) { 0140 FieldCompletion* completion = new FieldCompletion(field->hasFlag(Data::Field::AllowMultiple)); 0141 completion->setItems(Data::Document::self()->collection()->valuesByFieldName(field->name())); 0142 completion->setIgnoreCase(true); 0143 m_ruleValue->setCompletionObject(completion); 0144 m_ruleValue->setAutoDeleteCompletionObject(true); 0145 } else { 0146 m_ruleValue->setCompletionObject(nullptr); 0147 } 0148 0149 if(field) { 0150 if(field->type() == Data::Field::Date) { 0151 m_ruleType = Date; 0152 } else if(field->type() == Data::Field::Number || field->type() == Data::Field::Rating) { 0153 m_ruleType = Number; 0154 } else if(field->type() == Data::Field::Image) { 0155 m_ruleType = Image; 0156 } 0157 } 0158 updateFunctionList(); 0159 } 0160 0161 void FilterRuleWidget::slotRuleFunctionChanged(int which_) { 0162 const QVariant data = m_ruleFunc->itemData(which_); 0163 if(m_editRegExp) { 0164 m_editRegExp->setEnabled(data == FilterRule::FuncRegExp || 0165 data == FilterRule::FuncNotRegExp); 0166 } 0167 0168 // don't show the date picker if we're using regular expressions 0169 if(m_ruleType == Date && data != FilterRule::FuncRegExp && data != FilterRule::FuncNotRegExp) { 0170 m_valueStack->setCurrentWidget(m_ruleDate); 0171 } else { 0172 m_valueStack->setCurrentWidget(m_ruleValue); 0173 m_ruleValue->setPlaceholderText(QString()); 0174 if(m_ruleType == Number && 0175 (data != FilterRule::FuncRegExp && data != FilterRule::FuncNotRegExp)) { 0176 m_ruleValue->setValidator(new QIntValidator(this)); 0177 } else { 0178 m_ruleValue->setValidator(nullptr); 0179 } 0180 } 0181 } 0182 0183 void FilterRuleWidget::setRule(const Tellico::FilterRule* rule_) { 0184 if(!rule_) { 0185 reset(); 0186 return; 0187 } 0188 0189 blockSignals(true); 0190 0191 m_ruleType = General; 0192 if(rule_->fieldName().isEmpty()) { 0193 m_ruleField->setCurrentIndex(0); // "All Fields" 0194 } else { 0195 Data::FieldPtr field = Data::Document::self()->collection()->fieldByName(rule_->fieldName()); 0196 if(field && field->type() == Data::Field::Date) { 0197 m_ruleType = Date; 0198 const QDate date = QDate::fromString(rule_->pattern(), Qt::ISODate); 0199 if(date.isValid()) { 0200 m_ruleDate->setDate(date); 0201 } 0202 } 0203 const int idx = m_ruleField->findText(field ? field->title() : QString()); 0204 m_ruleField->setCurrentIndex(idx); 0205 } 0206 0207 // update the rulle fields first, before possible values 0208 slotRuleFieldChanged(m_ruleField->currentIndex()); 0209 0210 //--------------set function and contents 0211 m_ruleFunc->setCurrentData(rule_->function()); 0212 m_ruleValue->setText(rule_->pattern()); 0213 0214 slotRuleFunctionChanged(m_ruleFunc->currentIndex()); 0215 blockSignals(false); 0216 } 0217 0218 Tellico::FilterRule* FilterRuleWidget::rule() const { 0219 QString fieldName; // empty string 0220 if(m_ruleField->currentIndex() > 0) { // 0 is "All Fields", field is empty 0221 fieldName = Data::Document::self()->collection()->fieldNameByTitle(m_ruleField->currentText()); 0222 } 0223 0224 QString ruleValue; 0225 if(m_valueStack->currentWidget() == m_ruleDate) { 0226 ruleValue = m_ruleDate->date().toString(Qt::ISODate); 0227 } else { 0228 ruleValue = m_ruleValue->text().trimmed(); 0229 } 0230 0231 return new FilterRule(fieldName, ruleValue, 0232 static_cast<FilterRule::Function>(m_ruleFunc->currentData().toInt())); 0233 } 0234 0235 void FilterRuleWidget::reset() { 0236 // myDebug(); 0237 blockSignals(true); 0238 0239 m_ruleField->setCurrentIndex(0); 0240 m_ruleFunc->setCurrentIndex(0); 0241 m_ruleValue->clear(); 0242 0243 if(m_editRegExp) { 0244 m_editRegExp->setEnabled(false); 0245 } 0246 0247 blockSignals(false); 0248 } 0249 0250 void FilterRuleWidget::setFocus() { 0251 m_ruleValue->setFocus(); 0252 } 0253 0254 void FilterRuleWidget::updateFunctionList() { 0255 Q_ASSERT(m_ruleFunc); 0256 const QVariant data = m_ruleFunc->currentData(); 0257 m_ruleFunc->clear(); 0258 switch(m_ruleType) { 0259 case Date: 0260 m_ruleFunc->addItem(i18n("equals"), FilterRule::FuncEquals); 0261 m_ruleFunc->addItem(i18n("does not equal"), FilterRule::FuncNotEquals); 0262 m_ruleFunc->addItem(i18n("matches regular expression"), FilterRule::FuncRegExp); 0263 m_ruleFunc->addItem(i18n("does not match regular expression"), FilterRule::FuncNotRegExp); 0264 m_ruleFunc->addItem(i18nc("is before a date", "is before"), FilterRule::FuncBefore); 0265 m_ruleFunc->addItem(i18nc("is after a date", "is after"), FilterRule::FuncAfter); 0266 break; 0267 case Number: 0268 m_ruleFunc->addItem(i18n("equals"), FilterRule::FuncEquals); 0269 m_ruleFunc->addItem(i18n("does not equal"), FilterRule::FuncNotEquals); 0270 m_ruleFunc->addItem(i18n("matches regular expression"), FilterRule::FuncRegExp); 0271 m_ruleFunc->addItem(i18n("does not match regular expression"), FilterRule::FuncNotRegExp); 0272 m_ruleFunc->addItem(i18nc("is less than a number", "is less than"), FilterRule::FuncLess); 0273 m_ruleFunc->addItem(i18nc("is greater than a number", "is greater than"), FilterRule::FuncGreater); 0274 break; 0275 case Image: 0276 m_ruleFunc->addItem(i18n("image size equals"), FilterRule::FuncEquals); 0277 m_ruleFunc->addItem(i18n("image size does not equal"), FilterRule::FuncNotEquals); 0278 m_ruleFunc->addItem(i18nc("image size is less than a number", "image size is less than"), FilterRule::FuncLess); 0279 m_ruleFunc->addItem(i18nc("image size is greater than a number", "image size is greater than"), FilterRule::FuncGreater); 0280 break; 0281 case General: 0282 m_ruleFunc->addItem(i18n("contains"), FilterRule::FuncContains); 0283 m_ruleFunc->addItem(i18n("does not contain"), FilterRule::FuncNotContains); 0284 m_ruleFunc->addItem(i18n("equals"), FilterRule::FuncEquals); 0285 m_ruleFunc->addItem(i18n("does not equal"), FilterRule::FuncNotEquals); 0286 m_ruleFunc->addItem(i18n("matches regular expression"), FilterRule::FuncRegExp); 0287 m_ruleFunc->addItem(i18n("does not match regular expression"), FilterRule::FuncNotRegExp); 0288 break; 0289 } 0290 m_ruleFunc->setCurrentData(data); 0291 slotRuleFunctionChanged(m_ruleFunc->currentIndex()); 0292 }