/*===========================================================================*\ * * * OpenFlipper * * Copyright (C) 2001-2011 by Computer Graphics Group, RWTH Aachen * * www.openflipper.org * * * *--------------------------------------------------------------------------- * * This file is part of OpenFlipper. * * * * 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 with the * * following exceptions: * * * * If other files instantiate templates or use macros * * or inline functions from this file, or you compile this file and * * link it with other files to produce an executable, this file does * * not by itself cause the resulting executable to be covered by the * * GNU Lesser General Public License. This exception does not however * * invalidate any other reasons why the executable file might be * * covered by the GNU Lesser General Public License. * * * * 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 LesserGeneral Public * * License along with OpenFlipper. If not, * * see . * * * \*===========================================================================*/ /*===========================================================================*\ * * * $Revision$ * * $LastChangedBy$ * * $Date$ * * * \*===========================================================================*/ #include #include "ScriptingPlugin.hh" #include #include #include "OpenFlipper/common/GlobalOptions.hh" #include #include #include #include #include ScriptingPlugin::ScriptingPlugin() { } void ScriptingPlugin::pluginsInitialized() { if ( OpenFlipper::Options::nogui() ) return; ///@todo register objectid variable // Scriping Menu QMenu *scriptingMenu; emit getMenubarMenu(tr("&Scripting"), scriptingMenu, true ); QIcon icon; QAction* showWidget = scriptingMenu->addAction( tr("Show script editor") ); icon.addFile(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"scriptEditor.png"); showWidget->setIcon(icon); connect( showWidget, SIGNAL( triggered() ) , this , SLOT( showScriptWidget() )); scriptWidget_ = new ScriptWidget(); QString iconPath = OpenFlipper::Options::iconDirStr() + OpenFlipper::Options::dirSeparator(); scriptWidget_->setWindowIcon( OpenFlipper::Options::OpenFlipperIcon() ); icon.addFile(iconPath+"document-open.png"); scriptWidget_->actionLoad_Script->setIcon(icon); icon.addFile(iconPath+"document-save.png"); scriptWidget_->actionSave_Script->setIcon(icon); icon.addFile(iconPath+"document-save-as.png"); scriptWidget_->actionSave_Script_As->setIcon(icon); icon.addFile(iconPath+"window-close.png"); scriptWidget_->actionClose->setIcon(icon); // ================================================================== // Add a toolbar // ================================================================== QToolBar* toolBar = new QToolBar(tr("Scripting Toolbar")); QAction* openButton = new QAction(QIcon(iconPath + "document-open.png"), "Open", toolBar); toolBar->addAction(openButton); connect (openButton, SIGNAL( triggered() ), this, SLOT( slotLoadScript() ) ); QAction* saveButton = new QAction(QIcon(iconPath + "document-save.png"), "Save", toolBar); toolBar->addAction(saveButton); connect (saveButton, SIGNAL( triggered() ), this, SLOT( slotSaveScript() ) ); QAction* saveAsButton = new QAction(QIcon(iconPath + "document-save-as.png"), "Save as", toolBar); toolBar->addAction(saveAsButton); connect (saveAsButton, SIGNAL( triggered() ), this, SLOT( slotSaveScriptAs() ) ); toolBar->addSeparator(); QAction* executeButton = new QAction(QIcon(iconPath + "arrow-right.png"), "Execute", toolBar); toolBar->addAction(executeButton); connect (executeButton, SIGNAL( triggered() ), this, SLOT( slotExecuteScriptButton() ) ); scriptWidget_->addToolBar(toolBar); // ================================================================== // Create a status bar // ================================================================== statusBar_ = new QStatusBar(); scriptWidget_->setStatusBar( statusBar_ ); // ================================================================== scriptWidget_->hide(); scriptWidget_->resize(scriptWidget_->width() , std::min(QApplication::desktop()->screenGeometry().height() - 150 , 800) ); connect (scriptWidget_->actionLoad_Script, SIGNAL( triggered() ), this, SLOT( slotLoadScript() ) ); scriptWidget_->actionLoad_Script->setShortcut( QKeySequence(Qt::CTRL + Qt::Key_O) ); connect (scriptWidget_->actionSave_Script, SIGNAL( triggered() ), this, SLOT( slotSaveScript() ) ); scriptWidget_->actionSave_Script->setShortcut( QKeySequence(Qt::CTRL + Qt::Key_S) ); connect (scriptWidget_->actionSave_Script_As, SIGNAL( triggered() ), this, SLOT( slotSaveScriptAs() ) ); connect (scriptWidget_->actionClose, SIGNAL( triggered() ), scriptWidget_, SLOT( close() ) ); connect (scriptWidget_->currentScript, SIGNAL( textChanged() ), this, SLOT( slotEnableSave() ) ); connect (scriptWidget_->functionList, SIGNAL( itemClicked(QListWidgetItem*) ), this, SLOT( slotFunctionClicked(QListWidgetItem*) )); connect (scriptWidget_->functionList, SIGNAL( itemDoubleClicked(QListWidgetItem*) ), this, SLOT( slotFunctionDoubleClicked(QListWidgetItem*) )); //filter connect (scriptWidget_->filterButton, SIGNAL( clicked() ), this, SLOT( slotApplyFilter() )); connect (scriptWidget_->resetButton, SIGNAL( clicked() ), scriptWidget_->functionList, SLOT( reset() )); connect (scriptWidget_->resetButton, SIGNAL( clicked() ), scriptWidget_->filterEdit, SLOT( clear() )); connect (scriptWidget_->functionList, SIGNAL(getDescription(QString,QString&,QStringList&,QStringList&)), this , SIGNAL(getDescription(QString,QString&,QStringList&,QStringList&))); scriptWidget_->description->setVisible( false ); highlighterCurrent_ = new Highlighter( scriptWidget_->currentScript->document() ); highlighterLive_ = new Highlighter( scriptWidget_->liveEdit ); // highlighterList_ = new Highlighter( scriptWidget_->functionList ); frameTime_.start(); } void ScriptingPlugin::slotApplyFilter(){ scriptWidget_->functionList->filter( scriptWidget_->filterEdit->text() ); } void ScriptingPlugin::slotEnableSave(){ scriptWidget_->actionSave_Script->setEnabled( true ); } void ScriptingPlugin::showScriptWidget( ) { if ( OpenFlipper::Options::nogui() ) return; scriptWidget_->show(); // Update list of available functions QStringList completeList; emit getAvailableFunctions( completeList ); QStringList plugins; QStringList functions; scriptWidget_->functionList->clear( ); //Update Highlighters for ( int i = 0 ; i < completeList.size() ; ++i) { QString plugin = completeList[i].section('.',0,0); if ( ! plugins.contains( plugin ) ) plugins.push_back( plugin ); QString function = completeList[i].section('.',1,1); function = function.section('(',0,0); if ( ! functions.contains( function ) ) functions.push_back( function ); scriptWidget_->functionList->addItem( completeList[i] ); } highlighterCurrent_->pluginPatterns_ = plugins; highlighterCurrent_->functionPatterns_ = functions; highlighterCurrent_->update(); highlighterCurrent_->rehighlight(); highlighterLive_->pluginPatterns_ = plugins; highlighterLive_->functionPatterns_ = functions; highlighterLive_->update(); highlighterLive_->rehighlight(); // highlighterList_->pluginPatterns_ = plugins; // highlighterList_->functionPatterns_ = functions; // highlighterList_->update(); // highlighterList_->rehighlight(); } void ScriptingPlugin::hideScriptWidget( ) { if ( OpenFlipper::Options::nogui() ) return; scriptWidget_->hide(); } void ScriptingPlugin::slotScriptInfo( QString _pluginName , QString _functionName ) { if ( OpenFlipper::Options::scripting() || OpenFlipper::Options::nogui() ) return; scriptWidget_->liveEdit->append( _pluginName + "." + _functionName ); QScrollBar* bar = scriptWidget_->liveEdit->verticalScrollBar(); bar->setValue(bar->maximum()); } void ScriptingPlugin::slotExecuteScript( QString _script ) { if ( OpenFlipper::Options::gui()) statusBar_->showMessage(tr("Executing Script")); QScriptEngine* engine; emit getScriptingEngine( engine ); /// Switch scripting mode on OpenFlipper::Options::scripting(true); // Get the filename of the script and set it in the scripting environment engine->globalObject().setProperty("ScriptPath",QScriptValue(engine,lastFile_.section(OpenFlipper::Options::dirSeparator(), 0, -2))); // Execute the script engine->evaluate( _script ); // Catch errors and print some reasonable error message to log and statusbar bool error = false; if ( engine->hasUncaughtException() ) { error = true; QScriptValue result = engine->uncaughtException(); QString exception = result.toString(); int lineNumber = engine->uncaughtExceptionLineNumber(); emit log( LOGERR , tr("Script execution failed at line %1, with : %2 ").arg(lineNumber).arg(exception) ); if ( OpenFlipper::Options::gui()) { statusBar_->showMessage(tr("Script execution failed at line %1, with : %2 ").arg(lineNumber).arg(exception)); // Get cursor and move it to the line containing the error QTextCursor cursor = scriptWidget_->currentScript->textCursor(); cursor.setPosition(0); cursor.movePosition ( QTextCursor::Down, QTextCursor::MoveAnchor, lineNumber - 1 ); scriptWidget_->currentScript->setTextCursor(cursor); scriptWidget_->currentScript->highLightErrorLine(lineNumber); } } if ( OpenFlipper::Options::gui() && !error) statusBar_->clearMessage(); /// Switch scripting mode off OpenFlipper::Options::scripting(false); } void ScriptingPlugin::slotExecuteFileScript( QString _filename ) { QString script; QFile data(_filename); if (data.open(QFile::ReadOnly)) { QTextStream input(&data); do { script.append(input.readLine() + "\n"); } while (!input.atEnd()); if ( OpenFlipper::Options::gui() ) scriptWidget_->currentScript->setPlainText(script); // Set lastfilename to the opened file lastFile_ = _filename; slotExecuteScript(script); } else emit log(LOGERR,tr("Unable to open script file!")); } void ScriptingPlugin::slotExecuteScriptButton() { slotExecuteScript( scriptWidget_->currentScript->toPlainText() ); } QString ScriptingPlugin::mangleScript(QString _input ) { // Update list of available functions QStringList functions; emit getAvailableFunctions( functions ); std::cerr << "Todo : mangle script " << std::endl; return _input; } void ScriptingPlugin::sleep( int _seconds ) { if ( OpenFlipper::Options::nogui() ) return; QTimer timer; timer.setSingleShot(true); timer.start( _seconds * 1000 ); while (timer.isActive() ) QApplication::processEvents(); } void ScriptingPlugin::sleepmsecs( int _mseconds ) { if ( OpenFlipper::Options::nogui() ) return; QTimer timer; timer.setSingleShot(true); timer.start( _mseconds ); while (timer.isActive() ) QApplication::processEvents(); } void ScriptingPlugin::frameStart( ) { frameTime_.restart(); } void ScriptingPlugin::waitFrameEnd( int _mseconds ) { int elapsed = frameTime_.elapsed(); // Wait remaining time if ( elapsed < _mseconds ) { sleepmsecs( _mseconds - elapsed ); } // restart timer frameTime_.restart(); } void ScriptingPlugin::waitContinue( ) { if ( OpenFlipper::Options::nogui() ) return; QMessageBox box; box.addButton(tr("Continue"),QMessageBox::AcceptRole); box.setText(tr("Script execution has been interrupted")); box.setIcon(QMessageBox::Information); box.setWindowModality(Qt::NonModal); box.setWindowTitle(tr("Continue?")); box.setWindowFlags( box.windowFlags() | Qt::WindowStaysOnTopHint); box.show(); while ( box.isVisible() ) QApplication::processEvents(); } void ScriptingPlugin::waitContinue( QString _msg, int _x, int _y ) { if ( OpenFlipper::Options::nogui() ) return; QMessageBox box; box.addButton(tr("Continue"),QMessageBox::AcceptRole); box.setText(_msg); box.setIcon(QMessageBox::Information); box.setWindowModality(Qt::NonModal); box.setWindowTitle(tr("Continue?")); box.setWindowFlags( box.windowFlags() | Qt::WindowStaysOnTopHint); if(_x!=-1 && _y!=-1) box.move(_x,_y); box.show(); while ( box.isVisible() ) QApplication::processEvents(); } void ScriptingPlugin::slotLoadScript(){ QString filename = QFileDialog::getOpenFileName(0, tr("Load Script"),OpenFlipper::Options::currentScriptDirStr(), tr("Script Files (*.ofs)")); if (filename == "") return; slotLoadScript(filename); } void ScriptingPlugin::slotLoadScript( QString _filename ) { if (_filename == "") return; // Check if we are in gui mode. Otherwise just ignore this call if ( OpenFlipper::Options::gui() ) { scriptWidget_->currentScript->clear(); QFile data(_filename); if (data.open(QFile::ReadOnly)) { QTextStream input(&data); do { scriptWidget_->currentScript->appendPlainText(input.readLine()); } while (!input.atEnd()); lastFile_ = _filename; OpenFlipper::Options::currentScriptDir( QFileInfo(_filename).absolutePath() ); scriptWidget_->actionSave_Script->setEnabled( false ); scriptWidget_->show(); } } } void ScriptingPlugin::slotSaveScript(){ QFile file(lastFile_); if ( !file.exists()) slotSaveScriptAs(); else{ //write script to file if (file.open(QFile::WriteOnly)) { QTextStream output(&file); output << scriptWidget_->currentScript->toPlainText(); } scriptWidget_->actionSave_Script->setEnabled( false ); } } void ScriptingPlugin::slotSaveScriptAs(){ QString filename = QFileDialog::getSaveFileName(scriptWidget_, tr("Save Script"),OpenFlipper::Options::currentScriptDirStr(), tr("Script Files (*.ofs)")); if (filename == "") return; QFile data(filename); //perhaps add an extension if (!data.exists()){ QFileInfo fi(filename); if (fi.completeSuffix() == ""){ filename = filename + ".ofs"; data.setFileName(filename); } } //write script to file if (data.open(QFile::WriteOnly)) { QTextStream output(&data); output << scriptWidget_->currentScript->toPlainText(); } lastFile_ = filename; OpenFlipper::Options::currentScriptDir( QFileInfo(filename).absolutePath() ); scriptWidget_->actionSave_Script->setEnabled( false ); } void ScriptingPlugin::slotFunctionClicked(QListWidgetItem * _item) { QString slotDescription; QStringList params; QStringList descriptions; emit getDescription(_item->text(), slotDescription, params, descriptions); if ( !slotDescription.isEmpty() ){ if (descriptionLabels_.count() > 0){ //first remove old stuff for (int i = 0; i < descriptionLabels_.count(); i++){ descrLayout_->removeWidget( descriptionLabels_[i] ); delete descriptionLabels_[i]; } descriptionLabels_.clear(); }else descrLayout_ = new QVBoxLayout(); QLabel* lSlotName = new QLabel("" + _item->text() + ""); QLabel* lDescription = new QLabel(slotDescription); lDescription->setWordWrap(true); descrLayout_->addWidget(lSlotName); descrLayout_->addWidget(lDescription); descriptionLabels_.append(lSlotName); descriptionLabels_.append(lDescription); if ( params.count() == descriptions.count() ){ //get parameter-types from function-name QString typeStr = _item->text().section("(",1,1).section(")",0,0); QStringList types = typeStr.split(","); if (types.count() == params.count()){ for(int p=0; p < params.count(); p++ ){ QLabel* param = new QLabel("" + types[p] + " " + params[p] + ":" ); QLabel* descr = new QLabel(descriptions[p]); descr->setWordWrap(true); descrLayout_->addWidget(param); descrLayout_->addWidget(descr); descriptionLabels_.append(param); descriptionLabels_.append(descr); } } } scriptWidget_->description->setLayout( descrLayout_ ); } scriptWidget_->description->setVisible( !slotDescription.isEmpty() ); } void ScriptingPlugin::slotFunctionDoubleClicked(QListWidgetItem * _item) { scriptWidget_->currentScript->insertPlainText( _item->text() ); } void ScriptingPlugin::showScriptInEditor(QString _code) { if ( OpenFlipper::Options::nogui() ) return; showScriptWidget (); scriptWidget_->currentScript->setPlainText(_code); } void ScriptingPlugin::clearEditor() { scriptWidget_->currentScript->clear(); } Q_EXPORT_PLUGIN2( skriptingplugin , ScriptingPlugin );