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 "behaviorsettingswidget.h"
27 #include "ui_behaviorsettingswidget.h"
28
29 #include "tabsettingswidget.h"
30
31 #include <coreplugin/coreconstants.h>
32 #include <coreplugin/icore.h>
33
34 #include <texteditor/typingsettings.h>
35 #include <texteditor/storagesettings.h>
36 #include <texteditor/behaviorsettings.h>
37 #include <texteditor/extraencodingsettings.h>
38 #include <utils/algorithm.h>
39
40 #include <QList>
41 #include <QString>
42 #include <QByteArray>
43 #include <QTextCodec>
44 #include <QTextStream>
45
46 #include <functional>
47
48 namespace TextEditor {
49
50 struct BehaviorSettingsWidgetPrivate
51 {
52 Internal::Ui::BehaviorSettingsWidget m_ui;
53 QList<QTextCodec *> m_codecs;
54 };
55
BehaviorSettingsWidget(QWidget * parent)56 BehaviorSettingsWidget::BehaviorSettingsWidget(QWidget *parent)
57 : QWidget(parent)
58 , d(new BehaviorSettingsWidgetPrivate)
59 {
60 d->m_ui.setupUi(this);
61
62 QList<int> mibs = QTextCodec::availableMibs();
63 Utils::sort(mibs);
64 QList<int>::iterator firstNonNegative =
65 std::find_if(mibs.begin(), mibs.end(), [](int n) { return n >=0; });
66 if (firstNonNegative != mibs.end())
67 std::rotate(mibs.begin(), firstNonNegative, mibs.end());
68 foreach (int mib, mibs) {
69 if (QTextCodec *codec = QTextCodec::codecForMib(mib)) {
70 QString compoundName = QLatin1String(codec->name());
71 foreach (const QByteArray &alias, codec->aliases()) {
72 compoundName += QLatin1String(" / ");
73 compoundName += QString::fromLatin1(alias);
74 }
75 d->m_ui.encodingBox->addItem(compoundName);
76 d->m_codecs.append(codec);
77 }
78 }
79
80 // Qt5 doesn't list the system locale (QTBUG-34283), so add it manually
81 const QString system(QLatin1String("System"));
82 if (d->m_ui.encodingBox->findText(system) == -1) {
83 d->m_ui.encodingBox->insertItem(0, system);
84 d->m_codecs.prepend(QTextCodec::codecForLocale());
85 }
86
87 d->m_ui.defaultLineEndings->addItems(ExtraEncodingSettings::lineTerminationModeNames());
88
89 auto currentIndexChanged = QOverload<int>::of(&QComboBox::currentIndexChanged);
90 connect(d->m_ui.autoIndent, &QAbstractButton::toggled,
91 this, &BehaviorSettingsWidget::slotTypingSettingsChanged);
92 connect(d->m_ui.smartBackspaceBehavior, currentIndexChanged,
93 this, &BehaviorSettingsWidget::slotTypingSettingsChanged);
94 connect(d->m_ui.tabKeyBehavior, currentIndexChanged,
95 this, &BehaviorSettingsWidget::slotTypingSettingsChanged);
96 connect(d->m_ui.cleanWhitespace, &QAbstractButton::clicked,
97 this, &BehaviorSettingsWidget::slotStorageSettingsChanged);
98 connect(d->m_ui.inEntireDocument, &QAbstractButton::clicked,
99 this, &BehaviorSettingsWidget::slotStorageSettingsChanged);
100 connect(d->m_ui.addFinalNewLine, &QAbstractButton::clicked,
101 this, &BehaviorSettingsWidget::slotStorageSettingsChanged);
102 connect(d->m_ui.cleanIndentation, &QAbstractButton::clicked,
103 this, &BehaviorSettingsWidget::slotStorageSettingsChanged);
104 connect(d->m_ui.skipTrailingWhitespace, &QAbstractButton::clicked,
105 this, &BehaviorSettingsWidget::slotStorageSettingsChanged);
106 connect(d->m_ui.mouseHiding, &QAbstractButton::clicked,
107 this, &BehaviorSettingsWidget::slotBehaviorSettingsChanged);
108 connect(d->m_ui.mouseNavigation, &QAbstractButton::clicked,
109 this, &BehaviorSettingsWidget::slotBehaviorSettingsChanged);
110 connect(d->m_ui.scrollWheelZooming, &QAbstractButton::clicked,
111 this, &BehaviorSettingsWidget::slotBehaviorSettingsChanged);
112 connect(d->m_ui.camelCaseNavigation, &QAbstractButton::clicked,
113 this, &BehaviorSettingsWidget::slotBehaviorSettingsChanged);
114 connect(d->m_ui.utf8BomBox, currentIndexChanged,
115 this, &BehaviorSettingsWidget::slotExtraEncodingChanged);
116 connect(d->m_ui.encodingBox, currentIndexChanged,
117 this, &BehaviorSettingsWidget::slotEncodingBoxChanged);
118 connect(d->m_ui.constrainTooltipsBox, currentIndexChanged,
119 this, &BehaviorSettingsWidget::slotBehaviorSettingsChanged);
120 connect(d->m_ui.keyboardTooltips, &QAbstractButton::clicked,
121 this, &BehaviorSettingsWidget::slotBehaviorSettingsChanged);
122 connect(d->m_ui.smartSelectionChanging, &QAbstractButton::clicked,
123 this, &BehaviorSettingsWidget::slotBehaviorSettingsChanged);
124 }
125
~BehaviorSettingsWidget()126 BehaviorSettingsWidget::~BehaviorSettingsWidget()
127 {
128 delete d;
129 }
130
setActive(bool active)131 void BehaviorSettingsWidget::setActive(bool active)
132 {
133 d->m_ui.tabPreferencesWidget->setEnabled(active);
134 d->m_ui.groupBoxTyping->setEnabled(active);
135 d->m_ui.groupBoxEncodings->setEnabled(active);
136 d->m_ui.groupBoxMouse->setEnabled(active);
137 d->m_ui.groupBoxStorageSettings->setEnabled(active);
138 }
139
setAssignedCodec(QTextCodec * codec)140 void BehaviorSettingsWidget::setAssignedCodec(QTextCodec *codec)
141 {
142 const QString codecName = Core::ICore::settings()->value(
143 Core::Constants::SETTINGS_DEFAULTTEXTENCODING).toString();
144
145 int rememberedSystemPosition = -1;
146 for (int i = 0; i < d->m_codecs.size(); ++i) {
147 if (codec == d->m_codecs.at(i)) {
148 if (d->m_ui.encodingBox->itemText(i) == codecName) {
149 d->m_ui.encodingBox->setCurrentIndex(i);
150 return;
151 } else { // we've got System matching encoding - but have explicitly set the codec
152 rememberedSystemPosition = i;
153 }
154 }
155 }
156 if (rememberedSystemPosition != -1)
157 d->m_ui.encodingBox->setCurrentIndex(rememberedSystemPosition);
158 }
159
assignedCodecName() const160 QByteArray BehaviorSettingsWidget::assignedCodecName() const
161 {
162 return d->m_ui.encodingBox->currentIndex() == 0
163 ? QByteArray("System") // we prepend System to the available codecs
164 : d->m_codecs.at(d->m_ui.encodingBox->currentIndex())->name();
165
166 }
167
setCodeStyle(ICodeStylePreferences * preferences)168 void BehaviorSettingsWidget::setCodeStyle(ICodeStylePreferences *preferences)
169 {
170 d->m_ui.tabPreferencesWidget->setPreferences(preferences);
171 }
172
setAssignedTypingSettings(const TypingSettings & typingSettings)173 void BehaviorSettingsWidget::setAssignedTypingSettings(const TypingSettings &typingSettings)
174 {
175 d->m_ui.autoIndent->setChecked(typingSettings.m_autoIndent);
176 d->m_ui.smartBackspaceBehavior->setCurrentIndex(typingSettings.m_smartBackspaceBehavior);
177 d->m_ui.tabKeyBehavior->setCurrentIndex(typingSettings.m_tabKeyBehavior);
178
179 d->m_ui.preferSingleLineComments->setChecked(typingSettings.m_preferSingleLineComments);
180 }
181
assignedTypingSettings(TypingSettings * typingSettings) const182 void BehaviorSettingsWidget::assignedTypingSettings(TypingSettings *typingSettings) const
183 {
184 typingSettings->m_autoIndent = d->m_ui.autoIndent->isChecked();
185 typingSettings->m_smartBackspaceBehavior =
186 (TypingSettings::SmartBackspaceBehavior)(d->m_ui.smartBackspaceBehavior->currentIndex());
187 typingSettings->m_tabKeyBehavior =
188 (TypingSettings::TabKeyBehavior)(d->m_ui.tabKeyBehavior->currentIndex());
189
190 typingSettings->m_preferSingleLineComments = d->m_ui.preferSingleLineComments->isChecked();
191 }
192
setAssignedStorageSettings(const StorageSettings & storageSettings)193 void BehaviorSettingsWidget::setAssignedStorageSettings(const StorageSettings &storageSettings)
194 {
195 d->m_ui.cleanWhitespace->setChecked(storageSettings.m_cleanWhitespace);
196 d->m_ui.inEntireDocument->setChecked(storageSettings.m_inEntireDocument);
197 d->m_ui.cleanIndentation->setChecked(storageSettings.m_cleanIndentation);
198 d->m_ui.addFinalNewLine->setChecked(storageSettings.m_addFinalNewLine);
199 d->m_ui.skipTrailingWhitespace->setChecked(storageSettings.m_skipTrailingWhitespace);
200 d->m_ui.ignoreFileTypes->setText(storageSettings.m_ignoreFileTypes);
201 d->m_ui.ignoreFileTypes->setEnabled(d->m_ui.skipTrailingWhitespace->isChecked());
202 }
203
assignedStorageSettings(StorageSettings * storageSettings) const204 void BehaviorSettingsWidget::assignedStorageSettings(StorageSettings *storageSettings) const
205 {
206 storageSettings->m_cleanWhitespace = d->m_ui.cleanWhitespace->isChecked();
207 storageSettings->m_inEntireDocument = d->m_ui.inEntireDocument->isChecked();
208 storageSettings->m_cleanIndentation = d->m_ui.cleanIndentation->isChecked();
209 storageSettings->m_addFinalNewLine = d->m_ui.addFinalNewLine->isChecked();
210 storageSettings->m_skipTrailingWhitespace = d->m_ui.skipTrailingWhitespace->isChecked();
211 storageSettings->m_ignoreFileTypes = d->m_ui.ignoreFileTypes->text();
212 }
213
updateConstrainTooltipsBoxTooltip() const214 void BehaviorSettingsWidget::updateConstrainTooltipsBoxTooltip() const
215 {
216 if (d->m_ui.constrainTooltipsBox->currentIndex() == 0) {
217 d->m_ui.constrainTooltipsBox->setToolTip(
218 tr("Displays context-sensitive help or type information on mouseover."));
219 } else {
220 d->m_ui.constrainTooltipsBox->setToolTip(
221 tr("Displays context-sensitive help or type information on Shift+Mouseover."));
222 }
223 }
224
setAssignedBehaviorSettings(const BehaviorSettings & behaviorSettings)225 void BehaviorSettingsWidget::setAssignedBehaviorSettings(const BehaviorSettings &behaviorSettings)
226 {
227 d->m_ui.mouseHiding->setChecked(behaviorSettings.m_mouseHiding);
228 d->m_ui.mouseNavigation->setChecked(behaviorSettings.m_mouseNavigation);
229 d->m_ui.scrollWheelZooming->setChecked(behaviorSettings.m_scrollWheelZooming);
230 d->m_ui.constrainTooltipsBox->setCurrentIndex(behaviorSettings.m_constrainHoverTooltips ? 1 : 0);
231 d->m_ui.camelCaseNavigation->setChecked(behaviorSettings.m_camelCaseNavigation);
232 d->m_ui.keyboardTooltips->setChecked(behaviorSettings.m_keyboardTooltips);
233 d->m_ui.smartSelectionChanging->setChecked(behaviorSettings.m_smartSelectionChanging);
234 updateConstrainTooltipsBoxTooltip();
235 }
236
assignedBehaviorSettings(BehaviorSettings * behaviorSettings) const237 void BehaviorSettingsWidget::assignedBehaviorSettings(BehaviorSettings *behaviorSettings) const
238 {
239 behaviorSettings->m_mouseHiding = d->m_ui.mouseHiding->isChecked();
240 behaviorSettings->m_mouseNavigation = d->m_ui.mouseNavigation->isChecked();
241 behaviorSettings->m_scrollWheelZooming = d->m_ui.scrollWheelZooming->isChecked();
242 behaviorSettings->m_constrainHoverTooltips = (d->m_ui.constrainTooltipsBox->currentIndex() == 1);
243 behaviorSettings->m_camelCaseNavigation = d->m_ui.camelCaseNavigation->isChecked();
244 behaviorSettings->m_keyboardTooltips = d->m_ui.keyboardTooltips->isChecked();
245 behaviorSettings->m_smartSelectionChanging = d->m_ui.smartSelectionChanging->isChecked();
246 }
247
setAssignedExtraEncodingSettings(const ExtraEncodingSettings & encodingSettings)248 void BehaviorSettingsWidget::setAssignedExtraEncodingSettings(
249 const ExtraEncodingSettings &encodingSettings)
250 {
251 d->m_ui.utf8BomBox->setCurrentIndex(encodingSettings.m_utf8BomSetting);
252 }
253
assignedExtraEncodingSettings(ExtraEncodingSettings * encodingSettings) const254 void BehaviorSettingsWidget::assignedExtraEncodingSettings(
255 ExtraEncodingSettings *encodingSettings) const
256 {
257 encodingSettings->m_utf8BomSetting =
258 (ExtraEncodingSettings::Utf8BomSetting)d->m_ui.utf8BomBox->currentIndex();
259 }
260
setAssignedLineEnding(int lineEnding)261 void BehaviorSettingsWidget::setAssignedLineEnding(int lineEnding)
262 {
263 d->m_ui.defaultLineEndings->setCurrentIndex(lineEnding);
264 }
265
assignedLineEnding() const266 int BehaviorSettingsWidget::assignedLineEnding() const
267 {
268 return d->m_ui.defaultLineEndings->currentIndex();
269 }
270
tabSettingsWidget() const271 TabSettingsWidget *BehaviorSettingsWidget::tabSettingsWidget() const
272 {
273 return d->m_ui.tabPreferencesWidget->tabSettingsWidget();
274 }
275
slotTypingSettingsChanged()276 void BehaviorSettingsWidget::slotTypingSettingsChanged()
277 {
278 TypingSettings settings;
279 assignedTypingSettings(&settings);
280 emit typingSettingsChanged(settings);
281 }
282
slotStorageSettingsChanged()283 void BehaviorSettingsWidget::slotStorageSettingsChanged()
284 {
285 StorageSettings settings;
286 assignedStorageSettings(&settings);
287
288 bool ignoreFileTypesEnabled = d->m_ui.cleanWhitespace->isChecked() && d->m_ui.skipTrailingWhitespace->isChecked();
289 d->m_ui.ignoreFileTypes->setEnabled(ignoreFileTypesEnabled);
290
291 emit storageSettingsChanged(settings);
292 }
293
slotBehaviorSettingsChanged()294 void BehaviorSettingsWidget::slotBehaviorSettingsChanged()
295 {
296 BehaviorSettings settings;
297 assignedBehaviorSettings(&settings);
298 updateConstrainTooltipsBoxTooltip();
299 emit behaviorSettingsChanged(settings);
300 }
301
slotExtraEncodingChanged()302 void BehaviorSettingsWidget::slotExtraEncodingChanged()
303 {
304 ExtraEncodingSettings settings;
305 assignedExtraEncodingSettings(&settings);
306 emit extraEncodingSettingsChanged(settings);
307 }
308
slotEncodingBoxChanged(int index)309 void BehaviorSettingsWidget::slotEncodingBoxChanged(int index)
310 {
311 emit textCodecChanged(d->m_codecs.at(index));
312 }
313
314 } // TextEditor
315