Subversion Repositories Scribus

Rev

Rev 2614 | Rev 2705 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1467 cbradney 1
#include "scriptercore.h"
2
 
1718 craig 3
#include <qglobal.h>
4
#include <qwidget.h>
5
#include <qstring.h>
6
#include <qapplication.h>
7
#include <qmessagebox.h>
8
#include <qtextcodec.h>
9
#include <qdom.h>
10
#include <qtextstream.h>
11
#include <cstdlib>
2503 subik 12
#include <qtextedit.h>
1718 craig 13
 
2622 craig 14
#include "runscriptdialog.h"
1467 cbradney 15
#include "helpbrowser.h"
16
#include "mpalette.h"
1718 craig 17
#include "seiten.h"
18
#include "layers.h"
19
#include "tree.h"
20
#include "menumanager.h"
21
#include "scraction.h"
22
#include "scpaths.h"
1750 craig 23
#include "prefsfile.h"
24
#include "prefscontext.h"
25
#include "prefstable.h"
1467 cbradney 26
 
1750 craig 27
extern PrefsFile* prefsFile;
28
 
1718 craig 29
#include "scriptercore.moc"
1467 cbradney 30
 
2503 subik 31
ScripterCore::ScripterCore(QWidget* parent)
1718 craig 32
{
2503 subik 33
        pcon = new PythonConsole(parent);
1718 craig 34
        menuMgr = Carrier->scrMenuMgr;
35
        scrScripterActions.clear();
36
        scrRecentScriptActions.clear();
1467 cbradney 37
 
1718 craig 38
        scrScripterActions.insert("scripterExecuteScript", new ScrAction(QObject::tr("&Execute Script..."), QKeySequence(), this, "scripterExecuteScript"));
39
        scrScripterActions.insert("scripterShowConsole", new ScrAction(QObject::tr("Show &Console"), QKeySequence(), this, "scripterShowConsole"));
40
        scrScripterActions.insert("scripterAboutScript", new ScrAction(QObject::tr("&About Script..."), QKeySequence(), this, "scripterAboutScript"));
1467 cbradney 41
 
1718 craig 42
        scrScripterActions["scripterShowConsole"]->setToggleAction(true);
43
 
2622 craig 44
        QObject::connect( scrScripterActions["scripterExecuteScript"], SIGNAL(activated()) , this, SLOT(runScriptDialog()) );
1718 craig 45
        QObject::connect( scrScripterActions["scripterShowConsole"], SIGNAL(toggled(bool)) , this, SLOT(slotInteractiveScript(bool)) );
46
        QObject::connect( scrScripterActions["scripterAboutScript"], SIGNAL(activated()) , this, SLOT(aboutScript()) );
47
 
48
        menuMgr->createMenu("Scripter", QObject::tr("&Script"));
1846 cbradney 49
        menuMgr->addMenuToMenuBarAfter("Scripter","Extras");
1718 craig 50
        menuMgr->createMenu("ScribusScripts", QObject::tr("&Scribus Scripts"), "Scripter");
51
        menuMgr->addMenuItem(scrScripterActions["scripterExecuteScript"], "Scripter");
52
        menuMgr->createMenu("RecentScripts", QObject::tr("&Recent Scripts"), "Scripter");
53
        menuMgr->addMenuSeparator("Scripter");
54
        menuMgr->addMenuItem(scrScripterActions["scripterShowConsole"], "Scripter");
55
        menuMgr->addMenuItem(scrScripterActions["scripterAboutScript"], "Scripter");
56
 
57
        SavedRecentScripts.clear();
58
        ReadPlugPrefs();
59
        buildScribusScriptsMenu();
60
        buildRecentScriptsMenu();
61
 
2503 subik 62
        QObject::connect(pcon, SIGNAL(runCommand()), this, SLOT(slotExecute()));
63
        QObject::connect(pcon, SIGNAL(paletteShown(bool)), this, SLOT(slotInteractiveScript(bool)));
1718 craig 64
}
65
 
66
ScripterCore::~ScripterCore()
1467 cbradney 67
{
1750 craig 68
        SavePlugPrefs();
1718 craig 69
}
70
 
71
 
72
void ScripterCore::buildScribusScriptsMenu()
73
{
74
        QString pfad = ScPaths::instance().scriptDir();
1467 cbradney 75
        QString pfad2;
76
        pfad2 = QDir::convertSeparators(pfad);
77
        QDir ds(pfad2, "*.py", QDir::Name, QDir::Files | QDir::NoSymLinks);
78
        if ((ds.exists()) && (ds.count() != 0))
79
        {
80
                for (uint dc = 0; dc < ds.count(); ++dc)
81
                {
82
                        QFileInfo fs(ds[dc]);
1718 craig 83
                        QString strippedName=fs.baseName(false);
84
                        scrScripterActions.insert(strippedName, new ScrAction( ScrAction::RecentScript, QIconSet(), strippedName, QKeySequence(), this, strippedName));
85
                        connect( scrScripterActions[strippedName], SIGNAL(activatedData(QString)), this, SLOT(StdScript(QString)) );
86
                        menuMgr->addMenuItem(scrScripterActions[strippedName], "ScribusScripts");
1467 cbradney 87
                }
88
        }
1718 craig 89
 
90
 
91
}
92
 
93
void ScripterCore::rebuildRecentScriptsMenu()
94
{
95
        for( QMap<QString, QGuardedPtr<ScrAction> >::Iterator it = scrRecentScriptActions.begin(); it!=scrRecentScriptActions.end(); ++it )
96
                menuMgr->removeMenuItem((*it), "RecentScripts");
97
 
98
        scrRecentScriptActions.clear();
99
        uint max = QMIN(Carrier->Prefs.RecentDCount, RecentScripts.count());
100
        for (uint m = 0; m < max; ++m)
1467 cbradney 101
        {
1718 craig 102
                QString strippedName=RecentScripts[m];
103
                strippedName.remove(QDir::separator());
104
                scrRecentScriptActions.insert(strippedName, new ScrAction( ScrAction::RecentScript, QIconSet(), RecentScripts[m], QKeySequence(), this, strippedName));
105
                connect( scrRecentScriptActions[strippedName], SIGNAL(activatedData(QString)), this, SLOT(RecentScript(QString)) );
106
                menuMgr->addMenuItem(scrRecentScriptActions[strippedName], "RecentScripts");
1467 cbradney 107
        }
108
}
109
 
1718 craig 110
void ScripterCore::buildRecentScriptsMenu()
1467 cbradney 111
{
1718 craig 112
        RecentScripts.clear();
113
        scrRecentScriptActions.clear();
114
        if (SavedRecentScripts.count() != 0)
1467 cbradney 115
        {
1718 craig 116
                uint max = QMIN(Carrier->Prefs.RecentDCount, SavedRecentScripts.count());
117
                for (uint m = 0; m < max; ++m)
1467 cbradney 118
                {
1718 craig 119
                        QFileInfo fd(SavedRecentScripts[m]);
120
                        if (fd.exists())
121
                        {
122
                                QString strippedName=SavedRecentScripts[m];
123
                                strippedName.remove(QDir::separator());
124
                                scrRecentScriptActions.insert(strippedName, new ScrAction( ScrAction::RecentScript, QIconSet(), SavedRecentScripts[m], QKeySequence(), this, strippedName));
125
                                connect( scrRecentScriptActions[strippedName], SIGNAL(activatedData(QString)), this, SLOT(RecentScript(QString)) );
126
                                menuMgr->addMenuItem(scrRecentScriptActions[strippedName], "RecentScripts");
127
                        }
1467 cbradney 128
                }
129
        }
130
}
131
 
132
void ScripterCore::FinishScriptRun()
133
{
134
        if (Carrier->HaveDoc)
135
        {
1718 craig 136
                Carrier->propertiesPalette->SetDoc(Carrier->doc);
137
                Carrier->propertiesPalette->updateCList();
138
                Carrier->propertiesPalette->Spal->setFormats(Carrier->doc);
139
                Carrier->propertiesPalette->SetLineFormats(Carrier->doc);
140
                Carrier->propertiesPalette->Cpal->SetColors(Carrier->doc->PageColors);
141
                Carrier->layerPalette->setLayers(&Carrier->doc->Layers, &Carrier->doc->ActiveLayer);
142
                Carrier->outlinePalette->BuildTree(Carrier->doc);
143
                Carrier->pagePalette->SetView(Carrier->view);
144
                Carrier->pagePalette->Rebuild();
145
                if (Carrier->view->SelItem.count() != 0)
2071 subik 146
                {
147
                        Carrier->view->EmitValues(Carrier->view->SelItem.at(0));
1718 craig 148
                        Carrier->HaveNewSel(Carrier->view->SelItem.at(0)->itemType());
2071 subik 149
                }
1467 cbradney 150
                else
151
                        Carrier->HaveNewSel(-1);
152
                Carrier->view->DrawNew();
153
        }
154
}
155
 
2622 craig 156
void ScripterCore::runScriptDialog()
1467 cbradney 157
{
158
        QString fileName;
2622 craig 159
        QString curDirPath = QDir::currentDirPath();
160
        RunScriptDialog dia( Carrier, enableExtPython );
161
        if (dia.exec())
1467 cbradney 162
        {
2622 craig 163
                fileName = dia.selectedFile();
164
                slotRunScriptFile(fileName, dia.extensionRequested());
1718 craig 165
 
1467 cbradney 166
                if (RecentScripts.findIndex(fileName) == -1)
167
                        RecentScripts.prepend(fileName);
168
                else
169
                {
170
                        RecentScripts.remove(fileName);
171
                        RecentScripts.prepend(fileName);
172
                }
1718 craig 173
                rebuildRecentScriptsMenu();
1467 cbradney 174
        }
2622 craig 175
        QDir::setCurrent(curDirPath);
1467 cbradney 176
        FinishScriptRun();
177
}
178
 
1718 craig 179
void ScripterCore::StdScript(QString basefilename)
1467 cbradney 180
{
1718 craig 181
        QString pfad = ScPaths::instance().scriptDir();
1467 cbradney 182
        QString pfad2;
183
        pfad2 = QDir::convertSeparators(pfad);
1718 craig 184
        QString fn = pfad2+basefilename+".py";
185
        //QString fn = pfad2+smen->text(id)+".py";
1467 cbradney 186
        QFileInfo fd(fn);
187
        if (!fd.exists())
188
                return;
189
        slotRunScriptFile(fn);
190
        FinishScriptRun();
191
}
192
 
1718 craig 193
void ScripterCore::RecentScript(QString fn)
1467 cbradney 194
{
1718 craig 195
        //QString fn = rmen->text(id);
1467 cbradney 196
        QFileInfo fd(fn);
197
        if (!fd.exists())
198
        {
199
                RecentScripts.remove(fn);
1718 craig 200
                rebuildRecentScriptsMenu();
1467 cbradney 201
                return;
202
        }
203
        slotRunScriptFile(fn);
204
        FinishScriptRun();
205
}
206
 
1752 craig 207
void ScripterCore::slotRunScriptFile(QString fileName, bool inMainInterpreter)
1467 cbradney 208
{
209
        char* comm[1];
1753 craig 210
        PyThreadState *stateo, *state;
1467 cbradney 211
        QFileInfo fi(fileName);
212
        QCString na = fi.fileName().latin1();
1753 craig 213
        // Set up a sub-interpreter if needed:
214
        if (!inMainInterpreter)
215
        {
216
                Carrier->ScriptRunning = true;
217
                qApp->setOverrideCursor(QCursor(waitCursor), false);
218
                // Create the sub-interpreter
219
                // FIXME: This calls abort() in a Python debug build. We're doing something wrong.
220
                stateo = PyEval_SaveThread();
221
                state = Py_NewInterpreter();
222
                // Chdir to the dir the script is in
223
                QDir::setCurrent(fi.dirPath(true));
224
                // Init the scripter module in the sub-interpreter
225
                initscribus(Carrier);
226
        }
227
        // Make sure sys.argv[0] is the path to the script
1467 cbradney 228
        comm[0] = na.data();
1753 craig 229
        PySys_SetArgv(1, comm);
1718 craig 230
        // call python script
1467 cbradney 231
        PyObject* m = PyImport_AddModule((char*)"__main__");
232
        if (m == NULL)
233
                qDebug("Failed to get __main__ - aborting script");
234
        else
235
        {
236
                // FIXME: If filename contains chars outside 7bit ascii, might be problems
237
                PyObject* globals = PyModule_GetDict(m);
238
                // Build the Python code to run the script
1753 craig 239
                QString cm = QString("from __future__ import division\n");
240
                cm        += QString("import sys\n");
241
                cm        += QString("import cStringIO\n");
1467 cbradney 242
                /* Implementation of the help() in pydoc.py reads some OS variables
243
                 * for output settings. I use ugly hack to stop freezing calling help()
244
                 * in script. pv. */
1753 craig 245
                cm        += QString("import os\nos.environ['PAGER'] = '/bin/false'\n"); // HACK
246
                cm        += QString("sys.path[0] = \"%1\"\n").arg(fi.dirPath(true));
247
                // Replace sys.stdin with a dummy StringIO that always returns
248
                // "" for read
249
                cm        += QString("sys.stdin = cStringIO.StringIO()\n");
250
                cm        += QString("try:\n");
251
                cm        += QString("    execfile(\"%1\")\n").arg(fileName);
252
                cm        += QString("except SystemExit:\n");
253
                cm        += QString("    pass\n");
1467 cbradney 254
                // Capture the text of any other exception that's raised by the interpreter
255
                // into a StringIO buffer for later extraction.
1753 craig 256
                cm        += QString("except:\n");
257
                cm        += QString("    import traceback\n");
258
                cm        += QString("    import scribus\n");                  // we stash our working vars here
259
                cm        += QString("    scribus._f=cStringIO.StringIO()\n");
260
                cm        += QString("    traceback.print_exc(file=scribus._f)\n");
261
                cm        += QString("    _errorMsg = scribus._f.getvalue()\n");
262
                cm        += QString("    del(scribus._f)\n");
263
                // We re-raise the exception so the return value of PyRun_StringFlags reflects
1467 cbradney 264
                // the fact that an exception has ocurred.
1753 craig 265
                cm        += QString("    raise\n");
1467 cbradney 266
                // FIXME: if cmd contains chars outside 7bit ascii, might be problems
267
                QCString cmd = cm.latin1();
1753 craig 268
                // Now run the script in the interpreter's global scope. It'll run in a
269
                // sub-interpreter if we created and switched to one earlier, otherwise
270
                // it'll run in the main interpreter.
1467 cbradney 271
                PyObject* result = PyRun_String(cmd.data(), Py_file_input, globals, globals);
272
                // NULL is returned if an exception is set. We don't care about any
273
                // other return value (most likely None anyway) and can ignore it.
274
                if (result == NULL)
275
                {
1753 craig 276
                        // We've already saved the exception text, so clear the exception
277
                        PyErr_Clear();
278
                        PyObject* errorMsgPyStr = PyMapping_GetItemString(globals, (char*)"_errorMsg");
1467 cbradney 279
                        if (errorMsgPyStr == NULL)
280
                        {
281
                                // It's rather unlikely that this will ever be reached - to get here
282
                                // we'd have to fail to retrive the string we just created.
283
                                qDebug("Error retrieving error message content after script exception!");
284
                                qDebug("Exception was:");
285
                                PyErr_Print();
286
                        }
287
                        else
288
                        {
289
                                QString errorMsg = PyString_AsString(errorMsgPyStr);
290
                                // Display a dialog to the user with the exception
291
                                QClipboard *cp = QApplication::clipboard();
292
                                cp->setText(errorMsg);
293
                                QMessageBox::warning(Carrier,
294
                                                                        tr("Script error"),
295
                                                                        tr("If you are running an official script report it at <a href=\"http://bugs.scribus.net\">bugs.scribus.net</a> please.")
296
                                                                        + "<pre>" +errorMsg + "</pre>"
297
                                                                        + tr("This message is in your clipboard too. Use Ctrl+V to paste it into bug tracker."));
298
                        }
299
                } // end if result == NULL
300
                // Because 'result' may be NULL, not a PyObject*, we must call PyXDECREF not Py_DECREF
301
                Py_XDECREF(result);
302
        } // end if m == NULL
1753 craig 303
        if (!inMainInterpreter)
304
        {
305
                Py_EndInterpreter(state);
306
                PyEval_RestoreThread(stateo);
307
                Carrier->ScriptRunning = false;
308
                qApp->restoreOverrideCursor();
309
        }
1467 cbradney 310
}
311
 
312
QString ScripterCore::slotRunScript(QString Script)
313
{
1718 craig 314
        Carrier->ScriptRunning = true;
1467 cbradney 315
        qApp->setOverrideCursor(QCursor(waitCursor), false);
316
        char* comm[1];
317
        QString cm;
318
        InValue = Script;
319
        QString CurDir = QDir::currentDirPath();
320
        if(PyThreadState_Get() != NULL)
321
        {
322
                initscribus(Carrier);
323
                if (RetVal == 0)
324
                {
325
                        // FIXME: if CurDir contains chars outside 7bit ascii, might be problems
1718 craig 326
                        cm = "import sys\nsys.path[0] = \""+CurDir+"\"\n";
1467 cbradney 327
                        cm += "import cStringIO\n";
1718 craig 328
                        // TODO: fix it during macro/properties merging
329
                        //if (useDummyStdin)
330
                        cm += QString("sys.stdin = cStringIO.StringIO()\n");
331
                        cm += "from scribus import *\n";
332
                        cm += "bu = cStringIO.StringIO()\n";
333
                        cm += "sys.stdout = bu\n";
334
                        cm += "sys.stderr = bu\n";
1467 cbradney 335
                        cm += "import code\n";
1718 craig 336
                        cm += "ia = code.InteractiveConsole(globals())\n";
1467 cbradney 337
                }
2614 subik 338
                /* HACK: following loop handles all input line by line.
339
                It *should* use I.C. because of docstrings etc. I.I. cannot
340
                handle docstrings right.
341
                Calling all code in one command:
342
                ia = code.InteractiveInterpreter() ia.runsource(getval())
343
                works fine in plain Python. Not here. WTF?
344
                */
345
                cm += "for i in getval().split('\\n'):\n";
346
                cm += "\tia.push(i)\n";
347
                cm += "retval(bu.getvalue(), 0)\n";
1467 cbradney 348
        }
349
        // FIXME: if cmd contains chars outside 7bit ascii, might be problems
350
        QCString cmd = cm.latin1();
351
        comm[0] = (char*)"scribus";
352
        PySys_SetArgv(1, comm);
353
        PyRun_SimpleString(cmd.data());
1718 craig 354
        Carrier->ScriptRunning = false;
1467 cbradney 355
        qApp->restoreOverrideCursor();
356
        return RetString;
357
}
358
 
1718 craig 359
void ScripterCore::slotInteractiveScript(bool visible)
1467 cbradney 360
{
2600 cbradney 361
        QObject::disconnect( scrScripterActions["scripterShowConsole"], SIGNAL(toggled(bool)) , this, SLOT(slotInteractiveScript(bool)) );
2614 subik 362
 
1718 craig 363
        scrScripterActions["scripterShowConsole"]->setOn(visible);
2503 subik 364
        pcon->setShown(visible);
2614 subik 365
 
2600 cbradney 366
        QObject::connect( scrScripterActions["scripterShowConsole"], SIGNAL(toggled(bool)) , this, SLOT(slotInteractiveScript(bool)) );
1467 cbradney 367
}
368
 
369
void ScripterCore::slotExecute()
370
{
2503 subik 371
        pcon->outputEdit->append(slotRunScript(pcon->command));
2543 subik 372
        pcon->outputEdit->setCursorPosition(0, 0);
2503 subik 373
        pcon->commandEdit->ensureCursorVisible();
1467 cbradney 374
        FinishScriptRun();
375
}
376
 
377
void ScripterCore::ReadPlugPrefs()
378
{
1750 craig 379
        PrefsContext* prefs = prefsFile->getPluginContext("scriptplugin");
380
        if (!prefs)
1467 cbradney 381
        {
1750 craig 382
                qDebug("scriptplugin: Unable to load prefs");
1467 cbradney 383
                return;
384
        }
1750 craig 385
        PrefsTable* prefRecentScripts = prefs->getTable("recentscripts");
386
        if (!prefRecentScripts)
387
        {
388
                qDebug("scriptplugin: Unable to get recent scripts");
1467 cbradney 389
                return;
390
        }
1750 craig 391
        // Load recent scripts from the prefs
392
        for (int i = 0; i < prefRecentScripts->getRowCount(); i++)
393
                SavedRecentScripts.append(prefRecentScripts->get(i,0));
1752 craig 394
        // then get more general preferences
395
        enableExtPython = prefs->getBool("extensionscripts",false);
396
        importAllNames = prefs->getBool("importall",true);
397
        startupScript = prefs->get("startupscript", QString::null);
1467 cbradney 398
}
399
 
400
void ScripterCore::SavePlugPrefs()
401
{
1750 craig 402
        PrefsContext* prefs = prefsFile->getPluginContext("scriptplugin");
403
        if (!prefs)
1467 cbradney 404
        {
1750 craig 405
                qDebug("scriptplugin: Unable to load prefs");
406
                return;
1467 cbradney 407
        }
1750 craig 408
        PrefsTable* prefRecentScripts = prefs->getTable("recentscripts");
409
        if (!prefRecentScripts)
410
        {
411
                qDebug("scriptplugin: Unable to get recent scripts");
1467 cbradney 412
                return;
1750 craig 413
        }
414
        for (uint i = 0; i < RecentScripts.count(); i++)
415
                prefRecentScripts->set(i, 0, RecentScripts[i]);
1752 craig 416
        // then save more general preferences
417
        prefs->set("extensionscripts", enableExtPython);
418
        prefs->set("importall", importAllNames);
419
        prefs->set("startupscript", startupScript);
1467 cbradney 420
}
421
 
422
/* 11/1/2004 pv - Show docstring of the script to the user.
423
 * I don't know how to get docstring via e.g. pydoc because of
424
 * it needs to run script => error cannot find scribus module
425
 */
426
void ScripterCore::aboutScript()
427
{
2503 subik 428
        QString fname = Carrier->CFileDialog(".", tr("Examine Script"), tr("Python Scripts (*.py)"), "", 0, 0, 0, 0);
429
        if (fname == QString::null)
430
                return;
1467 cbradney 431
        QFileInfo fi = QFileInfo(fname);
432
        QString html = QDir::convertSeparators(QDir::homeDirPath()+"/.scribus/aboutScript.html");
433
        QFile input(fname);
434
        if(!input.open(IO_ReadOnly))
435
                return;
436
        QFile output(html);
437
        if(!output.open(IO_WriteOnly))
438
                return;
439
        QTextStream intputstream(&input);
440
        QTextStream outputstream(&output);
441
        QString content = intputstream.read();
442
        QString docstring = content.section("\"\"\"", 1, 1);
443
        if (docstring != "")
444
        {
445
                outputstream << "<h1>Documentation for: " << fi.fileName() << "</h1><p>";
446
                outputstream << docstring.replace("\n\n", "<p>");
447
        }
448
        else
449
        {
450
                outputstream << "<pre>" << endl;
451
                outputstream << "<p><b>Script "<< fi.fileName() << " doesn't contain any docstring!</b></p>" << content;
452
                outputstream << "</pre>" << endl;
453
        }
454
        output.close();
455
        input.close();
1718 craig 456
        HelpBrowser *dia = new HelpBrowser(0, QObject::tr("About Script") + " " + fi.fileName(), "en", "", html);
1467 cbradney 457
        dia->show();
458
}
1752 craig 459
 
460
void ScripterCore::initExtensionScripts()
461
{
462
        // Nothing to do currently
463
}
464
 
465
void ScripterCore::runStartupScript()
466
{
467
        if ((enableExtPython) && (startupScript))
468
        {
469
                if (QFile::exists(this->startupScript))
470
                {
471
                        // run the script in the main interpreter. The user will be informed
472
                        // with a dialog if something has gone wrong.
473
                        this->slotRunScriptFile(this->startupScript, true);
474
                }
475
                else
476
                        qDebug("Startup script enabled, but couln't find script %s.", startupScript.ascii());
477
        }
478
}
479
 
2226 cbradney 480
void ScripterCore::languageChange()
2223 cbradney 481
{
482
        scrScripterActions["scripterExecuteScript"]->setMenuText(QObject::tr("&Execute Script..."));
483
        scrScripterActions["scripterShowConsole"]->setMenuText(QObject::tr("Show &Console"));
2503 subik 484
        scrScripterActions["scripterAboutScript"]->setMenuText(QObject::tr("&About Script..."));
485
 
2223 cbradney 486
        menuMgr->setMenuText("Scripter", QObject::tr("&Script"));
487
        menuMgr->setMenuText("ScribusScripts", QObject::tr("&Scribus Scripts"));
488
        menuMgr->setMenuText("RecentScripts", QObject::tr("&Recent Scripts"));
489
}