WMainWindow.cpp 16.8 KB
Newer Older
1 2
//---------------------------------------------------------------------------
//
3
// Project: OpenWalnut ( http://www.openwalnut.org )
4
//
5 6
// Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
// For more information see http://www.openwalnut.org/copying
wiebel's avatar
wiebel committed
7
//
wiebel's avatar
wiebel committed
8
// This file is part of OpenWalnut.
wiebel's avatar
wiebel committed
9
//
wiebel's avatar
wiebel committed
10
// OpenWalnut is free software: you can redistribute it and/or modify
wiebel's avatar
wiebel committed
11 12 13 14
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
wiebel's avatar
wiebel committed
15
// OpenWalnut is distributed in the hope that it will be useful,
wiebel's avatar
wiebel committed
16 17 18 19 20
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
wiebel's avatar
wiebel committed
21
// along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
wiebel's avatar
wiebel committed
22
//
23 24
//---------------------------------------------------------------------------

25
#include <iostream>
26 27
#include <string>
#include <vector>
28
#include <map>
29

30 31
#include <boost/thread.hpp>

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

43
#include "WMainWindow.h"
44
#include "WOpenCustomDockWidgetEvent.h"
45
#include "WQtGLWidget.h"
46
#include "WQtNavGLWidget.h"
47
#include "WQtCustomDockWidget.h"
48 49 50
#include "events/WModuleReadyEvent.h"
#include "events/WEventTypes.h"
#include "datasetbrowser/WPropertyBoolWidget.h"
51 52 53
#include "../../common/WColor.h"
#include "../../common/WPreferences.h"
#include "../../kernel/WKernel.h"
wiebel's avatar
wiebel committed
54

schurade's avatar
schurade committed
55 56
#include "../../graphicsEngine/WROIBox.h"

57
#include "../icons/WIcons.h"
58

59
WMainWindow::WMainWindow() :
60
    QMainWindow(),
61
    m_iconManager()
Sebastian Eichelbaum's avatar
Sebastian Eichelbaum committed
62
{
63
    setupGUI();
Sebastian Eichelbaum's avatar
Sebastian Eichelbaum committed
64
}
65

66
void WMainWindow::setupGUI()
67
{
68
    m_iconManager.addIcon( std::string( "load" ), fileopen_xpm );
69
    m_iconManager.addIcon( std::string( "logo" ), logoIcon_xpm );
70
    m_iconManager.addIcon( std::string( "help" ), question_xpm );
71
    m_iconManager.addIcon( std::string( "quit" ), quit_xpm );
72

73
    if( objectName().isEmpty() )
74
    {
75
        setObjectName( QString::fromUtf8( "MainWindow" ) );
76
    }
77 78 79
    resize( 946, 632 );
    setWindowIcon( m_iconManager.getIcon( "logo" ) );
    setWindowTitle( QApplication::translate( "MainWindow", "OpenWalnut", 0, QApplication::UnicodeUTF8 ) );
80

81 82 83 84 85 86 87 88 89
    m_menuBar = new QMenuBar( 0 );
    QMenu* fileMenu = m_menuBar->addMenu( "File" );
    fileMenu->addAction( m_iconManager.getIcon( "load" ), "Load", this, SLOT( openLoadDialog() ), QKeySequence( "Ctrl+L" ) );
    fileMenu->addAction( m_iconManager.getIcon( "quit" ), "Quit", this, SLOT( close() ), QKeySequence( "Ctrl+Q" ) );

    QMenu* helpMenu = m_menuBar->addMenu( "Help" );
    helpMenu->addAction( m_iconManager.getIcon( "help" ), "About OpenWalnut", this, SLOT( openAboutDialog() ), QKeySequence( "F1" ) );
    setMenuBar( m_menuBar );

90
    m_centralwidget = new QWidget( this );
91
    m_centralwidget->setObjectName( QString::fromUtf8( "centralwidget" ) );
92
    setCentralWidget( m_centralwidget );
93

94
    m_mainGLWidget = boost::shared_ptr< WQtGLWidget >( new WQtGLWidget( "main", this, WGECamera::ORTHOGRAPHIC ) );
95 96
    m_mainGLWidget->initialize();
    setCentralWidget( m_mainGLWidget.get() );
wiebel's avatar
wiebel committed
97

98 99 100 101 102 103
    // initially 3 navigation views
    {
        bool hideWidget;
        if( !( WPreferences::getPreference( "qt4gui.hideAxial", &hideWidget ) && hideWidget) )
        {
            m_navAxial = boost::shared_ptr< WQtNavGLWidget >( new WQtNavGLWidget( "axial", this, 160, "axialPos" ) );
104
            m_navAxial->setFeatures( QDockWidget::AllDockWidgetFeatures );
105
            addDockWidget( Qt::LeftDockWidgetArea, m_navAxial.get() );
Sebastian Eichelbaum's avatar
[STYLE]  
Sebastian Eichelbaum committed
106 107 108
            // TODO(ebaum): adopt!
            // connect( m_navAxial.get(), SIGNAL( navSliderValueChanged( QString, int ) ),
            //          &m_propertyManager, SLOT( slotIntChanged( QString, int ) ) );
109 110 111 112
        }
        if( !( WPreferences::getPreference( "qt4gui.hideCoronal", &hideWidget ) && hideWidget) )
        {
            m_navCoronal = boost::shared_ptr< WQtNavGLWidget >( new WQtNavGLWidget( "coronal", this, 200, "coronalPos" ) );
113
            m_navCoronal->setFeatures( QDockWidget::AllDockWidgetFeatures );
114
            addDockWidget( Qt::LeftDockWidgetArea, m_navCoronal.get() );
Sebastian Eichelbaum's avatar
[STYLE]  
Sebastian Eichelbaum committed
115 116 117
            // TODO(ebaum): adopt!
            // connect( m_navCoronal.get(), SIGNAL( navSliderValueChanged( QString, int ) ),
            //          &m_propertyManager, SLOT( slotIntChanged( QString, int ) ) );
118 119 120 121
        }
        if( !( WPreferences::getPreference( "qt4gui.hideSagittal", &hideWidget ) && hideWidget) )
        {
            m_navSagittal = boost::shared_ptr< WQtNavGLWidget >( new WQtNavGLWidget( "sagittal", this, 160, "sagittalPos" ) );
122
            m_navSagittal->setFeatures( QDockWidget::AllDockWidgetFeatures );
123
            addDockWidget( Qt::LeftDockWidgetArea, m_navSagittal.get() );
Sebastian Eichelbaum's avatar
[STYLE]  
Sebastian Eichelbaum committed
124 125 126
            // TODO(ebaum): adopt!
            // connect( m_navSagittal.get(), SIGNAL( navSliderValueChanged( QString, int ) ),
            //          &m_propertyManager, SLOT( slotIntChanged( QString, int ) ) );
127 128
        }
    }
129

130
    // Default background color from config file
131
    {
132 133 134 135 136 137 138 139 140 141 142
        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 );
        }
143 144
    }

145
    setupPermanentToolBar();
146

147 148
    setupCompatiblesToolBar();

149
    m_datasetBrowser = new WQtDatasetBrowser( this );
150
    m_datasetBrowser->setFeatures( QDockWidget::AllDockWidgetFeatures );
151
    addDockWidget( Qt::RightDockWidgetArea, m_datasetBrowser );
152
    m_datasetBrowser->addSubject( "Default Subject" );
153

154 155
    // TODO(ebaum): adopt!
    //connect( m_datasetBrowser, SIGNAL( dataSetBrowserEvent( QString, bool ) ), &m_propertyManager, SLOT( slotBoolChanged( QString, bool ) ) );
156
}
157

158
void WMainWindow::setupPermanentToolBar()
159
{
160
    m_permanentToolBar = new WQtToolBar( "Permanent Toolbar", this );
161

162 163 164 165
    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 );
166 167


168 169
    WQtPushButton* loadButton = new WQtPushButton( m_iconManager.getIcon( "load" ), "load", m_permanentToolBar );
    WQtPushButton* roiButton = new WQtPushButton( m_iconManager.getIcon( "ROI" ), "ROI", m_permanentToolBar );
170

171 172
    connect( loadButton, SIGNAL( pressed() ), this, SLOT( openLoadDialog() ) );
    connect( roiButton, SIGNAL( pressed() ), this, SLOT( newRoi() ) );
173

174 175
    loadButton->setToolTip( "Load Data" );
    roiButton->setToolTip( "Create New ROI" );
176

177 178
    m_permanentToolBar->addWidget( loadButton );
    m_permanentToolBar->addWidget( roiButton );
179

180
    m_permanentToolBar->addSeparator();
181

182 183
    addToolBar( Qt::TopToolBarArea, m_permanentToolBar );
}
184

185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
void WMainWindow::moduleSpecificSetup( boost::shared_ptr< WModule > module )
{
    // nav slices use separate buttons for slice on/off switching
    if ( module->getName() == "Navigation Slice Module" )
    {
        boost::shared_ptr< WPropertyBase > prop = module->getProperties2()->findProperty( "showAxial" );
        if ( !prop )
        {
               WLogger::getLogger()->
                   addLogMessage( "Navigation Slice Module does not provide the property \"showAxial\", which is required by the GUI.", "GUI",
                                  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 );
        }
205

206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
        prop = module->getProperties2()->findProperty( "showCoronal" );
        if ( !prop )
        {
               WLogger::getLogger()->
                   addLogMessage( "Navigation Slice Module does not provide the property \"showCoronal\", which is required by the GUI.", "GUI",
                                  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 );
        }
221

222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
        prop = module->getProperties2()->findProperty( "showSagittal" );
        if ( !prop )
        {
               WLogger::getLogger()->
                   addLogMessage( "Navigation Slice Module does not provide the property \"showSagittal\", which is required by the GUI.", "GUI",
                                  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 );
        }
    }
238

wiebel's avatar
wiebel committed
239
}
240

241 242
void WMainWindow::setupCompatiblesToolBar()
{
243 244
    m_iconManager.addIcon( std::string( "o" ), o_xpm ); // duumy icon for modules

245
    m_compatiblesToolBar = new WQtToolBar( "Compatible Modules Toolbar", this );
246 247 248 249 250 251 252 253 254 255 256

    // optional toolbar break
    {
        bool useToolBarBreak = true;
        WPreferences::getPreference( "qt4gui.useToolBarBreak", &useToolBarBreak );
        if( useToolBarBreak )
        {
            addToolBarBreak( Qt::TopToolBarArea );
        }
    }

257 258
    addToolBar( Qt::TopToolBarArea, m_compatiblesToolBar );
}
259

260
WQtDatasetBrowser* WMainWindow::getDatasetBrowser()
261
{
262
    return m_datasetBrowser;
263
}
264

265
WQtToolBar* WMainWindow::getCompatiblesToolBar()
266 267 268 269
{
    return m_compatiblesToolBar;
}

270
void WMainWindow::openLoadDialog()
271
{
272 273
    QFileDialog fd;
    fd.setFileMode( QFileDialog::ExistingFiles );
wiebel's avatar
wiebel committed
274 275

    QStringList filters;
276 277
    filters << "Known file types (*.edf *.asc *.nii *.nii.gz *.fib)"
            << "EEG files (*.asc *.edf)"
wiebel's avatar
wiebel committed
278
            << "NIfTI (*.nii *.nii.gz)"
279 280
            << "Fibers (*.fib)"
            << "Any files (*)";
wiebel's avatar
wiebel committed
281
    fd.setNameFilters( filters );
282 283 284 285 286 287 288 289 290 291 292 293 294 295
    fd.setViewMode( QFileDialog::Detail );
    QStringList fileNames;
    if ( fd.exec() )
    {
        fileNames = fd.selectedFiles();
    }

    std::vector< std::string >stdFileNames;

    QStringList::const_iterator constIterator;
    for ( constIterator = fileNames.constBegin(); constIterator != fileNames.constEnd(); ++constIterator )
    {
        stdFileNames.push_back( ( *constIterator ).toLocal8Bit().constData() );
    }
296 297
    m_loaderSignal( stdFileNames );
}
298

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

schurade's avatar
schurade committed
314
boost::signals2::signal1< void, std::vector< std::string > >* WMainWindow::getLoaderSignal()
315 316 317 318
{
    return &m_loaderSignal;
}

319
boost::signals2::signal2< void, boost::shared_ptr< WModule >, boost::shared_ptr< WModule > >* WMainWindow::getModuleButtonSignal()
320 321 322 323
{
    return &m_moduleButtonSignal;
}

324 325 326
WIconManager*  WMainWindow::getIconManager()
{
    return &m_iconManager;
327
}
328 329 330 331 332 333 334 335 336 337

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


    // handle close event
    if ( reallyClose )
    {
338 339
        // signal everybody to shut down properly.
        WKernel::getRunningKernel()->finalize();
340 341 342 343

        // now nobody acesses the osg anymore
        // clean up gl widgets
        m_mainGLWidget->close();
344 345 346 347 348 349 350 351 352 353 354 355
        if( m_navAxial )
        {
            m_navAxial->close();
        }
        if( m_navCoronal )
        {
            m_navCoronal->close();
        }
        if( m_navSagittal )
        {
            m_navSagittal->close();
        }
356

357 358 359 360 361 362 363
        // 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();
        }
364
        //m_customDockWidgetsLock.unlock();
365

366 367 368 369 370 371 372 373 374
        // finally close
        e->accept();
    }
    else
    {
        e->ignore();
    }
}

375 376
void WMainWindow::customEvent( QEvent* event )
{
377
    if( event->type() == WOpenCustomDockWidgetEvent::CUSTOM_TYPE )
378
    {
379 380 381 382 383
        // OpenCustomDockWidgetEvent
        WOpenCustomDockWidgetEvent* ocdwEvent = static_cast< WOpenCustomDockWidgetEvent* >( event );
        std::string title = ocdwEvent->getTitle();

        boost::shared_ptr< WQtCustomDockWidget > widget;
384 385

        boost::mutex::scoped_lock lock( m_customDockWidgetsLock );
386 387
        if( m_customDockWidgets.count( title ) == 0 )
        {
388 389 390
            // create new custom dock widget
            widget = boost::shared_ptr< WQtCustomDockWidget >(
                new WQtCustomDockWidget( title, this, ocdwEvent->getProjectionMode() ) );
391 392 393 394 395 396 397
            addDockWidget( Qt::BottomDockWidgetArea, widget.get() );

            // store it in CustomDockWidget list
            m_customDockWidgets.insert( make_pair( title, widget ) );
        }
        else
        {
398 399
            widget = m_customDockWidgets[title];
            widget->increaseUseCount();
400
        }
401
        //m_customDockWidgetsLock.unlock();
402 403

        ocdwEvent->getFlag()->set( widget );
404 405 406 407 408 409 410 411
    }
    else
    {
        // other event
        QMainWindow::customEvent( event );
    }
}

412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427
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() );
        }
    }

    return QMainWindow::event( event );
}

428 429 430 431 432 433
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 >();
434
    //m_customDockWidgetsLock.unlock();
435 436 437 438
    return out;
}


439 440 441
void WMainWindow::closeCustomDockWidget( std::string title )
{
    boost::mutex::scoped_lock lock( m_customDockWidgetsLock );
442
    if( m_customDockWidgets.count( title ) > 0 )
443
    {
444 445 446 447 448
        if( m_customDockWidgets[title]->decreaseUseCount() )
        {
            // custom dock widget should be deleted
            m_customDockWidgets.erase( title );
        }
449
    }
450
    //m_customDockWidgetsLock.unlock();
451 452
}

453 454
void WMainWindow::slotActivateModule( QString module )
{
455 456
    // TODO(schurade): do we really need the signal? Why can't we use the kernel directly?
    m_moduleButtonSignal( getDatasetBrowser()->getSelectedModule(), WModuleFactory::getModuleFactory()->getPrototypeByName( module.toStdString() ) );
457
}
458

schurade's avatar
schurade committed
459 460 461 462
void WMainWindow::newRoi()
{
    if ( m_datasetBrowser->getSelectedRoi().get() == NULL )
    {
schurade's avatar
[STYLE]  
schurade committed
463 464
        boost::shared_ptr< WROIBox > newRoi = boost::shared_ptr< WROIBox >( new WROIBox( wmath::WPosition( 60., 60., 60. ),
                wmath::WPosition( 80., 80., 80. ) ) );
schurade's avatar
schurade committed
465 466 467 468
        WKernel::getRunningKernel()->getRoiManager()->addRoi( newRoi );
    }
    else
    {
schurade's avatar
[STYLE]  
schurade committed
469 470
        boost::shared_ptr< WROIBox > newRoi = boost::shared_ptr< WROIBox >( new WROIBox( wmath::WPosition( 60., 60., 60. ),
                wmath::WPosition( 80., 80., 80. ) ) );
schurade's avatar
schurade committed
471 472 473
        WKernel::getRunningKernel()->getRoiManager()->addRoi( newRoi, m_datasetBrowser->getSelectedRoi()->getROI() );
    }
}