Update ooo320-m1
[ooovba.git] / vcl / source / gdi / impimagetree.cxx
blob4bc8ab0f57e51066acc30d7af3c9f3d3547eb18e
1 /*************************************************************************
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 * Copyright 2008 by Sun Microsystems, Inc.
6 * OpenOffice.org - a multi-platform office productivity suite
8 * $RCSfile: code,v $
10 * $Revision: 1.4 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
28 ************************************************************************/
30 #include "precompiled_vcl.hxx"
31 #include "sal/config.h"
33 #include <list>
34 #include <memory>
35 #include <utility>
36 #include <vector>
38 #include <hash_map>
40 #include "com/sun/star/container/XNameAccess.hpp"
41 #include "com/sun/star/io/XInputStream.hpp"
42 #include "com/sun/star/lang/Locale.hpp"
43 #include "com/sun/star/uno/Any.hxx"
44 #include "com/sun/star/uno/Exception.hpp"
45 #include "com/sun/star/uno/Reference.hxx"
46 #include "com/sun/star/uno/RuntimeException.hpp"
47 #include "com/sun/star/uno/Sequence.hxx"
48 #include "comphelper/processfactory.hxx"
49 #include "osl/file.hxx"
50 #include "osl/diagnose.h"
51 #include "rtl/bootstrap.hxx"
52 #include "rtl/string.h"
53 #include "rtl/textenc.h"
54 #include "rtl/ustrbuf.hxx"
55 #include "rtl/ustring.h"
56 #include "rtl/ustring.hxx"
57 #include "sal/types.h"
58 #include "tools/stream.hxx"
59 #include "tools/urlobj.hxx"
60 #include "vcl/bitmapex.hxx"
61 #include "vcl/impimagetree.hxx"
62 #include "vcl/pngread.hxx"
63 #include "vcl/settings.hxx"
64 #include "vcl/svapp.hxx"
66 namespace {
68 namespace css = com::sun::star;
70 rtl::OUString createPath(
71 rtl::OUString const & name, sal_Int32 pos, rtl::OUString const & locale)
73 rtl::OUStringBuffer b(name.copy(0, pos + 1));
74 b.append(locale);
75 b.append(name.copy(pos));
76 return b.makeStringAndClear();
79 std::auto_ptr< SvStream > wrapStream(
80 css::uno::Reference< css::io::XInputStream > const & stream)
82 // This could use SvInputStream instead if that did not have a broken
83 // SeekPos implementation for an XInputStream that is not also XSeekable
84 // (cf. "@@@" at tags/DEV300_m37/svtools/source/misc1/strmadpt.cxx@264807
85 // l. 593):
86 OSL_ASSERT(stream.is());
87 std::auto_ptr< SvStream > s(new SvMemoryStream);
88 for (;;) {
89 css::uno::Sequence< sal_Int8 > data;
90 sal_Int32 const size = 30000;
91 sal_Int32 n = stream->readBytes(data, size);
92 s->Write(data.getConstArray(), n);
93 if (n < size) {
94 break;
97 s->Seek(0);
98 return s;
101 void loadFromStream(
102 css::uno::Reference< css::io::XInputStream > const & stream,
103 rtl::OUString const & path, BitmapEx & bitmap)
105 std::auto_ptr< SvStream > s(wrapStream(stream));
106 if (path.endsWithAsciiL(RTL_CONSTASCII_STRINGPARAM(".png")))
108 vcl::PNGReader aPNGReader( *s );
109 aPNGReader.SetIgnoreGammaChunk( sal_True );
110 bitmap = aPNGReader.Read();
111 } else {
112 *s >> bitmap;
118 ImplImageTree::ImplImageTree()
120 m_datadir = ::rtl::OUString::createFromAscii ( "/usr/share/" );
121 #ifdef X86_64
122 m_libdir = ::rtl::OUString::createFromAscii ( "/usr/lib64/" );
123 #else
124 m_libdir = ::rtl::OUString::createFromAscii ( "/usr/lib/" );
125 #endif
128 ImplImageTree::~ImplImageTree() {}
130 bool ImplImageTree::checkStyle(rtl::OUString const & style)
132 bool exists;
134 // using cache because setStyle is an expensive operation
135 // setStyle calls resetZips => closes any opened zip files with icons, cleans the icon cache, ...
136 if (checkStyleCacheLookup(style, exists)) {
137 return exists;
140 setStyle(style);
142 exists = false;
143 const rtl::OUString sBrandURLSuffix(RTL_CONSTASCII_USTRINGPARAM("_brand.zip"));
144 for (Zips::iterator i(m_zips.begin()); i != m_zips.end() && !exists;) {
145 ::rtl::OUString aZipURL = i->first;
146 sal_Int32 nFromIndex = aZipURL.getLength() - sBrandURLSuffix.getLength();
147 // skip brand-specific icon themes; they are incomplete and thus not useful for this check
148 if (nFromIndex < 0 || !aZipURL.match(sBrandURLSuffix, nFromIndex)) {
149 osl::File aZip(aZipURL);
150 if (aZip.open(OpenFlag_Read) == ::osl::FileBase::E_None) {
151 aZip.close();
152 exists = true;
155 ++i;
157 m_checkStyleCache[style] = exists;
158 return exists;
161 bool ImplImageTree::loadImage(
162 rtl::OUString const & name, rtl::OUString const & style, BitmapEx & bitmap,
163 bool localized)
165 setStyle(style);
166 if (iconCacheLookup(name, localized, bitmap)) {
167 return true;
169 if (!bitmap.IsEmpty()) {
170 bitmap.SetEmpty();
172 std::vector< rtl::OUString > paths;
173 paths.push_back(name);
174 if (localized) {
175 sal_Int32 pos = name.lastIndexOf('/');
176 if (pos != -1) {
177 css::lang::Locale const & loc =
178 Application::GetSettings().GetUILocale();
179 paths.push_back(createPath(name, pos, loc.Language));
180 if (loc.Country.getLength() != 0) {
181 rtl::OUStringBuffer b(loc.Language);
182 b.append(sal_Unicode('-'));
183 b.append(loc.Country);
184 rtl::OUString p(createPath(name, pos, b.makeStringAndClear()));
185 paths.push_back(p);
186 if (loc.Variant.getLength() != 0) {
187 b.append(p);
188 b.append(sal_Unicode('-'));
189 b.append(loc.Variant);
190 paths.push_back(
191 createPath(name, pos, b.makeStringAndClear()));
196 bool found = false;
197 try {
198 found = find(paths, bitmap);
199 } catch (css::uno::RuntimeException &) {
200 throw;
201 } catch (css::uno::Exception & e) {
202 OSL_TRACE(
203 "ImplImageTree::loadImage exception \"%s\"",
204 rtl::OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8).getStr());
206 if (found) {
207 m_iconCache[name.intern()] = std::make_pair(localized, bitmap);
209 return found;
212 void ImplImageTree::shutDown() {
213 m_style = rtl::OUString();
214 // for safety; empty m_style means "not initialized"
215 m_zips.clear();
216 m_iconCache.clear();
217 m_checkStyleCache.clear();
220 void ImplImageTree::setStyle(rtl::OUString const & style) {
221 OSL_ASSERT(style.getLength() != 0); // empty m_style means "not initialized"
222 if (style != m_style) {
223 m_style = style;
224 resetZips();
225 m_iconCache.clear();
229 void ImplImageTree::addUrlToZips(const rtl::OUString &url) {
230 if ( url.getLength() == 0 )
231 return;
232 m_zips.push_back(
233 std::make_pair(
234 url,
235 css::uno::Reference< css::container::XNameAccess >()));
236 sal_Int32 nLibDirPos = url.indexOf( m_libdir );
237 if ( nLibDirPos >= 0 ) {
238 m_zips.push_back(
239 std::make_pair(
240 url.replaceAt( nLibDirPos, m_libdir.getLength(), m_datadir ),
241 css::uno::Reference< css::container::XNameAccess >()));
245 void ImplImageTree::resetZips() {
246 m_zips.clear();
248 rtl::OUString url(
249 RTL_CONSTASCII_USTRINGPARAM("$BRAND_BASE_DIR/program/edition/images.zip"));
250 rtl::Bootstrap::expandMacros(url);
251 INetURLObject u(url);
252 OSL_ASSERT(!u.HasError());
253 m_zips.push_back(
254 std::make_pair(
255 u.GetMainURL(INetURLObject::NO_DECODE),
256 css::uno::Reference< css::container::XNameAccess >()));
259 rtl::OUString url(
260 RTL_CONSTASCII_USTRINGPARAM("$BRAND_BASE_DIR/share/config"));
261 rtl::Bootstrap::expandMacros(url);
262 INetURLObject u(url);
263 OSL_ASSERT(!u.HasError());
264 rtl::OUStringBuffer b;
265 b.appendAscii(RTL_CONSTASCII_STRINGPARAM("images_"));
266 b.append(m_style);
267 b.appendAscii(RTL_CONSTASCII_STRINGPARAM("_brand.zip"));
268 bool ok = u.Append(b.makeStringAndClear(), INetURLObject::ENCODE_ALL);
269 OSL_ASSERT(ok); (void) ok;
270 addUrlToZips(u.GetMainURL(INetURLObject::NO_DECODE));
273 rtl::OUString url(
274 RTL_CONSTASCII_USTRINGPARAM(
275 "$BRAND_BASE_DIR/share/config/images_brand.zip"));
276 rtl::Bootstrap::expandMacros(url);
277 addUrlToZips(url);
280 rtl::OUString url(
281 RTL_CONSTASCII_USTRINGPARAM("$OOO_BASE_DIR/share/config"));
282 rtl::Bootstrap::expandMacros(url);
283 INetURLObject u(url);
284 OSL_ASSERT(!u.HasError());
285 rtl::OUStringBuffer b;
286 b.appendAscii(RTL_CONSTASCII_STRINGPARAM("images_"));
287 b.append(m_style);
288 b.appendAscii(RTL_CONSTASCII_STRINGPARAM(".zip"));
289 bool ok = u.Append(b.makeStringAndClear(), INetURLObject::ENCODE_ALL);
290 OSL_ASSERT(ok); (void) ok;
291 addUrlToZips(u.GetMainURL(INetURLObject::NO_DECODE));
293 if ( m_style.equals(::rtl::OUString::createFromAscii("default")) )
295 rtl::OUString url(
296 RTL_CONSTASCII_USTRINGPARAM(
297 "$OOO_BASE_DIR/share/config/images.zip"));
298 rtl::Bootstrap::expandMacros(url);
299 addUrlToZips(url);
303 bool ImplImageTree::checkStyleCacheLookup(
304 rtl::OUString const & style, bool &exists)
306 CheckStyleCache::iterator i(m_checkStyleCache.find(style));
307 if (i != m_checkStyleCache.end()) {
308 exists = i->second;
309 return true;
310 } else {
311 return false;
315 bool ImplImageTree::iconCacheLookup(
316 rtl::OUString const & name, bool localized, BitmapEx & bitmap)
318 IconCache::iterator i(m_iconCache.find(name));
319 if (i != m_iconCache.end() && i->second.first == localized) {
320 bitmap = i->second.second;
321 return true;
322 } else {
323 return false;
327 bool ImplImageTree::find(
328 std::vector< rtl::OUString > const & paths, BitmapEx & bitmap)
330 for (Zips::iterator i(m_zips.begin()); i != m_zips.end();) {
331 if (!i->second.is()) {
332 css::uno::Sequence< css::uno::Any > args(1);
333 args[0] <<= i->first;
334 try {
335 i->second.set(
336 comphelper::createProcessComponentWithArguments(
337 rtl::OUString(
338 RTL_CONSTASCII_USTRINGPARAM(
339 "com.sun.star.packages.zip.ZipFileAccess")),
340 args),
341 css::uno::UNO_QUERY_THROW);
342 } catch (css::uno::RuntimeException &) {
343 throw;
344 } catch (css::uno::Exception & e) {
345 OSL_TRACE(
346 "ImplImageTree::find exception \"%s\"",
347 rtl::OUStringToOString(
348 e.Message, RTL_TEXTENCODING_UTF8).getStr());
349 i = m_zips.erase(i);
350 continue;
353 for (std::vector< rtl::OUString >::const_reverse_iterator j(
354 paths.rbegin());
355 j != paths.rend(); ++j)
357 if (i->second->hasByName(*j)) {
358 css::uno::Reference< css::io::XInputStream > s;
359 bool ok = i->second->getByName(*j) >>= s;
360 OSL_ASSERT(ok); (void) ok;
361 loadFromStream(s, *j, bitmap);
362 return true;
365 ++i;
367 return false;