include/svx/ColorSets.hxx              |    4 ++
 include/vcl/UserResourceScanner.hxx    |    2 +
 svx/source/styles/ColorSets.cxx        |   62 +++++++++++++++++++++++++++++++--
 vcl/source/app/UserResourceScanner.cxx |   26 ++++++-------
 4 files changed, 79 insertions(+), 15 deletions(-)

New commits:
commit 89c27a63a70f46ad290fc8cd34a08fae8fe94c8a
Author:     Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk>
AuthorDate: Tue Jan 21 19:08:33 2025 +0900
Commit:     Tomaž Vajngerl <qui...@gmail.com>
CommitDate: Thu Jan 23 02:17:56 2025 +0100

    docthemes: Save themes def. to a file when added to ColorSets
    
    Color themes will be written to the user folder.
    
    Change-Id: I58e650550044bd35a5054a303ce41789d3d51d32
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/180542
    Tested-by: Jenkins
    Reviewed-by: Tomaž Vajngerl <qui...@gmail.com>

diff --git a/include/svx/ColorSets.hxx b/include/svx/ColorSets.hxx
index 4cf3313e0855..6bf29c4ea196 100644
--- a/include/svx/ColorSets.hxx
+++ b/include/svx/ColorSets.hxx
@@ -19,6 +19,8 @@ class SVXCORE_DLLPUBLIC ColorSets
 {
 private:
     std::vector<model::ColorSet> maColorSets;
+    OUString maUserFolder;
+
     ColorSets();
     void init();
 public:
@@ -38,6 +40,8 @@ public:
     model::ColorSet const* getColorSet(std::u16string_view rName) const;
 
     void insert(model::ColorSet const& rColorSet, IdenticalNameAction eAction);
+    void writeToUserFolder(model::ColorSet const& rNewColorSet);
+
 };
 
 } // end of namespace svx
diff --git a/include/vcl/UserResourceScanner.hxx 
b/include/vcl/UserResourceScanner.hxx
index db7da3accc90..2b2d4da0e7c5 100644
--- a/include/vcl/UserResourceScanner.hxx
+++ b/include/vcl/UserResourceScanner.hxx
@@ -13,6 +13,7 @@
 #include <rtl/ustring.hxx>
 #include <memory>
 #include <vector>
+#include <deque>
 #include <osl/file.hxx>
 
 namespace vcl
@@ -20,6 +21,7 @@ namespace vcl
 namespace file
 {
 VCL_DLLPUBLIC bool readFileStatus(osl::FileStatus& rStatus, const OUString& 
rFile);
+VCL_DLLPUBLIC void splitPathString(std::u16string_view aPathString, 
std::deque<OUString>& rPaths);
 }
 
 class VCL_DLLPUBLIC UserResourceScanner
diff --git a/svx/source/styles/ColorSets.cxx b/svx/source/styles/ColorSets.cxx
index 57c4b44227a2..5143854e1823 100644
--- a/svx/source/styles/ColorSets.cxx
+++ b/svx/source/styles/ColorSets.cxx
@@ -15,12 +15,14 @@
 #include <vector>
 
 #include <docmodel/theme/ColorSet.hxx>
+#include <docmodel/theme/ThemeColorType.hxx>
 #include <o3tl/numeric.hxx>
 #include <tools/stream.hxx>
 #include <tools/XmlWalker.hxx>
+#include <tools/XmlWriter.hxx>
 #include <vcl/UserResourceScanner.hxx>
 #include <unotools/pathoptions.hxx>
-#include <docmodel/theme/ThemeColorType.hxx>
+#include <o3tl/enumrange.hxx>
 #include <frozen/bits/defines.h>
 #include <frozen/bits/elsa_std.h>
 #include <frozen/unordered_map.h>
@@ -150,8 +152,15 @@ ColorSets& ColorSets::get()
 void ColorSets::init()
 {
     SvtPathOptions aPathOptions;
+    OUString aURLString = aPathOptions.GetDocumentThemePath();
+
     DocumentThemeScanner aScanner(maColorSets);
-    aScanner.addPaths(aPathOptions.GetDocumentThemePath());
+    aScanner.addPaths(aURLString);
+
+    std::deque<OUString> aURLs;
+    vcl::file::splitPathString(aURLString, aURLs);
+    if (aURLs.size() > 0)
+        maUserFolder = aURLs[0];
 }
 
 model::ColorSet const* ColorSets::getColorSet(std::u16string_view rName) const
@@ -200,6 +209,7 @@ void ColorSets::insert(model::ColorSet const& rNewColorSet, 
IdenticalNameAction
         }
         // color set not found, so insert it
         maColorSets.push_back(rNewColorSet);
+        writeToUserFolder(rNewColorSet);
     }
     else if (eAction == IdenticalNameAction::AutoRename)
     {
@@ -211,8 +221,56 @@ void ColorSets::insert(model::ColorSet const& 
rNewColorSet, IdenticalNameAction
 
         model::ColorSet aNewColorSet = rNewColorSet;
         aNewColorSet.setName(aName);
+
         maColorSets.push_back(aNewColorSet);
+        writeToUserFolder(aNewColorSet);
+    }
+}
+
+void ColorSets::writeToUserFolder(model::ColorSet const& rNewColorSet)
+{
+    static constexpr auto constThemeColorTypeToName = 
frozen::make_unordered_map<model::ThemeColorType, std::string_view>({
+        { model::ThemeColorType::Dark1, "dark1" },
+        { model::ThemeColorType::Light1, "light1" },
+        { model::ThemeColorType::Dark2, "dark2" },
+        { model::ThemeColorType::Light2, "light2" },
+        { model::ThemeColorType::Accent1, "accent1" },
+        { model::ThemeColorType::Accent2, "accent2" },
+        { model::ThemeColorType::Accent3, "accent3" },
+        { model::ThemeColorType::Accent4, "accent4" },
+        { model::ThemeColorType::Accent5, "accent5" },
+        { model::ThemeColorType::Accent6, "accent6" },
+        { model::ThemeColorType::Hyperlink, "hyperlink" },
+        { model::ThemeColorType::FollowedHyperlink, "followed-hyperlink" }
+    });
+
+    SvFileStream aFileStream(maUserFolder + "/" + rNewColorSet.getName() + 
".theme", StreamMode::WRITE | StreamMode::TRUNC);
+
+    tools::XmlWriter aWriter(&aFileStream);
+    aWriter.startDocument();
+    aWriter.startElement("theme");
+    aWriter.attribute("name", rNewColorSet.getName());
+
+    aWriter.startElement("theme-colors");
+    aWriter.attribute("name", rNewColorSet.getName());
+
+    for (auto eThemeColorType : o3tl::enumrange<model::ThemeColorType>())
+    {
+        auto iterator = constThemeColorTypeToName.find(eThemeColorType);
+        if (iterator != constThemeColorTypeToName.end())
+        {
+            Color aColor = rNewColorSet.getColor(eThemeColorType);
+            aWriter.startElement("color");
+            aWriter.attribute("name", OString(iterator->second));
+            aWriter.attribute("color", "#"_ostr + 
aColor.AsRGBHexString().toUtf8());
+            aWriter.endElement();
+        }
     }
+
+    aWriter.endElement();
+
+    aWriter.endElement();
+    aWriter.endDocument();
 }
 
 } // end of namespace svx
diff --git a/vcl/source/app/UserResourceScanner.cxx 
b/vcl/source/app/UserResourceScanner.cxx
index 0e01da5b3b0d..5dd42c9830c1 100644
--- a/vcl/source/app/UserResourceScanner.cxx
+++ b/vcl/source/app/UserResourceScanner.cxx
@@ -37,15 +37,6 @@ OUString convertToAbsolutePath(const OUString& path)
     }
     return resolver.m_aStatus.getFileURL();
 }
-
-void splitPathString(std::u16string_view aPathString, std::deque<OUString>& 
rPaths)
-{
-    sal_Int32 nIndex = 0;
-    do
-    {
-        rPaths.push_front(OUString(o3tl::getToken(aPathString, 0, ';', 
nIndex)));
-    } while (nIndex >= 0);
-}
 }
 
 namespace file
@@ -68,6 +59,15 @@ bool readFileStatus(osl::FileStatus& status, const OUString& 
file)
     }
     return true;
 }
+
+void splitPathString(std::u16string_view aPathString, std::deque<OUString>& 
rPaths)
+{
+    sal_Int32 nIndex = 0;
+    do
+    {
+        rPaths.push_front(OUString(o3tl::getToken(aPathString, 0, ';', 
nIndex)));
+    } while (nIndex >= 0);
+}
 }
 
 UserResourceScanner::UserResourceScanner() = default;
@@ -75,7 +75,7 @@ UserResourceScanner::UserResourceScanner() = default;
 void UserResourceScanner::addPaths(std::u16string_view aPathString)
 {
     std::deque<OUString> aPaths;
-    splitPathString(aPathString, aPaths);
+    vcl::file::splitPathString(aPathString, aPaths);
 
     for (const auto& path : aPaths)
     {
@@ -86,8 +86,8 @@ void UserResourceScanner::addPaths(std::u16string_view 
aPathString)
 
         if (!aFileStatus.isDirectory())
         {
-            SAL_INFO("vcl.app",
-                     "Cannot search for icon themes in '" << path << "'. It is 
not a directory.");
+            SAL_INFO("vcl.app", "Cannot search for resaource files in '"
+                                    << path << "'. It is not a directory.");
             continue;
         }
 
@@ -96,7 +96,7 @@ void UserResourceScanner::addPaths(std::u16string_view 
aPathString)
         if (aResourcePaths.empty())
         {
             SAL_WARN("vcl.app",
-                     "Could not find any icon themes in the provided directory 
('" << path << "'.");
+                     "Could not find any file in the provided directory ('" << 
path << "'.");
             continue;
         }
 

Reply via email to