Commit ea313f3e authored by Leandro Melo's avatar Leandro Melo

Text editor: Introduce per project settings

With some refactorings to make the code look better.

Reviewed-by: con
parent cbafc50a
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/
#ifndef SETTINGSUTILS_H
#define SETTINGSUTILS_H
#include <QtCore/QString>
#include <QtCore/QLatin1String>
#include <QtCore/QSettings>
#include <QtCore/QVariant>
namespace Utils {
template <class SettingsClassT>
void fromSettings(const QString &postFix,
const QString &category,
const QSettings *s,
SettingsClassT *obj)
{
QVariantMap map;
const QStringList &keys = s->allKeys();
foreach (const QString &key, keys)
map.insert(key, s->value(key));
QString group = postFix;
if (!category.isEmpty())
group.insert(0, category);
group += QLatin1Char('/');
obj->fromMap(group, map);
}
template <class SettingsClassT>
void toSettings(const QString &postFix,
const QString &category,
QSettings *s,
const SettingsClassT *obj)
{
QString group = postFix;
if (!category.isEmpty())
group.insert(0, category);
group += QLatin1Char('/');
QVariantMap map;
obj->toMap(group, &map);
QVariantMap::const_iterator it = map.constBegin();
for (; it != map.constEnd(); ++it)
s->setValue(it.key(), it.value());
}
} // Utils
#endif // SETTINGSUTILS_H
......@@ -167,7 +167,8 @@ HEADERS += $$PWD/environment.h \
$$PWD/ssh/sftpdefs.h \
$$PWD/ssh/sftpchannel.h \
$$PWD/ssh/sftpchannel_p.h \
$$PWD/ssh/sshremoteprocessrunner.h
$$PWD/ssh/sshremoteprocessrunner.h \
$$PWD/settingsutils.h
FORMS += $$PWD/filewizardpage.ui \
$$PWD/projectintropage.ui \
......
......@@ -220,7 +220,6 @@ struct EditorManagerPrivate {
OpenEditorsModel *m_editorModel;
IFile::ReloadSetting m_reloadSetting;
IFile::Utf8BomSetting m_utf8BomSetting;
QString m_titleAddition;
};
......@@ -242,8 +241,7 @@ EditorManagerPrivate::EditorManagerPrivate(ICore *core, QWidget *parent) :
m_goForwardAction(new QAction(QIcon(QLatin1String(Constants::ICON_NEXT)), EditorManager::tr("Go Forward"), parent)),
m_windowPopup(0),
m_coreListener(0),
m_reloadSetting(IFile::AlwaysAsk),
m_utf8BomSetting(IFile::OnlyKeep)
m_reloadSetting(IFile::AlwaysAsk)
{
m_editorModel = new OpenEditorsModel(parent);
}
......@@ -1803,14 +1801,12 @@ bool EditorManager::restoreState(const QByteArray &state)
static const char * const documentStatesKey = "EditorManager/DocumentStates";
static const char * const reloadBehaviorKey = "EditorManager/ReloadBehavior";
static const char * const utf8BomBehaviorKey = "EditorManager/Utf8BomBehavior";
void EditorManager::saveSettings()
{
SettingsDatabase *settings = m_d->m_core->settingsDatabase();
settings->setValue(QLatin1String(documentStatesKey), m_d->m_editorStates);
settings->setValue(QLatin1String(reloadBehaviorKey), m_d->m_reloadSetting);
settings->setValue(QLatin1String(utf8BomBehaviorKey), m_d->m_utf8BomSetting);
}
void EditorManager::readSettings()
......@@ -1830,9 +1826,6 @@ void EditorManager::readSettings()
if (settings->contains(QLatin1String(reloadBehaviorKey)))
m_d->m_reloadSetting = (IFile::ReloadSetting)settings->value(QLatin1String(reloadBehaviorKey)).toInt();
if (settings->contains(QLatin1String(utf8BomBehaviorKey)))
m_d->m_utf8BomSetting = (IFile::Utf8BomSetting)settings->value(QLatin1String(utf8BomBehaviorKey)).toInt();
}
......@@ -1900,17 +1893,7 @@ IFile::ReloadSetting EditorManager::reloadSetting() const
return m_d->m_reloadSetting;
}
void EditorManager::setUtf8BomSetting(IFile::Utf8BomSetting behavior)
{
m_d->m_utf8BomSetting = behavior;
}
IFile::Utf8BomSetting EditorManager::utf8BomSetting() const
{
return m_d->m_utf8BomSetting;
}
QTextCodec *EditorManager::defaultTextEncoding() const
QTextCodec *EditorManager::defaultTextCodec() const
{
QSettings *settings = Core::ICore::instance()->settings();
if (QTextCodec *candidate = QTextCodec::codecForName(
......
......@@ -187,10 +187,7 @@ public:
void setReloadSetting(IFile::ReloadSetting behavior);
IFile::ReloadSetting reloadSetting() const;
void setUtf8BomSetting(IFile::Utf8BomSetting behavior);
IFile::Utf8BomSetting utf8BomSetting() const;
QTextCodec *defaultTextEncoding() const;
QTextCodec *defaultTextCodec() const;
static qint64 maxTextFileSize();
......
......@@ -214,7 +214,7 @@ QString CppFileSettings::licenseTemplate(const QString &fileName, const QString
return QString();
}
QTextCodec *codec = Core::EditorManager::instance()->defaultTextEncoding();
QTextCodec *codec = Core::EditorManager::instance()->defaultTextCodec();
QTextStream licenseStream(&file);
licenseStream.setCodec(codec);
licenseStream.setAutoDetectUnicode(true);
......
......@@ -39,6 +39,7 @@
#include <cpptools/cppmodelmanager.h>
#include <texteditor/texteditorsettings.h>
#include <texteditor/tabsettings.h>
#include <projectexplorer/editorconfiguration.h>
#include <QtGui/QTextBlock>
......@@ -64,7 +65,9 @@ CppRefactoringFile CppRefactoringChanges::file(const QString &fileName)
return CppRefactoringFile(fileName, this);
}
void CppRefactoringChanges::indentSelection(const QTextCursor &selection) const
void CppRefactoringChanges::indentSelection(const QTextCursor &selection,
const QString &fileName,
const TextEditor::BaseTextEditor *textEditor) const
{
// ### shares code with CPPEditor::indent()
QTextDocument *doc = selection.document();
......@@ -72,7 +75,8 @@ void CppRefactoringChanges::indentSelection(const QTextCursor &selection) const
QTextBlock block = doc->findBlock(selection.selectionStart());
const QTextBlock end = doc->findBlock(selection.selectionEnd()).next();
const TextEditor::TabSettings &tabSettings(TextEditor::TextEditorSettings::instance()->tabSettings());
const TextEditor::TabSettings &tabSettings =
ProjectExplorer::actualTabSettings(fileName, textEditor);
CppTools::QtStyleCodeFormatter codeFormatter(tabSettings);
codeFormatter.updateStateUntil(block);
......
......@@ -92,7 +92,9 @@ public:
CppRefactoringFile file(const QString &fileName);
private:
virtual void indentSelection(const QTextCursor &selection) const;
virtual void indentSelection(const QTextCursor &selection,
const QString &fileName,
const TextEditor::BaseTextEditor *textEditor) const;
virtual void fileChanged(const QString &fileName);
private:
......
......@@ -1169,9 +1169,12 @@ void FakeVimPluginPrivate::setUseFakeVim(const QVariant &value)
//core->updateAdditionalContexts(Core::Context(),
// Core::Context(FAKEVIM_CONTEXT));
showCommandBuffer(QString());
TabSettings ts = TextEditorSettings::instance()->tabSettings();
foreach (Core::IEditor *editor, m_editorToHandler.keys())
m_editorToHandler[editor]->restoreWidget(ts.m_tabSize);
foreach (Core::IEditor *editor, m_editorToHandler.keys()) {
if (TextEditor::BaseTextEditor *textEditor =
qobject_cast<TextEditor::BaseTextEditor *>(editor->widget())) {
m_editorToHandler[editor]->restoreWidget(textEditor->tabSettings().m_tabSize);
}
}
}
}
......
......@@ -111,9 +111,7 @@ Utils::FileIterator *AllProjectsFind::files() const
foreach (const QString &fileName, filteredFiles) {
QTextCodec *codec = openEditorEncodings.value(fileName);
if (!codec)
codec = project->editorConfiguration()->defaultTextCodec();
if (!codec)
codec = Core::EditorManager::instance()->defaultTextEncoding();
codec = project->editorConfiguration()->textCodec();
encodings.insert(fileName, codec);
}
}
......
......@@ -36,30 +36,99 @@
#include "projectexplorer_export.h"
#include <QtCore/QObject>
#include <QtCore/QVariantMap>
#include <QtCore/QScopedPointer>
QT_BEGIN_NAMESPACE
class QTextCodec;
QT_END_NAMESPACE
namespace TextEditor {
class ITextEditor;
class BaseTextEditor;
class TabSettings;
class StorageSettings;
class BehaviorSettings;
class ExtraEncodingSettings;
}
namespace ProjectExplorer {
class PROJECTEXPLORER_EXPORT EditorConfiguration
struct EditorConfigurationPrivate;
class PROJECTEXPLORER_EXPORT EditorConfiguration : public QObject
{
Q_OBJECT
public:
EditorConfiguration();
~EditorConfiguration();
bool useGlobalSettings() const;
void cloneGlobalSettings();
// The default codec is returned in the case the project doesn't override it.
QTextCodec *textCodec() const;
// defaultTextCodec can be 0, in that case the editor settings default encoding shall be used
QTextCodec *defaultTextCodec() const;
void setDefaultTextCodec(QTextCodec *codec);
const TextEditor::TabSettings &tabSettings() const;
const TextEditor::StorageSettings &storageSettings() const;
const TextEditor::BehaviorSettings &behaviorSettings() const;
const TextEditor::ExtraEncodingSettings &extraEncodingSettings() const;
void apply(TextEditor::ITextEditor *textEditor) const;
QVariantMap toMap() const;
void fromMap(const QVariantMap &map);
signals:
void tabSettingsChanged(const TextEditor::TabSettings &);
void storageSettingsChanged(const TextEditor::StorageSettings &);
void behaviorSettingsChanged(const TextEditor::BehaviorSettings &);
void extraEncodingSettingsChanged(const TextEditor::ExtraEncodingSettings &);
private slots:
void setUseGlobalSettings(bool use);
void setInsertSpaces(bool spaces);
void setAutoInsertSpaces(bool autoSpaces);
void setAutoIndent(bool autoIndent);
void setSmartBackSpace(bool smartBackSpace);
void setTabSize(int size);
void setIndentSize(int size);
void setIndentBlocksBehavior(int index);
void setTabKeyBehavior(int index);
void setContinuationAlignBehavior(int index);
void setCleanWhiteSpace(bool cleanWhiteSpace);
void setInEntireDocument(bool entireDocument);
void setAddFinalNewLine(bool newLine);
void setCleanIndentation(bool cleanIndentation);
void setMouseNavigation(bool mouseNavigation);
void setScrollWheelZooming(bool scrollZooming);
void setUtf8BomSettings(int index);
void setTextCodec(QTextCodec *textCodec);
private:
QTextCodec *m_defaultTextCodec;
void switchSettings(TextEditor::BaseTextEditor *baseTextEditor) const;
template <class NewSenderT, class OldSenderT>
void switchSettings_helper(const NewSenderT *newSender,
const OldSenderT *oldSender,
TextEditor::BaseTextEditor *baseTextEditor) const;
void emitTabSettingsChanged();
void emitStorageSettingsChanged();
void emitBehaviorSettingsChanged();
void emitExtraEncodingSettingsChanged();
QScopedPointer<EditorConfigurationPrivate> m_d;
};
// Return the editor settings in the case it's not null. Otherwise, try to find the project
// the file belongs to and return the project settings. If the file doesn't belong to any
// project return the global settings.
PROJECTEXPLORER_EXPORT const TextEditor::TabSettings &actualTabSettings(
const QString &fileName, const TextEditor::BaseTextEditor *baseTextEditor);
} // ProjectExplorer
#endif // EDITORCONFIGURATION_H
......@@ -36,7 +36,6 @@
#include "project.h"
#include <QtCore/QTextCodec>
#include <QtCore/QDebug>
using namespace ProjectExplorer;
using namespace ProjectExplorer::Internal;
......@@ -88,48 +87,75 @@ QIcon EditorSettingsPanel::icon() const
return m_icon;
}
EditorSettingsWidget::EditorSettingsWidget(Project *project)
: QWidget(),
m_project(project)
EditorSettingsWidget::EditorSettingsWidget(Project *project) : QWidget(), m_project(project)
{
m_ui.setupUi(this);
QTextCodec *defaultTextCodec = 0;
m_codecs += defaultTextCodec;
m_ui.encodingComboBox->addItem(tr("Default"));
defaultTextCodec = m_project->editorConfiguration()->defaultTextCodec();
QList<int> mibs = QTextCodec::availableMibs();
qSort(mibs);
QList<int> sortedMibs;
foreach (int mib, mibs)
if (mib >= 0)
sortedMibs += mib;
foreach (int mib, mibs)
if (mib < 0)
sortedMibs += mib;
int i = 1; // 0 is the default
foreach (int mib, sortedMibs) {
QTextCodec *codec = QTextCodec::codecForMib(mib);
m_codecs += codec;
QString name = codec->name();
foreach (const QByteArray &alias, codec->aliases()) {
name += QLatin1String(" / ");
name += QString::fromLatin1(alias);
}
m_ui.encodingComboBox->addItem(name);
if (defaultTextCodec == codec)
m_ui.encodingComboBox->setCurrentIndex(i);
i++;
}
connect(m_ui.encodingComboBox, SIGNAL(currentIndexChanged(int)),
this, SLOT(currentEncodingChanged(int)));
const EditorConfiguration *config = m_project->editorConfiguration();
settingsToUi(config);
setGlobalSettingsEnabled(config->useGlobalSettings());
connect(m_ui.useGlobalCheckBox, SIGNAL(clicked(bool)),
this, SLOT(setGlobalSettingsEnabled(bool)));
connect(m_ui.useGlobalCheckBox, SIGNAL(clicked(bool)),
config, SLOT(setUseGlobalSettings(bool)));
connect(m_ui.restoreButton, SIGNAL(clicked()), this, SLOT(restoreDefaultValues()));
connect(m_ui.behaviorSettingsWidget, SIGNAL(insertSpacesChanged(bool)),
config, SLOT(setInsertSpaces(bool)));
connect(m_ui.behaviorSettingsWidget, SIGNAL(autoInsertSpacesChanged(bool)),
config, SLOT(setAutoInsertSpaces(bool)));
connect(m_ui.behaviorSettingsWidget, SIGNAL(autoIndentChanged(bool)),
config, SLOT(setAutoIndent(bool)));
connect(m_ui.behaviorSettingsWidget, SIGNAL(smartBackSpaceChanged(bool)),
config, SLOT(setSmartBackSpace(bool)));
connect(m_ui.behaviorSettingsWidget, SIGNAL(tabSizeChanged(int)),
config, SLOT(setTabSize(int)));
connect(m_ui.behaviorSettingsWidget, SIGNAL(indentSizeChanged(int)),
config, SLOT(setIndentSize(int)));
connect(m_ui.behaviorSettingsWidget, SIGNAL(indentBlocksBehaviorChanged(int)),
config, SLOT(setIndentBlocksBehavior(int)));
connect(m_ui.behaviorSettingsWidget, SIGNAL(tabKeyBehaviorChanged(int)),
config, SLOT(setTabKeyBehavior(int)));
connect(m_ui.behaviorSettingsWidget, SIGNAL(continuationAlignBehaviorChanged(int)),
config, SLOT(setContinuationAlignBehavior(int)));
connect(m_ui.behaviorSettingsWidget, SIGNAL(cleanWhiteSpaceChanged(bool)),
config, SLOT(setCleanWhiteSpace(bool)));
connect(m_ui.behaviorSettingsWidget, SIGNAL(inEntireDocumentChanged(bool)),
config, SLOT(setInEntireDocument(bool)));
connect(m_ui.behaviorSettingsWidget, SIGNAL(addFinalNewLineChanged(bool)),
config, SLOT(setAddFinalNewLine(bool)));
connect(m_ui.behaviorSettingsWidget, SIGNAL(cleanIndentationChanged(bool)),
config, SLOT(setCleanIndentation(bool)));
connect(m_ui.behaviorSettingsWidget, SIGNAL(mouseNavigationChanged(bool)),
config, SLOT(setMouseNavigation(bool)));
connect(m_ui.behaviorSettingsWidget, SIGNAL(scrollWheelZoomingChanged(bool)),
config, SLOT(setScrollWheelZooming(bool)));
connect(m_ui.behaviorSettingsWidget, SIGNAL(utf8BomSettingsChanged(int)),
config, SLOT(setUtf8BomSettings(int)));
connect(m_ui.behaviorSettingsWidget, SIGNAL(textCodecChanged(QTextCodec*)),
config, SLOT(setTextCodec(QTextCodec*)));
}
void EditorSettingsWidget::currentEncodingChanged(int index)
void EditorSettingsWidget::settingsToUi(const EditorConfiguration *config)
{
m_project->editorConfiguration()->setDefaultTextCodec(m_codecs.at(index));
m_ui.useGlobalCheckBox->setChecked(config->useGlobalSettings());
m_ui.behaviorSettingsWidget->setAssignedCodec(config->textCodec());
m_ui.behaviorSettingsWidget->setAssignedTabSettings(config->tabSettings());
m_ui.behaviorSettingsWidget->setAssignedStorageSettings(config->storageSettings());
m_ui.behaviorSettingsWidget->setAssignedBehaviorSettings(config->behaviorSettings());
m_ui.behaviorSettingsWidget->setAssignedExtraEncodingSettings(config->extraEncodingSettings());
}
void EditorSettingsWidget::setGlobalSettingsEnabled(bool enabled)
{
m_ui.behaviorSettingsWidget->setActive(!enabled);
m_ui.restoreButton->setEnabled(!enabled);
}
void EditorSettingsWidget::restoreDefaultValues()
{
EditorConfiguration *config = m_project->editorConfiguration();
config->cloneGlobalSettings();
settingsToUi(config);
}
......@@ -39,6 +39,8 @@
namespace ProjectExplorer {
class EditorConfiguration;
namespace Internal {
const char * const EDITORSETTINGS_PANEL_ID("ProjectExplorer.EditorSettingsPanel");
......@@ -75,12 +77,14 @@ public:
EditorSettingsWidget(Project *project);
private slots:
void currentEncodingChanged(int index);
void setGlobalSettingsEnabled(bool enabled);
void restoreDefaultValues();
private:
void settingsToUi(const EditorConfiguration *config);
Ui::EditorSettingsPropertiesPage m_ui;
Project *m_project;
QList<QTextCodec *> m_codecs;
};
} // namespace Internal
......
......@@ -6,29 +6,64 @@
<rect>
<x>0</x>
<y>0</y>
<width>275</width>
<height>44</height>
<width>368</width>
<height>98</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="encodingLabel">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" colspan="2">
<widget class="QCheckBox" name="useGlobalCheckBox">
<property name="text">
<string>Default file encoding:</string>
<string>Use global settings</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="encodingComboBox"/>
<item row="1" column="0" colspan="3">
<widget class="TextEditor::BehaviorSettingsWidget" name="behaviorSettingsWidget" native="true"/>
</item>
<item row="2" column="0" colspan="2">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>224</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="3" column="1">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>12</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="2">
<widget class="QPushButton" name="restoreButton">
<property name="text">
<string>Restore Global Values</string>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>TextEditor::BehaviorSettingsWidget</class>
<extends>QWidget</extends>
<header>texteditor/behaviorsettingswidget.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
......@@ -321,7 +321,7 @@ SessionManager::SessionManager(QObject *parent)
Core::EditorManager *em = m_core->editorManager();
connect(em, SIGNAL(editorCreated(Core::IEditor *, QString)),
this, SLOT(setEditorCodec(Core::IEditor *, QString)));
this, SLOT(configureEditor(Core::IEditor *, QString)));
connect(ProjectExplorerPlugin::instance(), SIGNAL(currentProjectChanged(ProjectExplorer::Project *)),
this, SLOT(updateWindowTitle()));
connect(em, SIGNAL(editorOpened(Core::IEditor*)),
......@@ -823,13 +823,15 @@ bool SessionManager::projectContainsFile(Project *p, const QString &fileName) co
return m_projectFileCache.value(p).contains(fileName);
}
void SessionManager::setEditorCodec(Core::IEditor *editor, const QString &fileName)
void SessionManager::configureEditor(Core::IEditor *editor, const QString &fileName)
{
if (TextEditor::ITextEditor *textEditor = qobject_cast<TextEditor::ITextEditor*>(editor))
if (Project *project = projectForFile(fileName)) {
if (QTextCodec *codec = project->editorConfiguration()->defaultTextCodec())
textEditor->setTextCodec(codec, TextEditor::ITextEditor::TextCodecFromProjectSetting);
if (TextEditor::ITextEditor *textEditor = qobject_cast<TextEditor::ITextEditor*>(editor)) {
Project *project = projectForFile(fileName);
// Global settings are the default.
if (project && !project->editorConfiguration()->useGlobalSettings()) {
project->editorConfiguration()->apply(textEditor);
}