File indexing completed on 2024-05-12 05:09:47
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 0033 #include <KLocalizedString> 0034 #include <KComboBox> 0035 #include <KLineEdit> 0036 #include <KDateComboBox> 0037 0038 #include <QDialog> 0039 #include <QHBoxLayout> 0040 #include <QStackedWidget> 0041 #include <QPushButton> 0042 0043 using Tellico::FilterRuleWidget; 0044 0045 FilterRuleWidget::FilterRuleWidget(Tellico::FilterRule* rule_, QWidget* parent_) 0046 : QWidget(parent_), m_ruleDate(nullptr), m_ruleType(General) { 0047 QHBoxLayout* l = new QHBoxLayout(this); 0048 l->setMargin(0); 0049 // l->setSizeConstraint(QLayout::SetFixedSize); 0050 setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); 0051 0052 initLists(); 0053 initWidget(); 0054 0055 if(rule_) { 0056 setRule(rule_); 0057 } else { 0058 reset(); 0059 } 0060 } 0061 0062 QString FilterRuleWidget::anyFieldString() { 0063 static const QString anyField = QLatin1Char('<') + i18n("Any Field") + QLatin1Char('>'); 0064 return anyField; 0065 } 0066 0067 void FilterRuleWidget::initLists() { 0068 //---------- initialize list of filter fields 0069 if(m_ruleFieldList.isEmpty()) { 0070 m_ruleFieldList.append(anyFieldString()); 0071 QStringList titles = Data::Document::self()->collection()->fieldTitles(); 0072 titles.sort(); 0073 m_ruleFieldList += titles; 0074 } 0075 0076 } 0077 0078 void FilterRuleWidget::initWidget() { 0079 m_ruleField = new KComboBox(this); 0080 layout()->addWidget(m_ruleField); 0081 void (KComboBox::* activatedInt)(int) = &KComboBox::activated; 0082 // change the rule field before emitting modified 0083 connect(m_ruleField, activatedInt, this, &FilterRuleWidget::slotRuleFieldChanged); 0084 connect(m_ruleField, activatedInt, this, &FilterRuleWidget::signalModified); 0085 0086 m_ruleFunc = new GUI::ComboBox(this); 0087 layout()->addWidget(m_ruleFunc); 0088 connect(m_ruleFunc, activatedInt, this, &FilterRuleWidget::slotRuleFunctionChanged); 0089 connect(m_ruleFunc, activatedInt, this, &FilterRuleWidget::signalModified); 0090 0091 m_valueStack = new QStackedWidget(this); 0092 layout()->addWidget(m_valueStack); 0093 0094 m_ruleValue = new KLineEdit(m_valueStack); //krazy:exclude=qclasses 0095 connect(m_ruleValue, &QLineEdit::textChanged, this, &FilterRuleWidget::signalModified); 0096 m_valueStack->addWidget(m_ruleValue); 0097 0098 m_ruleDate = new KDateComboBox(m_valueStack); 0099 connect(m_ruleDate, &KDateComboBox::dateChanged, this, &FilterRuleWidget::signalModified); 0100 m_valueStack->addWidget(m_ruleDate); 0101 0102 m_ruleField->addItems(m_ruleFieldList); 0103 updateFunctionList(); 0104 slotRuleFunctionChanged(m_ruleFunc->currentIndex()); 0105 } 0106 0107 void FilterRuleWidget::slotRuleFieldChanged(int which_) { 0108 Q_UNUSED(which_); 0109 m_ruleType = General; 0110 const QString fieldTitle = m_ruleField->currentText(); 0111 if(fieldTitle.isEmpty() || fieldTitle == anyFieldString()) { 0112 m_ruleValue->setCompletionObject(nullptr); 0113 updateFunctionList(); 0114 return; 0115 } 0116 Data::FieldPtr field = Data::Document::self()->collection()->fieldByTitle(fieldTitle); 0117 if(field && field->hasFlag(Data::Field::AllowCompletion)) { 0118 FieldCompletion* completion = new FieldCompletion(field->hasFlag(Data::Field::AllowMultiple)); 0119 completion->setItems(Data::Document::self()->collection()->valuesByFieldName(field->name())); 0120 completion->setIgnoreCase(true); 0121 m_ruleValue->setCompletionObject(completion); 0122 m_ruleValue->setAutoDeleteCompletionObject(true); 0123 } else { 0124 m_ruleValue->setCompletionObject(nullptr); 0125 } 0126 0127 if(field) { 0128 if(field->type() == Data::Field::Date) { 0129 m_ruleType = Date; 0130 } else if(field->type() == Data::Field::Number || field->type() == Data::Field::Rating) { 0131 m_ruleType = Number; 0132 } else if(field->type() == Data::Field::Image) { 0133 m_ruleType = Image; 0134 } else if(field->type() == Data::Field::Bool) { 0135 m_ruleType = Bool; 0136 } 0137 } 0138 updateFunctionList(); 0139 } 0140 0141 void FilterRuleWidget::slotRuleFunctionChanged(int which_) { 0142 const QVariant data = m_ruleFunc->itemData(which_); 0143 0144 // don't show the date picker if we're using regular expressions 0145 if(m_ruleType == Date && data != FilterRule::FuncRegExp && data != FilterRule::FuncNotRegExp) { 0146 m_valueStack->setCurrentWidget(m_ruleDate); 0147 } else { 0148 m_valueStack->setCurrentWidget(m_ruleValue); 0149 m_ruleValue->setPlaceholderText(m_ruleType == Bool ? QChar(0x2611): QString()); 0150 if(m_ruleType == Number && 0151 (data != FilterRule::FuncRegExp && data != FilterRule::FuncNotRegExp)) { 0152 m_ruleValue->setValidator(new QIntValidator(this)); 0153 } else { 0154 m_ruleValue->setValidator(nullptr); 0155 } 0156 // Bool rules don't use a value 0157 m_ruleValue->setEnabled(m_ruleType != Bool); 0158 } 0159 } 0160 0161 void FilterRuleWidget::setRule(const Tellico::FilterRule* rule_) { 0162 if(!rule_) { 0163 reset(); 0164 return; 0165 } 0166 0167 blockSignals(true); 0168 0169 m_ruleType = General; 0170 if(rule_->fieldName().isEmpty()) { 0171 m_ruleField->setCurrentIndex(0); // "All Fields" 0172 } else { 0173 Data::FieldPtr field = Data::Document::self()->collection()->fieldByName(rule_->fieldName()); 0174 if(field && field->type() == Data::Field::Date) { 0175 m_ruleType = Date; 0176 const QDate date = QDate::fromString(rule_->pattern(), Qt::ISODate); 0177 if(date.isValid()) { 0178 m_ruleDate->setDate(date); 0179 } 0180 } 0181 const int idx = m_ruleField->findText(field ? field->title() : QString()); 0182 m_ruleField->setCurrentIndex(idx); 0183 } 0184 0185 // update the rule fields first, before possible values 0186 slotRuleFieldChanged(m_ruleField->currentIndex()); 0187 0188 //--------------set function and contents 0189 m_ruleFunc->setCurrentData(rule_->function()); 0190 m_ruleValue->setText(m_ruleType == Bool ? QString() : rule_->pattern()); 0191 0192 slotRuleFunctionChanged(m_ruleFunc->currentIndex()); 0193 blockSignals(false); 0194 } 0195 0196 Tellico::FilterRule* FilterRuleWidget::rule() const { 0197 QString fieldName; // empty string 0198 if(m_ruleField->currentIndex() > 0) { // 0 is "All Fields", field is empty 0199 fieldName = Data::Document::self()->collection()->fieldNameByTitle(m_ruleField->currentText()); 0200 } 0201 0202 QString ruleValue; 0203 if(m_valueStack->currentWidget() == m_ruleDate) { 0204 ruleValue = m_ruleDate->date().toString(Qt::ISODate); 0205 } else { 0206 // bool values only get checked against true 0207 ruleValue = m_ruleType == Bool ? QStringLiteral("true") : m_ruleValue->text().trimmed(); 0208 } 0209 0210 return new FilterRule(fieldName, ruleValue, 0211 static_cast<FilterRule::Function>(m_ruleFunc->currentData().toInt())); 0212 } 0213 0214 void FilterRuleWidget::reset() { 0215 blockSignals(true); 0216 0217 m_ruleField->setCurrentIndex(0); 0218 m_ruleFunc->setCurrentIndex(0); 0219 m_ruleValue->clear(); 0220 0221 blockSignals(false); 0222 } 0223 0224 void FilterRuleWidget::setFocus() { 0225 m_ruleValue->setFocus(); 0226 } 0227 0228 void FilterRuleWidget::updateFunctionList() { 0229 Q_ASSERT(m_ruleFunc); 0230 const QVariant data = m_ruleFunc->currentData(); 0231 m_ruleFunc->clear(); 0232 switch(m_ruleType) { 0233 case Date: 0234 m_ruleFunc->addItem(i18n("equals"), FilterRule::FuncEquals); 0235 m_ruleFunc->addItem(i18n("does not equal"), FilterRule::FuncNotEquals); 0236 m_ruleFunc->addItem(i18n("matches regular expression"), FilterRule::FuncRegExp); 0237 m_ruleFunc->addItem(i18n("does not match regular expression"), FilterRule::FuncNotRegExp); 0238 m_ruleFunc->addItem(i18nc("is before a date", "is before"), FilterRule::FuncBefore); 0239 m_ruleFunc->addItem(i18nc("is after a date", "is after"), FilterRule::FuncAfter); 0240 break; 0241 case Number: 0242 m_ruleFunc->addItem(i18n("equals"), FilterRule::FuncEquals); 0243 m_ruleFunc->addItem(i18n("does not equal"), FilterRule::FuncNotEquals); 0244 m_ruleFunc->addItem(i18n("matches regular expression"), FilterRule::FuncRegExp); 0245 m_ruleFunc->addItem(i18n("does not match regular expression"), FilterRule::FuncNotRegExp); 0246 m_ruleFunc->addItem(i18nc("is less than a number", "is less than"), FilterRule::FuncLess); 0247 m_ruleFunc->addItem(i18nc("is greater than a number", "is greater than"), FilterRule::FuncGreater); 0248 break; 0249 case Image: 0250 m_ruleFunc->addItem(i18n("image size equals"), FilterRule::FuncEquals); 0251 m_ruleFunc->addItem(i18n("image size does not equal"), FilterRule::FuncNotEquals); 0252 m_ruleFunc->addItem(i18nc("image size is less than a number", "image size is less than"), FilterRule::FuncLess); 0253 m_ruleFunc->addItem(i18nc("image size is greater than a number", "image size is greater than"), FilterRule::FuncGreater); 0254 break; 0255 case Bool: 0256 m_ruleFunc->addItem(i18n("equals"), FilterRule::FuncEquals); 0257 m_ruleFunc->addItem(i18n("does not equal"), FilterRule::FuncNotEquals); 0258 break; 0259 case General: 0260 m_ruleFunc->addItem(i18n("contains"), FilterRule::FuncContains); 0261 m_ruleFunc->addItem(i18n("does not contain"), FilterRule::FuncNotContains); 0262 m_ruleFunc->addItem(i18n("equals"), FilterRule::FuncEquals); 0263 m_ruleFunc->addItem(i18n("does not equal"), FilterRule::FuncNotEquals); 0264 m_ruleFunc->addItem(i18n("matches regular expression"), FilterRule::FuncRegExp); 0265 m_ruleFunc->addItem(i18n("does not match regular expression"), FilterRule::FuncNotRegExp); 0266 break; 0267 } 0268 m_ruleFunc->setCurrentData(data); 0269 slotRuleFunctionChanged(m_ruleFunc->currentIndex()); 0270 }