diff --git a/src/libs/utils/fileutils.cpp b/src/libs/utils/fileutils.cpp index 3579dc56ece..4832d6cf834 100644 --- a/src/libs/utils/fileutils.cpp +++ b/src/libs/utils/fileutils.cpp @@ -40,7 +40,6 @@ #include #include #include -#include #include #include @@ -705,8 +704,16 @@ FileName &FileName::appendString(QChar str) return *this; } -static bool isDesktopFileManagerDrop(const QMimeData *d, QStringList *files = 0) +static bool isFileDrop(const QMimeData *d, QList *files = 0) { + // internal drop + if (const FileDropMimeData *internalData = qobject_cast(d)) { + if (files) + *files = internalData->files(); + return true; + } + + // external drop if (files) files->clear(); // Extract dropped files from Mime data. @@ -723,7 +730,7 @@ static bool isDesktopFileManagerDrop(const QMimeData *d, QStringList *files = 0) if (!fileName.isEmpty()) { hasFiles = true; if (files) - files->push_back(fileName); + files->append(FileDropSupport::FileSpec(fileName)); else break; // No result list, sufficient for checking } @@ -745,27 +752,12 @@ QStringList FileDropSupport::mimeTypesForFilePaths() return QStringList() << QStringLiteral("text/uri-list"); } -QMimeData *FileDropSupport::mimeDataForFilePaths(const QStringList &filePaths) -{ - QList 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) { Q_UNUSED(obj) if (event->type() == QEvent::DragEnter) { auto dee = static_cast(event); - if (isDesktopFileManagerDrop(dee->mimeData()) + if (isFileDrop(dee->mimeData()) && (!m_filterFunction || m_filterFunction(dee))) event->accept(); else @@ -776,8 +768,8 @@ bool FileDropSupport::eventFilter(QObject *obj, QEvent *event) return true; } else if (event->type() == QEvent::Drop) { auto de = static_cast(event); - QStringList tempFiles; - if (isDesktopFileManagerDrop(de->mimeData(), &tempFiles) + QList tempFiles; + if (isFileDrop(de->mimeData(), &tempFiles) && (!m_filterFunction || m_filterFunction(de))) { event->accept(); de->acceptProposedAction(); @@ -800,6 +792,21 @@ void FileDropSupport::emitFilesDropped() m_files.clear(); } +void FileDropMimeData::addFile(const QString &filePath, int line, int column) +{ + // standard mime data + QList currentUrls = urls(); + currentUrls.append(QUrl::fromLocalFile(filePath)); + setUrls(currentUrls); + // special mime data + m_files.append(FileDropSupport::FileSpec(filePath, line, column)); +} + +QList FileDropMimeData::files() const +{ + return m_files; +} + } // namespace Utils QT_BEGIN_NAMESPACE diff --git a/src/libs/utils/fileutils.h b/src/libs/utils/fileutils.h index 53f61790b37..54b1a46018e 100644 --- a/src/libs/utils/fileutils.h +++ b/src/libs/utils/fileutils.h @@ -35,6 +35,7 @@ #include #include // Mac. #include +#include #include #include @@ -48,7 +49,6 @@ class QDir; class QDropEvent; class QFile; class QFileInfo; -class QMimeData; class QTemporaryFile; class QTextStream; class QWidget; @@ -202,18 +202,22 @@ class QTCREATOR_UTILS_EXPORT FileDropSupport : public QObject { Q_OBJECT 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 DropFilterFunction; FileDropSupport(QWidget *parentWidget, const DropFilterFunction &filterFunction = DropFilterFunction()); static QStringList mimeTypesForFilePaths(); - static QMimeData *mimeDataForFilePaths(const QStringList &filePaths); - static QMimeData *mimeDataForFilePath(const QString &filePath); signals: - void filesDropped(const QStringList &files); + void filesDropped(const QList &files); protected: bool eventFilter(QObject *obj, QEvent *event); @@ -223,10 +227,21 @@ private slots: private: DropFilterFunction m_filterFunction; - QStringList m_files; + QList m_files; }; +class QTCREATOR_UTILS_EXPORT FileDropMimeData : public QMimeData +{ + Q_OBJECT +public: + void addFile(const QString &filePath, int line = -1, int column = -1); + QList files() const; + +private: + QList m_files; +}; + } // namespace Utils QT_BEGIN_NAMESPACE diff --git a/src/plugins/bookmarks/bookmarkmanager.cpp b/src/plugins/bookmarks/bookmarkmanager.cpp index ff8c49d276a..57f6d68d421 100644 --- a/src/plugins/bookmarks/bookmarkmanager.cpp +++ b/src/plugins/bookmarks/bookmarkmanager.cpp @@ -229,6 +229,8 @@ BookmarkView::BookmarkView(BookmarkManager *manager) : setSelectionModel(manager->selectionModel()); setSelectionMode(QAbstractItemView::SingleSelection); setSelectionBehavior(QAbstractItemView::SelectRows); + setDragEnabled(true); + setDragDropMode(QAbstractItemView::DragOnly); connect(this, SIGNAL(clicked(QModelIndex)), this, SLOT(gotoBookmark(QModelIndex))); @@ -408,6 +410,35 @@ QVariant BookmarkManager::data(const QModelIndex &index, int role) const 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() { BaseTextEditor *editor = BaseTextEditor::currentTextEditor(); diff --git a/src/plugins/bookmarks/bookmarkmanager.h b/src/plugins/bookmarks/bookmarkmanager.h index 0fbd7876dae..c390bdfe317 100644 --- a/src/plugins/bookmarks/bookmarkmanager.h +++ b/src/plugins/bookmarks/bookmarkmanager.h @@ -74,6 +74,11 @@ public: int rowCount(const QModelIndex &parent = QModelIndex()) const; int columnCount(const QModelIndex &parent = QModelIndex()) 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 QItemSelectionModel *selectionModel() const; diff --git a/src/plugins/coreplugin/editormanager/documentmodel.cpp b/src/plugins/coreplugin/editormanager/documentmodel.cpp index 1b972ca8d9e..4cc7412927c 100644 --- a/src/plugins/coreplugin/editormanager/documentmodel.cpp +++ b/src/plugins/coreplugin/editormanager/documentmodel.cpp @@ -426,14 +426,14 @@ Qt::ItemFlags DocumentModelPrivate::flags(const QModelIndex &index) const QMimeData *DocumentModelPrivate::mimeData(const QModelIndexList &indexes) const { - QStringList filePaths; + auto data = new Utils::FileDropMimeData; foreach (const QModelIndex &index, indexes) { const DocumentModel::Entry *e = DocumentModel::entryAtRow(index.row()); if (!e || e->fileName().isEmpty()) continue; - filePaths.append(e->fileName()); + data->addFile(e->fileName()); } - return Utils::FileDropSupport::mimeDataForFilePaths(filePaths); + return data; } int DocumentModel::rowOfDocument(IDocument *document) diff --git a/src/plugins/coreplugin/editormanager/editormanager.cpp b/src/plugins/coreplugin/editormanager/editormanager.cpp index 338390a004d..65497dbe72a 100644 --- a/src/plugins/coreplugin/editormanager/editormanager.cpp +++ b/src/plugins/coreplugin/editormanager/editormanager.cpp @@ -577,6 +577,19 @@ IEditor *EditorManagerPrivate::openEditor(EditorView *view, const QString &fileN 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, EditorManager::OpenEditorFlags flags) { @@ -2222,14 +2235,8 @@ IEditor *EditorManager::openEditor(const QString &fileName, Id editorId, IEditor *EditorManager::openEditorAt(const QString &fileName, int line, int column, Id editorId, OpenEditorFlags flags, bool *newEditor) { - m_instance->cutForwardNavigationHistory(); - m_instance->addCurrentPositionToNavigationHistory(); - OpenEditorFlags tempFlags = flags | IgnoreNavigationHistory; - Core::IEditor *editor = Core::EditorManager::openEditor(fileName, editorId, - tempFlags, newEditor); - if (editor && line != -1) - editor->gotoLine(line, column); - return editor; + return EditorManagerPrivate::openEditorAt(EditorManagerPrivate::currentEditorView(), + fileName, line, column, editorId, flags, newEditor); } // Extract line number suffix. Return the suffix (e.g. ":132") and truncates the filename accordingly. diff --git a/src/plugins/coreplugin/editormanager/editormanager_p.h b/src/plugins/coreplugin/editormanager/editormanager_p.h index 5d7de60a110..6acefae6ee5 100644 --- a/src/plugins/coreplugin/editormanager/editormanager_p.h +++ b/src/plugins/coreplugin/editormanager/editormanager_p.h @@ -75,6 +75,13 @@ public: Id editorId = Id(), EditorManager::OpenEditorFlags flags = EditorManager::NoFlags, 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 *activateEditor(EditorView *view, IEditor *editor, EditorManager::OpenEditorFlags flags = EditorManager::NoFlags); diff --git a/src/plugins/coreplugin/editormanager/editorview.cpp b/src/plugins/coreplugin/editormanager/editorview.cpp index 1699ae01ba0..0afdfd3d64d 100644 --- a/src/plugins/coreplugin/editormanager/editorview.cpp +++ b/src/plugins/coreplugin/editormanager/editorview.cpp @@ -40,7 +40,6 @@ #include #include #include -#include #include #include @@ -125,8 +124,8 @@ EditorView::EditorView(SplitterOrView *parentSplitterOrView, QWidget *parent) : 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))); + connect(dropSupport, &Utils::FileDropSupport::filesDropped, + this, &EditorView::openDroppedFiles); updateNavigatorActions(); } @@ -350,11 +349,12 @@ void EditorView::closeSplit() EditorManagerPrivate::updateActions(); } -void EditorView::openDroppedFiles(const QStringList &files) +void EditorView::openDroppedFiles(const QList &files) { const int count = files.size(); 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 | EditorManager::DoNotMakeVisible : EditorManager::NoFlags); diff --git a/src/plugins/coreplugin/editormanager/editorview.h b/src/plugins/coreplugin/editormanager/editorview.h index c6770b988d3..d5df7c4f857 100644 --- a/src/plugins/coreplugin/editormanager/editorview.h +++ b/src/plugins/coreplugin/editormanager/editorview.h @@ -32,6 +32,8 @@ #include "coreplugin/id.h" +#include + #include #include #include @@ -119,7 +121,7 @@ private slots: void splitVertically(); void splitNewWindow(); void closeSplit(); - void openDroppedFiles(const QStringList &files); + void openDroppedFiles(const QList &files); private: friend class SplitterOrView; // for setParentSplitterOrView diff --git a/src/plugins/coreplugin/editortoolbar.cpp b/src/plugins/coreplugin/editortoolbar.cpp index 2495951f1e9..6a92055f290 100644 --- a/src/plugins/coreplugin/editortoolbar.cpp +++ b/src/plugins/coreplugin/editortoolbar.cpp @@ -453,8 +453,10 @@ bool EditorToolBar::eventFilter(QObject *obj, QEvent *event) 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())); + auto drag = new QDrag(this); + auto data = new Utils::FileDropMimeData; + data->addFile(entry->fileName()); + drag->setMimeData(data); Qt::DropAction action = drag->exec(Qt::MoveAction | Qt::CopyAction, Qt::MoveAction); if (action == Qt::MoveAction) emit currentDocumentMoved(); diff --git a/src/plugins/coreplugin/mainwindow.cpp b/src/plugins/coreplugin/mainwindow.cpp index 8c6cb9c1f03..b369b2ff3ac 100644 --- a/src/plugins/coreplugin/mainwindow.cpp +++ b/src/plugins/coreplugin/mainwindow.cpp @@ -73,7 +73,7 @@ #include #include #include -#include +#include #include #include #include @@ -212,8 +212,8 @@ MainWindow::MainWindow() : 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))); + connect(dropSupport, &Utils::FileDropSupport::filesDropped, + this, &MainWindow::openDroppedFiles); } void MainWindow::setSidebarVisible(bool visible) @@ -384,10 +384,14 @@ void MainWindow::closeEvent(QCloseEvent *event) event->accept(); } -void MainWindow::openDroppedFiles(const QStringList &files) +void MainWindow::openDroppedFiles(const QList &files) { 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 diff --git a/src/plugins/coreplugin/mainwindow.h b/src/plugins/coreplugin/mainwindow.h index 7c901b3fb41..f652b390f71 100644 --- a/src/plugins/coreplugin/mainwindow.h +++ b/src/plugins/coreplugin/mainwindow.h @@ -35,6 +35,7 @@ #include "dialogs/newdialog.h" #include +#include #include #include @@ -148,7 +149,7 @@ private slots: void updateFocusWidget(QWidget *old, QWidget *now); void setSidebarVisible(bool visible); void destroyVersionDialog(); - void openDroppedFiles(const QStringList &files); + void openDroppedFiles(const QList &files); void restoreWindowState(); void newItemDialogFinished(); diff --git a/src/plugins/projectexplorer/projectmodels.cpp b/src/plugins/projectexplorer/projectmodels.cpp index cdc3f8f4ff8..9507f94e799 100644 --- a/src/plugins/projectexplorer/projectmodels.cpp +++ b/src/plugins/projectexplorer/projectmodels.cpp @@ -500,13 +500,13 @@ QStringList FlatModel::mimeTypes() const QMimeData *FlatModel::mimeData(const QModelIndexList &indexes) const { - QStringList filePaths; + auto data = new Utils::FileDropMimeData; foreach (const QModelIndex &index, indexes) { Node *node = nodeForIndex(index); if (qobject_cast(node)) - filePaths.append(node->path()); + data->addFile(node->path()); } - return Utils::FileDropSupport::mimeDataForFilePaths(filePaths); + return data; } QModelIndex FlatModel::indexForNode(const Node *node_)