--- /dev/null
+#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();
+}
--- /dev/null
+#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
--- /dev/null
+#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";
+}
--- /dev/null
+#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
#include "mylist.h"
#include "database.h"
+#include "mylistmodel.h"
#include <QDebug>
{
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()));
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()
class MainWindow;
}
-class QSqlTableModel;
+class MyListModel;
class QLabel;
class MainWindow : public QMainWindow
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:
QLabel *databaseConnectionStatusIndicator;
- QSqlTableModel *animeModel;
+ MyListModel *animeModel;
};
#endif // MAINWINDOW_H
<widget class="QWidget" name="centralWidget">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
- <widget class="QTableView" name="tableView"/>
+ <widget class="QTreeView" name="myListView"/>
</item>
</layout>
</widget>