]> Some of my projects - localmylist.git/commitdiff
Add MyListModel
authorAPTX <marek321@gmail.com>
Fri, 1 Jun 2012 17:05:47 +0000 (19:05 +0200)
committerAPTX <marek321@gmail.com>
Fri, 1 Jun 2012 17:05:47 +0000 (19:05 +0200)
localmylist/mylistmodel.cpp [new file with mode: 0644]
localmylist/mylistmodel.h [new file with mode: 0644]
localmylist/mylistnode.cpp [new file with mode: 0644]
localmylist/mylistnode.h [new file with mode: 0644]
management-gui/mainwindow.cpp
management-gui/mainwindow.h
management-gui/mainwindow.ui

diff --git a/localmylist/mylistmodel.cpp b/localmylist/mylistmodel.cpp
new file mode 100644 (file)
index 0000000..a7bfe08
--- /dev/null
@@ -0,0 +1,134 @@
+#include "mylistmodel.h"
+
+#include "mylistnode.h"
+
+#include <QDebug>
+
+MyListModel::MyListModel(QObject *parent) :
+       QAbstractItemModel(parent)
+{
+       rootItem = new MyListNode();
+}
+
+MyListModel::~MyListModel()
+{
+       delete rootItem;
+}
+
+QVariant MyListModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+       if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
+               return rootItem->data(section);
+
+       return QVariant();
+}
+
+Qt::ItemFlags MyListModel::flags(const QModelIndex &index) const
+{
+       if (!index.isValid())
+               return 0;
+
+       return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
+}
+
+QVariant MyListModel::data(const QModelIndex &index, int role) const
+{
+       if (!index.isValid())
+               return QVariant();
+
+       if (role != Qt::DisplayRole)
+               return QVariant();
+
+       MyListNode *item = static_cast<MyListNode *>(index.internalPointer());
+
+       return item->data(index.column());
+}
+
+QModelIndex MyListModel::index(int row, int column, const QModelIndex &parent) const
+{
+       if (!hasIndex(row, column, parent))
+               return QModelIndex();
+
+       MyListNode *parentItem;
+
+       if (!parent.isValid())
+               parentItem = rootItem;
+       else
+               parentItem = static_cast<MyListNode*>(parent.internalPointer());
+
+       MyListNode *childItem = parentItem->child(row);
+       if (childItem)
+               return createIndex(row, column, childItem);
+       else
+               return QModelIndex();
+}
+
+QModelIndex MyListModel::parent(const QModelIndex &index) const
+{
+       if (!index.isValid())
+               return QModelIndex();
+
+       MyListNode *childItem = static_cast<MyListNode *>(index.internalPointer());
+       MyListNode *parentItem = childItem->parent();
+
+       if (parentItem == rootItem)
+               return QModelIndex();
+
+       return createIndex(parentItem->row(), 0, parentItem);
+}
+
+int MyListModel::rowCount(const QModelIndex &parent) const
+{
+       MyListNode *parentItem;
+       if (parent.column() > 0)
+               return 0;
+
+       if (!parent.isValid())
+               parentItem = rootItem;
+       else
+               parentItem = static_cast<MyListNode *>(parent.internalPointer());
+
+       return parentItem->childCount();
+}
+
+int MyListModel::columnCount(const QModelIndex &parent) const
+{
+       if (parent.isValid())
+               return static_cast<MyListNode *>(parent.internalPointer())->columnCount();
+       else
+               return rootItem->columnCount();
+}
+
+bool MyListModel::canFetchMore(const QModelIndex &parent) const
+{
+       if (parent.isValid())
+               return static_cast<MyListNode *>(parent.internalPointer())->canFetchMore();
+       else
+               return rootItem->canFetchMore();
+}
+
+void MyListModel::fetchMore(const QModelIndex &parent)
+{
+       int newrows = 0;
+
+       if (parent.isValid())
+               newrows = static_cast<MyListNode *>(parent.internalPointer())->fetchMore();
+       else
+               newrows = rootItem->fetchMore();
+
+       if (!newrows)
+               return;
+
+       beginInsertRows(parent, rowCount(parent) - newrows, rowCount(parent) - 1);
+       endInsertRows();
+
+       qDebug() << "added" << newrows << "new rows";
+}
+
+bool MyListModel::hasChildren(const QModelIndex &parent) const
+{
+       if (parent.isValid())
+               return static_cast<MyListNode *>(parent.internalPointer())->hasChildren();
+       else
+               return rootItem->hasChildren();
+}
diff --git a/localmylist/mylistmodel.h b/localmylist/mylistmodel.h
new file mode 100644 (file)
index 0000000..a4630a8
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef MYLISTMODEL_H
+#define MYLISTMODEL_H
+
+#include "localmylist_global.h"
+#include <QAbstractItemModel>
+
+class MyListNode;
+
+class LOCALMYLISTSHARED_EXPORT MyListModel : public QAbstractItemModel
+{
+       Q_OBJECT
+
+public:
+       explicit MyListModel(QObject *parent = 0);
+       ~MyListModel();
+
+       QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
+       Qt::ItemFlags flags(const QModelIndex &index) const;
+       QVariant data(const QModelIndex &index, int role) const;
+       QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
+       QModelIndex parent(const QModelIndex &index) const;
+
+       int rowCount(const QModelIndex &parent = QModelIndex()) const;
+       int columnCount(const QModelIndex &parent = QModelIndex()) const;
+
+       // Lazy loading
+       bool canFetchMore(const QModelIndex &parent) const;
+       void fetchMore(const QModelIndex &parent);
+       bool hasChildren(const QModelIndex &parent = QModelIndex()) const;
+
+signals:
+       
+public slots:
+private:
+       void setupModelData(const QStringList &lines, MyListNode *parent);
+
+       MyListNode *rootItem;
+};
+
+#endif // MYLISTMODEL_H
diff --git a/localmylist/mylistnode.cpp b/localmylist/mylistnode.cpp
new file mode 100644 (file)
index 0000000..a301d14
--- /dev/null
@@ -0,0 +1,205 @@
+#include "mylistnode.h"
+
+#include "mylist.h"
+#include "database.h"
+#include <QSqlQuery>
+
+#include <QDebug>
+
+MyListNode::MyListNode(NodeType type, int id, const QList<QVariant> &data, MyListNode *parent) :
+       m_totalRowCount(-1), fetchedRowCount(0)
+{
+       this->type = type;
+       this->id = id;
+       parentItem = parent;
+       itemData = data;
+
+       if (type != Root)
+               return;
+
+       itemData << "Title" << "Episode / Version";
+
+}
+
+MyListNode::~MyListNode()
+{
+       qDeleteAll(childItems);
+}
+
+MyListNode *MyListNode::child(int row)
+{
+       return childItems.value(row);
+}
+
+int MyListNode::childCount() const
+{
+       return childItems.count();
+}
+
+int MyListNode::row() const
+{
+       if (parentItem)
+               return parentItem->childItems.indexOf(const_cast<MyListNode *>(this));
+
+       return 0;
+}
+
+int MyListNode::columnCount() const
+{
+       return itemData.count();
+}
+
+QVariant MyListNode::data(int column) const
+{
+       return itemData.value(column);
+}
+
+MyListNode *MyListNode::parent()
+{
+       return parentItem;
+}
+
+int MyListNode::totalRowCount() const
+{
+       if (m_totalRowCount != -1)
+               return m_totalRowCount;
+
+       if (type == File)
+       {
+               m_totalRowCount = 0;
+               return m_totalRowCount;
+       }
+
+       QSqlQuery q(LocalMyList::instance()->database()->connection());
+
+       if (!q.exec(totalRowCountSql()))
+       {
+               m_totalRowCount = 0;
+               return 0;
+       }
+
+       q.next();
+       m_totalRowCount = q.value(0).toInt();
+
+       return m_totalRowCount;
+}
+
+bool MyListNode::canFetchMore() const
+{
+       if (type != File && childCount() < totalRowCount())
+               return true;
+       return false;
+}
+
+int MyListNode::fetchMore()
+{
+       qDebug() << "fetching some more for" << id;
+       QSqlQuery q(LocalMyList::instance()->database()->connection());
+
+       if (!q.exec("SELECT aid, title_romaji AS title, (SELECT COUNT(e.eid) FROM episode e WHERE e.aid = a.aid) FROM anime a ORDER BY title ASC "
+                               "LIMIT " + QString::number(LIMIT) + " "
+                               "OFFSET " + QString::number(childCount())))
+               return 0;
+
+       while (q.next())
+       {
+               int id = q.value(0).toInt();
+               QVariantList data;
+               data << q.value(1) << q.value(2);
+               childItems << new MyListAnimeNode(id, data, this);
+       }
+       return q.size();
+}
+
+bool MyListNode::hasChildren() const
+{
+       if (type == File)
+               return false;
+
+       return true;
+}
+
+QString MyListNode::totalRowCountSql() const
+{
+       return "SELECT COUNT(aid) FROM anime";
+}
+
+// ------
+
+MyListAnimeNode::MyListAnimeNode(int id, const QList<QVariant> &data, MyListNode *parent) :
+       MyListNode(Anime, id, data, parent)
+{
+}
+
+QString MyListAnimeNode::totalRowCountSql() const
+{
+       return "SELECT COUNT(eid) FROM episode WHERE aid = " + QString::number(id);
+}
+
+int MyListAnimeNode::fetchMore()
+{
+       qDebug() << "fetching some more for" << id;
+       QSqlQuery q(LocalMyList::instance()->database()->connection());
+
+       if (!q.exec("SELECT eid, title_english, epno FROM episode WHERE aid = " + QString::number(id)
+                       + " ORDER BY epno ASC"))
+               return 0;
+
+       while (q.next())
+       {
+               int id = q.value(0).toInt();
+               QVariantList data;
+               data << q.value(1) << q.value(2);
+               childItems << new MyListEpisodeNode(id, data, this);
+       }
+
+       return q.size();
+}
+
+// ----
+
+MyListEpisodeNode::MyListEpisodeNode(int id, const QList<QVariant> &data, MyListNode *parent) :
+       MyListNode(Episode, id, data, parent)
+{
+}
+
+QString MyListEpisodeNode::totalRowCountSql() const
+{
+       return "SELECT COUNT(fid) FROM file WHERE eid = " + QString::number(id);
+}
+
+int MyListEpisodeNode::fetchMore()
+{
+       qDebug() << "fetching some more for" << id;
+       QSqlQuery q(LocalMyList::instance()->database()->connection());
+
+       if (!q.exec("SELECT fid, group_name, version FROM file WHERE eid = " + QString::number(id)))
+               return 0;
+
+       while (q.next())
+       {
+               int id = q.value(0).toInt();
+               QVariantList data;
+               data << q.value(1) << q.value(2);
+               childItems << new MyListFileNode(id, data, this);
+       }
+
+       return q.size();
+}
+
+// ---------------
+
+MyListFileNode::MyListFileNode(int id, const QList<QVariant> &data, MyListNode *parent) :
+       MyListNode(File, id, data, parent)
+{
+}
+
+int MyListFileNode::fetchMore()
+{
+       return 0;
+}
+
+QString MyListFileNode::totalRowCountSql() const
+{
+       return "SELECT 0";
+}
diff --git a/localmylist/mylistnode.h b/localmylist/mylistnode.h
new file mode 100644 (file)
index 0000000..9fa3907
--- /dev/null
@@ -0,0 +1,84 @@
+#ifndef MYLISTNODE_H
+#define MYLISTNODE_H
+
+#include <QVariant>
+
+class MyListNode
+{
+public:
+       enum NodeType {
+               Root,
+               Anime,
+               Episode,
+               File
+       };
+
+       MyListNode(NodeType type = Root, int id = 0, const QList<QVariant> &data = QList<QVariant>(), MyListNode *parent = 0);
+       virtual ~MyListNode();
+
+       void appendChild(MyListNode *child);
+
+       MyListNode *child(int row);
+       int childCount() const;
+       int columnCount() const;
+       QVariant data(int column) const;
+       int row() const;
+       MyListNode *parent();
+
+       int totalRowCount() const;
+
+       bool canFetchMore() const;
+       virtual int fetchMore();
+       bool hasChildren() const;
+
+protected:
+       virtual QString totalRowCountSql() const;
+
+       NodeType type;
+       int id;
+
+       mutable int m_totalRowCount;
+       int fetchedRowCount;
+
+       QList<MyListNode *> childItems;
+       QList<QVariant> itemData;
+       MyListNode *parentItem;
+
+       static const int LIMIT = 100;
+};
+
+class MyListAnimeNode : public MyListNode
+{
+public:
+       MyListAnimeNode(int id = 0, const QList<QVariant> &data = QList<QVariant>(), MyListNode *parent = 0);
+
+       int fetchMore();
+
+protected:
+       QString totalRowCountSql() const;
+};
+
+class MyListEpisodeNode : public MyListNode
+{
+public:
+       MyListEpisodeNode(int id = 0, const QList<QVariant> &data = QList<QVariant>(), MyListNode *parent = 0);
+
+       int fetchMore();
+
+protected:
+       QString totalRowCountSql() const;
+};
+
+class MyListFileNode : public MyListNode
+{
+public:
+       MyListFileNode(int id = 0, const QList<QVariant> &data = QList<QVariant>(), MyListNode *parent = 0);
+
+       int fetchMore();
+
+protected:
+       QString totalRowCountSql() const;
+};
+
+
+#endif // MYLISTNODE_H
index 18d928c6c93e64778e7096f2cf319cc819964e74..b0c6f1dae64ee9ac53734f37019da30f8aab222e 100644 (file)
@@ -7,6 +7,7 @@
 
 #include "mylist.h"
 #include "database.h"
+#include "mylistmodel.h"
 
 #include <QDebug>
 
@@ -18,7 +19,6 @@ MainWindow::MainWindow(QWidget *parent) :
 {
        ui->setupUi(this);
 
-
        connect(MyList::instance()->database(), SIGNAL(connected()), this, SLOT(dbConnected()));
        connect(MyList::instance()->database(), SIGNAL(disconnected()), this, SLOT(dbDisconnected()));
        connect(MyList::instance()->database(), SIGNAL(newPendingRequest()), this, SLOT(handleNotification()));
@@ -26,7 +26,8 @@ MainWindow::MainWindow(QWidget *parent) :
        databaseConnectionStatusIndicator = new QLabel(MyList::instance()->database()->isConnected() ? "Connected" : "Disconnected");
        ui->statusBar->addPermanentWidget(databaseConnectionStatusIndicator);
 
-       animeModel = 0;
+       animeModel = new MyListModel(this);
+       ui->myListView->setModel(animeModel);
 }
 
 MainWindow::~MainWindow()
index 782694b48467660d0ae7541224fa4a5e781373e7..0f923d6439bc32ffe37b0aa5ed8ffa62e946a75a 100644 (file)
@@ -7,7 +7,7 @@ namespace Ui {
 class MainWindow;
 }
 
-class QSqlTableModel;
+class MyListModel;
 class QLabel;
 
 class MainWindow : public QMainWindow
@@ -28,13 +28,11 @@ private slots:
 
        void on_actionDisconnect_triggered();
        void on_actionScanDirectory_triggered();
+       void on_actionImportMyList_triggered();
        void on_actionImportTitles_triggered();
        void on_actionClearDatabase_triggered();
        void on_actionClearMyListData_triggered();
        void on_actionClearAnimeTitleData_triggered();
-
-       void on_actionImportMyList_triggered();
-
        void on_actionHandlePendingRequests_triggered();
 
 private:
@@ -42,7 +40,7 @@ private:
 
        QLabel *databaseConnectionStatusIndicator;
 
-       QSqlTableModel *animeModel;
+       MyListModel *animeModel;
 };
 
 #endif // MAINWINDOW_H
index 782796a6ac46c849684b29bc61092f43e08fd259..12f156b9baa8d515409fd9636f80afb45c7fb928 100644 (file)
@@ -16,7 +16,7 @@
   <widget class="QWidget" name="centralWidget">
    <layout class="QHBoxLayout" name="horizontalLayout">
     <item>
-     <widget class="QTableView" name="tableView"/>
+     <widget class="QTreeView" name="myListView"/>
     </item>
    </layout>
   </widget>