44 #include "ScriptingPlugin.hh" 50 ScriptingPlugin::ScriptingPlugin() :
57 highlighterCurrent_(0),
63 #ifdef ENABLE_SCRIPT_DEBUGGER
64 #ifdef QT_SCRIPTTOOLS_LIB
74 if ( OpenFlipper::Options::nogui() )
82 emit getMenubarMenu(tr(
"&Scripting"), scriptingMenu,
true );
85 QAction* showWidget = scriptingMenu->addAction( tr(
"Show script editor") );
86 icon.addFile(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+
"scriptEditor.png");
87 showWidget->setIcon(icon);
88 connect( showWidget, SIGNAL( triggered() ) ,
89 this , SLOT( showScriptWidget() ));
94 QString iconPath = OpenFlipper::Options::iconDirStr() + OpenFlipper::Options::dirSeparator();
96 scriptWidget_->setWindowIcon( OpenFlipper::Options::OpenFlipperIcon() );
98 icon.addFile(iconPath+
"document-open.png");
99 scriptWidget_->actionLoad_Script->setIcon(icon);
101 icon.addFile(iconPath+
"document-save.png");
102 scriptWidget_->actionSave_Script->setIcon(icon);
104 icon.addFile(iconPath+
"document-save-as.png");
105 scriptWidget_->actionSave_Script_As->setIcon(icon);
107 icon.addFile(iconPath+
"window-close.png");
108 scriptWidget_->actionClose->setIcon(icon);
114 QToolBar* toolBar =
new QToolBar(tr(
"Scripting Toolbar"));
116 QAction* openButton =
new QAction(QIcon(iconPath +
"document-open.png"),
"Open", toolBar);
117 toolBar->addAction(openButton);
118 connect (openButton, SIGNAL( triggered() ),
this, SLOT( slotLoadScript() ) );
120 QAction* saveButton =
new QAction(QIcon(iconPath +
"document-save.png"),
"Save", toolBar);
121 toolBar->addAction(saveButton);
122 connect (saveButton, SIGNAL( triggered() ),
this, SLOT( slotSaveScript() ) );
124 QAction* saveAsButton =
new QAction(QIcon(iconPath +
"document-save-as.png"),
"Save as", toolBar);
125 toolBar->addAction(saveAsButton);
126 connect (saveAsButton, SIGNAL( triggered() ),
this, SLOT( slotSaveScriptAs() ) );
128 toolBar->addSeparator();
130 debuggerButton_ =
new QAction(QIcon(iconPath +
"script-debugger.png"),
"Enable Debugger", toolBar);
131 debuggerButton_->setCheckable(
true);
132 toolBar->addAction(debuggerButton_);
134 #ifdef ENABLE_SCRIPT_DEBUGGER 136 debuggerButton_->setChecked(
true);
138 debuggerButton_->setChecked(
false);
140 connect (debuggerButton_, SIGNAL( triggered() ),
this, SLOT( slotDebuggerButton() ) );
142 debuggerButton_->setEnabled(
false);
143 debuggerButton_->setToolTip(tr(
"QtScriptTools library not available. Debugger is not available!"));
146 toolBar->addSeparator();
148 QAction* executeButton =
new QAction(QIcon(iconPath +
"arrow-right.png"),
"Execute", toolBar);
149 toolBar->addAction(executeButton);
150 connect (executeButton, SIGNAL( triggered() ),
this, SLOT( slotExecuteScriptButton() ) );
152 scriptWidget_->addToolBar(toolBar);
158 statusBar_ =
new QStatusBar();
160 scriptWidget_->setStatusBar( statusBar_ );
164 scriptWidget_->hide();
167 QScreen *screen = QGuiApplication::primaryScreen();
168 QRect screenGeometry = screen->geometry();
170 scriptWidget_->resize(scriptWidget_->width() , std::min(screenGeometry.height() - 150 , 800) );
172 connect (scriptWidget_->actionLoad_Script, SIGNAL( triggered() ),
this, SLOT( slotLoadScript() ) );
173 scriptWidget_->actionLoad_Script->setShortcut( QKeySequence(Qt::CTRL + Qt::Key_O) );
174 connect (scriptWidget_->actionSave_Script, SIGNAL( triggered() ),
this, SLOT( slotSaveScript() ) );
175 scriptWidget_->actionSave_Script->setShortcut( QKeySequence(Qt::CTRL + Qt::Key_S) );
176 connect (scriptWidget_->actionSave_Script_As, SIGNAL( triggered() ),
this, SLOT( slotSaveScriptAs() ) );
177 connect (scriptWidget_->actionClose, SIGNAL( triggered() ), scriptWidget_, SLOT( close() ) );
179 connect (scriptWidget_->currentScript, SIGNAL( textChanged() ),
this, SLOT( slotScriptChanged() ) );
181 connect (scriptWidget_->functionList, SIGNAL( currentItemChanged (QListWidgetItem*, QListWidgetItem*) ),
182 this, SLOT( slotFunctionClicked(QListWidgetItem*) ));
183 connect (scriptWidget_->functionList, SIGNAL( itemDoubleClicked(QListWidgetItem*) ),
184 this, SLOT( slotFunctionDoubleClicked(QListWidgetItem*) ));
187 connect (scriptWidget_->filterButton, SIGNAL( clicked() ),
188 this, SLOT( slotApplyFilter() ));
189 connect (scriptWidget_->resetButton, SIGNAL( clicked() ),
190 scriptWidget_->functionList, SLOT( reset() ));
191 connect (scriptWidget_->resetButton, SIGNAL( clicked() ),
192 scriptWidget_->filterEdit, SLOT( clear() ));
193 connect (scriptWidget_->functionList, SIGNAL(getDescription(QString,QString&,QStringList&,QStringList&)),
194 this , SIGNAL(getDescription(QString,QString&,QStringList&,QStringList&)));
196 scriptWidget_->description->setVisible(
false );
198 highlighterCurrent_ =
new Highlighter( scriptWidget_->currentScript->document() );
199 highlighterLive_ =
new Highlighter( scriptWidget_->liveEdit );
207 errorTimer_ =
new QTimer();
208 errorTimer_->setSingleShot(
true);
209 connect(errorTimer_,SIGNAL(timeout()),
this,SLOT(slotHighlightError()));
215 #ifdef ENABLE_SCRIPT_DEBUGGER 216 #ifdef QT_SCRIPTTOOLS_LIB 217 QScriptEngine* engine;
218 emit getScriptingEngine( engine );
219 debugger_ =
new QScriptEngineDebugger;
222 debugger_->attachTo(engine);
227 void ScriptingPlugin::slotApplyFilter(){
228 scriptWidget_->functionList->filter( scriptWidget_->filterEdit->text() );
232 scriptWidget_->actionSave_Script->setEnabled(
true );
238 const QString script = scriptWidget_->currentScript->toPlainText();
239 QScriptSyntaxCheckResult syntaxCheck = QScriptEngine::checkSyntax ( script );
241 switch (syntaxCheck.state() ) {
242 case QScriptSyntaxCheckResult::Error :
243 lastProblemLine_ = syntaxCheck.errorLineNumber();
244 lastError_ = syntaxCheck.errorMessage();
245 errorTimer_->start(500);
247 case QScriptSyntaxCheckResult::Valid :
255 scriptWidget_->currentScript->highLightErrorLine(lastProblemLine_);
256 statusBar_->showMessage(lastError_,5000);
260 if ( OpenFlipper::Options::nogui() )
263 scriptWidget_->show();
266 QStringList completeList;
267 emit getAvailableFunctions( completeList );
270 QStringList functions;
272 scriptWidget_->functionList->clear( );
275 for (
int i = 0 ; i < completeList.size() ; ++i) {
277 QString plugin = completeList[i].section(
'.',0,0);
281 if ( ! plugins.contains( plugin ) )
282 plugins.push_back( plugin );
286 QString
function = completeList[i].section(
'.',1,1);
287 function =
function.section(
'(',0,0);
288 if ( ! functions.contains(
function ) )
289 functions.push_back(
function );
293 scriptWidget_->functionList->addItem( completeList[i] );
295 scriptWidget_->functionList->addItem( completeList[i].right(completeList[i].size() - 2) );
300 scriptWidget_->functionList->sortItems ( );
302 highlighterCurrent_->pluginPatterns_ = plugins;
303 highlighterCurrent_->functionPatterns_ = functions;
304 highlighterCurrent_->update();
305 highlighterCurrent_->rehighlight();
307 highlighterLive_->pluginPatterns_ = plugins;
308 highlighterLive_->functionPatterns_ = functions;
309 highlighterLive_->update();
310 highlighterLive_->rehighlight();
313 scriptWidget_->raise();
318 if ( OpenFlipper::Options::nogui() )
321 scriptWidget_->hide();
324 void ScriptingPlugin::slotScriptInfo( QString _pluginName , QString _functionName ) {
326 if ( OpenFlipper::Options::scripting() || OpenFlipper::Options::nogui() )
329 scriptWidget_->liveEdit->append( _pluginName +
"." + _functionName );
331 QScrollBar* bar = scriptWidget_->liveEdit->verticalScrollBar();
332 bar->setValue(bar->maximum());
337 if ( OpenFlipper::Options::gui())
338 statusBar_->showMessage(tr(
"Executing Script"));
340 QScriptEngine* engine;
341 emit getScriptingEngine( engine );
344 OpenFlipper::Options::scripting(
true);
347 engine->globalObject().setProperty(
"ScriptPath",OpenFlipper::Options::currentScriptDirStr());
350 if (_script.contains(QRegExp(
"^include <")) ) {
353 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) 354 QStringList script = _script.split(QRegExp(
"[\r\n]"),QString::SkipEmptyParts);
356 QStringList script = _script.split(QRegExp(
"[\r\n]"),Qt::SkipEmptyParts);
362 int include_index = script.indexOf(QRegExp(
"^include.*"));
364 while ( include_index != -1) {
366 QString include_statement = script[include_index];
369 include_statement.remove(QRegExp(
"^include") );
370 include_statement.remove(
"<" );
371 include_statement.remove(
">" );
372 include_statement = include_statement.trimmed();
375 include_statement.replace(
"ScriptPath",OpenFlipper::Options::currentScriptDirStr());
377 QFile includeFile(include_statement);
379 if (!includeFile.exists() ) {
380 emit log(
LOGERR,
"Script file include not found : " + include_statement +
" from " + script[include_index] );
384 if (!includeFile.open(QFile::ReadOnly | QFile::Text)) {
385 emit log(
LOGERR,
"Unable to open file : " + include_statement);
389 QTextStream in(&includeFile);
390 script[include_index] = in.readAll();
395 _script = script.join(
"\n");
398 include_index = script.indexOf(QRegExp(
"^include.*"));
405 engine->evaluate( _script );
409 if ( engine->hasUncaughtException() ) {
411 QScriptValue result = engine->uncaughtException();
412 QString exception = result.toString();
413 int lineNumber = engine->uncaughtExceptionLineNumber();
414 emit log(
LOGERR , tr(
"Script execution failed at line %1, with : %2 ").arg(lineNumber).arg(exception) );
416 if ( OpenFlipper::Options::gui()) {
417 statusBar_->showMessage(tr(
"Script execution failed at line %1, with : %2 ").arg(lineNumber).arg(exception));
420 QTextCursor cursor = scriptWidget_->currentScript->textCursor();
421 cursor.setPosition(0);
422 cursor.movePosition ( QTextCursor::Down, QTextCursor::MoveAnchor, lineNumber - 1 );
423 scriptWidget_->currentScript->setTextCursor(cursor);
425 scriptWidget_->currentScript->highLightErrorLine(lineNumber);
427 lastProblemLine_ = lineNumber;
428 lastError_ = exception;
433 if ( OpenFlipper::Options::gui() && !error)
434 statusBar_->clearMessage();
437 OpenFlipper::Options::scripting(
false);
440 void ScriptingPlugin::slotExecuteFileScript( QString _filename ) {
443 QFile data(_filename);
444 if (data.open(QFile::ReadOnly)) {
445 QTextStream input(&data);
447 script.append(input.readLine() +
"\n");
448 }
while (!input.atEnd());
450 if ( OpenFlipper::Options::gui() )
451 scriptWidget_->currentScript->setPlainText(script);
454 OpenFlipper::Options::currentScriptDir( _filename.section(OpenFlipper::Options::dirSeparator(), 0, -2) );
456 slotExecuteScript(script);
459 emit log(
LOGERR,tr(
"Unable to open script file!"));
462 void ScriptingPlugin::slotExecuteScriptButton() {
463 slotExecuteScript( scriptWidget_->currentScript->toPlainText() );
468 #ifdef ENABLE_SCRIPT_DEBUGGER 469 #ifdef QT_SCRIPTTOOLS_LIB 470 QScriptEngine* engine;
471 emit getScriptingEngine( engine );
473 if ( debuggerButton_->isChecked() ) {
474 debugger_->attachTo(engine);
485 QString ScriptingPlugin::mangleScript(QString _input ) {
488 QStringList functions;
489 emit getAvailableFunctions( functions );
491 std::cerr <<
"Todo : mangle script " << std::endl;
498 if ( OpenFlipper::Options::nogui() )
503 timer.setSingleShot(
true);
504 timer.start( _seconds * 1000 );
506 while (timer.isActive() )
507 QApplication::processEvents();
513 if ( OpenFlipper::Options::nogui() )
518 timer.setSingleShot(
true);
519 timer.start( _mseconds );
521 while (timer.isActive() )
522 QApplication::processEvents();
527 frameTime_.restart();
531 int elapsed = frameTime_.elapsed();
534 if ( elapsed < _mseconds ) {
535 sleepmsecs( _mseconds - elapsed );
539 frameTime_.restart();
545 if ( OpenFlipper::Options::nogui() )
550 box.addButton(tr(
"Continue"),QMessageBox::AcceptRole);
551 box.setText(tr(
"Script execution has been interrupted"));
552 box.setIcon(QMessageBox::Information);
553 box.setWindowModality(Qt::NonModal);
554 box.setWindowTitle(tr(
"Continue?"));
555 box.setWindowFlags( box.windowFlags() | Qt::WindowStaysOnTopHint);
558 while ( box.isVisible() )
559 QApplication::processEvents();
564 if ( OpenFlipper::Options::nogui() )
570 box.addButton(tr(
"Continue"),QMessageBox::AcceptRole);
572 box.setIcon(QMessageBox::Information);
573 box.setWindowModality(Qt::NonModal);
574 box.setWindowTitle(tr(
"Continue?"));
575 box.setWindowFlags( box.windowFlags() | Qt::WindowStaysOnTopHint);
580 while ( box.isVisible() )
581 QApplication::processEvents();
586 void ScriptingPlugin::slotLoadScript(){
588 QString lastOpened =
OpenFlipperSettings().
value(
"Scripting/CurrentDir",OpenFlipper::Options::currentScriptDirStr()).toString();
590 QString filename = QFileDialog::getOpenFileName(0,
591 tr(
"Load Script"),lastOpened , tr(
"Script Files (*.ofs)"));
596 QFileInfo info (filename);
599 slotLoadScript(filename);
602 void ScriptingPlugin::slotLoadScript( QString _filename ) {
608 if ( OpenFlipper::Options::gui() ) {
609 scriptWidget_->currentScript->clear();
611 QFile data(_filename);
613 if (data.open(QFile::ReadOnly)) {
614 QTextStream input(&data);
616 scriptWidget_->currentScript->appendPlainText(input.readLine());
617 }
while (!input.atEnd());
619 lastFile_ = _filename;
620 OpenFlipper::Options::currentScriptDir( QFileInfo(_filename).absolutePath() );
622 scriptWidget_->actionSave_Script->setEnabled(
false );
624 scriptWidget_->show();
630 void ScriptingPlugin::slotSaveScript(){
632 QFile file(lastFile_);
638 if (file.open(QFile::WriteOnly)) {
639 QTextStream output(&file);
640 output << scriptWidget_->currentScript->toPlainText();
642 scriptWidget_->actionSave_Script->setEnabled(
false );
646 void ScriptingPlugin::slotSaveScriptAs(){
647 QString lastOpened =
OpenFlipperSettings().
value(
"Scripting/CurrentDir",OpenFlipper::Options::currentScriptDirStr()).toString();
649 QString filename = QFileDialog::getSaveFileName(scriptWidget_,
650 tr(
"Save Script"),lastOpened, tr(
"Script Files (*.ofs)"));
652 if (filename ==
"")
return;
654 QFileInfo info (filename);
658 QFile data(filename);
662 QFileInfo fi(filename);
663 if (fi.completeSuffix() ==
""){
664 filename = filename +
".ofs";
665 data.setFileName(filename);
670 if (data.open(QFile::WriteOnly)) {
671 QTextStream output(&data);
672 output << scriptWidget_->currentScript->toPlainText();
675 lastFile_ = filename;
676 OpenFlipper::Options::currentScriptDir( QFileInfo(filename).absolutePath() );
678 scriptWidget_->actionSave_Script->setEnabled(
false );
681 void ScriptingPlugin::slotFunctionClicked(QListWidgetItem * _item)
687 QString slotDescription;
689 QStringList descriptions;
691 emit getDescription(_item->text(), slotDescription, params, descriptions);
693 if ( !slotDescription.isEmpty() ){
695 if (descriptionLabels_.count() > 0){
697 for (
int i = 0; i < descriptionLabels_.count(); i++){
698 descrLayout_->removeWidget( descriptionLabels_[i] );
699 delete descriptionLabels_[i];
701 descriptionLabels_.clear();
703 descrLayout_ =
new QVBoxLayout();
705 QLabel* lSlotName =
new QLabel(
"<B>" + _item->text() +
"</B>");
706 QLabel* lDescription =
new QLabel(slotDescription);
707 lDescription->setWordWrap(
true);
709 descrLayout_->addWidget(lSlotName);
710 descrLayout_->addWidget(lDescription);
712 descriptionLabels_.append(lSlotName);
713 descriptionLabels_.append(lDescription);
715 if ( params.count() == descriptions.count() ){
718 QString typeStr = _item->text().section(
"(",1,1).section(
")",0,0);
719 QStringList types = typeStr.split(
",");
721 if (types.count() == params.count()){
723 for(
int p=0; p < params.count(); p++ ){
724 QLabel* param =
new QLabel(
"<B>" + types[p] +
" " + params[p] +
":</B>" );
725 QLabel* descr =
new QLabel(descriptions[p]);
726 descr->setWordWrap(
true);
727 descrLayout_->addWidget(param);
728 descrLayout_->addWidget(descr);
730 descriptionLabels_.append(param);
731 descriptionLabels_.append(descr);
739 scriptWidget_->description->setLayout( descrLayout_ );
742 scriptWidget_->description->setVisible( !slotDescription.isEmpty() );
745 void ScriptingPlugin::slotFunctionDoubleClicked(QListWidgetItem * _item)
747 scriptWidget_->currentScript->insertPlainText( _item->text() );
752 if ( OpenFlipper::Options::nogui() )
760 OpenFlipper::Options::currentScriptDir(
"" );
764 scriptWidget_->currentScript->setPlainText(_code);
768 if ( OpenFlipper::Options::nogui() )
771 scriptWidget_->currentScript->clear();
void hideScriptWidget()
Hide the script editor widget.
void pluginsInitialized()
void slotHighlightError()
Called when an error is detected when checking the syntax.
void showScriptWidget()
Show the script editor widget.
void sleepmsecs(int _mseconds)
Sleeps for some mseconds in script execution ( Gui will remain functional)
void clearEditor()
Clear the editor window Clears the script editor window.
void waitFrameEnd(int _mseconds)
wait until _mseconds have passed since frameStart (if more time has passed, it will return immediatel...
void slotDebuggerButton()
Triggered by the debugger button.
void sleep(int _seconds)
Sleeps for some seconds in script execution ( Gui will remain functional)
QVariant value(const QString &key, const QVariant &defaultValue=QVariant()) const
void frameStart()
Marks the current time as the frame start ( Use wait sleepFrameLength to wait until _mseconds have pa...
void showScriptInEditor(QString _code)
Show the given Code in the script editor.
void setValue(const QString &key, const QVariant &value)
Wrapper function which makes it possible to enable Debugging output with -DOPENFLIPPER_SETTINGS_DEBUG...
DLLEXPORT OpenFlipperQSettings & OpenFlipperSettings()
QSettings object containing all program settings of OpenFlipper.
void slotExecuteScript(QString _script)
void slotScriptChanged()
Called everytime the text in the scriptingwidget is changed by the user.