mirror of
https://github.com/clementine-player/Clementine
synced 2025-01-31 03:27:40 +01:00
Refactor ScriptInfo into another class, add some (currently unused) code to read scripts from archives.
This commit is contained in:
parent
a883630ab3
commit
35a61de0a4
@ -58,6 +58,7 @@ pkg_check_modules(USBMUXD libusbmuxd)
|
||||
pkg_check_modules(LIBMTP libmtp>=1.0)
|
||||
pkg_check_modules(INDICATEQT indicate-qt)
|
||||
pkg_check_modules(QJSON QJson)
|
||||
pkg_check_modules(ARCHIVE REQUIRED libarchive)
|
||||
|
||||
if (WIN32)
|
||||
find_package(ZLIB REQUIRED)
|
||||
|
@ -156,7 +156,9 @@ set(SOURCES
|
||||
|
||||
scripting/languageengine.cpp
|
||||
scripting/script.cpp
|
||||
scripting/scriptarchive.cpp
|
||||
scripting/scriptdialog.cpp
|
||||
scripting/scriptinfo.cpp
|
||||
scripting/scriptinterface.cpp
|
||||
scripting/scriptmanager.cpp
|
||||
scripting/uiinterface.cpp
|
||||
@ -872,6 +874,7 @@ target_link_libraries(clementine_lib
|
||||
${QTSINGLECOREAPPLICATION_LIBRARIES}
|
||||
${QTIOCOMPRESSOR_LIBRARIES}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
${ARCHIVE_LIBRARIES}
|
||||
dl
|
||||
z
|
||||
)
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <QObject>
|
||||
|
||||
class Script;
|
||||
class ScriptInfo;
|
||||
|
||||
class LanguageEngine : public QObject {
|
||||
Q_OBJECT
|
||||
@ -33,11 +34,10 @@ public:
|
||||
|
||||
ScriptManager* manager() const { return manager_; }
|
||||
|
||||
virtual ScriptManager::Language language() const = 0;
|
||||
virtual ScriptInfo::Language language() const = 0;
|
||||
virtual QString name() const = 0;
|
||||
|
||||
virtual Script* CreateScript(const QString& path, const QString& script_file,
|
||||
const QString& id) = 0;
|
||||
virtual Script* CreateScript(const ScriptInfo& info) = 0;
|
||||
virtual void DestroyScript(Script* script) = 0;
|
||||
|
||||
private:
|
||||
|
@ -78,9 +78,7 @@ const sipAPIDef* PythonEngine::GetSIPApi() {
|
||||
#endif
|
||||
}
|
||||
|
||||
Script* PythonEngine::CreateScript(const QString& path,
|
||||
const QString& script_file,
|
||||
const QString& id) {
|
||||
Script* PythonEngine::CreateScript(const ScriptInfo& info) {
|
||||
// Initialise Python if it hasn't been done yet
|
||||
if (!initialised_) {
|
||||
AddLogLine("Initialising python...", false);
|
||||
@ -135,8 +133,8 @@ Script* PythonEngine::CreateScript(const QString& path,
|
||||
initialised_ = true;
|
||||
}
|
||||
|
||||
Script* ret = new PythonScript(this, path, script_file, id);
|
||||
loaded_scripts_[id] = ret; // Used by RegisterNativeObject during startup
|
||||
Script* ret = new PythonScript(this, info);
|
||||
loaded_scripts_[ret->info().id()] = ret; // Used by RegisterNativeObject during startup
|
||||
if (ret->Init()) {
|
||||
return ret;
|
||||
}
|
||||
@ -147,7 +145,7 @@ Script* PythonEngine::CreateScript(const QString& path,
|
||||
|
||||
void PythonEngine::DestroyScript(Script* script) {
|
||||
script->Unload();
|
||||
loaded_scripts_.remove(script->id());
|
||||
loaded_scripts_.remove(script->info().id());
|
||||
delete script;
|
||||
}
|
||||
|
||||
|
@ -35,11 +35,10 @@ public:
|
||||
|
||||
static const char* kModulePrefix;
|
||||
|
||||
ScriptManager::Language language() const { return ScriptManager::Language_Python; }
|
||||
ScriptInfo::Language language() const { return ScriptInfo::Language_Python; }
|
||||
QString name() const { return "python"; }
|
||||
|
||||
Script* CreateScript(const QString& path, const QString& script_file,
|
||||
const QString& id);
|
||||
Script* CreateScript(const ScriptInfo& info);
|
||||
void DestroyScript(Script* script);
|
||||
|
||||
const _sipAPIDef* sip_api() const { return sip_api_; }
|
||||
|
@ -21,24 +21,24 @@
|
||||
#include "pythonengine.h"
|
||||
#include "pythonscript.h"
|
||||
#include "sipAPIclementine.h"
|
||||
#include "scripting/scriptinfo.h"
|
||||
|
||||
#include <QFile>
|
||||
#include <QtDebug>
|
||||
|
||||
|
||||
PythonScript::PythonScript(PythonEngine* engine, const QString& path,
|
||||
const QString& script_file, const QString& id)
|
||||
: Script(engine, path, script_file, id),
|
||||
PythonScript::PythonScript(PythonEngine* engine, const ScriptInfo& info)
|
||||
: Script(engine, info),
|
||||
engine_(engine),
|
||||
module_name_(QString(PythonEngine::kModulePrefix) + "." + id)
|
||||
module_name_(QString(PythonEngine::kModulePrefix) + "." + info.id())
|
||||
{
|
||||
}
|
||||
|
||||
bool PythonScript::Init() {
|
||||
engine_->AddLogLine("Loading script file \"" + script_file() + "\"", false);
|
||||
engine_->AddLogLine("Loading script file \"" + info().script_file() + "\"", false);
|
||||
|
||||
// Open the file
|
||||
QFile file(script_file());
|
||||
QFile file(info().script_file());
|
||||
if (!file.open(QIODevice::ReadOnly)) {
|
||||
engine_->AddLogLine("Could not open file", true);
|
||||
return false;
|
||||
@ -56,11 +56,11 @@ bool PythonScript::Init() {
|
||||
PyModule_AddObject(module, "__builtins__", builtin_mod);
|
||||
|
||||
// Set __file__
|
||||
PyModule_AddStringConstant(module, "__file__", script_file().toLocal8Bit().constData());
|
||||
PyModule_AddStringConstant(module, "__file__", info().script_file().toLocal8Bit().constData());
|
||||
|
||||
// Set __path__
|
||||
PyObject* __path__ = PyList_New(1);
|
||||
PyList_SetItem(__path__, 0, PyString_FromString(path().toLocal8Bit().constData()));
|
||||
PyList_SetItem(__path__, 0, PyString_FromString(info().path().toLocal8Bit().constData()));
|
||||
PyModule_AddObject(module, "__path__", __path__);
|
||||
|
||||
// Set script
|
||||
@ -73,7 +73,7 @@ bool PythonScript::Init() {
|
||||
|
||||
// Run the script
|
||||
PyObject* result = PyRun_File(stream,
|
||||
script_file().toLocal8Bit().constData(), Py_file_input, dict, dict);
|
||||
info().script_file().toLocal8Bit().constData(), Py_file_input, dict, dict);
|
||||
if (result == NULL) {
|
||||
engine_->AddLogLine("Could not execute file", true);
|
||||
PyErr_Print();
|
||||
|
@ -21,13 +21,13 @@
|
||||
#include "scripting/script.h"
|
||||
|
||||
class PythonEngine;
|
||||
class ScriptInfo;
|
||||
|
||||
struct _object; // PyObject
|
||||
|
||||
class PythonScript : public Script {
|
||||
public:
|
||||
PythonScript(PythonEngine* engine, const QString& path,
|
||||
const QString& script_file, const QString& id);
|
||||
PythonScript(PythonEngine* engine, const ScriptInfo& info);
|
||||
|
||||
bool Init();
|
||||
bool Unload();
|
||||
|
@ -18,13 +18,10 @@
|
||||
#include "script.h"
|
||||
#include "scriptinterface.h"
|
||||
|
||||
Script::Script(LanguageEngine* language, const QString& path,
|
||||
const QString& script_file, const QString& id)
|
||||
Script::Script(LanguageEngine* language, const ScriptInfo& info)
|
||||
: interface_(new ScriptInterface(this)),
|
||||
language_(language),
|
||||
path_(path),
|
||||
script_file_(script_file),
|
||||
id_(id)
|
||||
info_(info)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,8 @@
|
||||
#ifndef SCRIPT_H
|
||||
#define SCRIPT_H
|
||||
|
||||
#include "scriptinfo.h"
|
||||
|
||||
#include <QList>
|
||||
#include <QMetaType>
|
||||
#include <QString>
|
||||
@ -31,14 +33,11 @@ class QObject;
|
||||
|
||||
class Script {
|
||||
public:
|
||||
Script(LanguageEngine* language, const QString& path,
|
||||
const QString& script_file, const QString& id);
|
||||
Script(LanguageEngine* language, const ScriptInfo& info);
|
||||
virtual ~Script();
|
||||
|
||||
LanguageEngine* language() const { return language_; }
|
||||
const QString& path() const { return path_; }
|
||||
const QString& script_file() const { return script_file_; }
|
||||
const QString& id() const { return id_; }
|
||||
const ScriptInfo& info() const { return info_; }
|
||||
ScriptInterface* interface() const { return interface_.get(); }
|
||||
|
||||
// The script can "own" QObjects like QActions that must be deleted (and
|
||||
@ -57,9 +56,7 @@ private:
|
||||
|
||||
boost::scoped_ptr<ScriptInterface> interface_;
|
||||
LanguageEngine* language_;
|
||||
QString path_;
|
||||
QString script_file_;
|
||||
QString id_;
|
||||
ScriptInfo info_;
|
||||
};
|
||||
Q_DECLARE_METATYPE(Script*);
|
||||
|
||||
|
77
src/scripting/scriptarchive.cpp
Normal file
77
src/scripting/scriptarchive.cpp
Normal file
@ -0,0 +1,77 @@
|
||||
/* 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/>.
|
||||
*/
|
||||
|
||||
#include "scriptarchive.h"
|
||||
|
||||
#include <QFile>
|
||||
|
||||
#include <archive.h>
|
||||
#include <archive_entry.h>
|
||||
|
||||
namespace {
|
||||
// Read callbacks for libarchive
|
||||
struct IODeviceReadState {
|
||||
QIODevice* device_;
|
||||
char buf_[1024];
|
||||
};
|
||||
|
||||
ssize_t IODeviceRead(struct archive* a, void* client_data, const void** buf) {
|
||||
IODeviceReadState* state = reinterpret_cast<IODeviceReadState*>(client_data);
|
||||
|
||||
*buf = state->buf_;
|
||||
return state->device_->read(state->buf_, sizeof(state->buf_));
|
||||
}
|
||||
|
||||
int IODeviceClose(struct archive* a, void* client_data) {
|
||||
IODeviceReadState* state = reinterpret_cast<IODeviceReadState*>(client_data);
|
||||
|
||||
state->device_->close();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool ScriptArchive::Load(const QString& filename) {
|
||||
QFile file(filename);
|
||||
if (!file.open(QIODevice::ReadOnly)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return Load(&file);
|
||||
}
|
||||
|
||||
bool ScriptArchive::Load(QIODevice* device) {
|
||||
archive* a = archive_read_new();
|
||||
archive_read_support_compression_gzip(a);
|
||||
archive_read_support_format_tar(a);
|
||||
|
||||
IODeviceReadState read_state;
|
||||
read_state.device_ = device;
|
||||
|
||||
if (archive_read_open(a, &read_state, NULL, IODeviceRead, IODeviceClose)) {
|
||||
archive_read_finish(a);
|
||||
return false;
|
||||
}
|
||||
|
||||
archive_entry* entry;
|
||||
while (archive_read_next_header(a, &entry) == 0) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
archive_read_finish(a);
|
||||
|
||||
return true;
|
||||
}
|
40
src/scripting/scriptarchive.h
Normal file
40
src/scripting/scriptarchive.h
Normal file
@ -0,0 +1,40 @@
|
||||
/* 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 SCRIPTARCHIVE_H
|
||||
#define SCRIPTARCHIVE_H
|
||||
|
||||
#include "scriptinfo.h"
|
||||
|
||||
#include <QFuture>
|
||||
|
||||
class ScriptArchive {
|
||||
public:
|
||||
bool Load(const QString& filename);
|
||||
bool Load(QIODevice* device);
|
||||
QFuture<bool> LoadAsync(const QString& filename);
|
||||
QFuture<bool> LoadAsync(QIODevice* device);
|
||||
|
||||
const ScriptInfo& info() const { return info_; }
|
||||
|
||||
bool Install() const;
|
||||
|
||||
private:
|
||||
ScriptInfo info_;
|
||||
};
|
||||
|
||||
#endif // SCRIPTARCHIVE_H
|
99
src/scripting/scriptinfo.cpp
Normal file
99
src/scripting/scriptinfo.cpp
Normal file
@ -0,0 +1,99 @@
|
||||
/* 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/>.
|
||||
*/
|
||||
|
||||
#include "languageengine.h"
|
||||
#include "scriptinfo.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QSettings>
|
||||
#include <QtDebug>
|
||||
|
||||
const char* ScriptInfo::kIniFileName = "script.ini";
|
||||
const char* ScriptInfo::kIniSettingsGroup = "Script";
|
||||
|
||||
|
||||
void ScriptInfo::InitFromDirectory(const ScriptManager* manager, const QString& path) {
|
||||
const QString ini_file = path + "/" + kIniFileName;
|
||||
const QString id = QFileInfo(path).completeBaseName();
|
||||
|
||||
// Does the file exist?
|
||||
if (!QFile::exists(ini_file)) {
|
||||
qWarning() << "Script definition file not found:" << ini_file;
|
||||
return;
|
||||
}
|
||||
|
||||
InitFromFile(manager, id, path, ini_file);
|
||||
}
|
||||
|
||||
void ScriptInfo::InitFromFile(const ScriptManager* manager,
|
||||
const QString& id,
|
||||
const QString& path,
|
||||
const QString& ini_file) {
|
||||
// Open it
|
||||
QSettings s(ini_file, QSettings::IniFormat);
|
||||
if (!s.childGroups().contains(kIniSettingsGroup)) {
|
||||
qWarning() << "Missing" << kIniSettingsGroup << "section in" << ini_file;
|
||||
return;
|
||||
}
|
||||
s.beginGroup(kIniSettingsGroup);
|
||||
|
||||
// Find out what language it's in
|
||||
QString language_name = s.value("language").toString();
|
||||
LanguageEngine* engine = manager->EngineForLanguage(language_name);
|
||||
if (!engine) {
|
||||
qWarning() << "Unknown language" << language_name << "in" << ini_file;
|
||||
return;
|
||||
}
|
||||
d->language_ = engine->language();
|
||||
|
||||
// Load the rest of the metadata
|
||||
d->path_ = path;
|
||||
d->id_ = id;
|
||||
d->name_ = s.value("name").toString();
|
||||
d->description_ = s.value("description").toString();
|
||||
d->author_ = s.value("author").toString();
|
||||
d->url_ = s.value("url").toString();
|
||||
d->script_file_ = QFileInfo(QDir(path), s.value("script_file").toString()).absoluteFilePath();
|
||||
d->icon_ = QIcon(QFileInfo(QDir(path), s.value("icon").toString()).absoluteFilePath());
|
||||
}
|
||||
|
||||
bool ScriptInfo::operator ==(const ScriptInfo& other) const {
|
||||
return path() == other.path() &&
|
||||
name() == other.name() &&
|
||||
description() == other.description() &&
|
||||
author() == other.author() &&
|
||||
url() == other.url() &&
|
||||
language() == other.language() &&
|
||||
script_file() == other.script_file();
|
||||
}
|
||||
|
||||
bool ScriptInfo::operator !=(const ScriptInfo& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
void ScriptInfo::TakeMetadataFrom(const ScriptInfo& other) {
|
||||
d->path_ = other.path();
|
||||
d->name_ = other.name();
|
||||
d->description_ = other.description();
|
||||
d->author_ = other.author();
|
||||
d->url_ = other.url();
|
||||
d->icon_ = other.icon();
|
||||
d->language_ = other.language();
|
||||
d->script_file_ = other.script_file();
|
||||
}
|
86
src/scripting/scriptinfo.h
Normal file
86
src/scripting/scriptinfo.h
Normal file
@ -0,0 +1,86 @@
|
||||
/* 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 SCRIPTINFO_H
|
||||
#define SCRIPTINFO_H
|
||||
|
||||
#include <QIcon>
|
||||
#include <QSharedData>
|
||||
#include <QSharedDataPointer>
|
||||
|
||||
class Script;
|
||||
class ScriptManager;
|
||||
|
||||
class ScriptInfo {
|
||||
public:
|
||||
enum Language {
|
||||
Language_Unknown = 0,
|
||||
Language_Python,
|
||||
};
|
||||
|
||||
static const char* kIniFileName;
|
||||
static const char* kIniSettingsGroup;
|
||||
|
||||
void InitFromDirectory(const ScriptManager* manager, const QString& path);
|
||||
void InitFromFile(const ScriptManager* manager,
|
||||
const QString& id,
|
||||
const QString& path,
|
||||
const QString& filename);
|
||||
void TakeMetadataFrom(const ScriptInfo& other);
|
||||
|
||||
bool is_valid() const { return d->language_ != Language_Unknown; }
|
||||
bool operator ==(const ScriptInfo& other) const;
|
||||
bool operator !=(const ScriptInfo& other) const;
|
||||
|
||||
const QString& path() const { return d->path_; }
|
||||
const QString& id() const { return d->id_; }
|
||||
|
||||
const QString& name() const { return d->name_; }
|
||||
const QString& description() const { return d->description_; }
|
||||
const QString& author() const { return d->author_; }
|
||||
const QString& url() const { return d->url_; }
|
||||
const QIcon& icon() const { return d->icon_; }
|
||||
|
||||
Language language() const { return d->language_; }
|
||||
const QString& script_file() const { return d->script_file_; }
|
||||
|
||||
Script* loaded() const { return d->loaded_; }
|
||||
void set_loaded(Script* loaded) { d->loaded_ = loaded; }
|
||||
|
||||
private:
|
||||
struct Private : public QSharedData {
|
||||
Private() : language_(Language_Unknown), loaded_(NULL) {}
|
||||
|
||||
QString path_;
|
||||
QString id_;
|
||||
|
||||
QString name_;
|
||||
QString description_;
|
||||
QString author_;
|
||||
QString url_;
|
||||
QIcon icon_;
|
||||
|
||||
Language language_;
|
||||
QString script_file_;
|
||||
|
||||
Script* loaded_;
|
||||
};
|
||||
|
||||
QSharedDataPointer<Private> d;
|
||||
};
|
||||
|
||||
#endif // SCRIPTINFO_H
|
@ -40,8 +40,6 @@
|
||||
#include <QtDebug>
|
||||
|
||||
const char* ScriptManager::kSettingsGroup = "Scripts";
|
||||
const char* ScriptManager::kIniFileName = "script.ini";
|
||||
const char* ScriptManager::kIniSettingsGroup = "Script";
|
||||
|
||||
ScriptManager::ScriptManager(QObject* parent)
|
||||
: QAbstractListModel(parent),
|
||||
@ -84,8 +82,8 @@ ScriptManager::ScriptManager(QObject* parent)
|
||||
|
||||
ScriptManager::~ScriptManager() {
|
||||
foreach (const ScriptInfo& info, info_) {
|
||||
if (info.loaded_) {
|
||||
info.loaded_->language()->DestroyScript(info.loaded_);
|
||||
if (info.loaded()) {
|
||||
info.loaded()->language()->DestroyScript(info.loaded());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -109,24 +107,24 @@ void ScriptManager::Init(const GlobalData& data) {
|
||||
|
||||
void ScriptManager::MaybeAutoEnable(ScriptInfo* info) {
|
||||
// Load the script if it's enabled
|
||||
if (enabled_scripts_.contains(info->id_)) {
|
||||
if (enabled_scripts_.contains(info->id())) {
|
||||
// Find an engine for it
|
||||
LanguageEngine* engine = EngineForLanguage(info->language_);
|
||||
LanguageEngine* engine = EngineForLanguage(info->language());
|
||||
if (!engine) {
|
||||
qWarning() << "Unknown language in" << info->path_;
|
||||
qWarning() << "Unknown language in" << info->path();
|
||||
return;
|
||||
}
|
||||
|
||||
info->loaded_ = engine->CreateScript(info->path_, info->script_file_, info->id_);
|
||||
if (!info->loaded_) {
|
||||
info->set_loaded(engine->CreateScript(*info));
|
||||
if (!info->loaded()) {
|
||||
// Failed to load? Disable it so we don't try again
|
||||
enabled_scripts_.remove(info->id_);
|
||||
enabled_scripts_.remove(info->id());
|
||||
SaveSettings();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QMap<QString, ScriptManager::ScriptInfo> ScriptManager::LoadAllScriptInfo() const {
|
||||
QMap<QString, ScriptInfo> ScriptManager::LoadAllScriptInfo() const {
|
||||
QMap<QString, ScriptInfo> ret;
|
||||
|
||||
foreach (const QString& search_path, search_paths_) {
|
||||
@ -147,19 +145,20 @@ QMap<QString, ScriptManager::ScriptInfo> ScriptManager::LoadAllScriptInfo() cons
|
||||
watcher_->addPath(path);
|
||||
}
|
||||
|
||||
ScriptInfo info = LoadScriptInfo(path);
|
||||
ScriptInfo info;
|
||||
info.InitFromDirectory(this, path);
|
||||
if (!info.is_valid()) {
|
||||
qWarning() << "Not a valid Clementine script directory, ignoring:"
|
||||
<< path;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ret.contains(info.id_)) {
|
||||
if (ret.contains(info.id())) {
|
||||
// Seen this script already
|
||||
continue;
|
||||
}
|
||||
|
||||
ret.insert(info.id_, info);
|
||||
ret.insert(info.id(), info);
|
||||
}
|
||||
}
|
||||
|
||||
@ -188,7 +187,7 @@ LanguageEngine* ScriptManager::EngineForLanguage(const QString& language_name) c
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LanguageEngine* ScriptManager::EngineForLanguage(ScriptManager::Language language) const {
|
||||
LanguageEngine* ScriptManager::EngineForLanguage(ScriptInfo::Language language) const {
|
||||
foreach (LanguageEngine* engine, engines_) {
|
||||
if (engine->language() == language) {
|
||||
return engine;
|
||||
@ -197,47 +196,6 @@ LanguageEngine* ScriptManager::EngineForLanguage(ScriptManager::Language languag
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ScriptManager::ScriptInfo ScriptManager::LoadScriptInfo(const QString& path) const {
|
||||
const QString ini_file = path + "/" + kIniFileName;
|
||||
const QString id = QFileInfo(path).completeBaseName();
|
||||
|
||||
// Does the file exist?
|
||||
ScriptManager::ScriptInfo ret;
|
||||
if (!QFile::exists(ini_file)) {
|
||||
qWarning() << "Script definition file not found:" << ini_file;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Open it
|
||||
QSettings s(ini_file, QSettings::IniFormat);
|
||||
if (!s.childGroups().contains(kIniSettingsGroup)) {
|
||||
qWarning() << "Missing" << kIniSettingsGroup << "section in" << ini_file;
|
||||
return ret;
|
||||
}
|
||||
s.beginGroup(kIniSettingsGroup);
|
||||
|
||||
// Find out what language it's in
|
||||
QString language_name = s.value("language").toString();
|
||||
LanguageEngine* engine = EngineForLanguage(language_name);
|
||||
if (!engine) {
|
||||
qWarning() << "Unknown language" << language_name << "in" << ini_file;
|
||||
return ret;
|
||||
}
|
||||
ret.language_ = engine->language();
|
||||
|
||||
// Load the rest of the metadata
|
||||
ret.path_ = path;
|
||||
ret.id_ = id;
|
||||
ret.name_ = s.value("name").toString();
|
||||
ret.description_ = s.value("description").toString();
|
||||
ret.author_ = s.value("author").toString();
|
||||
ret.url_ = s.value("url").toString();
|
||||
ret.script_file_ = QFileInfo(QDir(path), s.value("script_file").toString()).absoluteFilePath();
|
||||
ret.icon_ = QIcon(QFileInfo(QDir(path), s.value("icon").toString()).absoluteFilePath());
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ScriptManager::rowCount(const QModelIndex& parent) const {
|
||||
if (parent.isValid())
|
||||
return 0;
|
||||
@ -252,28 +210,28 @@ QVariant ScriptManager::data(const QModelIndex& index, int role) const {
|
||||
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
return info.name_;
|
||||
return info.name();
|
||||
|
||||
case Qt::DecorationRole:
|
||||
return info.icon_;
|
||||
return info.icon();
|
||||
|
||||
case Role_Author:
|
||||
return info.author_;
|
||||
return info.author();
|
||||
|
||||
case Role_Description:
|
||||
return info.description_;
|
||||
return info.description();
|
||||
|
||||
case Role_Language:
|
||||
return info.language_;
|
||||
return info.language();
|
||||
|
||||
case Role_ScriptFile:
|
||||
return info.script_file_;
|
||||
return info.script_file();
|
||||
|
||||
case Role_Url:
|
||||
return info.url_;
|
||||
return info.url();
|
||||
|
||||
case Role_IsEnabled:
|
||||
return info.loaded_ != NULL;
|
||||
return info.loaded() != NULL;
|
||||
|
||||
default:
|
||||
return QVariant();
|
||||
@ -285,22 +243,22 @@ void ScriptManager::Enable(const QModelIndex& index) {
|
||||
return;
|
||||
|
||||
ScriptInfo* info = &info_[index.row()];
|
||||
if (info->loaded_)
|
||||
if (info->loaded())
|
||||
return;
|
||||
|
||||
// Find an engine for it
|
||||
LanguageEngine* engine = EngineForLanguage(info->language_);
|
||||
LanguageEngine* engine = EngineForLanguage(info->language());
|
||||
if (!engine) {
|
||||
qWarning() << "Unknown language in" << info->path_;
|
||||
qWarning() << "Unknown language in" << info->path();
|
||||
return;
|
||||
}
|
||||
|
||||
// Load the script
|
||||
info->loaded_ = engine->CreateScript(info->path_, info->script_file_, info->id_);
|
||||
info->set_loaded(engine->CreateScript(*info));
|
||||
|
||||
// If it loaded correctly then automatically load it in the future
|
||||
if (info->loaded_) {
|
||||
enabled_scripts_.insert(info->id_);
|
||||
if (info->loaded()) {
|
||||
enabled_scripts_.insert(info->id());
|
||||
SaveSettings();
|
||||
}
|
||||
|
||||
@ -312,13 +270,13 @@ void ScriptManager::Disable(const QModelIndex& index) {
|
||||
return;
|
||||
|
||||
ScriptInfo* info = &info_[index.row()];
|
||||
if (!info->loaded_)
|
||||
if (!info->loaded())
|
||||
return;
|
||||
|
||||
info->loaded_->language()->DestroyScript(info->loaded_);
|
||||
info->loaded_ = NULL;
|
||||
info->loaded()->language()->DestroyScript(info->loaded());
|
||||
info->set_loaded(NULL);
|
||||
|
||||
enabled_scripts_.remove(info->id_);
|
||||
enabled_scripts_.remove(info->id());
|
||||
SaveSettings();
|
||||
|
||||
emit dataChanged(index, index);
|
||||
@ -329,10 +287,10 @@ void ScriptManager::ShowSettingsDialog(const QModelIndex& index) {
|
||||
return;
|
||||
|
||||
ScriptInfo* info = &info_[index.row()];
|
||||
if (!info->loaded_)
|
||||
if (!info->loaded())
|
||||
return;
|
||||
|
||||
info->loaded_->interface()->ShowSettingsDialog();
|
||||
info->loaded()->interface()->ShowSettingsDialog();
|
||||
}
|
||||
|
||||
void ScriptManager::AddLogLine(const QString& who, const QString& message, bool error) {
|
||||
@ -363,7 +321,7 @@ void ScriptManager::RescanScripts() {
|
||||
// Look at existing scripts, find ones that have changed or been deleted
|
||||
for (int i=0 ; i<info_.count() ; ++i) {
|
||||
ScriptInfo* info = &info_[i];
|
||||
const QString id = info->id_;
|
||||
const QString id = info->id();
|
||||
|
||||
if (!new_info.contains(id)) {
|
||||
// This script was deleted - unload it and remove it from the model
|
||||
@ -405,28 +363,3 @@ void ScriptManager::RescanScripts() {
|
||||
endInsertRows();
|
||||
}
|
||||
}
|
||||
|
||||
bool ScriptManager::ScriptInfo::operator ==(const ScriptInfo& other) const {
|
||||
return path_ == other.path_ &&
|
||||
name_ == other.name_ &&
|
||||
description_ == other.description_ &&
|
||||
author_ == other.author_ &&
|
||||
url_ == other.url_ &&
|
||||
language_ == other.language_ &&
|
||||
script_file_ == other.script_file_;
|
||||
}
|
||||
|
||||
bool ScriptManager::ScriptInfo::operator !=(const ScriptInfo& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
void ScriptManager::ScriptInfo::TakeMetadataFrom(const ScriptInfo& other) {
|
||||
path_ = other.path_;
|
||||
name_ = other.name_;
|
||||
description_ = other.description_;
|
||||
author_ = other.author_;
|
||||
url_ = other.url_;
|
||||
icon_ = other.icon_;
|
||||
language_ = other.language_;
|
||||
script_file_ = other.script_file_;
|
||||
}
|
||||
|
@ -18,6 +18,8 @@
|
||||
#ifndef SCRIPTMANAGER_H
|
||||
#define SCRIPTMANAGER_H
|
||||
|
||||
#include "scriptinfo.h"
|
||||
|
||||
#include <QAbstractItemModel>
|
||||
#include <QIcon>
|
||||
#include <QSet>
|
||||
@ -53,11 +55,6 @@ public:
|
||||
RoleCount
|
||||
};
|
||||
|
||||
enum Language {
|
||||
Language_Unknown = 0,
|
||||
Language_Python,
|
||||
};
|
||||
|
||||
struct GlobalData {
|
||||
GlobalData() {}
|
||||
GlobalData(Library* library, Player* player, PlaylistManager* playlists,
|
||||
@ -80,8 +77,6 @@ public:
|
||||
};
|
||||
|
||||
static const char* kSettingsGroup;
|
||||
static const char* kIniFileName;
|
||||
static const char* kIniSettingsGroup;
|
||||
|
||||
void Init(const GlobalData& data);
|
||||
const GlobalData& data() const { return data_; }
|
||||
@ -97,6 +92,10 @@ public:
|
||||
int rowCount(const QModelIndex& parent = QModelIndex()) const;
|
||||
QVariant data(const QModelIndex& index, int role) const;
|
||||
|
||||
// These need to be public for ScriptInfo
|
||||
LanguageEngine* EngineForLanguage(const QString& language_name) const;
|
||||
LanguageEngine* EngineForLanguage(ScriptInfo::Language language) const;
|
||||
|
||||
public slots:
|
||||
void AddLogLine(const QString& who, const QString& message, bool error);
|
||||
|
||||
@ -104,41 +103,13 @@ signals:
|
||||
void LogLineAdded(const QString& html);
|
||||
|
||||
private:
|
||||
struct ScriptInfo {
|
||||
ScriptInfo() : language_(Language_Unknown), loaded_(NULL) {}
|
||||
|
||||
bool is_valid() const { return language_ != Language_Unknown; }
|
||||
bool operator ==(const ScriptInfo& other) const;
|
||||
bool operator !=(const ScriptInfo& other) const;
|
||||
|
||||
void TakeMetadataFrom(const ScriptInfo& other);
|
||||
|
||||
QString path_;
|
||||
QString id_;
|
||||
|
||||
QString name_;
|
||||
QString description_;
|
||||
QString author_;
|
||||
QString url_;
|
||||
QIcon icon_;
|
||||
|
||||
Language language_;
|
||||
QString script_file_;
|
||||
|
||||
Script* loaded_;
|
||||
};
|
||||
|
||||
void LoadSettings();
|
||||
void SaveSettings() const;
|
||||
|
||||
QMap<QString, ScriptInfo> LoadAllScriptInfo() const;
|
||||
ScriptInfo LoadScriptInfo(const QString& path) const;
|
||||
|
||||
void MaybeAutoEnable(ScriptInfo* info);
|
||||
|
||||
LanguageEngine* EngineForLanguage(const QString& language_name) const;
|
||||
LanguageEngine* EngineForLanguage(Language language) const;
|
||||
|
||||
private slots:
|
||||
void ScriptDirectoryChanged();
|
||||
void RescanScripts();
|
||||
|
Loading…
x
Reference in New Issue
Block a user