WQt4Gui.cpp 15.6 KB
Newer Older
Mathias Goldau's avatar
[STYLE]  
Mathias Goldau committed
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
7
//
wiebel's avatar
wiebel committed
8
// This file is part of OpenWalnut.
9
//
wiebel's avatar
wiebel committed
10
// OpenWalnut is free software: you can redistribute it and/or modify
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,
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/>.
22 23 24
//
//---------------------------------------------------------------------------

ebaum's avatar
ebaum committed
25
#include <iostream>
26
#include <fstream>
27 28
#include <string>
#include <vector>
29

30 31 32 33
// Use filesystem version 2 for compatibility with newer boost versions.
#ifndef BOOST_FILESYSTEM_VERSION
    #define BOOST_FILESYSTEM_VERSION 2
#endif
34
#include <boost/filesystem.hpp>
35
#include <boost/shared_ptr.hpp>
36

37
#include <QtGui/QApplication>
38
#include <QtGui/QFileDialog>
39
#include <QtCore/QDir>
40
#include <QtCore/QSettings>
41

Mathias Goldau's avatar
Mathias Goldau committed
42
#include "WMainWindow.h" // this has to be included before any other includes
43
#include "WApplication.h"
44 45 46 47 48 49 50 51 52 53
#include "core/common/WConditionOneShot.h"
#include "core/common/WIOTools.h"
#include "core/common/WPathHelper.h"
#include "core/dataHandler/WDataHandler.h"
#include "core/dataHandler/WSubject.h"
#include "core/graphicsEngine/WGraphicsEngine.h"
#include "core/kernel/WKernel.h"
#include "core/kernel/WModuleContainer.h"
#include "core/kernel/WProjectFile.h"
#include "core/kernel/WROIManager.h"
54
#include "controlPanel/WQtControlPanel.h"
55
#include "events/WModuleAssocEvent.h"
56
#include "events/WModuleConnectEvent.h"
Mathias Goldau's avatar
Mathias Goldau committed
57
#include "events/WModuleCrashEvent.h"
58
#include "events/WModuleDisconnectEvent.h"
59
#include "events/WModuleReadyEvent.h"
60
#include "events/WModuleRemovedEvent.h"
61
#include "events/WOpenCustomDockWidgetEvent.h"
Mathias Goldau's avatar
Mathias Goldau committed
62 63
#include "events/WRoiAssocEvent.h"
#include "events/WRoiRemoveEvent.h"
64
#include "events/WUpdateTextureSorterEvent.h"
65 66
#include "WQtModuleConfig.h"

Mathias Goldau's avatar
Mathias Goldau committed
67
#include "WQt4Gui.h"
ebaum's avatar
ebaum committed
68

69 70 71 72 73
#ifdef Q_WS_X11
    #include <X11/Xlib.h>   // NOLINT - this needs to be done AFTER Qt has set some defines in their headers and after several other
                            //          headers which are included indirectly, although it is a system header.
#endif

74 75
WMainWindow* WQt4Gui::m_mainWindow = NULL;

76
QSettings* WQt4Gui::m_settings = NULL;
ebaum's avatar
ebaum committed
77

78 79
WQt4Gui::WQt4Gui( const boost::program_options::variables_map& options, int argc, char** argv )
    : WGUI( argc, argv ),
80 81
    m_optionsMap( options ),
    m_loadDeferredOnce( true )
82
{
ebaum's avatar
ebaum committed
83
}
Sebastian Eichelbaum's avatar
[STYLE]  
Sebastian Eichelbaum committed
84

85
WQt4Gui::~WQt4Gui()
86
{
87
    delete m_settings;
88 89
}

90 91 92 93 94
void WQt4Gui::moduleError( boost::shared_ptr< WModule > module, const WException& exception )
{
    QCoreApplication::postEvent( m_mainWindow, new WModuleCrashEvent( module, exception.what() ) );
}

95 96 97 98 99
WMainWindow* WQt4Gui::getMainWindow()
{
    return m_mainWindow;
}

100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
void WQt4Gui::deferredLoad()
{
    m_deferredLoadMutex.lock();
    if( m_loadDeferredOnce )
    {
        m_loadDeferredOnce = false;
        wlog::debug( "OpenWalnut" ) << "Deferred loading of data and project files.";

       // check if we want to load data due to command line and call the respective function
        if( m_optionsMap.count( "input" ) )
        {
            m_kernel->loadDataSets( m_optionsMap["input"].as< std::vector< std::string > >() );
        }

        // Load project file
        if( m_optionsMap.count( "project" ) )
        {
            try
            {
                boost::shared_ptr< WProjectFile > proj = boost::shared_ptr< WProjectFile >(
                        new WProjectFile( m_optionsMap["project"].as< std::string >() )
                );

                // This call is asynchronous. It parses the file and the starts a thread to actually do all the stuff
                proj->load();
            }
            catch( const WException& e )
            {
                wlog::error( "GUI" ) << "Project file \"" << m_optionsMap["project"].as< std::string >() << "\" could not be loaded. Message: " <<
                    e.what();
            }
        }
    }
    m_deferredLoadMutex.unlock();
}

136 137
int WQt4Gui::run()
{
138 139 140 141
#ifdef Q_WS_X11
    XInitThreads();
#endif

142 143
    // init logger
    m_loggerConnection = WLogger::getLogger()->subscribeSignal( WLogger::AddLog, boost::bind( &WQt4Gui::slotAddLog, this, _1 ) );
144

145
    // make qapp instance before using the applicationDirPath() function
146 147 148 149
#ifdef Q_WS_MAC
    //TODO(mario): this should run on all platforms but crashes at least on Linux right now. Therefore, I only use it on OSX
    WApplication appl( m_argc, m_argv, true );
#else
150 151
    // TODO( mario ): I want a WApplication here for session handling but that code crashes
    QApplication appl( m_argc, m_argv, true );
152
#endif
153

154
    // the call path of the application, this uses QApplication which needs to be instantiated.
155
    boost::filesystem::path walnutBin = boost::filesystem::path( QApplication::applicationDirPath().toStdString() );
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
    // setup path helper which provides several paths to others
#ifdef Q_WS_MAC
    // apple has a special file hierarchy in so-called bundles
    // this code determines whether we are started from a bundle context
    // and sets the paths according to Apple's guidelines inside the bundle
    if ( QApplication::applicationDirPath().endsWith( "/MacOS" ) )
    {
        std::cout <<  "OSX bundle" << std::endl;
        // we are in a bundle
        // TODO(mario): apply default OSX behavior of using $HOME/Library/OpenWalnut ?
        WPathHelper::getPathHelper()->setBasePathsOSXBundle( walnutBin, boost::filesystem::path( QDir::homePath().toStdString() ) / ".OpenWalnut" );
    }
    else
    {
        // assume standard behavior
        WPathHelper::getPathHelper()->setBasePaths( walnutBin, boost::filesystem::path( QDir::homePath().toStdString() ) / ".OpenWalnut" );
    }
#else
    // on all other platforms, get the home directory form Qt and the path from the application binary location
175
    WPathHelper::getPathHelper()->setBasePaths( walnutBin, boost::filesystem::path( QDir::homePath().toStdString() ) / ".OpenWalnut" );
176
#endif
177 178 179 180
    // with the correct paths, we can load the settings
    m_settings = new QSettings( QString::fromStdString( ( WPathHelper::getHomePath() / "config.qt4gui" ).string() ), QSettings::IniFormat );

    WQtModuleConfig::initPathHelper();
181

182
    // get the minimum log level from preferences
183 184
    LogLevel logLevel = static_cast< LogLevel >( WQt4Gui::getSettings().value( "qt4gui/logLevel", LL_INFO ).toInt() );
    WLogger::getLogger()->setDefaultLogLevel( logLevel );
185

186
    // print the first output
187
    wlog::debug( "OpenWalnut" ) << "OpenWalnut binary path: " << walnutBin;
188
    wlog::info( "GUI" ) << "Bringing up GUI";
189

190
    // startup graphics engine
191
    m_ge = WGraphicsEngine::getGraphicsEngine();
192
    m_ge->subscribeSignal( GE_STARTUPCOMPLETE, boost::bind( &WQt4Gui::deferredLoad, this ) );
193

194
    // and startup kernel
195
    m_kernel = boost::shared_ptr< WKernel >( WKernel::instance( m_ge, shared_from_this() ) );
196
    m_kernel->run();
197 198 199
    t_ModuleErrorSignalHandlerType func = boost::bind( &WQt4Gui::moduleError, this, _1, _2 );
    m_kernel->getRootContainer()->addDefaultNotifier( WM_ERROR, func );

200
    // bind the GUI's slot with the signals provided by the kernel
201 202 203
    WCondition::t_ConditionNotifierType newDatasetSignal = boost::bind( &WQt4Gui::slotUpdateTextureSorter, this );
    WDataHandler::getDefaultSubject()->getListChangeCondition()->subscribeSignal( newDatasetSignal );

204
    // Assoc Event
205
    t_ModuleGenericSignalHandlerType assocSignal = boost::bind( &WQt4Gui::slotAddDatasetOrModuleToTree, this, _1 );
206
    m_kernel->getRootContainer()->addDefaultNotifier( WM_ASSOCIATED, assocSignal );
207 208

    // Ready Event
209
    t_ModuleGenericSignalHandlerType readySignal = boost::bind( &WQt4Gui::slotActivateDatasetOrModuleInTree, this, _1 );
210
    m_kernel->getRootContainer()->addDefaultNotifier( WM_READY, readySignal );
211 212

    // Remove Event
213
    t_ModuleGenericSignalHandlerType removedSignal = boost::bind( &WQt4Gui::slotRemoveDatasetOrModuleInTree, this, _1 );
214 215
    m_kernel->getRootContainer()->addDefaultNotifier( WM_REMOVED, removedSignal );

216 217 218 219 220 221 222 223
    // Connect Event
    t_GenericSignalHandlerType connectionEstablishedSignal = boost::bind( &WQt4Gui::slotConnectionEstablished, this, _1, _2 );
    m_kernel->getRootContainer()->addDefaultNotifier( CONNECTION_ESTABLISHED, connectionEstablishedSignal );

    // Disconnect Event
    t_GenericSignalHandlerType connectionClosedSignal = boost::bind( &WQt4Gui::slotConnectionClosed, this, _1, _2 );
    m_kernel->getRootContainer()->addDefaultNotifier( CONNECTION_CLOSED, connectionClosedSignal );

224 225 226 227
    boost::shared_ptr< boost::function< void( osg::ref_ptr< WROI > ) > > assocRoiSignal;
    assocRoiSignal =
        boost::shared_ptr< boost::function< void( osg::ref_ptr< WROI > ) > >(
            new boost::function< void( osg::ref_ptr< WROI > ) > ( boost::bind( &WQt4Gui::slotAddRoiToTree, this, _1 ) ) );
228
    m_kernel->getRoiManager()->addAddNotifier( assocRoiSignal );
229 230 231 232 233

    boost::shared_ptr< boost::function< void( osg::ref_ptr< WROI > ) > > removeRoiSignal;
    removeRoiSignal =
        boost::shared_ptr< boost::function< void( osg::ref_ptr< WROI > ) > >(
            new boost::function< void( osg::ref_ptr< WROI > ) > ( boost::bind( &WQt4Gui::slotRemoveRoiFromTree, this, _1 ) ) );
234
    m_kernel->getRoiManager()->addRemoveNotifier( removeRoiSignal );
235

236 237
    // create the window
    m_mainWindow = new WMainWindow();
238 239 240 241
#ifdef Q_WS_MAC
    //TODO(mario): this should run on all platforms but crashes at least on Linux right now. Therefore, I only use it on OSX
    appl.setMyMainWidget( m_mainWindow );
#endif
242 243
    m_mainWindow->setupGUI();
    m_mainWindow->show();
244

245 246 247 248 249 250
    // connect out loader signal with kernel
#ifdef _WIN32
    getLoadButtonSignal()->connect( boost::bind( &WKernel::loadDataSetsSynchronously, m_kernel, _1 ) );
#else
    getLoadButtonSignal()->connect( boost::bind( &WKernel::loadDataSets, m_kernel, _1 ) );
#endif
251

252 253
    // now we are initialized
    m_isInitialized( true );
254

255
     // run
256 257
    int qtRetCode = appl.exec();

258 259
    delete m_mainWindow;

260 261 262 263
    // signal everybody to shut down properly.
    WKernel::getRunningKernel()->wait( true );
    WKernel::getRunningKernel()->getGraphicsEngine()->wait( true );

264 265
    m_loggerConnection.disconnect();

266
    return qtRetCode;
267 268
}

269 270 271
void WQt4Gui::slotUpdateTextureSorter()
{
    // create a new event for this and insert it into event queue
272
    QCoreApplication::postEvent( m_mainWindow->getControlPanel(), new WUpdateTextureSorterEvent() );
273 274
}

Sebastian Eichelbaum's avatar
Sebastian Eichelbaum committed
275
void WQt4Gui::slotAddLog( const WLogEntry& /*entry*/ )
276
{
Sebastian Eichelbaum's avatar
Sebastian Eichelbaum committed
277
    // TODO(rfrohl): create a new event for this and insert it into event queue
278 279
}

280
void WQt4Gui::slotAddDatasetOrModuleToTree( boost::shared_ptr< WModule > module )
281
{
282
    // create a new event for this and insert it into event queue
283
    QCoreApplication::postEvent( m_mainWindow->getControlPanel(), new WModuleAssocEvent( module ) );
284 285 286 287
    if( m_mainWindow->getNetworkEditor() )
    {
        QCoreApplication::postEvent( m_mainWindow->getNetworkEditor(), new WModuleAssocEvent( module ) );
    }
288 289
}

290
void WQt4Gui::slotAddRoiToTree( osg::ref_ptr< WROI > roi )
schurade's avatar
schurade committed
291
{
292
    QCoreApplication::postEvent( m_mainWindow->getControlPanel(), new WRoiAssocEvent( roi ) );
schurade's avatar
schurade committed
293 294
}

295
void WQt4Gui::slotRemoveRoiFromTree( osg::ref_ptr< WROI > roi )
296
{
297
    QCoreApplication::postEvent( m_mainWindow->getControlPanel(), new WRoiRemoveEvent( roi ) );
298 299
}

300
void WQt4Gui::slotActivateDatasetOrModuleInTree( boost::shared_ptr< WModule > module )
301 302
{
    // create a new event for this and insert it into event queue
303
    QCoreApplication::postEvent( m_mainWindow->getControlPanel(), new WModuleReadyEvent( module ) );
304
    QCoreApplication::postEvent( m_mainWindow, new WModuleReadyEvent( module ) );
305 306 307 308
    if( m_mainWindow->getNetworkEditor() )
    {
        QCoreApplication::postEvent( m_mainWindow->getNetworkEditor(), new WModuleReadyEvent( module ) );
    }
309 310
}

311
void WQt4Gui::slotRemoveDatasetOrModuleInTree( boost::shared_ptr< WModule > module )
312 313
{
    // create a new event for this and insert it into event queue
314 315 316 317
    if( m_mainWindow->getNetworkEditor() )
    {
        QCoreApplication::postEvent( m_mainWindow->getNetworkEditor(), new WModuleRemovedEvent( module ) );
    }
318
    QCoreApplication::postEvent( m_mainWindow->getControlPanel(), new WModuleRemovedEvent( module ) );
319
    QCoreApplication::postEvent( m_mainWindow, new WModuleRemovedEvent( module ) );
320 321
}

322 323 324
void WQt4Gui::slotConnectionEstablished( boost::shared_ptr<WModuleConnector> in, boost::shared_ptr<WModuleConnector> out )
{
    // create a new event for this and insert it into event queue
325
    if( in->isInputConnector() )
326
    {
327
        QCoreApplication::postEvent( m_mainWindow->getControlPanel(), new WModuleConnectEvent( in, out ) );
328 329 330 331
        if( m_mainWindow->getNetworkEditor() )
        {
            QCoreApplication::postEvent( m_mainWindow->getNetworkEditor(), new WModuleConnectEvent( in, out ) );
        }
332 333 334
    }
    else
    {
335
        QCoreApplication::postEvent( m_mainWindow->getControlPanel(), new WModuleConnectEvent( out, in ) );
336 337 338 339
        if( m_mainWindow->getNetworkEditor() )
        {
            QCoreApplication::postEvent( m_mainWindow->getNetworkEditor(), new WModuleConnectEvent( out, in ) );
        }
340
    }
341 342 343 344 345
}

void WQt4Gui::slotConnectionClosed( boost::shared_ptr<WModuleConnector> in, boost::shared_ptr<WModuleConnector> out )
{
    // create a new event for this and insert it into event queue
346
    if( in->isInputConnector() )
347
    {
348 349 350 351
        if( m_mainWindow->getNetworkEditor() )
        {
            QCoreApplication::postEvent( m_mainWindow->getNetworkEditor(), new WModuleDisconnectEvent( in, out ) );
        }
352
        QCoreApplication::postEvent( m_mainWindow->getControlPanel(), new WModuleDisconnectEvent( in, out ) );
353 354 355
    }
    else
    {
356 357 358 359
        if( m_mainWindow->getNetworkEditor() )
        {
            QCoreApplication::postEvent( m_mainWindow->getNetworkEditor(), new WModuleDisconnectEvent( out, in ) );
        }
360
        QCoreApplication::postEvent( m_mainWindow->getControlPanel(), new WModuleDisconnectEvent( out, in ) );
361
    }
362 363
}

364 365
boost::shared_ptr< WModule > WQt4Gui::getSelectedModule()
{
366
    return m_mainWindow->getControlPanel()->getSelectedModule();
367 368
}

schurade's avatar
schurade committed
369
boost::signals2::signal1< void, std::vector< std::string > >* WQt4Gui::getLoadButtonSignal()
370
{
371
    return m_mainWindow->getLoaderSignal();
372 373
}

374
boost::shared_ptr< WCustomWidget > WQt4Gui::openCustomWidget( std::string title, WGECamera::ProjectionMode projectionMode,
375
    boost::shared_ptr< WCondition > shutdownCondition )
376
{
377 378 379 380
    WConditionSet conditionSet;
    conditionSet.setResetable( true, false );
    conditionSet.add( shutdownCondition );

381 382
    boost::shared_ptr< WFlag< boost::shared_ptr< WCustomWidget > > > widgetFlag(
        new WFlag< boost::shared_ptr< WCustomWidget > >( new WConditionOneShot, boost::shared_ptr< WCustomWidget >() ) );
383 384
    conditionSet.add( widgetFlag->getCondition() );

385
    QCoreApplication::postEvent( m_mainWindow, new WOpenCustomDockWidgetEvent( title, projectionMode, widgetFlag ) );
386 387 388

    conditionSet.wait();
    return widgetFlag->get();
389 390 391 392
}

void WQt4Gui::closeCustomWidget( std::string title )
{
393
    m_mainWindow->closeCustomDockWidget( title );
394
}
395

396 397 398 399 400
void WQt4Gui::closeCustomWidget( WCustomWidget::SPtr widget )
{
    m_mainWindow->closeCustomDockWidget( widget->getTitle() );
}

401 402 403 404 405
QSettings& WQt4Gui::getSettings()
{
    return *m_settings;
}

406 407 408 409
const boost::program_options::variables_map& WQt4Gui::getOptionMap() const
{
    return m_optionsMap;
}