WMainWindow.cpp 36.9 KB
Newer Older
1 2
//---------------------------------------------------------------------------
//
3
// Project: OpenWalnut ( http://www.openwalnut.org )
4
//
5 6
// Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
// For more information see http://www.openwalnut.org/copying
wiebel's avatar
wiebel committed
7
//
wiebel's avatar
wiebel committed
8
// This file is part of OpenWalnut.
wiebel's avatar
wiebel committed
9
//
wiebel's avatar
wiebel committed
10
// OpenWalnut is free software: you can redistribute it and/or modify
wiebel's avatar
wiebel committed
11 12 13 14
// 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.
//
wiebel's avatar
wiebel committed
15
// OpenWalnut is distributed in the hope that it will be useful,
wiebel's avatar
wiebel committed
16 17 18 19 20
// 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
wiebel's avatar
wiebel committed
21
// along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
wiebel's avatar
wiebel committed
22
//
23 24
//---------------------------------------------------------------------------

25
#include <iostream>
Mathias Goldau's avatar
Mathias Goldau committed
26
#include <map>
27 28
#include <string>
#include <vector>
29

30 31
#include <boost/thread.hpp>

32
#include <QtGui/QApplication>
wiebel's avatar
wiebel committed
33
#include <QtGui/QDockWidget>
34
#include <QtGui/QFileDialog>
Mathias Goldau's avatar
Mathias Goldau committed
35 36 37
#include <QtGui/QMainWindow>
#include <QtGui/QMenu>
#include <QtGui/QMenuBar>
38
#include <QtGui/QMessageBox>
39
#include <QtGui/QShortcut>
Mathias Goldau's avatar
Mathias Goldau committed
40
#include <QtGui/QSlider>
41 42
#include <QtGui/QVBoxLayout>

43 44
#include "../../common/WColor.h"
#include "../../common/WPreferences.h"
Mathias Goldau's avatar
Mathias Goldau committed
45 46 47 48
#include "../../dataHandler/WDataSetFibers.h"
#include "../../dataHandler/WDataSetSingle.h"
#include "../../dataHandler/WEEG2.h"
#include "../../graphicsEngine/WROIBox.h"
schurade's avatar
schurade committed
49
#include "../../graphicsEngine/WGEZoomTrackballManipulator.h"
50
#include "../../kernel/WKernel.h"
51 52 53
#include "../../kernel/WModule.h"
#include "../../kernel/WModuleCombiner.h"
#include "../../kernel/WModuleCombinerTypes.h"
54
#include "../../kernel/WProjectFile.h"
55 56
#include "../../kernel/modules/data/WMData.h"
#include "../../kernel/modules/navSlices/WMNavSlices.h"
57
#include "../icons/WIcons.h"
Mathias Goldau's avatar
Mathias Goldau committed
58 59 60 61
#include "datasetbrowser/WPropertyBoolWidget.h"
#include "events/WEventTypes.h"
#include "events/WModuleCrashEvent.h"
#include "events/WModuleReadyEvent.h"
62
#include "events/WOpenCustomDockWidgetEvent.h"
Sebastian Eichelbaum's avatar
[MERGE]  
Sebastian Eichelbaum committed
63
#include "guiElements/WQtPropertyBoolAction.h"
Mathias Goldau's avatar
Mathias Goldau committed
64 65 66 67 68
#include "WQtCustomDockWidget.h"
#include "WQtGLWidget.h"
#include "WQtNavGLWidget.h"

#include "WMainWindow.h"
69

70
WMainWindow::WMainWindow() :
71
    QMainWindow(),
72
    m_currentCompatiblesToolbar( NULL ),
73 74
    m_iconManager(),
    m_fibLoaded( false )
Sebastian Eichelbaum's avatar
Sebastian Eichelbaum committed
75 76
{
}
77

78
void WMainWindow::setupGUI()
79
{
80
    m_iconManager.addIcon( std::string( "load" ), fileopen_xpm );
81
    m_iconManager.addIcon( std::string( "loadProject" ), projOpen_xpm );
82
    m_iconManager.addIcon( std::string( "saveProject" ), projSave_xpm );
83
    m_iconManager.addIcon( std::string( "logo" ), logoIcon_xpm );
84
    m_iconManager.addIcon( std::string( "help" ), question_xpm );
85
    m_iconManager.addIcon( std::string( "quit" ), quit_xpm );
86 87 88
    m_iconManager.addIcon( std::string( "moduleBusy" ), moduleBusy_xpm );
    m_iconManager.addIcon( std::string( "moduleCrashed" ), moduleCrashed_xpm );
    m_iconManager.addIcon( std::string( "remove" ), remove_xpm );
89
    m_iconManager.addIcon( std::string( "config" ), preferences_system_xpm );
90

91

92
    if( objectName().isEmpty() )
93
    {
94
        setObjectName( QString::fromUtf8( "MainWindow" ) );
95
    }
96
    // TODO(all): what is this?
97 98
    resize( 946, 632 );
    setWindowIcon( m_iconManager.getIcon( "logo" ) );
99
    setWindowTitle( QApplication::translate( "MainWindow", "OpenWalnut 1.1", 0, QApplication::UnicodeUTF8 ) );
100

101 102
    setupPermanentToolBar();

103 104 105 106 107 108
    // the dataset browser instance is needed for the menu
    m_datasetBrowser = new WQtDatasetBrowser( this );
    m_datasetBrowser->setFeatures( QDockWidget::AllDockWidgetFeatures );
    addDockWidget( Qt::RightDockWidgetArea, m_datasetBrowser );
    m_datasetBrowser->addSubject( "Default Subject" );

109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
    // set the size of the dsb according to config file
    int dsbWidth = 250;
    if ( WPreferences::getPreference( "qt4gui.dsbWidth", &dsbWidth ) )
    {
        m_datasetBrowser->setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred ) );
        m_datasetBrowser->setMinimumWidth( dsbWidth );
    }

    // hide the DSB by default?
    bool dsbInvisibleByDefault = false;
    if ( WPreferences::getPreference( "qt4gui.dsbInvisibleByDefault", &dsbInvisibleByDefault ) )
    {
        m_datasetBrowser->setVisible( !dsbInvisibleByDefault );
    }

    // undock the DSB by default?
    bool dsbFloatingByDefault = false;
    if ( WPreferences::getPreference( "qt4gui.dsbFloatingByDefault", &dsbFloatingByDefault ) )
    {
        m_datasetBrowser->setFloating( dsbFloatingByDefault );
    }

Sebastian Eichelbaum's avatar
Sebastian Eichelbaum committed
131 132 133 134
    // NOTE: Please be aware that not every menu needs a shortcut key. If you add a shortcut, you should use one of the
    // QKeySequence::StandardKey defaults and avoid ambiguities like Ctrl-C for the configure dialog is not the best choice as Ctrl-C, for the
    // most users is the Copy shortcut.

135
    m_menuBar = new QMenuBar( this );
136 137 138 139 140 141

    // hide menu?
    bool hideMenu = false;
    WPreferences::getPreference( "qt4gui.hideMenuBar", &hideMenu );
    m_menuBar->setVisible( !hideMenu );

142
    QMenu* fileMenu = m_menuBar->addMenu( "File" );
143

Sebastian Eichelbaum's avatar
Sebastian Eichelbaum committed
144 145
    fileMenu->addAction( m_iconManager.getIcon( "load" ), "Load Dataset", this, SLOT( openLoadDialog() ), QKeySequence(  QKeySequence::Open ) );
    fileMenu->addSeparator();
146
    fileMenu->addAction( m_iconManager.getIcon( "loadProject" ), "Load Project", this, SLOT( projectLoad() ) );
147 148
    QMenu* saveMenu = fileMenu->addMenu( m_iconManager.getIcon( "saveProject" ), "Save Project" );
    saveMenu->addAction( "Save Project", this, SLOT( projectSaveAll() ), QKeySequence::Save );
Sebastian Eichelbaum's avatar
Sebastian Eichelbaum committed
149 150 151 152
    saveMenu->addAction( "Save Modules Only", this, SLOT( projectSaveModuleOnly() ) );
    saveMenu->addAction( "Save Camera Only", this, SLOT( projectSaveCameraOnly() ) );
    saveMenu->addAction( "Save ROIs Only", this, SLOT( projectSaveROIOnly() ) );
    fileMenu->addSeparator();
153
    fileMenu->addAction( m_iconManager.getIcon( "config" ), "Config", this, SLOT( openConfigDialog() ) );
Sebastian Eichelbaum's avatar
Sebastian Eichelbaum committed
154
    fileMenu->addSeparator();
155 156 157
    // TODO(all): If all distributions provide a newer QT version we should use QKeySequence::Quit here
    //fileMenu->addAction( m_iconManager.getIcon( "quit" ), "Quit", this, SLOT( close() ), QKeySequence( QKeySequence::Quit ) );
    fileMenu->addAction( m_iconManager.getIcon( "quit" ), "Quit", this, SLOT( close() ),  QKeySequence( Qt::CTRL + Qt::Key_Q ) );
Sebastian Eichelbaum's avatar
Sebastian Eichelbaum committed
158

Sebastian Eichelbaum's avatar
Sebastian Eichelbaum committed
159
    // This QAction stuff is quite ugly and complicated some times ... There is no nice constructor which takes name, slot keysequence and so on
160 161
    // directly -> set shortcuts, and some further properties using QAction's interface
    QMenu* viewMenu = m_menuBar->addMenu( "View" );
162 163

    QAction* dsbTrigger = m_datasetBrowser->toggleViewAction();
164 165 166 167 168
    QList< QKeySequence > dsbShortcut;
    dsbShortcut.append( QKeySequence( Qt::Key_F9 ) );
    dsbTrigger->setShortcuts( dsbShortcut );
    viewMenu->addAction( dsbTrigger );
    viewMenu->addSeparator();
169
    this->addAction( dsbTrigger );  // this enables the action even if the menu bar is invisible
170

Sebastian Eichelbaum's avatar
Sebastian Eichelbaum committed
171 172 173
    // NOTE: the shortcuts for these view presets should be chosen carefully. Most keysequences have another meaning in the most applications
    // so the user may get confused. It is also not a good idea to take letters as they might be used by OpenSceneGraph widget ( like "S" for
    // statistics ).
174 175 176 177 178 179
    viewMenu->addAction( "Left", this, SLOT( setPresetViewLeft() ),           QKeySequence( Qt::CTRL + Qt::SHIFT + Qt::Key_L ) );
    viewMenu->addAction( "Right", this, SLOT( setPresetViewRight() ),         QKeySequence( Qt::CTRL + Qt::SHIFT + Qt::Key_R ) );
    viewMenu->addAction( "Superior", this, SLOT( setPresetViewSuperior() ),   QKeySequence( Qt::CTRL + Qt::SHIFT + Qt::Key_S ) );
    viewMenu->addAction( "Inferior", this, SLOT( setPresetViewInferior() ),   QKeySequence( Qt::CTRL + Qt::SHIFT + Qt::Key_I ) );
    viewMenu->addAction( "Anterior", this, SLOT( setPresetViewAnterior() ),   QKeySequence( Qt::CTRL + Qt::SHIFT + Qt::Key_A ) );
    viewMenu->addAction( "Posterior", this, SLOT( setPresetViewPosterior() ), QKeySequence( Qt::CTRL + Qt::SHIFT + Qt::Key_P ) );
180

181
    QMenu* helpMenu = m_menuBar->addMenu( "Help" );
Sebastian Eichelbaum's avatar
Sebastian Eichelbaum committed
182 183 184
    helpMenu->addAction( m_iconManager.getIcon( "help" ), "About OpenWalnut", this, SLOT( openAboutDialog() ),
                         QKeySequence( QKeySequence::HelpContents )
    );
185

186 187
    setMenuBar( m_menuBar );

188
    m_mainGLWidget = boost::shared_ptr< WQtGLWidget >( new WQtGLWidget( "main", this, WGECamera::ORTHOGRAPHIC ) );
189
    setCentralWidget( m_mainGLWidget.get() );
wiebel's avatar
wiebel committed
190

191 192 193 194 195
    // initially 3 navigation views
    {
        bool hideWidget;
        if( !( WPreferences::getPreference( "qt4gui.hideAxial", &hideWidget ) && hideWidget) )
        {
196
            m_navAxial = boost::shared_ptr< WQtNavGLWidget >( new WQtNavGLWidget( "Axial View", this, "Axial Slice" ) );
197
            m_navAxial->setFeatures( QDockWidget::AllDockWidgetFeatures );
198 199 200 201
            addDockWidget( Qt::LeftDockWidgetArea, m_navAxial.get() );
        }
        if( !( WPreferences::getPreference( "qt4gui.hideCoronal", &hideWidget ) && hideWidget) )
        {
202
            m_navCoronal = boost::shared_ptr< WQtNavGLWidget >( new WQtNavGLWidget( "Coronal View", this, "Coronal Slice" ) );
203
            m_navCoronal->setFeatures( QDockWidget::AllDockWidgetFeatures );
204 205 206 207
            addDockWidget( Qt::LeftDockWidgetArea, m_navCoronal.get() );
        }
        if( !( WPreferences::getPreference( "qt4gui.hideSagittal", &hideWidget ) && hideWidget) )
        {
208
            m_navSagittal = boost::shared_ptr< WQtNavGLWidget >( new WQtNavGLWidget( "Sagittal View", this, "Sagittal Slice" ) );
209
            m_navSagittal->setFeatures( QDockWidget::AllDockWidgetFeatures );
210 211 212
            addDockWidget( Qt::LeftDockWidgetArea, m_navSagittal.get() );
        }
    }
213

Mathias Goldau's avatar
[MERGE]  
Mathias Goldau committed
214 215 216 217 218 219 220 221 222
    // we do not need the dummy widget if there are no other widgets.
    if( m_navAxial || m_navCoronal || m_navSagittal )
    {
        m_dummyWidget = new QDockWidget( this );
        m_dummyWidget->setFeatures( QDockWidget::NoDockWidgetFeatures );
        m_dummyWidget->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Ignored );
        addDockWidget( Qt::LeftDockWidgetArea, m_dummyWidget );
    }

223
    // Default background color from config file
224
    {
225 226 227 228 229 230 231 232 233 234
        WColor bgColor;
        double r;
        double g;
        double b;
        if( WPreferences::getPreference( "ge.bgColor.r", &r )
            && WPreferences::getPreference( "ge.bgColor.g", &g )
            && WPreferences::getPreference( "ge.bgColor.b", &b ) )
        {
            bgColor.setRGB( r, g, b );
            m_mainGLWidget->setBgColor( bgColor );
235 236 237 238 239 240 241 242 243 244 245 246 247

            if ( m_navAxial )
            {
                m_navAxial->getGLWidget()->setBgColor( bgColor );
            }
            if ( m_navCoronal )
            {
                m_navCoronal->getGLWidget()->setBgColor( bgColor );
            }
            if ( m_navSagittal )
            {
                m_navSagittal->getGLWidget()->setBgColor( bgColor );
            }
248
        }
249
    }
250
}
251

252
void WMainWindow::setupPermanentToolBar()
253
{
254
    m_permanentToolBar = new WQtToolBar( "Permanent Toolbar", this );
255

256 257 258 259
    // Set the style of the toolbar
    // NOTE: this only works if the toolbar is used with QActions instead of buttons and other widgets
    m_permanentToolBar->setToolButtonStyle( getToolbarStyle() );

260 261 262 263
    m_iconManager.addIcon( std::string( "ROI icon" ), box_xpm );
    m_iconManager.addIcon( std::string( "axial icon" ), axial_xpm );
    m_iconManager.addIcon( std::string( "coronal icon" ), cor_xpm );
    m_iconManager.addIcon( std::string( "sagittal icon" ), sag_xpm );
264

265
    // TODO(all): this should be QActions to allow the toolbar style to work properly
266
    m_loadButton = new WQtPushButton( m_iconManager.getIcon( "load" ), "load", m_permanentToolBar );
267
    WQtPushButton* roiButton = new WQtPushButton( m_iconManager.getIcon( "ROI icon" ), "ROI", m_permanentToolBar );
268 269
    WQtPushButton* projectLoadButton = new WQtPushButton( m_iconManager.getIcon( "loadProject" ), "loadProject", m_permanentToolBar );
    WQtPushButton* projectSaveButton = new WQtPushButton( m_iconManager.getIcon( "saveProject" ), "saveProject", m_permanentToolBar );
270

271 272 273
    // setup save button
    QMenu* saveMenu = new QMenu( "Save Project", projectSaveButton );
    saveMenu->addAction( "Save Project", this, SLOT( projectSaveAll() ) );
274
    saveMenu->addAction( "Save Modules", this, SLOT( projectSaveModuleOnly() ) );
275 276 277 278 279
    saveMenu->addAction( "Save Camera", this, SLOT( projectSaveCameraOnly() ) );
    saveMenu->addAction( "Save ROIs", this, SLOT( projectSaveROIOnly() ) );
    projectSaveButton->setPopupMode( QToolButton::MenuButtonPopup );
    projectSaveButton->setMenu( saveMenu );

280
    connect( m_loadButton, SIGNAL( pressed() ), this, SLOT( openLoadDialog() ) );
281
    connect( roiButton, SIGNAL( pressed() ), this, SLOT( newRoi() ) );
282
    connect( projectLoadButton, SIGNAL( pressed() ), this, SLOT( projectLoad() ) );
283
    connect( projectSaveButton, SIGNAL( pressed() ), this, SLOT( projectSaveAll() ) );
284

285
    m_loadButton->setToolTip( "Load Data" );
286
    roiButton->setToolTip( "Create New ROI" );
287 288
    projectLoadButton->setToolTip( "Load a project from file" );
    projectSaveButton->setToolTip( "Save current project to file" );
289

290
    m_permanentToolBar->addWidget( m_loadButton );
291
    m_permanentToolBar->addSeparator();
292 293
    m_permanentToolBar->addWidget( projectLoadButton );
    m_permanentToolBar->addWidget( projectSaveButton );
294
    m_permanentToolBar->addSeparator();
295 296
    m_permanentToolBar->addWidget( roiButton );
    m_permanentToolBar->addSeparator();
297

298 299 300 301 302 303 304 305 306 307 308 309 310 311
    if ( getToolbarPos() == InDSB )
    {
        m_datasetBrowser->addToolbar( m_permanentToolBar );
        //m_datasetBrowser->setTitleBarWidget( m_permanentToolBar );
    }
    else if ( getToolbarPos() == Hide )
    {
        m_permanentToolBar->setVisible( false );
        addToolBar( Qt::TopToolBarArea, m_permanentToolBar );
    }
    else
    {
        addToolBar( toQtToolBarArea( getToolbarPos() ), m_permanentToolBar );
    }
312
}
313

314 315 316 317 318 319 320 321 322 323
void WMainWindow::autoAdd( boost::shared_ptr< WModule > module, std::string proto )
{
    // get the prototype.
    if ( !WKernel::getRunningKernel()->getRootContainer()->applyModule( module, proto, true ) )
    {
        WLogger::getLogger()->addLogMessage( "Auto Display active but module " + proto + " could not be added.",
                                             "GUI", LL_ERROR );
    }
}

324 325
void WMainWindow::moduleSpecificSetup( boost::shared_ptr< WModule > module )
{
326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341
    // Add all special handlings here. This method is called whenever a module is marked "ready". You can set up the gui for special modules,
    // load certain modules for datasets and so on.

    // The Data Modules also play an special role. To have modules being activated when certain data got loaded, we need to hook it up here.
    bool useAutoDisplay = true;
    WPreferences::getPreference( "qt4gui.useAutoDisplay", &useAutoDisplay );
    if ( useAutoDisplay && module->getType() == MODULE_DATA )
    {
        WLogger::getLogger()->addLogMessage( "Auto Display active and Data module added. The proper module will be added.",
                                             "GUI", LL_DEBUG );

        // data modules contain an member denoting the real data type. Currently we only have one data module and a not very modulated data
        // structures.
        boost::shared_ptr< WMData > dataModule = boost::shared_static_cast< WMData >( module );

        // grab data and identify type
342
        if ( dataModule->getDataSet()->isA< WDataSetSingle >() && dataModule->getDataSet()->isTexture() )
343 344 345 346
        {
            // it is a dataset single
            // load a nav slice module if a WDataSetSingle is available!?

347
            // if it not already is running: add it
348 349
            if ( !WMNavSlices::isRunning() )
            {
350
                autoAdd( module, "Navigation Slices" );
351
            }
352 353 354 355
        }
        else if ( dataModule->getDataSet()->isA< WDataSetFibers >() )
        {
            // it is a fiber dataset -> add the FiberDisplay module
356 357 358 359 360 361

            // if it not already is running: add it
            if ( !WMFiberDisplay::isRunning() )
            {
                autoAdd( module, "Fiber Display" );
            }
362
        }
363
        else if ( dataModule->getDataSet()->isA< WEEG2 >() )
364
        {
365
            // it is a eeg dataset -> add the eegView module
366 367 368 369
            autoAdd( module, "EEG View" );
        }
    }

370
    // nav slices use separate buttons for slice on/off switching
371
    if ( module->getName() == "Navigation Slices" )
372
    {
373
        boost::shared_ptr< WPropertyBase > prop = module->getProperties()->findProperty( "showAxial" );
374 375 376
        if ( !prop )
        {
               WLogger::getLogger()->
377
                   addLogMessage( "Navigation Slices module does not provide the property \"showAxial\", which is required by the GUI.", "GUI",
378 379 380 381
                                  LL_ERROR );
        }
        else
        {
382 383 384
            WQtPropertyBoolAction* a = new WQtPropertyBoolAction( prop->toPropBool(), m_permanentToolBar );
            a->setToolTip( "Toggle Axial Slice" );
            a->setText( "Toggle Axial Slice" );
385
            a->setIcon( m_iconManager.getIcon( "axial icon" ) );
386
            m_permanentToolBar->addAction( a );
387
        }
388

389
        prop = module->getProperties()->findProperty( "showCoronal" );
390 391 392
        if ( !prop )
        {
               WLogger::getLogger()->
393
                   addLogMessage( "Navigation Slices module does not provide the property \"showCoronal\", which is required by the GUI.", "GUI",
394 395 396 397
                                  LL_ERROR );
        }
        else
        {
398 399 400
            WQtPropertyBoolAction* a = new WQtPropertyBoolAction( prop->toPropBool(), m_permanentToolBar );
            a->setToolTip( "Toggle Coronal Slice" );
            a->setText( "Toggle Coronal Slice" );
401
            a->setIcon( m_iconManager.getIcon( "coronal icon" ) );
402
            m_permanentToolBar->addAction( a );
403
        }
404

405
        prop = module->getProperties()->findProperty( "showSagittal" );
406 407 408
        if ( !prop )
        {
               WLogger::getLogger()->
409
                   addLogMessage( "Navigation Slices module does not provide the property \"showSagittal\", which is required by the GUI.", "GUI",
410 411 412 413
                                  LL_ERROR );
        }
        else
        {
414 415 416
            WQtPropertyBoolAction* a = new WQtPropertyBoolAction( prop->toPropBool(), m_permanentToolBar );
            a->setToolTip( "Toggle Saggital Slice" );
            a->setText( "Toggle Saggital Slice" );
417
            a->setIcon( m_iconManager.getIcon( "sagittal icon" ) );
418
            m_permanentToolBar->addAction( a );
419
        }
420 421

        // now setup the nav widget sliders
422
        prop = module->getProperties()->findProperty( "Axial Slice" );
423 424 425
        if ( !prop )
        {
               WLogger::getLogger()->
426
                   addLogMessage( "Navigation Slices module does not provide the property \"Axial Slice\", which is required by the GUI.", "GUI",
427 428 429 430
                                  LL_ERROR );
        }
        else
        {
431 432 433 434
            if( m_navAxial )
            {
                m_navAxial->setSliderProperty( prop->toPropInt() );
            }
435 436
        }

437
        prop = module->getProperties()->findProperty( "Coronal Slice" );
438 439 440
        if ( !prop )
        {
               WLogger::getLogger()->
441
                   addLogMessage( "Navigation Slices module does not provide the property \"Coronal Slice\", which is required by the GUI.", "GUI",
442 443 444 445
                                  LL_ERROR );
        }
        else
        {
446 447 448 449
            if( m_navCoronal )
            {
                m_navCoronal->setSliderProperty( prop->toPropInt() );
            }
450 451
        }

452
        prop = module->getProperties()->findProperty( "Sagittal Slice" );
453 454 455
        if ( !prop )
        {
               WLogger::getLogger()->
456
                   addLogMessage( "Navigation Slices module does not provide the property \"Sagittal Slice\", which is required by the GUI.", "GUI",
457 458 459 460
                                  LL_ERROR );
        }
        else
        {
461 462 463 464
            if( m_navSagittal )
            {
               m_navSagittal->setSliderProperty( prop->toPropInt() );
            }
465
        }
466
    }
wiebel's avatar
wiebel committed
467
}
468

469 470 471 472 473 474 475 476 477 478 479 480 481 482
Qt::ToolButtonStyle WMainWindow::getToolbarStyle() const
{
    // this sets the toolbar style
    int toolBarStyle = 0;
    WPreferences::getPreference( "qt4gui.toolBarStyle", &toolBarStyle );
    if ( ( toolBarStyle < 0 ) || ( toolBarStyle > 3 ) ) // ensure a valid value
    {
        toolBarStyle = 0;
    }

    // cast and return
    return static_cast< Qt::ToolButtonStyle >( toolBarStyle );
}

483 484 485 486 487 488 489 490
WMainWindow::ToolBarPosition WMainWindow::getToolbarPos()
{
    int toolbarPos = 0;
    WPreferences::getPreference( "qt4gui.toolBarPos", &toolbarPos );
    return static_cast< ToolBarPosition >( toolbarPos );
}

WMainWindow::ToolBarPosition WMainWindow::getCompatiblesToolbarPos()
491
{
492
    int compatiblesToolbarPos = 0;
493
    if ( !WPreferences::getPreference( "qt4gui.compatiblesToolBarPos", &compatiblesToolbarPos ) )
494
    {
495 496 497 498 499 500 501 502 503 504 505 506
        return getToolbarPos();
    }

    return static_cast< ToolBarPosition >( compatiblesToolbarPos );
}

Qt::ToolBarArea WMainWindow::toQtToolBarArea( ToolBarPosition pos )
{
    switch ( pos )
    {
        case Top:
            return Qt::TopToolBarArea;
507
            break;
508 509
        case Bottom:
            return Qt::BottomToolBarArea;
510
            break;
511 512
        case Left:
            return Qt::LeftToolBarArea;
513
            break;
514 515
        case Right:
            return Qt::RightToolBarArea;
516
            break;
517 518
        case InDSB:
            return Qt::RightToolBarArea;
519
        default:
520
            return Qt::NoToolBarArea;
521
            break;
522
      }
523 524 525 526 527 528 529 530 531 532
}

void WMainWindow::setCompatiblesToolbar( WQtCombinerToolbar* toolbar )
{
    if ( m_currentCompatiblesToolbar )
    {
        delete m_currentCompatiblesToolbar;
    }
    m_currentCompatiblesToolbar = toolbar;

533 534 535 536 537 538 539 540 541 542
    // hide it?
    if ( getCompatiblesToolbarPos() == Hide )
    {
        if ( toolbar )
        {
            toolbar->setVisible( false );
        }
        return;
    }

543 544 545 546
    if ( !toolbar )
    {
        // ok, reset the toolbar
        // So create a dummy to permanently reserve the space
547
        m_currentCompatiblesToolbar = new WQtCombinerToolbar( this, WCombinerTypes::WCompatiblesList() );
548 549 550 551 552 553 554 555
    }

    // optional toolbar break
    {
        bool useToolBarBreak = true;
        WPreferences::getPreference( "qt4gui.useToolBarBreak", &useToolBarBreak );
        if( useToolBarBreak )
        {
556
            addToolBarBreak( toQtToolBarArea( getCompatiblesToolbarPos() ) );
557 558 559 560
        }
    }

    // and the position of the toolbar
561
    addToolBar( toQtToolBarArea( getCompatiblesToolbarPos() ), m_currentCompatiblesToolbar );
562
}
563

564
WQtDatasetBrowser* WMainWindow::getDatasetBrowser()
565
{
566
    return m_datasetBrowser;
567
}
568

569
void WMainWindow::projectSave( const std::vector< boost::shared_ptr< WProjectFileIO > >& writer )
570 571 572 573
{
    QFileDialog fd;
    fd.setWindowTitle( "Save Project as" );
    fd.setFileMode( QFileDialog::AnyFile );
574
    fd.setAcceptMode( QFileDialog::AcceptSave );
575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593

    QStringList filters;
    filters << "Project File (*.owproj)"
            << "Any files (*)";
    fd.setNameFilters( filters );
    fd.setViewMode( QFileDialog::Detail );
    QStringList fileNames;
    if ( fd.exec() )
    {
        fileNames = fd.selectedFiles();
    }

    QStringList::const_iterator constIterator;
    for ( constIterator = fileNames.constBegin(); constIterator != fileNames.constEnd(); ++constIterator )
    {
        boost::shared_ptr< WProjectFile > proj = boost::shared_ptr< WProjectFile >(
                new WProjectFile( ( *constIterator ).toStdString() )
        );

594 595 596
        try
        {
            // This call is synchronous.
597 598 599 600 601 602 603 604
            if ( writer.empty() )
            {
                proj->save();
            }
            else
            {
                proj->save( writer );
            }
605 606 607 608 609 610 611 612
        }
        catch( const std::exception& e )
        {
            QString title = "Problem while saving project file.";
            QString message = "<b>Problem while saving project file.</b><br/><br/><b>File:  </b>" + ( *constIterator ) +
                              "<br/><b>Message:  </b>" + QString::fromStdString( e.what() );
            QMessageBox::critical( this, title, message );
        }
613 614 615
    }
}

616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636
void WMainWindow::projectSaveAll()
{
    std::vector< boost::shared_ptr< WProjectFileIO > > w;
    // an empty list equals "all"
    projectSave( w );
}

void WMainWindow::projectSaveCameraOnly()
{
    std::vector< boost::shared_ptr< WProjectFileIO > > w;
    w.push_back( WProjectFile::getCameraWriter() );
    projectSave( w );
}

void WMainWindow::projectSaveROIOnly()
{
    std::vector< boost::shared_ptr< WProjectFileIO > > w;
    w.push_back( WProjectFile::getROIWriter() );
    projectSave( w );
}

637 638 639 640 641 642 643
void WMainWindow::projectSaveModuleOnly()
{
    std::vector< boost::shared_ptr< WProjectFileIO > > w;
    w.push_back( WProjectFile::getModuleWriter() );
    projectSave( w );
}

644 645 646 647 648 649
void WMainWindow::projectLoad()
{
    QFileDialog fd;
    fd.setFileMode( QFileDialog::ExistingFiles );

    QStringList filters;
650
    filters << "Simple Project File (*.owproj)"
651 652 653 654 655 656 657 658 659 660 661 662
            << "Any files (*)";
    fd.setNameFilters( filters );
    fd.setViewMode( QFileDialog::Detail );
    QStringList fileNames;
    if ( fd.exec() )
    {
        fileNames = fd.selectedFiles();
    }

    QStringList::const_iterator constIterator;
    for ( constIterator = fileNames.constBegin(); constIterator != fileNames.constEnd(); ++constIterator )
    {
663 664
        boost::shared_ptr< WProjectFile > proj = boost::shared_ptr< WProjectFile >(
                new WProjectFile( ( *constIterator ).toStdString() )
665
        );
666 667

        // This call is asynchronous. It parses the file and the starts a thread to actually do all the stuff
668
        proj->load();
669 670 671
    }
}

672
void WMainWindow::openLoadDialog()
673
{
674 675
    QFileDialog fd;
    fd.setFileMode( QFileDialog::ExistingFiles );
wiebel's avatar
wiebel committed
676 677

    QStringList filters;
678 679
    filters << "Known file types (*.cnt *.edf *.asc *.nii *.nii.gz *.fib)"
            << "EEG files (*.cnt *.edf *.asc)"
wiebel's avatar
wiebel committed
680
            << "NIfTI (*.nii *.nii.gz)"
681 682
            << "Fibers (*.fib)"
            << "Any files (*)";
wiebel's avatar
wiebel committed
683
    fd.setNameFilters( filters );
684 685 686 687 688 689 690
    fd.setViewMode( QFileDialog::Detail );
    QStringList fileNames;
    if ( fd.exec() )
    {
        fileNames = fd.selectedFiles();
    }

691
    std::vector< std::string > stdFileNames;
692 693 694 695 696 697

    QStringList::const_iterator constIterator;
    for ( constIterator = fileNames.constBegin(); constIterator != fileNames.constEnd(); ++constIterator )
    {
        stdFileNames.push_back( ( *constIterator ).toLocal8Bit().constData() );
    }
698 699

    //
Alexander Wiebel's avatar
Alexander Wiebel committed
700
    // WE KNOW THAT THIS IS KIND OF A HACK. It is only provided to prevent naive users from having trouble.
701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725
    //
    bool allowOnlyOneFiberDataSet = false;
    bool doubleFibersFound = false; // have we detected the multiple loading of fibers?
    if( WPreferences::getPreference( "general.allowOnlyOneFiberDataSet", &allowOnlyOneFiberDataSet ) && allowOnlyOneFiberDataSet )
    {
        for( std::vector< std::string >::iterator it = stdFileNames.begin(); it != stdFileNames.end(); ++it )
        {
            using wiotools::getSuffix;
            std::string suffix = getSuffix( *it );
            bool isFib = ( suffix == ".fib" );
            if( m_fibLoaded && isFib )
            {
                QCoreApplication::postEvent( this, new WModuleCrashEvent(
                                                 WModuleFactory::getModuleFactory()->getPrototypeByName( "Data Module" ),
                                                 std::string( "Tried to load two fiber data sets. This is not allowed by your preferences." ) ) );
                doubleFibersFound = true;
            }
            m_fibLoaded |= isFib;
        }
    }

    if( !doubleFibersFound )
    {
        m_loaderSignal( stdFileNames );
    }
726

ledig's avatar
[STYLE]  
ledig committed
727
    // walkaround that a button keeps his down state after invoking a dialog
728
    m_loadButton->setDown( false );
729
}
730

731 732 733 734
void WMainWindow::openAboutDialog()
{
    QMessageBox::about( this, "About OpenWalnut",
                        "OpenWalnut ( http://www.openwalnut.org )\n\n"
735
                        "Copyright (C) 2009-2010 OpenWalnut Community, BSV@Uni-Leipzig and\nCNCF@MPI-CBS. "
736 737 738 739 740 741 742 743 744 745
                        "For more information see http://www.openwalnut.org/copying.\n\n"
                        "This program comes with ABSOLUTELY NO WARRANTY. "
                        "This is free software, and you are welcome to redistribute it "
                        "under the terms of the GNU Lesser General Public License. "
                        "You should have received a copy of the GNU Lesser General Public License "
                        "along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.\n"
                        "\n"
                        "Thank you for using OpenWalnut." );
}

746 747 748 749
void WMainWindow::setPresetViewLeft()
{
    boost::shared_ptr< WGEViewer > viewer;
    viewer = WKernel::getRunningKernel()->getGraphicsEngine()->getViewerByName( "main" );
schurade's avatar
schurade committed
750 751 752
    osg::ref_ptr<osgGA::TrackballManipulator>  cm = osg::dynamic_pointer_cast<osgGA::TrackballManipulator>( viewer->getCameraManipulator() );
    osg::Quat q( 0.5, -0.5, -0.5, 0.5 );
    cm->setRotation( q );
753 754 755 756 757 758
}

void WMainWindow::setPresetViewRight()
{
    boost::shared_ptr< WGEViewer > viewer;
    viewer = WKernel::getRunningKernel()->getGraphicsEngine()->getViewerByName( "main" );
schurade's avatar
schurade committed
759 760 761
    osg::ref_ptr<osgGA::TrackballManipulator>  cm = osg::dynamic_pointer_cast<osgGA::TrackballManipulator>( viewer->getCameraManipulator() );
    osg::Quat q( -0.5, -0.5, -0.5, -0.5 );
    cm->setRotation( q );
762 763 764 765 766 767
}

void WMainWindow::setPresetViewSuperior()
{
    boost::shared_ptr< WGEViewer > viewer;
    viewer = WKernel::getRunningKernel()->getGraphicsEngine()->getViewerByName( "main" );
schurade's avatar
schurade committed
768 769 770
    osg::ref_ptr<osgGA::TrackballManipulator>  cm = osg::dynamic_pointer_cast<osgGA::TrackballManipulator>( viewer->getCameraManipulator() );
    osg::Quat q( 0., 0., 0., 1 );
    cm->setRotation( q );
771 772 773 774 775 776
}

void WMainWindow::setPresetViewInferior()
{
    boost::shared_ptr< WGEViewer > viewer;
    viewer = WKernel::getRunningKernel()->getGraphicsEngine()->getViewerByName( "main" );
schurade's avatar
schurade committed
777 778 779
    osg::ref_ptr<osgGA::TrackballManipulator>  cm = osg::dynamic_pointer_cast<osgGA::TrackballManipulator>( viewer->getCameraManipulator() );
    osg::Quat q( 0., -1., 0., 0. );
    cm->setRotation( q );
780 781 782 783 784 785
}

void WMainWindow::setPresetViewAnterior()
{
    boost::shared_ptr< WGEViewer > viewer;
    viewer = WKernel::getRunningKernel()->getGraphicsEngine()->getViewerByName( "main" );
schurade's avatar
schurade committed
786 787 788
    osg::ref_ptr<osgGA::TrackballManipulator>  cm = osg::dynamic_pointer_cast<osgGA::TrackballManipulator>( viewer->getCameraManipulator() );
    osg::Quat q( 0., -0.707107, -0.707107, 0. );
    cm->setRotation( q );
789 790 791 792 793 794
}

void WMainWindow::setPresetViewPosterior()
{
    boost::shared_ptr< WGEViewer > viewer;
    viewer = WKernel::getRunningKernel()->getGraphicsEngine()->getViewerByName( "main" );
schurade's avatar
schurade committed
795 796 797
    osg::ref_ptr<osgGA::TrackballManipulator>  cm = osg::dynamic_pointer_cast<osgGA::TrackballManipulator>( viewer->getCameraManipulator() );
    osg::Quat q( 0.707107, 0., 0., 0.707107 );
    cm->setRotation( q );
798 799
}

800 801 802 803 804 805 806
void WMainWindow::openNotImplementedDialog()
{
    QMessageBox::information( this, "Not yet implemented!",
                              "This functionality is planned for future versions of OpenWalnut. "
                              "It is not yet implemented." );
}

schurade's avatar
schurade committed
807
boost::signals2::signal1< void, std::vector< std::string > >* WMainWindow::getLoaderSignal()
808 809 810 811
{
    return &m_loaderSignal;
}

812 813 814
WIconManager*  WMainWindow::getIconManager()
{
    return &m_iconManager;
815
}
816 817 818 819 820 821 822 823 824 825

void WMainWindow::closeEvent( QCloseEvent* e )
{
    // use some "Really Close?" Dialog here
    bool reallyClose = true;


    // handle close event
    if ( reallyClose )
    {
826 827
        // signal everybody to shut down properly.
        WKernel::getRunningKernel()->finalize();
828 829 830 831

        // now nobody acesses the osg anymore
        // clean up gl widgets
        m_mainGLWidget->close();
832 833 834 835 836 837 838 839 840 841 842 843
        if( m_navAxial )
        {
            m_navAxial->close();
        }
        if( m_navCoronal )
        {
            m_navCoronal->close();
        }
        if( m_navSagittal )
        {
            m_navSagittal->close();
        }
844

845 846 847 848 849 850 851
        // delete CustomDockWidgets
        boost::mutex::scoped_lock lock( m_customDockWidgetsLock );
        for( std::map< std::string, boost::shared_ptr< WQtCustomDockWidget > >::iterator it = m_customDockWidgets.begin();
             it != m_customDockWidgets.end(); ++it )
        {
            it->second->close();
        }
852
        //m_customDockWidgetsLock.unlock();
853

854 855 856 857 858 859 860 861 862
        // finally close
        e->accept();
    }
    else
    {
        e->ignore();
    }
}

863 864
void WMainWindow::customEvent( QEvent* event )
{
865
    if( event->type() == WOpenCustomDockWidgetEvent::CUSTOM_TYPE )
866
    {
867 868 869 870 871
        // OpenCustomDockWidgetEvent
        WOpenCustomDockWidgetEvent* ocdwEvent = static_cast< WOpenCustomDockWidgetEvent* >( event );
        std::string title = ocdwEvent->getTitle();

        boost::shared_ptr< WQtCustomDockWidget > widget;
872 873

        boost::mutex::scoped_lock lock( m_customDockWidgetsLock );
874 875
        if( m_customDockWidgets.count( title ) == 0 )
        {
876 877 878
            // create new custom dock widget
            widget = boost::shared_ptr< WQtCustomDockWidget >(
                new WQtCustomDockWidget( title, this, ocdwEvent->getProjectionMode() ) );
879 880 881 882 883 884 885
            addDockWidget( Qt::BottomDockWidgetArea, widget.get() );

            // store it in CustomDockWidget list
            m_customDockWidgets.insert( make_pair( title, widget ) );
        }
        else
        {
886 887
            widget = m_customDockWidgets[title];
            widget->increaseUseCount();
888
        }
889
        //m_customDockWidgetsLock.unlock();
890 891

        ocdwEvent->getFlag()->set( widget );
892 893 894 895 896 897 898 899
    }
    else
    {
        // other event
        QMainWindow::customEvent( event );
    }
}

900 901 902 903 904 905 906 907 908 909 910 911 912
bool WMainWindow::event( QEvent* event )
{
    // a module got associated with the root container -> add it to the list
    if ( event->type() == WQT_READY_EVENT )
    {
        // convert event to ready event
        WModuleReadyEvent* e1 = dynamic_cast< WModuleReadyEvent* >( event );     // NOLINT
        if ( e1 )
        {
            moduleSpecificSetup( e1->getModule() );
        }
    }

913 914 915 916 917 918
    if ( event->type() == WQT_CRASH_EVENT )
    {
        // convert event to ready event
        WModuleCrashEvent* e1 = dynamic_cast< WModuleCrashEvent* >( event );     // NOLINT
        if ( e1 )
        {
919
            QString title = "Problem in module: " + QString::fromStdString( e1->getModule()->getName() );
920 921 922 923 924 925 926 927
            QString description = "<b>Module Problem</b><br/><br/><b>Module:  </b>" + QString::fromStdString( e1->getModule()->getName() );

            QString message = QString::fromStdString( e1->getMessage() );
            QMessageBox msgBox;
            msgBox.setText( description );
            msgBox.setInformativeText( message  );
            msgBox.setStandardButtons( QMessageBox::Ok );
            msgBox.exec();
928 929 930
        }
    }

931 932 933
    return QMainWindow::event( event );
}

934 935 936 937 938 939
boost::shared_ptr< WQtCustomDockWidget > WMainWindow::getCustomDockWidget( std::string title )
{
    boost::mutex::scoped_lock lock( m_customDockWidgetsLock );
    boost::shared_ptr< WQtCustomDockWidget > out = m_customDockWidgets.count( title ) > 0 ?
        m_customDockWidgets[title] :
        boost::shared_ptr< WQtCustomDockWidget >();