forked from qt-creator/qt-creator
Support external editors for locator, projects and file system tree
When setting an external editor as the default editor in the MIME type settings. Other operations like File > Open, or when using navigation shortcuts like Follow Symbol, and stepping with the debugger will still always open the file within Qt Creator. The Open with... menu can still be used to explicitly open a file in an external editor afterwards. One of the use cases is to be able to open some files that would otherwise unhelpfully be opened in Qt Creator's binary editor in the systems default editor. Fixes: QTCREATORBUG-13880 Change-Id: I852f097da8badd10de78b74e7078987447eebe98 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: David Schulz <david.schulz@qt.io> Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
@@ -185,7 +185,9 @@ void OpenCMakeTargetLocatorFilter::accept(Core::LocatorFilterEntry selection,
|
|||||||
const auto file = FilePath::fromVariant(extraData.value("file"));
|
const auto file = FilePath::fromVariant(extraData.value("file"));
|
||||||
|
|
||||||
if (line >= 0)
|
if (line >= 0)
|
||||||
Core::EditorManager::openEditorAt({file, line});
|
Core::EditorManager::openEditorAt({file, line},
|
||||||
|
{},
|
||||||
|
Core::EditorManager::AllowExternalEditor);
|
||||||
else
|
else
|
||||||
Core::EditorManager::openEditor(file);
|
Core::EditorManager::openEditor(file, {}, Core::EditorManager::AllowExternalEditor);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -135,6 +135,14 @@ using namespace Core;
|
|||||||
using namespace Core::Internal;
|
using namespace Core::Internal;
|
||||||
using namespace Utils;
|
using namespace Utils;
|
||||||
|
|
||||||
|
static void checkEditorFlags(EditorManager::OpenEditorFlags flags)
|
||||||
|
{
|
||||||
|
if (flags & EditorManager::OpenInOtherSplit) {
|
||||||
|
QTC_CHECK(!(flags & EditorManager::SwitchSplitIfAlreadyVisible));
|
||||||
|
QTC_CHECK(!(flags & EditorManager::AllowExternalEditor));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//===================EditorManager=====================
|
//===================EditorManager=====================
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -812,13 +820,21 @@ IEditor *EditorManagerPrivate::openEditor(EditorView *view, const FilePath &file
|
|||||||
return activateEditor(view, editor, flags);
|
return activateEditor(view, editor, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (skipOpeningBigTextFile(filePath))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
FilePath realFp = autoSaveName(filePath);
|
FilePath realFp = autoSaveName(filePath);
|
||||||
if (!filePath.exists() || !realFp.exists() || filePath.lastModified() >= realFp.lastModified()) {
|
if (!filePath.exists() || !realFp.exists() || filePath.lastModified() >= realFp.lastModified()) {
|
||||||
realFp.removeFile();
|
realFp.removeFile();
|
||||||
realFp = filePath;
|
realFp = filePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
EditorFactoryList factories = EditorManagerPrivate::findFactories(Id(), filePath);
|
EditorTypeList factories = EditorType::preferredEditorTypes(filePath);
|
||||||
|
if (!(flags & EditorManager::AllowExternalEditor)) {
|
||||||
|
factories = Utils::filtered(factories, [](EditorType *type) {
|
||||||
|
return type->asEditorFactory() != nullptr;
|
||||||
|
});
|
||||||
|
}
|
||||||
if (factories.isEmpty()) {
|
if (factories.isEmpty()) {
|
||||||
Utils::MimeType mimeType = Utils::mimeTypeForFile(filePath);
|
Utils::MimeType mimeType = Utils::mimeTypeForFile(filePath);
|
||||||
QMessageBox msgbox(QMessageBox::Critical, EditorManager::tr("File Error"),
|
QMessageBox msgbox(QMessageBox::Critical, EditorManager::tr("File Error"),
|
||||||
@@ -829,48 +845,56 @@ IEditor *EditorManagerPrivate::openEditor(EditorView *view, const FilePath &file
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
if (editorId.isValid()) {
|
if (editorId.isValid()) {
|
||||||
IEditorFactory *factory = Utils::findOrDefault(IEditorFactory::allEditorFactories(),
|
EditorType *factory = EditorType::editorTypeForId(editorId);
|
||||||
Utils::equal(&IEditorFactory::id, editorId));
|
|
||||||
if (factory) {
|
if (factory) {
|
||||||
|
QTC_CHECK(factory->asEditorFactory() || (flags & EditorManager::AllowExternalEditor));
|
||||||
factories.removeOne(factory);
|
factories.removeOne(factory);
|
||||||
factories.push_front(factory);
|
factories.push_front(factory);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (skipOpeningBigTextFile(filePath))
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
IEditor *editor = nullptr;
|
IEditor *editor = nullptr;
|
||||||
auto overrideCursor = Utils::OverrideCursor(QCursor(Qt::WaitCursor));
|
auto overrideCursor = Utils::OverrideCursor(QCursor(Qt::WaitCursor));
|
||||||
|
|
||||||
IEditorFactory *factory = factories.takeFirst();
|
EditorType *factory = factories.takeFirst();
|
||||||
while (factory) {
|
while (factory) {
|
||||||
editor = createEditor(factory, filePath);
|
|
||||||
if (!editor) {
|
|
||||||
factory = factories.takeFirst();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString errorString;
|
QString errorString;
|
||||||
IDocument::OpenResult openResult = editor->document()->open(&errorString, filePath, realFp);
|
|
||||||
if (openResult == IDocument::OpenResult::Success)
|
|
||||||
break;
|
|
||||||
|
|
||||||
overrideCursor.reset();
|
if (factory->asEditorFactory()) {
|
||||||
delete editor;
|
editor = createEditor(factory->asEditorFactory(), filePath);
|
||||||
editor = nullptr;
|
if (!editor) {
|
||||||
|
factory = factories.isEmpty() ? nullptr : factories.takeFirst();
|
||||||
if (openResult == IDocument::OpenResult::ReadError) {
|
continue;
|
||||||
QMessageBox msgbox(QMessageBox::Critical, EditorManager::tr("File Error"),
|
}
|
||||||
tr("Could not open \"%1\" for reading. "
|
IDocument::OpenResult openResult = editor->document()->open(&errorString,
|
||||||
"Either the file does not exist or you do not have "
|
filePath,
|
||||||
"the permissions to open it.")
|
realFp);
|
||||||
.arg(realFp.toUserOutput()),
|
if (openResult == IDocument::OpenResult::Success)
|
||||||
QMessageBox::Ok, ICore::dialogParent());
|
break;
|
||||||
msgbox.exec();
|
overrideCursor.reset();
|
||||||
return nullptr;
|
delete editor;
|
||||||
|
editor = nullptr;
|
||||||
|
if (openResult == IDocument::OpenResult::ReadError) {
|
||||||
|
QMessageBox msgbox(QMessageBox::Critical,
|
||||||
|
EditorManager::tr("File Error"),
|
||||||
|
tr("Could not open \"%1\" for reading. "
|
||||||
|
"Either the file does not exist or you do not have "
|
||||||
|
"the permissions to open it.")
|
||||||
|
.arg(realFp.toUserOutput()),
|
||||||
|
QMessageBox::Ok,
|
||||||
|
ICore::dialogParent());
|
||||||
|
msgbox.exec();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
// can happen e.g. when trying to open an completely empty .qrc file
|
||||||
|
QTC_CHECK(openResult == IDocument::OpenResult::CannotHandle);
|
||||||
|
} else {
|
||||||
|
QTC_ASSERT(factory->asExternalEditor(),
|
||||||
|
factory = factories.isEmpty() ? nullptr : factories.takeFirst();
|
||||||
|
continue);
|
||||||
|
if (factory->asExternalEditor()->startEditor(filePath, &errorString))
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
QTC_CHECK(openResult == IDocument::OpenResult::CannotHandle);
|
|
||||||
|
|
||||||
if (errorString.isEmpty())
|
if (errorString.isEmpty())
|
||||||
errorString = tr("Could not open \"%1\": Unknown error.").arg(realFp.toUserOutput());
|
errorString = tr("Could not open \"%1\": Unknown error.").arg(realFp.toUserOutput());
|
||||||
@@ -881,12 +905,12 @@ IEditor *EditorManagerPrivate::openEditor(EditorView *view, const FilePath &file
|
|||||||
QMessageBox::Open | QMessageBox::Cancel,
|
QMessageBox::Open | QMessageBox::Cancel,
|
||||||
ICore::dialogParent());
|
ICore::dialogParent());
|
||||||
|
|
||||||
IEditorFactory *selectedFactory = nullptr;
|
EditorType *selectedFactory = nullptr;
|
||||||
if (!factories.isEmpty()) {
|
if (!factories.isEmpty()) {
|
||||||
auto button = qobject_cast<QPushButton *>(msgbox.button(QMessageBox::Open));
|
auto button = qobject_cast<QPushButton *>(msgbox.button(QMessageBox::Open));
|
||||||
QTC_ASSERT(button, return nullptr);
|
QTC_ASSERT(button, return nullptr);
|
||||||
auto menu = new QMenu(button);
|
auto menu = new QMenu(button);
|
||||||
foreach (IEditorFactory *factory, factories) {
|
foreach (EditorType *factory, factories) {
|
||||||
QAction *action = menu->addAction(factory->displayName());
|
QAction *action = menu->addAction(factory->displayName());
|
||||||
connect(action, &QAction::triggered, &msgbox, [&selectedFactory, factory, &msgbox]() {
|
connect(action, &QAction::triggered, &msgbox, [&selectedFactory, factory, &msgbox]() {
|
||||||
selectedFactory = factory;
|
selectedFactory = factory;
|
||||||
@@ -3020,8 +3044,11 @@ bool EditorManager::closeEditors(const QList<IEditor*> &editorsToClose, bool ask
|
|||||||
*/
|
*/
|
||||||
void EditorManager::activateEditorForEntry(DocumentModel::Entry *entry, OpenEditorFlags flags)
|
void EditorManager::activateEditorForEntry(DocumentModel::Entry *entry, OpenEditorFlags flags)
|
||||||
{
|
{
|
||||||
|
QTC_CHECK(!(flags & EditorManager::AllowExternalEditor));
|
||||||
|
|
||||||
EditorManagerPrivate::activateEditorForEntry(EditorManagerPrivate::currentEditorView(),
|
EditorManagerPrivate::activateEditorForEntry(EditorManagerPrivate::currentEditorView(),
|
||||||
entry, flags);
|
entry,
|
||||||
|
flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -3031,7 +3058,9 @@ void EditorManager::activateEditorForEntry(DocumentModel::Entry *entry, OpenEdit
|
|||||||
*/
|
*/
|
||||||
void EditorManager::activateEditor(IEditor *editor, OpenEditorFlags flags)
|
void EditorManager::activateEditor(IEditor *editor, OpenEditorFlags flags)
|
||||||
{
|
{
|
||||||
QTC_ASSERT(editor, return);
|
QTC_CHECK(!(flags & EditorManager::AllowExternalEditor));
|
||||||
|
|
||||||
|
QTC_ASSERT(editor, return );
|
||||||
EditorView *view = EditorManagerPrivate::viewForEditor(editor);
|
EditorView *view = EditorManagerPrivate::viewForEditor(editor);
|
||||||
// an IEditor doesn't have to belong to a view, it might be kept in storage by the editor model
|
// an IEditor doesn't have to belong to a view, it might be kept in storage by the editor model
|
||||||
if (!view)
|
if (!view)
|
||||||
@@ -3045,7 +3074,11 @@ void EditorManager::activateEditor(IEditor *editor, OpenEditorFlags flags)
|
|||||||
*/
|
*/
|
||||||
IEditor *EditorManager::activateEditorForDocument(IDocument *document, OpenEditorFlags flags)
|
IEditor *EditorManager::activateEditorForDocument(IDocument *document, OpenEditorFlags flags)
|
||||||
{
|
{
|
||||||
return EditorManagerPrivate::activateEditorForDocument(EditorManagerPrivate::currentEditorView(), document, flags);
|
QTC_CHECK(!(flags & EditorManager::AllowExternalEditor));
|
||||||
|
|
||||||
|
return EditorManagerPrivate::activateEditorForDocument(EditorManagerPrivate::currentEditorView(),
|
||||||
|
document,
|
||||||
|
flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -3066,6 +3099,7 @@ IEditor *EditorManager::activateEditorForDocument(IDocument *document, OpenEdito
|
|||||||
IEditor *EditorManager::openEditor(const FilePath &filePath, Id editorId,
|
IEditor *EditorManager::openEditor(const FilePath &filePath, Id editorId,
|
||||||
OpenEditorFlags flags, bool *newEditor)
|
OpenEditorFlags flags, bool *newEditor)
|
||||||
{
|
{
|
||||||
|
checkEditorFlags(flags);
|
||||||
if (flags & EditorManager::OpenInOtherSplit)
|
if (flags & EditorManager::OpenInOtherSplit)
|
||||||
EditorManager::gotoOtherSplit();
|
EditorManager::gotoOtherSplit();
|
||||||
|
|
||||||
@@ -3097,6 +3131,7 @@ IEditor *EditorManager::openEditorAt(const Link &link,
|
|||||||
OpenEditorFlags flags,
|
OpenEditorFlags flags,
|
||||||
bool *newEditor)
|
bool *newEditor)
|
||||||
{
|
{
|
||||||
|
checkEditorFlags(flags);
|
||||||
if (flags & EditorManager::OpenInOtherSplit)
|
if (flags & EditorManager::OpenInOtherSplit)
|
||||||
EditorManager::gotoOtherSplit();
|
EditorManager::gotoOtherSplit();
|
||||||
|
|
||||||
@@ -3251,6 +3286,9 @@ IEditor *EditorManager::openEditorWithContents(Id editorId,
|
|||||||
const QString &uniqueId,
|
const QString &uniqueId,
|
||||||
OpenEditorFlags flags)
|
OpenEditorFlags flags)
|
||||||
{
|
{
|
||||||
|
QTC_CHECK(!(flags & EditorManager::AllowExternalEditor));
|
||||||
|
checkEditorFlags(flags);
|
||||||
|
|
||||||
if (debugEditorManager)
|
if (debugEditorManager)
|
||||||
qDebug() << Q_FUNC_INFO << editorId.name() << titlePattern << uniqueId << contents;
|
qDebug() << Q_FUNC_INFO << editorId.name() << titlePattern << uniqueId << contents;
|
||||||
|
|
||||||
|
|||||||
@@ -84,7 +84,8 @@ public:
|
|||||||
DoNotSwitchToDesignMode = 16,
|
DoNotSwitchToDesignMode = 16,
|
||||||
DoNotSwitchToEditMode = 32,
|
DoNotSwitchToEditMode = 32,
|
||||||
SwitchSplitIfAlreadyVisible = 64,
|
SwitchSplitIfAlreadyVisible = 64,
|
||||||
DoNotRaise = 128
|
DoNotRaise = 128,
|
||||||
|
AllowExternalEditor = 256
|
||||||
};
|
};
|
||||||
Q_DECLARE_FLAGS(OpenEditorFlags, OpenEditorFlag)
|
Q_DECLARE_FLAGS(OpenEditorFlags, OpenEditorFlag)
|
||||||
|
|
||||||
|
|||||||
@@ -616,7 +616,9 @@ void FolderNavigationWidget::openItem(const QModelIndex &index)
|
|||||||
if (m_fileSystemModel->isDir(index))
|
if (m_fileSystemModel->isDir(index))
|
||||||
return;
|
return;
|
||||||
const QString path = m_fileSystemModel->filePath(index);
|
const QString path = m_fileSystemModel->filePath(index);
|
||||||
Core::EditorManager::openEditor(FilePath::fromString(path));
|
Core::EditorManager::openEditor(FilePath::fromString(path),
|
||||||
|
{},
|
||||||
|
Core::EditorManager::AllowExternalEditor);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FolderNavigationWidget::createNewFolder(const QModelIndex &parent)
|
void FolderNavigationWidget::createNewFolder(const QModelIndex &parent)
|
||||||
|
|||||||
@@ -237,11 +237,11 @@ void BaseFileFilter::openEditorAt(const LocatorFilterEntry& selection)
|
|||||||
const LineColumn lineColumn = LineColumn::extractFromFileName(postfix, postfixPos);
|
const LineColumn lineColumn = LineColumn::extractFromFileName(postfix, postfixPos);
|
||||||
if (postfixPos >= 0) {
|
if (postfixPos >= 0) {
|
||||||
const Link link(selection.filePath, lineColumn.line, lineColumn.column);
|
const Link link(selection.filePath, lineColumn.line, lineColumn.column);
|
||||||
EditorManager::openEditorAt(link);
|
EditorManager::openEditorAt(link, {}, Core::EditorManager::AllowExternalEditor);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EditorManager::openEditor(selection.filePath);
|
EditorManager::openEditor(selection.filePath, {}, Core::EditorManager::AllowExternalEditor);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|||||||
@@ -143,8 +143,11 @@ void CppLocatorFilter::accept(Core::LocatorFilterEntry selection,
|
|||||||
Q_UNUSED(selectionStart)
|
Q_UNUSED(selectionStart)
|
||||||
Q_UNUSED(selectionLength)
|
Q_UNUSED(selectionLength)
|
||||||
IndexItem::Ptr info = qvariant_cast<IndexItem::Ptr>(selection.internalData);
|
IndexItem::Ptr info = qvariant_cast<IndexItem::Ptr>(selection.internalData);
|
||||||
Core::EditorManager::openEditorAt(
|
Core::EditorManager::openEditorAt({Utils::FilePath::fromString(info->fileName()),
|
||||||
{Utils::FilePath::fromString(info->fileName()), info->line(), info->column()});
|
info->line(),
|
||||||
|
info->column()},
|
||||||
|
{},
|
||||||
|
Core::EditorManager::AllowExternalEditor);
|
||||||
}
|
}
|
||||||
|
|
||||||
CppClassesFilter::CppClassesFilter(CppLocatorData *locatorData)
|
CppClassesFilter::CppClassesFilter(CppLocatorData *locatorData)
|
||||||
|
|||||||
@@ -179,8 +179,11 @@ void SymbolsFindFilter::openEditor(const SearchResultItem &item)
|
|||||||
if (!item.userData().canConvert<IndexItem::Ptr>())
|
if (!item.userData().canConvert<IndexItem::Ptr>())
|
||||||
return;
|
return;
|
||||||
IndexItem::Ptr info = item.userData().value<IndexItem::Ptr>();
|
IndexItem::Ptr info = item.userData().value<IndexItem::Ptr>();
|
||||||
EditorManager::openEditorAt(
|
EditorManager::openEditorAt({FilePath::fromString(info->fileName()),
|
||||||
{FilePath::fromString(info->fileName()), info->line(), info->column()});
|
info->line(),
|
||||||
|
info->column()},
|
||||||
|
{},
|
||||||
|
Core::EditorManager::AllowExternalEditor);
|
||||||
}
|
}
|
||||||
|
|
||||||
QWidget *SymbolsFindFilter::createConfigWidget()
|
QWidget *SymbolsFindFilter::createConfigWidget()
|
||||||
|
|||||||
@@ -226,9 +226,11 @@ void DocumentLocatorFilter::accept(Core::LocatorFilterEntry selection,
|
|||||||
if (selection.internalData.canConvert<Utils::LineColumn>()) {
|
if (selection.internalData.canConvert<Utils::LineColumn>()) {
|
||||||
auto lineColumn = qvariant_cast<Utils::LineColumn>(selection.internalData);
|
auto lineColumn = qvariant_cast<Utils::LineColumn>(selection.internalData);
|
||||||
const Utils::Link link(m_currentUri.toFilePath(), lineColumn.line + 1, lineColumn.column);
|
const Utils::Link link(m_currentUri.toFilePath(), lineColumn.line + 1, lineColumn.column);
|
||||||
Core::EditorManager::openEditorAt(link);
|
Core::EditorManager::openEditorAt(link, {}, Core::EditorManager::AllowExternalEditor);
|
||||||
} else if (selection.internalData.canConvert<Utils::Link>()) {
|
} else if (selection.internalData.canConvert<Utils::Link>()) {
|
||||||
Core::EditorManager::openEditorAt(qvariant_cast<Utils::Link>(selection.internalData));
|
Core::EditorManager::openEditorAt(qvariant_cast<Utils::Link>(selection.internalData),
|
||||||
|
{},
|
||||||
|
Core::EditorManager::AllowExternalEditor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -329,7 +331,9 @@ void WorkspaceLocatorFilter::accept(Core::LocatorFilterEntry selection,
|
|||||||
int * /*selectionLength*/) const
|
int * /*selectionLength*/) const
|
||||||
{
|
{
|
||||||
if (selection.internalData.canConvert<Utils::Link>())
|
if (selection.internalData.canConvert<Utils::Link>())
|
||||||
Core::EditorManager::openEditorAt(qvariant_cast<Utils::Link>(selection.internalData));
|
Core::EditorManager::openEditorAt(qvariant_cast<Utils::Link>(selection.internalData),
|
||||||
|
{},
|
||||||
|
Core::EditorManager::AllowExternalEditor);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorkspaceLocatorFilter::handleResponse(Client *client,
|
void WorkspaceLocatorFilter::handleResponse(Client *client,
|
||||||
|
|||||||
@@ -3643,7 +3643,9 @@ void ProjectExplorerPluginPrivate::updateLocationSubMenus()
|
|||||||
: tr("%1 in %2").arg(li.displayName).arg(li.path.toUserOutput());
|
: tr("%1 in %2").arg(li.displayName).arg(li.path.toUserOutput());
|
||||||
auto *action = new QAction(displayName, nullptr);
|
auto *action = new QAction(displayName, nullptr);
|
||||||
connect(action, &QAction::triggered, this, [line, path]() {
|
connect(action, &QAction::triggered, this, [line, path]() {
|
||||||
Core::EditorManager::openEditorAt(Link(path, line));
|
Core::EditorManager::openEditorAt(Link(path, line),
|
||||||
|
{},
|
||||||
|
Core::EditorManager::AllowExternalEditor);
|
||||||
});
|
});
|
||||||
|
|
||||||
projectMenu->addAction(action);
|
projectMenu->addAction(action);
|
||||||
|
|||||||
@@ -563,7 +563,9 @@ void ProjectTreeWidget::openItem(const QModelIndex &mainIndex)
|
|||||||
Node *node = m_model->nodeForIndex(mainIndex);
|
Node *node = m_model->nodeForIndex(mainIndex);
|
||||||
if (!node || !node->asFileNode())
|
if (!node || !node->asFileNode())
|
||||||
return;
|
return;
|
||||||
IEditor *editor = EditorManager::openEditor(node->filePath());
|
IEditor *editor = EditorManager::openEditor(node->filePath(),
|
||||||
|
{},
|
||||||
|
Core::EditorManager::AllowExternalEditor);
|
||||||
if (editor && node->line() >= 0)
|
if (editor && node->line() >= 0)
|
||||||
editor->gotoLine(node->line());
|
editor->gotoLine(node->line());
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user