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:
Eike Ziller
2021-11-11 11:51:11 +01:00
parent 0bbc465f61
commit 2fab827782
10 changed files with 107 additions and 50 deletions

View File

@@ -185,7 +185,9 @@ void OpenCMakeTargetLocatorFilter::accept(Core::LocatorFilterEntry selection,
const auto file = FilePath::fromVariant(extraData.value("file"));
if (line >= 0)
Core::EditorManager::openEditorAt({file, line});
Core::EditorManager::openEditorAt({file, line},
{},
Core::EditorManager::AllowExternalEditor);
else
Core::EditorManager::openEditor(file);
Core::EditorManager::openEditor(file, {}, Core::EditorManager::AllowExternalEditor);
}

View File

@@ -135,6 +135,14 @@ using namespace Core;
using namespace Core::Internal;
using namespace Utils;
static void checkEditorFlags(EditorManager::OpenEditorFlags flags)
{
if (flags & EditorManager::OpenInOtherSplit) {
QTC_CHECK(!(flags & EditorManager::SwitchSplitIfAlreadyVisible));
QTC_CHECK(!(flags & EditorManager::AllowExternalEditor));
}
}
//===================EditorManager=====================
/*!
@@ -812,13 +820,21 @@ IEditor *EditorManagerPrivate::openEditor(EditorView *view, const FilePath &file
return activateEditor(view, editor, flags);
}
if (skipOpeningBigTextFile(filePath))
return nullptr;
FilePath realFp = autoSaveName(filePath);
if (!filePath.exists() || !realFp.exists() || filePath.lastModified() >= realFp.lastModified()) {
realFp.removeFile();
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()) {
Utils::MimeType mimeType = Utils::mimeTypeForFile(filePath);
QMessageBox msgbox(QMessageBox::Critical, EditorManager::tr("File Error"),
@@ -829,48 +845,56 @@ IEditor *EditorManagerPrivate::openEditor(EditorView *view, const FilePath &file
return nullptr;
}
if (editorId.isValid()) {
IEditorFactory *factory = Utils::findOrDefault(IEditorFactory::allEditorFactories(),
Utils::equal(&IEditorFactory::id, editorId));
EditorType *factory = EditorType::editorTypeForId(editorId);
if (factory) {
QTC_CHECK(factory->asEditorFactory() || (flags & EditorManager::AllowExternalEditor));
factories.removeOne(factory);
factories.push_front(factory);
}
}
if (skipOpeningBigTextFile(filePath))
return nullptr;
IEditor *editor = nullptr;
auto overrideCursor = Utils::OverrideCursor(QCursor(Qt::WaitCursor));
IEditorFactory *factory = factories.takeFirst();
EditorType *factory = factories.takeFirst();
while (factory) {
editor = createEditor(factory, filePath);
if (!editor) {
factory = factories.takeFirst();
continue;
}
QString errorString;
IDocument::OpenResult openResult = editor->document()->open(&errorString, filePath, realFp);
if (openResult == IDocument::OpenResult::Success)
break;
overrideCursor.reset();
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;
if (factory->asEditorFactory()) {
editor = createEditor(factory->asEditorFactory(), filePath);
if (!editor) {
factory = factories.isEmpty() ? nullptr : factories.takeFirst();
continue;
}
IDocument::OpenResult openResult = editor->document()->open(&errorString,
filePath,
realFp);
if (openResult == IDocument::OpenResult::Success)
break;
overrideCursor.reset();
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())
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,
ICore::dialogParent());
IEditorFactory *selectedFactory = nullptr;
EditorType *selectedFactory = nullptr;
if (!factories.isEmpty()) {
auto button = qobject_cast<QPushButton *>(msgbox.button(QMessageBox::Open));
QTC_ASSERT(button, return nullptr);
auto menu = new QMenu(button);
foreach (IEditorFactory *factory, factories) {
foreach (EditorType *factory, factories) {
QAction *action = menu->addAction(factory->displayName());
connect(action, &QAction::triggered, &msgbox, [&selectedFactory, factory, &msgbox]() {
selectedFactory = factory;
@@ -3020,8 +3044,11 @@ bool EditorManager::closeEditors(const QList<IEditor*> &editorsToClose, bool ask
*/
void EditorManager::activateEditorForEntry(DocumentModel::Entry *entry, OpenEditorFlags flags)
{
QTC_CHECK(!(flags & EditorManager::AllowExternalEditor));
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)
{
QTC_ASSERT(editor, return);
QTC_CHECK(!(flags & EditorManager::AllowExternalEditor));
QTC_ASSERT(editor, return );
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
if (!view)
@@ -3045,7 +3074,11 @@ void EditorManager::activateEditor(IEditor *editor, 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,
OpenEditorFlags flags, bool *newEditor)
{
checkEditorFlags(flags);
if (flags & EditorManager::OpenInOtherSplit)
EditorManager::gotoOtherSplit();
@@ -3097,6 +3131,7 @@ IEditor *EditorManager::openEditorAt(const Link &link,
OpenEditorFlags flags,
bool *newEditor)
{
checkEditorFlags(flags);
if (flags & EditorManager::OpenInOtherSplit)
EditorManager::gotoOtherSplit();
@@ -3251,6 +3286,9 @@ IEditor *EditorManager::openEditorWithContents(Id editorId,
const QString &uniqueId,
OpenEditorFlags flags)
{
QTC_CHECK(!(flags & EditorManager::AllowExternalEditor));
checkEditorFlags(flags);
if (debugEditorManager)
qDebug() << Q_FUNC_INFO << editorId.name() << titlePattern << uniqueId << contents;

View File

@@ -84,7 +84,8 @@ public:
DoNotSwitchToDesignMode = 16,
DoNotSwitchToEditMode = 32,
SwitchSplitIfAlreadyVisible = 64,
DoNotRaise = 128
DoNotRaise = 128,
AllowExternalEditor = 256
};
Q_DECLARE_FLAGS(OpenEditorFlags, OpenEditorFlag)

View File

@@ -616,7 +616,9 @@ void FolderNavigationWidget::openItem(const QModelIndex &index)
if (m_fileSystemModel->isDir(index))
return;
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)

View File

@@ -237,11 +237,11 @@ void BaseFileFilter::openEditorAt(const LocatorFilterEntry& selection)
const LineColumn lineColumn = LineColumn::extractFromFileName(postfix, postfixPos);
if (postfixPos >= 0) {
const Link link(selection.filePath, lineColumn.line, lineColumn.column);
EditorManager::openEditorAt(link);
EditorManager::openEditorAt(link, {}, Core::EditorManager::AllowExternalEditor);
return;
}
}
EditorManager::openEditor(selection.filePath);
EditorManager::openEditor(selection.filePath, {}, Core::EditorManager::AllowExternalEditor);
}
/*!

View File

@@ -143,8 +143,11 @@ void CppLocatorFilter::accept(Core::LocatorFilterEntry selection,
Q_UNUSED(selectionStart)
Q_UNUSED(selectionLength)
IndexItem::Ptr info = qvariant_cast<IndexItem::Ptr>(selection.internalData);
Core::EditorManager::openEditorAt(
{Utils::FilePath::fromString(info->fileName()), info->line(), info->column()});
Core::EditorManager::openEditorAt({Utils::FilePath::fromString(info->fileName()),
info->line(),
info->column()},
{},
Core::EditorManager::AllowExternalEditor);
}
CppClassesFilter::CppClassesFilter(CppLocatorData *locatorData)

View File

@@ -179,8 +179,11 @@ void SymbolsFindFilter::openEditor(const SearchResultItem &item)
if (!item.userData().canConvert<IndexItem::Ptr>())
return;
IndexItem::Ptr info = item.userData().value<IndexItem::Ptr>();
EditorManager::openEditorAt(
{FilePath::fromString(info->fileName()), info->line(), info->column()});
EditorManager::openEditorAt({FilePath::fromString(info->fileName()),
info->line(),
info->column()},
{},
Core::EditorManager::AllowExternalEditor);
}
QWidget *SymbolsFindFilter::createConfigWidget()

View File

@@ -226,9 +226,11 @@ void DocumentLocatorFilter::accept(Core::LocatorFilterEntry selection,
if (selection.internalData.canConvert<Utils::LineColumn>()) {
auto lineColumn = qvariant_cast<Utils::LineColumn>(selection.internalData);
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>()) {
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
{
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,

View File

@@ -3643,7 +3643,9 @@ void ProjectExplorerPluginPrivate::updateLocationSubMenus()
: tr("%1 in %2").arg(li.displayName).arg(li.path.toUserOutput());
auto *action = new QAction(displayName, nullptr);
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);

View File

@@ -563,7 +563,9 @@ void ProjectTreeWidget::openItem(const QModelIndex &mainIndex)
Node *node = m_model->nodeForIndex(mainIndex);
if (!node || !node->asFileNode())
return;
IEditor *editor = EditorManager::openEditor(node->filePath());
IEditor *editor = EditorManager::openEditor(node->filePath(),
{},
Core::EditorManager::AllowExternalEditor);
if (editor && node->line() >= 0)
editor->gotoLine(node->line());
}