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 <vcl/IconThemeScanner.hxx>
17 #include <osl/file.hxx>
18 #include <salhelper/linkhelper.hxx>
19 #include <unotools/pathoptions.hxx>
20 #include <vcl/IconThemeInfo.hxx>
26 // set the status of a file. Returns false if the status could not be determined.
27 bool set_file_status(osl::FileStatus
& status
, const OUString
& file
)
29 osl::DirectoryItem dirItem
;
30 osl::FileBase::RC retvalGet
= osl::DirectoryItem::get(file
, dirItem
);
31 if (retvalGet
!= osl::FileBase::E_None
) {
32 SAL_WARN("vcl.app", "Could not determine status for file '" << file
<< "'.");
35 osl::FileBase::RC retvalStatus
= dirItem
.getFileStatus(status
);
36 if (retvalStatus
!= osl::FileBase::E_None
) {
37 SAL_WARN("vcl.app", "Could not determine status for file '" << file
<< "'.");
43 OUString
convert_to_absolute_path(const OUString
& path
)
45 salhelper::LinkResolver
resolver(0);
46 osl::FileBase::RC rc
= resolver
.fetchFileStatus(path
);
47 if (rc
!= osl::FileBase::E_None
) {
48 SAL_WARN("vcl.app", "Could not resolve path '" << path
<< "' to search for icon themes.");
49 if (rc
== osl::FileBase::E_MULTIHOP
)
51 throw std::runtime_error("Provided a recursive symlink to an icon theme directory that could not be resolved.");
54 return resolver
.m_aStatus
.getFileURL();
59 IconThemeScanner::IconThemeScanner()
62 void IconThemeScanner::ScanDirectoryForIconThemes(const OUString
& paths
)
64 mFoundIconThemes
.clear();
66 std::deque
<OUString
> aPaths
;
71 aPaths
.push_front(paths
.getToken(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
);
170 /*static*/ std::shared_ptr
<IconThemeScanner
>
171 IconThemeScanner::Create(const OUString
&path
)
173 std::shared_ptr
<IconThemeScanner
> retval(new IconThemeScanner
);
174 retval
->ScanDirectoryForIconThemes(path
);
179 IconThemeScanner::GetStandardIconThemePath()
181 SvtPathOptions aPathOptions
;
182 return aPathOptions
.GetIconsetPath();
190 const OUString
& m_rThemeId
;
192 explicit SameTheme(const OUString
&rThemeId
) : m_rThemeId(rThemeId
) {}
193 bool operator()(const vcl::IconThemeInfo
&rInfo
)
195 return m_rThemeId
== rInfo
.GetThemeId();
200 const vcl::IconThemeInfo
&
201 IconThemeScanner::GetIconThemeInfo(const OUString
& themeId
)
203 std::vector
<IconThemeInfo
>::iterator info
= std::find_if(mFoundIconThemes
.begin(), mFoundIconThemes
.end(),
205 if (info
== mFoundIconThemes
.end()) {
206 SAL_WARN("vcl.app", "Requested information for icon theme with id '" << themeId
207 << "' which does not exist.");
208 throw std::runtime_error("Requested information on not-installed icon theme");
213 } // end namespace vcl
215 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */