WMainWindow.cpp 31 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>
26 27
#include <string>
#include <vector>
28
#include <map>
29

30 31
#include <boost/thread.hpp>

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

43
#include "WMainWindow.h"
44
#include "WOpenCustomDockWidgetEvent.h"
45
#include "WQtGLWidget.h"
46
#include "WQtNavGLWidget.h"
47
#include "WQtCustomDockWidget.h"
48
#include "events/WModuleReadyEvent.h"
49
#include "events/WModuleCrashEvent.h"
50 51
#include "events/WEventTypes.h"
#include "datasetbrowser/WPropertyBoolWidget.h"
52 53 54
#include "../../common/WColor.h"
#include "../../common/WPreferences.h"
#include "../../kernel/WKernel.h"
55
#include "../../kernel/WProjectFile.h"
56
#include "../../modules/data/WMData.h"
57
#include "../../modules/navSlices/WMNavSlices.h"
58

59
#include "../../dataHandler/WEEG2.h"
60 61
#include "../../dataHandler/WDataSetSingle.h"
#include "../../dataHandler/WDataSetFibers.h"
wiebel's avatar
wiebel committed
62

schurade's avatar
schurade committed
63 64
#include "../../graphicsEngine/WROIBox.h"

65
#include "../icons/WIcons.h"
66

67
WMainWindow::WMainWindow() :
68
    QMainWindow(),
69 70
    m_iconManager(),
    m_fibLoaded( false )
Sebastian Eichelbaum's avatar
Sebastian Eichelbaum committed
71 72
{
}
73

74
void WMainWindow::setupGUI()
75
{
76
    m_iconManager.addIcon( std::string( "load" ), fileopen_xpm );
77
    m_iconManager.addIcon( std::string( "loadProject" ), projOpen_xpm );
78
    m_iconManager.addIcon( std::string( "saveProject" ), projSave_xpm );
79
    m_iconManager.addIcon( std::string( "logo" ), logoIcon_xpm );
80
    m_iconManager.addIcon( std::string( "help" ), question_xpm );
81
    m_iconManager.addIcon( std::string( "quit" ), quit_xpm );
82 83 84
    m_iconManager.addIcon( std::string( "moduleBusy" ), moduleBusy_xpm );
    m_iconManager.addIcon( std::string( "moduleCrashed" ), moduleCrashed_xpm );
    m_iconManager.addIcon( std::string( "remove" ), remove_xpm );
85

86
    if( objectName().isEmpty() )
87
    {
88
        setObjectName( QString::fromUtf8( "MainWindow" ) );
89
    }
90 91
    resize( 946, 632 );
    setWindowIcon( m_iconManager.getIcon( "logo" ) );
92
    setWindowTitle( QApplication::translate( "MainWindow", "OpenWalnut (development version)", 0, QApplication::UnicodeUTF8 ) );
93

94 95 96 97 98 99
    // 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" );

Sebastian Eichelbaum's avatar
Sebastian Eichelbaum committed
100 101 102 103
    // 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.

104
    m_menuBar = new QMenuBar( this );
105
    QMenu* fileMenu = m_menuBar->addMenu( "File" );
Sebastian Eichelbaum's avatar
Sebastian Eichelbaum committed
106 107 108 109 110 111 112 113 114 115 116
    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();
117 118 119
    // 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
120

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

    QAction* dsbTrigger = m_datasetBrowser->toggleViewAction();
126 127 128 129 130 131
    QList< QKeySequence > dsbShortcut;
    dsbShortcut.append( QKeySequence( Qt::Key_F9 ) );
    dsbTrigger->setShortcuts( dsbShortcut );
    viewMenu->addAction( dsbTrigger );
    viewMenu->addSeparator();

Sebastian Eichelbaum's avatar
Sebastian Eichelbaum committed
132 133 134 135 136 137 138 139 140
    // 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 ).
    viewMenu->addAction( "Left", this, SLOT( openNotImplementedDialog() ),      QKeySequence( Qt::CTRL + Qt::SHIFT + Qt::Key_L ) );
    viewMenu->addAction( "Right", this, SLOT( openNotImplementedDialog() ),     QKeySequence( Qt::CTRL + Qt::SHIFT + Qt::Key_R ) );
    viewMenu->addAction( "Superior", this, SLOT( openNotImplementedDialog() ),  QKeySequence( Qt::CTRL + Qt::SHIFT + Qt::Key_S ) );
    viewMenu->addAction( "Inferior", this, SLOT( openNotImplementedDialog() ),  QKeySequence( Qt::CTRL + Qt::SHIFT + Qt::Key_I ) );
    viewMenu->addAction( "Anterior", this, SLOT( openNotImplementedDialog() ),  QKeySequence( Qt::CTRL + Qt::SHIFT + Qt::Key_A ) );
    viewMenu->addAction( "Posterior", this, SLOT( openNotImplementedDialog() ), QKeySequence( Qt::CTRL + Qt::SHIFT + Qt::Key_P ) );
141

142
    QMenu* helpMenu = m_menuBar->addMenu( "Help" );
Sebastian Eichelbaum's avatar
Sebastian Eichelbaum committed
143 144 145
    helpMenu->addAction( m_iconManager.getIcon( "help" ), "About OpenWalnut", this, SLOT( openAboutDialog() ),
                         QKeySequence( QKeySequence::HelpContents )
    );
146

147 148
    setMenuBar( m_menuBar );

149
    m_centralwidget = new QWidget( this );
150
    m_centralwidget->setObjectName( QString::fromUtf8( "centralwidget" ) );
151
    setCentralWidget( m_centralwidget );
152

153
    m_mainGLWidget = boost::shared_ptr< WQtGLWidget >( new WQtGLWidget( "main", this, WGECamera::ORTHOGRAPHIC ) );
154 155
    m_mainGLWidget->initialize();
    setCentralWidget( m_mainGLWidget.get() );
wiebel's avatar
wiebel committed
156

157 158 159 160 161
    // initially 3 navigation views
    {
        bool hideWidget;
        if( !( WPreferences::getPreference( "qt4gui.hideAxial", &hideWidget ) && hideWidget) )
        {
162
            m_navAxial = boost::shared_ptr< WQtNavGLWidget >( new WQtNavGLWidget( "axial", this, "Axial Slice" ) );
163
            m_navAxial->setFeatures( QDockWidget::AllDockWidgetFeatures );
164 165 166 167
            addDockWidget( Qt::LeftDockWidgetArea, m_navAxial.get() );
        }
        if( !( WPreferences::getPreference( "qt4gui.hideCoronal", &hideWidget ) && hideWidget) )
        {
168
            m_navCoronal = boost::shared_ptr< WQtNavGLWidget >( new WQtNavGLWidget( "coronal", this, "Coronal Slice" ) );
169
            m_navCoronal->setFeatures( QDockWidget::AllDockWidgetFeatures );
170 171 172 173
            addDockWidget( Qt::LeftDockWidgetArea, m_navCoronal.get() );
        }
        if( !( WPreferences::getPreference( "qt4gui.hideSagittal", &hideWidget ) && hideWidget) )
        {
174
            m_navSagittal = boost::shared_ptr< WQtNavGLWidget >( new WQtNavGLWidget( "sagittal", this, "Sagittal Slice" ) );
175
            m_navSagittal->setFeatures( QDockWidget::AllDockWidgetFeatures );
176 177 178
            addDockWidget( Qt::LeftDockWidgetArea, m_navSagittal.get() );
        }
    }
179

Mathias Goldau's avatar
[MERGE]  
Mathias Goldau committed
180 181 182 183 184 185 186 187 188
    // 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 );
    }

189
    // Default background color from config file
190
    {
191 192 193 194 195 196 197 198 199 200
        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 );
201 202 203 204 205 206 207 208 209 210 211 212 213

            if ( m_navAxial )
            {
                m_navAxial->getGLWidget()->setBgColor( bgColor );
            }
            if ( m_navCoronal )
            {
                m_navCoronal->getGLWidget()->setBgColor( bgColor );
            }
            if ( m_navSagittal )
            {
                m_navSagittal->getGLWidget()->setBgColor( bgColor );
            }
214
        }
215 216
    }

217
    setupPermanentToolBar();
218

219
    setupCompatiblesToolBar();
220
}
221

222
void WMainWindow::setupPermanentToolBar()
223
{
224
    m_permanentToolBar = new WQtToolBar( "Permanent Toolbar", this );
225

226 227 228 229
    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 );
230 231


232 233
    WQtPushButton* loadButton = new WQtPushButton( m_iconManager.getIcon( "load" ), "load", m_permanentToolBar );
    WQtPushButton* roiButton = new WQtPushButton( m_iconManager.getIcon( "ROI" ), "ROI", m_permanentToolBar );
234 235
    WQtPushButton* projectLoadButton = new WQtPushButton( m_iconManager.getIcon( "loadProject" ), "loadProject", m_permanentToolBar );
    WQtPushButton* projectSaveButton = new WQtPushButton( m_iconManager.getIcon( "saveProject" ), "saveProject", m_permanentToolBar );
236

237 238 239
    // setup save button
    QMenu* saveMenu = new QMenu( "Save Project", projectSaveButton );
    saveMenu->addAction( "Save Project", this, SLOT( projectSaveAll() ) );
240
    saveMenu->addAction( "Save Modules", this, SLOT( projectSaveModuleOnly() ) );
241 242 243 244 245
    saveMenu->addAction( "Save Camera", this, SLOT( projectSaveCameraOnly() ) );
    saveMenu->addAction( "Save ROIs", this, SLOT( projectSaveROIOnly() ) );
    projectSaveButton->setPopupMode( QToolButton::MenuButtonPopup );
    projectSaveButton->setMenu( saveMenu );

246 247
    connect( loadButton, SIGNAL( pressed() ), this, SLOT( openLoadDialog() ) );
    connect( roiButton, SIGNAL( pressed() ), this, SLOT( newRoi() ) );
248
    connect( projectLoadButton, SIGNAL( pressed() ), this, SLOT( projectLoad() ) );
249
    connect( projectSaveButton, SIGNAL( pressed() ), this, SLOT( projectSaveAll() ) );
250

251 252
    loadButton->setToolTip( "Load Data" );
    roiButton->setToolTip( "Create New ROI" );
253 254
    projectLoadButton->setToolTip( "Load a project from file" );
    projectSaveButton->setToolTip( "Save current project to file" );
255

256
    m_permanentToolBar->addWidget( loadButton );
257
    m_permanentToolBar->addSeparator();
258 259
    m_permanentToolBar->addWidget( projectLoadButton );
    m_permanentToolBar->addWidget( projectSaveButton );
260
    m_permanentToolBar->addSeparator();
261
    m_permanentToolBar->addWidget( roiButton );
262

263
    m_permanentToolBar->addSeparator();
264

265 266
    addToolBar( Qt::TopToolBarArea, m_permanentToolBar );
}
267

268 269 270 271 272 273 274 275 276 277
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 );
    }
}

278 279
void WMainWindow::moduleSpecificSetup( boost::shared_ptr< WModule > module )
{
280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300
    // 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
        if ( dataModule->getDataSet()->isA< WDataSetSingle >() )
        {
            // it is a dataset single
            // load a nav slice module if a WDataSetSingle is available!?

301
            // if it not already is running: add it
302 303
            if ( !WMNavSlices::isRunning() )
            {
304
                autoAdd( module, "Navigation Slices" );
305
            }
306 307 308 309
        }
        else if ( dataModule->getDataSet()->isA< WDataSetFibers >() )
        {
            // it is a fiber dataset -> add the FiberDisplay module
310 311 312 313 314 315

            // if it not already is running: add it
            if ( !WMFiberDisplay::isRunning() )
            {
                autoAdd( module, "Fiber Display" );
            }
316
        }
317
        else if ( dataModule->getDataSet()->isA< WEEG2 >() )
318
        {
319
            // it is a eeg dataset -> add the eegView module
320 321 322 323
            autoAdd( module, "EEG View" );
        }
    }

324
    // nav slices use separate buttons for slice on/off switching
325
    if ( module->getName() == "Navigation Slices" )
326
    {
327
        boost::shared_ptr< WPropertyBase > prop = module->getProperties()->findProperty( "showAxial" );
328 329 330
        if ( !prop )
        {
               WLogger::getLogger()->
331
                   addLogMessage( "Navigation Slices module does not provide the property \"showAxial\", which is required by the GUI.", "GUI",
332 333 334 335 336 337 338 339 340 341
                                  LL_ERROR );
        }
        else
        {
            WPropertyBoolWidget* button = new WPropertyBoolWidget( prop->toPropBool(), NULL, m_permanentToolBar, true );
            button->setToolTip( "Toggle Axial Slice" );
            button->getButton()->setMaximumSize( 24, 24 );
            button->getButton()->setIcon( m_iconManager.getIcon( "axial" ) );
            m_permanentToolBar->addWidget( button );
        }
342

343
        prop = module->getProperties()->findProperty( "showCoronal" );
344 345 346
        if ( !prop )
        {
               WLogger::getLogger()->
347
                   addLogMessage( "Navigation Slices module does not provide the property \"showCoronal\", which is required by the GUI.", "GUI",
348 349 350 351 352 353 354 355 356 357
                                  LL_ERROR );
        }
        else
        {
            WPropertyBoolWidget* button = new WPropertyBoolWidget( prop->toPropBool(), NULL, m_permanentToolBar, true );
            button->setToolTip( "Toggle Coronal Slice" );
            button->getButton()->setMaximumSize( 24, 24 );
            button->getButton()->setIcon( m_iconManager.getIcon( "coronal" ) );
            m_permanentToolBar->addWidget( button );
        }
358

359
        prop = module->getProperties()->findProperty( "showSagittal" );
360 361 362
        if ( !prop )
        {
               WLogger::getLogger()->
363
                   addLogMessage( "Navigation Slices module does not provide the property \"showSagittal\", which is required by the GUI.", "GUI",
364 365 366 367 368 369 370 371 372 373
                                  LL_ERROR );
        }
        else
        {
            WPropertyBoolWidget* button = new WPropertyBoolWidget( prop->toPropBool(), NULL, m_permanentToolBar, true );
            button->setToolTip( "Toggle Sagittal Slice" );
            button->getButton()->setMaximumSize( 24, 24 );
            button->getButton()->setIcon( m_iconManager.getIcon( "sagittal" ) );
            m_permanentToolBar->addWidget( button );
        }
374 375

        // now setup the nav widget sliders
376
        prop = module->getProperties()->findProperty( "Axial Slice" );
377 378 379
        if ( !prop )
        {
               WLogger::getLogger()->
380
                   addLogMessage( "Navigation Slices module does not provide the property \"Axial Slice\", which is required by the GUI.", "GUI",
381 382 383 384
                                  LL_ERROR );
        }
        else
        {
385 386 387 388
            if( m_navAxial )
            {
                m_navAxial->setSliderProperty( prop->toPropInt() );
            }
389 390
        }

391
        prop = module->getProperties()->findProperty( "Coronal Slice" );
392 393 394
        if ( !prop )
        {
               WLogger::getLogger()->
395
                   addLogMessage( "Navigation Slices module does not provide the property \"Coronal Slice\", which is required by the GUI.", "GUI",
396 397 398 399
                                  LL_ERROR );
        }
        else
        {
400 401 402 403
            if( m_navCoronal )
            {
                m_navCoronal->setSliderProperty( prop->toPropInt() );
            }
404 405
        }

406
        prop = module->getProperties()->findProperty( "Sagittal Slice" );
407 408 409
        if ( !prop )
        {
               WLogger::getLogger()->
410
                   addLogMessage( "Navigation Slices module does not provide the property \"Sagittal Slice\", which is required by the GUI.", "GUI",
411 412 413 414
                                  LL_ERROR );
        }
        else
        {
415 416 417 418
            if( m_navSagittal )
            {
               m_navSagittal->setSliderProperty( prop->toPropInt() );
            }
419
        }
420
    }
wiebel's avatar
wiebel committed
421
}
422

423 424
void WMainWindow::setupCompatiblesToolBar()
{
425 426
    m_iconManager.addIcon( std::string( "o" ), o_xpm ); // duumy icon for modules

427
    m_compatiblesToolBar = new WQtToolBar( "Compatible Modules Toolbar", this );
428 429 430 431 432 433 434

    // optional toolbar break
    {
        bool useToolBarBreak = true;
        WPreferences::getPreference( "qt4gui.useToolBarBreak", &useToolBarBreak );
        if( useToolBarBreak )
        {
435 436 437 438
            // Blank toolbar for nicer layout in case of toolbar break
            // This can be done nicer very probably.
            WQtToolBar* blankToolBar = new WQtToolBar( "Blank Toolbar", this );
            addToolBar( Qt::TopToolBarArea, blankToolBar );
439 440 441 442
            addToolBarBreak( Qt::TopToolBarArea );
        }
    }

443 444
    addToolBar( Qt::TopToolBarArea, m_compatiblesToolBar );
}
445

446
WQtDatasetBrowser* WMainWindow::getDatasetBrowser()
447
{
448
    return m_datasetBrowser;
449
}
450

451
WQtToolBar* WMainWindow::getCompatiblesToolBar()
452 453 454 455
{
    return m_compatiblesToolBar;
}

456
void WMainWindow::projectSave( const std::vector< boost::shared_ptr< WProjectFileIO > >& writer )
457 458 459 460
{
    QFileDialog fd;
    fd.setWindowTitle( "Save Project as" );
    fd.setFileMode( QFileDialog::AnyFile );
461
    fd.setAcceptMode( QFileDialog::AcceptSave );
462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480

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

481 482 483
        try
        {
            // This call is synchronous.
484 485 486 487 488 489 490 491
            if ( writer.empty() )
            {
                proj->save();
            }
            else
            {
                proj->save( writer );
            }
492 493 494 495 496 497 498 499
        }
        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 );
        }
500 501 502
    }
}

503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523
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 );
}

524 525 526 527 528 529 530
void WMainWindow::projectSaveModuleOnly()
{
    std::vector< boost::shared_ptr< WProjectFileIO > > w;
    w.push_back( WProjectFile::getModuleWriter() );
    projectSave( w );
}

531 532 533 534 535 536
void WMainWindow::projectLoad()
{
    QFileDialog fd;
    fd.setFileMode( QFileDialog::ExistingFiles );

    QStringList filters;
537
    filters << "Simple Project File (*.owproj)"
538 539 540 541 542 543 544 545 546 547 548 549
            << "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 )
    {
550 551
        boost::shared_ptr< WProjectFile > proj = boost::shared_ptr< WProjectFile >(
                new WProjectFile( ( *constIterator ).toStdString() )
552
        );
553 554

        // This call is asynchronous. It parses the file and the starts a thread to actually do all the stuff
555
        proj->load();
556 557 558
    }
}

559
void WMainWindow::openLoadDialog()
560
{
561 562
    QFileDialog fd;
    fd.setFileMode( QFileDialog::ExistingFiles );
wiebel's avatar
wiebel committed
563 564

    QStringList filters;
565 566
    filters << "Known file types (*.cnt *.edf *.asc *.nii *.nii.gz *.fib)"
            << "EEG files (*.cnt *.edf *.asc)"
wiebel's avatar
wiebel committed
567
            << "NIfTI (*.nii *.nii.gz)"
568 569
            << "Fibers (*.fib)"
            << "Any files (*)";
wiebel's avatar
wiebel committed
570
    fd.setNameFilters( filters );
571 572 573 574 575 576 577
    fd.setViewMode( QFileDialog::Detail );
    QStringList fileNames;
    if ( fd.exec() )
    {
        fileNames = fd.selectedFiles();
    }

578
    std::vector< std::string > stdFileNames;
579 580 581 582 583 584

    QStringList::const_iterator constIterator;
    for ( constIterator = fileNames.constBegin(); constIterator != fileNames.constEnd(); ++constIterator )
    {
        stdFileNames.push_back( ( *constIterator ).toLocal8Bit().constData() );
    }
585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612

    //
    // WE KNOW THAT THIS IS KIND OF A HACK. Iis is only provided to prevent naive users from having trouble.
    //
    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 );
    }
613
}
614

615 616 617 618 619 620 621 622 623 624 625 626 627 628 629
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." );
}

630 631 632 633 634 635 636
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
637
boost::signals2::signal1< void, std::vector< std::string > >* WMainWindow::getLoaderSignal()
638 639 640 641
{
    return &m_loaderSignal;
}

642 643 644
WIconManager*  WMainWindow::getIconManager()
{
    return &m_iconManager;
645
}
646 647 648 649 650 651 652 653 654 655

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


    // handle close event
    if ( reallyClose )
    {
656 657
        // signal everybody to shut down properly.
        WKernel::getRunningKernel()->finalize();
658 659 660 661

        // now nobody acesses the osg anymore
        // clean up gl widgets
        m_mainGLWidget->close();
662 663 664 665 666 667 668 669 670 671 672 673
        if( m_navAxial )
        {
            m_navAxial->close();
        }
        if( m_navCoronal )
        {
            m_navCoronal->close();
        }
        if( m_navSagittal )
        {
            m_navSagittal->close();
        }
674

675 676 677 678 679 680 681
        // 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();
        }
682
        //m_customDockWidgetsLock.unlock();
683

684 685 686 687 688 689 690 691 692
        // finally close
        e->accept();
    }
    else
    {
        e->ignore();
    }
}

693 694
void WMainWindow::customEvent( QEvent* event )
{
695
    if( event->type() == WOpenCustomDockWidgetEvent::CUSTOM_TYPE )
696
    {
697 698 699 700 701
        // OpenCustomDockWidgetEvent
        WOpenCustomDockWidgetEvent* ocdwEvent = static_cast< WOpenCustomDockWidgetEvent* >( event );
        std::string title = ocdwEvent->getTitle();

        boost::shared_ptr< WQtCustomDockWidget > widget;
702 703

        boost::mutex::scoped_lock lock( m_customDockWidgetsLock );
704 705
        if( m_customDockWidgets.count( title ) == 0 )
        {
706 707 708
            // create new custom dock widget
            widget = boost::shared_ptr< WQtCustomDockWidget >(
                new WQtCustomDockWidget( title, this, ocdwEvent->getProjectionMode() ) );
709 710 711 712 713 714 715
            addDockWidget( Qt::BottomDockWidgetArea, widget.get() );

            // store it in CustomDockWidget list
            m_customDockWidgets.insert( make_pair( title, widget ) );
        }
        else
        {
716 717
            widget = m_customDockWidgets[title];
            widget->increaseUseCount();
718
        }
719
        //m_customDockWidgetsLock.unlock();
720 721

        ocdwEvent->getFlag()->set( widget );
722 723 724 725 726 727 728 729
    }
    else
    {
        // other event
        QMainWindow::customEvent( event );
    }
}

730 731 732 733 734 735 736 737 738 739 740 741 742
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() );
        }
    }

743 744 745 746 747 748
    if ( event->type() == WQT_CRASH_EVENT )
    {
        // convert event to ready event
        WModuleCrashEvent* e1 = dynamic_cast< WModuleCrashEvent* >( event );     // NOLINT
        if ( e1 )
        {
749
            QString title = "Problem in module: " + QString::fromStdString( e1->getModule()->getName() );
750 751 752 753 754 755 756 757
            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();
758 759 760
        }
    }

761 762 763
    return QMainWindow::event( event );
}

764 765 766 767 768 769
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 >();
770
    //m_customDockWidgetsLock.unlock();
771 772 773 774
    return out;
}


775 776 777
void WMainWindow::closeCustomDockWidget( std::string title )
{
    boost::mutex::scoped_lock lock( m_customDockWidgetsLock );
778
    if( m_customDockWidgets.count( title ) > 0 )
779
    {
780 781 782 783 784
        if( m_customDockWidgets[title]->decreaseUseCount() )
        {
            // custom dock widget should be deleted
            m_customDockWidgets.erase( title );
        }
785
    }
786
    //m_customDockWidgetsLock.unlock();
787 788
}

schurade's avatar
schurade committed
789 790
void WMainWindow::newRoi()
{
Mathias Goldau's avatar
[MERGE]  
Mathias Goldau committed
791
    // do nothing if we can not get
792
    if( !WKernel::getRunningKernel()->getRoiManager()->getBitField() )
Mathias Goldau's avatar
[MERGE]  
Mathias Goldau committed
793
    {
794
        wlog::warn( "WMainWindow" ) << "Refused to add ROI, as ROIManager does not have computed its bitfield yet.";
Mathias Goldau's avatar
[MERGE]  
Mathias Goldau committed
795 796 797
        return;
    }

798 799 800 801
    wmath::WPosition crossHairPos = WKernel::getRunningKernel()->getSelectionManager()->getCrosshair()->getPosition();
    wmath::WPosition minROIPos = crossHairPos - wmath::WPosition( 10., 10., 10. );
    wmath::WPosition maxROIPos = crossHairPos + wmath::WPosition( 10., 10., 10. );

schurade's avatar
schurade committed
802
    if ( m_datasetBrowser->getFirstRoiInSelectedBranch().get() == NULL )
schurade's avatar
schurade committed
803
    {
804
        osg::ref_ptr< WROIBox > newRoi = osg::ref_ptr< WROIBox >( new WROIBox( minROIPos, maxROIPos ) );
schurade's avatar
schurade committed
805 806 807 808
        WKernel::getRunningKernel()->getRoiManager()->addRoi( newRoi );
    }
    else
    {
809
        osg::ref_ptr< WROIBox > newRoi = osg::ref_ptr< WROIBox >( new WROIBox( minROIPos, maxROIPos ) );
schurade's avatar
schurade committed
810
        WKernel::getRunningKernel()->getRoiManager()->addRoi( newRoi, m_datasetBrowser->getFirstRoiInSelectedBranch()->getROI() );
schurade's avatar
schurade committed
811 812
    }
}
813 814 815 816 817

void WMainWindow::setFibersLoaded()
{
    m_fibLoaded = true;
}
818 819 820 821 822 823 824

void WMainWindow::openConfigDialog()
{
    m_configWidget = boost::shared_ptr< WQtConfigWidget >( new WQtConfigWidget );

    m_configWidget->initAndShow();
}
825