WMainWindow.cpp 30.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"
49
#include "../../kernel/WKernel.h"
50
#include "../../kernel/WProjectFile.h"
51
#include "../../modules/data/WMData.h"
52
#include "../../modules/navSlices/WMNavSlices.h"
53
#include "../icons/WIcons.h"
Mathias Goldau's avatar
Mathias Goldau committed
54 55 56 57
#include "datasetbrowser/WPropertyBoolWidget.h"
#include "events/WEventTypes.h"
#include "events/WModuleCrashEvent.h"
#include "events/WModuleReadyEvent.h"
58
#include "events/WOpenCustomDockWidgetEvent.h"
Mathias Goldau's avatar
Mathias Goldau committed
59 60 61 62 63
#include "WQtCustomDockWidget.h"
#include "WQtGLWidget.h"
#include "WQtNavGLWidget.h"

#include "WMainWindow.h"
64

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

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

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

92 93 94 95 96 97
    // 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
98 99 100 101
    // 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.

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

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

123
    viewMenu->addAction( m_datasetBrowser->toggleViewAction() );
124 125
    viewMenu->addSeparator();

Sebastian Eichelbaum's avatar
Sebastian Eichelbaum committed
126 127 128 129 130 131 132 133 134
    // 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 ) );
135

136
    QMenu* helpMenu = m_menuBar->addMenu( "Help" );
Sebastian Eichelbaum's avatar
Sebastian Eichelbaum committed
137 138 139
    helpMenu->addAction( m_iconManager.getIcon( "help" ), "About OpenWalnut", this, SLOT( openAboutDialog() ),
                         QKeySequence( QKeySequence::HelpContents )
    );
140

141 142
    setMenuBar( m_menuBar );

143
    m_mainGLWidget = boost::shared_ptr< WQtGLWidget >( new WQtGLWidget( "main", this, WGECamera::ORTHOGRAPHIC ) );
144 145
    m_mainGLWidget->initialize();
    setCentralWidget( m_mainGLWidget.get() );
wiebel's avatar
wiebel committed
146

147 148 149 150 151
    // initially 3 navigation views
    {
        bool hideWidget;
        if( !( WPreferences::getPreference( "qt4gui.hideAxial", &hideWidget ) && hideWidget) )
        {
152
            m_navAxial = boost::shared_ptr< WQtNavGLWidget >( new WQtNavGLWidget( "axial", this, "Axial Slice" ) );
153
            m_navAxial->setFeatures( QDockWidget::AllDockWidgetFeatures );
154 155 156 157
            addDockWidget( Qt::LeftDockWidgetArea, m_navAxial.get() );
        }
        if( !( WPreferences::getPreference( "qt4gui.hideCoronal", &hideWidget ) && hideWidget) )
        {
158
            m_navCoronal = boost::shared_ptr< WQtNavGLWidget >( new WQtNavGLWidget( "coronal", this, "Coronal Slice" ) );
159
            m_navCoronal->setFeatures( QDockWidget::AllDockWidgetFeatures );
160 161 162 163
            addDockWidget( Qt::LeftDockWidgetArea, m_navCoronal.get() );
        }
        if( !( WPreferences::getPreference( "qt4gui.hideSagittal", &hideWidget ) && hideWidget) )
        {
164
            m_navSagittal = boost::shared_ptr< WQtNavGLWidget >( new WQtNavGLWidget( "sagittal", this, "Sagittal Slice" ) );
165
            m_navSagittal->setFeatures( QDockWidget::AllDockWidgetFeatures );
166 167 168
            addDockWidget( Qt::LeftDockWidgetArea, m_navSagittal.get() );
        }
    }
169

Mathias Goldau's avatar
[MERGE]  
Mathias Goldau committed
170 171 172 173 174 175 176 177 178
    // 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 );
    }

179
    // Default background color from config file
180
    {
181 182 183 184 185 186 187 188 189 190
        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 );
191 192 193 194 195 196 197 198 199 200 201 202 203

            if ( m_navAxial )
            {
                m_navAxial->getGLWidget()->setBgColor( bgColor );
            }
            if ( m_navCoronal )
            {
                m_navCoronal->getGLWidget()->setBgColor( bgColor );
            }
            if ( m_navSagittal )
            {
                m_navSagittal->getGLWidget()->setBgColor( bgColor );
            }
204
        }
205 206
    }

207
    setupPermanentToolBar();
208

209
    setupCompatiblesToolBar();
210
}
211

212
void WMainWindow::setupPermanentToolBar()
213
{
214
    m_permanentToolBar = new WQtToolBar( "Permanent Toolbar", this );
215

216 217 218 219
    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 );
220 221


222
    m_loadButton = new WQtPushButton( m_iconManager.getIcon( "load" ), "load", m_permanentToolBar );
223
    WQtPushButton* roiButton = new WQtPushButton( m_iconManager.getIcon( "ROI" ), "ROI", m_permanentToolBar );
224 225
    WQtPushButton* projectLoadButton = new WQtPushButton( m_iconManager.getIcon( "loadProject" ), "loadProject", m_permanentToolBar );
    WQtPushButton* projectSaveButton = new WQtPushButton( m_iconManager.getIcon( "saveProject" ), "saveProject", m_permanentToolBar );
226

227 228 229
    // setup save button
    QMenu* saveMenu = new QMenu( "Save Project", projectSaveButton );
    saveMenu->addAction( "Save Project", this, SLOT( projectSaveAll() ) );
230
    saveMenu->addAction( "Save Modules", this, SLOT( projectSaveModuleOnly() ) );
231 232 233 234 235
    saveMenu->addAction( "Save Camera", this, SLOT( projectSaveCameraOnly() ) );
    saveMenu->addAction( "Save ROIs", this, SLOT( projectSaveROIOnly() ) );
    projectSaveButton->setPopupMode( QToolButton::MenuButtonPopup );
    projectSaveButton->setMenu( saveMenu );

236
    connect( m_loadButton, SIGNAL( pressed() ), this, SLOT( openLoadDialog() ) );
237
    connect( roiButton, SIGNAL( pressed() ), this, SLOT( newRoi() ) );
238
    connect( projectLoadButton, SIGNAL( pressed() ), this, SLOT( projectLoad() ) );
239
    connect( projectSaveButton, SIGNAL( pressed() ), this, SLOT( projectSaveAll() ) );
240

241
    m_loadButton->setToolTip( "Load Data" );
242
    roiButton->setToolTip( "Create New ROI" );
243 244
    projectLoadButton->setToolTip( "Load a project from file" );
    projectSaveButton->setToolTip( "Save current project to file" );
245

246
    m_permanentToolBar->addWidget( m_loadButton );
247
    m_permanentToolBar->addSeparator();
248 249
    m_permanentToolBar->addWidget( projectLoadButton );
    m_permanentToolBar->addWidget( projectSaveButton );
250
    m_permanentToolBar->addSeparator();
251
    m_permanentToolBar->addWidget( roiButton );
252

253
    m_permanentToolBar->addSeparator();
254

255 256
    addToolBar( Qt::TopToolBarArea, m_permanentToolBar );
}
257

258 259 260 261 262 263 264 265 266 267
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 );
    }
}

268 269
void WMainWindow::moduleSpecificSetup( boost::shared_ptr< WModule > module )
{
270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285
    // 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
286
        if ( dataModule->getDataSet()->isA< WDataSetSingle >() && dataModule->getDataSet()->isTexture() )
287 288 289 290
        {
            // it is a dataset single
            // load a nav slice module if a WDataSetSingle is available!?

291
            // if it not already is running: add it
292 293
            if ( !WMNavSlices::isRunning() )
            {
294
                autoAdd( module, "Navigation Slices" );
295
            }
296 297 298 299
        }
        else if ( dataModule->getDataSet()->isA< WDataSetFibers >() )
        {
            // it is a fiber dataset -> add the FiberDisplay module
300 301 302 303 304 305

            // if it not already is running: add it
            if ( !WMFiberDisplay::isRunning() )
            {
                autoAdd( module, "Fiber Display" );
            }
306
        }
307
        else if ( dataModule->getDataSet()->isA< WEEG2 >() )
308
        {
309
            // it is a eeg dataset -> add the eegView module
310 311 312 313
            autoAdd( module, "EEG View" );
        }
    }

314
    // nav slices use separate buttons for slice on/off switching
315
    if ( module->getName() == "Navigation Slices" )
316
    {
317
        boost::shared_ptr< WPropertyBase > prop = module->getProperties()->findProperty( "showAxial" );
318 319 320
        if ( !prop )
        {
               WLogger::getLogger()->
321
                   addLogMessage( "Navigation Slices module does not provide the property \"showAxial\", which is required by the GUI.", "GUI",
322 323 324 325 326 327 328 329 330 331
                                  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 );
        }
332

333
        prop = module->getProperties()->findProperty( "showCoronal" );
334 335 336
        if ( !prop )
        {
               WLogger::getLogger()->
337
                   addLogMessage( "Navigation Slices module does not provide the property \"showCoronal\", which is required by the GUI.", "GUI",
338 339 340 341 342 343 344 345 346 347
                                  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 );
        }
348

349
        prop = module->getProperties()->findProperty( "showSagittal" );
350 351 352
        if ( !prop )
        {
               WLogger::getLogger()->
353
                   addLogMessage( "Navigation Slices module does not provide the property \"showSagittal\", which is required by the GUI.", "GUI",
354 355 356 357 358 359 360 361 362 363
                                  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 );
        }
364 365

        // now setup the nav widget sliders
366
        prop = module->getProperties()->findProperty( "Axial Slice" );
367 368 369
        if ( !prop )
        {
               WLogger::getLogger()->
370
                   addLogMessage( "Navigation Slices module does not provide the property \"Axial Slice\", which is required by the GUI.", "GUI",
371 372 373 374
                                  LL_ERROR );
        }
        else
        {
375 376 377 378
            if( m_navAxial )
            {
                m_navAxial->setSliderProperty( prop->toPropInt() );
            }
379 380
        }

381
        prop = module->getProperties()->findProperty( "Coronal Slice" );
382 383 384
        if ( !prop )
        {
               WLogger::getLogger()->
385
                   addLogMessage( "Navigation Slices module does not provide the property \"Coronal Slice\", which is required by the GUI.", "GUI",
386 387 388 389
                                  LL_ERROR );
        }
        else
        {
390 391 392 393
            if( m_navCoronal )
            {
                m_navCoronal->setSliderProperty( prop->toPropInt() );
            }
394 395
        }

396
        prop = module->getProperties()->findProperty( "Sagittal Slice" );
397 398 399
        if ( !prop )
        {
               WLogger::getLogger()->
400
                   addLogMessage( "Navigation Slices module does not provide the property \"Sagittal Slice\", which is required by the GUI.", "GUI",
401 402 403 404
                                  LL_ERROR );
        }
        else
        {
405 406 407 408
            if( m_navSagittal )
            {
               m_navSagittal->setSliderProperty( prop->toPropInt() );
            }
409
        }
410
    }
wiebel's avatar
wiebel committed
411
}
412

413 414
void WMainWindow::setupCompatiblesToolBar()
{
415 416
    m_iconManager.addIcon( std::string( "o" ), o_xpm ); // duumy icon for modules

417
    m_compatiblesToolBar = new WQtToolBar( "Compatible Modules Toolbar", this );
418 419 420 421 422 423 424

    // optional toolbar break
    {
        bool useToolBarBreak = true;
        WPreferences::getPreference( "qt4gui.useToolBarBreak", &useToolBarBreak );
        if( useToolBarBreak )
        {
425 426 427 428
            // 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 );
429 430 431 432
            addToolBarBreak( Qt::TopToolBarArea );
        }
    }

433 434
    addToolBar( Qt::TopToolBarArea, m_compatiblesToolBar );
}
435

436
WQtDatasetBrowser* WMainWindow::getDatasetBrowser()
437
{
438
    return m_datasetBrowser;
439
}
440

441
WQtToolBar* WMainWindow::getCompatiblesToolBar()
442 443 444 445
{
    return m_compatiblesToolBar;
}

446
void WMainWindow::projectSave( const std::vector< boost::shared_ptr< WProjectFileIO > >& writer )
447 448 449 450
{
    QFileDialog fd;
    fd.setWindowTitle( "Save Project as" );
    fd.setFileMode( QFileDialog::AnyFile );
451
    fd.setAcceptMode( QFileDialog::AcceptSave );
452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470

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

471 472 473
        try
        {
            // This call is synchronous.
474 475 476 477 478 479 480 481
            if ( writer.empty() )
            {
                proj->save();
            }
            else
            {
                proj->save( writer );
            }
482 483 484 485 486 487 488 489
        }
        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 );
        }
490 491 492
    }
}

493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513
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 );
}

514 515 516 517 518 519 520
void WMainWindow::projectSaveModuleOnly()
{
    std::vector< boost::shared_ptr< WProjectFileIO > > w;
    w.push_back( WProjectFile::getModuleWriter() );
    projectSave( w );
}

521 522 523 524 525 526
void WMainWindow::projectLoad()
{
    QFileDialog fd;
    fd.setFileMode( QFileDialog::ExistingFiles );

    QStringList filters;
527
    filters << "Simple Project File (*.owproj)"
528 529 530 531 532 533 534 535 536 537 538 539
            << "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 )
    {
540 541
        boost::shared_ptr< WProjectFile > proj = boost::shared_ptr< WProjectFile >(
                new WProjectFile( ( *constIterator ).toStdString() )
542
        );
543 544

        // This call is asynchronous. It parses the file and the starts a thread to actually do all the stuff
545
        proj->load();
546 547 548
    }
}

549
void WMainWindow::openLoadDialog()
550
{
551 552
    QFileDialog fd;
    fd.setFileMode( QFileDialog::ExistingFiles );
wiebel's avatar
wiebel committed
553 554

    QStringList filters;
555 556
    filters << "Known file types (*.cnt *.edf *.asc *.nii *.nii.gz *.fib)"
            << "EEG files (*.cnt *.edf *.asc)"
wiebel's avatar
wiebel committed
557
            << "NIfTI (*.nii *.nii.gz)"
558 559
            << "Fibers (*.fib)"
            << "Any files (*)";
wiebel's avatar
wiebel committed
560
    fd.setNameFilters( filters );
561 562 563 564 565 566 567
    fd.setViewMode( QFileDialog::Detail );
    QStringList fileNames;
    if ( fd.exec() )
    {
        fileNames = fd.selectedFiles();
    }

568
    std::vector< std::string > stdFileNames;
569 570 571 572 573 574

    QStringList::const_iterator constIterator;
    for ( constIterator = fileNames.constBegin(); constIterator != fileNames.constEnd(); ++constIterator )
    {
        stdFileNames.push_back( ( *constIterator ).toLocal8Bit().constData() );
    }
575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602

    //
    // 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 );
    }
603 604 605

    // walkaround that a button keeps his down state after invoking a dialog
    m_loadButton->setDown( false );
606
}
607

608 609 610 611 612 613 614 615 616 617 618 619 620 621 622
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." );
}

623 624 625 626 627 628 629
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
630
boost::signals2::signal1< void, std::vector< std::string > >* WMainWindow::getLoaderSignal()
631 632 633 634
{
    return &m_loaderSignal;
}

635 636 637
WIconManager*  WMainWindow::getIconManager()
{
    return &m_iconManager;
638
}
639 640 641 642 643 644 645 646 647 648

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


    // handle close event
    if ( reallyClose )
    {
649 650
        // signal everybody to shut down properly.
        WKernel::getRunningKernel()->finalize();
651 652 653 654

        // now nobody acesses the osg anymore
        // clean up gl widgets
        m_mainGLWidget->close();
655 656 657 658 659 660 661 662 663 664 665 666
        if( m_navAxial )
        {
            m_navAxial->close();
        }
        if( m_navCoronal )
        {
            m_navCoronal->close();
        }
        if( m_navSagittal )
        {
            m_navSagittal->close();
        }
667

668 669 670 671 672 673 674
        // 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();
        }
675
        //m_customDockWidgetsLock.unlock();
676

677 678 679 680 681 682 683 684 685
        // finally close
        e->accept();
    }
    else
    {
        e->ignore();
    }
}

686 687
void WMainWindow::customEvent( QEvent* event )
{
688
    if( event->type() == WOpenCustomDockWidgetEvent::CUSTOM_TYPE )
689
    {
690 691 692 693 694
        // OpenCustomDockWidgetEvent
        WOpenCustomDockWidgetEvent* ocdwEvent = static_cast< WOpenCustomDockWidgetEvent* >( event );
        std::string title = ocdwEvent->getTitle();

        boost::shared_ptr< WQtCustomDockWidget > widget;
695 696

        boost::mutex::scoped_lock lock( m_customDockWidgetsLock );
697 698
        if( m_customDockWidgets.count( title ) == 0 )
        {
699 700 701
            // create new custom dock widget
            widget = boost::shared_ptr< WQtCustomDockWidget >(
                new WQtCustomDockWidget( title, this, ocdwEvent->getProjectionMode() ) );
702 703 704 705 706 707 708
            addDockWidget( Qt::BottomDockWidgetArea, widget.get() );

            // store it in CustomDockWidget list
            m_customDockWidgets.insert( make_pair( title, widget ) );
        }
        else
        {
709 710
            widget = m_customDockWidgets[title];
            widget->increaseUseCount();
711
        }
712
        //m_customDockWidgetsLock.unlock();
713 714

        ocdwEvent->getFlag()->set( widget );
715 716 717 718 719 720 721 722
    }
    else
    {
        // other event
        QMainWindow::customEvent( event );
    }
}

723 724 725 726 727 728 729 730 731 732 733 734 735
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() );
        }
    }

736 737 738 739 740 741
    if ( event->type() == WQT_CRASH_EVENT )
    {
        // convert event to ready event
        WModuleCrashEvent* e1 = dynamic_cast< WModuleCrashEvent* >( event );     // NOLINT
        if ( e1 )
        {
742
            QString title = "Problem in module: " + QString::fromStdString( e1->getModule()->getName() );
743 744 745 746 747 748 749 750
            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();
751 752 753
        }
    }

754 755 756
    return QMainWindow::event( event );
}

757 758 759 760 761 762
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 >();
763
    //m_customDockWidgetsLock.unlock();
764 765 766 767
    return out;
}


768 769 770
void WMainWindow::closeCustomDockWidget( std::string title )
{
    boost::mutex::scoped_lock lock( m_customDockWidgetsLock );
771
    if( m_customDockWidgets.count( title ) > 0 )
772
    {
773 774 775 776 777
        if( m_customDockWidgets[title]->decreaseUseCount() )
        {
            // custom dock widget should be deleted
            m_customDockWidgets.erase( title );
        }
778
    }
779
    //m_customDockWidgetsLock.unlock();
780 781
}

schurade's avatar
schurade committed
782 783
void WMainWindow::newRoi()
{
Mathias Goldau's avatar
[MERGE]  
Mathias Goldau committed
784
    // do nothing if we can not get
785
    if( !WKernel::getRunningKernel()->getRoiManager()->getBitField() )
Mathias Goldau's avatar
[MERGE]  
Mathias Goldau committed
786
    {
787
        wlog::warn( "WMainWindow" ) << "Refused to add ROI, as ROIManager does not have computed its bitfield yet.";
Mathias Goldau's avatar
[MERGE]  
Mathias Goldau committed
788 789 790
        return;
    }

791 792 793 794
    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
795
    if ( m_datasetBrowser->getFirstRoiInSelectedBranch().get() == NULL )
schurade's avatar
schurade committed
796
    {
797
        osg::ref_ptr< WROIBox > newRoi = osg::ref_ptr< WROIBox >( new WROIBox( minROIPos, maxROIPos ) );
schurade's avatar
schurade committed
798 799 800 801
        WKernel::getRunningKernel()->getRoiManager()->addRoi( newRoi );
    }
    else
    {
802
        osg::ref_ptr< WROIBox > newRoi = osg::ref_ptr< WROIBox >( new WROIBox( minROIPos, maxROIPos ) );
schurade's avatar
schurade committed
803
        WKernel::getRunningKernel()->getRoiManager()->addRoi( newRoi, m_datasetBrowser->getFirstRoiInSelectedBranch()->getROI() );
schurade's avatar
schurade committed
804 805
    }
}
806 807 808 809 810

void WMainWindow::setFibersLoaded()
{
    m_fibLoaded = true;
}
811 812 813

void WMainWindow::openConfigDialog()
{
814 815 816 817 818
    if ( m_configWidget.get() )
    {
        m_configWidget->wait( true );
    }

819 820 821 822
    m_configWidget = boost::shared_ptr< WQtConfigWidget >( new WQtConfigWidget );

    m_configWidget->initAndShow();
}
823