Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ***********************************************************************/
28 : :
29 : :
30 : : #include "sal/config.h"
31 : :
32 : : #include <list>
33 : : #include <memory>
34 : : #include <utility>
35 : : #include <vector>
36 : : #include <boost/unordered_map.hpp>
37 : : #include <boost/shared_ptr.hpp>
38 : :
39 : : #include "com/sun/star/container/XNameAccess.hpp"
40 : : #include "com/sun/star/io/XInputStream.hpp"
41 : : #include "com/sun/star/lang/Locale.hpp"
42 : : #include "com/sun/star/uno/Any.hxx"
43 : : #include "com/sun/star/uno/Exception.hpp"
44 : : #include "com/sun/star/uno/Reference.hxx"
45 : : #include "com/sun/star/uno/RuntimeException.hpp"
46 : : #include "com/sun/star/uno/Sequence.hxx"
47 : :
48 : : #include "comphelper/processfactory.hxx"
49 : :
50 : : #include "osl/file.hxx"
51 : : #include "osl/diagnose.h"
52 : :
53 : : #include "rtl/bootstrap.hxx"
54 : : #include "rtl/string.h"
55 : : #include "rtl/textenc.h"
56 : : #include "rtl/ustrbuf.hxx"
57 : : #include "rtl/ustring.h"
58 : : #include "rtl/ustring.hxx"
59 : :
60 : : #include "sal/types.h"
61 : :
62 : : #include "tools/stream.hxx"
63 : : #include "tools/urlobj.hxx"
64 : :
65 : : #include "vcl/bitmapex.hxx"
66 : : #include "vcl/pngread.hxx"
67 : : #include "vcl/settings.hxx"
68 : : #include "vcl/svapp.hxx"
69 : :
70 : : #include "impimagetree.hxx"
71 : :
72 : : namespace {
73 : :
74 : : namespace css = com::sun::star;
75 : :
76 : 18430 : rtl::OUString createPath(
77 : : rtl::OUString const & name, sal_Int32 pos, rtl::OUString const & locale)
78 : : {
79 [ + - ]: 18430 : rtl::OUStringBuffer b(name.copy(0, pos + 1));
80 [ + - ]: 18430 : b.append(locale);
81 [ + - ]: 18430 : b.append(name.copy(pos));
82 [ + - ]: 18430 : return b.makeStringAndClear();
83 : : }
84 : :
85 : 0 : boost::shared_ptr< SvStream > wrapFile(osl::File & file)
86 : : {
87 : : // This could use SvInputStream instead if that did not have a broken
88 : : // SeekPos implementation for an XInputStream that is not also XSeekable
89 : : // (cf. "@@@" at tags/DEV300_m37/svtools/source/misc1/strmadpt.cxx@264807
90 : : // l. 593):
91 [ # # ][ # # ]: 0 : boost::shared_ptr< SvStream > s(new SvMemoryStream);
92 : 0 : for (;;) {
93 : : void *data[2048];
94 : : sal_uInt64 n;
95 [ # # ]: 0 : file.read(data, 2048, n);
96 [ # # ]: 0 : s->Write(data, n);
97 [ # # ]: 0 : if (n < 2048) {
98 : : break;
99 : : }
100 : : }
101 [ # # ]: 0 : s->Seek(0);
102 : 0 : return s;
103 : : }
104 : :
105 : 0 : void loadFromFile(
106 : : osl::File & file,
107 : : rtl::OUString const & path, BitmapEx & bitmap)
108 : : {
109 [ # # ]: 0 : boost::shared_ptr< SvStream > s(wrapFile(file));
110 [ # # ]: 0 : if (path.endsWithAsciiL(RTL_CONSTASCII_STRINGPARAM(".png")))
111 : : {
112 [ # # ]: 0 : vcl::PNGReader aPNGReader( *s );
113 [ # # ]: 0 : aPNGReader.SetIgnoreGammaChunk( sal_True );
114 [ # # ][ # # ]: 0 : bitmap = aPNGReader.Read();
[ # # ][ # # ]
115 : : } else {
116 [ # # ]: 0 : *s >> bitmap;
117 [ # # ]: 0 : }
118 : 0 : }
119 : :
120 : 7400 : boost::shared_ptr< SvStream > wrapStream(
121 : : css::uno::Reference< css::io::XInputStream > const & stream)
122 : : {
123 : : // This could use SvInputStream instead if that did not have a broken
124 : : // SeekPos implementation for an XInputStream that is not also XSeekable
125 : : // (cf. "@@@" at tags/DEV300_m37/svtools/source/misc1/strmadpt.cxx@264807
126 : : // l. 593):
127 : : OSL_ASSERT(stream.is());
128 [ + - ][ + - ]: 7400 : boost::shared_ptr< SvStream > s(new SvMemoryStream);
129 : 24 : for (;;) {
130 : 7424 : sal_Int32 const size = 2048;
131 [ + - ]: 7424 : css::uno::Sequence< sal_Int8 > data(size);
132 [ + - ][ + - ]: 7424 : sal_Int32 n = stream->readBytes(data, size);
133 [ + - ]: 7424 : s->Write(data.getConstArray(), n);
134 [ + + ]: 7424 : if (n < size) {
135 : : break;
136 : : }
137 [ + - ][ + + ]: 7424 : }
138 [ + - ]: 7400 : s->Seek(0);
139 : 7400 : return s;
140 : : }
141 : :
142 : 7400 : void loadFromStream(
143 : : css::uno::Reference< css::io::XInputStream > const & stream,
144 : : rtl::OUString const & path, BitmapEx & bitmap)
145 : : {
146 [ + - ]: 7400 : boost::shared_ptr< SvStream > s(wrapStream(stream));
147 [ + + ]: 7400 : if (path.endsWithAsciiL(RTL_CONSTASCII_STRINGPARAM(".png")))
148 : : {
149 [ + - ]: 7392 : vcl::PNGReader aPNGReader( *s );
150 [ + - ]: 7392 : aPNGReader.SetIgnoreGammaChunk( sal_True );
151 [ + - ][ + - ]: 7392 : bitmap = aPNGReader.Read();
[ + - ][ + - ]
152 : : } else {
153 [ + - ]: 8 : *s >> bitmap;
154 [ + - ]: 7400 : }
155 : 7400 : }
156 : :
157 : : }
158 : :
159 [ + - ][ + - ]: 212 : ImplImageTree::ImplImageTree() { m_cacheIcons = true; }
[ + - ]
160 : :
161 [ + - ][ + - ]: 212 : ImplImageTree::~ImplImageTree() {}
162 : :
163 : 494 : bool ImplImageTree::checkStyle(rtl::OUString const & style)
164 : : {
165 : : bool exists;
166 : :
167 : : // using cache because setStyle is an expensive operation
168 : : // setStyle calls resetPaths => closes any opened zip files with icons, cleans the icon cache, ...
169 [ + - ][ + + ]: 494 : if (checkStyleCacheLookup(style, exists)) {
170 : 54 : return exists;
171 : : }
172 : :
173 [ + - ]: 440 : setStyle(style);
174 : :
175 : 440 : exists = false;
176 : 440 : const rtl::OUString sBrandURLSuffix("_brand");
177 [ + + ][ + - ]: 2254 : for (Paths::iterator i(m_paths.begin()); i != m_paths.end() && !exists; ++i) {
[ + - ][ + + ]
178 : 1814 : ::rtl::OUString aURL = i->first;
179 : 1814 : sal_Int32 nFromIndex = aURL.getLength() - sBrandURLSuffix.getLength();
180 : : // skip brand-specific icon themes; they are incomplete and thus not useful for this check
181 [ + + ][ + + ]: 1814 : if (nFromIndex < 0 || !aURL.match(sBrandURLSuffix, nFromIndex)) {
[ + + ]
182 : 1312 : osl::File aZip(aURL + ".zip");
183 [ + + ][ + - ]: 1312 : if (aZip.open(osl_File_OpenFlag_Read) == ::osl::FileBase::E_None) {
184 [ + - ]: 62 : aZip.close();
185 : 62 : exists = true;
186 : : }
187 : :
188 : 1312 : osl::Directory aLookaside(aURL);
189 [ - + ][ + - ]: 1312 : if (aLookaside.open() == ::osl::FileBase::E_None) {
190 [ # # ]: 0 : aLookaside.close();
191 : 0 : exists = true;
192 : 0 : m_cacheIcons = false;
193 : : } else {
194 : 1312 : m_cacheIcons = true;
195 [ + - ][ + - ]: 1312 : }
196 : : }
197 : 1814 : }
198 [ + - ]: 440 : m_checkStyleCache[style] = exists;
199 : 494 : return exists;
200 : : }
201 : :
202 : 39484 : bool ImplImageTree::loadImage(
203 : : rtl::OUString const & name, rtl::OUString const & style, BitmapEx & bitmap,
204 : : bool localized, bool loadMissing )
205 : : {
206 : 39484 : bool found = false;
207 : : try {
208 [ + - ]: 39484 : found = doLoadImage(name, style, bitmap, localized);
209 [ # # ]: 0 : } catch (css::uno::RuntimeException &) {
210 [ # # ]: 0 : if (!loadMissing)
211 : 0 : throw;
212 : : }
213 [ + + ][ + - ]: 39484 : if (found || !loadMissing)
214 : 39484 : return found;
215 : :
216 : : OSL_TRACE(
217 : : "ImplImageTree::loadImage exception couldn't load \"%s\", fetching default image",
218 : : rtl::OUStringToOString(name, RTL_TEXTENCODING_UTF8).getStr());
219 : 39484 : return loadDefaultImage(style, bitmap);
220 : : }
221 : :
222 : 8080 : bool ImplImageTree::loadDefaultImage(
223 : : rtl::OUString const & style,
224 : : BitmapEx& bitmap)
225 : : {
226 : : return doLoadImage(
227 : : rtl::OUString("res/grafikde.png"),
228 [ + - ]: 8080 : style, bitmap, false);
229 : : }
230 : :
231 : :
232 : 47564 : bool ImplImageTree::doLoadImage(
233 : : rtl::OUString const & name, rtl::OUString const & style, BitmapEx & bitmap,
234 : : bool localized)
235 : : {
236 [ + - ]: 47564 : setStyle(style);
237 [ + - ][ + - ]: 47564 : if (m_cacheIcons && iconCacheLookup(name, localized, bitmap)) {
[ + + ][ + + ]
238 : 38255 : return true;
239 : : }
240 [ + - ][ - + ]: 9309 : if (!bitmap.IsEmpty()) {
241 [ # # ]: 0 : bitmap.SetEmpty();
242 : : }
243 [ + - ]: 9309 : std::vector< rtl::OUString > paths;
244 [ + - ]: 9309 : paths.push_back(name);
245 [ + + ]: 9309 : if (localized) {
246 : 9215 : sal_Int32 pos = name.lastIndexOf('/');
247 [ + - ]: 9215 : if (pos != -1) {
248 : : css::lang::Locale const & loc =
249 [ + - ][ + - ]: 9215 : Application::GetSettings().GetUILocale();
250 [ + - ][ + - ]: 9215 : paths.push_back(createPath(name, pos, loc.Language));
251 [ + - ]: 9215 : if (!loc.Country.isEmpty()) {
252 [ + - ]: 9215 : rtl::OUStringBuffer b(loc.Language);
253 [ + - ]: 9215 : b.append(sal_Unicode('-'));
254 [ + - ]: 9215 : b.append(loc.Country);
255 [ + - ][ + - ]: 9215 : rtl::OUString p(createPath(name, pos, b.makeStringAndClear()));
256 [ + - ]: 9215 : paths.push_back(p);
257 [ - + ]: 9215 : if (!loc.Variant.isEmpty()) {
258 [ # # ]: 0 : b.append(p);
259 [ # # ]: 0 : b.append(sal_Unicode('-'));
260 [ # # ]: 0 : b.append(loc.Variant);
261 : : paths.push_back(
262 [ # # ][ # # ]: 0 : createPath(name, pos, b.makeStringAndClear()));
[ # # ]
263 : 9215 : }
264 : : }
265 : : }
266 : : }
267 : 9309 : bool found = false;
268 : : try {
269 [ + - ]: 9309 : found = find(paths, bitmap);
270 [ # # # ]: 0 : } catch (css::uno::RuntimeException &) {
271 : 0 : throw;
272 [ # # ]: 0 : } catch (const css::uno::Exception & e) {
273 : : OSL_TRACE(
274 : : "ImplImageTree::loadImage exception \"%s\"",
275 : : rtl::OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8).getStr());
276 : : }
277 [ + - ][ + + ]: 9309 : if (m_cacheIcons && found) {
278 [ + - ][ + - ]: 7400 : m_iconCache[name.intern()] = std::make_pair(localized, bitmap);
[ + - ][ + - ]
[ + - ]
279 : : }
280 : 47564 : return found;
281 : : }
282 : :
283 : 158 : void ImplImageTree::shutDown() {
284 : 158 : m_style = rtl::OUString();
285 : : // for safety; empty m_style means "not initialized"
286 : 158 : m_paths.clear();
287 : 158 : m_iconCache.clear();
288 : 158 : m_checkStyleCache.clear();
289 : 158 : }
290 : :
291 : 48004 : void ImplImageTree::setStyle(rtl::OUString const & style) {
292 : : OSL_ASSERT(!style.isEmpty()); // empty m_style means "not initialized"
293 [ + + ]: 48004 : if (style != m_style) {
294 : 494 : m_style = style;
295 : 494 : resetPaths();
296 : 494 : m_iconCache.clear();
297 : : }
298 : 48004 : }
299 : :
300 : 494 : void ImplImageTree::resetPaths() {
301 : 494 : m_paths.clear();
302 : : {
303 : : rtl::OUString url(
304 : 494 : "$BRAND_BASE_DIR/program/edition/images");
305 : 494 : rtl::Bootstrap::expandMacros(url);
306 [ + - ]: 494 : INetURLObject u(url);
307 : : OSL_ASSERT(!u.HasError());
308 : : m_paths.push_back(
309 : : std::make_pair(
310 : : u.GetMainURL(INetURLObject::NO_DECODE),
311 [ + - ][ + - ]: 494 : css::uno::Reference< css::container::XNameAccess >()));
[ + - ][ + - ]
[ + - ]
312 : : }
313 : : {
314 : : rtl::OUString url(
315 : 494 : "$BRAND_BASE_DIR/share/config");
316 : 494 : rtl::Bootstrap::expandMacros(url);
317 [ + - ]: 494 : INetURLObject u(url);
318 : : OSL_ASSERT(!u.HasError());
319 : 494 : rtl::OUStringBuffer b;
320 [ + - ]: 494 : b.appendAscii(RTL_CONSTASCII_STRINGPARAM("images_"));
321 [ + - ]: 494 : b.append(m_style);
322 [ + - ]: 494 : b.appendAscii(RTL_CONSTASCII_STRINGPARAM("_brand"));
323 [ + - ][ + - ]: 494 : bool ok = u.Append(b.makeStringAndClear(), INetURLObject::ENCODE_ALL);
324 : : OSL_ASSERT(ok); (void) ok;
325 : : m_paths.push_back(
326 : : std::make_pair(
327 : : u.GetMainURL(INetURLObject::NO_DECODE),
328 [ + - ][ + - ]: 494 : css::uno::Reference< css::container::XNameAccess >()));
[ + - ][ + - ]
[ + - ]
329 : : }
330 : : {
331 : 494 : rtl::OUString url( "$BRAND_BASE_DIR/share/config/images_brand");
332 : 494 : rtl::Bootstrap::expandMacros(url);
333 : : m_paths.push_back(
334 : : std::make_pair(
335 [ + - ][ + - ]: 494 : url, css::uno::Reference< css::container::XNameAccess >()));
[ + - ]
336 : : }
337 : : {
338 : : rtl::OUString url(
339 : 494 : "$BRAND_BASE_DIR/share/config");
340 : 494 : rtl::Bootstrap::expandMacros(url);
341 [ + - ]: 494 : INetURLObject u(url);
342 : : OSL_ASSERT(!u.HasError());
343 : 494 : rtl::OUStringBuffer b;
344 [ + - ]: 494 : b.appendAscii(RTL_CONSTASCII_STRINGPARAM("images_"));
345 [ + - ]: 494 : b.append(m_style);
346 [ + - ][ + - ]: 494 : bool ok = u.Append(b.makeStringAndClear(), INetURLObject::ENCODE_ALL);
347 : : OSL_ASSERT(ok); (void) ok;
348 : : m_paths.push_back(
349 : : std::make_pair(
350 : : u.GetMainURL(INetURLObject::NO_DECODE),
351 [ + - ][ + - ]: 494 : css::uno::Reference< css::container::XNameAccess >()));
[ + - ][ + - ]
[ + - ]
352 : : }
353 [ + + ]: 494 : if ( m_style == "default" )
354 : : {
355 : 54 : rtl::OUString url( "$BRAND_BASE_DIR/share/config/images");
356 : 54 : rtl::Bootstrap::expandMacros(url);
357 : : m_paths.push_back(
358 : : std::make_pair(
359 [ + - ][ + - ]: 54 : url, css::uno::Reference< css::container::XNameAccess >()));
[ + - ]
360 : : }
361 : 494 : }
362 : :
363 : 494 : bool ImplImageTree::checkStyleCacheLookup(
364 : : rtl::OUString const & style, bool &exists)
365 : : {
366 [ + - ]: 494 : CheckStyleCache::iterator i(m_checkStyleCache.find(style));
367 [ + - ][ + + ]: 494 : if (i != m_checkStyleCache.end()) {
368 [ + - ]: 54 : exists = i->second;
369 : 54 : return true;
370 : : } else {
371 : 494 : return false;
372 : : }
373 : : }
374 : :
375 : 47564 : bool ImplImageTree::iconCacheLookup(
376 : : rtl::OUString const & name, bool localized, BitmapEx & bitmap)
377 : : {
378 [ + - ]: 47564 : IconCache::iterator i(m_iconCache.find(name));
379 [ + - ][ + + ]: 47564 : if (i != m_iconCache.end() && i->second.first == localized) {
[ + - ][ + - ]
[ + - ]
[ + + # # ]
380 [ + - ][ + - ]: 38255 : bitmap = i->second.second;
381 : 38255 : return true;
382 : : } else {
383 : 47564 : return false;
384 : : }
385 : : }
386 : :
387 : 9309 : bool ImplImageTree::find(
388 : : std::vector< rtl::OUString > const & paths, BitmapEx & bitmap)
389 : : {
390 [ - + ]: 9309 : if (!m_cacheIcons) {
391 [ # # ]: 0 : for (Paths::iterator i(m_paths.begin()); i != m_paths.end(); ++i) {
392 [ # # ][ # # ]: 0 : for (std::vector< rtl::OUString >::const_reverse_iterator j(
[ # # ]
393 : 0 : paths.rbegin());
394 : 0 : j != paths.rend(); ++j)
395 : : {
396 [ # # ]: 0 : osl::File file(i->first + "/" + *j);
397 [ # # ][ # # ]: 0 : if (file.open(osl_File_OpenFlag_Read) == ::osl::FileBase::E_None) {
398 [ # # ][ # # ]: 0 : loadFromFile(file, *j, bitmap);
399 [ # # ]: 0 : file.close();
400 : 0 : return true;
401 : : }
402 [ # # ][ # # ]: 0 : }
403 : : }
404 : : }
405 : :
406 [ + + ]: 9711 : for (Paths::iterator i(m_paths.begin()); i != m_paths.end();) {
407 [ + + ]: 7802 : if (!i->second.is()) {
408 [ + - ]: 464 : css::uno::Sequence< css::uno::Any > args(1);
409 [ + - ][ + - ]: 464 : args[0] <<= i->first + ".zip";
410 : : try {
411 : 62 : i->second.set(
412 : : comphelper::createProcessComponentWithArguments(
413 : : rtl::OUString( "com.sun.star.packages.zip.ZipFileAccess"),
414 : : args),
415 [ + + ]: 990 : css::uno::UNO_QUERY_THROW);
[ + + + - ]
416 : 0 : } catch (css::uno::RuntimeException &) {
417 : 0 : throw;
418 [ - - + ]: 804 : } catch (const css::uno::Exception & e) {
[ + - ]
419 : : OSL_TRACE(
420 : : "ImplImageTree::find exception \"%s\"",
421 : : rtl::OUStringToOString(
422 : : e.Message, RTL_TEXTENCODING_UTF8).getStr());
423 [ - + ]: 402 : i = m_paths.erase(i);
424 : 402 : continue;
425 [ + - ]: 464 : }
426 : : }
427 [ + - + - ]: 44384 : for (std::vector< rtl::OUString >::const_reverse_iterator j(
[ + - ]
428 : 7400 : paths.rbegin());
429 : 22192 : j != paths.rend(); ++j)
430 : : {
431 [ + - ][ + - ]: 22192 : if (i->second->hasByName(*j)) {
[ + - ][ + + ]
432 : 7400 : css::uno::Reference< css::io::XInputStream > s;
433 [ + - ][ + - ]: 7400 : bool ok = i->second->getByName(*j) >>= s;
[ + - ][ + - ]
434 : : OSL_ASSERT(ok); (void) ok;
435 [ + - ][ + - ]: 7400 : loadFromStream(s, *j, bitmap);
436 : 7400 : return true;
437 : : }
438 : : }
439 : 0 : ++i;
440 : : }
441 : 9309 : return false;
442 : : }
443 : :
444 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|