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 * *
44 * $Revision$ *
45 * $LastChangedBy$ *
46 * $Date$ *
47 * *
48 \*===========================================================================*/
49 
51 #include <OpenFlipper/common/RendererInfo.hh>
53 
54 #if QT_VERSION >= 0x050000
55  #include <QtWidgets>
56 #else
57  #include <QtGui>
58 #endif
59 
60 #include "postProcessorWidget.hh"
61 
62 
63 PostProcessorDialog::PostProcessorDialog(QWidget *_parent)
64  : QDialog(_parent)
65 {
66  setupUi(this);
67 
68  list->setContextMenuPolicy(Qt::CustomContextMenu);
69  activeList->setContextMenuPolicy(Qt::CustomContextMenu);
70 
71  connect(closeButton, SIGNAL(clicked()), this, SLOT(accept()));
72  connect(list,SIGNAL(customContextMenuRequested(const QPoint&)),this,SLOT(slotContextMenuActivate(const QPoint&)));
73  connect(activeList,SIGNAL(customContextMenuRequested(const QPoint&)),this,SLOT(slotContextMenuDeactivate(const QPoint&)));
74  connect(activateButton,SIGNAL(clicked()),this,SLOT(slotActivatePostProcessor()));
75  connect(deactivateButton,SIGNAL(clicked()),this,SLOT(slotDeactivatePostProcessor()));
76  connect(upButton,SIGNAL(clicked()),this,SLOT(slotMoveUp()));
77  connect(downButton,SIGNAL(clicked()),this,SLOT(slotMoveDown()));
78  connect(saveButton,SIGNAL(clicked()),this,SLOT(slotSaveActive()));
79  connect(refreshButton,SIGNAL(clicked()), this,SLOT(refresh()));
80 
81  //set icons
82  QString iconPath = OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator();
83 
84  closeButton->setIcon( QIcon(iconPath + "window-close.png"));
85  saveButton->setIcon( QIcon(iconPath + "document-save.png"));
86  refreshButton->setIcon( QIcon(iconPath + "edit-redo.png"));
87 
88 }
89 
90 void PostProcessorDialog::closeEvent(QCloseEvent *_event)
91 {
92  _event->accept();
93  accept();
94 }
95 
96 void PostProcessorDialog::showEvent ( QShowEvent * )
97 {
98  initWindow();
99 }
100 
102 {
103  currentExaminer_ = PluginFunctions::activeExaminer();
104  list->clear();
105  activeList->clear();
106  activeRowToRow_.clear();
107 
108  //first, fill already activated processors in the right order
109  for (int i = 0; i < postProcessorManager().numActive(currentExaminer_); ++i)
110  {
111  unsigned int id = postProcessorManager().activeId(currentExaminer_, i);
112  activeRowToRow_.push_back(id);
113 
114  QListWidgetItem *activeItem = new QListWidgetItem("");
115  activeList->addItem(activeItem);
116  QFrame* frame = createFrame(*postProcessorManager()[id]);
117  activeItem->setSizeHint(frame->sizeHint());
118  activeList->setItemWidget(activeItem,frame);
119  }
120 
121  //list all available post processors (hidden, if active)
122  for ( unsigned int i = 0 ; i < postProcessorManager().available() ; ++i)
123  {
124 
125  // Get and check post processor
126  PostProcessorInfo* processor = postProcessorManager()[i];
127  if ( ! processor )
128  continue;
129 
130  QFrame* frame = createFrame(*processor);
131 
132  QListWidgetItem *item = new QListWidgetItem("");
133  item->setSizeHint( frame->sizeHint() );
134 
135  list->addItem(item);
136 
137  list->setItemWidget(item, frame);
138 
139  //is the postProcess active? if so, hide it
140  bool found = false;
141  for (std::vector<unsigned>::iterator iter = activeRowToRow_.begin(); iter != activeRowToRow_.end() && !found; ++iter)
142  found = (*iter == i);
143  if ( found )
144  list->setRowHidden(list->row(item),true);
145  }
146 
147 }
148 
150 {
151  QList<QListWidgetItem*> selectedItems = list->selectedItems();
152 
153  for (int i=0; i < selectedItems.size(); ++i)
154  {
155  QListWidgetItem* item = selectedItems[i];
156  const int currentRow = list->row( item );
157 
158  postProcessorManager().append( currentRow, currentExaminer_);
159 
160  //disable in aviable list
161  item->setHidden(true);
162  item->setSelected(false);
163 
164  //add to active list
165  QListWidgetItem *activeItem = new QListWidgetItem("");
166  activeList->addItem(activeItem);
167  activeItem->setSelected(true);
168 
169  QFrame* frame = createFrame(*postProcessorManager()[currentRow]);
170  activeItem->setSizeHint( frame->sizeHint() );
171  activeList->setItemWidget(activeItem,frame);
172  activeRowToRow_.push_back(currentRow);
173  }
174 
175  emit updateExaminer(currentExaminer_);
176 
177 }
178 
180 {
181  QList<QListWidgetItem*> selectedItems = activeList->selectedItems();
182 
183  for (int i=0; i < selectedItems.size(); ++i)
184  {
185  QListWidgetItem* activeItem = selectedItems[i];
186 
187  const unsigned chainPos = activeList->row(activeItem);
188  const unsigned activeID = activeRowToRow_[chainPos];
189  QListWidgetItem* item = list->item(activeID);
190 
191  //remove postprocessor
192  postProcessorManager().remove(currentExaminer_, chainPos);
193 
194  //enable in aviable list
195  item->setHidden(false);
196  item->setSelected(true);
197 
198  //remove from active list
199  //update active row ids
200  for (unsigned i = chainPos; i < activeRowToRow_.size()-1; ++i)
201  activeRowToRow_[i] = activeRowToRow_[i+1];
202 
203  //from qt doc: Items removed from a list widget will not be managed by Qt, and will need to be deleted manually.
204  activeItem = activeList->takeItem(activeList->row(activeItem));
205  delete activeItem;
206  }
207  activeRowToRow_.erase( activeRowToRow_.end()-selectedItems.size(), activeRowToRow_.end());
208 
209  emit updateExaminer(currentExaminer_);
210 }
211 
212 void PostProcessorDialog::slotMovePostProcessor(unsigned _from,unsigned _to)
213 {
214 
215  if (_from >= static_cast<unsigned>(activeList->count()))
216  return;
217 
218  if (_to >= static_cast<unsigned>(activeList->count()))
219  _to = activeList->count()-1;
220 
221  if (_from == _to)
222  return;
223 
224  //swap widget
225  QListWidgetItem* activeItem = activeList->takeItem(_from);
226  activeList->insertItem(_to,activeItem);
227  QFrame* frame = createFrame(*postProcessorManager()[activeRowToRow_[_from]]);
228  activeItem->setSizeHint(frame->sizeHint());
229  activeList->setItemWidget(activeItem,frame);
230  activeList->setItemSelected(activeItem,true);
231 
232  //swap postprocessor
233  const int chainPos = _from;
234  const int activeID = activeRowToRow_[_from];
235  postProcessorManager().remove(currentExaminer_, chainPos);
236  postProcessorManager().insert(activeID,_to,currentExaminer_);
237 
238  //swap active ID to current chain position map
239  int inc = (_from > _to)? -1: +1;
240  for(unsigned int currentRow = _from;currentRow != _to; currentRow += inc)
241  std::swap(activeRowToRow_[currentRow+inc],activeRowToRow_[currentRow]);
242 
243  emit updateExaminer(currentExaminer_);
244 }
245 
246 
248 {
249  if (!list->count())
250  return;
251 
252  QMenu *menu = new QMenu(list);
253  QAction* action = 0;
254 
255  action = menu->addAction(tr("Activate"));
256  connect(action,SIGNAL(triggered(bool)),this,SLOT(slotActivatePostProcessor()));
257 
258  menu->exec(list->mapToGlobal(_point),0);
259 
260 }
261 
263 {
264  if (!activeList->count())
265  return;
266 
267  QMenu *menu = new QMenu(activeList);
268  QAction* action = 0;
269 
270  action = menu->addAction(tr("Up"));
271  connect(action,SIGNAL(triggered(bool)),this,SLOT(slotMoveUp()));
272  action = menu->addAction(tr("Down"));
273  connect(action,SIGNAL(triggered(bool)),this,SLOT(slotMoveDown()));
274  action = menu->addAction(tr("Deactivate"));
275  connect(action,SIGNAL(triggered(bool)),this,SLOT(slotDeactivatePostProcessor()));
276 
277  menu->exec(activeList->mapToGlobal(_point),0);
278 
279 }
280 
281 QFrame* PostProcessorDialog::createFrame(const PostProcessorInfo& _pPI)
282 {
283  QFrame* frame = new QFrame();
284  QHBoxLayout* hlayout = new QHBoxLayout;
285 
286  QLabel* name = new QLabel( _pPI.name );
287  QFont font;
288  font.setBold(true);
289  font.setPointSize(10);
290  name->setFont(font);
291  QLabel* version = new QLabel( _pPI.version );
292  QPushButton* optionsButton = new QPushButton("Options");
293  hlayout->addWidget(name);
294  hlayout->addStretch();
295  hlayout->addWidget(version);
296 
297  optionsButton->setEnabled(false);
298  if (_pPI.optionsAction != 0)
299  {
300  optionsButton->setEnabled(true);
301  connect(optionsButton,SIGNAL(clicked()),_pPI.optionsAction,SLOT(trigger()));
302  }
303 
304  QVBoxLayout* vlayout = new QVBoxLayout;
305 
306  QLabel* description = new QLabel( _pPI.description );
307 
308  vlayout->addLayout(hlayout,20);
309 
310  QHBoxLayout* optionsLayout = new QHBoxLayout();
311  vlayout->addLayout(optionsLayout);
312  optionsLayout->addWidget(description);
313  optionsLayout->addStretch();
314  optionsLayout->addWidget(optionsButton);
315 
316  frame->setLayout(vlayout);
317  frame->adjustSize();
318 
319  return frame;
320 }
321 
322 
323 
324 template<typename TCmp>
326 {
327  QListWidget* list_;
328 public:
329  QListWidgetRowCmp(QListWidget* _list):list_(_list){}
330  bool operator()(QListWidgetItem* left, QListWidgetItem* right)
331  {
332  return TCmp()(list_->row(left) , list_->row(right));
333  }
334 };
335 
337 {
338  int start = 0;
339  QList<QListWidgetItem*> selectedItems = activeList->selectedItems();
340 
341  //sort list, so the top is the last element
342  std::sort(selectedItems.begin(), selectedItems.end(), QListWidgetRowCmp<std::greater<int> >(activeList));
343 
344  //dont move the last one
345  //if the last one wasnt moved, dont move the direct followers
346  for(int i=0; i < selectedItems.size() && activeList->row(selectedItems[i]) == activeList->count()-1-i;++i)
347  --start;
348 
349  //move bottom first
350  for (int i=selectedItems.size()-1+start; i >= 0 ; --i)
351  {
352  QListWidgetItem* activeItem = activeList->selectedItems()[i];
353  unsigned selectedRow = activeList->row(activeItem);
354  slotMovePostProcessor(selectedRow,selectedRow+1);
355  }
356 }
357 
358 
360 {
361  int start = 0;
362  QList<QListWidgetItem*> selectedItems = activeList->selectedItems();
363 
364  //sort list, so the top is the first element
365  std::sort(selectedItems.begin(), selectedItems.end(), QListWidgetRowCmp<std::less<int> >(activeList));
366 
367  //dont move the first one
368  //if the first one wasnt moved, dont move the direct followers
369  for(int i=0; i < selectedItems.size() && activeList->row(selectedItems[i]) == i;++i)
370  ++start;
371 
372  //move top first
373  for (int i=start; i < selectedItems.size(); ++i)
374  {
375  QListWidgetItem* activeItem = selectedItems[i];
376  unsigned selectedRow = activeList->row(activeItem);
377  slotMovePostProcessor(selectedRow,selectedRow-1);
378  }
379 }
380 
382 {
383  QStringList activeList("");
384 
385  for (int i = 0; i < postProcessorManager().numActive(currentExaminer_); ++i)
386  {
387  unsigned int id = postProcessorManager().activeId(currentExaminer_, i);
388  activeList.push_back(postProcessorManager()[id]->name);
389  }
390 
391  OpenFlipperSettings().setValue(QString("PostProcessor/Viewer/%1").arg(currentExaminer_),activeList);
392 }
393 
394 QStringList PostProcessorDialog::getSavedPostProcessorNames(const unsigned _examiner)
395 {
396  return OpenFlipperSettings().value(QString("PostProcessor/Viewer/%1").arg(_examiner),QStringList("")).toStringList();
397 }
398 
399 void PostProcessorDialog::loadSavedPostProcessors(const unsigned _examiner)
400 {
401  QStringList active = getSavedPostProcessorNames(_examiner);
402  for (QStringList::iterator iter = active.begin(); iter != active.end(); ++iter)
403  {
404  postProcessorManager().append(*iter,_examiner);
405  }
406 }
407 
409 {
410  initWindow();
411 }
void slotMoveDown()
move the selected active postprocessor 1 down
void initWindow()
initiaize the window with the post processors of the current examiner
static void loadSavedPostProcessors(const unsigned _examiner)
append all saved post processors
QAction * optionsAction
Possible action to add an options action or menu to the system.
void insert(unsigned int _active, int _chainIdx, int _viewerId)
Insert the active post processor to the chain for viewer.
unsigned int available()
number of available post processor
void slotMovePostProcessor(unsigned _from, unsigned _to)
Move the position/ordering of postprocessor in the postprocessor.
int numActive(int _id)
Get the number of active post processors for viewer.
DLLEXPORT OpenFlipperQSettings & OpenFlipperSettings()
QSettings object containing all program settings of OpenFlipper.
void slotMoveUp()
move the selected active postprocessor 1 up
unsigned int activeId(int _id, int _chainIdx=0)
Get the id of the active post processor for viewer at chain index.
void slotDeactivatePostProcessor()
Deactivates the current postProcessor.
void slotContextMenuDeactivate(const QPoint &_point)
Show the custom context menu for deactivation.
void setValue(const QString &key, const QVariant &value)
Wrapper function which makes it possible to enable Debugging output with -DOPENFLIPPER_SETTINGS_DEBUG...
void slotSaveActive()
saves active post processor chain
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)
QVariant value(const QString &key, const QVariant &defaultValue=QVariant()) const
QString description
Description of the plugin.
QString name
Name of the plugin ( requested from the plugin on load)
unsigned int activeExaminer()
Get the id of the examiner which got the last mouse events.
void slotContextMenuActivate(const QPoint &_point)
Show the custom context menu for activation.
void refresh()
refreshes the content of the dialog with current examiner
void append(unsigned int _active, int _viewerId)
Append the active post processor to the chain for viewer.
QString version
Version of the plugin.
void remove(int _id, int _chainIdx)
Remove a post processor at the specified chain index.