diff --git a/src/core/core/settings.json b/src/core/core/settings.json index 8d1b8974..464f67d5 100644 --- a/src/core/core/settings.json +++ b/src/core/core/settings.json @@ -63,7 +63,8 @@ "tab": { "insertSpaces": true, "tabSize": 4 - } + }, + "encoding": "utf8" }, "toggle_section": { "tag": "KDAB_TEMPORARILY_REMOVED", diff --git a/src/core/knutcore.cpp b/src/core/knutcore.cpp index 62e41517..fb3c74f5 100644 --- a/src/core/knutcore.cpp +++ b/src/core/knutcore.cpp @@ -34,6 +34,13 @@ KnutCore::KnutCore(QObject *parent) initialize(Settings::Mode::Test); } +KnutCore::~KnutCore() +{ + delete m_scriptManager; + delete m_project; + delete m_settings; +} + KnutCore::KnutCore(InternalTag, QObject *parent) : QObject(parent) { @@ -188,10 +195,10 @@ void KnutCore::initialize(Settings::Mode mode) // If creating a KnutCore and then processing command line arguments if (m_initialized) return; - new Settings(mode, this); - new Project(this); - new ScriptManager(this); - if (Core::Settings::instance()->value(Core::Settings::SaveLogsToFile)) + m_settings = new Settings(mode, this); + m_project = new Project(this); + m_scriptManager = new ScriptManager(this); + if (DEFAULT_VALUE(bool, SaveLogsToFile)) initializeMultiSinkLogger(); // auto flush when "info" or higher message is logged. spdlog::flush_on(spdlog::level::info); diff --git a/src/core/knutcore.h b/src/core/knutcore.h index aad7eef6..6549936c 100644 --- a/src/core/knutcore.h +++ b/src/core/knutcore.h @@ -17,12 +17,17 @@ namespace Core { +class Settings; +class Project; +class ScriptManager; + class KnutCore : public QObject { Q_OBJECT public: explicit KnutCore(QObject *parent = nullptr); + ~KnutCore() override; bool process(const QStringList &arguments); @@ -41,6 +46,10 @@ class KnutCore : public QObject void initializeMultiSinkLogger(); bool m_initialized = false; + + Settings *m_settings = nullptr; + Project *m_project = nullptr; + ScriptManager *m_scriptManager = nullptr; }; } // namespace Core diff --git a/src/core/logger.cpp b/src/core/logger.cpp index ef95c755..76301b67 100644 --- a/src/core/logger.cpp +++ b/src/core/logger.cpp @@ -105,7 +105,7 @@ void HistoryModel::clear() QString HistoryModel::createScript(int start, int end) { - const auto settings = Core::Settings::instance()->value(Core::Settings::Tab); + const auto settings = DEFAULT_VALUE(Core::TabSettings, Tab); const auto tab = settings.insertSpaces ? QString(settings.tabSize, ' ') : QString('\t'); std::tie(start, end) = std::minmax(start, end); diff --git a/src/core/rcdocument.h b/src/core/rcdocument.h index bf4369b7..b728aa3c 100644 --- a/src/core/rcdocument.h +++ b/src/core/rcdocument.h @@ -57,6 +57,8 @@ class RcDocument : public Document static inline constexpr char DefaultLanguage[] = "[default]"; + using LanguageMap = std::map; + public: explicit RcDocument(QObject *parent = nullptr); diff --git a/src/core/settings.h b/src/core/settings.h index 42479e5d..085de80d 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -53,6 +53,7 @@ class Settings : public QObject static inline constexpr char SaveLogsToFile[] = "/logs/saveToFile"; static inline constexpr char ScriptPaths[] = "/script_paths"; static inline constexpr char Tab[] = "/text_editor/tab"; + static inline constexpr char Encoding[] = "/text_editor/encoding"; static inline constexpr char ToggleSection[] = "/toggle_section"; public: diff --git a/src/core/textdocument.cpp b/src/core/textdocument.cpp index f4768cb3..9b147ce3 100644 --- a/src/core/textdocument.cpp +++ b/src/core/textdocument.cpp @@ -255,6 +255,7 @@ bool TextDocument::doSave(const QString &fileName) plainText.replace('\n', "\r\n"); QTextStream stream(&file); + stream.setEncoding(static_cast(DEFAULT_VALUE(TextDocument::Encoding, Encoding))); stream << plainText; return true; } @@ -273,6 +274,7 @@ bool TextDocument::doLoad(const QString &fileName) QByteArray data = file.readAll(); detectFormat(data); QTextStream stream(data); + stream.setEncoding(static_cast(DEFAULT_VALUE(TextDocument::Encoding, Encoding))); const QString text = stream.readAll(); QSignalBlocker sb(m_document->document()); @@ -1559,7 +1561,7 @@ static int indentOneLine(QTextCursor &cursor, int tabCount, const TabSettings &s static void indentBlocksInTextEdit(QPlainTextEdit *textEdit, int blockStart, int blockEnd, int tabCount, bool relative) { - const auto settings = Core::Settings::instance()->value(Core::Settings::Tab); + const auto settings = DEFAULT_VALUE(Core::TabSettings, Tab); QTextCursor cursor = textEdit->textCursor(); // Make sure we don't move the cursor outside the first line it started on. @@ -1725,7 +1727,7 @@ int TextDocument::indentationAtPosition(int pos) const LOG(LOG_ARG("position", pos)); const auto indentText = indentTextAtPosition(pos); - const auto settings = Core::Settings::instance()->value(Core::Settings::Tab); + const auto settings = DEFAULT_VALUE(Core::TabSettings, Tab); return columnAt(indentText, indentText.size(), settings.tabSize) / settings.tabSize; } @@ -1741,7 +1743,7 @@ int TextDocument::indentationAtLine(int line /* = -1 */) const LOG(LOG_ARG("line", line)); const auto indentText = indentTextAtLine(line); - const auto settings = Core::Settings::instance()->value(Core::Settings::Tab); + const auto settings = DEFAULT_VALUE(Core::TabSettings, Tab); return columnAt(indentText, indentText.size(), settings.tabSize) / settings.tabSize; } diff --git a/src/core/textdocument.h b/src/core/textdocument.h index e88f3662..ddac51fc 100644 --- a/src/core/textdocument.h +++ b/src/core/textdocument.h @@ -13,6 +13,7 @@ #include "document.h" #include "mark.h" #include "rangemark.h" +#include "utils/json.h" #include #include @@ -64,6 +65,19 @@ class TextDocument : public Document Q_DECLARE_FLAGS(FindFlags, FindFlag) Q_ENUM(FindFlag) + enum class Encoding { + Utf8 = QStringConverter::Utf8, + Utf16 = QStringConverter::Utf16, + Utf16BE = QStringConverter::Utf16BE, + Utf16LE = QStringConverter::Utf16LE, + Utf32 = QStringConverter::Utf32, + Utf32BE = QStringConverter::Utf32BE, + Utf32LE = QStringConverter::Utf32LE, + Latin1 = QStringConverter::Latin1, + System = QStringConverter::System, + }; + Q_ENUM(Encoding) + explicit TextDocument(QObject *parent = nullptr); ~TextDocument() override; @@ -240,6 +254,17 @@ public slots: bool m_utf8Bom = false; }; +NLOHMANN_JSON_SERIALIZE_ENUM(TextDocument::Encoding, + {{TextDocument::Encoding::Utf8, "utf8"}, + {TextDocument::Encoding::Utf16, "utf16"}, + {TextDocument::Encoding::Utf16BE, "utf16be"}, + {TextDocument::Encoding::Utf16LE, "utf16le"}, + {TextDocument::Encoding::Utf32, "utf32"}, + {TextDocument::Encoding::Utf32BE, "utf32be"}, + {TextDocument::Encoding::Utf32LE, "utf32le"}, + {TextDocument::Encoding::Latin1, "latin1"}, + {TextDocument::Encoding::System, "system"}}) + } // namespace Core Q_DECLARE_OPERATORS_FOR_FLAGS(Core::TextDocument::FindFlags) diff --git a/src/gui/guisettings.cpp b/src/gui/guisettings.cpp index c47a8617..1d2008d8 100644 --- a/src/gui/guisettings.cpp +++ b/src/gui/guisettings.cpp @@ -314,7 +314,7 @@ GuiSettings::TextEditSettings GuiSettings::computeTextEditSettings() const f.setPointSize(m_fontSize); QFontMetrics fm(f); - const auto tabSettings = Core::Settings::instance()->value(Core::Settings::Tab); + const auto tabSettings = DEFAULT_VALUE(Core::TabSettings, Tab); return {f, tabSettings.tabSize * fm.horizontalAdvance(' ')}; } diff --git a/src/gui/optionsdialog.cpp b/src/gui/optionsdialog.cpp index c408fb07..04ff50d4 100644 --- a/src/gui/optionsdialog.cpp +++ b/src/gui/optionsdialog.cpp @@ -13,6 +13,7 @@ #include "core/rcdocument.h" #include "core/scriptmanager.h" #include "core/settings.h" +#include "core/textdocument.h" #include "core/textdocument_p.h" #include "ui_optionsdialog.h" @@ -43,7 +44,7 @@ OptionsDialog::OptionsDialog(QWidget *parent) connect(ui->listWidget, &QListWidget::currentItemChanged, this, &OptionsDialog::changePage); initializeScriptPathSettings(); - initializeScriptBehaviorSettings(); + initializeTextSettings(); initializeRcSettings(); initializeSaveToLogFileSetting(); initializeEnableLSPSetting(); @@ -63,14 +64,14 @@ OptionsDialog::~OptionsDialog() = default; void OptionsDialog::initializeSaveToLogFileSetting() { // Save Logs to file - ui->saveLogsToFile->setChecked(Core::Settings::instance()->value(Core::Settings::SaveLogsToFile)); + ui->saveLogsToFile->setChecked(DEFAULT_VALUE(bool, SaveLogsToFile)); connect(ui->saveLogsToFile, &QCheckBox::toggled, this, &OptionsDialog::changeSaveLogsToFileSetting); } void OptionsDialog::initializeEnableLSPSetting() { // Enable LSP when running in Gui mode - ui->enableLSP->setChecked(Core::Settings::instance()->value(Core::Settings::EnableLSP)); + ui->enableLSP->setChecked(DEFAULT_VALUE(bool, EnableLSP)); connect(ui->enableLSP, &QCheckBox::toggled, this, &OptionsDialog::changeEnableLSPSetting); } @@ -101,7 +102,7 @@ void OptionsDialog::initializeScriptPathSettings() ui->scriptsList->setModel(Core::ScriptManager::model()); } -void OptionsDialog::initializeScriptBehaviorSettings() +void OptionsDialog::initializeTextSettings() { // Text editor settings ui->tabSize->setValidator(new QIntValidator(ui->tabSize)); @@ -109,14 +110,25 @@ void OptionsDialog::initializeScriptBehaviorSettings() ui->insertSpacesCheck->setChecked(settings.insertSpaces); ui->tabSize->setText(QString::number(settings.tabSize)); + // Encoding combobox + const auto metaEnum = QMetaEnum::fromType(); + for (int i = 0; i < metaEnum.keyCount(); ++i) { + ui->encoding->addItem(QLatin1String(metaEnum.key(i)), metaEnum.value(i)); + } + const auto encoding = DEFAULT_VALUE(Core::TextDocument::Encoding, Encoding); + ui->encoding->setCurrentIndex(ui->encoding->findData(QVariant::fromValue(encoding))); + auto changeTextEditorSettings = [this]() { auto settings = DEFAULT_VALUE(Core::TabSettings, Tab); settings.insertSpaces = ui->insertSpacesCheck->isChecked(); settings.tabSize = ui->tabSize->text().toInt(); - Core::Settings::instance()->setValue(Core::Settings::Tab, settings); + SET_DEFAULT_VALUE(Tab, settings); + const auto encoding = ui->encoding->currentData().value(); + SET_DEFAULT_VALUE(Encoding, encoding); }; connect(ui->insertSpacesCheck, &QCheckBox::toggled, this, changeTextEditorSettings); connect(ui->tabSize, &QLineEdit::textEdited, this, changeTextEditorSettings); + connect(ui->encoding, &QComboBox::currentIndexChanged, this, changeTextEditorSettings); // Toggle section settings auto sectionSettings = DEFAULT_VALUE(Core::ToggleSectionSettings, ToggleSection); @@ -191,8 +203,7 @@ void OptionsDialog::initializeRcSettings() SET_DEFAULT_VALUE(RcDialogScaleY, value); }); - auto languageMap = - Core::Settings::instance()->value>(Core::Settings::RcLanguageMap); + auto languageMap = DEFAULT_VALUE(Core::RcDocument::LanguageMap, RcLanguageMap); for (const auto &[source, result] : languageMap) { auto item = new QTreeWidgetItem(ui->languageMap); item->setText(0, QString::fromStdString(source)); @@ -322,7 +333,7 @@ void OptionsDialog::changeToggleSectionSetting() sectionSettings.tag = ui->tagEdit->text(); sectionSettings.debug = ui->debugEdit->text(); sectionSettings.return_values = returnValues; - Core::Settings::instance()->setValue(Core::Settings::ToggleSection, sectionSettings); + SET_DEFAULT_VALUE(ToggleSection, sectionSettings); } void OptionsDialog::changeAssetFlagsSetting() @@ -363,8 +374,7 @@ void OptionsDialog::changeDialogFlagsSetting() void OptionsDialog::changeLanguageMap() { - auto oldLanguageMap = - Core::Settings::instance()->value>(Core::Settings::RcLanguageMap); + auto oldLanguageMap = DEFAULT_VALUE(Core::RcDocument::LanguageMap, RcLanguageMap); std::map languageMap; for (int i = 0; i < ui->languageMap->topLevelItemCount(); ++i) { auto item = ui->languageMap->topLevelItem(i); @@ -374,7 +384,7 @@ void OptionsDialog::changeLanguageMap() item->text(1).isEmpty() ? Core::RcDocument::DefaultLanguage : item->text(1).toStdString(); languageMap[item->text(0).toStdString()] = result; } - Core::Settings::instance()->setValue(Core::Settings::RcLanguageMap, languageMap); + SET_DEFAULT_VALUE(RcLanguageMap, languageMap); } void OptionsDialog::changePage() diff --git a/src/gui/optionsdialog.h b/src/gui/optionsdialog.h index d7108b5e..81950da1 100644 --- a/src/gui/optionsdialog.h +++ b/src/gui/optionsdialog.h @@ -33,7 +33,7 @@ class OptionsDialog : public QDialog void initializeEnableLSPSetting(); void initializeSaveToLogFileSetting(); void initializeScriptPathSettings(); - void initializeScriptBehaviorSettings(); + void initializeTextSettings(); void initializeRcSettings(); void initializeCppSettings(); diff --git a/src/gui/optionsdialog.ui b/src/gui/optionsdialog.ui index c60dc390..59ff5b7e 100644 --- a/src/gui/optionsdialog.ui +++ b/src/gui/optionsdialog.ui @@ -6,8 +6,8 @@ 0 0 - 829 - 510 + 828 + 514 @@ -17,14 +17,14 @@ - QDialogButtonBox::Close + QDialogButtonBox::StandardButton::Close - Qt::Horizontal + Qt::Orientation::Horizontal @@ -147,7 +147,7 @@ - Qt::Vertical + Qt::Orientation::Vertical @@ -189,14 +189,14 @@ - QAbstractItemView::NoEditTriggers + QAbstractItemView::EditTrigger::NoEditTriggers - Qt::Vertical + Qt::Orientation::Vertical @@ -232,7 +232,7 @@ Scripts in Path: - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignTop @@ -263,7 +263,14 @@ Text Editor Behavior - + + + + + Insert spaces when pressing tab. + + + @@ -271,15 +278,35 @@ - - + + + + + - Insert spaces when pressing tab. + Default Encoding: - - + + + + + + + + + Qt::Orientation::Horizontal + + + + 248 + 17 + + + + + @@ -362,7 +389,7 @@ - Qt::Vertical + Qt::Orientation::Vertical @@ -380,7 +407,7 @@ - Qt::Vertical + Qt::Orientation::Vertical @@ -604,7 +631,7 @@ - Qt::Vertical + Qt::Orientation::Vertical @@ -646,7 +673,7 @@ Excluded Macros - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignTop @@ -677,10 +704,10 @@ - Script Paths + General - Qt::AlignCenter + Qt::AlignmentFlag::AlignCenter @@ -705,10 +732,10 @@ - QFrame::StyledPanel + QFrame::Shape::StyledPanel - -1 + 0 @@ -722,7 +749,7 @@ - Script Behavior + Text Files diff --git a/tests/tst_jsondocument.cpp b/tests/tst_jsondocument.cpp index 8b68e72c..56880344 100644 --- a/tests/tst_jsondocument.cpp +++ b/tests/tst_jsondocument.cpp @@ -10,6 +10,7 @@ #include "common/test_utils.h" #include "core/jsondocument.h" +#include "core/knutcore.h" #include "core/utils.h" #include @@ -19,7 +20,17 @@ class TestJsonDocument : public QObject Q_OBJECT private slots: - void initTestCase() { Q_INIT_RESOURCE(core); } + void initTestCase() + { + Q_INIT_RESOURCE(core); + m_core = new Core::KnutCore(); + } + + void cleanupTestCase() + { + delete m_core; + m_core = nullptr; + } void load() { @@ -136,6 +147,9 @@ private slots: QFile::remove(saveFileName); QFile::remove(saveAsFileName); } + +private: + Core::KnutCore *m_core = nullptr; }; QTEST_MAIN(TestJsonDocument) diff --git a/tests/tst_textdocument.cpp b/tests/tst_textdocument.cpp index de566c1a..0c1d32f2 100644 --- a/tests/tst_textdocument.cpp +++ b/tests/tst_textdocument.cpp @@ -47,7 +47,17 @@ class TestTextDocument : public QObject Q_OBJECT private slots: - void initTestCase() { Q_INIT_RESOURCE(core); } + void initTestCase() + { + Q_INIT_RESOURCE(core); + m_core = new Core::KnutCore(); + } + + void cleanupTestCase() + { + delete m_core; + m_core = nullptr; + } void load() { @@ -364,7 +374,6 @@ private slots: Test::FileTester file(Test::testDataPath() + "/tst_textdocument/indent/indent.txt"); { - Core::KnutCore core; Core::TextDocument document; document.load(file.fileName()); @@ -684,6 +693,9 @@ private slots: document.setText("IDOK:"); QVERIFY(document.find("IDOK", Core::TextDocument::FindWholeWords)); } + +private: + Core::KnutCore *m_core = nullptr; }; QTEST_MAIN(TestTextDocument)