1
//---------------------------------------------------------------------------
3
// Project: OpenWalnut ( http://www.openwalnut.org )
5
// Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
6
// For more information see http://www.openwalnut.org/copying
8
// This file is part of OpenWalnut.
10
// OpenWalnut is free software: you can redistribute it and/or modify
11
// it under the terms of the GNU Lesser General Public License as published by
12
// the Free Software Foundation, either version 3 of the License, or
13
// (at your option) any later version.
15
// OpenWalnut is distributed in the hope that it will be useful,
16
// but WITHOUT ANY WARRANTY; without even the implied warranty of
17
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
// GNU Lesser General Public License for more details.
20
// You should have received a copy of the GNU Lesser General Public License
21
// along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
23
//---------------------------------------------------------------------------
32
#include <QtCore/QList>
33
#include <QtGui/QMenu>
34
#include <QtGui/QScrollArea>
35
#include <QtGui/QShortcut>
36
#include <QtGui/QSplitter>
37
#include <QtGui/QMessageBox>
39
#include "core/common/WLogger.h"
40
#include "core/common/WPredicateHelper.h"
41
#include "core/dataHandler/WDataSet.h"
42
#include "core/kernel/WDataModule.h"
43
#include "core/kernel/WKernel.h"
44
#include "core/kernel/WModule.h"
45
#include "core/kernel/WModuleContainer.h"
46
#include "core/kernel/WModuleFactory.h"
47
#include "core/kernel/WROIManager.h"
48
#include "../WMainWindow.h"
49
#include "../WQt4Gui.h"
50
#include "../WQtCombinerActionList.h"
51
#include "../WQtModuleConfig.h"
52
#include "../events/WEventTypes.h"
53
#include "../events/WModuleAssocEvent.h"
54
#include "../events/WModuleConnectEvent.h"
55
#include "../events/WModuleConnectorEvent.h"
56
#include "../events/WModuleDeleteEvent.h"
57
#include "../events/WModuleDisconnectEvent.h"
58
#include "../events/WModuleReadyEvent.h"
59
#include "../events/WModuleRemovedEvent.h"
60
#include "../events/WRoiAssocEvent.h"
61
#include "../events/WRoiRemoveEvent.h"
62
#include "../guiElements/WQtModuleMetaInfo.h"
63
#include "../guiElements/WQtMenuFiltered.h"
64
#include "../networkEditor/WQtNetworkEditor.h"
65
#include "WQtBranchTreeItem.h"
66
#include "WQtColormapper.h"
68
#include "WQtControlPanel.h"
69
#include "WQtControlPanel.moc"
71
WQtControlPanel::WQtControlPanel( WMainWindow* parent )
72
: QDockWidget( "Control Panel", parent ),
73
m_ignoreSelectionChange( false ),
74
m_activeModule( WModule::SPtr() ),
77
setObjectName( "Control Panel Dock" );
79
m_mainWindow = parent;
80
setMinimumWidth( 200 );
82
m_moduleTreeWidget = new WQtTreeWidget();
83
m_moduleTreeWidget->setContextMenuPolicy( Qt::ActionsContextMenu );
85
m_moduleTreeWidget->setHeaderLabel( QString( "Module Tree" ) );
86
m_moduleTreeWidget->setDragEnabled( false );
87
m_moduleTreeWidget->viewport()->setAcceptDrops( true );
88
m_moduleTreeWidget->setDropIndicatorShown( true );
89
m_moduleTreeWidget->setMinimumHeight( 100 );
91
// create context menu for tree items
93
// a separator to clean up the tree widget's context menu
94
QAction* separator = new QAction( m_moduleTreeWidget );
95
separator->setSeparator( true );
96
m_moduleTreeWidget->addAction( separator );
98
m_addModuleAction = new QAction( WQt4Gui::getMainWindow()->getIconManager()->getIcon( "add" ), "Add Module", m_moduleTreeWidget );
99
m_moduleTreeWidget->addAction( m_addModuleAction );
100
m_connectWithPrototypeAction = new QAction( WQt4Gui::getMainWindow()->getIconManager()->getIcon( "addAndLink" ), "Add Module and Connect",
101
m_moduleTreeWidget );
102
m_moduleTreeWidget->addAction( m_connectWithPrototypeAction );
103
m_connectWithModuleAction = new QAction( WQt4Gui::getMainWindow()->getIconManager()->getIcon( "link" ), "Connect Existing Module",
104
m_moduleTreeWidget );
105
m_moduleTreeWidget->addAction( m_connectWithModuleAction );
106
m_disconnectAction = new QAction( WQt4Gui::getMainWindow()->getIconManager()->getIcon( "unlink" ), "Disconnect", m_moduleTreeWidget );
107
m_moduleTreeWidget->addAction( m_disconnectAction );
109
// a separator to clean up the tree widget's context menu
110
m_moduleTreeWidget->addAction( separator );
112
m_deleteModuleAction = new QAction( WQt4Gui::getMainWindow()->getIconManager()->getIcon( "remove" ), "Remove Module", m_moduleTreeWidget );
114
// Set the key for removing modules
115
//m_deleteModuleAction->setShortcutContext( Qt::WidgetShortcut );
116
m_deleteModuleAction->setShortcutContext( Qt::WidgetWithChildrenShortcut );
117
m_deleteModuleAction->setShortcut( QKeySequence::Delete );
118
m_deleteModuleAction->setIconVisibleInMenu( true );
120
connect( m_deleteModuleAction, SIGNAL( triggered() ), this, SLOT( deleteModule() ) );
121
m_moduleTreeWidget->addAction( m_deleteModuleAction );
123
// a separator to clean up the tree widget's context menu
124
m_moduleTreeWidget->addAction( separator );
126
// add an entry for those who search their module without luck
127
m_missingModuleAction = new QAction( WQt4Gui::getMainWindow()->getIconManager()->getIcon( "missingModule" ), "Missing Module?",
128
m_moduleTreeWidget );
129
m_missingModuleAction->setToolTip( "Having trouble finding your module? This opens the module configuration, which allows you to define the "
130
"modules that should be shown or hidden." );
131
m_missingModuleAction->setIconVisibleInMenu( true );
132
m_moduleTreeWidget->addAction( m_missingModuleAction );
134
// the network editor also needs the context menu
135
if( m_mainWindow->getNetworkEditor() )
137
m_mainWindow->getNetworkEditor()->getView()->setContextMenuPolicy( Qt::ActionsContextMenu );
138
m_mainWindow->getNetworkEditor()->getView()->addAction( m_addModuleAction );
139
m_mainWindow->getNetworkEditor()->getView()->addAction( m_connectWithPrototypeAction );
140
m_mainWindow->getNetworkEditor()->getView()->addAction( m_connectWithModuleAction );
141
m_mainWindow->getNetworkEditor()->getView()->addAction( m_disconnectAction );
142
m_mainWindow->getNetworkEditor()->getView()->addAction( m_deleteModuleAction );
143
m_mainWindow->getNetworkEditor()->getView()->addAction( separator );
144
m_mainWindow->getNetworkEditor()->getView()->addAction( m_missingModuleAction );
147
m_colormapper = new WQtColormapper( m_mainWindow );
148
m_colormapper->setToolTip( "Reorder the textures." );
150
m_tabWidget = new QTabWidget( );
151
m_tabWidget->setMinimumHeight( 100 );
153
m_moduleDock = new QDockWidget( "Module Tree", m_mainWindow );
154
m_moduleDock->setObjectName( "Module Dock" );
155
m_moduleDock->setWidget( m_moduleTreeWidget );
157
m_roiDock = new QDockWidget( "ROIs", m_mainWindow );
158
m_roiDock->setObjectName( "ROI Dock" );
159
m_roiTreeWidget = new WQtTreeWidget();
160
m_roiTreeWidget->setToolTip( "Regions of intrest (ROIs) for selecting fiber clusters. Branches are combined using logic <b>or</b>, "
161
"inside the branches the ROIs are combined using logic <b>and</b>." );
162
m_roiTreeWidget->setHeaderLabel( QString( "ROIs" ) );
163
m_roiTreeWidget->setHeaderHidden( true );
164
m_roiTreeWidget->setDragEnabled( true );
165
m_roiTreeWidget->viewport()->setAcceptDrops( true );
166
m_roiTreeWidget->setDropIndicatorShown( true );
167
m_roiTreeWidget->setDragDropMode( QAbstractItemView::InternalMove );
168
m_roiDock->setWidget( m_roiTreeWidget );
170
m_moduleExcluder = new WQtModuleConfig( parent );
171
connect( m_missingModuleAction, SIGNAL( triggered( bool ) ), m_moduleExcluder, SLOT( configure() ) );
173
this->setAllowedAreas( Qt::AllDockWidgetAreas );
174
this->setFeatures( QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable );
175
this->setWidget( m_tabWidget );
177
m_tiModules = new WQtModuleHeaderTreeItem( m_moduleTreeWidget );
178
m_tiModules->setText( 0, QString( "Subject-independent Modules" ) );
179
m_tiModules->setToolTip( 0, "Subject-independent modules and modules for which no parent module could be detected." );
180
m_tiRois = new WQtRoiHeaderTreeItem( m_roiTreeWidget );
181
m_tiRois->setText( 0, QString( "ROIs" ) );
185
// similar to the module delete action: a ROI delete action
186
m_deleteRoiAction = new QAction( WQt4Gui::getMainWindow()->getIconManager()->getIcon( "remove" ), "Remove ROI", m_roiTreeWidget );
188
// Set the key for removing modules
189
m_deleteRoiAction->setShortcutContext( Qt::WidgetShortcut );
190
m_deleteRoiAction->setShortcut( QKeySequence::Delete );
191
m_deleteRoiAction->setIconVisibleInMenu( true );
193
connect( m_deleteRoiAction, SIGNAL( triggered() ), this, SLOT( deleteROITreeItem() ) );
194
m_roiTreeWidget->addAction( m_deleteModuleAction );
195
m_roiTreeWidget->addAction( m_deleteRoiAction );
198
WQtControlPanel::~WQtControlPanel()
202
void WQtControlPanel::completeGuiSetup()
204
m_mainWindow->addGlobalMenu( m_mainWindow->getNetworkEditor()->getView() );
207
void WQtControlPanel::connectSlots()
209
// if the user changes some white/blacklist setting: update.
210
connect( m_moduleExcluder, SIGNAL( updated() ), this, SLOT( reselectTreeItem() ) );
211
connect( m_moduleTreeWidget, SIGNAL( itemSelectionChanged() ), this, SLOT( selectTreeItem() ) );
212
connect( m_moduleTreeWidget, SIGNAL( itemClicked( QTreeWidgetItem*, int ) ), this, SLOT( changeTreeItem( QTreeWidgetItem*, int ) ) );
213
connect( m_moduleTreeWidget, SIGNAL( itemClicked( QTreeWidgetItem*, int ) ), m_roiTreeWidget, SLOT( clearSelection() ) );
214
connect( m_roiTreeWidget, SIGNAL( itemClicked( QTreeWidgetItem*, int ) ), this, SLOT( selectRoiTreeItem() ) );
215
connect( m_roiTreeWidget, SIGNAL( itemClicked( QTreeWidgetItem*, int ) ), m_moduleTreeWidget, SLOT( clearSelection() ) );
216
connect( m_colormapper, SIGNAL( textureSelectionChanged( osg::ref_ptr< WGETexture3D > ) ),
217
this, SLOT( selectDataModule( osg::ref_ptr< WGETexture3D > ) ) );
218
connect( m_roiTreeWidget, SIGNAL( dragDrop() ), this, SLOT( handleRoiDragDrop() ) );
221
WQtSubjectTreeItem* WQtControlPanel::addSubject( std::string name )
223
WQtSubjectTreeItem* subject = new WQtSubjectTreeItem( m_moduleTreeWidget );
224
subject->setText( 0, QString::fromStdString( name ) );
225
subject->setToolTip( 0, QString::fromStdString( "All data and modules that are children of this tree item belong to the subject \"" +
231
bool WQtControlPanel::event( QEvent* event )
233
if( event->type() == WQT_ROI_ASSOC_EVENT )
235
WRoiAssocEvent* e2 = dynamic_cast< WRoiAssocEvent* >( event ); // NOLINT
238
addRoi( e2->getRoi() );
239
WLogger::getLogger()->addLogMessage( "Inserting ROI to control panel.", "ControlPanel", LL_DEBUG );
244
if( event->type() == WQT_ROI_REMOVE_EVENT )
246
WRoiRemoveEvent* e3 = dynamic_cast< WRoiRemoveEvent* >( event );
249
removeRoi( e3->getRoi() );
250
WLogger::getLogger()->addLogMessage( "Removing ROI from control panel.", "ControlPanel", LL_DEBUG );
256
// a module got associated with the root container -> add it to the list
257
if( event->type() == WQT_ASSOC_EVENT )
259
// convert event to assoc event
260
WModuleAssocEvent* e1 = dynamic_cast< WModuleAssocEvent* >( event ); // NOLINT
263
WLogger::getLogger()->addLogMessage( "Inserting module " + e1->getModule()->getName() + " to control panel.",
264
"ControlPanel", LL_DEBUG );
266
// show deprecation message?
267
if( e1->getModule()->isDeprecated() )
269
std::string d = e1->getModule()->getDeprecationMessage();
270
std::string m = "The module \"" + e1->getModule()->getName() + "\" is marked deprecated. You should avoid using it."
273
QMessageBox::warning( this, "Deprecation Warning", QString::fromStdString( m ) );
276
// finally add the module
277
// TODO(schurade): is this differentiation between data and "normal" modules really needed?
278
if( boost::shared_dynamic_cast< WDataModule >( e1->getModule() ).get() )
280
addDataset( e1->getModule(), 0 );
284
addModule( e1->getModule() );
290
// a module changed its state to "ready" -> activate it in control panel
291
if( event->type() == WQT_READY_EVENT )
293
// convert event to assoc event
294
WModuleReadyEvent* e = dynamic_cast< WModuleReadyEvent* >( event ); // NOLINT
297
// this should never happen, since the type is set to WQT_READY_EVENT.
298
WLogger::getLogger()->addLogMessage( "Event is not an WModueReadyEvent although its type claims it. Ignoring event.",
299
"ControlPanel", LL_WARNING );
304
std::list< WQtTreeItem* > items = findItemsByModule( e->getModule() );
305
for( std::list< WQtTreeItem* >::const_iterator it = items.begin(); it != items.end(); ++it )
307
( *it )->setDisabled( false );
310
setActiveModule( e->getModule() );
315
// a module tree item was connected to another one
316
if( event->type() == WQT_MODULE_CONNECT_EVENT )
318
WModuleConnectEvent* e = dynamic_cast< WModuleConnectEvent* >( event ); // NOLINT
321
// this should never happen, since the type is set to WQT_MODULE_CONNECT_EVENT.
322
WLogger::getLogger()->addLogMessage( "Event is not an WModuleConnectEvent although its type claims it. Ignoring event.",
323
"ControlPanel", LL_WARNING );
327
// get the module of the input involved in this connection
328
boost::shared_ptr< WModule > mIn = e->getInput()->getModule();
329
boost::shared_ptr< WModule > mOut = e->getOutput()->getModule();
331
// NOTE: the following is ugly. We definitely should rethink our GUI
333
// at this moment items for each input connector are inside the tree.
334
// search the items not yet associated with some other module for the first item
335
std::list< WQtTreeItem* > items = findItemsByModule( mIn, m_tiModules );
336
for( std::list< WQtTreeItem* >::const_iterator iter = items.begin(); iter != items.end(); ++iter )
338
( *iter )->setHidden( false );
339
( *iter )->setHandledInput( e->getInput()->getName() );
340
( *iter )->setHandledOutput( e->getOutput()->getName() );
342
// move it to the module with the involved output
343
std::list< WQtTreeItem* > possibleParents = findItemsByModule( mOut );
344
for( std::list< WQtTreeItem* >::const_iterator parIter = possibleParents.begin(); parIter != possibleParents.end(); ++parIter )
346
// remove child from tiModules
347
m_tiModules->removeChild( *iter );
348
if( !( *parIter )->isHidden() )
350
( *parIter )->addChild( *iter );
351
( *parIter )->setExpanded( true );
361
// a module tree item was disconnected from another one
362
if( event->type() == WQT_MODULE_DISCONNECT_EVENT )
364
WModuleDisconnectEvent* e = dynamic_cast< WModuleDisconnectEvent* >( event ); // NOLINT
367
// this should never happen, since the type is set to WQT_MODULE_DISCONNECT_EVENT.
368
WLogger::getLogger()->addLogMessage( "Event is not an WModuleDisconnectEvent although its type claims it. Ignoring event.",
369
"ControlPanel", LL_WARNING );
373
// get the module of the input involved in this connection
374
boost::shared_ptr< WModule > mIn = e->getInput()->getModule();
375
boost::shared_ptr< WModule > mOut = e->getOutput()->getModule();
377
// NOTE: the following is ugly. We definitely should rethink our GUI
379
// at this moment items for each input connector are inside the tree.
380
// search all items an find those containing a children which belongs to the connection input
381
std::list< WQtTreeItem* > items = findItemsByModule( mOut );
382
for( std::list< WQtTreeItem* >::const_iterator iter = items.begin(); iter != items.end(); ++iter )
384
// each of them can contain a child with the involved input
385
std::list< WQtTreeItem* > childs = findItemsByModule( mIn, *iter );
386
for( std::list< WQtTreeItem* >::const_iterator citer = childs.begin(); citer != childs.end(); ++citer )
388
if( ( *citer )->getHandledInput() == e->getInput()->getName() )
390
( *iter )->removeChild( *citer );
392
// move it back to the reservoir in m_tiModules
393
m_tiModules->addChild( *citer );
394
( *citer )->setHidden( true );
395
( *citer )->setHandledInput( "" );
396
( *citer )->setHandledOutput( "" );
401
// we need to ensure that at least one item for mIn is visible somewhere
402
items = findItemsByModule( mIn );
403
bool oneVisible = false;
404
for( std::list< WQtTreeItem* >::const_iterator iter = items.begin(); iter != items.end(); ++iter )
406
oneVisible = oneVisible || !( *iter )->isHidden();
410
( *items.begin() )->setHidden( false );
414
// a module tree item should be deleted
415
if( event->type() == WQT_MODULE_DELETE_EVENT )
417
WModuleDeleteEvent* e = dynamic_cast< WModuleDeleteEvent* >( event );
420
// this should never happen, since the type is set to WQT_MODULE_DELETE_EVENT.
421
WLogger::getLogger()->addLogMessage( "Event is not an WModuleDeleteEvent although its type claims it. Ignoring event.",
422
"ControlPanel", LL_WARNING );
426
// grab the module reference and print some info
427
boost::shared_ptr< WModule > module = e->getTreeItem()->getModule();
428
WLogger::getLogger()->addLogMessage( "Deleting module \"" + module->getName() + "\" from Tree.",
429
"ControlPanel", LL_DEBUG );
431
// remove it from the tree and free last ref count
432
m_moduleTreeWidget->deleteItem( e->getTreeItem() );
434
// ref count != 1? (only if there are now tree items left)
435
bool lastTreeItem = !findItemsByModule( module ).size();
436
if( lastTreeItem && ( module.use_count() != 1 ) )
438
wlog::error( "ControlPanel" ) << "Removed module has strange usage count: " << module.use_count() << ". Should be 1 here. " <<
439
"Module reference is held by someone else.";
445
// a module was removed from the container
446
if( event->type() == WQT_MODULE_REMOVE_EVENT )
448
WModuleRemovedEvent* e = dynamic_cast< WModuleRemovedEvent* >( event );
451
// this should never happen, since the type is set to WQT_MODULE_REMOVE_EVENT.
452
WLogger::getLogger()->addLogMessage( "Event is not an WModuleRemovedEvent although its type claims it. Ignoring event.",
453
"ControlPanel", LL_WARNING );
457
// iterate tree items and find proper one
458
std::list< WQtTreeItem* > items = findItemsByModule( e->getModule() );
459
for( std::list< WQtTreeItem* >::const_iterator iter = items.begin(); iter != items.end(); ++iter )
461
( *iter )->gotRemoved();
464
// be nice and print some info
465
WLogger::getLogger()->addLogMessage( "Removing module \"" + e->getModule()->getName() + "\" from Tree.", "ControlPanel", LL_DEBUG );
468
e->getModule()->requestStop();
469
WLogger::getLogger()->addLogMessage( "Waiting for module \"" + e->getModule()->getName() + "\" to finish before deleting.",
470
"ControlPanel", LL_DEBUG );
475
// a connector was updated
476
if( event->type() == WQT_MODULE_CONNECTOR_EVENT )
478
// convert event to ready event
479
WModuleConnectorEvent* e1 = dynamic_cast< WModuleConnectorEvent* >( event ); // NOLINT
482
// iterate tree items and find proper one -> check if selected
483
// NOTE: This could return multiple items here. But, the GUI always selects all of the same module or none. So it is enough to check
484
// the first item if it is selected to check whether the current module is active.
485
std::list< WQtTreeItem* > items = findItemsByModule( e1->getModule() );
486
if( !items.empty() && ( *items.begin() )->isSelected() )
488
// ok, the module is selected. Now, update the connectables lists (buttons and menu)
489
createCompatibleButtons( e1->getModule() );
496
return QDockWidget::event( event );
499
std::list< WQtTreeItem* > WQtControlPanel::findItemsByModule( boost::shared_ptr< WModule > module, QTreeWidgetItem* where )
501
std::list< WQtTreeItem* > l;
503
// iterate tree items and find proper one
504
QTreeWidgetItemIterator it( where );
507
WQtTreeItem* item = dynamic_cast< WQtTreeItem* >( *it );
508
boost::shared_ptr< WModule > itemModule = boost::shared_ptr< WModule >();
511
itemModule = item->getModule();
514
// if the pointer is NULL the item was none of the above
515
if( !itemModule.get() )
522
if( module == itemModule )
532
std::list< WQtTreeItem* > WQtControlPanel::findItemsByModule( boost::shared_ptr< WModule > module )
534
std::list< WQtTreeItem* > ret = findItemsByModule( module, m_moduleTreeWidget->invisibleRootItem() );
535
std::list< WQtTreeItem* > ret2 = findItemsByModule( module, m_moduleTreeWidget->topLevelItem( 0 ) );
540
WQtDatasetTreeItem* WQtControlPanel::addDataset( boost::shared_ptr< WModule > module, int subjectId )
542
int c = getFirstSubject();
543
WQtSubjectTreeItem* subject = static_cast< WQtSubjectTreeItem* >( m_moduleTreeWidget->topLevelItem( subjectId + c ) );
544
subject->setExpanded( true );
545
WQtDatasetTreeItem* item = subject->addDatasetItem( module );
546
item->setDisabled( true );
547
item->setExpanded( true );
552
WQtModuleTreeItem* WQtControlPanel::addModule( boost::shared_ptr< WModule > module )
554
m_tiModules->setExpanded( true );
555
WQtModuleTreeItem* item;
556
// for each input, create an item
557
m_moduleTreeWidget->setCurrentItem( NULL );
558
bool firstItem = true;
559
WModule::InputConnectorList cons = module->getInputConnectors();
560
for( WModule::InputConnectorList::const_iterator iter = cons.begin(); iter != cons.end(); ++iter )
562
// every module gets added to tiModules first. The connection events then move these things to the right parent
563
item = m_tiModules->addModuleItem( module );
564
item->setDisabled( true );
565
item->setExpanded( true );
567
// all but the first item get hidden by default. They get visible after a connection event has been fired
570
item->setHidden( true );
576
// this module has not inputs. So we simply add it to the tiModules
579
item = m_tiModules->addModuleItem( module );
580
item->setDisabled( true );
586
void WQtControlPanel::addRoi( osg::ref_ptr< WROI > roi )
588
WQtRoiTreeItem* newItem;
589
WQtBranchTreeItem* branchItem;
591
m_tiRois->setExpanded( true );
594
// go through all branches
595
for( int branchID = 0; branchID < m_tiRois->childCount(); ++branchID )
597
branchItem = dynamic_cast< WQtBranchTreeItem* >( m_tiRois->child( branchID ) );
598
// if branch == roi branch
599
if( branchItem->getBranch() == WKernel::getRunningKernel()->getRoiManager()->getBranch( roi ) )
608
branchItem = m_tiRois->addBranch( WKernel::getRunningKernel()->getRoiManager()->getBranch( roi ) );
611
branchItem->setExpanded( true );
612
newItem = branchItem->addRoiItem( roi );
613
newItem->setDisabled( false );
614
newItem->setSelected( true );
615
WKernel::getRunningKernel()->getRoiManager()->setSelectedRoi( getSelectedRoi() );
618
void WQtControlPanel::removeRoi( osg::ref_ptr< WROI > roi )
620
for( int branchID = 0; branchID < m_tiRois->childCount(); ++branchID )
622
QTreeWidgetItem* branchTreeItem = m_tiRois->child( branchID );
623
for( int roiID = 0; roiID < branchTreeItem->childCount(); ++roiID )
625
WQtRoiTreeItem* roiTreeItem = dynamic_cast< WQtRoiTreeItem* >( branchTreeItem->child( roiID ) );
626
if( roiTreeItem && roiTreeItem->getRoi() == roi )
630
if( branchTreeItem->childCount() == 0 )
632
delete branchTreeItem;
639
WKernel::getRunningKernel()->getRoiManager()->setSelectedRoi( getSelectedRoi() );
642
boost::shared_ptr< WModule > WQtControlPanel::getSelectedModule()
644
if( m_moduleTreeWidget->selectedItems().at( 0 )->type() == 1 )
646
return ( static_cast< WQtDatasetTreeItem* >( m_moduleTreeWidget->selectedItems().at( 0 ) )->getModule() );
648
else if( m_moduleTreeWidget->selectedItems().at( 0 )->type() == 3 )
650
return ( static_cast< WQtModuleTreeItem* >( m_moduleTreeWidget->selectedItems().at( 0 ) )->getModule() );
653
return boost::shared_ptr< WModule >();
656
void WQtControlPanel::reselectTreeItem()
658
setActiveModule( getSelectedModule(), true );
661
void WQtControlPanel::selectTreeItem()
663
if( m_ignoreSelectionChange )
668
if( m_moduleTreeWidget->selectedItems().size() != 0 )
670
switch( m_moduleTreeWidget->selectedItems().at( 0 )->type() )
675
// deletion of headers and subjects is not allowed
676
deactivateModuleSelection( false );
681
WModule::SPtr module = ( static_cast< WQtDatasetTreeItem* >( m_moduleTreeWidget->selectedItems().at( 0 ) ) )->getModule();
682
setActiveModule( module );
687
WModule::SPtr module = ( static_cast< WQtModuleTreeItem* >( m_moduleTreeWidget->selectedItems().at( 0 ) ) )->getModule();
688
setActiveModule( module );
695
deactivateModuleSelection( false );
701
// clean up if nothing is selected
702
setActiveModule( WModule::SPtr() ); // module is NULL at this point
706
void WQtControlPanel::selectRoiTreeItem()
708
clearAndDeleteTabs();
710
// Make compatibles toolbar empty
712
if( m_mainWindow->getCompatiblesToolbar() != 0 )
714
m_mainWindow->getCompatiblesToolbar()->makeEmpty();
718
m_mainWindow->setCompatiblesToolbar( new WQtCombinerToolbar( m_mainWindow ) );
722
boost::shared_ptr< WModule > module;
723
boost::shared_ptr< WProperties > props;
725
if( m_roiTreeWidget->selectedItems().size() != 0 )
727
switch( m_roiTreeWidget->selectedItems().at( 0 )->type() )
734
WKernel::getRunningKernel()->getRoiManager()->setSelectedRoi( getSelectedRoi() );
737
props = ( static_cast< WQtBranchTreeItem* >( m_roiTreeWidget->selectedItems().at( 0 ) ) )->getBranch()->getProperties();
738
WKernel::getRunningKernel()->getRoiManager()->setSelectedRoi( getFirstRoiInSelectedBranch() );
741
props = ( static_cast< WQtRoiTreeItem* >( m_roiTreeWidget->selectedItems().at( 0 ) ) )->getRoi()->getProperties();
742
WKernel::getRunningKernel()->getRoiManager()->setSelectedRoi( getSelectedRoi() );
749
if( m_roiTreeWidget->selectedItems().size() == 1 && m_roiTreeWidget->selectedItems().at( 0 )->type() == ROI )
751
osg::ref_ptr< WROI > roi = ( static_cast< WQtRoiTreeItem* >( m_roiTreeWidget->selectedItems().at( 0 ) ) )->getRoi();
752
roi->getProperties()->getProperty( "active" )->toPropBool()->set( m_roiTreeWidget->selectedItems().at( 0 )->checkState( 0 ) );
755
buildPropTab( props, boost::shared_ptr< WProperties >() );
758
void WQtControlPanel::selectDataModule( osg::ref_ptr< WGETexture3D > texture )
760
clearAndDeleteTabs();
761
buildPropTab( texture->getProperties(), texture->getInformationProperties() );
764
QTreeWidgetItem* WQtControlPanel::findModuleItem( WModule::SPtr module ) const
766
QTreeWidgetItemIterator it( m_moduleTreeWidget );
767
QTreeWidgetItem* item = NULL;
770
if( dynamic_cast< WQtModuleTreeItem* >( *it ) )
772
WModule::SPtr currentModule;
773
currentModule = boost::shared_dynamic_cast< WModule >( ( dynamic_cast< WQtModuleTreeItem* >( *it ) )->getModule() );
776
if( currentModule == module )
783
else if( dynamic_cast< WQtDatasetTreeItem* >( *it ) )
785
boost::shared_ptr< WDataModule > dataModule;
786
dataModule = boost::shared_dynamic_cast< WDataModule >( ( dynamic_cast< WQtDatasetTreeItem* >( *it ) )->getModule() );
789
if( dataModule == module )
802
void WQtControlPanel::deactivateModuleSelection( bool selectTopmost )
804
m_ignoreSelectionChange = true;
806
m_activeModule = WModule::SPtr();
808
// select top element and reset some menu actions
811
m_moduleTreeWidget->clearSelection();
812
selectUpperMostEntry();
814
m_deleteModuleAction->setEnabled( false );
816
// remove properties tabs
817
clearAndDeleteTabs();
819
// clean compatibles toolbar, add only subject independent items
820
createCompatibleButtons( m_activeModule );
822
// also notify network editor
823
WQtNetworkEditor* nwe = m_mainWindow->getNetworkEditor();
826
nwe->clearSelection();
829
m_ignoreSelectionChange = false;
834
void WQtControlPanel::setActiveModule( WModule::SPtr module, bool forceUpdate )
836
m_ignoreSelectionChange = true;
838
// is module NULL? remove everything
841
deactivateModuleSelection();
842
m_ignoreSelectionChange = false;
846
// only if something has changed
847
if( ( m_activeModule == module ) && !forceUpdate )
849
m_ignoreSelectionChange = false;
852
m_activeModule = module;
854
wlog::debug( "ControlPanel" ) << "Activating module \"" << module->getName() << "\".";
856
// update the m_moduleTreeWidget
857
std::list< WQtTreeItem* > items = findItemsByModule( module );
858
WAssert( items.size(), "No item found for module " + module->getName() );
859
m_moduleTreeWidget->clearSelection();
860
for( std::list< WQtTreeItem* >::const_iterator it = items.begin(); it != items.end(); ++it )
862
( *it )->setSelected( true );
865
// also notify network editor
866
WQtNetworkEditor* nwe = m_mainWindow->getNetworkEditor();
869
nwe->selectByModule( module );
872
// remove property tabs
873
clearAndDeleteTabs();
874
// update module meta info tab also for crashed modules
875
WQtModuleMetaInfo* metaInfoWidget = new WQtModuleMetaInfo( module );
876
m_tabWidget->addTab( metaInfoWidget, "About && Help" );
878
// set new property tabs if module is not crashed
879
if( !module->isCrashed() )
881
buildPropTab( module->getProperties(), module->getInformationProperties() );
884
// re-select the previous tab
885
bool foundTab = false;
886
std::map< QString, int > priorityList;
887
if( m_previousTab != "" )
889
// search the tab with the previous title
890
for( int idx = 0; idx < m_tabWidget->count(); ++idx )
892
if( m_tabWidget->tabText( idx ) == m_previousTab )
894
m_tabWidget->setCurrentIndex( idx );
899
// keep track of the indices in the tab. we use this map later as priority list. Please not that we add 1 to the index. This ensures
900
// that the invalid index is 0, even if it is -1 in Qt.
901
priorityList[ m_tabWidget->tabText( idx ) ] = idx + 1;
906
// the tab does not exist anymore. We need to use our priority list
907
if( priorityList[ "Settings" ] != 0 )
909
m_tabWidget->setCurrentIndex( priorityList[ "Settings" ] - 1 );
911
else if( priorityList[ "Information" ] != 0 )
913
m_tabWidget->setCurrentIndex( priorityList[ "Settings" ] - 1 );
917
// there is no info and no settings tab. Set the first tab.
918
m_tabWidget->setCurrentIndex( 0 );
923
// update compatibles toolbar
924
createCompatibleButtons( module );
926
// disable delete action for tree items that have children.
927
if( m_moduleTreeWidget->selectedItems().at( 0 )->childCount() != 0 )
929
m_deleteModuleAction->setEnabled( false );
933
m_deleteModuleAction->setEnabled( true );
936
m_ignoreSelectionChange = false;
939
void WQtControlPanel::buildPropTab( boost::shared_ptr< WProperties > props, boost::shared_ptr< WProperties > infoProps )
941
WQtPropertyGroupWidget* tab = NULL;
942
WQtPropertyGroupWidget* infoTab = NULL;
945
tab = new WQtPropertyGroupWidget( props );
948
tab->setName( "Settings" );
953
infoTab = new WQtPropertyGroupWidget( infoProps );
956
infoTab->setName( "Information" );
960
int infoIdx = addTabWidgetContent( infoTab );
961
int propIdx = addTabWidgetContent( tab );
963
// select the property widget preferably
964
if( m_previousTab == "" )
968
m_tabWidget->setCurrentIndex( propIdx );
970
else if( infoIdx != -1 )
972
m_tabWidget->setCurrentIndex( infoIdx );
977
void WQtControlPanel::createCompatibleButtons( boost::shared_ptr< WModule > module )
979
// we need to clean up the action lists
980
WQtCombinerActionList::deepDeleteActionList( m_addModuleActionList );
981
WQtCombinerActionList::deepDeleteActionList( m_connectWithPrototypeActionList );
982
WQtCombinerActionList::deepDeleteActionList( m_connectWithModuleActionList );
983
WQtCombinerActionList::deepDeleteActionList( m_disconnectActionList );
985
// acquire new action lists
986
m_connectWithPrototypeActionList = WQtCombinerActionList( this, m_mainWindow->getIconManager(),
987
WModuleFactory::getModuleFactory()->getCompatiblePrototypes( module ),
989
m_connectWithModuleActionList = WQtCombinerActionList( this, m_mainWindow->getIconManager(),
990
WKernel::getRunningKernel()->getRootContainer()->getPossibleConnections( module ),
993
m_addModuleActionList = WQtCombinerActionList( this, m_mainWindow->getIconManager(),
994
WModuleFactory::getModuleFactory()->getAllPrototypes(),
998
m_disconnectActionList = WQtCombinerActionList( this, m_mainWindow->getIconManager(), module->getPossibleDisconnections() );
1001
// build the add menu
1002
QMenu* m = new WQtMenuFiltered( m_moduleTreeWidget );
1003
m->addActions( m_addModuleActionList );
1004
m_addModuleAction->setDisabled( !m_addModuleActionList.size() || module ); // disable if no entry inside or a module was selected
1005
delete( m_addModuleAction->menu() ); // ensure that combiners get free'd
1006
m_addModuleAction->setMenu( m );
1008
// build the prototype menu
1009
m = new WQtMenuFiltered( m_moduleTreeWidget );
1010
m->addActions( m_connectWithPrototypeActionList );
1011
m_connectWithPrototypeAction->setDisabled( !m_connectWithPrototypeActionList.size() ); // disable if no entry inside
1012
delete( m_connectWithPrototypeAction->menu() ); // ensure that combiners get free'd
1013
m_connectWithPrototypeAction->setMenu( m );
1015
// build the module menu
1016
m = new WQtMenuFiltered( m_moduleTreeWidget );
1017
m->addActions( m_connectWithModuleActionList );
1018
m_connectWithModuleAction->setDisabled( !m_connectWithModuleActionList.size() ); // disable if no entry inside
1019
delete m_connectWithModuleAction->menu();
1020
m_connectWithModuleAction->setMenu( m );
1022
// build the disconnect menu
1023
m = new WQtMenuFiltered( m_moduleTreeWidget );
1024
m->addActions( m_disconnectActionList );
1025
m_disconnectAction->setDisabled( !m_disconnectActionList.size() ); // disable if no entry inside
1026
delete( m_disconnectAction->menu() ); // ensure that combiners get free'd
1027
m_disconnectAction->setMenu( m );
1029
// finally, set the actions to the compatibles toolbar.
1030
if( m_mainWindow->getCompatiblesToolbar() != 0 )
1032
m_mainWindow->getCompatiblesToolbar()->updateButtons( m_connectWithPrototypeActionList );
1036
m_mainWindow->setCompatiblesToolbar( new WQtCombinerToolbar( m_mainWindow, m_connectWithPrototypeActionList ) );
1040
void WQtControlPanel::changeTreeItem( QTreeWidgetItem* item, int /* column */ )
1042
WQtTreeItem* witem = dynamic_cast< WQtTreeItem* >( item );
1045
witem->handleCheckStateChange();
1049
int WQtControlPanel::addTabWidgetContent( WQtPropertyGroupWidget* content )
1051
if( !content || content->isEmpty() )
1053
// we destroy the widget if we not use it to avoid empty widgets popping up
1061
QScrollArea* sa = new QScrollArea();
1062
sa->setWidget( content );
1063
sa->setWidgetResizable( true );
1065
return m_tabWidget->addTab( sa, content->getName() );
1068
int WQtControlPanel::getFirstSubject()
1071
for( int i = 0; i < m_moduleTreeWidget->topLevelItemCount() ; ++i )
1073
if( m_moduleTreeWidget->topLevelItem( i )->type() == SUBJECT )
1082
osg::ref_ptr< WROI > WQtControlPanel::getSelectedRoi()
1084
osg::ref_ptr< WROI > roi;
1085
if( m_roiTreeWidget->selectedItems().count() == 0 )
1089
if( m_roiTreeWidget->selectedItems().at( 0 )->type() == ROI )
1091
roi =( static_cast< WQtRoiTreeItem* >( m_roiTreeWidget->selectedItems().at( 0 ) ) )->getRoi();
1096
osg::ref_ptr< WROI > WQtControlPanel::getFirstRoiInSelectedBranch()
1098
osg::ref_ptr< WROI >roi;
1099
if( m_roiTreeWidget->selectedItems().count() == 0 )
1103
if( m_roiTreeWidget->selectedItems().at( 0 )->type() == ROI )
1105
WQtBranchTreeItem* branch = ( static_cast< WQtBranchTreeItem* >( m_roiTreeWidget->selectedItems().at( 0 )->parent() ) );
1106
roi =( static_cast< WQtRoiTreeItem* >( branch->child( 0 ) ) )->getRoi();
1108
if( m_roiTreeWidget->selectedItems().at( 0 )->type() == ROIBRANCH )
1110
WQtBranchTreeItem* branch = ( static_cast< WQtBranchTreeItem* >( m_roiTreeWidget->selectedItems().at( 0 ) ) );
1111
if( branch->childCount() > 0 )
1113
roi =( static_cast< WQtRoiTreeItem* >( branch->child( 0 ) ) )->getRoi();
1119
QAction* WQtControlPanel::toggleViewAction() const
1121
QAction* result = QDockWidget::toggleViewAction();
1122
QList< QKeySequence > shortcut;
1123
#if defined( __APPLE__ )
1124
shortcut.append( QKeySequence( Qt::CTRL + Qt::Key_F9 ) ); // In Mac OS X F9 is already taken by window managment
1126
shortcut.append( QKeySequence( Qt::Key_F9 ) );
1128
result->setShortcuts( shortcut );
1132
void WQtControlPanel::deleteModule()
1134
if( m_moduleTreeWidget->hasFocus() )
1136
if( m_moduleTreeWidget->selectedItems().count() > 0 )
1138
if( ( m_moduleTreeWidget->selectedItems().at( 0 )->type() == MODULE ) ||
1139
( m_moduleTreeWidget->selectedItems().at( 0 )->type() == DATASET ) )
1141
// deleting crashed modules is not really save as we do not know the internal state of it
1142
if( static_cast< WQtTreeItem* >( m_moduleTreeWidget->selectedItems().at( 0 ) )->getModule()->isCrashed() )
1147
// remove from the container. It will create a new event in the GUI after it has been removed which is then handled by the tree item.
1148
// This method deep removes the module ( it also removes depending modules )
1149
WKernel::getRunningKernel()->getRootContainer()->remove(
1150
static_cast< WQtTreeItem* >( m_moduleTreeWidget->selectedItems().at( 0 ) )->getModule()
1152
// select another item
1153
m_moduleTreeWidget->setCurrentItem( m_moduleTreeWidget->topLevelItem( 0 ) );
1157
else if( m_mainWindow->getNetworkEditor()->hasFocus() )
1159
if( m_mainWindow->getNetworkEditor()->selectedItems().count() > 0 )
1161
// deleting crashed modules is not really save as we do not know the internal state of it
1162
if( static_cast< WQtNetworkItem* >( m_mainWindow->getNetworkEditor()->selectedItems().at( 0 ) )->getModule()->isCrashed() )
1167
// This method deep removes the module ( it also removes depending modules )
1168
WKernel::getRunningKernel()->getRootContainer()->remove(
1169
static_cast< WQtNetworkItem* >( m_mainWindow->getNetworkEditor()->selectedItems().at( 0 ) )->getModule()
1175
void WQtControlPanel::deleteROITreeItem()
1177
osg::ref_ptr< WROI >roi;
1178
if( m_roiTreeWidget->selectedItems().count() > 0 )
1180
if( m_roiTreeWidget->selectedItems().at( 0 )->type() == ROIBRANCH )
1182
roi = getFirstRoiInSelectedBranch();
1185
WKernel::getRunningKernel()->getRoiManager()->removeBranch( roi );
1187
delete m_roiTreeWidget->selectedItems().at( 0 );
1190
else if( m_roiTreeWidget->selectedItems().at( 0 )->type() == ROI )
1192
roi =( static_cast< WQtRoiTreeItem* >( m_roiTreeWidget->selectedItems().at( 0 ) ) )->getRoi();
1195
WKernel::getRunningKernel()->getRoiManager()->removeRoi( roi );
1196
// Removing the roi from the tree widget is also done by WROIManagerFibers::removeRoi().
1200
WKernel::getRunningKernel()->getRoiManager()->setSelectedRoi( getFirstRoiInSelectedBranch() );
1203
void WQtControlPanel::selectUpperMostEntry()
1205
m_tiModules->setSelected( true );
1208
void WQtControlPanel::handleRoiDragDrop()
1210
WLogger::getLogger()->addLogMessage( "Drag and drop handler not implemented yet!", "ControlPanel", LL_DEBUG );
1213
QDockWidget* WQtControlPanel::getRoiDock() const
1218
QDockWidget* WQtControlPanel::getModuleDock() const
1220
return m_moduleDock;
1223
QDockWidget* WQtControlPanel::getColormapperDock() const
1225
return m_colormapper;
1228
WQtModuleConfig& WQtControlPanel::getModuleConfig() const
1230
return *m_moduleExcluder;
1233
QAction* WQtControlPanel::getMissingModuleAction() const
1235
return m_missingModuleAction;
1238
void WQtControlPanel::clearAndDeleteTabs()
1240
if( m_tabWidget->currentIndex() != -1 )
1242
m_previousTab = m_tabWidget->tabText( m_tabWidget->currentIndex() );
1245
m_tabWidget->setDisabled( true );
1247
while( ( widget = m_tabWidget->widget( 0 ) ))
1249
m_tabWidget->removeTab( 0 );
1252
m_tabWidget->setEnabled( true );