#include "mylistnode.h"
+#include "mylistmodel.h"
#include "mylist.h"
#include "database.h"
#include <QSqlQuery>
-
+#include "sqlasyncquery.h"
#include <QDebug>
namespace LocalMyList {
-MyListNode::MyListNode(NodeType type, int id, const QList<QVariant> &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";
MyListNode::~MyListNode()
{
qDeleteAll(childItems);
+ delete query;
}
MyListNode *MyListNode::child(int row)
int MyListNode::columnCount() const
{
- return itemData.count();
+ return 5;
}
QVariant MyListNode::data(int column) const
if (m_totalRowCount != -1)
return m_totalRowCount;
- if (m_type == FileLocation)
+ if (m_type == FileLocationNode)
{
m_totalRowCount = 0;
return m_totalRowCount;
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()
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";
int MyListNode::id() const
{
- return m_id;
+ return 0;
}
// ------
-MyListAnimeNode::MyListAnimeNode(int id, const QList<QVariant> &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 "
" 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<QVariant> &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
" 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;
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<QVariant> &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();
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<QVariant> &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