1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of Qt Creator.
7 **
8 ** Commercial License Usage
9 ** Licensees holding valid commercial Qt licenses may use this file in
10 ** accordance with the commercial license agreement provided with the
11 ** Software or, alternatively, in accordance with the terms contained in
12 ** a written agreement between you and The Qt Company. For licensing terms
13 ** and conditions see https://www.qt.io/terms-conditions. For further
14 ** information use the contact form at https://www.qt.io/contact-us.
15 **
16 ** GNU General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU
18 ** General Public License version 3 as published by the Free Software
19 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 ** included in the packaging of this file. Please review the following
21 ** information to ensure the GNU General Public License requirements will
22 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 **
24 ****************************************************************************/
25
26 #include "cppcodestylesettingspage.h"
27
28 #include "cppcodestylepreferences.h"
29 #include "cppcodestylesnippets.h"
30 #include "cpppointerdeclarationformatter.h"
31 #include "cppqtstyleindenter.h"
32 #include "cpptoolsconstants.h"
33 #include "cpptoolssettings.h"
34 #include <ui_cppcodestylesettingspage.h>
35
36 #include <coreplugin/icore.h>
37 #include <cppeditor/cppeditorconstants.h>
38 #include <texteditor/codestyleeditor.h>
39 #include <texteditor/fontsettings.h>
40 #include <texteditor/icodestylepreferencesfactory.h>
41 #include <texteditor/textdocument.h>
42 #include <texteditor/displaysettings.h>
43 #include <texteditor/snippets/snippetprovider.h>
44 #include <texteditor/texteditorsettings.h>
45
46 #include <cplusplus/Overview.h>
47 #include <cplusplus/pp.h>
48
49 #include <extensionsystem/pluginmanager.h>
50
51 #include <QTextBlock>
52 #include <QTextStream>
53
54 using namespace TextEditor;
55
56 namespace CppTools {
57
58 namespace Internal {
59
applyRefactorings(QTextDocument * textDocument,TextEditorWidget * editor,const CppCodeStyleSettings & settings)60 static void applyRefactorings(QTextDocument *textDocument, TextEditorWidget *editor,
61 const CppCodeStyleSettings &settings)
62 {
63 // Preprocess source
64 Environment env;
65 Preprocessor preprocess(nullptr, &env);
66 const QByteArray preprocessedSource
67 = preprocess.run(QLatin1String("<no-file>"), textDocument->toPlainText());
68
69 Document::Ptr cppDocument = Document::create(QLatin1String("<no-file>"));
70 cppDocument->setUtf8Source(preprocessedSource);
71 cppDocument->parse(Document::ParseTranlationUnit);
72 cppDocument->check();
73
74 CppRefactoringFilePtr cppRefactoringFile = CppRefactoringChanges::file(editor, cppDocument);
75
76 // Run the formatter
77 Overview overview;
78 overview.showReturnTypes = true;
79 overview.starBindFlags = {};
80
81 if (settings.bindStarToIdentifier)
82 overview.starBindFlags |= Overview::BindToIdentifier;
83 if (settings.bindStarToTypeName)
84 overview.starBindFlags |= Overview::BindToTypeName;
85 if (settings.bindStarToLeftSpecifier)
86 overview.starBindFlags |= Overview::BindToLeftSpecifier;
87 if (settings.bindStarToRightSpecifier)
88 overview.starBindFlags |= Overview::BindToRightSpecifier;
89
90 PointerDeclarationFormatter formatter(cppRefactoringFile, overview);
91 Utils::ChangeSet change = formatter.format(cppDocument->translationUnit()->ast());
92
93 // Apply change
94 QTextCursor cursor(textDocument);
95 change.apply(&cursor);
96 }
97
98 // ------------------ CppCodeStyleSettingsWidget
99
CppCodeStylePreferencesWidget(QWidget * parent)100 CppCodeStylePreferencesWidget::CppCodeStylePreferencesWidget(QWidget *parent)
101 : QWidget(parent),
102 m_ui(new Ui::CppCodeStyleSettingsPage)
103 {
104 m_ui->setupUi(this);
105 m_ui->categoryTab->setProperty("_q_custom_style_disabled", true);
106
107 m_previews << m_ui->previewTextEditGeneral << m_ui->previewTextEditContent
108 << m_ui->previewTextEditBraces << m_ui->previewTextEditSwitch
109 << m_ui->previewTextEditPadding << m_ui->previewTextEditPointerReferences;
110 for (int i = 0; i < m_previews.size(); ++i)
111 m_previews[i]->setPlainText(QLatin1String(Constants::DEFAULT_CODE_STYLE_SNIPPETS[i]));
112
113 decorateEditors(TextEditorSettings::fontSettings());
114 connect(TextEditorSettings::instance(), &TextEditorSettings::fontSettingsChanged,
115 this, &CppCodeStylePreferencesWidget::decorateEditors);
116
117 setVisualizeWhitespace(true);
118
119 connect(m_ui->tabSettingsWidget, &TabSettingsWidget::settingsChanged,
120 this, &CppCodeStylePreferencesWidget::slotTabSettingsChanged);
121 connect(m_ui->indentBlockBraces, &QCheckBox::toggled,
122 this, &CppCodeStylePreferencesWidget::slotCodeStyleSettingsChanged);
123 connect(m_ui->indentBlockBody, &QCheckBox::toggled,
124 this, &CppCodeStylePreferencesWidget::slotCodeStyleSettingsChanged);
125 connect(m_ui->indentClassBraces, &QCheckBox::toggled,
126 this, &CppCodeStylePreferencesWidget::slotCodeStyleSettingsChanged);
127 connect(m_ui->indentNamespaceBraces, &QCheckBox::toggled,
128 this, &CppCodeStylePreferencesWidget::slotCodeStyleSettingsChanged);
129 connect(m_ui->indentEnumBraces, &QCheckBox::toggled,
130 this, &CppCodeStylePreferencesWidget::slotCodeStyleSettingsChanged);
131 connect(m_ui->indentNamespaceBody, &QCheckBox::toggled,
132 this, &CppCodeStylePreferencesWidget::slotCodeStyleSettingsChanged);
133 connect(m_ui->indentSwitchLabels, &QCheckBox::toggled,
134 this, &CppCodeStylePreferencesWidget::slotCodeStyleSettingsChanged);
135 connect(m_ui->indentCaseStatements, &QCheckBox::toggled,
136 this, &CppCodeStylePreferencesWidget::slotCodeStyleSettingsChanged);
137 connect(m_ui->indentCaseBlocks, &QCheckBox::toggled,
138 this, &CppCodeStylePreferencesWidget::slotCodeStyleSettingsChanged);
139 connect(m_ui->indentCaseBreak, &QCheckBox::toggled,
140 this, &CppCodeStylePreferencesWidget::slotCodeStyleSettingsChanged);
141 connect(m_ui->indentAccessSpecifiers, &QCheckBox::toggled,
142 this, &CppCodeStylePreferencesWidget::slotCodeStyleSettingsChanged);
143 connect(m_ui->indentDeclarationsRelativeToAccessSpecifiers, &QCheckBox::toggled,
144 this, &CppCodeStylePreferencesWidget::slotCodeStyleSettingsChanged);
145 connect(m_ui->indentFunctionBody, &QCheckBox::toggled,
146 this, &CppCodeStylePreferencesWidget::slotCodeStyleSettingsChanged);
147 connect(m_ui->indentFunctionBraces, &QCheckBox::toggled,
148 this, &CppCodeStylePreferencesWidget::slotCodeStyleSettingsChanged);
149 connect(m_ui->extraPaddingConditions, &QCheckBox::toggled,
150 this, &CppCodeStylePreferencesWidget::slotCodeStyleSettingsChanged);
151 connect(m_ui->alignAssignments, &QCheckBox::toggled,
152 this, &CppCodeStylePreferencesWidget::slotCodeStyleSettingsChanged);
153 connect(m_ui->bindStarToIdentifier, &QCheckBox::toggled,
154 this, &CppCodeStylePreferencesWidget::slotCodeStyleSettingsChanged);
155 connect(m_ui->bindStarToTypeName, &QCheckBox::toggled,
156 this, &CppCodeStylePreferencesWidget::slotCodeStyleSettingsChanged);
157 connect(m_ui->bindStarToLeftSpecifier, &QCheckBox::toggled,
158 this, &CppCodeStylePreferencesWidget::slotCodeStyleSettingsChanged);
159 connect(m_ui->bindStarToRightSpecifier, &QCheckBox::toggled,
160 this, &CppCodeStylePreferencesWidget::slotCodeStyleSettingsChanged);
161
162 m_ui->categoryTab->setCurrentIndex(0);
163 }
164
~CppCodeStylePreferencesWidget()165 CppCodeStylePreferencesWidget::~CppCodeStylePreferencesWidget()
166 {
167 delete m_ui;
168 }
169
setCodeStyle(CppTools::CppCodeStylePreferences * codeStylePreferences)170 void CppCodeStylePreferencesWidget::setCodeStyle(CppTools::CppCodeStylePreferences *codeStylePreferences)
171 {
172 // code preferences
173 m_preferences = codeStylePreferences;
174
175 connect(m_preferences, &CppCodeStylePreferences::currentTabSettingsChanged,
176 this, &CppCodeStylePreferencesWidget::setTabSettings);
177 connect(m_preferences, &CppCodeStylePreferences::currentCodeStyleSettingsChanged,
178 this, [this](const CppTools::CppCodeStyleSettings &codeStyleSettings) {
179 setCodeStyleSettings(codeStyleSettings);
180 });
181
182 connect(m_preferences, &ICodeStylePreferences::currentPreferencesChanged,
183 this, [this](TextEditor::ICodeStylePreferences *currentPreferences) {
184 slotCurrentPreferencesChanged(currentPreferences);
185 });
186
187 setTabSettings(m_preferences->tabSettings());
188 setCodeStyleSettings(m_preferences->codeStyleSettings(), false);
189 slotCurrentPreferencesChanged(m_preferences->currentPreferences(), false);
190
191 updatePreview();
192 }
193
cppCodeStyleSettings() const194 CppCodeStyleSettings CppCodeStylePreferencesWidget::cppCodeStyleSettings() const
195 {
196 CppCodeStyleSettings set;
197
198 set.indentBlockBraces = m_ui->indentBlockBraces->isChecked();
199 set.indentBlockBody = m_ui->indentBlockBody->isChecked();
200 set.indentClassBraces = m_ui->indentClassBraces->isChecked();
201 set.indentEnumBraces = m_ui->indentEnumBraces->isChecked();
202 set.indentNamespaceBraces = m_ui->indentNamespaceBraces->isChecked();
203 set.indentNamespaceBody = m_ui->indentNamespaceBody->isChecked();
204 set.indentAccessSpecifiers = m_ui->indentAccessSpecifiers->isChecked();
205 set.indentDeclarationsRelativeToAccessSpecifiers = m_ui->indentDeclarationsRelativeToAccessSpecifiers->isChecked();
206 set.indentFunctionBody = m_ui->indentFunctionBody->isChecked();
207 set.indentFunctionBraces = m_ui->indentFunctionBraces->isChecked();
208 set.indentSwitchLabels = m_ui->indentSwitchLabels->isChecked();
209 set.indentStatementsRelativeToSwitchLabels = m_ui->indentCaseStatements->isChecked();
210 set.indentBlocksRelativeToSwitchLabels = m_ui->indentCaseBlocks->isChecked();
211 set.indentControlFlowRelativeToSwitchLabels = m_ui->indentCaseBreak->isChecked();
212 set.bindStarToIdentifier = m_ui->bindStarToIdentifier->isChecked();
213 set.bindStarToTypeName = m_ui->bindStarToTypeName->isChecked();
214 set.bindStarToLeftSpecifier = m_ui->bindStarToLeftSpecifier->isChecked();
215 set.bindStarToRightSpecifier = m_ui->bindStarToRightSpecifier->isChecked();
216 set.extraPaddingForConditionsIfConfusingAlign = m_ui->extraPaddingConditions->isChecked();
217 set.alignAssignments = m_ui->alignAssignments->isChecked();
218
219 return set;
220 }
221
setTabSettings(const TabSettings & settings)222 void CppCodeStylePreferencesWidget::setTabSettings(const TabSettings &settings)
223 {
224 m_ui->tabSettingsWidget->setTabSettings(settings);
225 }
226
setCodeStyleSettings(const CppCodeStyleSettings & s,bool preview)227 void CppCodeStylePreferencesWidget::setCodeStyleSettings(const CppCodeStyleSettings &s, bool preview)
228 {
229 const bool wasBlocked = m_blockUpdates;
230 m_blockUpdates = true;
231 m_ui->indentBlockBraces->setChecked(s.indentBlockBraces);
232 m_ui->indentBlockBody->setChecked(s.indentBlockBody);
233 m_ui->indentClassBraces->setChecked(s.indentClassBraces);
234 m_ui->indentEnumBraces->setChecked(s.indentEnumBraces);
235 m_ui->indentNamespaceBraces->setChecked(s.indentNamespaceBraces);
236 m_ui->indentNamespaceBody->setChecked(s.indentNamespaceBody);
237 m_ui->indentAccessSpecifiers->setChecked(s.indentAccessSpecifiers);
238 m_ui->indentDeclarationsRelativeToAccessSpecifiers->setChecked(s.indentDeclarationsRelativeToAccessSpecifiers);
239 m_ui->indentFunctionBody->setChecked(s.indentFunctionBody);
240 m_ui->indentFunctionBraces->setChecked(s.indentFunctionBraces);
241 m_ui->indentSwitchLabels->setChecked(s.indentSwitchLabels);
242 m_ui->indentCaseStatements->setChecked(s.indentStatementsRelativeToSwitchLabels);
243 m_ui->indentCaseBlocks->setChecked(s.indentBlocksRelativeToSwitchLabels);
244 m_ui->indentCaseBreak->setChecked(s.indentControlFlowRelativeToSwitchLabels);
245 m_ui->bindStarToIdentifier->setChecked(s.bindStarToIdentifier);
246 m_ui->bindStarToTypeName->setChecked(s.bindStarToTypeName);
247 m_ui->bindStarToLeftSpecifier->setChecked(s.bindStarToLeftSpecifier);
248 m_ui->bindStarToRightSpecifier->setChecked(s.bindStarToRightSpecifier);
249 m_ui->extraPaddingConditions->setChecked(s.extraPaddingForConditionsIfConfusingAlign);
250 m_ui->alignAssignments->setChecked(s.alignAssignments);
251 m_blockUpdates = wasBlocked;
252 if (preview)
253 updatePreview();
254 }
255
slotCurrentPreferencesChanged(ICodeStylePreferences * preferences,bool preview)256 void CppCodeStylePreferencesWidget::slotCurrentPreferencesChanged(ICodeStylePreferences *preferences, bool preview)
257 {
258 const bool enable = !preferences->isReadOnly() && !m_preferences->currentDelegate();
259 m_ui->tabSettingsWidget->setEnabled(enable);
260 m_ui->contentGroupBox->setEnabled(enable);
261 m_ui->bracesGroupBox->setEnabled(enable);
262 m_ui->switchGroupBox->setEnabled(enable);
263 m_ui->alignmentGroupBox->setEnabled(enable);
264 m_ui->pointerReferencesGroupBox->setEnabled(enable);
265 if (preview)
266 updatePreview();
267 }
268
slotCodeStyleSettingsChanged()269 void CppCodeStylePreferencesWidget::slotCodeStyleSettingsChanged()
270 {
271 if (m_blockUpdates)
272 return;
273
274 if (m_preferences) {
275 auto current = qobject_cast<CppCodeStylePreferences *>(m_preferences->currentPreferences());
276 if (current)
277 current->setCodeStyleSettings(cppCodeStyleSettings());
278 }
279
280 updatePreview();
281 }
282
slotTabSettingsChanged(const TabSettings & settings)283 void CppCodeStylePreferencesWidget::slotTabSettingsChanged(const TabSettings &settings)
284 {
285 if (m_blockUpdates)
286 return;
287
288 if (m_preferences) {
289 auto current = qobject_cast<CppCodeStylePreferences *>(m_preferences->currentPreferences());
290 if (current)
291 current->setTabSettings(settings);
292 }
293
294 updatePreview();
295 }
296
updatePreview()297 void CppCodeStylePreferencesWidget::updatePreview()
298 {
299 CppCodeStylePreferences *cppCodeStylePreferences = m_preferences
300 ? m_preferences
301 : CppToolsSettings::instance()->cppCodeStyle();
302 const CppCodeStyleSettings ccss = cppCodeStylePreferences->currentCodeStyleSettings();
303 const TabSettings ts = cppCodeStylePreferences->currentTabSettings();
304 QtStyleCodeFormatter formatter(ts, ccss);
305 foreach (SnippetEditorWidget *preview, m_previews) {
306 preview->textDocument()->setTabSettings(ts);
307 preview->setCodeStyle(cppCodeStylePreferences);
308
309 QTextDocument *doc = preview->document();
310 formatter.invalidateCache(doc);
311
312 QTextBlock block = doc->firstBlock();
313 QTextCursor tc = preview->textCursor();
314 tc.beginEditBlock();
315 while (block.isValid()) {
316 preview->textDocument()->indenter()->indentBlock(block, QChar::Null, ts);
317
318 block = block.next();
319 }
320 applyRefactorings(doc, preview, ccss);
321 tc.endEditBlock();
322 }
323 }
324
decorateEditors(const FontSettings & fontSettings)325 void CppCodeStylePreferencesWidget::decorateEditors(const FontSettings &fontSettings)
326 {
327 foreach (SnippetEditorWidget *editor, m_previews) {
328 editor->textDocument()->setFontSettings(fontSettings);
329 SnippetProvider::decorateEditor(editor, CppEditor::Constants::CPP_SNIPPETS_GROUP_ID);
330 }
331 }
332
setVisualizeWhitespace(bool on)333 void CppCodeStylePreferencesWidget::setVisualizeWhitespace(bool on)
334 {
335 foreach (SnippetEditorWidget *editor, m_previews) {
336 DisplaySettings displaySettings = editor->displaySettings();
337 displaySettings.m_visualizeWhitespace = on;
338 editor->setDisplaySettings(displaySettings);
339 }
340 }
341
342
343 // ------------------ CppCodeStyleSettingsPage
344
CppCodeStyleSettingsPage()345 CppCodeStyleSettingsPage::CppCodeStyleSettingsPage()
346 {
347 setId(Constants::CPP_CODE_STYLE_SETTINGS_ID);
348 setDisplayName(QCoreApplication::translate("CppTools", Constants::CPP_CODE_STYLE_SETTINGS_NAME));
349 setCategory(Constants::CPP_SETTINGS_CATEGORY);
350 }
351
widget()352 QWidget *CppCodeStyleSettingsPage::widget()
353 {
354 if (!m_widget) {
355 CppCodeStylePreferences *originalCodeStylePreferences = CppToolsSettings::instance()
356 ->cppCodeStyle();
357 m_pageCppCodeStylePreferences = new CppCodeStylePreferences();
358 m_pageCppCodeStylePreferences->setDelegatingPool(
359 originalCodeStylePreferences->delegatingPool());
360 m_pageCppCodeStylePreferences->setCodeStyleSettings(
361 originalCodeStylePreferences->codeStyleSettings());
362 m_pageCppCodeStylePreferences->setCurrentDelegate(
363 originalCodeStylePreferences->currentDelegate());
364 // we set id so that it won't be possible to set delegate to the original prefs
365 m_pageCppCodeStylePreferences->setId(originalCodeStylePreferences->id());
366 m_widget = TextEditorSettings::codeStyleFactory(CppTools::Constants::CPP_SETTINGS_ID)
367 ->createCodeStyleEditor(m_pageCppCodeStylePreferences);
368 }
369 return m_widget;
370 }
371
apply()372 void CppCodeStyleSettingsPage::apply()
373 {
374 if (m_widget) {
375 QSettings *s = Core::ICore::settings();
376
377 CppCodeStylePreferences *originalCppCodeStylePreferences = CppToolsSettings::instance()->cppCodeStyle();
378 if (originalCppCodeStylePreferences->codeStyleSettings() != m_pageCppCodeStylePreferences->codeStyleSettings()) {
379 originalCppCodeStylePreferences->setCodeStyleSettings(m_pageCppCodeStylePreferences->codeStyleSettings());
380 originalCppCodeStylePreferences->toSettings(QLatin1String(CppTools::Constants::CPP_SETTINGS_ID), s);
381 }
382 if (originalCppCodeStylePreferences->tabSettings() != m_pageCppCodeStylePreferences->tabSettings()) {
383 originalCppCodeStylePreferences->setTabSettings(m_pageCppCodeStylePreferences->tabSettings());
384 originalCppCodeStylePreferences->toSettings(QLatin1String(CppTools::Constants::CPP_SETTINGS_ID), s);
385 }
386 if (originalCppCodeStylePreferences->currentDelegate() != m_pageCppCodeStylePreferences->currentDelegate()) {
387 originalCppCodeStylePreferences->setCurrentDelegate(m_pageCppCodeStylePreferences->currentDelegate());
388 originalCppCodeStylePreferences->toSettings(QLatin1String(CppTools::Constants::CPP_SETTINGS_ID), s);
389 }
390
391 m_widget->apply();
392 }
393 }
394
finish()395 void CppCodeStyleSettingsPage::finish()
396 {
397 delete m_widget;
398 }
399
400 } // namespace Internal
401 } // namespace CppTools
402