1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
10 #include <sal/config.h>
11 #include <sal/log.hxx>
15 #include <IconThemeScanner.hxx>
17 #include <osl/file.hxx>
18 #include <salhelper/linkhelper.hxx>
19 #include <unotools/pathoptions.hxx>
20 #include <vcl/IconThemeInfo.hxx>
21 #include <o3tl/string_view.hxx>
27 // set the status of a file. Returns false if the status could not be determined.
28 bool set_file_status(osl::FileStatus
& status
, const OUString
& file
)
30 osl::DirectoryItem dirItem
;
31 osl::FileBase::RC retvalGet
= osl::DirectoryItem::get(file
, dirItem
);
32 if (retvalGet
!= osl::FileBase::E_None
) {
33 SAL_WARN("vcl.app", "Could not determine status for file '" << file
<< "'.");
36 osl::FileBase::RC retvalStatus
= dirItem
.getFileStatus(status
);
37 if (retvalStatus
!= osl::FileBase::E_None
) {
38 SAL_WARN("vcl.app", "Could not determine status for file '" << file
<< "'.");
44 OUString
convert_to_absolute_path(const OUString
& path
)
46 salhelper::LinkResolver
resolver(0);
47 osl::FileBase::RC rc
= resolver
.fetchFileStatus(path
);
48 if (rc
!= osl::FileBase::E_None
) {
49 SAL_WARN("vcl.app", "Could not resolve path '" << path
<< "' to search for icon themes.");
50 if (rc
== osl::FileBase::E_MULTIHOP
)
52 throw std::runtime_error("Provided a recursive symlink to an icon theme directory that could not be resolved.");
55 return resolver
.m_aStatus
.getFileURL();
60 IconThemeScanner::IconThemeScanner() = default;
62 IconThemeScanner::IconThemeScanner(std::u16string_view paths
)
64 mFoundIconThemes
.clear();
66 std::deque
<OUString
> aPaths
;
71 aPaths
.push_front(OUString(o3tl::getToken(paths
, 0, ';', nIndex
)));
75 for (const auto& path
: aPaths
)
77 osl::FileStatus
fileStatus(osl_FileStatus_Mask_Type
);
78 bool couldSetFileStatus
= set_file_status(fileStatus
, path
);
79 if (!couldSetFileStatus
) {
83 if (!fileStatus
.isDirectory()) {
84 SAL_INFO("vcl.app", "Cannot search for icon themes in '"<< path
<< "'. It is not a directory.");
88 std::vector
<OUString
> iconThemePaths
= ReadIconThemesFromPath(path
);
89 if (iconThemePaths
.empty()) {
90 SAL_WARN("vcl.app", "Could not find any icon themes in the provided directory ('" <<path
<<"'.");
93 for (auto const& iconThemePath
: iconThemePaths
)
95 AddIconThemeByPath(iconThemePath
);
101 IconThemeScanner::AddIconThemeByPath(const OUString
&url
)
103 if (!IconThemeInfo::UrlCanBeParsed(url
)) {
106 SAL_INFO("vcl.app", "Found a file that seems to be an icon theme: '" << url
<< "'" );
107 IconThemeInfo
newTheme(url
);
108 mFoundIconThemes
.push_back(newTheme
);
109 SAL_INFO("vcl.app", "Adding the file as '" << newTheme
.GetDisplayName() <<
110 "' with id '" << newTheme
.GetThemeId() << "'.");
114 /*static*/ std::vector
<OUString
>
115 IconThemeScanner::ReadIconThemesFromPath(const OUString
& dir
)
117 std::vector
<OUString
> found
;
118 SAL_INFO("vcl.app", "Scanning directory '" << dir
<< " for icon themes.");
120 osl::Directory
dirToScan(dir
);
121 osl::FileBase::RC retvalOpen
= dirToScan
.open();
122 if (retvalOpen
!= osl::FileBase::E_None
) {
126 osl::DirectoryItem directoryItem
;
127 while (dirToScan
.getNextItem(directoryItem
) == osl::FileBase::E_None
) {
128 osl::FileStatus
status(osl_FileStatus_Mask_Type
| osl_FileStatus_Mask_FileURL
| osl_FileStatus_Mask_FileName
);
129 osl::FileBase::RC retvalStatus
= directoryItem
.getFileStatus(status
);
130 if (retvalStatus
!= osl::FileBase::E_None
) {
134 OUString filename
= convert_to_absolute_path(status
.getFileURL());
135 if (!FileIsValidIconTheme(filename
)) {
138 found
.push_back(filename
);
144 IconThemeScanner::FileIsValidIconTheme(const OUString
& filename
)
146 // check whether we can construct an IconThemeInfo from it
147 if (!IconThemeInfo::UrlCanBeParsed(filename
)) {
148 SAL_INFO("vcl.app", "File '" << filename
<< "' does not seem to be an icon theme.");
152 osl::FileStatus
fileStatus(osl_FileStatus_Mask_Type
);
153 bool couldSetFileStatus
= set_file_status(fileStatus
, filename
);
154 if (!couldSetFileStatus
) {
158 if (!fileStatus
.isRegular()) {
165 IconThemeScanner::IconThemeIsInstalled(const OUString
& themeId
) const
167 return IconThemeInfo::IconThemeIsInVector(mFoundIconThemes
, themeId
);
171 IconThemeScanner::GetStandardIconThemePath()
173 SvtPathOptions aPathOptions
;
174 return aPathOptions
.GetIconsetPath();
182 const OUString
& m_rThemeId
;
184 explicit SameTheme(const OUString
&rThemeId
) : m_rThemeId(rThemeId
) {}
185 bool operator()(const vcl::IconThemeInfo
&rInfo
)
187 return m_rThemeId
== rInfo
.GetThemeId();
192 const vcl::IconThemeInfo
&
193 IconThemeScanner::GetIconThemeInfo(const OUString
& themeId
)
195 std::vector
<IconThemeInfo
>::iterator info
= std::find_if(mFoundIconThemes
.begin(), mFoundIconThemes
.end(),
197 if (info
== mFoundIconThemes
.end()) {
198 SAL_WARN("vcl.app", "Requested information for icon theme with id '" << themeId
199 << "' which does not exist.");
200 throw std::runtime_error("Requested information on not-installed icon theme");
205 } // end namespace vcl
207 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */