src/hbcore/theme/hbthemeutils_p.cpp
changeset 7 923ff622b8b9
parent 6 c3690ec91ef8
child 21 4633027730f5
child 34 ed14f46c0e55
--- a/src/hbcore/theme/hbthemeutils_p.cpp	Wed Jun 23 18:33:25 2010 +0300
+++ b/src/hbcore/theme/hbthemeutils_p.cpp	Tue Jul 06 14:36:53 2010 +0300
@@ -23,6 +23,19 @@
 **
 ****************************************************************************/
 
+#include "hbthemeutils_p.h"
+#include "hbtheme.h"
+#include "hbiniparser_p.h"
+#include "hbthemecommon_p.h"
+#include "hbthemeclient_p.h"
+#include "hbtheme_p.h"
+
+#ifdef Q_OS_SYMBIAN
+#include "hbthemecommon_symbian_p.h"
+#include <e32std.h>
+#include <centralrepository.h>
+#endif
+
 #include <QLocale>
 #include <QSettings>
 #include <QFile>
@@ -31,19 +44,6 @@
 #include <QMap>
 #include <QVariant>
 
-#ifdef Q_OS_SYMBIAN
-#include "hbthemecommon_symbian_p.h"
-#include <e32std.h>
-#include <centralrepository.h>
-#endif
-
-#include "hbthemeutils_p.h"
-#include "hbtheme.h"
-#include "hbiniparser_p.h"
-#include "hbthemecommon_p.h"
-#include "hbthemeclient_p.h"
-
-
 // Standard folder names
 const char *HbThemeUtils::themeResourceFolder = "theme";
 const char *HbThemeUtils::platformHierarchy = "themes";
@@ -61,7 +61,25 @@
 
 // These are the used setting names corresponding to HbThemeUtils::Setting enumeration.
 static const QString settingNames[6] = {"", "basetheme", "defaulttheme",
-                                        "defaultthemedir", "currenttheme", "operatorbasepath"};
+                                        "", "currenttheme", "operatorbasepath"};
+
+static HbHeapIndexInfo *heapIndex = 0;
+
+QString themesDir()
+{
+#ifdef Q_OS_SYMBIAN
+    static QString mainThemesDir("z:/resource/hb");
+#else
+    static QString mainThemesDir = QDir::fromNativeSeparators(qgetenv("HB_THEMES_DIR"));
+    // Do not call absolutePath if the path is empty,
+    // because it would return current path in that case.
+    if (!mainThemesDir.isEmpty()) {
+        mainThemesDir = QDir(mainThemesDir).absolutePath();
+    }
+#endif
+    return mainThemesDir;
+}
+
 
 /*!
     @proto
@@ -76,40 +94,46 @@
 */
 
 
-class HbThemeUtilsPrivate
+class HbThemeSettings
 {
 public:
-    HbThemeUtilsPrivate() : settingsRetrieved(false), mHeapThemeOffset(0)
+    HbThemeSettings() : settingsRetrieved(false)
     {
     }
 
-    ~HbThemeUtilsPrivate();
+    ~HbThemeSettings();
 
     void readSettings();
-    int heapThemeOffset(const HbThemeIndexInfo &info);
+    void initSettings();
+    QString getThemeFromFile(const QString &variable, const QString &rootDir);
 
 public: // data
     bool settingsRetrieved;
     // Setting values are stored here to avoid overhead of reading from QSettings every time.
     QString currentTheme;
     QString defaultTheme;
-    QString defaultThemeRootDir;
     QString baseTheme;
     QString operatorName;
-
-private:
-    int mHeapThemeOffset;
 };
 
-HbThemeUtilsPrivate::~HbThemeUtilsPrivate()
+HbThemeSettings::~HbThemeSettings()
 {
-    if (mHeapThemeOffset > 0) {
-        GET_MEMORY_MANAGER(HbMemoryManager::HeapMemory);
-        manager->free(mHeapThemeOffset);
+    if (heapIndex) {
+        // Free allocated memory
+        if (heapIndex->baseTheme.address) {
+            delete heapIndex->baseTheme.address;
+        }
+        if (heapIndex->priorityTheme.address) {
+            delete heapIndex->priorityTheme.address;
+        }
+        if (heapIndex->activeTheme.address) {
+            delete heapIndex->activeTheme.address;
+        }
+        delete heapIndex;
     }
 }
 
-void HbThemeUtilsPrivate::readSettings()
+void HbThemeSettings::readSettings()
 {
     // The only changing setting is currentThemeSetting and its value is updated in server side in theme change event.
 
@@ -129,14 +153,6 @@
                 defaultTheme = qvalue.trimmed();
             }
             value.Zero();
-            if (KErrNone == repository->Get(HbThemeUtils::DefaultThemeRootDirSetting, value)) {
-                QString qvalue((QChar*)value.Ptr(), value.Length());
-                defaultThemeRootDir = qvalue.trimmed();
-            } else {
-                // Use the default value
-                defaultThemeRootDir = HbThemeUtils::themesDir();           
-            }
-            value.Zero();
             if (KErrNone == repository->Get(HbThemeUtils::BaseThemeSetting, value)) {
                 QString qvalue((QChar*)value.Ptr(), value.Length());
                 baseTheme = qvalue.trimmed();
@@ -149,106 +165,106 @@
             delete repository;
         }
 #else
-        QSettings settings(QLatin1String(ORGANIZATION), QLatin1String(THEME_COMPONENT));
+        QSettings settings(QSettings::IniFormat, QSettings::UserScope, QLatin1String(ORGANIZATION), QLatin1String(THEME_COMPONENT));
 
         currentTheme = settings.value(settingNames[HbThemeUtils::CurrentThemeSetting]).toString();
         defaultTheme = settings.value(settingNames[HbThemeUtils::DefaultThemeSetting]).toString();
-        defaultThemeRootDir =
-                settings.value(settingNames[HbThemeUtils::DefaultThemeRootDirSetting]).toString();
         baseTheme = settings.value(settingNames[HbThemeUtils::BaseThemeSetting]).toString();
         operatorName = settings.value(settingNames[HbThemeUtils::OperatorNameSetting]).toString();
 #endif
+        initSettings();
+
         settingsRetrieved = true;
     }
 }
 
-int HbThemeUtilsPrivate::heapThemeOffset(const HbThemeIndexInfo &info)
+void HbThemeSettings::initSettings()
 {
-    if (mHeapThemeOffset == 0) {
-        QString themeindexfile = info.path + "/" + info.name +".themeindex";
-        QFile indexFile(themeindexfile);
-        if (indexFile.open(QIODevice::ReadOnly)) {
-            GET_MEMORY_MANAGER(HbMemoryManager::HeapMemory);
-            qint64 byteSize = indexFile.size();
-            mHeapThemeOffset = manager->alloc(byteSize);
-            if (mHeapThemeOffset >= 0) {
-                char *address = HbMemoryUtils::getAddress<char>(HbMemoryManager::HeapMemory, mHeapThemeOffset);
-                indexFile.read(address, byteSize);
-                indexFile.close();
-            }
+    // Validate base theme
+    bool modified = false;
+    if (baseTheme.isEmpty()) {
+        modified = true;
+        baseTheme = getThemeFromFile(baseThemeVariable, themesDir());
+        if (baseTheme.isEmpty()) {
+            baseTheme = getThemeFromFile(baseThemeVariable, coreResourcesRootDir);
+        }
+    }
+    if (!HbThemeUtils::isThemeValid(baseTheme)) {
+        modified = true;
+        // check if the theme name is logical
+        baseTheme = themesDir() + '/' + HbThemeUtils::platformHierarchy + '/' +
+                    HbThemeUtils::iconsResourceFolder + '/' + baseTheme;
+        if (!HbThemeUtils::isThemeValid(baseTheme)) {
+            baseTheme = getThemeFromFile(baseThemeVariable, coreResourcesRootDir);
         }
     }
-    return mHeapThemeOffset;
+    // Save if needed
+    if (modified) {
+        HbThemeUtils::setThemeSetting(HbThemeUtils::BaseThemeSetting, baseTheme);
+        modified = false;
+    }
+
+    // Validate default theme    
+    if (defaultTheme.isEmpty()) {
+        modified = true;
+        defaultTheme = getThemeFromFile(defaultThemeVariable, themesDir());
+        if (defaultTheme.isEmpty()) {
+            defaultTheme = getThemeFromFile(defaultThemeVariable, coreResourcesRootDir);
+        }
+    }
+    if (!HbThemeUtils::isThemeValid(defaultTheme)) {
+        modified = true;
+        // check if the theme name is logical
+        defaultTheme = themesDir() + '/' + HbThemeUtils::platformHierarchy + '/' +
+                    HbThemeUtils::iconsResourceFolder + '/' + defaultTheme;
+        if (!HbThemeUtils::isThemeValid(defaultTheme)) {
+            defaultTheme = getThemeFromFile(defaultThemeVariable, coreResourcesRootDir);
+        }
+    }
+    if (modified) {
+        HbThemeUtils::setThemeSetting(HbThemeUtils::DefaultThemeSetting, defaultTheme);
+        modified = false;
+    }
+
+    // Validate current theme
+    if (!HbThemeUtils::isThemeValid(currentTheme)) {
+        currentTheme = defaultTheme;
+        HbThemeUtils::setThemeSetting(HbThemeUtils::CurrentThemeSetting, currentTheme);
+    }
 }
 
-static HbThemeUtilsPrivate d;
-
-/* returns information of base theme
+/* reads the theme from theme.theme file
  */
-const HbThemeInfo &HbThemeUtils::baseTheme()
+QString HbThemeSettings::getThemeFromFile(const QString &variable, const QString &rootDir)
 {
-    static HbThemeInfo baseThemeInfo;
-   
-    if (baseThemeInfo.name.isEmpty()) {
-        // basetheme is empty, means it was not yet filled with appropriate values      
-        // Check if its value is stored in settings.
-        baseThemeInfo.name = getThemeSetting(BaseThemeSetting).trimmed();
-        if ( baseThemeInfo.name.isEmpty() ) {
-            // Settings not yet initialized
-            // Check if Base theme is defined in theme.theme
-            baseThemeInfo = getBaseThemeFromFile(HbThemeUtils::themesDir());
-            if (baseThemeInfo.name.isEmpty()) {
-                // Base theme does not exists in rom
-                // Get the base theme info from core resources
-                baseThemeInfo = getBaseThemeFromFile(coreResourcesRootDir);
-            }
-        } else {
-            // So settings are initialized, it will have other value as well
-            baseThemeInfo.rootDir = getThemeSetting(DefaultThemeRootDirSetting).trimmed();
-            // On desktop platforms try the HB_THEMES_DIR environment variable instead of
-            // blindly sticking to the previous stored setting, the theme directory may have been
-            // moved meanwhile and that usually results in a changed HB_THEMES_DIR but nobody will
-            // update the our settings stored via QSettings.
-#ifndef Q_OS_SYMBIAN            
-            QString themesDirFromEnv = HbThemeUtils::themesDir();
-            if (!themesDirFromEnv.isEmpty()) {
-                baseThemeInfo.rootDir = themesDirFromEnv;
-            }
-#endif
-        }
+    QFile themeSetting(rootDir + '/' + HbThemeUtils::platformHierarchy + '/' + themeSettingFile);
+    QString theme;
+    HbIniParser iniParser;
+
+    if (themeSetting.open(QIODevice::ReadOnly) && iniParser.read(&themeSetting)){
+        theme = rootDir + '/' + HbThemeUtils::platformHierarchy + '/' +
+                HbThemeUtils::iconsResourceFolder + '/' +
+                iniParser.value("Default", variable).trimmed();
     }
-    
-    return baseThemeInfo;
+    return theme;
 }
 
-/* returns name of default theme
- */
-HbThemeInfo HbThemeUtils::defaultTheme()
-{
-    // getting base theme makes sure that default theme was added in
-    // QSettings, if it was not already done
-    const HbThemeInfo &themeInfo = baseTheme(); 
-
-    // Assuming the path of default theme and base theme are same
-    return HbThemeInfo(getThemeSetting(DefaultThemeSetting), themeInfo.rootDir);    
-}
+Q_GLOBAL_STATIC(HbThemeSettings, themeSettings);
 
 QString HbThemeUtils::getThemeSetting(Setting setting)
 {
     // Make sure settings are read from QSettings.
-    d.readSettings();
+    themeSettings()->readSettings();
 
     switch (setting) {
         case CurrentThemeSetting:
-            return d.currentTheme;
+            return themeSettings()->currentTheme;
         case DefaultThemeSetting:
-            return d.defaultTheme;
-        case DefaultThemeRootDirSetting:
-            return d.defaultThemeRootDir;
+            return themeSettings()->defaultTheme;
         case BaseThemeSetting:
-            return d.baseTheme;
+            return themeSettings()->baseTheme;
         case OperatorNameSetting:
-            return d.operatorName;
+            return themeSettings()->operatorName;
         default:
             return QString();
     }
@@ -268,93 +284,47 @@
         delete repository;
     }
 #else
-    QSettings settings(QLatin1String(ORGANIZATION), QLatin1String(THEME_COMPONENT));
+    QSettings settings(QSettings::IniFormat, QSettings::UserScope, QLatin1String(ORGANIZATION), QLatin1String(THEME_COMPONENT));
     settings.setValue(settingNames[setting], QVariant(value));
     // Destructor of QSettings flushes the changed setting in the INI file.
 #endif
+    updateThemeSetting(setting, value);
 }   
 
 /**
 * Updates the setting's value in stored member variables.
 * Normally the settings are loaded from QSettings when method getThemeSetting() is called for the first time.
-* When there is a change in settings, this method can be used to sync the setting value stored in HbThemeUtilsPrivate.
+* When there is a change in settings, this method can be used to sync the setting value stored in HbThemeSettings.
 * E.g. theme change event updates the current theme setting, currently no other settings are changing their values.
 */
 void HbThemeUtils::updateThemeSetting(Setting setting, const QString &value)
 {
     switch (setting) {
         case CurrentThemeSetting:
-            d.currentTheme = value;
+            themeSettings()->currentTheme = value;
             break;
         case DefaultThemeSetting:
-            d.defaultTheme = value;
-            break;
-        case DefaultThemeRootDirSetting:
-            d.defaultThemeRootDir = value;
+            themeSettings()->defaultTheme = value;
             break;
         case BaseThemeSetting:
-            d.baseTheme = value;
+            themeSettings()->baseTheme = value;
             break;
         case OperatorNameSetting:
-            d.operatorName = value;
+            themeSettings()->operatorName = value;
             break;
         default:
             break;
     }
 }   
- 
-/* reads the theme name from theme.theme file, stores the same in theme settings,
-   returns the pair of theme name and its root directory
- */
-HbThemeInfo HbThemeUtils::getBaseThemeFromFile(const QString &rootDir)
-{
-    QFile themeSetting(rootDir + '/' + platformHierarchy + '/' + themeSettingFile);
-    HbThemeInfo themeInfo;
-    HbIniParser iniParser;
-
-    if (themeSetting.open(QIODevice::ReadOnly) && iniParser.read(&themeSetting)){
-        themeInfo.name = iniParser.value("Default", baseThemeVariable).trimmed();
-        
-        QString defaultTheme = iniParser.value("Default", defaultThemeVariable).trimmed();
-
-        // default theme name may not exist, in which case using base theme as default theme
-        if (defaultTheme.isEmpty()) {
-            defaultTheme = themeInfo.name;
-        }
-
-        // Save theme names in settings
-        saveBaseThemeSettings(themeInfo, defaultTheme, rootDir);
-    }
-    return themeInfo;
-}
-
-void HbThemeUtils::saveBaseThemeSettings(HbThemeInfo &baseThemeInfo,
-                                                const QString &defaultTheme,
-                                                const QString &rootDir)
-{
-    // If there is any base theme
-    if ((!baseThemeInfo.name.isEmpty()) && isThemeValid(HbThemeInfo(baseThemeInfo.name, rootDir))) {
-        // Save these theme names in settings
-        setThemeSetting(BaseThemeSetting, baseThemeInfo.name);
-        setThemeSetting(DefaultThemeRootDirSetting, rootDir);
-
-        // Store default theme also in settings, only if it is valid
-        if (baseThemeInfo.name == defaultTheme || isThemeValid(HbThemeInfo(defaultTheme, rootDir))) {
-            setThemeSetting(DefaultThemeSetting, defaultTheme);
-        }
-        baseThemeInfo.rootDir = rootDir;
-        d.settingsRetrieved = false;
-    }
-}
 
 /* checks whether the theme is valid
  */
-bool HbThemeUtils::isThemeValid(const HbThemeInfo &themeInfo)
+bool HbThemeUtils::isThemeValid(const QString &themePath)
 {
-    // If the theme contains index.theme in icons resources
+    // If the theme contains .themeindex and index.theme files
     // it will be assumed valid
-    return QFile::exists(themeInfo.rootDir + '/' + platformHierarchy + '/' +
-                         iconsResourceFolder + '/' + themeInfo.name + "/index.theme");
+    QString indexFile = QString(themePath).replace("/icons/", QString('/')) + ".themeindex";
+    return (QFile::exists(themePath + "/index.theme") && QFile::exists(indexFile));
 }
 
 HbThemeIndexInfo HbThemeUtils::getThemeIndexInfo(const HbThemeType &type)
@@ -362,23 +332,27 @@
     HbThemeIndexInfo info;
 
 #ifndef Q_OS_SYMBIAN
-    // If there is no themeserver connection load theme to client's heap
-    if (!HbThemeClient::global()->clientConnected()) {
-        HbThemeInfo baseinfo = baseTheme();
-        if (baseinfo.name.isEmpty() || baseinfo.name == "hbdefault") {
-            info.name = "hbdefault";
-            info.path = ":/themes";
-        } else {
-            info.name = baseinfo.name;
-            info.path = baseinfo.rootDir + "/themes";
+    if (!heapIndex) {
+        heapIndex = new HbHeapIndexInfo();
+        HbThemeUtils::loadHeapThemeIndexes();
+    }
+
+    if (heapIndex) {
+        switch(type) {
+        case BaseTheme:
+            info = heapIndex->baseTheme;
+            break;
+        case OperatorC:
+            info = heapIndex->priorityTheme;
+            break;
+        case ActiveTheme:
+            info = heapIndex->activeTheme;
+            break;
+        default:
+            break;
         }
-
-        info.address = HbMemoryUtils::getAddress<char>(HbMemoryManager::HeapMemory,
-                                                       d.heapThemeOffset(info));
-        return info;
     }
-#endif // Q_OS_SYMBIAN
-
+#else
     GET_MEMORY_MANAGER(HbMemoryManager::SharedMemory);
     if (manager) { 
         HbSharedChunkHeader *chunkHeader = (HbSharedChunkHeader*)(manager->base());
@@ -428,25 +402,112 @@
             break;
         }
     }
+#endif // Q_OS_SYMBIAN
     return info;
 }
 
 bool HbThemeUtils::isLogicalName(const QString &fileName)
 {
-    return !(fileName.contains(QChar('/'), Qt::CaseSensitive) || fileName.contains(QChar('\\'), Qt::CaseSensitive));
+    return !(fileName.contains(QChar(':'), Qt::CaseSensitive) ||
+             fileName.contains(QChar('/'), Qt::CaseSensitive) ||
+             fileName.contains(QChar('\\'), Qt::CaseSensitive));
+}
+
+char *HbThemeUtils::createHeapThemeIndex(const HbThemeInfo &theme)
+{
+    char *address = 0;
+
+    QString path = QDir::toNativeSeparators(theme.rootDir);
+    QString filename;
+
+    filename.append(path);
+    filename.append('/');
+    filename.append(theme.name);
+    filename.append(".themeindex");
+
+    QFile indexFile(filename);
+    if (indexFile.open(QIODevice::ReadOnly)) {
+        GET_MEMORY_MANAGER(HbMemoryManager::HeapMemory);
+        qint64 byteSize = indexFile.size();
+        int indexOffset = manager->alloc(byteSize);
+        if (indexOffset != -1) {
+            address = HbMemoryUtils::getAddress<char>(HbMemoryManager::HeapMemory, indexOffset);
+            indexFile.read(address, byteSize);
+            indexFile.close();
+        }
+    }
+
+    return address;
 }
 
-QString HbThemeUtils::themesDir()
+void HbThemeUtils::loadHeapThemeIndex(HbThemeType type)
 {
-#ifdef Q_OS_SYMBIAN
-    static QString mainThemesDir("Z:/resource/hb");
-#else
-    static QString mainThemesDir = QDir::fromNativeSeparators(qgetenv("HB_THEMES_DIR"));
-    // Do not call absolutePath if the path is empty,
-    // because it would return current path in that case.
-    if (!mainThemesDir.isEmpty()) {
-        mainThemesDir = QDir(mainThemesDir).absolutePath();
+    if (heapIndex) {
+        switch(type) {
+        case BaseTheme: {
+            if (heapIndex->baseTheme.address) {
+                delete heapIndex->baseTheme.address;
+            }
+            QString baseThemeName = getThemeSetting(BaseThemeSetting);
+            HbThemeInfo baseInfo;
+            QDir path(baseThemeName);
+            baseInfo.name = path.dirName();
+            QString absolutePath = path.absolutePath();
+            baseInfo.rootDir = absolutePath.left(absolutePath.indexOf("/icons/"));
+
+            heapIndex->baseTheme.address = createHeapThemeIndex(baseInfo);
+            if (heapIndex->baseTheme.address) {
+                heapIndex->baseTheme.name = baseInfo.name;
+                heapIndex->baseTheme.path = baseInfo.rootDir;
+            }
+            break;
+        }
+        case OperatorC: {
+            if (heapIndex->priorityTheme.address) {
+                delete heapIndex->priorityTheme.address;
+            }
+            HbThemeInfo operatorInfo;
+            operatorInfo.name = getThemeSetting(OperatorNameSetting);
+            if (!operatorInfo.name.isEmpty()) {
+                operatorInfo.rootDir.append(themesDir() + '/' + QLatin1String(operatorHierarchy));
+                heapIndex->priorityTheme.address =  createHeapThemeIndex(operatorInfo);
+                if (heapIndex->priorityTheme.address) {
+                    heapIndex->priorityTheme.name = operatorInfo.name;
+                    heapIndex->priorityTheme.path = operatorInfo.rootDir;
+                }
+            }
+            break;
+        }
+        case ActiveTheme: {
+            if (heapIndex->activeTheme.address) {
+                delete heapIndex->activeTheme.address;
+            }
+            QString currentThemeName = getThemeSetting(CurrentThemeSetting);
+            QDir path(currentThemeName);
+            HbThemeInfo activeInfo;
+            activeInfo.name = path.dirName();
+            QString absolutePath = path.absolutePath();
+            activeInfo.rootDir = absolutePath.left(absolutePath.indexOf("/icons/"));
+
+            heapIndex->activeTheme.address = createHeapThemeIndex(activeInfo);
+            if (heapIndex->activeTheme.address) {
+                heapIndex->activeTheme.name = activeInfo.name;
+                heapIndex->activeTheme.path = activeInfo.rootDir;
+            }
+            break;
+        }
+        default:
+            break;
+        }
     }
-#endif
-    return mainThemesDir;
 }
+
+void HbThemeUtils::loadHeapThemeIndexes()
+{
+    // Process base theme index, it is used as parent index also when the current theme is something else
+    loadHeapThemeIndex(BaseTheme);
+    // Process operator theme indexes
+    loadHeapThemeIndex(OperatorC);
+    // Process current theme index
+    loadHeapThemeIndex(ActiveTheme);
+}