WMainWindow.cpp 52.7 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
#include <boost/thread.hpp>
31
#include <boost/regex.hpp>
32
#include <boost/filesystem.hpp>
33

34
#include <QtGui/QApplication>
35
#include <QtGui/QCloseEvent>
wiebel's avatar
wiebel committed
36
#include <QtGui/QDockWidget>
37
#include <QtGui/QFileDialog>
38
#include <QtGui/QIcon>
Mathias Goldau's avatar
Mathias Goldau committed
39 40
#include <QtGui/QMenu>
#include <QtGui/QMenuBar>
41
#include <QtGui/QMessageBox>
42
#include <QtGui/QTextEdit>
43
#include <QtGui/QShortcut>
Mathias Goldau's avatar
Mathias Goldau committed
44
#include <QtGui/QSlider>
45
#include <QtGui/QVBoxLayout>
46
#include <QtGui/QWidget>
47
#include <QtCore/QSettings>
48
#include <QtCore/QUrl>
49
#include <QtGui/QInputDialog>
50

51 52 53 54
#ifndef QT4GUI_NOWEBKIT
    #include <QtWebKit/QWebView>
#endif

55
#include "core/WVersion.h"   // NOTE: this file is auto-generated by CMAKE
56

57 58
#include "controlPanel/WPropertyBoolWidget.h"
#include "controlPanel/WQtControlPanel.h"
59 60 61
#include "core/common/WColor.h"
#include "core/common/WIOTools.h"
#include "core/common/WPathHelper.h"
62
#include "core/common/WProjectFileIO.h"
63
#include "core/dataHandler/WDataHandler.h"
64 65
#include "core/dataHandler/WDataSetFibers.h"
#include "core/dataHandler/WDataSetSingle.h"
66
#include "core/dataHandler/WDataSetPoints.h"
67 68 69
#include "core/dataHandler/WEEG2.h"
#include "core/graphicsEngine/WGEZoomTrackballManipulator.h"
#include "core/graphicsEngine/WROIBox.h"
70
#include "core/kernel/WDataModule.h"
71 72 73 74 75 76 77
#include "core/kernel/WKernel.h"
#include "core/kernel/WModule.h"
#include "core/kernel/WModuleCombiner.h"
#include "core/kernel/WModuleCombinerTypes.h"
#include "core/kernel/WProjectFile.h"
#include "core/kernel/WROIManager.h"
#include "core/kernel/WSelectionManager.h"
Mathias Goldau's avatar
Mathias Goldau committed
78 79 80
#include "events/WEventTypes.h"
#include "events/WModuleCrashEvent.h"
#include "events/WModuleReadyEvent.h"
81
#include "events/WModuleRemovedEvent.h"
82
#include "events/WOpenCustomDockWidgetEvent.h"
83
#include "events/WCloseCustomDockWidgetEvent.h"
84
#include "events/WLoadFinishedEvent.h"
85
#include "events/WLogEvent.h"
Sebastian Eichelbaum's avatar
[MERGE]  
Sebastian Eichelbaum committed
86
#include "guiElements/WQtPropertyBoolAction.h"
87
#include "WQtMessagePopup.h"
88
#include "WQt4Gui.h"
89
#include "WQtCombinerToolbar.h"
Mathias Goldau's avatar
Mathias Goldau committed
90
#include "WQtCustomDockWidget.h"
91
#include "WQtGLDockWidget.h"
92
#include "WQtNavGLWidget.h"
93
#include "WSettingAction.h"
94
#include "WSettingMenu.h"
95
#include "WQtMessageDialog.h"
96
#include "WQtGLScreenCapture.h"
Mathias Goldau's avatar
Mathias Goldau committed
97 98

#include "WMainWindow.h"
99
#include "WMainWindow.moc"
100

101
WMainWindow::WMainWindow( QSplashScreen* splash ):
102
    QMainWindow(),
103
    m_splash( splash ),
104
    m_currentCompatiblesToolbar( NULL ),
105
    m_iconManager()
Sebastian Eichelbaum's avatar
Sebastian Eichelbaum committed
106
{
107
    setAcceptDrops( true ); // enable drag and drop events
Sebastian Eichelbaum's avatar
Sebastian Eichelbaum committed
108
}
109

110 111 112 113 114
WMainWindow::~WMainWindow()
{
    // cleanup
}

115
void WMainWindow::setupGUI()
116
{
117 118
    wlog::info( "WMainWindow" ) << "Setting up GUI";

119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // Setting setup
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    WSettingAction* hideMenuAction = new WSettingAction( this, "qt4gui/showMenu",
                                                               "Show Menubar",
                                                               "Allows you to hide the menu. Can be restored using CTRL-M.",
                                                               true,
                                                               false,
                                                               QKeySequence( Qt::CTRL + Qt::Key_M ) );

    WSettingAction* showNavWidgets = new WSettingAction( this, "qt4gui/showNavigationWidgets",
                                                               "Show Navigation Views",
                                                               "Disables the navigation views completely. This can lead to a speed-up and is "
                                                               "recommended for those who do not need them.",
                                                               true,
                                                               true    // this requires a restart
                                                       );
    m_autoDisplaySetting = new WSettingAction( this, "qt4gui/useAutoDisplay",
                                                     "Auto-Display",
                                                     "If enabled, the best matching module is automatically added if some data was loaded.",
                                                     true );
141 142 143 144
    m_sliderMinMaxEditSetting = new WSettingAction( this, std::string( "qt4gui/" ) +  std::string( "sliderMinMaxEdit" ),
                                                    "Slider Min/Max Editing",
                                                    "If enabled, the maximum and minimum values of slider can be edited.",
                                                    false );
145 146

    WSettingAction* mtViews = new WSettingAction( this, "qt4gui/ge/multiThreadedViewer",
Alexander Wiebel's avatar
Alexander Wiebel committed
147
                                                        "Multi-Threaded Views",
148
                                                        "If enabled, the graphic windows are rendered in different threads. This can speed-up "
149
                                                        "rendering on machines with multiple cores. WARNING: can lead to crashes sometimes.",
150 151 152 153 154 155
                                                        false,
                                                        true // require restart
                                                );
    // NOTE: the multi-threading feature needs to be activated BEFORE the first viewer is created. To ensure this we do it here.
    WGraphicsEngine::getGraphicsEngine()->setMultiThreadedViews( mtViews->get() );

156 157 158 159 160 161 162 163 164
    // set the log-level setting.
    // NOTE: see WQt4Gui which reads the setting.
    QList< QString > logOptions;
    logOptions.push_back( "Debug" );
    logOptions.push_back( "Info" );
    logOptions.push_back( "Warning" );
    logOptions.push_back( "Error" );
    WSettingMenu* logLevels = new WSettingMenu( this, "qt4gui/logLevel",
                                                      "Log-Level",
165
                                                      "Allows one to set the log verbosity.",
166 167 168 169 170
                                                      1,    // info is the default
                                                      logOptions
                                              );
    connect( logLevels, SIGNAL( change( unsigned int ) ), this, SLOT( handleLogLevelUpdate( unsigned int ) ) );

171 172 173 174
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // GUI setup
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////

175
    // We need several icons later in the GUI. Build some mappings:
176
    m_iconManager.addMapping( "logo", "openwalnut" );
177 178 179 180 181 182 183 184 185 186
    m_iconManager.addMapping( "axial icon", "orientation_axial" );
    m_iconManager.addMapping( "coronal icon", "orientation_coronal" );
    m_iconManager.addMapping( "sagittal icon", "orientation_sagittal" );
    m_iconManager.addMapping( "ROI icon", "roi" );
    m_iconManager.addMapping( "DefaultModuleIcon", "default" );
    m_iconManager.addMapping( "missingModule", "question" );
    m_iconManager.addMapping( "view", "camera" );
    m_iconManager.addMapping( "moduleCrashed", "error" );
    m_iconManager.addMapping( "moduleBusy", "busy" );
    m_iconManager.addMapping( "saveProject", "save" );
Sebastian Eichelbaum's avatar
[MERGE]  
Sebastian Eichelbaum committed
187
    m_iconManager.addMapping( "newProject", "new" );
188

189
    if( objectName().isEmpty() )
190
    {
191
        setObjectName( QString::fromUtf8( "MainWindow" ) );
192
    }
193 194 195

    // NOTE: this only is an initial size. The state reloaded from QSettings will set it to the value the user had last session.
    resize( 800, 600 );
196
    setWindowIcon( m_iconManager.getIcon( "logo" ) );
197 198
    std::string windowHeading =  std::string( "OpenWalnut " ) + std::string( W_VERSION );
    setWindowTitle( QApplication::translate( "MainWindow", windowHeading.c_str(), 0, QApplication::UnicodeUTF8 ) );
199

200 201
    setDockOptions( QMainWindow::AnimatedDocks |  QMainWindow::AllowNestedDocks | QMainWindow::AllowTabbedDocks );

202
    //network Editor
203
    m_networkEditor = NULL;
204 205
    m_networkEditor = new WQtNetworkEditor( this );
    m_networkEditor->setFeatures( QDockWidget::AllDockWidgetFeatures );
206

207 208 209
    // strangely, the QGraphics* objects do not properly forward drag/drop events. We need to explicitly handle them.
    connect( m_networkEditor->getView(), SIGNAL( dragDrop( QDropEvent* ) ),
             this, SLOT( handleDrop( QDropEvent* ) ) );
210

211 212 213 214
    // the control panel instance is needed for the menu
    m_controlPanel = new WQtControlPanel( this );
    m_controlPanel->setFeatures( QDockWidget::AllDockWidgetFeatures );
    m_controlPanel->addSubject( "Default Subject" );
215

216 217
    // add all docks
    addDockWidget( Qt::RightDockWidgetArea, m_controlPanel->getModuleDock() );
218 219 220 221
    if( m_networkEditor )
    {
        addDockWidget( Qt::RightDockWidgetArea, m_networkEditor );
    }
222

223
    addDockWidget( Qt::RightDockWidgetArea, m_controlPanel->getColormapperDock() );
224
    addDockWidget( Qt::RightDockWidgetArea, m_controlPanel->getRoiDock() );
225

226 227 228 229
    // the message dock:
    m_messageDock = new WQtMessageDock( "Messages", this );
    addDockWidget( Qt::RightDockWidgetArea, m_messageDock );

230
    // tabify those panels by default
231 232 233 234
    if( m_networkEditor )
    {
        tabifyDockWidget( m_networkEditor, m_controlPanel->getModuleDock() );
    }
235
    tabifyDockWidget( m_controlPanel->getModuleDock(), m_controlPanel->getColormapperDock() );
236
    tabifyDockWidget( m_controlPanel->getColormapperDock(), m_controlPanel->getRoiDock() );
237
    tabifyDockWidget( m_controlPanel->getRoiDock(), m_messageDock );
238

239
    m_glDock = new QMainWindow();
240
    m_glDock->setObjectName( "GLDock" );
241 242 243
    m_glDock->setDockOptions( QMainWindow::AnimatedDocks |  QMainWindow::AllowNestedDocks | QMainWindow::AllowTabbedDocks );
    m_glDock->setDocumentMode( true );
    setCentralWidget( m_glDock );
244
    WQtGLDockWidget* mainGLDock = new WQtGLDockWidget( "Main View", "3D View", m_glDock );
245 246
    mainGLDock->getGLWidget()->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
    m_mainGLWidget = mainGLDock->getGLWidget();
247
    m_mainGLWidgetScreenCapture = m_mainGLWidget->getScreenCapture( this );
248
    m_glDock->addDockWidget( Qt::RightDockWidgetArea, mainGLDock );
249
    addDockWidget( Qt::RightDockWidgetArea, m_mainGLWidgetScreenCapture );
250
    tabifyDockWidget( m_controlPanel->getRoiDock(), m_mainGLWidgetScreenCapture );
251
    connect( m_mainGLWidget.get(), SIGNAL( renderedFirstFrame() ), this, SLOT( handleGLVendor() ) );
252

253 254 255
    addDockWidget( Qt::RightDockWidgetArea, m_controlPanel );

    // by default, the module editor should be in front
256 257 258 259 260 261 262 263
    if( m_networkEditor )
    {
        m_networkEditor->raise();
    }
    else
    {
        m_controlPanel->getModuleDock()->raise();
    }
264

265 266
    // NOTE: we abuse the gl widgets first frame event to handle startup news.
    connect( m_mainGLWidget.get(), SIGNAL( renderedFirstFrame() ), this, SLOT( handleStartMessages() ) );
267
    connect( m_mainGLWidget.get(), SIGNAL( renderedFirstFrame() ), this, SLOT( closeSplash() ) );
268

269
    m_permanentToolBar = new WQtToolBar( "Standard Toolbar", this );
270
    addToolBar( Qt::TopToolBarArea, m_permanentToolBar );
271

272
    m_loadButton = new QAction( m_iconManager.getIcon( "load" ), "Load Dataset or Project", m_permanentToolBar );
273
    m_loadButton->setShortcut( QKeySequence(  QKeySequence::Open ) );
274 275
    QAction* roiButton = new QAction( m_iconManager.getIcon( "ROI icon" ), "ROI", m_permanentToolBar );
    QAction* resetButton = new QAction( m_iconManager.getIcon( "view" ), "Reset", m_permanentToolBar );
276
    m_saveAction = new QAction( m_iconManager.getIcon( "saveProject" ), "Save Project", m_permanentToolBar );
277 278 279 280

    connect( m_loadButton, SIGNAL(  triggered( bool ) ), this, SLOT( openLoadDialog() ) );
    connect( resetButton, SIGNAL(  triggered( bool ) ), m_mainGLWidget.get(), SLOT( reset() ) );
    connect( roiButton, SIGNAL(  triggered( bool ) ), this, SLOT( newRoi() ) );
281
    connect( m_saveAction, SIGNAL( triggered( bool ) ), this, SLOT( projectSaveAll() ) );
282

283
    m_loadButton->setToolTip( "Load a dataset or project from file" );
284
    resetButton->setToolTip( "Reset main view" );
285
    roiButton->setToolTip( "Create new ROI" );
286
    m_saveAction->setToolTip( "Save current project to file" );
287 288 289

    // we want the upper most tree item to be selected. This helps to make the always compatible modules
    // show up in the tool bar from the beginning. And ... it doesn't hurt.
290
    m_controlPanel->selectUpperMostEntry();
291

Sebastian Eichelbaum's avatar
Sebastian Eichelbaum committed
292 293 294 295
    // 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.

296
    m_menuBar = new QMenuBar( this );
297 298

    // hide menu?
299 300 301
    m_menuBar->setVisible( hideMenuAction->get() );
    connect( hideMenuAction, SIGNAL( change( bool ) ), m_menuBar, SLOT( setVisible( bool ) ) );
    addAction( hideMenuAction );
302

303
    QMenu* fileMenu = m_menuBar->addMenu( "File" );
304

305 306 307 308 309
    m_newAction = fileMenu->addAction( m_iconManager.getIcon( "newProject" ),
                                       "New Project",
                                       this,
                                       SLOT( newProject() ),
                                       QKeySequence( Qt::CTRL + Qt::Key_N ) );
310
    fileMenu->addAction( m_loadButton );
311 312 313 314 315 316
    m_saveMenu = fileMenu->addMenu( m_iconManager.getIcon( "saveProject" ), "Save Project" );
    m_saveMenu->addAction( "Save Project", this, SLOT( projectSaveAll() ), QKeySequence::Save );
    m_saveMenu->addAction( "Save Modules Only", this, SLOT( projectSaveModuleOnly() ) );
    m_saveMenu->addAction( "Save Camera Only", this, SLOT( projectSaveCameraOnly() ) );
    // saveMenu->addAction( "Save ROIs Only", this, SLOT( projectSaveROIOnly() ) );
    m_saveAction->setMenu( m_saveMenu );
317

318
    fileMenu->addSeparator();
319 320
    // 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 ) );
321
    m_quitAction = fileMenu->addAction( m_iconManager.getIcon( "quit" ), "Quit", this, SLOT( close() ),  QKeySequence( Qt::CTRL + Qt::Key_Q ) );
Sebastian Eichelbaum's avatar
Sebastian Eichelbaum committed
322

Sebastian Eichelbaum's avatar
Sebastian Eichelbaum committed
323
    // This QAction stuff is quite ugly and complicated some times ... There is no nice constructor which takes name, slot keysequence and so on
324
    // directly -> set shortcuts, and some further properties using QAction's interface
325

326 327 328 329 330 331 332 333
    m_viewAction = new QAction( "View", this );
    m_viewMenu = m_menuBar->addMenu( "View" );
    m_viewMenu->addAction( hideMenuAction );
    m_viewMenu->addSeparator();
    m_viewMenu->addAction( showNavWidgets );
    m_viewMenu->addSeparator();
    m_viewMenu->addMenu( m_permanentToolBar->getStyleMenu() );
    m_viewAction->setMenu( m_viewMenu );
334 335

    // Camera menu
336 337 338 339 340 341 342 343
    m_cameraAction = new QAction( "Camera", this );
    m_cameraMenu = m_menuBar->addMenu( "Camera" );
    m_cameraMenu->addAction( mainGLDock->getGLWidget()->getThrowingSetting() );
    m_cameraAction->setMenu( m_cameraMenu );

    m_settingsAction = new QAction( "Settings", this );
    m_settingsMenu = m_menuBar->addMenu( "Settings" );
    m_settingsMenu->addAction( m_autoDisplaySetting );
344
    m_settingsMenu->addAction( m_sliderMinMaxEditSetting );
345 346 347 348 349 350
    m_settingsMenu->addAction( m_controlPanel->getModuleConfig().getConfigureAction() );
    m_settingsMenu->addSeparator();
    m_settingsMenu->addAction( mtViews );
    m_settingsMenu->addSeparator();
    m_settingsMenu->addMenu( logLevels );
    m_settingsAction->setMenu( m_settingsMenu );
351

352 353 354 355 356
    QAction* controlPanelTrigger = m_controlPanel->toggleViewAction();
    QList< QKeySequence > controlPanelShortcut;
    controlPanelShortcut.append( QKeySequence( Qt::Key_F9 ) );
    controlPanelTrigger->setShortcuts( controlPanelShortcut );
    this->addAction( controlPanelTrigger );  // this enables the action even if the menu bar is invisible
357

358
    m_cameraMenu->addAction( m_mainGLWidget->getCameraResetAction() );
359
    m_cameraMenu->addMenu( m_mainGLWidget->getCameraPresetsMenu() );
360
    resetButton->setMenu( m_mainGLWidget->getCameraPresetsMenu() );
361

362 363 364 365 366 367 368
    m_helpAction = new QAction( "Help", this );
    m_helpMenu = m_menuBar->addMenu( "Help" );
    m_helpMenu->addAction( m_iconManager.getIcon( "help" ), "OpenWalnut Help", this, SLOT( openOpenWalnutHelpDialog() ),
                           QKeySequence( QKeySequence::HelpContents ) );
    m_helpMenu->addAction( m_iconManager.getIcon( "logo" ), "Welcome to OpenWalnut", this, SLOT( showWelcomeDialog() ) );
    m_helpMenu->addSeparator();
    m_helpMenu->addAction( m_iconManager.getIcon( "logo" ), "About OpenWalnut", this, SLOT( openAboutDialog() ) );
Alexander Wiebel's avatar
Alexander Wiebel committed
369
    m_helpMenu->addAction(  m_iconManager.getIcon( "qt" ), "About Qt", this, SLOT( openAboutQtDialog() ) );
370
    m_helpAction->setMenu( m_helpMenu );
371

372 373
    setMenuBar( m_menuBar );

374 375
    // initially 3 navigation views
    {
376
        if( showNavWidgets->get() )
377
        {
Sebastian Eichelbaum's avatar
[STYLE]  
Sebastian Eichelbaum committed
378
            m_navAxial = boost::shared_ptr< WQtNavGLWidget >( new WQtNavGLWidget( "Axial View", "Axial View", this, "Axial Slice",
379
                                                                                  m_mainGLWidget.get() ) );
380
            m_navAxial->setFeatures( QDockWidget::AllDockWidgetFeatures );
381
            m_navAxial->setSliderProperty( WKernel::getRunningKernel()->getSelectionManager()->getPropAxialPos() );
382
            m_navAxial->getGLWidget()->setCameraManipulator( WQtGLWidget::NO_OP );
383

384
            m_glDock->addDockWidget( Qt::LeftDockWidgetArea, m_navAxial.get() );
385

386 387
            m_navCoronal = boost::shared_ptr< WQtNavGLWidget >( new WQtNavGLWidget( "Coronal View", "Coronal View", this, "Coronal Slice",
                                                                                    m_mainGLWidget.get() ) );
388
            m_navCoronal->setFeatures( QDockWidget::AllDockWidgetFeatures );
389
            m_navCoronal->setSliderProperty( WKernel::getRunningKernel()->getSelectionManager()->getPropCoronalPos() );
390
            m_navCoronal->getGLWidget()->setCameraManipulator( WQtGLWidget::NO_OP );
391

392
            m_glDock->addDockWidget( Qt::LeftDockWidgetArea, m_navCoronal.get() );
393

ledig's avatar
ledig committed
394
            m_navSagittal =
395 396
                boost::shared_ptr< WQtNavGLWidget >( new WQtNavGLWidget( "Sagittal View", "Sagittal View", this, "Sagittal Slice",
                                                                         m_mainGLWidget.get() ) );
397
            m_navSagittal->setFeatures( QDockWidget::AllDockWidgetFeatures );
398
            m_navSagittal->setSliderProperty( WKernel::getRunningKernel()->getSelectionManager()->getPropSagittalPos() );
399
            m_navSagittal->getGLWidget()->setCameraManipulator( WQtGLWidget::NO_OP );
400

401
            m_glDock->addDockWidget( Qt::LeftDockWidgetArea, m_navSagittal.get() );
402 403 404
        }
    }

405 406 407
    // create the show/hide actions using the selection manager's props
    WQtPropertyBoolAction* showAxial = new WQtPropertyBoolAction( WKernel::getRunningKernel()->getSelectionManager()->getPropAxialShow(),
                                                                  m_permanentToolBar );
408
    showAxial->setToolTip( "Toggle axial slice" );
409 410 411 412 413
    showAxial->setText( "Toggle Axial Slice" );
    showAxial->setIcon( m_iconManager.getIcon( "axial icon" ) );

    WQtPropertyBoolAction* showCoronal = new WQtPropertyBoolAction( WKernel::getRunningKernel()->getSelectionManager()->getPropCoronalShow(),
                                                                    m_permanentToolBar );
414
    showCoronal->setToolTip( "Toggle coronal slice" );
415 416 417 418 419
    showCoronal->setText( "Toggle Coronal Slice" );
    showCoronal->setIcon( m_iconManager.getIcon( "coronal icon" ) );

    WQtPropertyBoolAction* showSagittal = new WQtPropertyBoolAction( WKernel::getRunningKernel()->getSelectionManager()->getPropSagittalShow(),
                                                                     m_permanentToolBar );
420
    showSagittal->setToolTip( "Toggle sagittal slice" );
421 422 423
    showSagittal->setText( "Toggle Sagittal Slice" );
    showSagittal->setIcon( m_iconManager.getIcon( "sagittal icon" ) );

424
    // setup permanent toolbar
425
    m_permanentToolBar->addAction( m_newAction );
426
    m_permanentToolBar->addAction( m_loadButton );
427
    m_permanentToolBar->addAction( m_saveAction );
428
    m_permanentToolBar->addSeparator();
429 430
    m_permanentToolBar->addAction( m_mainGLWidgetScreenCapture->getScreenshotTrigger() );
    m_permanentToolBar->addSeparator();
431 432
    m_permanentToolBar->addAction( resetButton );
    m_permanentToolBar->addAction( roiButton );
433
    m_permanentToolBar->addSeparator();
434 435 436 437
    m_permanentToolBar->addAction( showAxial );
    m_permanentToolBar->addAction( showCoronal );
    m_permanentToolBar->addAction( showSagittal );
    m_permanentToolBar->addSeparator();
438

439 440 441
    // allow the control panel to complete setup
    m_controlPanel->completeGuiSetup();

442 443
    // after creating the GUI, restore its saved state
    restoreSavedState();
444
}
445

446
void WMainWindow::autoAdd( boost::shared_ptr< WModule > module, std::string proto, bool onlyOnce )
447
{
448 449 450 451 452 453
    // if only one module should be added, and there already is one --- skip.
    if( onlyOnce && !WKernel::getRunningKernel()->getRootContainer()->getModules( proto ).empty() )
    {
        return;
    }

454
    // get the prototype.
Alexander Wiebel's avatar
Alexander Wiebel committed
455
    if( !WKernel::getRunningKernel()->getRootContainer()->applyModule( module, proto, true ) )
456 457 458 459 460 461
    {
        WLogger::getLogger()->addLogMessage( "Auto Display active but module " + proto + " could not be added.",
                                             "GUI", LL_ERROR );
    }
}

462
void WMainWindow::moduleSpecificCleanup( boost::shared_ptr< WModule > /* module */ )
463
{
464
    // called for each removed module. Use this to undo modifications done due to added modules (moduleSpecificSetup)
465 466
}

467 468
void WMainWindow::moduleSpecificSetup( boost::shared_ptr< WModule > module )
{
469 470 471 472
    // 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.
473
    bool useAutoDisplay = m_autoDisplaySetting->get();
Alexander Wiebel's avatar
Alexander Wiebel committed
474
    if( useAutoDisplay && module->getType() == MODULE_DATA )
475 476 477 478 479 480
    {
        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.
481
        boost::shared_ptr< WDataModule > dataModule = boost::shared_static_cast< WDataModule >( module );
482 483

        // grab data and identify type
Alexander Wiebel's avatar
Alexander Wiebel committed
484
        if( dataModule->getDataSet()->isA< WDataSetSingle >() && dataModule->getDataSet()->isTexture() )
485 486 487
        {
            // it is a dataset single
            // load a nav slice module if a WDataSetSingle is available!?
488
            autoAdd( module, "Navigation Slices", true );
489
        }
Alexander Wiebel's avatar
Alexander Wiebel committed
490
        else if( dataModule->getDataSet()->isA< WDataSetFibers >() )
491 492
        {
            // it is a fiber dataset -> add the FiberDisplay module
493
            autoAdd( module, "Fiber Display" );
494
        }
Alexander Wiebel's avatar
Alexander Wiebel committed
495
        else if( dataModule->getDataSet()->isA< WEEG2 >() )
496
        {
497
            // it is a eeg dataset -> add the eegView module
498 499
            autoAdd( module, "EEG View" );
        }
500 501 502 503 504
        else if( dataModule->getDataSet()->isA< WDataSetPoints >() )
        {
            // it is a point dataset -> add the point render module
            autoAdd( module, "Point Renderer" );
        }
505
    }
wiebel's avatar
wiebel committed
506
}
507

508 509
void WMainWindow::setCompatiblesToolbar( WQtCombinerToolbar* toolbar )
{
Alexander Wiebel's avatar
Alexander Wiebel committed
510
    if( m_currentCompatiblesToolbar )
511 512 513 514 515
    {
        delete m_currentCompatiblesToolbar;
    }
    m_currentCompatiblesToolbar = toolbar;

Alexander Wiebel's avatar
Alexander Wiebel committed
516
    if( !toolbar )
517 518 519
    {
        // ok, reset the toolbar
        // So create a dummy to permanently reserve the space
520
        m_currentCompatiblesToolbar = new WQtCombinerToolbar( this );
521 522
    }

523 524 525 526 527
    // we want to keep the tool-button styles in sync
    m_currentCompatiblesToolbar->setToolButtonStyle( m_permanentToolBar->toolButtonStyle() );
    connect( m_permanentToolBar, SIGNAL( toolButtonStyleChanged( Qt::ToolButtonStyle ) ),
             m_currentCompatiblesToolbar, SLOT( setToolButtonStyle( Qt::ToolButtonStyle ) ) );

528
    // and the position of the toolbar
529
    addToolBar( Qt::TopToolBarArea, m_currentCompatiblesToolbar );
530
}
531

532 533 534 535 536
WQtCombinerToolbar* WMainWindow::getCompatiblesToolbar()
{
    return m_currentCompatiblesToolbar;
}

537
WQtControlPanel* WMainWindow::getControlPanel()
538
{
539
    return m_controlPanel;
540
}
541

542 543 544 545 546
WQtNetworkEditor* WMainWindow::getNetworkEditor()
{
    return m_networkEditor;
}

547
bool WMainWindow::projectSave( const std::vector< boost::shared_ptr< WProjectFileIO > >& writer )
548
{
549
    QString lastPath = WQt4Gui::getSettings().value( "LastProjectSavePath", "" ).toString();
Sebastian Eichelbaum's avatar
[STYLE]  
Sebastian Eichelbaum committed
550
    QString selected = QFileDialog::getSaveFileName( this, "Save Project as", lastPath,
551 552
                                                     "Project File (*.owproj *.owp)" );
    if( selected == "" )
553
    {
554
        return false;
555
    }
556

557 558 559 560
    // extract path and save to settings
    boost::filesystem::path p( selected.toStdString() );
    WQt4Gui::getSettings().setValue( "LastProjectSavePath", QString::fromStdString( p.parent_path().string() ) );

561
    bool success = true;
562
    std::string filename = ( selected ).toStdString();
563

564 565 566 567 568 569
    // append owp if suffix is not present, yet
    if( filename.rfind( ".owp" ) != filename.size() - 4
     && filename.rfind( ".owproj" ) != filename.size() - 7 )
    {
        filename += ".owp";
    }
570

571 572 573
    boost::shared_ptr< WProjectFile > proj = boost::shared_ptr< WProjectFile >(
            new WProjectFile( filename )
    );
574

575 576 577 578
    try
    {
        // This call is synchronous.
        if( writer.empty() )
579
        {
580
            proj->save();
581
        }
582
        else
583
        {
584
            proj->save( writer );
585
        }
586
    }
587 588 589 590 591 592 593 594
    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>" + selected +
                          "<br/><b>Message:  </b>" + QString::fromStdString( e.what() );
        QMessageBox::critical( this, title, message );
        success = false;
    }
595
    return success;
596 597
}

598
bool WMainWindow::projectSaveAll()
599 600 601
{
    std::vector< boost::shared_ptr< WProjectFileIO > > w;
    // an empty list equals "all"
602
    return projectSave( w );
603 604
}

605
bool WMainWindow::projectSaveCameraOnly()
606 607 608
{
    std::vector< boost::shared_ptr< WProjectFileIO > > w;
    w.push_back( WProjectFile::getCameraWriter() );
609
    return projectSave( w );
610 611
}

612
bool WMainWindow::projectSaveROIOnly()
613 614 615
{
    std::vector< boost::shared_ptr< WProjectFileIO > > w;
    w.push_back( WProjectFile::getROIWriter() );
616
    return projectSave( w );
617 618
}

619
bool WMainWindow::projectSaveModuleOnly()
620 621 622
{
    std::vector< boost::shared_ptr< WProjectFileIO > > w;
    w.push_back( WProjectFile::getModuleWriter() );
623
    return projectSave( w );
624 625
}

626 627 628 629 630 631
void WMainWindow::newProject()
{
    WKernel::getRunningKernel()->getRootContainer()->removeAll();
    WDataHandler::getDataHandler()->clear();
}

632
void WMainWindow::openLoadDialog()
633
{
634 635 636 637 638 639 640 641 642 643
    QString lastPath = WQt4Gui::getSettings().value( "LastOpenPath", "" ).toString();

    // build filter list
    // NOTE: Qt Doc says we need to separate multiple filters by ";;"
    QString filters;
    filters = QString( "Known file types (*.cnt *.edf *.asc *.nii *.nii.gz *.vtk *.fib *.owproj *.owp);;" )
            + QString( "Simple Project File (*.owproj *.owp);;" )
            + QString( "EEG files (*.cnt *.edf *.asc);;" )
            + QString( "NIfTI (*.nii *.nii.gz);;" )
            + QString( "Fibers (*.fib);;" );
644 645
    for( std::size_t k = 0; k < WKernel::getRunningKernel()->getScriptEngine()->getNumInterpreters(); ++k )
    {
646 647 648
        filters += QString::fromStdString( WKernel::getRunningKernel()->getScriptEngine()->getInterpreter( k )->getName() + " (*"
                   + WKernel::getRunningKernel()->getScriptEngine()->getInterpreter( k )->getExtension() + ")" );
        filters += QString( ";;" );
649
    }
650
    filters += QString( "Any files (*)" );
651

Sebastian Eichelbaum's avatar
[STYLE]  
Sebastian Eichelbaum committed
652
    QStringList filenames = QFileDialog::getOpenFileNames( this, "Open Data, Project or Script", lastPath, filters );
653
    if( filenames.empty() )
654
    {
655
        return;
656 657
    }

658 659 660
    // extract path and save to settings
    boost::filesystem::path p( filenames[0].toStdString() );
    WQt4Gui::getSettings().setValue( "LastOpenPath", QString::fromStdString( p.parent_path().string() ) );
661

662
    std::vector< std::string > loadDataFilenames;
663
    QStringList::const_iterator constIterator;
664
    for( constIterator = filenames.constBegin(); constIterator != filenames.constEnd(); ++constIterator )
665
    {
666 667 668 669 670 671
        boost::filesystem::path fn( ( *constIterator ).toLocal8Bit().constData() );
        std::string suffix = getSuffix( fn );

        // is this a project file?
        if( ( suffix == ".owp" ) || ( suffix == ".owproj" ) )
        {
672
            asyncProjectLoad( fn.string() );
673 674 675
        }
        else
        {
676 677 678 679 680 681
            // this is not a project. So we assume it is a data file or script
            boost::shared_ptr< WScriptInterpreter > scriptInterpreter =
                    WKernel::getRunningKernel()->getScriptEngine()->getInterpreterByFileExtension( suffix );

            if( scriptInterpreter )
            {
682
                scriptInterpreter->executeFileAsync( fn.string() );
683 684 685 686 687
            }
            else
            {
                loadDataFilenames.push_back( fn.string() );
            }
688
        }
689
    }
690

691
    m_loaderSignal( loadDataFilenames );
692
}
693

694 695
void WMainWindow::asyncProjectLoad( std::string filename )
{
696
    WProjectFile::SPtr proj( new WProjectFile( filename, boost::bind( &WMainWindow::slotLoadFinished, this, _1, _2, _3 ) ) );
697 698 699
    proj->load();
}

700
void WMainWindow::slotLoadFinished( boost::filesystem::path file, std::vector< std::string > errors, std::vector< std::string > warnings )
701 702
{
    // as this function might be called from outside the gui thread, use an event:
703
    QCoreApplication::postEvent( this, new WLoadFinishedEvent( file, errors, warnings ) );
704 705 706 707 708 709 710

    if( errors.size() )
    {
        wlog::warn( "MainWindow" ) << "Async load error occurred. Informing user.";
    }
}

711 712 713 714
void WMainWindow::openAboutQtDialog()
{
    QMessageBox::aboutQt( this, "About Qt" );
}
715

716 717
void WMainWindow::openAboutDialog()
{
718
    std::string filename( WPathHelper::getDocPath().string() + "/openwalnut-qt4/OpenWalnutAbout.html" );
719
    std::string content = readFileIntoString( filename );
720 721
    std::string windowHeading =  std::string( "About OpenWalnut " ) + std::string( W_VERSION );
    QMessageBox::about( this, windowHeading.c_str(), content.c_str() );
722 723
}

724
void WMainWindow::openOpenWalnutHelpDialog()
725
{
726
    std::string filename( WPathHelper::getDocPath().string() + "/openwalnut-qt4/OpenWalnutHelp.html" );
727 728

#ifndef QT4GUI_NOWEBKIT
729
    std::string content = readFileIntoString( filename );
730 731

    QWidget* window = new QWidget( this, Qt::Window );
732
    window->setWindowTitle( "OpenWalnut Help" );
733 734
    // specify intial layout
    QVBoxLayout *layout = new QVBoxLayout( window );
735
    window->setLayout( layout );
736 737 738 739