WQtControlPanel.cpp 40.6 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

37
#include "../../../common/WLogger.h"
38
#include "../../../common/WPreferences.h"
39
#include "../../../dataHandler/WDataSet.h"
40
#include "../../../kernel/modules/data/WMData.h"
41
#include "../../../kernel/WKernel.h"
42
#include "../../../kernel/WModule.h"
43 44
#include "../../../kernel/WModuleFactory.h"
#include "../events/WEventTypes.h"
45
#include "../events/WModuleAssocEvent.h"
46
#include "../events/WModuleConnectEvent.h"
47
#include "../events/WModuleDeleteEvent.h"
48
#include "../events/WModuleDisconnectEvent.h"
49
#include "../events/WModuleReadyEvent.h"
50
#include "../events/WModuleRemovedEvent.h"
51 52
#include "../events/WRoiAssocEvent.h"
#include "../events/WRoiRemoveEvent.h"
53
#include "../WMainWindow.h"
54
#include "../WQt4Gui.h"
55
#include "../WQtCombinerActionList.h"
56
#include "WQtBranchTreeItem.h"
57
#include "WQtControlPanel.h"
58
#include "WQtTextureSorter.h"
59

60
WQtControlPanel::WQtControlPanel( WMainWindow* parent )
61
    : QDockWidget( "Control Panel", parent ),
62
    m_ignoreSelectionChange( false )
63
{
64 65
    m_mainWindow = parent;

66
    m_panel = new QWidget( this );
67
    m_moduleTreeWidget = new WQtTreeWidget( m_panel );
68
    m_moduleTreeWidget->setContextMenuPolicy( Qt::ActionsContextMenu );
69

70 71
    m_moduleTreeWidget->setHeaderLabel( QString( "Module Tree" ) );
    m_moduleTreeWidget->setDragEnabled( false );
72 73 74
    m_moduleTreeWidget->viewport()->setAcceptDrops( true );
    m_moduleTreeWidget->setDropIndicatorShown( true );
    m_moduleTreeWidget->setMinimumHeight( 250 );
75

76
    // create context menu for tree items
77 78 79 80 81

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

83 84 85 86 87 88 89
    m_connectWithPrototypeAction = new QAction( "Connect with Prototype", m_moduleTreeWidget );
    m_moduleTreeWidget->addAction( m_connectWithPrototypeAction );
    m_connectWithModuleAction = new QAction( "Connect with Module", m_moduleTreeWidget );
    m_moduleTreeWidget->addAction( m_connectWithModuleAction );
    m_disconnectAction = new QAction( "Disconnect", m_moduleTreeWidget );
    m_moduleTreeWidget->addAction( m_disconnectAction );

90 91 92 93
    // 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 );
94 95 96 97 98 99 100 101 102 103 104

    {
        // Set the key for removing modules
        std::string deleteKey = "";
        WPreferences::getPreference( "qt4gui.deleteModuleKey", &deleteKey );
        if( deleteKey == "" )
        {
            deleteKey = "Backspace";
        }
        m_deleteModuleAction->setShortcut( QKeySequence( QString::fromStdString( deleteKey ) ) );
    }
105 106 107
    connect( m_deleteModuleAction, SIGNAL( triggered() ), this, SLOT( deleteModuleTreeItem() ) );
    m_moduleTreeWidget->addAction( m_deleteModuleAction );

108
    m_textureSorter = new WQtTextureSorter( this );
109 110
    m_textureSorter->setToolTip( "Reorder the textures." );

111
    m_tabWidget = new QTabWidget( m_panel );
112
    m_tabWidget2 = new QTabWidget( m_panel );
schurade's avatar
schurade committed
113
    m_tabWidget->setMinimumHeight( 220 );
114

115 116 117 118
    // should the Tree, Texture Sorter and the ROI Display be combined in one tab widget?
    bool combineThem = false;
    WPreferences::getPreference( "qt4gui.combineTreeAndRoiAndTextureSorter", &combineThem );

119
    m_layout = new QVBoxLayout();
120 121 122 123 124 125 126 127
    if ( !combineThem )
    {
        m_layout->addWidget( m_moduleTreeWidget );
    }
    else
    {
        m_tabWidget2->addTab( m_moduleTreeWidget, QString( "Modules" ) );
    }
128 129
    m_layout->addWidget( m_tabWidget2 );

Alexander Wiebel's avatar
Alexander Wiebel committed
130
    m_tabWidget2->addTab( m_textureSorter, QString( "Texture Sorter" ) );
131 132

    m_roiTreeWidget = new WQtTreeWidget();
133 134
    m_roiTreeWidget->setToolTip( "Regions of intrest (ROIs) for selecting fiber  clusters. Branches are combined using logic <b>or</b>, "
"inside the branches the ROIs are combined using logic <b>and</b>." );
135 136 137 138 139 140
    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 );
Alexander Wiebel's avatar
Alexander Wiebel committed
141
    m_tabWidget2->addTab( m_roiTreeWidget, QString( "ROIs" ) );
142 143


144 145 146 147 148 149 150
    m_layout->addWidget( m_tabWidget );

    m_panel->setLayout( m_layout );

    this->setAllowedAreas( Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea );
    this->setFeatures( QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable );
    this->setWidget( m_panel );
151

152
    m_tiModules = new WQtModuleHeaderTreeItem( m_moduleTreeWidget );
153 154
    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." );
155
    m_tiRois = new WQtRoiHeaderTreeItem( m_roiTreeWidget );
Alexander Wiebel's avatar
Alexander Wiebel committed
156
    m_tiRois->setText( 0, QString( "ROIs" ) );
157

158
    connectSlots();
159

160 161 162 163 164 165 166 167 168 169 170
    {
        // Set the key for removing ROIs and connect the event
        std::string deleteKey = "";
        WPreferences::getPreference( "qt4gui.deleteROIKey", &deleteKey );
        if( deleteKey == "" )
        {
            deleteKey = "Delete";
        }
        QShortcut* shortcut = new QShortcut( QKeySequence( QString::fromStdString( deleteKey ) ), m_roiTreeWidget );
        connect( shortcut, SIGNAL( activated() ), this, SLOT( deleteROITreeItem() ) );
    }
171 172
}

173
WQtControlPanel::~WQtControlPanel()
174 175 176
{
}

177
void WQtControlPanel::connectSlots()
178
{
179
    connect( m_moduleTreeWidget, SIGNAL( itemSelectionChanged() ), this, SLOT( selectTreeItem() ) );
180
    connect( m_moduleTreeWidget, SIGNAL( itemClicked( QTreeWidgetItem*, int ) ), this, SLOT( changeTreeItem() ) );
181 182 183
    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() ) );
184 185
    connect( m_textureSorter, SIGNAL( textureSelectionChanged( boost::shared_ptr< WDataSet > ) ),
             this, SLOT( selectDataModule( boost::shared_ptr< WDataSet > ) ) );
186
    connect( m_roiTreeWidget, SIGNAL( dragDrop() ), this, SLOT( handleDragDrop() ) );
187
}
188

189
void WQtControlPanel::addToolbar( QToolBar* tb )
190 191 192 193
{
    m_layout->insertWidget( 0, tb );
}

194
WQtSubjectTreeItem* WQtControlPanel::addSubject( std::string name )
195
{
196
    WQtSubjectTreeItem* subject = new WQtSubjectTreeItem( m_moduleTreeWidget );
197 198 199
    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 + "\"." ) );
200 201 202 203

    return subject;
}

204
bool WQtControlPanel::event( QEvent* event )
205
{
206 207 208 209 210 211
    // a subject singals a newly registered data set
    if ( event->type() == WQT_UPDATE_TEXTURE_SORTER_EVENT )
    {
        m_textureSorter->update();
    }

212 213 214 215 216 217
    if ( event->type() == WQT_ROI_ASSOC_EVENT )
    {
        WRoiAssocEvent* e2 = dynamic_cast< WRoiAssocEvent* >( event );     // NOLINT
        if ( e2 )
        {
            addRoi( e2->getRoi() );
218
            WLogger::getLogger()->addLogMessage( "Inserting ROI to control panel.", "ControlPanel", LL_DEBUG );
219 220 221 222 223 224 225 226 227 228
        }

        return true;
    }
    if( event->type() == WQT_ROI_REMOVE_EVENT )
    {
        WRoiRemoveEvent* e3 = dynamic_cast< WRoiRemoveEvent* >( event );
        if( e3 )
        {
            removeRoi( e3->getRoi() );
229
            WLogger::getLogger()->addLogMessage( "Removing ROI from control panel.", "ControlPanel", LL_DEBUG );
230 231 232 233 234
        }

        return true;
    }

235 236 237 238
    // a module got associated with the root container -> add it to the list
    if ( event->type() == WQT_ASSOC_EVENT )
    {
        // convert event to assoc event
schurade's avatar
schurade committed
239 240
        WModuleAssocEvent* e1 = dynamic_cast< WModuleAssocEvent* >( event );     // NOLINT
        if ( e1 )
241
        {
242 243
            WLogger::getLogger()->addLogMessage( "Inserting module " + e1->getModule()->getName() + " to control panel.",
                                                 "ControlPanel", LL_DEBUG );
244

schurade's avatar
schurade committed
245 246 247 248 249 250 251 252 253 254
            // finally add the module
            // TODO(schurade): is this differentiation between data and "normal" modules really needed?
            if ( boost::shared_dynamic_cast< WMData >( e1->getModule() ).get() )
            {
                addDataset( e1->getModule(), 0 );
            }
            else
            {
                addModule( e1->getModule() );
            }
255
        }
schurade's avatar
schurade committed
256 257
        return true;
    }
258

259
    // a module changed its state to "ready" -> activate it in control panel
260
    if ( event->type() == WQT_READY_EVENT )
schurade's avatar
schurade committed
261
    {
262 263 264
        // convert event to assoc event
        WModuleReadyEvent* e = dynamic_cast< WModuleReadyEvent* >( event );     // NOLINT
        if ( !e )
265
        {
266
            // this should never happen, since the type is set to WQT_READY_EVENT.
267
            WLogger::getLogger()->addLogMessage( "Event is not an WModueReadyEvent although its type claims it. Ignoring event.",
268
                                                 "ControlPanel", LL_WARNING );
269 270

            return true;
271 272
        }

273 274
        WLogger::getLogger()->addLogMessage( "Activating module " + e->getModule()->getName() + " in control panel.",
                                             "ControlPanel", LL_DEBUG );
275

276 277 278
        // search all the item matching the module
        std::list< WQtTreeItem* > items = findItemsByModule( e->getModule() );
        for ( std::list< WQtTreeItem* >::const_iterator iter = items.begin(); iter != items.end(); ++iter )
279
        {
280 281
            ( *iter )->setSelected( true );
            ( *iter )->setDisabled( false );
282 283
        }

284
        selectTreeItem();
285

286 287
        return true;
    }
288

289 290
    // a module tree item was connected to another one
    if ( event->type() == WQT_MODULE_CONNECT_EVENT )
291
    {
292 293
        WModuleConnectEvent* e = dynamic_cast< WModuleConnectEvent* >( event );     // NOLINT
        if ( !e )
294
        {
295
            // this should never happen, since the type is set to WQT_MODULE_CONNECT_EVENT.
296
            WLogger::getLogger()->addLogMessage( "Event is not an WModuleConnectEvent although its type claims it. Ignoring event.",
297
                                                 "ControlPanel", LL_WARNING );
298
            return true;
299 300
        }

301 302 303 304
        // 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();

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

307 308 309 310 311 312 313 314 315 316 317 318 319 320 321
        // 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 );
        for ( std::list< WQtTreeItem* >::const_iterator iter = items.begin(); iter != items.end(); ++iter )
        {
            ( *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 );
            for ( std::list< WQtTreeItem* >::const_iterator parIter = possibleParents.begin(); parIter != possibleParents.end(); ++parIter )
            {
                // remove child from tiModules
                m_tiModules->removeChild( *iter );
322 323 324 325 326 327
                if ( !( *parIter )->isHidden() )
                {
                    ( *parIter )->addChild( *iter );
                    ( *parIter )->setExpanded( true );
                    break;
                }
328 329 330 331 332
            }

            // job done.
            break;
        }
333 334 335 336 337 338 339 340
    }

    // a module tree item was disconnected from another one
    if ( event->type() == WQT_MODULE_DISCONNECT_EVENT )
    {
        WModuleDisconnectEvent* e = dynamic_cast< WModuleDisconnectEvent* >( event );     // NOLINT
        if ( !e )
        {
341
            // this should never happen, since the type is set to WQT_MODULE_DISCONNECT_EVENT.
342
            WLogger::getLogger()->addLogMessage( "Event is not an WModuleDisconnectEvent although its type claims it. Ignoring event.",
343
                                                 "ControlPanel", LL_WARNING );
344 345 346
            return true;
        }

347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385
        // 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 );
        for ( std::list< WQtTreeItem* >::const_iterator iter = items.begin(); iter != items.end(); ++iter )
        {
            // each of them can contain a child with the involved input
            std::list< WQtTreeItem* > childs = findItemsByModule( mIn, *iter );
            for ( std::list< WQtTreeItem* >::const_iterator citer = childs.begin(); citer != childs.end(); ++citer )
            {
                if ( ( *citer )->getHandledInput() == e->getInput()->getName() )
                {
                    ( *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;
        for ( std::list< WQtTreeItem* >::const_iterator iter = items.begin(); iter != items.end(); ++iter )
        {
            oneVisible = oneVisible || !( *iter )->isHidden();
        }
        if ( !oneVisible )
        {
            ( *items.begin() )->setHidden( false );
        }
386
    }
387

388
    // a module tree item should be deleted
389
    if ( event->type() == WQT_MODULE_DELETE_EVENT )
390
    {
391
        WModuleDeleteEvent* e = dynamic_cast< WModuleDeleteEvent* >( event );
392 393
        if ( !e )
        {
394
            // this should never happen, since the type is set to WQT_MODULE_DELETE_EVENT.
395
            WLogger::getLogger()->addLogMessage( "Event is not an WModuleDeleteEvent although its type claims it. Ignoring event.",
396
                                                 "ControlPanel", LL_WARNING );
397 398 399 400 401
            return true;
        }

        // grab the module reference and print some info
        boost::shared_ptr< WModule > module = e->getTreeItem()->getModule();
402
        WLogger::getLogger()->addLogMessage( "Deleting module \"" + module->getName() + "\" from Tree.",
403
                                             "ControlPanel", LL_DEBUG );
404 405 406 407

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

408 409 410
        // ref count != 1? (only if there are now tree items left)
        bool lastTreeItem = !findItemsByModule( module ).size();
        if ( lastTreeItem && ( module.use_count() != 1 ) )
411
        {
412
            wlog::error( "ControlPanel" ) << "Removed module has strange usage count: " << module.use_count() << ". Should be 1 here. " <<
413 414 415 416 417 418
                                              "Module reference is held by someone else.";
        }

        return true;
    }

419 420 421
    // a module was removed from the container
    if ( event->type() == WQT_MODULE_REMOVE_EVENT )
    {
422
        WModuleRemovedEvent* e = dynamic_cast< WModuleRemovedEvent* >( event );
423 424
        if ( !e )
        {
425
            // this should never happen, since the type is set to WQT_MODULE_REMOVE_EVENT.
426
            WLogger::getLogger()->addLogMessage( "Event is not an WModuleRemovedEvent although its type claims it. Ignoring event.",
427
                                                 "ControlPanel", LL_WARNING );
428 429 430 431
            return true;
        }

        // iterate tree items and find proper one
432 433
        std::list< WQtTreeItem* > items = findItemsByModule( e->getModule() );
        for ( std::list< WQtTreeItem* >::const_iterator iter = items.begin(); iter != items.end(); ++iter )
434
        {
435
            ( *iter )->gotRemoved();
436 437 438
        }

        // be nice and print some info
439
        WLogger::getLogger()->addLogMessage( "Removing module \"" + e->getModule()->getName() + "\" from Tree.", "ControlPanel", LL_DEBUG );
440 441 442 443

        // stop the module
        e->getModule()->requestStop();
        WLogger::getLogger()->addLogMessage( "Waiting for module \"" + e->getModule()->getName() + "\" to finish before deleting.",
444
                                             "ControlPanel", LL_DEBUG );
445 446 447 448

        return true;
    }

449 450
    return QDockWidget::event( event );
}
451

452
std::list< WQtTreeItem* > WQtControlPanel::findItemsByModule( boost::shared_ptr< WModule > module, QTreeWidgetItem* where )
453 454 455 456
{
    std::list< WQtTreeItem* > l;

    // iterate tree items and find proper one
457
    QTreeWidgetItemIterator it( where );
458
    while ( *it )
459
    {
460 461 462
        WQtTreeItem* item = dynamic_cast< WQtTreeItem* >( *it );
        boost::shared_ptr< WModule > itemModule = boost::shared_ptr< WModule >();
        if ( item )
463
        {
464
            itemModule = item->getModule();
465 466
        }

467 468
        // if the pointer is NULL the item was none of the above
        if ( !itemModule.get() )
469 470
        {
            ++it;
471
            continue;
472
        }
473

474 475 476 477 478 479 480
        // we found it
        if ( module == itemModule )
        {
            l.push_back( item );
        }

        ++it;
481
    }
482 483
    return l;
}
484

485
std::list< WQtTreeItem* > WQtControlPanel::findItemsByModule( boost::shared_ptr< WModule > module )
486
{
487 488 489 490
    std::list< WQtTreeItem* > ret = findItemsByModule( module, m_moduleTreeWidget->invisibleRootItem() );
    std::list< WQtTreeItem* > ret2 = findItemsByModule( module, m_moduleTreeWidget->topLevelItem( 0 ) );
    ret.merge( ret2 );
    return ret;
491
}
492

493
WQtDatasetTreeItem* WQtControlPanel::addDataset( boost::shared_ptr< WModule > module, int subjectId )
494
{
schurade's avatar
schurade committed
495
    int c = getFirstSubject();
496
    WQtSubjectTreeItem* subject = static_cast< WQtSubjectTreeItem* >( m_moduleTreeWidget->topLevelItem( subjectId + c ) );
schurade's avatar
schurade committed
497
    subject->setExpanded( true );
498
    WQtDatasetTreeItem* item = subject->addDatasetItem( module );
499
    m_moduleTreeWidget->setCurrentItem( item );
500
    item->setDisabled( true );
501

502
    return item;
503
}
504

505
WQtModuleTreeItem* WQtControlPanel::addModule( boost::shared_ptr< WModule > module )
506
{
schurade's avatar
schurade committed
507
    m_tiModules->setExpanded( true );
508
    WQtModuleTreeItem* item;
509 510 511 512 513
    // for each input, create an item
    m_moduleTreeWidget->setCurrentItem( NULL );
    bool firstItem = true;
    WModule::InputConnectorList cons = module->getInputConnectors();
    for ( WModule::InputConnectorList::const_iterator iter = cons.begin(); iter != cons.end(); ++iter )
514
    {
515 516 517 518 519 520 521 522 523 524 525 526
        // 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
        if ( !firstItem )
        {
            item->setHidden( true );
        }

        firstItem = false;
527
    }
528 529 530

    // this module has not inputs. So we simply add it to the tiModules
    if ( firstItem )
531 532
    {
        item = m_tiModules->addModuleItem( module );
533
        item->setDisabled( true );
534
    }
535

536
    return item;
537 538
}

539
void WQtControlPanel::addRoi( osg::ref_ptr< WROI > roi )
schurade's avatar
schurade committed
540
{
541 542 543 544
    WQtRoiTreeItem* newItem;
    WQtBranchTreeItem* branchItem;

    m_tiRois->setExpanded( true );
545
    bool found = false;
546

547 548
    // go through all branches
    for( int branchID = 0; branchID < m_tiRois->childCount(); ++branchID )
schurade's avatar
schurade committed
549
    {
550 551
        branchItem = dynamic_cast< WQtBranchTreeItem* >( m_tiRois->child( branchID ) );
        // if branch == roi branch
552
        if ( branchItem->getBranch() == WKernel::getRunningKernel()->getRoiManager()->getBranch( roi ) )
schurade's avatar
schurade committed
553
        {
554 555
            found = true;
            break;
schurade's avatar
schurade committed
556 557
        }
    }
558 559

    if ( !found )
schurade's avatar
schurade committed
560
    {
561
        branchItem = m_tiRois->addBranch( WKernel::getRunningKernel()->getRoiManager()->getBranch( roi ) );
schurade's avatar
schurade committed
562
    }
563 564 565 566 567 568

    m_tabWidget2->setCurrentIndex( m_tabWidget2->indexOf( m_roiTreeWidget ) );
    branchItem->setExpanded( true );
    newItem = branchItem->addRoiItem( roi );
    newItem->setDisabled( false );
    newItem->setSelected( true );
569
    WKernel::getRunningKernel()->getRoiManager()->setSelectedRoi( getSelectedRoi() );
schurade's avatar
schurade committed
570 571
}

572
void WQtControlPanel::removeRoi( osg::ref_ptr< WROI > roi )
573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592
{
    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;
            }
        }
    }
593
    WKernel::getRunningKernel()->getRoiManager()->setSelectedRoi( getSelectedRoi() );
594 595
}

596
boost::shared_ptr< WModule > WQtControlPanel::getSelectedModule()
597
{
598
    if ( m_moduleTreeWidget->selectedItems().at( 0 )->type() == 1 )
599
    {
600
        return ( static_cast< WQtDatasetTreeItem* >( m_moduleTreeWidget->selectedItems().at( 0 ) )->getModule() );
601
    }
602
    else if ( m_moduleTreeWidget->selectedItems().at( 0 )->type() == 3 )
603
    {
604
        return ( static_cast< WQtModuleTreeItem* >( m_moduleTreeWidget->selectedItems().at( 0 ) )->getModule() );
605 606 607 608
    }

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

610
void WQtControlPanel::selectTreeItem()
611
{
612 613 614 615 616
    if ( m_ignoreSelectionChange )
    {
        return;
    }

617
    boost::shared_ptr< WModule > module;
618
    boost::shared_ptr< WProperties > props;
619
    boost::shared_ptr< WProperties > infoProps;
Sebastian Eichelbaum's avatar
[MERGE]  
Sebastian Eichelbaum committed
620

621
    if ( m_moduleTreeWidget->selectedItems().size() != 0  )
622
    {
623 624 625
        // TODO(schurade): qt doc says clear() doesn't delete tabs so this is possibly a memory leak
        m_tabWidget->clear();

626 627 628 629 630 631 632 633 634 635
        // 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 );
        }

636
        switch ( m_moduleTreeWidget->selectedItems().at( 0 )->type() )
schurade's avatar
schurade committed
637
        {
638
            case SUBJECT:
639
            case MODULEHEADER:
640 641
                // deletion of headers and subjects is not allowed
                m_deleteModuleAction->setEnabled( false );
642
                createCompatibleButtons( module );  // module is NULL at this point
schurade's avatar
schurade committed
643
                break;
644
            case DATASET:
645
                module = ( static_cast< WQtDatasetTreeItem* >( m_moduleTreeWidget->selectedItems().at( 0 ) ) )->getModule();
646
                // crashed modules should not provide any props
647 648 649 650
                if ( module->isCrashed()() )
                {
                    return;
                }
651

652
                props = module->getProperties();
653
                infoProps = module->getInformationProperties();
654
                createCompatibleButtons( module );
655 656 657 658

                {
                    boost::shared_ptr< WMData > dataModule = boost::shared_dynamic_cast< WMData >( module );

659
                    // if the selected module contains a texture, select the corresponding texture in the texture sorter.
660 661 662 663
                    if( dataModule )
                    {
                        if( dataModule->getDataSet() )
                        {
664
                            m_textureSorter->selectTexture( dataModule->getDataSet() );
665 666 667 668
                        }
                    }
                }

schurade's avatar
schurade committed
669
                break;
670
            case MODULE:
671
                {
672
                    module = ( static_cast< WQtModuleTreeItem* >( m_moduleTreeWidget->selectedItems().at( 0 ) ) )->getModule();
673
                    m_deleteModuleAction->setEnabled( true );
674

675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692
                    // 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 );
                    for ( std::list< WQtTreeItem* >::const_iterator iter = items.begin(); iter != items.end(); ++iter )
                    {
                        ( *iter )->setSelected( true );
                    }
                    m_ignoreSelectionChange = false;

                    // crashed modules should not provide any props
                    if ( module->isCrashed()() )
                    {
                        return;
                    }
                    props = module->getProperties();
                    infoProps = module->getInformationProperties();
693
                    createCompatibleButtons( module );
694
                }
695
                break;
696 697 698 699 700 701 702 703
            case ROIHEADER:
            case ROIBRANCH:
            case ROI:
                break;
            default:
                break;
        }
    }
704 705


706
    buildPropTab( props, infoProps );
707 708
}

709
void WQtControlPanel::selectRoiTreeItem()
710 711 712
{
    // TODO(schurade): qt doc says clear() doesn't delete tabs so this is possibly a memory leak
    m_tabWidget->clear();
713 714 715 716 717 718 719 720 721

    // Make compatibles toolbar empty
    {
        if( m_mainWindow->getCompatiblesToolbar() != 0 )
        {
            m_mainWindow->getCompatiblesToolbar()->makeEmpty();
        }
        else
        {
722
            m_mainWindow->setCompatiblesToolbar( new WQtCombinerToolbar( m_mainWindow ) );
723 724
        }
    }
725 726

    boost::shared_ptr< WModule > module;
727
    boost::shared_ptr< WProperties > props;
728 729 730 731 732 733 734 735 736

    if ( m_roiTreeWidget->selectedItems().size() != 0  )
    {
        switch ( m_roiTreeWidget->selectedItems().at( 0 )->type() )
        {
            case SUBJECT:
            case DATASET:
            case MODULEHEADER:
            case MODULE:
737
            case ROIHEADER:
738
                WKernel::getRunningKernel()->getRoiManager()->setSelectedRoi( getSelectedRoi() );
schurade's avatar
schurade committed
739
                break;
schurade's avatar
schurade committed
740
            case ROIBRANCH:
741
                props = ( static_cast< WQtBranchTreeItem* >( m_roiTreeWidget->selectedItems().at( 0 ) ) )->getBranch()->getProperties();
742
                WKernel::getRunningKernel()->getRoiManager()->setSelectedRoi( getFirstRoiInSelectedBranch() );
schurade's avatar
schurade committed
743
                break;
744
            case ROI:
745
                props = ( static_cast< WQtRoiTreeItem* >( m_roiTreeWidget->selectedItems().at( 0 ) ) )->getRoi()->getProperties();
746
                WKernel::getRunningKernel()->getRoiManager()->setSelectedRoi( getSelectedRoi() );
schurade's avatar
schurade committed
747 748 749 750
                break;
            default:
                break;
        }
751
    }
752 753 754 755 756 757 758

    if ( m_roiTreeWidget->selectedItems().size() == 1 && m_roiTreeWidget->selectedItems().at( 0 )->type() == ROI )
    {
        osg::ref_ptr< WROI > roi = ( static_cast< WQtRoiTreeItem* >( m_roiTreeWidget->selectedItems().at( 0 ) ) )->getRoi();
        roi->getProperties()->getProperty( "active" )->toPropBool()->set( m_roiTreeWidget->selectedItems().at( 0 )->checkState( 0 ) );
    }

759
    buildPropTab( props, boost::shared_ptr< WProperties >() );
760
}
761

762
void WQtControlPanel::selectDataModule( boost::shared_ptr< WDataSet > dataSet )
763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786
{
    m_moduleTreeWidget->clearSelection();

    QTreeWidgetItemIterator it( m_moduleTreeWidget );
    while( *it )
    {
        if( dynamic_cast< WQtDatasetTreeItem* >( *it ) )
        {
            boost::shared_ptr< WMData > dataModule;
            dataModule = boost::shared_dynamic_cast< WMData >( ( dynamic_cast< WQtDatasetTreeItem* >( *it ) )->getModule() );
            if( dataModule )
            {
                if( dataModule->getDataSet() == dataSet )
                {
                    ( *it )->setSelected( true );
                }
            }
        }
        ++it;
    }

    selectTreeItem();
}

787
WQtPropertyGroupWidget*  WQtControlPanel::buildPropWidget( boost::shared_ptr< WProperties > props )
788
{
789
    WQtPropertyGroupWidget* tab = new WQtPropertyGroupWidget( props->getName() );
790 791

    if ( props.get() )
792
    {
793 794
        // read lock, gets unlocked upon destruction (out of scope)
        WProperties::PropertySharedContainerType::ReadTicket propAccess = props->getProperties();
795

796 797
        tab->setName( QString::fromStdString( props->getName() ) );

798
        // iterate all properties.
799
        for ( WProperties::PropertyConstIterator iter = propAccess->get().begin(); iter != propAccess->get().end(); ++iter )
800
        {
801
            if ( !( *iter )->isHidden() )
802
            {
803
                switch ( ( *iter )->getType() )
804
                {
805
                    case PV_BOOL:
806
                        tab->addProp( ( *iter )->toPropBool() );
807 808
                        break;
                    case PV_INT:
809
                        tab->addProp( ( *iter )->toPropInt() );
810 811
                        break;
                    case PV_DOUBLE:
812
                        tab->addProp( ( *iter )->toPropDouble() );
813 814
                        break;
                    case PV_STRING:
815
                        tab->addProp( ( *iter )->toPropString() );
816 817
                        break;
                    case PV_PATH:
818
                        tab->addProp( ( *iter )->toPropFilename() );
819
                        break;
820