Isis 3 Programmer Reference
FilterWidget.cpp
1
7/* SPDX-License-Identifier: CC0-1.0 */
8
9#include "FilterWidget.h"
10
11#include <iostream>
12
13#include <QButtonGroup>
14#include <QHBoxLayout>
15#include <QIcon>
16#include <QLabel>
17#include <QPair>
18#include <QPushButton>
19#include <QRadioButton>
20#include <QString>
21#include <QVBoxLayout>
22
23#include "IException.h"
24#include "IString.h"
25#include "FileName.h"
26
27#include "FilterGroup.h"
28
29
30using std::swap;
31using std::nothrow;
32
33
34namespace Isis {
35 FilterWidget::FilterWidget(QString type) {
36 nullify();
37
38 m_filterType = new QString(type);
39
40 init();
41 addGroup();
42 updateDescription();
43 }
44
45
46 FilterWidget::FilterWidget(const FilterWidget &other) {
47 nullify();
48
49 m_filterType = new QString(*other.m_filterType);
50
51 init();
52
53 foreach (FilterGroup * group, *other.m_filterGroups) {
54 addGroup(new FilterGroup(*group));
55 }
56
57 m_buttonGroup->button(other.m_buttonGroup->checkedId())->click();
58
59 updateDescription();
60 }
61
62
63 FilterWidget::~FilterWidget() {
64 if (m_buttonGroup) {
65 delete m_buttonGroup;
66 m_buttonGroup = NULL;
67 }
68
69 if (m_filterGroups) {
70 delete m_filterGroups;
71 m_filterGroups = NULL;
72 }
73
74 if (m_filterType) {
75 delete m_filterType;
76 m_filterType = NULL;
77 }
78 }
79
80
81 bool FilterWidget::evaluate(const QPair<QString, ControlNet *> *imageAndNet) const {
82 return evaluate(imageAndNet, &AbstractFilter::canFilterImages);
83 }
84
85
86 bool FilterWidget::evaluate(const ControlPoint *point) const {
87 return evaluate(point, &AbstractFilter::canFilterPoints);
88 }
89
90
91 bool FilterWidget::evaluate(const ControlMeasure *measure) const {
92 return evaluate(measure, &AbstractFilter::canFilterMeasures);
93 }
94
95
96 bool FilterWidget::hasFilter(bool (AbstractFilter::*meth)() const) const {
97 bool found = false;
98
99 for (int i = 0; !found && i < m_filterGroups->size(); i++)
100 found = m_filterGroups->at(i)->hasFilter(meth);
101
102 return found;
103 }
104
105
106 FilterWidget &FilterWidget::operator=(FilterWidget other) {
107
108 // create temporary list of new groups
109 QList< FilterGroup * > newGroups;
110 foreach (FilterGroup * group, *other.m_filterGroups) {
111 FilterGroup *newGroup = new(nothrow) FilterGroup(*other.m_filterType);
112 if (newGroup) {
113 *newGroup = *group;
114 newGroups.append(newGroup);
115 }
116 }
117
118 // if all is ok, and it is safe to assign
119 if (newGroups.size() == other.m_filterGroups->size()) {
120 foreach (FilterGroup * group, *m_filterGroups) {
121 deleteGroup(group);
122 }
123
124 foreach (FilterGroup * newGroup, newGroups) {
125 addGroup(newGroup);
126 }
127
128 swap(*m_filterType, *other.m_filterType);
129 m_buttonGroup->button(other.m_buttonGroup->checkedId())->click();
130 }
131 else {
132 // clean up any temp groups
133 foreach (FilterGroup * newGroup, newGroups) {
134 if (newGroup) {
135 delete newGroup;
136 newGroup = NULL;
137 }
138 }
139
140 IString msg = "Assignment of FilterWidget failed";
141 throw IException(IException::Programmer, msg, _FILEINFO_);
142 }
143
144 return *this;
145 }
146
147
148 void FilterWidget::nullify() {
149 m_addGroupButton = NULL;
150 m_buttonGroup = NULL;
151 m_imageDescription = NULL;
152 m_pointDescription = NULL;
153 m_measureDescription = NULL;
154 m_mainLayout = NULL;
155 m_filterGroups = NULL;
156 m_filterType = NULL;
157 }
158
159
160 void FilterWidget::init() {
161 m_filterGroups = new QList< FilterGroup * >;
162
163 QString whatsThis = "<html>Filters are organized into groups (bounded by a box)."
164 " Filters within a group will be combined using either AND or OR "
165 "logic. Furthermore, multiple groups are supported, and the logic "
166 "used to combine the various groups is also configurable.<br/><br/>"
167 "For example, let A, B, and C be filters. By creating two "
168 "groups, one with A and B and the other with C, it is possible to "
169 "build the expression \"(A and B) or C\".<br/><br/>"
170 "Each group has a green plus (+) button, which adds a new filter to "
171 "the group. There is also a green plus (+) button outside any group "
172 "for adding a new group.</html>";
173
174
175 QString title = "Filter " + *m_filterType;
176 QLabel *titleLabel = new QLabel(title);
177 titleLabel->setFont(QFont("SansSerif", 15, QFont::DemiBold));
178
179 QHBoxLayout *titleLayout = new QHBoxLayout;
180 titleLayout->addStretch();
181 titleLayout->addWidget(titleLabel);
182 titleLayout->addStretch();
183
184 QLabel *logicTypeLabel = new QLabel("Combine groups using logic type: ");
185 QFont logicTypeLabelFont("SansSerif", 12);
186 logicTypeLabel->setFont(logicTypeLabelFont);
187
188 QFont logicTypeFont("SansSerif", 12, QFont::Bold);
189 QRadioButton *andButton = new QRadioButton("AND");
190 andButton->setFont(logicTypeFont);
191 QRadioButton *orButton = new QRadioButton("OR");
192 orButton->setFont(logicTypeFont);
193 m_buttonGroup = new QButtonGroup;
194 m_buttonGroup->addButton(andButton, 0);
195 m_buttonGroup->addButton(orButton, 1);
196 connect(m_buttonGroup, SIGNAL(buttonClicked(int)), this,
197 SLOT(changeGroupCombinationLogic(int)));
198
199 // FIXME: this should be controlled by QSettings
200 orButton->click();
201
202 QHBoxLayout *buttonLayout = new QHBoxLayout;
203 buttonLayout->addStretch();
204 buttonLayout->addWidget(logicTypeLabel);
205 buttonLayout->addWidget(andButton);
206 buttonLayout->addWidget(orButton);
207 buttonLayout->addStretch();
208 m_logicWidget = new QWidget;
209 m_logicWidget->setLayout(buttonLayout);
210
211 m_addGroupButton = new QPushButton;
212 m_addGroupButton->setIcon(QIcon(FileName("$ISISROOT/appdata/images/icons/add.png").expanded()));
213 QString addGroupTooltip = "Add new filter group";
214 m_addGroupButton->setToolTip(addGroupTooltip);
215 m_addGroupButton->setStatusTip(addGroupTooltip);
216 m_addGroupButton->setWhatsThis(whatsThis);
217 connect(m_addGroupButton, SIGNAL(clicked()), this, SLOT(addGroup()));
218 QHBoxLayout *addGroupLayout = new QHBoxLayout;
219 addGroupLayout->addWidget(m_addGroupButton);
220 addGroupLayout->addStretch();
221
222 QLabel *titleDummy = new QLabel;
223 titleDummy->setFont(QFont("SansSerif", 6)); // FIXME
224
225 m_imageDescription = new QLabel;
226 m_imageDescription->setWordWrap(true);
227 m_imageDescription->setFont(QFont("SansSerif", 10)); // FIXME
228
229 m_pointDescription = new QLabel;
230 m_pointDescription->setWordWrap(true);
231 m_pointDescription->setFont(QFont("SansSerif", 10)); // FIXME
232
233 m_measureDescription = new QLabel;
234 m_measureDescription->setWordWrap(true);
235 m_measureDescription->setFont(QFont("SansSerif", 10)); // FIXME
236
237 QVBoxLayout *descriptionLayout = new QVBoxLayout;
238 descriptionLayout->addWidget(titleDummy);
239 descriptionLayout->addWidget(m_imageDescription);
240 descriptionLayout->addWidget(m_pointDescription);
241 descriptionLayout->addWidget(m_measureDescription);
242
243 connect(this, SIGNAL(filterChanged()),
244 this, SLOT(updateDescription()));
245
246 m_mainLayout = new QVBoxLayout;
247 m_mainLayout->addLayout(titleLayout);
248 m_mainLayout->addLayout(descriptionLayout);
249 m_mainLayout->addWidget(m_logicWidget);
250 m_mainLayout->addLayout(addGroupLayout);
251 m_mainLayout->addStretch();
252
253 setLayout(m_mainLayout);
254 setWhatsThis(whatsThis);
255 }
256
257
258 void FilterWidget::updateDescription() {
259 updateDescription(m_imageDescription, &AbstractFilter::canFilterImages,
260 &AbstractFilter::getImageDescription, "images");
261 updateDescription(m_pointDescription, &AbstractFilter::canFilterPoints,
262 &AbstractFilter::getPointDescription, "points");
263 updateDescription(m_measureDescription, &AbstractFilter::canFilterMeasures,
264 &AbstractFilter::getMeasureDescription, "measures");
265 }
266
267
268 void FilterWidget::updateDescription(QLabel *label,
269 bool (AbstractFilter::*hasFilterMeth)() const,
270 QString(AbstractFilter::*descriptionMeth)() const,
271 QString title) {
272
273 if (label) {
274 label->clear();
275
276 QList< FilterGroup * > groups;
277 for (int i = 0; i < m_filterGroups->size(); i++)
278 if (m_filterGroups->at(i)->hasFilter(hasFilterMeth))
279 groups.append(m_filterGroups->at(i));
280
281 const int GROUP_SIZE = groups.size();
282
283 if (GROUP_SIZE) {
284 QString black = "<font color=black>";
285 QString blue = "<font color=darkBlue>";
286 QString red = "<font color=darkRed>";
287 QString end = "</font>";
288
289 QString text = "Showing " + red + title + end + black + " which " + end;
290
291 QString groupLogic;
292 if (m_andGroupsTogether)
293 groupLogic += " AND ";
294 else
295 groupLogic += " OR ";
296
297 QString leftParen = black + "<b>(</b>" + end;
298 QString rightParen = black + "<b>)</b>" + end;
299
300 for (int i = 0; i < GROUP_SIZE - 1; i++) {
301 if (GROUP_SIZE > 1)
302 text += leftParen;
303 text += blue + groups[i]->getDescription(
304 hasFilterMeth, descriptionMeth) + end;
305 if (GROUP_SIZE > 1)
306 text += rightParen + black + "<b>" + groupLogic + "</b>" + end;
307 }
308
309 if (GROUP_SIZE > 1)
310 text += leftParen;
311 text += blue + groups[GROUP_SIZE - 1]->getDescription(
312 hasFilterMeth, descriptionMeth) + end;
313 if (GROUP_SIZE > 1)
314 text += rightParen;
315
316 text += black + "." + end;
317
318 label->setText(text);
319 }
320 }
321 }
322
323
324 void FilterWidget::maybeScroll(FilterGroup *group) {
325
326 if (m_filterGroups && m_filterGroups->size() &&
327 m_filterGroups->at(m_filterGroups->size() - 1) == group)
328 emit scrollToBottom();
329 }
330
331
332 void FilterWidget::addGroup() {
333 FilterGroup *newGroup = new FilterGroup(*m_filterType);
334 addGroup(newGroup);
335 }
336
337
338 void FilterWidget::addGroup(FilterGroup *newGroup) {
339 connect(newGroup, SIGNAL(close(FilterGroup *)),
340 this, SLOT(deleteGroup(FilterGroup *)));
341 connect(newGroup, SIGNAL(filterChanged()), this, SIGNAL(filterChanged()));
342 connect(newGroup, SIGNAL(sizeChanged(FilterGroup *)),
343 this, SLOT(maybeScroll(FilterGroup *)));
344 m_mainLayout->insertWidget(m_mainLayout->count() - 2, newGroup);
345 m_filterGroups->append(newGroup);
346 m_filterGroups->size() > 1 ? m_logicWidget->show() : m_logicWidget->hide();
347
348 emit scrollToBottom();
349 emit filterChanged();
350 }
351
352
353 void FilterWidget::deleteGroup(FilterGroup *filterGroup) {
354 m_mainLayout->removeWidget(filterGroup);
355 delete filterGroup;
356 m_filterGroups->removeOne(filterGroup);
357 m_filterGroups->size() > 1 ? m_logicWidget->show() : m_logicWidget->hide();
358 emit filterChanged();
359 }
360
361
362 void FilterWidget::changeGroupCombinationLogic(int button) {
363 m_andGroupsTogether = button == 0;
364 emit filterChanged();
365 }
366}
This is free and unencumbered software released into the public domain.
Definition Apollo.h:16