From: APTX Date: Mon, 25 Mar 2013 15:30:14 +0000 (+0100) Subject: New implementation of MyListModel X-Git-Url: https://gitweb.aptx.org/?a=commitdiff_plain;h=182f352d740e08a099c3f8d6d40d6bd87a2f1e11;p=localmylist.git New implementation of MyListModel --- diff --git a/localmylist/localmylist.pro b/localmylist/localmylist.pro index ba79b19..6f50ac1 100644 --- a/localmylist/localmylist.pro +++ b/localmylist/localmylist.pro @@ -18,6 +18,7 @@ SOURCES += \ mylist.cpp \ mylistmodel.cpp \ mylistnode.cpp \ + mylistnodedata.cpp \ animetitleparsetask.cpp \ mylistexportparsetask.cpp \ settings.cpp \ @@ -42,6 +43,7 @@ HEADERS += \ mylist.h \ mylistmodel.h \ mylistnode.h \ + mylistnodedata.h \ animetitleparsetask.h \ mylistexportparsetask.h \ settings.h \ @@ -54,7 +56,8 @@ HEADERS += \ sqlquery.h \ sqlasyncquery.h \ sqlasyncqueryinternal.h \ - asyncquerytask.h + asyncquerytask.h \ + sqlresultiteratorinterface.h CONV_HEADERS += \ include/LocalMyList/AbstractTask \ diff --git a/localmylist/mylistmodel.cpp b/localmylist/mylistmodel.cpp index 330e8d7..d7a38c9 100644 --- a/localmylist/mylistmodel.cpp +++ b/localmylist/mylistmodel.cpp @@ -7,9 +7,11 @@ namespace LocalMyList { MyListModel::MyListModel(QObject *parent) : - QAbstractItemModel(parent) + QAbstractItemModel(parent), delayedFetchNode(0) { - rootItem = new MyListNode(); + rootItem = new MyListNode(this); + delayFetchTimer.setSingleShot(true); + connect(&delayFetchTimer, SIGNAL(timeout()), this, SLOT(finishDelayedFetch())); } MyListModel::~MyListModel() @@ -103,10 +105,13 @@ int MyListModel::columnCount(const QModelIndex &parent) const bool MyListModel::canFetchMore(const QModelIndex &parent) const { + MyListNode *parentItem; if (parent.isValid()) - return static_cast(parent.internalPointer())->canFetchMore(); + parentItem = static_cast(parent.internalPointer()); else - return rootItem->canFetchMore(); + parentItem = rootItem; + + return parentItem->canFetchMore(); } void MyListModel::fetchMore(const QModelIndex &parent) @@ -118,16 +123,11 @@ void MyListModel::fetchMore(const QModelIndex &parent) else node = rootItem; - int newrows = node->fetchMore(); - - if (!newrows) + if (node->isWorking()) return; - beginInsertRows(parent, rowCount(parent), rowCount(parent) + newrows - 1); - node->addFetched(); - endInsertRows(); - - qDebug() << "added" << newrows << "new rows"; + node->setWorking(true); + node->fetchMore(); } bool MyListModel::hasChildren(const QModelIndex &parent) const @@ -149,8 +149,52 @@ void MyListModel::reload() { beginResetModel(); delete rootItem; - rootItem = new MyListNode(); + rootItem = new MyListNode(this); endResetModel(); } +void MyListModel::finishDelayedFetch() +{ + if (delayedFetchNode) + delayedFetchNode->setWorking(false); + delayedFetchNode = 0; +} + +QModelIndex MyListModel::index(MyListNode *node) const +{ + if (!node || node == rootItem) + return QModelIndex(); + return createIndex(node->row(), 0, node); +} + +void MyListModel::fetchFinished(MyListNode *node, int newrows) +{ + if (!newrows) + return; + + const QModelIndex parent = index(node); + + + beginInsertRows(parent, rowCount(parent), rowCount(parent) + newrows - 1); + node->addFetched(); + endInsertRows(); + + // Delay fetching of more rows untill they are really needed. + // Only for the root node + // Lazy loading didn't work before for children, not sure why + // TODO figure out if it can be fixed + // Enableing this for non-root makes it never fetch more. + if (node == rootItem) + { + delayFetchTimer.start(0); + delayedFetchNode = node; + } + else + { + node->setWorking(false); + } + + qDebug() << "added" << newrows << "new rows"; +} + } // namespace LocalMyList diff --git a/localmylist/mylistmodel.h b/localmylist/mylistmodel.h index 78f1880..b1315b7 100644 --- a/localmylist/mylistmodel.h +++ b/localmylist/mylistmodel.h @@ -3,6 +3,12 @@ #include "localmylist_global.h" #include +#include + +#include "databaseclasses.h" +#include "mylistnodedata.h" + +#include namespace LocalMyList { @@ -11,9 +17,14 @@ class MyListNode; class LOCALMYLISTSHARED_EXPORT MyListModel : public QAbstractItemModel { Q_OBJECT + friend class MyListNode; + friend class MyListAnimeNode; + friend class MyListEpisodeNode; + friend class MyListFileNode; + friend class MyListFileLocationNode; public: - enum NodeType { + enum class NodeType { None, Anime, Episode, @@ -24,9 +35,16 @@ public: explicit MyListModel(QObject *parent = 0); ~MyListModel(); + Anime anime(int id) const; + Anime anime(const QModelIndex &index) const; + QModelIndex animeIndex(int id) const; + + File file(int id) const; + QModelIndex fileIndex(int id) const; + 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; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; QModelIndex parent(const QModelIndex &index) const; @@ -37,14 +55,31 @@ public: bool canFetchMore(const QModelIndex &parent) const; void fetchMore(const QModelIndex &parent); bool hasChildren(const QModelIndex &parent = QModelIndex()) const; + signals: - + public slots: MyListNode *node(const QModelIndex &idx) const; void reload(); + +private slots: + void finishDelayedFetch(); + +protected: + QModelIndex index(MyListNode *node) const; + void fetchFinished(MyListNode *node, int newrows); + private: + boost::intrusive::set animeSet; + boost::intrusive::set episodeSet; + boost::intrusive::set fileSet; + boost::intrusive::set fileLocationSet; + MyListNode *rootItem; + + QTimer delayFetchTimer; + MyListNode *delayedFetchNode; }; } // namespace LocalMyList diff --git a/localmylist/mylistnode.cpp b/localmylist/mylistnode.cpp index 4a4ea67..7ab2082 100644 --- a/localmylist/mylistnode.cpp +++ b/localmylist/mylistnode.cpp @@ -1,22 +1,25 @@ #include "mylistnode.h" +#include "mylistmodel.h" #include "mylist.h" #include "database.h" #include - +#include "sqlasyncquery.h" #include namespace LocalMyList { -MyListNode::MyListNode(NodeType type, int id, const QList &data, MyListNode *parent) : - m_totalRowCount(-1), fetchedRowCount(0) +MyListNode::MyListNode(MyListModel *model_, NodeType type, MyListNode *parent) : + m_totalRowCount(-1), fetchedRowCount(0), m_working(false) { m_type = type; - m_id = id; parentItem = parent; - itemData = data; + model = model_; + + query = new SqlAsyncQuery; + QObject::connect(query, &SqlAsyncQuery::resultReady, [this](){ fetchComplete();}); - if (m_type != Root) + if (m_type != RootNode) return; itemData << "Title" << "Episode / Version" << "Rating / Quality" << "Vote" << "Watched / Renamed"; @@ -25,6 +28,7 @@ MyListNode::MyListNode(NodeType type, int id, const QList &data, MyLis MyListNode::~MyListNode() { qDeleteAll(childItems); + delete query; } MyListNode *MyListNode::child(int row) @@ -47,7 +51,7 @@ int MyListNode::row() const int MyListNode::columnCount() const { - return itemData.count(); + return 5; } QVariant MyListNode::data(int column) const @@ -65,7 +69,7 @@ int MyListNode::totalRowCount() const if (m_totalRowCount != -1) return m_totalRowCount; - if (m_type == FileLocation) + if (m_type == FileLocationNode) { m_totalRowCount = 0; return m_totalRowCount; @@ -87,49 +91,51 @@ int MyListNode::totalRowCount() const bool MyListNode::canFetchMore() const { - if (m_type != FileLocation && childCount() < totalRowCount()) + if (!isWorking() && m_type != FileLocationNode && childCount() < totalRowCount()) return true; return false; } -int MyListNode::fetchMore() +void MyListNode::fetchMore() { - QSqlQuery &q = LocalMyList::instance()->database()->prepare( - "SELECT aid, title_romaji AS title, " + query->prepare(QString( + "SELECT " " (SELECT COUNT(e.eid) " " FROM episode e " " WHERE e.aid = a.aid), " - " rating, my_vote, " " (SELECT COUNT(DISTINCT f.eid) " " FROM episode e " " JOIN file f ON (f.eid = e.eid) " " WHERE e.aid = a.aid " - " AND f.my_watched IS NOT NULL) " + " AND f.my_watched IS NOT NULL), " + " %1 " " FROM anime a " - " ORDER BY title ASC " + " ORDER BY title_romaji ASC " "LIMIT :limit " - "OFFSET :offset "); - q.bindValue(":limit", LIMIT); - q.bindValue(":offset", childCount()); + "OFFSET :offset ").arg(Database::animeFields())); + query->bindValue(":limit", LIMIT); + query->bindValue(":offset", childCount()); - if (!LocalMyList::instance()->database()->exec(q)) - return 0; + query->exec(); +} - while (q.next()) +void MyListNode::fetchComplete() +{ + while (query->next()) { - int id = q.value(0).toInt(); - QVariantList data; - - data << q.value(1) << q.value(2) - << (q.value(3).toDouble() < 1 ? "n/a" : QString::number(q.value(3).toDouble(), 'f', 2)) - << (q.value(4).toDouble() < 1 ? "n/a" : QString::number(q.value(4).toDouble(), 'f', 2)) - << QObject::tr("%1 of %2").arg(q.value(5).toInt()).arg(q.value(2).toInt()); - newItems << new MyListAnimeNode(id, data, this); + int epsInMyList = query->value(0).toInt(); + int watchedEps = query->value(1).toInt(); + Anime a; + Database::readAnimeData(*query, a, 2); + + AnimeData ad(a, epsInMyList, watchedEps); + auto node = new MyListAnimeNode(model, ad, this); + newItems << node; } - q.finish(); + query->finish(); - return newItems.count(); + model->fetchFinished(this, newItems.count()); } void MyListNode::addFetched() @@ -140,12 +146,22 @@ void MyListNode::addFetched() bool MyListNode::hasChildren() const { - if (m_type == FileLocation) + if (m_type == FileLocationNode) return false; return true; } +bool MyListNode::isWorking() const +{ + return m_working; +} + +void MyListNode::setWorking(bool working) +{ + m_working = working; +} + QString MyListNode::totalRowCountSql() const { return "SELECT COUNT(aid) FROM anime"; @@ -158,26 +174,63 @@ MyListNode::NodeType MyListNode::type() const int MyListNode::id() const { - return m_id; + return 0; } // ------ -MyListAnimeNode::MyListAnimeNode(int id, const QList &data, MyListNode *parent) : - MyListNode(Anime, id, data, parent) +MyListAnimeNode::MyListAnimeNode(MyListModel *model, const AnimeData &data, MyListNode *parent) : + MyListNode(model, AnimeNode, parent), animeData(data) +{ + animeData.node = this; + model->animeSet.insert(animeData); +} + +MyListAnimeNode::~MyListAnimeNode() +{ + model->animeSet.erase(model->animeSet.s_iterator_to(animeData)); +} + +QVariant MyListAnimeNode::data(int column) const { + switch (column) + { + case 0: + return animeData.data.titleRomaji; + case 1: + return watchedEpisodes(); + case 2: + if (animeData.data.rating < 1) + return "n/a"; + return QString::number(animeData.data.rating, 'f', 2); + case 3: + if (animeData.data.myVote < 1) + return "n/a"; + return QString::number(animeData.data.myVote, 'f', 2); + case 4: + return QString("%1 of %2").arg(animeData.watchedEpisodes) + .arg(watchedEpisodes()); + } + return QVariant(); } QString MyListAnimeNode::totalRowCountSql() const { - return "SELECT COUNT(eid) FROM episode WHERE aid = " + QString::number(m_id); + return "SELECT COUNT(eid) FROM episode WHERE aid = " + QString::number(id()); +} + +int MyListAnimeNode::watchedEpisodes() const +{ + return qMax(animeData.data.totalEpisodeCount, + qMax(animeData.data.highestEpno, + animeData.episodesInMyList)); } -int MyListAnimeNode::fetchMore() +void MyListAnimeNode::fetchMore() { - qDebug() << "fetching some more for aid" << m_id; - QSqlQuery &q = LocalMyList::instance()->database()->prepare( - "SELECT e.eid, e.title_english, et.type, e.epno, e.rating, e.my_vote, " + qDebug() << "fetching some more for aid" << id(); + query->prepare(QString( + "SELECT " " (SELECT MIN(my_watched) " " FROM " " (SELECT my_watched " @@ -189,41 +242,80 @@ int MyListAnimeNode::fetchMore() " FROM file f " " JOIN file_episode_rel fer ON (fer.fid = f.fid) " " WHERE fer.eid = e.eid " - " AND my_watched IS NOT NULL) AS sq) AS my_watched " + " AND my_watched IS NOT NULL) AS sq) AS my_watched, " + " %1 " " FROM episode e " " JOIN episode_type et ON (et.type = e.type)" " WHERE e.aid = :aid " " ORDER BY et.ordering ASC, e.epno ASC " " LIMIT :limit " - " OFFSET :offset "); - q.bindValue(":aid", m_id); - q.bindValue(":limit", LIMIT); - q.bindValue(":offset", childCount()); + " OFFSET :offset ").arg(Database::episodeFields())); + query->bindValue(":aid", id()); + query->bindValue(":limit", LIMIT); + query->bindValue(":offset", childCount()); - if (!LocalMyList::instance()->database()->exec(q)) - return 0; + query->exec(); +} - while (q.next()) +void MyListAnimeNode::fetchComplete() +{ + while (query->next()) { - int id = q.value(0).toInt(); - QVariantList data; - data << q.value(1) << (q.value(2).toString() + q.value(3).toString()) - << (q.value(4).toDouble() < 1 ? "n/a" : QString::number(q.value(4).toDouble(), 'f', 2)) - << (q.value(5).toDouble() < 1 ? "n/a" : QString::number(q.value(5).toDouble(), 'f', 2)) - << (q.value(6).toDateTime().isValid() ? QObject::tr("Yes, on %1").arg(q.value(6).toDateTime().toString()) : QObject::tr("No")); - newItems << new MyListEpisodeNode(id, data, this); + QDateTime watchedDate = query->value(0).toDateTime(); + Episode e; + Database::readEpisodeData(*query, e, 1); + + EpisodeData ed(e, watchedDate); + auto node = new MyListEpisodeNode(model, ed, this); + newItems << node; } - q.finish(); + query->finish(); - return newItems.count(); + model->fetchFinished(this, newItems.count()); +} + +int MyListAnimeNode::id() const +{ + return animeData.data.aid; } // ---- -MyListEpisodeNode::MyListEpisodeNode(int id, const QList &data, MyListNode *parent) : - MyListNode(Episode, id, data, parent) +MyListEpisodeNode::MyListEpisodeNode(MyListModel *model, const EpisodeData &data, MyListNode *parent) : + MyListNode(model, EpisodeNode, parent), episodeData(data) +{ + episodeData.node = this; + model->episodeSet.insert(episodeData); +} + +MyListEpisodeNode::~MyListEpisodeNode() +{ + model->episodeSet.erase(model->episodeSet.s_iterator_to(episodeData)); +} + +QVariant MyListEpisodeNode::data(int column) const { + switch (column) + { + case 0: + return episodeData.data.titleEnglish; + case 1: + return episodeData.data.type + QString::number(episodeData.data.epno); + case 2: + if (episodeData.data.rating < 1) + return "n/a"; + return QString::number(episodeData.data.rating, 'f', 2); + case 3: + if (episodeData.data.myVote < 1) + return "n/a"; + return QString::number(episodeData.data.myVote, 'f', 2); + case 4: + if (!episodeData.watchedDate.isValid()) + return QObject::tr("No"); + return QObject::tr("Yes, on %1").arg(episodeData.watchedDate.toString()); + } + return QVariant(); } QString MyListEpisodeNode::totalRowCountSql() const @@ -238,23 +330,26 @@ QString MyListEpisodeNode::totalRowCountSql() const " SELECT f.fid FROM file f " " JOIN file_episode_rel fer ON (fer.fid = f.fid) " " WHERE fer.eid = %1 " - " ) AS sq ").arg(m_id); + " ) AS sq ").arg(id()); } -int MyListEpisodeNode::fetchMore() +void MyListEpisodeNode::fetchMore() { - qDebug() << "fetching some more for eid" << m_id; - QSqlQuery &q = LocalMyList::instance()->database()->prepare( - "SELECT fid, group_name, version, quality, my_watched " - " FROM file " - " WHERE eid = :eida " + qDebug() << "fetching some more for eid" << id(); + query->prepare(QString( + "SELECT %1 " + " FROM file f " + " WHERE f.eid = :eida " "UNION " - "SELECT f.fid, f.group_name, f.version, f.quality, f.my_watched FROM file f " + "SELECT %1 FROM file f " " JOIN file_episode_rel fer ON (fer.fid = f.fid) " - " WHERE fer.eid = :eidb "); - q.bindValue(":eida", m_id); - q.bindValue(":eidb", m_id); + " WHERE fer.eid = :eidb ") + .arg(Database::fileFields())); + query->bindValue(":eida", id()); + query->bindValue(":eidb", id()); + query->exec(); +/* if (!LocalMyList::instance()->database()->exec(q)) return 0; @@ -269,28 +364,70 @@ int MyListEpisodeNode::fetchMore() q.finish(); - return newItems.count(); +*/ +} + +void MyListEpisodeNode::fetchComplete() +{ + while (query->next()) + { + File f; + Database::readFileData(*query, f); + + FileData fd(f); + auto node = new MyListFileNode(model, fd, this); + newItems << node; + } + + query->finish(); + + model->fetchFinished(this, newItems.count()); +} + +int MyListEpisodeNode::id() const +{ + return episodeData.data.eid; } // --------------- -MyListFileNode::MyListFileNode(int id, const QList &data, MyListNode *parent) : - MyListNode(File, id, data, parent) +MyListFileNode::MyListFileNode(MyListModel *model, const FileData &data, MyListNode *parent) : + MyListNode(model, FileNode, parent), fileData(data) { } -int MyListFileNode::fetchMore() +QVariant MyListFileNode::data(int column) const { - qDebug() << "fetching some more for fid" << m_id; - QSqlQuery &q = LocalMyList::instance()->database()->prepare( - "SELECT fl.fid, fl.host_id, h.name, fl.path, fl.renamed, fl.failed_rename FROM file_location fl " - " JOIN host h ON (fl.host_id = h.host_id) " - "WHERE fl.fid = :fid"); - q.bindValue(":fid", m_id); + switch (column) + { + case 0: + return fileData.data.groupName; + case 1: + return "v" + QString::number(fileData.data.version); + case 2: + return fileData.data.quality; + case 3: + return ""; + case 4: + if (!fileData.data.myWatched.isValid()) + return QObject::tr("No"); + return QObject::tr("Yes, on %1").arg(fileData.data.myWatched.toString()); + } + return QVariant(); +} - if (!LocalMyList::instance()->database()->exec(q)) - return 0; +void MyListFileNode::fetchMore() +{ + qDebug() << "fetching some more for fid" << id(); + query->prepare(QString( + "SELECT h.name, %1 FROM file_location fl " + " JOIN host h ON (fl.host_id = h.host_id) " + "WHERE fl.fid = :fid") + .arg(Database::fileLocationFields())); + query->bindValue(":fid", id()); + query->exec(); +/* while (q.next()) { int id = q.value(0).toInt(); @@ -306,23 +443,80 @@ int MyListFileNode::fetchMore() q.finish(); return newItems.count(); +*/ +} + +void MyListFileNode::fetchComplete() +{ + while (query->next()) + { + QString hostName = query->value(0).toString(); + + FileLocation fl; + Database::readFileLocationData(*query, fl, 1); + + FileLocationData fld(fl, hostName); + + auto node = new MyListFileLocationNode(model, fld, this); + newItems << node; + } + + query->finish(); + + model->fetchFinished(this, newItems.count()); +} + +int MyListFileNode::id() const +{ + return fileData.data.fid; } QString MyListFileNode::totalRowCountSql() const { - return "SELECT COUNT(fid) FROM file_location WHERE fid = " + QString::number(m_id); + return "SELECT COUNT(fid) FROM file_location WHERE fid = " + QString::number(id()); } // --------------- -MyListFileLocationNode::MyListFileLocationNode(int id, const QList &data, MyListNode *parent) : - MyListNode(FileLocation, id, data, parent) +MyListFileLocationNode::MyListFileLocationNode(MyListModel *model, const FileLocationData &data, MyListNode *parent) : + MyListNode(model, FileLocationNode, parent), fileLocationData(data) { } -int MyListFileLocationNode::fetchMore() +QVariant MyListFileLocationNode::data(int column) const { - return 0; + switch (column) + { + case 0: + return fileLocationData.data.path; + case 1: + return QString("%1 (%2)").arg(fileLocationData.hostName) + .arg(fileLocationData.data.hostId); + case 2: + return ""; + case 3: + return ""; + case 4: + if (!fileLocationData.data.renamed.isValid()) + return QObject::tr("No"); + if (fileLocationData.data.failedRename) + return QObject::tr("Rename failed"); + return QObject::tr("Yes, on %1").arg(fileLocationData.data.renamed.toString()); + } + return QVariant(); +} + +void MyListFileLocationNode::fetchMore() +{ +} + +void MyListFileLocationNode::fetchComplete() +{ +} + +int MyListFileLocationNode::id() const +{ + return fileLocationData.data.locationId; } QString MyListFileLocationNode::totalRowCountSql() const diff --git a/localmylist/mylistnode.h b/localmylist/mylistnode.h index f7442ca..d4e01cc 100644 --- a/localmylist/mylistnode.h +++ b/localmylist/mylistnode.h @@ -2,46 +2,54 @@ #define MYLISTNODE_H #include "localmylist_global.h" +#include "mylistmodel.h" +#include "databaseclasses.h" #include namespace LocalMyList { +class MyListModel; +class SqlAsyncQuery; + class LOCALMYLISTSHARED_EXPORT MyListNode { public: enum NodeType { - Root, - Anime, - Episode, - File, - FileLocation + RootNode, + AnimeNode, + EpisodeNode, + FileNode, + FileLocationNode }; - MyListNode(NodeType type = Root, int m_id = 0, const QList &data = QList(), MyListNode *parent = 0); + MyListNode(MyListModel *model, NodeType type = RootNode, MyListNode *parent = 0); virtual ~MyListNode(); MyListNode *child(int row); int childCount() const; int columnCount() const; - QVariant data(int column) const; + virtual QVariant data(int column) const; int row() const; MyListNode *parent(); int totalRowCount() const; bool canFetchMore() const; - virtual int fetchMore(); + virtual void fetchMore(); + virtual void fetchComplete(); void addFetched(); bool hasChildren() const; + bool isWorking() const; + void setWorking(bool working); + NodeType type() const; - int id() const; + virtual int id() const; protected: virtual QString totalRowCountSql() const; NodeType m_type; - int m_id; mutable int m_totalRowCount; int fetchedRowCount; @@ -50,6 +58,10 @@ protected: QList newItems; QList itemData; MyListNode *parentItem; + MyListModel *model; + SqlAsyncQuery *query; + + bool m_working; static const int LIMIT = 200; }; @@ -57,45 +69,72 @@ protected: class LOCALMYLISTSHARED_EXPORT MyListAnimeNode : public MyListNode { public: - MyListAnimeNode(int id = 0, const QList &data = QList(), MyListNode *parent = 0); + MyListAnimeNode(MyListModel *model, const AnimeData &data, MyListNode *parent); + ~MyListAnimeNode(); - int fetchMore(); + QVariant data(int column) const; + void fetchMore(); + void fetchComplete(); + int id() const; protected: QString totalRowCountSql() const; + +private: + int watchedEpisodes() const; + AnimeData animeData; }; class LOCALMYLISTSHARED_EXPORT MyListEpisodeNode : public MyListNode { public: - MyListEpisodeNode(int id = 0, const QList &data = QList(), MyListNode *parent = 0); + MyListEpisodeNode(MyListModel *model, const EpisodeData &data, MyListNode *parent); + ~MyListEpisodeNode(); - int fetchMore(); + QVariant data(int column) const; + void fetchMore(); + void fetchComplete(); + int id() const; protected: QString totalRowCountSql() const; + +private: + EpisodeData episodeData; }; class LOCALMYLISTSHARED_EXPORT MyListFileNode : public MyListNode { public: - MyListFileNode(int id = 0, const QList &data = QList(), MyListNode *parent = 0); + MyListFileNode(MyListModel *model, const FileData &data, MyListNode *parent); - int fetchMore(); + QVariant data(int column) const; + void fetchMore(); + void fetchComplete(); + int id() const; protected: QString totalRowCountSql() const; + +private: + FileData fileData; }; class LOCALMYLISTSHARED_EXPORT MyListFileLocationNode : public MyListNode { public: - MyListFileLocationNode(int id = 0, const QList &data = QList(), MyListNode *parent = 0); + MyListFileLocationNode(MyListModel *model, const FileLocationData &data, MyListNode *parent); - int fetchMore(); + QVariant data(int column) const; + void fetchMore(); + void fetchComplete(); + int id() const; protected: QString totalRowCountSql() const; + +private: + FileLocationData fileLocationData; }; } // namespace LocalMyList diff --git a/localmylist/mylistnodedata.cpp b/localmylist/mylistnodedata.cpp new file mode 100644 index 0000000..5e859d8 --- /dev/null +++ b/localmylist/mylistnodedata.cpp @@ -0,0 +1,3 @@ +#include "mylistnodedata.h" + + diff --git a/localmylist/mylistnodedata.h b/localmylist/mylistnodedata.h new file mode 100644 index 0000000..4ed0016 --- /dev/null +++ b/localmylist/mylistnodedata.h @@ -0,0 +1,75 @@ +#ifndef MYLISTNODEDATA_H +#define MYLISTNODEDATA_H + +#include "databaseclasses.h" +#include + +namespace LocalMyList { + +class MyListAnimeNode; +class MyListEpisodeNode; +class MyListFileNode; +class MyListFileLocationNode; + +struct AnimeData : public boost::intrusive::set_base_hook< > +{ + Anime data; + MyListAnimeNode *node; + + int episodesInMyList; + int watchedEpisodes; + + friend bool operator<(const AnimeData &a, const AnimeData &b) + { return a.data.aid < b.data.aid; } + + AnimeData(const Anime &animeData, int epsInML, int watchedEps) : data(animeData), node(0), + episodesInMyList(epsInML), watchedEpisodes(watchedEps) + {} +}; + +struct EpisodeData : public boost::intrusive::set_base_hook< > +{ + Episode data; + MyListEpisodeNode *node; + + QDateTime watchedDate; + + friend bool operator<(const EpisodeData &a, const EpisodeData &b) + { return a.data.eid < b.data.eid; } + + EpisodeData(const Episode &episodeData, const QDateTime &watchedDate_) + : data(episodeData), node(0), watchedDate(watchedDate_) + {} +}; + +struct FileData : public boost::intrusive::set_base_hook< > +{ + File data; + MyListFileNode *node; + + friend bool operator<(const FileData &a, const FileData &b) + { return a.data.fid < b.data.fid; } + + FileData(const File &fileData) + : data(fileData), node(0) + {} +}; + +struct FileLocationData : public boost::intrusive::set_base_hook< > +{ + FileLocation data; + MyListFileLocationNode *node; + + QString hostName; + + friend bool operator<(const FileLocationData &a, const FileLocationData &b) + { return a.data.locationId < b.data.locationId; } + + FileLocationData(const FileLocation &fileLocationData, const QString &hostName_) + : data(fileLocationData), node(0), hostName(hostName_) + {} +}; + +} // namespace LocalMyList + +#endif // MYLISTNODEDATA_H diff --git a/management-gui/mainwindow.cpp b/management-gui/mainwindow.cpp index 4331dd0..12e3d24 100644 --- a/management-gui/mainwindow.cpp +++ b/management-gui/mainwindow.cpp @@ -296,15 +296,15 @@ void MainWindow::on_myListView_openFileRequested(const QModelIndex &index) OpenFileData data; - if (node->type() == MyListNode::Anime) + if (node->type() == MyListNode::AnimeNode) { data = MyList::instance()->database()->firstUnwatchedByAid(node->id()); } - else if (node->type() == MyListNode::Episode) + else if (node->type() == MyListNode::EpisodeNode) { data = MyList::instance()->database()->openFileByEid(node->id()); } - else if (node->type() == MyListNode::File) + else if (node->type() == MyListNode::FileNode) { data = MyList::instance()->database()->openFile(node->id()); } @@ -335,7 +335,7 @@ void MainWindow::on_myListView_renameFilesRequested(const QModelIndex &index) QSqlQuery q(MyList::instance()->database()->connection()); QChar typeLetter; - if (node->type() == MyListNode::Anime) + if (node->type() == MyListNode::AnimeNode) { q.prepare( "UPDATE file_location fl SET renamed = NULL, failed_rename = false " @@ -345,7 +345,7 @@ void MainWindow::on_myListView_renameFilesRequested(const QModelIndex &index) typeLetter = 'a'; } - else if (node->type() == MyListNode::Episode) + else if (node->type() == MyListNode::EpisodeNode) { q.prepare( "UPDATE file_location fl SET renamed = NULL, failed_rename = false " @@ -355,7 +355,7 @@ void MainWindow::on_myListView_renameFilesRequested(const QModelIndex &index) typeLetter = 'e'; } - else if (node->type() == MyListNode::File) + else if (node->type() == MyListNode::FileNode) { q.prepare( "UPDATE file_location fl SET renamed = NULL, failed_rename = false " @@ -389,13 +389,13 @@ void MainWindow::on_myListView_dataRequested(const QModelIndex &index) switch (node->type()) { - case MyListNode::Anime: + case MyListNode::AnimeNode: r.aid = node->id(); break; - case MyListNode::Episode: + case MyListNode::EpisodeNode: r.eid = node->id(); break; - case MyListNode::File: + case MyListNode::FileNode: r.fid = node->id(); break; default: diff --git a/management-gui/mylistview.cpp b/management-gui/mylistview.cpp index 8baf0a9..bebe6ec 100644 --- a/management-gui/mylistview.cpp +++ b/management-gui/mylistview.cpp @@ -60,21 +60,21 @@ void MyListView::showCustomContextMenu(const QPoint &pos) switch (node->type()) { - case MyListNode::Anime: + case MyListNode::AnimeNode: aniDBLinkAction->setText(tr("Open AniDB Page (%1%2)").arg('a').arg(node->id())); actions << aniDBLinkAction << openNextAction << renameFilesAction << requestDataAction; break; - case MyListNode::Episode: + case MyListNode::EpisodeNode: aniDBLinkAction->setText(tr("Open AniDB Page (%1%2)").arg('e').arg(node->id())); actions << aniDBLinkAction << openAction << renameFilesAction << requestDataAction; break; - case MyListNode::File: + case MyListNode::FileNode: aniDBLinkAction->setText(tr("Open AniDB Page (%1%2)").arg('f').arg(node->id())); actions << aniDBLinkAction << openAction @@ -83,7 +83,7 @@ void MyListView::showCustomContextMenu(const QPoint &pos) << renameFilesAction << requestDataAction; break; - case MyListNode::FileLocation: + case MyListNode::FileLocationNode: aniDBLinkAction->setText(tr("Open AniDB Page (%1%2)").arg('f').arg(node->id())); actions << aniDBLinkAction << markWatchedAction @@ -125,14 +125,14 @@ void MyListView::openAnidbPage() switch (node->type()) { - case MyListNode::Anime: + case MyListNode::AnimeNode: QDesktopServices::openUrl(QUrl(aniDBUrlBase.arg('a').arg(node->id()))); break; - case MyListNode::Episode: + case MyListNode::EpisodeNode: QDesktopServices::openUrl(QUrl(aniDBUrlBase.arg('e').arg(node->id()))); break; - case MyListNode::File: - case MyListNode::FileLocation: + case MyListNode::FileNode: + case MyListNode::FileLocationNode: QDesktopServices::openUrl(QUrl(aniDBUrlBase.arg('f').arg(node->id()))); break; default: