forked from qt-creator/qt-creator
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: Daniel Teske <daniel.teske@digia.com> Reviewed-by: Fawzi Mohamed <fawzi.mohamed@digia.com>
This commit is contained in:
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user