]> Some of my projects - localmylist.git/commitdiff
MyListModel now handles additions to the database.
authorAPTX <marek321@gmail.com>
Sun, 31 Mar 2013 19:26:16 +0000 (21:26 +0200)
committerAPTX <marek321@gmail.com>
Sun, 31 Mar 2013 19:26:16 +0000 (21:26 +0200)
It also reorders rows caused by data updates.

localmylist/database.cpp
localmylist/database.h
localmylist/mylistmodel.cpp
localmylist/mylistmodel.h
localmylist/mylistnode.cpp
localmylist/mylistnode.h
localmylist/mylistnodedata.h
localmylist/share/schema/schema.sql

index dee3533dd1b40a3c9f09f959a897981070d6461d..eac20af293b00814d7764408559349336a44270a 100644 (file)
@@ -1476,6 +1476,10 @@ void Database::subscribeToNotifications()
        d->db.driver()->subscribeToNotification("episode_update");
        d->db.driver()->subscribeToNotification("file_update");
        d->db.driver()->subscribeToNotification("file_location_update");
+       d->db.driver()->subscribeToNotification("anime_insert");
+       d->db.driver()->subscribeToNotification("episode_insert");
+       d->db.driver()->subscribeToNotification("file_insert");
+       d->db.driver()->subscribeToNotification("file_location_insert");
 }
 
 OpenFileData Database::readOpenFileData(QSqlQuery &q)
@@ -1786,6 +1790,48 @@ void Database::handleNotification(const QString &name, QSqlDriver::NotificationS
                if (id)
                        emit fileLocationUpdate(id);
        }
+       else if (name == "anime_insert")
+       {
+               int id = payload.toInt();
+               if (id)
+                       emit animeInsert(id);
+       }
+       else if (name == "episode_insert")
+       {
+               QStringList ids = payload.toString().split(QChar(','), QString::SkipEmptyParts);
+               int eid = 0;
+               int aid = 0;
+               if (ids.count())
+                       eid = ids.takeFirst().toInt();
+               if (ids.count())
+                       aid = ids.takeFirst().toInt();
+
+               if (eid)
+                       emit episodeInsert(eid, aid);
+       }
+       else if (name == "file_insert")
+       {
+               QStringList ids = payload.toString().split(QChar(','), QString::SkipEmptyParts);
+               int fid = 0;
+               int eid = 0;
+               int aid = 0;
+
+               if (ids.count())
+                       fid = ids.takeFirst().toInt();
+               if (ids.count())
+                       eid = ids.takeFirst().toInt();
+               if (ids.count())
+                       aid = ids.takeFirst().toInt();
+
+               if (fid)
+                       emit fileUpdate(fid, eid, aid);
+       }
+       else if (name == "file_location_insert")
+       {
+               int id = payload.toInt();
+               if (id)
+                       emit fileLocationInsert(id);
+       }
 }
 
 
index d569522e491fd1733f591997ff8991095e44eeac..849343700d302e559ed594918229960920ac6a42 100644 (file)
@@ -158,6 +158,11 @@ signals:
        void fileUpdate(int fid, int eid, int aid);
        void fileLocationUpdate(int id);
 
+       void animeInsert(int aid);
+       void episodeInsert(int eid, int aid);
+       void fileInsert(int fid, int eid, int aid);
+       void fileLocationInsert(int id);
+
 private slots:
        void handleNotification(const QString &name, QSqlDriver::NotificationSource source, const QVariant &payload);
 
index 4ac83e2701346596cad8415c8f3e5f3d7f1ad113..d3aa66add272b26187f117c30d59ffe5ea898aac 100644 (file)
@@ -18,6 +18,11 @@ MyListModel::MyListModel(QObject *parent) :
        connect(MyList::instance()->database(), SIGNAL(episodeUpdate(int,int)), this, SLOT(episodeUpdate(int,int)));
        connect(MyList::instance()->database(), SIGNAL(fileUpdate(int,int,int)), this, SLOT(fileUpdate(int,int,int)));
        connect(MyList::instance()->database(), SIGNAL(fileLocationUpdate(int)), this, SLOT(fileLocationUpdate(int)));
+
+       connect(MyList::instance()->database(), SIGNAL(animeInsert(int)), this, SLOT(animeInsert(int)));
+       connect(MyList::instance()->database(), SIGNAL(episodeInsert(int,int)), this, SLOT(episodeInsert(int,int)));
+       connect(MyList::instance()->database(), SIGNAL(fileInsert(int,int,int)), this, SLOT(fileInsert(int,int,int)));
+       connect(MyList::instance()->database(), SIGNAL(fileLocationInsert(int)), this, SLOT(fileLocationInsert(int)));
 }
 
 MyListModel::~MyListModel()
@@ -308,7 +313,8 @@ void MyListModel::animeUpdate(int aid)
        if (!updatedNode)
                return;
 
-       updatedNode->updated();
+       if (updatedNode->updated(MyListNode::UpdateOperation))
+               updatedNode->parent()->moveChild(updatedNode, MyListNode::UpdateOperation);
 }
 
 void MyListModel::episodeUpdate(int eid, int aid)
@@ -320,7 +326,8 @@ void MyListModel::episodeUpdate(int eid, int aid)
                return;
        }
 
-       updatedNode->updated();
+       if (updatedNode->updated(MyListNode::UpdateOperation))
+               updatedNode->parent()->moveChild(updatedNode, MyListNode::UpdateOperation);
 }
 
 void MyListModel::fileUpdate(int fid, int eid, int aid)
@@ -332,7 +339,8 @@ void MyListModel::fileUpdate(int fid, int eid, int aid)
                return;
        }
 
-       updatedNode->updated();
+       if (updatedNode->updated(MyListNode::UpdateOperation))
+               updatedNode->parent()->moveChild(updatedNode, MyListNode::UpdateOperation);
 }
 
 void MyListModel::fileLocationUpdate(int id)
@@ -341,7 +349,55 @@ void MyListModel::fileLocationUpdate(int id)
        if (!updatedNode)
                return;
 
-       updatedNode->updated();
+       if (updatedNode->updated(MyListNode::UpdateOperation))
+               updatedNode->parent()->moveChild(updatedNode, MyListNode::UpdateOperation);
+}
+
+void MyListModel::animeInsert(int aid)
+{
+       if (animeIndex(aid).isValid())
+               return;
+       rootItem->childAdded(aid);
+}
+
+void MyListModel::episodeInsert(int eid, int aid)
+{
+       if (episodeIndex(eid).isValid())
+               return;
+
+       MyListNode *parentNode = node(animeIndex(aid));
+
+       if (!parentNode)
+               return;
+
+       parentNode->childAdded(eid);
+}
+
+void MyListModel::fileInsert(int fid, int eid, int aid)
+{
+       if (fileIndex(fid).isValid())
+               return;
+
+       MyListNode *parentNode = node(episodeIndex(eid));
+
+       if (!parentNode)
+       {
+               parentNode = node(animeIndex(aid));
+               if (!parentNode)
+                       return;
+               parentNode->updated(MyListNode::UpdateOperation);
+               return;
+       }
+
+       parentNode->childAdded(eid);
+}
+
+void MyListModel::fileLocationInsert(int id)
+{
+       if (fileLocationIndex(id).isValid())
+               return;
+
+
 }
 
 QModelIndex MyListModel::index(MyListNode *node) const
index 0ccba04608d523296370ba96e0e37bce4421596e..e92e4a4840042834649f311f25f874842db74c27 100644 (file)
@@ -80,6 +80,11 @@ private slots:
        void fileUpdate(int fid, int eid, int aid);
        void fileLocationUpdate(int id);
 
+       void animeInsert(int aid);
+       void episodeInsert(int eid, int aid);
+       void fileInsert(int fid, int eid, int aid);
+       void fileLocationInsert(int id);
+
 protected:
        QModelIndex index(MyListNode *node) const;
        void fetchFinished(MyListNode *node, int newrows);
index 811d03c8117b9a98d3e5477d84b4d589d9a12dc2..ddf355cb0f8da31b84fab008d8230892923e427c 100644 (file)
@@ -5,6 +5,7 @@
 #include "database.h"
 #include <QSqlQuery>
 #include "sqlasyncquery.h"
+#include <algorithm>
 #include <QDebug>
 
 namespace LocalMyList {
@@ -154,21 +155,119 @@ QString MyListNode::totalRowCountSql() const
        return "SELECT COUNT(aid) FROM anime";
 }
 
-void MyListNode::childUpdate(const EpisodeData &oldData, const EpisodeData &newData)
+void MyListNode::childUpdate(const EpisodeData &oldData, const EpisodeData &newData, Operation type)
 {
        Q_UNUSED(oldData)
        Q_UNUSED(newData)
+       Q_UNUSED(type)
 }
 
-void MyListNode::childUpdate(const FileData &oldData, const FileData &newData)
+void MyListNode::childUpdate(const FileData &oldData, const FileData &newData, Operation type)
 {
        Q_UNUSED(oldData)
-       Q_UNUSED(newData)}
+       Q_UNUSED(newData)
+       Q_UNUSED(type)
+}
 
-void MyListNode::childUpdate(const FileLocationData &oldData, const FileLocationData &newData)
+void MyListNode::childUpdate(const FileLocationData &oldData, const FileLocationData &newData, Operation type)
 {
        Q_UNUSED(oldData)
        Q_UNUSED(newData)
+       Q_UNUSED(type)
+}
+
+MyListNodeCompare MyListNode::compareFunction() const
+{
+       return [](MyListNode *a, MyListNode *b) -> bool
+       {
+               const MyListAnimeNode *aa = static_cast<MyListAnimeNode *>(a);
+               const MyListAnimeNode *ab = static_cast<MyListAnimeNode *>(b);
+               return aa->internalData().data.titleRomaji < ab->internalData().data.titleRomaji;
+       };
+}
+
+MyListNode::MoveType MyListNode::moveChild(MyListNode *child, Operation type)
+{
+       const QModelIndex idx = model->index(this);
+
+       if (type == InsertOperation)
+       {
+               auto it = std::upper_bound(childItems.begin(), childItems.end(), child, compareFunction());
+
+               if (it == childItems.end() && canFetchMore())
+               {
+                       delete child;
+                       return OutOfBoundsMove;
+               }
+
+               const int newRow = qMax(0, (it - childItems.begin()) - 1);
+
+               model->beginInsertRows(idx, newRow, newRow);
+               it = childItems.insert(it, child);
+               model->endInsertRows();
+               return SuccessfulMove;
+       }
+
+       const auto oldPos = std::find(childItems.begin(), childItems.end(), child);
+       const int oldRow = oldPos == childItems.end() ? -1 : oldPos - childItems.begin();
+
+       if (type == DeleteOperation)
+       {
+               if (oldRow != -1)
+               {
+                       model->beginRemoveRows(idx, oldRow, oldRow);
+                       childItems.removeAt(oldRow);
+                       model->endRemoveRows();
+               }
+               delete child;
+               return SuccessfulMove;
+       }
+
+       auto lower = std::upper_bound(childItems.begin(), oldPos, child, compareFunction());
+       auto upper = std::lower_bound(oldPos, childItems.end(), child, compareFunction());
+
+       // No move needed
+       if (lower == upper)
+       {
+               return NoMove;
+       }
+
+       decltype(childItems.begin()) it;
+
+       // New pos in upper part
+       if (lower == oldPos)
+               it = upper;
+       else
+               it = lower;
+
+       // Added item is not in the currently loaded data
+       if (it == childItems.end() && canFetchMore())
+       {
+               model->beginRemoveRows(idx, oldRow, oldRow);
+               childItems.removeAt(oldRow);
+               model->endRemoveRows();
+               delete child;
+
+               return OutOfBoundsMove;
+       }
+
+       const int nextRow = it - childItems.begin();
+       const int newRow = qMax(0, nextRow - 1);
+
+       if (oldRow < newRow)
+       {
+               model->beginMoveRows(idx, oldRow, oldRow, idx, nextRow);
+               childItems.move(oldRow, newRow);
+               model->endMoveRows();
+       }
+       else
+       {
+               model->beginMoveRows(idx, oldRow, oldRow, idx, newRow);
+               childItems.move(oldRow, nextRow);
+               model->endMoveRows();
+       }
+
+       return SuccessfulMove;
 }
 
 MyListNode::NodeType MyListNode::type() const
@@ -181,8 +280,25 @@ int MyListNode::id() const
        return 0;
 }
 
-void MyListNode::updated()
+void MyListNode::childAdded(int id)
+{
+       qDebug() << "childAdded" << id;
+       if (m_totalRowCount == -1)
+               return;
+
+       MyListAnimeNode *newChild = new MyListAnimeNode(model, AnimeData(id), this);
+       newChild->updated(InsertOperation);
+
+       MoveType result = moveChild(newChild, InsertOperation);
+
+       if (result == SuccessfulMove)
+               ++m_totalRowCount;
+}
+
+bool MyListNode::updated(Operation type)
 {
+       Q_UNUSED(type)
+       return false;
 }
 
 // ------
@@ -270,42 +386,80 @@ int MyListAnimeNode::id() const
        return animeData.data.aid;
 }
 
-void MyListAnimeNode::updated()
+void MyListAnimeNode::childAdded(int id)
+{
+       qDebug() << "MyListAnimeNode::childAdded" << id << m_totalRowCount;
+       if (m_totalRowCount == -1)
+               return;
+
+       MyListEpisodeNode *newChild = new MyListEpisodeNode(model, EpisodeData(id), this);
+       newChild->updated(InsertOperation);
+
+       MoveType result = moveChild(newChild, InsertOperation);
+
+       if (result == SuccessfulMove)
+               ++m_totalRowCount;
+}
+
+bool MyListAnimeNode::updated(Operation type)
 {
+       Q_UNUSED(type)
        QSqlQuery q = MyList::instance()->database()->prepareOneShot(QString(
        " %1 "
        "WHERE a.aid = :aid").arg(baseQuery()));
        q.bindValue(":aid", id());
 
        if(!MyList::instance()->database()->exec(q))
-               return;
+               return false;
 
        if (!q.next())
-               return;
+               return false;
 
        AnimeData newData;
        fillAnimeData(newData, QSqlResultIterator(q));
+
+       bool orderingChange = animeData.data.titleRomaji != newData.data.titleKanji;
+
        animeData = newData;
        animeData.node = this;
        model->nodeChanged(this);
+
+       return orderingChange;
 }
 
-void MyListAnimeNode::childUpdate(const EpisodeData &oldData, const EpisodeData &newData)
+void MyListAnimeNode::childUpdate(const EpisodeData &oldData, const EpisodeData &newData, Operation type)
 {
        // Episode got watched
-       if (!oldData.watchedDate.isValid() && newData.watchedDate.isValid())
+       if ((type == InsertOperation || !oldData.watchedDate.isValid()) && newData.watchedDate.isValid())
        {
                ++animeData.watchedEpisodes;
                model->nodeChanged(this);
        }
        // Episode got unwatched
-       else if (oldData.watchedDate.isValid() && !newData.watchedDate.isValid())
+       else if ((type == DeleteOperation || !newData.watchedDate.isValid()) && oldData.watchedDate.isValid())
        {
                --animeData.watchedEpisodes;
                model->nodeChanged(this);
        }
 }
 
+MyListNodeCompare MyListAnimeNode::compareFunction() const
+{
+       return [](MyListNode *a, MyListNode *b) -> bool
+       {
+               const MyListEpisodeNode *aa = static_cast<MyListEpisodeNode *>(a);
+               const MyListEpisodeNode *ab = static_cast<MyListEpisodeNode *>(b);
+               if (aa->internalData().episodeTypeOrdering == ab->internalData().episodeTypeOrdering)
+                       return aa->internalData().data.epno < ab->internalData().data.epno;
+               return aa->internalData().episodeTypeOrdering < ab->internalData().episodeTypeOrdering;
+       };
+}
+
+const AnimeData &MyListAnimeNode::internalData() const
+{
+       return animeData;
+}
+
 QString MyListAnimeNode::baseQuery()
 {
        return QString(
@@ -422,33 +576,52 @@ int MyListEpisodeNode::id() const
        return episodeData.data.eid;
 }
 
-void MyListEpisodeNode::updated()
+void MyListEpisodeNode::childAdded(int id)
+{
+       if (m_totalRowCount == -1)
+               return;
+
+       MyListFileNode *newChild = new MyListFileNode(model, FileData(id), this);
+       newChild->updated(InsertOperation);
+
+       MoveType result = moveChild(newChild, InsertOperation);
+
+       if (result == SuccessfulMove)
+               ++m_totalRowCount;
+}
+
+bool MyListEpisodeNode::updated(Operation type)
 {
+       Q_UNUSED(type)
        QSqlQuery q = MyList::instance()->database()->prepareOneShot(QString(
        " %1 "
        "WHERE e.eid = :eid").arg(baseQuery()));
        q.bindValue(":eid", id());
 
        if(!MyList::instance()->database()->exec(q))
-               return;
+               return false;
 
        if (!q.next())
-               return;
+               return false;
 
        EpisodeData newData;
        fillEpisodeData(newData, QSqlResultIterator(q));
 
-       parent()->childUpdate(episodeData, newData);
+       parent()->childUpdate(episodeData, newData, type);
+       bool orderingChanged = episodeData.episodeTypeOrdering != newData.episodeTypeOrdering
+                       || episodeData.data.epno != newData.data.epno;
 
        episodeData = newData;
        episodeData.node = this;
        model->nodeChanged(this);
+
+       return orderingChanged;
 }
 
-void MyListEpisodeNode::childUpdate(const FileData &oldData, const FileData &newData)
+void MyListEpisodeNode::childUpdate(const FileData &oldData, const FileData &newData, Operation type)
 {
        // File from episode got watched
-       if (!oldData.data.myWatched.isValid() && newData.data.myWatched.isValid())
+       if ((type == InsertOperation || !oldData.data.myWatched.isValid()) && newData.data.myWatched.isValid())
        {
                if (!episodeData.watchedDate.isValid()
                        || (episodeData.watchedDate.isValid()
@@ -459,11 +632,11 @@ void MyListEpisodeNode::childUpdate(const FileData &oldData, const FileData &new
                        episodeData.watchedDate = newData.data.myWatched;
                        model->nodeChanged(this);
 
-                       parent()->childUpdate(oldData, episodeData);
+                       parent()->childUpdate(oldData, episodeData, UpdateOperation);
                }
        }
        // Watched date changed
-       else if (oldData.data.myWatched.isValid() && newData.data.myWatched.isValid())
+       else if ((type == UpdateOperation && oldData.data.myWatched.isValid()) && newData.data.myWatched.isValid())
        {
                if (episodeData.watchedDate.isValid() && newData.data.myWatched < episodeData.watchedDate)
                {
@@ -472,18 +645,33 @@ void MyListEpisodeNode::childUpdate(const FileData &oldData, const FileData &new
                        episodeData.watchedDate = newData.data.myWatched;
                        model->nodeChanged(this);
 
-                       parent()->childUpdate(oldData, episodeData);
+                       parent()->childUpdate(oldData, episodeData, UpdateOperation);
                }
        }
        // File got unwatched
-       else if (oldData.data.myWatched.isValid() && !newData.data.myWatched.isValid())
+       else if ((type == DeleteOperation || !newData.data.myWatched.isValid()) && oldData.data.myWatched.isValid())
        {
                // No real way to get the proper watched date without
                // looking at other children.
-               updated();
+               updated(UpdateOperation);
        }
 }
 
+MyListNodeCompare MyListEpisodeNode::compareFunction() const
+{
+       return [](MyListNode *a, MyListNode *b) -> bool
+       {
+               const MyListFileNode *aa = static_cast<MyListFileNode *>(a);
+               const MyListFileNode *ab = static_cast<MyListFileNode *>(b);
+               return aa->internalData().data.fid < ab->internalData().data.fid;
+       };
+}
+
+const EpisodeData &MyListEpisodeNode::internalData() const
+{
+       return episodeData;
+}
+
 QString MyListEpisodeNode::baseQuery()
 {
        return QString(
@@ -500,7 +688,7 @@ QString MyListEpisodeNode::baseQuery()
        "                                       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, "
-       "               %1 "
+       "               et.ordering, %1 "
        "       FROM episode e "
        "       JOIN episode_type et ON (et.type = e.type)")
                        .arg(Database::episodeFields());
@@ -509,7 +697,8 @@ QString MyListEpisodeNode::baseQuery()
 void MyListEpisodeNode::fillEpisodeData(EpisodeData &data, SqlResultIteratorInterface &query)
 {
        data.watchedDate = query.value(0).toDateTime();
-       Database::readEpisodeData(query, data.data, 1);
+       data.episodeTypeOrdering = query.value(1).toInt();
+       Database::readEpisodeData(query, data.data, 2);
 }
 
 // ---------------
@@ -579,7 +768,12 @@ int MyListFileNode::id() const
        return fileData.data.fid;
 }
 
-void MyListFileNode::updated()
+void MyListFileNode::childAdded(int id)
+{
+       Q_UNUSED(id)
+}
+
+bool MyListFileNode::updated(Operation type)
 {
        QSqlQuery q = MyList::instance()->database()->prepareOneShot(QString(
        "SELECT %1 "
@@ -589,19 +783,36 @@ void MyListFileNode::updated()
        q.bindValue(":fid", id());
 
        if(!MyList::instance()->database()->exec(q))
-               return;
+               return false;
 
        if (!q.next())
-               return;
+               return false;
 
        FileData newData;
        fillFileData(newData, QSqlResultIterator(q));
 
-       parent()->childUpdate(fileData, newData);
+       parent()->childUpdate(fileData, newData, type);
 
        fileData = newData;
        fileData.node = this;
        model->nodeChanged(this);
+
+       return false;
+}
+
+MyListNodeCompare MyListFileNode::compareFunction() const
+{
+       return [](MyListNode *a, MyListNode *b) -> bool
+       {
+               const MyListFileLocationNode *aa = static_cast<MyListFileLocationNode *>(a);
+               const MyListFileLocationNode *ab = static_cast<MyListFileLocationNode *>(b);
+               return aa->internalData().data.locationId < ab->internalData().data.locationId;
+       };
+}
+
+const FileData &MyListFileNode::internalData() const
+{
+       return fileData;
 }
 
 QString MyListFileNode::baseQuery()
@@ -669,7 +880,7 @@ int MyListFileLocationNode::id() const
        return fileLocationData.data.locationId;
 }
 
-void MyListFileLocationNode::updated()
+bool MyListFileLocationNode::updated(Operation type)
 {
        QSqlQuery q = MyList::instance()->database()->prepareOneShot(QString(
        " %1 "
@@ -678,20 +889,26 @@ void MyListFileLocationNode::updated()
        q.bindValue(":locationId", id());
 
        if(!MyList::instance()->database()->exec(q))
-               return;
+               return false;
 
        if (!q.next())
-               return;
+               return false;
 
        FileLocationData newData;
        fillFileLocationData(newData, QSqlResultIterator(q));
 
-       parent()->childUpdate(fileLocationData, newData);
+       parent()->childUpdate(fileLocationData, newData, type);
 
        fileLocationData = newData;
        fileLocationData.node = this;
        model->nodeChanged(this);
 
+       return false;
+}
+
+const FileLocationData &MyListFileLocationNode::internalData() const
+{
+       return fileLocationData;
 }
 
 QString MyListFileLocationNode::baseQuery()
index fa429a9f8bf3ca91f5d98197aa56d604aed4f591..ccc7226548ae9350dc74c6692c32a18f494f4d62 100644 (file)
@@ -12,6 +12,8 @@ class MyListModel;
 class SqlAsyncQuery;
 class SqlResultIteratorInterface;
 
+typedef bool (*MyListNodeCompare)(MyListNode *a, MyListNode *b);
+
 class LOCALMYLISTSHARED_EXPORT MyListNode
 {
 public:
@@ -23,6 +25,18 @@ public:
                FileLocationNode
        };
 
+       enum Operation {
+               UpdateOperation,
+               InsertOperation,
+               DeleteOperation
+       };
+
+       enum MoveType {
+               NoMove,
+               SuccessfulMove,
+               OutOfBoundsMove
+       };
+
        MyListNode(MyListModel *model, NodeType type = RootNode, MyListNode *parent = 0);
        virtual ~MyListNode();
 
@@ -47,10 +61,15 @@ public:
        NodeType type() const;
        virtual int id() const;
 
-       virtual void updated();
-       virtual void childUpdate(const EpisodeData &oldData, const EpisodeData &newData);
-       virtual void childUpdate(const FileData &oldData, const FileData &newData);
-       virtual void childUpdate(const FileLocationData &oldData, const FileLocationData &newData);
+       virtual void childAdded(int id);
+       virtual bool updated(Operation type);
+       virtual void childUpdate(const EpisodeData &oldData, const EpisodeData &newData, Operation type);
+       virtual void childUpdate(const FileData &oldData, const FileData &newData, Operation type);
+       virtual void childUpdate(const FileLocationData &oldData, const FileLocationData &newData, Operation type);
+
+       virtual MyListNodeCompare compareFunction() const;
+
+       MoveType moveChild(MyListNode *child, Operation type);
 
 protected:
        virtual QString totalRowCountSql() const;
@@ -82,8 +101,13 @@ public:
        void fetchMore();
        void fetchComplete();
        int id() const;
-       void updated();
-       void childUpdate(const EpisodeData &oldData, const EpisodeData &newData);
+       void childAdded(int id);
+       bool updated(Operation type);
+       void childUpdate(const EpisodeData &oldData, const EpisodeData &newData, Operation type);
+
+       MyListNodeCompare compareFunction() const;
+
+       const AnimeData &internalData() const;
 
        static QString baseQuery();
        static void fillAnimeData(AnimeData &data, SqlResultIteratorInterface &q);
@@ -106,8 +130,13 @@ public:
        void fetchMore();
        void fetchComplete();
        int id() const;
-       void updated();
-       void childUpdate(const FileData &oldData, const FileData &newData);
+       void childAdded(int id);
+       bool updated(Operation type);
+       void childUpdate(const FileData &oldData, const FileData &newData, Operation type);
+
+       MyListNodeCompare compareFunction() const;
+
+       const EpisodeData &internalData() const;
 
        static QString baseQuery();
        static void fillEpisodeData(EpisodeData &data, SqlResultIteratorInterface &query);
@@ -129,7 +158,12 @@ public:
        void fetchMore();
        void fetchComplete();
        int id() const;
-       void updated();
+       void childAdded(int id);
+       bool updated(Operation type);
+
+       MyListNodeCompare compareFunction() const;
+
+       const FileData &internalData() const;
 
        static QString baseQuery();
        static void fillFileData(FileData &data, SqlResultIteratorInterface &query);
@@ -151,7 +185,9 @@ public:
        void fetchMore();
        void fetchComplete();
        int id() const;
-       void updated();
+       bool updated(Operation type);
+
+       const FileLocationData &internalData() const;
 
        static QString baseQuery();
        static void fillFileLocationData(FileLocationData &data, SqlResultIteratorInterface &query);
index 046f5aef8abf5102c160d8c2c42e958a418c86c6..09e6efed59ea9ce788df4ccffcd4ac91221b5f88 100644 (file)
@@ -24,10 +24,6 @@ struct AnimeData : public boost::intrusive::set_base_hook< >
 
        AnimeData(int aid = 0)
        { data.aid = 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< >
@@ -36,16 +32,13 @@ struct EpisodeData : public boost::intrusive::set_base_hook< >
        MyListEpisodeNode *node;
 
        QDateTime watchedDate;
+       int episodeTypeOrdering;
 
        friend bool operator<(const EpisodeData &a, const EpisodeData &b)
        { return a.data.eid < b.data.eid; }
 
        EpisodeData(int eid = 0)
        { data.eid = eid; }
-
-       EpisodeData(const Episode &episodeData, const QDateTime &watchedDate_)
-               : data(episodeData), node(0), watchedDate(watchedDate_)
-       {}
 };
 
 struct FileData : public boost::intrusive::set_base_hook< >
@@ -58,10 +51,6 @@ struct FileData : public boost::intrusive::set_base_hook< >
 
        FileData(int fid = 0)
        { data.fid = fid; }
-
-       FileData(const File &fileData)
-               : data(fileData), node(0)
-       {}
 };
 
 struct FileLocationData : public boost::intrusive::set_base_hook< >
@@ -76,10 +65,6 @@ struct FileLocationData : public boost::intrusive::set_base_hook< >
 
        FileLocationData(int locationId = 0)
        { data.locationId = locationId; }
-
-       FileLocationData(const FileLocation &fileLocationData, const QString &hostName_)
-               : data(fileLocationData), node(0), hostName(hostName_)
-       {}
 };
 
 } // namespace LocalMyList
index fe3c07efa048f73470d295b185b93a50bed56e29..782f8eed2d6821e35fd23ee8ef6b6351703dc7ac 100644 (file)
@@ -237,10 +237,6 @@ CREATE VIEW rename_data AS
                JOIN episode e ON e.eid = f.eid
                JOIN file_location fl ON fl.fid = f.fid;
 
-CREATE RULE new_anime_rule AS ON INSERT TO anime DO NOTIFY rename_data_changed;
-CREATE RULE new_episode_rule AS ON INSERT TO episode DO NOTIFY rename_data_changed;
-CREATE RULE new_file_rule AS ON INSERT TO file DO NOTIFY rename_data_changed;
-
 --  WHEN (OLD.* IS DISTINCT FROM NEW.*) <- means if anything changed
 CREATE RULE update_anime_rule AS
        ON UPDATE TO anime
@@ -292,6 +288,22 @@ COMMENT ON RULE unknown_file_ignore_duplicate ON unknown_file IS 'Adding the sam
 
 CREATE RULE new_pending_mylist_update_rule AS ON INSERT TO pending_mylist_update DO NOTIFY new_pending_mylist_update;
 
+-- Add rules
+CREATE OR REPLACE RULE anime_insert_rule AS
+       ON INSERT TO anime DO SELECT pg_notify('rename_data_changed', ''),
+               pg_notify('anime_insert', new.aid::text);
+
+CREATE OR REPLACE RULE episode_insert_rule AS
+       ON INSERT TO episode DO SELECT pg_notify('rename_data_changed', ''),
+               pg_notify('episode_insert', new.eid::text || ',' || new.aid::text);
+
+CREATE OR REPLACE RULE file_insert_rule AS
+       ON INSERT TO file DO SELECT pg_notify('rename_data_changed', ''),
+               pg_notify('file_insert', new.fid::text || ',' || new.eid::text || ',' || new.aid::text);
+
+CREATE OR REPLACE RULE file_location_insert_rule AS
+       ON INSERT TO file_location DO SELECT
+               pg_notify('file_location_insert', new.location_id::text);
 
 -- Update rules
 CREATE OR REPLACE RULE anime_update_rule AS