mirror of
https://github.com/YACReader/yacreader
synced 2025-06-04 01:28:55 -04:00
reading sublists are now sortable using Drag&Drop
This commit is contained in:
parent
e0b6581003
commit
400acb077e
@ -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())
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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())
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -73,6 +73,7 @@ namespace YACReader
|
||||
{
|
||||
|
||||
static const QString YACReaderLibrarComiscSelectionMimeDataFormat = "application/yacreaderlibrary-comics-ids";
|
||||
static const QString YACReaderLibrarSubReadingListMimeDataFormat = "application/yacreaderlibrary-sublist-rows";
|
||||
|
||||
enum FlowType
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user