From eb5389847a97234197930c5dd18ad66489f33047 Mon Sep 17 00:00:00 2001 From: APTX Date: Fri, 1 Jun 2012 19:05:47 +0200 Subject: [PATCH] Add MyListModel --- localmylist/mylistmodel.cpp | 134 ++++++++++++++++++++++ localmylist/mylistmodel.h | 40 +++++++ localmylist/mylistnode.cpp | 205 ++++++++++++++++++++++++++++++++++ localmylist/mylistnode.h | 84 ++++++++++++++ management-gui/mainwindow.cpp | 5 +- management-gui/mainwindow.h | 8 +- management-gui/mainwindow.ui | 2 +- 7 files changed, 470 insertions(+), 8 deletions(-) create mode 100644 localmylist/mylistmodel.cpp create mode 100644 localmylist/mylistmodel.h create mode 100644 localmylist/mylistnode.cpp create mode 100644 localmylist/mylistnode.h diff --git a/localmylist/mylistmodel.cpp b/localmylist/mylistmodel.cpp new file mode 100644 index 0000000..a7bfe08 --- /dev/null +++ b/localmylist/mylistmodel.cpp @@ -0,0 +1,134 @@ +#include "mylistmodel.h" + +#include "mylistnode.h" + +#include + +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(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(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(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(parent.internalPointer()); + + return parentItem->childCount(); +} + +int MyListModel::columnCount(const QModelIndex &parent) const +{ + if (parent.isValid()) + return static_cast(parent.internalPointer())->columnCount(); + else + return rootItem->columnCount(); +} + +bool MyListModel::canFetchMore(const QModelIndex &parent) const +{ + if (parent.isValid()) + return static_cast(parent.internalPointer())->canFetchMore(); + else + return rootItem->canFetchMore(); +} + +void MyListModel::fetchMore(const QModelIndex &parent) +{ + int newrows = 0; + + if (parent.isValid()) + newrows = static_cast(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(parent.internalPointer())->hasChildren(); + else + return rootItem->hasChildren(); +} diff --git a/localmylist/mylistmodel.h b/localmylist/mylistmodel.h new file mode 100644 index 0000000..a4630a8 --- /dev/null +++ b/localmylist/mylistmodel.h @@ -0,0 +1,40 @@ +#ifndef MYLISTMODEL_H +#define MYLISTMODEL_H + +#include "localmylist_global.h" +#include + +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 index 0000000..a301d14 --- /dev/null +++ b/localmylist/mylistnode.cpp @@ -0,0 +1,205 @@ +#include "mylistnode.h" + +#include "mylist.h" +#include "database.h" +#include + +#include + +MyListNode::MyListNode(NodeType type, int id, const QList &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(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 &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 &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 &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 index 0000000..9fa3907 --- /dev/null +++ b/localmylist/mylistnode.h @@ -0,0 +1,84 @@ +#ifndef MYLISTNODE_H +#define MYLISTNODE_H + +#include + +class MyListNode +{ +public: + enum NodeType { + Root, + Anime, + Episode, + File + }; + + MyListNode(NodeType type = Root, int id = 0, const QList &data = QList(), 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 childItems; + QList itemData; + MyListNode *parentItem; + + static const int LIMIT = 100; +}; + +class MyListAnimeNode : public MyListNode +{ +public: + MyListAnimeNode(int id = 0, const QList &data = QList(), MyListNode *parent = 0); + + int fetchMore(); + +protected: + QString totalRowCountSql() const; +}; + +class MyListEpisodeNode : public MyListNode +{ +public: + MyListEpisodeNode(int id = 0, const QList &data = QList(), MyListNode *parent = 0); + + int fetchMore(); + +protected: + QString totalRowCountSql() const; +}; + +class MyListFileNode : public MyListNode +{ +public: + MyListFileNode(int id = 0, const QList &data = QList(), MyListNode *parent = 0); + + int fetchMore(); + +protected: + QString totalRowCountSql() const; +}; + + +#endif // MYLISTNODE_H diff --git a/management-gui/mainwindow.cpp b/management-gui/mainwindow.cpp index 18d928c..b0c6f1d 100644 --- a/management-gui/mainwindow.cpp +++ b/management-gui/mainwindow.cpp @@ -7,6 +7,7 @@ #include "mylist.h" #include "database.h" +#include "mylistmodel.h" #include @@ -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() diff --git a/management-gui/mainwindow.h b/management-gui/mainwindow.h index 782694b..0f923d6 100644 --- a/management-gui/mainwindow.h +++ b/management-gui/mainwindow.h @@ -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 diff --git a/management-gui/mainwindow.ui b/management-gui/mainwindow.ui index 782796a..12f156b 100644 --- a/management-gui/mainwindow.ui +++ b/management-gui/mainwindow.ui @@ -16,7 +16,7 @@ - + -- 2.52.0