]> Some of my projects - localmylist.git/commitdiff
"progress"
authorAPTX <marek321@gmail.com>
Sat, 6 Jul 2013 10:50:10 +0000 (12:50 +0200)
committerAPTX <marek321@gmail.com>
Sat, 6 Jul 2013 23:41:07 +0000 (01:41 +0200)
21 files changed:
localmylist-management/localmylist-management.pro
localmylist-management/registertabs.cpp
localmylist-management/tabs/dynamicmodeltab.cpp [new file with mode: 0644]
localmylist-management/tabs/dynamicmodeltab.h [new file with mode: 0644]
localmylist-management/tabs/dynamicmodeltab.ui [new file with mode: 0644]
localmylist/dynamicmodel/data.cpp
localmylist/dynamicmodel/data.h
localmylist/dynamicmodel/datamanager.cpp [deleted file]
localmylist/dynamicmodel/datamodel.cpp [new file with mode: 0644]
localmylist/dynamicmodel/datamodel.h [moved from localmylist/dynamicmodel/datamanager.h with 61% similarity]
localmylist/dynamicmodel/datatype.cpp
localmylist/dynamicmodel/datatype.h
localmylist/dynamicmodel/model.cpp
localmylist/dynamicmodel/model.h
localmylist/dynamicmodel/node.cpp
localmylist/dynamicmodel/node.h
localmylist/dynamicmodel/typerelation.cpp [new file with mode: 0644]
localmylist/dynamicmodel/typerelation.h [new file with mode: 0644]
localmylist/dynamicmodel/types.cpp
localmylist/dynamicmodel/types.h
localmylist/localmylist.pro

index 074c58771e749322482c7a64ba4ac00cdd051fe4..f3a1948ebf9dd88be3696a02b917ab7d732db94b 100644 (file)
@@ -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)
index 8e0ea67fddb7440da06e5d80e2e3b667833eebcd..bf00af856945274dc42a57f6d58c2c15cea3a88a 100644 (file)
@@ -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<PendingRequestTab>();
        TabWidget::registerTab<DatabaseLogTab>();
        TabWidget::registerTab<ClientLogTab>();
+       TabWidget::registerTab<DynamicModelTab>();
 }
diff --git a/localmylist-management/tabs/dynamicmodeltab.cpp b/localmylist-management/tabs/dynamicmodeltab.cpp
new file mode 100644 (file)
index 0000000..40a9026
--- /dev/null
@@ -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 (file)
index 0000000..2c8703e
--- /dev/null
@@ -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<DynamicModelTab>
+{
+       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 (file)
index 0000000..7cd03c6
--- /dev/null
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>DynamicModelTab</class>
+ <widget class="QWidget" name="DynamicModelTab">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>400</width>
+    <height>300</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <property name="leftMargin">
+    <number>0</number>
+   </property>
+   <property name="rightMargin">
+    <number>0</number>
+   </property>
+   <item>
+    <layout class="QHBoxLayout" name="filterLayout">
+     <item>
+      <widget class="FilterLineEdit" name="filterInput"/>
+     </item>
+     <item>
+      <widget class="QComboBox" name="filterType"/>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <widget class="MyListView" name="myListView"/>
+   </item>
+  </layout>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>FilterLineEdit</class>
+   <extends>QLineEdit</extends>
+   <header>filterlineedit.h</header>
+  </customwidget>
+  <customwidget>
+   <class>MyListView</class>
+   <extends>QTreeView</extends>
+   <header>mylistview.h</header>
+  </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
index 4baf303b265bee32a4aaa2ebb71705899b31870a..47c1bc896ff1829d2c8d360b5731828bc1b6ae3f 100644 (file)
@@ -3,9 +3,29 @@
 #include "node.h"
 #include "datatype.h"
 
+#include <QDebug>
+
 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
index cd586196454e9783293b10f432dc5ce52f4a0ca1..54692b471683cbb26fb949ff6c5756c4013228a6 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef DATA_H
 #define DATA_H
 
+#include "../localmylist_global.h"
+
 #include <QList>
 #include <QVariant>
 
@@ -11,8 +13,9 @@ namespace DynamicModel {
 
 class DataType;
 class Node;
+typedef QList<Node *> NodeList;
 
-class Data
+class LOCALMYLISTSHARED_EXPORT Data
 {
 public:
        Data(DataType *dataType);
@@ -29,21 +32,22 @@ public:
        void updated();
 
 private:
-       QList<Node *> 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 (file)
index ff67d4c..0000000
+++ /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 (file)
index 0000000..67e8b52
--- /dev/null
@@ -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<QString, TypeRelation *>());
+
+       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
similarity index 61%
rename from localmylist/dynamicmodel/datamanager.h
rename to localmylist/dynamicmodel/datamodel.h
index 7e966403773b589c34ff846be645e410c091d1f3..8f589ac4cabdca646292c9e6ee35e17ca2212992 100644 (file)
@@ -1,7 +1,10 @@
-#ifndef DATAMANAGER_H
-#define DATAMANAGER_H
+#ifndef DATAMODEL_H
+#define DATAMODEL_H
 
+#include <functional>
+#include "../localmylist_global.h"
 #include "dynamicmodel_global.h"
+#include "node.h"
 
 #include <QObject>
 #include <QSet>
@@ -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<QString, DataType *> dataTypeNames;
        QSet<DataType *> dataTypes;
+
+       QHash<QString, QHash<QString, TypeRelation *> > typeRelations;
 };
 
 } // namespace DynamicModel
 } // namespace LocalMyList
 
-#endif // DATAMANAGER_H
+#endif // DATAMODEL_H
index c069d7867c582b8d73c6439b167ee73fbaa820f6..19966a6a3eb415a278cbf6b7e8168070c87b99ee 100644 (file)
@@ -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
index cea939cb2211cd499853d965892fa9c57e3a67e3..575cd41f43a91c5f583a3193e88a9a931c0f2f2b 100644 (file)
@@ -1,7 +1,9 @@
 #ifndef ABSTRACTDATATYPE_H
 #define ABSTRACTDATATYPE_H
 
-#include "datamanager.h"
+#include "../localmylist_global.h"
+#include "datamodel.h"
+#include "../sqlasyncquery.h"
 
 #include <QObject>
 #include <QString>
@@ -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<int, Data *> m_dataStore;
 };
index 711182c6df4006685d98cfd45ea63e45b91d9edd..953f4c9c1826e8c88fb752548ed81147b065cef6 100644 (file)
@@ -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
index 93050147bc9a781a3d4d2219f42abb3e9f7320c5..a9c8ba8c6f13d0c23060e72f692b3057e3fef1c4 100644 (file)
@@ -1,16 +1,21 @@
 #ifndef MODEL_H
 #define MODEL_H
 
+#include "../localmylist_global.h"
 #include <QAbstractItemModel>
 
 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
index 146d37d01aa2d0c62216b74018312156178bdad0..996afc94470047428b9d8886364d67bc8c0bd36d 100644 (file)
@@ -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()
index ddf295b618078c112026ec7787701a24cf23053a..ee6b6ff4f919916d0524e9fc9efddcdad17741db 100644 (file)
@@ -1,9 +1,11 @@
 #ifndef NODE_H
 #define NODE_H
 
+#include "../localmylist_global.h"
 #include "dynamicmodel_global.h"
 
 #include <QVariant>
+#include <QList>
 
 namespace LocalMyList {
 namespace DynamicModel {
@@ -12,11 +14,17 @@ class Model;
 class Data;
 class DataType;
 
-class Node {
+class Node;
+typedef QList<Node *> 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<Node *> 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 (file)
index 0000000..3591b5e
--- /dev/null
@@ -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 (file)
index 0000000..68e1be2
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef TYPERELATION_H
+#define TYPERELATION_H
+
+#include <QObject>
+
+#include <QString>
+#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
index 5ca5b7889cd8a231a80a66909dd4d7f12405e5d4..6ed95e24ce18ab029182369c2e32a4d5fd95038c 100644 (file)
@@ -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
index 147f89a72ac2c9418c6da1d103a04f7291404999..7b294762b20309c9fb0a087f55f0206d84c1cb95 100644 (file)
@@ -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<int, AnimeData *> cache;
+};
+
 } // namespace DynamicModel
 } // namespace LocalMyList
 
index 423a15db83a28f137f9591e66d838abbad829a8c..98e4063e141cef784c36c50fb83b3d6f5cb8b6d7 100644 (file)
@@ -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 \