--- a/src/hbcore/theme/hbthemeutils_p.cpp Mon Apr 19 14:02:13 2010 +0300
+++ b/src/hbcore/theme/hbthemeutils_p.cpp Mon May 03 12:48:33 2010 +0300
@@ -31,35 +31,55 @@
#include <QtDebug>
#include <QDir>
#include <QMap>
+#include <QVariant>
#include <hbapplication.h>
-
+#include <hbtheme.h>
#include "hbstandarddirs_p.h"
#include "hbiniparser_p.h"
#include "hblayeredstyleloader_p.h"
#include "hbthemecommon_p.h"
-static const QString iconsResourceFolder("icons");
-static const QString effectsResourceFolder("effects");
-static const QString styleResourceFolder("style");
-static const QString themeResourceFolder("theme");
+#ifdef Q_OS_SYMBIAN
+#include "hbthemecommon_symbian_p.h"
+#include <e32std.h>
+#endif
+
+// Standard folder names
-static const QString &getResourceFolderName(Hb::ResourceType resType)
+const char *HbThemeUtils::iconsResourceFolder = "icons";
+const char *HbThemeUtils::effectsResourceFolder = "effects";
+const char *HbThemeUtils::styleResourceFolder = "style";
+const char *HbThemeUtils::themeResourceFolder = "theme";
+const char *HbThemeUtils::operatorHierarchy = "operatortheme";
+const char *HbThemeUtils::appHierarchy = "apptheme";
+const char *HbThemeUtils::platformHierarchy = "themes";
+
+const char *operatorBasePathKey = "OperatorBasePath";
+static const char *themeSettingFile = "theme.theme";
+static const char *baseThemeVariable = "BaseTheme";
+static const char *defaultThemeVariable = "DefaultActiveTheme";
+
+// These are the used setting names corresponding to HbThemeUtils::Setting enumeration.
+// Value 0 is not used to be able to change the implementation to use Symbian's Cenrep if needed.
+static const QString settingNames[6] = {"", "currenttheme", "defaulttheme", "defaultthemedir", "basetheme", "operatorbasepath"};
+
+static const char *getResourceFolderName(Hb::ResourceType resType)
{
switch(resType) {
case Hb::IconResource:
- return iconsResourceFolder;
+ return HbThemeUtils::iconsResourceFolder;
case Hb::EffectResource:
- return effectsResourceFolder;
+ return HbThemeUtils::effectsResourceFolder;
case Hb::ThemeResource:
- return themeResourceFolder;
+ return HbThemeUtils::themeResourceFolder;
case Hb::StyleSheetResource:
- return styleResourceFolder;
+ return HbThemeUtils::styleResourceFolder;
default:
break;
}
// This just to avoid warning
- return iconsResourceFolder;
+ return HbThemeUtils::iconsResourceFolder;
}
/*!
@@ -78,23 +98,82 @@
class HbThemeUtilsPrivate
{
public:
- HbThemeUtilsPrivate()
+ HbThemeUtilsPrivate() : settingsRetrieved(false)
{
// add the operator level, app level and platform level hierarchies in the hierarchy list.
- hierarchy<<HbThemeUtils::operatorHierarchy()
- <<HbThemeUtils::appHierarchy()
- <<HbThemeUtils::platformHierarchy();
+ hierarchies << HbHierarchy(HbThemeUtils::operatorHierarchy, HbLayeredStyleLoader::Priority_Operator)
+#ifdef USE_APPTHEMES
+ << HbHierarchy(HbThemeUtils::appHierarchy, HbLayeredStyleLoader::Priority_Application)
+#endif
+ << HbHierarchy(HbThemeUtils::platformHierarchy, HbLayeredStyleLoader::Priority_Theme);
// @todo: The operator name has been hard-coded here. Will be removed once it is decided on how to
// get the operator name.
operatorName = "myoperator";
}
+ QString constructOperatorPath(const QString &basePath, const QString &resourcePath, const QString &fileName) const
+ {
+ return basePath + resourcePath + '/' + operatorName + '/' + fileName;
+ }
+ void initSettings();
+ void readSettings();
+
+public: // data
QString operatorName;
- QStringList hierarchy;
+ QVector<HbHierarchy> hierarchies;
+
+ 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 operatorBasePath;
};
+void HbThemeUtilsPrivate::initSettings()
+{
+ //server gets and stores the operator path to settings, clients only read it.
+ if (HbMemoryUtils::getCleanAppName()== THEME_SERVER_NAME) {
+ QStringList operatorPath;
+ operatorPath << QLatin1String(HbThemeUtils::operatorHierarchy) + '/';
+ operatorPath = HbStandardDirs::findExistingFolderList(operatorPath, QString(), Hb::IconResource);
+ if (operatorPath.size() > 0) {
+ operatorBasePath = operatorPath.at(0);
+ }
+ HbThemeUtils::setThemeSetting(HbThemeUtils::OperatorBasePathSetting, operatorBasePath);
+ } else {
+ operatorBasePath = HbThemeUtils::getThemeSetting(HbThemeUtils::OperatorBasePathSetting).trimmed();
+ }
+}
+
+void HbThemeUtilsPrivate::readSettings()
+{
+ // Read settings from QSettings and store them in member variables to
+ // avoid slow instantiating of QSettings in advance.
+
+ // The only changing setting is currentThemeSetting and its value is updated in theme change event.
+
+ if (!settingsRetrieved) {
+ QSettings settings(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();
+ operatorBasePath = settings.value(settingNames[HbThemeUtils::OperatorBasePathSetting]).toString();
+
+ settingsRetrieved = true;
+ }
+}
+
static HbThemeUtilsPrivate d;
+void HbThemeUtils::initSettings()
+{
+ d.initSettings();
+}
+
/* Adds a new hierarchy level to be used for attribute look-up
*
* @param newHierrachy the name of the new hierrachy
@@ -104,23 +183,26 @@
*
* @return the positon in the new hierarchy in the hierarchy list. -1 if the new hierarchy is not added.
*/
+
int HbThemeUtils::addHierarchy(const QString &newHierarchy, int priorityOrder)
{
int retValue = -1;
if (priorityOrder >= 0) {
// check that the hierarchy to be added is neither of opertor level,app level and platform level.
- if(newHierarchy != HbThemeUtils::operatorHierarchy()
- && newHierarchy != HbThemeUtils::appHierarchy()
- && newHierarchy != HbThemeUtils::platformHierarchy()){
+ if(newHierarchy != HbThemeUtils::operatorHierarchy
+ && newHierarchy != HbThemeUtils::appHierarchy
+ && newHierarchy != HbThemeUtils::platformHierarchy){
+
// if priority given is more than the number of hierarchies already existing, append the new
// hierarchy at end.
- if (priorityOrder > d.hierarchy.count()) {
- d.hierarchy.append(newHierarchy);
- retValue = d.hierarchy.count() - 1;
+ HbHierarchy add(newHierarchy, HbLayeredStyleLoader::Priority_Theme);
+ if (priorityOrder > d.hierarchies.count()) {
+ d.hierarchies.append(add);
+ retValue = d.hierarchies.count() - 1;
}
// else insert it at the correct position
else {
- d.hierarchy.insert(priorityOrder, newHierarchy);
+ d.hierarchies.insert(priorityOrder,add);
retValue = priorityOrder;
}
}
@@ -128,30 +210,40 @@
return retValue;
}
-
/* Removes a hierarchy level from the hierarchy list
*
* @param newHierrachy the name of the hierrachy to be removed.
*
* @ret true if the hierarchy has been removed, else false.
*/
-bool HbThemeUtils::removeHierarchy(const QString &hierarchy)
+bool HbThemeUtils::removeHierarchy(const QString &hierarchyName)
{
bool retValue = false;
// check whether an attempt is made to remove operator level, app level or platform level hierarchy
- if (hierarchy != HbThemeUtils::operatorHierarchy()
- && hierarchy != HbThemeUtils::appHierarchy()
- && hierarchy != HbThemeUtils::platformHierarchy()) {
- retValue = d.hierarchy.removeOne(hierarchy);
+ if (hierarchyName != HbThemeUtils::operatorHierarchy
+ && hierarchyName != HbThemeUtils::appHierarchy
+ && hierarchyName != HbThemeUtils::platformHierarchy) {
+ QVector<HbHierarchy>::iterator end = d.hierarchies.end();
+ for (QVector<HbHierarchy>::iterator i = d.hierarchies.begin(); i != end; ++i) {
+ if (i->name == hierarchyName) {
+ d.hierarchies.erase(i);
+ retValue = true;
+ break;
+ }
+ }
}
return retValue;
}
+QString HbThemeUtils::operatorBasePath()
+{
+ return d.operatorBasePath;
+}
/* @ret hierarchy of themes in priority.
*/
-QStringList HbThemeUtils::hierarchy()
+QVector<HbHierarchy> HbThemeUtils::hierarchies()
{
- return d.hierarchy;
+ return d.hierarchies;
}
/* It constructs the hierarchy list with complete path info using the existing hierarchy list.
@@ -166,96 +258,188 @@
const QString ¤tTheme,
const Hb::ResourceType resType)
{
- Q_UNUSED(currentTheme);
QMap<int,QString> hierarchyListWithPathInfo;
// Map the resource enum to string here
- const QString &resourceFolder = getResourceFolderName(resType);
-
- foreach (const QString &hierarchy, HbThemeUtils::hierarchy()) {
- if (hierarchy == HbThemeUtils::operatorHierarchy()) {
- hierarchyListWithPathInfo.insert(HbLayeredStyleLoader::Priority_Operator, (hierarchy + '/' + resourceFolder + '/' + d.operatorName + '/' + fileName));
- }
- else if (hierarchy == HbThemeUtils::appHierarchy()) {
- QString exebasename = QFileInfo(QCoreApplication::applicationFilePath()).baseName();
- hierarchyListWithPathInfo.insert(HbLayeredStyleLoader::Priority_Application, (hierarchy + '/' + exebasename + '/' + resourceFolder + '/' + currentTheme + '/' + fileName));
- }
- else if(hierarchy == HbThemeUtils::platformHierarchy()) {
- hierarchyListWithPathInfo.insert(HbLayeredStyleLoader::Priority_Theme, (hierarchy + '/' + resourceFolder + '/' + currentTheme + '/' + fileName));
- }
- else {
+ const QString &resourcePath = getResourceFolderName(resType);
+
+ foreach (const HbHierarchy &hierarchy, d.hierarchies) {
+ switch(hierarchy.layerPriority) {
+ case HbLayeredStyleLoader::Priority_Operator:
+ if (!d.operatorBasePath.isEmpty()) {
+ hierarchyListWithPathInfo.insert(HbLayeredStyleLoader::Priority_Operator,
+ d.constructOperatorPath(d.operatorBasePath, resourcePath, fileName));
+ }
+ break;
+ case HbLayeredStyleLoader::Priority_Application:
+ hierarchyListWithPathInfo.insert(HbLayeredStyleLoader::Priority_Application,
+ (hierarchy.name + '/' + HbMemoryUtils::getCleanAppName() + '/' + resourcePath + '/' + currentTheme + '/' + fileName));
+ break;
+ case HbLayeredStyleLoader::Priority_Theme:
+ // Add platform theme folder only if it is different from base theme
+ // Base theme is anyway added at the core priority
+ if (currentTheme != baseTheme().name) {
+ hierarchyListWithPathInfo.insert(HbLayeredStyleLoader::Priority_Theme,
+ (hierarchy.name + '/' + resourcePath + '/' + currentTheme + '/' + fileName));
+ }
+ break;
+ default:
// this is for a new hierarchy level and for the time being HbLayeredStyleLoader::Priority_Theme prirority is used,since there is no enum defined in hblayeredstyleloader_p.h
// priority should be replaced with respective enum.
- hierarchyListWithPathInfo.insert(HbLayeredStyleLoader::Priority_Theme, (hierarchy + '/' + resourceFolder + '/' + currentTheme + '/' + fileName));
+ hierarchyListWithPathInfo.insert(HbLayeredStyleLoader::Priority_Theme,
+ (hierarchy.name + '/' + resourcePath + '/' + currentTheme + '/' + fileName));
}
}
- if (resType == Hb::StyleSheetResource) {
- // lets add default CSS path too in this list for now
- // This comes last in fallback hierarchy
- hierarchyListWithPathInfo.insert(HbLayeredStyleLoader::Priority_Core, ("themes/" + resourceFolder + '/' + defaultTheme() + '/' + fileName));
+ if (resType == Hb::StyleSheetResource || resType == Hb::EffectResource) {
+ // lets add base CSS path too in this list for now
+ // This comes last in base hierarchy
+ hierarchyListWithPathInfo.insert(HbLayeredStyleLoader::Priority_Core,
+ (QLatin1String("themes/") + resourcePath + '/' + baseTheme().name + '/' + fileName));
}
return hierarchyListWithPathInfo;
}
-
+/* returns information of base theme
+ */
+const HbThemeInfo &HbThemeUtils::baseTheme()
+{
+ 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 in rom set
+ baseThemeInfo = getBaseThemeFromFile(HbStandardDirs::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();
+ }
+ }
+
+ return baseThemeInfo;
+}
/* returns name of default theme
*/
-
-QString HbThemeUtils::defaultTheme()
+HbThemeInfo HbThemeUtils::defaultTheme()
{
- static QString defaultThemeName;
-
- // defaultThemeName is empty, means it was not yet filled with appropriate value
- if (defaultThemeName.isEmpty()) {
- HbIniParser iniParser;
+ // 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);
+}
+
+QString HbThemeUtils::getThemeSetting(Setting setting)
+{
+ // Make sure settings are read from QSettings.
+ d.readSettings();
- // First check whether it is already stored in QSettings
- QSettings& settings = getThemeSettings();
- defaultThemeName = settings.value("defaulttheme").toString();
+ switch (setting) {
+ case CurrentThemeSetting:
+ return d.currentTheme;
+ case DefaultThemeSetting:
+ return d.defaultTheme;
+ case DefaultThemeRootDirSetting:
+ return d.defaultThemeRootDir;
+ case BaseThemeSetting:
+ return d.baseTheme;
+ case OperatorBasePathSetting:
+ return d.operatorBasePath;
+ default:
+ return QString();
+ }
+}
- // if not in QSettings, read from theme.theme file
- if (defaultThemeName.isEmpty()) {
- // Find theme.theme file
- QString dir = "themes";
- QString masterThemeFile = HbStandardDirs::findResource( dir + '/' + "themes" +
- '/' + "theme.theme", Hb::ThemeResource);
+void HbThemeUtils::setThemeSetting(Setting setting, const QString &value)
+{
+ QSettings settings(QLatin1String(ORGANIZATION), QLatin1String(THEME_COMPONENT));
+ settings.setValue(settingNames[setting], QVariant(value));
+ // Destructor of QSettings flushes the changed setting in the INI file.
+}
- // Try to read file and get parameters
- QFile themeFile(masterThemeFile);
- if (!themeFile.open(QIODevice::ReadOnly) || !iniParser.read(&themeFile)){
- qDebug() << "Can't access file";
- return false;
- }
+/**
+* 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.
+* 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;
+ break;
+ case DefaultThemeSetting:
+ d.defaultTheme = value;
+ break;
+ case DefaultThemeRootDirSetting:
+ d.defaultThemeRootDir = value;
+ break;
+ case BaseThemeSetting:
+ d.baseTheme = value;
+ break;
+ case OperatorBasePathSetting:
+ d.operatorBasePath = 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;
- //Find default theme index.theme file and clean it
- defaultThemeName = iniParser.value("Default Theme", "Name").trimmed();
- //Save Default theme
- settings.setValue("defaulttheme", defaultThemeName);
- }
- else {
+ if (themeSetting.open(QIODevice::ReadOnly) && iniParser.read(&themeSetting)){
+ themeInfo.name = iniParser.value("Default", baseThemeVariable).trimmed();
- QString cleanDefThemeName = defaultThemeName.trimmed();
- // if stored default theme name is not clean, store the cleaned theme name
- // (stored theme name may not be clean in case old implementaion which did not
- // handle dirty theme name, was run on the same device earlier.)
- if (cleanDefThemeName != defaultThemeName) {
- defaultThemeName = cleanDefThemeName;
- settings.setValue("defaulttheme", defaultThemeName);
+ 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;
+ }
+
+ // If there is any base theme
+ if (!themeInfo.name.isEmpty() && isThemeValid(HbThemeInfo(themeInfo.name,rootDir))) {
+ // Save these theme names in settings
+ setThemeSetting(BaseThemeSetting, themeInfo.name);
+ setThemeSetting(DefaultThemeRootDirSetting, rootDir);
+
+ // Store default theme also in settings, only if it is valid
+ if (themeInfo.name == defaultTheme || isThemeValid(HbThemeInfo(defaultTheme, rootDir))) {
+ setThemeSetting(DefaultThemeSetting, defaultTheme);
}
+ themeInfo.rootDir = rootDir;
+ d.settingsRetrieved = false;
}
}
-
- return defaultThemeName;
+ return themeInfo;
}
-/* returns settings for the theme
+/* checks whether the theme is valid
*/
-QSettings& HbThemeUtils::getThemeSettings()
- {
- static QSettings settings(QLatin1String(ORGANIZATION), QLatin1String(THEME_COMPONENT));
- return settings;
- }
-
+bool HbThemeUtils::isThemeValid(const HbThemeInfo &themeInfo)
+{
+ // If the theme contains index.theme in icons resources
+ // it will be assumed valid
+ QFile themeIndexFile(themeInfo.rootDir + '/' + platformHierarchy + '/' + iconsResourceFolder + "/" + themeInfo.name + "/index.theme");
+ return themeIndexFile.open(QIODevice::ReadOnly);
+}