Newer
Older
Gigg, Martyn Anthony
committed
//-------------------------------------------
// Includes
//-------------------------------------------
#include "ScriptingWindow.h"
#include "MultiTabScriptInterpreter.h"
Gigg, Martyn Anthony
committed
#include "ScriptingEnv.h"
#include "ScriptFileInterpreter.h"
Gigg, Martyn Anthony
committed
#include "pixmaps.h"
Gigg, Martyn Anthony
committed
// Mantid
#include "MantidKernel/ConfigService.h"
Gigg, Martyn Anthony
committed
#include "ApplicationWindow.h"
// MantidQt
#include "MantidQtMantidWidgets/ScriptEditor.h"
Gigg, Martyn Anthony
committed
//Qt
#include <QTextEdit>
#include <QMenuBar>
#include <QMenu>
#include <QAction>
#include <QSettings>
#include <QPrintDialog>
#include <QPrinter>
Gigg, Martyn Anthony
committed
#include <QDateTime>
Gigg, Martyn Anthony
committed
#include <QFileDialog>
#include <QMessageBox>
#include <QApplication>
#include <QTextStream>
Gigg, Martyn Anthony
committed
//-------------------------------------------
// Public member functions
//-------------------------------------------
/**
* Constructor
Janik Zikovsky
committed
* @param env :: The scripting environment
* @param parent :: The parent widget
* @param flags :: Window flags passed to the base class
Gigg, Martyn Anthony
committed
*/
ScriptingWindow::ScriptingWindow(ScriptingEnv *env, bool capturePrint, QWidget *parent, Qt::WindowFlags flags) :
QMainWindow(parent, flags), m_acceptClose(false),g_log(Mantid::Kernel::Logger::get("ScriptingWindow"))
Gigg, Martyn Anthony
committed
{
Gigg, Martyn Anthony
committed
Q_UNUSED(capturePrint);
Gigg, Martyn Anthony
committed
setObjectName("MantidScriptWindow");
Gigg, Martyn Anthony
committed
// Sub-widgets
m_manager = new MultiTabScriptInterpreter(env, this);
Gigg, Martyn Anthony
committed
setCentralWidget(m_manager);
setFocusProxy(m_manager);
Gigg, Martyn Anthony
committed
Sofia Antony
committed
// Create menus and actions
initMenus();
readSettings();
Sofia Antony
committed
Gigg, Martyn Anthony
committed
setWindowIcon(QIcon(":/MantidPlot_Icon_32offset.png"));
Gigg, Martyn Anthony
committed
setWindowTitle("MantidPlot: " + env->languageName() + " Window");
Gigg, Martyn Anthony
committed
// Start with a single script
m_manager->newTab();
Gigg, Martyn Anthony
committed
}
/**
* Destructor
*/
ScriptingWindow::~ScriptingWindow()
{
delete m_manager;
}
/**
Gigg, Martyn Anthony
committed
* @returns A flag indicating the current state
*/
bool ScriptingWindow::isExecuting() const
Gigg, Martyn Anthony
committed
{
return m_manager->isExecuting();
Gigg, Martyn Anthony
committed
}
/**
* Save the settings on the window
*/
void ScriptingWindow::saveSettings()
{
QSettings settings;
settings.beginGroup("/ScriptWindow");
settings.setValue("/AlwaysOnTop", m_alwaysOnTop->isChecked());
settings.setValue("/ProgressArrow", m_toggleProgress->isChecked());
Gigg, Martyn Anthony
committed
settings.setValue("/LastDirectoryVisited", m_manager->m_last_dir);
Sofia Antony
committed
settings.setValue("/RecentScripts",m_manager->recentScripts());
settings.setValue("/ZoomLevel",m_manager->globalZoomLevel());
Gigg, Martyn Anthony
committed
settings.endGroup();
Gigg, Martyn Anthony
committed
}
Gigg, Martyn Anthony
committed
/**
* Read the settings on the window
*/
void ScriptingWindow::readSettings()
{
QSettings settings;
settings.beginGroup("/ScriptWindow");
QString lastdir = settings.value("LastDirectoryVisited", "").toString();
// If nothing, set the last directory to the Mantid scripts directory (if present)
if( lastdir.isEmpty() )
{
lastdir = QString::fromStdString(Mantid::Kernel::ConfigService::Instance().getString("pythonscripts.directory"));
}
m_manager->m_last_dir = lastdir;
m_toggleProgress->setChecked(settings.value("ProgressArrow", true).toBool());
m_manager->setRecentScripts(settings.value("/RecentScripts").toStringList());
m_manager->m_globalZoomLevel = settings.value("ZoomLevel",0).toInt();
settings.endGroup();
}
Gigg, Martyn Anthony
committed
/**
* Override the closeEvent
* @param event :: A pointer to the event object
*/
void ScriptingWindow::closeEvent(QCloseEvent *event)
{
Gigg, Martyn Anthony
committed
// We ideally don't want a close button but are force by some window managers.
// Therefore if someone clicks close and MantidPlot is not quitting then we will just hide
if( !m_acceptClose )
{
Gigg, Martyn Anthony
committed
emit hideMe();
Gigg, Martyn Anthony
committed
//this->hide();
Gigg, Martyn Anthony
committed
return;
}
Gigg, Martyn Anthony
committed
emit closeMe();
// This will ensure each is saved correctly
Gigg, Martyn Anthony
committed
m_manager->closeAllTabs();
Gigg, Martyn Anthony
committed
event->accept();
}
/**
* Override the showEvent function
* @param event :: A pointer to the event object
*/
void ScriptingWindow::showEvent(QShowEvent *event)
{
if( m_manager->count() == 0 )
{
m_manager->newTab();
}
event->accept();
Gigg, Martyn Anthony
committed
}
Gigg, Martyn Anthony
committed
Gigg, Martyn Anthony
committed
/**
* Open a script directly. This is here for backwards compatability with the old ScriptWindow
* class
Janik Zikovsky
committed
* @param filename :: The file name
* @param newtab :: Do we want a new tab
Gigg, Martyn Anthony
committed
*/
Gigg, Martyn Anthony
committed
void ScriptingWindow::open(const QString & filename, bool newtab)
Gigg, Martyn Anthony
committed
{
Gigg, Martyn Anthony
committed
m_manager->open(newtab, filename);
Gigg, Martyn Anthony
committed
}
/**
* Executes whatever is in the current tab. Primarily useful for automatically
* running a script loaded with open
* @param mode :: The execution type
* */
void ScriptingWindow::executeCurrentTab(const Script::ExecutionMode mode)
Gigg, Martyn Anthony
committed
{
m_manager->executeAll(mode);
Gigg, Martyn Anthony
committed
}
//-------------------------------------------
// Private slot member functions
Gigg, Martyn Anthony
committed
//-------------------------------------------
/// Populate file menu
void ScriptingWindow::populateFileMenu()
Gigg, Martyn Anthony
committed
{
m_fileMenu->clear();
const bool scriptsOpen(m_manager->count() > 0);
m_fileMenu->addAction(m_newTab);
m_fileMenu->addAction(m_openInNewTab);
if(scriptsOpen)
Gigg, Martyn Anthony
committed
{
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
m_fileMenu->addAction(m_openInCurTab);
m_fileMenu->insertSeparator();
m_fileMenu->addAction(m_save);
m_fileMenu->addAction(m_saveAs);
m_fileMenu->addAction(m_print);
}
m_fileMenu->insertSeparator();
m_fileMenu->addMenu(m_recentScripts);
m_recentScripts->setEnabled(m_manager->recentScripts().count() > 0);
if(scriptsOpen)
{
m_fileMenu->insertSeparator();
m_fileMenu->addAction(m_closeTab);
}
}
/// Ensure the list is up to date
void ScriptingWindow::populateRecentScriptsMenu()
{
m_recentScripts->clear();
QStringList recentScripts = m_manager->recentScripts();
QStringListIterator iter(recentScripts);
while(iter.hasNext())
{
m_recentScripts->addAction(iter.next());
}
}
/// Populate edit menu
void ScriptingWindow::populateEditMenu()
{
m_editMenu->clear();
m_editMenu->addAction(m_undo);
m_editMenu->addAction(m_redo);
m_editMenu->addAction(m_cut);
m_editMenu->addAction(m_copy);
m_editMenu->addAction(m_paste);
m_editMenu->insertSeparator();
m_editMenu->addAction(m_find);
}
/// Populate execute menu
void ScriptingWindow::populateExecMenu()
{
m_runMenu->clear();
m_runMenu->addAction(m_execSelect);
m_runMenu->addAction(m_execAll);
m_runMenu->addSeparator();
m_execModeMenu->clear();
m_execModeMenu->addAction(m_execParallel);
m_execModeMenu->addAction(m_execSerial);
m_runMenu->addMenu(m_execModeMenu);
}
/// Populate window menu
void ScriptingWindow::populateWindowMenu()
{
m_windowMenu->clear();
const bool scriptsOpen(m_manager->count() > 0);
m_windowMenu->addAction(m_alwaysOnTop);
m_windowMenu->addAction(m_hide);
if(scriptsOpen)
{
m_windowMenu->insertSeparator();
m_windowMenu->addAction(m_zoomIn);
m_windowMenu->addAction(m_zoomOut);
m_windowMenu->addAction(m_resetZoom);
m_windowMenu->insertSeparator();
m_windowMenu->addAction(m_toggleProgress);
m_windowMenu->addAction(m_toggleFolding);
Gigg, Martyn Anthony
committed
}
}
/**
*
*/
Gigg, Martyn Anthony
committed
void ScriptingWindow::updateWindowFlags()
{
Qt::WindowFlags flags = Qt::Window;
if( m_alwaysOnTop->isChecked() )
Gigg, Martyn Anthony
committed
{
flags |= Qt::WindowStaysOnTopHint;
}
setWindowFlags(flags);
//This is necessary due to the setWindowFlags function reparenting the window and causing is
//to hide itself
show();
}
/**
* Update menus based on current tab states. Called when
* the number of tabs changes
* @param ntabs :: The number of tabs now open
*/
void ScriptingWindow::setMenuStates(int ntabs)
const bool tabsOpen(ntabs > 0);
m_editMenu->setEnabled(tabsOpen);
m_runMenu->setEnabled(tabsOpen);
}
/**
* Set the state of the execution actions/menu depending on the flag
* @param state :: If the true the items are enabled, otherwise the are disabled
*/
void ScriptingWindow::setEditActionsDisabled(bool state)
{
m_editMenu->setDisabled(state);
}
/**
* Set the state of the execution actions/menu depending on the flag
* @param state :: If the true the items are enabled, otherwise the are disabled
*/
void ScriptingWindow::setExecutionActionsDisabled(bool state)
{
m_execSelect->setDisabled(state);
m_execAll->setDisabled(state);
m_execModeMenu->setDisabled(state);
m_runMenu->setDisabled(state);
}
/**
* Maps the QAction to an index in the recent scripts list
* @param item A pointer to the action that triggered the slot
*/
void ScriptingWindow::openRecentScript(QAction* item)
{
const QList<QAction*> actions = m_recentScripts->actions();
const int index = actions.indexOf(item);
assert(index >= 0);
m_manager->openRecentScript(index);
}
/**
* Ask the manager to execute all code based on the currently selected mode
*/
void ScriptingWindow::executeAll()
{
m_manager->executeAll(this->getExecutionMode());
}
/**
* Ask the manager to execute the current selection based on the currently selected mode
*/
void ScriptingWindow::executeSelection()
{
m_manager->executeSelection(this->getExecutionMode());
}
Gigg, Martyn Anthony
committed
/**
* calls MultiTabScriptInterpreter saveToString and
* saves the currently opened script file names to a string
*/
QString ScriptingWindow::saveToString()
{
return m_manager->saveToString();
}
/**
* Saves scripts file names to a string
* @param value If true a future close event will be accepted otherwise it will be ignored
*/
void ScriptingWindow::acceptCloseEvent(const bool value)
{
m_acceptClose = value;
}
//-------------------------------------------
// Private non-slot member functions
//-------------------------------------------
/**
* Initialise the menus
Gigg, Martyn Anthony
committed
*/
void ScriptingWindow::initMenus()
{
initActions();
m_fileMenu = menuBar()->addMenu(tr("&File"));
Gigg, Martyn Anthony
committed
#ifdef SCRIPTING_DIALOG
m_scripting_lang = new QAction(tr("Scripting &language"), this);
connect(m_scripting_lang, SIGNAL(triggered()), this, SIGNAL(chooseScriptingLanguage()));
Gigg, Martyn Anthony
committed
#endif
connect(m_fileMenu, SIGNAL(aboutToShow()), this, SLOT(populateFileMenu()));
m_editMenu = menuBar()->addMenu(tr("&Edit"));
connect(m_editMenu, SIGNAL(aboutToShow()), this, SLOT(populateEditMenu()));
connect(m_manager, SIGNAL(executionStateChanged(bool)), this, SLOT(setEditActionsDisabled(bool)));
m_runMenu = menuBar()->addMenu(tr("E&xecute"));
connect(m_runMenu, SIGNAL(aboutToShow()), this, SLOT(populateExecMenu()));
connect(m_manager, SIGNAL(executionStateChanged(bool)), this, SLOT(setExecutionActionsDisabled(bool)));
m_execModeMenu = new QMenu("Mode", this);
m_windowMenu = menuBar()->addMenu(tr("&Window"));
connect(m_windowMenu, SIGNAL(aboutToShow()), this, SLOT(populateWindowMenu()));
connect(m_manager, SIGNAL(tabCountChanged(int)), this, SLOT(setMenuStates(int)));
// The menu items must be populated for the shortcuts to work
populateFileMenu();
populateEditMenu();
populateExecMenu();
populateWindowMenu();
connect(m_manager, SIGNAL(tabCountChanged(int)), this, SLOT(populateFileMenu()));
connect(m_manager, SIGNAL(tabCountChanged(int)), this, SLOT(populateEditMenu()));
connect(m_manager, SIGNAL(tabCountChanged(int)), this, SLOT(populateExecMenu()));
connect(m_manager, SIGNAL(tabCountChanged(int)), this, SLOT(populateWindowMenu()));
}
Gigg, Martyn Anthony
committed
Gigg, Martyn Anthony
committed
/**
* Create all actions
Gigg, Martyn Anthony
committed
*/
void ScriptingWindow::initActions()
Gigg, Martyn Anthony
committed
{
initFileMenuActions();
initEditMenuActions();
initExecMenuActions();
initWindowMenuActions();
}
Gigg, Martyn Anthony
committed
/**
* Create the file actions
*/
void ScriptingWindow::initFileMenuActions()
{
m_newTab = new QAction(tr("&New Tab"), this);
connect(m_newTab, SIGNAL(triggered()), m_manager, SLOT(newTab()));
m_newTab->setShortcut(tr("Ctrl+N"));
m_openInCurTab = new QAction(tr("&Open"), this);
connect(m_openInCurTab, SIGNAL(triggered()), m_manager, SLOT(openInCurrentTab()));
m_openInCurTab->setShortcut(tr("Ctrl+O"));
m_openInNewTab = new QAction(tr("&Open in New Tab"), this);
connect(m_openInNewTab, SIGNAL(triggered()), m_manager, SLOT(openInNewTab()));
m_openInNewTab->setShortcut(tr("Ctrl+Shift+O"));
m_save = new QAction(tr("&Save"), this);
connect(m_save, SIGNAL(triggered()), m_manager, SLOT(saveToCurrentFile()));
m_save->setShortcut(QKeySequence::Save);
m_saveAs = new QAction(tr("&Save As"), this);
connect(m_saveAs, SIGNAL(triggered()), m_manager, SLOT(saveAs()));
m_saveAs->setShortcut(tr("Ctrl+Shift+S"));
m_print = new QAction(tr("&Print script"), this);
connect(m_print, SIGNAL(triggered()), m_manager, SLOT(print()));
m_print->setShortcut(QKeySequence::Print);
m_closeTab = new QAction(tr("&Close Tab"), this);
connect(m_closeTab, SIGNAL(triggered()), m_manager, SLOT(closeCurrentTab()));
m_closeTab->setShortcut(tr("Ctrl+W"));
Gigg, Martyn Anthony
committed
m_recentScripts = new QMenu(tr("&Recent Scripts"),this);
connect(m_recentScripts, SIGNAL(aboutToShow()), this, SLOT(populateRecentScriptsMenu()));
connect(m_recentScripts, SIGNAL(triggered(QAction*)), this, SLOT(openRecentScript(QAction*)));
Gigg, Martyn Anthony
committed
}
Gigg, Martyn Anthony
committed
Sofia Antony
committed
/**
* Create the edit menu action*/
void ScriptingWindow::initEditMenuActions()
{
m_undo = new QAction(tr("&Undo"), this);
connect(m_undo, SIGNAL(triggered()), m_manager, SLOT(undo()));
connect(m_manager, SIGNAL(undoAvailable(bool)), m_undo, SLOT(setEnabled(bool)));
m_undo->setShortcut(QKeySequence::Undo);
m_redo = new QAction(tr("&Redo"), this);
connect(m_redo, SIGNAL(triggered()), m_manager, SLOT(redo()));
connect(m_manager, SIGNAL(redoAvailable(bool)), m_redo, SLOT(setEnabled(bool)));
m_redo->setShortcut(QKeySequence::Redo);
m_cut = new QAction(tr("C&ut"), this);
connect(m_cut, SIGNAL(triggered()), m_manager, SLOT(cut()));
m_cut->setShortcut(QKeySequence::Cut);
m_copy = new QAction(tr("&Copy"), this);
connect(m_copy, SIGNAL(triggered()), m_manager, SLOT(copy()));
m_copy->setShortcut(QKeySequence::Copy);
m_paste = new QAction(tr("&Paste"), this);
connect(m_paste, SIGNAL(triggered()), m_manager, SLOT(paste()));
m_paste->setShortcut(QKeySequence::Paste);
m_find = new QAction(tr("&Find/Replace"), this);
connect(m_find, SIGNAL(triggered()), m_manager,
SLOT(showFindReplaceDialog()));
m_find->setShortcut(QKeySequence::Find);
}
/**
* Create the execute menu actions
Sofia Antony
committed
*/
void ScriptingWindow::initExecMenuActions()
Sofia Antony
committed
{
m_execSelect = new QAction(tr("E&xecute Selection"), this);
connect(m_execSelect, SIGNAL(triggered()), this, SLOT(executeSelection()));
QList<QKeySequence> shortcuts;
shortcuts << Qt::CTRL + Qt::Key_Return << Qt::CTRL + Qt::Key_Enter;
m_execSelect->setShortcuts(shortcuts);
m_execAll = new QAction(tr("Execute &All"), this);
connect(m_execAll, SIGNAL(triggered()), this, SLOT(executeAll()));
shortcuts.clear();
shortcuts << Qt::CTRL + Qt::SHIFT + Qt::Key_Return << Qt::CTRL + Qt::SHIFT + Qt::Key_Enter;
m_execAll->setShortcuts(shortcuts);
m_execParallel = new QAction("Asynchronous", this);
m_execParallel->setCheckable(true);
m_execSerial = new QAction("Serialised", this);
m_execSerial->setCheckable(true);
m_execModeGroup = new QActionGroup(this);
m_execModeGroup->addAction(m_execParallel);
m_execModeGroup->addAction(m_execSerial);
m_execParallel->setChecked(true);
Sofia Antony
committed
}
Gigg, Martyn Anthony
committed
/**
* Create the window menu actions
Gigg, Martyn Anthony
committed
*/
void ScriptingWindow::initWindowMenuActions()
Gigg, Martyn Anthony
committed
{
m_alwaysOnTop = new QAction(tr("Always on &Top"), this);
m_alwaysOnTop->setCheckable(true);
connect(m_alwaysOnTop, SIGNAL(toggled(bool)), this, SLOT(updateWindowFlags()));
m_hide = new QAction(tr("&Hide"), this);
#ifdef __APPLE__
m_hide->setShortcut(tr("Ctrl+3")); // F3 is used by the window manager on Mac
#else
m_hide->setShortcut(tr("F3"));
#endif
// Note that we channel the hide through the parent so that we can save the geometry state
connect(m_hide, SIGNAL(triggered()), this, SIGNAL(hideMe()));
m_zoomIn = new QAction(("&Increase font size"), this);
// Setting two shortcuts makes it work for both the plus on the keypad and one above an =
// Despite the Qt docs advertising the use of QKeySequence::ZoomIn as the solution to this,
// it doesn't seem to work for me
m_zoomIn->setShortcut(Qt::SHIFT+Qt::CTRL+Qt::Key_Equal);
m_zoomIn->setShortcut(Qt::CTRL+Qt::Key_Plus);
connect(m_zoomIn, SIGNAL(triggered()), m_manager, SLOT(zoomIn()));
connect(m_zoomIn, SIGNAL(triggered()), m_manager, SLOT(trackZoomIn()));
m_zoomOut = new QAction(("&Decrease font size"), this);
m_zoomOut->setShortcut(QKeySequence::ZoomOut);
connect(m_zoomOut, SIGNAL(triggered()), m_manager, SLOT(zoomOut()));
connect(m_zoomOut, SIGNAL(triggered()), m_manager, SLOT(trackZoomOut()));
m_resetZoom = new QAction(("&Reset font size"), this);
connect(m_resetZoom, SIGNAL(triggered()), m_manager, SLOT(resetZoom()));
// Toggle the progress arrow
m_toggleProgress = new QAction(tr("&Progress Reporting"), this);
m_toggleProgress->setCheckable(true);
connect(m_toggleProgress, SIGNAL(toggled(bool)), m_manager, SLOT(toggleProgressReporting(bool)));
// Toggle code folding
m_toggleFolding = new QAction(tr("Code &Folding"), this);
m_toggleFolding->setCheckable(true);
connect(m_toggleFolding, SIGNAL(toggled(bool)), m_manager, SLOT(toggleCodeFolding(bool)));
Gigg, Martyn Anthony
committed
}
/**
* Returns the current execution mode set in the menu
*/
Script::ExecutionMode ScriptingWindow::getExecutionMode() const
{
if(m_execParallel->isChecked()) return Script::Asynchronous;
else return Script::Serialised;
}
/**
* Accept a custom event and in this case test if it is a ScriptingChangeEvent
* @param event :: The custom event
*/
void ScriptingWindow::customEvent(QEvent *event)
{
if( !m_manager->isExecuting() && event->type() == SCRIPTING_CHANGE_EVENT )
{
ScriptingChangeEvent *sce = static_cast<ScriptingChangeEvent*>(event);
setWindowTitle("MantidPlot: " + sce->scriptingEnv()->languageName() + " Window");
}
}
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
/**
* Accept a drag move event and selects whether to accept the action
* @param de :: The drag move event
*/
void ScriptingWindow::dragMoveEvent(QDragMoveEvent *de)
{
const QMimeData *mimeData = de->mimeData();
if (mimeData->hasUrls())
{
if (extractPyFiles(mimeData->urls()).size() > 0)
{
de->accept();
}
}
}
/**
* Accept a drag enter event and selects whether to accept the action
* @param de :: The drag enter event
*/
void ScriptingWindow::dragEnterEvent(QDragEnterEvent *de)
{
const QMimeData *mimeData = de->mimeData();
if (mimeData->hasUrls())
{
if (extractPyFiles(mimeData->urls()).size() > 0)
{
de->acceptProposedAction();
}
}
}
/**
* Accept a drag drop event and process the data appropriately
* @param de :: The drag drop event
*/
void ScriptingWindow::dropEvent(QDropEvent *de)
{
const QMimeData *mimeData = de->mimeData();
if (mimeData->hasUrls())
{
QStringList filenames = extractPyFiles(mimeData->urls());
de->acceptProposedAction();
for (int i = 0; i < filenames.size(); ++i)
{
m_manager->openInNewTab(filenames[i]);
}
}
}
QStringList ScriptingWindow::extractPyFiles(const QList<QUrl>& urlList) const
{
QStringList filenames;
for (int i = 0; i < urlList.size(); ++i)
{
QString fName = urlList[i].toLocalFile();
if (fName.size()>0)
{
QFileInfo fi(fName);
if (fi.suffix().upper()=="PY")
{
filenames.append(fName);
}
}
}
return filenames;