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 }
DLLEXPORT OpenFlipperQSettings & OpenFlipperSettings()
QSettings object containing all program settings of OpenFlipper.
void append(unsigned int _active, int _viewerId)
Append the active post processor to the chain for viewer.
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 slotMoveDown()
move the selected active postprocessor 1 down
void slotSaveActive()
saves active post processor chain
void setValue(const QString &key, const QVariant &value)
Wrapper function which makes it possible to enable Debugging output with -DOPENFLIPPER_SETTINGS_DEBUG...
void initWindow()
initiaize the window with the post processors of the current examiner
void insert(unsigned int _active, int _chainIdx, int _viewerId)
Insert the active post processor to the chain for viewer.
QAction * optionsAction
Possible action to add an options action or menu to the system.
static QStringList getSavedPostProcessorNames(const unsigned _examiner)
return the names of all saved post processors
unsigned int activeId(int _id, int _chainIdx=0)
Get the id of the active post processor for viewer at chain index.
QString description
Description of the plugin.
void refresh()
refreshes the content of the dialog with current examiner
void slotMoveUp()
move the selected active postprocessor 1 up
void remove(int _id, int _chainIdx)
Remove a post processor at the specified chain index.
void slotDeactivatePostProcessor()
Deactivates the current postProcessor.
size_t available()
number of available post processor
int numActive(int _id)
Get the number of active post processors for viewer.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant()) const
void slotActivatePostProcessor()
Activates the post processor (triggered via the context menu)
QString version
Version of the plugin.
void slotContextMenuDeactivate(const QPoint &_point)
Show the custom context menu for deactivation.
void slotContextMenuActivate(const QPoint &_point)
Show the custom context menu for activation.
void slotMovePostProcessor(unsigned _from, unsigned _to)
Move the position/ordering of postprocessor in the postprocessor.
static void loadSavedPostProcessors(const unsigned _examiner)
append all saved post processors