1
//---------------------------------------------------------------------------
3
// Project: OpenWalnut ( http://www.openwalnut.org )
5
// Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
6
// For more information see http://www.openwalnut.org/copying
8
// This file is part of OpenWalnut.
10
// OpenWalnut is free software: you can redistribute it and/or modify
11
// it under the terms of the GNU Lesser General Public License as published by
12
// the Free Software Foundation, either version 3 of the License, or
13
// (at your option) any later version.
15
// OpenWalnut is distributed in the hope that it will be useful,
16
// but WITHOUT ANY WARRANTY; without even the implied warranty of
17
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
// GNU Lesser General Public License for more details.
20
// You should have received a copy of the GNU Lesser General Public License
21
// along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
23
//---------------------------------------------------------------------------
30
#include <boost/thread.hpp>
31
#include <boost/regex.hpp>
32
#include <boost/filesystem.hpp>
34
#include <QtGui/QApplication>
35
#include <QtGui/QCloseEvent>
36
#include <QtGui/QDockWidget>
37
#include <QtGui/QFileDialog>
38
#include <QtGui/QIcon>
39
#include <QtGui/QMenu>
40
#include <QtGui/QMenuBar>
41
#include <QtGui/QMessageBox>
42
#include <QtGui/QTextEdit>
43
#include <QtGui/QShortcut>
44
#include <QtGui/QSlider>
45
#include <QtGui/QVBoxLayout>
46
#include <QtGui/QWidget>
47
#include <QtCore/QSettings>
48
#include <QtCore/QUrl>
49
#include <QtGui/QInputDialog>
51
#ifndef QT4GUI_NOWEBKIT
52
#include <QtWebKit/QWebView>
55
#include "core/WVersion.h" // NOTE: this file is auto-generated by CMAKE
57
#include "controlPanel/WPropertyBoolWidget.h"
58
#include "controlPanel/WQtControlPanel.h"
59
#include "core/common/WColor.h"
60
#include "core/common/WIOTools.h"
61
#include "core/common/WPathHelper.h"
62
#include "core/common/WProjectFileIO.h"
63
#include "core/dataHandler/WDataSetFibers.h"
64
#include "core/dataHandler/WDataSetSingle.h"
65
#include "core/dataHandler/WEEG2.h"
66
#include "core/graphicsEngine/WGEZoomTrackballManipulator.h"
67
#include "core/graphicsEngine/WROIBox.h"
68
#include "core/kernel/WDataModule.h"
69
#include "core/kernel/WKernel.h"
70
#include "core/kernel/WModule.h"
71
#include "core/kernel/WModuleCombiner.h"
72
#include "core/kernel/WModuleCombinerTypes.h"
73
#include "core/kernel/WProjectFile.h"
74
#include "core/kernel/WROIManager.h"
75
#include "core/kernel/WSelectionManager.h"
76
#include "events/WEventTypes.h"
77
#include "events/WModuleCrashEvent.h"
78
#include "events/WModuleReadyEvent.h"
79
#include "events/WModuleRemovedEvent.h"
80
#include "events/WOpenCustomDockWidgetEvent.h"
81
#include "events/WCloseCustomDockWidgetEvent.h"
82
#include "events/WLoadFinishedEvent.h"
83
#include "guiElements/WQtPropertyBoolAction.h"
85
#include "WQtCombinerToolbar.h"
86
#include "WQtCustomDockWidget.h"
87
#include "WQtGLDockWidget.h"
88
#include "WQtNavGLWidget.h"
89
#include "WSettingAction.h"
90
#include "WSettingMenu.h"
91
#include "WQtMessageDialog.h"
92
#include "WQtGLScreenCapture.h"
94
#include "WMainWindow.h"
95
#include "WMainWindow.moc"
97
WMainWindow::WMainWindow( QSplashScreen* splash ):
100
m_currentCompatiblesToolbar( NULL ),
103
setAcceptDrops( true ); // enable drag and drop events
106
WMainWindow::~WMainWindow()
111
void WMainWindow::setupGUI()
113
wlog::info( "WMainWindow" ) << "Setting up GUI";
115
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
117
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
119
WSettingAction* hideMenuAction = new WSettingAction( this, "qt4gui/showMenu",
121
"Allows you to hide the menu. Can be restored using CTRL-M.",
124
QKeySequence( Qt::CTRL + Qt::Key_M ) );
126
WSettingAction* showNavWidgets = new WSettingAction( this, "qt4gui/showNavigationWidgets",
127
"Show Navigation Views",
128
"Disables the navigation views completely. This can lead to a speed-up and is "
129
"recommended for those who do not need them.",
131
true // this requires a restart
133
m_autoDisplaySetting = new WSettingAction( this, "qt4gui/useAutoDisplay",
135
"If enabled, the best matching module is automatically added if some data was loaded.",
138
WSettingAction* mtViews = new WSettingAction( this, "qt4gui/ge/multiThreadedViewer",
139
"Multi-Threaded Views",
140
"If enabled, the graphic windows are rendered in different threads. This can speed-up "
141
"rendering on machines with multiple cores. WARNING: can lead to crashes sometimes.",
143
true // require restart
145
// NOTE: the multi-threading feature needs to be activated BEFORE the first viewer is created. To ensure this we do it here.
146
WGraphicsEngine::getGraphicsEngine()->setMultiThreadedViews( mtViews->get() );
148
// set the log-level setting.
149
// NOTE: see WQt4Gui which reads the setting.
150
QList< QString > logOptions;
151
logOptions.push_back( "Debug" );
152
logOptions.push_back( "Info" );
153
logOptions.push_back( "Warning" );
154
logOptions.push_back( "Error" );
155
WSettingMenu* logLevels = new WSettingMenu( this, "qt4gui/logLevel",
157
"Allows one to set the log verbosity.",
158
1, // info is the default
161
connect( logLevels, SIGNAL( change( unsigned int ) ), this, SLOT( handleLogLevelUpdate( unsigned int ) ) );
163
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
165
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
167
// We need several icons later in the GUI. Build some mappings:
168
m_iconManager.addMapping( "logo", "openwalnut" );
169
m_iconManager.addMapping( "axial icon", "orientation_axial" );
170
m_iconManager.addMapping( "coronal icon", "orientation_coronal" );
171
m_iconManager.addMapping( "sagittal icon", "orientation_sagittal" );
172
m_iconManager.addMapping( "ROI icon", "roi" );
173
m_iconManager.addMapping( "DefaultModuleIcon", "default" );
174
m_iconManager.addMapping( "missingModule", "question" );
175
m_iconManager.addMapping( "view", "camera" );
176
m_iconManager.addMapping( "moduleCrashed", "error" );
177
m_iconManager.addMapping( "moduleBusy", "busy" );
178
m_iconManager.addMapping( "saveProject", "save" );
180
if( objectName().isEmpty() )
182
setObjectName( QString::fromUtf8( "MainWindow" ) );
185
// NOTE: this only is an initial size. The state reloaded from QSettings will set it to the value the user had last session.
187
setWindowIcon( m_iconManager.getIcon( "logo" ) );
188
std::string windowHeading = std::string( "OpenWalnut " ) + std::string( W_VERSION );
189
setWindowTitle( QApplication::translate( "MainWindow", windowHeading.c_str(), 0, QApplication::UnicodeUTF8 ) );
191
setDockOptions( QMainWindow::AnimatedDocks | QMainWindow::AllowNestedDocks | QMainWindow::AllowTabbedDocks );
194
m_networkEditor = NULL;
195
m_networkEditor = new WQtNetworkEditor( this );
196
m_networkEditor->setFeatures( QDockWidget::AllDockWidgetFeatures );
198
// strangely, the QGraphics* objects do not properly forward drag/drop events. We need to explicitly handle them.
199
connect( m_networkEditor->getView(), SIGNAL( dragDrop( QDropEvent* ) ),
200
this, SLOT( handleDrop( QDropEvent* ) ) );
202
// the control panel instance is needed for the menu
203
m_controlPanel = new WQtControlPanel( this );
204
m_controlPanel->setFeatures( QDockWidget::AllDockWidgetFeatures );
205
m_controlPanel->addSubject( "Default Subject" );
208
addDockWidget( Qt::RightDockWidgetArea, m_controlPanel->getModuleDock() );
209
if( m_networkEditor )
211
addDockWidget( Qt::RightDockWidgetArea, m_networkEditor );
214
addDockWidget( Qt::RightDockWidgetArea, m_controlPanel->getColormapperDock() );
215
addDockWidget( Qt::RightDockWidgetArea, m_controlPanel->getRoiDock() );
217
// tabify those panels by default
218
if( m_networkEditor )
220
tabifyDockWidget( m_networkEditor, m_controlPanel->getModuleDock() );
222
tabifyDockWidget( m_controlPanel->getModuleDock(), m_controlPanel->getColormapperDock() );
223
tabifyDockWidget( m_controlPanel->getColormapperDock(), m_controlPanel->getRoiDock() );
225
m_glDock = new QMainWindow();
226
m_glDock->setObjectName( "GLDock" );
227
m_glDock->setDockOptions( QMainWindow::AnimatedDocks | QMainWindow::AllowNestedDocks | QMainWindow::AllowTabbedDocks );
228
m_glDock->setDocumentMode( true );
229
setCentralWidget( m_glDock );
230
WQtGLDockWidget* mainGLDock = new WQtGLDockWidget( "Main View", "3D View", m_glDock );
231
mainGLDock->getGLWidget()->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
232
m_mainGLWidget = mainGLDock->getGLWidget();
233
m_mainGLWidgetScreenCapture = m_mainGLWidget->getScreenCapture( this );
234
m_glDock->addDockWidget( Qt::RightDockWidgetArea, mainGLDock );
235
addDockWidget( Qt::RightDockWidgetArea, m_mainGLWidgetScreenCapture );
236
tabifyDockWidget( m_controlPanel->getRoiDock(), m_mainGLWidgetScreenCapture );
237
connect( m_mainGLWidget.get(), SIGNAL( renderedFirstFrame() ), this, SLOT( handleGLVendor() ) );
239
addDockWidget( Qt::RightDockWidgetArea, m_controlPanel );
241
// by default, the module editor should be in front
242
if( m_networkEditor )
244
m_networkEditor->raise();
248
m_controlPanel->getModuleDock()->raise();
251
// NOTE: we abuse the gl widgets first frame event to handle startup news.
252
connect( m_mainGLWidget.get(), SIGNAL( renderedFirstFrame() ), this, SLOT( handleStartMessages() ) );
253
connect( m_mainGLWidget.get(), SIGNAL( renderedFirstFrame() ), this, SLOT( closeSplash() ) );
255
m_permanentToolBar = new WQtToolBar( "Standard Toolbar", this );
256
addToolBar( Qt::TopToolBarArea, m_permanentToolBar );
258
m_loadButton = new QAction( m_iconManager.getIcon( "load" ), "Load Dataset or Project", m_permanentToolBar );
259
m_loadButton->setShortcut( QKeySequence( QKeySequence::Open ) );
260
QAction* roiButton = new QAction( m_iconManager.getIcon( "ROI icon" ), "ROI", m_permanentToolBar );
261
QAction* resetButton = new QAction( m_iconManager.getIcon( "view" ), "Reset", m_permanentToolBar );
262
m_saveAction = new QAction( m_iconManager.getIcon( "saveProject" ), "Save Project", m_permanentToolBar );
264
connect( m_loadButton, SIGNAL( triggered( bool ) ), this, SLOT( openLoadDialog() ) );
265
connect( resetButton, SIGNAL( triggered( bool ) ), m_mainGLWidget.get(), SLOT( reset() ) );
266
connect( roiButton, SIGNAL( triggered( bool ) ), this, SLOT( newRoi() ) );
267
connect( m_saveAction, SIGNAL( triggered( bool ) ), this, SLOT( projectSaveAll() ) );
269
m_loadButton->setToolTip( "Load a dataset or project from file" );
270
resetButton->setToolTip( "Reset main view" );
271
roiButton->setToolTip( "Create new ROI" );
272
m_saveAction->setToolTip( "Save current project to file" );
274
// we want the upper most tree item to be selected. This helps to make the always compatible modules
275
// show up in the tool bar from the beginning. And ... it doesn't hurt.
276
m_controlPanel->selectUpperMostEntry();
278
// NOTE: Please be aware that not every menu needs a shortcut key. If you add a shortcut, you should use one of the
279
// QKeySequence::StandardKey defaults and avoid ambiguities like Ctrl-C for the configure dialog is not the best choice as Ctrl-C, for the
280
// most users is the Copy shortcut.
282
m_menuBar = new QMenuBar( this );
285
m_menuBar->setVisible( hideMenuAction->get() );
286
connect( hideMenuAction, SIGNAL( change( bool ) ), m_menuBar, SLOT( setVisible( bool ) ) );
287
addAction( hideMenuAction );
289
QMenu* fileMenu = m_menuBar->addMenu( "File" );
291
fileMenu->addAction( m_loadButton );
292
m_saveMenu = fileMenu->addMenu( m_iconManager.getIcon( "saveProject" ), "Save Project" );
293
m_saveMenu->addAction( "Save Project", this, SLOT( projectSaveAll() ), QKeySequence::Save );
294
m_saveMenu->addAction( "Save Modules Only", this, SLOT( projectSaveModuleOnly() ) );
295
m_saveMenu->addAction( "Save Camera Only", this, SLOT( projectSaveCameraOnly() ) );
296
// saveMenu->addAction( "Save ROIs Only", this, SLOT( projectSaveROIOnly() ) );
297
m_saveAction->setMenu( m_saveMenu );
299
fileMenu->addSeparator();
300
// TODO(all): If all distributions provide a newer QT version we should use QKeySequence::Quit here
301
//fileMenu->addAction( m_iconManager.getIcon( "quit" ), "Quit", this, SLOT( close() ), QKeySequence( QKeySequence::Quit ) );
302
m_quitAction = fileMenu->addAction( m_iconManager.getIcon( "quit" ), "Quit", this, SLOT( close() ), QKeySequence( Qt::CTRL + Qt::Key_Q ) );
304
// This QAction stuff is quite ugly and complicated some times ... There is no nice constructor which takes name, slot keysequence and so on
305
// directly -> set shortcuts, and some further properties using QAction's interface
307
m_viewAction = new QAction( "View", this );
308
m_viewMenu = m_menuBar->addMenu( "View" );
309
m_viewMenu->addAction( hideMenuAction );
310
m_viewMenu->addSeparator();
311
m_viewMenu->addAction( showNavWidgets );
312
m_viewMenu->addSeparator();
313
m_viewMenu->addMenu( m_permanentToolBar->getStyleMenu() );
314
m_viewAction->setMenu( m_viewMenu );
317
m_cameraAction = new QAction( "Camera", this );
318
m_cameraMenu = m_menuBar->addMenu( "Camera" );
319
m_cameraMenu->addAction( mainGLDock->getGLWidget()->getThrowingSetting() );
320
m_cameraAction->setMenu( m_cameraMenu );
322
m_settingsAction = new QAction( "Settings", this );
323
m_settingsMenu = m_menuBar->addMenu( "Settings" );
324
m_settingsMenu->addAction( m_autoDisplaySetting );
325
m_settingsMenu->addAction( m_controlPanel->getModuleConfig().getConfigureAction() );
326
m_settingsMenu->addSeparator();
327
m_settingsMenu->addAction( mtViews );
328
m_settingsMenu->addSeparator();
329
m_settingsMenu->addMenu( logLevels );
330
m_settingsAction->setMenu( m_settingsMenu );
332
QAction* controlPanelTrigger = m_controlPanel->toggleViewAction();
333
QList< QKeySequence > controlPanelShortcut;
334
controlPanelShortcut.append( QKeySequence( Qt::Key_F9 ) );
335
controlPanelTrigger->setShortcuts( controlPanelShortcut );
336
this->addAction( controlPanelTrigger ); // this enables the action even if the menu bar is invisible
338
m_cameraMenu->addAction( m_mainGLWidget->getCameraResetAction() );
339
m_cameraMenu->addMenu( m_mainGLWidget->getCameraPresetsMenu() );
340
resetButton->setMenu( m_mainGLWidget->getCameraPresetsMenu() );
342
m_helpAction = new QAction( "Help", this );
343
m_helpMenu = m_menuBar->addMenu( "Help" );
344
m_helpMenu->addAction( m_iconManager.getIcon( "help" ), "OpenWalnut Help", this, SLOT( openOpenWalnutHelpDialog() ),
345
QKeySequence( QKeySequence::HelpContents ) );
346
m_helpMenu->addAction( m_iconManager.getIcon( "logo" ), "Welcome to OpenWalnut", this, SLOT( showWelcomeDialog() ) );
347
m_helpMenu->addSeparator();
348
m_helpMenu->addAction( m_iconManager.getIcon( "logo" ), "About OpenWalnut", this, SLOT( openAboutDialog() ) );
349
m_helpMenu->addAction( "About Qt", this, SLOT( openAboutQtDialog() ) );
350
m_helpAction->setMenu( m_helpMenu );
352
setMenuBar( m_menuBar );
354
// initially 3 navigation views
356
if( showNavWidgets->get() )
358
m_navAxial = boost::shared_ptr< WQtNavGLWidget >( new WQtNavGLWidget( "Axial View", "Axial View", this, "Axial Slice",
359
m_mainGLWidget.get() ) );
360
m_navAxial->setFeatures( QDockWidget::AllDockWidgetFeatures );
361
m_navAxial->setSliderProperty( WKernel::getRunningKernel()->getSelectionManager()->getPropAxialPos() );
362
m_navAxial->getGLWidget()->setCameraManipulator( WQtGLWidget::NO_OP );
364
m_glDock->addDockWidget( Qt::LeftDockWidgetArea, m_navAxial.get() );
366
m_navCoronal = boost::shared_ptr< WQtNavGLWidget >( new WQtNavGLWidget( "Coronal View", "Coronal View", this, "Coronal Slice",
367
m_mainGLWidget.get() ) );
368
m_navCoronal->setFeatures( QDockWidget::AllDockWidgetFeatures );
369
m_navCoronal->setSliderProperty( WKernel::getRunningKernel()->getSelectionManager()->getPropCoronalPos() );
370
m_navCoronal->getGLWidget()->setCameraManipulator( WQtGLWidget::NO_OP );
372
m_glDock->addDockWidget( Qt::LeftDockWidgetArea, m_navCoronal.get() );
375
boost::shared_ptr< WQtNavGLWidget >( new WQtNavGLWidget( "Sagittal View", "Sagittal View", this, "Sagittal Slice",
376
m_mainGLWidget.get() ) );
377
m_navSagittal->setFeatures( QDockWidget::AllDockWidgetFeatures );
378
m_navSagittal->setSliderProperty( WKernel::getRunningKernel()->getSelectionManager()->getPropSagittalPos() );
379
m_navSagittal->getGLWidget()->setCameraManipulator( WQtGLWidget::NO_OP );
381
m_glDock->addDockWidget( Qt::LeftDockWidgetArea, m_navSagittal.get() );
385
// create the show/hide actions using the selection manager's props
386
WQtPropertyBoolAction* showAxial = new WQtPropertyBoolAction( WKernel::getRunningKernel()->getSelectionManager()->getPropAxialShow(),
387
m_permanentToolBar );
388
showAxial->setToolTip( "Toggle axial slice" );
389
showAxial->setText( "Toggle Axial Slice" );
390
showAxial->setIcon( m_iconManager.getIcon( "axial icon" ) );
392
WQtPropertyBoolAction* showCoronal = new WQtPropertyBoolAction( WKernel::getRunningKernel()->getSelectionManager()->getPropCoronalShow(),
393
m_permanentToolBar );
394
showCoronal->setToolTip( "Toggle coronal slice" );
395
showCoronal->setText( "Toggle Coronal Slice" );
396
showCoronal->setIcon( m_iconManager.getIcon( "coronal icon" ) );
398
WQtPropertyBoolAction* showSagittal = new WQtPropertyBoolAction( WKernel::getRunningKernel()->getSelectionManager()->getPropSagittalShow(),
399
m_permanentToolBar );
400
showSagittal->setToolTip( "Toggle sagittal slice" );
401
showSagittal->setText( "Toggle Sagittal Slice" );
402
showSagittal->setIcon( m_iconManager.getIcon( "sagittal icon" ) );
404
// setup permanent toolbar
405
m_permanentToolBar->addAction( m_loadButton );
406
m_permanentToolBar->addAction( m_saveAction );
407
m_permanentToolBar->addSeparator();
408
m_permanentToolBar->addAction( m_mainGLWidgetScreenCapture->getScreenshotTrigger() );
409
m_permanentToolBar->addSeparator();
410
m_permanentToolBar->addAction( resetButton );
411
m_permanentToolBar->addAction( roiButton );
412
m_permanentToolBar->addSeparator();
413
m_permanentToolBar->addAction( showAxial );
414
m_permanentToolBar->addAction( showCoronal );
415
m_permanentToolBar->addAction( showSagittal );
416
m_permanentToolBar->addSeparator();
418
// allow the control panel to complete setup
419
m_controlPanel->completeGuiSetup();
421
// after creating the GUI, restore its saved state
425
void WMainWindow::autoAdd( boost::shared_ptr< WModule > module, std::string proto, bool onlyOnce )
427
// if only one module should be added, and there already is one --- skip.
428
if( onlyOnce && !WKernel::getRunningKernel()->getRootContainer()->getModules( proto ).empty() )
433
// get the prototype.
434
if( !WKernel::getRunningKernel()->getRootContainer()->applyModule( module, proto, true ) )
436
WLogger::getLogger()->addLogMessage( "Auto Display active but module " + proto + " could not be added.",
441
void WMainWindow::moduleSpecificCleanup( boost::shared_ptr< WModule > /* module */ )
443
// called for each removed module. Use this to undo modifications done due to added modules (moduleSpecificSetup)
446
void WMainWindow::moduleSpecificSetup( boost::shared_ptr< WModule > module )
448
// Add all special handlings here. This method is called whenever a module is marked "ready". You can set up the gui for special modules,
449
// load certain modules for datasets and so on.
451
// 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.
452
bool useAutoDisplay = m_autoDisplaySetting->get();
453
if( useAutoDisplay && module->getType() == MODULE_DATA )
455
WLogger::getLogger()->addLogMessage( "Auto Display active and Data module added. The proper module will be added.",
458
// data modules contain an member denoting the real data type. Currently we only have one data module and a not very modulated data
460
boost::shared_ptr< WDataModule > dataModule = boost::shared_static_cast< WDataModule >( module );
462
// grab data and identify type
463
if( dataModule->getDataSet()->isA< WDataSetSingle >() && dataModule->getDataSet()->isTexture() )
465
// it is a dataset single
466
// load a nav slice module if a WDataSetSingle is available!?
467
autoAdd( module, "Navigation Slices", true );
469
else if( dataModule->getDataSet()->isA< WDataSetFibers >() )
471
// it is a fiber dataset -> add the FiberDisplay module
472
autoAdd( module, "Fiber Display" );
474
else if( dataModule->getDataSet()->isA< WEEG2 >() )
476
// it is a eeg dataset -> add the eegView module
477
autoAdd( module, "EEG View" );
482
void WMainWindow::setCompatiblesToolbar( WQtCombinerToolbar* toolbar )
484
if( m_currentCompatiblesToolbar )
486
delete m_currentCompatiblesToolbar;
488
m_currentCompatiblesToolbar = toolbar;
492
// ok, reset the toolbar
493
// So create a dummy to permanently reserve the space
494
m_currentCompatiblesToolbar = new WQtCombinerToolbar( this );
497
// we want to keep the tool-button styles in sync
498
m_currentCompatiblesToolbar->setToolButtonStyle( m_permanentToolBar->toolButtonStyle() );
499
connect( m_permanentToolBar, SIGNAL( toolButtonStyleChanged( Qt::ToolButtonStyle ) ),
500
m_currentCompatiblesToolbar, SLOT( setToolButtonStyle( Qt::ToolButtonStyle ) ) );
502
// and the position of the toolbar
503
addToolBar( Qt::TopToolBarArea, m_currentCompatiblesToolbar );
506
WQtCombinerToolbar* WMainWindow::getCompatiblesToolbar()
508
return m_currentCompatiblesToolbar;
511
WQtControlPanel* WMainWindow::getControlPanel()
513
return m_controlPanel;
516
WQtNetworkEditor* WMainWindow::getNetworkEditor()
518
return m_networkEditor;
521
bool WMainWindow::projectSave( const std::vector< boost::shared_ptr< WProjectFileIO > >& writer )
524
fd.setWindowTitle( "Save Project as" );
525
fd.setFileMode( QFileDialog::AnyFile );
526
fd.setAcceptMode( QFileDialog::AcceptSave );
528
// My Mac OSX Lion automatically appends .owproj to the file name
529
// if no extension is given.
531
filters << "Project File (*.owproj *.owp)";
532
fd.setNameFilters( filters );
533
fd.setViewMode( QFileDialog::Detail );
534
QStringList filenames;
537
filenames = fd.selectedFiles();
541
return false; // the user canceled, no files, so nothing saved
545
QStringList::const_iterator constIterator;
546
for( constIterator = filenames.constBegin(); constIterator != filenames.constEnd(); ++constIterator )
548
std::string filename = ( *constIterator ).toStdString();
550
// append owp if suffix is not present, yet
551
if( filename.rfind( ".owp" ) != filename.size() - 4
552
&& filename.rfind( ".owproj" ) != filename.size() - 7 )
557
boost::shared_ptr< WProjectFile > proj = boost::shared_ptr< WProjectFile >(
558
new WProjectFile( filename )
563
// This call is synchronous.
570
proj->save( writer );
573
catch( const std::exception& e )
575
QString title = "Problem while saving project file.";
576
QString message = "<b>Problem while saving project file.</b><br/><br/><b>File: </b>" + ( *constIterator ) +
577
"<br/><b>Message: </b>" + QString::fromStdString( e.what() );
578
QMessageBox::critical( this, title, message );
585
bool WMainWindow::projectSaveAll()
587
std::vector< boost::shared_ptr< WProjectFileIO > > w;
588
// an empty list equals "all"
589
return projectSave( w );
592
bool WMainWindow::projectSaveCameraOnly()
594
std::vector< boost::shared_ptr< WProjectFileIO > > w;
595
w.push_back( WProjectFile::getCameraWriter() );
596
return projectSave( w );
599
bool WMainWindow::projectSaveROIOnly()
601
std::vector< boost::shared_ptr< WProjectFileIO > > w;
602
w.push_back( WProjectFile::getROIWriter() );
603
return projectSave( w );
606
bool WMainWindow::projectSaveModuleOnly()
608
std::vector< boost::shared_ptr< WProjectFileIO > > w;
609
w.push_back( WProjectFile::getModuleWriter() );
610
return projectSave( w );
613
void WMainWindow::openLoadDialog()
616
fd.setFileMode( QFileDialog::ExistingFiles );
619
filters << "Known file types (*.cnt *.edf *.asc *.nii *.nii.gz *.fib *.owproj *.owp)"
620
<< "Simple Project File (*.owproj *.owp)"
621
<< "EEG files (*.cnt *.edf *.asc)"
622
<< "NIfTI (*.nii *.nii.gz)"
625
fd.setNameFilters( filters );
626
fd.setViewMode( QFileDialog::Detail );
627
QStringList filenames;
630
filenames = fd.selectedFiles();
633
std::vector< std::string > loadDataFilenames;
635
QStringList::const_iterator constIterator;
636
for( constIterator = filenames.constBegin(); constIterator != filenames.constEnd(); ++constIterator )
638
boost::filesystem::path fn( ( *constIterator ).toLocal8Bit().constData() );
639
std::string suffix = getSuffix( fn );
641
// is this a project file?
642
if( ( suffix == ".owp" ) || ( suffix == ".owproj" ) )
644
asyncProjectLoad( fn.string() );
648
// this is not a project. So we assume it is a data file
649
loadDataFilenames.push_back( fn.string() );
653
m_loaderSignal( loadDataFilenames );
656
void WMainWindow::asyncProjectLoad( std::string filename )
658
WProjectFile::SPtr proj( new WProjectFile( filename, boost::bind( &WMainWindow::slotLoadFinished, this, _1, _2 ) ) );
662
void WMainWindow::slotLoadFinished( boost::filesystem::path file, std::vector< std::string > errors )
664
// as this function might be called from outside the gui thread, use an event:
665
QCoreApplication::postEvent( this, new WLoadFinishedEvent( file, errors ) );
669
wlog::warn( "MainWindow" ) << "Async load error occurred. Informing user.";
673
void WMainWindow::openAboutQtDialog()
675
QMessageBox::aboutQt( this, "About Qt" );
678
void WMainWindow::openAboutDialog()
680
std::string filename( WPathHelper::getDocPath().string() + "/openwalnut-qt4/OpenWalnutAbout.html" );
681
std::string content = readFileIntoString( filename );
682
std::string windowHeading = std::string( "About OpenWalnut " ) + std::string( W_VERSION );
683
QMessageBox::about( this, windowHeading.c_str(), content.c_str() );
686
void WMainWindow::openOpenWalnutHelpDialog()
688
std::string filename( WPathHelper::getDocPath().string() + "/openwalnut-qt4/OpenWalnutHelp.html" );
690
#ifndef QT4GUI_NOWEBKIT
691
std::string content = readFileIntoString( filename );
693
QWidget* window = new QWidget( this, Qt::Window );
694
window->setWindowTitle( "OpenWalnut Help" );
695
// specify intial layout
696
QVBoxLayout *layout = new QVBoxLayout( window );
697
window->setLayout( layout );
698
window->resize( 500, 500 );
702
QWebView *view = new QWebView( this );
703
QString location( QString( "file://" ) + WPathHelper::getDocPath().string().c_str() + "/openwalnut-qt4/" );
704
view->setHtml( content.c_str(), QUrl( location ) );
706
layout->addWidget( view );
708
QMessageBox::information( this, "Help", QString::fromStdString( "Sorry! Your version of OpenWalnut was not compiled with embedded help. "
709
"To open the help pages in your browser, use this link: <a href=" +
710
filename + ">Help</a>." ) );
714
void WMainWindow::openNotImplementedDialog()
716
QMessageBox::information( this, "Not yet implemented!",
717
"This functionality is planned for future versions of OpenWalnut. "
718
"It is not yet implemented." );
721
boost::signals2::signal1< void, std::vector< std::string > >* WMainWindow::getLoaderSignal()
723
return &m_loaderSignal;
726
WIconManager* WMainWindow::getIconManager()
728
return &m_iconManager;
731
void WMainWindow::closeEvent( QCloseEvent* e )
733
// use some "Really Close?" Dialog here
734
bool reallyClose = true;
736
// handle close event
740
m_splash->showMessage( "Shutting down" );
744
// signal everybody to shut down properly.
745
m_splash->showMessage( "Shutting down kernel. Waiting for modules to finish." );
746
WKernel::getRunningKernel()->finalize();
748
// now nobody acesses the osg anymore
749
m_splash->showMessage( "Shutting down GUI." );
751
// clean up gl widgets
752
m_mainGLWidget->close();
759
m_navCoronal->close();
763
m_navSagittal->close();
766
// delete CustomDockWidgets
767
boost::mutex::scoped_lock lock( m_customDockWidgetsLock );
768
for( std::map< std::string, boost::shared_ptr< WQtCustomDockWidget > >::iterator it = m_customDockWidgets.begin();
769
it != m_customDockWidgets.end(); ++it )
773
//m_customDockWidgetsLock.unlock();
784
void WMainWindow::customEvent( QEvent* event )
786
if( event->type() == WOpenCustomDockWidgetEvent::CUSTOM_TYPE )
788
// OpenCustomDockWidgetEvent
789
WOpenCustomDockWidgetEvent* ocdwEvent = static_cast< WOpenCustomDockWidgetEvent* >( event );
790
std::string title = ocdwEvent->getTitle();
792
boost::shared_ptr< WQtCustomDockWidget > widget;
794
boost::mutex::scoped_lock lock( m_customDockWidgetsLock );
795
if( m_customDockWidgets.count( title ) == 0 )
797
// create new custom dock widget
798
widget = boost::shared_ptr< WQtCustomDockWidget >(
799
new WQtCustomDockWidget( title, m_glDock, ocdwEvent->getProjectionMode() ) );
800
m_glDock->addDockWidget( Qt::BottomDockWidgetArea, widget.get() );
802
// restore state and geometry
803
m_glDock->restoreDockWidget( widget.get() );
804
//TODO(mario): is there a fallback if the configuration is "stupid" or not set?
806
// store it in CustomDockWidget list
807
m_customDockWidgets.insert( make_pair( title, widget ) );
811
widget = m_customDockWidgets[title];
812
widget->increaseUseCount();
815
ocdwEvent->getFlag()->set( widget );
816
boost::shared_dynamic_cast< QDockWidget >( widget )->toggleViewAction()->activate( QAction::Trigger );
818
else if( event->type() == WCloseCustomDockWidgetEvent::CUSTOM_TYPE )
820
WCloseCustomDockWidgetEvent* closeEvent = static_cast< WCloseCustomDockWidgetEvent* >( event );
821
boost::mutex::scoped_lock lock( m_customDockWidgetsLock );
822
if( m_customDockWidgets.count( closeEvent->getTitle() ) > 0 )
824
if( m_customDockWidgets[closeEvent->getTitle()]->decreaseUseCount() )
826
// custom dock widget should be deleted
827
m_customDockWidgets.erase( closeEvent->getTitle() );
834
QMainWindow::customEvent( event );
838
bool WMainWindow::event( QEvent* event )
840
// a module got associated with the root container -> add it to the list
841
if( event->type() == WQT_READY_EVENT )
843
// convert event to ready event
844
WModuleReadyEvent* e1 = dynamic_cast< WModuleReadyEvent* >( event ); // NOLINT
847
moduleSpecificSetup( e1->getModule() );
851
if( event->type() == WQT_CRASH_EVENT )
853
// convert event to ready event
854
WModuleCrashEvent* e1 = dynamic_cast< WModuleCrashEvent* >( event ); // NOLINT
857
QString title = "Problem in module: " + QString::fromStdString( e1->getModule()->getName() );
858
QString description = "<b>Module Problem</b><br/><br/><b>Module: </b>" + QString::fromStdString( e1->getModule()->getName() );
860
QString message = QString::fromStdString( e1->getMessage() );
862
msgBox.setText( description );
863
msgBox.setInformativeText( message );
864
msgBox.setStandardButtons( QMessageBox::Ok );
869
if( event->type() == WQT_MODULE_REMOVE_EVENT )
871
// convert event to ready event
872
WModuleRemovedEvent* e1 = dynamic_cast< WModuleRemovedEvent* >( event ); // NOLINT
875
moduleSpecificCleanup( e1->getModule() );
879
if( event->type() == WQT_LOADFINISHED )
882
WLoadFinishedEvent* e1 = dynamic_cast< WLoadFinishedEvent* >( event );
885
if( e1->getErrors().size() )
887
size_t curErrCount = 0;
888
const size_t maxErrCount = 5;
889
std::string errors = "<ul>";
890
for( std::vector< std::string >::const_iterator iter = e1->getErrors().begin(); iter != e1->getErrors().end(); ++iter )
892
errors += "<li> " + *iter;
895
if( ( curErrCount == maxErrCount ) && ( e1->getErrors().size() > maxErrCount ) )
897
size_t errDiff = e1->getErrors().size() - curErrCount;
898
errors += "<li> ... and " + string_utils::toString( errDiff ) + " more errors.";
904
QMessageBox::critical( this, "Error during load",
905
"Errors occurred during load of \"" + QString::fromStdString( e1->getFilename() ) + "\". "
906
"The loader tried to apply as much as possible, ignoring the erroneous data. The first errors where:"
908
"<font color=\"#f00\">" + QString::fromStdString( errors )+ "</font>" );
913
return QMainWindow::event( event );
916
boost::shared_ptr< WQtCustomDockWidget > WMainWindow::getCustomDockWidget( std::string title )
918
boost::mutex::scoped_lock lock( m_customDockWidgetsLock );
919
boost::shared_ptr< WQtCustomDockWidget > out = m_customDockWidgets.count( title ) > 0 ?
920
m_customDockWidgets[title] :
921
boost::shared_ptr< WQtCustomDockWidget >();
926
void WMainWindow::closeCustomDockWidget( std::string title )
928
QCoreApplication::postEvent( this, new WCloseCustomDockWidgetEvent( title ) );
931
void WMainWindow::newRoi()
933
// do nothing if we can not get
934
WPosition crossHairPos = WKernel::getRunningKernel()->getSelectionManager()->getCrosshair()->getPosition();
935
WPosition minROIPos = crossHairPos - WPosition( 10., 10., 10. );
936
WPosition maxROIPos = crossHairPos + WPosition( 10., 10., 10. );
938
if( m_controlPanel->getFirstRoiInSelectedBranch().get() == NULL )
940
osg::ref_ptr< WROIBox > newRoi = osg::ref_ptr< WROIBox >( new WROIBox( minROIPos, maxROIPos ) );
941
WKernel::getRunningKernel()->getRoiManager()->addRoi( newRoi );
945
osg::ref_ptr< WROIBox > newRoi = osg::ref_ptr< WROIBox >( new WROIBox( minROIPos, maxROIPos ) );
946
WKernel::getRunningKernel()->getRoiManager()->addRoi( newRoi, m_controlPanel->getFirstRoiInSelectedBranch() );
950
void WMainWindow::restoreSavedState()
952
wlog::info( "MainWindow" ) << "Restoring window state.";
954
restoreGeometry( WQt4Gui::getSettings().value( "MainWindowGeometry", "" ).toByteArray() );
955
restoreState( WQt4Gui::getSettings().value( "MainWindowState", "" ).toByteArray() );
957
m_glDock->restoreGeometry( WQt4Gui::getSettings().value( "GLDockWindowGeometry", "" ).toByteArray() );
958
m_glDock->restoreState( WQt4Gui::getSettings().value( "GLDockWindowState", "" ).toByteArray() );
961
void WMainWindow::saveWindowState()
963
wlog::info( "MainWindow" ) << "Saving window state.";
965
// this saves the window state to some common location on the target OS in user scope.
966
WQt4Gui::getSettings().setValue( "MainWindowState", saveState() );
967
WQt4Gui::getSettings().setValue( "GLDockWindowState", m_glDock->saveState() );
969
// NOTE: Qt Doc says that saveState also saves geometry. But this somehow is wrong (at least for 4.6.3)
970
WQt4Gui::getSettings().setValue( "MainWindowGeometry", saveGeometry() );
971
WQt4Gui::getSettings().setValue( "GLDockWindowGeometry", m_glDock->saveGeometry() );
974
QSettings& WMainWindow::getSettings()
976
return WQt4Gui::getSettings();
979
void WMainWindow::handleLogLevelUpdate( unsigned int logLevel )
981
WLogger::getLogger()->setDefaultLogLevel( static_cast< LogLevel >( logLevel ) );
984
void WMainWindow::handleGLVendor()
986
// WARNING: never put blocking code here, as it might freeze the mainGLWidget.
987
std::string vendor = string_utils::toLower( m_mainGLWidget->getViewer()->getOpenGLVendor() );
989
// is this a mesa card?
990
if( vendor.find( "mesa" ) != std::string::npos )
992
QString msg = "<b>Warning:</b> Your graphics card is powered by the Mesa OpenGL implementation. OpenWalnut does not support Mesa "
993
"officially, since Mesa has some severe problems with GLSL shaders. You can still use OpenWalnut, but you should be "
994
"aware that Mesa can freeze OpenWalnut. Ensure you have the latest version of Mesa installed to avoid problems.";
995
QLabel* l = new QLabel( msg );
996
l->setWordWrap( true );
997
l->setMinimumWidth( 640 );
999
WQtMessageDialog* msgDia = new WQtMessageDialog( "MesaWarning", "Mesa Warning", l, getSettings(), this );
1003
// is this a mesa card?
1004
if( ( vendor.find( "Chromium" ) != std::string::npos ) ||
1005
( vendor.find( "Humper" ) != std::string::npos ) )
1007
QString msg = "<b>Warning:</b> You seem to use OpenWalnut from inside a virtual machine. Graphics acceleration on these virtual machines"
1008
" is often limited. OpenWalnut might not properly work in your setup.";
1009
QLabel* l = new QLabel( msg );
1010
l->setWordWrap( true );
1011
l->setMinimumWidth( 640 );
1013
WQtMessageDialog* msgDia = new WQtMessageDialog( "VMChromiumWarning", "Virtual Machine Warning", l, getSettings(), this );
1018
void WMainWindow::showWelcomeDialog( bool force )
1020
// Load welcome file
1021
std::string filename( WPathHelper::getDocPath().string() + "/openwalnut-qt4/OpenWalnutWelcome.html" );
1022
std::string content = readFileIntoString( filename );
1024
// gen ID for it using version (allows showing release/welcome message for each new release)
1025
QString msgID = "OpenWalnutWelcome" + QString( W_LIB_VERSION );
1027
// replace OW_VERSION
1028
boost::regex reg1( "%OW_LIB_VERSION%" );
1029
boost::regex reg2( "%OW_VERSION%" );
1030
content = boost::regex_replace( content, reg1, std::string( W_LIB_VERSION ) );
1031
content = boost::regex_replace( content, reg2, std::string( W_VERSION ) );
1034
#ifndef QT4GUI_NOWEBKIT
1035
QWebView* view = new QWebView( this );
1036
view->setHtml( QString::fromStdString( content ) );
1037
view->setMinimumWidth( 640 );
1038
view->page()->setLinkDelegationPolicy( QWebPage::DelegateExternalLinks );
1041
QLabel* l = new QLabel( QString::fromStdString( content ) );
1042
l->setWordWrap( true );
1043
l->setMinimumWidth( 640 );
1047
WQtMessageDialog* msgDia = new WQtMessageDialog( msgID, "Welcome to OpenWalnut", w, getSettings(), this );
1048
msgDia->show( force );
1051
void WMainWindow::handleStartMessages()
1053
// only show welcome dialog for now
1054
showWelcomeDialog( false );
1057
void WMainWindow::forceMainGLWidgetSize( size_t w, size_t h )
1059
m_mainGLWidget->setFixedSize( w, h );
1062
void WMainWindow::restoreMainGLWidgetSize()
1064
m_mainGLWidget->setMinimumHeight( 250 );
1065
m_mainGLWidget->setMaximumHeight( QWIDGETSIZE_MAX );
1066
m_mainGLWidget->setMinimumWidth( 250 );
1067
m_mainGLWidget->setMaximumWidth( QWIDGETSIZE_MAX );
1070
void WMainWindow::handleDrop( QDropEvent* event )
1072
if( event->mimeData()->hasUrls() )
1074
std::vector < std::string > projects;
1075
std::vector < std::string > filenames;
1076
std::vector < std::string > unsupported;
1077
foreach( QUrl url, event->mimeData()->urls() )
1079
QString path = url.toLocalFile();
1080
QFileInfo info( path );
1081
QString suffix = info.completeSuffix();
1082
if( suffix.endsWith( "cnt" )
1083
|| suffix.endsWith( "edf" )
1084
|| suffix.endsWith( "asc" )
1085
|| suffix.endsWith( "nii" )
1086
|| suffix.endsWith( "nii.gz" )
1087
|| suffix.endsWith( "fib" ) )
1089
filenames.push_back( path.toStdString() );
1093
if( suffix == "owp" || suffix == "owproj" )
1095
projects.push_back( path.toStdString() );
1099
unsupported.push_back( path.toStdString() );
1103
if( projects.size() > 0 )
1105
for( size_t i = 0; i < projects.size(); ++i )
1107
asyncProjectLoad( projects[ i ] );
1111
if( filenames.size() > 0 )
1113
m_loaderSignal( filenames );
1116
if( unsupported.size() > 0 )
1118
QString message = QString() +
1119
"The following files are not supported as standard data types by OpenWalnut at the moment:<br>";
1120
for( size_t i = 0; i < unsupported.size(); ++i )
1122
message += QString::fromStdString( unsupported[ i ] ) + QString( "<br>" );
1124
message += "There may be additional modules supporting them.<br>"
1125
"All other files have been loaded and should be visible in the module "
1126
"browser and network editor.";
1127
QMessageBox::information( this, "Not yet implemented!",
1134
void WMainWindow::dropEvent( QDropEvent* event )
1136
handleDrop( event );
1137
QMainWindow::dropEvent( event );
1140
bool WMainWindow::isDropAcceptable( const QMimeData* mimeData )
1142
if( mimeData->hasUrls() )
1144
foreach( QUrl url, mimeData->urls() )
1146
QString path = url.toLocalFile();
1147
QFileInfo info( path );
1148
QString suffix = info.completeSuffix();
1149
if( suffix.endsWith( "cnt" )
1150
|| suffix.endsWith( "edf" )
1151
|| suffix.endsWith( "asc" )
1152
|| suffix.endsWith( "nii" )
1153
|| suffix.endsWith( "nii.gz" )
1154
|| suffix.endsWith( "fib" )
1155
|| suffix.endsWith( "owp" )
1156
|| suffix.endsWith( "owproj" ) )
1166
void WMainWindow::dragMoveEvent( QDragMoveEvent* event )
1168
if( WMainWindow::isDropAcceptable( event->mimeData() ) )
1170
event->acceptProposedAction();
1172
QMainWindow::dragMoveEvent( event );
1175
void WMainWindow::dragEnterEvent( QDragEnterEvent* event )
1177
if( WMainWindow::isDropAcceptable( event->mimeData() ) )
1179
event->acceptProposedAction();
1181
QMainWindow::dragEnterEvent( event );
1184
void WMainWindow::closeSplash()
1186
m_splash->finish( this );
1189
QSplashScreen* WMainWindow::getSplash() const
1195
* Create a distinct separator.
1197
* \param parent the parent
1199
* \return the separator
1201
QAction* createSeperator( QWidget* parent )
1203
QAction* separator = new QAction( parent );
1204
separator->setSeparator( true );
1208
void WMainWindow::addGlobalMenu( QWidget* widget )
1210
widget->addAction( createSeperator( this ) );
1211
widget->addAction( m_loadButton );
1212
widget->addAction( m_saveAction );
1213
widget->addAction( createSeperator( this ) );
1214
widget->addAction( m_viewAction );
1215
widget->addAction( m_cameraAction );
1216
widget->addAction( m_settingsAction );
1217
widget->addAction( createSeperator( this ) );
1218
widget->addAction( m_helpAction );
1219
widget->addAction( createSeperator( this ) );
1220
widget->addAction( m_quitAction );