1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  */
9 
10 #include "CommandImageResolver.hxx"
11 #include <vcl/settings.hxx>
12 #include <vcl/svapp.hxx>
13 #include <rtl/ustrbuf.hxx>
14 #include <tools/urlobj.hxx>
15 
16 using css::uno::Sequence;
17 
18 namespace vcl
19 {
20 
21 namespace
22 {
23 
24 constexpr o3tl::enumarray<ImageType, OUString> ImageType_Prefixes
25 {
26     u"cmd/sc_"_ustr,
27     u"cmd/lc_"_ustr,
28     u"cmd/32/"_ustr
29 };
30 
lclConvertToCanonicalName(const OUString & rFileName)31 OUString lclConvertToCanonicalName(const OUString& rFileName)
32 {
33     bool bRemoveSlash(true);
34     sal_Int32 nLength = rFileName.getLength();
35     const sal_Unicode* pString = rFileName.getStr();
36 
37     OUStringBuffer aBuffer(nLength*2);
38 
39     for (sal_Int32 i = 0; i < nLength; i++)
40     {
41         const sal_Unicode cCurrentChar = pString[i];
42         switch (cCurrentChar)
43         {
44             // map forbidden characters to escape
45             case '/':
46                 if (!bRemoveSlash)
47                     aBuffer.append("%2f");
48                 break;
49             case '\\': aBuffer.append("%5c"); bRemoveSlash = false; break;
50             case ':':  aBuffer.append("%3a"); bRemoveSlash = false; break;
51             case '*':  aBuffer.append("%2a"); bRemoveSlash = false; break;
52             case '?':  aBuffer.append("%3f"); bRemoveSlash = false; break;
53             case '<':  aBuffer.append("%3c"); bRemoveSlash = false; break;
54             case '>':  aBuffer.append("%3e"); bRemoveSlash = false; break;
55             case '|':  aBuffer.append("%7c"); bRemoveSlash = false; break;
56             default:
57                 aBuffer.append(cCurrentChar); bRemoveSlash = false; break;
58         }
59     }
60     return aBuffer.makeStringAndClear();
61 }
62 
63 } // end anonymous namespace
64 
CommandImageResolver()65 CommandImageResolver::CommandImageResolver()
66 {
67 }
68 
~CommandImageResolver()69 CommandImageResolver::~CommandImageResolver()
70 {
71 }
72 
registerCommands(const Sequence<OUString> & aCommandSequence)73 void CommandImageResolver::registerCommands(const Sequence<OUString>& aCommandSequence)
74 {
75     sal_Int32 nSequenceSize = aCommandSequence.getLength();
76 
77     m_aImageCommandNameVector.resize(nSequenceSize);
78     m_aImageNameVector.resize(nSequenceSize);
79 
80     for (sal_Int32 i = 0; i < nSequenceSize; ++i)
81     {
82         OUString aCommandName(aCommandSequence[i]);
83         OUString aImageName;
84 
85         m_aImageCommandNameVector[i] = aCommandName;
86 
87         if (aCommandName.indexOf(".uno:") != 0)
88         {
89             INetURLObject aUrlObject(aCommandName, INetURLObject::EncodeMechanism::All);
90             aImageName = aUrlObject.GetURLPath();
91             aImageName = lclConvertToCanonicalName(aImageName);
92         }
93         else
94         {
95             // just remove the schema
96             if (aCommandName.getLength() > 5)
97                 aImageName = aCommandName.copy(5);
98 
99             // Search for query part.
100             if (aImageName.indexOf('?') != -1)
101                 aImageName = lclConvertToCanonicalName(aImageName);
102         }
103 
104         // Image names are not case-dependent. Always use lower case characters to
105         // reflect this.
106         aImageName = aImageName.toAsciiLowerCase() + ".png";
107 
108         m_aImageNameVector[i] = aImageName;
109         m_aCommandToImageNameMap[aCommandName] = aImageName;
110     }
111 }
112 
hasImage(const OUString & rCommandURL)113 bool CommandImageResolver::hasImage(const OUString& rCommandURL)
114 {
115     CommandToImageNameMap::const_iterator pIterator = m_aCommandToImageNameMap.find(rCommandURL);
116     return pIterator != m_aCommandToImageNameMap.end();
117 }
118 
getImageList(ImageType nImageType)119 ImageList* CommandImageResolver::getImageList(ImageType nImageType)
120 {
121     const OUString sIconTheme = Application::GetSettings().GetStyleSettings().DetermineIconTheme();
122 
123     if (sIconTheme != m_sIconTheme)
124     {
125         m_sIconTheme = sIconTheme;
126         for (auto& rp : m_pImageList)
127             rp.reset();
128     }
129 
130     if (!m_pImageList[nImageType])
131     {
132         OUString sIconPath = ImageType_Prefixes[nImageType];
133         m_pImageList[nImageType].reset( new ImageList(m_aImageNameVector, sIconPath) );
134     }
135 
136     return m_pImageList[nImageType].get();
137 }
138 
getImageFromCommandURL(ImageType nImageType,const OUString & rCommandURL)139 Image CommandImageResolver::getImageFromCommandURL(ImageType nImageType, const OUString& rCommandURL)
140 {
141     CommandToImageNameMap::const_iterator pIterator = m_aCommandToImageNameMap.find(rCommandURL);
142     if (pIterator != m_aCommandToImageNameMap.end())
143     {
144         ImageList* pImageList = getImageList(nImageType);
145         return pImageList->GetImage(pIterator->second);
146     }
147     return Image();
148 }
149 
150 } // end namespace vcl
151 
152 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
153