From 4943f387c728e40c050eb67b8604858dc89283fa Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 21 Aug 2023 11:42:56 +0200 Subject: [PATCH] Core: Merge editor factory classes Mainly to simplify the implementation and naming. Kind of follow-up to 862c9694. There is some consolidation needed as followup as well as some potential renamings. I'd leave that for separate patches to keep this here somewhat self-contained. Change-Id: I152e138a1d5baadec3f7542fed0894b8d4ffc8a3 Reviewed-by: David Schulz --- .../dialogs/filepropertiesdialog.cpp | 2 +- .../editormanager/editormanager.cpp | 76 ++--- .../editormanager/editormanager_p.h | 2 +- .../editormanager/ieditorfactory.cpp | 302 ++++++++---------- .../coreplugin/editormanager/ieditorfactory.h | 65 ++-- .../editormanager/ieditorfactory_p.h | 6 +- .../coreplugin/editormanager/systemeditor.cpp | 26 +- .../coreplugin/editormanager/systemeditor.h | 6 +- src/plugins/coreplugin/mimetypesettings.cpp | 28 +- src/plugins/qtsupport/externaleditors.cpp | 109 +++---- src/plugins/qtsupport/externaleditors.h | 8 +- 11 files changed, 278 insertions(+), 352 deletions(-) diff --git a/src/plugins/coreplugin/dialogs/filepropertiesdialog.cpp b/src/plugins/coreplugin/dialogs/filepropertiesdialog.cpp index c37125d447a..de3362a408f 100644 --- a/src/plugins/coreplugin/dialogs/filepropertiesdialog.cpp +++ b/src/plugins/coreplugin/dialogs/filepropertiesdialog.cpp @@ -192,7 +192,7 @@ void FilePropertiesDialog::refresh() const Utils::MimeType mimeType = Utils::mimeTypeForFile(m_filePath); m_mimeType->setText(mimeType.name()); - const EditorTypeList factories = IEditorFactory::preferredEditorTypes(m_filePath); + const EditorFactories factories = IEditorFactory::preferredEditorTypes(m_filePath); m_defaultEditor->setText(!factories.isEmpty() ? factories.at(0)->displayName() : Tr::tr("Undefined")); diff --git a/src/plugins/coreplugin/editormanager/editormanager.cpp b/src/plugins/coreplugin/editormanager/editormanager.cpp index 44e5f18ef35..245fc89ff6f 100644 --- a/src/plugins/coreplugin/editormanager/editormanager.cpp +++ b/src/plugins/coreplugin/editormanager/editormanager.cpp @@ -797,12 +797,10 @@ IEditor *EditorManagerPrivate::openEditor(EditorView *view, const FilePath &file realFp = filePath; } - EditorTypeList factories = EditorType::preferredEditorTypes(filePath); - if (!(flags & EditorManager::AllowExternalEditor)) { - factories = Utils::filtered(factories, [](EditorType *type) { - return type->asEditorFactory() != nullptr; - }); - } + EditorFactories factories = IEditorFactory::preferredEditorTypes(filePath); + if (!(flags & EditorManager::AllowExternalEditor)) + factories = Utils::filtered(factories, &IEditorFactory::isInternalEditor); + if (factories.isEmpty()) { Utils::MimeType mimeType = Utils::mimeTypeForFile(filePath); QMessageBox msgbox(QMessageBox::Critical, ::Core::Tr::tr("File Error"), @@ -813,9 +811,9 @@ IEditor *EditorManagerPrivate::openEditor(EditorView *view, const FilePath &file return nullptr; } if (editorId.isValid()) { - EditorType *factory = EditorType::editorTypeForId(editorId); + IEditorFactory *factory = IEditorFactory::editorFactoryForId(editorId); if (factory) { - QTC_CHECK(factory->asEditorFactory() || (flags & EditorManager::AllowExternalEditor)); + QTC_CHECK(factory->isInternalEditor() || (flags & EditorManager::AllowExternalEditor)); factories.removeOne(factory); factories.push_front(factory); } @@ -824,12 +822,12 @@ IEditor *EditorManagerPrivate::openEditor(EditorView *view, const FilePath &file IEditor *editor = nullptr; auto overrideCursor = Utils::OverrideCursor(QCursor(Qt::WaitCursor)); - EditorType *factory = factories.takeFirst(); + IEditorFactory *factory = factories.takeFirst(); while (factory) { QString errorString; - if (factory->asEditorFactory()) { - editor = createEditor(factory->asEditorFactory(), filePath); + if (factory->isInternalEditor()) { + editor = createEditor(factory, filePath); if (!editor) { factory = factories.isEmpty() ? nullptr : factories.takeFirst(); continue; @@ -857,10 +855,10 @@ IEditor *EditorManagerPrivate::openEditor(EditorView *view, const FilePath &file // can happen e.g. when trying to open an completely empty .qrc file QTC_CHECK(openResult == IDocument::OpenResult::CannotHandle); } else { - QTC_ASSERT(factory->asExternalEditor(), + QTC_ASSERT(factory->isExternalEditor(), factory = factories.isEmpty() ? nullptr : factories.takeFirst(); continue); - if (factory->asExternalEditor()->startEditor(filePath, &errorString)) + if (factory->startEditor(filePath, &errorString)) break; } @@ -873,12 +871,12 @@ IEditor *EditorManagerPrivate::openEditor(EditorView *view, const FilePath &file QMessageBox::Open | QMessageBox::Cancel, ICore::dialogParent()); - EditorType *selectedFactory = nullptr; + IEditorFactory *selectedFactory = nullptr; if (!factories.isEmpty()) { auto button = qobject_cast(msgbox.button(QMessageBox::Open)); QTC_ASSERT(button, return nullptr); auto menu = new QMenu(button); - for (EditorType *factory : std::as_const(factories)) { + for (IEditorFactory *factory : std::as_const(factories)) { QAction *action = menu->addAction(factory->displayName()); connect(action, &QAction::triggered, &msgbox, [&selectedFactory, factory, &msgbox] { selectedFactory = factory; @@ -1148,7 +1146,7 @@ Id EditorManagerPrivate::getOpenWithEditorId(const Utils::FilePath &fileName, bo QList allEditorIds; QStringList allEditorDisplayNames; // Built-in - const EditorTypeList editors = EditorType::preferredEditorTypes(fileName); + const EditorFactories editors = IEditorFactory::preferredEditorTypes(fileName); const int size = editors.size(); allEditorDisplayNames.reserve(size); for (int i = 0; i < size; i++) { @@ -1166,13 +1164,13 @@ Id EditorManagerPrivate::getOpenWithEditorId(const Utils::FilePath &fileName, bo return Id(); const Id selectedId = allEditorIds.at(dialog.editor()); if (isExternalEditor) { - EditorType *type = EditorType::editorTypeForId(selectedId); - *isExternalEditor = type && type->asExternalEditor() != nullptr; + IEditorFactory *type = IEditorFactory::editorFactoryForId(selectedId); + *isExternalEditor = type && type->isExternalEditor(); } return selectedId; } -static QMap toMap(const QHash &hash) +static QMap toMap(const QHash &hash) { QMap map; auto it = hash.begin(); @@ -1184,18 +1182,18 @@ static QMap toMap(const QHash return map; } -static QHash fromMap(const QMap &map) +static QHash fromMap(const QMap &map) { - const EditorTypeList factories = EditorType::allEditorTypes(); - QHash hash; + const EditorFactories factories = IEditorFactory::allEditorFactories(); + QHash hash; auto it = map.begin(); const auto end = map.end(); while (it != end) { const Utils::MimeType mimeType = Utils::mimeTypeForName(it.key()); if (mimeType.isValid()) { const Id factoryId = Id::fromSetting(it.value()); - EditorType *factory = Utils::findOrDefault(factories, - Utils::equal(&EditorType::id, factoryId)); + IEditorFactory *factory = Utils::findOrDefault(factories, + Utils::equal(&IEditorFactory::id, factoryId)); if (factory) hash.insert(mimeType, factory); } @@ -1225,7 +1223,7 @@ void EditorManagerPrivate::readSettings() else HostOsInfo::setOverrideFileNameCaseSensitivity(sensitivity); - const QHash preferredEditorFactories = fromMap( + const QHash preferredEditorFactories = fromMap( qs->value(preferredEditorFactoriesKey).toMap()); setUserPreferredEditorTypes(preferredEditorFactories); @@ -1266,12 +1264,12 @@ void EditorManagerPrivate::writeFileSystemSensitivity(Utils::QtcSettings *settin HostOsInfo::hostOs()))); } -EditorFactoryList EditorManagerPrivate::findFactories(Id editorId, const FilePath &filePath) +EditorFactories EditorManagerPrivate::findFactories(Id editorId, const FilePath &filePath) { if (debugEditorManager) qDebug() << Q_FUNC_INFO << editorId.name() << filePath; - EditorFactoryList factories; + EditorFactories factories; if (!editorId.isValid()) { factories = IEditorFactory::preferredEditorFactories(filePath); } else { @@ -2810,11 +2808,11 @@ void EditorManager::populateOpenWithMenu(QMenu *menu, const FilePath &filePath) { menu->clear(); - const EditorTypeList factories = IEditorFactory::preferredEditorTypes(filePath); + const EditorFactories factories = IEditorFactory::preferredEditorTypes(filePath); const bool anyMatches = !factories.empty(); if (anyMatches) { // Add all suitable editors - for (EditorType *editorType : factories) { + for (IEditorFactory *editorType : factories) { const Id editorId = editorType->id(); // Add action to open with this very editor factory QString const actionTitle = editorType->displayName(); @@ -2824,8 +2822,8 @@ void EditorManager::populateOpenWithMenu(QMenu *menu, const FilePath &filePath) // crashes happen, because the editor instance is deleted by openEditorWith // while the menu is still being processed. connect(action, &QAction::triggered, d, [filePath, editorId] { - EditorType *type = EditorType::editorTypeForId(editorId); - if (type && type->asExternalEditor()) + IEditorFactory *type = IEditorFactory::editorFactoryForId(editorId); + if (type && type->isExternalEditor()) EditorManager::openExternalEditor(filePath, editorId); else EditorManagerPrivate::openEditorWith(filePath, editorId); @@ -2839,11 +2837,10 @@ void EditorManager::runWithTemporaryEditor(const Utils::FilePath &filePath, const std::function &callback) { const MimeType mt = mimeTypeForFile(filePath, MimeMatchMode::MatchDefaultAndRemote); - const QList factories = Utils::transform( - EditorType::defaultEditorTypes(mt), [](EditorType *t) { - return t->asEditorFactory(); }); + const QList factories = IEditorFactory::defaultEditorFactories(mt); for (IEditorFactory * const factory : factories) { - if (!factory) + QTC_ASSERT(factory, continue); + if (!factory->isInternalEditor()) continue; std::unique_ptr editor(factory->createEditor()); if (!editor) @@ -3103,8 +3100,11 @@ bool EditorManager::autoSaveAfterRefactoring() */ bool EditorManager::openExternalEditor(const FilePath &filePath, Id editorId) { - IExternalEditor *ee = Utils::findOrDefault(IExternalEditor::allExternalEditors(), - Utils::equal(&IExternalEditor::id, editorId)); + IEditorFactory *ee = Utils::findOrDefault(IEditorFactory::allEditorFactories(), + [editorId](IEditorFactory *factory) { + return factory->isExternalEditor() && factory->id() == editorId; + }); + if (!ee) return false; QString errorMessage; @@ -3228,7 +3228,7 @@ IEditor *EditorManager::openEditorWithContents(Id editorId, } const FilePath filePath = FilePath::fromString(title); - EditorFactoryList factories = EditorManagerPrivate::findFactories(editorId, filePath); + EditorFactories factories = EditorManagerPrivate::findFactories(editorId, filePath); if (factories.isEmpty()) return nullptr; diff --git a/src/plugins/coreplugin/editormanager/editormanager_p.h b/src/plugins/coreplugin/editormanager/editormanager_p.h index 3cae95ba96e..1d8aba0b92e 100644 --- a/src/plugins/coreplugin/editormanager/editormanager_p.h +++ b/src/plugins/coreplugin/editormanager/editormanager_p.h @@ -167,7 +167,7 @@ private: static OpenEditorsWindow *windowPopup(); static void showPopupOrSelectDocument(); - static EditorFactoryList findFactories(Utils::Id editorId, const Utils::FilePath &filePath); + static EditorFactories findFactories(Utils::Id editorId, const Utils::FilePath &filePath); static IEditor *createEditor(IEditorFactory *factory, const Utils::FilePath &filePath); static void addEditor(IEditor *editor); static void removeEditor(IEditor *editor, bool removeSusependedEntry); diff --git a/src/plugins/coreplugin/editormanager/ieditorfactory.cpp b/src/plugins/coreplugin/editormanager/ieditorfactory.cpp index 1b467837632..a87b427e62d 100644 --- a/src/plugins/coreplugin/editormanager/ieditorfactory.cpp +++ b/src/plugins/coreplugin/editormanager/ieditorfactory.cpp @@ -51,29 +51,26 @@ static void mimeTypeFactoryLookup(const Utils::MimeType &mimeType, IEditorFactory is then asked to create an editor. Implementations should set the properties of the IEditorFactory subclass in - their constructor with EditorType::setId(), EditorType::setDisplayName(), - EditorType::setMimeTypes(), and setEditorCreator() + their constructor with IEditorFactory::setId(), IEditorFactory::setDisplayName(), + IEditorFactory::setMimeTypes(), and setEditorCreator() IEditorFactory instances automatically register themselves in \QC in their constructor. - \sa Core::EditorType + There are two varieties of editors: Internal and external. Internal editors + open within the main editing area of Qt Creator. An IEditorFactory defines + an internal editor by using the \c setEditorCreator function. External + editors are external applications and are defined by using the + \c setEditorStarter function. They are accessible by the user using + the \uicontrol{Open With} dialog + \sa Core::IEditor \sa Core::IDocument \sa Core::EditorManager */ /*! - \class Core::EditorType - \inheaderfile coreplugin/editormanager/ieditorfactory.h - \inmodule QtCreator - - \brief The EditorType class is the base class for Core::IEditorFactory and - Core::IExternalEditor. -*/ - -/*! - \fn void Core::EditorType::addMimeType(const QString &mimeType) + \fn void Core::IEditorFactory::addMimeType(const QString &mimeType) Adds \a mimeType to the list of MIME types supported by this editor type. @@ -82,7 +79,7 @@ static void mimeTypeFactoryLookup(const Utils::MimeType &mimeType, */ /*! - \fn QString Core::EditorType::displayName() const + \fn QString Core::IEditorFactory::displayName() const Returns a user-visible description of the editor type. @@ -90,7 +87,7 @@ static void mimeTypeFactoryLookup(const Utils::MimeType &mimeType, */ /*! - \fn Utils::Id Core::EditorType::id() const + \fn Utils::Id Core::IEditorFactory::id() const Returns the ID of the editors' document type. @@ -98,7 +95,7 @@ static void mimeTypeFactoryLookup(const Utils::MimeType &mimeType, */ /*! - \fn QString Core::EditorType::mimeTypes() const + \fn QString Core::IEditorFactory::mimeTypes() const Returns the list of supported MIME types of this editor type. @@ -107,7 +104,7 @@ static void mimeTypeFactoryLookup(const Utils::MimeType &mimeType, */ /*! - \fn void Core::EditorType::setDisplayName(const QString &displayName) + \fn void Core::IEditorFactory::setDisplayName(const QString &displayName) Sets the \a displayName of the editor type. This is for example shown in the \uicontrol {Open With} menu and the MIME type preferences. @@ -116,7 +113,7 @@ static void mimeTypeFactoryLookup(const Utils::MimeType &mimeType, */ /*! - \fn void Core::EditorType::setId(Utils::Id id) + \fn void Core::IEditorFactory::setId(Utils::Id id) Sets the \a id of the editors' document type. This must be the same as the IDocument::id() of the documents returned by created editors. @@ -125,7 +122,7 @@ static void mimeTypeFactoryLookup(const Utils::MimeType &mimeType, */ /*! - \fn void Core::EditorType::setMimeTypes(const QStringList &mimeTypes) + \fn void Core::IEditorFactory::setMimeTypes(const QStringList &mimeTypes) Sets the MIME types supported by the editor type to \a mimeTypes. @@ -133,88 +130,8 @@ static void mimeTypeFactoryLookup(const Utils::MimeType &mimeType, \sa mimeTypes() */ -static QList g_editorTypes; -static QHash g_userPreferredEditorTypes; static QList g_editorFactories; - -/*! - \internal -*/ -EditorType::EditorType() -{ - g_editorTypes.append(this); -} - -/*! - \internal -*/ -EditorType::~EditorType() -{ - g_editorTypes.removeOne(this); -} - -/*! - Returns all registered internal and external editors. -*/ -const EditorTypeList EditorType::allEditorTypes() -{ - return g_editorTypes; -} - -EditorType *EditorType::editorTypeForId(const Utils::Id &id) -{ - return Utils::findOrDefault(allEditorTypes(), Utils::equal(&EditorType::id, id)); -} - -/*! - Returns all available internal and external editors for the \a mimeType in the - default order: Editor types ordered by MIME type hierarchy, internal editors - first. -*/ -const EditorTypeList EditorType::defaultEditorTypes(const MimeType &mimeType) -{ - EditorTypeList result; - const EditorTypeList allTypes = EditorType::allEditorTypes(); - const EditorTypeList allEditorFactories = Utils::filtered(allTypes, [](EditorType *e) { - return e->asEditorFactory() != nullptr; - }); - const EditorTypeList allExternalEditors = Utils::filtered(allTypes, [](EditorType *e) { - return e->asExternalEditor() != nullptr; - }); - mimeTypeFactoryLookup(mimeType, allEditorFactories, &result); - mimeTypeFactoryLookup(mimeType, allExternalEditors, &result); - return result; -} - -const EditorTypeList EditorType::preferredEditorTypes(const FilePath &filePath) -{ - // default factories by mime type - const Utils::MimeType mimeType = Utils::mimeTypeForFile(filePath, - MimeMatchMode::MatchDefaultAndRemote); - EditorTypeList factories = defaultEditorTypes(mimeType); - // user preferred factory to front - EditorType *userPreferred = Internal::userPreferredEditorTypes().value(mimeType); - if (userPreferred) { - factories.removeAll(userPreferred); - factories.prepend(userPreferred); - } - // make binary editor first internal editor for text files > 48 MB - if (filePath.fileSize() > EditorManager::maxTextFileSize() && mimeType.inherits("text/plain")) { - const Utils::MimeType binary = Utils::mimeTypeForName("application/octet-stream"); - const EditorTypeList binaryEditors = defaultEditorTypes(binary); - if (!binaryEditors.isEmpty()) { - EditorType *binaryEditor = binaryEditors.first(); - factories.removeAll(binaryEditor); - int insertionIndex = 0; - while (factories.size() > insertionIndex - && factories.at(insertionIndex)->asExternalEditor() != nullptr) { - ++insertionIndex; - } - factories.insert(insertionIndex, binaryEditor); - } - } - return factories; -} +static QHash g_userPreferredEditorTypes; /*! Creates an IEditorFactory. @@ -235,54 +152,124 @@ IEditorFactory::~IEditorFactory() } /*! - \internal + Returns all registered internal and external editors. */ -const EditorFactoryList IEditorFactory::allEditorFactories() +const EditorFactories IEditorFactory::allEditorFactories() { return g_editorFactories; } +IEditorFactory *IEditorFactory::editorFactoryForId(const Utils::Id &id) +{ + return Utils::findOrDefault(allEditorFactories(), Utils::equal(&IEditorFactory::id, id)); +} + +/*! + Returns all available internal and external editors for the \a mimeType in the + default order: Editor types ordered by MIME type hierarchy, internal editors + first. +*/ +const EditorFactories IEditorFactory::defaultEditorFactories(const MimeType &mimeType) +{ + EditorFactories result; + const EditorFactories allTypes = IEditorFactory::allEditorFactories(); + const EditorFactories allEditorFactories + = Utils::filtered(allTypes, &IEditorFactory::isInternalEditor); + const EditorFactories allExternalEditors + = Utils::filtered(allTypes, &IEditorFactory::isExternalEditor); + mimeTypeFactoryLookup(mimeType, allEditorFactories, &result); + mimeTypeFactoryLookup(mimeType, allExternalEditors, &result); + return result; +} + +// FIXME: Consolidate with preferredEditorFactories() +const EditorFactories IEditorFactory::preferredEditorTypes(const FilePath &filePath) +{ + // default factories by mime type + const Utils::MimeType mimeType = Utils::mimeTypeForFile(filePath, + MimeMatchMode::MatchDefaultAndRemote); + EditorFactories factories = defaultEditorFactories(mimeType); + // user preferred factory to front + IEditorFactory *userPreferred = Internal::userPreferredEditorTypes().value(mimeType); + if (userPreferred) { + factories.removeAll(userPreferred); + factories.prepend(userPreferred); + } + // make binary editor first internal editor for text files > 48 MB + if (filePath.fileSize() > EditorManager::maxTextFileSize() && mimeType.inherits("text/plain")) { + const Utils::MimeType binary = Utils::mimeTypeForName("application/octet-stream"); + const EditorFactories binaryEditors = defaultEditorFactories(binary); + if (!binaryEditors.isEmpty()) { + IEditorFactory *binaryEditor = binaryEditors.first(); + factories.removeAll(binaryEditor); + int insertionIndex = 0; + while (factories.size() > insertionIndex + && !factories.at(insertionIndex)->isInternalEditor()) { + ++insertionIndex; + } + factories.insert(insertionIndex, binaryEditor); + } + } + return factories; +} + /*! Returns the available editor factories for \a filePath in order of preference. That is the default order for the document's MIME type but with a user overridden default editor first, and the binary editor as the very first item if a text document is too large to be opened as a text file. */ -const EditorFactoryList IEditorFactory::preferredEditorFactories(const FilePath &filePath) +const EditorFactories IEditorFactory::preferredEditorFactories(const FilePath &filePath) { const auto defaultEditorFactories = [](const MimeType &mimeType) { QList editorFactories; - for (EditorType *type : defaultEditorTypes(mimeType)) { - if (IEditorFactory *editorFactory = type->asEditorFactory()) - editorFactories.append(editorFactory); + for (IEditorFactory *type : IEditorFactory::defaultEditorFactories(mimeType)) { + if (type->isInternalEditor()) + editorFactories.append(type); } return editorFactories; }; // default factories by mime type const Utils::MimeType mimeType = Utils::mimeTypeForFile(filePath); - EditorFactoryList factories = defaultEditorFactories(mimeType); + EditorFactories factories = defaultEditorFactories(mimeType); const auto factories_moveToFront = [&factories](IEditorFactory *f) { factories.removeAll(f); factories.prepend(f); }; // user preferred factory to front - EditorType *userPreferred = Internal::userPreferredEditorTypes().value(mimeType); - if (userPreferred && userPreferred->asEditorFactory()) - factories_moveToFront(userPreferred->asEditorFactory()); + IEditorFactory *userPreferred = Internal::userPreferredEditorTypes().value(mimeType); + if (userPreferred && userPreferred->isInternalEditor()) + factories_moveToFront(userPreferred); // open text files > 48 MB in binary editor if (filePath.fileSize() > EditorManager::maxTextFileSize() && mimeType.inherits("text/plain")) { const Utils::MimeType binary = Utils::mimeTypeForName("application/octet-stream"); - const EditorFactoryList binaryEditors = defaultEditorFactories(binary); + const EditorFactories binaryEditors = defaultEditorFactories(binary); if (!binaryEditors.isEmpty()) factories_moveToFront(binaryEditors.first()); } return factories; } +/** + Returns true if this factory creates internal editors. +*/ +bool IEditorFactory::isInternalEditor() const +{ + return bool(m_creator); +} + +/** + Returns true if this factory creates external editors. +*/ +bool IEditorFactory::isExternalEditor() const +{ + return bool(m_starter); +} + /*! - Creates an editor. + Creates an internal editor. Uses the function set with setEditorCreator() to create the editor. @@ -294,21 +281,54 @@ IEditor *IEditorFactory::createEditor() const return m_creator(); } +/*! + Starts an external editor. + + Uses the function set with setEditorStarter() to start the editor. + + \sa setEditorStarter() +*/ +bool IEditorFactory::startEditor(const FilePath &filePath, QString *errorMessage) +{ + QTC_ASSERT(m_starter, return false); + return m_starter(filePath, errorMessage); +} + /*! Sets the function that is used to create an editor instance in createEditor() to \a creator. + This is mutually exclusive with the use of setEditorStarter. + \sa createEditor() */ void IEditorFactory::setEditorCreator(const std::function &creator) { + QTC_CHECK(!m_starter); + // The check below triggers within the TextEditorFactory sub-hierarchy + // as the base TextEditorFactory already sets as simple creator. + //QTC_CHECK(!m_creator); m_creator = creator; } +/*! + Opens the editor with \a fileName. Returns \c true on success or \c false + on failure along with the error in \a errorMessage. + + This is mutually exclusive with the use of setEditorCreator. +*/ + +void IEditorFactory::setEditorStarter(const std::function &starter) +{ + QTC_CHECK(!m_starter); + QTC_CHECK(!m_creator); + m_starter = starter; +} + /*! \internal */ -QHash Core::Internal::userPreferredEditorTypes() +QHash Internal::userPreferredEditorTypes() { return g_userPreferredEditorTypes; } @@ -316,64 +336,10 @@ QHash Core::Internal::userPreferredEditorTy /*! \internal */ -void Internal::setUserPreferredEditorTypes(const QHash &factories) +void Internal::setUserPreferredEditorTypes(const QHash &factories) { g_userPreferredEditorTypes = factories; } -/*! - \class Core::IExternalEditor - \inheaderfile coreplugin/editormanager/ieditorfactory.h - \inmodule QtCreator - \ingroup mainclasses - - \brief The IExternalEditor class enables registering an external - editor in the \uicontrol{Open With} dialog. -*/ - -/*! - \fn bool Core::IExternalEditor::startEditor(const Utils::FilePath &fileName, QString *errorMessage) - - Opens the editor with \a fileName. Returns \c true on success or \c false - on failure along with the error in \a errorMessage. -*/ - -static QList g_externalEditors; - -/*! - \internal -*/ -IExternalEditor::IExternalEditor() -{ - g_externalEditors.append(this); -} - -/*! - \internal -*/ -IExternalEditor::~IExternalEditor() -{ - g_externalEditors.removeOne(this); -} - -/*! - Returns all available external editors. -*/ -const ExternalEditorList IExternalEditor::allExternalEditors() -{ - return g_externalEditors; -} - -/*! - Returns all external editors available for this \a mimeType in the default - order (editors ordered by MIME type hierarchy). -*/ -const ExternalEditorList IExternalEditor::externalEditors(const Utils::MimeType &mimeType) -{ - ExternalEditorList rc; - const ExternalEditorList allEditors = IExternalEditor::allExternalEditors(); - mimeTypeFactoryLookup(mimeType, allEditors, &rc); - return rc; -} } // Core diff --git a/src/plugins/coreplugin/editormanager/ieditorfactory.h b/src/plugins/coreplugin/editormanager/ieditorfactory.h index e28694ffa0d..29b07f384ff 100644 --- a/src/plugins/coreplugin/editormanager/ieditorfactory.h +++ b/src/plugins/coreplugin/editormanager/ieditorfactory.h @@ -18,77 +18,48 @@ class MimeType; namespace Core { -class IExternalEditor; class IEditor; class IEditorFactory; -class EditorType; -using EditorFactoryList = QList; -using EditorTypeList = QList; -using ExternalEditorList = QList; +using EditorFactories = QList; -class CORE_EXPORT EditorType +class CORE_EXPORT IEditorFactory { public: - virtual ~EditorType(); + virtual ~IEditorFactory(); - static const EditorTypeList allEditorTypes(); - static EditorType *editorTypeForId(const Utils::Id &id); - static const EditorTypeList defaultEditorTypes(const Utils::MimeType &mimeType); - static const EditorTypeList preferredEditorTypes(const Utils::FilePath &filePath); + static const EditorFactories allEditorFactories(); + static IEditorFactory *editorFactoryForId(const Utils::Id &id); + static const EditorFactories defaultEditorFactories(const Utils::MimeType &mimeType); + static const EditorFactories preferredEditorTypes(const Utils::FilePath &filePath); + static const EditorFactories preferredEditorFactories(const Utils::FilePath &filePath); Utils::Id id() const { return m_id; } QString displayName() const { return m_displayName; } QStringList mimeTypes() const { return m_mimeTypes; } - virtual IEditorFactory *asEditorFactory() { return nullptr; }; - virtual IExternalEditor *asExternalEditor() { return nullptr; }; + bool isInternalEditor() const; + bool isExternalEditor() const; + + IEditor *createEditor() const; + bool startEditor(const Utils::FilePath &filePath, QString *errorMessage); protected: - EditorType(); + IEditorFactory(); + void setId(Utils::Id id) { m_id = id; } void setDisplayName(const QString &displayName) { m_displayName = displayName; } void setMimeTypes(const QStringList &mimeTypes) { m_mimeTypes = mimeTypes; } void addMimeType(const QString &mimeType) { m_mimeTypes.append(mimeType); } + void setEditorCreator(const std::function &creator); + void setEditorStarter(const std::function &starter); private: Utils::Id m_id; QString m_displayName; QStringList m_mimeTypes; -}; - -class CORE_EXPORT IEditorFactory : public EditorType -{ -public: - IEditorFactory(); - ~IEditorFactory() override; - - static const EditorFactoryList allEditorFactories(); - static const EditorFactoryList preferredEditorFactories(const Utils::FilePath &filePath); - - IEditor *createEditor() const; - - IEditorFactory *asEditorFactory() override { return this; } - -protected: - void setEditorCreator(const std::function &creator); - -private: std::function m_creator; -}; - -class CORE_EXPORT IExternalEditor : public EditorType -{ -public: - explicit IExternalEditor(); - ~IExternalEditor() override; - - static const ExternalEditorList allExternalEditors(); - static const ExternalEditorList externalEditors(const Utils::MimeType &mimeType); - - IExternalEditor *asExternalEditor() override { return this; } - - virtual bool startEditor(const Utils::FilePath &filePath, QString *errorMessage) = 0; + std::function m_starter; }; } // namespace Core diff --git a/src/plugins/coreplugin/editormanager/ieditorfactory_p.h b/src/plugins/coreplugin/editormanager/ieditorfactory_p.h index 8f251728424..338f5ea24df 100644 --- a/src/plugins/coreplugin/editormanager/ieditorfactory_p.h +++ b/src/plugins/coreplugin/editormanager/ieditorfactory_p.h @@ -9,12 +9,12 @@ namespace Core { -class EditorType; +class IEditorFactory; namespace Internal { -QHash userPreferredEditorTypes(); -void setUserPreferredEditorTypes(const QHash &factories); +QHash userPreferredEditorTypes(); +void setUserPreferredEditorTypes(const QHash &factories); } // Internal } // Core diff --git a/src/plugins/coreplugin/editormanager/systemeditor.cpp b/src/plugins/coreplugin/editormanager/systemeditor.cpp index d54446aa480..2b0f91cbd2c 100644 --- a/src/plugins/coreplugin/editormanager/systemeditor.cpp +++ b/src/plugins/coreplugin/editormanager/systemeditor.cpp @@ -7,7 +7,6 @@ #include -#include #include #include @@ -20,20 +19,19 @@ SystemEditor::SystemEditor() setId("CorePlugin.OpenWithSystemEditor"); setDisplayName(Tr::tr("System Editor")); setMimeTypes({"application/octet-stream"}); -} -bool SystemEditor::startEditor(const FilePath &filePath, QString *errorMessage) -{ - Q_UNUSED(errorMessage) - QUrl url; - url.setPath(filePath.toString()); - url.setScheme(QLatin1String("file")); - if (!QDesktopServices::openUrl(url)) { - if (errorMessage) - *errorMessage = Tr::tr("Could not open URL %1.").arg(url.toString()); - return false; - } - return true; + setEditorStarter([](const FilePath &filePath, QString *errorMessage) { + Q_UNUSED(errorMessage) + QUrl url; + url.setPath(filePath.toString()); + url.setScheme(QLatin1String("file")); + if (!QDesktopServices::openUrl(url)) { + if (errorMessage) + *errorMessage = Tr::tr("Could not open URL %1.").arg(url.toString()); + return false; + } + return true; + }); } } // Core::Internal diff --git a/src/plugins/coreplugin/editormanager/systemeditor.h b/src/plugins/coreplugin/editormanager/systemeditor.h index 6218e63335f..45cbd7d2406 100644 --- a/src/plugins/coreplugin/editormanager/systemeditor.h +++ b/src/plugins/coreplugin/editormanager/systemeditor.h @@ -7,12 +7,10 @@ namespace Core::Internal { -class SystemEditor : public IExternalEditor +class SystemEditor final : public IEditorFactory { public: - explicit SystemEditor(); - - bool startEditor(const Utils::FilePath &filePath, QString *errorMessage) override; + SystemEditor(); }; } // namespace Core::Internal diff --git a/src/plugins/coreplugin/mimetypesettings.cpp b/src/plugins/coreplugin/mimetypesettings.cpp index 7edba5625e9..347ece7fcec 100644 --- a/src/plugins/coreplugin/mimetypesettings.cpp +++ b/src/plugins/coreplugin/mimetypesettings.cpp @@ -98,13 +98,13 @@ public: void load(); - QList handlersForMimeType(const Utils::MimeType &mimeType) const; - EditorType *defaultHandlerForMimeType(const Utils::MimeType &mimeType) const; + QList handlersForMimeType(const Utils::MimeType &mimeType) const; + IEditorFactory *defaultHandlerForMimeType(const Utils::MimeType &mimeType) const; void resetUserDefaults(); QList m_mimeTypes; - mutable QHash> m_handlersByMimeType; - QHash m_userDefault; + mutable QHash> m_handlersByMimeType; + QHash m_userDefault; }; int MimeTypeSettingsModel::rowCount(const QModelIndex &) const @@ -139,7 +139,7 @@ QVariant MimeTypeSettingsModel::data(const QModelIndex &modelIndex, int role) co if (column == 0) { return type.name(); } else { - EditorType *defaultHandler = defaultHandlerForMimeType(type); + IEditorFactory *defaultHandler = defaultHandlerForMimeType(type); return defaultHandler ? defaultHandler->displayName() : QString(); } } else if (role == Qt::EditRole) { @@ -166,12 +166,12 @@ bool MimeTypeSettingsModel::setData(const QModelIndex &index, const QVariant &va { if (role != int(Role::DefaultHandler) || index.column() != 1) return false; - auto factory = value.value(); + auto factory = value.value(); QTC_ASSERT(factory, return false); const int row = index.row(); QTC_ASSERT(row >= 0 && row < m_mimeTypes.size(), return false); const Utils::MimeType mimeType = m_mimeTypes.at(row); - const QList handlers = handlersForMimeType(mimeType); + const QList handlers = handlersForMimeType(mimeType); QTC_ASSERT(handlers.contains(factory), return false); if (handlers.first() == factory) // selection is the default anyhow m_userDefault.remove(mimeType); @@ -200,18 +200,18 @@ void MimeTypeSettingsModel::load() endResetModel(); } -QList MimeTypeSettingsModel::handlersForMimeType(const Utils::MimeType &mimeType) const +QList MimeTypeSettingsModel::handlersForMimeType(const Utils::MimeType &mimeType) const { if (!m_handlersByMimeType.contains(mimeType)) - m_handlersByMimeType.insert(mimeType, EditorType::defaultEditorTypes(mimeType)); + m_handlersByMimeType.insert(mimeType, IEditorFactory::defaultEditorFactories(mimeType)); return m_handlersByMimeType.value(mimeType); } -EditorType *MimeTypeSettingsModel::defaultHandlerForMimeType(const Utils::MimeType &mimeType) const +IEditorFactory *MimeTypeSettingsModel::defaultHandlerForMimeType(const Utils::MimeType &mimeType) const { if (m_userDefault.contains(mimeType)) return m_userDefault.value(mimeType); - const QList handlers = handlersForMimeType(mimeType); + const QList handlers = handlersForMimeType(mimeType); return handlers.isEmpty() ? nullptr : handlers.first(); } @@ -808,13 +808,13 @@ QWidget *MimeEditorDelegate::createEditor(QWidget *parent, void MimeEditorDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const { auto box = static_cast(editor); - const auto factories = index.model()->data(index, Qt::EditRole).value>(); - for (EditorType *factory : factories) + const auto factories = index.model()->data(index, Qt::EditRole).value>(); + for (IEditorFactory *factory : factories) box->addItem(factory->displayName(), QVariant::fromValue(factory)); int currentIndex = factories.indexOf( index.model() ->data(index, int(MimeTypeSettingsModel::Role::DefaultHandler)) - .value()); + .value()); if (QTC_GUARD(currentIndex != -1)) box->setCurrentIndex(currentIndex); } diff --git a/src/plugins/qtsupport/externaleditors.cpp b/src/plugins/qtsupport/externaleditors.cpp index 73bb1116144..257347fa6bd 100644 --- a/src/plugins/qtsupport/externaleditors.cpp +++ b/src/plugins/qtsupport/externaleditors.cpp @@ -258,63 +258,62 @@ DesignerExternalEditor::DesignerExternalEditor() setId("Qt.Designer"); setDisplayName(::Core::Tr::tr("Qt Designer")); setMimeTypes({ProjectExplorer::Constants::FORM_MIMETYPE}); -} -bool DesignerExternalEditor::startEditor(const FilePath &filePath, QString *errorMessage) -{ - LaunchData data; + setEditorStarter([this](const FilePath &filePath, QString *errorMessage) { + LaunchData data; - // Find the editor binary - if (!getEditorLaunchData(designerBinary, filePath, &data, errorMessage)) - return false; + // Find the editor binary + if (!getEditorLaunchData(designerBinary, filePath, &data, errorMessage)) + return false; - if (HostOsInfo::isMacHost()) - return startEditorProcess(data, errorMessage); + if (HostOsInfo::isMacHost()) + return startEditorProcess(data, errorMessage); - /* Qt Designer on the remaining platforms: Uses Designer's own - * Tcp-based communication mechanism to ensure all files are opened - * in one instance (per version). */ + /* Qt Designer on the remaining platforms: Uses Designer's own + * Tcp-based communication mechanism to ensure all files are opened + * in one instance (per version). */ - // Known one? - const ProcessCache::iterator it = m_processCache.find(data.binary); - if (it != m_processCache.end()) { - // Process is known, write to its socket to cause it to open the file - if (debug) - qDebug() << Q_FUNC_INFO << "\nWriting to socket:" << data.binary << filePath; - QTcpSocket *socket = it.value(); - if (!socket->write(filePath.toString().toUtf8() + '\n')) { - *errorMessage = Tr::tr("Qt Designer is not responding (%1).").arg(socket->errorString()); + // Known one? + const ProcessCache::iterator it = m_processCache.find(data.binary); + if (it != m_processCache.end()) { + // Process is known, write to its socket to cause it to open the file + if (debug) + qDebug() << Q_FUNC_INFO << "\nWriting to socket:" << data.binary << filePath; + QTcpSocket *socket = it.value(); + if (!socket->write(filePath.toString().toUtf8() + '\n')) { + *errorMessage = Tr::tr("Qt Designer is not responding (%1).").arg(socket->errorString()); + return false; + } + return true; + } + // No process yet. Create socket & launch the process + QTcpServer server; + if (!server.listen(QHostAddress::LocalHost)) { + *errorMessage = Tr::tr("Unable to create server socket: %1").arg(server.errorString()); return false; } - return true; - } - // No process yet. Create socket & launch the process - QTcpServer server; - if (!server.listen(QHostAddress::LocalHost)) { - *errorMessage = Tr::tr("Unable to create server socket: %1").arg(server.errorString()); - return false; - } - const quint16 port = server.serverPort(); - if (debug) - qDebug() << Q_FUNC_INFO << "\nLaunching server:" << port << data.binary << filePath; - // Start first one with file and socket as '-client port file' - // Wait for the socket listening - data.arguments.push_front(QString::number(port)); - data.arguments.push_front(QLatin1String("-client")); + const quint16 port = server.serverPort(); + if (debug) + qDebug() << Q_FUNC_INFO << "\nLaunching server:" << port << data.binary << filePath; + // Start first one with file and socket as '-client port file' + // Wait for the socket listening + data.arguments.push_front(QString::number(port)); + data.arguments.push_front(QLatin1String("-client")); - if (!startEditorProcess(data, errorMessage)) - return false; - // Insert into cache if socket is created, else try again next time - if (server.waitForNewConnection(3000)) { - QTcpSocket *socket = server.nextPendingConnection(); - socket->setParent(&m_guard); - const QString binary = data.binary; - m_processCache.insert(binary, socket); - auto mapSlot = [binary] { processTerminated(binary); }; - QObject::connect(socket, &QAbstractSocket::disconnected, &m_guard, mapSlot); - QObject::connect(socket, &QAbstractSocket::errorOccurred, &m_guard, mapSlot); - } - return true; + if (!startEditorProcess(data, errorMessage)) + return false; + // Insert into cache if socket is created, else try again next time + if (server.waitForNewConnection(3000)) { + QTcpSocket *socket = server.nextPendingConnection(); + socket->setParent(&m_guard); + const QString binary = data.binary; + m_processCache.insert(binary, socket); + auto mapSlot = [binary] { processTerminated(binary); }; + QObject::connect(socket, &QAbstractSocket::disconnected, &m_guard, mapSlot); + QObject::connect(socket, &QAbstractSocket::errorOccurred, &m_guard, mapSlot); + } + return true; + }); } // Linguist @@ -331,13 +330,11 @@ LinguistEditor::LinguistEditor() setId("Qt.Linguist"); setDisplayName(::Core::Tr::tr("Qt Linguist")); setMimeTypes({ProjectExplorer::Constants::LINGUIST_MIMETYPE}); -} - -bool LinguistEditor::startEditor(const Utils::FilePath &filePath, QString *errorMessage) -{ - LaunchData data; - return getEditorLaunchData(linguistBinary, filePath, &data, errorMessage) - && startEditorProcess(data, errorMessage); + setEditorStarter([](const FilePath &filePath, QString *errorMessage) { + LaunchData data; + return getEditorLaunchData(linguistBinary, filePath, &data, errorMessage) + && startEditorProcess(data, errorMessage); + }); } } // QtSupport::Internal diff --git a/src/plugins/qtsupport/externaleditors.h b/src/plugins/qtsupport/externaleditors.h index 1901046b658..5c34940f572 100644 --- a/src/plugins/qtsupport/externaleditors.h +++ b/src/plugins/qtsupport/externaleditors.h @@ -9,23 +9,19 @@ namespace QtSupport::Internal { -class DesignerExternalEditor : public Core::IExternalEditor +class DesignerExternalEditor : public Core::IEditorFactory { public: DesignerExternalEditor(); - bool startEditor(const Utils::FilePath &filePath, QString *errorMessage) final; - private: QObject m_guard; }; -class LinguistEditor : public Core::IExternalEditor +class LinguistEditor : public Core::IEditorFactory { public: LinguistEditor(); - - bool startEditor(const Utils::FilePath &filePath, QString *errorMessage) final; }; } // QtSupport::Internal