LibreOffice Module vcl (master)  1
IconThemeScanner.cxx
Go to the documentation of this file.
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 <sal/config.h>
11 #include <sal/log.hxx>
12 
13 #include <deque>
14 
15 #include <vcl/IconThemeScanner.hxx>
16 
17 #include <osl/file.hxx>
18 #include <salhelper/linkhelper.hxx>
19 #include <unotools/pathoptions.hxx>
20 #include <vcl/IconThemeInfo.hxx>
21 
22 namespace vcl {
23 
24 namespace {
25 
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)
28 {
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 << "'.");
33  return false;
34  }
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 << "'.");
38  return false;
39  }
40  return true;
41 }
42 
43 OUString convert_to_absolute_path(const OUString& path)
44 {
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)
50  {
51  throw std::runtime_error("Provided a recursive symlink to an icon theme directory that could not be resolved.");
52  }
53  }
54  return resolver.m_aStatus.getFileURL();
55 }
56 
57 }
58 
60 {}
61 
63 {
64  mFoundIconThemes.clear();
65 
66  std::deque<OUString> aPaths;
67 
68  sal_Int32 nIndex = 0;
69  do
70  {
71  aPaths.push_front(paths.getToken(0, ';', nIndex));
72  }
73  while (nIndex >= 0);
74 
75  for (const auto& path : aPaths)
76  {
77  osl::FileStatus fileStatus(osl_FileStatus_Mask_Type);
78  bool couldSetFileStatus = set_file_status(fileStatus, path);
79  if (!couldSetFileStatus) {
80  continue;
81  }
82 
83  if (!fileStatus.isDirectory()) {
84  SAL_INFO("vcl.app", "Cannot search for icon themes in '"<< path << "'. It is not a directory.");
85  continue;
86  }
87 
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<<"'.");
91  continue;
92  }
93  for (auto const& iconThemePath : iconThemePaths)
94  {
95  AddIconThemeByPath(iconThemePath);
96  }
97  }
98 }
99 
100 bool
102 {
103  if (!IconThemeInfo::UrlCanBeParsed(url)) {
104  return false;
105  }
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() << "'.");
111  return true;
112 }
113 
114 /*static*/ std::vector<OUString>
116 {
117  std::vector<OUString> found;
118  SAL_INFO("vcl.app", "Scanning directory '" << dir << " for icon themes.");
119 
120  osl::Directory dirToScan(dir);
121  osl::FileBase::RC retvalOpen = dirToScan.open();
122  if (retvalOpen != osl::FileBase::E_None) {
123  return found;
124  }
125 
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) {
131  continue;
132  }
133 
134  OUString filename = convert_to_absolute_path(status.getFileURL());
135  if (!FileIsValidIconTheme(filename)) {
136  continue;
137  }
138  found.push_back(filename);
139  }
140  return found;
141 }
142 
143 /*static*/ bool
144 IconThemeScanner::FileIsValidIconTheme(const OUString& filename)
145 {
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.");
149  return false;
150  }
151 
152  osl::FileStatus fileStatus(osl_FileStatus_Mask_Type);
153  bool couldSetFileStatus = set_file_status(fileStatus, filename);
154  if (!couldSetFileStatus) {
155  return false;
156  }
157 
158  if (!fileStatus.isRegular()) {
159  return false;
160  }
161  return true;
162 }
163 
164 bool
165 IconThemeScanner::IconThemeIsInstalled(const OUString& themeId) const
166 {
168 }
169 
170 /*static*/ std::shared_ptr<IconThemeScanner>
171 IconThemeScanner::Create(const OUString &path)
172 {
173  std::shared_ptr<IconThemeScanner> retval(new IconThemeScanner);
174  retval->ScanDirectoryForIconThemes(path);
175  return retval;
176 }
177 
178 /*static*/ OUString
180 {
181  SvtPathOptions aPathOptions;
182  return aPathOptions.GetIconsetPath();
183 }
184 
185 namespace
186 {
187  class SameTheme
188  {
189  private:
190  const OUString& m_rThemeId;
191  public:
192  explicit SameTheme(const OUString &rThemeId) : m_rThemeId(rThemeId) {}
193  bool operator()(const vcl::IconThemeInfo &rInfo)
194  {
195  return m_rThemeId == rInfo.GetThemeId();
196  }
197  };
198 }
199 
200 const vcl::IconThemeInfo&
201 IconThemeScanner::GetIconThemeInfo(const OUString& themeId)
202 {
203  std::vector<IconThemeInfo>::iterator info = std::find_if(mFoundIconThemes.begin(), mFoundIconThemes.end(),
204  SameTheme(themeId));
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");
209  }
210  return *info;
211 }
212 
213 } // end namespace vcl
214 
215 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
This class provides information about an icon theme.
const OUString & GetThemeId() const
tuple resolver
static std::shared_ptr< IconThemeScanner > Create(const OUString &path)
Factory method to create the object.
static bool UrlCanBeParsed(const OUString &url)
Check whether an IconThemeInfo can be constructed from a URL.
void ScanDirectoryForIconThemes(const OUString &path)
Scan a directory for icon themes.
static bool FileIsValidIconTheme(const OUString &)
Check whether a single file is valid.
bool AddIconThemeByPath(const OUString &path)
Adds the provided icon theme by path.
static OUString GetStandardIconThemePath()
This method will return the standard path where icon themes are located.
This class scans a folder for icon themes and provides the results.
const OUString & m_rThemeId
static bool IconThemeIsInVector(const std::vector< vcl::IconThemeInfo > &themes, const OUString &themeId)
Check whether a theme with a specified id is in a vector of IconThemeInfo.
const IconThemeInfo & GetIconThemeInfo(const OUString &themeId)
Get the IconThemeInfo for a theme.
#define SAL_INFO(area, stream)
bool IconThemeIsInstalled(const OUString &themeId) const
Checks whether the theme with the provided name has been found in the scanned directory.
const OUString & GetIconsetPath() const
std::vector< IconThemeInfo > mFoundIconThemes
#define SAL_WARN(area, stream)
const OUString & GetDisplayName() const
static std::vector< OUString > ReadIconThemesFromPath(const OUString &dir)
Scans the provided directory for icon themes.