//============================================================================= // // OpenFlipper // Copyright (C) 2008 by Computer Graphics Group, RWTH Aachen // www.openflipper.org // //----------------------------------------------------------------------------- // // License // // OpenFlipper is free software: you can redistribute it and/or modify // 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. // // OpenFlipper is distributed in the hope that it will be useful, // 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 // along with OpenFlipper. If not, see . // //----------------------------------------------------------------------------- // // $Revision$ // $Author$ // $Date$ // //============================================================================= //============================================================================= // // CLASS Core - IMPLEMENTATION // //============================================================================= //== INCLUDES ================================================================= // -------------------- mview #include "Core.hh" // -------------------- ACG #include #include // -------------------- Qt #include #include #include #include #include #include #include #include #include #include "OpenFlipper/BasePlugin/BaseInterface.hh" #include "OpenFlipper/BasePlugin/KeyInterface.hh" #include "OpenFlipper/BasePlugin/MouseInterface.hh" #include "OpenFlipper/BasePlugin/PickingInterface.hh" #include "OpenFlipper/BasePlugin/ToolboxInterface.hh" #include "OpenFlipper/BasePlugin/TextureInterface.hh" #include "OpenFlipper/BasePlugin/MenuInterface.hh" #include "OpenFlipper/BasePlugin/INIInterface.hh" #include "OpenFlipper/BasePlugin/GlobalAccessInterface.hh" #include "OpenFlipper/INIFile/INIFile.hh" #include "OpenFlipper/common/GlobalOptions.hh" #include #include #include #include #include #include "OpenFlipper/BasePlugin/PluginFunctions.hh" #include #define WIDGET_HEIGHT 800 #define WIDGET_WIDTH 800 //== IMPLEMENTATION ========================================================== /** \brief Constuctor for the Core Widget ( This is stage 1 , call init for stage 2) * * Initialization is working the following way:\n * - Setup basic paths \n * - Get Options from Option files ( While skipping the OpenFiles Sections as Core is not running )\n * - Jump back ( Stage two is done by calling init from main ) so CALL init!! * - This Two stage system allows using commandline options which override Option Files */ Core:: Core() : QObject(), nextBackupId_(0), set_random_base_color_(true), coreWidget_(0) { //init logFile logStream_ = 0; logFile_ = 0; OpenFlipper::Options::logFileEnabled(true); //init nodes root_node_scenegraph_ = new ACG::SceneGraph::SeparatorNode(0, "SceneGraph Root Node"); root_node_ = new ACG::SceneGraph::SeparatorNode(root_node_scenegraph_, "Data Root Node"); // Add ViewMode All ViewMode* vm = new ViewMode(); vm->name = "All"; vm->custom = false; vm->visibleWidgets = QStringList(); viewModes_.push_front(vm); // Get all relevant Paths and Options from option files setupOptions(); } /** \brief Second initialization stage * * This Stage does the following :\n * - Create the Core GUI Elements (Examiner, Toolbox,...)\n * - Create the MenuBar \n * - load the Plugins \n * - connect the Mouse slots \n * - Load all ini files (This includes the Global Option files) \n */ void Core::init() { // Make root_node available to the plugins ( defined in PluginFunctions.hh) PluginFunctions::set_rootNode( root_node_ ); PluginFunctions::set_sceneGraphRootNode( root_node_scenegraph_ ); // Initialize the first object as the root Object for the object tree objectRoot_ = dynamic_cast< BaseObject* > ( new GroupObject("ObjectRoot") ); PluginFunctions::setDataRoot( objectRoot_ ); if ( OpenFlipper::Options::gui() ) { redrawTimer_ = new QTimer(); redrawTimer_->setSingleShot(true); connect(redrawTimer_, SIGNAL(timeout()), this, SLOT(updateView()),Qt::DirectConnection); if ( OpenFlipper::Options::splash() ) { QPixmap splashPixmap(OpenFlipper::Options::iconDirStr() + OpenFlipper::Options::dirSeparator() + "splash.png"); splash_ = new QSplashScreen(splashPixmap); splash_->show(); splash_->showMessage("Initializing mainwindow" , Qt::AlignBottom | Qt::AlignLeft , Qt::white); QApplication::processEvents(); } coreWidget_ = new CoreWidget(viewModes_ , plugins); connect(coreWidget_, SIGNAL(clearAll()) , this, SLOT(clearAll())); connect(coreWidget_, SIGNAL(loadMenu()) , this, SLOT(slotLoadMenu())); connect(coreWidget_, SIGNAL(addEmptyObjectMenu()) , this, SLOT(slotAddEmptyObjectMenu())); connect(coreWidget_, SIGNAL(saveMenu()) , this, SLOT(slotSaveMenu())); connect(coreWidget_, SIGNAL(saveToMenu()) , this, SLOT(slotSaveToMenu())); connect(coreWidget_, SIGNAL(loadIniMenu()) , this, SLOT(slotLoadIniMenu())); connect(coreWidget_, SIGNAL(saveIniMenu()) , this, SLOT(slotSaveIniMenu())); connect(coreWidget_, SIGNAL(applyOptions()) , this, SLOT(applyOptions())); connect(coreWidget_, SIGNAL(saveOptions()) , this, SLOT(saveOptions())); connect(coreWidget_, SIGNAL(recentOpen(QAction*)) , this, SLOT(slotRecentOpen(QAction*))); connect(coreWidget_, SIGNAL(exit()) , this, SLOT(slotExit())); connect(coreWidget_, SIGNAL(loadPlugin()) , this, SLOT(slotLoadPlugin())); connect(coreWidget_, SIGNAL(unloadPlugin()) , this, SLOT(slotUnloadPlugin())); coreWidget_->resize(1000,1000); coreWidget_->setWindowTitle( OpenFlipper::Options::windowTitle() ); // Make examiner available to the plugins ( defined in PluginFunctions.hh) PluginFunctions::set_examiner( coreWidget_->examiner_widget_ ); } // ====================================================================== // Create intermediate logger class for Core which will mangle the output // ====================================================================== PluginLogger* newlog = new PluginLogger("Core"); loggers_.push_back(newlog); connect(this,SIGNAL(log(Logtype, QString )),newlog,SLOT(slotLog(Logtype, QString )),Qt::DirectConnection); connect(this,SIGNAL(log(QString )),newlog,SLOT(slotLog(QString )),Qt::DirectConnection); // Connect it to the Master logger if ( OpenFlipper::Options::gui() ) connect(newlog,SIGNAL(log(Logtype, QString )),coreWidget_,SLOT(slotLog(Logtype, QString )),Qt::DirectConnection); connect(newlog,SIGNAL(log(Logtype, QString )),this,SLOT(slotLog(Logtype, QString )),Qt::DirectConnection); // connection to file logger connect(newlog,SIGNAL(log(Logtype, QString )),this,SLOT(slotLogToFile(Logtype, QString )),Qt::DirectConnection); // ====================================================================== // Create a logger class for CoreWidget // ====================================================================== if ( OpenFlipper::Options::gui() ){ PluginLogger* widgetlog = new PluginLogger("CoreWidget"); loggers_.push_back(widgetlog); connect(coreWidget_,SIGNAL(log(Logtype, QString )),widgetlog,SLOT(slotLog(Logtype, QString )),Qt::DirectConnection); connect(coreWidget_,SIGNAL(log(QString )),widgetlog,SLOT(slotLog(QString )),Qt::DirectConnection); // Connect it to the Master logger connect(widgetlog,SIGNAL(log(Logtype, QString )),coreWidget_,SLOT(slotLog(Logtype, QString )),Qt::DirectConnection); connect(widgetlog,SIGNAL(log(Logtype, QString )),this,SLOT(slotLog(Logtype, QString )),Qt::DirectConnection); // connection to file logger connect(widgetlog,SIGNAL(log(Logtype, QString )),this,SLOT(slotLogToFile(Logtype, QString )),Qt::DirectConnection); } // ====================================================================== // Catch OpenMesh Error logs with an own Logger // ====================================================================== newlog = new PluginLogger("Core ( OpenMesh )",LOGERR); omerr().connect(*newlog); omerr().disconnect(std::cerr); loggers_.push_back(newlog); // Connect it to the Master logger if ( OpenFlipper::Options::gui() ) connect(newlog,SIGNAL(log(Logtype, QString )),coreWidget_,SLOT(slotLog(Logtype, QString )),Qt::DirectConnection); connect(newlog,SIGNAL(log(Logtype, QString )),this,SLOT(slotLog(Logtype, QString )),Qt::DirectConnection); // connection to file logger connect(newlog,SIGNAL(log(Logtype, QString )),this,SLOT(slotLogToFile(Logtype, QString )),Qt::DirectConnection); // ====================================================================== // Catch OpenMesh omout logs with an own Logger // ====================================================================== newlog = new PluginLogger("Core ( OpenMesh )",LOGINFO); omout().connect(*newlog); omout().disconnect(std::cout); loggers_.push_back(newlog); // Connect it to the Master logger if ( OpenFlipper::Options::gui() ) connect(newlog,SIGNAL(log(Logtype, QString )),coreWidget_,SLOT(slotLog(Logtype, QString )),Qt::DirectConnection); connect(newlog,SIGNAL(log(Logtype, QString )),this,SLOT(slotLog(Logtype, QString )),Qt::DirectConnection); // connection to file logger connect(newlog,SIGNAL(log(Logtype, QString )),this,SLOT(slotLogToFile(Logtype, QString )),Qt::DirectConnection); // ====================================================================== // Catch OpenMesh omlog logs with an own Logger // ====================================================================== newlog = new PluginLogger("Core ( OpenMesh )",LOGOUT); omlog().connect(*newlog); loggers_.push_back(newlog); // Connect it to the Master logger if ( OpenFlipper::Options::gui() ) connect(newlog,SIGNAL(log(Logtype, QString )),coreWidget_,SLOT(slotLog(Logtype, QString )),Qt::DirectConnection); connect(newlog,SIGNAL(log(Logtype, QString )),this,SLOT(slotLog(Logtype, QString )),Qt::DirectConnection); // connection to file logger connect(newlog,SIGNAL(log(Logtype, QString )),this,SLOT(slotLogToFile(Logtype, QString )),Qt::DirectConnection); // ====================================================================== // Log Scripting stuff through a separate logger // ====================================================================== newlog = new PluginLogger("Scripting",LOGOUT); loggers_.push_back(newlog); // Connect it to the Master logger if ( OpenFlipper::Options::gui() ) connect(newlog,SIGNAL(log(Logtype, QString )),coreWidget_,SLOT(slotLog(Logtype, QString )),Qt::DirectConnection); connect(newlog,SIGNAL(log(Logtype, QString )),this,SLOT(slotLog(Logtype, QString )),Qt::DirectConnection); // connection to file logger connect(newlog,SIGNAL(log(Logtype, QString )),this,SLOT(slotLogToFile(Logtype, QString )),Qt::DirectConnection); // connect signal to logger connect(this,SIGNAL(scriptLog(QString )),newlog,SLOT(slotLog(QString )),Qt::DirectConnection); // ====================================================================== // This connection will tell the plugins, when their Toolbox is active // ====================================================================== ///@todo reimplement // connect(module_list,SIGNAL(currentChanged(int)),this,SLOT(slotToolboxSwitched(int))); // process Events every 500 msecs during script execution scriptEngine_.setProcessEventsInterval( 500 ); // Register own print function : QScriptValue printFunction = scriptEngine_.newFunction(myPrintFunction); printFunction.setProperty("textedit",scriptEngine_.newQObject(this)); scriptEngine_.globalObject().setProperty("print", printFunction); // Register Vector Type to ScriptEngine ( is Vec3d ) qScriptRegisterMetaType(&scriptEngine_, toScriptValueVector, fromScriptValueVector, scriptEngine_.newQObject(&vec3dPrototype_)); // set a constructor to allow creation via Vector(x,y,z) QScriptValue ctor = scriptEngine_.newFunction(createVector); scriptEngine_.globalObject().setProperty("Vector", ctor); // // Register ObjectId Type to ScriptEngine ( is int ) // qScriptRegisterMetaType(&scriptEngine_, // toScriptValueObjectId, // fromScriptValueObjectId); // // // set a constructor to allow creation via Vector(x,y,z) // ctor = scriptEngine_.newFunction(createObjectId); // scriptEngine_.globalObject().setProperty("ObjectId", ctor); // Register idList Type to scripting Engine qScriptRegisterSequenceMetaType< idList >(&scriptEngine_); qScriptRegisterSequenceMetaType< QVector< int > >(&scriptEngine_); // Register Matrix Type to scripting Engine ( is ACG::Matrix4x4d ) qScriptRegisterMetaType(&scriptEngine_, toScriptValueMatrix4x4 , fromScriptValueMatrix4x4, scriptEngine_.newQObject(&matrix4x4Prototype_)); // set a constructor to allow creation via Matrix(x,y,z) QScriptValue matrix4x4ctor = scriptEngine_.newFunction(createMatrix4x4); scriptEngine_.globalObject().setProperty("Matrix4x4", matrix4x4ctor); // Collect Core scripting information QScriptValue scriptInstance = scriptEngine_.newQObject(this, QScriptEngine::QtOwnership, QScriptEngine::ExcludeChildObjects | QScriptEngine::ExcludeSuperClassMethods | QScriptEngine::ExcludeSuperClassProperties ); scriptEngine_.globalObject().setProperty("core", scriptInstance); emit log(LOGOUT,"Core Scripting initialized with Name : core "); emit log(LOGOUT,"Available scripting functions :"); QScriptValueIterator it(scriptInstance); while (it.hasNext()) { it.next(); /// Skip all signals for function calls if ( checkSignal( this, it.name().toAscii() ) ) continue; scriptingFunctions_.push_back( "core." + it.name() ); emit log(LOGOUT,"\t" + it.name()); } emit log(LOGOUT,"============================================================================================="); loadPlugins(); if ( OpenFlipper::Options::gui() ) { if ( OpenFlipper::Options::defaultToolboxMode( ) != "" ) coreWidget_->setViewMode( OpenFlipper::Options::defaultToolboxMode() ); else coreWidget_->setViewMode("All"); connect( coreWidget_->examiner_widget_, SIGNAL(signalMouseEvent(QMouseEvent*)), this,SLOT(slotMouseEvent(QMouseEvent*))); connect( coreWidget_->examiner_widget_, SIGNAL(signalMouseEventIdentify(QMouseEvent*)), this,SLOT(slotMouseEventIdentify(QMouseEvent*))); connect( coreWidget_->examiner_widget_, SIGNAL(signalWheelEvent(QWheelEvent *, const std::string &)), this, SLOT(slotWheelEvent(QWheelEvent *, const std::string &))); } QStringList optionFiles = OpenFlipper::Options::optionFiles(); for ( int i = 0 ; i < (int)optionFiles.size(); ++i) { if ( OpenFlipper::Options::gui() && OpenFlipper::Options::splash() ) { splash_->showMessage("Loading Configuration File " + QString::number(i) + "/" + QString::number(optionFiles.size()) , Qt::AlignBottom | Qt::AlignLeft , Qt::white); QApplication::processEvents(); } openIniFile( optionFiles[i] ); } if ( OpenFlipper::Options::lang().contains("UTF") || OpenFlipper::Options::lang().contains("utf") ) { emit log(LOGWARN,"Warning, OpenFlipper detected that you are using an utf-8 locale!"); emit log(LOGWARN,"Only OFF files are fully supported with UTF8. Others might fail."); emit log(LOGWARN,"You can change your locale by :"); emit log(LOGWARN,"export LANG=C"); emit log(LOGWARN,"Work is in progress to resolve this issue."); } applyOptions(); if ( OpenFlipper::Options::gui() ) { coreWidget_->show(); if ( OpenFlipper::Options::splash() ) { splash_->finish(coreWidget_); } } } //----------------------------------------------------------------------------- Core::~Core() { for ( uint i = 0 ; i < plugins.size() ; ++i ){ BaseInterface* basePlugin = qobject_cast< BaseInterface * >(plugins[i].plugin); // Dont call exit if we cannot get the Plugin if ( basePlugin ) if ( checkSlot( plugins[i].plugin , "exit()" ) ) QMetaObject::invokeMethod(plugins[i].plugin, "exit", Qt::DirectConnection); } objectRoot_->deleteSubtree(); delete objectRoot_; // Clean up loggers for ( uint i = 0 ; i < loggers_.size(); ++i ) delete loggers_[i]; } //----------------------------------------------------------------------------- void Core::slotMouseEventIdentify( QMouseEvent* _event ) { // Dont do anything as a context Menu will popup on right button click if ( _event->button() == Qt::RightButton ) return; emit PluginMouseEventIdentify( _event ); } //----------------------------------------------------------------------------- void Core::slotMouseEvent( QMouseEvent* _event ) { // Dont do anything as a context Menu will popup on right button click if ( _event->button() == Qt::RightButton ) return; emit PluginMouseEvent(_event ); } //----------------------------------------------------------------------------- void Core::slotWheelEvent( QWheelEvent * _event, const std::string & _mode) { emit PluginWheelEvent(_event , _mode ); } //----------------------------------------------------------------------------- void Core::slotAddPickMode( const std::string _mode ) { if ( OpenFlipper::Options::gui() ) coreWidget_->examiner_widget_->addPickMode(_mode); } //----------------------------------------------------------------------------- void Core::slotAddHiddenPickMode( const std::string _mode ) { if ( OpenFlipper::Options::gui() ) coreWidget_->examiner_widget_->addPickMode(_mode,false,1000,false); } //----------------------------------------------------------------------------- void Core::slotAddPickMode( const std::string _mode , QCursor _cursor) { if ( OpenFlipper::Options::gui() ) coreWidget_->examiner_widget_->addPickMode(_mode,false,1000,true,_cursor); } //----------------------------------------------------------------------------- void Core::slotAddHiddenPickMode( const std::string _mode , QCursor _cursor) { if ( OpenFlipper::Options::gui() ) coreWidget_->examiner_widget_->addPickMode(_mode,false,1000,false, _cursor); } //----------------------------------------------------------------------------- /** Update the view in the examiner widget */ void Core::updateView() { if ( OpenFlipper::Options::doSlotDebugging() ) { if ( sender() != 0 ) { if ( sender()->metaObject() != 0 ) { emit log(LOGINFO,"updateView() called by " + QString( sender()->metaObject()->className() ) ); } } } if ( OpenFlipper::Options::restrictFrameRate() ) { // redraw time not reached ... waiting for timer event for next redraw if ( redrawTimer_->isActive() ) { if ( OpenFlipper::Options::doSlotDebugging() ) emit log(LOGINFO,"Too early for redraw! Delaying request from " + QString( sender()->metaObject()->className() ) ); return; } // std::cerr << "Redraw" << std::endl; // Start the timer if we are not called by the timer if ( sender() != redrawTimer_ ) { redrawTimer_->start( 1000 / OpenFlipper::Options::maxFrameRate() ); } } if ( OpenFlipper::Options::gui() && !OpenFlipper::Options::openingIni() ) { coreWidget_->examiner_widget_->sceneGraph(root_node_scenegraph_); coreWidget_->examiner_widget_->updateGL(); } } //----------------------------------------------------------------------------- void Core::clearAll() { objectRoot_->deleteSubtree(); emit allCleared(); emit ObjectListUpdated(-1); slotScriptInfo( "core" , "clearAll()" ); } //----------------------------------------------------------------------------- void Core::exitApplication() { QTimer* timer = new QTimer(); connect(timer, SIGNAL(timeout()), this, SLOT(slotExit())); timer->start(100); QApplication::quit(); } //----------------------------------------------------------------------------- void Core::setDrawMode(QString _mode) { QStringList list = _mode.split(';'); std::vector< QString > drawModeList; for ( int i = 0 ; i < list.size() ; ++i ) drawModeList.push_back(list[i]); unsigned int mode = ListToDrawMode(drawModeList); PluginFunctions::setDrawMode( mode ); emit updateView(); } //----------------------------------------------------------------------------- void Core::translate( Vector _vec ) { PluginFunctions::translate( _vec ); } //----------------------------------------------------------------------------- void Core::rotate( Vector _axis, double _angle, Vector _center ) { PluginFunctions::rotate( _axis, _angle, _center ); } //----------------------------------------------------------------------------- void Core::setViewingDirection( Vector _direction, Vector _upvector ) { PluginFunctions::viewingDirection(_direction, _upvector); } //----------------------------------------------------------------------------- void Core::fullscreen() { if ( OpenFlipper::Options::gui() ) coreWidget_->toggleFullscreen(); } //----------------------------------------------------------------------------- void Core::logger() { if ( OpenFlipper::Options::gui() ) coreWidget_->toggleLogger(); } //----------------------------------------------------------------------------- void Core::toolbox() { if ( OpenFlipper::Options::gui() ) coreWidget_->toggleToolbox(); } //----------------------------------------------------------------------------- void Core::slotRecentOpen(QAction* _action) { QVector< OpenFlipper::Options::RecentFile > recentFiles = OpenFlipper::Options::recentFiles(); for (int i = 0 ; i < recentFiles.size() ; ++i ) if ( recentFiles[i].filename == _action->text() ){ loadObject(recentFiles[i].type, recentFiles[i].filename); break; } } void Core::writeOnExit() { QString inifile = QDir::home().absolutePath() + OpenFlipper::Options::dirSeparator() + ".OpenFlipper" + OpenFlipper::Options::dirSeparator() + "OpenFlipper.ini"; INIFile ini; if ( ! ini.connect( inifile ,false) ) { emit log(LOGERR,"Failed to connect to users ini file"); if ( ! ini.connect( inifile,true) ) { emit log(LOGERR,"Can not create user ini file"); } else { writeApplicationOptions(ini); ini.disconnect(); } } else { writeApplicationOptions(ini); ini.disconnect(); } // Call exit for all plugins for (uint i = 0 ; i < plugins.size() ; ++i) { BaseInterface* basePlugin = qobject_cast< BaseInterface * >(plugins[i].plugin); if ( basePlugin ) if ( checkSlot( plugins[i].plugin , "exit()" ) ) QMetaObject::invokeMethod(plugins[i].plugin, "exit", Qt::DirectConnection); } } void Core::slotExit() { writeOnExit(); if (logFile_) logFile_->close(); qApp->quit(); } /// Synchronise two viewers bool Core::add_sync_host(const QString& _name) { if ( OpenFlipper::Options::gui() ) { emit log(LOGINFO,"Adding SyncHost"); bool ok = coreWidget_->examiner_widget_->add_sync_host(_name); if (ok) coreWidget_->examiner_widget_->setSynchronization(true); else emit log(LOGERR,"Sync failed! "); return ok; } return false; } /// log to file void Core::slotLogToFile(Logtype _type, QString _message){ if (!OpenFlipper::Options::logFileEnabled()) return; if (logStream_ == 0){ //check if a logfile has been specified if (OpenFlipper::Options::logFile() == "") OpenFlipper::Options::logFile(QDir::home().absolutePath() + OpenFlipper::Options::dirSeparator() + ".OpenFlipper" + OpenFlipper::Options::dirSeparator() + "OpenFlipper.log"); logFile_ = new QFile( OpenFlipper::Options::logFile() ); if ( logFile_->open(QFile::WriteOnly) ) { logStream_ = new QTextStream (logFile_); }else{ emit log(LOGERR, "Unable to open logfile!"); return; } } switch (_type) { case LOGINFO: (*logStream_) << "INFO:"; break; case LOGOUT: (*logStream_) << "OUT :"; break; case LOGWARN: (*logStream_) << "WARN:"; break; case LOGERR: (*logStream_) << "ERR :"; break; } (*logStream_) << _message << "\n" << flush; } //=============================================================================