added drag&drop support for sorting comics in lists

This commit is contained in:
Luis Ángel San Martín
2015-01-30 16:40:57 +01:00
parent 27d096162d
commit aa1398666e
21 changed files with 429 additions and 49 deletions

View File

@ -81,8 +81,6 @@ ClassicComicsView::ClassicComicsView(QWidget *parent)
if(settings->contains(COMICS_VIEW_FLOW_SPLITTER_STATUS))
sVertical->restoreState(settings->value(COMICS_VIEW_FLOW_SPLITTER_STATUS).toByteArray());
}
void ClassicComicsView::setToolBar(QToolBar *toolBar)
@ -104,6 +102,8 @@ void ClassicComicsView::setModel(ComicModel *model)
{
connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)), this, SLOT(applyModelChanges(QModelIndex,QModelIndex,QVector<int>)),Qt::UniqueConnection);
connect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(removeItemsFromFlow(QModelIndex,int,int)),Qt::UniqueConnection);
connect(model, SIGNAL(resortedIndexes(QList<int>)),comicFlow,SLOT(resortCovers(QList<int>)),Qt::UniqueConnection);
connect(model, SIGNAL(newSelectedIndex(QModelIndex)),this,SLOT(setCurrentIndex(QModelIndex)),Qt::UniqueConnection);
tableView->setModel(model);
if(model->rowCount()>0)
@ -146,8 +146,9 @@ void ClassicComicsView::setModel(ComicModel *model)
void ClassicComicsView::setCurrentIndex(const QModelIndex &index)
{
QLOG_INFO() << "*******************************************************ClassicComicsView::setCurrentIndex";
tableView->setCurrentIndex(index);
//TODO ComicsView: scroll comicFlow to index
centerComicFlow(index);
}
QModelIndex ClassicComicsView::currentIndex()

View File

@ -20,7 +20,7 @@ public:
ClassicComicsView(QWidget *parent = 0);
void setToolBar(QToolBar * toolBar);
void setModel(ComicModel *model);
void setCurrentIndex(const QModelIndex &index);
QModelIndex currentIndex();
QItemSelectionModel * selectionModel();
void scrollTo(const QModelIndex & mi, QAbstractItemView::ScrollHint hint );
@ -31,6 +31,7 @@ public:
void selectIndex(int index);
public slots:
void setCurrentIndex(const QModelIndex &index);
void centerComicFlow(const QModelIndex & mi);
void updateTableView(int i);
void saveTableHeadersStatus();

View File

@ -142,7 +142,33 @@ void ComicFlow::removeSlide(int cover)
YACReaderFlow::removeSlide(cover);
worker->unlock();
preload();
preload();
}
void ComicFlow::resortCovers(QList<int> newOrder)
{
worker->lock();
worker->reset();
YACReaderFlow::resortCovers(newOrder);
QStringList imageFilesNew;
QVector<bool> imagesLoadedNew;
QVector<bool> imagesSettedNew;
foreach(int index, newOrder)
{
imageFilesNew << imageFiles.at(index);
imagesLoadedNew << imagesLoaded.at(index);
imagesSettedNew << imagesSetted.at(index);
}
imageFiles = imageFilesNew;
imagesLoaded = imagesLoadedNew;
imagesSetted = imagesSettedNew;
worker->unlock();
}
//-----------------------------------------------------------------------------
//ImageLoader

View File

@ -24,6 +24,7 @@ public:
//bool eventFilter(QObject *target, QEvent *event);
void keyPressEvent(QKeyEvent* event);
void removeSlide(int cover);
void resortCovers(QList<int> newOrder);
private slots:
void preload();

View File

@ -137,7 +137,12 @@ void ComicFlowWidgetSW::updateConfig(QSettings * settings)
void ComicFlowWidgetSW::remove(int cover)
{
flow->removeSlide(cover);
flow->removeSlide(cover);
}
void ComicFlowWidgetSW::resortCovers(QList<int> newOrder)
{
flow->resortCovers(newOrder);
}
@ -329,7 +334,12 @@ void ComicFlowWidgetGL::updateConfig(QSettings * settings)
void ComicFlowWidgetGL::remove(int cover)
{
flow->remove(cover);
flow->remove(cover);
}
void ComicFlowWidgetGL::resortCovers(QList<int> newOrder)
{
flow->resortCovers(newOrder);
}
//void ComicFlowWidgetGL::setCF_RX(int value){ flow->setCF_RX(value);}
@ -342,4 +352,4 @@ void ComicFlowWidgetGL::remove(int cover)
//void ComicFlowWidgetGL::setZ_Distance(int distance){ flow->setZ_Distance(distance);}
//void ComicFlowWidgetGL::setCF_Y(int value){ flow->setCF_Y(value);}
//void ComicFlowWidgetGL::setY_Distance(int value){ flow->setY_Distance(value);}
//void ComicFlowWidgetGL::setPreset(const Preset & p){ flow->setPreset(p);}
//void ComicFlowWidgetGL::setPreset(const Preset & p){ flow->setPreset(p);}

View File

@ -31,6 +31,7 @@ public slots:
virtual void render() = 0;
virtual void updateConfig(QSettings * settings) = 0;
virtual void remove(int cover) = 0;
virtual void resortCovers(QList<int> newOrder) = 0;
signals:
void centerIndexChanged(int);
void selected(unsigned int);
@ -61,6 +62,7 @@ public:
void render();
void updateConfig(QSettings * settings);
void remove(int cover);
void resortCovers(QList<int> newOrder);
protected:
void keyPressEvent(QKeyEvent* event);
void paintEvent(QPaintEvent *event);
@ -97,6 +99,7 @@ public:
void render();
void updateConfig(QSettings * settings);
void remove(int cover);
void resortCovers(QList<int> newOrder);
//public slots:
// void setCF_RX(int value);
// //the Y Rotation of the Coverflow
@ -125,4 +128,4 @@ protected:
QSize sizeHint() const;
};
#endif
#endif

View File

@ -17,6 +17,11 @@ void ComicsView::setModel(ComicModel *m)
void ComicsView::dragEnterEvent(QDragEnterEvent *event)
{
if(model->canDropMimeData(event->mimeData(),event->proposedAction(),0,0,QModelIndex()))
event->acceptProposedAction();
else
{
QLOG_INFO() << "dragEnterEvent";
QList<QUrl> urlList;
if (event->mimeData()->hasUrls() && event->dropAction() == Qt::CopyAction)
@ -34,6 +39,7 @@ void ComicsView::dragEnterEvent(QDragEnterEvent *event)
}
}
}
}
}
void ComicsView::dropEvent(QDropEvent *event)
@ -42,7 +48,7 @@ void ComicsView::dropEvent(QDropEvent *event)
bool validAction = event->dropAction() == Qt::CopyAction;// || event->dropAction() & Qt::MoveAction; TODO move
if(validAction)
if(event->mimeData()->hasUrls() && validAction)
{
QList<QPair<QString, QString> > droppedFiles = ComicFilesManager::getDroppedFiles(event->mimeData()->urls());

View File

@ -40,6 +40,118 @@ int ComicModel::columnCount(const QModelIndex &parent) const
return _data.first()->columnCount();
}
bool ComicModel::canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) const
{
if(!enableResorting)
return false;
return data->formats().contains(YACReader::YACReaderLibrarComiscSelectionMimeDataFormat);
}
//TODO: optimize this method
bool ComicModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
{
QAbstractItemModel::dropMimeData(data,action,row,column,parent);
QLOG_INFO() << ">>>>>>>>>>>>>>dropMimeData ComicModel<<<<<<<<<<<<<<<<<"<< parent << row << "," << column;
if(!data->formats().contains(YACReader::YACReaderLibrarComiscSelectionMimeDataFormat))
return false;
QList<qulonglong> comicIds = YACReader::mimeDataToComicsIds(data);
QList<int> currentIndexes;
int i;
foreach(qulonglong id, comicIds)
{
i = 0;
foreach (ComicItem *item, _data) {
if(item->data(Id)==id)
{
currentIndexes << i;
break;
}
i++;
}
}
std::sort(currentIndexes.begin(), currentIndexes.end());
QList<ComicItem *> resortedData;
if(currentIndexes.contains(row))//no resorting
return false;
ComicItem * destinationItem;
if(row == -1 || row >= _data.length())
destinationItem = 0;
else
destinationItem = _data.at(row);
QList<int> newSorting;
i = 0;
foreach (ComicItem *item, _data) {
if(!currentIndexes.contains(i))
{
if(item == destinationItem) {
foreach(int index, currentIndexes)
{
resortedData << _data.at(index);
newSorting << index;
}
}
resortedData << item;
newSorting << i;
}
i++;
}
if(destinationItem == 0)
{
foreach(int index, currentIndexes)
{
resortedData << _data.at(index);
newSorting << index;
}
}
QLOG_INFO() << newSorting;
_data = resortedData;
//TODO emit signals
//TODO fix selection
QList<qulonglong> allComicIds;
foreach (ComicItem *item, _data) {
allComicIds << item->data(Id).toULongLong();
}
QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath);
switch (mode) {
case Favorites:
DBHelper::reasignOrderToComicsInFavorites(allComicIds,db);
break;
case Label:
DBHelper::reasignOrderToComicsInLabel(sourceId,allComicIds,db);
break;
case ReadingList:
DBHelper::reasignOrderToComicsInReadingList(sourceId,allComicIds,db);
break;
}
QSqlDatabase::removeDatabase(_databasePath);
emit resortedIndexes(newSorting);
int destSelectedIndex = row<0?_data.length():row;
if(destSelectedIndex>currentIndexes.at(0))
emit newSelectedIndex(index(qMax(0,destSelectedIndex-1),0,parent));
else
emit newSelectedIndex(index(qMax(0,destSelectedIndex),0,parent));
return true;
}
QMimeData *ComicModel::mimeData(const QModelIndexList &indexes) const
{
//custom model data
@ -62,6 +174,14 @@ QMimeData *ComicModel::mimeData(const QModelIndexList &indexes) const
return mimeData;
}
QStringList ComicModel::mimeTypes() const
{
QLOG_DEBUG() << "mimeTypes";
QStringList list;
list << YACReader::YACReaderLibrarComiscSelectionMimeDataFormat;
return list;
}
QHash<int, QByteArray> ComicModel::roleNames() const {
QHash<int, QByteArray> roles;
@ -162,10 +282,10 @@ QVariant ComicModel::data(const QModelIndex &index, int role) const
Qt::ItemFlags ComicModel::flags(const QModelIndex &index) const
{
if (!index.isValid())
return 0;
return 0;
if(index.column() == ComicModel::Rating)
return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable;
return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled;
return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled ;
}
QVariant ComicModel::headerData(int section, Qt::Orientation orientation,
@ -284,6 +404,10 @@ QStringList ComicModel::getPaths(const QString & _source)
void ComicModel::setupFolderModelData(unsigned long long int folderId,const QString & databasePath)
{
enableResorting = false;
mode = Folder;
sourceId=folderId;
beginResetModel();
qDeleteAll(_data);
_data.clear();
@ -309,6 +433,10 @@ void ComicModel::setupFolderModelData(unsigned long long int folderId,const QStr
void ComicModel::setupLabelModelData(unsigned long long parentLabel, const QString &databasePath)
{
enableResorting = true;
mode = Label;
sourceId = parentLabel;
beginResetModel();
qDeleteAll(_data);
_data.clear();
@ -336,6 +464,9 @@ void ComicModel::setupLabelModelData(unsigned long long parentLabel, const QStri
void ComicModel::setupReadingListModelData(unsigned long long parentReadingList, const QString &databasePath)
{
mode = ReadingList;
sourceId = parentReadingList;
beginResetModel();
qDeleteAll(_data);
_data.clear();
@ -356,6 +487,9 @@ void ComicModel::setupReadingListModelData(unsigned long long parentReadingList,
while(subfolders.next())
ids << subfolders.record().value(0).toULongLong();
enableResorting = ids.length()==1;//only resorting if no sublists exist
foreach(qulonglong id, ids)
{
QSqlQuery selectQuery(db);
@ -371,7 +505,7 @@ void ComicModel::setupReadingListModelData(unsigned long long parentReadingList,
QList<ComicItem *> tempData = _data;
_data.clear();
setupModelData(selectQuery);
setupModelDataForList(selectQuery);
_data = tempData << _data;
}
@ -384,6 +518,9 @@ void ComicModel::setupReadingListModelData(unsigned long long parentReadingList,
void ComicModel::setupFavoritesModelData(const QString &databasePath)
{
enableResorting = true;
mode = Favorites;
beginResetModel();
qDeleteAll(_data);
_data.clear();
@ -411,6 +548,9 @@ void ComicModel::setupFavoritesModelData(const QString &databasePath)
void ComicModel::setupReadingModelData(const QString &databasePath)
{
enableResorting = false;
mode = Reading;
beginResetModel();
qDeleteAll(_data);
_data.clear();

View File

@ -34,7 +34,10 @@ public:
QModelIndex parent(const QModelIndex &index) const;
int rowCount(const QModelIndex &parent = QModelIndex()) const;
int columnCount(const QModelIndex &parent = QModelIndex()) 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;
QStringList mimeTypes() const;
void setupFolderModelData(unsigned long long int parentFolder,const QString & databasePath);
void setupLabelModelData(unsigned long long int parentLabel, const QString & databasePath);
@ -113,6 +116,16 @@ public:
};
enum Mode {
Folder,
Favorites,
Reading,
Label,
ReadingList
};
public slots:
void remove(int row);
void startTransaction();
@ -135,11 +148,17 @@ private:
QSqlDatabase dbTransaction;
bool enableResorting;
Mode mode;
qulonglong sourceId;
signals:
void beforeReset();
void reset();
void isEmpty();
void searchNumResults(int);
void resortedIndexes(QList<int>);
void newSelectedIndex(const QModelIndex &);
};
//! [0]

View File

@ -220,7 +220,7 @@ bool DataBaseManagement::createTables(QSqlDatabase & database)
return success;
}
#include "QsLog.h"
bool DataBaseManagement::createV8Tables(QSqlDatabase &database)
{
bool success = true;
@ -304,7 +304,6 @@ bool DataBaseManagement::createV8Tables(QSqlDatabase &database)
//1 Favorites
//queryInsertDefaultReadingList.bindValue(":name", "Favorites");
success = success && queryInsertDefaultReadingList.exec("INSERT INTO default_reading_list (name) VALUES (\"Favorites\")");
QLOG_ERROR() << success;
//Reading doesn't need its onw list

View File

@ -244,10 +244,7 @@ bool ReadingListModel::dropMimeData(const QMimeData *data, Qt::DropAction action
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);
in >> comicIds; //deserialize the list of indentifiers
QList<qulonglong> comicIds = YACReader::mimeDataToComicsIds(data);
QLOG_DEBUG() << "dropped : " << comicIds;

View File

@ -428,6 +428,63 @@ void DBHelper::reasignOrderToSublists(QList<qulonglong> ids, QSqlDatabase &db)
db.commit();
}
void DBHelper::reasignOrderToComicsInFavorites(QList<qulonglong> comicIds, QSqlDatabase &db)
{
QSqlQuery updateOrdering(db);
updateOrdering.prepare("UPDATE comic_default_reading_list SET "
"ordering = :ordering "
"WHERE comic_id = :comic_id AND default_reading_list_id = 0");
db.transaction();
int order = 0;
foreach(qulonglong id, comicIds)
{
updateOrdering.bindValue(":ordering",order++);
updateOrdering.bindValue(":comic_id", id);
updateOrdering.exec();
}
db.commit();
}
void DBHelper::reasignOrderToComicsInLabel(qulonglong labelId, QList<qulonglong> comicIds, QSqlDatabase &db)
{
QSqlQuery updateOrdering(db);
updateOrdering.prepare("UPDATE comic_label SET "
"ordering = :ordering "
"WHERE comic_id = :comic_id AND label_id = :label_id");
db.transaction();
int order = 0;
foreach(qulonglong id, comicIds)
{
updateOrdering.bindValue(":ordering",order++);
updateOrdering.bindValue(":comic_id", id);
updateOrdering.bindValue(":label_id", labelId);
updateOrdering.exec();
}
db.commit();
}
void DBHelper::reasignOrderToComicsInReadingList(qulonglong readingListId, QList<qulonglong> comicIds, QSqlDatabase &db)
{
QSqlQuery updateOrdering(db);
updateOrdering.prepare("UPDATE comic_reading_list SET "
"ordering = :ordering "
"WHERE comic_id = :comic_id AND reading_list_id = :reading_list_id");
db.transaction();
int order = 0;
foreach(qulonglong id, comicIds)
{
updateOrdering.bindValue(":ordering",order++);
updateOrdering.bindValue(":comic_id", id);
updateOrdering.bindValue(":reading_list_id", readingListId);
updateOrdering.exec();
QLOG_INFO() << updateOrdering.lastError().databaseText() << "-" << updateOrdering.lastError().driverText();
}
db.commit();
}
//inserts
qulonglong DBHelper::insert(Folder * folder, QSqlDatabase & db)
{

View File

@ -59,6 +59,9 @@ public:
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 void reasignOrderToComicsInFavorites(QList<qulonglong> comicIds, QSqlDatabase & db);
static void reasignOrderToComicsInLabel(qulonglong labelId, QList<qulonglong> comicIds, QSqlDatabase & db);
static void reasignOrderToComicsInReadingList(qulonglong readingListId, QList<qulonglong> comicIds, QSqlDatabase & db);
static QList<LibraryItem *> getFoldersFromParent(qulonglong parentId, QSqlDatabase & db, bool sort = true);
static QList<ComicDB> getSortedComicsFromParent(qulonglong parentId, QSqlDatabase & db);