src/hbservers/hbsplashgenerator/hbsplashgenerator.cpp
changeset 0 16d8024aca5e
child 1 f7ac710697a9
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hbservers/hbsplashgenerator/hbsplashgenerator.cpp	Mon Apr 19 14:02:13 2010 +0300
@@ -0,0 +1,725 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (developer.feedback@nokia.com)
+**
+** This file is part of the HbServers module of the UI Extensions for Mobile.
+**
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at developer.feedback@nokia.com.
+**
+****************************************************************************/
+
+#include "hbsplashgenerator_p.h"
+#include "hbsplashdirs_p.h"
+#include "hbmainwindow.h"
+#include "hbmainwindow_p.h"
+#include "hbinstance.h"
+#include "hbtheme.h"
+#include "hbeffectinternal_p.h"
+#include "hbview.h"
+#include "hbdocumentloader.h"
+#include "hbicon.h"
+#include "hbaction.h"
+#include "hbcolorscheme.h"
+#include "hbstatusbar_p.h"
+#include "hbstyle.h"
+#include "hbbackgrounditem_p.h"
+#include <QCoreApplication>
+#include <QPainter>
+#include <QDir>
+#include <QFile>
+#include <QSet>
+#include <QTranslator>
+#include <QLocale>
+
+const char *last_theme_key = "lasttheme";
+const char *last_lang_key = "lastlang";
+const char *last_file_count_key = "lastfilecount";
+const char *last_output_dir_key = "lastoutdir";
+
+HbSplashGenerator::HbSplashGenerator()
+    : mBusy(false), mMainWindow(0), mFirstRegenerate(true),
+      mSettings("Nokia", "HbSplash")
+{
+    // Effects on decorators (started when they are shown) would ruin
+    // the screenshot. So disable everything (except the orientation
+    // switch effect which is needed for a proper rotated image).
+    HbEffectInternal::setEffectsEnabled(false);
+}
+
+HbSplashGenerator::~HbSplashGenerator()
+{
+    delete mMainWindow;
+    clearTranslators();
+}
+
+static QString orientationName(Qt::Orientation orientation)
+{
+    switch (orientation) {
+    case Qt::Horizontal:
+        return QString("lsc");
+    case Qt::Vertical:
+        return QString("prt");
+    default:
+        return QString();
+    }
+}
+
+#define PRE "[hbsplashgenerator]"
+
+static void log(const QString &msg, const QString &theme = QString(), int orientation = -1)
+{
+    const char *fmt = PRE " %s ('%s' '%s')";
+    QString oriName = orientationName(static_cast<Qt::Orientation>(orientation));
+    qDebug(fmt, qPrintable(msg), qPrintable(theme), qPrintable(oriName));
+}
+
+// To be called on startup and after each fully completed regeneration.
+// Returns the number of files in the output directory.
+int HbSplashGenerator::updateOutputDirContents(const QString &outDir)
+{
+    QDir dir(outDir);
+    QStringList entries = dir.entryList(QDir::Files);
+    emit outputDirContentsUpdated(outDir, entries);
+    return entries.count();
+}
+
+void HbSplashGenerator::start(bool forceRegen)
+{
+    // Start listening to the theme-change-finished signal and
+    // generate screens for the current theme if needed.
+    HbTheme *theme = hbInstance->theme();
+    connect(theme, SIGNAL(changeFinished()), SLOT(regenerate()));
+    // Regenerate screens on startup only when the theme, the language, the
+    // number of files in the splash screen directory, or the splash screen
+    // directory path is different than the recorded values. (or when
+    // regeneration is forced via command line arg)
+    QString lastTheme = mSettings.value(QLatin1String(last_theme_key)).toString();
+    QString lastLang = mSettings.value(QLatin1String(last_lang_key)).toString();
+    int lastFileCount = mSettings.value(QLatin1String(last_file_count_key)).toInt();
+    QString lastOutputDir = mSettings.value(QLatin1String(last_output_dir_key)).toString();
+    QString currentTheme = theme->name();
+    QString currentLang = QLocale::system().name();
+    QString currentOutputDir = hbsplash_output_dir();
+    int currentFileCount = updateOutputDirContents(currentOutputDir);
+    qDebug() << PRE << "last regen:" << lastTheme << lastLang << lastFileCount << lastOutputDir
+             << "current:" << currentTheme << currentLang << currentFileCount << currentOutputDir;
+    if (forceRegen
+        || currentTheme != lastTheme
+        || currentLang != lastLang
+        || currentFileCount != lastFileCount
+        || currentOutputDir != lastOutputDir)
+    {
+        QMetaObject::invokeMethod(this, "regenerate", Qt::QueuedConnection);
+    }
+}
+
+void HbSplashGenerator::regenerate()
+{
+    QString themeName = hbInstance->theme()->name();
+    qDebug() << PRE << "regenerate() theme:" << themeName;
+    if (!themeName.isEmpty()) {
+        try {
+            QTime queuePrepTime;
+            queuePrepTime.start();
+            // Delete existing splash screens. This is important because apps
+            // should never pick up a screen with the previous theme or
+            // language. If the generation of the new screens (at least the
+            // empty view) has not finished when a new app is started then it is
+            // better to show no splash screen at all.
+            QDir outDir(hbsplash_output_dir());
+            if (outDir.exists()) {
+                QStringList names = outDir.entryList(QStringList() << "*", QDir::Files);
+                foreach (const QString &name, names) {
+                    outDir.remove(name);
+                }
+            }
+            // Clear the queue, generating screens with a non-current theme is
+            // not possible anyway.
+            mQueue.clear();
+            // If this is the first invocation then put some requests for
+            // screens we won't use. On certain platforms the very first
+            // rendering (with a newly created mainwindow) may lead to
+            // mysteriously scaled down output.
+            if (mFirstRegenerate) {
+                mFirstRegenerate = false;
+                mQueue.enqueue(QueueItem(themeName, Qt::Vertical));
+                mQueue.enqueue(QueueItem(themeName, Qt::Horizontal));
+            }
+            // Queue the screenshot request for both orientations.
+            mQueue.enqueue(QueueItem(themeName, Qt::Vertical));
+            mQueue.enqueue(QueueItem(themeName, Qt::Horizontal));
+            queueAppSpecificItems(themeName, Qt::Vertical);
+            queueAppSpecificItems(themeName, Qt::Horizontal);
+            qDebug() << PRE << "queue preparation time (ms):" << queuePrepTime.elapsed();
+            QMetaObject::invokeMethod(this, "processQueue", Qt::QueuedConnection);
+        } catch (const std::bad_alloc &) {
+            cleanup();
+        }
+    }
+}
+
+QImage HbSplashGenerator::renderView()
+{
+    log("renderView()", mItem.mThemeName, mItem.mOrientation);
+    // Note: Do not use QPixmap::grabWidget() because our widget has never been
+    // shown (it is not visible). QGraphicsView::render() seems to work better
+    // in this respect. Also, let's use QImage because the stuff is going to a
+    // file and is never drawn anywhere. This makes using graphics system
+    // dependent things (e.g. some special filter effects) impossible but using
+    // those for a splash screen would not be the best idea anyway.
+    QTime t;
+    t.start();
+    // The image format must be the one that fits the OpenVG paint engine best.
+    // (in order to avoid unnecessary conversions later when apps load and show
+    // these images)
+    QImage image(mMainWindow->size(), QImage::Format_ARGB32_Premultiplied);
+    image.fill(QColor(Qt::transparent).rgba());
+    QPainter painter(&image);
+    mMainWindow->render(&painter);
+    qDebug() << PRE << "rendering time (ms):" << t.elapsed();
+    return image;
+}
+
+void HbSplashGenerator::processQueue()
+{
+    qDebug() << PRE << "processQueue()";
+    // If the queue is empty then the splash regeneraton is complete so store
+    // the current theme and language names as the last fully processed ones in
+    // the settings and stop.
+    if (mQueue.isEmpty()) {
+        qDebug() << PRE << "queue is empty  regen finished";
+        mSettings.setValue(last_theme_key, hbInstance->theme()->name());
+        mSettings.setValue(last_lang_key, QLocale::system().name());
+        QString outDir = hbsplash_output_dir();
+        mSettings.setValue(last_file_count_key, updateOutputDirContents(outDir));
+        mSettings.setValue(last_output_dir_key, outDir);
+        qDebug() << PRE << "processQueue() over";
+        return;
+    }
+    // If a previous splash generation is still in progress then do nothing.
+    if (mBusy) {
+        qDebug() << PRE << "still busy  processQueue() over";
+        return;
+    }
+    try {
+        mBusy = true;
+        mItem = mQueue.dequeue();
+        mItemTime.start();
+        log("generating splash screen", mItem.mThemeName, mItem.mOrientation);
+
+        if (!mMainWindow) {
+            // The FixedVertical flag is used just to disable the sensor-based
+            // orientation switching.
+            mMainWindow = new HbMainWindow(0, Hb::WindowFlagFixedVertical);
+        }
+        mMainWindow->setOrientation(mItem.mOrientation, false);
+        qDebug() << PRE << "mainwindow init time (ms):" << mItemTime.elapsed();
+
+        QTime setupTime;
+        setupTime.start();
+        setupAppSpecificWindow();
+        finishWindow();
+        qDebug() << PRE << "content setup time(ms):" << setupTime.elapsed();
+
+        QMetaObject::invokeMethod(this, "processWindow", Qt::QueuedConnection);
+
+    } catch (const std::bad_alloc &) {
+        cleanup();
+    }
+    qDebug() << PRE << "processQueue() over";
+}
+
+void HbSplashGenerator::processWindow()
+{
+    // Take the screenshot, remove content, and move on to the next request in the queue.
+    log("processWindow()  rendering splash screen", mItem.mThemeName, mItem.mOrientation);
+    takeScreenshot();
+    qDebug() << PRE << "total time for screen (ms):" << mItemTime.elapsed();
+
+    QList<HbView *> views = mMainWindow->views();
+    foreach (HbView *view, views) {
+        mMainWindow->removeView(view);
+        delete view;
+    }
+    clearTranslators();
+
+    mBusy = false;
+    QMetaObject::invokeMethod(this, "processQueue", Qt::QueuedConnection);
+    log("processWindow() over", mItem.mThemeName, mItem.mOrientation);
+}
+
+void HbSplashGenerator::takeScreenshot()
+{
+    log("takeScreenshot()", mItem.mThemeName, mItem.mOrientation);
+    try {
+        // Render the content. Note that this may use the wrong theme
+        // graphics if there are quick theme changes on-going. We only
+        // guarantee that there will always be a correct splash screen for
+        // the currently set theme, and that can be fulfilled because even
+        // though the screenshot we make here may be wrong in such a case
+        // there will already be a new request queued due to the theme
+        // change.
+        QImage image = renderView();
+        QTime t;
+        t.start();
+        QString splashFile = splashFileName();
+        qDebug() << PRE << "saving to" << splashFile;
+        if (saveSpl(splashFile, image)) {
+#if !defined(Q_OS_SYMBIAN) && defined(QT_DEBUG)
+            image.save(splashFile + QLatin1String(".png"));
+#endif
+        } else {
+            qWarning() << PRE << "file write failed for" << splashFile;
+        }
+        qDebug() << PRE << "save time (ms):" << t.elapsed();
+        log("takeScreenshot() over", mItem.mThemeName, mItem.mOrientation);
+    } catch (const std::bad_alloc &) {
+        cleanup();
+    }
+}
+
+QString HbSplashGenerator::splashFileName()
+{
+    QString outDirName = hbsplash_output_dir();
+    QDir dir(outDirName);
+    if (!dir.exists()) {
+        if (!QDir(".").mkdir(outDirName)) {
+            qWarning() << PRE << "mkdir failed for" << outDirName;
+        }
+    }
+    QString splashFile = dir.filePath("splash_%1").arg(orientationName(mItem.mOrientation));
+    if (!mItem.mAppId.isEmpty()) {
+        splashFile.append('_');
+        splashFile.append(mItem.mAppId);
+    }
+    return splashFile;
+}
+
+// helper to avoid calling the non-const version of QImage::bits()
+inline const uchar *imageBits(const QImage &image)
+{
+    return image.bits();
+}
+
+bool HbSplashGenerator::saveSpl(const QString &nameWithoutExt, const QImage &image)
+{
+    QString fn(nameWithoutExt);
+    fn.append(".spl");
+    QFile f(fn);
+    if (f.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
+        int w = image.width();
+        int h = image.height();
+        int bpl = image.bytesPerLine();
+        QImage::Format fmt = image.format();
+        f.write((char *) &w, sizeof(int));
+        f.write((char *) &h, sizeof(int));
+        f.write((char *) &bpl, sizeof(int));
+        f.write((char *) &fmt, sizeof(QImage::Format));
+        f.write((const char *) imageBits(image), bpl * h);
+        f.close();
+        return true;
+    }
+    return false;
+}
+
+void HbSplashGenerator::cleanup()
+{
+    mQueue.clear();
+    delete mMainWindow;
+    mMainWindow = 0;
+    clearTranslators();
+    mBusy = false;
+}
+
+QDebug operator<<(QDebug dbg, const HbSplashGenerator::QueueItem& item)
+{
+    dbg << "["
+        << item.mDocmlFileName
+        << item.mAppId
+        << item.mDocmlWidgetName
+        << item.mThemeName
+        << orientationName(item.mOrientation)
+        << item.mTsAppName
+        << "]";
+    return dbg;
+}
+
+HbSplashGenerator::QueueItem::QueueItem()
+    : mOrientation(Qt::Vertical),
+      mHideBackground(false)
+{
+}
+
+HbSplashGenerator::QueueItem::QueueItem(const QString &themeName, Qt::Orientation orientation)
+    : mThemeName(themeName), mOrientation(orientation),
+      mHideBackground(false)
+{
+}
+
+void HbSplashGenerator::addSplashmlItemToQueue(const QueueItem &item)
+{
+    bool fixedPortrait = item.mFixedOrientation == QLatin1String("portrait");
+    bool fixedLandscape = item.mFixedOrientation == QLatin1String("landscape");
+    if (fixedPortrait && item.mOrientation != Qt::Vertical) {
+        return;
+    }
+    if (fixedLandscape && item.mOrientation != Qt::Horizontal) {
+        return;
+    }
+    mQueue.enqueue(item);
+}
+
+void HbSplashGenerator::queueAppSpecificItems(const QString &themeName, Qt::Orientation orientation)
+{
+    QSet<QString> processedFileNames;
+    QStringList dirNames(hbsplash_splashml_dirs());
+    foreach (const QString &dirName, dirNames) {
+        QDir dir(dirName);
+        if (!dir.exists()) {
+            continue;
+        }
+        QStringList entries = dir.entryList(QStringList() << "*.splashml", QDir::Files);
+        foreach (const QString &entry, entries) {
+            // Skip if a file with the same name has already been processed from
+            // a different location.
+            if (processedFileNames.contains(entry)) {
+                qDebug() << PRE << "skipping splashml (already found at other location)" << dir.filePath(entry);
+                continue;
+            }
+            processedFileNames.insert(entry);
+            QString fullName = dir.filePath(entry);
+            qDebug() << PRE << "parsing splashml" << fullName;
+            if (mParsedSplashmls.contains(fullName)) {
+                QueueItem item(mParsedSplashmls.value(fullName));
+                item.mThemeName = themeName;
+                item.mOrientation = orientation;
+                qDebug() << PRE << "splashml already parsed  queuing request" << item;
+                addSplashmlItemToQueue(item);
+                continue;
+            }
+            QueueItem item(themeName, orientation);
+            QFile f(fullName);
+            bool ok = f.open(QIODevice::ReadOnly);
+            if (ok) {
+                QXmlStreamReader xml(&f);
+                bool docOk = false;
+                while (!xml.atEnd()) {
+                    QXmlStreamReader::TokenType token = xml.readNext();
+                    if (token == QXmlStreamReader::Invalid) {
+                        qWarning() << PRE << fullName << xml.errorString();
+                        ok = false;
+                        break;
+                    } else if (token == QXmlStreamReader::StartElement
+                               && xml.name() == QLatin1String("hbsplash"))
+                    {
+                        docOk = true;
+                    } else if (docOk) {
+                        processSplashml(xml, item);
+                    }
+                }
+                f.close();
+            }
+            if (ok
+                && !item.mAppId.isEmpty()
+                && !item.mDocmlWidgetName.isEmpty()
+                && !item.mDocmlFileName.isEmpty())
+            {
+                // Add the full path to the filename. The docml is supposed to
+                // be in the same directory as the splashml.
+                item.mDocmlFileName = dir.filePath(item.mDocmlFileName);
+                qDebug() << PRE << "queuing request" << item;
+                addSplashmlItemToQueue(item);
+                mParsedSplashmls.insert(fullName, item);
+            } else {
+                qWarning() << PRE << "Unable to parse" << fullName;
+            }
+        }
+    }
+}
+
+inline bool readBool(QXmlStreamReader &xml)
+{
+    QString text = xml.readElementText().trimmed();
+    return text == QLatin1String("true") || text == QLatin1String("1");
+}
+
+void HbSplashGenerator::processSplashml(QXmlStreamReader &xml, QueueItem &item)
+{
+    if (xml.isStartElement()) {
+        QStringRef name = xml.name();
+        if (name == QLatin1String("docml")) {
+            item.mDocmlFileName = xml.readElementText().trimmed();
+        } else if (name == QLatin1String("widget")) {
+            item.mDocmlWidgetName = xml.readElementText().trimmed();
+        } else if (name == QLatin1String("appid") || name == QLatin1String("appuid")) {
+            item.mAppId = xml.readElementText().trimmed();
+            if (item.mAppId.startsWith("0x")) {
+                item.mAppId.remove(0, 2);
+            }
+        } else if (name == QLatin1String("tsappname")) {
+            item.mTsAppName = xml.readElementText().trimmed();
+        } else if (name == QLatin1String("view-flags")) {
+            item.mViewFlags = xml.readElementText().split(",", QString::SkipEmptyParts);
+            for (int i = 0, ie = item.mViewFlags.count(); i != ie; ++i) {
+                item.mViewFlags[i] = item.mViewFlags[i].trimmed().toLower();
+            }
+        } else if (name == QLatin1String("background-item-visible")) {
+            item.mHideBackground = !readBool(xml);
+        } else if (name == QLatin1String("navi-action-icon")) {
+            item.mNaviActionIcon = xml.readElementText().trimmed();
+        } else if (name == QLatin1String("background-brush-color")) {
+            item.mBackgroundBrushColor = QColor(xml.readElementText().trimmed());
+        } else if (name == QLatin1String("themed-background-brush-color")) {
+            item.mThemedBackgroundBrushColor = xml.readElementText().trimmed();
+        } else if (name == QLatin1String("background-image-name")) {
+            QString whenToUse = xml.attributes().value("when").toString().trimmed();
+            QString imageName = xml.readElementText().trimmed();
+            if (whenToUse.isEmpty()) {
+                whenToUse = QLatin1String("always");
+            }
+            item.mBackgroundImageName.insert(whenToUse, imageName);
+        } else if (name == QLatin1String("use-section")) {
+            QString whenToUse = xml.attributes().value("when").toString().trimmed();
+            QString whichSection = xml.readElementText().trimmed();
+            if (!whenToUse.isEmpty()) {
+                item.mCondSections.insert(whenToUse, whichSection);
+            } else {
+                item.mForcedSections.append(whichSection);
+            }
+        } else if (name == QLatin1String("custom-widget-substitute")) {
+            QString originalType = xml.attributes().value("for").toString().trimmed();
+            QString substitutedType = xml.readElementText().trimmed();
+            item.mCustomWidgetSubsts.insert(originalType, substitutedType);
+        } else if (name == QLatin1String("fixed-orientation")) {
+            item.mFixedOrientation = xml.readElementText().trimmed().toLower();
+        } else {
+            qWarning() << PRE << "unknown element" << name;
+        }
+    }
+}
+
+class CustomDocumentLoader : public HbDocumentLoader
+{
+public:
+    CustomDocumentLoader(const HbMainWindow *window, const HbSplashGenerator::QueueItem &item)
+        : HbDocumentLoader(window), mItem(item) { }
+    QObject *createObject(const QString &type, const QString &name);
+private:
+    const HbSplashGenerator::QueueItem &mItem;
+};
+
+QObject *CustomDocumentLoader::createObject(const QString &type, const QString &name)
+{
+    QObject *obj = HbDocumentLoader::createObject(type, name);
+    if (!obj) {
+        qDebug() << PRE << "unsupported object" << type << name;
+        // Cannot let parsing fail because of unknown custom widgets
+        // so provide an empty HbWidget (or HbView if the splashml
+        // prefers that).
+        if (mItem.mCustomWidgetSubsts.contains(type)) {
+            QString preferredType = mItem.mCustomWidgetSubsts.value(type);
+            if (preferredType == QLatin1String("HbView")) {
+                obj = new HbView;
+            } else {
+                qWarning() << PRE << "unsupported custom widget substitute type"
+                           << type << "falling back to HbWidget";
+            }
+        }
+        if (!obj) {
+            obj = new HbWidget;
+        }
+        if (obj) {
+            obj->setObjectName(name);
+        }
+    }
+    return obj;
+}
+
+void HbSplashGenerator::setupAppSpecificWindow()
+{
+    // Check if the splash screen request is really application-specific.
+    if (mItem.mDocmlFileName.isEmpty() || mItem.mAppId.isEmpty() || mItem.mDocmlWidgetName.isEmpty()) {
+        return;
+    }
+
+    // Install translators if needed.
+    addTranslator(QLatin1String("common"));
+    if (!mItem.mTsAppName.isEmpty()) {
+        addTranslator(mItem.mTsAppName);
+    }
+
+    // Parse the docml file and add the specified widget as a view.
+    CustomDocumentLoader loader(mMainWindow, mItem);
+    QStringList sections;
+    if (!mItem.mCondSections.isEmpty()) {
+        if (mItem.mCondSections.contains("portrait") && mItem.mOrientation == Qt::Vertical) {
+            sections << mItem.mCondSections.value("portrait");
+        } else if (mItem.mCondSections.contains("landscape") && mItem.mOrientation == Qt::Horizontal) {
+            sections << mItem.mCondSections.value("landscape");
+        }
+    }
+    sections << mItem.mForcedSections;
+    qDebug() << PRE << "loading" << mItem.mDocmlFileName << "common section";
+    bool ok;
+    loader.load(mItem.mDocmlFileName, &ok);
+    if (ok && !sections.isEmpty()) {
+        foreach (const QString &section, sections) {
+            qDebug() << PRE << "loading" << mItem.mDocmlFileName << "section" << section;
+            loader.load(mItem.mDocmlFileName, section, &ok);
+        }
+    }
+    if (ok) {
+        QGraphicsWidget *widget = loader.findWidget(mItem.mDocmlWidgetName);
+        if (widget) {
+            qDebug() << PRE << "widget created from" << mItem;
+            mMainWindow->addView(widget);
+        } else {
+            qWarning() << PRE << "widget creation failed from" << mItem;
+        }
+    } else {
+        qWarning() << PRE << "Unable to parse" << mItem.mDocmlFileName;
+    }
+}
+
+void HbSplashGenerator::finishWindow()
+{
+    // Process additional settings.
+    if (mMainWindow->views().isEmpty()) {
+        // There must be a view always in order to support view-specific settings.
+        mMainWindow->addView(new HbWidget);
+    }
+
+    QList<HbView *> views = mMainWindow->views();
+    if (!views.isEmpty()) {
+        HbView *view = views.at(0);
+
+        // view-flags
+        HbView::HbViewFlags viewFlags = HbView::ViewFlagNone;
+        if (mItem.mViewFlags.contains("tb-minimizable")) {
+            viewFlags |= HbView::ViewTitleBarMinimizable;
+        }
+        if (mItem.mViewFlags.contains("tb-minimized")) {
+            viewFlags |= HbView::ViewTitleBarMinimized;
+        }
+        if (mItem.mViewFlags.contains("tb-hidden")) {
+            viewFlags |= HbView::ViewTitleBarHidden;
+        }
+        if (mItem.mViewFlags.contains("tb-transparent")) {
+            viewFlags |= HbView::ViewTitleBarTransparent;
+        }
+        if (mItem.mViewFlags.contains("tb-floating")) {
+            viewFlags |= HbView::ViewTitleBarFloating;
+        }
+        if (mItem.mViewFlags.contains("sb-hidden")) {
+            viewFlags |= HbView::ViewStatusBarHidden;
+        }
+        if (mItem.mViewFlags.contains("sb-transparent")) {
+            viewFlags |= HbView::ViewStatusBarTransparent;
+        }
+        if (mItem.mViewFlags.contains("sb-floating")) {
+            viewFlags |= HbView::ViewStatusBarFloating;
+        }
+        view->setViewFlags(viewFlags);
+
+        // navi-action-icon
+        if (!mItem.mNaviActionIcon.isEmpty()) {
+            view->setNavigationAction(new HbAction(HbIcon(mItem.mNaviActionIcon), QString(), view));
+        } // else will use the default navigation action (e.g. quit)
+    }
+
+    HbMainWindowPrivate *mwd = HbMainWindowPrivate::d_ptr(mMainWindow);
+    // background-item-visible, background-brush-color, themed-background-brush-color
+    if (mItem.mHideBackground) {
+        mwd->removeBackgroundItem();
+        QColor fillColor = mItem.mBackgroundBrushColor;
+        if (!mItem.mThemedBackgroundBrushColor.isEmpty()) {
+            QColor color = HbColorScheme::color(mItem.mThemedBackgroundBrushColor);
+            if (color.isValid()) {
+                fillColor = color;
+            }
+        }
+        mMainWindow->scene()->setBackgroundBrush(fillColor.isValid() ? fillColor : Qt::black);
+    } else {
+        mwd->addBackgroundItem();
+        mMainWindow->scene()->setBackgroundBrush(Qt::NoBrush);
+        // background-image-name
+        HbBackgroundItem *bgItem = mwd->mBgItem;
+        if (bgItem) {
+            QString backgroundImageName = mItem.mBackgroundImageName.value(
+                mItem.mOrientation == Qt::Vertical ? "portrait" : "landscape");
+            if (backgroundImageName.isEmpty()) {
+                backgroundImageName = mItem.mBackgroundImageName.value("always");
+                if (backgroundImageName.isEmpty()) {
+                    backgroundImageName = bgItem->defaultImageName(mItem.mOrientation);
+                }
+            }
+            mMainWindow->setBackgroundImageName(mItem.mOrientation, backgroundImageName);
+        }
+    }
+
+    // Hide dynamic content from status bar (clock, indicators).
+    HbStatusBar *statusBar = mwd->mStatusBar;
+    if (statusBar) {
+        foreach (QGraphicsItem *item, statusBar->childItems()) {
+            QString name = HbStyle::itemName(item);
+            bool hideItem = name == QLatin1String("signal")
+                || name == QLatin1String("battery")
+                || name == QLatin1String("notificationindicators")
+                || name == QLatin1String("settingsindicators")
+                || name == QLatin1String("timetext");
+            if (hideItem) {
+                item->setVisible(false);
+            }
+        }
+    }
+}
+
+void HbSplashGenerator::addTranslator(const QString &name)
+{
+    QString lang = QLocale::system().name();
+    QTranslator *translator = new QTranslator;
+    bool ok = false;
+    QStringList dirNames(hbsplash_translation_dirs());
+    foreach (const QString &dirName, dirNames) {
+        QDir dir(dirName);
+        QString fullName = dir.filePath(name + '_' + lang);
+        // fullName is not necessarily an existing file, however the translator
+        // may still pick up another suitable file based on this name.
+        if (translator->load(fullName)) {
+            QCoreApplication::installTranslator(translator);
+            qDebug() << PRE << "Translator installed:" << fullName;
+            ok = true;
+            break;
+        }
+    }
+    if (ok) {
+        mTranslators.append(translator);
+    } else {
+        qWarning() << PRE << "Unable to find translations based on name" << name;
+        delete translator;
+    }
+}
+
+void HbSplashGenerator::clearTranslators()
+{
+    foreach (QTranslator *translator, mTranslators) {
+        QCoreApplication::removeTranslator(translator);
+    }
+    qDeleteAll(mTranslators);
+    mTranslators.clear();
+}