Commit fd9b2af9 authored by Eike Ziller's avatar Eike Ziller

Editors: Support drag & drop from bookmarks pane

Change-Id: I9b68d35b04968779f111885ba7a24f18fecfada5
Reviewed-by: default avatarDaniel Teske <daniel.teske@digia.com>
parent 72c33cba
...@@ -40,7 +40,6 @@ ...@@ -40,7 +40,6 @@
#include <QDragEnterEvent> #include <QDragEnterEvent>
#include <QDropEvent> #include <QDropEvent>
#include <QMessageBox> #include <QMessageBox>
#include <QMimeData>
#include <QTimer> #include <QTimer>
#include <QUrl> #include <QUrl>
...@@ -705,8 +704,16 @@ FileName &FileName::appendString(QChar str) ...@@ -705,8 +704,16 @@ FileName &FileName::appendString(QChar str)
return *this; return *this;
} }
static bool isDesktopFileManagerDrop(const QMimeData *d, QStringList *files = 0) static bool isFileDrop(const QMimeData *d, QList<FileDropSupport::FileSpec> *files = 0)
{ {
// internal drop
if (const FileDropMimeData *internalData = qobject_cast<const FileDropMimeData *>(d)) {
if (files)
*files = internalData->files();
return true;
}
// external drop
if (files) if (files)
files->clear(); files->clear();
// Extract dropped files from Mime data. // Extract dropped files from Mime data.
...@@ -723,7 +730,7 @@ static bool isDesktopFileManagerDrop(const QMimeData *d, QStringList *files = 0) ...@@ -723,7 +730,7 @@ static bool isDesktopFileManagerDrop(const QMimeData *d, QStringList *files = 0)
if (!fileName.isEmpty()) { if (!fileName.isEmpty()) {
hasFiles = true; hasFiles = true;
if (files) if (files)
files->push_back(fileName); files->append(FileDropSupport::FileSpec(fileName));
else else
break; // No result list, sufficient for checking break; // No result list, sufficient for checking
} }
...@@ -745,27 +752,12 @@ QStringList FileDropSupport::mimeTypesForFilePaths() ...@@ -745,27 +752,12 @@ QStringList FileDropSupport::mimeTypesForFilePaths()
return QStringList() << QStringLiteral("text/uri-list"); return QStringList() << QStringLiteral("text/uri-list");
} }
QMimeData *FileDropSupport::mimeDataForFilePaths(const QStringList &filePaths)
{
QList<QUrl> localUrls = Utils::transform(filePaths, [filePaths](const QString &path) {
return QUrl::fromLocalFile(path);
});
auto data = new QMimeData;
data->setUrls(localUrls);
return data;
}
QMimeData *FileDropSupport::mimeDataForFilePath(const QString &filePath)
{
return mimeDataForFilePaths(QStringList() << filePath);
}
bool FileDropSupport::eventFilter(QObject *obj, QEvent *event) 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 (isFileDrop(dee->mimeData())
&& (!m_filterFunction || m_filterFunction(dee))) && (!m_filterFunction || m_filterFunction(dee)))
event->accept(); event->accept();
else else
...@@ -776,8 +768,8 @@ bool FileDropSupport::eventFilter(QObject *obj, QEvent *event) ...@@ -776,8 +768,8 @@ bool FileDropSupport::eventFilter(QObject *obj, QEvent *event)
return true; 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; QList<FileSpec> tempFiles;
if (isDesktopFileManagerDrop(de->mimeData(), &tempFiles) if (isFileDrop(de->mimeData(), &tempFiles)
&& (!m_filterFunction || m_filterFunction(de))) { && (!m_filterFunction || m_filterFunction(de))) {
event->accept(); event->accept();
de->acceptProposedAction(); de->acceptProposedAction();
...@@ -800,6 +792,21 @@ void FileDropSupport::emitFilesDropped() ...@@ -800,6 +792,21 @@ void FileDropSupport::emitFilesDropped()
m_files.clear(); m_files.clear();
} }
void FileDropMimeData::addFile(const QString &filePath, int line, int column)
{
// standard mime data
QList<QUrl> currentUrls = urls();
currentUrls.append(QUrl::fromLocalFile(filePath));
setUrls(currentUrls);
// special mime data
m_files.append(FileDropSupport::FileSpec(filePath, line, column));
}
QList<FileDropSupport::FileSpec> FileDropMimeData::files() const
{
return m_files;
}
} // namespace Utils } // namespace Utils
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include <QCoreApplication> #include <QCoreApplication>
#include <QXmlStreamWriter> // Mac. #include <QXmlStreamWriter> // Mac.
#include <QMetaType> #include <QMetaType>
#include <QMimeData>
#include <QStringList> #include <QStringList>
#include <functional> #include <functional>
...@@ -48,7 +49,6 @@ class QDir; ...@@ -48,7 +49,6 @@ class QDir;
class QDropEvent; class QDropEvent;
class QFile; class QFile;
class QFileInfo; class QFileInfo;
class QMimeData;
class QTemporaryFile; class QTemporaryFile;
class QTextStream; class QTextStream;
class QWidget; class QWidget;
...@@ -202,18 +202,22 @@ class QTCREATOR_UTILS_EXPORT FileDropSupport : public QObject ...@@ -202,18 +202,22 @@ class QTCREATOR_UTILS_EXPORT FileDropSupport : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
// returns true if the event should be accepted struct FileSpec {
FileSpec(const QString &path, int r = -1, int c = -1) : filePath(path), line(r), column(c) {}
QString filePath;
int line;
int column;
};
// returns true if the event should be accepted
typedef std::function<bool(QDropEvent*)> DropFilterFunction; typedef std::function<bool(QDropEvent*)> DropFilterFunction;
FileDropSupport(QWidget *parentWidget, const DropFilterFunction &filterFunction FileDropSupport(QWidget *parentWidget, const DropFilterFunction &filterFunction
= DropFilterFunction()); = DropFilterFunction());
static QStringList mimeTypesForFilePaths(); static QStringList mimeTypesForFilePaths();
static QMimeData *mimeDataForFilePaths(const QStringList &filePaths);
static QMimeData *mimeDataForFilePath(const QString &filePath);
signals: signals:
void filesDropped(const QStringList &files); void filesDropped(const QList<Utils::FileDropSupport::FileSpec> &files);
protected: protected:
bool eventFilter(QObject *obj, QEvent *event); bool eventFilter(QObject *obj, QEvent *event);
...@@ -223,10 +227,21 @@ private slots: ...@@ -223,10 +227,21 @@ private slots:
private: private:
DropFilterFunction m_filterFunction; DropFilterFunction m_filterFunction;
QStringList m_files; QList<FileSpec> m_files;
}; };
class QTCREATOR_UTILS_EXPORT FileDropMimeData : public QMimeData
{
Q_OBJECT
public:
void addFile(const QString &filePath, int line = -1, int column = -1);
QList<FileDropSupport::FileSpec> files() const;
private:
QList<FileDropSupport::FileSpec> m_files;
};
} // namespace Utils } // namespace Utils
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
......
...@@ -229,6 +229,8 @@ BookmarkView::BookmarkView(BookmarkManager *manager) : ...@@ -229,6 +229,8 @@ BookmarkView::BookmarkView(BookmarkManager *manager) :
setSelectionModel(manager->selectionModel()); setSelectionModel(manager->selectionModel());
setSelectionMode(QAbstractItemView::SingleSelection); setSelectionMode(QAbstractItemView::SingleSelection);
setSelectionBehavior(QAbstractItemView::SelectRows); setSelectionBehavior(QAbstractItemView::SelectRows);
setDragEnabled(true);
setDragDropMode(QAbstractItemView::DragOnly);
connect(this, SIGNAL(clicked(QModelIndex)), connect(this, SIGNAL(clicked(QModelIndex)),
this, SLOT(gotoBookmark(QModelIndex))); this, SLOT(gotoBookmark(QModelIndex)));
...@@ -408,6 +410,35 @@ QVariant BookmarkManager::data(const QModelIndex &index, int role) const ...@@ -408,6 +410,35 @@ QVariant BookmarkManager::data(const QModelIndex &index, int role) const
return QVariant(); return QVariant();
} }
Qt::ItemFlags BookmarkManager::flags(const QModelIndex &index) const
{
if (!index.isValid() || index.column() !=0 || index.row() < 0 || index.row() >= m_bookmarksList.count())
return Qt::NoItemFlags;
return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled;
}
Qt::DropActions BookmarkManager::supportedDragActions() const
{
return Qt::MoveAction;
}
QStringList BookmarkManager::mimeTypes() const
{
return FileDropSupport::mimeTypesForFilePaths();
}
QMimeData *BookmarkManager::mimeData(const QModelIndexList &indexes) const
{
auto data = new Utils::FileDropMimeData;
foreach (const QModelIndex &index, indexes) {
if (!index.isValid() || index.column() != 0 || index.row() < 0 || index.row() >= m_bookmarksList.count())
continue;
Bookmark *bookMark = m_bookmarksList.at(index.row());
data->addFile(bookMark->fileName(), bookMark->lineNumber());
}
return data;
}
void BookmarkManager::toggleBookmark() void BookmarkManager::toggleBookmark()
{ {
BaseTextEditor *editor = BaseTextEditor::currentTextEditor(); BaseTextEditor *editor = BaseTextEditor::currentTextEditor();
......
...@@ -74,6 +74,11 @@ public: ...@@ -74,6 +74,11 @@ public:
int rowCount(const QModelIndex &parent = QModelIndex()) const; int rowCount(const QModelIndex &parent = QModelIndex()) const;
int columnCount(const QModelIndex &parent = QModelIndex()) const; int columnCount(const QModelIndex &parent = QModelIndex()) const;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
Qt::ItemFlags flags(const QModelIndex &index) const;
Qt::DropActions supportedDragActions() const;
QStringList mimeTypes() const;
QMimeData *mimeData(const QModelIndexList &indexes) const;
// this QItemSelectionModel is shared by all views // this QItemSelectionModel is shared by all views
QItemSelectionModel *selectionModel() const; QItemSelectionModel *selectionModel() const;
......
...@@ -426,14 +426,14 @@ Qt::ItemFlags DocumentModelPrivate::flags(const QModelIndex &index) const ...@@ -426,14 +426,14 @@ Qt::ItemFlags DocumentModelPrivate::flags(const QModelIndex &index) const
QMimeData *DocumentModelPrivate::mimeData(const QModelIndexList &indexes) const QMimeData *DocumentModelPrivate::mimeData(const QModelIndexList &indexes) const
{ {
QStringList filePaths; auto data = new Utils::FileDropMimeData;
foreach (const QModelIndex &index, indexes) { foreach (const QModelIndex &index, indexes) {
const DocumentModel::Entry *e = DocumentModel::entryAtRow(index.row()); const DocumentModel::Entry *e = DocumentModel::entryAtRow(index.row());
if (!e || e->fileName().isEmpty()) if (!e || e->fileName().isEmpty())
continue; continue;
filePaths.append(e->fileName()); data->addFile(e->fileName());
} }
return Utils::FileDropSupport::mimeDataForFilePaths(filePaths); return data;
} }
int DocumentModel::rowOfDocument(IDocument *document) int DocumentModel::rowOfDocument(IDocument *document)
......
...@@ -577,6 +577,19 @@ IEditor *EditorManagerPrivate::openEditor(EditorView *view, const QString &fileN ...@@ -577,6 +577,19 @@ IEditor *EditorManagerPrivate::openEditor(EditorView *view, const QString &fileN
return result; return result;
} }
IEditor *EditorManagerPrivate::openEditorAt(EditorView *view, const QString &fileName, int line,
int column, Id editorId,
EditorManager::OpenEditorFlags flags, bool *newEditor)
{
EditorManager::cutForwardNavigationHistory();
EditorManager::addCurrentPositionToNavigationHistory();
EditorManager::OpenEditorFlags tempFlags = flags | EditorManager::IgnoreNavigationHistory;
Core::IEditor *editor = openEditor(view, fileName, editorId, tempFlags, newEditor);
if (editor && line != -1)
editor->gotoLine(line, column);
return editor;
}
IEditor *EditorManagerPrivate::activateEditorForDocument(EditorView *view, IDocument *document, IEditor *EditorManagerPrivate::activateEditorForDocument(EditorView *view, IDocument *document,
EditorManager::OpenEditorFlags flags) EditorManager::OpenEditorFlags flags)
{ {
...@@ -2222,14 +2235,8 @@ IEditor *EditorManager::openEditor(const QString &fileName, Id editorId, ...@@ -2222,14 +2235,8 @@ IEditor *EditorManager::openEditor(const QString &fileName, Id editorId,
IEditor *EditorManager::openEditorAt(const QString &fileName, int line, int column, IEditor *EditorManager::openEditorAt(const QString &fileName, int line, int column,
Id editorId, OpenEditorFlags flags, bool *newEditor) Id editorId, OpenEditorFlags flags, bool *newEditor)
{ {
m_instance->cutForwardNavigationHistory(); return EditorManagerPrivate::openEditorAt(EditorManagerPrivate::currentEditorView(),
m_instance->addCurrentPositionToNavigationHistory(); fileName, line, column, editorId, flags, newEditor);
OpenEditorFlags tempFlags = flags | IgnoreNavigationHistory;
Core::IEditor *editor = Core::EditorManager::openEditor(fileName, editorId,
tempFlags, newEditor);
if (editor && line != -1)
editor->gotoLine(line, column);
return editor;
} }
// Extract line number suffix. Return the suffix (e.g. ":132") and truncates the filename accordingly. // Extract line number suffix. Return the suffix (e.g. ":132") and truncates the filename accordingly.
......
...@@ -75,6 +75,13 @@ public: ...@@ -75,6 +75,13 @@ public:
Id editorId = Id(), Id editorId = Id(),
EditorManager::OpenEditorFlags flags = EditorManager::NoFlags, EditorManager::OpenEditorFlags flags = EditorManager::NoFlags,
bool *newEditor = 0); bool *newEditor = 0);
static IEditor *openEditorAt(EditorView *view,
const QString &fileName,
int line,
int column = 0,
Id editorId = Id(),
EditorManager::OpenEditorFlags flags = EditorManager::NoFlags,
bool *newEditor = 0);
static IEditor *duplicateEditor(IEditor *editor); static IEditor *duplicateEditor(IEditor *editor);
static IEditor *activateEditor(EditorView *view, IEditor *editor, static IEditor *activateEditor(EditorView *view, IEditor *editor,
EditorManager::OpenEditorFlags flags = EditorManager::NoFlags); EditorManager::OpenEditorFlags flags = EditorManager::NoFlags);
......
...@@ -40,7 +40,6 @@ ...@@ -40,7 +40,6 @@
#include <coreplugin/minisplitter.h> #include <coreplugin/minisplitter.h>
#include <coreplugin/editormanager/ieditor.h> #include <coreplugin/editormanager/ieditor.h>
#include <coreplugin/findplaceholder.h> #include <coreplugin/findplaceholder.h>
#include <utils/fileutils.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <QDebug> #include <QDebug>
...@@ -125,8 +124,8 @@ EditorView::EditorView(SplitterOrView *parentSplitterOrView, QWidget *parent) : ...@@ -125,8 +124,8 @@ EditorView::EditorView(SplitterOrView *parentSplitterOrView, QWidget *parent) :
auto dropSupport = new Utils::FileDropSupport(this, [this](QDropEvent *event) { auto dropSupport = new Utils::FileDropSupport(this, [this](QDropEvent *event) {
return event->source() != m_toolBar; // do not accept drops on ourselves return event->source() != m_toolBar; // do not accept drops on ourselves
}); });
connect(dropSupport, SIGNAL(filesDropped(QStringList)), connect(dropSupport, &Utils::FileDropSupport::filesDropped,
this, SLOT(openDroppedFiles(QStringList))); this, &EditorView::openDroppedFiles);
updateNavigatorActions(); updateNavigatorActions();
} }
...@@ -350,11 +349,12 @@ void EditorView::closeSplit() ...@@ -350,11 +349,12 @@ void EditorView::closeSplit()
EditorManagerPrivate::updateActions(); EditorManagerPrivate::updateActions();
} }
void EditorView::openDroppedFiles(const QStringList &files) void EditorView::openDroppedFiles(const QList<Utils::FileDropSupport::FileSpec> &files)
{ {
const int count = files.size(); const int count = files.size();
for (int i = 0; i < count; ++i) { for (int i = 0; i < count; ++i) {
EditorManagerPrivate::openEditor(this, files.at(i), Id(), const Utils::FileDropSupport::FileSpec spec = files.at(i);
EditorManagerPrivate::openEditorAt(this, spec.filePath, spec.line, spec.column, Id(),
i < count - 1 ? EditorManager::DoNotChangeCurrentEditor i < count - 1 ? EditorManager::DoNotChangeCurrentEditor
| EditorManager::DoNotMakeVisible | EditorManager::DoNotMakeVisible
: EditorManager::NoFlags); : EditorManager::NoFlags);
......
...@@ -32,6 +32,8 @@ ...@@ -32,6 +32,8 @@
#include "coreplugin/id.h" #include "coreplugin/id.h"
#include <utils/fileutils.h>
#include <QMap> #include <QMap>
#include <QList> #include <QList>
#include <QString> #include <QString>
...@@ -119,7 +121,7 @@ private slots: ...@@ -119,7 +121,7 @@ private slots:
void splitVertically(); void splitVertically();
void splitNewWindow(); void splitNewWindow();
void closeSplit(); void closeSplit();
void openDroppedFiles(const QStringList &files); void openDroppedFiles(const QList<Utils::FileDropSupport::FileSpec> &files);
private: private:
friend class SplitterOrView; // for setParentSplitterOrView friend class SplitterOrView; // for setParentSplitterOrView
......
...@@ -453,8 +453,10 @@ bool EditorToolBar::eventFilter(QObject *obj, QEvent *event) ...@@ -453,8 +453,10 @@ bool EditorToolBar::eventFilter(QObject *obj, QEvent *event)
d->m_editorList->currentIndex()); d->m_editorList->currentIndex());
if (!entry) // no document if (!entry) // no document
return Utils::StyledBar::eventFilter(obj, event); return Utils::StyledBar::eventFilter(obj, event);
auto *drag = new QDrag(this); auto drag = new QDrag(this);
drag->setMimeData(Utils::FileDropSupport::mimeDataForFilePath(entry->fileName())); auto data = new Utils::FileDropMimeData;
data->addFile(entry->fileName());
drag->setMimeData(data);
Qt::DropAction action = drag->exec(Qt::MoveAction | Qt::CopyAction, Qt::MoveAction); Qt::DropAction action = drag->exec(Qt::MoveAction | Qt::CopyAction, Qt::MoveAction);
if (action == Qt::MoveAction) if (action == Qt::MoveAction)
emit currentDocumentMoved(); emit currentDocumentMoved();
......
...@@ -73,7 +73,7 @@ ...@@ -73,7 +73,7 @@
#include <coreplugin/progressmanager/progressmanager_p.h> #include <coreplugin/progressmanager/progressmanager_p.h>
#include <coreplugin/progressmanager/progressview.h> #include <coreplugin/progressmanager/progressview.h>
#include <coreplugin/settingsdatabase.h> #include <coreplugin/settingsdatabase.h>
#include <utils/fileutils.h> #include <utils/algorithm.h>
#include <utils/historycompleter.h> #include <utils/historycompleter.h>
#include <utils/hostosinfo.h> #include <utils/hostosinfo.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
...@@ -212,8 +212,8 @@ MainWindow::MainWindow() : ...@@ -212,8 +212,8 @@ MainWindow::MainWindow() :
auto dropSupport = new Utils::FileDropSupport(this, [](QDropEvent *event) { auto dropSupport = new Utils::FileDropSupport(this, [](QDropEvent *event) {
return event->source() == 0; // only accept drops from the "outside" (e.g. file manager) return event->source() == 0; // only accept drops from the "outside" (e.g. file manager)
}); });
connect(dropSupport, SIGNAL(filesDropped(QStringList)), connect(dropSupport, &Utils::FileDropSupport::filesDropped,
this, SLOT(openDroppedFiles(QStringList))); this, &MainWindow::openDroppedFiles);
} }
void MainWindow::setSidebarVisible(bool visible) void MainWindow::setSidebarVisible(bool visible)
...@@ -384,10 +384,14 @@ void MainWindow::closeEvent(QCloseEvent *event) ...@@ -384,10 +384,14 @@ void MainWindow::closeEvent(QCloseEvent *event)
event->accept(); event->accept();
} }
void MainWindow::openDroppedFiles(const QStringList &files) void MainWindow::openDroppedFiles(const QList<Utils::FileDropSupport::FileSpec> &files)
{ {
raiseWindow(); raiseWindow();
openFiles(files, ICore::SwitchMode); QStringList filePaths = Utils::transform(files,
[](const Utils::FileDropSupport::FileSpec &spec) -> QString {
return spec.filePath;
});
openFiles(filePaths, ICore::SwitchMode);
} }
IContext *MainWindow::currentContextObject() const IContext *MainWindow::currentContextObject() const
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include "dialogs/newdialog.h" #include "dialogs/newdialog.h"
#include <utils/appmainwindow.h> #include <utils/appmainwindow.h>
#include <utils/fileutils.h>
#include <QMap> #include <QMap>
#include <QColor> #include <QColor>
...@@ -148,7 +149,7 @@ private slots: ...@@ -148,7 +149,7 @@ private slots:
void updateFocusWidget(QWidget *old, QWidget *now); void updateFocusWidget(QWidget *old, QWidget *now);
void setSidebarVisible(bool visible); void setSidebarVisible(bool visible);
void destroyVersionDialog(); void destroyVersionDialog();
void openDroppedFiles(const QStringList &files); void openDroppedFiles(const QList<Utils::FileDropSupport::FileSpec> &files);
void restoreWindowState(); void restoreWindowState();
void newItemDialogFinished(); void newItemDialogFinished();
......
...@@ -500,13 +500,13 @@ QStringList FlatModel::mimeTypes() const ...@@ -500,13 +500,13 @@ QStringList FlatModel::mimeTypes() const
QMimeData *FlatModel::mimeData(const QModelIndexList &indexes) const QMimeData *FlatModel::mimeData(const QModelIndexList &indexes) const
{ {
QStringList filePaths; auto data = new Utils::FileDropMimeData;
foreach (const QModelIndex &index, indexes) { foreach (const QModelIndex &index, indexes) {
Node *node = nodeForIndex(index); Node *node = nodeForIndex(index);
if (qobject_cast<FileNode *>(node)) if (qobject_cast<FileNode *>(node))
filePaths.append(node->path()); data->addFile(node->path());
} }
return Utils::FileDropSupport::mimeDataForFilePaths(filePaths); return data;
} }
QModelIndex FlatModel::indexForNode(const Node *node_) QModelIndex FlatModel::indexForNode(const Node *node_)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment