diff options
author | Arno <am@disconnect.de> | 2014-04-10 16:14:32 +0200 |
---|---|---|
committer | Arno <am@disconnect.de> | 2014-04-10 16:14:32 +0200 |
commit | b0d671fede5adfadad2b465fb4c8ae50b40516f3 (patch) | |
tree | 0215645b3be6eea7dd11c72c987222eddc0a0faa | |
parent | 9f314ad26720a925e8e7a7f1a9f61330f3fd29c1 (diff) | |
download | SheMov-b0d671fede5adfadad2b465fb4c8ae50b40516f3.tar.gz SheMov-b0d671fede5adfadad2b465fb4c8ae50b40516f3.tar.bz2 SheMov-b0d671fede5adfadad2b465fb4c8ae50b40516f3.zip |
Implement Drag and Drop in Movie Archive
Well, this was actually a bit of a drag. You have read the docs very
carefully to get it right. For one, don't construct the drag object in
mousePressEvent if you also want a double click, otherwise you end up
with very weird behavior.
Same goes for the receiving end. Differentiate between dragEnterEvent
and dragMoveEvent, otherwise you'll only be able to drop items if you
hit the right row on entering.
There are some artefacts during the drag, but I guess that's a Qt bug.
Didn't bother to look into it.
-rw-r--r-- | archivecontroller.cpp | 7 | ||||
-rw-r--r-- | archivecontroller.h | 1 | ||||
-rw-r--r-- | archivemodel.cpp | 23 | ||||
-rw-r--r-- | archivemodel.h | 3 | ||||
-rw-r--r-- | archiveview.cpp | 104 | ||||
-rw-r--r-- | archiveview.h | 14 |
6 files changed, 150 insertions, 2 deletions
diff --git a/archivecontroller.cpp b/archivecontroller.cpp index a7d0501..5638119 100644 --- a/archivecontroller.cpp +++ b/archivecontroller.cpp @@ -232,6 +232,13 @@ void ArchiveController::readConfig(){ mGenreIcon = SmGlobals::instance()->iconFor("genre"); } +void ArchiveController::moveFilesToSeriespart(const QStringList &md5Sums, int newSeriesPart){ + foreach(QString md5, md5Sums){ + mArchiveFilesModel->updateSeriesPartForFile(md5, newSeriesPart); + } + mArchiveFilesModel->refresh(); +} + void ArchiveController::treeSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected){ Q_UNUSED(selected); Q_UNUSED(deselected); diff --git a/archivecontroller.h b/archivecontroller.h index e7593e1..fb02383 100644 --- a/archivecontroller.h +++ b/archivecontroller.h @@ -56,6 +56,7 @@ class ArchiveController : public QObject { void addActionForTree(QAction *a); void addCovers(); void readConfig(); + void moveFilesToSeriespart(const QStringList &md5Sums, int newSeriesPart); private slots: void fileDoubleClicked(const QModelIndex &idx); diff --git a/archivemodel.cpp b/archivemodel.cpp index 5369ff7..578ff5c 100644 --- a/archivemodel.cpp +++ b/archivemodel.cpp @@ -62,6 +62,19 @@ ArchiveModel::~ArchiveModel(){ } } +Qt::ItemFlags ArchiveModel::flags(const QModelIndex &index) const{ + SmTreeItem *item = itemAt(index); + Qt::ItemFlags retval = Qt::ItemIsSelectable | Qt::ItemIsEnabled; + if(item->data(Type).toInt() == ArchiveModel::SeriesPartNode){ + retval |= Qt::ItemIsDropEnabled; + } + return retval; +} + +Qt::DropActions ArchiveModel::supportedDragActions() const{ + return Qt::MoveAction; +} + const QStringList ArchiveModel::availableOrders() const { QStringList retval = mAvailableOrders.keys(); qSort(retval); @@ -896,7 +909,7 @@ Qt::ItemFlags ArchiveFilesModel::flags(const QModelIndex &index) const{ return Qt::ItemIsEnabled; } } - return SmTreeModel::flags(index); + return (Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled); } int ArchiveFilesModel::nextDvd() const{ @@ -982,6 +995,14 @@ QStringList ArchiveFilesModel::filesForSeriespart(int seriesPartId) const{ return retval; } +void ArchiveFilesModel::updateSeriesPartForFile(const QString &md5sum, int newSeriesPart){ + QSqlQuery q(mDb); + q.prepare("UPDATE files SET iseriespart_id = :id WHERE cmd5sum = :md5"); + q.bindValue(":id", newSeriesPart); + q.bindValue(":md5", md5sum); + q.exec(); +} + void ArchiveFilesModel::refresh(){ populate(mSeriesPartIds); } diff --git a/archivemodel.h b/archivemodel.h index a9a11eb..20f878c 100644 --- a/archivemodel.h +++ b/archivemodel.h @@ -31,6 +31,8 @@ class ArchiveModel : public SmTreeModel { enum NodeType { SeriesNode = 1, SeriesPartNode = 2, GenreNode = 4, ActorNode = 8, AllNodes = 15 }; explicit ArchiveModel(const QStringList &headers, QObject *parent = 0); virtual ~ArchiveModel(); + virtual Qt::ItemFlags flags(const QModelIndex &index) const; + virtual Qt::DropActions supportedDragActions() const; const QStringList availableOrders() const; const QHash<QString, int> availableOrdersHash() const { return mAvailableOrders; } virtual QVariant data(const QModelIndex &index, int role) const; @@ -103,6 +105,7 @@ class ArchiveFilesModel : public SmTreeModel { bool isMovie(const QModelIndex &idx) const; void populate(const QSet<int> &seriesPartIds); QStringList filesForSeriespart(int seriesPartId) const; + void updateSeriesPartForFile(const QString &md5sum, int newSeriesPart); public slots: void refresh(); diff --git a/archiveview.cpp b/archiveview.cpp index f3656f7..c59130c 100644 --- a/archiveview.cpp +++ b/archiveview.cpp @@ -24,6 +24,12 @@ #include <QStandardItemModel> #include <QFormLayout> #include <QToolBar> +#include <QMouseEvent> +#include <QDrag> +#include <QMimeData> +#include <QDropEvent> +#include <QApplication> +#include <QDataStream> #include "archiveview.h" #include "archivecontroller.h" @@ -152,6 +158,7 @@ ArchiveView::ArchiveView(QWidget *parent) : QWidget(parent) { mainLayout->addWidget(mTreeSplitter); setLayout(mainLayout); + initController(); } @@ -267,7 +274,10 @@ void ArchiveView::initController(){ SmGlobals::instance()->setArchiveController(mController); } -ArchiveTree::ArchiveTree(QWidget *parent) : SmTreeView(parent) {} +ArchiveTree::ArchiveTree(QWidget *parent) : SmTreeView(parent) { + setAcceptDrops(true); + +} void ArchiveTree::setModel(ArchiveProxy *model){ mProxy = model; @@ -440,6 +450,53 @@ void ArchiveTree::newPart(){ } } +void ArchiveTree::dragEnterEvent(QDragEnterEvent *e){ + if(e->mimeData()->hasFormat("application/x-shemov-file")){ + e->acceptProposedAction(); + }else{ + e->ignore(); + } +} + +void ArchiveTree::dragMoveEvent(QDragMoveEvent *e){ + QModelIndex idx = indexAt(e->pos()); + if(idx.isValid()){ + int flags = idx.flags(); + if(flags & Qt::ItemIsDropEnabled){ + e->acceptProposedAction(); + return; + } + } + e->ignore(); + return; +} + +void ArchiveTree::dropEvent(QDropEvent *e){ + QDataStream stream(e->mimeData()->data("application/x-shemov-file")); + int size; + stream >> size; + QString question = QString(tr("Really move %1 items?")).arg(QString::number(size)); + int retval = QMessageBox::question(this, tr("Question"), question); + if(retval == QMessageBox::Yes){ + QModelIndex dropIdx = indexAt(e->pos()); + if(dropIdx.isValid()){ + int newPartId = dropIdx.data(ArchiveModel::SeriesPartIdRole).toInt(); + ArchiveController *c = SmGlobals::instance()->archiveController(); + QStringList md5Sums; + for(int i = 0; i < size; ++i){ + QVariant md5; + stream >> md5; + md5Sums << md5.toString(); + } + c->moveFilesToSeriespart(md5Sums, newPartId); + c->archiveFiles()->expandAll(); + e->accept(); + return; + } + } + e->ignore(); +} + void ArchiveTree::impossible(const QString msg){ QMessageBox::critical(this, tr("Error"), msg); } @@ -454,6 +511,51 @@ QModelIndex ArchiveTree::firstSelected(){ ArchiveFiles::ArchiveFiles(const QString &headerSettings, QWidget *parent) : SmTreeView(headerSettings, parent){ setEditTriggers(QAbstractItemView::NoEditTriggers); + setDragEnabled(true); +} + +void ArchiveFiles::mousePressEvent(QMouseEvent *e){ + if(e->button() == Qt::LeftButton){ + mDragStartPos = e->pos(); + } + return SmTreeView::mousePressEvent(e); +} + +void ArchiveFiles::mouseMoveEvent(QMouseEvent *e){ + if(!(e->buttons() & Qt::LeftButton)){ + return; + } + if((e->pos() - mDragStartPos).manhattanLength() < qApp->startDragDistance()){ + return; + } + + QModelIndexList sel = selectionModel()->selectedRows(); + if(sel.isEmpty()){ + return; + } + + QString files("<ul ul style=\"margin-left: -25; margin-top: 10px; margin-right: 10px; margin-bottom: 10px\">"); + QByteArray dataBuf; + QDataStream stream(&dataBuf, QIODevice::WriteOnly); + stream << sel.size(); + foreach(QModelIndex i, sel){ + files.append("<li>"); + files.append(i.data(ArchiveFilesModel::FilenameRole).toString()); + stream << i.data(ArchiveFilesModel::Md5SumRole); + files.append("</li>"); + } + files.append("</ul>"); + + QLabel dragLabel(files); + QPixmap dragPixmap(dragLabel.size()); + dragLabel.render(&dragPixmap); + + QDrag *drag = new QDrag(this); + QMimeData *mimeData = new QMimeData; + mimeData->setData("application/x-shemov-file", dataBuf); + drag->setMimeData(mimeData); + drag->setPixmap(dragPixmap); + drag->exec(Qt::MoveAction | Qt::CopyAction); } ArchiveProxy::ArchiveProxy(QObject *parent) : QSortFilterProxyModel(parent) {} diff --git a/archiveview.h b/archiveview.h index f1b9029..dbe0e8f 100644 --- a/archiveview.h +++ b/archiveview.h @@ -33,6 +33,8 @@ class QCompleter; class QStandardItemModel; class QSpinBox; class QToolBar; +class QMouseEvent; +class QDragEnterEvent; class ArchiveView : public QWidget { Q_OBJECT @@ -96,6 +98,11 @@ class ArchiveTree : public SmTreeView { void deleteFromTree(); void newPart(); + protected: + virtual void dragEnterEvent(QDragEnterEvent *e); + virtual void dragMoveEvent(QDragMoveEvent *e); + virtual void dropEvent(QDropEvent *e); + private: void impossible(const QString msg = tr("Unable to perform function!")); QModelIndex firstSelected(); @@ -106,6 +113,13 @@ class ArchiveTree : public SmTreeView { class ArchiveFiles : public SmTreeView { public: explicit ArchiveFiles(const QString &headerSettings = "afilesheaders", QWidget *parent = 0); + + protected: + virtual void mousePressEvent(QMouseEvent *e); + virtual void mouseMoveEvent(QMouseEvent *e); + + private: + QPoint mDragStartPos; }; class ArchiveProxy : public QSortFilterProxyModel { |