WMainWindow.cpp 36.8 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( "o" ), o_xpm ); // duumy icon for modules
90

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

100 101 102 103 104 105
    // 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" );

106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
    // 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
128 129 130 131
    // 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.

132
    m_menuBar = new QMenuBar( this );
133 134 135 136 137 138

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

139
    QMenu* fileMenu = m_menuBar->addMenu( "File" );
140

Sebastian Eichelbaum's avatar
Sebastian Eichelbaum committed
141 142 143 144 145 146 147 148 149 150 151
    fileMenu->addAction( m_iconManager.getIcon( "load" ), "Load Dataset", this, SLOT( openLoadDialog() ), QKeySequence(  QKeySequence::Open ) );
    fileMenu->addSeparator();
    fileMenu->addAction( "Load Project", this, SLOT( projectLoad() ) );
    QMenu* saveMenu = fileMenu->addMenu( "Save" );
    saveMenu->addAction( "Save Project", this, SLOT( projectSaveAll() ), QKeySequence::Save );
    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();
    fileMenu->addAction( "Config", this, SLOT( openConfigDialog() ) );
    fileMenu->addSeparator();
152 153 154
    // 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
155

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

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

Sebastian Eichelbaum's avatar
Sebastian Eichelbaum committed
168 169 170
    // 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 ).
171 172 173 174 175 176
    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 ) );
177

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

183 184
    setMenuBar( m_menuBar );

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

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

Mathias Goldau's avatar
[MERGE]  
Mathias Goldau committed
211 212 213 214 215 216 217 218 219
    // 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 );
    }

220
    // Default background color from config file
221
    {
222 223 224 225 226 227 228 229 230 231
        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 );
232 233 234 235 236 237 238 239 240 241 242 243 244

            if ( m_navAxial )
            {
                m_navAxial->getGLWidget()->setBgColor( bgColor );
            }
            if ( m_navCoronal )
            {
                m_navCoronal->getGLWidget()->setBgColor( bgColor );
            }
            if ( m_navSagittal )
            {
                m_navSagittal->getGLWidget()->setBgColor( bgColor );
            }
245
        }
246 247
    }

248
    setupPermanentToolBar();
249
}
250

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

255 256 257 258
    // 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() );

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

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

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

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

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

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

297 298 299 300 301 302 303 304 305 306 307 308 309 310
    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 );
    }
311
}
312

313 314 315 316 317 318 319 320 321 322
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 );
    }
}

323 324
void WMainWindow::moduleSpecificSetup( boost::shared_ptr< WModule > module )
{
325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340
    // 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
341
        if ( dataModule->getDataSet()->isA< WDataSetSingle >() && dataModule->getDataSet()->isTexture() )
342 343 344 345
        {
            // it is a dataset single
            // load a nav slice module if a WDataSetSingle is available!?

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

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

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

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

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

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

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

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

468 469 470 471 472 473 474 475 476 477 478 479 480 481
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 );
}

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

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

    return static_cast< ToolBarPosition >( compatiblesToolbarPos );
}

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

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

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

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

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

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

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

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

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

593 594 595
        try
        {
            // This call is synchronous.
596 597 598 599 600 601 602 603
            if ( writer.empty() )
            {
                proj->save();
            }
            else
            {
                proj->save( writer );
            }
604 605 606 607 608 609 610 611
        }
        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 );
        }
612 613 614
    }
}

615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635
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 );
}

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

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

    QStringList filters;
649
    filters << "Simple Project File (*.owproj)"
650 651 652 653 654 655 656 657 658 659 660 661
            << "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 )
    {
662 663
        boost::shared_ptr< WProjectFile > proj = boost::shared_ptr< WProjectFile >(
                new WProjectFile( ( *constIterator ).toStdString() )
664
        );
665 666

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

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

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

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

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

    //
Alexander Wiebel's avatar
Alexander Wiebel committed
699
    // WE KNOW THAT THIS IS KIND OF A HACK. It is only provided to prevent naive users from having trouble.
700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724
    //
    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 );
    }
725

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

730 731 732 733 734 735 736 737 738 739 740 741 742 743 744
void WMainWindow::openAboutDialog()
{
    QMessageBox::about( this, "About OpenWalnut",
                        "OpenWalnut ( http://www.openwalnut.org )\n\n"
                        "Copyright (C) 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS. "
                        "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." );
}

745 746 747 748
void WMainWindow::setPresetViewLeft()
{
    boost::shared_ptr< WGEViewer > viewer;
    viewer = WKernel::getRunningKernel()->getGraphicsEngine()->getViewerByName( "main" );
schurade's avatar
schurade committed
749 750 751
    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 );
752 753 754 755 756 757
}

void WMainWindow::setPresetViewRight()
{
    boost::shared_ptr< WGEViewer > viewer;
    viewer = WKernel::getRunningKernel()->getGraphicsEngine()->getViewerByName( "main" );
schurade's avatar
schurade committed
758 759 760
    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 );
761 762 763 764 765 766
}

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

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

void WMainWindow::setPresetViewAnterior()
{
    boost::shared_ptr< WGEViewer > viewer;
    viewer = WKernel::getRunningKernel()->getGraphicsEngine()->getViewerByName( "main" );
schurade's avatar
schurade committed
785 786 787
    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 );
788 789 790 791 792 793
}

void WMainWindow::setPresetViewPosterior()
{
    boost::shared_ptr< WGEViewer > viewer;
    viewer = WKernel::getRunningKernel()->getGraphicsEngine()->getViewerByName( "main" );
schurade's avatar
schurade committed
794 795 796
    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 );
797 798
}

799 800 801 802 803 804 805
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
806
boost::signals2::signal1< void, std::vector< std::string > >* WMainWindow::getLoaderSignal()
807 808 809 810
{
    return &m_loaderSignal;
}

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

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


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

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

844 845 846 847 848 849 850
        // 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();
        }
851
        //m_customDockWidgetsLock.unlock();
852

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

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

        boost::shared_ptr< WQtCustomDockWidget > widget;
871 872

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

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

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

899 900 901 902 903 904 905 906 907 908 909 910 911
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() );
        }
    }

912 913 914 915 916 917
    if ( event->type() == WQT_CRASH_EVENT )
    {
        // convert event to ready event
        WModuleCrashEvent* e1 = dynamic_cast< WModuleCrashEvent* >( event );     // NOLINT
        if ( e1 )
        {
918
            QString title = "Problem in module: " + QString::fromStdString( e1->getModule()->getName() );
919 920 921 922 923 924 925 926
            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();
927 928 929
        }
    }

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

933 934 935 936 937 938
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 >();
939
    //m_customDockWidgetsLock.unlock();
940 941 942 943
    return out;
}


944 945 946
void WMainWindow::closeCustomDockWidget( std::string title )
{
    boost::mutex::scoped_lock lock( m_customDockWidgetsLock );
947
    if( m_customDockWidgets.count( title ) > 0 )
948
    {
949 950 951 952 953
        if( m_customDockWidgets[title]->decreaseUseCount() )
        {
            // custom dock widget should be deleted
            m_customDockWidgets.erase( title );
        }
954
    }
955
    //m_customDockWidgetsLock.unlock();
956 957
}

schurade's avatar
schurade committed