epno = 0;
}
+Report::Report()
+{
+ reportId = 0;
+}
DatabaseConnectionSettings::DatabaseConnectionSettings()
{
QStringList Database::getWatchedDirectories(int hostId)
{
QSqlQuery &q = prepare("SELECT directory FROM watched_directory WHERE host_id = :hostId");
+
q.bindValue(":hostId", hostId);
if (!exec(q))
return ret;
}
+QList<Report> Database::getReports()
+{
+ QList<Report> reports;
+
+ QSqlQuery &q = prepare("SELECT report_id, name, script FROM report");
+
+ if (!exec(q))
+ return reports;
+
+ while (q.next())
+ {
+ Report report;
+ report.reportId = q.value(0).toInt();
+ report.name = q.value(1).toString();
+ report.script = q.value(2).toString();
+
+ reports << report;
+ }
+
+ return reports;
+}
+
+bool Database::addReport(const Report &report)
+{
+ QSqlQuery &q = prepare("INSERT INTO report VALUES (DEFAULT, :name, :script)");
+ q.bindValue(":name", report.name);
+ q.bindValue(":script", report.script);
+
+ return exec(q);
+}
+
+bool Database::setReport(const Report &report)
+{
+ QSqlQuery &q = prepare(
+ "UPDATE report "
+ " SET name = :name, script = :script "
+ " WHERE report_id = :reportId");
+
+ q.bindValue(":reportId", report.reportId);
+ q.bindValue(":name", report.name);
+ q.bindValue(":script", report.script);
+
+ return exec(q);
+}
+
+bool Database::removeReport(int reportId)
+{
+ QSqlQuery &q = prepare(
+ "DELETE FROM report "
+ " WHERE report_id = :reportId");
+
+ q.bindValue(":reportId", reportId);
+
+ return exec(q);
+}
+
bool Database::clearStartedPendingRequests()
{
return exec(
qDebug() << "Not connected";
return;
}
+
+ d->preparedQueries.clear();
d->db.close();
+
emit disconnected();
}
OpenFileData();
};
+struct LOCALMYLISTSHARED_EXPORT Report
+{
+ int reportId;
+ QString name;
+ QString script;
+
+ Report();
+};
+
struct LOCALMYLISTSHARED_EXPORT DatabaseConnectionSettings
{
QString host;
QStringList getWatchedDirectories(int hostId);
+ QList<LocalMyList::Report> getReports();
+ bool addReport(const LocalMyList::Report &report);
+ bool setReport(const LocalMyList::Report &report);
+ bool removeReport(int reportId);
+
bool clearStartedPendingRequests();
bool clearStartedMyListUpdateRequests();
bool clearFileRenames();
Q_DECLARE_METATYPE(LocalMyList::OpenFileData*)
Q_DECLARE_METATYPE(QList<LocalMyList::OpenFileData>)
Q_DECLARE_METATYPE(QList<LocalMyList::OpenFileData*>)
+Q_DECLARE_METATYPE(LocalMyList::Report)
+Q_DECLARE_METATYPE(LocalMyList::Report*)
+Q_DECLARE_METATYPE(QList<LocalMyList::Report>)
+Q_DECLARE_METATYPE(QList<LocalMyList::Report*>)
Q_DECLARE_METATYPE(LocalMyList::DatabaseConnectionSettings)
Q_DECLARE_METATYPE(LocalMyList::DatabaseConnectionSettings*)
Q_DECLARE_METATYPE(QList<LocalMyList::DatabaseConnectionSettings>)
unknownfilelookuptask.cpp \
renameutils.cpp \
directorywatcher.cpp \
- addrelatedepisodestask.cpp
+ addrelatedepisodestask.cpp \
+ scriptablesql.cpp \
+ reportengine.cpp
HEADERS += \
localmylist_global.h \
unknownfilelookuptask.h \
renameutils.h \
directorywatcher.h \
- addrelatedepisodestask.h
+ addrelatedepisodestask.h \
+ scriptablesql.h \
+ reportengine.h
CONV_HEADERS += \
include/LocalMyList/AbstractTask \
--- /dev/null
+#include "reportengine.h"
+
+#include <QScriptEngine>
+#include <QSqlError>
+#include "database.h"
+#include "scriptablesql.h"
+
+#include <QDebug>
+
+namespace LocalMyList {
+
+ReportEngine::ReportEngine(QObject *parent) :
+ QObject(parent)
+{
+ m_engine = new QScriptEngine(this);
+ registerSqlTypes(m_engine);
+}
+
+QSqlQuery ReportEngine::query() const
+{
+ QSqlQuery q = m_engine->globalObject().property("query").toVariant().value<QSqlQuery>();
+ qDebug() << q.lastError();
+ return q;
+}
+
+QScriptEngine *ReportEngine::engine() const
+{
+ return m_engine;
+}
+
+void ReportEngine::run(const Report &report)
+{
+ run(report.script);
+}
+
+void ReportEngine::run(const QString &report)
+{
+ m_engine->evaluate(report);
+ if (m_engine->hasUncaughtException())
+ qDebug() << m_engine->uncaughtException().toString();
+}
+
+} // namespace LocalMyList
--- /dev/null
+#ifndef REPORTENGINE_H
+#define REPORTENGINE_H
+
+#include "localmylist_global.h"
+#include <QObject>
+
+#include <QSqlQuery>
+
+class QScriptEngine;
+
+namespace LocalMyList {
+
+struct Report;
+
+class LOCALMYLISTSHARED_EXPORT ReportEngine : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QSqlQuery query READ query)
+ Q_PROPERTY(QScriptEngine *engine READ engine)
+
+public:
+ explicit ReportEngine(QObject *parent = 0);
+
+ QSqlQuery query() const;
+ QScriptEngine *engine() const;
+signals:
+
+public slots:
+ void run(const Report &report);
+ void run(const QString &report);
+
+private:
+ QScriptEngine *m_engine;
+};
+
+} // namespace LocalMyList
+
+#endif // REPORTENGINE_H
--- /dev/null
+#include "scriptablesql.h"
+
+#include <QSqlRecord>
+
+#include "mylist.h"
+#include "database.h"
+#include <QDebug>
+
+namespace LocalMyList {
+
+void registerSqlTypes(QScriptEngine *engine)
+{
+ Scriptable::SqlQuery *SqlQueryPrototype = new Scriptable::SqlQuery();
+ engine->setDefaultPrototype(qMetaTypeId<QSqlQuery>(), engine->newQObject(SqlQueryPrototype));
+ engine->setDefaultPrototype(qMetaTypeId<QSqlQuery*>(), engine->newQObject(SqlQueryPrototype));
+ engine->globalObject().setProperty("SqlQuery", engine->newFunction(Scriptable::SqlQuery_ctor));
+}
+
+namespace Scriptable {
+
+SqlQuery::SqlQuery(QObject *parent) :
+ QObject(parent), QScriptable()
+{
+}
+
+bool SqlQuery::prepare(const QString &sql)
+{
+ auto o = thisObj();
+ if (!o) return false;
+ QString tmp = sql;
+ tmp.replace(QRegExp("[\\n\\r]+"), " ");
+ qDebug() << tmp;
+ *o = MyList::instance()->database()->prepareOneShot(tmp);
+ return true;
+}
+
+bool SqlQuery::bindValue(const QString &name, const QVariant &value)
+{
+ auto o = thisObj();
+ if (!o) return false;
+ o->bindValue(name, value);
+ return true;
+}
+
+bool SqlQuery::exec()
+{
+ auto o = thisObj();
+ if (!o) return false;
+ return MyList::instance()->database()->exec(*o);
+}
+
+bool SqlQuery::next()
+{
+ auto o = thisObj();
+ if (!o) return false;
+ return o->next();
+}
+
+QVariant SqlQuery::column(const QString &column)
+{
+ auto o = thisObj();
+ if (!o) return QVariant();
+ return o->record().value(column);
+}
+
+QVariant SqlQuery::columnNo(int column)
+{
+ auto o = thisObj();
+ if (!o) return QVariant();
+ return o->value(column);
+}
+
+QSqlQuery *SqlQuery::thisObj() const
+{
+ return qscriptvalue_cast<QSqlQuery *>(thisObject());
+}
+
+QScriptValue SqlQuery_ctor(QScriptContext *, QScriptEngine *engine)
+{
+ return engine->toScriptValue(QSqlQuery());
+}
+
+} // namespace Scriptable
+} // namespace LocalMyList
--- /dev/null
+#ifndef SCRIPTABLESQL_H
+#define SCRIPTABLESQL_H
+
+#include "localmylist_global.h"
+
+#include <QObject>
+#include <QtScript/QScriptable>
+#include <QtScript/QScriptEngine>
+
+#include <QSqlQuery>
+
+namespace LocalMyList {
+
+void LOCALMYLISTSHARED_EXPORT registerSqlTypes(QScriptEngine *engine);
+
+namespace Scriptable {
+
+class LOCALMYLISTSHARED_EXPORT SqlQuery : public QObject, protected QScriptable
+{
+ Q_OBJECT
+public:
+ SqlQuery(QObject *parent = 0);
+
+public slots:
+ bool prepare(const QString &sql);
+ bool bindValue(const QString &name, const QVariant &value);
+
+ bool exec();
+
+ bool next();
+
+ QVariant column(const QString &column);
+ QVariant columnNo(int column);
+
+private:
+ QSqlQuery *thisObj() const;
+};
+
+QScriptValue SqlQuery_ctor(QScriptContext *, QScriptEngine *engine);
+
+} // namespace Scriptable
+} // namespace LocalMyList
+
+Q_DECLARE_METATYPE(QSqlQuery)
+Q_DECLARE_METATYPE(QSqlQuery*)
+
+#endif // SCRIPTABLESQL_H
CONSTRAINT watched_directory_pk PRIMARY KEY (host_id, directory)
);
+CREATE TABLE report
+(
+ report_id serial,
+ name character varying(500),
+ script text,
+ CONSTRAINT report_pk PRIMARY KEY (report_id)
+);
+
CREATE TABLE log (
log_id serial NOT NULL,
type integer,
#include <QSortFilterProxyModel>
#include <QDragEnterEvent>
#include <QDropEvent>
+#include <QSqlQueryModel>
+#include <QScriptEngineDebugger>
#include "mylist.h"
#include "database.h"
#include "mylistfiltermodel.h"
#include "unknownfilelookuptask.h"
#include "addrelatedepisodestask.h"
+#include "reportengine.h"
#include "renamesettingsdialog.h"
+#include "reporteditordialog.h"
#include <QDebug>
connect(ui->myListView, SIGNAL(renameTest(int)), this, SLOT(openRenameScriptEditor(int)));
+ reportResultModel = new QSqlQueryModel(this);
+ ui->reportResultView->setModel(reportResultModel);
+
setAcceptDrops(true);
}
on_filterInput_textChanged(ui->filterInput->text());
}
+void MainWindow::on_reloadReports_clicked()
+{
+ ui->reports->clear();
+
+ QList<Report> reports = MyList::instance()->database()->getReports();
+
+ foreach (const Report &report, reports)
+ {
+ ui->reports->addItem(report.name, QVariant::fromValue(report));
+ }
+}
+
void MainWindow::dragEnterEvent(QDragEnterEvent *event)
{
if (event->mimeData()->hasFormat("text/uri-list"))
}
event->acceptProposedAction();
}
+
+
+
+void MainWindow::on_reports_currentIndexChanged(int)
+{
+ on_runReport_clicked();
+}
+
+void MainWindow::on_runReport_clicked()
+{
+ Report report = ui->reports->itemData(ui->reports->currentIndex()).value<Report>();
+ ReportEngine e;
+
+ e.run(report);
+
+ reportResultModel->setQuery(e.query());
+ ui->reportResultView->resizeColumnsToContents();
+}
+
+void MainWindow::on_editReport_clicked()
+{
+ if (!ui->reports->count())
+ return;
+
+ int idx = ui->reports->currentIndex();
+
+ ReportEditorDialog d;
+ d.setReport(ui->reports->itemData(idx).value<Report>());
+
+ if (!d.exec())
+ return;
+
+ MyList::instance()->database()->setReport(d.report());
+
+ ui->reports->setItemData(idx, QVariant::fromValue(d.report()));
+ on_runReport_clicked();
+}
+
+void MainWindow::on_addReport_clicked()
+{
+ ReportEditorDialog d;
+
+ if (!d.exec())
+ return;
+
+ MyList::instance()->database()->addReport(d.report());
+
+ ui->reports->addItem(d.report().name, QVariant::fromValue(d.report()));
+
+ ui->reports->setCurrentIndex(ui->reports->count() - 1);
+}
+
+
+void MainWindow::on_tabWidget_currentChanged(QWidget *arg1)
+{
+ if (arg1 != ui->reportsTab)
+ return;
+
+ if (ui->reports->count())
+ return;
+
+ on_reloadReports_clicked();
+}
namespace LocalMyList {
class MyListModel;
+ class ReportEngine;
}
+
class QLabel;
+class QSqlQueryModel;
class RenameSettingsDialog;
class MyListFilterModel;
void on_filterInput_textChanged(const QString &filter);
void on_filterType_currentIndexChanged(int);
+ // Reports
+ void on_reloadReports_clicked();
+ void on_reports_currentIndexChanged(int index);
+ void on_runReport_clicked();
+ void on_editReport_clicked();
+ void on_addReport_clicked();
+ void on_tabWidget_currentChanged(QWidget *arg1);
+
protected:
void dragEnterEvent(QDragEnterEvent *event);
void dropEvent(QDropEvent *event);
LocalMyList::MyListModel *myListModel;
MyListFilterModel *myListFilterModel;
+
+ QSqlQueryModel *reportResultModel;
};
#endif // MAINWINDOW_H
<string>LocalMyList Management</string>
</property>
<widget class="QWidget" name="centralWidget">
- <layout class="QVBoxLayout" name="verticalLayout">
- <item>
- <layout class="QHBoxLayout" name="horizontalLayout_2">
- <item>
- <widget class="QLineEdit" name="filterInput"/>
- </item>
- <item>
- <widget class="QComboBox" name="filterType"/>
- </item>
- </layout>
- </item>
- <item>
- <widget class="MyListView" name="myListView"/>
- </item>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
<item>
- <layout class="QHBoxLayout" name="horizontalLayout">
- <item>
- <spacer name="horizontalSpacer">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
+ <widget class="QTabWidget" name="tabWidget">
+ <property name="currentIndex">
+ <number>0</number>
+ </property>
+ <property name="documentMode">
+ <bool>true</bool>
+ </property>
+ <widget class="QWidget" name="myListTab">
+ <attribute name="title">
+ <string>MyList</string>
+ </attribute>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>9</number>
</property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
+ <property name="rightMargin">
+ <number>0</number>
</property>
- </spacer>
- </item>
- <item>
- <widget class="QPushButton" name="refreshButton">
- <property name="text">
- <string>Refresh</string>
+ <property name="bottomMargin">
+ <number>0</number>
</property>
- </widget>
- </item>
- </layout>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QLineEdit" name="filterInput"/>
+ </item>
+ <item>
+ <widget class="QComboBox" name="filterType"/>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="MyListView" name="myListView"/>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="refreshButton">
+ <property name="text">
+ <string>Refresh</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="reportsTab">
+ <attribute name="title">
+ <string>Reports</string>
+ </attribute>
+ <layout class="QVBoxLayout" name="verticalLayout_3" stretch="0,1">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Report:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="reports">
+ <property name="minimumSize">
+ <size>
+ <width>300</width>
+ <height>0</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="editReport">
+ <property name="text">
+ <string>Edit...</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="addReport">
+ <property name="text">
+ <string>Add</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="deleteReport">
+ <property name="text">
+ <string>Delete</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="runReport">
+ <property name="text">
+ <string>Run</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="reloadReports">
+ <property name="text">
+ <string>Reload</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QSplitter" name="splitter">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <widget class="QTableView" name="reportResultView"/>
+ <widget class="QPlainTextEdit" name="plainTextEdit"/>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </widget>
</item>
</layout>
</widget>
<header>mylistview.h</header>
</customwidget>
</customwidgets>
- <tabstops>
- <tabstop>filterInput</tabstop>
- <tabstop>filterType</tabstop>
- <tabstop>myListView</tabstop>
- <tabstop>refreshButton</tabstop>
- </tabstops>
<resources/>
<connections/>
</ui>
-QT += core gui
+QT += core gui scripttools
include(../config.pri)
databaseconnectiondialog.cpp \
mylistview.cpp \
renamesettingsdialog.cpp \
- mylistfiltermodel.cpp
+ mylistfiltermodel.cpp \
+ reporteditordialog.cpp
HEADERS += mainwindow.h \
databaseconnectiondialog.h \
mylistview.h \
renamesettingsdialog.h \
- mylistfiltermodel.h
+ mylistfiltermodel.h \
+ reporteditordialog.h
FORMS += mainwindow.ui \
databaseconnectiondialog.ui \
--- /dev/null
+#include "reporteditordialog.h"
+
+#include <QLabel>
+#include <QLineEdit>
+#include <QPlainTextEdit>
+#include <QVBoxLayout>
+#include <QHBoxLayout>
+#include <QDialogButtonBox>
+
+ReportEditorDialog::ReportEditorDialog(QWidget *parent) :
+ QDialog(parent)
+{
+ resize(800, 600);
+ QLabel *nameLabel = new QLabel("Report Name:", this);
+ name = new QLineEdit(this);
+ QHBoxLayout *hLayout = new QHBoxLayout;
+
+ hLayout->addWidget(nameLabel);
+ hLayout->addWidget(name);
+
+ script = new QPlainTextEdit(this);
+
+ buttons = new QDialogButtonBox(QDialogButtonBox::Save | QDialogButtonBox::Cancel | QDialogButtonBox::Reset, Qt::Horizontal, this);
+
+ QVBoxLayout *vLayout = new QVBoxLayout;
+
+ vLayout->addLayout(hLayout);
+ vLayout->addWidget(script);
+ vLayout->addWidget(buttons);
+
+ setLayout(vLayout);
+
+ connect(buttons, SIGNAL(clicked(QAbstractButton*)), this, SLOT(buttonClicked(QAbstractButton*)));
+}
+
+LocalMyList::Report ReportEditorDialog::report() const
+{
+ m_report.name = name->text();
+ m_report.script = script->toPlainText();
+ return m_report;
+}
+
+void ReportEditorDialog::setReport(const LocalMyList::Report &report)
+{
+ m_report = report;
+ name->setText(m_report.name);
+ script->setPlainText(m_report.script);
+}
+
+void ReportEditorDialog::buttonClicked(QAbstractButton *button)
+{
+ switch (buttons->standardButton(button))
+ {
+ case QDialogButtonBox::Save:
+ accept();
+ break;
+ case QDialogButtonBox::Cancel:
+ reject();
+ break;
+ case QDialogButtonBox::Reset:
+ name->setText(m_report.name);
+ script->setPlainText(m_report.script);
+ break;
+ default: ;
+ }
+}
--- /dev/null
+#ifndef REPORTEDITORDIALOG_H
+#define REPORTEDITORDIALOG_H
+
+#include <QDialog>
+
+#include "database.h"
+
+class QAbstractButton;
+class QLineEdit;
+class QDialogButtonBox;
+class QPlainTextEdit;
+
+class ReportEditorDialog : public QDialog
+{
+ Q_OBJECT
+public:
+ explicit ReportEditorDialog(QWidget *parent = 0);
+
+ LocalMyList::Report report() const;
+ void setReport(const LocalMyList::Report &report);
+
+signals:
+
+private slots:
+ void buttonClicked(QAbstractButton *button);
+
+private:
+ mutable LocalMyList::Report m_report;
+
+ QLineEdit *name;
+ QDialogButtonBox *buttons;
+ QPlainTextEdit *script;
+};
+
+#endif // REPORTEDITORDIALOG_H