Developer Documentation
postProcessorWidget.cc
1 /*===========================================================================*\
2 * *
3 * OpenFlipper *
4  * Copyright (c) 2001-2015, RWTH-Aachen University *
5  * Department of Computer Graphics and Multimedia *
6  * All rights reserved. *
7  * www.openflipper.org *
8  * *
9  *---------------------------------------------------------------------------*
10  * This file is part of OpenFlipper. *
11  *---------------------------------------------------------------------------*
12  * *
13  * Redistribution and use in source and binary forms, with or without *
14  * modification, are permitted provided that the following conditions *
15  * are met: *
16  * *
17  * 1. Redistributions of source code must retain the above copyright notice, *
18  * this list of conditions and the following disclaimer. *
19  * *
20  * 2. Redistributions in binary form must reproduce the above copyright *
21  * notice, this list of conditions and the following disclaimer in the *
22  * documentation and/or other materials provided with the distribution. *
23  * *
24  * 3. Neither the name of the copyright holder nor the names of its *
25  * contributors may be used to endorse or promote products derived from *
26  * this software without specific prior written permission. *
27  * *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39 * *
40 \*===========================================================================*/
41 
42 
43 
45 #include <OpenFlipper/common/RendererInfo.hh>
47 
48 #include <QtWidgets>
49 
50 #include "postProcessorWidget.hh"
51 
52 
53 PostProcessorDialog::PostProcessorDialog(QWidget *_parent)
54  : QDialog(_parent)
55 {
56  setupUi(this);
57 
58  list->setContextMenuPolicy(Qt::CustomContextMenu);
59  activeList->setContextMenuPolicy(Qt::CustomContextMenu);
60 
61  connect(closeButton, SIGNAL(clicked()), this, SLOT(accept()));
62  connect(list,SIGNAL(customContextMenuRequested(const QPoint&)),this,SLOT(slotContextMenuActivate(const QPoint&)));
63  connect(activeList,SIGNAL(customContextMenuRequested(const QPoint&)),this,SLOT(slotContextMenuDeactivate(const QPoint&)));
64  connect(activateButton,SIGNAL(clicked()),this,SLOT(slotActivatePostProcessor()));
65  connect(deactivateButton,SIGNAL(clicked()),this,SLOT(slotDeactivatePostProcessor()));
66  connect(upButton,SIGNAL(clicked()),this,SLOT(slotMoveUp()));
67  connect(downButton,SIGNAL(clicked()),this,SLOT(slotMoveDown()));
68  connect(saveButton,SIGNAL(clicked()),this,SLOT(slotSaveActive()));
69  connect(refreshButton,SIGNAL(clicked()), this,SLOT(refresh()));
70 
71  //set icons
72  QString iconPath = OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator();
73 
74  closeButton->setIcon( QIcon(iconPath + "window-close.png"));
75  saveButton->setIcon( QIcon(iconPath + "document-save.png"));
76  refreshButton->setIcon( QIcon(iconPath + "edit-redo.png"));
77 
78 }
79 
80 void PostProcessorDialog::closeEvent(QCloseEvent *_event)
81 {
82  _event->accept();
83  accept();
84 }
85 
86 void PostProcessorDialog::showEvent ( QShowEvent * )
87 {
88  initWindow();
89 }
90 
92 {
93  currentExaminer_ = PluginFunctions::activeExaminer();
94  list->clear();
95  activeList->clear();
96  activeRowToRow_.clear();
97 
98  //first, fill already activated processors in the right order
99  for (int i = 0; i < postProcessorManager().numActive(currentExaminer_); ++i)
100  {
101  unsigned int id = postProcessorManager().activeId(currentExaminer_, i);
102  activeRowToRow_.push_back(id);
103 
104  QListWidgetItem *activeItem = new QListWidgetItem("");
105  activeList->addItem(activeItem);
106  QFrame* frame = createFrame(*postProcessorManager()[id]);
107  activeItem->setSizeHint(frame->sizeHint());
108  activeList->setItemWidget(activeItem,frame);
109  }
110 
111  //list all available post processors (hidden, if active)
112  for ( unsigned int i = 0 ; i < postProcessorManager().available() ; ++i)
113  {
114 
115  // Get and check post processor
116  PostProcessorInfo* processor = postProcessorManager()[i];
117  if ( ! processor )
118  continue;
119 
120  QFrame* frame = createFrame(*processor);
121 
122  QListWidgetItem *item = new QListWidgetItem("");
123  item->setSizeHint( frame->sizeHint() );
124 
125  list->addItem(item);
126 
127  list->setItemWidget(item, frame);
128 
129  //is the postProcess active? if so, hide it
130  bool found = false;
131  for (std::vector<unsigned>::iterator iter = activeRowToRow_.begin(); iter != activeRowToRow_.end() && !found; ++iter)
132  found = (*iter == i);
133  if ( found )
134  list->setRowHidden(list->row(item),true);
135  }
136 
137 }
138 
140 {
141  QList<QListWidgetItem*> selectedItems = list->selectedItems();
142 
143  for (int i=0; i < selectedItems.size(); ++i)
144  {
145  QListWidgetItem* item = selectedItems[i];
146  const int currentRow = list->row( item );
147 
148  postProcessorManager().append( currentRow, currentExaminer_);
149 
150  //disable in aviable list
151  item->setHidden(true);
152  item->setSelected(false);
153 
154  //add to active list
155  QListWidgetItem *activeItem = new QListWidgetItem("");
156  activeList->addItem(activeItem);
157  activeItem->setSelected(true);
158 
159  QFrame* frame = createFrame(*postProcessorManager()[currentRow]);
160  activeItem->setSizeHint( frame->sizeHint() );
161  activeList->setItemWidget(activeItem,frame);
162  activeRowToRow_.push_back(currentRow);
163  }
164 
165  emit updateExaminer(currentExaminer_);
166 
167 }
168 
170 {
171  QList<QListWidgetItem*> selectedItems = activeList->selectedItems();
172 
173  for (int i=0; i < selectedItems.size(); ++i)
174  {
175  QListWidgetItem* activeItem = selectedItems[i];
176 
177  const unsigned chainPos = activeList->row(activeItem);
178  const unsigned activeID = activeRowToRow_[chainPos];
179  QListWidgetItem* item = list->item(activeID);
180 
181  //remove postprocessor
182  postProcessorManager().remove(currentExaminer_, chainPos);
183 
184  //enable in aviable list
185  item->setHidden(false);
186  item->setSelected(true);
187 
188  //remove from active list
189  //update active row ids
190  for (unsigned i = chainPos; i < activeRowToRow_.size()-1; ++i)
191  activeRowToRow_[i] = activeRowToRow_[i+1];
192 
193  //from qt doc: Items removed from a list widget will not be managed by Qt, and will need to be deleted manually.
194  activeItem = activeList->takeItem(activeList->row(activeItem));
195  delete activeItem;
196  }
197  activeRowToRow_.erase( activeRowToRow_.end()-selectedItems.size(), activeRowToRow_.end());
198 
199  emit updateExaminer(currentExaminer_);
200 }
201 
202 void PostProcessorDialog::slotMovePostProcessor(unsigned _from,unsigned _to)
203 {
204 
205  if (_from >= static_cast<unsigned>(activeList->count()))
206  return;
207 
208  if (_to >= static_cast<unsigned>(activeList->count()))
209  _to = activeList->count()-1;
210 
211  if (_from == _to)
212  return;
213 
214  //swap widget
215  QListWidgetItem* activeItem = activeList->takeItem(_from);
216  activeList->insertItem(_to,activeItem);
217  QFrame* frame = createFrame(*postProcessorManager()[activeRowToRow_[_from]]);
218  activeItem->setSizeHint(frame->sizeHint());
219  activeList->setItemWidget(activeItem,frame);
220  activeList->setItemSelected(activeItem,true);
221 
222  //swap postprocessor
223  const int chainPos = _from;
224  const int activeID = activeRowToRow_[_from];
225  postProcessorManager().remove(currentExaminer_, chainPos);
226  postProcessorManager().insert(activeID,_to,currentExaminer_);
227 
228  //swap active ID to current chain position map
229  int inc = (_from > _to)? -1: +1;
230  for(unsigned int currentRow = _from;currentRow != _to; currentRow += inc)
231  std::swap(activeRowToRow_[currentRow+inc],activeRowToRow_[currentRow]);
232 
233  emit updateExaminer(currentExaminer_);
234 }
235 
236 
238 {
239  if (!list->count())
240  return;
241 
242  QMenu *menu = new QMenu(list);
243  QAction* action = 0;
244 
245  action = menu->addAction(tr("Activate"));
246  connect(action,SIGNAL(triggered(bool)),this,SLOT(slotActivatePostProcessor()));
247 
248  menu->exec(list->mapToGlobal(_point),0);
249 
250 }
251 
253 {
254  if (!activeList->count())
255  return;
256 
257  QMenu *menu = new QMenu(activeList);
258  QAction* action = 0;
259 
260  action = menu->addAction(tr("Up"));
261  connect(action,SIGNAL(triggered(bool)),this,SLOT(slotMoveUp()));
262  action = menu->addAction(tr("Down"));
263  connect(action,SIGNAL(triggered(bool)),this,SLOT(slotMoveDown()));
264  action = menu->addAction(tr("Deactivate"));
265  connect(action,SIGNAL(triggered(bool)),this,SLOT(slotDeactivatePostProcessor()));
266 
267  menu->exec(activeList->mapToGlobal(_point),0);
268 
269 }
270 
271 QFrame* PostProcessorDialog::createFrame(const PostProcessorInfo& _pPI)
272 {
273  QFrame* frame = new QFrame();
274  QHBoxLayout* hlayout = new QHBoxLayout;
275 
276  QLabel* name = new QLabel( _pPI.name );
277  QFont font;
278  font.setBold(true);
279  font.setPointSize(10);
280  name->setFont(font);
281  QLabel* version = new QLabel( _pPI.version );
282  QPushButton* optionsButton = new QPushButton("Options");
283  hlayout->addWidget(name);
284  hlayout->addStretch();
285  hlayout->addWidget(version);
286 
287  optionsButton->setEnabled(false);
288  if (_pPI.optionsAction != 0)
289  {
290  optionsButton->setEnabled(true);
291  connect(optionsButton,SIGNAL(clicked()),_pPI.optionsAction,SLOT(trigger()));
292  }
293 
294  QVBoxLayout* vlayout = new QVBoxLayout;
295 
296  QLabel* description = new QLabel( _pPI.description );
297 
298  vlayout->addLayout(hlayout,20);
299 
300  QHBoxLayout* optionsLayout = new QHBoxLayout();
301  vlayout->addLayout(optionsLayout);
302  optionsLayout->addWidget(description);
303  optionsLayout->addStretch();
304  optionsLayout->addWidget(optionsButton);
305 
306  frame->setLayout(vlayout);
307  frame->adjustSize();
308 
309  return frame;
310 }
311 
312 
313 
314 template<typename TCmp>
316 {
317  QListWidget* list_;
318 public:
319  explicit QListWidgetRowCmp(QListWidget* _list):list_(_list){}
320  bool operator()(QListWidgetItem* left, QListWidgetItem* right)
321  {
322  return TCmp()(list_->row(left) , list_->row(right));
323  }
324 };
325 
327 {
328  int start = 0;
329  QList<QListWidgetItem*> selectedItems = activeList->selectedItems();
330 
331  //sort list, so the top is the last element
332  std::sort(selectedItems.begin(), selectedItems.end(), QListWidgetRowCmp<std::greater<int> >(activeList));
333 
334  //dont move the last one
335  //if the last one wasnt moved, dont move the direct followers
336  for(int i=0; i < selectedItems.size() && activeList->row(selectedItems[i]) == activeList->count()-1-i;++i)
337  --start;
338 
339  //move bottom first
340  for (int i=selectedItems.size()-1+start; i >= 0 ; --i)
341  {
342  QListWidgetItem* activeItem = activeList->selectedItems()[i];
343  unsigned selectedRow = activeList->row(activeItem);
344  slotMovePostProcessor(selectedRow,selectedRow+1);
345  }
346 }
347 
348 
350 {
351  int start = 0;
352  QList<QListWidgetItem*> selectedItems = activeList->selectedItems();
353 
354  //sort list, so the top is the first element
355  std::sort(selectedItems.begin(), selectedItems.end(), QListWidgetRowCmp<std::less<int> >(activeList));
356 
357  //dont move the first one
358  //if the first one wasnt moved, dont move the direct followers
359  for(int i=0; i < selectedItems.size() && activeList->row(selectedItems[i]) == i;++i)
360  ++start;
361 
362  //move top first
363  for (int i=start; i < selectedItems.size(); ++i)
364  {
365  QListWidgetItem* activeItem = selectedItems[i];
366  unsigned selectedRow = activeList->row(activeItem);
367  slotMovePostProcessor(selectedRow,selectedRow-1);
368  }
369 }
370 
372 {
373  QStringList activeList("");
374 
375  for (int i = 0; i < postProcessorManager().numActive(currentExaminer_); ++i)
376  {
377  unsigned int id = postProcessorManager().activeId(currentExaminer_, i);
378  activeList.push_back(postProcessorManager()[id]->name);
379  }
380 
381  OpenFlipperSettings().setValue(QString("PostProcessor/Viewer/%1").arg(currentExaminer_),activeList);
382 }
383 
384 QStringList PostProcessorDialog::getSavedPostProcessorNames(const unsigned _examiner)
385 {
386  return OpenFlipperSettings().value(QString("PostProcessor/Viewer/%1").arg(_examiner),QStringList("")).toStringList();
387 }
388 
389 void PostProcessorDialog::loadSavedPostProcessors(const unsigned _examiner)
390 {
391  QStringList active = getSavedPostProcessorNames(_examiner);
392  for (QStringList::iterator iter = active.begin(); iter != active.end(); ++iter)
393  {
394  postProcessorManager().append(*iter,_examiner);
395  }
396 }
397 
399 {
400  initWindow();
401 }
static void loadSavedPostProcessors(const unsigned _examiner)
append all saved post processors
void slotDeactivatePostProcessor()
Deactivates the current postProcessor.
QString description
Description of the plugin.
QString version
Version of the plugin.
size_t available()
number of available post processor
void initWindow()
initiaize the window with the post processors of the current examiner
void slotMovePostProcessor(unsigned _from, unsigned _to)
Move the position/ordering of postprocessor in the postprocessor.
void slotMoveUp()
move the selected active postprocessor 1 up
unsigned int activeExaminer()
Get the id of the examiner which got the last mouse events.
void remove(int _id, int _chainIdx)
Remove a post processor at the specified chain index.
QString name
Name of the plugin ( requested from the plugin on load)
void append(unsigned int _active, int _viewerId)
Append the active post processor to the chain for viewer.
void insert(unsigned int _active, int _chainIdx, int _viewerId)
Insert the active post processor to the chain for viewer.
void refresh()
refreshes the content of the dialog with current examiner
QVariant value(const QString &key, const QVariant &defaultValue=QVariant()) const
unsigned int activeId(int _id, int _chainIdx=0)
Get the id of the active post processor for viewer at chain index.
void slotContextMenuDeactivate(const QPoint &_point)
Show the custom context menu for deactivation.
int numActive(int _id)
Get the number of active post processors for viewer.
void setValue(const QString &key, const QVariant &value)
Wrapper function which makes it possible to enable Debugging output with -DOPENFLIPPER_SETTINGS_DEBUG...
void slotMoveDown()
move the selected active postprocessor 1 down
DLLEXPORT OpenFlipperQSettings & OpenFlipperSettings()
QSettings object containing all program settings of OpenFlipper.
static QStringList getSavedPostProcessorNames(const unsigned _examiner)
return the names of all saved post processors
void slotActivatePostProcessor()
Activates the post processor (triggered via the context menu)
QAction * optionsAction
Possible action to add an options action or menu to the system.
void slotSaveActive()
saves active post processor chain
void slotContextMenuActivate(const QPoint &_point)
Show the custom context menu for activation.