summaryrefslogtreecommitdiff
path: root/vcl/source/image/ImplImageTree.cxx
diff options
context:
space:
mode:
authorTomaž Vajngerl <tomaz.vajngerl@collabora.com>2015-11-19 12:57:52 +0100
committerTomaž Vajngerl <tomaz.vajngerl@collabora.com>2015-11-19 13:02:54 +0100
commit25d60232ff5d882017ffb88453f16fd6cef5534c (patch)
treeb62faddecbe82d0c75a51335c6518e3cdb20f558 /vcl/source/image/ImplImageTree.cxx
parent6480b4d11a0cf2dd489d30b6290aa6d831704a45 (diff)
vcl: move and split up "Image" related sources to "image" folder
This commit moves all sources related to Image class into its own "vcl/source/image" folder. Sources containing more classes were split up into its own source file. Change-Id: Ie6edcdb0a7caf936bccdc210c31f78bb15667945
Diffstat (limited to 'vcl/source/image/ImplImageTree.cxx')
-rw-r--r--vcl/source/image/ImplImageTree.cxx439
1 files changed, 439 insertions, 0 deletions
diff --git a/vcl/source/image/ImplImageTree.cxx b/vcl/source/image/ImplImageTree.cxx
new file mode 100644
index 000000000000..6726673c867d
--- /dev/null
+++ b/vcl/source/image/ImplImageTree.cxx
@@ -0,0 +1,439 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_folders.h>
+
+#include "sal/config.h"
+
+#include "com/sun/star/container/XNameAccess.hpp"
+#include "com/sun/star/io/XInputStream.hpp"
+#include "com/sun/star/lang/Locale.hpp"
+#include "com/sun/star/lang/XMultiServiceFactory.hpp"
+#include "com/sun/star/packages/zip/ZipFileAccess.hpp"
+#include "com/sun/star/uno/Any.hxx"
+#include "com/sun/star/uno/Exception.hpp"
+#include "com/sun/star/uno/RuntimeException.hpp"
+#include "com/sun/star/uno/Sequence.hxx"
+#include "comphelper/processfactory.hxx"
+#include "osl/file.hxx"
+#include "osl/diagnose.h"
+#include "rtl/bootstrap.hxx"
+#include "rtl/uri.hxx"
+
+#include "tools/stream.hxx"
+#include "tools/urlobj.hxx"
+#include "vcl/bitmapex.hxx"
+#include <vcl/dibtools.hxx>
+#include <vcl/implimagetree.hxx>
+#include "vcl/pngread.hxx"
+#include "vcl/settings.hxx"
+#include "vcl/svapp.hxx"
+#include <vcldemo-debug.hxx>
+
+#include <vcl/BitmapProcessor.hxx>
+#include <vcl/BitmapTools.hxx>
+
+using namespace css;
+
+namespace {
+
+static OUString createPath(OUString const & name, sal_Int32 pos, OUString const & locale)
+{
+ return name.copy(0, pos + 1) + locale + name.copy(pos);
+}
+
+static std::shared_ptr<SvStream> wrapStream(css::uno::Reference< css::io::XInputStream > const & stream)
+{
+ // This could use SvInputStream instead if that did not have a broken
+ // SeekPos implementation for an XInputStream that is not also XSeekable
+ // (cf. "@@@" at tags/DEV300_m37/svtools/source/misc1/strmadpt.cxx@264807
+ // l. 593):
+ OSL_ASSERT(stream.is());
+ std::shared_ptr<SvStream> s(std::make_shared<SvMemoryStream>());
+ for (;;)
+ {
+ sal_Int32 const size = 2048;
+ css::uno::Sequence< sal_Int8 > data(size);
+ sal_Int32 n = stream->readBytes(data, size);
+ s->Write(data.getConstArray(), n);
+ if (n < size)
+ break;
+ }
+ s->Seek(0);
+ return s;
+}
+
+static void loadImageFromStream(std::shared_ptr<SvStream> xStream, OUString const & rPath, BitmapEx & rBitmap)
+{
+ if (rPath.endsWith(".png"))
+ {
+ vcl::PNGReader aPNGReader(*xStream);
+ aPNGReader.SetIgnoreGammaChunk( true );
+ rBitmap = aPNGReader.Read();
+ }
+ else if (rPath.endsWith(".svg"))
+ {
+ vcl::BitmapTools::loadFromSvg(*xStream.get(), rPath, rBitmap);
+ }
+ else
+ {
+ ReadDIBBitmapEx(rBitmap, *xStream);
+ }
+}
+
+}
+
+ImplImageTree & ImplImageTree::get() {
+ static ImplImageTree s_ImplImageTree;
+ return s_ImplImageTree;
+}
+
+ImplImageTree::ImplImageTree()
+{
+}
+
+ImplImageTree::~ImplImageTree()
+{
+}
+
+OUString ImplImageTree::getImageUrl(
+ OUString const & name, OUString const & style, OUString const & lang)
+{
+ OUString aStyle(style);
+ while (!aStyle.isEmpty())
+ {
+ try {
+ setStyle(aStyle);
+
+ std::vector< OUString > paths;
+ paths.push_back(getRealImageName(name));
+
+ if (!lang.isEmpty())
+ {
+ sal_Int32 pos = name.lastIndexOf('/');
+ if (pos != -1)
+ {
+ std::vector<OUString> aFallbacks(
+ LanguageTag(lang).getFallbackStrings(true));
+ for (std::vector< OUString >::reverse_iterator it( aFallbacks.rbegin());
+ it != aFallbacks.rend(); ++it)
+ {
+ paths.push_back( getRealImageName( createPath(name, pos, *it) ) );
+ }
+ }
+ }
+
+ try {
+ if (checkPathAccess()) {
+ const uno::Reference<container::XNameAccess> &rNameAccess = maIconSet[maCurrentStyle].maNameAccess;
+
+ for (std::vector<OUString>::const_reverse_iterator j(paths.rbegin()); j != paths.rend(); ++j)
+ {
+ if (rNameAccess->hasByName(*j))
+ {
+ return "vnd.sun.star.zip://"
+ + rtl::Uri::encode(
+ maIconSet[maCurrentStyle].maURL + ".zip",
+ rtl_UriCharClassRegName,
+ rtl_UriEncodeIgnoreEscapes,
+ RTL_TEXTENCODING_UTF8)
+ + "/" + *j;
+ // assuming *j contains no problematic chars
+ }
+ }
+ }
+ } catch (css::uno::RuntimeException &) {
+ throw;
+ } catch (const css::uno::Exception & e) {
+ SAL_INFO("vcl", "exception " << e.Message);
+ }
+ }
+ catch (css::uno::RuntimeException &) {}
+
+ aStyle = fallbackStyle(aStyle);
+ }
+ return OUString();
+}
+
+OUString ImplImageTree::fallbackStyle(const OUString &style)
+{
+ if (style == "galaxy")
+ return OUString();
+ else if (style == "industrial")
+ return OUString("galaxy");
+ else if (style == "tango")
+ return OUString("galaxy");
+ else if (style == "breeze")
+ return OUString("galaxy");
+ else if (style == "sifr")
+ return OUString("breeze");
+
+ return OUString("tango");
+}
+
+bool ImplImageTree::loadImage(OUString const & name, OUString const & style, BitmapEx & bitmap,
+ bool localized, bool loadMissing)
+{
+ OUString aStyle(style);
+ while (!aStyle.isEmpty())
+ {
+ try {
+ if (doLoadImage(name, aStyle, bitmap, localized))
+ {
+ static bool bIconsForDarkTheme = !!getenv("VCL_ICONS_FOR_DARK_THEME");
+ if (bIconsForDarkTheme)
+ bitmap = BitmapProcessor::createLightImage(bitmap);
+ return true;
+ }
+ }
+ catch (css::uno::RuntimeException &) {}
+
+ aStyle = fallbackStyle(aStyle);
+ }
+
+ if (!loadMissing)
+ return false;
+
+ SAL_INFO("vcl", "ImplImageTree::loadImage couldn't load \"" << name << "\", fetching default image");
+
+ return loadDefaultImage(style, bitmap);
+}
+
+bool ImplImageTree::loadDefaultImage(OUString const & style, BitmapEx& bitmap)
+{
+ return doLoadImage(
+ "res/grafikde.png",
+ style, bitmap, false);
+}
+
+bool ImplImageTree::doLoadImage(OUString const & name, OUString const & style, BitmapEx & bitmap,
+ bool localized)
+{
+ setStyle(style);
+ if (iconCacheLookup(name, localized, bitmap))
+ return true;
+
+ if (!bitmap.IsEmpty())
+ bitmap.SetEmpty();
+
+ std::vector< OUString > paths;
+ paths.push_back(getRealImageName(name));
+
+ if (localized)
+ {
+ sal_Int32 pos = name.lastIndexOf('/');
+ if (pos != -1)
+ {
+ // findImage() uses a reverse iterator, so push in reverse order.
+ std::vector< OUString > aFallbacks( Application::GetSettings().GetUILanguageTag().getFallbackStrings(true));
+ for (std::vector< OUString >::reverse_iterator it( aFallbacks.rbegin());
+ it != aFallbacks.rend(); ++it)
+ {
+ paths.push_back( getRealImageName( createPath(name, pos, *it) ) );
+ }
+ }
+ }
+
+ bool found = false;
+ try {
+ found = findImage(paths, bitmap);
+ } catch (css::uno::RuntimeException &) {
+ throw;
+ } catch (const css::uno::Exception & e) {
+ SAL_INFO("vcl", "ImplImageTree::doLoadImage exception " << e.Message);
+ }
+
+ if (found)
+ maIconSet[maCurrentStyle].maIconCache[name] = std::make_pair(localized, bitmap);
+
+ return found;
+}
+
+void ImplImageTree::shutDown()
+{
+ maCurrentStyle.clear();
+ for (StyleIconSet::iterator it = maIconSet.begin(); it != maIconSet.end(); ++it)
+ {
+ it->second.maIconCache.clear();
+ it->second.maLinkHash.clear();
+ }
+}
+
+void ImplImageTree::setStyle(OUString const & style)
+{
+ assert(!style.isEmpty());
+ if (style != maCurrentStyle)
+ {
+ maCurrentStyle = style;
+ createStyle();
+ }
+}
+
+void ImplImageTree::createStyle()
+{
+ if (maIconSet.find(maCurrentStyle) != maIconSet.end())
+ return;
+
+ OUString url( "$BRAND_BASE_DIR/" LIBO_SHARE_FOLDER "/config/" );
+ rtl::Bootstrap::expandMacros(url);
+ if (maCurrentStyle != "default")
+ {
+ INetURLObject u(url);
+ OSL_ASSERT(!u.HasError());
+ bool ok = u.Append("images_" + maCurrentStyle, INetURLObject::ENCODE_ALL);
+ OSL_ASSERT(ok); (void) ok;
+ url = u.GetMainURL(INetURLObject::NO_DECODE);
+ }
+ else
+ url += "images";
+
+ maIconSet[maCurrentStyle] = IconSet(url);
+
+ loadImageLinks();
+}
+
+bool ImplImageTree::iconCacheLookup(OUString const & name, bool localized, BitmapEx & bitmap)
+{
+ IconCache &rIconCache = maIconSet[maCurrentStyle].maIconCache;
+
+ IconCache::iterator i(rIconCache.find(getRealImageName(name)));
+ if (i != rIconCache.end() && i->second.first == localized)
+ {
+ bitmap = i->second.second;
+ return true;
+ }
+ return false;
+}
+
+bool ImplImageTree::findImage(std::vector<OUString> const & paths, BitmapEx & bitmap)
+{
+ if (!checkPathAccess())
+ return false;
+
+ const uno::Reference<container::XNameAccess> &rNameAccess = maIconSet[maCurrentStyle].maNameAccess;
+
+ for (std::vector<OUString>::const_reverse_iterator j(paths.rbegin()); j != paths.rend(); ++j)
+ {
+ if (rNameAccess->hasByName(*j))
+ {
+ css::uno::Reference< css::io::XInputStream > s;
+ bool ok = rNameAccess->getByName(*j) >>= s;
+ assert(ok);
+ (void)ok; // prevent unused warning in release build
+
+ loadImageFromStream( wrapStream(s), *j, bitmap );
+ return true;
+ }
+ }
+ return false;
+}
+
+void ImplImageTree::loadImageLinks()
+{
+ const OUString aLinkFilename("links.txt");
+
+ if (!checkPathAccess())
+ return;
+
+ const uno::Reference<container::XNameAccess> &rNameAccess = maIconSet[maCurrentStyle].maNameAccess;
+
+ if (rNameAccess->hasByName(aLinkFilename))
+ {
+ css::uno::Reference< css::io::XInputStream > s;
+ bool ok = rNameAccess->getByName(aLinkFilename) >>= s;
+ assert(ok);
+ (void)ok; // prevent unused warning in release build
+
+ parseLinkFile( wrapStream(s) );
+ return;
+ }
+}
+
+void ImplImageTree::parseLinkFile(std::shared_ptr<SvStream> xStream)
+{
+ OString aLine;
+ OUString aLink, aOriginal;
+ int nLineNo = 0;
+ while (xStream->ReadLine(aLine))
+ {
+ ++nLineNo;
+ if ( aLine.isEmpty() )
+ continue;
+
+ sal_Int32 nIndex = 0;
+ aLink = OStringToOUString( aLine.getToken(0, ' ', nIndex), RTL_TEXTENCODING_UTF8 );
+ aOriginal = OStringToOUString( aLine.getToken(0, ' ', nIndex), RTL_TEXTENCODING_UTF8 );
+
+ // skip comments, or incomplete entries
+ if (aLink.isEmpty() || aLink[0] == '#' || aOriginal.isEmpty())
+ {
+ if (aLink.isEmpty() || aOriginal.isEmpty())
+ SAL_WARN("vcl", "ImplImageTree::parseLinkFile: icon links.txt parse error, incomplete link at line " << nLineNo);
+ continue;
+ }
+
+ maIconSet[maCurrentStyle].maLinkHash[aLink] = aOriginal;
+ }
+}
+
+OUString const & ImplImageTree::getRealImageName(OUString const & name)
+{
+ IconLinkHash &rLinkHash = maIconSet[maCurrentStyle].maLinkHash;
+
+ IconLinkHash::iterator it(rLinkHash.find(name));
+ if (it == rLinkHash.end())
+ return name;
+
+ return it->second;
+}
+
+bool ImplImageTree::checkPathAccess()
+{
+ uno::Reference<container::XNameAccess> &rNameAccess = maIconSet[maCurrentStyle].maNameAccess;
+ if (rNameAccess.is())
+ return true;
+
+ try {
+ rNameAccess = css::packages::zip::ZipFileAccess::createWithURL(comphelper::getProcessComponentContext(), maIconSet[maCurrentStyle].maURL + ".zip");
+ }
+ catch (const css::uno::RuntimeException &) {
+ throw;
+ }
+ catch (const css::uno::Exception & e) {
+ SAL_INFO("vcl", "ImplImageTree::zip file location exception " << e.Message << " for " << maIconSet[maCurrentStyle].maURL);
+ return false;
+ }
+ return rNameAccess.is();
+}
+
+css::uno::Reference<css::container::XNameAccess> ImplImageTree::getNameAccess()
+{
+ checkPathAccess();
+ return maIconSet[maCurrentStyle].maNameAccess;
+}
+
+/// Recursively dump all names ...
+css::uno::Sequence<OUString> ImageTree_getAllImageNames()
+{
+ css::uno::Reference<css::container::XNameAccess> xRef(ImplImageTree::get().getNameAccess());
+
+ return xRef->getElementNames();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */