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