Changeset View
Changeset View
Standalone View
Standalone View
kdevplatform/shell/sourceformattercontroller.cpp
Show First 20 Lines • Show All 68 Lines • ▼ Show 20 Line(s) | |||||
69 | } | 69 | } | ||
70 | 70 | | |||
71 | namespace KDevelop | 71 | namespace KDevelop | ||
72 | { | 72 | { | ||
73 | 73 | | |||
74 | class SourceFormatterControllerPrivate | 74 | class SourceFormatterControllerPrivate | ||
75 | { | 75 | { | ||
76 | public: | 76 | public: | ||
77 | // cache of formatter plugins, to avoid querying plugincontroller | ||||
78 | QVector<ISourceFormatter*> sourceFormatters; | ||||
77 | // GUI actions | 79 | // GUI actions | ||
78 | QAction* formatTextAction; | 80 | QAction* formatTextAction; | ||
79 | QAction* formatFilesAction; | 81 | QAction* formatFilesAction; | ||
80 | QAction* formatLine; | 82 | QAction* formatLine; | ||
81 | QList<KDevelop::ProjectBaseItem*> prjItems; | 83 | QList<KDevelop::ProjectBaseItem*> prjItems; | ||
82 | QList<QUrl> urls; | 84 | QList<QUrl> urls; | ||
83 | bool enabled = true; | 85 | bool enabled = true; | ||
84 | }; | 86 | }; | ||
Show All 37 Lines | 121 | { | |||
122 | setXMLFile(QStringLiteral("kdevsourceformatter.rc")); | 124 | setXMLFile(QStringLiteral("kdevsourceformatter.rc")); | ||
123 | 125 | | |||
124 | if (Core::self()->setupFlags() & Core::NoUi) return; | 126 | if (Core::self()->setupFlags() & Core::NoUi) return; | ||
125 | 127 | | |||
126 | d->formatTextAction = actionCollection()->addAction(QStringLiteral("edit_reformat_source")); | 128 | d->formatTextAction = actionCollection()->addAction(QStringLiteral("edit_reformat_source")); | ||
127 | d->formatTextAction->setText(i18n("&Reformat Source")); | 129 | d->formatTextAction->setText(i18n("&Reformat Source")); | ||
128 | d->formatTextAction->setToolTip(i18n("Reformat source using AStyle")); | 130 | d->formatTextAction->setToolTip(i18n("Reformat source using AStyle")); | ||
129 | d->formatTextAction->setWhatsThis(i18n("Source reformatting functionality using <b>astyle</b> library.")); | 131 | d->formatTextAction->setWhatsThis(i18n("Source reformatting functionality using <b>astyle</b> library.")); | ||
132 | d->formatTextAction->setEnabled(false); | ||||
130 | connect(d->formatTextAction, &QAction::triggered, this, &SourceFormatterController::beautifySource); | 133 | connect(d->formatTextAction, &QAction::triggered, this, &SourceFormatterController::beautifySource); | ||
131 | 134 | | |||
132 | d->formatLine = actionCollection()->addAction(QStringLiteral("edit_reformat_line")); | 135 | d->formatLine = actionCollection()->addAction(QStringLiteral("edit_reformat_line")); | ||
133 | d->formatLine->setText(i18n("Reformat Line")); | 136 | d->formatLine->setText(i18n("Reformat Line")); | ||
134 | d->formatLine->setToolTip(i18n("Reformat current line using AStyle")); | 137 | d->formatLine->setToolTip(i18n("Reformat current line using AStyle")); | ||
135 | d->formatLine->setWhatsThis(i18n("Source reformatting of line under cursor using <b>astyle</b> library.")); | 138 | d->formatLine->setWhatsThis(i18n("Source reformatting of line under cursor using <b>astyle</b> library.")); | ||
139 | d->formatLine->setEnabled(false); | ||||
136 | connect(d->formatLine, &QAction::triggered, this, &SourceFormatterController::beautifyLine); | 140 | connect(d->formatLine, &QAction::triggered, this, &SourceFormatterController::beautifyLine); | ||
137 | 141 | | |||
138 | d->formatFilesAction = actionCollection()->addAction(QStringLiteral("tools_astyle")); | 142 | d->formatFilesAction = actionCollection()->addAction(QStringLiteral("tools_astyle")); | ||
139 | d->formatFilesAction->setText(i18n("Reformat Files...")); | 143 | d->formatFilesAction->setText(i18n("Reformat Files...")); | ||
140 | d->formatFilesAction->setToolTip(i18n("Format file(s) using the current theme")); | 144 | d->formatFilesAction->setToolTip(i18n("Format file(s) using the current theme")); | ||
141 | d->formatFilesAction->setWhatsThis(i18n("Formatting functionality using <b>astyle</b> library.")); | 145 | d->formatFilesAction->setWhatsThis(i18n("Formatting functionality using <b>astyle</b> library.")); | ||
146 | d->formatFilesAction->setEnabled(false); | ||||
142 | connect(d->formatFilesAction, &QAction::triggered, this, static_cast<void(SourceFormatterController::*)()>(&SourceFormatterController::formatFiles)); | 147 | connect(d->formatFilesAction, &QAction::triggered, this, static_cast<void(SourceFormatterController::*)()>(&SourceFormatterController::formatFiles)); | ||
143 | 148 | | |||
149 | | ||||
150 | connect(Core::self()->pluginController(), &IPluginController::pluginLoaded, | ||||
151 | this, &SourceFormatterController::pluginLoaded); | ||||
152 | connect(Core::self()->pluginController(), &IPluginController::unloadingPlugin, | ||||
153 | this, &SourceFormatterController::unloadingPlugin); | ||||
154 | | ||||
144 | // connect to both documentActivated & documentClosed, | 155 | // connect to both documentActivated & documentClosed, | ||
145 | // otherwise we miss when the last document was closed | 156 | // otherwise we miss when the last document was closed | ||
146 | connect(Core::self()->documentController(), &IDocumentController::documentActivated, | 157 | connect(Core::self()->documentController(), &IDocumentController::documentActivated, | ||
147 | this, &SourceFormatterController::updateFormatTextAction); | 158 | this, &SourceFormatterController::updateFormatTextAction); | ||
148 | connect(Core::self()->documentController(), &IDocumentController::documentClosed, | 159 | connect(Core::self()->documentController(), &IDocumentController::documentClosed, | ||
149 | this, &SourceFormatterController::updateFormatTextAction); | 160 | this, &SourceFormatterController::updateFormatTextAction); | ||
150 | // Use a queued connection, because otherwise the view is not yet fully set up | 161 | // Use a queued connection, because otherwise the view is not yet fully set up | ||
151 | connect(Core::self()->documentController(), &IDocumentController::documentLoaded, | 162 | connect(Core::self()->documentController(), &IDocumentController::documentLoaded, | ||
Show All 11 Lines | 169 | { | |||
163 | if (!doc->textDocument()) { | 174 | if (!doc->textDocument()) { | ||
164 | return; | 175 | return; | ||
165 | } | 176 | } | ||
166 | const auto url = doc->url(); | 177 | const auto url = doc->url(); | ||
167 | const auto mime = QMimeDatabase().mimeTypeForUrl(url); | 178 | const auto mime = QMimeDatabase().mimeTypeForUrl(url); | ||
168 | adaptEditorIndentationMode(doc->textDocument(), formatterForUrl(url, mime), url); | 179 | adaptEditorIndentationMode(doc->textDocument(), formatterForUrl(url, mime), url); | ||
169 | } | 180 | } | ||
170 | 181 | | |||
182 | void SourceFormatterController::pluginLoaded(IPlugin* plugin) | ||||
183 | { | ||||
184 | ISourceFormatter* sourceFormatter = plugin->extension<ISourceFormatter>(); | ||||
kfunk: Minor: Would prefer early-return here.
```
if (!sourceFormatter) {
return;
}
``` | |||||
185 | | ||||
186 | if (!sourceFormatter) { | ||||
187 | return; | ||||
188 | } | ||||
189 | | ||||
190 | d->sourceFormatters << sourceFormatter; | ||||
kfunk: Shouldn't this be `>= 1`? | |||||
== 1 only. Because for > 1 the actions should have been already enabled before, no state change when there are more than one plugin. Unless things are flawed elsewhere,, which they should not :) kossebau: `== 1` only. Because for > 1 the actions should have been already enabled before, no state… | |||||
add a comment on the == 1 case to explain why this is OK. Also, personal pet-peeve: please try to use size() everywhere in preference over count(), to make this more in align with C++/STL. mwolff: add a comment on the `== 1` case to explain why this is OK.
Also, personal pet-peeve: please… | |||||
Would factor this out into a separate function (i.e. resetUi() as you did in the other class) and use that from both pluginLoaded and unloadingPlugin. kfunk: Would factor this out into a separate function (i.e. `resetUi()` as you did in the other class)… | |||||
kossebau: `resetUi()` done as proposed. | |||||
191 | | ||||
192 | resetUi(); | ||||
193 | | ||||
194 | emit formatterLoaded(sourceFormatter); | ||||
195 | // with one plugin now added, hasFormatters turned to true, so report to listeners | ||||
196 | if (d->sourceFormatters.size() == 1) { | ||||
197 | emit hasFormattersChanged(true); | ||||
198 | } | ||||
199 | } | ||||
200 | | ||||
kfunk: Dito | |||||
201 | void SourceFormatterController::unloadingPlugin(IPlugin* plugin) | ||||
202 | { | ||||
203 | ISourceFormatter* sourceFormatter = plugin->extension<ISourceFormatter>(); | ||||
204 | | ||||
205 | if (!sourceFormatter) { | ||||
206 | return; | ||||
207 | } | ||||
208 | | ||||
209 | const int idx = d->sourceFormatters.indexOf(sourceFormatter); | ||||
210 | Q_ASSERT(idx != -1); | ||||
211 | d->sourceFormatters.remove(idx); | ||||
212 | | ||||
213 | resetUi(); | ||||
214 | | ||||
215 | emit formatterUnloading(sourceFormatter); | ||||
216 | if (d->sourceFormatters.isEmpty()) { | ||||
217 | emit hasFormattersChanged(false); | ||||
218 | } | ||||
219 | } | ||||
220 | | ||||
221 | | ||||
171 | void SourceFormatterController::initialize() | 222 | void SourceFormatterController::initialize() | ||
172 | { | 223 | { | ||
173 | } | 224 | } | ||
174 | 225 | | |||
175 | SourceFormatterController::~SourceFormatterController() | 226 | SourceFormatterController::~SourceFormatterController() | ||
176 | { | 227 | { | ||
177 | } | 228 | } | ||
178 | 229 | | |||
Show All 28 Lines | |||||
207 | } | 258 | } | ||
208 | 259 | | |||
209 | ISourceFormatter* SourceFormatterController::findFirstFormatterForMimeType(const QMimeType& mime ) const | 260 | ISourceFormatter* SourceFormatterController::findFirstFormatterForMimeType(const QMimeType& mime ) const | ||
210 | { | 261 | { | ||
211 | static QHash<QString, ISourceFormatter*> knownFormatters; | 262 | static QHash<QString, ISourceFormatter*> knownFormatters; | ||
212 | if (knownFormatters.contains(mime.name())) | 263 | if (knownFormatters.contains(mime.name())) | ||
213 | return knownFormatters[mime.name()]; | 264 | return knownFormatters[mime.name()]; | ||
214 | 265 | | |||
215 | QList<IPlugin*> plugins = Core::self()->pluginController()->allPluginsForExtension( QStringLiteral("org.kdevelop.ISourceFormatter") ); | 266 | foreach (ISourceFormatter* iformatter, d->sourceFormatters) { | ||
216 | foreach( IPlugin* p, plugins) { | | |||
217 | ISourceFormatter *iformatter = p->extension<ISourceFormatter>(); | | |||
218 | QSharedPointer<SourceFormatter> formatter(createFormatterForPlugin(iformatter)); | 267 | QSharedPointer<SourceFormatter> formatter(createFormatterForPlugin(iformatter)); | ||
219 | if( formatter->supportedMimeTypes().contains(mime.name()) ) { | 268 | if( formatter->supportedMimeTypes().contains(mime.name()) ) { | ||
220 | knownFormatters[mime.name()] = iformatter; | 269 | knownFormatters[mime.name()] = iformatter; | ||
221 | return iformatter; | 270 | return iformatter; | ||
222 | } | 271 | } | ||
223 | } | 272 | } | ||
224 | knownFormatters[mime.name()] = nullptr; | 273 | knownFormatters[mime.name()] = nullptr; | ||
225 | return nullptr; | 274 | return nullptr; | ||
Show All 37 Lines | 308 | { | |||
263 | 312 | | |||
264 | const auto formatter = configForUrl(url).readEntry(mime.name(), QString()); | 313 | const auto formatter = configForUrl(url).readEntry(mime.name(), QString()); | ||
265 | 314 | | |||
266 | if( formatter.isEmpty() ) | 315 | if( formatter.isEmpty() ) | ||
267 | { | 316 | { | ||
268 | return findFirstFormatterForMimeType( mime ); | 317 | return findFirstFormatterForMimeType( mime ); | ||
269 | } | 318 | } | ||
270 | 319 | | |||
271 | QStringList formatterinfo = formatter.split( QStringLiteral("||"), QString::SkipEmptyParts ); | 320 | QStringList formatterinfo = formatter.split( QStringLiteral("||"), QString::SkipEmptyParts ); | ||
mwolff: future optimization opportunity: use `splitRef` | |||||
272 | 321 | | |||
273 | if( formatterinfo.size() != 2 ) { | 322 | if( formatterinfo.size() != 2 ) { | ||
274 | qCDebug(SHELL) << "Broken formatting entry for mime:" << mime.name() << "current value:" << formatter; | 323 | qCDebug(SHELL) << "Broken formatting entry for mime:" << mime.name() << "current value:" << formatter; | ||
275 | return nullptr; | 324 | return nullptr; | ||
276 | } | 325 | } | ||
277 | 326 | | |||
278 | return Core::self()->pluginControllerInternal()->extensionForPlugin<ISourceFormatter>( QStringLiteral("org.kdevelop.ISourceFormatter"), formatterinfo.at(0) ); | 327 | foreach (ISourceFormatter* iformatter, d->sourceFormatters) { | ||
328 | if (iformatter->name() == formatterinfo.first()) { | ||||
mwolff: use `.first()` instead of `.at(0)` | |||||
329 | return iformatter; | ||||
330 | } | ||||
331 | } | ||||
332 | | ||||
333 | return nullptr; | ||||
279 | } | 334 | } | ||
280 | 335 | | |||
281 | bool SourceFormatterController::isMimeTypeSupported(const QMimeType& mime) | 336 | bool SourceFormatterController::isMimeTypeSupported(const QMimeType& mime) | ||
282 | { | 337 | { | ||
283 | if( findFirstFormatterForMimeType( mime ) ) { | 338 | if( findFirstFormatterForMimeType( mime ) ) { | ||
284 | return true; | 339 | return true; | ||
285 | } | 340 | } | ||
286 | return false; | 341 | return false; | ||
▲ Show 20 Lines • Show All 85 Lines • ▼ Show 20 Line(s) | |||||
372 | void SourceFormatterController::cleanup() | 427 | void SourceFormatterController::cleanup() | ||
373 | { | 428 | { | ||
374 | } | 429 | } | ||
375 | 430 | | |||
376 | void SourceFormatterController::updateFormatTextAction() | 431 | void SourceFormatterController::updateFormatTextAction() | ||
377 | { | 432 | { | ||
378 | bool enabled = false; | 433 | bool enabled = false; | ||
379 | 434 | | |||
435 | if (!d->sourceFormatters.isEmpty()) { | ||||
380 | IDocument* doc = KDevelop::ICore::self()->documentController()->activeDocument(); | 436 | IDocument* doc = KDevelop::ICore::self()->documentController()->activeDocument(); | ||
381 | if (doc) { | 437 | if (doc) { | ||
382 | QMimeType mime = QMimeDatabase().mimeTypeForUrl(doc->url()); | 438 | QMimeType mime = QMimeDatabase().mimeTypeForUrl(doc->url()); | ||
383 | if (isMimeTypeSupported(mime)) | 439 | if (isMimeTypeSupported(mime)) | ||
384 | enabled = true; | 440 | enabled = true; | ||
385 | } | 441 | } | ||
442 | } | ||||
386 | 443 | | |||
387 | d->formatLine->setEnabled(enabled); | 444 | d->formatLine->setEnabled(enabled); | ||
388 | d->formatTextAction->setEnabled(enabled); | 445 | d->formatTextAction->setEnabled(enabled); | ||
389 | } | 446 | } | ||
390 | 447 | | |||
391 | void SourceFormatterController::beautifySource() | 448 | void SourceFormatterController::beautifySource() | ||
392 | { | 449 | { | ||
393 | IDocument* idoc = KDevelop::ICore::self()->documentController()->activeDocument(); | 450 | IDocument* idoc = KDevelop::ICore::self()->documentController()->activeDocument(); | ||
▲ Show 20 Lines • Show All 217 Lines • ▼ Show 20 Line(s) | |||||
611 | KDevelop::ContextMenuExtension SourceFormatterController::contextMenuExtension(KDevelop::Context* context, QWidget* parent) | 668 | KDevelop::ContextMenuExtension SourceFormatterController::contextMenuExtension(KDevelop::Context* context, QWidget* parent) | ||
612 | { | 669 | { | ||
613 | Q_UNUSED(parent); | 670 | Q_UNUSED(parent); | ||
614 | 671 | | |||
615 | KDevelop::ContextMenuExtension ext; | 672 | KDevelop::ContextMenuExtension ext; | ||
616 | d->urls.clear(); | 673 | d->urls.clear(); | ||
617 | d->prjItems.clear(); | 674 | d->prjItems.clear(); | ||
618 | 675 | | |||
676 | if (d->sourceFormatters.isEmpty()) { | ||||
677 | return ext; | ||||
678 | } | ||||
679 | | ||||
619 | if (context->hasType(KDevelop::Context::EditorContext)) | 680 | if (context->hasType(KDevelop::Context::EditorContext)) | ||
620 | { | 681 | { | ||
621 | if (d->formatTextAction->isEnabled()) | 682 | if (d->formatTextAction->isEnabled()) | ||
622 | ext.addAction(KDevelop::ContextMenuExtension::EditGroup, d->formatTextAction); | 683 | ext.addAction(KDevelop::ContextMenuExtension::EditGroup, d->formatTextAction); | ||
623 | } else if (context->hasType(KDevelop::Context::FileContext)) { | 684 | } else if (context->hasType(KDevelop::Context::FileContext)) { | ||
624 | KDevelop::FileContext* filectx = static_cast<KDevelop::FileContext*>(context); | 685 | KDevelop::FileContext* filectx = static_cast<KDevelop::FileContext*>(context); | ||
625 | d->urls = filectx->urls(); | 686 | d->urls = filectx->urls(); | ||
626 | ext.addAction(KDevelop::ContextMenuExtension::EditGroup, d->formatFilesAction); | 687 | ext.addAction(KDevelop::ContextMenuExtension::EditGroup, d->formatFilesAction); | ||
Show All 29 Lines | 716 | { | |||
656 | d->enabled = !disable; | 717 | d->enabled = !disable; | ||
657 | } | 718 | } | ||
658 | 719 | | |||
659 | bool SourceFormatterController::sourceFormattingEnabled() | 720 | bool SourceFormatterController::sourceFormattingEnabled() | ||
660 | { | 721 | { | ||
661 | return d->enabled; | 722 | return d->enabled; | ||
662 | } | 723 | } | ||
663 | 724 | | |||
725 | bool SourceFormatterController::hasFormatters() const | ||||
726 | { | ||||
727 | return !d->sourceFormatters.isEmpty(); | ||||
kfunk: Minor: Remove extra parens | |||||
728 | } | ||||
729 | | ||||
730 | QVector<ISourceFormatter*> SourceFormatterController::formatters() const | ||||
731 | { | ||||
732 | return d->sourceFormatters; | ||||
733 | } | ||||
734 | | ||||
735 | void SourceFormatterController::resetUi() | ||||
736 | { | ||||
737 | d->formatFilesAction->setEnabled(!d->sourceFormatters.isEmpty()); | ||||
738 | | ||||
739 | updateFormatTextAction(); | ||||
740 | } | ||||
741 | | ||||
664 | } | 742 | } |
Minor: Would prefer early-return here.