From d9f4cedc2bfdf944fea725a9b9cd8e81c43fe3b0 Mon Sep 17 00:00:00 2001 From: Ken Moore Date: Thu, 27 Aug 2015 13:11:50 -0400 Subject: Get drag and drop functionality completely working (Internal only - will not talk to other applications) --- lumina-fm/widgets/DDListWidgets.h | 188 ++++++++++++++++++++++++++++++++++++++ lumina-fm/widgets/DirWidget.cpp | 102 +++++++++++---------- lumina-fm/widgets/DirWidget.h | 7 +- lumina-fm/widgets/DirWidget.ui | 63 +------------ 4 files changed, 253 insertions(+), 107 deletions(-) create mode 100644 lumina-fm/widgets/DDListWidgets.h (limited to 'lumina-fm/widgets') diff --git a/lumina-fm/widgets/DDListWidgets.h b/lumina-fm/widgets/DDListWidgets.h new file mode 100644 index 00000000..d62a0a5d --- /dev/null +++ b/lumina-fm/widgets/DDListWidgets.h @@ -0,0 +1,188 @@ +//=========================================== +// Lumina-DE source code +// Copyright (c) 2015, Ken Moore +// Available under the 3-clause BSD license +// See the LICENSE file for full details +//=========================================== +// This is a couple simple widget subclasses to enable drag and drop functionality +// NOTE: The "whatsThis()" item information needs to correspond to the "[cut/copy]::::" syntax +//NOTE2: The "whatsThis()" information on the widget itself should be the current dir path *if* it can accept drops +//=========================================== +#ifndef _LUMINA_FM_DRAG_DROP_WIDGETS_H +#define _LUMINA_FM_DRAG_DROP_WIDGETS_H + +#define MIME QString("x-special/lumina-copied-files") + +#include +#include +#include +#include +#include +#include +#include + +//============== +// LIST WIDGET +//============== +class DDListWidget : public QListWidget{ + Q_OBJECT +public: + DDListWidget(QWidget *parent=0) : QListWidget(parent){ + //Drag and Drop Properties + this->setDragDropMode(QAbstractItemView::DragDrop); + this->setDefaultDropAction(Qt::MoveAction); //prevent any built-in Qt actions - the class handles it + //Other custom properties necessary for the FM + this->setFocusPolicy(Qt::StrongFocus); + this->setContextMenuPolicy(Qt::CustomContextMenu); + this->setSelectionMode(QAbstractItemView::ExtendedSelection); + this->setSelectionBehavior(QAbstractItemView::SelectRows); + this->setFlow(QListView::TopToBottom); + this->setWrapping(true); + this->setMouseTracking(true); + } + ~DDListWidget(){} + +signals: + void DataDropped(QString, QStringList); //Dir path, List of commands + +protected: + void startDrag(Qt::DropActions act){ + QList items = this->selectedItems(); + if(items.length()<1){ return; } + QStringList info; + for(int i=0; iwhatsThis(); } + //Create the mime data + QMimeData *mime = new QMimeData; + mime->setData(MIME,info.join("\n").toLocal8Bit()); + //Create the drag structure + QDrag *drag = new QDrag(this); + drag->setMimeData(mime); + drag->exec(act | Qt::MoveAction | Qt::CopyAction); + } + + void dragEnterEvent(QDragEnterEvent *ev){ + //qDebug() << "Drag Enter Event:" << ev->mimeData()->hasFormat(MIME); + if(ev->mimeData()->hasFormat(MIME) && !this->whatsThis().isEmpty() ){ + //qDebug() << "Accepted:" << ev->mimeData()->data(MIME); + if(QString(ev->mimeData()->data(MIME)).section("::::",0,0)=="cut"){ + ev->setDropAction(Qt::MoveAction); + }else{ + ev->setDropAction(Qt::CopyAction); + } + ev->accept(); //allow this to be dropped here + } + } + + void dragMoveEvent(QDragMoveEvent *ev){ + //qDebug() << "Drag Move Event:" << ev->mimeData()->hasFormat(MIME); + if(ev->mimeData()->hasFormat(MIME) && !this->whatsThis().isEmpty()){ + //qDebug() << "Accepted:" << ev->mimeData()->data(MIME); + if(QString(ev->mimeData()->data(MIME)).section("::::",0,0)=="cut"){ + ev->setDropAction(Qt::MoveAction); + }else{ + ev->setDropAction(Qt::CopyAction); + } + ev->accept(); //allow this to be dropped here + } + } + + void dropEvent(QDropEvent *ev){ + if(this->whatsThis().isEmpty()){ return; } //not supported + ev->accept(); //handled here + QString dirpath = this->whatsThis(); + //See if the item under the drop point is a directory or not + QListWidgetItem *it = this->itemAt( ev->pos()); + if(it!=0){ + QFileInfo info(it->whatsThis().section("::::",1,100)); + if(info.isDir() && info.isWritable()){ + dirpath = info.absoluteFilePath(); + } + } + //qDebug() << "Drop Event:" << dirpath; + emit DataDropped( dirpath, QString(ev->mimeData()->data(MIME)).split("\n") ); + } +}; + +//================ +// TreeWidget +//================ +class DDTreeWidget : public QTreeWidget{ + Q_OBJECT +public: + DDTreeWidget(QWidget *parent=0) : QTreeWidget(parent){ + //Drag and Drop Properties + this->setDragDropMode(QAbstractItemView::DragDrop); + this->setDefaultDropAction(Qt::MoveAction); //prevent any built-in Qt actions - the class handles it + //Other custom properties necessary for the FM + this->setFocusPolicy(Qt::StrongFocus); + this->setContextMenuPolicy(Qt::CustomContextMenu); + this->setSelectionMode(QAbstractItemView::ExtendedSelection); + this->setSelectionBehavior(QAbstractItemView::SelectRows); + this->setMouseTracking(true); + this->setSortingEnabled(true); + this->setIndentation(0); + this->setItemsExpandable(false); + } + ~DDTreeWidget(){} + +signals: + void DataDropped(QString, QStringList); //Dir path, List of commands + +protected: + void startDrag(Qt::DropActions act){ + QList items = this->selectedItems(); + if(items.length()<1){ return; } + QStringList info; + for(int i=0; iwhatsThis(0); } + //Create the mime data + QMimeData *mime = new QMimeData; + mime->setData(MIME,info.join("\n").toLocal8Bit()); + //Create the drag structure + QDrag *drag = new QDrag(this); + drag->setMimeData(mime); + drag->exec(act | Qt::MoveAction | Qt::CopyAction); + } + + void dragEnterEvent(QDragEnterEvent *ev){ + //qDebug() << "Drag Enter Event:" << ev->mimeData()->hasFormat(MIME); + if(ev->mimeData()->hasFormat(MIME) && !this->whatsThis().isEmpty() ){ + //qDebug() << "Accepted:" << ev->mimeData()->data(MIME); + if(QString(ev->mimeData()->data(MIME)).section("::::",0,0)=="cut"){ + ev->setDropAction(Qt::MoveAction); + }else{ + ev->setDropAction(Qt::CopyAction); + } + ev->accept(); //allow this to be dropped here + } + } + + void dragMoveEvent(QDragMoveEvent *ev){ + //qDebug() << "Drag Move Event:" << ev->mimeData()->hasFormat(MIME); + if(ev->mimeData()->hasFormat(MIME) && !this->whatsThis().isEmpty()){ + //qDebug() << "Accepted:" << ev->mimeData()->data(MIME); + if(QString(ev->mimeData()->data(MIME)).section("::::",0,0)=="cut"){ + ev->setDropAction(Qt::MoveAction); + }else{ + ev->setDropAction(Qt::CopyAction); + } + ev->accept(); //allow this to be dropped here + } + } + + void dropEvent(QDropEvent *ev){ + if(this->whatsThis().isEmpty()){ return; } //not supported + ev->accept(); //handled here + QString dirpath = this->whatsThis(); + //See if the item under the drop point is a directory or not + QTreeWidgetItem *it = this->itemAt( ev->pos()); + if(it!=0){ + QFileInfo info(it->whatsThis(0).section("::::",1,100)); + if(info.isDir() && info.isWritable()){ + dirpath = info.absoluteFilePath(); + } + } + //qDebug() << "Drop Event:" << dirpath; + emit DataDropped( dirpath, QString(ev->mimeData()->data(MIME)).split("\n") ); + } +}; +#endif \ No newline at end of file diff --git a/lumina-fm/widgets/DirWidget.cpp b/lumina-fm/widgets/DirWidget.cpp index f1135694..1c8df0bd 100644 --- a/lumina-fm/widgets/DirWidget.cpp +++ b/lumina-fm/widgets/DirWidget.cpp @@ -38,6 +38,11 @@ DirWidget::DirWidget(QString objID, QWidget *parent) : QWidget(parent), ui(new U toolbar->addWidget(line_dir); toolbar->addAction(ui->actionStopLoad); toolbar->addAction(ui->actionClose_Browser); + //Add the browser widgets + listWidget = new DDListWidget(this); + treeWidget = new DDTreeWidget(this); + ui->browser_layout->addWidget(listWidget); + ui->browser_layout->addWidget(treeWidget); //Create the keyboard shortcuts copyFilesShort = new QShortcut( QKeySequence(tr("Ctrl+C")), this); pasteFilesShort = new QShortcut( QKeySequence(tr("Ctrl+V")), this); @@ -79,8 +84,8 @@ QString DirWidget::currentDir(){ void DirWidget::setShowDetails(bool show){ showDetails = show; - ui->listWidget->setVisible(!showDetails); - ui->treeWidget->setVisible(showDetails); + listWidget->setVisible(!showDetails); + treeWidget->setVisible(showDetails); this->refresh(); } @@ -119,19 +124,19 @@ void DirWidget::setDetails(QList list){ break; } } - ui->treeWidget->setHeaderItem(it); + treeWidget->setHeaderItem(it); //Now reset the sorting (alphabetically, dirs first) - if(nmcol>=0){ ui->treeWidget->sortItems(nmcol, Qt::AscendingOrder); } // sort by name - if(typecol>=0){ ui->treeWidget->sortItems(typecol, Qt::AscendingOrder); } //sort by type first + if(nmcol>=0){ treeWidget->sortItems(nmcol, Qt::AscendingOrder); } // sort by name + if(typecol>=0){ treeWidget->sortItems(typecol, Qt::AscendingOrder); } //sort by type first if(CDIR.isEmpty() || !showDetails){ return; } //don't need to reload dir if details are not visible this->refresh(); } void DirWidget::setThumbnailSize(int px){ - bool larger = ui->listWidget->iconSize().height() < px; - ui->listWidget->setIconSize(QSize(px,px)); - ui->treeWidget->setIconSize(QSize(px,px)); + bool larger = listWidget->iconSize().height() < px; + listWidget->setIconSize(QSize(px,px)); + treeWidget->setIconSize(QSize(px,px)); if(CDIR.isEmpty() || !larger ){ return; } //don't need to reload icons unless the new size is larger this->refresh(); } @@ -160,6 +165,14 @@ void DirWidget::LoadDir(QString dir, QList list){ ui->tool_goToImages->setVisible(false); ui->tool_new_dir->setVisible(canmodify); ui->tool_new_file->setVisible(canmodify); + //Set the drab/drop info as appripriate + if(canmodify){ + listWidget->setWhatsThis(CDIR); + treeWidget->setWhatsThis(CDIR); + }else{ + listWidget->setWhatsThis(""); + treeWidget->setWhatsThis(""); + } //Determine if this is an internal ZFS snapshot bool loadsnaps = false; if( dir.contains(ZSNAPDIR) ){ @@ -204,8 +217,8 @@ void DirWidget::LoadDir(QString dir, QList list){ ui->actionStopLoad->setVisible(true); stopload = false; //Clear the display widget - if(showDetails){ ui->treeWidget->clear(); } - else{ ui->listWidget->clear(); } + if(showDetails){ treeWidget->clear(); } + else{ listWidget->clear(); } //Now fill the display widget bool hasimages, hasmultimedia; hasimages = hasmultimedia = false; @@ -222,14 +235,14 @@ void DirWidget::LoadDir(QString dir, QList list){ if(showDetails){ //Now create all the individual items for the details tree QTreeWidgetItem *it = new QTreeWidgetItem(); - it->setWhatsThis(0, list[i].fileName()); + it->setWhatsThis(0, QString(canmodify ? "cut": "copy")+"::::"+list[i].absoluteFilePath()); for(int t=0; tsetText(t,list[i].fileName()); it->setStatusTip(t, list[i].fileName()); if(list[i].isImage()){ - if(showThumbs){ it->setIcon(t, QIcon( QPixmap(list[i].absoluteFilePath()).scaled(ui->treeWidget->iconSize(),Qt::IgnoreAspectRatio, Qt::FastTransformation) ) ); } + if(showThumbs){ it->setIcon(t, QIcon( QPixmap(list[i].absoluteFilePath()).scaled(treeWidget->iconSize(),Qt::IgnoreAspectRatio, Qt::FastTransformation) ) ); } else{ it->setIcon(t, LXDG::findIcon(list[i].iconfile(),"image-x-generic") ); } }else{ it->setIcon(t, LXDG::findIcon(list[i].iconfile(),"unknown") ); @@ -251,27 +264,27 @@ void DirWidget::LoadDir(QString dir, QList list){ break; } } - ui->treeWidget->addTopLevelItem(it); - if(lastdir == CDIR+"/"+it->whatsThis(0)){ - ui->treeWidget->setCurrentItem(it); - ui->treeWidget->scrollToItem(it); + treeWidget->addTopLevelItem(it); + if(lastdir == CDIR+"/"+list[i].fileName()){ + treeWidget->setCurrentItem(it); + treeWidget->scrollToItem(it); } }else{ //Create all the individual items for the basic list QListWidgetItem *it = new QListWidgetItem(); - it->setWhatsThis(list[i].fileName()); + it->setWhatsThis( QString(canmodify ? "cut": "copy")+"::::"+list[i].absoluteFilePath()); //used for drag and drop it->setText(list[i].fileName()); it->setStatusTip(list[i].fileName()); if(list[i].isImage()){ - if(showThumbs){ it->setIcon(QIcon( QPixmap(list[i].absoluteFilePath()).scaled(ui->listWidget->iconSize(),Qt::IgnoreAspectRatio, Qt::FastTransformation) ) ); } + if(showThumbs){ it->setIcon(QIcon( QPixmap(list[i].absoluteFilePath()).scaled(listWidget->iconSize(),Qt::IgnoreAspectRatio, Qt::FastTransformation) ) ); } else{ it->setIcon(LXDG::findIcon(list[i].iconfile(),"image-x-generic") ); } }else{ it->setIcon(LXDG::findIcon(list[i].iconfile(),"unknown") ); } - ui->listWidget->addItem(it); + listWidget->addItem(it); if(lastdir == CDIR+"/"+it->whatsThis()){ - ui->listWidget->setCurrentItem(it); - ui->listWidget->scrollToItem(it); + listWidget->setCurrentItem(it); + listWidget->scrollToItem(it); } } QApplication::processEvents(); //keep the UI snappy while loading a directory @@ -279,10 +292,10 @@ void DirWidget::LoadDir(QString dir, QList list){ ui->actionStopLoad->setVisible(false); //Another check to ensure the current item is visible if(showDetails){ - if(ui->treeWidget->currentItem()!=0){ ui->treeWidget->scrollToItem(ui->treeWidget->currentItem()); } - for(int t=0; ttreeWidget->columnCount(); t++){ui->treeWidget->resizeColumnToContents(t); } + if(treeWidget->currentItem()!=0){ treeWidget->scrollToItem(treeWidget->currentItem()); } + for(int t=0; tcolumnCount(); t++){treeWidget->resizeColumnToContents(t); } }else{ - if(ui->listWidget->currentItem()!=0){ ui->listWidget->scrollToItem(ui->listWidget->currentItem()); } + if(listWidget->currentItem()!=0){ listWidget->scrollToItem(listWidget->currentItem()); } } //Now Re-enable buttons as necessary ui->tool_goToPlayer->setVisible(hasmultimedia); @@ -383,14 +396,16 @@ void DirWidget::UpdateButtons(){ // ================= void DirWidget::setupConnections(){ //Info routines - connect(ui->treeWidget, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(OpenContextMenu()) ); - connect(ui->listWidget, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(OpenContextMenu()) ); - connect(ui->treeWidget, SIGNAL(itemSelectionChanged()), this, SLOT(SelectionChanged()) ); - connect(ui->listWidget, SIGNAL(itemSelectionChanged()), this, SLOT(SelectionChanged()) ); - + connect(treeWidget, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(OpenContextMenu()) ); + connect(listWidget, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(OpenContextMenu()) ); + connect(treeWidget, SIGNAL(itemSelectionChanged()), this, SLOT(SelectionChanged()) ); + connect(listWidget, SIGNAL(itemSelectionChanged()), this, SLOT(SelectionChanged()) ); + //Activation routines - connect(ui->treeWidget, SIGNAL(itemActivated(QTreeWidgetItem*,int)), this, SLOT(on_tool_act_run_clicked()) ); - connect(ui->listWidget, SIGNAL(itemActivated(QListWidgetItem*)), this, SLOT(on_tool_act_run_clicked()) ); + connect(treeWidget, SIGNAL(itemActivated(QTreeWidgetItem*,int)), this, SLOT(on_tool_act_run_clicked()) ); + connect(treeWidget, SIGNAL(DataDropped(QString, QStringList)), this, SIGNAL(PasteFiles(QString, QStringList)) ); + connect(listWidget, SIGNAL(itemActivated(QListWidgetItem*)), this, SLOT(on_tool_act_run_clicked()) ); + connect(listWidget, SIGNAL(DataDropped(QString, QStringList)), this, SIGNAL(PasteFiles(QString, QStringList)) ); connect(line_dir, SIGNAL(returnPressed()), this, SLOT(dir_changed()) ); //Keyboard Shortcuts @@ -407,14 +422,14 @@ void DirWidget::setupConnections(){ QStringList DirWidget::currentSelection(){ QStringList out; if(showDetails){ - QList sel = ui->treeWidget->selectedItems(); + QList sel = treeWidget->selectedItems(); for(int i=0; iwhatsThis(0); + out << sel[i]->whatsThis(0).section("::::",1,100); //absolute file path } }else{ - QList sel = ui->listWidget->selectedItems(); + QList sel = listWidget->selectedItems(); for(int i=0; iwhatsThis(); + out << sel[i]->whatsThis().section("::::",1,100); //absolute file path } } out.removeDuplicates(); @@ -429,39 +444,34 @@ QStringList DirWidget::currentSelection(){ void DirWidget::on_tool_act_cut_clicked(){ QStringList sel = currentSelection(); if(sel.isEmpty()){ return; } - for(int i=0; i Status + + true + @@ -111,7 +114,7 @@ - + 1 @@ -176,64 +179,6 @@ - - - - Qt::CustomContextMenu - - - QAbstractItemView::DragDrop - - - Qt::MoveAction - - - QAbstractItemView::ExtendedSelection - - - 0 - - - true - - - true - - - 30 - - - - 1 - - - - - - - - Qt::CustomContextMenu - - - QAbstractItemView::DragDrop - - - Qt::MoveAction - - - QAbstractItemView::ExtendedSelection - - - QAbstractItemView::SelectItems - - - QListView::TopToBottom - - - true - - - -- cgit