Branch data Line data Source code
1 : : #include "FilterPopoverWidget.h"
2 : : #include "CheckableFolderCombo.h"
3 : :
4 : : #include <QComboBox>
5 : : #include <QDateEdit>
6 : : #include <QEvent>
7 : : #include <QFormLayout>
8 : : #include <QLabel>
9 : : #include <QLineEdit>
10 : : #include <QVBoxLayout>
11 : : #include <QGroupBox>
12 : : #include <QSignalBlocker>
13 : :
14 : : using Tri = MailCache::SearchFilter::Tri;
15 : :
16 : : namespace {
17 : 384 : int triToIndex(Tri t) {
18 [ + + + - ]: 384 : switch (t) {
19 : 9 : case Tri::Yes: return 1;
20 : 2 : case Tri::No: return 2;
21 : 373 : case Tri::Any: break;
22 : : }
23 : 373 : return 0;
24 : : }
25 : 540 : Tri indexToTri(int index) {
26 [ + + + ]: 540 : switch (index) {
27 : 4 : case 1: return Tri::Yes;
28 : 2 : case 2: return Tri::No;
29 : 534 : default: return Tri::Any;
30 : : }
31 : : }
32 : : enum DatePreset { PresetAny = 0, PresetToday, PresetWeek, PresetMonth, PresetYear, PresetCustom };
33 : : }
34 : :
35 [ + - ]: 66 : FilterPopoverWidget::FilterPopoverWidget(QWidget *parent) : QWidget(parent) {
36 : : // Make it a popup that closes when clicking outside
37 [ + - ]: 66 : setWindowFlags(Qt::Popup | Qt::FramelessWindowHint);
38 [ + - ]: 66 : setAttribute(Qt::WA_StyledBackground, true);
39 [ + - ]: 132 : setObjectName("filterPopover");
40 [ + - ]: 66 : setupUi();
41 : 66 : }
42 : :
43 : 66 : void FilterPopoverWidget::setupUi() {
44 [ + - + - : 66 : auto *mainLayout = new QVBoxLayout(this);
- + - - ]
45 [ + - ]: 66 : mainLayout->setContentsMargins(12, 12, 12, 12);
46 [ + - ]: 66 : mainLayout->setSpacing(12);
47 : :
48 : : // Helper to connect signals
49 : 726 : auto connectEdit = [this](QWidget *w) {
50 [ + + ]: 726 : if (auto *le = qobject_cast<QLineEdit*>(w))
51 [ + - ]: 264 : connect(le, &QLineEdit::textEdited, this, &FilterPopoverWidget::onFieldChanged);
52 [ + + ]: 462 : else if (auto *cb = qobject_cast<QComboBox*>(w))
53 [ + - ]: 330 : connect(cb, &QComboBox::currentIndexChanged, this, &FilterPopoverWidget::onFieldChanged);
54 [ + - ]: 132 : else if (auto *de = qobject_cast<QDateEdit*>(w))
55 [ + - ]: 132 : connect(de, &QDateEdit::dateChanged, this, &FilterPopoverWidget::onFieldChanged);
56 [ # # ]: 0 : else if (auto *cfc = qobject_cast<CheckableFolderCombo*>(w))
57 [ # # ]: 0 : connect(cfc, &CheckableFolderCombo::selectionChanged, this, &FilterPopoverWidget::onFieldChanged);
58 : 726 : };
59 : :
60 : : // Text Form
61 [ + - + - : 66 : auto *textForm = new QFormLayout();
- + - - ]
62 [ + - + - : 66 : m_subject = new QLineEdit(this);
- + - - ]
63 [ + - ]: 132 : m_subject->setObjectName("subjectEdit");
64 [ + - + - : 66 : m_from = new QLineEdit(this);
- + - - ]
65 [ + - ]: 132 : m_from->setObjectName("fromEdit");
66 [ + - + - : 66 : m_to = new QLineEdit(this);
- + - - ]
67 [ + - ]: 132 : m_to->setObjectName("toEdit");
68 [ + - + - : 66 : m_subjectLabel = new QLabel(tr("Subject:"), this);
+ - - + -
- ]
69 [ + - + - : 66 : m_fromLabel = new QLabel(tr("From:"), this);
+ - - + -
- ]
70 [ + - + - : 66 : m_toLabel = new QLabel(tr("To:"), this);
+ - - + -
- ]
71 [ + - ]: 66 : textForm->addRow(m_subjectLabel, m_subject);
72 [ + - ]: 66 : textForm->addRow(m_fromLabel, m_from);
73 [ + - ]: 66 : textForm->addRow(m_toLabel, m_to);
74 [ + - + - : 66 : connectEdit(m_subject); connectEdit(m_from); connectEdit(m_to);
+ - ]
75 [ + - ]: 66 : mainLayout->addLayout(textForm);
76 : :
77 : : // Status Form
78 [ + - + - : 66 : auto *statusForm = new QFormLayout();
- + - - ]
79 : 264 : auto makeTriCombo = [this, connectEdit]() {
80 [ + - - + : 264 : auto *cb = new QComboBox(this);
- - ]
81 [ + - + + : 1056 : cb->addItems({tr("Any"), tr("Yes"), tr("No")});
- - ]
82 : 264 : connectEdit(cb);
83 : 264 : return cb;
84 [ + - + - : 264 : };
+ - + - -
- - - ]
85 [ + - ]: 66 : m_unread = makeTriCombo();
86 [ + - ]: 66 : m_flagged = makeTriCombo();
87 [ + - ]: 66 : m_answered = makeTriCombo();
88 [ + - ]: 66 : m_attachment = makeTriCombo();
89 [ + - + - : 66 : m_unreadLabel = new QLabel(tr("Unread:"), this);
+ - - + -
- ]
90 [ + - + - : 66 : m_flaggedLabel = new QLabel(tr("Flagged:"), this);
+ - - + -
- ]
91 [ + - + - : 66 : m_answeredLabel = new QLabel(tr("Answered:"), this);
+ - - + -
- ]
92 [ + - + - : 66 : m_attachmentLabel = new QLabel(tr("Attachment:"), this);
+ - - + -
- ]
93 [ + - ]: 66 : statusForm->addRow(m_unreadLabel, m_unread);
94 [ + - ]: 66 : statusForm->addRow(m_flaggedLabel, m_flagged);
95 [ + - ]: 66 : statusForm->addRow(m_answeredLabel, m_answered);
96 [ + - ]: 66 : statusForm->addRow(m_attachmentLabel, m_attachment);
97 [ + - ]: 66 : mainLayout->addLayout(statusForm);
98 : :
99 : : // Location Form
100 [ + - + - : 66 : auto *locForm = new QFormLayout();
- + - - ]
101 [ + - + - : 66 : m_folder = new CheckableFolderCombo(this);
- + - - ]
102 [ + - + - : 66 : m_tags = new QLineEdit(this);
- + - - ]
103 [ + - + - : 66 : m_folderLabel = new QLabel(tr("Folder:"), this);
+ - - + -
- ]
104 [ + - + - : 66 : m_tagsLabel = new QLabel(tr("Tags:"), this);
+ - - + -
- ]
105 [ + - ]: 66 : locForm->addRow(m_folderLabel, m_folder);
106 [ + - ]: 66 : locForm->addRow(m_tagsLabel, m_tags);
107 [ + - + - ]: 66 : connectEdit(m_folder); connectEdit(m_tags);
108 [ + - ]: 66 : mainLayout->addLayout(locForm);
109 : :
110 : : // Date Form
111 [ + - + - : 66 : auto *dateForm = new QFormLayout();
- + - - ]
112 [ + - + - : 66 : m_datePreset = new QComboBox(this);
- + - - ]
113 [ + - + + : 462 : m_datePreset->addItems({tr("Any time"), tr("Today"), tr("Past week"), tr("Past month"), tr("Past year"), tr("Custom range")});
- - ]
114 [ + - + - : 66 : m_dateFrom = new QDateEdit(this);
- + - - ]
115 [ + - ]: 66 : m_dateFrom->setCalendarPopup(true);
116 [ + - + - : 66 : m_dateTo = new QDateEdit(this);
- + - - ]
117 [ + - ]: 66 : m_dateTo->setCalendarPopup(true);
118 [ + - ]: 66 : m_dateFrom->setEnabled(false);
119 [ + - ]: 66 : m_dateTo->setEnabled(false);
120 : :
121 [ + - ]: 66 : connect(m_datePreset, &QComboBox::currentIndexChanged, this, [this](int idx) {
122 : 0 : bool custom = (idx == PresetCustom);
123 : 0 : m_dateFrom->setEnabled(custom);
124 : 0 : m_dateTo->setEnabled(custom);
125 : 0 : onFieldChanged();
126 : 0 : });
127 : :
128 [ + - + - : 66 : m_dateLabel = new QLabel(tr("Date:"), this);
+ - - + -
- ]
129 [ + - + - : 66 : m_sinceLabel = new QLabel(tr("Since:"), this);
+ - - + -
- ]
130 [ + - + - : 66 : m_untilLabel = new QLabel(tr("Until:"), this);
+ - - + -
- ]
131 [ + - ]: 66 : dateForm->addRow(m_dateLabel, m_datePreset);
132 [ + - ]: 66 : dateForm->addRow(m_sinceLabel, m_dateFrom);
133 [ + - ]: 66 : dateForm->addRow(m_untilLabel, m_dateTo);
134 [ + - + - ]: 66 : connectEdit(m_dateFrom); connectEdit(m_dateTo);
135 [ + - ]: 66 : mainLayout->addLayout(dateForm);
136 [ + - + - : 132 : }
+ - + - +
- + - + -
- - - - ]
137 : :
138 : 1799 : void FilterPopoverWidget::changeEvent(QEvent *event) {
139 [ + + ]: 1799 : if (event->type() == QEvent::LanguageChange)
140 : 170 : retranslateUi();
141 : 1799 : QWidget::changeEvent(event);
142 : 1799 : }
143 : :
144 : 170 : void FilterPopoverWidget::retranslateUi() {
145 [ + - + - ]: 170 : m_subjectLabel->setText(tr("Subject:"));
146 [ + - + - ]: 170 : m_fromLabel->setText(tr("From:"));
147 [ + - + - ]: 170 : m_toLabel->setText(tr("To:"));
148 [ + - + - ]: 170 : m_unreadLabel->setText(tr("Unread:"));
149 [ + - + - ]: 170 : m_flaggedLabel->setText(tr("Flagged:"));
150 [ + - + - ]: 170 : m_answeredLabel->setText(tr("Answered:"));
151 [ + - + - ]: 170 : m_attachmentLabel->setText(tr("Attachment:"));
152 [ + - + - ]: 170 : m_folderLabel->setText(tr("Folder:"));
153 [ + - + - ]: 170 : m_tagsLabel->setText(tr("Tags:"));
154 [ + - + - ]: 170 : m_dateLabel->setText(tr("Date:"));
155 [ + - + - ]: 170 : m_sinceLabel->setText(tr("Since:"));
156 [ + - + - ]: 170 : m_untilLabel->setText(tr("Until:"));
157 : :
158 [ + + ]: 850 : for (auto *cb : {m_unread, m_flagged, m_answered, m_attachment}) {
159 [ + - + - ]: 680 : cb->setItemText(0, tr("Any"));
160 [ + - + - ]: 680 : cb->setItemText(1, tr("Yes"));
161 [ + - + - ]: 680 : cb->setItemText(2, tr("No"));
162 : : }
163 : :
164 [ + - + - ]: 170 : m_datePreset->setItemText(PresetAny, tr("Any time"));
165 [ + - + - ]: 170 : m_datePreset->setItemText(PresetToday, tr("Today"));
166 [ + - + - ]: 170 : m_datePreset->setItemText(PresetWeek, tr("Past week"));
167 [ + - + - ]: 170 : m_datePreset->setItemText(PresetMonth, tr("Past month"));
168 [ + - + - ]: 170 : m_datePreset->setItemText(PresetYear, tr("Past year"));
169 [ + - + - ]: 170 : m_datePreset->setItemText(PresetCustom, tr("Custom range"));
170 : 170 : }
171 : :
172 : 36 : void FilterPopoverWidget::onFieldChanged() {
173 : 36 : emit filterEdited();
174 : 36 : }
175 : :
176 : 96 : void FilterPopoverWidget::setFilter(const MailCache::SearchFilter &f) {
177 : 96 : QSignalBlocker bSub(m_subject), bFrom(m_from), bTo(m_to);
178 : 96 : QSignalBlocker bUnr(m_unread), bFlg(m_flagged), bAns(m_answered), bAtt(m_attachment);
179 : 96 : QSignalBlocker bFol(m_folder), bTag(m_tags), bDatP(m_datePreset), bDatF(m_dateFrom), bDatT(m_dateTo);
180 : :
181 [ + - ]: 96 : m_subject->setText(f.subjectFilter);
182 [ + - ]: 96 : m_from->setText(f.fromFilter);
183 [ + - ]: 96 : m_to->setText(f.toFilter);
184 : :
185 [ + - ]: 96 : m_unread->setCurrentIndex(triToIndex(f.unread));
186 [ + - ]: 96 : m_flagged->setCurrentIndex(triToIndex(f.flagged));
187 [ + - ]: 96 : m_answered->setCurrentIndex(triToIndex(f.answered));
188 [ + - ]: 96 : m_attachment->setCurrentIndex(triToIndex(f.hasAttachment));
189 : :
190 [ + - ]: 96 : m_folder->setCheckedFolders(f.folderPatterns);
191 [ + - + - : 96 : m_tags->setText(f.tags.join(", "));
+ - ]
192 : :
193 [ + - + + : 96 : if (f.dateFrom.isValid() || f.dateTo.isValid()) {
+ - - + +
+ ]
194 [ + - ]: 1 : m_datePreset->setCurrentIndex(PresetCustom);
195 [ + - + - : 1 : m_dateFrom->setDate(f.dateFrom.isValid() ? f.dateFrom.date() : QDate::currentDate());
+ - - - +
- ]
196 [ + - + - : 1 : m_dateTo->setDate(f.dateTo.isValid() ? f.dateTo.date() : QDate::currentDate());
+ - - - +
- ]
197 [ + - ]: 1 : m_dateFrom->setEnabled(true);
198 [ + - ]: 1 : m_dateTo->setEnabled(true);
199 : : } else {
200 [ + - ]: 95 : m_datePreset->setCurrentIndex(PresetAny);
201 [ + - ]: 95 : m_dateFrom->setEnabled(false);
202 [ + - ]: 95 : m_dateTo->setEnabled(false);
203 : : }
204 : 96 : }
205 : :
206 : 135 : MailCache::SearchFilter FilterPopoverWidget::filter() const {
207 : 135 : MailCache::SearchFilter f;
208 [ + - ]: 135 : f.subjectFilter = m_subject->text();
209 [ + - ]: 135 : f.fromFilter = m_from->text();
210 [ + - ]: 135 : f.toFilter = m_to->text();
211 : :
212 [ + - ]: 135 : f.unread = indexToTri(m_unread->currentIndex());
213 [ + - ]: 135 : f.flagged = indexToTri(m_flagged->currentIndex());
214 [ + - ]: 135 : f.answered = indexToTri(m_answered->currentIndex());
215 [ + - ]: 135 : f.hasAttachment = indexToTri(m_attachment->currentIndex());
216 : :
217 [ + - ]: 135 : f.folderPatterns = m_folder->checkedFolders();
218 [ + - + - ]: 135 : const QStringList rawTags = m_tags->text().split(QLatin1Char(','), Qt::SkipEmptyParts);
219 [ + + ]: 137 : for (const QString &t : rawTags) {
220 [ + - ]: 2 : const QString trimmed = t.trimmed();
221 [ + - ]: 2 : if (!trimmed.isEmpty())
222 [ + - ]: 2 : f.tags.append(trimmed);
223 : 2 : }
224 : :
225 [ + - + + ]: 135 : if (m_datePreset->currentIndex() == PresetCustom) {
226 [ + - + - : 1 : f.dateFrom = QDateTime(m_dateFrom->date(), QTime(0, 0, 0));
+ - ]
227 [ + - + - : 1 : f.dateTo = QDateTime(m_dateTo->date(), QTime(23, 59, 59));
+ - ]
228 [ + - - + ]: 134 : } else if (m_datePreset->currentIndex() != PresetAny) {
229 [ # # ]: 0 : QDate now = QDate::currentDate();
230 [ # # # # ]: 0 : f.dateTo = QDateTime(now, QTime(23, 59, 59));
231 [ # # # # : 0 : switch (m_datePreset->currentIndex()) {
# # # ]
232 [ # # # # ]: 0 : case PresetToday: f.dateFrom = QDateTime(now, QTime(0, 0)); break;
233 [ # # # # : 0 : case PresetWeek: f.dateFrom = QDateTime(now.addDays(-7), QTime(0, 0)); break;
# # ]
234 [ # # # # : 0 : case PresetMonth: f.dateFrom = QDateTime(now.addMonths(-1), QTime(0, 0)); break;
# # ]
235 [ # # # # : 0 : case PresetYear: f.dateFrom = QDateTime(now.addYears(-1), QTime(0, 0)); break;
# # ]
236 : : }
237 : : }
238 : :
239 : 135 : return f;
240 : 135 : }
241 : :
242 : 36 : void FilterPopoverWidget::setKnownFolders(const QStringList &paths) {
243 : 36 : m_folder->setFolders(paths);
244 : 36 : }
245 : :
246 : 36 : void FilterPopoverWidget::setKnownTags(const QStringList &tags) {
247 : 36 : m_knownTags = tags;
248 : : // Could set up a QCompleter here if needed.
249 : 36 : }
|