WQtControlPanel.cpp 44.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
//---------------------------------------------------------------------------
//
// Project: OpenWalnut ( http://www.openwalnut.org )
//
// Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
// For more information see http://www.openwalnut.org/copying
//
// This file is part of OpenWalnut.
//
// OpenWalnut is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// OpenWalnut is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
//
//---------------------------------------------------------------------------

25
#include <iostream>
Sebastian Eichelbaum's avatar
[STYLE]  
Sebastian Eichelbaum committed
26
#include <list>
27
#include <map>
Sebastian Eichelbaum's avatar
[MERGE]  
Sebastian Eichelbaum committed
28
#include <set>
29
#include <string>
30
#include <vector>
31

32
#include <QtCore/QList>
33
#include <QtGui/QMenu>
34
#include <QtGui/QScrollArea>
schurade's avatar
schurade committed
35
#include <QtGui/QShortcut>
36
#include <QtGui/QSplitter>
37
#include <QtGui/QMessageBox>
38

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 44 45 46 47
#include "core/kernel/WKernel.h"
#include "core/kernel/WModule.h"
#include "core/kernel/WModuleContainer.h"
#include "core/kernel/WModuleFactory.h"
#include "core/kernel/WROIManager.h"
48
#include "../events/WEventTypes.h"
49
#include "../events/WModuleAssocEvent.h"
50
#include "../events/WModuleConnectEvent.h"
51
#include "../events/WModuleConnectorEvent.h"
52
#include "../events/WModuleDeleteEvent.h"
53
#include "../events/WModuleDisconnectEvent.h"
54
#include "../events/WModuleReadyEvent.h"
55
#include "../events/WModuleRemovedEvent.h"
56 57
#include "../events/WRoiAssocEvent.h"
#include "../events/WRoiRemoveEvent.h"
58
#include "../WMainWindow.h"
59
#include "../WQt4Gui.h"
60
#include "../WQtCombinerActionList.h"
61
#include "../WQtModuleExcluder.h"
62
#include "WQtBranchTreeItem.h"
63
#include "WQtColormapper.h"
64

65 66 67
#include "WQtControlPanel.h"
#include "WQtControlPanel.moc"

68
WQtControlPanel::WQtControlPanel( WMainWindow* parent )
69
    : QDockWidget( "Control Panel", parent ),
70
    m_ignoreSelectionChange( false )
71
{
72 73
    setObjectName( "Control Panel Dock" );

74
    m_mainWindow = parent;
75
    setMinimumWidth( 200 );
76

77
    m_panel = new QWidget( this );
78
    m_moduleTreeWidget = new WQtTreeWidget( m_panel );
79
    m_moduleTreeWidget->setContextMenuPolicy( Qt::ActionsContextMenu );
80

81 82
    m_moduleTreeWidget->setHeaderLabel( QString( "Module Tree" ) );
    m_moduleTreeWidget->setDragEnabled( false );
83 84
    m_moduleTreeWidget->viewport()->setAcceptDrops( true );
    m_moduleTreeWidget->setDropIndicatorShown( true );
85
    m_moduleTreeWidget->setMinimumHeight( 100 );
86

87
    // create context menu for tree items
88 89 90 91 92

    // a separator to clean up the tree widget's context menu
    QAction* separator = new QAction( m_moduleTreeWidget );
    separator->setSeparator( true );
    m_moduleTreeWidget->addAction( separator );
93

94
    m_connectWithPrototypeAction = new QAction( "Connect with new module", m_moduleTreeWidget );
95
    m_moduleTreeWidget->addAction( m_connectWithPrototypeAction );
96
    m_connectWithModuleAction = new QAction( "Connect with module", m_moduleTreeWidget );
97 98 99 100
    m_moduleTreeWidget->addAction( m_connectWithModuleAction );
    m_disconnectAction = new QAction( "Disconnect", m_moduleTreeWidget );
    m_moduleTreeWidget->addAction( m_disconnectAction );

101 102 103 104
    // a separator to clean up the tree widget's context menu
    m_moduleTreeWidget->addAction( separator );

    m_deleteModuleAction = new QAction( WQt4Gui::getMainWindow()->getIconManager()->getIcon( "remove" ), "Remove Module", m_moduleTreeWidget );
105 106
    {
        // Set the key for removing modules
107 108
        m_deleteModuleAction->setShortcutContext( Qt::WidgetShortcut );
        m_deleteModuleAction->setShortcut( QKeySequence( "Delete" ) );
109
        m_deleteModuleAction->setIconVisibleInMenu( true );
110
    }
111 112 113
    connect( m_deleteModuleAction, SIGNAL( triggered() ), this, SLOT( deleteModuleTreeItem() ) );
    m_moduleTreeWidget->addAction( m_deleteModuleAction );

114 115 116 117 118 119 120 121 122 123 124
    // a separator to clean up the tree widget's context menu
    m_moduleTreeWidget->addAction( separator );

    // add an entry for those who search their module without luck
    m_missingModuleAction = new QAction( WQt4Gui::getMainWindow()->getIconManager()->getIcon( "missingModule" ), "Missing Module?",
                                          m_moduleTreeWidget );
    m_missingModuleAction->setToolTip( "Having trouble finding your module? This opens the module configuration, which allows you to define the "
                                       "modules that should be shown or hidden." );
    m_missingModuleAction->setIconVisibleInMenu( true );
    m_moduleTreeWidget->addAction( m_missingModuleAction );

125 126 127 128 129 130 131 132 133 134 135
    // Disabled Network Editor due to bug: #11
    // // the network editor also needs the context menu
    // // TODO(rfrohl): context menu gets not opened if a graphicitem is clicked. This should be fixed.
    // m_mainWindow->getNetworkEditor()->setContextMenuPolicy( Qt::ActionsContextMenu );
    // m_mainWindow->getNetworkEditor()->addAction( m_connectWithPrototypeAction );
    // m_mainWindow->getNetworkEditor()->addAction( m_connectWithModuleAction );
    // m_mainWindow->getNetworkEditor()->addAction( m_disconnectAction );
    // m_mainWindow->getNetworkEditor()->addAction( separator );
    // m_mainWindow->getNetworkEditor()->addAction( m_deleteModuleAction );
    // m_mainWindow->getNetworkEditor()->addAction( separator );
    // m_mainWindow->getNetworkEditor()->addAction( m_missingModuleAction );
136

137 138
    m_colormapper = new WQtColormapper( m_mainWindow );
    m_colormapper->setToolTip( "Reorder the textures." );
139

140
    m_tabWidget = new QTabWidget( m_panel );
141
    m_tabWidget->setMinimumHeight( 100 );
142

143 144 145
    m_moduleDock = new QDockWidget( "Module Tree", m_mainWindow );
    m_moduleDock->setObjectName( "Module Dock" );
    m_moduleDock->setWidget( m_moduleTreeWidget );
146

147 148
    m_roiDock = new QDockWidget( "ROIs", m_mainWindow );
    m_roiDock->setObjectName( "ROI Dock" );
149
    m_roiTreeWidget = new WQtTreeWidget();
150
    m_roiTreeWidget->setToolTip( "Regions of intrest (ROIs) for selecting fiber  clusters. Branches are combined using logic <b>or</b>, "
151
                                 "inside the branches the ROIs are combined using logic <b>and</b>." );
152 153 154 155 156 157
    m_roiTreeWidget->setHeaderLabel( QString( "ROIs" ) );
    m_roiTreeWidget->setHeaderHidden( true );
    m_roiTreeWidget->setDragEnabled( true );
    m_roiTreeWidget->viewport()->setAcceptDrops( true );
    m_roiTreeWidget->setDropIndicatorShown( true );
    m_roiTreeWidget->setDragDropMode( QAbstractItemView::InternalMove );
158
    m_roiDock->setWidget( m_roiTreeWidget );
159

160
    m_moduleExcluder = new WQtModuleExcluder( parent );
161
    connect( m_missingModuleAction, SIGNAL( triggered( bool ) ), m_moduleExcluder, SLOT( configure() ) );
162

163
    m_layout = new QVBoxLayout();
164 165 166 167
    m_layout->addWidget( m_tabWidget );

    m_panel->setLayout( m_layout );

168 169
    this->setAllowedAreas( Qt::AllDockWidgetAreas );
    this->setFeatures( QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable );
170
    this->setWidget( m_panel );
171

172
    m_tiModules = new WQtModuleHeaderTreeItem( m_moduleTreeWidget );
173 174
    m_tiModules->setText( 0, QString( "Subject-independent Modules" ) );
    m_tiModules->setToolTip( 0, "Subject-independent modules and modules for which no parent module could be detected." );
175
    m_tiRois = new WQtRoiHeaderTreeItem( m_roiTreeWidget );
Alexander Wiebel's avatar
Alexander Wiebel committed
176
    m_tiRois->setText( 0, QString( "ROIs" ) );
177

178
    connectSlots();
179

180 181
    // similar to the module delete action: a ROI delete action
    m_deleteRoiAction = new QAction( WQt4Gui::getMainWindow()->getIconManager()->getIcon( "remove" ), "Remove ROI", m_roiTreeWidget );
182
    {
183 184 185
        // Set the key for removing modules
        m_deleteRoiAction->setShortcutContext( Qt::WidgetShortcut );
        m_deleteRoiAction->setShortcut( QKeySequence( "Delete" ) );
186
        m_deleteRoiAction->setIconVisibleInMenu( true );
187
    }
188 189
    connect( m_deleteRoiAction, SIGNAL( triggered() ), this, SLOT( deleteROITreeItem() ) );
    m_roiTreeWidget->addAction( m_deleteModuleAction );
190
    m_roiTreeWidget->addAction( m_deleteRoiAction );
191 192
}

193
WQtControlPanel::~WQtControlPanel()
194 195 196
{
}

197
void WQtControlPanel::connectSlots()
198
{
199
    // if the user changes some white/blacklist setting: update.
200
    connect( m_moduleExcluder, SIGNAL( updated() ), this, SLOT( selectTreeItem() ) );
201
    connect( m_moduleTreeWidget, SIGNAL( itemSelectionChanged() ), this, SLOT( selectTreeItem() ) );
202
    connect( m_moduleTreeWidget, SIGNAL( itemClicked( QTreeWidgetItem*, int ) ), this, SLOT( changeTreeItem( QTreeWidgetItem*, int ) ) );
203 204 205
    connect( m_moduleTreeWidget, SIGNAL( itemClicked( QTreeWidgetItem*, int ) ),  m_roiTreeWidget, SLOT( clearSelection() ) );
    connect( m_roiTreeWidget, SIGNAL( itemClicked( QTreeWidgetItem*, int ) ), this, SLOT( selectRoiTreeItem() ) );
    connect( m_roiTreeWidget, SIGNAL( itemClicked( QTreeWidgetItem*, int ) ), m_moduleTreeWidget, SLOT( clearSelection() ) );
206 207
    connect( m_colormapper, SIGNAL( textureSelectionChanged( osg::ref_ptr< WGETexture3D > ) ),
             this, SLOT( selectDataModule( osg::ref_ptr< WGETexture3D > ) ) );
208
    connect( m_roiTreeWidget, SIGNAL( dragDrop() ), this, SLOT( handleDragDrop() ) );
209
}
210

211
void WQtControlPanel::addToolbar( QToolBar* tb )
212 213 214 215
{
    m_layout->insertWidget( 0, tb );
}

216
WQtSubjectTreeItem* WQtControlPanel::addSubject( std::string name )
217
{
218
    WQtSubjectTreeItem* subject = new WQtSubjectTreeItem( m_moduleTreeWidget );
219 220 221
    subject->setText( 0, QString::fromStdString( name ) );
    subject->setToolTip( 0, QString::fromStdString( "All data and modules that are children of this tree item belong to the subject \"" +
                name + "\"." ) );
222 223 224 225

    return subject;
}

226
bool WQtControlPanel::event( QEvent* event )
227
{
228
    if( event->type() == WQT_ROI_ASSOC_EVENT )
229 230
    {
        WRoiAssocEvent* e2 = dynamic_cast< WRoiAssocEvent* >( event );     // NOLINT
231
        if( e2 )
232 233
        {
            addRoi( e2->getRoi() );
234
            WLogger::getLogger()->addLogMessage( "Inserting ROI to control panel.", "ControlPanel", LL_DEBUG );
235 236 237 238 239 240 241 242 243 244
        }

        return true;
    }
    if( event->type() == WQT_ROI_REMOVE_EVENT )
    {
        WRoiRemoveEvent* e3 = dynamic_cast< WRoiRemoveEvent* >( event );
        if( e3 )
        {
            removeRoi( e3->getRoi() );
245
            WLogger::getLogger()->addLogMessage( "Removing ROI from control panel.", "ControlPanel", LL_DEBUG );
246 247 248 249 250
        }

        return true;
    }

251
    // a module got associated with the root container -> add it to the list
252
    if( event->type() == WQT_ASSOC_EVENT )
253 254
    {
        // convert event to assoc event
schurade's avatar
schurade committed
255
        WModuleAssocEvent* e1 = dynamic_cast< WModuleAssocEvent* >( event );     // NOLINT
256
        if( e1 )
257
        {
258 259
            WLogger::getLogger()->addLogMessage( "Inserting module " + e1->getModule()->getName() + " to control panel.",
                                                 "ControlPanel", LL_DEBUG );
260

261 262 263 264 265 266 267 268 269 270
            // show deprecation message?
            if( e1->getModule()->isDeprecated() )
            {
                std::string d = e1->getModule()->getDeprecationMessage();
                std::string m = "The module \"" + e1->getModule()->getName() + "\" is marked deprecated. You should avoid using it."
                                "<br><br>"
                                "Message: " + d;
                QMessageBox::warning( this, "Deprecation Warning", QString::fromStdString( m ) );
            }

schurade's avatar
schurade committed
271 272
            // finally add the module
            // TODO(schurade): is this differentiation between data and "normal" modules really needed?
273
            if( boost::shared_dynamic_cast< WDataModule >( e1->getModule() ).get() )
schurade's avatar
schurade committed
274 275 276 277 278 279 280
            {
                addDataset( e1->getModule(), 0 );
            }
            else
            {
                addModule( e1->getModule() );
            }
281
        }
schurade's avatar
schurade committed
282 283
        return true;
    }
284

285
    // a module changed its state to "ready" -> activate it in control panel
286
    if( event->type() == WQT_READY_EVENT )
schurade's avatar
schurade committed
287
    {
288 289
        // convert event to assoc event
        WModuleReadyEvent* e = dynamic_cast< WModuleReadyEvent* >( event );     // NOLINT
290
        if( !e )
291
        {
292
            // this should never happen, since the type is set to WQT_READY_EVENT.
293
            WLogger::getLogger()->addLogMessage( "Event is not an WModueReadyEvent although its type claims it. Ignoring event.",
294
                                                 "ControlPanel", LL_WARNING );
295 296

            return true;
297 298
        }

299 300
        WLogger::getLogger()->addLogMessage( "Activating module " + e->getModule()->getName() + " in control panel.",
                                             "ControlPanel", LL_DEBUG );
301

302 303
        // search all the item matching the module
        std::list< WQtTreeItem* > items = findItemsByModule( e->getModule() );
304
        for( std::list< WQtTreeItem* >::const_iterator iter = items.begin(); iter != items.end(); ++iter )
305
        {
306 307
            ( *iter )->setSelected( true );
            ( *iter )->setDisabled( false );
308 309
        }

310
        selectTreeItem();
311

312 313
        return true;
    }
314

315
    // a module tree item was connected to another one
316
    if( event->type() == WQT_MODULE_CONNECT_EVENT )
317
    {
318
        WModuleConnectEvent* e = dynamic_cast< WModuleConnectEvent* >( event );     // NOLINT
319
        if( !e )
320
        {
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 );
324
            return true;
325 326
        }

327 328 329 330
        // get the module of the input involved in this connection
        boost::shared_ptr< WModule > mIn = e->getInput()->getModule();
        boost::shared_ptr< WModule > mOut = e->getOutput()->getModule();

331 332
        // NOTE: the following is ugly. We definitely should rethink our GUI

333 334 335
        // at this moment items for each input connector are inside the tree.
        // search the items not yet associated with some other module for the first item
        std::list< WQtTreeItem* > items = findItemsByModule( mIn, m_tiModules );
336
        for( std::list< WQtTreeItem* >::const_iterator iter = items.begin(); iter != items.end(); ++iter )
337 338 339 340 341 342 343
        {
            ( *iter )->setHidden( false );
            ( *iter )->setHandledInput( e->getInput()->getName() );
            ( *iter )->setHandledOutput( e->getOutput()->getName() );

            // move it to the module with the involved output
            std::list< WQtTreeItem* > possibleParents = findItemsByModule( mOut );
344
            for( std::list< WQtTreeItem* >::const_iterator parIter = possibleParents.begin(); parIter != possibleParents.end(); ++parIter )
345 346 347
            {
                // remove child from tiModules
                m_tiModules->removeChild( *iter );
348
                if( !( *parIter )->isHidden() )
349 350 351 352 353
                {
                    ( *parIter )->addChild( *iter );
                    ( *parIter )->setExpanded( true );
                    break;
                }
354 355 356 357 358
            }

            // job done.
            break;
        }
359 360 361
    }

    // a module tree item was disconnected from another one
362
    if( event->type() == WQT_MODULE_DISCONNECT_EVENT )
363 364
    {
        WModuleDisconnectEvent* e = dynamic_cast< WModuleDisconnectEvent* >( event );     // NOLINT
365
        if( !e )
366
        {
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 );
370 371 372
            return true;
        }

373 374 375 376 377 378 379 380 381
        // get the module of the input involved in this connection
        boost::shared_ptr< WModule > mIn = e->getInput()->getModule();
        boost::shared_ptr< WModule > mOut = e->getOutput()->getModule();

        // NOTE: the following is ugly. We definitely should rethink our GUI

        // at this moment items for each input connector are inside the tree.
        // search all items an find those containing a children which belongs to the connection input
        std::list< WQtTreeItem* > items = findItemsByModule( mOut );
382
        for( std::list< WQtTreeItem* >::const_iterator iter = items.begin(); iter != items.end(); ++iter )
383 384 385
        {
            // each of them can contain a child with the involved input
            std::list< WQtTreeItem* > childs = findItemsByModule( mIn, *iter );
386
            for( std::list< WQtTreeItem* >::const_iterator citer = childs.begin(); citer != childs.end(); ++citer )
387
            {
388
                if( ( *citer )->getHandledInput() == e->getInput()->getName() )
389 390 391 392 393 394 395 396 397 398 399 400 401 402 403
                {
                    ( *iter )->removeChild( *citer );

                    // move it back to the reservoir in m_tiModules
                    m_tiModules->addChild( *citer );
                    ( *citer )->setHidden( true );
                    ( *citer )->setHandledInput( "" );
                    ( *citer )->setHandledOutput( "" );
                }
            }
        }

        // we need to ensure that at least one item for mIn is visible somewhere
        items = findItemsByModule( mIn );
        bool oneVisible = false;
404
        for( std::list< WQtTreeItem* >::const_iterator iter = items.begin(); iter != items.end(); ++iter )
405 406 407
        {
            oneVisible = oneVisible || !( *iter )->isHidden();
        }
408
        if( !oneVisible )
409 410 411
        {
            ( *items.begin() )->setHidden( false );
        }
412
    }
413

414
    // a module tree item should be deleted
415
    if( event->type() == WQT_MODULE_DELETE_EVENT )
416
    {
417
        WModuleDeleteEvent* e = dynamic_cast< WModuleDeleteEvent* >( event );
418
        if( !e )
419
        {
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 );
423 424 425 426 427
            return true;
        }

        // grab the module reference and print some info
        boost::shared_ptr< WModule > module = e->getTreeItem()->getModule();
428
        WLogger::getLogger()->addLogMessage( "Deleting module \"" + module->getName() + "\" from Tree.",
429
                                             "ControlPanel", LL_DEBUG );
430 431 432 433

        // remove it from the tree and free last ref count
        m_moduleTreeWidget->deleteItem( e->getTreeItem() );

434 435
        // ref count != 1? (only if there are now tree items left)
        bool lastTreeItem = !findItemsByModule( module ).size();
436
        if( lastTreeItem && ( module.use_count() != 1 ) )
437
        {
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.";
440
            WAssert( false, "Removed module has strange usage count. Should be 1 here. Module reference is held by someone else." );
441 442 443 444 445
        }

        return true;
    }

446
    // a module was removed from the container
447
    if( event->type() == WQT_MODULE_REMOVE_EVENT )
448
    {
449
        WModuleRemovedEvent* e = dynamic_cast< WModuleRemovedEvent* >( event );
450
        if( !e )
451
        {
452
            // this should never happen, since the type is set to WQT_MODULE_REMOVE_EVENT.
453
            WLogger::getLogger()->addLogMessage( "Event is not an WModuleRemovedEvent although its type claims it. Ignoring event.",
454
                                                 "ControlPanel", LL_WARNING );
455 456 457 458
            return true;
        }

        // iterate tree items and find proper one
459
        std::list< WQtTreeItem* > items = findItemsByModule( e->getModule() );
460
        for( std::list< WQtTreeItem* >::const_iterator iter = items.begin(); iter != items.end(); ++iter )
461
        {
462
            ( *iter )->gotRemoved();
463 464 465
        }

        // be nice and print some info
466
        WLogger::getLogger()->addLogMessage( "Removing module \"" + e->getModule()->getName() + "\" from Tree.", "ControlPanel", LL_DEBUG );
467 468 469 470

        // stop the module
        e->getModule()->requestStop();
        WLogger::getLogger()->addLogMessage( "Waiting for module \"" + e->getModule()->getName() + "\" to finish before deleting.",
471
                                             "ControlPanel", LL_DEBUG );
472 473 474 475

        return true;
    }

476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496
    // a connector was updated
    if( event->type() == WQT_MODULE_CONNECTOR_EVENT )
    {
        // convert event to ready event
        WModuleConnectorEvent* e1 = dynamic_cast< WModuleConnectorEvent* >( event );     // NOLINT
        if( e1 )
        {
            // iterate tree items and find proper one -> check if selected
            // 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
            // the first item if it is selected to check whether the current module is active.
            std::list< WQtTreeItem* > items = findItemsByModule( e1->getModule() );
            if( !items.empty() && ( *items.begin() )->isSelected() )
            {
                // ok, the module is selected. Now, update the connectables lists (buttons and menu)
                createCompatibleButtons( e1->getModule() );
            }
        }

        return true;
    }

497 498
    return QDockWidget::event( event );
}
499

500
std::list< WQtTreeItem* > WQtControlPanel::findItemsByModule( boost::shared_ptr< WModule > module, QTreeWidgetItem* where )
501 502 503 504
{
    std::list< WQtTreeItem* > l;

    // iterate tree items and find proper one
505
    QTreeWidgetItemIterator it( where );
506
    while( *it )
507
    {
508 509
        WQtTreeItem* item = dynamic_cast< WQtTreeItem* >( *it );
        boost::shared_ptr< WModule > itemModule = boost::shared_ptr< WModule >();
510
        if( item )
511
        {
512
            itemModule = item->getModule();
513 514
        }

515
        // if the pointer is NULL the item was none of the above
516
        if( !itemModule.get() )
517 518
        {
            ++it;
519
            continue;
520
        }
521

522
        // we found it
523
        if( module == itemModule )
524 525 526 527 528
        {
            l.push_back( item );
        }

        ++it;
529
    }
530 531
    return l;
}
532

533
std::list< WQtTreeItem* > WQtControlPanel::findItemsByModule( boost::shared_ptr< WModule > module )
534
{
535 536 537 538
    std::list< WQtTreeItem* > ret = findItemsByModule( module, m_moduleTreeWidget->invisibleRootItem() );
    std::list< WQtTreeItem* > ret2 = findItemsByModule( module, m_moduleTreeWidget->topLevelItem( 0 ) );
    ret.merge( ret2 );
    return ret;
539
}
540

541
WQtDatasetTreeItem* WQtControlPanel::addDataset( boost::shared_ptr< WModule > module, int subjectId )
542
{
schurade's avatar
schurade committed
543
    int c = getFirstSubject();
544
    WQtSubjectTreeItem* subject = static_cast< WQtSubjectTreeItem* >( m_moduleTreeWidget->topLevelItem( subjectId + c ) );
schurade's avatar
schurade committed
545
    subject->setExpanded( true );
546
    WQtDatasetTreeItem* item = subject->addDatasetItem( module );
547
    m_moduleTreeWidget->setCurrentItem( item );
548
    item->setDisabled( true );
Sebastian Eichelbaum's avatar
[STYLE]  
Sebastian Eichelbaum committed
549
    item->setExpanded( true );
550

551
    return item;
552
}
553

554
WQtModuleTreeItem* WQtControlPanel::addModule( boost::shared_ptr< WModule > module )
555
{
schurade's avatar
schurade committed
556
    m_tiModules->setExpanded( true );
557
    WQtModuleTreeItem* item;
558 559 560 561
    // for each input, create an item
    m_moduleTreeWidget->setCurrentItem( NULL );
    bool firstItem = true;
    WModule::InputConnectorList cons = module->getInputConnectors();
562
    for( WModule::InputConnectorList::const_iterator iter = cons.begin(); iter != cons.end(); ++iter )
563
    {
564 565 566 567 568 569
        // every module gets added to tiModules first. The connection events then move these things to the right parent
        item = m_tiModules->addModuleItem( module );
        item->setDisabled( true );
        item->setExpanded( true );

        // all but the first item get hidden by default. They get visible after a connection event has been fired
570
        if( !firstItem )
571 572 573 574 575
        {
            item->setHidden( true );
        }

        firstItem = false;
576
    }
577 578

    // this module has not inputs. So we simply add it to the tiModules
579
    if( firstItem )
580 581
    {
        item = m_tiModules->addModuleItem( module );
582
        item->setDisabled( true );
583
    }
584

585
    return item;
586 587
}

588
void WQtControlPanel::addRoi( osg::ref_ptr< WROI > roi )
schurade's avatar
schurade committed
589
{
590 591 592 593
    WQtRoiTreeItem* newItem;
    WQtBranchTreeItem* branchItem;

    m_tiRois->setExpanded( true );
594
    bool found = false;
595

596 597
    // go through all branches
    for( int branchID = 0; branchID < m_tiRois->childCount(); ++branchID )
schurade's avatar
schurade committed
598
    {
599 600
        branchItem = dynamic_cast< WQtBranchTreeItem* >( m_tiRois->child( branchID ) );
        // if branch == roi branch
601
        if( branchItem->getBranch() == WKernel::getRunningKernel()->getRoiManager()->getBranch( roi ) )
schurade's avatar
schurade committed
602
        {
603 604
            found = true;
            break;
schurade's avatar
schurade committed
605 606
        }
    }
607

608
    if( !found )
schurade's avatar
schurade committed
609
    {
610
        branchItem = m_tiRois->addBranch( WKernel::getRunningKernel()->getRoiManager()->getBranch( roi ) );
schurade's avatar
schurade committed
611
    }
612 613 614 615 616

    branchItem->setExpanded( true );
    newItem = branchItem->addRoiItem( roi );
    newItem->setDisabled( false );
    newItem->setSelected( true );
617
    WKernel::getRunningKernel()->getRoiManager()->setSelectedRoi( getSelectedRoi() );
schurade's avatar
schurade committed
618 619
}

620
void WQtControlPanel::removeRoi( osg::ref_ptr< WROI > roi )
621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640
{
    for( int branchID = 0; branchID < m_tiRois->childCount(); ++branchID )
    {
        QTreeWidgetItem* branchTreeItem = m_tiRois->child( branchID );
        for( int roiID = 0; roiID < branchTreeItem->childCount(); ++roiID )
        {
            WQtRoiTreeItem* roiTreeItem = dynamic_cast< WQtRoiTreeItem* >( branchTreeItem->child( roiID ) );
            if( roiTreeItem && roiTreeItem->getRoi() == roi )
            {
                delete roiTreeItem;

                if( branchTreeItem->childCount() == 0 )
                {
                    delete branchTreeItem;
                }

                break;
            }
        }
    }
641
    WKernel::getRunningKernel()->getRoiManager()->setSelectedRoi( getSelectedRoi() );
642 643
}

644
boost::shared_ptr< WModule > WQtControlPanel::getSelectedModule()
645
{
646
    if( m_moduleTreeWidget->selectedItems().at( 0 )->type() == 1 )
647
    {
648
        return ( static_cast< WQtDatasetTreeItem* >( m_moduleTreeWidget->selectedItems().at( 0 ) )->getModule() );
649
    }
650
    else if( m_moduleTreeWidget->selectedItems().at( 0 )->type() == 3 )
651
    {
652
        return ( static_cast< WQtModuleTreeItem* >( m_moduleTreeWidget->selectedItems().at( 0 ) )->getModule() );
653 654 655 656
    }

    return boost::shared_ptr< WModule >();
}
657

658
void WQtControlPanel::selectTreeItem()
659
{
660
    if( m_ignoreSelectionChange )
661 662 663 664
    {
        return;
    }

665
    boost::shared_ptr< WModule > module;
666
    boost::shared_ptr< WProperties > props;
667
    boost::shared_ptr< WProperties > infoProps;
Sebastian Eichelbaum's avatar
[MERGE]  
Sebastian Eichelbaum committed
668

669
    if( m_moduleTreeWidget->selectedItems().size() != 0  )
670
    {
671 672 673
        // TODO(schurade): qt doc says clear() doesn't delete tabs so this is possibly a memory leak
        m_tabWidget->clear();

674 675 676 677 678 679 680 681 682 683
        // disable delete action for tree items that have children.
        if( m_moduleTreeWidget->selectedItems().at( 0 )->childCount() != 0 )
        {
            m_deleteModuleAction->setEnabled( false );
        }
        else
        {
            m_deleteModuleAction->setEnabled( true );
        }

684
        switch ( m_moduleTreeWidget->selectedItems().at( 0 )->type() )
schurade's avatar
schurade committed
685
        {
686
            case SUBJECT:
687
            case MODULEHEADER:
688 689
                // deletion of headers and subjects is not allowed
                m_deleteModuleAction->setEnabled( false );
690
                createCompatibleButtons( module );  // module is NULL at this point
schurade's avatar
schurade committed
691
                break;
692
            case DATASET:
693
                module = ( static_cast< WQtDatasetTreeItem* >( m_moduleTreeWidget->selectedItems().at( 0 ) ) )->getModule();
694
                // crashed modules should not provide any props
695
                if( module->isCrashed()() )
696 697 698
                {
                    return;
                }
699

700
                props = module->getProperties();
701
                infoProps = module->getInformationProperties();
702
                createCompatibleButtons( module );
703 704

                {
705
                    boost::shared_ptr< WDataModule > dataModule = boost::shared_dynamic_cast< WDataModule >( module );
706

707
                    // if the selected module contains a texture, select the corresponding texture in the texture sorter.
708 709 710 711
                    if( dataModule )
                    {
                        if( dataModule->getDataSet() )
                        {
712
                            m_colormapper->selectTexture( dataModule->getDataSet() );
713 714 715 716
                        }
                    }
                }

schurade's avatar
schurade committed
717
                break;
718
            case MODULE:
719
                {
720
                    module = ( static_cast< WQtModuleTreeItem* >( m_moduleTreeWidget->selectedItems().at( 0 ) ) )->getModule();
721
                    m_deleteModuleAction->setEnabled( true );
722

723 724 725 726 727
                    // this is ugly since it causes the property tab to update multiple times if multiple items get selected by this call
                    // but it highlights all the same items which is nice and wanted here
                    // Set the ignore flag to avoid that this method gets called several times
                    m_ignoreSelectionChange = true;
                    std::list< WQtTreeItem* > items = findItemsByModule( module );