reading sublists are now sortable using Drag&Drop

This commit is contained in:
Luis Ángel San Martín 2015-01-18 20:36:19 +01:00
parent e0b6581003
commit 400acb077e
10 changed files with 182 additions and 20 deletions

View File

@ -348,7 +348,8 @@ void ComicModel::setupReadingListModelData(unsigned long long parentReadingList,
QSqlQuery subfolders(db);
subfolders.prepare("SELECT id "
"FROM reading_list "
"WHERE parentId = :parentId");
"WHERE parentId = :parentId "
"ORDER BY ordering ASC");
subfolders.bindValue(":parentId", parentReadingList);
subfolders.exec();
while(subfolders.next())

View File

@ -1,4 +1,5 @@
#include "reading_list_item.h"
#include "qnaturalsorting.h"
ListItem::ListItem(const QList<QVariant> &data)
:itemData(data)
@ -125,10 +126,6 @@ ReadingListItem *ReadingListItem::child(int row)
//items are sorted by order
void ReadingListItem::appendChild(ReadingListItem *item)
{
childItems.append(item);
item->parent = this;
return; //TODO
item->parent = this;
if(childItems.isEmpty())
@ -137,11 +134,17 @@ void ReadingListItem::appendChild(ReadingListItem *item)
{
if(item->parent->getId()==0) //sort by name, top level child
{
int i= 0;
while(i<childItems.length() && naturalSortLessThanCI(childItems.at(i)->name(),item->name()))
i++;
childItems.insert(i,item);
}
else
{
int i= 0;
while(i<childItems.length() && (childItems.at(i)->getOrdering()<item->getOrdering()))
i++;
childItems.insert(i,item);
}
/*ReadingListItem * last = childItems.back();
@ -164,6 +167,11 @@ void ReadingListItem::appendChild(ReadingListItem *item)
}
void ReadingListItem::appendChild(ReadingListItem *item, int pos)
{
childItems.insert(pos, item);
}
void ReadingListItem::removeChild(ReadingListItem *item)
{
childItems.removeOne(item);

View File

@ -69,6 +69,7 @@ public:
int row() const;
ReadingListItem * child(int row);
void appendChild(ReadingListItem *item);
void appendChild(ReadingListItem *item, int pos);
void removeChild(ReadingListItem *item);
qulonglong getId() const;
QString name() const;

View File

@ -114,7 +114,10 @@ Qt::ItemFlags ReadingListModel::flags(const QModelIndex &index) const
if(typeid(*item) == typeid(ReadingListSeparatorItem))
return 0;
return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDropEnabled | Qt::ItemIsDragEnabled;
if(typeid(*item) == typeid(ReadingListItem) && static_cast<ReadingListItem *>(item)->parent->getId()!=0)
return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDropEnabled | Qt::ItemIsDragEnabled; //only sublists are dragable
return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDropEnabled;
}
QVariant ReadingListModel::headerData(int section, Qt::Orientation orientation, int role) const
@ -183,7 +186,7 @@ QModelIndex ReadingListModel::parent(const QModelIndex &index) const
ReadingListItem * childItem = static_cast<ReadingListItem*>(index.internalPointer());
ReadingListItem * parent = childItem->parent;
if(parent->getId() != 0)
return createIndex(parent->row(), 0, parent);
return createIndex(parent->row()+specialLists.count()+labels.count()+2, 0, parent);
}
return QModelIndex();
@ -208,13 +211,39 @@ bool ReadingListModel::canDropMimeData(const QMimeData *data, Qt::DropAction act
return false;
}
return data->formats().contains(YACReader::YACReaderLibrarComiscSelectionMimeDataFormat);
if(data->formats().contains(YACReader::YACReaderLibrarComiscSelectionMimeDataFormat))
return true;
if(rowIsReadingList(row,parent))// TODO avoid droping in a different parent
if(!parent.isValid())
return false;
else
{
QList<QPair<int,int> > sublistsRows;
QByteArray rawData = data->data(YACReader::YACReaderLibrarSubReadingListMimeDataFormat);
QDataStream in(&rawData,QIODevice::ReadOnly);
in >> sublistsRows; //deserialize the list of indentifiers
if(parent.row()!= sublistsRows.at(0).second)
return false;
return data->formats().contains(YACReader::YACReaderLibrarSubReadingListMimeDataFormat);
}
return false;
}
bool ReadingListModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
{
QLOG_DEBUG() << "drop mimedata into row = " << row << " column = " << column << "parent" << parent;
if(data->formats().contains(YACReader::YACReaderLibrarComiscSelectionMimeDataFormat))
return dropComics(data, action, row, column, parent);
if(data->formats().contains(YACReader::YACReaderLibrarSubReadingListMimeDataFormat))
return dropSublist(data, action, row, column, parent);
}
bool ReadingListModel::dropComics(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
{
QList<qulonglong> comicIds;
QByteArray rawData = data->data(YACReader::YACReaderLibrarComiscSelectionMimeDataFormat);
QDataStream in(&rawData,QIODevice::ReadOnly);
@ -258,6 +287,71 @@ bool ReadingListModel::dropMimeData(const QMimeData *data, Qt::DropAction action
return false;
}
bool ReadingListModel::dropSublist(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
{
QList<QPair<int,int> > sublistsRows;
QByteArray rawData = data->data(YACReader::YACReaderLibrarSubReadingListMimeDataFormat);
QDataStream in(&rawData,QIODevice::ReadOnly);
in >> sublistsRows; //deserialize the list of indentifiers
QLOG_DEBUG() << "dropped : " << sublistsRows;
int sourceRow = sublistsRows.at(0).first;
int destRow = row;
QModelIndex destParent = parent;
if(row == -1)
{
QLOG_DEBUG() << "droping inside parent";
destRow = parent.row();
destParent = parent.parent();
}
QLOG_DEBUG() << "move " << sourceRow << "-" << destRow;
if(sourceRow == destRow)
return false;
//beginMoveRows(destParent,sourceRow,sourceRow,destParent,destRow);
ReadingListItem * parentItem = static_cast<ReadingListItem *>(destParent.internalPointer());
ReadingListItem * child = parentItem->child(sourceRow);
parentItem->removeChild(child);
parentItem->appendChild(child,destRow);
reorderingChildren(parentItem->children());
//endMoveRows();
return true;
}
QMimeData *ReadingListModel::mimeData(const QModelIndexList &indexes) const
{
QLOG_DEBUG() << "mimeData requested" << indexes;
if(indexes.length() == 0)
{
QLOG_ERROR() << "mimeData requested: indexes is empty";
return new QMimeData();//TODO what happens if 0 is returned?
}
if(indexes.length() > 1)
QLOG_DEBUG() << "mimeData requested for more than one index, this shouldn't be possible";
QModelIndex modelIndex = indexes.at(0);
QList<QPair<int,int> > rows;
rows << QPair<int,int>(modelIndex.row(),modelIndex.parent().row());
QLOG_DEBUG() << "mimeData requested for row : " << modelIndex.row();
QByteArray data;
QDataStream out(&data,QIODevice::WriteOnly);
out << rows; //serialize the list of identifiers
QMimeData * mimeData = new QMimeData();
mimeData->setData(YACReader::YACReaderLibrarSubReadingListMimeDataFormat, data);
return mimeData;
}
void ReadingListModel::setupReadingListsData(QString path)
{
beginResetModel();
@ -331,17 +425,16 @@ void ReadingListModel::addReadingListAt(const QString &name, const QModelIndex &
beginInsertRows(mi, 0, 0); //TODO calculate the right coordinates before inserting
qulonglong id = DBHelper::insertReadingSubList(name,mi.data(IDRole).toULongLong(),db);
ReadingListItem * newItem;
ReadingListItem * readingListParent = static_cast<ReadingListItem*>(mi.internalPointer());
qulonglong id = DBHelper::insertReadingSubList(name,mi.data(IDRole).toULongLong(),readingListParent->childCount(),db);
ReadingListItem * newItem;
readingListParent->appendChild(newItem = new ReadingListItem(QList<QVariant>()
<< name
<< id
<< false
<< true
<< mi.data(IDRole).toULongLong()));
<< readingListParent->childCount()));
items.insert(id, newItem);
@ -430,6 +523,7 @@ void ReadingListModel::deleteItem(const QModelIndex &mi)
{
if(isEditable(mi))
{
QLOG_DEBUG() << "parent row :" << mi.parent().data() << "-" << mi.row();
beginRemoveRows(mi.parent(),mi.row(),mi.row());
QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath);
@ -439,8 +533,15 @@ void ReadingListModel::deleteItem(const QModelIndex &mi)
if(typeid(*item) == typeid(ReadingListItem))
{
ReadingListItem * rli = static_cast<ReadingListItem*>(item);
QLOG_DEBUG() << "num children : " << rli->parent->childCount();
rli->parent->removeChild(rli);
QLOG_DEBUG() << "num children : " << rli->parent->childCount();
DBHelper::removeListFromDB(item->getId(), db);
if(rli->parent->getId()!=0)
{
reorderingChildren(rli->parent->children());
}
QLOG_DEBUG() << "num children : " << rli->parent->childCount();
}
else if(typeid(*item) == typeid(LabelItem))
{
@ -607,6 +708,20 @@ int ReadingListModel::addLabelIntoList(LabelItem *item)
return 0;
}
void ReadingListModel::reorderingChildren(QList<ReadingListItem *> children)
{
QList<qulonglong> childrenIds;
int i = 0;
foreach (ReadingListItem * item, children) {
item->setOrdering(i++);
childrenIds << item->getId();
}
QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath);
DBHelper::reasignOrderToSublists(childrenIds, db);
QSqlDatabase::removeDatabase(_databasePath);
}
bool ReadingListModel::rowIsSpecialList(int row, const QModelIndex &parent) const
{
if(parent.isValid())

View File

@ -40,6 +40,7 @@ public:
QModelIndex parent(const QModelIndex &index) const;
bool canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) const;
bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent);
QMimeData *mimeData(const QModelIndexList &indexes) const;
//Convenience methods
void setupReadingListsData(QString path);
@ -86,12 +87,15 @@ private:
void setupLabels(QSqlDatabase &db);
void setupReadingLists(QSqlDatabase &db);
int addLabelIntoList(LabelItem *item);
void reorderingChildren(QList<ReadingListItem *> children);
bool rowIsSpecialList(int row, const QModelIndex & parent = QModelIndex()) const;
bool rowIsLabel(int row, const QModelIndex & parent = QModelIndex()) const;
bool rowIsReadingList(int row, const QModelIndex & parent = QModelIndex()) const;
bool rowIsSeparator(int row, const QModelIndex & parent = QModelIndex()) const;
bool dropComics(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent);
bool dropSublist(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent);
//Special lists
QList<SpecialListItem *> specialLists;

View File

@ -410,6 +410,24 @@ void DBHelper::renameList(qulonglong id, const QString &name, QSqlDatabase &db)
renameLabelQuery.exec();
}
void DBHelper::reasignOrderToSublists(QList<qulonglong> ids, QSqlDatabase &db)
{
QSqlQuery updateOrdering(db);
updateOrdering.prepare("UPDATE reading_list SET "
"ordering = :ordering "
"WHERE id = :id");
db.transaction();
int order = 0;
foreach(qulonglong id, ids)
{
updateOrdering.bindValue(":ordering",order++);
updateOrdering.bindValue(":id", id);
updateOrdering.exec();
}
db.commit();
}
//inserts
qulonglong DBHelper::insert(Folder * folder, QSqlDatabase & db)
{
@ -472,13 +490,14 @@ qulonglong DBHelper::insertReadingList(const QString &name, QSqlDatabase &db)
return query.lastInsertId().toULongLong();
}
qulonglong DBHelper::insertReadingSubList(const QString &name, qulonglong parentId, QSqlDatabase &db)
qulonglong DBHelper::insertReadingSubList(const QString &name, qulonglong parentId, int ordering, QSqlDatabase &db)
{
QSqlQuery query(db);
query.prepare("INSERT INTO reading_list (name, parentId) "
"VALUES (:name, :parentId)");
query.prepare("INSERT INTO reading_list (name, parentId, ordering) "
"VALUES (:name, :parentId, :ordering)");
query.bindValue(":name", name);
query.bindValue(":parentId", parentId);
query.bindValue(":ordering", ordering);
query.exec();
return query.lastInsertId().toULongLong();
}

View File

@ -45,7 +45,7 @@ public:
static qulonglong insert(ComicDB * comic, QSqlDatabase & db);
static qulonglong insertLabel(const QString & name, YACReader::LabelColors color , QSqlDatabase & db);
static qulonglong insertReadingList(const QString & name, QSqlDatabase & db);
static qulonglong insertReadingSubList(const QString & name, qulonglong parentId, QSqlDatabase & db);
static qulonglong insertReadingSubList(const QString & name, qulonglong parentId, int ordering, QSqlDatabase & db);
static void insertComicsInFavorites(const QList<ComicDB> & comicsList, QSqlDatabase & db);
static void insertComicsInLabel(const QList<ComicDB> & comicsList, qulonglong labelId, QSqlDatabase & db);
static void insertComicsInReadingList(const QList<ComicDB> & comicsList, qulonglong readingListId, QSqlDatabase & db);
@ -58,6 +58,7 @@ public:
static void updateProgress(qulonglong libraryId,const ComicInfo & comicInfo);
static void renameLabel(qulonglong id, const QString & name, QSqlDatabase & db);
static void renameList(qulonglong id, const QString & name, QSqlDatabase & db);
static void reasignOrderToSublists(QList<qulonglong> ids, QSqlDatabase & db);
static QList<LibraryItem *> getFoldersFromParent(qulonglong parentId, QSqlDatabase & db, bool sort = true);
static QList<ComicDB> getSortedComicsFromParent(qulonglong parentId, QSqlDatabase & db);

View File

@ -8,6 +8,9 @@ YACReaderReadingListsView::YACReaderReadingListsView(QWidget *parent)
{
setItemDelegate(new YACReaderReadingListsViewItemDeletegate(this));
setUniformRowHeights(false);
//enabling internal drag&drop
setDragDropMode(QAbstractItemView::DragDrop);
}
void YACReaderReadingListsView::dragEnterEvent(QDragEnterEvent *event)
@ -27,6 +30,13 @@ void YACReaderReadingListsView::dragMoveEvent(QDragMoveEvent *event)
event->acceptProposedAction();
}
void YACReaderReadingListsView::dropEvent(QDropEvent *event)
{
YACReaderTreeView::dropEvent(event);
}
//----------------------------------------------------------------------
YACReaderReadingListsViewItemDeletegate::YACReaderReadingListsViewItemDeletegate(QObject *parent)

View File

@ -12,9 +12,11 @@ public:
explicit YACReaderReadingListsView(QWidget * parent = 0);
protected:
//Drop to import
//Drop to import & internal Drag&Drop for resorting
void dragEnterEvent(QDragEnterEvent *event);
void dragMoveEvent(QDragMoveEvent *event);
void dropEvent(QDropEvent *event);
};
class YACReaderReadingListsViewItemDeletegate: public QStyledItemDelegate

View File

@ -73,6 +73,7 @@ namespace YACReader
{
static const QString YACReaderLibrarComiscSelectionMimeDataFormat = "application/yacreaderlibrary-comics-ids";
static const QString YACReaderLibrarSubReadingListMimeDataFormat = "application/yacreaderlibrary-sublist-rows";
enum FlowType
{