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;
|
return hasFiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
FileDropSupport::FileDropSupport(QWidget *parentWidget)
|
FileDropSupport::FileDropSupport(QWidget *parentWidget, const DropFilterFunction &filterFunction)
|
||||||
: QObject(parentWidget)
|
: QObject(parentWidget),
|
||||||
|
m_filterFunction(filterFunction)
|
||||||
{
|
{
|
||||||
QTC_ASSERT(parentWidget, return);
|
QTC_ASSERT(parentWidget, return);
|
||||||
parentWidget->setAcceptDrops(true);
|
parentWidget->setAcceptDrops(true);
|
||||||
@@ -744,15 +745,22 @@ bool FileDropSupport::eventFilter(QObject *obj, QEvent *event)
|
|||||||
Q_UNUSED(obj)
|
Q_UNUSED(obj)
|
||||||
if (event->type() == QEvent::DragEnter) {
|
if (event->type() == QEvent::DragEnter) {
|
||||||
auto dee = static_cast<QDragEnterEvent *>(event);
|
auto dee = static_cast<QDragEnterEvent *>(event);
|
||||||
if (isDesktopFileManagerDrop(dee->mimeData()))
|
if (isDesktopFileManagerDrop(dee->mimeData())
|
||||||
|
&& (!m_filterFunction || m_filterFunction(dee)))
|
||||||
event->accept();
|
event->accept();
|
||||||
else
|
else
|
||||||
event->ignore();
|
event->ignore();
|
||||||
|
return true;
|
||||||
|
} else if (event->type() == QEvent::DragMove) {
|
||||||
|
event->accept();
|
||||||
|
return true;
|
||||||
} else if (event->type() == QEvent::Drop) {
|
} else if (event->type() == QEvent::Drop) {
|
||||||
auto de = static_cast<QDropEvent *>(event);
|
auto de = static_cast<QDropEvent *>(event);
|
||||||
QStringList tempFiles;
|
QStringList tempFiles;
|
||||||
if (isDesktopFileManagerDrop(de->mimeData(), &tempFiles)) {
|
if (isDesktopFileManagerDrop(de->mimeData(), &tempFiles)
|
||||||
|
&& (!m_filterFunction || m_filterFunction(de))) {
|
||||||
event->accept();
|
event->accept();
|
||||||
|
de->acceptProposedAction();
|
||||||
bool needToScheduleEmit = m_files.isEmpty();
|
bool needToScheduleEmit = m_files.isEmpty();
|
||||||
m_files.append(tempFiles);
|
m_files.append(tempFiles);
|
||||||
if (needToScheduleEmit) // otherwise we already have a timer pending
|
if (needToScheduleEmit) // otherwise we already have a timer pending
|
||||||
@@ -760,6 +768,7 @@ bool FileDropSupport::eventFilter(QObject *obj, QEvent *event)
|
|||||||
} else {
|
} else {
|
||||||
event->ignore();
|
event->ignore();
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@@ -37,18 +37,21 @@
|
|||||||
#include <QMetaType>
|
#include <QMetaType>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
namespace Utils {class FileName; }
|
namespace Utils {class FileName; }
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
class QFile;
|
|
||||||
class QMimeData;
|
|
||||||
class QTemporaryFile;
|
|
||||||
class QWidget;
|
|
||||||
class QTextStream;
|
|
||||||
class QDataStream;
|
class QDataStream;
|
||||||
class QDateTime;
|
class QDateTime;
|
||||||
class QFileInfo;
|
|
||||||
class QDir;
|
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);
|
QTCREATOR_UTILS_EXPORT QDebug operator<<(QDebug dbg, const Utils::FileName &c);
|
||||||
|
|
||||||
@@ -198,7 +201,11 @@ class QTCREATOR_UTILS_EXPORT FileDropSupport : public QObject
|
|||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
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 QStringList mimeTypesForFilePaths();
|
||||||
static QMimeData *mimeDataForFilePaths(const QStringList &filePaths);
|
static QMimeData *mimeDataForFilePaths(const QStringList &filePaths);
|
||||||
@@ -214,6 +221,7 @@ private slots:
|
|||||||
void emitFilesDropped();
|
void emitFilesDropped();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
DropFilterFunction m_filterFunction;
|
||||||
QStringList m_files;
|
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(goForwardClicked()), this, SLOT(goForwardInNavigationHistory()));
|
||||||
connect(m_toolBar, SIGNAL(closeClicked()), this, SLOT(closeCurrentEditor()));
|
connect(m_toolBar, SIGNAL(closeClicked()), this, SLOT(closeCurrentEditor()));
|
||||||
connect(m_toolBar, SIGNAL(listSelectionActivated(int)), this, SLOT(listSelectionActivated(int)));
|
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(horizontalSplitClicked()), this, SLOT(splitHorizontally()));
|
||||||
connect(m_toolBar, SIGNAL(verticalSplitClicked()), this, SLOT(splitVertically()));
|
connect(m_toolBar, SIGNAL(verticalSplitClicked()), this, SLOT(splitVertically()));
|
||||||
connect(m_toolBar, SIGNAL(splitNewWindowClicked()), this, SLOT(splitNewWindow()));
|
connect(m_toolBar, SIGNAL(splitNewWindowClicked()), this, SLOT(splitNewWindow()));
|
||||||
@@ -122,7 +123,9 @@ EditorView::EditorView(SplitterOrView *parentSplitterOrView, QWidget *parent) :
|
|||||||
m_container->addWidget(empty);
|
m_container->addWidget(empty);
|
||||||
m_widgetEditorMap.insert(empty, 0);
|
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)),
|
connect(dropSupport, SIGNAL(filesDropped(QStringList)),
|
||||||
this, SLOT(openDroppedFiles(QStringList)));
|
this, SLOT(openDroppedFiles(QStringList)));
|
||||||
|
|
||||||
|
@@ -29,24 +29,32 @@
|
|||||||
|
|
||||||
#include "editortoolbar.h"
|
#include "editortoolbar.h"
|
||||||
|
|
||||||
|
#include <coreplugin/actionmanager/actionmanager.h>
|
||||||
#include <coreplugin/coreconstants.h>
|
#include <coreplugin/coreconstants.h>
|
||||||
#include <coreplugin/editormanager/ieditor.h>
|
#include <coreplugin/editormanager/documentmodel.h>
|
||||||
#include <coreplugin/icore.h>
|
|
||||||
|
|
||||||
#include <coreplugin/editormanager/editormanager.h>
|
#include <coreplugin/editormanager/editormanager.h>
|
||||||
#include <coreplugin/editormanager/editormanager_p.h>
|
#include <coreplugin/editormanager/editormanager_p.h>
|
||||||
#include <coreplugin/editormanager/documentmodel.h>
|
#include <coreplugin/editormanager/ieditor.h>
|
||||||
#include <coreplugin/actionmanager/actionmanager.h>
|
#include <coreplugin/fileiconprovider.h>
|
||||||
|
#include <coreplugin/icore.h>
|
||||||
|
|
||||||
|
#include <utils/fileutils.h>
|
||||||
#include <utils/hostosinfo.h>
|
#include <utils/hostosinfo.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
#include <QDir>
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QComboBox>
|
#include <QComboBox>
|
||||||
#include <QVBoxLayout>
|
#include <QDir>
|
||||||
#include <QToolButton>
|
#include <QDrag>
|
||||||
|
#include <QLabel>
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
|
#include <QMimeData>
|
||||||
|
#include <QMouseEvent>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QToolButton>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
debug = false
|
debug = false
|
||||||
@@ -61,6 +69,7 @@ struct EditorToolBarPrivate
|
|||||||
QComboBox *m_editorList;
|
QComboBox *m_editorList;
|
||||||
QToolButton *m_closeEditorButton;
|
QToolButton *m_closeEditorButton;
|
||||||
QToolButton *m_lockButton;
|
QToolButton *m_lockButton;
|
||||||
|
QToolButton *m_dragHandle;
|
||||||
QAction *m_goBackAction;
|
QAction *m_goBackAction;
|
||||||
QAction *m_goForwardAction;
|
QAction *m_goForwardAction;
|
||||||
QToolButton *m_backButton;
|
QToolButton *m_backButton;
|
||||||
@@ -75,22 +84,25 @@ struct EditorToolBarPrivate
|
|||||||
QWidget *m_toolBarPlaceholder;
|
QWidget *m_toolBarPlaceholder;
|
||||||
QWidget *m_defaultToolBar;
|
QWidget *m_defaultToolBar;
|
||||||
|
|
||||||
|
QPoint m_dragStartPosition;
|
||||||
|
|
||||||
bool m_isStandalone;
|
bool m_isStandalone;
|
||||||
};
|
};
|
||||||
|
|
||||||
EditorToolBarPrivate::EditorToolBarPrivate(QWidget *parent, EditorToolBar *q) :
|
EditorToolBarPrivate::EditorToolBarPrivate(QWidget *parent, EditorToolBar *q) :
|
||||||
m_editorList(new QComboBox(q)),
|
m_editorList(new QComboBox(q)),
|
||||||
m_closeEditorButton(new QToolButton),
|
m_closeEditorButton(new QToolButton(q)),
|
||||||
m_lockButton(new QToolButton),
|
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_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_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_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_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_splitNewWindowAction(new QAction(EditorManager::tr("Open in New Window"), parent)),
|
||||||
m_closeSplitButton(new QToolButton),
|
m_closeSplitButton(new QToolButton(q)),
|
||||||
m_activeToolBar(0),
|
m_activeToolBar(0),
|
||||||
m_toolBarPlaceholder(new QWidget),
|
m_toolBarPlaceholder(new QWidget(q)),
|
||||||
m_defaultToolBar(new QWidget(q)),
|
m_defaultToolBar(new QWidget(q)),
|
||||||
m_isStandalone(false)
|
m_isStandalone(false)
|
||||||
{
|
{
|
||||||
@@ -115,6 +127,11 @@ EditorToolBar::EditorToolBar(QWidget *parent) :
|
|||||||
d->m_lockButton->setAutoRaise(true);
|
d->m_lockButton->setAutoRaise(true);
|
||||||
d->m_lockButton->setEnabled(false);
|
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_goBackAction, SIGNAL(triggered()), this, SIGNAL(goBackClicked()));
|
||||||
connect(d->m_goForwardAction, SIGNAL(triggered()), this, SIGNAL(goForwardClicked()));
|
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_backButton);
|
||||||
toplayout->addWidget(d->m_forwardButton);
|
toplayout->addWidget(d->m_forwardButton);
|
||||||
toplayout->addWidget(d->m_lockButton);
|
toplayout->addWidget(d->m_lockButton);
|
||||||
|
toplayout->addWidget(d->m_dragHandle);
|
||||||
toplayout->addWidget(d->m_editorList);
|
toplayout->addWidget(d->m_editorList);
|
||||||
toplayout->addWidget(d->m_closeEditorButton);
|
toplayout->addWidget(d->m_closeEditorButton);
|
||||||
toplayout->addWidget(d->m_toolBarPlaceholder, 1); // Custom toolbar stretches
|
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->setIcon(QIcon());
|
||||||
d->m_lockButton->setEnabled(false);
|
d->m_lockButton->setEnabled(false);
|
||||||
d->m_lockButton->setToolTip(QString());
|
d->m_lockButton->setToolTip(QString());
|
||||||
|
d->m_dragHandle->setIcon(QIcon());
|
||||||
d->m_editorList->setToolTip(QString());
|
d->m_editorList->setToolTip(QString());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -386,12 +405,50 @@ void EditorToolBar::updateDocumentStatus(IDocument *document)
|
|||||||
d->m_lockButton->setEnabled(false);
|
d->m_lockButton->setEnabled(false);
|
||||||
d->m_lockButton->setToolTip(tr("File is writable"));
|
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(
|
d->m_editorList->setToolTip(
|
||||||
document->filePath().isEmpty()
|
document->filePath().isEmpty()
|
||||||
? document->displayName()
|
? document->displayName()
|
||||||
: QDir::toNativeSeparators(document->filePath()));
|
: 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)
|
void EditorToolBar::setNavigationVisible(bool isVisible)
|
||||||
{
|
{
|
||||||
d->m_goBackAction->setVisible(isVisible);
|
d->m_goBackAction->setVisible(isVisible);
|
||||||
|
@@ -94,11 +94,15 @@ signals:
|
|||||||
void closeSplitClicked();
|
void closeSplitClicked();
|
||||||
void listSelectionActivated(int row);
|
void listSelectionActivated(int row);
|
||||||
void listContextMenuRequested(QPoint globalpos);
|
void listContextMenuRequested(QPoint globalpos);
|
||||||
|
void currentDocumentMoved();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool eventFilter(QObject *obj, QEvent *event);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void updateEditorListSelection(Core::IEditor *newSelection);
|
void updateEditorListSelection(Core::IEditor *newSelection);
|
||||||
void changeActiveEditor(int row);
|
void changeActiveEditor(int row);
|
||||||
void listContextMenu(QPoint);
|
void listContextMenu(QPoint pos);
|
||||||
void makeEditorWritable();
|
void makeEditorWritable();
|
||||||
|
|
||||||
void checkDocumentStatus();
|
void checkDocumentStatus();
|
||||||
|
@@ -207,7 +207,9 @@ MainWindow::MainWindow() :
|
|||||||
|
|
||||||
statusBar()->setProperty("p_styled", true);
|
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)),
|
connect(dropSupport, SIGNAL(filesDropped(QStringList)),
|
||||||
this, SLOT(openDroppedFiles(QStringList)));
|
this, SLOT(openDroppedFiles(QStringList)));
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user