From: APTX Date: Sat, 6 Jul 2013 10:50:10 +0000 (+0200) Subject: "progress" X-Git-Url: https://gitweb.tyo.aptx.org/?a=commitdiff_plain;h=a706d6df3cb05585384918ecfc26d34ab7aef61e;p=localmylist.git "progress" --- diff --git a/localmylist-management/localmylist-management.pro b/localmylist-management/localmylist-management.pro index 074c587..f3a1948 100644 --- a/localmylist-management/localmylist-management.pro +++ b/localmylist-management/localmylist-management.pro @@ -31,7 +31,8 @@ SOURCES += main.cpp\ fonts.cpp \ aniaddsyntaxhighlighter.cpp \ settingsdialog.cpp \ - codeeditor.cpp + codeeditor.cpp \ + tabs/dynamicmodeltab.cpp HEADERS += mainwindow.h \ databaseconnectiondialog.h \ @@ -53,7 +54,8 @@ HEADERS += mainwindow.h \ fonts.h \ aniaddsyntaxhighlighter.h \ settingsdialog.h \ - codeeditor.h + codeeditor.h \ + tabs/dynamicmodeltab.h FORMS += mainwindow.ui \ databaseconnectiondialog.ui \ @@ -64,7 +66,8 @@ FORMS += mainwindow.ui \ tabs/unknownfilestab.ui \ tabs/pendingrequesttab.ui \ tabs/databaselogtab.ui \ - tabs/clientlogtab.ui + tabs/clientlogtab.ui \ + tabs/dynamicmodeltab.ui include(../localmylist.pri) include(qtsingleapplication/qtsingleapplication.pri) diff --git a/localmylist-management/registertabs.cpp b/localmylist-management/registertabs.cpp index 8e0ea67..bf00af8 100644 --- a/localmylist-management/registertabs.cpp +++ b/localmylist-management/registertabs.cpp @@ -6,6 +6,7 @@ #include "tabs/pendingrequesttab.h" #include "tabs/databaselogtab.h" #include "tabs/clientlogtab.h" +#include "tabs/dynamicmodeltab.h" void registerTabs() { @@ -16,4 +17,5 @@ void registerTabs() TabWidget::registerTab(); TabWidget::registerTab(); TabWidget::registerTab(); + TabWidget::registerTab(); } diff --git a/localmylist-management/tabs/dynamicmodeltab.cpp b/localmylist-management/tabs/dynamicmodeltab.cpp new file mode 100644 index 0000000..40a9026 --- /dev/null +++ b/localmylist-management/tabs/dynamicmodeltab.cpp @@ -0,0 +1,91 @@ +#include "dynamicmodeltab.h" +#include "ui_dynamicmodeltab.h" + +#include "mainwindow.h" +#include "database.h" +#include "mylist.h" +#include "mylistfiltermodel.h" +#include "mylistitemdelegate.h" + +#include "dynamicmodel/model.h" +#include "dynamicmodel/datamodel.h" +#include "dynamicmodel/types.h" + +using namespace LocalMyList::DynamicModel; + +DynamicModelTab::DynamicModelTab(QWidget *parent) : + AbstractTabBase(parent), + ui(new Ui::DynamicModelTab) +{ + ui->setupUi(this); + setLabel(name()); +} + +DynamicModelTab::~DynamicModelTab() +{ + delete ui; +} + +QString DynamicModelTab::staticId() +{ + return "dynamic_model"; +} + +QString DynamicModelTab::name() +{ + return tr("Dynamic Model"); +} + +void DynamicModelTab::init() +{ + dataModel = new DataModel(this); + dataModel->registerDataType(new AnimeType); + + model = new Model(this); + model->setDataModel(dataModel); + +// myListFilterModel = new MyListFilterModel(this); +// myListFilterModel->setSourceModel(model); + ui->myListView->setModel(model /*myListFilterModel*/); + ui->myListView->setItemDelegate(new MyListItemDelegate(ui->myListView)); +/* +#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) + ui->myListView->header()->setSectionResizeMode(0, QHeaderView::Stretch); +#else + ui->myListView->header()->setResizeMode(0, QHeaderView::Stretch); +#endif + ui->myListView->header()->setStretchLastSection(false); + ui->myListView->header()->resizeSection(4, 200); +*/ + ui->filterType->addItems(QStringList() + << tr("Fixed String") + << tr("Wildcard") + << tr("Regexp")); + + connect(ui->myListView, SIGNAL(renameTest(int)), mainWindow(), SLOT(openRenameScriptEditor(int))); + connect(ui->myListView->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(currentSelectionChanged(QModelIndex,QModelIndex))); + connect(ui->filterInput, SIGNAL(textChanged(QString)), this, SLOT(currentSelectionChanged())); + +} + +void DynamicModelTab::activate() +{ + ui->filterInput->setFocus(); +} + +void DynamicModelTab::reload() +{ + model->reload(); +} + +void DynamicModelTab::changeEvent(QEvent *e) +{ + QWidget::changeEvent(e); + switch (e->type()) { + case QEvent::LanguageChange: + ui->retranslateUi(this); + break; + default: + break; + } +} diff --git a/localmylist-management/tabs/dynamicmodeltab.h b/localmylist-management/tabs/dynamicmodeltab.h new file mode 100644 index 0000000..2c8703e --- /dev/null +++ b/localmylist-management/tabs/dynamicmodeltab.h @@ -0,0 +1,46 @@ +#ifndef DYNAMICMODELTAB_H +#define DYNAMICMODELTAB_H + +#include "abstracttab.h" + +class MyListFilterModel; + +namespace LocalMyList { +namespace DynamicModel { +class DataModel; +class Model; +} +} + +namespace Ui { +class DynamicModelTab; +} + +class DynamicModelTab : public AbstractTabBase +{ + Q_OBJECT + +public: + explicit DynamicModelTab(QWidget *parent = 0); + ~DynamicModelTab(); + + static QString staticId(); + static QString name(); + + void init(); + void activate(); + + void reload(); + +protected: + void changeEvent(QEvent *e); + +private: + Ui::DynamicModelTab *ui; + + MyListFilterModel *myListFilterModel; + LocalMyList::DynamicModel::DataModel *dataModel; + LocalMyList::DynamicModel::Model *model; +}; + +#endif // DYNAMICMODELTAB_H diff --git a/localmylist-management/tabs/dynamicmodeltab.ui b/localmylist-management/tabs/dynamicmodeltab.ui new file mode 100644 index 0000000..7cd03c6 --- /dev/null +++ b/localmylist-management/tabs/dynamicmodeltab.ui @@ -0,0 +1,52 @@ + + + DynamicModelTab + + + + 0 + 0 + 400 + 300 + + + + Form + + + + 0 + + + 0 + + + + + + + + + + + + + + + + + + + FilterLineEdit + QLineEdit +
filterlineedit.h
+
+ + MyListView + QTreeView +
mylistview.h
+
+
+ + +
diff --git a/localmylist/dynamicmodel/data.cpp b/localmylist/dynamicmodel/data.cpp index 4baf303..47c1bc8 100644 --- a/localmylist/dynamicmodel/data.cpp +++ b/localmylist/dynamicmodel/data.cpp @@ -3,9 +3,29 @@ #include "node.h" #include "datatype.h" +#include + namespace LocalMyList { namespace DynamicModel { +QString stateIdToState(int id) +{ + switch (id) + { + case -1: + return QObject::tr("Mixed"); + case 0: + return QObject::tr("Unknown"); + case 1: + return QObject::tr("On HDD"); + case 2: + return QObject::tr("On Cd"); + case 3: + return QObject::tr("Deleted"); + } + return QString(); +} + Data::Data(DataType *dataType) : m_type(dataType) { } @@ -49,5 +69,71 @@ void Data::updated() } } +AnimeData::AnimeData(DataType *dataType) : Data(dataType) +{ +} + +int AnimeData::id() const +{ + return animeData.aid; +} + +QVariant AnimeData::data(int column, int role) const +{ + switch (role) + { + case Qt::DisplayRole: + switch (column) + { + case 0: + return animeData.titleRomaji; + case 1: + if (animeData.totalEpisodeCount) + return QString("%1 of %2") + .arg(episodesInMyList).arg(animeData.totalEpisodeCount); + return QString("%1 of (%2)") + .arg(episodesInMyList) + .arg(qMax(animeData.highestEpno, + episodesInMyList)); + case 2: + if (animeData.rating < 1) + return "n/a"; + return QString::number(animeData.rating, 'f', 2); + case 3: + if (animeData.myVote < 1) + return "n/a"; + return QString::number(animeData.myVote, 'f', 2); + case 4: + return QString("%1 of %2").arg(watchedEpisodes) + .arg(episodesInMyList); + case 5: + return stateIdToState(myState); + } + break; + case Qt::ToolTipRole: + switch (column) + { + case 0: + if (!animeData.titleEnglish.isEmpty() && !animeData.titleKanji.isEmpty()) + return QString("%1 -- %2").arg(animeData.titleEnglish) + .arg(animeData.titleKanji); + if (!animeData.titleEnglish.isEmpty()) + return animeData.titleEnglish; + if (!animeData.titleKanji.isEmpty()) + return animeData.titleKanji; + } + break; + case Qt::EditRole: + switch (column) + { + case 3: + return animeData.myVote; + } + break; + } + + return QVariant(); +} + } // namespace DynamicModel } // namespace LocalMyList diff --git a/localmylist/dynamicmodel/data.h b/localmylist/dynamicmodel/data.h index cd58619..54692b4 100644 --- a/localmylist/dynamicmodel/data.h +++ b/localmylist/dynamicmodel/data.h @@ -1,6 +1,8 @@ #ifndef DATA_H #define DATA_H +#include "../localmylist_global.h" + #include #include @@ -11,8 +13,9 @@ namespace DynamicModel { class DataType; class Node; +typedef QList NodeList; -class Data +class LOCALMYLISTSHARED_EXPORT Data { public: Data(DataType *dataType); @@ -29,21 +32,22 @@ public: void updated(); private: - QList references; + NodeList references; DataType * const m_type; }; -class AnimeData : public Data +class LOCALMYLISTSHARED_EXPORT AnimeData : public Data { public: AnimeData(DataType *dataType); int id() const; - QVariant data(int row, int role) const; + QVariant data(int column, int role) const; Anime animeData; int episodesInMyList; int watchedEpisodes; + int myState; }; } // namespace DynamicModel diff --git a/localmylist/dynamicmodel/datamanager.cpp b/localmylist/dynamicmodel/datamanager.cpp deleted file mode 100644 index ff67d4c..0000000 --- a/localmylist/dynamicmodel/datamanager.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include "datamanager.h" - -#include "datatype.h" - -namespace LocalMyList { -namespace DynamicModel { - -DataManager::DataManager(QObject *parent) : QObject(parent) -{ -} - -DataManager::~DataManager() -{ - qDeleteAll(dataTypes); -} - -bool DataManager::registerDataType(DataType *dataType) -{ - if (dataTypes.contains(dataType)) - return true; - - if (dataTypeNames.contains(dataType->name())) - return false; - - dataTypes.insert(dataType); - dataTypeNames.insert(dataType->name(), dataType); - return true; -} - -DataType *DataManager::dataType(const QString &name) const -{ - return dataTypeNames.value(name, 0); -} - -} // namespace DynamicModel -} // namespace LocalMyList diff --git a/localmylist/dynamicmodel/datamodel.cpp b/localmylist/dynamicmodel/datamodel.cpp new file mode 100644 index 0000000..67e8b52 --- /dev/null +++ b/localmylist/dynamicmodel/datamodel.cpp @@ -0,0 +1,77 @@ +#include "datamodel.h" + +#include "datatype.h" +#include "typerelation.h" + +namespace LocalMyList { +namespace DynamicModel { + +DataModel::DataModel(QObject *parent) : QObject(parent) +{ +} + +DataModel::~DataModel() +{ + qDeleteAll(dataTypes); +} + +bool DataModel::registerDataType(DataType *dataType) +{ + if (dataTypes.contains(dataType)) + return true; + + if (dataTypeNames.contains(dataType->name())) + return false; + + dataTypes.insert(dataType); + dataTypeNames.insert(dataType->name(), dataType); + return true; +} + +bool DataModel::registerTypeRelation(TypeRelation *typeRelation) +{ + Q_ASSERT(typeRelation); + + if (!typeRelation->sourceType().isEmpty() && !dataTypeNames.contains(typeRelation->sourceType())) + return false; + + if (!dataTypeNames.contains(typeRelation->destinationType())) + return false; + + auto it = typeRelations.find(typeRelation->sourceType()); + + if (it == typeRelations.end()) + it = typeRelations.insert(typeRelation->sourceType(), QHash()); + + auto inner = it.value().find(typeRelation->destinationType()); + if (inner != it.value().end()) + return false; + + it.value().insert(typeRelation->destinationType(), typeRelation); + return true; +} + +DataType *DataModel::dataType(const QString &name) const +{ + DataType *t = dataTypeNames.value(name, 0); + Q_ASSERT(t); + return t; +} + +TypeRelation *DataModel::typeRelation(const QString &source, const QString &destiantion) +{ + const auto it = typeRelations.find(source); + + if (it == typeRelations.constEnd()) + return 0; + + const auto inner = it.value().find(destiantion); + + if (inner == it.value().constEnd()) + return 0; + + return inner.value(); +} + +} // namespace DynamicModel +} // namespace LocalMyList diff --git a/localmylist/dynamicmodel/datamanager.h b/localmylist/dynamicmodel/datamodel.h similarity index 61% rename from localmylist/dynamicmodel/datamanager.h rename to localmylist/dynamicmodel/datamodel.h index 7e96640..8f589ac 100644 --- a/localmylist/dynamicmodel/datamanager.h +++ b/localmylist/dynamicmodel/datamodel.h @@ -1,7 +1,10 @@ -#ifndef DATAMANAGER_H -#define DATAMANAGER_H +#ifndef DATAMODEL_H +#define DATAMODEL_H +#include +#include "../localmylist_global.h" #include "dynamicmodel_global.h" +#include "node.h" #include #include @@ -11,18 +14,23 @@ namespace LocalMyList { namespace DynamicModel { class DataType; +class TypeRelation; -class DataManager : public QObject +class LOCALMYLISTSHARED_EXPORT DataModel : public QObject { Q_OBJECT public: - DataManager(QObject *parent = 0); - ~DataManager(); + DataModel(QObject *parent = 0); + ~DataModel(); bool registerDataType(DataType *dataType); + bool registerTypeRelation(TypeRelation *typeRelation); DataType *dataType(const QString &name) const; + TypeRelation *typeRelation(const QString &source, const QString &destiantion); + + private slots: /* void animeUpdate(int aid); @@ -38,9 +46,11 @@ private slots: private: QHash dataTypeNames; QSet dataTypes; + + QHash > typeRelations; }; } // namespace DynamicModel } // namespace LocalMyList -#endif // DATAMANAGER_H +#endif // DATAMODEL_H diff --git a/localmylist/dynamicmodel/datatype.cpp b/localmylist/dynamicmodel/datatype.cpp index c069d78..19966a6 100644 --- a/localmylist/dynamicmodel/datatype.cpp +++ b/localmylist/dynamicmodel/datatype.cpp @@ -7,8 +7,14 @@ namespace LocalMyList { namespace DynamicModel { -DataType::DataType(QObject *parent) : QObject(parent) +DataType::DataType(QObject *parent) : QObject(parent), m_size(0) { + query = new SqlAsyncQuery(this); +} + +DataType::~DataType() +{ + } QStringList DataType::availableChildRelations() const diff --git a/localmylist/dynamicmodel/datatype.h b/localmylist/dynamicmodel/datatype.h index cea939c..575cd41 100644 --- a/localmylist/dynamicmodel/datatype.h +++ b/localmylist/dynamicmodel/datatype.h @@ -1,7 +1,9 @@ #ifndef ABSTRACTDATATYPE_H #define ABSTRACTDATATYPE_H -#include "datamanager.h" +#include "../localmylist_global.h" +#include "datamodel.h" +#include "../sqlasyncquery.h" #include #include @@ -14,11 +16,12 @@ class Node; typedef bool (*NodeCompare)(Node *a, Node *b); -class DataType : public QObject +class LOCALMYLISTSHARED_EXPORT DataType : public QObject { Q_OBJECT public: DataType(QObject *parent = 0); + virtual ~DataType(); virtual QString name() const = 0; virtual QStringList availableChildRelations() const; @@ -31,7 +34,7 @@ public: // Acquire virtual bool canGetChildren(const QString &childTypeName) const; - virtual void getChildren(const Data *parent, const QString &childTypeName, int offset) = 0; + virtual NodeList getChildren(Model *model, Node *parent, const QString &childTypeName, int offset) = 0; // Update virtual void update(Data *data); @@ -42,6 +45,11 @@ public: virtual NodeCompare nodeCompareFunction() const = 0; +protected: + SqlAsyncQuery *query; + mutable int m_size; + + static const int LIMIT = 400; private: QHash m_dataStore; }; diff --git a/localmylist/dynamicmodel/model.cpp b/localmylist/dynamicmodel/model.cpp index 711182c..953f4c9 100644 --- a/localmylist/dynamicmodel/model.cpp +++ b/localmylist/dynamicmodel/model.cpp @@ -1,13 +1,15 @@ #include "model.h" #include "node.h" +#include "datamodel.h" namespace LocalMyList { namespace DynamicModel { Model::Model(QObject *parent) : - QAbstractItemModel(parent) + QAbstractItemModel(parent), m_dataModel(0) { + rootItem = createRootNode(); } Model::~Model() @@ -141,14 +143,43 @@ QModelIndex Model::index(Node *node) const return createIndex(node->row(), 0, node); } +DataModel *Model::dataModel() const +{ + return m_dataModel; +} + +DataType *Model::rootDataType() const +{ + return m_dataModel->dataType("anime"); +} + void Model::reload() { beginResetModel(); delete rootItem; - rootItem = new Node(this, 0, 0, 0); + rootItem = createRootNode(); endResetModel(); } +void Model::setDataModel(DataModel *dataModel) +{ + if (m_dataModel == dataModel) + return; + + m_dataModel = dataModel; + emit dataModelChanged(dataModel); + + reload(); +} + +Node *Model::createRootNode() +{ + Node *n = new Node(this, 0, 0, 0); + if (m_dataModel) + n->setChildDataType(m_dataModel->dataType("anime")); + return n; +} + } // namespace DynamicModel } // namespace Local diff --git a/localmylist/dynamicmodel/model.h b/localmylist/dynamicmodel/model.h index 9305014..a9c8ba8 100644 --- a/localmylist/dynamicmodel/model.h +++ b/localmylist/dynamicmodel/model.h @@ -1,16 +1,21 @@ #ifndef MODEL_H #define MODEL_H +#include "../localmylist_global.h" #include namespace LocalMyList { namespace DynamicModel { class Node; +class DataModel; +class DataType; -class Model : public QAbstractItemModel +class LOCALMYLISTSHARED_EXPORT Model : public QAbstractItemModel { Q_OBJECT + Q_PROPERTY(DataModel* dataModel READ dataModel WRITE setDataModel NOTIFY dataModelChanged) + friend class Node; public: @@ -34,11 +39,23 @@ public: Node *node(const QModelIndex &idx) const; QModelIndex index(Node *node) const; + DataModel *dataModel() const; + + DataType *rootDataType() const; + public slots: void reload(); + void setDataModel(DataModel *dataModel); + +signals: + void dataModelChanged(DataModel *dataModel); + private: + Node *createRootNode(); + Node *rootItem; + DataModel* m_dataModel; }; } // namespace DynamicModel diff --git a/localmylist/dynamicmodel/node.cpp b/localmylist/dynamicmodel/node.cpp index 146d37d..996afc9 100644 --- a/localmylist/dynamicmodel/node.cpp +++ b/localmylist/dynamicmodel/node.cpp @@ -13,17 +13,35 @@ namespace DynamicModel { Node::Node(Model *model, Node *parent, int totalRowCount, Data *data) : m_model(model), m_parent(parent), m_totalRowCount(totalRowCount), - m_data(data) + m_data(data), m_childType(0) { + Q_ASSERT_X((parent && data) || (!parent && !data), "dynamic model", "Root node has no data and no parent. Other nodes must have both"); + + if (!data) + return; m_data->ref(this); } Node::~Node() { + if (!m_data) + return; + m_data->deref(this); qDeleteAll(m_children); } +DataType *Node::childDataType() const +{ + return m_childType; +} + +void Node::setChildDataType(DataType *dataType) +{ + Q_ASSERT_X(dataType, "dynamicmodel", "NULL data type"); + m_childType = dataType; +} + Node *Node::parent() const { return m_parent; @@ -54,11 +72,14 @@ int Node::row() const bool Node::hasChildren() const { + if (this == m_model->rootItem) + return true; return totalRowCount() > 0; } QVariant Node::data(int column, int role) const { + qDebug() << parent() << column; if (parent()) return m_data->data(column, role); @@ -89,11 +110,14 @@ Data *Node::data() const int Node::totalRowCount() const { - return m_totalRowCount; + return m_totalRowCount ? m_totalRowCount : childDataType() ? childDataType()->size() : 0; } bool Node::canFetchMore() const { + if (!m_parent && !totalRowCount()) + return true; + if (childCount() < totalRowCount()) return true; return false; @@ -101,7 +125,28 @@ bool Node::canFetchMore() const void Node::fetchMore() { - m_data->type()->getChildren(m_data, m_childType->name(), childCount()); + if (!m_childType) + return; + qDebug() << "fetchMote" << this; + NodeList newItems; + if (m_data) + newItems = data()->type()->getChildren(m_model, this, m_childType->name(), childCount()); + else + newItems = m_model->rootDataType()->getChildren(m_model, this, m_childType->name(), childCount()); + + const QModelIndex parent = m_model->index(this); + const int newrows = newItems.count(); + + if (!newrows) + return; + + qDebug() << parent << m_model->rowCount(parent) << m_model->rowCount(parent) + newrows - 1; + m_model->beginInsertRows(parent, m_model->rowCount(parent), m_model->rowCount(parent) + newrows - 1); + while (newItems.count()) + m_children << newItems.takeFirst(); + m_model->endInsertRows(); + + qDebug() << m_children.count(); qDebug() << m_model->rowCount(); } void Node::fetchComplete() diff --git a/localmylist/dynamicmodel/node.h b/localmylist/dynamicmodel/node.h index ddf295b..ee6b6ff 100644 --- a/localmylist/dynamicmodel/node.h +++ b/localmylist/dynamicmodel/node.h @@ -1,9 +1,11 @@ #ifndef NODE_H #define NODE_H +#include "../localmylist_global.h" #include "dynamicmodel_global.h" #include +#include namespace LocalMyList { namespace DynamicModel { @@ -12,11 +14,17 @@ class Model; class Data; class DataType; -class Node { +class Node; +typedef QList NodeList; + +class LOCALMYLISTSHARED_EXPORT Node { public: Node(Model *model, Node *parent, int totalRowCount, Data *data); ~Node(); + DataType *childDataType() const; + void setChildDataType(DataType *dataType); + // Structure Node *parent() const; Node *child(int row) const; @@ -42,7 +50,7 @@ public: protected: Node *m_parent; - QList m_children; + NodeList m_children; int m_totalRowCount; Model *m_model; diff --git a/localmylist/dynamicmodel/typerelation.cpp b/localmylist/dynamicmodel/typerelation.cpp new file mode 100644 index 0000000..3591b5e --- /dev/null +++ b/localmylist/dynamicmodel/typerelation.cpp @@ -0,0 +1,84 @@ +#include "typerelation.h" + +#include "../mylist.h" +#include "../database.h" +#include "../databaseclasses.h" +#include "node.h" +#include "datatype.h" +#include "data.h" +#include "types.h" + +namespace LocalMyList { +namespace DynamicModel { + +TypeRelation::TypeRelation(QObject *parent) : QObject(parent) +{ +} + +Node *TypeRelation::createNode(Model *model, Node *parent, int totalRowCount, Data *data) +{ + return new Node(model, parent, totalRowCount, data); +} + +QString RootAnimeRelation::sourceType() const +{ + return QString(); +} + +QString RootAnimeRelation::destinationType() const +{ + return "anime"; +} + +bool RootAnimeRelation::canGetChildren() const +{ + return false; +} + +NodeList RootAnimeRelation::getChildren(Model *model, Node *parent, int offset) +{ +/* QSqlQuery q = MyList::instance()->database()->prepareOneShot(QString( + "%1 " + "ORDER BY title_romaji ASC " + "LIMIT :limit " + "OFFSET :offset ") + .arg(parent->childDataType()->baseQuery())); + q.bindValue(":limit", 200); + q.bindValue(":offset", offset); + + if (!q.exec()) + return NodeList(); + + NodeList newItems; + while (q.next()) + { + AnimeData *ad = new AnimeData(this); + int totalRowCount = query->value(0).toInt(); + + { + QSqlResultIterator it(q); + fillAnimeData(*ad, it); + } + + auto it = cache.find(ad->id()); + if (it != cache.end()) + { + delete ad; + ad = *it; + } + else + { + cache.insert(ad->id(), ad); + } + + auto node = new Node(model, parent, totalRowCount, ad); + newItems << node; + } + + return newItems; +*/ + return NodeList(); +} + +} // namespace DynamicModel +} // namespace LocalMyList diff --git a/localmylist/dynamicmodel/typerelation.h b/localmylist/dynamicmodel/typerelation.h new file mode 100644 index 0000000..68e1be2 --- /dev/null +++ b/localmylist/dynamicmodel/typerelation.h @@ -0,0 +1,45 @@ +#ifndef TYPERELATION_H +#define TYPERELATION_H + +#include + +#include +#include "node.h" +#include "dynamicmodel_global.h" + +namespace LocalMyList { +namespace DynamicModel { + +class TypeRelation : public QObject +{ +public: + TypeRelation(QObject *parent = 0); + + virtual QString sourceType() const = 0; + virtual QString destinationType() const = 0; + + // Acquire + virtual bool canGetChildren() const = 0; + virtual NodeList getChildren(Model *model, Node *parent, const QString &childTypeName, int offset) = 0; + + +protected: + Node *createNode(Model *model, Node *parent, int totalRowCount, Data *data); +}; + +// ========================================================================================================= + +class RootAnimeRelation +{ + QString sourceType() const; + QString destinationType() const; + + // Acquire + bool canGetChildren() const; + NodeList getChildren(Model *model, Node *parent, int offset); +}; + +} // namespace DynamicModel +} // namespace LocalMyList + +#endif // TYPERELATION_H diff --git a/localmylist/dynamicmodel/types.cpp b/localmylist/dynamicmodel/types.cpp index 5ca5b78..6ed95e2 100644 --- a/localmylist/dynamicmodel/types.cpp +++ b/localmylist/dynamicmodel/types.cpp @@ -1,7 +1,152 @@ #include "types.h" +#include "../database.h" +#include "../mylist.h" + namespace LocalMyList { namespace DynamicModel { +QString AnimeType::name() const +{ + return "anime"; +} + +QStringList AnimeType::availableChildRelations() const +{ + return QStringList(); +} + +QString AnimeType::baseQuery() const +{ + return QString( + "SELECT (SELECT COUNT(eid) FROM episode WHERE aid = a.aid), " + " (SELECT COUNT(e.eid) " + " FROM episode e " + " WHERE e.aid = a.aid), " + " (SELECT COUNT(DISTINCT eid) " + " FROM " + " (SELECT e.eid FROM episode e " + " JOIN file f ON (f.eid = e.eid) " + " WHERE e.aid = a.aid " + " AND f.my_watched IS NOT NULL " + " UNION " + " SELECT e.eid FROM episode e " + " JOIN file_episode_rel fer ON fer.eid = e.eid " + " JOIN file f ON f.fid = fer.fid " + " WHERE e.aid = a.aid " + " AND f.my_watched IS NOT NULL) sq), " + " (SELECT CASE WHEN array_length(my_state_array, 1) > 1 THEN -1 ELSE my_state_array[1] END " + " FROM " + " (SELECT array_agg(my_state) my_state_array " + " FROM " + " (SELECT my_state " + " FROM file " + " WHERE aid = a.aid " + " UNION " + " SELECT f.my_state " + " FROM file f " + " JOIN file_episode_rel fer ON (fer.fid = f.eid) " + " JOIN episode e ON (e.eid = fer.eid AND e.aid = a.aid) " + " ) AS sq) AS sq) AS my_state, " + " %1 " + " FROM anime a ") + .arg(Database::animeFields()); +} + +int AnimeType::size() const +{ + if (m_size) + return m_size; + + QSqlQuery &q = MyList::instance()->database()->prepare( + "SELECT count(aid) FROM anime"); + + if (!MyList::instance()->database()->exec(q)) + return 0; + + if (!q.next()) + return 0; + + m_size = q.value(0).toInt(); + q.finish(); + + return m_size; +} + +bool AnimeType::canGetChildren(const QString &childTypeName) const +{ + Q_UNUSED(childTypeName) + return false; +} + +NodeList AnimeType::getChildren(Model *model, Node *parent, const QString &childTypeName, int offset) +{ + QSqlQuery q = MyList::instance()->database()->prepareOneShot(QString( + "%1 " + "ORDER BY title_romaji ASC " + "LIMIT :limit " + "OFFSET :offset ") + .arg(baseQuery())); + q.bindValue(":limit", LIMIT); + q.bindValue(":offset", offset); + + if (!q.exec()) + return NodeList(); + + NodeList newItems; + while (q.next()) + { + AnimeData *ad = new AnimeData(this); + int totalRowCount = query->value(0).toInt(); + + { + QSqlResultIterator it(q); + fillAnimeData(*ad, it); + } + + auto it = cache.find(ad->id()); + if (it != cache.end()) + { + delete ad; + ad = *it; + } + else + { + cache.insert(ad->id(), ad); + } + + auto node = new Node(model, parent, totalRowCount, ad); + newItems << node; + } + + return newItems; +} + +void AnimeType::update(Data *data) +{ + +} + +void AnimeType::childUpdate(Data *parentData, const Data *oldData, const Data *newData, Operation operation) +{ + +} + +NodeCompare AnimeType::nodeCompareFunction() const +{ + return [](Node *a, Node *b) -> bool + { + return a < b; + }; +} + +void AnimeType::fillAnimeData(AnimeData &data, SqlResultIteratorInterface &query) +{ + data.episodesInMyList = query.value(1).toInt(); + data.watchedEpisodes = query.value(2).toInt(); + data.myState = query.value(3).toInt(); + Database::readAnimeData(query, data.animeData, 4); +} + } // namespace DynamicModel } // namespace LocalMyList diff --git a/localmylist/dynamicmodel/types.h b/localmylist/dynamicmodel/types.h index 147f89a..7b29476 100644 --- a/localmylist/dynamicmodel/types.h +++ b/localmylist/dynamicmodel/types.h @@ -1,9 +1,35 @@ #ifndef TYPES_H #define TYPES_H +#include "../localmylist_global.h" +#include "datatype.h" +#include "data.h" + namespace LocalMyList { namespace DynamicModel { +class LOCALMYLISTSHARED_EXPORT AnimeType : public DataType +{ + QString name() const; + QStringList availableChildRelations() const; + + QString baseQuery() const; + + int size() const; + + bool canGetChildren(const QString &childTypeName) const; + NodeList getChildren(Model *model, Node *parent, const QString &childTypeName, int offset); + + void update(Data *data); + void childUpdate(Data *parentData, const Data *oldData, const Data *newData, Operation operation); + + NodeCompare nodeCompareFunction() const; + +private: + void fillAnimeData(AnimeData &data, SqlResultIteratorInterface &query); + QMap cache; +}; + } // namespace DynamicModel } // namespace LocalMyList diff --git a/localmylist/localmylist.pro b/localmylist/localmylist.pro index 423a15d..98e4063 100644 --- a/localmylist/localmylist.pro +++ b/localmylist/localmylist.pro @@ -34,12 +34,13 @@ SOURCES += \ filelocationchecktask.cpp \ messagehandler.cpp \ asyncquerytask.cpp \ - dynamicmodel/datamanager.cpp \ dynamicmodel/data.cpp \ dynamicmodel/node.cpp \ dynamicmodel/model.cpp \ dynamicmodel/datatype.cpp \ - dynamicmodel/types.cpp + dynamicmodel/types.cpp \ + dynamicmodel/datamodel.cpp \ + dynamicmodel/typerelation.cpp HEADERS += \ localmylist_global.h \ @@ -65,14 +66,17 @@ HEADERS += \ sqlasyncquery.h \ sqlasyncqueryinternal.h \ asyncquerytask.h \ + filelocationchecktask.h \ sqlresultiteratorinterface.h \ - dynamicmodel/datamanager.h \ dynamicmodel/data.h \ dynamicmodel/node.h \ dynamicmodel/model.h \ dynamicmodel/datatype.h \ dynamicmodel/dynamicmodel_global.h \ - dynamicmodel/types.h + dynamicmodel/types.h \ + dynamicmodel/datamodel.h \ + dynamicmodel/typerelation.h + CONV_HEADERS += \ include/LocalMyList/AbstractTask \ include/LocalMyList/AddFileTask \