From 2ac71ccc455df411471269d9a5ec1e52c11bb40a Mon Sep 17 00:00:00 2001 From: Christian Loose Date: Wed, 9 Dec 2015 09:43:57 +0100 Subject: [PATCH 01/20] Introduce Theme class A theme represents the combination of markdown, code and preview styles. --- app-static/app-static.pro | 2 + app-static/themes/theme.cpp | 45 ++++++++++++++++++++ app-static/themes/theme.h | 60 ++++++++++++++++++++++++++ test/unit/main.cpp | 6 ++- test/unit/themetest.cpp | 84 +++++++++++++++++++++++++++++++++++++ test/unit/themetest.h | 36 ++++++++++++++++ test/unit/unit.pro | 6 ++- 7 files changed, 236 insertions(+), 3 deletions(-) create mode 100644 app-static/themes/theme.cpp create mode 100644 app-static/themes/theme.h create mode 100644 test/unit/themetest.cpp create mode 100644 test/unit/themetest.h diff --git a/app-static/app-static.pro b/app-static/app-static.pro index 1e760ff5..07ba25e2 100644 --- a/app-static/app-static.pro +++ b/app-static/app-static.pro @@ -21,6 +21,7 @@ SOURCES += \ converter/revealmarkdownconverter.cpp \ template/htmltemplate.cpp \ template/presentationtemplate.cpp \ + themes/theme.cpp \ completionlistmodel.cpp \ datalocation.cpp \ slidelinemapping.cpp \ @@ -43,6 +44,7 @@ HEADERS += \ template/template.h \ template/htmltemplate.h \ template/presentationtemplate.h \ + themes/theme.h \ completionlistmodel.h \ datalocation.h \ slidelinemapping.h \ diff --git a/app-static/themes/theme.cpp b/app-static/themes/theme.cpp new file mode 100644 index 00000000..7a88d417 --- /dev/null +++ b/app-static/themes/theme.cpp @@ -0,0 +1,45 @@ +/* + * Copyright 2015 Christian Loose + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "theme.h" + +Theme::Theme(const QString &name, + const QString &markdownHighlighting, + const QString &codeHighlighting, + const QString &previewStylesheet) : + m_name(name), + m_markdownHighlighting(markdownHighlighting), + m_codeHighlighting(codeHighlighting), + m_previewStylesheet(previewStylesheet) +{ + checkInvariants(); +} + +void Theme::checkInvariants() const +{ + if (m_name.isEmpty()) { + throw std::runtime_error("theme name must not be empty"); + } + if (m_markdownHighlighting.isEmpty()) { + throw std::runtime_error("markdown highlighting style must not be empty"); + } + if (m_codeHighlighting.isEmpty()) { + throw std::runtime_error("code highlighting style must not be empty"); + } + if (m_previewStylesheet.isEmpty()) { + throw std::runtime_error("preview stylesheet must not be empty"); + } +} diff --git a/app-static/themes/theme.h b/app-static/themes/theme.h new file mode 100644 index 00000000..94b4c5c2 --- /dev/null +++ b/app-static/themes/theme.h @@ -0,0 +1,60 @@ +/* + * Copyright 2015 Christian Loose + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef THEME_H +#define THEME_H + +#include +#include + + +class Theme +{ +public: + Theme(const QString &name, + const QString &markdownHighlighting, + const QString &codeHighlighting, + const QString &previewStylesheet); + + QString name() const { return m_name; } + + QString markdownHighlighting() const { return m_markdownHighlighting; } + + QString codeHighlighting() const { return m_codeHighlighting; } + + QString previewStylesheet() const { return m_previewStylesheet; } + + bool operator<(const Theme &rhs) const + { + return m_name < rhs.name(); + } + + bool operator ==(const Theme &rhs) const + { + return m_name == rhs.name(); + } + +private: + void checkInvariants() const; + +private: + QString m_name; + QString m_markdownHighlighting; + QString m_codeHighlighting; + QString m_previewStylesheet; +}; + +#endif // THEME_H diff --git a/test/unit/main.cpp b/test/unit/main.cpp index 155b2995..2b0c98ea 100644 --- a/test/unit/main.cpp +++ b/test/unit/main.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2014 Christian Loose + * Copyright 2013-2015 Christian Loose * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,6 +23,7 @@ #include "snippetcollectiontest.h" #include "completionlistmodeltest.h" #include "snippettest.h" +#include "themetest.h" #include "yamlheadercheckertest.h" int main(int argc, char *argv[]) @@ -53,5 +54,8 @@ int main(int argc, char *argv[]) YamlHeaderCheckerTest test8; ret += QTest::qExec(&test8, argc, argv); + ThemeTest test9; + ret += QTest::qExec(&test9, argc, argv); + return ret; } diff --git a/test/unit/themetest.cpp b/test/unit/themetest.cpp new file mode 100644 index 00000000..5d97e36b --- /dev/null +++ b/test/unit/themetest.cpp @@ -0,0 +1,84 @@ +/* + * Copyright 2015 Christian Loose + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "themetest.h" + +#include + +#include + +static const QLatin1String A_THEME_NAME("name"); +static const QLatin1String A_MARKDOWN_HIGHLIGHTING("markdown"); +static const QLatin1String A_CODE_HIGHLIGHTING("code"); +static const QLatin1String A_PREVIEW_STYLESHEET("preview"); + +void ThemeTest::isLessThanComparable() +{ + Theme theme1("abc", A_MARKDOWN_HIGHLIGHTING, A_CODE_HIGHLIGHTING, A_PREVIEW_STYLESHEET); + + Theme theme2("xyz", A_MARKDOWN_HIGHLIGHTING, A_CODE_HIGHLIGHTING, A_PREVIEW_STYLESHEET); + + QCOMPARE(theme1 < theme2, true); + QCOMPARE(theme2 < theme1, false); + QCOMPARE(theme1 < theme1, false); +} + +void ThemeTest::isEqualComparable() +{ + Theme theme1("abc", A_MARKDOWN_HIGHLIGHTING, A_CODE_HIGHLIGHTING, A_PREVIEW_STYLESHEET); + + Theme theme2("abc", A_MARKDOWN_HIGHLIGHTING, A_CODE_HIGHLIGHTING, A_PREVIEW_STYLESHEET); + + Theme theme3("xyz", A_MARKDOWN_HIGHLIGHTING, A_CODE_HIGHLIGHTING, A_PREVIEW_STYLESHEET); + + QCOMPARE(theme1 == theme1, true); + QCOMPARE(theme1 == theme2, true); + QCOMPARE(theme1 == theme3, false); +} + +void ThemeTest::throwsIfNameIsEmpty() +{ + try { + Theme theme("", A_MARKDOWN_HIGHLIGHTING, A_CODE_HIGHLIGHTING, A_PREVIEW_STYLESHEET); + QFAIL("Expected exception of type runtime_error not thrown"); + } catch(const std::runtime_error &) {} +} + +void ThemeTest::throwsIfMarkdownHighlightingIsEmpty() +{ + try { + Theme theme(A_THEME_NAME, "", A_CODE_HIGHLIGHTING, A_PREVIEW_STYLESHEET); + QFAIL("Expected exception of type runtime_error not thrown"); + } catch(const std::runtime_error &) {} +} + +void ThemeTest::throwsIfCodeHighlightingIsEmpty() +{ + try { + Theme theme(A_THEME_NAME, A_MARKDOWN_HIGHLIGHTING, "", A_PREVIEW_STYLESHEET); + QFAIL("Expected exception of type runtime_error not thrown"); + } catch(const std::runtime_error &) {} +} + +void ThemeTest::throwsIfPreviewStylesheetIsEmpty() +{ + try { + Theme theme(A_THEME_NAME, A_MARKDOWN_HIGHLIGHTING, A_CODE_HIGHLIGHTING, ""); + QFAIL("Expected exception of type runtime_error not thrown"); + } catch(const std::runtime_error &) {} +} + + diff --git a/test/unit/themetest.h b/test/unit/themetest.h new file mode 100644 index 00000000..9e567742 --- /dev/null +++ b/test/unit/themetest.h @@ -0,0 +1,36 @@ +/* + * Copyright 2015 Christian Loose + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef THEMETEST_H +#define THEMETEST_H + +#include + +class ThemeTest : public QObject +{ + Q_OBJECT + +private slots: + void isLessThanComparable(); + void isEqualComparable(); + void throwsIfNameIsEmpty(); + void throwsIfMarkdownHighlightingIsEmpty(); + void throwsIfCodeHighlightingIsEmpty(); + void throwsIfPreviewStylesheetIsEmpty(); +}; + +#endif // THEMETEST_H + diff --git a/test/unit/unit.pro b/test/unit/unit.pro index ac004fe8..4742605f 100644 --- a/test/unit/unit.pro +++ b/test/unit/unit.pro @@ -18,7 +18,8 @@ SOURCES += \ slidelinemappingtest.cpp \ snippetcollectiontest.cpp \ dictionarytest.cpp \ - yamlheadercheckertest.cpp + yamlheadercheckertest.cpp \ + themetest.cpp HEADERS += \ completionlistmodeltest.h \ @@ -28,7 +29,8 @@ HEADERS += \ slidelinemappingtest.h \ snippetcollectiontest.h \ dictionarytest.h \ - yamlheadercheckertest.h + yamlheadercheckertest.h \ + themetest.h target.CONFIG += no_default_install From 8b227fd2db508336b1662db9fce438b9ec47bd1a Mon Sep 17 00:00:00 2001 From: Christian Loose Date: Wed, 9 Dec 2015 11:42:22 +0100 Subject: [PATCH 02/20] Introduce ThemeCollection class A collection of themes that can be loaded from a JSON file. --- app-static/app-static.pro | 2 ++ app-static/themes/themecollection.cpp | 40 ++++++++++++++++++++++ app-static/themes/themecollection.h | 42 +++++++++++++++++++++++ test/unit/main.cpp | 4 +++ test/unit/themecollectiontest.cpp | 49 +++++++++++++++++++++++++++ test/unit/themecollectiontest.h | 34 +++++++++++++++++++ test/unit/unit.pro | 6 ++-- 7 files changed, 175 insertions(+), 2 deletions(-) create mode 100644 app-static/themes/themecollection.cpp create mode 100644 app-static/themes/themecollection.h create mode 100644 test/unit/themecollectiontest.cpp create mode 100644 test/unit/themecollectiontest.h diff --git a/app-static/app-static.pro b/app-static/app-static.pro index 07ba25e2..5a2c9eac 100644 --- a/app-static/app-static.pro +++ b/app-static/app-static.pro @@ -22,6 +22,7 @@ SOURCES += \ template/htmltemplate.cpp \ template/presentationtemplate.cpp \ themes/theme.cpp \ + themes/themecollection.cpp \ completionlistmodel.cpp \ datalocation.cpp \ slidelinemapping.cpp \ @@ -45,6 +46,7 @@ HEADERS += \ template/htmltemplate.h \ template/presentationtemplate.h \ themes/theme.h \ + themes/themecollection.h \ completionlistmodel.h \ datalocation.h \ slidelinemapping.h \ diff --git a/app-static/themes/themecollection.cpp b/app-static/themes/themecollection.cpp new file mode 100644 index 00000000..e9f86c1a --- /dev/null +++ b/app-static/themes/themecollection.cpp @@ -0,0 +1,40 @@ +/* + * Copyright 2015 Christian Loose + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "themecollection.h" + + +int ThemeCollection::insert(const Theme &theme) +{ + themesIndex << theme.name(); + themes << theme; + return 0; +} + +int ThemeCollection::count() const +{ + return themes.count(); +} + +const Theme &ThemeCollection::at(int offset) const +{ + return themes.at(offset); +} + +const QString ThemeCollection::name() const +{ + return QStringLiteral("themes"); +} diff --git a/app-static/themes/themecollection.h b/app-static/themes/themecollection.h new file mode 100644 index 00000000..ca7a18e0 --- /dev/null +++ b/app-static/themes/themecollection.h @@ -0,0 +1,42 @@ +/* + * Copyright 2015 Christian Loose + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef THEMECOLLECTION_H +#define THEMECOLLECTION_H + +#include +#include +#include +#include "theme.h" + + +class ThemeCollection : public JsonCollection +{ +public: + int insert(const Theme &theme); + + int count() const; + const Theme &at(int offset) const; + + const QString name() const; + +private: + QStringList themesIndex; + QList themes; +}; + +#endif // THEMECOLLECTION_H + diff --git a/test/unit/main.cpp b/test/unit/main.cpp index 2b0c98ea..9b247d73 100644 --- a/test/unit/main.cpp +++ b/test/unit/main.cpp @@ -23,6 +23,7 @@ #include "snippetcollectiontest.h" #include "completionlistmodeltest.h" #include "snippettest.h" +#include "themecollectiontest.h" #include "themetest.h" #include "yamlheadercheckertest.h" @@ -57,5 +58,8 @@ int main(int argc, char *argv[]) ThemeTest test9; ret += QTest::qExec(&test9, argc, argv); + ThemeCollectionTest test10; + ret += QTest::qExec(&test10, argc, argv); + return ret; } diff --git a/test/unit/themecollectiontest.cpp b/test/unit/themecollectiontest.cpp new file mode 100644 index 00000000..6a157495 --- /dev/null +++ b/test/unit/themecollectiontest.cpp @@ -0,0 +1,49 @@ +/* + * Copyright 2015 Christian Loose + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "themecollectiontest.h" + +#include + +#include + + +void ThemeCollectionTest::returnsConstantNameOfJsonArray() +{ + ThemeCollection collection; + QCOMPARE(collection.name(), QStringLiteral("themes")); +} + +void ThemeCollectionTest::returnsNumberOfThemesInCollection() +{ + ThemeCollection collection; + Theme theme("name", "markdown", "code", "preview"); + collection.insert(theme); + + QCOMPARE(collection.count(), 1); +} + +void ThemeCollectionTest::returnsThemeAtIndexPosition() +{ + ThemeCollection collection; + Theme theme("name", "markdown", "code", "preview"); + collection.insert(theme); + + Theme actual = collection.at(0); + + QCOMPARE(actual, theme); +} + diff --git a/test/unit/themecollectiontest.h b/test/unit/themecollectiontest.h new file mode 100644 index 00000000..df274fdd --- /dev/null +++ b/test/unit/themecollectiontest.h @@ -0,0 +1,34 @@ +/* + * Copyright 2015 Christian Loose + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef THEMECOLLECTIONTEST_H +#define THEMECOLLECTIONTEST_H + +#include + +class ThemeCollectionTest : public QObject +{ + Q_OBJECT + +private slots: + void returnsConstantNameOfJsonArray(); + void returnsNumberOfThemesInCollection(); + void returnsThemeAtIndexPosition(); +}; + +#endif // THEMECOLLECTIONTEST_H + + diff --git a/test/unit/unit.pro b/test/unit/unit.pro index 4742605f..336f9284 100644 --- a/test/unit/unit.pro +++ b/test/unit/unit.pro @@ -19,7 +19,8 @@ SOURCES += \ snippetcollectiontest.cpp \ dictionarytest.cpp \ yamlheadercheckertest.cpp \ - themetest.cpp + themetest.cpp \ + themecollectiontest.cpp HEADERS += \ completionlistmodeltest.h \ @@ -30,7 +31,8 @@ HEADERS += \ snippetcollectiontest.h \ dictionarytest.h \ yamlheadercheckertest.h \ - themetest.h + themetest.h \ + themecollectiontest.h target.CONFIG += no_default_install From cd8ea26f63d9a2c32570c12a59eb8ce3ff91ca1a Mon Sep 17 00:00:00 2001 From: Christian Loose Date: Wed, 9 Dec 2015 12:47:21 +0100 Subject: [PATCH 03/20] Add JSON translator for themes Add JsonThemeTranslator class to translate between JSON and Theme objects. --- app-static/app-static.pro | 2 + app-static/themes/jsonthemetranslator.cpp | 48 +++++++++ app-static/themes/jsonthemetranslator.h | 34 +++++++ test/unit/jsonthemetranslatortest.cpp | 117 ++++++++++++++++++++++ test/unit/jsonthemetranslatortest.h | 44 ++++++++ test/unit/main.cpp | 4 + test/unit/unit.pro | 2 + 7 files changed, 251 insertions(+) create mode 100644 app-static/themes/jsonthemetranslator.cpp create mode 100644 app-static/themes/jsonthemetranslator.h create mode 100644 test/unit/jsonthemetranslatortest.cpp create mode 100644 test/unit/jsonthemetranslatortest.h diff --git a/app-static/app-static.pro b/app-static/app-static.pro index 5a2c9eac..ec4f8a97 100644 --- a/app-static/app-static.pro +++ b/app-static/app-static.pro @@ -21,6 +21,7 @@ SOURCES += \ converter/revealmarkdownconverter.cpp \ template/htmltemplate.cpp \ template/presentationtemplate.cpp \ + themes/jsonthemetranslator.cpp \ themes/theme.cpp \ themes/themecollection.cpp \ completionlistmodel.cpp \ @@ -45,6 +46,7 @@ HEADERS += \ template/template.h \ template/htmltemplate.h \ template/presentationtemplate.h \ + themes/jsonthemetranslator.h \ themes/theme.h \ themes/themecollection.h \ completionlistmodel.h \ diff --git a/app-static/themes/jsonthemetranslator.cpp b/app-static/themes/jsonthemetranslator.cpp new file mode 100644 index 00000000..fb671b7d --- /dev/null +++ b/app-static/themes/jsonthemetranslator.cpp @@ -0,0 +1,48 @@ +/* + * Copyright 2015 Christian Loose + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "jsonthemetranslator.h" + +namespace { + +static const QLatin1String NAME("name"); +static const QLatin1String MARKDOWN_HIGHLIGHTING("markdownHighlighting"); +static const QLatin1String CODE_HIGHLIGHTING("codeHighlighting"); +static const QLatin1String PREVIEW_STYLESHEET("previewStylesheet"); + +} + +Theme JsonThemeTranslator::fromJsonObject(const QJsonObject &object) +{ + QString name = object.value(NAME).toString(); + QString markdownHighlighting = object.value(MARKDOWN_HIGHLIGHTING).toString(); + QString codeHighlighting = object.value(CODE_HIGHLIGHTING).toString(); + QString previewStylesheet = object.value(PREVIEW_STYLESHEET).toString(); + + return { name, markdownHighlighting, codeHighlighting, previewStylesheet }; +} + +QJsonObject JsonThemeTranslator::toJsonObject(const Theme &theme) +{ + QJsonObject object; + object.insert(NAME, theme.name()); + object.insert(MARKDOWN_HIGHLIGHTING, theme.markdownHighlighting()); + object.insert(CODE_HIGHLIGHTING, theme.codeHighlighting()); + object.insert(PREVIEW_STYLESHEET, theme.previewStylesheet()); + + return object; +} + diff --git a/app-static/themes/jsonthemetranslator.h b/app-static/themes/jsonthemetranslator.h new file mode 100644 index 00000000..de13f0d8 --- /dev/null +++ b/app-static/themes/jsonthemetranslator.h @@ -0,0 +1,34 @@ +/* + * Copyright 2015 Christian Loose + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef JSONTHEMETRANSLATOR_H +#define JSONTHEMETRANSLATOR_H + +#include +#include +#include "theme.h" + + +class JsonThemeTranslator : public JsonTranslator +{ +private: + Theme fromJsonObject(const QJsonObject &object); + QJsonObject toJsonObject(const Theme &theme); +}; + +#endif // JSONTHEMETRANSLATOR_H + + diff --git a/test/unit/jsonthemetranslatortest.cpp b/test/unit/jsonthemetranslatortest.cpp new file mode 100644 index 00000000..8731f018 --- /dev/null +++ b/test/unit/jsonthemetranslatortest.cpp @@ -0,0 +1,117 @@ +/* + * Copyright 2015 Christian Loose + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "jsonthemetranslatortest.h" + +#include + +#include +#include +#include + +static const QLatin1String A_THEME_NAME("mytheme"); +static const QLatin1String A_MARKDOWN_HIGHLIGHTING("default"); +static const QLatin1String A_CODE_HIGHLIGHTING("monokai"); +static const QLatin1String A_PREVIEW_STYLESHEET("github"); + + +QJsonDocument NewJsonDocumentWithObject(const QJsonObject &jsonObject) +{ + QJsonArray themeArray; + themeArray.append(jsonObject); + + QJsonObject object; + object.insert("themes", themeArray); + + return QJsonDocument(object); +} + +QJsonObject NewJsonThemeObject() +{ + QJsonObject jsonObject; + jsonObject.insert("name", A_THEME_NAME); + jsonObject.insert("markdownHighlighting", A_MARKDOWN_HIGHLIGHTING); + jsonObject.insert("codeHighlighting", A_CODE_HIGHLIGHTING); + jsonObject.insert("previewStylesheet", A_PREVIEW_STYLESHEET); + + return jsonObject; +} + +void JsonThemeTranslatorTest::initTestCase() +{ + translator = new JsonThemeTranslator(); +} + +void JsonThemeTranslatorTest::cleanupTestCase() +{ + delete translator; +} + +void JsonThemeTranslatorTest::doesNotProcessInvalidJsonDocument() +{ + QJsonDocument doc; + + ThemeCollection collection; + bool success = translator->processDocument(doc, &collection); + + QVERIFY(!success); + QCOMPARE(collection.count(), 0); +} + +void JsonThemeTranslatorTest::translatesEmptyJsonDocumentToEmptyThemes() +{ + QJsonObject themesObject; + themesObject.insert("themes", QJsonArray()); + + QJsonDocument doc(themesObject); + + ThemeCollection collection; + bool success = translator->processDocument(doc, &collection); + + QVERIFY(success); + QCOMPARE(collection.count(), 0); +} + +void JsonThemeTranslatorTest::translatesJsonDocumentToThemes() +{ + QJsonDocument doc = NewJsonDocumentWithObject(NewJsonThemeObject()); + + ThemeCollection collection; + bool success = translator->processDocument(doc, &collection); + + QVERIFY(success); + QCOMPARE(collection.count(), 1); + QCOMPARE(collection.at(0).name(), A_THEME_NAME); + QCOMPARE(collection.at(0).markdownHighlighting(), A_MARKDOWN_HIGHLIGHTING); + QCOMPARE(collection.at(0).codeHighlighting(), A_CODE_HIGHLIGHTING); + QCOMPARE(collection.at(0).previewStylesheet(), A_PREVIEW_STYLESHEET); +} + +void JsonThemeTranslatorTest::translatesThemesToJsonDocument() +{ + Theme theme(A_THEME_NAME, A_MARKDOWN_HIGHLIGHTING, A_CODE_HIGHLIGHTING, A_PREVIEW_STYLESHEET); + ThemeCollection collection; + collection.insert(theme); + + QJsonDocument doc = translator->createDocument(&collection); + + QJsonObject actual = doc.object().value("themes").toArray().first().toObject(); + QCOMPARE(actual["name"].toString(), A_THEME_NAME); + QCOMPARE(actual["markdownHighlighting"].toString(), A_MARKDOWN_HIGHLIGHTING); + QCOMPARE(actual["codeHighlighting"].toString(), A_CODE_HIGHLIGHTING); + QCOMPARE(actual["previewStylesheet"].toString(), A_PREVIEW_STYLESHEET); +} + diff --git a/test/unit/jsonthemetranslatortest.h b/test/unit/jsonthemetranslatortest.h new file mode 100644 index 00000000..ab44d4de --- /dev/null +++ b/test/unit/jsonthemetranslatortest.h @@ -0,0 +1,44 @@ +/* + * Copyright 2015 Christian Loose + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef JSONTHEMETRANSLATORTEST_H +#define JSONTHEMETRANSLATORTEST_H + +#include +class JsonThemeTranslator; + + +class JsonThemeTranslatorTest : public QObject +{ + Q_OBJECT + +private slots: + void initTestCase(); + void cleanupTestCase(); + + void doesNotProcessInvalidJsonDocument(); + void translatesEmptyJsonDocumentToEmptyThemes(); + void translatesJsonDocumentToThemes(); + void translatesThemesToJsonDocument(); + +private: + JsonThemeTranslator *translator; +}; + +#endif // JSONTHEMETRANSLATORTEST_H + + + diff --git a/test/unit/main.cpp b/test/unit/main.cpp index 9b247d73..c271ee57 100644 --- a/test/unit/main.cpp +++ b/test/unit/main.cpp @@ -18,6 +18,7 @@ #include "dictionarytest.h" #include "jsonsnippettranslatortest.h" +#include "jsonthemetranslatortest.h" #include "jsontranslatorfactorytest.h" #include "slidelinemappingtest.h" #include "snippetcollectiontest.h" @@ -61,5 +62,8 @@ int main(int argc, char *argv[]) ThemeCollectionTest test10; ret += QTest::qExec(&test10, argc, argv); + JsonThemeTranslatorTest test11; + ret += QTest::qExec(&test11, argc, argv); + return ret; } diff --git a/test/unit/unit.pro b/test/unit/unit.pro index 336f9284..ca584408 100644 --- a/test/unit/unit.pro +++ b/test/unit/unit.pro @@ -14,6 +14,7 @@ SOURCES += \ completionlistmodeltest.cpp \ snippettest.cpp \ jsonsnippettranslatortest.cpp \ + jsonthemetranslatortest.cpp \ jsontranslatorfactorytest.cpp \ slidelinemappingtest.cpp \ snippetcollectiontest.cpp \ @@ -26,6 +27,7 @@ HEADERS += \ completionlistmodeltest.h \ snippettest.h \ jsonsnippettranslatortest.h \ + jsonthemetranslatortest.h \ jsontranslatorfactorytest.h \ slidelinemappingtest.h \ snippetcollectiontest.h \ From aa2e2da925239711823d98db8c6f7891cfa83c77 Mon Sep 17 00:00:00 2001 From: Christian Loose Date: Wed, 9 Dec 2015 15:15:08 +0100 Subject: [PATCH 04/20] Add integration test for reading themes from JSON file --- app-static/app-static.pro | 1 + .../themes/jsonthemetranslatorfactory.h | 37 +++++ test/integration/integration.pro | 2 + test/integration/jsonthemefiletest.cpp | 153 ++++++++++++++++++ test/integration/jsonthemefiletest.h | 36 +++++ test/integration/main.cpp | 8 +- 6 files changed, 235 insertions(+), 2 deletions(-) create mode 100644 app-static/themes/jsonthemetranslatorfactory.h create mode 100644 test/integration/jsonthemefiletest.cpp create mode 100644 test/integration/jsonthemefiletest.h diff --git a/app-static/app-static.pro b/app-static/app-static.pro index ec4f8a97..4fd70850 100644 --- a/app-static/app-static.pro +++ b/app-static/app-static.pro @@ -47,6 +47,7 @@ HEADERS += \ template/htmltemplate.h \ template/presentationtemplate.h \ themes/jsonthemetranslator.h \ + themes/jsonthemetranslatorfactory.h \ themes/theme.h \ themes/themecollection.h \ completionlistmodel.h \ diff --git a/app-static/themes/jsonthemetranslatorfactory.h b/app-static/themes/jsonthemetranslatorfactory.h new file mode 100644 index 00000000..5d4994b7 --- /dev/null +++ b/app-static/themes/jsonthemetranslatorfactory.h @@ -0,0 +1,37 @@ +/* + * Copyright 2015 Christian Loose + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef JSONTHEMETRANSLATORFACTORY_H +#define JSONTHEMETRANSLATORFACTORY_H + +#include +#include + +#include "themes/theme.h" +#include "themes/jsonthemetranslator.h" + + +template <> class JsonTranslatorFactory +{ +public: + static JsonTranslator *create() + { + return new JsonThemeTranslator(); + } +}; + +#endif // JSONTHEMETRANSLATORFACTORY_H + diff --git a/test/integration/integration.pro b/test/integration/integration.pro index 786f4aeb..7936f8ba 100644 --- a/test/integration/integration.pro +++ b/test/integration/integration.pro @@ -15,6 +15,7 @@ SOURCES += \ htmlpreviewcontrollertest.cpp \ htmltemplatetest.cpp \ jsonsnippetfiletest.cpp \ + jsonthemefiletest.cpp \ main.cpp \ pmhmarkdownparsertest.cpp \ revealmarkdownconvertertest.cpp @@ -24,6 +25,7 @@ HEADERS += \ htmlpreviewcontrollertest.h \ htmltemplatetest.h \ jsonsnippetfiletest.h \ + jsonthemefiletest.h \ pmhmarkdownparsertest.h \ revealmarkdownconvertertest.h diff --git a/test/integration/jsonthemefiletest.cpp b/test/integration/jsonthemefiletest.cpp new file mode 100644 index 00000000..effe6888 --- /dev/null +++ b/test/integration/jsonthemefiletest.cpp @@ -0,0 +1,153 @@ +/* + * Copyright 2015 Christian Loose + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "jsonthemefiletest.h" + + +#include +#include +#include + +#include +#include +#include + + +void JsonThemeFileTest::loadsEmptyThemeCollectionFromFile() +{ + QTemporaryFile themeFile(this); + if (!themeFile.open()) + QFAIL("Failed to create temporary theme file"); + + QTextStream out(&themeFile); out << "{ \"themes\": [] }"; + + themeFile.close(); + + ThemeCollection collection; + bool success = JsonFile::load(themeFile.fileName(), &collection); + + QVERIFY(success); + QCOMPARE(collection.count(), 0); +} + +void JsonThemeFileTest::loadsThemesCollectionFromFile() +{ + QTemporaryFile themeFile(this); + if (!themeFile.open()) + QFAIL("Failed to create temporary theme file"); + + QTextStream out(&themeFile); + out << "{ \"themes\": [" + << " { \"name\": \"default\"," + << " \"markdownHighlighting\": \"default\"," + << " \"codeHighlighting\": \"default\"," + << " \"previewStylesheet\": \"default\" }," + << " { \"name\": \"dark\"," + << " \"markdownHighlighting\": \"dark\"," + << " \"codeHighlighting\": \"black\"," + << " \"previewStylesheet\": \"dark\" } ] }"; + + themeFile.close(); + + ThemeCollection collection; + bool success = JsonFile::load(themeFile.fileName(), &collection); + + QVERIFY(success); + QCOMPARE(collection.count(), 2); + QCOMPARE(collection.at(0).name(), QLatin1String("default")); + QCOMPARE(collection.at(1).name(), QLatin1String("dark")); +} + +void JsonThemeFileTest::savesEmptyThemesCollectionToFile() +{ + QTemporaryFile themeFile(this); + if (!themeFile.open()) + QFAIL("Failed to create temporary theme file"); + + ThemeCollection collection; + bool success = JsonFile::save(themeFile.fileName(), &collection); + + QVERIFY(success); + + QTextStream in(&themeFile); + QString fileContent = in.readAll().trimmed(); + + QVERIFY(fileContent.startsWith("{")); + QVERIFY(fileContent.contains("\"themes\": [")); + QVERIFY(fileContent.endsWith("}")); +} + +void JsonThemeFileTest::savesThemesCollectionToFile() +{ + QTemporaryFile themeFile(this); + if (!themeFile.open()) + QFAIL("Failed to create temporary theme file"); + + Theme theme1("default", "default", "default", "default"); + + Theme theme2("dark", "dark", "black", "dark"); + + ThemeCollection collection; + collection.insert(theme1); + collection.insert(theme2); + + bool success = JsonFile::save(themeFile.fileName(), &collection); + + QVERIFY(success); + + QTextStream in(&themeFile); + QString fileContent = in.readAll().trimmed(); + + QVERIFY(fileContent.startsWith("{")); + QVERIFY(fileContent.contains("\"themes\": [")); + QVERIFY(fileContent.contains("\"name\": \"default\"")); + QVERIFY(fileContent.contains("\"name\": \"dark\"")); + QVERIFY(fileContent.endsWith("}")); +} + +void JsonThemeFileTest::roundtripTest() +{ + QTemporaryFile themeFile(this); + if (!themeFile.open()) + QFAIL("Failed to create temporary theme file"); + + Theme theme1("default", "default", "default", "default"); + + Theme theme2("dark", "dark", "black", "dark"); + + ThemeCollection collection1; + collection1.insert(theme1); + collection1.insert(theme2); + + bool saveSuccess = JsonFile::save(themeFile.fileName(), &collection1); + QVERIFY(saveSuccess); + + ThemeCollection collection2; + bool loadSuccess = JsonFile::load(themeFile.fileName(), &collection2); + QVERIFY(loadSuccess); + + QCOMPARE(collection2.count(), 2); + + QCOMPARE(collection2.at(0).name(), theme1.name()); + QCOMPARE(collection2.at(0).markdownHighlighting(), theme1.markdownHighlighting()); + QCOMPARE(collection2.at(0).codeHighlighting(), theme1.codeHighlighting()); + QCOMPARE(collection2.at(0).previewStylesheet(), theme1.previewStylesheet()); + + QCOMPARE(collection2.at(1).name(), theme2.name()); + QCOMPARE(collection2.at(1).markdownHighlighting(), theme2.markdownHighlighting()); + QCOMPARE(collection2.at(1).codeHighlighting(), theme2.codeHighlighting()); + QCOMPARE(collection2.at(1).previewStylesheet(), theme2.previewStylesheet()); +} diff --git a/test/integration/jsonthemefiletest.h b/test/integration/jsonthemefiletest.h new file mode 100644 index 00000000..f2898303 --- /dev/null +++ b/test/integration/jsonthemefiletest.h @@ -0,0 +1,36 @@ +/* + * Copyright 2015 Christian Loose + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef JSONTHEMEFILETEST_H +#define JSONTHEMEFILETEST_H + +#include + +class JsonThemeFileTest : public QObject +{ + Q_OBJECT + +private slots: + void loadsEmptyThemeCollectionFromFile(); + void loadsThemesCollectionFromFile(); + + void savesEmptyThemesCollectionToFile(); + void savesThemesCollectionToFile(); + + void roundtripTest(); +}; + +#endif // JSONTHEMEFILETEST_H diff --git a/test/integration/main.cpp b/test/integration/main.cpp index 48f5d183..477668f4 100644 --- a/test/integration/main.cpp +++ b/test/integration/main.cpp @@ -22,6 +22,7 @@ #include "htmlpreviewcontrollertest.h" #include "htmltemplatetest.h" #include "jsonsnippetfiletest.h" +#include "jsonthemefiletest.h" #include "pmhmarkdownparsertest.h" #include "revealmarkdownconvertertest.h" @@ -55,8 +56,11 @@ int main(int argc, char *argv[]) HtmlPreviewControllerTest test6; ret += QTest::qExec(&test6, argc, argv); - HtmlTemplateTest test7; - ret += QTest::qExec(&test7, argc, argv); + HtmlTemplateTest test7; + ret += QTest::qExec(&test7, argc, argv); + + JsonThemeFileTest test8; + ret += QTest::qExec(&test8, argc, argv); return ret; } From 7eb3e01cb386e941670708ca60976892e79e55d4 Mon Sep 17 00:00:00 2001 From: Christian Loose Date: Wed, 9 Dec 2015 19:40:00 +0100 Subject: [PATCH 05/20] Add contains() method to ThemeCollection class --- app-static/themes/themecollection.cpp | 5 +++++ app-static/themes/themecollection.h | 1 + test/unit/themecollectiontest.cpp | 9 +++++++++ test/unit/themecollectiontest.h | 1 + 4 files changed, 16 insertions(+) diff --git a/app-static/themes/themecollection.cpp b/app-static/themes/themecollection.cpp index e9f86c1a..dc39cdb5 100644 --- a/app-static/themes/themecollection.cpp +++ b/app-static/themes/themecollection.cpp @@ -34,6 +34,11 @@ const Theme &ThemeCollection::at(int offset) const return themes.at(offset); } +bool ThemeCollection::contains(const QString &name) const +{ + return themesIndex.contains(name); +} + const QString ThemeCollection::name() const { return QStringLiteral("themes"); diff --git a/app-static/themes/themecollection.h b/app-static/themes/themecollection.h index ca7a18e0..82191d96 100644 --- a/app-static/themes/themecollection.h +++ b/app-static/themes/themecollection.h @@ -30,6 +30,7 @@ class ThemeCollection : public JsonCollection int count() const; const Theme &at(int offset) const; + bool contains(const QString &name) const; const QString name() const; diff --git a/test/unit/themecollectiontest.cpp b/test/unit/themecollectiontest.cpp index 6a157495..de7333df 100644 --- a/test/unit/themecollectiontest.cpp +++ b/test/unit/themecollectiontest.cpp @@ -47,3 +47,12 @@ void ThemeCollectionTest::returnsThemeAtIndexPosition() QCOMPARE(actual, theme); } +void ThemeCollectionTest::returnsIfCollectionContainsTheme() +{ + ThemeCollection collection; + Theme theme("name", "markdown", "code", "preview"); + collection.insert(theme); + + QCOMPARE(collection.contains("name"), true); + QCOMPARE(collection.contains("missing"), false); +} diff --git a/test/unit/themecollectiontest.h b/test/unit/themecollectiontest.h index df274fdd..28128ed6 100644 --- a/test/unit/themecollectiontest.h +++ b/test/unit/themecollectiontest.h @@ -27,6 +27,7 @@ private slots: void returnsConstantNameOfJsonArray(); void returnsNumberOfThemesInCollection(); void returnsThemeAtIndexPosition(); + void returnsIfCollectionContainsTheme(); }; #endif // THEMECOLLECTIONTEST_H From 65f55c76d2c5aaa18ccc7793bd9af7a46fcb9699 Mon Sep 17 00:00:00 2001 From: Christian Loose Date: Thu, 10 Dec 2015 19:38:32 +0100 Subject: [PATCH 06/20] Add theme() and themeNames() to ThemeCollection class Add methods to retrieve a theme by name or the names of all themes to the ThemeCollection class. --- app-static/themes/themecollection.cpp | 10 ++++++++++ app-static/themes/themecollection.h | 2 ++ test/unit/themecollectiontest.cpp | 27 +++++++++++++++++++++++++++ test/unit/themecollectiontest.h | 2 ++ 4 files changed, 41 insertions(+) diff --git a/app-static/themes/themecollection.cpp b/app-static/themes/themecollection.cpp index dc39cdb5..981767d8 100644 --- a/app-static/themes/themecollection.cpp +++ b/app-static/themes/themecollection.cpp @@ -39,6 +39,16 @@ bool ThemeCollection::contains(const QString &name) const return themesIndex.contains(name); } +const Theme ThemeCollection::theme(const QString &name) const +{ + return at(themesIndex.indexOf(name)); +} + +QStringList ThemeCollection::themeNames() const +{ + return themesIndex; +} + const QString ThemeCollection::name() const { return QStringLiteral("themes"); diff --git a/app-static/themes/themecollection.h b/app-static/themes/themecollection.h index 82191d96..6c2c6ae5 100644 --- a/app-static/themes/themecollection.h +++ b/app-static/themes/themecollection.h @@ -31,6 +31,8 @@ class ThemeCollection : public JsonCollection int count() const; const Theme &at(int offset) const; bool contains(const QString &name) const; + const Theme theme(const QString &name) const; + QStringList themeNames() const; const QString name() const; diff --git a/test/unit/themecollectiontest.cpp b/test/unit/themecollectiontest.cpp index de7333df..3fbf9511 100644 --- a/test/unit/themecollectiontest.cpp +++ b/test/unit/themecollectiontest.cpp @@ -56,3 +56,30 @@ void ThemeCollectionTest::returnsIfCollectionContainsTheme() QCOMPARE(collection.contains("name"), true); QCOMPARE(collection.contains("missing"), false); } + +void ThemeCollectionTest::returnsThemeByName() +{ + ThemeCollection collection; + Theme theme("name", "markdown", "code", "preview"); + collection.insert(theme); + + Theme actual = collection.theme("name"); + + QCOMPARE(actual, theme); +} + +void ThemeCollectionTest::returnsNameOfAllThemes() +{ + Theme theme1("name 1", "markdown", "code", "preview"); + Theme theme2("name 2", "markdown", "code", "preview"); + ThemeCollection collection; + collection.insert(theme1); + collection.insert(theme2); + + QStringList themeNames = collection.themeNames(); + + QCOMPARE(themeNames.count(), 2); + QCOMPARE(themeNames.at(0), theme1.name()); + QCOMPARE(themeNames.at(1), theme2.name()); +} + diff --git a/test/unit/themecollectiontest.h b/test/unit/themecollectiontest.h index 28128ed6..3fc8d15b 100644 --- a/test/unit/themecollectiontest.h +++ b/test/unit/themecollectiontest.h @@ -28,6 +28,8 @@ private slots: void returnsNumberOfThemesInCollection(); void returnsThemeAtIndexPosition(); void returnsIfCollectionContainsTheme(); + void returnsThemeByName(); + void returnsNameOfAllThemes(); }; #endif // THEMECOLLECTIONTEST_H From b37ed38574624517a384edb4de193e082c4aa90c Mon Sep 17 00:00:00 2001 From: Christian Loose Date: Thu, 10 Dec 2015 19:48:16 +0100 Subject: [PATCH 07/20] Add JSON file with builtin HTML preview themes --- app/builtin-htmlpreview-themes.json | 46 +++++++++++++++++++++++++++++ app/resources.qrc | 1 + 2 files changed, 47 insertions(+) create mode 100644 app/builtin-htmlpreview-themes.json diff --git a/app/builtin-htmlpreview-themes.json b/app/builtin-htmlpreview-themes.json new file mode 100644 index 00000000..20beadda --- /dev/null +++ b/app/builtin-htmlpreview-themes.json @@ -0,0 +1,46 @@ +{ + "themes": [ + { + "name": "Default", + "markdownHighlighting": "Default", + "codeHighlighting": "Default", + "previewStylesheet": "Default" + }, + { + "name": "Github", + "markdownHighlighting": "Default", + "codeHighlighting": "Github", + "previewStylesheet": "Github" + }, + { + "name": "Solarized Light", + "markdownHighlighting": "Solarized Light", + "codeHighlighting": "Solarized Light", + "previewStylesheet": "Solarized Light" + }, + { + "name": "Solarized Dark", + "markdownHighlighting": "Solarized Dark", + "codeHighlighting": "Solarized Dark", + "previewStylesheet": "Solarized Dark" + }, + { + "name": "Clearness", + "markdownHighlighting": "Default", + "codeHighlighting": "Default", + "previewStylesheet": "Clearness" + }, + { + "name": "Clearness Dark", + "markdownHighlighting": "Clearness Dark", + "codeHighlighting": "Default", + "previewStylesheet": "Clearness Dark" + }, + { + "name": "Byword Dark", + "markdownHighlighting": "Byword Dark", + "codeHighlighting": "Default", + "previewStylesheet": "Byword Dark" + } + ] +} diff --git a/app/resources.qrc b/app/resources.qrc index c364e28d..b492a939 100644 --- a/app/resources.qrc +++ b/app/resources.qrc @@ -34,6 +34,7 @@ syntax_id.html syntax_da.html template_presentation.html + builtin-htmlpreview-themes.json images/icon-close.png From 58797e5bf4bac4bb980d097f299cf5edfc4a3926 Mon Sep 17 00:00:00 2001 From: Christian Loose Date: Thu, 10 Dec 2015 19:50:20 +0100 Subject: [PATCH 08/20] Introduce ThemeManager class It manages a theme collection and the association to the builtin markdown, code and preview styles --- app-static/app-static.pro | 2 + app-static/themes/thememanager.cpp | 84 +++++++++++++++++++++++++++ app-static/themes/thememanager.h | 44 ++++++++++++++ test/integration/integration.pro | 6 +- test/integration/main.cpp | 4 ++ test/integration/thememanagertest.cpp | 68 ++++++++++++++++++++++ test/integration/thememanagertest.h | 41 +++++++++++++ test/unit/main.cpp | 6 +- test/unit/thememanagertest.cpp | 64 ++++++++++++++++++++ test/unit/thememanagertest.h | 34 +++++++++++ test/unit/unit.pro | 6 +- 11 files changed, 354 insertions(+), 5 deletions(-) create mode 100644 app-static/themes/thememanager.cpp create mode 100644 app-static/themes/thememanager.h create mode 100644 test/integration/thememanagertest.cpp create mode 100644 test/integration/thememanagertest.h create mode 100644 test/unit/thememanagertest.cpp create mode 100644 test/unit/thememanagertest.h diff --git a/app-static/app-static.pro b/app-static/app-static.pro index 4fd70850..7a1a16cc 100644 --- a/app-static/app-static.pro +++ b/app-static/app-static.pro @@ -24,6 +24,7 @@ SOURCES += \ themes/jsonthemetranslator.cpp \ themes/theme.cpp \ themes/themecollection.cpp \ + themes/thememanager.cpp \ completionlistmodel.cpp \ datalocation.cpp \ slidelinemapping.cpp \ @@ -50,6 +51,7 @@ HEADERS += \ themes/jsonthemetranslatorfactory.h \ themes/theme.h \ themes/themecollection.h \ + themes/thememanager.h \ completionlistmodel.h \ datalocation.h \ slidelinemapping.h \ diff --git a/app-static/themes/thememanager.cpp b/app-static/themes/thememanager.cpp new file mode 100644 index 00000000..4f8ef6b4 --- /dev/null +++ b/app-static/themes/thememanager.cpp @@ -0,0 +1,84 @@ +/* + * Copyright 2015 Christian Loose + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "thememanager.h" + +#include +#include + + +static const QMap BUILTIN_MARKDOWN_HIGHLIGHTINGS = { + { "Default", "default" }, + { "Solarized Light", "solarized-light" }, + { "Solarized Dark", "solarized-dark" }, + { "Clearness Dark", "clearness-dark" }, + { "Byword Dark", "byword-dark" } +}; + +static const QMap BUILTIN_CODE_HIGHLIGHTINGS = { + { "Default", "default" }, + { "Github", "github" }, + { "Solarized Light", "solarized_light" }, + { "Solarized Dark", "solarized_dark" } +}; + +static const QMap BUILTIN_PREVIEW_STYLESHEETS = { + { "Default", "qrc:/css/markdown.css" }, + { "Github", "qrc:/css/github.css" }, + { "Solarized Light", "qrc:/css/solarized-light.css" }, + { "Solarized Dark", "qrc:/css/solarized-dark.css" }, + { "Clearness", "qrc:/css/clearness.css" }, + { "Clearness Dark", "qrc:/css/clearness-dark.css" }, + { "Byword Dark", "qrc:/css/byword-dark.css" } +}; + +ThemeCollection ThemeManager::m_htmlPreviewThemes; + + +ThemeManager::ThemeManager() : + ThemeManager(":/builtin-htmlpreview-themes.json") +{ +} + +ThemeManager::ThemeManager(const QString &themeFileName) +{ + JsonFile::load(themeFileName, &m_htmlPreviewThemes); +} + +Theme ThemeManager::themeByName(const QString &name) const +{ + return m_htmlPreviewThemes.theme(name); +} + +QStringList ThemeManager::themeNames() const +{ + return m_htmlPreviewThemes.themeNames(); +} + +QString ThemeManager::markdownHighlightingPath(const Theme &theme) +{ + return BUILTIN_MARKDOWN_HIGHLIGHTINGS[theme.markdownHighlighting()]; +} + +QString ThemeManager::codeHighlightingPath(const Theme &theme) +{ + return BUILTIN_CODE_HIGHLIGHTINGS[theme.codeHighlighting()]; +} + +QString ThemeManager::previewStylesheetPath(const Theme &theme) +{ + return BUILTIN_PREVIEW_STYLESHEETS[theme.previewStylesheet()]; +} diff --git a/app-static/themes/thememanager.h b/app-static/themes/thememanager.h new file mode 100644 index 00000000..1c2ab4da --- /dev/null +++ b/app-static/themes/thememanager.h @@ -0,0 +1,44 @@ +/* + * Copyright 2015 Christian Loose + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef THEMEMANAGER_H +#define THEMEMANAGER_H + +#include +#include +#include "theme.h" +#include "themecollection.h" + + +class ThemeManager +{ +public: + ThemeManager(); + explicit ThemeManager(const QString &themeFileName); + + Theme themeByName(const QString &name) const; + QStringList themeNames() const; + + static QString markdownHighlightingPath(const Theme &theme); + static QString codeHighlightingPath(const Theme &theme); + static QString previewStylesheetPath(const Theme &theme); + +private: + static ThemeCollection m_htmlPreviewThemes; +}; + +#endif // THEMEMANAGER_H + diff --git a/test/integration/integration.pro b/test/integration/integration.pro index 7936f8ba..5e0a0f35 100644 --- a/test/integration/integration.pro +++ b/test/integration/integration.pro @@ -18,7 +18,8 @@ SOURCES += \ jsonthemefiletest.cpp \ main.cpp \ pmhmarkdownparsertest.cpp \ - revealmarkdownconvertertest.cpp + revealmarkdownconvertertest.cpp \ + thememanagertest.cpp HEADERS += \ discountmarkdownconvertertest.h \ @@ -27,7 +28,8 @@ HEADERS += \ jsonsnippetfiletest.h \ jsonthemefiletest.h \ pmhmarkdownparsertest.h \ - revealmarkdownconvertertest.h + revealmarkdownconvertertest.h \ + thememanagertest.h target.CONFIG += no_default_install diff --git a/test/integration/main.cpp b/test/integration/main.cpp index 477668f4..0ce05c39 100644 --- a/test/integration/main.cpp +++ b/test/integration/main.cpp @@ -25,6 +25,7 @@ #include "jsonthemefiletest.h" #include "pmhmarkdownparsertest.h" #include "revealmarkdownconvertertest.h" +#include "thememanagertest.h" #ifdef ENABLE_HOEDOWN #include "hoedownmarkdownconvertertest.h" @@ -62,6 +63,9 @@ int main(int argc, char *argv[]) JsonThemeFileTest test8; ret += QTest::qExec(&test8, argc, argv); + ThemeManagerTest test9; + ret += QTest::qExec(&test9, argc, argv); + return ret; } diff --git a/test/integration/thememanagertest.cpp b/test/integration/thememanagertest.cpp new file mode 100644 index 00000000..26828b74 --- /dev/null +++ b/test/integration/thememanagertest.cpp @@ -0,0 +1,68 @@ +/* + * Copyright 2015 Christian Loose + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "thememanagertest.h" + +#include + +#include + +void ThemeManagerTest::initTestCase() +{ + QTemporaryFile themeFile(this); + if (!themeFile.open()) + QFAIL("Failed to create temporary theme file"); + + QTextStream out(&themeFile); + out << "{ \"themes\": [" + << " { \"name\": \"default\"," + << " \"markdownHighlighting\": \"default\"," + << " \"codeHighlighting\": \"default\"," + << " \"previewStylesheet\": \"default\" }," + << " { \"name\": \"dark\"," + << " \"markdownHighlighting\": \"dark\"," + << " \"codeHighlighting\": \"black\"," + << " \"previewStylesheet\": \"dark\" } ] }"; + + themeFile.close(); + + themeManager = new ThemeManager(themeFile.fileName()); +} + +void ThemeManagerTest::cleanupTestCase() +{ + delete themeManager; +} + +void ThemeManagerTest::returnsBuiltinThemeByName() +{ + Theme actual = themeManager->themeByName("dark"); + + QCOMPARE(actual.name(), QLatin1String("dark")); + QCOMPARE(actual.markdownHighlighting(), QLatin1String("dark")); + QCOMPARE(actual.codeHighlighting(), QLatin1String("black")); + QCOMPARE(actual.previewStylesheet(), QLatin1String("dark")); +} + +void ThemeManagerTest::returnsNameOfAllBuiltinThemes() +{ + QStringList themeNames = themeManager->themeNames(); + + QCOMPARE(themeNames.count(), 2); + QCOMPARE(themeNames.at(0), QLatin1String("default")); + QCOMPARE(themeNames.at(1), QLatin1String("dark")); +} + diff --git a/test/integration/thememanagertest.h b/test/integration/thememanagertest.h new file mode 100644 index 00000000..0485acbc --- /dev/null +++ b/test/integration/thememanagertest.h @@ -0,0 +1,41 @@ +/* + * Copyright 2015 Christian Loose + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef THEMEMANAGERTEST_H +#define THEMEMANAGERTEST_H + +#include +class ThemeManager; + + +class ThemeManagerTest : public QObject +{ + Q_OBJECT + +private slots: + void initTestCase(); + void cleanupTestCase(); + + void returnsBuiltinThemeByName(); + void returnsNameOfAllBuiltinThemes(); + +private: + ThemeManager *themeManager; +}; + +#endif // THEMEMANAGERTEST_H + + diff --git a/test/unit/main.cpp b/test/unit/main.cpp index c271ee57..8e29a615 100644 --- a/test/unit/main.cpp +++ b/test/unit/main.cpp @@ -25,6 +25,7 @@ #include "completionlistmodeltest.h" #include "snippettest.h" #include "themecollectiontest.h" +#include "thememanagertest.h" #include "themetest.h" #include "yamlheadercheckertest.h" @@ -62,8 +63,11 @@ int main(int argc, char *argv[]) ThemeCollectionTest test10; ret += QTest::qExec(&test10, argc, argv); - JsonThemeTranslatorTest test11; + ThemeManagerTest test11; ret += QTest::qExec(&test11, argc, argv); + JsonThemeTranslatorTest test12; + ret += QTest::qExec(&test12, argc, argv); + return ret; } diff --git a/test/unit/thememanagertest.cpp b/test/unit/thememanagertest.cpp new file mode 100644 index 00000000..fdcc0046 --- /dev/null +++ b/test/unit/thememanagertest.cpp @@ -0,0 +1,64 @@ +/* + * Copyright 2015 Christian Loose + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "thememanagertest.h" + +#include + +#include + +static const Theme defaultTheme("Default", "Default", "Default", "Default"); +static const Theme githubTheme("Github", "Github", "Github", "Github"); +static const Theme solarizedLightTheme("Solarized Light", "Solarized Light", "Solarized Light", "Solarized Light"); +static const Theme solarizedDarkTheme("Solarized Dark", "Solarized Dark", "Solarized Dark", "Solarized Dark"); +static const Theme clearnessTheme("Clearness", "Clearness", "Clearness", "Clearness"); +static const Theme clearnessDarkTheme("Clearness Dark", "Clearness Dark", "Clearness Dark", "Clearness Dark"); +static const Theme bywordDarkTheme("Byword Dark", "Byword Dark", "Byword Dark", "Byword Dark"); + +void ThemeManagerTest::returnsPathForMarkdownHighlighting() +{ + ThemeManager themeManager; + + QCOMPARE(themeManager.markdownHighlightingPath(defaultTheme), QLatin1String("default")); + QCOMPARE(themeManager.markdownHighlightingPath(solarizedLightTheme), QLatin1String("solarized-light")); + QCOMPARE(themeManager.markdownHighlightingPath(solarizedDarkTheme), QLatin1String("solarized-dark")); + QCOMPARE(themeManager.markdownHighlightingPath(clearnessDarkTheme), QLatin1String("clearness-dark")); + QCOMPARE(themeManager.markdownHighlightingPath(bywordDarkTheme), QLatin1String("byword-dark")); +} + +void ThemeManagerTest::returnsPathForCodeHighlighting() +{ + ThemeManager themeManager; + + QCOMPARE(themeManager.codeHighlightingPath(defaultTheme), QLatin1String("default")); + QCOMPARE(themeManager.codeHighlightingPath(githubTheme), QLatin1String("github")); + QCOMPARE(themeManager.codeHighlightingPath(solarizedLightTheme), QLatin1String("solarized_light")); + QCOMPARE(themeManager.codeHighlightingPath(solarizedDarkTheme), QLatin1String("solarized_dark")); +} + +void ThemeManagerTest::returnsPathForPreviewStylesheet() +{ + ThemeManager themeManager; + + QCOMPARE(themeManager.previewStylesheetPath(defaultTheme), QLatin1String("qrc:/css/markdown.css")); + QCOMPARE(themeManager.previewStylesheetPath(githubTheme), QLatin1String("qrc:/css/github.css")); + QCOMPARE(themeManager.previewStylesheetPath(solarizedLightTheme), QLatin1String("qrc:/css/solarized-light.css")); + QCOMPARE(themeManager.previewStylesheetPath(solarizedDarkTheme), QLatin1String("qrc:/css/solarized-dark.css")); + QCOMPARE(themeManager.previewStylesheetPath(clearnessTheme), QLatin1String("qrc:/css/clearness.css")); + QCOMPARE(themeManager.previewStylesheetPath(clearnessDarkTheme), QLatin1String("qrc:/css/clearness-dark.css")); + QCOMPARE(themeManager.previewStylesheetPath(bywordDarkTheme), QLatin1String("qrc:/css/byword-dark.css")); +} + diff --git a/test/unit/thememanagertest.h b/test/unit/thememanagertest.h new file mode 100644 index 00000000..72d9e8fa --- /dev/null +++ b/test/unit/thememanagertest.h @@ -0,0 +1,34 @@ +/* + * Copyright 2015 Christian Loose + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef THEMEMANAGERTEST_H +#define THEMEMANAGERTEST_H + +#include + +class ThemeManagerTest : public QObject +{ + Q_OBJECT + +private slots: + void returnsPathForMarkdownHighlighting(); + void returnsPathForCodeHighlighting(); + void returnsPathForPreviewStylesheet(); +}; + +#endif // THEMEMANAGERTEST_H + + diff --git a/test/unit/unit.pro b/test/unit/unit.pro index ca584408..7f436e33 100644 --- a/test/unit/unit.pro +++ b/test/unit/unit.pro @@ -21,7 +21,8 @@ SOURCES += \ dictionarytest.cpp \ yamlheadercheckertest.cpp \ themetest.cpp \ - themecollectiontest.cpp + themecollectiontest.cpp \ + thememanagertest.cpp HEADERS += \ completionlistmodeltest.h \ @@ -34,7 +35,8 @@ HEADERS += \ dictionarytest.h \ yamlheadercheckertest.h \ themetest.h \ - themecollectiontest.h + themecollectiontest.h \ + thememanagertest.h target.CONFIG += no_default_install From 10d74301b0adec063f7fc73331080d00357468ea Mon Sep 17 00:00:00 2001 From: Christian Loose Date: Thu, 10 Dec 2015 19:52:28 +0100 Subject: [PATCH 09/20] Remove specific style actions and use ThemeManager instead Remove the specific style actions from the main window and use the ThemeManager instead to fill the Styles submenu. Also rename option lastUsedStyle to lastUsedTheme. --- app/mainwindow.cpp | 132 ++++++++++++++++++++------------------------- app/mainwindow.h | 17 +++--- app/mainwindow.ui | 7 --- app/options.cpp | 45 ++++++++++++---- app/options.h | 11 ++-- 5 files changed, 110 insertions(+), 102 deletions(-) diff --git a/app/mainwindow.cpp b/app/mainwindow.cpp index a4d79707..5b7fc4e0 100644 --- a/app/mainwindow.cpp +++ b/app/mainwindow.cpp @@ -47,6 +47,7 @@ #include #include #include +#include #include #include "controls/activelabel.h" #include "controls/findreplacewidget.h" @@ -78,6 +79,7 @@ MainWindow::MainWindow(const QString &fileName, QWidget *parent) : snippetCollection(new SnippetCollection(this)), viewSynchronizer(0), htmlPreviewController(0), + themeManager(new ThemeManager()), splitFactor(0.5), rightViewCollapsed(false) { @@ -124,8 +126,10 @@ void MainWindow::initializeApp() ui->webView->page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks); ui->tocWebView->page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks); - // set last used style - lastUsedStyle(); + setupHtmlPreviewThemes(); + + // apply last used theme + lastUsedTheme(); ui->plainTextEdit->tabWidthChanged(options->tabWidth()); @@ -464,97 +468,61 @@ void MainWindow::viewChangeSplit() } } -void MainWindow::lastUsedStyle() +void MainWindow::lastUsedTheme() { - if (stylesGroup) { - foreach(QAction *action, stylesGroup->actions()) { - if (action->objectName() == options->lastUsedStyle()) { - action->trigger(); - } - } - } -} + QString themeName = options->lastUsedTheme(); -void MainWindow::styleDefault() -{ - generator->setCodeHighlightingStyle("default"); - ui->plainTextEdit->loadStyleFromStylesheet(stylePath("default")); - ui->webView->page()->settings()->setUserStyleSheetUrl(QUrl("qrc:/css/markdown.css")); + currentTheme = themeManager->themeByName(themeName); + applyCurrentTheme(); - styleLabel->setText(ui->actionDefault->text()); - options->setLastUsedStyle(ui->actionDefault->objectName()); + styleLabel->setText(themeName); } -void MainWindow::styleGithub() +void MainWindow::themeChanged() { - generator->setCodeHighlightingStyle("github"); - ui->plainTextEdit->loadStyleFromStylesheet(stylePath("default")); - ui->webView->page()->settings()->setUserStyleSheetUrl(QUrl("qrc:/css/github.css")); - - styleLabel->setText(ui->actionGithub->text()); - options->setLastUsedStyle(ui->actionGithub->objectName()); -} + QAction *action = qobject_cast(sender()); + QString themeName = action->text(); -void MainWindow::styleSolarizedLight() -{ - generator->setCodeHighlightingStyle("solarized_light"); - ui->plainTextEdit->loadStyleFromStylesheet(stylePath("solarized-light")); - ui->webView->page()->settings()->setUserStyleSheetUrl(QUrl("qrc:/css/solarized-light.css")); + currentTheme = themeManager->themeByName(themeName); + applyCurrentTheme(); - styleLabel->setText(ui->actionSolarizedLight->text()); - options->setLastUsedStyle(ui->actionSolarizedLight->objectName()); + styleLabel->setText(themeName); + options->setLastUsedTheme(themeName); } -void MainWindow::styleSolarizedDark() +void MainWindow::editorStyleChanged() { - generator->setCodeHighlightingStyle("solarized_dark"); - ui->plainTextEdit->loadStyleFromStylesheet(stylePath("solarized-dark")); - ui->webView->page()->settings()->setUserStyleSheetUrl(QUrl("qrc:/css/solarized-dark.css")); - - styleLabel->setText(ui->actionSolarizedDark->text()); - options->setLastUsedStyle(ui->actionSolarizedDark->objectName()); + QString markdownHighlighting = ThemeManager::markdownHighlightingPath(currentTheme); + ui->plainTextEdit->loadStyleFromStylesheet(stylePath(markdownHighlighting)); } -void MainWindow::styleClearness() +void MainWindow::styleCustomStyle() { - generator->setCodeHighlightingStyle("default"); - ui->plainTextEdit->loadStyleFromStylesheet(stylePath("default")); - ui->webView->page()->settings()->setUserStyleSheetUrl(QUrl("qrc:/css/clearness.css")); + QAction *action = qobject_cast(sender()); - styleLabel->setText(ui->actionClearness->text()); - options->setLastUsedStyle(ui->actionClearness->objectName()); -} + currentTheme = { action->text(), "Default", "Default", action->data().toString() }; -void MainWindow::styleClearnessDark() -{ - generator->setCodeHighlightingStyle("default"); - ui->plainTextEdit->loadStyleFromStylesheet(stylePath("clearness-dark")); - ui->webView->page()->settings()->setUserStyleSheetUrl(QUrl("qrc:/css/clearness-dark.css")); + QString markdownHighlighting = ThemeManager::markdownHighlightingPath(currentTheme); + QString codeHighlighting = ThemeManager::codeHighlightingPath(currentTheme); + QString previewStylesheet = ThemeManager::previewStylesheetPath(currentTheme); - styleLabel->setText(ui->actionClearnessDark->text()); - options->setLastUsedStyle(ui->actionClearnessDark->objectName()); -} + generator->setCodeHighlightingStyle(codeHighlighting); + ui->plainTextEdit->loadStyleFromStylesheet(stylePath(markdownHighlighting)); + ui->webView->page()->settings()->setUserStyleSheetUrl(QUrl::fromLocalFile(previewStylesheet)); -void MainWindow::styleBywordDark() -{ - generator->setCodeHighlightingStyle("default"); - ui->plainTextEdit->loadStyleFromStylesheet(stylePath("byword-dark")); - ui->webView->page()->settings()->setUserStyleSheetUrl(QUrl("qrc:/css/byword-dark.css")); - - styleLabel->setText(ui->actionBywordDark->text()); - options->setLastUsedStyle(ui->actionBywordDark->objectName()); + styleLabel->setText(action->text()); + options->setLastUsedTheme(action->objectName()); } -void MainWindow::styleCustomStyle() +void MainWindow::applyCurrentTheme() { - QAction *action = qobject_cast(sender()); - - generator->setCodeHighlightingStyle("default"); - ui->plainTextEdit->loadStyleFromStylesheet(stylePath("default")); - ui->webView->page()->settings()->setUserStyleSheetUrl(QUrl::fromLocalFile(action->data().toString())); + QString markdownHighlighting = ThemeManager::markdownHighlightingPath(currentTheme); + QString codeHighlighting = ThemeManager::codeHighlightingPath(currentTheme); + QString previewStylesheet = ThemeManager::previewStylesheetPath(currentTheme); - styleLabel->setText(action->text()); - options->setLastUsedStyle(action->objectName()); + generator->setCodeHighlightingStyle(codeHighlighting); + ui->plainTextEdit->loadStyleFromStylesheet(stylePath(markdownHighlighting)); + ui->webView->page()->settings()->setUserStyleSheetUrl(QUrl(previewStylesheet)); } void MainWindow::viewFullScreenMode() @@ -949,8 +917,8 @@ void MainWindow::setupUi() this, SLOT(proxyConfigurationChanged())); connect(options, SIGNAL(markdownConverterChanged()), this, SLOT(markdownConverterChanged())); - connect(options, SIGNAL(editorFontChanged(QFont)), - this, SLOT(lastUsedStyle())); + connect(options, &Options::editorStyleChanged, + this, &MainWindow::editorStyleChanged); readSettings(); setupCustomShortcuts(); @@ -1231,6 +1199,24 @@ void MainWindow::updateSplitter() ui->splitter->setSizes(childSizes); } +void MainWindow::setupHtmlPreviewThemes() +{ + ui->menuStyles->clear(); + + delete stylesGroup; + stylesGroup = new QActionGroup(this); + + int key = 1; + foreach(const QString &themeName, themeManager->themeNames()) { + QAction *action = ui->menuStyles->addAction(themeName); + action->setShortcut(QKeySequence(tr("Ctrl+%1").arg(key++))); + action->setCheckable(true); + action->setActionGroup(stylesGroup); + connect(action, &QAction::triggered, + this, &MainWindow::themeChanged); + } +} + void MainWindow::loadCustomStyles() { QStringList paths = DataLocation::standardLocations(); diff --git a/app/mainwindow.h b/app/mainwindow.h index 9e001a71..23f15b68 100644 --- a/app/mainwindow.h +++ b/app/mainwindow.h @@ -20,6 +20,7 @@ #include #include #include +#include namespace Ui { class MainWindow; @@ -37,6 +38,7 @@ class RecentFilesMenu; class Options; class SlideLineMapping; class SnippetCollection; +class ThemeManager; class ViewSynchronizer; @@ -83,14 +85,9 @@ private slots: void editInsertImage(); void viewChangeSplit(); - void lastUsedStyle(); - void styleDefault(); - void styleGithub(); - void styleSolarizedLight(); - void styleSolarizedDark(); - void styleClearness(); - void styleClearnessDark(); - void styleBywordDark(); + void lastUsedTheme(); + void themeChanged(); + void editorStyleChanged(); void styleCustomStyle(); void viewFullScreenMode(); void viewHorizontalLayout(bool checked); @@ -143,9 +140,11 @@ private slots: bool maybeSave(); void setFileName(const QString &fileName); void updateSplitter(); + void setupHtmlPreviewThemes(); void loadCustomStyles(); void readSettings(); void writeSettings(); + void applyCurrentTheme(); QString stylePath(const QString &styleName); private: @@ -161,6 +160,8 @@ private slots: SnippetCollection *snippetCollection; ViewSynchronizer *viewSynchronizer; HtmlPreviewController *htmlPreviewController; + ThemeManager *themeManager; + Theme currentTheme { "Default", "Default", "Default", "Default" }; QString fileName; float splitFactor; bool rightViewCollapsed; diff --git a/app/mainwindow.ui b/app/mainwindow.ui index 0de78cd1..a2a30a71 100644 --- a/app/mainwindow.ui +++ b/app/mainwindow.ui @@ -258,13 +258,6 @@ St&yles - - - - - - - diff --git a/app/options.cpp b/app/options.cpp index d708acd8..602a25e1 100644 --- a/app/options.cpp +++ b/app/options.cpp @@ -16,13 +16,12 @@ */ #include "options.h" -#include #include static const char* MARKDOWN_CONVERTER = "general/converter"; -static const char* LAST_USED_STYLE = "general/lastusedstyle"; -static const char* STYLE_DEFAULT = "actionDefault"; +static const char* LAST_USED_THEME = "general/lastusedtheme"; +static const char* THEME_DEFAULT = "Default"; static const char* FONT_FAMILY_DEFAULT = "Monospace"; static const char* FONT_FAMILY = "editor/font/family"; static const char* FONT_SIZE = "editor/font/size"; @@ -56,6 +55,7 @@ static const char* DICTIONARY_LANGUAGE = "spelling/language"; static const char* YAMLHEADERSUPPORT_ENABLED = "yamlheadersupport/enabled"; static const char* DIAGRAMSUPPORT_ENABLED = "diagramsupport/enabled"; +static const char* DEPRECATED__LAST_USED_STYLE = "general/lastusedstyle"; Options::Options(QObject *parent) : QObject(parent), @@ -78,7 +78,7 @@ Options::Options(QObject *parent) : m_spellingCheckEnabled(true), m_diagramSupportEnabled(false), m_markdownConverter(DiscountMarkdownConverter), - m_lastUsedStyle(STYLE_DEFAULT) + m_lastUsedTheme(THEME_DEFAULT) { } @@ -94,7 +94,6 @@ void Options::apply() emit proxyConfigurationChanged(); emit markdownConverterChanged(); - emit editorFontChanged(editorFont()); } QFont Options::editorFont() const @@ -373,6 +372,7 @@ bool Options::isSourceAtSingleSizeEnabled() const void Options::setSourceAtSingleSizeEnabled(bool enabled) { m_sourceAtSingleSizeEnabled = enabled; + emit editorStyleChanged(); } bool Options::isSpellingCheckEnabled() const @@ -428,14 +428,14 @@ void Options::setMarkdownConverter(Options::MarkdownConverter converter) } } -QString Options::lastUsedStyle() const +QString Options::lastUsedTheme() const { - return m_lastUsedStyle; + return m_lastUsedTheme; } -void Options::setLastUsedStyle(const QString &style) +void Options::setLastUsedTheme(const QString &theme) { - m_lastUsedStyle = style; + m_lastUsedTheme = theme; } void Options::readSettings() @@ -444,7 +444,7 @@ void Options::readSettings() // general settings m_markdownConverter = (Options::MarkdownConverter)settings.value(MARKDOWN_CONVERTER, 0).toInt(); - m_lastUsedStyle = settings.value(LAST_USED_STYLE, STYLE_DEFAULT).toString(); + m_lastUsedTheme = settings.value(LAST_USED_THEME, THEME_DEFAULT).toString(); // editor settings QString fontFamily = settings.value(FONT_FAMILY, FONT_FAMILY_DEFAULT).toString(); @@ -502,6 +502,11 @@ void Options::readSettings() m_spellingCheckEnabled = settings.value(SPELLINGCHECK_ENABLED, true).toBool(); m_dictionaryLanguage = settings.value(DICTIONARY_LANGUAGE, "en_US").toString(); + // migrate deprecated lastUsedStyle option + if (settings.contains(DEPRECATED__LAST_USED_STYLE)) { + migrateLastUsedStyleOption(settings); + } + apply(); } @@ -511,7 +516,7 @@ void Options::writeSettings() // general settings settings.setValue(MARKDOWN_CONVERTER, m_markdownConverter); - settings.setValue(LAST_USED_STYLE, m_lastUsedStyle); + settings.setValue(LAST_USED_THEME, m_lastUsedTheme); // editor settings settings.setValue(FONT_FAMILY, font.family()); @@ -564,3 +569,21 @@ void Options::writeSettings() settings.setValue(SPELLINGCHECK_ENABLED, m_spellingCheckEnabled); settings.setValue(DICTIONARY_LANGUAGE, m_dictionaryLanguage); } + +void Options::migrateLastUsedStyleOption(QSettings &settings) +{ + static const QMap migrations { + { "actionDefault", "Default" }, + { "actionGithub", "Github" }, + { "actionSolarizedLight", "Solarized Light" }, + { "actionSolarizedDark", "Solarized Dark" }, + { "actionClearness", "Clearness" }, + { "actionClearnessDark", "Clearness Dark" }, + { "actionBywordDark", "Byword Dark" } + }; + + QString lastUsedStyle = settings.value(DEPRECATED__LAST_USED_STYLE).toString(); + m_lastUsedTheme = migrations[lastUsedStyle]; + + settings.remove(DEPRECATED__LAST_USED_STYLE); +} diff --git a/app/options.h b/app/options.h index 8cc2c809..c281c6a3 100644 --- a/app/options.h +++ b/app/options.h @@ -21,6 +21,7 @@ #include #include #include +#include class Options : public QObject { @@ -139,18 +140,22 @@ class Options : public QObject MarkdownConverter markdownConverter() const; void setMarkdownConverter(MarkdownConverter converter); - QString lastUsedStyle() const; - void setLastUsedStyle(const QString &style); + QString lastUsedTheme() const; + void setLastUsedTheme(const QString &theme); void readSettings(); void writeSettings(); signals: void editorFontChanged(const QFont &font); + void editorStyleChanged(); void tabWidthChanged(int tabWidth); void proxyConfigurationChanged(); void markdownConverterChanged(); +private: + void migrateLastUsedStyleOption(QSettings &settings); + private: QFont font; int m_tabWidth; @@ -177,7 +182,7 @@ class Options : public QObject bool m_diagramSupportEnabled; QString m_dictionaryLanguage; MarkdownConverter m_markdownConverter; - QString m_lastUsedStyle; + QString m_lastUsedTheme; QString m_standardFontFamily; QString m_fixedFontFamily; QString m_serifFontFamily; From 103dcda5c26c55325ef623e4654869d961103067 Mon Sep 17 00:00:00 2001 From: Christian Loose Date: Fri, 11 Dec 2015 15:57:25 +0100 Subject: [PATCH 10/20] Fix build on Travis CI by upgrading g++ to 4.8 --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 06654b9c..6626679f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,8 +3,10 @@ compiler: - gcc - clang before_install: + - sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test # for g++ 4.8 - sudo add-apt-repository -y ppa:beineri/opt-qt521 # for Qt 5.2 - sudo apt-get update -qq + - sudo apt-get install -qq g++-4.8 - "export DISPLAY=:99.0" - "sh -e /etc/init.d/xvfb start" install: From 0f93a402dc75913250c1b174dc66723f0c0f8c4d Mon Sep 17 00:00:00 2001 From: Christian Loose Date: Fri, 11 Dec 2015 19:10:21 +0100 Subject: [PATCH 11/20] Fix build on Travis CI by upgrading g++ to 4.8 --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6626679f..9c22a3ce 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,15 +1,15 @@ language: cpp compiler: - - gcc + - g++ - clang before_install: - sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test # for g++ 4.8 - sudo add-apt-repository -y ppa:beineri/opt-qt521 # for Qt 5.2 - sudo apt-get update -qq - - sudo apt-get install -qq g++-4.8 - "export DISPLAY=:99.0" - "sh -e /etc/init.d/xvfb start" install: + - if [ "$CXX" == "g++" ]; then sudo apt-get install -qq g++-4.8; sudo update-alternatives --install /usr/bin/g++ /usr/bin/g++-4.8 90; fi - sudo apt-get install -qq qt52base qt52declarative qt52webkit qt52tools libhunspell-dev - sudo apt-get install -qq libgstreamer0.10-dev libgstreamer-plugins-base0.10-dev before_script: From a0d8c84c11f498d4a025401b6b101be36d45e697 Mon Sep 17 00:00:00 2001 From: Christian Loose Date: Fri, 11 Dec 2015 19:15:40 +0100 Subject: [PATCH 12/20] Fix build on Travis CI by upgrading g++ to 4.8 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 9c22a3ce..23de3ef6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,7 @@ before_install: - "export DISPLAY=:99.0" - "sh -e /etc/init.d/xvfb start" install: - - if [ "$CXX" == "g++" ]; then sudo apt-get install -qq g++-4.8; sudo update-alternatives --install /usr/bin/g++ /usr/bin/g++-4.8 90; fi + - if [ "$CXX" == "g++" ]; then sudo apt-get install -qq g++-4.8; sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 90; fi - sudo apt-get install -qq qt52base qt52declarative qt52webkit qt52tools libhunspell-dev - sudo apt-get install -qq libgstreamer0.10-dev libgstreamer-plugins-base0.10-dev before_script: From e91a1d03734c50e04cbc8e93491635e5cd29130e Mon Sep 17 00:00:00 2001 From: Christian Loose Date: Tue, 15 Dec 2015 17:21:01 +0100 Subject: [PATCH 13/20] Move theme handling fully to ThemeCollection class * Remove theme collection management from ThemeManager * Rename ThemeManager to StyleManager. The class is now responsible for mapping style names in themes to paths to style file. --- app-static/app-static.pro | 4 +- .../{thememanager.cpp => stylemanager.cpp} | 34 ++----------- .../themes/{thememanager.h => stylemanager.h} | 19 ++------ app-static/themes/themecollection.cpp | 7 +++ app-static/themes/themecollection.h | 2 + app/mainwindow.cpp | 27 ++++++----- app/mainwindow.h | 4 +- test/integration/integration.pro | 4 +- test/integration/main.cpp | 4 +- ...anagertest.cpp => themecollectiontest.cpp} | 36 +++++--------- ...ememanagertest.h => themecollectiontest.h} | 10 ++-- test/unit/main.cpp | 4 +- ...memanagertest.cpp => stylemanagertest.cpp} | 48 +++++++++---------- ...{thememanagertest.h => stylemanagertest.h} | 8 ++-- test/unit/unit.pro | 4 +- 15 files changed, 90 insertions(+), 125 deletions(-) rename app-static/themes/{thememanager.cpp => stylemanager.cpp} (71%) rename app-static/themes/{thememanager.h => stylemanager.h} (72%) rename test/integration/{thememanagertest.cpp => themecollectiontest.cpp} (63%) rename test/integration/{thememanagertest.h => themecollectiontest.h} (84%) rename test/unit/{thememanagertest.cpp => stylemanagertest.cpp} (60%) rename test/unit/{thememanagertest.h => stylemanagertest.h} (88%) diff --git a/app-static/app-static.pro b/app-static/app-static.pro index 7a1a16cc..d697818d 100644 --- a/app-static/app-static.pro +++ b/app-static/app-static.pro @@ -22,9 +22,9 @@ SOURCES += \ template/htmltemplate.cpp \ template/presentationtemplate.cpp \ themes/jsonthemetranslator.cpp \ + themes/stylemanager.cpp \ themes/theme.cpp \ themes/themecollection.cpp \ - themes/thememanager.cpp \ completionlistmodel.cpp \ datalocation.cpp \ slidelinemapping.cpp \ @@ -49,9 +49,9 @@ HEADERS += \ template/presentationtemplate.h \ themes/jsonthemetranslator.h \ themes/jsonthemetranslatorfactory.h \ + themes/stylemanager.h \ themes/theme.h \ themes/themecollection.h \ - themes/thememanager.h \ completionlistmodel.h \ datalocation.h \ slidelinemapping.h \ diff --git a/app-static/themes/thememanager.cpp b/app-static/themes/stylemanager.cpp similarity index 71% rename from app-static/themes/thememanager.cpp rename to app-static/themes/stylemanager.cpp index 4f8ef6b4..f3eb187c 100644 --- a/app-static/themes/thememanager.cpp +++ b/app-static/themes/stylemanager.cpp @@ -14,10 +14,9 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -#include "thememanager.h" +#include "stylemanager.h" -#include -#include +#include static const QMap BUILTIN_MARKDOWN_HIGHLIGHTINGS = { @@ -45,40 +44,17 @@ static const QMap BUILTIN_PREVIEW_STYLESHEETS = { { "Byword Dark", "qrc:/css/byword-dark.css" } }; -ThemeCollection ThemeManager::m_htmlPreviewThemes; - - -ThemeManager::ThemeManager() : - ThemeManager(":/builtin-htmlpreview-themes.json") -{ -} - -ThemeManager::ThemeManager(const QString &themeFileName) -{ - JsonFile::load(themeFileName, &m_htmlPreviewThemes); -} - -Theme ThemeManager::themeByName(const QString &name) const -{ - return m_htmlPreviewThemes.theme(name); -} - -QStringList ThemeManager::themeNames() const -{ - return m_htmlPreviewThemes.themeNames(); -} - -QString ThemeManager::markdownHighlightingPath(const Theme &theme) +QString StyleManager::markdownHighlightingPath(const Theme &theme) { return BUILTIN_MARKDOWN_HIGHLIGHTINGS[theme.markdownHighlighting()]; } -QString ThemeManager::codeHighlightingPath(const Theme &theme) +QString StyleManager::codeHighlightingPath(const Theme &theme) { return BUILTIN_CODE_HIGHLIGHTINGS[theme.codeHighlighting()]; } -QString ThemeManager::previewStylesheetPath(const Theme &theme) +QString StyleManager::previewStylesheetPath(const Theme &theme) { return BUILTIN_PREVIEW_STYLESHEETS[theme.previewStylesheet()]; } diff --git a/app-static/themes/thememanager.h b/app-static/themes/stylemanager.h similarity index 72% rename from app-static/themes/thememanager.h rename to app-static/themes/stylemanager.h index 1c2ab4da..0b4fed56 100644 --- a/app-static/themes/thememanager.h +++ b/app-static/themes/stylemanager.h @@ -14,31 +14,20 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -#ifndef THEMEMANAGER_H -#define THEMEMANAGER_H +#ifndef STYLEMANAGER_H +#define STYLEMANAGER_H -#include #include #include "theme.h" -#include "themecollection.h" -class ThemeManager +class StyleManager { public: - ThemeManager(); - explicit ThemeManager(const QString &themeFileName); - - Theme themeByName(const QString &name) const; - QStringList themeNames() const; - static QString markdownHighlightingPath(const Theme &theme); static QString codeHighlightingPath(const Theme &theme); static QString previewStylesheetPath(const Theme &theme); - -private: - static ThemeCollection m_htmlPreviewThemes; }; -#endif // THEMEMANAGER_H +#endif // STYLEMANAGER_H diff --git a/app-static/themes/themecollection.cpp b/app-static/themes/themecollection.cpp index 981767d8..4f4fe52f 100644 --- a/app-static/themes/themecollection.cpp +++ b/app-static/themes/themecollection.cpp @@ -16,6 +16,13 @@ */ #include "themecollection.h" +#include +#include + +bool ThemeCollection::load(const QString &fileName) +{ + return JsonFile::load(fileName, this); +} int ThemeCollection::insert(const Theme &theme) { diff --git a/app-static/themes/themecollection.h b/app-static/themes/themecollection.h index 6c2c6ae5..30cd0113 100644 --- a/app-static/themes/themecollection.h +++ b/app-static/themes/themecollection.h @@ -26,6 +26,8 @@ class ThemeCollection : public JsonCollection { public: + bool load(const QString &fileName); + int insert(const Theme &theme); int count() const; diff --git a/app/mainwindow.cpp b/app/mainwindow.cpp index 5b7fc4e0..b85bab21 100644 --- a/app/mainwindow.cpp +++ b/app/mainwindow.cpp @@ -47,7 +47,8 @@ #include #include #include -#include +#include +#include #include #include "controls/activelabel.h" #include "controls/findreplacewidget.h" @@ -79,7 +80,7 @@ MainWindow::MainWindow(const QString &fileName, QWidget *parent) : snippetCollection(new SnippetCollection(this)), viewSynchronizer(0), htmlPreviewController(0), - themeManager(new ThemeManager()), + themeCollection(new ThemeCollection()), splitFactor(0.5), rightViewCollapsed(false) { @@ -472,7 +473,7 @@ void MainWindow::lastUsedTheme() { QString themeName = options->lastUsedTheme(); - currentTheme = themeManager->themeByName(themeName); + currentTheme = themeCollection->theme(themeName); applyCurrentTheme(); styleLabel->setText(themeName); @@ -483,7 +484,7 @@ void MainWindow::themeChanged() QAction *action = qobject_cast(sender()); QString themeName = action->text(); - currentTheme = themeManager->themeByName(themeName); + currentTheme = themeCollection->theme(themeName); applyCurrentTheme(); styleLabel->setText(themeName); @@ -492,7 +493,7 @@ void MainWindow::themeChanged() void MainWindow::editorStyleChanged() { - QString markdownHighlighting = ThemeManager::markdownHighlightingPath(currentTheme); + QString markdownHighlighting = StyleManager::markdownHighlightingPath(currentTheme); ui->plainTextEdit->loadStyleFromStylesheet(stylePath(markdownHighlighting)); } @@ -502,9 +503,9 @@ void MainWindow::styleCustomStyle() currentTheme = { action->text(), "Default", "Default", action->data().toString() }; - QString markdownHighlighting = ThemeManager::markdownHighlightingPath(currentTheme); - QString codeHighlighting = ThemeManager::codeHighlightingPath(currentTheme); - QString previewStylesheet = ThemeManager::previewStylesheetPath(currentTheme); + QString markdownHighlighting = StyleManager::markdownHighlightingPath(currentTheme); + QString codeHighlighting = StyleManager::codeHighlightingPath(currentTheme); + QString previewStylesheet = StyleManager::previewStylesheetPath(currentTheme); generator->setCodeHighlightingStyle(codeHighlighting); ui->plainTextEdit->loadStyleFromStylesheet(stylePath(markdownHighlighting)); @@ -516,9 +517,9 @@ void MainWindow::styleCustomStyle() void MainWindow::applyCurrentTheme() { - QString markdownHighlighting = ThemeManager::markdownHighlightingPath(currentTheme); - QString codeHighlighting = ThemeManager::codeHighlightingPath(currentTheme); - QString previewStylesheet = ThemeManager::previewStylesheetPath(currentTheme); + QString markdownHighlighting = StyleManager::markdownHighlightingPath(currentTheme); + QString codeHighlighting = StyleManager::codeHighlightingPath(currentTheme); + QString previewStylesheet = StyleManager::previewStylesheetPath(currentTheme); generator->setCodeHighlightingStyle(codeHighlighting); ui->plainTextEdit->loadStyleFromStylesheet(stylePath(markdownHighlighting)); @@ -1201,13 +1202,15 @@ void MainWindow::updateSplitter() void MainWindow::setupHtmlPreviewThemes() { + themeCollection->load(":/builtin-htmlpreview-themes.json"); + ui->menuStyles->clear(); delete stylesGroup; stylesGroup = new QActionGroup(this); int key = 1; - foreach(const QString &themeName, themeManager->themeNames()) { + foreach(const QString &themeName, themeCollection->themeNames()) { QAction *action = ui->menuStyles->addAction(themeName); action->setShortcut(QKeySequence(tr("Ctrl+%1").arg(key++))); action->setCheckable(true); diff --git a/app/mainwindow.h b/app/mainwindow.h index 23f15b68..da354759 100644 --- a/app/mainwindow.h +++ b/app/mainwindow.h @@ -38,7 +38,7 @@ class RecentFilesMenu; class Options; class SlideLineMapping; class SnippetCollection; -class ThemeManager; +class ThemeCollection; class ViewSynchronizer; @@ -160,7 +160,7 @@ private slots: SnippetCollection *snippetCollection; ViewSynchronizer *viewSynchronizer; HtmlPreviewController *htmlPreviewController; - ThemeManager *themeManager; + ThemeCollection *themeCollection; Theme currentTheme { "Default", "Default", "Default", "Default" }; QString fileName; float splitFactor; diff --git a/test/integration/integration.pro b/test/integration/integration.pro index 5e0a0f35..9618d74e 100644 --- a/test/integration/integration.pro +++ b/test/integration/integration.pro @@ -19,7 +19,7 @@ SOURCES += \ main.cpp \ pmhmarkdownparsertest.cpp \ revealmarkdownconvertertest.cpp \ - thememanagertest.cpp + themecollectiontest.cpp HEADERS += \ discountmarkdownconvertertest.h \ @@ -29,7 +29,7 @@ HEADERS += \ jsonthemefiletest.h \ pmhmarkdownparsertest.h \ revealmarkdownconvertertest.h \ - thememanagertest.h + themecollectiontest.h target.CONFIG += no_default_install diff --git a/test/integration/main.cpp b/test/integration/main.cpp index 0ce05c39..a670e1c6 100644 --- a/test/integration/main.cpp +++ b/test/integration/main.cpp @@ -25,7 +25,7 @@ #include "jsonthemefiletest.h" #include "pmhmarkdownparsertest.h" #include "revealmarkdownconvertertest.h" -#include "thememanagertest.h" +#include "themecollectiontest.h" #ifdef ENABLE_HOEDOWN #include "hoedownmarkdownconvertertest.h" @@ -63,7 +63,7 @@ int main(int argc, char *argv[]) JsonThemeFileTest test8; ret += QTest::qExec(&test8, argc, argv); - ThemeManagerTest test9; + ThemeCollectionTest test9; ret += QTest::qExec(&test9, argc, argv); return ret; diff --git a/test/integration/thememanagertest.cpp b/test/integration/themecollectiontest.cpp similarity index 63% rename from test/integration/thememanagertest.cpp rename to test/integration/themecollectiontest.cpp index 26828b74..f97e78ff 100644 --- a/test/integration/thememanagertest.cpp +++ b/test/integration/themecollectiontest.cpp @@ -14,19 +14,19 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -#include "thememanagertest.h" +#include "themecollectiontest.h" #include -#include +#include -void ThemeManagerTest::initTestCase() +void ThemeCollectionTest::initTestCase() { - QTemporaryFile themeFile(this); - if (!themeFile.open()) + themeFile = new QTemporaryFile(this); + if (!themeFile->open()) QFAIL("Failed to create temporary theme file"); - QTextStream out(&themeFile); + QTextStream out(themeFile); out << "{ \"themes\": [" << " { \"name\": \"default\"," << " \"markdownHighlighting\": \"default\"," @@ -36,33 +36,21 @@ void ThemeManagerTest::initTestCase() << " \"markdownHighlighting\": \"dark\"," << " \"codeHighlighting\": \"black\"," << " \"previewStylesheet\": \"dark\" } ] }"; - - themeFile.close(); - - themeManager = new ThemeManager(themeFile.fileName()); } -void ThemeManagerTest::cleanupTestCase() +void ThemeCollectionTest::cleanupTestCase() { - delete themeManager; + themeFile->close(); } -void ThemeManagerTest::returnsBuiltinThemeByName() +void ThemeCollectionTest::loadsThemesFromFileIntoCollection() { - Theme actual = themeManager->themeByName("dark"); - - QCOMPARE(actual.name(), QLatin1String("dark")); - QCOMPARE(actual.markdownHighlighting(), QLatin1String("dark")); - QCOMPARE(actual.codeHighlighting(), QLatin1String("black")); - QCOMPARE(actual.previewStylesheet(), QLatin1String("dark")); -} + ThemeCollection themeCollection; -void ThemeManagerTest::returnsNameOfAllBuiltinThemes() -{ - QStringList themeNames = themeManager->themeNames(); + themeCollection.load(themeFile->fileName()); + QStringList themeNames = themeCollection.themeNames(); QCOMPARE(themeNames.count(), 2); QCOMPARE(themeNames.at(0), QLatin1String("default")); QCOMPARE(themeNames.at(1), QLatin1String("dark")); } - diff --git a/test/integration/thememanagertest.h b/test/integration/themecollectiontest.h similarity index 84% rename from test/integration/thememanagertest.h rename to test/integration/themecollectiontest.h index 0485acbc..80f2c3d3 100644 --- a/test/integration/thememanagertest.h +++ b/test/integration/themecollectiontest.h @@ -18,10 +18,11 @@ #define THEMEMANAGERTEST_H #include -class ThemeManager; +class QTemporaryFile; +class ThemeCollection; -class ThemeManagerTest : public QObject +class ThemeCollectionTest : public QObject { Q_OBJECT @@ -29,11 +30,10 @@ private slots: void initTestCase(); void cleanupTestCase(); - void returnsBuiltinThemeByName(); - void returnsNameOfAllBuiltinThemes(); + void loadsThemesFromFileIntoCollection(); private: - ThemeManager *themeManager; + QTemporaryFile *themeFile; }; #endif // THEMEMANAGERTEST_H diff --git a/test/unit/main.cpp b/test/unit/main.cpp index 8e29a615..768e25cb 100644 --- a/test/unit/main.cpp +++ b/test/unit/main.cpp @@ -24,8 +24,8 @@ #include "snippetcollectiontest.h" #include "completionlistmodeltest.h" #include "snippettest.h" +#include "stylemanagertest.h" #include "themecollectiontest.h" -#include "thememanagertest.h" #include "themetest.h" #include "yamlheadercheckertest.h" @@ -63,7 +63,7 @@ int main(int argc, char *argv[]) ThemeCollectionTest test10; ret += QTest::qExec(&test10, argc, argv); - ThemeManagerTest test11; + StyleManagerTest test11; ret += QTest::qExec(&test11, argc, argv); JsonThemeTranslatorTest test12; diff --git a/test/unit/thememanagertest.cpp b/test/unit/stylemanagertest.cpp similarity index 60% rename from test/unit/thememanagertest.cpp rename to test/unit/stylemanagertest.cpp index fdcc0046..8e0a9434 100644 --- a/test/unit/thememanagertest.cpp +++ b/test/unit/stylemanagertest.cpp @@ -14,11 +14,11 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -#include "thememanagertest.h" +#include "stylemanagertest.h" #include -#include +#include static const Theme defaultTheme("Default", "Default", "Default", "Default"); static const Theme githubTheme("Github", "Github", "Github", "Github"); @@ -28,37 +28,37 @@ static const Theme clearnessTheme("Clearness", "Clearness", "Clearness", "Clearn static const Theme clearnessDarkTheme("Clearness Dark", "Clearness Dark", "Clearness Dark", "Clearness Dark"); static const Theme bywordDarkTheme("Byword Dark", "Byword Dark", "Byword Dark", "Byword Dark"); -void ThemeManagerTest::returnsPathForMarkdownHighlighting() +void StyleManagerTest::returnsPathForMarkdownHighlighting() { - ThemeManager themeManager; + StyleManager styleManager; - QCOMPARE(themeManager.markdownHighlightingPath(defaultTheme), QLatin1String("default")); - QCOMPARE(themeManager.markdownHighlightingPath(solarizedLightTheme), QLatin1String("solarized-light")); - QCOMPARE(themeManager.markdownHighlightingPath(solarizedDarkTheme), QLatin1String("solarized-dark")); - QCOMPARE(themeManager.markdownHighlightingPath(clearnessDarkTheme), QLatin1String("clearness-dark")); - QCOMPARE(themeManager.markdownHighlightingPath(bywordDarkTheme), QLatin1String("byword-dark")); + QCOMPARE(styleManager.markdownHighlightingPath(defaultTheme), QLatin1String("default")); + QCOMPARE(styleManager.markdownHighlightingPath(solarizedLightTheme), QLatin1String("solarized-light")); + QCOMPARE(styleManager.markdownHighlightingPath(solarizedDarkTheme), QLatin1String("solarized-dark")); + QCOMPARE(styleManager.markdownHighlightingPath(clearnessDarkTheme), QLatin1String("clearness-dark")); + QCOMPARE(styleManager.markdownHighlightingPath(bywordDarkTheme), QLatin1String("byword-dark")); } -void ThemeManagerTest::returnsPathForCodeHighlighting() +void StyleManagerTest::returnsPathForCodeHighlighting() { - ThemeManager themeManager; + StyleManager styleManager; - QCOMPARE(themeManager.codeHighlightingPath(defaultTheme), QLatin1String("default")); - QCOMPARE(themeManager.codeHighlightingPath(githubTheme), QLatin1String("github")); - QCOMPARE(themeManager.codeHighlightingPath(solarizedLightTheme), QLatin1String("solarized_light")); - QCOMPARE(themeManager.codeHighlightingPath(solarizedDarkTheme), QLatin1String("solarized_dark")); + QCOMPARE(styleManager.codeHighlightingPath(defaultTheme), QLatin1String("default")); + QCOMPARE(styleManager.codeHighlightingPath(githubTheme), QLatin1String("github")); + QCOMPARE(styleManager.codeHighlightingPath(solarizedLightTheme), QLatin1String("solarized_light")); + QCOMPARE(styleManager.codeHighlightingPath(solarizedDarkTheme), QLatin1String("solarized_dark")); } -void ThemeManagerTest::returnsPathForPreviewStylesheet() +void StyleManagerTest::returnsPathForPreviewStylesheet() { - ThemeManager themeManager; + StyleManager styleManager; - QCOMPARE(themeManager.previewStylesheetPath(defaultTheme), QLatin1String("qrc:/css/markdown.css")); - QCOMPARE(themeManager.previewStylesheetPath(githubTheme), QLatin1String("qrc:/css/github.css")); - QCOMPARE(themeManager.previewStylesheetPath(solarizedLightTheme), QLatin1String("qrc:/css/solarized-light.css")); - QCOMPARE(themeManager.previewStylesheetPath(solarizedDarkTheme), QLatin1String("qrc:/css/solarized-dark.css")); - QCOMPARE(themeManager.previewStylesheetPath(clearnessTheme), QLatin1String("qrc:/css/clearness.css")); - QCOMPARE(themeManager.previewStylesheetPath(clearnessDarkTheme), QLatin1String("qrc:/css/clearness-dark.css")); - QCOMPARE(themeManager.previewStylesheetPath(bywordDarkTheme), QLatin1String("qrc:/css/byword-dark.css")); + QCOMPARE(styleManager.previewStylesheetPath(defaultTheme), QLatin1String("qrc:/css/markdown.css")); + QCOMPARE(styleManager.previewStylesheetPath(githubTheme), QLatin1String("qrc:/css/github.css")); + QCOMPARE(styleManager.previewStylesheetPath(solarizedLightTheme), QLatin1String("qrc:/css/solarized-light.css")); + QCOMPARE(styleManager.previewStylesheetPath(solarizedDarkTheme), QLatin1String("qrc:/css/solarized-dark.css")); + QCOMPARE(styleManager.previewStylesheetPath(clearnessTheme), QLatin1String("qrc:/css/clearness.css")); + QCOMPARE(styleManager.previewStylesheetPath(clearnessDarkTheme), QLatin1String("qrc:/css/clearness-dark.css")); + QCOMPARE(styleManager.previewStylesheetPath(bywordDarkTheme), QLatin1String("qrc:/css/byword-dark.css")); } diff --git a/test/unit/thememanagertest.h b/test/unit/stylemanagertest.h similarity index 88% rename from test/unit/thememanagertest.h rename to test/unit/stylemanagertest.h index 72d9e8fa..cf1308e7 100644 --- a/test/unit/thememanagertest.h +++ b/test/unit/stylemanagertest.h @@ -14,12 +14,12 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -#ifndef THEMEMANAGERTEST_H -#define THEMEMANAGERTEST_H +#ifndef STYLEMANAGERTEST_H +#define STYLEMANAGERTEST_H #include -class ThemeManagerTest : public QObject +class StyleManagerTest : public QObject { Q_OBJECT @@ -29,6 +29,6 @@ private slots: void returnsPathForPreviewStylesheet(); }; -#endif // THEMEMANAGERTEST_H +#endif // STYLEMANAGERTEST_H diff --git a/test/unit/unit.pro b/test/unit/unit.pro index 7f436e33..fe6d6d20 100644 --- a/test/unit/unit.pro +++ b/test/unit/unit.pro @@ -22,7 +22,7 @@ SOURCES += \ yamlheadercheckertest.cpp \ themetest.cpp \ themecollectiontest.cpp \ - thememanagertest.cpp + stylemanagertest.cpp HEADERS += \ completionlistmodeltest.h \ @@ -36,7 +36,7 @@ HEADERS += \ yamlheadercheckertest.h \ themetest.h \ themecollectiontest.h \ - thememanagertest.h + stylemanagertest.h target.CONFIG += no_default_install From 942b1ad5d00e53a9dbb768070e1d6f774a549f9b Mon Sep 17 00:00:00 2001 From: Christian Loose Date: Sat, 19 Dec 2015 14:26:59 +0100 Subject: [PATCH 14/20] Restore custom preview style functionality --- app-static/themes/stylemanager.cpp | 12 ++++++++++++ app-static/themes/stylemanager.h | 6 ++++++ app/mainwindow.cpp | 19 +++++++++---------- test/unit/stylemanagertest.cpp | 10 ++++++++++ test/unit/stylemanagertest.h | 1 + 5 files changed, 38 insertions(+), 10 deletions(-) diff --git a/app-static/themes/stylemanager.cpp b/app-static/themes/stylemanager.cpp index f3eb187c..36185d97 100644 --- a/app-static/themes/stylemanager.cpp +++ b/app-static/themes/stylemanager.cpp @@ -44,6 +44,14 @@ static const QMap BUILTIN_PREVIEW_STYLESHEETS = { { "Byword Dark", "qrc:/css/byword-dark.css" } }; +QMap StyleManager::customPreviewStylesheets; + + +void StyleManager::insertCustomPreviewStylesheet(const QString &styleName, const QString &stylePath) +{ + customPreviewStylesheets.insert(styleName, stylePath); +} + QString StyleManager::markdownHighlightingPath(const Theme &theme) { return BUILTIN_MARKDOWN_HIGHLIGHTINGS[theme.markdownHighlighting()]; @@ -56,5 +64,9 @@ QString StyleManager::codeHighlightingPath(const Theme &theme) QString StyleManager::previewStylesheetPath(const Theme &theme) { + if (customPreviewStylesheets.contains(theme.previewStylesheet())) { + return customPreviewStylesheets[theme.previewStylesheet()]; + } + return BUILTIN_PREVIEW_STYLESHEETS[theme.previewStylesheet()]; } diff --git a/app-static/themes/stylemanager.h b/app-static/themes/stylemanager.h index 0b4fed56..ba4b7fd8 100644 --- a/app-static/themes/stylemanager.h +++ b/app-static/themes/stylemanager.h @@ -17,6 +17,7 @@ #ifndef STYLEMANAGER_H #define STYLEMANAGER_H +#include #include #include "theme.h" @@ -24,9 +25,14 @@ class StyleManager { public: + void insertCustomPreviewStylesheet(const QString &styleName, const QString &stylePath); + static QString markdownHighlightingPath(const Theme &theme); static QString codeHighlightingPath(const Theme &theme); static QString previewStylesheetPath(const Theme &theme); + +private: + static QMap customPreviewStylesheets; }; #endif // STYLEMANAGER_H diff --git a/app/mainwindow.cpp b/app/mainwindow.cpp index b85bab21..bf795716 100644 --- a/app/mainwindow.cpp +++ b/app/mainwindow.cpp @@ -127,6 +127,8 @@ void MainWindow::initializeApp() ui->webView->page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks); ui->tocWebView->page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks); + themeCollection->load(":/builtin-htmlpreview-themes.json"); + loadCustomStyles(); setupHtmlPreviewThemes(); // apply last used theme @@ -163,7 +165,6 @@ void MainWindow::initializeApp() QWebInspector *inspector = new QWebInspector(); inspector->setPage(ui->webView->page()); - loadCustomStyles(); ui->menuLanguages->loadDictionaries(options->dictionaryLanguage()); //: path to built-in snippets resource. @@ -1202,7 +1203,6 @@ void MainWindow::updateSplitter() void MainWindow::setupHtmlPreviewThemes() { - themeCollection->load(":/builtin-htmlpreview-themes.json"); ui->menuStyles->clear(); @@ -1227,21 +1227,20 @@ void MainWindow::loadCustomStyles() QDir dataPath(paths.first() + QDir::separator() + "styles"); dataPath.setFilter(QDir::Files); if (dataPath.exists()) { - ui->menuStyles->addSeparator(); - // iterate over all files in the styles subdirectory QDirIterator it(dataPath); while (it.hasNext()) { it.next(); QString fileName = it.fileName(); - QAction *action = ui->menuStyles->addAction(QFileInfo(fileName).baseName()); - action->setCheckable(true); - action->setActionGroup(stylesGroup); - action->setData(it.filePath()); + QString styleName = QFileInfo(fileName).baseName(); + QString stylePath = QUrl::fromLocalFile(it.filePath()).toString(); + + Theme customTheme { styleName, "Default", "Default", styleName }; + themeCollection->insert(customTheme); - connect(action, SIGNAL(triggered()), - this, SLOT(styleCustomStyle())); + StyleManager styleManager; + styleManager.insertCustomPreviewStylesheet(styleName, stylePath); } } } diff --git a/test/unit/stylemanagertest.cpp b/test/unit/stylemanagertest.cpp index 8e0a9434..c6de8913 100644 --- a/test/unit/stylemanagertest.cpp +++ b/test/unit/stylemanagertest.cpp @@ -62,3 +62,13 @@ void StyleManagerTest::returnsPathForPreviewStylesheet() QCOMPARE(styleManager.previewStylesheetPath(bywordDarkTheme), QLatin1String("qrc:/css/byword-dark.css")); } +void StyleManagerTest::returnsPathForCustomPreviewStylesheet() +{ + QString expectedPath = "file:///C:/User/Test/custom.css"; + Theme customTheme("Custom", "Default", "Default", "Custom"); + StyleManager styleManager; + + styleManager.insertCustomPreviewStylesheet("Custom", expectedPath); + + QCOMPARE(styleManager.previewStylesheetPath(customTheme), expectedPath); +} diff --git a/test/unit/stylemanagertest.h b/test/unit/stylemanagertest.h index cf1308e7..af1fe57d 100644 --- a/test/unit/stylemanagertest.h +++ b/test/unit/stylemanagertest.h @@ -27,6 +27,7 @@ private slots: void returnsPathForMarkdownHighlighting(); void returnsPathForCodeHighlighting(); void returnsPathForPreviewStylesheet(); + void returnsPathForCustomPreviewStylesheet(); }; #endif // STYLEMANAGERTEST_H From 48b6509814a703cb65fa2709d21506fe79512fb7 Mon Sep 17 00:00:00 2001 From: Christian Loose Date: Mon, 21 Dec 2015 12:01:26 +0100 Subject: [PATCH 15/20] Additional test for custom overwriting builtins --- test/unit/stylemanagertest.cpp | 11 +++++++++++ test/unit/stylemanagertest.h | 1 + 2 files changed, 12 insertions(+) diff --git a/test/unit/stylemanagertest.cpp b/test/unit/stylemanagertest.cpp index c6de8913..87161278 100644 --- a/test/unit/stylemanagertest.cpp +++ b/test/unit/stylemanagertest.cpp @@ -72,3 +72,14 @@ void StyleManagerTest::returnsPathForCustomPreviewStylesheet() QCOMPARE(styleManager.previewStylesheetPath(customTheme), expectedPath); } + +void StyleManagerTest::customPreviewStylesheetOverwritesBuiltin() +{ + QString expectedPath = "file:///C:/User/Test/custom.css"; + Theme customTheme("Custom", "Default", "Default", "Github"); + StyleManager styleManager; + + styleManager.insertCustomPreviewStylesheet("Github", expectedPath); + + QCOMPARE(styleManager.previewStylesheetPath(customTheme), expectedPath); +} diff --git a/test/unit/stylemanagertest.h b/test/unit/stylemanagertest.h index af1fe57d..773c9460 100644 --- a/test/unit/stylemanagertest.h +++ b/test/unit/stylemanagertest.h @@ -28,6 +28,7 @@ private slots: void returnsPathForCodeHighlighting(); void returnsPathForPreviewStylesheet(); void returnsPathForCustomPreviewStylesheet(); + void customPreviewStylesheetOverwritesBuiltin(); }; #endif // STYLEMANAGERTEST_H From c3d94b37d4b0863809411f5d393c2ce1afdac572 Mon Sep 17 00:00:00 2001 From: Christian Loose Date: Mon, 21 Dec 2015 12:47:58 +0100 Subject: [PATCH 16/20] Remove unused styleCustomStlye() method --- app/mainwindow.cpp | 18 ------------------ app/mainwindow.h | 1 - 2 files changed, 19 deletions(-) diff --git a/app/mainwindow.cpp b/app/mainwindow.cpp index bf795716..94379274 100644 --- a/app/mainwindow.cpp +++ b/app/mainwindow.cpp @@ -498,24 +498,6 @@ void MainWindow::editorStyleChanged() ui->plainTextEdit->loadStyleFromStylesheet(stylePath(markdownHighlighting)); } -void MainWindow::styleCustomStyle() -{ - QAction *action = qobject_cast(sender()); - - currentTheme = { action->text(), "Default", "Default", action->data().toString() }; - - QString markdownHighlighting = StyleManager::markdownHighlightingPath(currentTheme); - QString codeHighlighting = StyleManager::codeHighlightingPath(currentTheme); - QString previewStylesheet = StyleManager::previewStylesheetPath(currentTheme); - - generator->setCodeHighlightingStyle(codeHighlighting); - ui->plainTextEdit->loadStyleFromStylesheet(stylePath(markdownHighlighting)); - ui->webView->page()->settings()->setUserStyleSheetUrl(QUrl::fromLocalFile(previewStylesheet)); - - styleLabel->setText(action->text()); - options->setLastUsedTheme(action->objectName()); -} - void MainWindow::applyCurrentTheme() { QString markdownHighlighting = StyleManager::markdownHighlightingPath(currentTheme); diff --git a/app/mainwindow.h b/app/mainwindow.h index da354759..c8a5439a 100644 --- a/app/mainwindow.h +++ b/app/mainwindow.h @@ -88,7 +88,6 @@ private slots: void lastUsedTheme(); void themeChanged(); void editorStyleChanged(); - void styleCustomStyle(); void viewFullScreenMode(); void viewHorizontalLayout(bool checked); From 8b4d8681b6b351dbd8fb22eda4431b17bee0acaf Mon Sep 17 00:00:00 2001 From: Christian Loose Date: Mon, 21 Dec 2015 13:08:54 +0100 Subject: [PATCH 17/20] Remove unused style actions --- app/mainwindow.cpp | 13 +--- app/mainwindow.ui | 189 --------------------------------------------- 2 files changed, 2 insertions(+), 200 deletions(-) diff --git a/app/mainwindow.cpp b/app/mainwindow.cpp index 94379274..42f7536f 100644 --- a/app/mainwindow.cpp +++ b/app/mainwindow.cpp @@ -73,6 +73,7 @@ MainWindow::MainWindow(const QString &fileName, QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow), options(new Options(this)), + stylesGroup(new QActionGroup(this)), styleLabel(0), wordCountLabel(0), viewLabel(0), @@ -988,16 +989,6 @@ void MainWindow::setupActions() connect(ui->menuLanguages, SIGNAL(languageTriggered(Dictionary)), this, SLOT(languageChanged(Dictionary))); - // put style actions in a group - stylesGroup = new QActionGroup(this); - ui->actionDefault->setActionGroup(stylesGroup); - ui->actionGithub->setActionGroup(stylesGroup); - ui->actionSolarizedLight->setActionGroup(stylesGroup); - ui->actionSolarizedDark->setActionGroup(stylesGroup); - ui->actionClearness->setActionGroup(stylesGroup); - ui->actionClearnessDark->setActionGroup(stylesGroup); - ui->actionBywordDark->setActionGroup(stylesGroup); - // help menu ui->actionMarkdownSyntax->setShortcut(QKeySequence::HelpContents); @@ -1025,7 +1016,7 @@ void MainWindow::setupStatusBar() statusBar()->setStyleSheet("QStatusBar::item { border: 0px solid black }; "); // add style label to statusbar - styleLabel = new QLabel(ui->actionDefault->text(), this); + styleLabel = new QLabel("Default", this); styleLabel->setToolTip(tr("Change Preview Style")); statusBar()->addPermanentWidget(styleLabel, 1); diff --git a/app/mainwindow.ui b/app/mainwindow.ui index a2a30a71..0456ea92 100644 --- a/app/mainwindow.ui +++ b/app/mainwindow.ui @@ -417,53 +417,6 @@ &Redo - - - true - - - true - - - Default - - - Ctrl+1 - - - - - true - - - Github - - - Ctrl+2 - - - - - true - - - Solarized Light - - - Ctrl+3 - - - - - true - - - Solarized Dark - - - Ctrl+4 - - &About CuteMarkEd... @@ -565,28 +518,6 @@ Code &Highlighting - - - true - - - Clearness - - - Ctrl+5 - - - - - true - - - Clearness Dark - - - Ctrl+6 - - Find/Replace @@ -742,14 +673,6 @@ Ctrl+T - - - Byword Dark - - - Ctrl+7 - - Insert &Image... @@ -972,70 +895,6 @@ - - actionDefault - triggered() - MainWindow - styleDefault() - - - -1 - -1 - - - 399 - 249 - - - - - actionGithub - triggered() - MainWindow - styleGithub() - - - -1 - -1 - - - 399 - 249 - - - - - actionSolarizedLight - triggered() - MainWindow - styleSolarizedLight() - - - -1 - -1 - - - 399 - 249 - - - - - actionSolarizedDark - triggered() - MainWindow - styleSolarizedDark() - - - -1 - -1 - - - 399 - 249 - - - actionAbout triggered() @@ -1356,38 +1215,6 @@ - - actionClearness - triggered() - MainWindow - styleClearness() - - - -1 - -1 - - - 399 - 249 - - - - - actionClearnessDark - triggered() - MainWindow - styleClearnessDark() - - - -1 - -1 - - - 399 - 249 - - - actionFindReplace triggered() @@ -1692,22 +1519,6 @@ - - actionBywordDark - triggered() - MainWindow - styleBywordDark() - - - -1 - -1 - - - 424 - 266 - - - actionInsertImage triggered() From 348b0791fb09ba7923cbc5c87b51f6154de8403c Mon Sep 17 00:00:00 2001 From: Christian Loose Date: Tue, 22 Dec 2015 16:33:00 +0100 Subject: [PATCH 18/20] Add built-in attribute to Theme class --- app-static/themes/theme.cpp | 6 ++++-- app-static/themes/theme.h | 6 +++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/app-static/themes/theme.cpp b/app-static/themes/theme.cpp index 7a88d417..3204f16d 100644 --- a/app-static/themes/theme.cpp +++ b/app-static/themes/theme.cpp @@ -19,11 +19,13 @@ Theme::Theme(const QString &name, const QString &markdownHighlighting, const QString &codeHighlighting, - const QString &previewStylesheet) : + const QString &previewStylesheet, + bool builtIn) : m_name(name), m_markdownHighlighting(markdownHighlighting), m_codeHighlighting(codeHighlighting), - m_previewStylesheet(previewStylesheet) + m_previewStylesheet(previewStylesheet), + m_builtIn(builtIn) { checkInvariants(); } diff --git a/app-static/themes/theme.h b/app-static/themes/theme.h index 94b4c5c2..227a1a75 100644 --- a/app-static/themes/theme.h +++ b/app-static/themes/theme.h @@ -27,7 +27,8 @@ class Theme Theme(const QString &name, const QString &markdownHighlighting, const QString &codeHighlighting, - const QString &previewStylesheet); + const QString &previewStylesheet, + bool builtIn = false); QString name() const { return m_name; } @@ -37,6 +38,8 @@ class Theme QString previewStylesheet() const { return m_previewStylesheet; } + bool isBuiltIn() const { return m_builtIn; } + bool operator<(const Theme &rhs) const { return m_name < rhs.name(); @@ -55,6 +58,7 @@ class Theme QString m_markdownHighlighting; QString m_codeHighlighting; QString m_previewStylesheet; + bool m_builtIn; }; #endif // THEME_H From 488f42b133bd95dc59b80c40707ec4b5818808e8 Mon Sep 17 00:00:00 2001 From: Christian Loose Date: Tue, 22 Dec 2015 16:33:38 +0100 Subject: [PATCH 19/20] Read built-in attribute from JSON file --- app-static/themes/jsonthemetranslator.cpp | 5 ++++- app/app.pro | 3 ++- app/builtin-htmlpreview-themes.json | 21 ++++++++++++++------- test/integration/jsonthemefiletest.cpp | 7 +++++-- test/unit/jsonthemetranslatortest.cpp | 5 ++++- 5 files changed, 29 insertions(+), 12 deletions(-) diff --git a/app-static/themes/jsonthemetranslator.cpp b/app-static/themes/jsonthemetranslator.cpp index fb671b7d..eeb36d7e 100644 --- a/app-static/themes/jsonthemetranslator.cpp +++ b/app-static/themes/jsonthemetranslator.cpp @@ -22,6 +22,7 @@ static const QLatin1String NAME("name"); static const QLatin1String MARKDOWN_HIGHLIGHTING("markdownHighlighting"); static const QLatin1String CODE_HIGHLIGHTING("codeHighlighting"); static const QLatin1String PREVIEW_STYLESHEET("previewStylesheet"); +static const QLatin1String BUILT_IN("builtIn"); } @@ -31,8 +32,9 @@ Theme JsonThemeTranslator::fromJsonObject(const QJsonObject &object) QString markdownHighlighting = object.value(MARKDOWN_HIGHLIGHTING).toString(); QString codeHighlighting = object.value(CODE_HIGHLIGHTING).toString(); QString previewStylesheet = object.value(PREVIEW_STYLESHEET).toString(); + bool builtIn = object.value(BUILT_IN).toBool(); - return { name, markdownHighlighting, codeHighlighting, previewStylesheet }; + return { name, markdownHighlighting, codeHighlighting, previewStylesheet, builtIn }; } QJsonObject JsonThemeTranslator::toJsonObject(const Theme &theme) @@ -42,6 +44,7 @@ QJsonObject JsonThemeTranslator::toJsonObject(const Theme &theme) object.insert(MARKDOWN_HIGHLIGHTING, theme.markdownHighlighting()); object.insert(CODE_HIGHLIGHTING, theme.codeHighlighting()); object.insert(PREVIEW_STYLESHEET, theme.previewStylesheet()); + object.insert(BUILT_IN, theme.isBuiltIn()); return object; } diff --git a/app/app.pro b/app/app.pro index 3f3197b1..a7faa183 100644 --- a/app/app.pro +++ b/app/app.pro @@ -131,7 +131,8 @@ OTHER_FILES += \ styles/clearness.css \ styles/byword-dark.css \ styles/solarized-light.css \ - markdown-snippets.json + markdown-snippets.json \ + builtin-htmlpreview-themes.json # translations lrelease.input = TRANSLATIONS diff --git a/app/builtin-htmlpreview-themes.json b/app/builtin-htmlpreview-themes.json index 20beadda..49f2334f 100644 --- a/app/builtin-htmlpreview-themes.json +++ b/app/builtin-htmlpreview-themes.json @@ -4,43 +4,50 @@ "name": "Default", "markdownHighlighting": "Default", "codeHighlighting": "Default", - "previewStylesheet": "Default" + "previewStylesheet": "Default", + "builtIn": true }, { "name": "Github", "markdownHighlighting": "Default", "codeHighlighting": "Github", - "previewStylesheet": "Github" + "previewStylesheet": "Github", + "builtIn": true }, { "name": "Solarized Light", "markdownHighlighting": "Solarized Light", "codeHighlighting": "Solarized Light", - "previewStylesheet": "Solarized Light" + "previewStylesheet": "Solarized Light", + "builtIn": true }, { "name": "Solarized Dark", "markdownHighlighting": "Solarized Dark", "codeHighlighting": "Solarized Dark", - "previewStylesheet": "Solarized Dark" + "previewStylesheet": "Solarized Dark", + "builtIn": true }, { "name": "Clearness", "markdownHighlighting": "Default", "codeHighlighting": "Default", - "previewStylesheet": "Clearness" + "previewStylesheet": "Clearness", + "builtIn": true }, { "name": "Clearness Dark", "markdownHighlighting": "Clearness Dark", "codeHighlighting": "Default", - "previewStylesheet": "Clearness Dark" + "previewStylesheet": "Clearness Dark", + "builtIn": true }, { "name": "Byword Dark", "markdownHighlighting": "Byword Dark", "codeHighlighting": "Default", - "previewStylesheet": "Byword Dark" + "previewStylesheet": "Byword Dark", + "builtIn": true } ] } diff --git a/test/integration/jsonthemefiletest.cpp b/test/integration/jsonthemefiletest.cpp index effe6888..016d7c92 100644 --- a/test/integration/jsonthemefiletest.cpp +++ b/test/integration/jsonthemefiletest.cpp @@ -54,7 +54,8 @@ void JsonThemeFileTest::loadsThemesCollectionFromFile() << " { \"name\": \"default\"," << " \"markdownHighlighting\": \"default\"," << " \"codeHighlighting\": \"default\"," - << " \"previewStylesheet\": \"default\" }," + << " \"previewStylesheet\": \"default\"," + << " \"builtIn\": true }," << " { \"name\": \"dark\"," << " \"markdownHighlighting\": \"dark\"," << " \"codeHighlighting\": \"black\"," @@ -124,7 +125,7 @@ void JsonThemeFileTest::roundtripTest() if (!themeFile.open()) QFAIL("Failed to create temporary theme file"); - Theme theme1("default", "default", "default", "default"); + Theme theme1("default", "default", "default", "default", true); Theme theme2("dark", "dark", "black", "dark"); @@ -145,9 +146,11 @@ void JsonThemeFileTest::roundtripTest() QCOMPARE(collection2.at(0).markdownHighlighting(), theme1.markdownHighlighting()); QCOMPARE(collection2.at(0).codeHighlighting(), theme1.codeHighlighting()); QCOMPARE(collection2.at(0).previewStylesheet(), theme1.previewStylesheet()); + QCOMPARE(collection2.at(0).isBuiltIn(), theme1.isBuiltIn()); QCOMPARE(collection2.at(1).name(), theme2.name()); QCOMPARE(collection2.at(1).markdownHighlighting(), theme2.markdownHighlighting()); QCOMPARE(collection2.at(1).codeHighlighting(), theme2.codeHighlighting()); QCOMPARE(collection2.at(1).previewStylesheet(), theme2.previewStylesheet()); + QCOMPARE(collection2.at(0).isBuiltIn(), theme1.isBuiltIn()); } diff --git a/test/unit/jsonthemetranslatortest.cpp b/test/unit/jsonthemetranslatortest.cpp index 8731f018..a100bc9a 100644 --- a/test/unit/jsonthemetranslatortest.cpp +++ b/test/unit/jsonthemetranslatortest.cpp @@ -46,6 +46,7 @@ QJsonObject NewJsonThemeObject() jsonObject.insert("markdownHighlighting", A_MARKDOWN_HIGHLIGHTING); jsonObject.insert("codeHighlighting", A_CODE_HIGHLIGHTING); jsonObject.insert("previewStylesheet", A_PREVIEW_STYLESHEET); + jsonObject.insert("builtIn", true); return jsonObject; } @@ -98,11 +99,12 @@ void JsonThemeTranslatorTest::translatesJsonDocumentToThemes() QCOMPARE(collection.at(0).markdownHighlighting(), A_MARKDOWN_HIGHLIGHTING); QCOMPARE(collection.at(0).codeHighlighting(), A_CODE_HIGHLIGHTING); QCOMPARE(collection.at(0).previewStylesheet(), A_PREVIEW_STYLESHEET); + QCOMPARE(collection.at(0).isBuiltIn(), true); } void JsonThemeTranslatorTest::translatesThemesToJsonDocument() { - Theme theme(A_THEME_NAME, A_MARKDOWN_HIGHLIGHTING, A_CODE_HIGHLIGHTING, A_PREVIEW_STYLESHEET); + Theme theme(A_THEME_NAME, A_MARKDOWN_HIGHLIGHTING, A_CODE_HIGHLIGHTING, A_PREVIEW_STYLESHEET, true); ThemeCollection collection; collection.insert(theme); @@ -113,5 +115,6 @@ void JsonThemeTranslatorTest::translatesThemesToJsonDocument() QCOMPARE(actual["markdownHighlighting"].toString(), A_MARKDOWN_HIGHLIGHTING); QCOMPARE(actual["codeHighlighting"].toString(), A_CODE_HIGHLIGHTING); QCOMPARE(actual["previewStylesheet"].toString(), A_PREVIEW_STYLESHEET); + QCOMPARE(actual["builtIn"].toBool(), true); } From 2a53e0130bb410b608b5e0df22cda4fcd61695f2 Mon Sep 17 00:00:00 2001 From: Christian Loose Date: Tue, 22 Dec 2015 16:34:07 +0100 Subject: [PATCH 20/20] Use built-in attribute to add separator between built-in and custom themes --- app/mainwindow.cpp | 16 +++++++++++++++- app/mainwindow.h | 1 + 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/app/mainwindow.cpp b/app/mainwindow.cpp index 42f7536f..f385909f 100644 --- a/app/mainwindow.cpp +++ b/app/mainwindow.cpp @@ -1176,13 +1176,13 @@ void MainWindow::updateSplitter() void MainWindow::setupHtmlPreviewThemes() { - ui->menuStyles->clear(); delete stylesGroup; stylesGroup = new QActionGroup(this); int key = 1; + bool separatorAdded = false; foreach(const QString &themeName, themeCollection->themeNames()) { QAction *action = ui->menuStyles->addAction(themeName); action->setShortcut(QKeySequence(tr("Ctrl+%1").arg(key++))); @@ -1190,9 +1190,23 @@ void MainWindow::setupHtmlPreviewThemes() action->setActionGroup(stylesGroup); connect(action, &QAction::triggered, this, &MainWindow::themeChanged); + + if (!separatorAdded && !themeCollection->theme(themeName).isBuiltIn()) { + addSeparatorAfterBuiltInThemes(); + separatorAdded = true; + } } } +void MainWindow::addSeparatorAfterBuiltInThemes() +{ + ui->menuStyles->addSeparator(); + + QAction *separator = new QAction(stylesGroup); + separator->setSeparator(true); + stylesGroup->addAction(separator); +} + void MainWindow::loadCustomStyles() { QStringList paths = DataLocation::standardLocations(); diff --git a/app/mainwindow.h b/app/mainwindow.h index c8a5439a..dc3b2aba 100644 --- a/app/mainwindow.h +++ b/app/mainwindow.h @@ -140,6 +140,7 @@ private slots: void setFileName(const QString &fileName); void updateSplitter(); void setupHtmlPreviewThemes(); + void addSeparatorAfterBuiltInThemes(); void loadCustomStyles(); void readSettings(); void writeSettings();