Add an interactive Python console to the script manager

This commit is contained in:
David Sansome 2011-05-15 13:44:06 +00:00
parent 7c05b42dcd
commit 930a2aa2bf
10 changed files with 234 additions and 4 deletions

View File

@ -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

View File

@ -0,0 +1,69 @@
/* This file is part of Clementine.
Copyright 2010, David Sansome <me@davidsansome.com>
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 <http://www.gnu.org/licenses/>.
*/
// Needs to be included first
#include "pythonengine.h"
#include "pythonconsole.h"
#include "ui_pythonconsole.h"
#include <gui/PythonQtScriptingConsole.h>
#include <QSortFilterProxyModel>
#include <QStandardItemModel>
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_);
}

View File

@ -0,0 +1,55 @@
/* This file is part of Clementine.
Copyright 2010, David Sansome <me@davidsansome.com>
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 <http://www.gnu.org/licenses/>.
*/
#ifndef PYTHONCONSOLE_H
#define PYTHONCONSOLE_H
#include <QWidget>
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

View File

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>PythonConsole</class>
<widget class="QWidget" name="PythonConsole">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>788</width>
<height>439</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Context:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="modules">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -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<PythonScript*>(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());
}
}

View File

@ -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<QString, Script*> loaded_scripts_;
QStandardItemModel* modules_model_;
};
#endif // PYTHONENGINE_H

View File

@ -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_;
};

View File

@ -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<PythonEngine*>(
manager_->EngineForLanguage(ScriptInfo::Language_Python)));
ui_->tab_widget->addTab(console, tr("Python console"));
#endif
}
void ScriptDialog::CurrentChanged(const QModelIndex& index) {

View File

@ -23,7 +23,7 @@
</size>
</property>
<property name="currentIndex">
<number>0</number>
<number>1</number>
</property>
<widget class="QWidget" name="tab">
<attribute name="title">

View File

@ -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"