From 930a2aa2bfd6b82bff00aadf36370a609f436ab7 Mon Sep 17 00:00:00 2001 From: David Sansome Date: Sun, 15 May 2011 13:44:06 +0000 Subject: [PATCH] Add an interactive Python console to the script manager --- src/CMakeLists.txt | 10 ++++ src/scripting/python/pythonconsole.cpp | 69 ++++++++++++++++++++++++++ src/scripting/python/pythonconsole.h | 55 ++++++++++++++++++++ src/scripting/python/pythonconsole.ui | 42 ++++++++++++++++ src/scripting/python/pythonengine.cpp | 27 +++++++++- src/scripting/python/pythonengine.h | 9 ++++ src/scripting/python/pythonscript.h | 4 +- src/scripting/scriptdialog.cpp | 14 ++++++ src/scripting/scriptdialog.ui | 2 +- src/translations/nl.po | 6 +++ 10 files changed, 234 insertions(+), 4 deletions(-) create mode 100644 src/scripting/python/pythonconsole.cpp create mode 100644 src/scripting/python/pythonconsole.h create mode 100644 src/scripting/python/pythonconsole.ui diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9fd98f8d1..b6a08ae61 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -507,6 +507,7 @@ set(UI scripting/installscriptdialog.ui scripting/scriptdialog.ui + scripting/python/pythonconsole.ui smartplaylists/querysearchpage.ui smartplaylists/querysortpage.ui @@ -818,11 +819,13 @@ endif(APPLE) if(HAVE_SCRIPTING_PYTHON) list(APPEND SOURCES + scripting/python/pythonconsole.cpp scripting/python/pythonengine.cpp scripting/python/pythonscript.cpp ) list(APPEND HEADERS + scripting/python/pythonconsole.h scripting/python/pythonengine.h ) endif(HAVE_SCRIPTING_PYTHON) @@ -898,6 +901,13 @@ list(APPEND OTHER_SOURCES remote/remoteconfig.cpp remote/remoteconfig.h ${CMAKE_CURRENT_BINARY_DIR}/ui_remoteconfig.h + scripting/python/pythonconsole.cpp + scripting/python/pythonconsole.h + scripting/python/pythonengine.cpp + scripting/python/pythonengine.h + scripting/python/pythonscript.cpp + scripting/python/pythonscript.h + ${CMAKE_CURRENT_BINARY_DIR}/ui_pythonconsole.h ui/macsystemtrayicon.h ui/macsystemtrayicon.mm ui/wiimotedevshortcutsconfig.cpp diff --git a/src/scripting/python/pythonconsole.cpp b/src/scripting/python/pythonconsole.cpp new file mode 100644 index 000000000..8864493aa --- /dev/null +++ b/src/scripting/python/pythonconsole.cpp @@ -0,0 +1,69 @@ +/* This file is part of Clementine. + Copyright 2010, David Sansome + + Clementine is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Clementine 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Clementine. If not, see . +*/ + +// Needs to be included first +#include "pythonengine.h" + +#include "pythonconsole.h" +#include "ui_pythonconsole.h" + +#include + +#include +#include + +PythonConsole::PythonConsole(QWidget *parent) + : QWidget(parent), + ui_(new Ui_PythonConsole), + proxy_model_(new QSortFilterProxyModel(this)), + engine_(NULL), + widget_(NULL) +{ + ui_->setupUi(this); + connect(ui_->modules, SIGNAL(currentIndexChanged(int)), SLOT(ModuleChanged(int))); +} + +PythonConsole::~PythonConsole() { + delete ui_; +} + +void PythonConsole::showEvent(QShowEvent* e) { + engine_->EnsureInitialised(); + + QWidget::showEvent(e); +} + +void PythonConsole::SetEngine(PythonEngine* engine) { + engine_ = engine; + + proxy_model_->setSourceModel(engine->modules_model()); + proxy_model_->setDynamicSortFilter(true); + + ui_->modules->setModel(proxy_model_); +} + +void PythonConsole::ModuleChanged(int row) { + const QModelIndex index = proxy_model_->index(row, 0); + + PythonQtObjectPtr ptr; + ptr.fromVariant(index.data(Qt::UserRole + 1)); + + delete widget_; + widget_ = new PythonQtScriptingConsole(this, ptr); + + layout()->addWidget(widget_); +} diff --git a/src/scripting/python/pythonconsole.h b/src/scripting/python/pythonconsole.h new file mode 100644 index 000000000..adca56dd7 --- /dev/null +++ b/src/scripting/python/pythonconsole.h @@ -0,0 +1,55 @@ +/* This file is part of Clementine. + Copyright 2010, David Sansome + + Clementine is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Clementine 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Clementine. If not, see . +*/ + +#ifndef PYTHONCONSOLE_H +#define PYTHONCONSOLE_H + +#include + + +class QSortFilterProxyModel; + +class PythonQtScriptingConsole; + +class PythonEngine; +class Ui_PythonConsole; + +class PythonConsole : public QWidget { + Q_OBJECT + +public: + PythonConsole(QWidget* parent = 0); + ~PythonConsole(); + + void SetEngine(PythonEngine* engine); + +protected: + void showEvent(QShowEvent* e); + +private slots: + void ModuleChanged(int row); + +private: + Ui_PythonConsole* ui_; + QSortFilterProxyModel* proxy_model_; + + PythonEngine* engine_; + + PythonQtScriptingConsole* widget_; +}; + +#endif // PYTHONCONSOLE_H diff --git a/src/scripting/python/pythonconsole.ui b/src/scripting/python/pythonconsole.ui new file mode 100644 index 000000000..b8e02cffc --- /dev/null +++ b/src/scripting/python/pythonconsole.ui @@ -0,0 +1,42 @@ + + + PythonConsole + + + + 0 + 0 + 788 + 439 + + + + Form + + + + + + + + Context: + + + + + + + + 0 + 0 + + + + + + + + + + + diff --git a/src/scripting/python/pythonengine.cpp b/src/scripting/python/pythonengine.cpp index 5b1e9f4b7..a8b9f2d2b 100644 --- a/src/scripting/python/pythonengine.cpp +++ b/src/scripting/python/pythonengine.cpp @@ -44,7 +44,8 @@ PythonEngine* PythonEngine::sInstance = NULL; PythonEngine::PythonEngine(ScriptManager* manager) : LanguageEngine(manager), - initialised_(false) + initialised_(false), + modules_model_(new QStandardItemModel(this)) { Q_ASSERT(sInstance == NULL); sInstance = this; @@ -57,6 +58,8 @@ PythonEngine::PythonEngine(ScriptManager* manager) PythonEngine::~PythonEngine() { sInstance = NULL; + modules_model_->clear(); + scripts_module_ = PythonQtObjectPtr(); clementine_module_ = PythonQtObjectPtr(); PythonQt::cleanup(); @@ -105,6 +108,10 @@ bool PythonEngine::EnsureInitialised() { qLog(Debug) << "Creating scripts module"; scripts_module_ = python_qt->createModuleFromScript(kScriptModulePrefix); + // The modules model contains all the modules + modules_model_->clear(); + AddModuleToModel("__main__", python_qt->getMainModule()); + qLog(Debug) << "Python initialisation complete"; initialised_ = true; return true; @@ -116,9 +123,10 @@ Script* PythonEngine::CreateScript(const ScriptInfo& info) { return NULL; } - Script* ret = new PythonScript(this, info); + PythonScript* ret = new PythonScript(this, info); loaded_scripts_[ret->info().id()] = ret; // Used by RegisterNativeObject during startup if (ret->Init()) { + AddModuleToModel(ret->module_name(), ret->module()); return ret; } @@ -127,6 +135,9 @@ Script* PythonEngine::CreateScript(const ScriptInfo& info) { } void PythonEngine::DestroyScript(Script* script) { + PythonScript* python_script = static_cast(script); + RemoveModuleFromModel(python_script->module_name()); + script->Unload(); loaded_scripts_.remove(script->info().id()); delete script; @@ -139,3 +150,15 @@ void PythonEngine::PythonStdOut(const QString& str) { void PythonEngine::PythonStdErr(const QString& str) { manager()->AddLogLine("Python", str, true); } + +void PythonEngine::AddModuleToModel(const QString& name, PythonQtObjectPtr ptr) { + QStandardItem* item = new QStandardItem(name); + item->setData(QVariant::fromValue(ptr)); + modules_model_->appendRow(item); +} + +void PythonEngine::RemoveModuleFromModel(const QString& name) { + foreach (QStandardItem* item, modules_model_->findItems(name)) { + modules_model_->removeRow(item->row()); + } +} diff --git a/src/scripting/python/pythonengine.h b/src/scripting/python/pythonengine.h index ba5687829..fd4d9e942 100644 --- a/src/scripting/python/pythonengine.h +++ b/src/scripting/python/pythonengine.h @@ -24,6 +24,9 @@ #include "gtest/gtest_prod.h" +class QStandardItemModel; + + class PythonEngine : public LanguageEngine { Q_OBJECT @@ -40,6 +43,7 @@ public: ScriptInfo::Language language() const { return ScriptInfo::Language_Python; } QString name() const { return "python"; } + QStandardItemModel* modules_model() const { return modules_model_; } bool EnsureInitialised(); @@ -50,6 +54,10 @@ private slots: void PythonStdOut(const QString& str); void PythonStdErr(const QString& str); +private: + void AddModuleToModel(const QString& name, PythonQtObjectPtr ptr); + void RemoveModuleFromModel(const QString& name); + private: static PythonEngine* sInstance; bool initialised_; @@ -58,6 +66,7 @@ private: PythonQtObjectPtr scripts_module_; QMap loaded_scripts_; + QStandardItemModel* modules_model_; }; #endif // PYTHONENGINE_H diff --git a/src/scripting/python/pythonscript.h b/src/scripting/python/pythonscript.h index 4f84a5519..78c872be6 100644 --- a/src/scripting/python/pythonscript.h +++ b/src/scripting/python/pythonscript.h @@ -27,6 +27,9 @@ class PythonScript : public Script { public: PythonScript(PythonEngine* engine, const ScriptInfo& info); + const QString& module_name() const { return module_name_; } + PythonQtObjectPtr module() const { return module_; } + bool Init(); bool Unload(); @@ -34,7 +37,6 @@ private: PythonEngine* engine_; QString module_name_; - PythonQtObjectPtr module_; }; diff --git a/src/scripting/scriptdialog.cpp b/src/scripting/scriptdialog.cpp index 1da6baf39..49f841002 100644 --- a/src/scripting/scriptdialog.cpp +++ b/src/scripting/scriptdialog.cpp @@ -16,6 +16,12 @@ */ #include "config.h" + +#ifdef HAVE_SCRIPTING_PYTHON +# include "scripting/python/pythonengine.h" +# include "scripting/python/pythonconsole.h" +#endif + #include "installscriptdialog.h" #include "scriptarchive.h" #include "scriptdialog.h" @@ -155,6 +161,14 @@ void ScriptDialog::SetManager(ScriptManager* manager) { foreach (const QString& html, manager->log_lines()) { LogLineAdded(html); } + +#ifdef HAVE_SCRIPTING_PYTHON + // Add the python console + PythonConsole* console = new PythonConsole(this); + console->SetEngine(qobject_cast( + manager_->EngineForLanguage(ScriptInfo::Language_Python))); + ui_->tab_widget->addTab(console, tr("Python console")); +#endif } void ScriptDialog::CurrentChanged(const QModelIndex& index) { diff --git a/src/scripting/scriptdialog.ui b/src/scripting/scriptdialog.ui index f6b6cf423..4d15a9234 100644 --- a/src/scripting/scriptdialog.ui +++ b/src/scripting/scriptdialog.ui @@ -23,7 +23,7 @@ - 0 + 1 diff --git a/src/translations/nl.po b/src/translations/nl.po index 27e785a47..e280814ea 100644 --- a/src/translations/nl.po +++ b/src/translations/nl.po @@ -681,6 +681,9 @@ msgstr "" msgid "Constant bitrate" msgstr "" +msgid "Context:" +msgstr "" + msgid "Convert all music" msgstr "Converteer alle muziek" @@ -2116,6 +2119,9 @@ msgstr "druk op Wiiremote knop" msgid "Put songs in a random order" msgstr "Zet liedjes in willekeurige volgorde" +msgid "Python console" +msgstr "" + msgid "Quality" msgstr "Kwaliteit"