Git commit a6a42ec30a7c1b884de8beb0b1be8b07cb0f1f85 by Friedrich W. H. Koss= ebau. Committed on 30/11/2017 at 23:51. Pushed by kossebau into branch 'master'. Make SourceFormatter plugins enablable, hide actions with no plugins Summary: Source formatting is a feature seemingly only used by some. So it makes sense to allow disabling this feature, for some minimal smaller runtime footprint and less unused clutter in the UI (like menu actions or settings). This patch achieves this to a good degree: * makes the plugins astyle & customscript normal global plugins which can be enabled/disabled by the user * removes the SourceFormatterController actions from the menus when there a= re no formatters available * shows no source formatting settings page in the project settings when there are no formatters available Not yet done is to hide the source formatting settings page from the application settings dialog in case no formatters are available. That might need some more custom logic all over the shell code, which is not so nice. Instead the option should be investigated to make the source formatting controller a normal plugin with a suited interface, which then can be queried by other code needing that service. Test Plan: See plugins astyle & customscript turn up in plugin selection settings. Disable and enable both and see how actions in the main Edit menu and the context menu on file items are present or not present, as well as the formatting settings page in the project settings dialog being shown or not. See also the formatting settings pages for projects and the global one only offering the formatters of the enabled plugins. Reviewers: #kdevelop, kfunk, mwolff Reviewed By: #kdevelop, kfunk, mwolff Subscribers: mwolff, kfunk, kdevelop-devel Differential Revision: https://phabricator.kde.org/D8492 M +5 -0 kdevplatform/interfaces/isourceformattercontroller.h M +5 -1 kdevplatform/shell/mainwindow.cpp M +12 -0 kdevplatform/shell/mainwindow_p.cpp M +1 -0 kdevplatform/shell/mainwindow_p.h M +87 -9 kdevplatform/shell/sourceformattercontroller.cpp M +13 -0 kdevplatform/shell/sourceformattercontroller.h M +92 -41 kdevplatform/shell/sourceformatterselectionedit.cpp M +5 -0 kdevplatform/shell/sourceformatterselectionedit.h M +1 -1 plugins/astyle/kdevastyle.json M +1 -1 plugins/customscript/kdevcustomscript.json M +4 -1 plugins/sourceformatter/sourceformatterplugin.cpp https://commits.kde.org/kdevelop/a6a42ec30a7c1b884de8beb0b1be8b07cb0f1f85 diff --git a/kdevplatform/interfaces/isourceformattercontroller.h b/kdevpla= tform/interfaces/isourceformattercontroller.h index 1210d774c1..480ec404e1 100644 --- a/kdevplatform/interfaces/isourceformattercontroller.h +++ b/kdevplatform/interfaces/isourceformattercontroller.h @@ -58,6 +58,8 @@ class KDEVPLATFORMINTERFACES_EXPORT ISourceFormatterContr= oller : public QObject * @param mime known mimetype of the url */ virtual ISourceFormatter* formatterForUrl(const QUrl& url, const QMimeTy= pe& mime) =3D 0; + ///\return @c true if there are formatters at all, @c false otherwise + virtual bool hasFormatters() const =3D 0; /** \return Whether this mime type is supported by any plugin. */ virtual bool isMimeTypeSupported(const QMimeType &mime) =3D 0; @@ -68,6 +70,9 @@ class KDEVPLATFORMINTERFACES_EXPORT ISourceFormatterContr= oller : public QObject virtual void disableSourceFormatting(bool disable) =3D 0; ///\return Whether or not source formatting is enabled virtual bool sourceFormattingEnabled() =3D 0; + + Q_SIGNALS: + void hasFormattersChanged(bool hasFormatters); }; = } diff --git a/kdevplatform/shell/mainwindow.cpp b/kdevplatform/shell/mainwin= dow.cpp index 0166466ac5..23ee93abf2 100644 --- a/kdevplatform/shell/mainwindow.cpp +++ b/kdevplatform/shell/mainwindow.cpp @@ -345,12 +345,16 @@ void MainWindow::initialize() d, &MainWindowPrivate::activePartChanged); connect( this, &MainWindow::activeViewChanged, d, &MainWindowPrivate::changeActiveView); + connect(Core::self()->sourceFormatterControllerInternal(), &SourceForm= atterController::hasFormattersChanged, + d, &MainWindowPrivate::updateSourceFormatterGuiClient); = foreach(IPlugin* plugin, Core::self()->pluginController()->loadedPlugi= ns()) d->addPlugin(plugin); = guiFactory()->addClient(Core::self()->sessionController()); - guiFactory()->addClient(Core::self()->sourceFormatterControllerInterna= l()); + if (Core::self()->sourceFormatterControllerInternal()->hasFormatters()= ) { + guiFactory()->addClient(Core::self()->sourceFormatterControllerInt= ernal()); + } = // Needed to re-plug the actions from the sessioncontroller as xmlguic= lients don't // seem to remember which actions where plugged in. diff --git a/kdevplatform/shell/mainwindow_p.cpp b/kdevplatform/shell/mainw= indow_p.cpp index 2506676a66..50aac80374 100644 --- a/kdevplatform/shell/mainwindow_p.cpp +++ b/kdevplatform/shell/mainwindow_p.cpp @@ -47,6 +47,7 @@ Boston, MA 02110-1301, USA. #include "mainwindow.h" #include "textdocument.h" #include "sessioncontroller.h" +#include "sourceformattercontroller.h" #include "debug.h" #include "ktexteditorpluginintegration.h" #include "colorschemechooser.h" @@ -125,6 +126,17 @@ void MainWindowPrivate::removePlugin( IPlugin *plugin ) m_mainWindow->guiFactory()->removeClient( plugin ); } = +void MainWindowPrivate::updateSourceFormatterGuiClient(bool hasFormatters) +{ + auto sourceFormatterController =3D Core::self()->sourceFormatterContro= llerInternal(); + auto guiFactory =3D m_mainWindow->guiFactory(); + if (hasFormatters) { + guiFactory->addClient(sourceFormatterController); + } else { + guiFactory->removeClient(sourceFormatterController); + } +} + void MainWindowPrivate::activePartChanged(KParts::Part *part) { if ( Core::self()->uiController()->activeMainWindow() =3D=3D m_mainWin= dow) diff --git a/kdevplatform/shell/mainwindow_p.h b/kdevplatform/shell/mainwin= dow_p.h index 01b2b985ae..fdb975e0d6 100644 --- a/kdevplatform/shell/mainwindow_p.h +++ b/kdevplatform/shell/mainwindow_p.h @@ -77,6 +77,7 @@ public: public Q_SLOTS: void addPlugin( KDevelop::IPlugin *plugin ); void removePlugin( KDevelop::IPlugin *plugin ); + void updateSourceFormatterGuiClient(bool hasFormatters); = void activePartChanged(KParts::Part *part); void mergeView(Sublime::View *view); diff --git a/kdevplatform/shell/sourceformattercontroller.cpp b/kdevplatfor= m/shell/sourceformattercontroller.cpp index de252c94ab..13ffaad816 100644 --- a/kdevplatform/shell/sourceformattercontroller.cpp +++ b/kdevplatform/shell/sourceformattercontroller.cpp @@ -74,6 +74,8 @@ namespace KDevelop class SourceFormatterControllerPrivate { public: + // cache of formatter plugins, to avoid querying plugincontroller + QVector sourceFormatters; // GUI actions QAction* formatTextAction; QAction* formatFilesAction; @@ -127,20 +129,29 @@ SourceFormatterController::SourceFormatterController(= QObject *parent) d->formatTextAction->setText(i18n("&Reformat Source")); d->formatTextAction->setToolTip(i18n("Reformat source using AStyle")); d->formatTextAction->setWhatsThis(i18n("Source reformatting functional= ity using astyle library.")); + d->formatTextAction->setEnabled(false); connect(d->formatTextAction, &QAction::triggered, this, &SourceFormatt= erController::beautifySource); = d->formatLine =3D actionCollection()->addAction(QStringLiteral("edit_r= eformat_line")); d->formatLine->setText(i18n("Reformat Line")); d->formatLine->setToolTip(i18n("Reformat current line using AStyle")); d->formatLine->setWhatsThis(i18n("Source reformatting of line under cu= rsor using astyle library.")); + d->formatLine->setEnabled(false); connect(d->formatLine, &QAction::triggered, this, &SourceFormatterCont= roller::beautifyLine); = d->formatFilesAction =3D actionCollection()->addAction(QStringLiteral(= "tools_astyle")); d->formatFilesAction->setText(i18n("Reformat Files...")); d->formatFilesAction->setToolTip(i18n("Format file(s) using the curren= t theme")); d->formatFilesAction->setWhatsThis(i18n("Formatting functionality usin= g astyle library.")); + d->formatFilesAction->setEnabled(false); connect(d->formatFilesAction, &QAction::triggered, this, static_cast(&SourceFormatterController::formatFile= s)); = + + connect(Core::self()->pluginController(), &IPluginController::pluginLo= aded, + this, &SourceFormatterController::pluginLoaded); + connect(Core::self()->pluginController(), &IPluginController::unloadin= gPlugin, + this, &SourceFormatterController::unloadingPlugin); + // connect to both documentActivated & documentClosed, // otherwise we miss when the last document was closed connect(Core::self()->documentController(), &IDocumentController::docu= mentActivated, @@ -168,6 +179,46 @@ void SourceFormatterController::documentLoaded( IDocum= ent* doc ) adaptEditorIndentationMode(doc->textDocument(), formatterForUrl(url, m= ime), url); } = +void SourceFormatterController::pluginLoaded(IPlugin* plugin) +{ + ISourceFormatter* sourceFormatter =3D plugin->extension(); + + if (!sourceFormatter) { + return; + } + + d->sourceFormatters << sourceFormatter; + + resetUi(); + + emit formatterLoaded(sourceFormatter); + // with one plugin now added, hasFormatters turned to true, so report = to listeners + if (d->sourceFormatters.size() =3D=3D 1) { + emit hasFormattersChanged(true); + } +} + +void SourceFormatterController::unloadingPlugin(IPlugin* plugin) +{ + ISourceFormatter* sourceFormatter =3D plugin->extension(); + + if (!sourceFormatter) { + return; + } + + const int idx =3D d->sourceFormatters.indexOf(sourceFormatter); + Q_ASSERT(idx !=3D -1); + d->sourceFormatters.remove(idx); + + resetUi(); + + emit formatterUnloading(sourceFormatter); + if (d->sourceFormatters.isEmpty()) { + emit hasFormattersChanged(false); + } +} + + void SourceFormatterController::initialize() { } @@ -212,9 +263,7 @@ ISourceFormatter* SourceFormatterController::findFirstF= ormatterForMimeType(const if (knownFormatters.contains(mime.name())) return knownFormatters[mime.name()]; = - QList plugins =3D Core::self()->pluginController()->allPlugi= nsForExtension( QStringLiteral("org.kdevelop.ISourceFormatter") ); - foreach( IPlugin* p, plugins) { - ISourceFormatter *iformatter =3D p->extension(); + foreach (ISourceFormatter* iformatter, d->sourceFormatters) { QSharedPointer formatter(createFormatterForPlugin= (iformatter)); if( formatter->supportedMimeTypes().contains(mime.name()) ) { knownFormatters[mime.name()] =3D iformatter; @@ -275,7 +324,13 @@ ISourceFormatter* SourceFormatterController::formatter= ForUrl(const QUrl& url, co return nullptr; } = - return Core::self()->pluginControllerInternal()->extensionForPlugin( QStringLiteral("org.kdevelop.ISourceFormatter"), formatter= info.at(0) ); + foreach (ISourceFormatter* iformatter, d->sourceFormatters) { + if (iformatter->name() =3D=3D formatterinfo.first()) { + return iformatter; + } + } + + return nullptr; } = bool SourceFormatterController::isMimeTypeSupported(const QMimeType& mime) @@ -377,11 +432,13 @@ void SourceFormatterController::updateFormatTextActio= n() { bool enabled =3D false; = - IDocument* doc =3D KDevelop::ICore::self()->documentController()->acti= veDocument(); - if (doc) { - QMimeType mime =3D QMimeDatabase().mimeTypeForUrl(doc->url()); - if (isMimeTypeSupported(mime)) - enabled =3D true; + if (!d->sourceFormatters.isEmpty()) { + IDocument* doc =3D KDevelop::ICore::self()->documentController()->= activeDocument(); + if (doc) { + QMimeType mime =3D QMimeDatabase().mimeTypeForUrl(doc->url()); + if (isMimeTypeSupported(mime)) + enabled =3D true; + } } = d->formatLine->setEnabled(enabled); @@ -616,6 +673,10 @@ KDevelop::ContextMenuExtension SourceFormatterControll= er::contextMenuExtension(K d->urls.clear(); d->prjItems.clear(); = + if (d->sourceFormatters.isEmpty()) { + return ext; + } + if (context->hasType(KDevelop::Context::EditorContext)) { if (d->formatTextAction->isEnabled()) @@ -661,4 +722,21 @@ bool SourceFormatterController::sourceFormattingEnable= d() return d->enabled; } = +bool SourceFormatterController::hasFormatters() const +{ + return !d->sourceFormatters.isEmpty(); +} + +QVector SourceFormatterController::formatters() const +{ + return d->sourceFormatters; +} + +void SourceFormatterController::resetUi() +{ + d->formatFilesAction->setEnabled(!d->sourceFormatters.isEmpty()); + + updateFormatTextAction(); +} + } diff --git a/kdevplatform/shell/sourceformattercontroller.h b/kdevplatform/= shell/sourceformattercontroller.h index f212800b5c..5d74d0280f 100644 --- a/kdevplatform/shell/sourceformattercontroller.h +++ b/kdevplatform/shell/sourceformattercontroller.h @@ -25,6 +25,7 @@ Boston, MA 02110-1301, USA. #include = #include +#include #include = #include @@ -102,6 +103,7 @@ public: * The source formatter is then ready to use on a file. */ ISourceFormatter* formatterForUrl(const QUrl& url, const QMimeType& mi= me) override; + bool hasFormatters() const override; /** \return Whether this mime type is supported by any plugin. */ bool isMimeTypeSupported(const QMimeType& mime) override; @@ -132,12 +134,21 @@ public: void disableSourceFormatting(bool disable) override; bool sourceFormattingEnabled() override; = + QVector formatters() const; + +Q_SIGNALS: + void formatterLoaded(KDevelop::ISourceFormatter* ifmt); + void formatterUnloading(KDevelop::ISourceFormatter* ifmt); + private Q_SLOTS: void updateFormatTextAction(); void beautifySource(); void beautifyLine(); void formatFiles(); void documentLoaded( KDevelop::IDocument* ); + void pluginLoaded(KDevelop::IPlugin* plugin); + void unloadingPlugin(KDevelop::IPlugin* plugin); + private: /** \return A modeline string (to add at the end or the beginning of a= file) * corresponding to the settings of the active language. @@ -152,6 +163,8 @@ private: void adaptEditorIndentationMode(KTextEditor::Document* doc, KDevelop::= ISourceFormatter* formatter, const QUrl& url, bool ignoreModeline = =3D false); = + void resetUi(); + private: const QScopedPointer d; }; diff --git a/kdevplatform/shell/sourceformatterselectionedit.cpp b/kdevplat= form/shell/sourceformatterselectionedit.cpp index c4818cf04c..56f15c84b8 100644 --- a/kdevplatform/shell/sourceformatterselectionedit.cpp +++ b/kdevplatform/shell/sourceformatterselectionedit.cpp @@ -112,6 +112,15 @@ SourceFormatterSelectionEdit::SourceFormatterSelection= Edit(QWidget* parent) iface->setConfigValue(QStringLiteral("dynamic-word-wrap"), false); iface->setConfigValue(QStringLiteral("icon-bar"), false); } + + SourceFormatterController* controller =3D Core::self()->sourceFormatte= rControllerInternal(); + connect(controller, &SourceFormatterController::formatterLoaded, + this, &SourceFormatterSelectionEdit::addSourceFormatter); + connect(controller, &SourceFormatterController::formatterUnloading, + this, &SourceFormatterSelectionEdit::removeSourceFormatter); + for (auto* formatter : controller->formatters()) { + addSourceFormatter(formatter); + } } = SourceFormatterSelectionEdit::~SourceFormatterSelectionEdit() @@ -125,58 +134,76 @@ static void selectAvailableStyle(LanguageSettings& la= ng) lang.selectedStyle =3D *lang.selectedFormatter->styles.begin(); } = -void SourceFormatterSelectionEdit::loadSettings(const KConfigGroup& config) +void SourceFormatterSelectionEdit::addSourceFormatter(ISourceFormatter* if= mt) { - SourceFormatterController* fmtctrl =3D Core::self()->sourceFormatterCo= ntrollerInternal(); - QList plugins =3D KDevelop::ICore::self()->pluginC= ontroller()->allPluginsForExtension( QStringLiteral("org.kdevelop.ISourceFo= rmatter") ); - foreach( KDevelop::IPlugin* plugin, plugins ) - { - KDevelop::ISourceFormatter* ifmt =3D plugin->extension(); - auto info =3D KDevelop::Core::self()->pluginControllerInternal()->= pluginInfo( plugin ); - KDevelop::SourceFormatter* formatter; - FormatterMap::const_iterator iter =3D d->formatters.constFind(ifmt= ->name()); - if (iter =3D=3D d->formatters.constEnd()) { - formatter =3D fmtctrl->createFormatterForPlugin(ifmt); - d->formatters[ifmt->name()] =3D formatter; - } else { - formatter =3D iter.value(); - } - foreach ( const SourceFormatterStyle* style, formatter->styles ) { - foreach ( const SourceFormatterStyle::MimeHighlightPair& item,= style->mimeTypes() ) { - QMimeType mime =3D QMimeDatabase().mimeTypeForName(item.mi= meType); - if (!mime.isValid()) { - qCWarning(SHELL) << "plugin" << info.name() << "suppor= ts unknown mimetype entry" << item.mimeType; - continue; - } - QString languageName =3D item.highlightMode; - LanguageSettings& l =3D d->languages[languageName]; - l.mimetypes.append(mime); - l.formatters.insert( formatter ); + SourceFormatter* formatter; + FormatterMap::const_iterator iter =3D d->formatters.constFind(ifmt->na= me()); + if (iter =3D=3D d->formatters.constEnd()) { + formatter =3D Core::self()->sourceFormatterControllerInternal()->c= reateFormatterForPlugin(ifmt); + d->formatters[ifmt->name()] =3D formatter; + } else { + qCWarning(SHELL) << "formatter plugin" << ifmt->name() << "loading= which was already seen before by SourceFormatterSelectionEdit"; + return; + } + + foreach ( const SourceFormatterStyle* style, formatter->styles ) { + foreach ( const SourceFormatterStyle::MimeHighlightPair& item, sty= le->mimeTypes() ) { + QMimeType mime =3D QMimeDatabase().mimeTypeForName(item.mimeTy= pe); + if (!mime.isValid()) { + qCWarning(SHELL) << "formatter plugin" << ifmt->name() << = "supports unknown mimetype entry" << item.mimeType; + continue; + } + QString languageName =3D item.highlightMode; + LanguageSettings& l =3D d->languages[languageName]; + l.mimetypes.append(mime); + l.formatters.insert( formatter ); + // init selection if needed + if (!l.selectedFormatter) { + l.selectedFormatter =3D formatter; + selectAvailableStyle(l); } } } = - // Sort the languages, preferring firstly active, then loaded languages - QList sortedLanguages; + resetUi(); +} = - foreach(const auto language, - KDevelop::ICore::self()->languageController()->activeLangu= ages() + - KDevelop::ICore::self()->languageController()->loadedLangu= ages()) - { - if (d->languages.contains(language->name()) && !sortedLanguages.co= ntains(language->name())) { - sortedLanguages.push_back( language->name() ); - } +void SourceFormatterSelectionEdit::removeSourceFormatter(ISourceFormatter*= ifmt) +{ + auto iter =3D d->formatters.find(ifmt->name()); + if (iter =3D=3D d->formatters.end()) { + qCWarning(SHELL) << "formatter plugin" << ifmt->name() << "unloadi= ng which was not seen before by SourceFormatterSelectionEdit"; + return; } + d->formatters.erase(iter); + auto formatter =3D iter.value(); = - foreach (const QString& name, d->languages.keys()) { - if( !sortedLanguages.contains( name ) ) - sortedLanguages.push_back( name ); + auto languageIter =3D d->languages.begin(); + while (languageIter !=3D d->languages.end()) { + LanguageSettings& l =3D languageIter.value(); + + l.formatters.remove(formatter); + if (l.formatters.isEmpty()) { + languageIter =3D d->languages.erase(languageIter); + } else { + // reset selected formatter if needed + if (l.selectedFormatter =3D=3D formatter) { + l.selectedFormatter =3D *l.formatters.begin(); + selectAvailableStyle(l); + } + ++languageIter; + } } + delete formatter; = - foreach( const QString& name, sortedLanguages ) - { + resetUi(); +} + +void SourceFormatterSelectionEdit::loadSettings(const KConfigGroup& config) +{ + for (auto languageIter =3D d->languages.begin(); languageIter !=3D d->= languages.end(); ++languageIter) { // Pick the first appropriate mimetype for this language - LanguageSettings& l =3D d->languages[name]; + LanguageSettings& l =3D languageIter.value(); const QList mimetypes =3D l.mimetypes; foreach (const QMimeType& mimetype, mimetypes) { QStringList formatterAndStyleName =3D config.readEntry(mimetyp= e.name(), QString()).split(QStringLiteral("||"), QString::KeepEmptyParts); @@ -205,6 +232,29 @@ void SourceFormatterSelectionEdit::loadSettings(const = KConfigGroup& config) selectAvailableStyle(l); } } + + resetUi(); +} + +void SourceFormatterSelectionEdit::resetUi() +{ + // Sort the languages, preferring firstly active, then loaded languages + QList sortedLanguages; + + foreach(const auto language, + KDevelop::ICore::self()->languageController()->activeLangu= ages() + + KDevelop::ICore::self()->languageController()->loadedLangu= ages()) + { + if (d->languages.contains(language->name()) && !sortedLanguages.co= ntains(language->name())) { + sortedLanguages.push_back( language->name() ); + } + } + + foreach (const QString& name, d->languages.keys()) { + if( !sortedLanguages.contains( name ) ) + sortedLanguages.push_back( name ); + } + bool b =3D blockSignals( true ); d->ui.cbLanguages->blockSignals(!b); d->ui.cbFormatters->blockSignals(!b); @@ -222,6 +272,7 @@ void SourceFormatterSelectionEdit::loadSettings(const K= ConfigGroup& config) } else { d->ui.cbLanguages->setCurrentIndex(0); + d->ui.cbLanguages->setEnabled(true); selectLanguage( 0 ); } updatePreview(); diff --git a/kdevplatform/shell/sourceformatterselectionedit.h b/kdevplatfo= rm/shell/sourceformatterselectionedit.h index 7478b64e28..0fadb8ddc2 100644 --- a/kdevplatform/shell/sourceformatterselectionedit.h +++ b/kdevplatform/shell/sourceformatterselectionedit.h @@ -32,6 +32,7 @@ class QListWidgetItem; namespace KDevelop { class SourceFormatterStyle; +class ISourceFormatter; = class KDEVPLATFORMSHELL_EXPORT SourceFormatterSelectionEdit : public QWidg= et { @@ -49,6 +50,9 @@ Q_SIGNALS: void changed(); = private Q_SLOTS: + void addSourceFormatter(KDevelop::ISourceFormatter* ifmt); + void removeSourceFormatter(KDevelop::ISourceFormatter* ifmt); + void deleteStyle(); void editStyle(); void newStyle(); @@ -58,6 +62,7 @@ private Q_SLOTS: void styleNameChanged(QListWidgetItem* ); = private: + void resetUi(); void updatePreview(); QListWidgetItem* addStyle(const KDevelop::SourceFormatterStyle& s); void enableStyleButtons(); diff --git a/plugins/astyle/kdevastyle.json b/plugins/astyle/kdevastyle.json index 958f4f94c0..31e107eac4 100644 --- a/plugins/astyle/kdevastyle.json +++ b/plugins/astyle/kdevastyle.json @@ -59,6 +59,6 @@ "X-KDevelop-Interfaces": [ "org.kdevelop.ISourceFormatter" ], - "X-KDevelop-LoadMode": "AlwaysOn", + "X-KDevelop-Category": "Global", "X-KDevelop-Mode": "NoGUI" } diff --git a/plugins/customscript/kdevcustomscript.json b/plugins/customscr= ipt/kdevcustomscript.json index 8b1d21ce8c..2f5a298d70 100644 --- a/plugins/customscript/kdevcustomscript.json +++ b/plugins/customscript/kdevcustomscript.json @@ -59,6 +59,6 @@ "X-KDevelop-Interfaces": [ "org.kdevelop.ISourceFormatter" ], - "X-KDevelop-LoadMode": "AlwaysOn", + "X-KDevelop-Category": "Global", "X-KDevelop-Mode": "NoGUI" } diff --git a/plugins/sourceformatter/sourceformatterplugin.cpp b/plugins/so= urceformatter/sourceformatterplugin.cpp index 49adf3486a..79202bbe93 100644 --- a/plugins/sourceformatter/sourceformatterplugin.cpp +++ b/plugins/sourceformatter/sourceformatterplugin.cpp @@ -21,6 +21,8 @@ = #include "config/projectconfigpage.h" = +#include +#include #include = #include @@ -38,7 +40,8 @@ SourceFormatterPlugin::~SourceFormatterPlugin() =3D defau= lt; = int SourceFormatterPlugin::perProjectConfigPages() const { - return 1; + const auto hasFormatters =3D KDevelop::ICore::self()->sourceFormatterC= ontroller()->hasFormatters(); + return hasFormatters ? 1 : 0; } = KDevelop::ConfigPage* SourceFormatterPlugin::perProjectConfigPage(int numb= er, const KDevelop::ProjectConfigOptions& options, QWidget* parent)