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

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

63
WQtControlPanel::WQtControlPanel( WMainWindow* parent )
64
    : QDockWidget( "Control Panel", parent ),
65
    m_ignoreSelectionChange( false )
66
{
67 68
    m_mainWindow = parent;

69
    m_panel = new QWidget( this );
70
    m_moduleTreeWidget = new WQtTreeWidget( m_panel );
71
    m_moduleTreeWidget->setContextMenuPolicy( Qt::ActionsContextMenu );
72

73 74
    m_moduleTreeWidget->setHeaderLabel( QString( "Module Tree" ) );
    m_moduleTreeWidget->setDragEnabled( false );
75 76
    m_moduleTreeWidget->viewport()->setAcceptDrops( true );
    m_moduleTreeWidget->setDropIndicatorShown( true );
77
    m_moduleTreeWidget->setMinimumHeight( 100 );
78

79
    // create context menu for tree items
80 81 82 83 84

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

86
    m_connectWithPrototypeAction = new QAction( "Connect with new module", m_moduleTreeWidget );
87
    m_moduleTreeWidget->addAction( m_connectWithPrototypeAction );
88
    m_connectWithModuleAction = new QAction( "Connect with module", m_moduleTreeWidget );
89 90 91 92
    m_moduleTreeWidget->addAction( m_connectWithModuleAction );
    m_disconnectAction = new QAction( "Disconnect", m_moduleTreeWidget );
    m_moduleTreeWidget->addAction( m_disconnectAction );

93 94 95 96
    // 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 );
97 98 99 100 101 102 103 104 105 106 107

    {
        // 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 ) ) );
    }
108 109 110
    connect( m_deleteModuleAction, SIGNAL( triggered() ), this, SLOT( deleteModuleTreeItem() ) );
    m_moduleTreeWidget->addAction( m_deleteModuleAction );

111
    m_textureSorter = new WQtTextureSorter( this );
112 113
    m_textureSorter->setToolTip( "Reorder the textures." );

114
    m_tabWidget = new QTabWidget( m_panel );
115
    m_tabWidget2 = new QTabWidget( m_panel );
116
    m_tabWidget->setMinimumHeight( 250 );
117

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

122
    m_splitter = new QSplitter( Qt::Vertical );
123

124 125
    if ( !combineThem )
    {
126
        m_splitter->addWidget( m_moduleTreeWidget );
127 128 129 130 131
    }
    else
    {
        m_tabWidget2->addTab( m_moduleTreeWidget, QString( "Modules" ) );
    }
132
    m_splitter->addWidget( m_tabWidget2 );
133

Alexander Wiebel's avatar
Alexander Wiebel committed
134
    m_tabWidget2->addTab( m_textureSorter, QString( "Texture Sorter" ) );
135 136

    m_roiTreeWidget = new WQtTreeWidget();
137 138
    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>." );
139 140 141 142 143 144
    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
145
    m_tabWidget2->addTab( m_roiTreeWidget, QString( "ROIs" ) );
146

147 148
    m_splitter->addWidget( m_tabWidget );

149 150 151 152 153 154 155 156 157
    // set the initial sizes.
    QList< int > splitterList;
    splitterList.push_back( 200 );
    if ( !combineThem )
    {
        splitterList.push_back( 200 );
    }
    splitterList.push_back( 400 );
    m_splitter->setSizes( splitterList );
158

159 160
    m_layout = new QVBoxLayout();
    m_layout->addWidget( m_splitter );
161 162 163 164 165 166

    m_panel->setLayout( m_layout );

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

168
    m_tiModules = new WQtModuleHeaderTreeItem( m_moduleTreeWidget );
169 170
    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." );
171
    m_tiRois = new WQtRoiHeaderTreeItem( m_roiTreeWidget );
Alexander Wiebel's avatar
Alexander Wiebel committed
172
    m_tiRois->setText( 0, QString( "ROIs" ) );
173

174
    connectSlots();
175

176 177 178 179 180 181 182 183 184 185 186
    {
        // 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() ) );
    }
187 188
}

189
WQtControlPanel::~WQtControlPanel()
190 191 192
{
}

193
void WQtControlPanel::connectSlots()
194
{
195
    connect( m_moduleTreeWidget, SIGNAL( itemSelectionChanged() ), this, SLOT( selectTreeItem() ) );
196
    connect( m_moduleTreeWidget, SIGNAL( itemClicked( QTreeWidgetItem*, int ) ), this, SLOT( changeTreeItem( QTreeWidgetItem*, int ) ) );
197 198 199
    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() ) );
200 201
    connect( m_textureSorter, SIGNAL( textureSelectionChanged( boost::shared_ptr< WDataSet > ) ),
             this, SLOT( selectDataModule( boost::shared_ptr< WDataSet > ) ) );
202
    connect( m_roiTreeWidget, SIGNAL( dragDrop() ), this, SLOT( handleDragDrop() ) );
203
}
204

205
void WQtControlPanel::addToolbar( QToolBar* tb )
206 207 208 209
{
    m_layout->insertWidget( 0, tb );
}

210
WQtSubjectTreeItem* WQtControlPanel::addSubject( std::string name )
211
{
212
    WQtSubjectTreeItem* subject = new WQtSubjectTreeItem( m_moduleTreeWidget );
213 214 215
    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 + "\"." ) );
216 217 218 219

    return subject;
}

220
bool WQtControlPanel::event( QEvent* event )
221
{
222
    // a subject signals a newly registered data set
223 224 225 226 227
    if ( event->type() == WQT_UPDATE_TEXTURE_SORTER_EVENT )
    {
        m_textureSorter->update();
    }

228 229 230 231 232 233
    if ( event->type() == WQT_ROI_ASSOC_EVENT )
    {
        WRoiAssocEvent* e2 = dynamic_cast< WRoiAssocEvent* >( event );     // NOLINT
        if ( e2 )
        {
            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 252 253 254
    // 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
255 256
        WModuleAssocEvent* e1 = dynamic_cast< WModuleAssocEvent* >( event );     // NOLINT
        if ( e1 )
257
        {
258 259
            WLogger::getLogger()->addLogMessage( "Inserting module " + e1->getModule()->getName() + " to control panel.",
                                                 "ControlPanel", LL_DEBUG );
260

schurade's avatar
schurade committed
261 262 263 264 265 266 267 268 269 270
            // 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() );
            }
271
        }
schurade's avatar
schurade committed
272 273
        return true;
    }
274

275
    // a module changed its state to "ready" -> activate it in control panel
276
    if ( event->type() == WQT_READY_EVENT )
schurade's avatar
schurade committed
277
    {
278 279 280
        // convert event to assoc event
        WModuleReadyEvent* e = dynamic_cast< WModuleReadyEvent* >( event );     // NOLINT
        if ( !e )
281
        {
282
            // this should never happen, since the type is set to WQT_READY_EVENT.
283
            WLogger::getLogger()->addLogMessage( "Event is not an WModueReadyEvent although its type claims it. Ignoring event.",
284
                                                 "ControlPanel", LL_WARNING );
285 286

            return true;
287 288
        }

289 290
        WLogger::getLogger()->addLogMessage( "Activating module " + e->getModule()->getName() + " in control panel.",
                                             "ControlPanel", LL_DEBUG );
291

292 293 294
        // 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 )
295
        {
296 297
            ( *iter )->setSelected( true );
            ( *iter )->setDisabled( false );
298 299
        }

300
        selectTreeItem();
301

302 303
        return true;
    }
304

305 306
    // a module tree item was connected to another one
    if ( event->type() == WQT_MODULE_CONNECT_EVENT )
307
    {
308 309
        WModuleConnectEvent* e = dynamic_cast< WModuleConnectEvent* >( event );     // NOLINT
        if ( !e )
310
        {
311
            // this should never happen, since the type is set to WQT_MODULE_CONNECT_EVENT.
312
            WLogger::getLogger()->addLogMessage( "Event is not an WModuleConnectEvent although its type claims it. Ignoring event.",
313
                                                 "ControlPanel", LL_WARNING );
314
            return true;
315 316
        }

317 318 319 320
        // 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();

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

323 324 325 326 327 328 329 330 331 332 333 334 335 336 337
        // 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 );
338 339 340 341 342 343
                if ( !( *parIter )->isHidden() )
                {
                    ( *parIter )->addChild( *iter );
                    ( *parIter )->setExpanded( true );
                    break;
                }
344 345 346 347 348
            }

            // job done.
            break;
        }
349 350 351 352 353 354 355 356
    }

    // 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 )
        {
357
            // this should never happen, since the type is set to WQT_MODULE_DISCONNECT_EVENT.
358
            WLogger::getLogger()->addLogMessage( "Event is not an WModuleDisconnectEvent although its type claims it. Ignoring event.",
359
                                                 "ControlPanel", LL_WARNING );
360 361 362
            return true;
        }

363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401
        // 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 );
        }
402
    }
403

404
    // a module tree item should be deleted
405
    if ( event->type() == WQT_MODULE_DELETE_EVENT )
406
    {
407
        WModuleDeleteEvent* e = dynamic_cast< WModuleDeleteEvent* >( event );
408 409
        if ( !e )
        {
410
            // this should never happen, since the type is set to WQT_MODULE_DELETE_EVENT.
411
            WLogger::getLogger()->addLogMessage( "Event is not an WModuleDeleteEvent although its type claims it. Ignoring event.",
412
                                                 "ControlPanel", LL_WARNING );
413 414 415 416 417
            return true;
        }

        // grab the module reference and print some info
        boost::shared_ptr< WModule > module = e->getTreeItem()->getModule();
418
        WLogger::getLogger()->addLogMessage( "Deleting module \"" + module->getName() + "\" from Tree.",
419
                                             "ControlPanel", LL_DEBUG );
420 421 422 423

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

424 425 426
        // ref count != 1? (only if there are now tree items left)
        bool lastTreeItem = !findItemsByModule( module ).size();
        if ( lastTreeItem && ( module.use_count() != 1 ) )
427
        {
428
            wlog::error( "ControlPanel" ) << "Removed module has strange usage count: " << module.use_count() << ". Should be 1 here. " <<
429
                                              "Module reference is held by someone else.";
430
            WAssert( false, "Removed module has strange usage count. Should be 1 here. Module reference is held by someone else." );
431 432 433 434 435
        }

        return true;
    }

436 437 438
    // a module was removed from the container
    if ( event->type() == WQT_MODULE_REMOVE_EVENT )
    {
439
        WModuleRemovedEvent* e = dynamic_cast< WModuleRemovedEvent* >( event );
440 441
        if ( !e )
        {
442
            // this should never happen, since the type is set to WQT_MODULE_REMOVE_EVENT.
443
            WLogger::getLogger()->addLogMessage( "Event is not an WModuleRemovedEvent although its type claims it. Ignoring event.",
444
                                                 "ControlPanel", LL_WARNING );
445 446 447 448
            return true;
        }

        // iterate tree items and find proper one
449 450
        std::list< WQtTreeItem* > items = findItemsByModule( e->getModule() );
        for ( std::list< WQtTreeItem* >::const_iterator iter = items.begin(); iter != items.end(); ++iter )
451
        {
452
            ( *iter )->gotRemoved();
453 454 455
        }

        // be nice and print some info
456
        WLogger::getLogger()->addLogMessage( "Removing module \"" + e->getModule()->getName() + "\" from Tree.", "ControlPanel", LL_DEBUG );
457 458 459 460

        // stop the module
        e->getModule()->requestStop();
        WLogger::getLogger()->addLogMessage( "Waiting for module \"" + e->getModule()->getName() + "\" to finish before deleting.",
461
                                             "ControlPanel", LL_DEBUG );
462 463 464 465

        return true;
    }

466 467
    return QDockWidget::event( event );
}
468

469
std::list< WQtTreeItem* > WQtControlPanel::findItemsByModule( boost::shared_ptr< WModule > module, QTreeWidgetItem* where )
470 471 472 473
{
    std::list< WQtTreeItem* > l;

    // iterate tree items and find proper one
474
    QTreeWidgetItemIterator it( where );
475
    while ( *it )
476
    {
477 478 479
        WQtTreeItem* item = dynamic_cast< WQtTreeItem* >( *it );
        boost::shared_ptr< WModule > itemModule = boost::shared_ptr< WModule >();
        if ( item )
480
        {
481
            itemModule = item->getModule();
482 483
        }

484 485
        // if the pointer is NULL the item was none of the above
        if ( !itemModule.get() )
486 487
        {
            ++it;
488
            continue;
489
        }
490

491 492 493 494 495 496 497
        // we found it
        if ( module == itemModule )
        {
            l.push_back( item );
        }

        ++it;
498
    }
499 500
    return l;
}
501

502
std::list< WQtTreeItem* > WQtControlPanel::findItemsByModule( boost::shared_ptr< WModule > module )
503
{
504 505 506 507
    std::list< WQtTreeItem* > ret = findItemsByModule( module, m_moduleTreeWidget->invisibleRootItem() );
    std::list< WQtTreeItem* > ret2 = findItemsByModule( module, m_moduleTreeWidget->topLevelItem( 0 ) );
    ret.merge( ret2 );
    return ret;
508
}
509

510
WQtDatasetTreeItem* WQtControlPanel::addDataset( boost::shared_ptr< WModule > module, int subjectId )
511
{
schurade's avatar
schurade committed
512
    int c = getFirstSubject();
513
    WQtSubjectTreeItem* subject = static_cast< WQtSubjectTreeItem* >( m_moduleTreeWidget->topLevelItem( subjectId + c ) );
schurade's avatar
schurade committed
514
    subject->setExpanded( true );
515
    WQtDatasetTreeItem* item = subject->addDatasetItem( module );
516
    m_moduleTreeWidget->setCurrentItem( item );
517
    item->setDisabled( true );
518
    item->setExpanded( true );
519

520
    return item;
521
}
522

523
WQtModuleTreeItem* WQtControlPanel::addModule( boost::shared_ptr< WModule > module )
524
{
schurade's avatar
schurade committed
525
    m_tiModules->setExpanded( true );
526
    WQtModuleTreeItem* item;
527 528 529 530 531
    // 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 )
532
    {
533 534 535 536 537 538 539 540 541 542 543 544
        // 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;
545
    }
546 547 548

    // this module has not inputs. So we simply add it to the tiModules
    if ( firstItem )
549 550
    {
        item = m_tiModules->addModuleItem( module );
551
        item->setDisabled( true );
552
    }
553

554
    return item;
555 556
}

557
void WQtControlPanel::addRoi( osg::ref_ptr< WROI > roi )
schurade's avatar
schurade committed
558
{
559 560 561 562
    WQtRoiTreeItem* newItem;
    WQtBranchTreeItem* branchItem;

    m_tiRois->setExpanded( true );
563
    bool found = false;
564

565 566
    // go through all branches
    for( int branchID = 0; branchID < m_tiRois->childCount(); ++branchID )
schurade's avatar
schurade committed
567
    {
568 569
        branchItem = dynamic_cast< WQtBranchTreeItem* >( m_tiRois->child( branchID ) );
        // if branch == roi branch
570
        if ( branchItem->getBranch() == WKernel::getRunningKernel()->getRoiManager()->getBranch( roi ) )
schurade's avatar
schurade committed
571
        {
572 573
            found = true;
            break;
schurade's avatar
schurade committed
574 575
        }
    }
576 577

    if ( !found )
schurade's avatar
schurade committed
578
    {
579
        branchItem = m_tiRois->addBranch( WKernel::getRunningKernel()->getRoiManager()->getBranch( roi ) );
schurade's avatar
schurade committed
580
    }
581 582 583 584 585 586

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

590
void WQtControlPanel::removeRoi( osg::ref_ptr< WROI > roi )
591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610
{
    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;
            }
        }
    }
611
    WKernel::getRunningKernel()->getRoiManager()->setSelectedRoi( getSelectedRoi() );
612 613
}

614
boost::shared_ptr< WModule > WQtControlPanel::getSelectedModule()
615
{
616
    if ( m_moduleTreeWidget->selectedItems().at( 0 )->type() == 1 )
617
    {
618
        return ( static_cast< WQtDatasetTreeItem* >( m_moduleTreeWidget->selectedItems().at( 0 ) )->getModule() );
619
    }
620
    else if ( m_moduleTreeWidget->selectedItems().at( 0 )->type() == 3 )
621
    {
622
        return ( static_cast< WQtModuleTreeItem* >( m_moduleTreeWidget->selectedItems().at( 0 ) )->getModule() );
623 624 625 626
    }

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

628
void WQtControlPanel::selectTreeItem()
629
{
630 631 632 633 634
    if ( m_ignoreSelectionChange )
    {
        return;
    }

635
    boost::shared_ptr< WModule > module;
636
    boost::shared_ptr< WProperties > props;
637
    boost::shared_ptr< WProperties > infoProps;
Sebastian Eichelbaum's avatar
[MERGE]  
Sebastian Eichelbaum committed
638

639
    if ( m_moduleTreeWidget->selectedItems().size() != 0  )
640
    {
641 642 643
        // TODO(schurade): qt doc says clear() doesn't delete tabs so this is possibly a memory leak
        m_tabWidget->clear();

644 645 646 647 648 649 650 651 652 653
        // 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 );
        }

654
        switch ( m_moduleTreeWidget->selectedItems().at( 0 )->type() )
schurade's avatar
schurade committed
655
        {
656
            case SUBJECT:
657
            case MODULEHEADER:
658 659
                // deletion of headers and subjects is not allowed
                m_deleteModuleAction->setEnabled( false );
660
                createCompatibleButtons( module );  // module is NULL at this point
schurade's avatar
schurade committed
661
                break;
662
            case DATASET:
663
                module = ( static_cast< WQtDatasetTreeItem* >( m_moduleTreeWidget->selectedItems().at( 0 ) ) )->getModule();
664
                // crashed modules should not provide any props
665 666 667 668
                if ( module->isCrashed()() )
                {
                    return;
                }
669

670
                props = module->getProperties();
671
                infoProps = module->getInformationProperties();
672
                createCompatibleButtons( module );
673 674 675 676

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

677
                    // if the selected module contains a texture, select the corresponding texture in the texture sorter.
678 679 680 681
                    if( dataModule )
                    {
                        if( dataModule->getDataSet() )
                        {
682
                            m_textureSorter->selectTexture( dataModule->getDataSet() );
683 684 685 686
                        }
                    }
                }

schurade's avatar
schurade committed
687
                break;
688
            case MODULE:
689
                {
690
                    module = ( static_cast< WQtModuleTreeItem* >( m_moduleTreeWidget->selectedItems().at( 0 ) ) )->getModule();
691
                    m_deleteModuleAction->setEnabled( true );
692

693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710
                    // 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();
711
                    createCompatibleButtons( module );
712
                }
713
                break;
714 715 716 717 718 719 720 721
            case ROIHEADER:
            case ROIBRANCH:
            case ROI:
                break;
            default:
                break;
        }
    }
722 723


724
    buildPropTab( props, infoProps );
725 726
}

727
void WQtControlPanel::selectRoiTreeItem()
728 729 730
{
    // TODO(schurade): qt doc says clear() doesn't delete tabs so this is possibly a memory leak
    m_tabWidget->clear();
731 732 733 734 735 736 737 738 739

    // Make compatibles toolbar empty
    {
        if( m_mainWindow->getCompatiblesToolbar() != 0 )
        {
            m_mainWindow->getCompatiblesToolbar()->makeEmpty();
        }
        else
        {
740
            m_mainWindow->setCompatiblesToolbar( new WQtCombinerToolbar( m_mainWindow ) );
741 742
        }
    }
743 744

    boost::shared_ptr< WModule > module;
745
    boost::shared_ptr< WProperties > props;
746 747 748 749 750 751 752 753 754

    if ( m_roiTreeWidget->selectedItems().size() != 0  )
    {
        switch ( m_roiTreeWidget->selectedItems().at( 0 )->type() )
        {
            case SUBJECT:
            case DATASET:
            case MODULEHEADER:
            case MODULE:
755
            case ROIHEADER:
756
                WKernel::getRunningKernel()->getRoiManager()->setSelectedRoi( getSelectedRoi() );
schurade's avatar
schurade committed
757
                break;
schurade's avatar
schurade committed
758
            case ROIBRANCH:
759
                props = ( static_cast< WQtBranchTreeItem* >( m_roiTreeWidget->selectedItems().at( 0 ) ) )->getBranch()->getProperties();
760
                WKernel::getRunningKernel()->getRoiManager()->setSelectedRoi( getFirstRoiInSelectedBranch() );
schurade's avatar
schurade committed
761
                break;
762
            case ROI:
763
                props = ( static_cast< WQtRoiTreeItem* >( m_roiTreeWidget->selectedItems().at( 0 ) ) )->getRoi()->getProperties();
764
                WKernel::getRunningKernel()->getRoiManager()->setSelectedRoi( getSelectedRoi() );
schurade's avatar
schurade committed
765 766 767 768
                break;
            default:
                break;
        }
769
    }
770 771 772 773 774 775 776

    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 ) );
    }

777
    buildPropTab( props, boost::shared_ptr< WProperties >() );
778
}
779

780
void WQtControlPanel::selectDataModule( boost::shared_ptr< WDataSet > dataSet )
781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804
{
    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();
}

Robert Frohl's avatar
Robert Frohl committed
805 806
void WQtControlPanel::setNewActiveModule( boost::shared_ptr< WModule > module )
{
807
    m_tabWidget->clear();
808 809 810 811

    // NOTE: this handles null pointers properly.
    createCompatibleButtons( module );

812 813
    if ( module )
    {
814
        createCompatibleButtons( module );
815 816
        buildPropTab( module->getProperties(), module->getInformationProperties() );
    }
Robert Frohl's avatar
Robert Frohl committed
817 818
}

819
WQtPropertyGroupWidget*  WQtControlPanel::buildPropWidget( boost::shared_ptr< WProperties > props )
820
{
821
    WQtPropertyGroupWidget* tab = new WQtPropertyGroupWidget( props );
822
    if ( props.get() )
823
    {
824 825
        // read lock, gets unlocked upon destruction (out of scope)
        WProperties::PropertySharedContainerType::ReadTicket propAccess = props->getProperties();
826

827 828
        tab->setName( QString::fromStdString( props->getName() ) );

829
        // iterate all properties.
830
        for ( WProperties::PropertyConstIterator iter = propAccess->get().begin(); iter != propAccess->get().end(); ++iter )
831
        {
832
            switch ( ( *iter )->getType() )
833
            {
834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869
                case PV_BOOL:
                    tab->addProp( ( *iter )->toPropBool() );
                    break;
                case PV_INT:
                    tab->addProp( ( *iter )->toPropInt() );
                    break;
                case PV_DOUBLE:
                    tab->addProp( ( *iter )->toPropDouble() );
                    break;
                case PV_STRING:
                    tab->addProp( ( *iter )->toPropString() );
                    break;
                case PV_PATH:
                    tab->addProp( ( *iter )->toPropFilename() );
                    break;
                case PV_SELECTION:
                    tab->addProp( ( *iter )->toPropSelection() );
                    break;
                case PV_COLOR:
                    tab->addProp( ( *iter )->toPropColor() );
                    break;
                case PV_POSITION:
                    tab->addProp( ( *iter )->toPropPosition() );
                    break;
                case PV_TRIGGER:
                    tab->addProp( ( *iter )->toPropTrigger() );
                    break;
                case PV_GROUP:
                    tab->addGroup( buildPropWidget( ( *iter )->toPropGroup() ) );
                    break;
                case PV_MATRIX4X4:
                    tab->addProp( ( *iter )->toPropMatrix4X4() );
                    break;
                default:
                    WLogger::getLogger()->addLogMessage( "This property type is not yet supported.", "ControlPanel", LL_WARNING );
                    break;
870 871 872
            }
        }
    }
873

874
    tab->addSpacer();
875 876 877
    return tab;
}

878
void WQtControlPanel::buildPropTab( boost::shared_ptr< WProperties > props, boost::shared_ptr< WProperties > infoProps )
879
{
880 881
    WQtPropertyGroupWidget* tab = NULL;
    WQtPropertyGroupWidget* infoTab = NULL;
882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900