19f62ea84SAndrew Rist /************************************************************** 2cdf0e10cSrcweir * 39f62ea84SAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one 49f62ea84SAndrew Rist * or more contributor license agreements. See the NOTICE file 59f62ea84SAndrew Rist * distributed with this work for additional information 69f62ea84SAndrew Rist * regarding copyright ownership. The ASF licenses this file 79f62ea84SAndrew Rist * to you under the Apache License, Version 2.0 (the 89f62ea84SAndrew Rist * "License"); you may not use this file except in compliance 99f62ea84SAndrew Rist * with the License. You may obtain a copy of the License at 109f62ea84SAndrew Rist * 119f62ea84SAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0 129f62ea84SAndrew Rist * 139f62ea84SAndrew Rist * Unless required by applicable law or agreed to in writing, 149f62ea84SAndrew Rist * software distributed under the License is distributed on an 159f62ea84SAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 169f62ea84SAndrew Rist * KIND, either express or implied. See the License for the 179f62ea84SAndrew Rist * specific language governing permissions and limitations 189f62ea84SAndrew Rist * under the License. 199f62ea84SAndrew Rist * 209f62ea84SAndrew Rist *************************************************************/ 219f62ea84SAndrew Rist 229f62ea84SAndrew Rist 23cdf0e10cSrcweir 24cdf0e10cSrcweir #include "precompiled_vcl.hxx" 25cdf0e10cSrcweir 26cdf0e10cSrcweir #include "sal/config.h" 27cdf0e10cSrcweir 28cdf0e10cSrcweir #include <list> 29cdf0e10cSrcweir #include <memory> 30cdf0e10cSrcweir #include <utility> 31cdf0e10cSrcweir #include <vector> 32cdf0e10cSrcweir #include <hash_map> 33cdf0e10cSrcweir 34cdf0e10cSrcweir #include "com/sun/star/container/XNameAccess.hpp" 35cdf0e10cSrcweir #include "com/sun/star/io/XInputStream.hpp" 36cdf0e10cSrcweir #include "com/sun/star/lang/Locale.hpp" 37cdf0e10cSrcweir #include "com/sun/star/uno/Any.hxx" 38cdf0e10cSrcweir #include "com/sun/star/uno/Exception.hpp" 39cdf0e10cSrcweir #include "com/sun/star/uno/Reference.hxx" 40cdf0e10cSrcweir #include "com/sun/star/uno/RuntimeException.hpp" 41cdf0e10cSrcweir #include "com/sun/star/uno/Sequence.hxx" 42cdf0e10cSrcweir 43cdf0e10cSrcweir #include "comphelper/processfactory.hxx" 44cdf0e10cSrcweir 45cdf0e10cSrcweir #include "osl/file.hxx" 46cdf0e10cSrcweir #include "osl/diagnose.h" 47cdf0e10cSrcweir 48cdf0e10cSrcweir #include "rtl/bootstrap.hxx" 49cdf0e10cSrcweir #include "rtl/string.h" 50cdf0e10cSrcweir #include "rtl/textenc.h" 51cdf0e10cSrcweir #include "rtl/ustrbuf.hxx" 52cdf0e10cSrcweir #include "rtl/ustring.h" 53cdf0e10cSrcweir #include "rtl/ustring.hxx" 54cdf0e10cSrcweir 55cdf0e10cSrcweir #include "sal/types.h" 56cdf0e10cSrcweir 57cdf0e10cSrcweir #include "tools/stream.hxx" 58cdf0e10cSrcweir #include "tools/urlobj.hxx" 59cdf0e10cSrcweir 60cdf0e10cSrcweir #include "vcl/bitmapex.hxx" 61cdf0e10cSrcweir #include "vcl/pngread.hxx" 62cdf0e10cSrcweir #include "vcl/settings.hxx" 63cdf0e10cSrcweir #include "vcl/svapp.hxx" 64cdf0e10cSrcweir 65cdf0e10cSrcweir #include "impimagetree.hxx" 66cdf0e10cSrcweir 67cdf0e10cSrcweir namespace { 68cdf0e10cSrcweir 69cdf0e10cSrcweir namespace css = com::sun::star; 70cdf0e10cSrcweir 71cdf0e10cSrcweir rtl::OUString createPath( 72cdf0e10cSrcweir rtl::OUString const & name, sal_Int32 pos, rtl::OUString const & locale) 73cdf0e10cSrcweir { 74cdf0e10cSrcweir rtl::OUStringBuffer b(name.copy(0, pos + 1)); 75cdf0e10cSrcweir b.append(locale); 76cdf0e10cSrcweir b.append(name.copy(pos)); 77cdf0e10cSrcweir return b.makeStringAndClear(); 78cdf0e10cSrcweir } 79cdf0e10cSrcweir 80cdf0e10cSrcweir std::auto_ptr< SvStream > wrapStream( 81cdf0e10cSrcweir css::uno::Reference< css::io::XInputStream > const & stream) 82cdf0e10cSrcweir { 83cdf0e10cSrcweir // This could use SvInputStream instead if that did not have a broken 84cdf0e10cSrcweir // SeekPos implementation for an XInputStream that is not also XSeekable 85cdf0e10cSrcweir // (cf. "@@@" at tags/DEV300_m37/svtools/source/misc1/strmadpt.cxx@264807 86cdf0e10cSrcweir // l. 593): 87cdf0e10cSrcweir OSL_ASSERT(stream.is()); 88cdf0e10cSrcweir std::auto_ptr< SvStream > s(new SvMemoryStream); 89cdf0e10cSrcweir for (;;) { 90cdf0e10cSrcweir css::uno::Sequence< sal_Int8 > data; 91cdf0e10cSrcweir sal_Int32 const size = 30000; 92cdf0e10cSrcweir sal_Int32 n = stream->readBytes(data, size); 93cdf0e10cSrcweir s->Write(data.getConstArray(), n); 94cdf0e10cSrcweir if (n < size) { 95cdf0e10cSrcweir break; 96cdf0e10cSrcweir } 97cdf0e10cSrcweir } 98cdf0e10cSrcweir s->Seek(0); 99cdf0e10cSrcweir return s; 100cdf0e10cSrcweir } 101cdf0e10cSrcweir 102cdf0e10cSrcweir void loadFromStream( 103cdf0e10cSrcweir css::uno::Reference< css::io::XInputStream > const & stream, 104cdf0e10cSrcweir rtl::OUString const & path, BitmapEx & bitmap) 105cdf0e10cSrcweir { 106cdf0e10cSrcweir std::auto_ptr< SvStream > s(wrapStream(stream)); 107cdf0e10cSrcweir if (path.endsWithAsciiL(RTL_CONSTASCII_STRINGPARAM(".png"))) 108cdf0e10cSrcweir { 109cdf0e10cSrcweir vcl::PNGReader aPNGReader( *s ); 110cdf0e10cSrcweir aPNGReader.SetIgnoreGammaChunk( sal_True ); 111cdf0e10cSrcweir bitmap = aPNGReader.Read(); 112cdf0e10cSrcweir } else { 113cdf0e10cSrcweir *s >> bitmap; 114cdf0e10cSrcweir } 115cdf0e10cSrcweir } 116cdf0e10cSrcweir 117cdf0e10cSrcweir } 118cdf0e10cSrcweir 119cdf0e10cSrcweir ImplImageTree::ImplImageTree() {} 120cdf0e10cSrcweir 121cdf0e10cSrcweir ImplImageTree::~ImplImageTree() {} 122cdf0e10cSrcweir 123cdf0e10cSrcweir bool ImplImageTree::checkStyle(rtl::OUString const & style) 124cdf0e10cSrcweir { 125cdf0e10cSrcweir bool exists; 126cdf0e10cSrcweir 127cdf0e10cSrcweir // using cache because setStyle is an expensive operation 128cdf0e10cSrcweir // setStyle calls resetZips => closes any opened zip files with icons, cleans the icon cache, ... 129cdf0e10cSrcweir if (checkStyleCacheLookup(style, exists)) { 130cdf0e10cSrcweir return exists; 131cdf0e10cSrcweir } 132cdf0e10cSrcweir 133cdf0e10cSrcweir setStyle(style); 134cdf0e10cSrcweir 135cdf0e10cSrcweir exists = false; 136cdf0e10cSrcweir const rtl::OUString sBrandURLSuffix(RTL_CONSTASCII_USTRINGPARAM("_brand.zip")); 137cdf0e10cSrcweir for (Zips::iterator i(m_zips.begin()); i != m_zips.end() && !exists;) { 138cdf0e10cSrcweir ::rtl::OUString aZipURL = i->first; 139cdf0e10cSrcweir sal_Int32 nFromIndex = aZipURL.getLength() - sBrandURLSuffix.getLength(); 140cdf0e10cSrcweir // skip brand-specific icon themes; they are incomplete and thus not useful for this check 141cdf0e10cSrcweir if (nFromIndex < 0 || !aZipURL.match(sBrandURLSuffix, nFromIndex)) { 142cdf0e10cSrcweir osl::File aZip(aZipURL); 143cdf0e10cSrcweir if (aZip.open(OpenFlag_Read) == ::osl::FileBase::E_None) { 144cdf0e10cSrcweir aZip.close(); 145cdf0e10cSrcweir exists = true; 146cdf0e10cSrcweir } 147cdf0e10cSrcweir } 148cdf0e10cSrcweir ++i; 149cdf0e10cSrcweir } 150cdf0e10cSrcweir m_checkStyleCache[style] = exists; 151cdf0e10cSrcweir return exists; 152cdf0e10cSrcweir } 153cdf0e10cSrcweir 154cdf0e10cSrcweir bool ImplImageTree::loadImage( 155cdf0e10cSrcweir rtl::OUString const & name, rtl::OUString const & style, BitmapEx & bitmap, 156cdf0e10cSrcweir bool localized) 157cdf0e10cSrcweir { 158cdf0e10cSrcweir setStyle(style); 159cdf0e10cSrcweir if (iconCacheLookup(name, localized, bitmap)) { 160cdf0e10cSrcweir return true; 161cdf0e10cSrcweir } 162cdf0e10cSrcweir if (!bitmap.IsEmpty()) { 163cdf0e10cSrcweir bitmap.SetEmpty(); 164cdf0e10cSrcweir } 165cdf0e10cSrcweir std::vector< rtl::OUString > paths; 166cdf0e10cSrcweir paths.push_back(name); 167cdf0e10cSrcweir if (localized) { 168cdf0e10cSrcweir sal_Int32 pos = name.lastIndexOf('/'); 169cdf0e10cSrcweir if (pos != -1) { 170cdf0e10cSrcweir css::lang::Locale const & loc = 171cdf0e10cSrcweir Application::GetSettings().GetUILocale(); 172cdf0e10cSrcweir paths.push_back(createPath(name, pos, loc.Language)); 173cdf0e10cSrcweir if (loc.Country.getLength() != 0) { 174cdf0e10cSrcweir rtl::OUStringBuffer b(loc.Language); 175cdf0e10cSrcweir b.append(sal_Unicode('-')); 176cdf0e10cSrcweir b.append(loc.Country); 177cdf0e10cSrcweir rtl::OUString p(createPath(name, pos, b.makeStringAndClear())); 178cdf0e10cSrcweir paths.push_back(p); 179cdf0e10cSrcweir if (loc.Variant.getLength() != 0) { 180cdf0e10cSrcweir b.append(p); 181cdf0e10cSrcweir b.append(sal_Unicode('-')); 182cdf0e10cSrcweir b.append(loc.Variant); 183cdf0e10cSrcweir paths.push_back( 184cdf0e10cSrcweir createPath(name, pos, b.makeStringAndClear())); 185cdf0e10cSrcweir } 186cdf0e10cSrcweir } 187cdf0e10cSrcweir } 188cdf0e10cSrcweir } 189cdf0e10cSrcweir bool found = false; 190cdf0e10cSrcweir try { 191cdf0e10cSrcweir found = find(paths, bitmap); 192cdf0e10cSrcweir } catch (css::uno::RuntimeException &) { 193cdf0e10cSrcweir throw; 194cdf0e10cSrcweir } catch (css::uno::Exception & e) { 195cdf0e10cSrcweir OSL_TRACE( 196cdf0e10cSrcweir "ImplImageTree::loadImage exception \"%s\"", 197cdf0e10cSrcweir rtl::OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8).getStr()); 198cdf0e10cSrcweir } 199cdf0e10cSrcweir if (found) { 200cdf0e10cSrcweir m_iconCache[name.intern()] = std::make_pair(localized, bitmap); 201cdf0e10cSrcweir } 202cdf0e10cSrcweir return found; 203cdf0e10cSrcweir } 204cdf0e10cSrcweir 205cdf0e10cSrcweir void ImplImageTree::shutDown() { 206cdf0e10cSrcweir m_style = rtl::OUString(); 207cdf0e10cSrcweir // for safety; empty m_style means "not initialized" 208cdf0e10cSrcweir m_zips.clear(); 209cdf0e10cSrcweir m_iconCache.clear(); 210cdf0e10cSrcweir m_checkStyleCache.clear(); 211cdf0e10cSrcweir } 212cdf0e10cSrcweir 213cdf0e10cSrcweir void ImplImageTree::setStyle(rtl::OUString const & style) { 214cdf0e10cSrcweir OSL_ASSERT(style.getLength() != 0); // empty m_style means "not initialized" 215cdf0e10cSrcweir if (style != m_style) { 216cdf0e10cSrcweir m_style = style; 217cdf0e10cSrcweir resetZips(); 218cdf0e10cSrcweir m_iconCache.clear(); 219cdf0e10cSrcweir } 220cdf0e10cSrcweir } 221cdf0e10cSrcweir 222cdf0e10cSrcweir void ImplImageTree::resetZips() { 223cdf0e10cSrcweir m_zips.clear(); 224cdf0e10cSrcweir { 225cdf0e10cSrcweir rtl::OUString url( 226cdf0e10cSrcweir RTL_CONSTASCII_USTRINGPARAM("$BRAND_BASE_DIR/program/edition/images.zip")); 227cdf0e10cSrcweir rtl::Bootstrap::expandMacros(url); 228cdf0e10cSrcweir INetURLObject u(url); 229cdf0e10cSrcweir OSL_ASSERT(!u.HasError()); 230cdf0e10cSrcweir m_zips.push_back( 231cdf0e10cSrcweir std::make_pair( 232cdf0e10cSrcweir u.GetMainURL(INetURLObject::NO_DECODE), 233cdf0e10cSrcweir css::uno::Reference< css::container::XNameAccess >())); 234cdf0e10cSrcweir } 235cdf0e10cSrcweir { 236cdf0e10cSrcweir rtl::OUString url( 237cdf0e10cSrcweir RTL_CONSTASCII_USTRINGPARAM("$BRAND_BASE_DIR/share/config")); 238cdf0e10cSrcweir rtl::Bootstrap::expandMacros(url); 239cdf0e10cSrcweir INetURLObject u(url); 240cdf0e10cSrcweir OSL_ASSERT(!u.HasError()); 241cdf0e10cSrcweir rtl::OUStringBuffer b; 242cdf0e10cSrcweir b.appendAscii(RTL_CONSTASCII_STRINGPARAM("images_")); 243cdf0e10cSrcweir b.append(m_style); 244cdf0e10cSrcweir b.appendAscii(RTL_CONSTASCII_STRINGPARAM("_brand.zip")); 245cdf0e10cSrcweir bool ok = u.Append(b.makeStringAndClear(), INetURLObject::ENCODE_ALL); 246cdf0e10cSrcweir OSL_ASSERT(ok); (void) ok; 247cdf0e10cSrcweir m_zips.push_back( 248cdf0e10cSrcweir std::make_pair( 249cdf0e10cSrcweir u.GetMainURL(INetURLObject::NO_DECODE), 250cdf0e10cSrcweir css::uno::Reference< css::container::XNameAccess >())); 251cdf0e10cSrcweir } 252cdf0e10cSrcweir { 253cdf0e10cSrcweir rtl::OUString url( 254cdf0e10cSrcweir RTL_CONSTASCII_USTRINGPARAM( 255cdf0e10cSrcweir "$BRAND_BASE_DIR/share/config/images_brand.zip")); 256cdf0e10cSrcweir rtl::Bootstrap::expandMacros(url); 257cdf0e10cSrcweir m_zips.push_back( 258cdf0e10cSrcweir std::make_pair( 259cdf0e10cSrcweir url, css::uno::Reference< css::container::XNameAccess >())); 260cdf0e10cSrcweir } 261cdf0e10cSrcweir { 262cdf0e10cSrcweir rtl::OUString url( 263cdf0e10cSrcweir RTL_CONSTASCII_USTRINGPARAM("$OOO_BASE_DIR/share/config")); 264cdf0e10cSrcweir rtl::Bootstrap::expandMacros(url); 265cdf0e10cSrcweir INetURLObject u(url); 266cdf0e10cSrcweir OSL_ASSERT(!u.HasError()); 267cdf0e10cSrcweir rtl::OUStringBuffer b; 268cdf0e10cSrcweir b.appendAscii(RTL_CONSTASCII_STRINGPARAM("images_")); 269cdf0e10cSrcweir b.append(m_style); 270cdf0e10cSrcweir b.appendAscii(RTL_CONSTASCII_STRINGPARAM(".zip")); 271cdf0e10cSrcweir bool ok = u.Append(b.makeStringAndClear(), INetURLObject::ENCODE_ALL); 272cdf0e10cSrcweir OSL_ASSERT(ok); (void) ok; 273cdf0e10cSrcweir m_zips.push_back( 274cdf0e10cSrcweir std::make_pair( 275cdf0e10cSrcweir u.GetMainURL(INetURLObject::NO_DECODE), 276cdf0e10cSrcweir css::uno::Reference< css::container::XNameAccess >())); 277cdf0e10cSrcweir } 278cdf0e10cSrcweir if ( m_style.equals(::rtl::OUString::createFromAscii("default")) ) 279cdf0e10cSrcweir { 280cdf0e10cSrcweir rtl::OUString url( 281cdf0e10cSrcweir RTL_CONSTASCII_USTRINGPARAM( 282cdf0e10cSrcweir "$OOO_BASE_DIR/share/config/images.zip")); 283cdf0e10cSrcweir rtl::Bootstrap::expandMacros(url); 284cdf0e10cSrcweir m_zips.push_back( 285cdf0e10cSrcweir std::make_pair( 286cdf0e10cSrcweir url, css::uno::Reference< css::container::XNameAccess >())); 287cdf0e10cSrcweir } 288cdf0e10cSrcweir } 289cdf0e10cSrcweir 290cdf0e10cSrcweir bool ImplImageTree::checkStyleCacheLookup( 291cdf0e10cSrcweir rtl::OUString const & style, bool &exists) 292cdf0e10cSrcweir { 293cdf0e10cSrcweir CheckStyleCache::iterator i(m_checkStyleCache.find(style)); 294cdf0e10cSrcweir if (i != m_checkStyleCache.end()) { 295cdf0e10cSrcweir exists = i->second; 296cdf0e10cSrcweir return true; 297cdf0e10cSrcweir } else { 298cdf0e10cSrcweir return false; 299cdf0e10cSrcweir } 300cdf0e10cSrcweir } 301cdf0e10cSrcweir 302cdf0e10cSrcweir bool ImplImageTree::iconCacheLookup( 303cdf0e10cSrcweir rtl::OUString const & name, bool localized, BitmapEx & bitmap) 304cdf0e10cSrcweir { 305cdf0e10cSrcweir IconCache::iterator i(m_iconCache.find(name)); 306cdf0e10cSrcweir if (i != m_iconCache.end() && i->second.first == localized) { 307cdf0e10cSrcweir bitmap = i->second.second; 308cdf0e10cSrcweir return true; 309cdf0e10cSrcweir } else { 310cdf0e10cSrcweir return false; 311cdf0e10cSrcweir } 312cdf0e10cSrcweir } 313cdf0e10cSrcweir 314cdf0e10cSrcweir bool ImplImageTree::find( 315cdf0e10cSrcweir std::vector< rtl::OUString > const & paths, BitmapEx & bitmap) 316cdf0e10cSrcweir { 317cdf0e10cSrcweir for (Zips::iterator i(m_zips.begin()); i != m_zips.end();) { 318cdf0e10cSrcweir if (!i->second.is()) { 319cdf0e10cSrcweir css::uno::Sequence< css::uno::Any > args(1); 320cdf0e10cSrcweir args[0] <<= i->first; 321cdf0e10cSrcweir try { 322cdf0e10cSrcweir i->second.set( 323cdf0e10cSrcweir comphelper::createProcessComponentWithArguments( 324cdf0e10cSrcweir rtl::OUString( 325cdf0e10cSrcweir RTL_CONSTASCII_USTRINGPARAM( 326cdf0e10cSrcweir "com.sun.star.packages.zip.ZipFileAccess")), 327cdf0e10cSrcweir args), 328cdf0e10cSrcweir css::uno::UNO_QUERY_THROW); 329cdf0e10cSrcweir } catch (css::uno::RuntimeException &) { 330cdf0e10cSrcweir throw; 331cdf0e10cSrcweir } catch (css::uno::Exception & e) { 332cdf0e10cSrcweir OSL_TRACE( 333*f8a117d3SHerbert Dürr "ImplImageTree::find exception \"%s\" for \"%s\"", 334*f8a117d3SHerbert Dürr rtl::OUStringToOString( e.Message, RTL_TEXTENCODING_UTF8).getStr(), 335*f8a117d3SHerbert Dürr rtl::OUStringToOString( i->first, RTL_TEXTENCODING_UTF8).getStr()); 336cdf0e10cSrcweir i = m_zips.erase(i); 337cdf0e10cSrcweir continue; 338cdf0e10cSrcweir } 339cdf0e10cSrcweir } 340cdf0e10cSrcweir for (std::vector< rtl::OUString >::const_reverse_iterator j( 341cdf0e10cSrcweir paths.rbegin()); 342cdf0e10cSrcweir j != paths.rend(); ++j) 343cdf0e10cSrcweir { 344cdf0e10cSrcweir if (i->second->hasByName(*j)) { 345cdf0e10cSrcweir css::uno::Reference< css::io::XInputStream > s; 346cdf0e10cSrcweir bool ok = i->second->getByName(*j) >>= s; 347cdf0e10cSrcweir OSL_ASSERT(ok); (void) ok; 348cdf0e10cSrcweir loadFromStream(s, *j, bitmap); 349cdf0e10cSrcweir return true; 350cdf0e10cSrcweir } 351cdf0e10cSrcweir } 352cdf0e10cSrcweir ++i; 353cdf0e10cSrcweir } 354cdf0e10cSrcweir return false; 355cdf0e10cSrcweir } 356