forked from qt-creator/qt-creator
Support drag and drop between splits
Change-Id: Ia1e43cb44639e332ee4f9100c7ce3029e9485198 Reviewed-by: Alessandro Portale <alessandro.portale@digia.com> Reviewed-by: Daniel Teske <daniel.teske@digia.com>
This commit is contained in:
@@ -711,8 +711,9 @@ static bool isDesktopFileManagerDrop(const QMimeData *d, QStringList *files = 0)
|
||||
return hasFiles;
|
||||
}
|
||||
|
||||
FileDropSupport::FileDropSupport(QWidget *parentWidget)
|
||||
: QObject(parentWidget)
|
||||
FileDropSupport::FileDropSupport(QWidget *parentWidget, const DropFilterFunction &filterFunction)
|
||||
: QObject(parentWidget),
|
||||
m_filterFunction(filterFunction)
|
||||
{
|
||||
QTC_ASSERT(parentWidget, return);
|
||||
parentWidget->setAcceptDrops(true);
|
||||
@@ -744,15 +745,22 @@ bool FileDropSupport::eventFilter(QObject *obj, QEvent *event)
|
||||
Q_UNUSED(obj)
|
||||
if (event->type() == QEvent::DragEnter) {
|
||||
auto dee = static_cast<QDragEnterEvent *>(event);
|
||||
if (isDesktopFileManagerDrop(dee->mimeData()))
|
||||
if (isDesktopFileManagerDrop(dee->mimeData())
|
||||
&& (!m_filterFunction || m_filterFunction(dee)))
|
||||
event->accept();
|
||||
else
|
||||
event->ignore();
|
||||
return true;
|
||||
} else if (event->type() == QEvent::DragMove) {
|
||||
event->accept();
|
||||
return true;
|
||||
} else if (event->type() == QEvent::Drop) {
|
||||
auto de = static_cast<QDropEvent *>(event);
|
||||
QStringList tempFiles;
|
||||
if (isDesktopFileManagerDrop(de->mimeData(), &tempFiles)) {
|
||||
if (isDesktopFileManagerDrop(de->mimeData(), &tempFiles)
|
||||
&& (!m_filterFunction || m_filterFunction(de))) {
|
||||
event->accept();
|
||||
de->acceptProposedAction();
|
||||
bool needToScheduleEmit = m_files.isEmpty();
|
||||
m_files.append(tempFiles);
|
||||
if (needToScheduleEmit) // otherwise we already have a timer pending
|
||||
@@ -760,6 +768,7 @@ bool FileDropSupport::eventFilter(QObject *obj, QEvent *event)
|
||||
} else {
|
||||
event->ignore();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@@ -37,18 +37,21 @@
|
||||
#include <QMetaType>
|
||||
#include <QStringList>
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace Utils {class FileName; }
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QFile;
|
||||
class QMimeData;
|
||||
class QTemporaryFile;
|
||||
class QWidget;
|
||||
class QTextStream;
|
||||
class QDataStream;
|
||||
class QDateTime;
|
||||
class QFileInfo;
|
||||
class QDir;
|
||||
class QDropEvent;
|
||||
class QFile;
|
||||
class QFileInfo;
|
||||
class QMimeData;
|
||||
class QTemporaryFile;
|
||||
class QTextStream;
|
||||
class QWidget;
|
||||
|
||||
QTCREATOR_UTILS_EXPORT QDebug operator<<(QDebug dbg, const Utils::FileName &c);
|
||||
|
||||
@@ -198,7 +201,11 @@ class QTCREATOR_UTILS_EXPORT FileDropSupport : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
FileDropSupport(QWidget *parentWidget);
|
||||
// returns true if the event should be accepted
|
||||
typedef std::function<bool(QDropEvent*)> DropFilterFunction;
|
||||
|
||||
FileDropSupport(QWidget *parentWidget, const DropFilterFunction &filterFunction
|
||||
= DropFilterFunction());
|
||||
|
||||
static QStringList mimeTypesForFilePaths();
|
||||
static QMimeData *mimeDataForFilePaths(const QStringList &filePaths);
|
||||
@@ -214,6 +221,7 @@ private slots:
|
||||
void emitFilesDropped();
|
||||
|
||||
private:
|
||||
DropFilterFunction m_filterFunction;
|
||||
QStringList m_files;
|
||||
|
||||
};
|
||||
|
@@ -78,6 +78,7 @@ EditorView::EditorView(SplitterOrView *parentSplitterOrView, QWidget *parent) :
|
||||
connect(m_toolBar, SIGNAL(goForwardClicked()), this, SLOT(goForwardInNavigationHistory()));
|
||||
connect(m_toolBar, SIGNAL(closeClicked()), this, SLOT(closeCurrentEditor()));
|
||||
connect(m_toolBar, SIGNAL(listSelectionActivated(int)), this, SLOT(listSelectionActivated(int)));
|
||||
connect(m_toolBar, &EditorToolBar::currentDocumentMoved, this, &EditorView::closeCurrentEditor);
|
||||
connect(m_toolBar, SIGNAL(horizontalSplitClicked()), this, SLOT(splitHorizontally()));
|
||||
connect(m_toolBar, SIGNAL(verticalSplitClicked()), this, SLOT(splitVertically()));
|
||||
connect(m_toolBar, SIGNAL(splitNewWindowClicked()), this, SLOT(splitNewWindow()));
|
||||
@@ -122,7 +123,9 @@ EditorView::EditorView(SplitterOrView *parentSplitterOrView, QWidget *parent) :
|
||||
m_container->addWidget(empty);
|
||||
m_widgetEditorMap.insert(empty, 0);
|
||||
|
||||
auto dropSupport = new Utils::FileDropSupport(this);
|
||||
auto dropSupport = new Utils::FileDropSupport(this, [this](QDropEvent *event) {
|
||||
return event->source() != m_toolBar; // do not accept drops on ourselves
|
||||
});
|
||||
connect(dropSupport, SIGNAL(filesDropped(QStringList)),
|
||||
this, SLOT(openDroppedFiles(QStringList)));
|
||||
|
||||
|
@@ -29,24 +29,32 @@
|
||||
|
||||
#include "editortoolbar.h"
|
||||
|
||||
#include <coreplugin/actionmanager/actionmanager.h>
|
||||
#include <coreplugin/coreconstants.h>
|
||||
#include <coreplugin/editormanager/ieditor.h>
|
||||
#include <coreplugin/icore.h>
|
||||
|
||||
#include <coreplugin/editormanager/documentmodel.h>
|
||||
#include <coreplugin/editormanager/editormanager.h>
|
||||
#include <coreplugin/editormanager/editormanager_p.h>
|
||||
#include <coreplugin/editormanager/documentmodel.h>
|
||||
#include <coreplugin/actionmanager/actionmanager.h>
|
||||
#include <coreplugin/editormanager/ieditor.h>
|
||||
#include <coreplugin/fileiconprovider.h>
|
||||
#include <coreplugin/icore.h>
|
||||
|
||||
#include <utils/fileutils.h>
|
||||
#include <utils/hostosinfo.h>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <QDir>
|
||||
#include <QApplication>
|
||||
#include <QComboBox>
|
||||
#include <QVBoxLayout>
|
||||
#include <QToolButton>
|
||||
#include <QDir>
|
||||
#include <QDrag>
|
||||
#include <QLabel>
|
||||
#include <QMenu>
|
||||
#include <QMimeData>
|
||||
#include <QMouseEvent>
|
||||
#include <QTimer>
|
||||
#include <QToolButton>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
enum {
|
||||
debug = false
|
||||
@@ -61,6 +69,7 @@ struct EditorToolBarPrivate
|
||||
QComboBox *m_editorList;
|
||||
QToolButton *m_closeEditorButton;
|
||||
QToolButton *m_lockButton;
|
||||
QToolButton *m_dragHandle;
|
||||
QAction *m_goBackAction;
|
||||
QAction *m_goForwardAction;
|
||||
QToolButton *m_backButton;
|
||||
@@ -75,22 +84,25 @@ struct EditorToolBarPrivate
|
||||
QWidget *m_toolBarPlaceholder;
|
||||
QWidget *m_defaultToolBar;
|
||||
|
||||
QPoint m_dragStartPosition;
|
||||
|
||||
bool m_isStandalone;
|
||||
};
|
||||
|
||||
EditorToolBarPrivate::EditorToolBarPrivate(QWidget *parent, EditorToolBar *q) :
|
||||
m_editorList(new QComboBox(q)),
|
||||
m_closeEditorButton(new QToolButton),
|
||||
m_lockButton(new QToolButton),
|
||||
m_closeEditorButton(new QToolButton(q)),
|
||||
m_lockButton(new QToolButton(q)),
|
||||
m_dragHandle(new QToolButton(q)),
|
||||
m_goBackAction(new QAction(QIcon(QLatin1String(Constants::ICON_PREV)), EditorManager::tr("Go Back"), parent)),
|
||||
m_goForwardAction(new QAction(QIcon(QLatin1String(Constants::ICON_NEXT)), EditorManager::tr("Go Forward"), parent)),
|
||||
m_splitButton(new QToolButton),
|
||||
m_splitButton(new QToolButton(q)),
|
||||
m_horizontalSplitAction(new QAction(QIcon(QLatin1String(Constants::ICON_SPLIT_HORIZONTAL)), EditorManager::tr("Split"), parent)),
|
||||
m_verticalSplitAction(new QAction(QIcon(QLatin1String(Constants::ICON_SPLIT_VERTICAL)), EditorManager::tr("Split Side by Side"), parent)),
|
||||
m_splitNewWindowAction(new QAction(EditorManager::tr("Open in New Window"), parent)),
|
||||
m_closeSplitButton(new QToolButton),
|
||||
m_closeSplitButton(new QToolButton(q)),
|
||||
m_activeToolBar(0),
|
||||
m_toolBarPlaceholder(new QWidget),
|
||||
m_toolBarPlaceholder(new QWidget(q)),
|
||||
m_defaultToolBar(new QWidget(q)),
|
||||
m_isStandalone(false)
|
||||
{
|
||||
@@ -115,6 +127,11 @@ EditorToolBar::EditorToolBar(QWidget *parent) :
|
||||
d->m_lockButton->setAutoRaise(true);
|
||||
d->m_lockButton->setEnabled(false);
|
||||
|
||||
d->m_dragHandle->setCheckable(false);
|
||||
d->m_dragHandle->setChecked(false);
|
||||
d->m_dragHandle->setToolTip(tr("Drag to drag documents between splits"));
|
||||
d->m_dragHandle->installEventFilter(this);
|
||||
|
||||
connect(d->m_goBackAction, SIGNAL(triggered()), this, SIGNAL(goBackClicked()));
|
||||
connect(d->m_goForwardAction, SIGNAL(triggered()), this, SIGNAL(goForwardClicked()));
|
||||
|
||||
@@ -164,6 +181,7 @@ EditorToolBar::EditorToolBar(QWidget *parent) :
|
||||
toplayout->addWidget(d->m_backButton);
|
||||
toplayout->addWidget(d->m_forwardButton);
|
||||
toplayout->addWidget(d->m_lockButton);
|
||||
toplayout->addWidget(d->m_dragHandle);
|
||||
toplayout->addWidget(d->m_editorList);
|
||||
toplayout->addWidget(d->m_closeEditorButton);
|
||||
toplayout->addWidget(d->m_toolBarPlaceholder, 1); // Custom toolbar stretches
|
||||
@@ -367,6 +385,7 @@ void EditorToolBar::updateDocumentStatus(IDocument *document)
|
||||
d->m_lockButton->setIcon(QIcon());
|
||||
d->m_lockButton->setEnabled(false);
|
||||
d->m_lockButton->setToolTip(QString());
|
||||
d->m_dragHandle->setIcon(QIcon());
|
||||
d->m_editorList->setToolTip(QString());
|
||||
return;
|
||||
}
|
||||
@@ -386,12 +405,50 @@ void EditorToolBar::updateDocumentStatus(IDocument *document)
|
||||
d->m_lockButton->setEnabled(false);
|
||||
d->m_lockButton->setToolTip(tr("File is writable"));
|
||||
}
|
||||
|
||||
if (document->filePath().isEmpty())
|
||||
d->m_dragHandle->setIcon(QIcon());
|
||||
else
|
||||
d->m_dragHandle->setIcon(FileIconProvider::icon(QFileInfo(document->filePath())));
|
||||
|
||||
d->m_editorList->setToolTip(
|
||||
document->filePath().isEmpty()
|
||||
? document->displayName()
|
||||
: QDir::toNativeSeparators(document->filePath()));
|
||||
}
|
||||
|
||||
bool EditorToolBar::eventFilter(QObject *obj, QEvent *event)
|
||||
{
|
||||
if (obj == d->m_dragHandle) {
|
||||
if (event->type() == QEvent::MouseButtonPress) {
|
||||
auto me = static_cast<QMouseEvent *>(event);
|
||||
if (me->buttons() == Qt::LeftButton) {
|
||||
d->m_dragStartPosition = me->pos();
|
||||
return true;
|
||||
}
|
||||
return Utils::StyledBar::eventFilter(obj, event);
|
||||
} else if (event->type() == QEvent::MouseMove) {
|
||||
auto me = static_cast<QMouseEvent *>(event);
|
||||
if (me->buttons() != Qt::LeftButton)
|
||||
return Utils::StyledBar::eventFilter(obj, event);
|
||||
if ((me->pos() - d->m_dragStartPosition).manhattanLength()
|
||||
< QApplication::startDragDistance())
|
||||
return Utils::StyledBar::eventFilter(obj, event);
|
||||
DocumentModel::Entry *entry = DocumentModel::entryAtRow(
|
||||
d->m_editorList->currentIndex());
|
||||
if (!entry) // no document
|
||||
return Utils::StyledBar::eventFilter(obj, event);
|
||||
auto *drag = new QDrag(this);
|
||||
drag->setMimeData(Utils::FileDropSupport::mimeDataForFilePath(entry->fileName()));
|
||||
Qt::DropAction action = drag->exec(Qt::MoveAction | Qt::CopyAction, Qt::MoveAction);
|
||||
if (action == Qt::MoveAction)
|
||||
emit currentDocumentMoved();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return Utils::StyledBar::eventFilter(obj, event);
|
||||
}
|
||||
|
||||
void EditorToolBar::setNavigationVisible(bool isVisible)
|
||||
{
|
||||
d->m_goBackAction->setVisible(isVisible);
|
||||
|
@@ -94,11 +94,15 @@ signals:
|
||||
void closeSplitClicked();
|
||||
void listSelectionActivated(int row);
|
||||
void listContextMenuRequested(QPoint globalpos);
|
||||
void currentDocumentMoved();
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject *obj, QEvent *event);
|
||||
|
||||
private slots:
|
||||
void updateEditorListSelection(Core::IEditor *newSelection);
|
||||
void changeActiveEditor(int row);
|
||||
void listContextMenu(QPoint);
|
||||
void listContextMenu(QPoint pos);
|
||||
void makeEditorWritable();
|
||||
|
||||
void checkDocumentStatus();
|
||||
|
@@ -207,7 +207,9 @@ MainWindow::MainWindow() :
|
||||
|
||||
statusBar()->setProperty("p_styled", true);
|
||||
|
||||
auto dropSupport = new Utils::FileDropSupport(this);
|
||||
auto dropSupport = new Utils::FileDropSupport(this, [](QDropEvent *event) {
|
||||
return event->source() == 0; // only accept drops from the "outside" (e.g. file manager)
|
||||
});
|
||||
connect(dropSupport, SIGNAL(filesDropped(QStringList)),
|
||||
this, SLOT(openDroppedFiles(QStringList)));
|
||||
}
|
||||
|
Reference in New Issue
Block a user