From 3cd32effdd65ea9428bd5cc242d8a3bf4750d40d Mon Sep 17 00:00:00 2001 From: Takumi ASAKI <asaki@users.sourceforge.jp> Date: Thu, 28 Oct 2010 19:47:49 +0200 Subject: [PATCH] Support UTF-8 BOM in TextEditor TextEditor will now recognize an UTF-8 BOM. A setting to determine what to do on saving has been added as well - the options are "Always Add", "Keep Already Present" and (mostly for completeness) "Always Delete". Note: if encoding is "System", "Always Add" doesn't work, because there is no API to know what the System encoding is. Task-number: QTCREATORBUG-1857 Merge-request: 2180 Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@nokia.com> --- .../editormanager/editormanager.cpp | 19 +++++- .../coreplugin/editormanager/editormanager.h | 3 + src/plugins/coreplugin/generalsettings.ui | 40 +++++++++++ src/plugins/coreplugin/ifile.h | 6 ++ src/plugins/texteditor/basetextdocument.cpp | 11 ++++ src/plugins/texteditor/basetextdocument.h | 1 + .../texteditor/behaviorsettingspage.cpp | 5 ++ .../texteditor/behaviorsettingspage.ui | 66 +++++++++++++++++-- 8 files changed, 145 insertions(+), 6 deletions(-) diff --git a/src/plugins/coreplugin/editormanager/editormanager.cpp b/src/plugins/coreplugin/editormanager/editormanager.cpp index a6dc3114378..5589fe567fc 100644 --- a/src/plugins/coreplugin/editormanager/editormanager.cpp +++ b/src/plugins/coreplugin/editormanager/editormanager.cpp @@ -217,6 +217,7 @@ struct EditorManagerPrivate { QString m_externalEditor; IFile::ReloadSetting m_reloadSetting; + IFile::Utf8BomSetting m_utf8BomSetting; }; } @@ -237,7 +238,8 @@ EditorManagerPrivate::EditorManagerPrivate(ICore *core, QWidget *parent) : m_openInExternalEditorAction(new QAction(EditorManager::tr("Open in External Editor"), parent)), m_windowPopup(0), m_coreListener(0), - m_reloadSetting(IFile::AlwaysAsk) + m_reloadSetting(IFile::AlwaysAsk), + m_utf8BomSetting(IFile::OnlyKeep) { m_editorModel = new OpenEditorsModel(parent); } @@ -1792,6 +1794,7 @@ bool EditorManager::restoreState(const QByteArray &state) static const char * const documentStatesKey = "EditorManager/DocumentStates"; static const char * const externalEditorKey = "EditorManager/ExternalEditorCommand"; static const char * const reloadBehaviorKey = "EditorManager/ReloadBehavior"; +static const char * const utf8BomBehaviorKey = "EditorManager/Utf8BomBehavior"; void EditorManager::saveSettings() { @@ -1799,6 +1802,7 @@ void EditorManager::saveSettings() settings->setValue(QLatin1String(documentStatesKey), m_d->m_editorStates); settings->setValue(QLatin1String(externalEditorKey), m_d->m_externalEditor); settings->setValue(QLatin1String(reloadBehaviorKey), m_d->m_reloadSetting); + settings->setValue(QLatin1String(utf8BomBehaviorKey), m_d->m_utf8BomSetting); } void EditorManager::readSettings() @@ -1824,6 +1828,9 @@ 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(); } @@ -1991,6 +1998,16 @@ 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 { QSettings *settings = Core::ICore::instance()->settings(); diff --git a/src/plugins/coreplugin/editormanager/editormanager.h b/src/plugins/coreplugin/editormanager/editormanager.h index caab7f0f6cd..6b55561dc68 100644 --- a/src/plugins/coreplugin/editormanager/editormanager.h +++ b/src/plugins/coreplugin/editormanager/editormanager.h @@ -192,6 +192,9 @@ public: void setReloadSetting(IFile::ReloadSetting behavior); IFile::ReloadSetting reloadSetting() const; + void setUtf8BomSetting(IFile::Utf8BomSetting behavior); + IFile::Utf8BomSetting utf8BomSetting() const; + QTextCodec *defaultTextEncoding() const; // Helper to display a message dialog when encountering a read-only diff --git a/src/plugins/coreplugin/generalsettings.ui b/src/plugins/coreplugin/generalsettings.ui index 6e4f9f9384a..a44dfdef5a3 100644 --- a/src/plugins/coreplugin/generalsettings.ui +++ b/src/plugins/coreplugin/generalsettings.ui @@ -104,6 +104,46 @@ </item> </layout> </item> + <item row="3" column="0"> + <widget class="QLabel" name="encodingLabel"> + <property name="text"> + <string>Default file encoding: </string> + </property> + </widget> + </item> + <item row="3" column="1"> + <layout class="QHBoxLayout" name="horizontalLayout_6"> + <item> + <widget class="QComboBox" name="encodingBox"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="sizeAdjustPolicy"> + <enum>QComboBox::AdjustToMinimumContentsLengthWithIcon</enum> + </property> + <property name="minimumContentsLength"> + <number>20</number> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_6"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>285</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> <item row="2" column="0"> <widget class="QLabel" name="languageLabel"> <property name="text"> diff --git a/src/plugins/coreplugin/ifile.h b/src/plugins/coreplugin/ifile.h index 6042ee51994..7bb2924ede7 100644 --- a/src/plugins/coreplugin/ifile.h +++ b/src/plugins/coreplugin/ifile.h @@ -50,6 +50,12 @@ public: IgnoreAll = 2 }; + enum Utf8BomSetting { + AlwaysAdd = 0, + OnlyKeep = 1, + AlwaysDelete = 2 + }; + enum ChangeTrigger { TriggerInternal, TriggerExternal diff --git a/src/plugins/texteditor/basetextdocument.cpp b/src/plugins/texteditor/basetextdocument.cpp index e52a38899c0..f8463fef7ef 100644 --- a/src/plugins/texteditor/basetextdocument.cpp +++ b/src/plugins/texteditor/basetextdocument.cpp @@ -133,6 +133,7 @@ BaseTextDocument::BaseTextDocument() m_fileIsReadOnly = false; m_isBinaryData = false; m_codec = Core::EditorManager::instance()->defaultTextEncoding(); + m_fileHasUtf8Bom = false; m_hasDecodingError = false; } @@ -187,6 +188,12 @@ bool BaseTextDocument::save(const QString &fileName) if (m_lineTerminatorMode == CRLFLineTerminator) plainText.replace(QLatin1Char('\n'), QLatin1String("\r\n")); + Core::IFile::Utf8BomSetting utf8bomSetting = Core::EditorManager::instance()->utf8BomSetting(); + if (m_codec->name() == "UTF-8" && + (utf8bomSetting == Core::IFile::AlwaysAdd || (utf8bomSetting == Core::IFile::OnlyKeep && m_fileHasUtf8Bom))) { + file.write("\xef\xbb\xbf", 3); + } + file.write(m_codec->fromUnicode(plainText)); if (!file.flush()) return false; @@ -259,6 +266,7 @@ bool BaseTextDocument::open(const QString &fileName) int bytesRead = buf.size(); QTextCodec *codec = m_codec; + m_fileHasUtf8Bom = false; // code taken from qtextstream if (bytesRead >= 4 && ((uchar(buf[0]) == 0xff && uchar(buf[1]) == 0xfe && uchar(buf[2]) == 0 && uchar(buf[3]) == 0) @@ -267,6 +275,9 @@ bool BaseTextDocument::open(const QString &fileName) } else if (bytesRead >= 2 && ((uchar(buf[0]) == 0xff && uchar(buf[1]) == 0xfe) || (uchar(buf[0]) == 0xfe && uchar(buf[1]) == 0xff))) { codec = QTextCodec::codecForName("UTF-16"); + } else if (bytesRead >= 3 && ((uchar(buf[0]) == 0xef && uchar(buf[1]) == 0xbb) && uchar(buf[2]) == 0xbf)) { + codec = QTextCodec::codecForName("UTF-8"); + m_fileHasUtf8Bom = true; } else if (!codec) { codec = QTextCodec::codecForLocale(); } diff --git a/src/plugins/texteditor/basetextdocument.h b/src/plugins/texteditor/basetextdocument.h index cd503276b33..dd9f93f5233 100644 --- a/src/plugins/texteditor/basetextdocument.h +++ b/src/plugins/texteditor/basetextdocument.h @@ -142,6 +142,7 @@ private: }; LineTerminatorMode m_lineTerminatorMode; QTextCodec *m_codec; + bool m_fileHasUtf8Bom; bool m_fileIsReadOnly; bool m_isBinaryData; diff --git a/src/plugins/texteditor/behaviorsettingspage.cpp b/src/plugins/texteditor/behaviorsettingspage.cpp index fdf5c8e2eeb..2176dc6dba5 100644 --- a/src/plugins/texteditor/behaviorsettingspage.cpp +++ b/src/plugins/texteditor/behaviorsettingspage.cpp @@ -36,6 +36,7 @@ #include <coreplugin/icore.h> #include <coreplugin/coreconstants.h> +#include <coreplugin/editormanager/editormanager.h> #include <QtCore/QSettings> #include <QtCore/QTextCodec> @@ -135,6 +136,8 @@ QWidget *BehaviorSettingsPage::createPage(QWidget *parent) m_d->m_page.encodingBox->setCurrentIndex(i); } + m_d->m_page.utf8BomBox->setCurrentIndex(Core::EditorManager::instance()->utf8BomSetting()); + return w; } @@ -177,6 +180,8 @@ void BehaviorSettingsPage::apply() settings->setValue(QLatin1String(Core::Constants::SETTINGS_DEFAULTTEXTENCODING), m_codecs.at(m_d->m_page.encodingBox->currentIndex())->name()); + Core::EditorManager::instance()->setUtf8BomSetting( + Core::IFile::Utf8BomSetting(m_d->m_page.utf8BomBox->currentIndex())); } void BehaviorSettingsPage::settingsFromUI(TabSettings &tabSettings, diff --git a/src/plugins/texteditor/behaviorsettingspage.ui b/src/plugins/texteditor/behaviorsettingspage.ui index 4aa89f81d6e..f0a21f0e406 100644 --- a/src/plugins/texteditor/behaviorsettingspage.ui +++ b/src/plugins/texteditor/behaviorsettingspage.ui @@ -6,7 +6,7 @@ <rect> <x>0</x> <y>0</y> - <width>576</width> + <width>662</width> <height>538</height> </rect> </property> @@ -442,6 +442,13 @@ Influences the indentation of continuation lines. <string>File Encodings</string> </property> <layout class="QGridLayout" name="gridLayout_4"> + <item row="0" column="0"> + <widget class="QLabel" name="encodingLabel"> + <property name="text"> + <string>Default encoding: </string> + </property> + </widget> + </item> <item row="0" column="1"> <layout class="QHBoxLayout" name="horizontalLayout_6"> <item> @@ -475,14 +482,63 @@ Influences the indentation of continuation lines. </item> </layout> </item> - <item row="0" column="0"> - <widget class="QLabel" name="encodingLabel"> + <item row="1" column="0"> + <widget class="QLabel" name="utf8BomLabel"> <property name="text"> - <string>Default encoding: </string> + <string>UTF-8 BOM:</string> </property> </widget> </item> - <item row="1" column="0" colspan="2"> + <item row="1" column="1"> + <layout class="QHBoxLayout" name="horizontalLayout_4"> + <item> + <widget class="QComboBox" name="utf8BomBox"> + <property name="toolTip"> + <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:10pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">How text editors should deal with UTF-8 Byte Order Marks. The options are:</p> +<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-style:italic;">Add If Encoding Is UTF-8:</span> always add a BOM when saving a file in UTF-8 encoding. Note that this will not work if the encoding is <span style=" font-style:italic;">System</span>, as Qt Creator does not know what it actually is.</li> +<li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-style:italic;">Keep If Already Present: </span>save the file with a BOM if it already had one when it was loaded.</li> +<li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-style:italic;">Always Delete:</span> never write an UTF-8 BOM, possibly deleting a pre-existing one.</li></ul> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Note that UTF-8 BOMs are uncommon and treated incorrectly by some editors, so it usually makes little sense to add any.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This setting does <span style=" font-weight:600;">not</span> influence the use of UTF-16 and UTF-32 BOMs.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p></body></html></string> + </property> + <item> + <property name="text"> + <string>Add If Encoding Is UTF-8</string> + </property> + </item> + <item> + <property name="text"> + <string>Keep If Already Present</string> + </property> + </item> + <item> + <property name="text"> + <string>Always Delete</string> + </property> + </item> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_4"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item row="2" column="0" colspan="2"> <spacer name="verticalSpacer_2"> <property name="orientation"> <enum>Qt::Vertical</enum> -- GitLab