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 <vcl/IconThemeScanner.hxx>
12 #include <config_folders.h>
13 #include <osl/file.hxx>
14 #include <rtl/bootstrap.hxx>
15 #include <salhelper/linkhelper.hxx>
17 #include <vcl/svapp.hxx>
18 #include <vcl/IconThemeInfo.hxx>
24 // set the status of a file. Returns false if the status could not be determined.
25 bool set_file_status(osl::FileStatus
& status
, const OUString
& file
)
27 osl::DirectoryItem dirItem
;
28 osl::FileBase::RC retvalGet
= osl::DirectoryItem::get(file
, dirItem
);
29 if (retvalGet
!= osl::FileBase::E_None
) {
30 SAL_WARN("vcl.app", "Could not determine status for file '" << file
<< "'.");
33 osl::FileBase::RC retvalStatus
= dirItem
.getFileStatus(status
);
34 if (retvalStatus
!= osl::FileBase::E_None
) {
35 SAL_WARN("vcl.app", "Could not determine status for file '" << file
<< "'.");
41 OUString
convert_to_absolute_path(const OUString
& path
)
43 salhelper::LinkResolver
resolver(0);
44 osl::FileBase::RC rc
= resolver
.fetchFileStatus(path
);
45 if (rc
!= osl::FileBase::E_None
) {
46 SAL_WARN("vcl.app", "Could not resolve path '" << path
<< "' to search for icon themes.");
47 if (rc
== osl::FileBase::E_MULTIHOP
)
49 throw std::runtime_error("Provided a recursive symlink to a icon theme directory that could not be resolved.");
52 return resolver
.m_aStatus
.getFileURL();
57 IconThemeScanner::IconThemeScanner()
61 IconThemeScanner::ScanDirectoryForIconThemes(const OUString
& path
)
63 osl::FileStatus
fileStatus(osl_FileStatus_Mask_Type
);
64 bool couldSetFileStatus
= set_file_status(fileStatus
, path
);
65 if (!couldSetFileStatus
) {
69 if (!fileStatus
.isDirectory()) {
70 SAL_INFO("vcl.app", "Cannot search for icon themes in '"<< path
<< "'. It is not a directory.");
74 std::vector
<OUString
> iconThemePaths
= ReadIconThemesFromPath(path
);
75 if (iconThemePaths
.empty()) {
76 SAL_WARN("vcl.app", "Could not find any icon themes in the provided directory ('" <<path
<<"'.");
79 mFoundIconThemes
.clear();
80 for (std::vector
<OUString
>::iterator aI
= iconThemePaths
.begin(); aI
!= iconThemePaths
.end(); ++aI
)
82 AddIconThemeByPath(*aI
);
88 IconThemeScanner::AddIconThemeByPath(const OUString
&url
)
90 if (!IconThemeInfo::UrlCanBeParsed(url
)) {
93 SAL_INFO("vcl.app", "Found a file that seems to be an icon theme: '" << url
<< "'" );
94 IconThemeInfo
newTheme(url
);
95 mFoundIconThemes
.push_back(newTheme
);
96 SAL_INFO("vcl.app", "Adding the file as '" << newTheme
.GetDisplayName() <<
97 "' with id '" << newTheme
.GetThemeId() << "'.");
101 /*static*/ std::vector
<OUString
>
102 IconThemeScanner::ReadIconThemesFromPath(const OUString
& dir
)
104 std::vector
<OUString
> found
;
105 SAL_INFO("vcl.app", "Scanning directory '" << dir
<< " for icon themes.");
107 osl::Directory
dirToScan(dir
);
108 osl::FileBase::RC retvalOpen
= dirToScan
.open();
109 if (retvalOpen
!= osl::FileBase::E_None
) {
113 osl::DirectoryItem directoryItem
;
114 while (dirToScan
.getNextItem(directoryItem
) == osl::FileBase::E_None
) {
115 osl::FileStatus
status(osl_FileStatus_Mask_Type
| osl_FileStatus_Mask_FileURL
| osl_FileStatus_Mask_FileName
);
116 osl::FileBase::RC retvalStatus
= directoryItem
.getFileStatus(status
);
117 if (retvalStatus
!= osl::FileBase::E_None
) {
121 OUString filename
= convert_to_absolute_path(status
.getFileURL());
122 if (!FileIsValidIconTheme(filename
)) {
125 found
.push_back(filename
);
131 IconThemeScanner::FileIsValidIconTheme(const OUString
& filename
)
133 // check whether we can construct a IconThemeInfo from it
134 if (!IconThemeInfo::UrlCanBeParsed(filename
)) {
135 SAL_INFO("vcl.app", "File '" << filename
<< "' does not seem to be an icon theme.");
139 osl::FileStatus
fileStatus(osl_FileStatus_Mask_Type
);
140 bool couldSetFileStatus
= set_file_status(fileStatus
, filename
);
141 if (!couldSetFileStatus
) {
145 if (!fileStatus
.isRegular()) {
152 IconThemeScanner::IconThemeIsInstalled(const OUString
& themeId
) const
154 return IconThemeInfo::IconThemeIsInVector(mFoundIconThemes
, themeId
);
157 /*static*/ std::shared_ptr
<IconThemeScanner
>
158 IconThemeScanner::Create(const OUString
&path
)
160 std::shared_ptr
<IconThemeScanner
> retval(new IconThemeScanner
);
161 retval
->ScanDirectoryForIconThemes(path
);
166 IconThemeScanner::GetStandardIconThemePath()
168 OUString
url( "$BRAND_BASE_DIR/" LIBO_SHARE_FOLDER
"/config/" );
169 rtl::Bootstrap::expandMacros(url
);
173 IconThemeScanner::~IconThemeScanner()
179 public std::unary_function
<const vcl::IconThemeInfo
&, bool>
182 const OUString
& m_rThemeId
;
184 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: */