Developer Documentation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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 {
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 
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)
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 
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 
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 }
DLLEXPORT OpenFlipperQSettings & OpenFlipperSettings()
QSettings object containing all program settings of OpenFlipper.
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)
unsigned int available()
number of available post processor
void append(unsigned int _active, int _viewerId)
Append the active post processor to the chain for viewer.
void slotContextMenuActivate(const QPoint &_point)
Show the custom context menu for activation.
void insert(unsigned int _active, int _chainIdx, int _viewerId)
Insert the active post processor to the chain for viewer.
QString description
Description of the plugin.
int numActive(int _id)
Get the number of active post processors for viewer.
unsigned currentExaminer_
holds the examiner id for the window
std::vector< unsigned > activeRowToRow_
maps activeRow from activeList (same as chainIdx from RendererInfo) to row from list (same as activeI...
QString version
Version of the plugin.
void updateExaminer(unsigned _viewer)
request an update for an specified viewer
static void loadSavedPostProcessors(const unsigned _examiner)
append all saved post processors
QVariant value(const QString &key, const QVariant &defaultValue=QVariant()) const
void slotContextMenuDeactivate(const QPoint &_point)
Show the custom context menu for deactivation.
void slotDeactivatePostProcessor()
Deactivates the current postProcessor.
void refresh()
refreshes the content of the dialog with current examiner
void slotMoveUp()
move the selected active postprocessor 1 up
QAction * optionsAction
Possible action to add an options action or menu to the system.
void setValue(const QString &key, const QVariant &value)
Wrapper function which makes it possible to enable Debugging output with -DOPENFLIPPER_SETTINGS_DEBUG...
void slotMovePostProcessor(unsigned _from, unsigned _to)
Move the position/ordering of postprocessor in the postprocessor.
void slotMoveDown()
move the selected active postprocessor 1 down
void initWindow()
initiaize the window with the post processors of the current examiner
unsigned int activeExaminer()
Get the id of the examiner which got the last mouse events.
void slotSaveActive()
saves active post processor chain
unsigned int activeId(int _id, int _chainIdx=0)
Get the id of the active post processor for viewer at chain index.
void slotActivatePostProcessor()
Activates the post processor (triggered via the context menu)
static QStringList getSavedPostProcessorNames(const unsigned _examiner)
return the names of all saved post processors