Commit 81cb4719 authored by Eike Ziller's avatar Eike Ziller

Editors: Support dragging from outline views

Fill the line and column information in the location returned by
QmlOutlineModel::sourceLocation for that.
The drag & drop code also needed a way to override the executed drop
action for file drops, because the QML outline supports move-drags, which
would lead to the items being removed from the outline when dragged onto
a split...

Change-Id: I2478abc7d5aa2f3aa676cdd609ecb69a50adce8c
Reviewed-by: default avatarDaniel Teske <daniel.teske@digia.com>
Reviewed-by: default avatarFawzi Mohamed <fawzi.mohamed@digia.com>
parent 92c4f26e
......@@ -34,6 +34,7 @@
#include <cplusplus/Scope.h>
#include <cplusplus/Literals.h>
#include <cplusplus/Symbols.h>
#include <utils/fileutils.h>
using namespace CPlusPlus;
......@@ -242,3 +243,35 @@ void OverviewModel::rebuild(Document::Ptr doc)
_cppDocument = doc;
endResetModel();
}
Qt::ItemFlags OverviewModel::flags(const QModelIndex &index) const
{
Q_UNUSED(index)
return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled;
}
Qt::DropActions OverviewModel::supportedDragActions() const
{
return Qt::MoveAction;
}
QStringList OverviewModel::mimeTypes() const
{
return Utils::FileDropSupport::mimeTypesForFilePaths();
}
QMimeData *OverviewModel::mimeData(const QModelIndexList &indexes) const
{
auto mimeData = new Utils::FileDropMimeData;
foreach (const QModelIndex &index, indexes) {
const QVariant fileName = data(index, FileNameRole);
if (!fileName.canConvert<QString>())
continue;
const QVariant lineNumber = data(index, LineNumberRole);
if (!fileName.canConvert<unsigned>())
continue;
mimeData->addFile(fileName.toString(), lineNumber.value<unsigned>());
}
return mimeData;
}
......@@ -61,6 +61,11 @@ public:
Document::Ptr document() const;
Symbol *symbolFromIndex(const QModelIndex &index) const;
Qt::ItemFlags flags(const QModelIndex &index) const;
Qt::DropActions supportedDragActions() const;
QStringList mimeTypes() const;
QMimeData *mimeData(const QModelIndexList &indexes) const;
public Q_SLOTS:
void rebuild(CPlusPlus::Document::Ptr doc);
......
......@@ -778,12 +778,22 @@ bool FileDropSupport::eventFilter(QObject *obj, QEvent *event)
QList<FileSpec> tempFiles;
if (isFileDrop(de->mimeData(), &tempFiles)
&& (!m_filterFunction || m_filterFunction(de))) {
const FileDropMimeData *fileDropMimeData = qobject_cast<const FileDropMimeData *>(de->mimeData());
event->accept();
de->acceptProposedAction();
if (fileDropMimeData && fileDropMimeData->isOverridingFileDropAction())
de->setDropAction(fileDropMimeData->overrideFileDropAction());
else
de->acceptProposedAction();
bool needToScheduleEmit = m_files.isEmpty();
m_files.append(tempFiles);
if (needToScheduleEmit) // otherwise we already have a timer pending
QTimer::singleShot(0, this, SLOT(emitFilesDropped()));
if (needToScheduleEmit) { // otherwise we already have a timer pending
// Delay the actual drop, to avoid conflict between
// actions that happen when opening files, and actions that the item views do
// after the drag operation.
// If we do not do this, e.g. dragging from Outline view crashes if the editor and
// the selected item changes
QTimer::singleShot(100, this, SLOT(emitFilesDropped()));
}
} else {
event->ignore();
}
......@@ -799,6 +809,34 @@ void FileDropSupport::emitFilesDropped()
m_files.clear();
}
/*!
Sets the drop action to effectively use, instead of the "proposed" drop action from the
drop event. This can be useful when supporting move drags within an item view, but not
"moving" an item from the item view into a split.
*/
FileDropMimeData::FileDropMimeData()
: m_overrideDropAction(Qt::IgnoreAction),
m_isOverridingDropAction(false)
{
}
void FileDropMimeData::setOverrideFileDropAction(Qt::DropAction action)
{
m_isOverridingDropAction = true;
m_overrideDropAction = action;
}
Qt::DropAction FileDropMimeData::overrideFileDropAction() const
{
return m_overrideDropAction;
}
bool FileDropMimeData::isOverridingFileDropAction() const
{
return m_isOverridingDropAction;
}
void FileDropMimeData::addFile(const QString &filePath, int line, int column)
{
// standard mime data
......
......@@ -236,11 +236,19 @@ class QTCREATOR_UTILS_EXPORT FileDropMimeData : public QMimeData
{
Q_OBJECT
public:
FileDropMimeData();
void setOverrideFileDropAction(Qt::DropAction action);
Qt::DropAction overrideFileDropAction() const;
bool isOverridingFileDropAction() const;
void addFile(const QString &filePath, int line = -1, int column = -1);
QList<FileDropSupport::FileSpec> files() const;
private:
QList<FileDropSupport::FileSpec> m_files;
Qt::DropAction m_overrideDropAction;
bool m_isOverridingDropAction;
};
} // namespace Utils
......
......@@ -51,6 +51,8 @@ CppOutlineTreeView::CppOutlineTreeView(QWidget *parent) :
Utils::NavigationTreeView(parent)
{
setExpandsOnDoubleClick(false);
setDragEnabled(true);
setDragDropMode(QAbstractItemView::DragOnly);
}
void CppOutlineTreeView::contextMenuEvent(QContextMenuEvent *event)
......@@ -90,6 +92,11 @@ bool CppOutlineFilterModel::filterAcceptsRow(int sourceRow,
return QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent);
}
Qt::DropActions CppOutlineFilterModel::supportedDragActions() const
{
return sourceModel()->supportedDragActions();
}
CppOutlineWidget::CppOutlineWidget(CppEditorWidget *editor) :
TextEditor::IOutlineWidget(),
......
......@@ -60,6 +60,7 @@ public:
// QSortFilterProxyModel
bool filterAcceptsRow(int sourceRow,
const QModelIndex &sourceParent) const;
Qt::DropActions supportedDragActions() const;
private:
CPlusPlus::OverviewModel *m_sourceModel;
};
......
......@@ -82,6 +82,11 @@ QVariant QmlJSOutlineFilterModel::data(const QModelIndex &index, int role) const
return QSortFilterProxyModel::data(index, role);
}
Qt::DropActions QmlJSOutlineFilterModel::supportedDragActions() const
{
return sourceModel()->supportedDragActions();
}
bool QmlJSOutlineFilterModel::filterBindings() const
{
return m_filterBindings;
......
......@@ -54,6 +54,7 @@ public:
bool filterAcceptsRow(int sourceRow,
const QModelIndex &sourceParent) const;
QVariant data(const QModelIndex &index, int role) const;
Qt::DropActions supportedDragActions() const;
bool filterBindings() const;
void setFilterBindings(bool filterBindings);
......
......@@ -37,6 +37,7 @@
#include <qmljs/qmljsrewriter.h>
#include <qmljstools/qmljsrefactoringchanges.h>
#include <utils/fileutils.h>
#include <utils/qtcassert.h>
#include <coreplugin/icore.h>
......@@ -53,6 +54,8 @@ enum {
debug = false
};
static const char INTERNAL_MIMETYPE[] = "application/x-qtcreator-qmloutlinemodel";
namespace QmlJSEditor {
namespace Internal {
......@@ -312,7 +315,8 @@ QmlOutlineModel::QmlOutlineModel(QmlJSEditorDocument *document) :
QStringList QmlOutlineModel::mimeTypes() const
{
QStringList types;
types << QLatin1String("application/x-qtcreator-qmloutlinemodel");
types << QLatin1String(INTERNAL_MIMETYPE);
types << Utils::FileDropSupport::mimeTypesForFilePaths();
return types;
}
......@@ -321,9 +325,8 @@ QMimeData *QmlOutlineModel::mimeData(const QModelIndexList &indexes) const
{
if (indexes.count() <= 0)
return 0;
QStringList types = mimeTypes();
QMimeData *data = new QMimeData();
QString format = types.at(0);
auto data = new Utils::FileDropMimeData;
data->setOverrideFileDropAction(Qt::CopyAction);
QByteArray encoded;
QDataStream stream(&encoded, QIODevice::WriteOnly);
stream << indexes.size();
......@@ -331,6 +334,10 @@ QMimeData *QmlOutlineModel::mimeData(const QModelIndexList &indexes) const
for (int i = 0; i < indexes.size(); ++i) {
QModelIndex index = indexes.at(i);
AST::SourceLocation location = sourceLocation(index);
data->addFile(m_editorDocument->filePath(), location.startLine,
location.startColumn - 1 /*editors have 0-based column*/);
QList<int> rowPath;
for (QModelIndex i = index; i.isValid(); i = i.parent()) {
rowPath.prepend(i.row());
......@@ -338,7 +345,7 @@ QMimeData *QmlOutlineModel::mimeData(const QModelIndexList &indexes) const
stream << rowPath;
}
data->setData(format, encoded);
data->setData(QLatin1String(INTERNAL_MIMETYPE), encoded);
return data;
}
......@@ -410,8 +417,8 @@ Qt::ItemFlags QmlOutlineModel::flags(const QModelIndex &index) const
Qt::DropActions QmlOutlineModel::supportedDragActions() const
{
// TODO: Maybe add a Copy Action?
return Qt::MoveAction;
// copy action used for dragging onto editor splits
return Qt::MoveAction | Qt::CopyAction;
}
......@@ -915,7 +922,7 @@ QString QmlOutlineModel::asString(AST::UiQualifiedId *id)
AST::SourceLocation QmlOutlineModel::getLocation(AST::UiObjectMember *objMember) {
AST::SourceLocation location;
location.offset = objMember->firstSourceLocation().offset;
location = objMember->firstSourceLocation();
location.length = objMember->lastSourceLocation().offset
- objMember->firstSourceLocation().offset
+ objMember->lastSourceLocation().length;
......@@ -924,7 +931,7 @@ AST::SourceLocation QmlOutlineModel::getLocation(AST::UiObjectMember *objMember)
AST::SourceLocation QmlOutlineModel::getLocation(AST::ExpressionNode *exprNode) {
AST::SourceLocation location;
location.offset = exprNode->firstSourceLocation().offset;
location = exprNode->firstSourceLocation();
location.length = exprNode->lastSourceLocation().offset
- exprNode->firstSourceLocation().offset
+ exprNode->lastSourceLocation().length;
......@@ -941,7 +948,7 @@ AST::SourceLocation QmlOutlineModel::getLocation(AST::PropertyAssignmentList *pr
AST::SourceLocation QmlOutlineModel::getLocation(AST::PropertyNameAndValue *propertyNode) {
AST::SourceLocation location;
location.offset = propertyNode->name->propertyNameToken.offset;
location = propertyNode->name->propertyNameToken;
location.length = propertyNode->value->lastSourceLocation().end() - location.offset;
return location;
......@@ -949,7 +956,7 @@ AST::SourceLocation QmlOutlineModel::getLocation(AST::PropertyNameAndValue *prop
AST::SourceLocation QmlOutlineModel::getLocation(AST::PropertyGetterSetter *propertyNode) {
AST::SourceLocation location;
location.offset = propertyNode->name->propertyNameToken.offset;
location = propertyNode->name->propertyNameToken;
location.length = propertyNode->rbraceToken.end() - location.offset;
return location;
......
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