BuildmLearn Toolkit  2.0.4
BuildmLearn Toolkit is an easy-to-use program that helps users make mobile apps without any knowledge of application development.
 All Classes Functions Enumerations Groups Pages
skinfactory.cpp
1 /*
2  Copyright (c) 2012, BuildmLearn Contributors listed at http://buildmlearn.org/people/
3  All rights reserved.
4 
5  Redistribution and use in source and binary forms, with or without
6  modification, are permitted provided that the following conditions are met:
7 
8  * Redistributions of source code must retain the above copyright notice, this
9  list of conditions and the following disclaimer.
10 
11  * Redistributions in binary form must reproduce the above copyright notice,
12  this list of conditions and the following disclaimer in the documentation
13  and/or other materials provided with the distribution.
14 
15  * Neither the name of the BuildmLearn nor the names of its
16  contributors may be used to endorse or promote products derived from
17  this software without specific prior written permission.
18 
19  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30 
31 #include "miscellaneous/skinfactory.h"
32 
33 #include "definitions/definitions.h"
34 #include "miscellaneous/settings.h"
35 #include "miscellaneous/application.h"
36 
37 #include <QDir>
38 #include <QStyleFactory>
39 #include <QDomDocument>
40 #include <QDomElement>
41 
42 
43 SkinFactory::SkinFactory(QObject *parent) : QObject(parent) {
44 }
45 
47  qDebug("Destroying SkinFactory instance.");
48 }
49 
51  QString skin_name_from_settings = selectedSkinName();
52  bool skin_parsed;
53  Skin skin_data = skinInfo(skin_name_from_settings, &skin_parsed);
54 
55  if (skin_parsed) {
56  loadSkinFromData(skin_data);
57 
58  // Set this 'Skin' object as active one.
59  m_currentSkin = skin_data;
60 
61  qDebug("Skin '%s' loaded.", qPrintable(skin_name_from_settings));
62  }
63  else {
64 #if defined(DEBUG)
65  qCritical("Skin '%s' not loaded because its data are corrupted. No skin is loaded now!",
66  qPrintable(skin_name_from_settings));
67 #else
68  qFatal("Skin '%s' not loaded because its data are corrupted. No skin is loaded now!",
69  qPrintable(skin_name_from_settings));
70 #endif
71  }
72 }
73 
74 bool SkinFactory::loadSkinFromData(const Skin &skin) {
75  qDebug("Loading skin '%s'.", qPrintable(skin.m_baseName));
76 
77  // Here we use "/" instead of QDir::separator() because CSS2.1 url field
78  // accepts '/' as path elements separator.
79  //
80  // "##" is placeholder for the actual path to skin file. This is needed for using
81  // images within the QSS file.
82  // So if one uses "##/images/border.png" in QSS then it is
83  // replaced by fully absolute path and target file can
84  // be safely loaded.
85  QString raw_data = skin.m_rawData;
86 
87  if (!raw_data.isEmpty()) {
88  QString parsed_data = raw_data.replace("##",
89  APP_SKIN_PATH + '/' +
90  skin.m_baseFolder);
91  qApp->setStyleSheet(parsed_data);
92  }
93 
94  // Iterate supported styles and load one.
95  foreach (const QString &style, skin.m_stylesNames) {
96  if (qApp->setStyle(style) != 0) {
97  qDebug("Style '%s' loaded.", qPrintable(style));
98  break;
99  }
100  }
101 
102  return true;
103 }
104 
105 
106 void SkinFactory::setCurrentSkinName(const QString &skin_name) {
107  qApp->settings()->setValue(APP_CFG_GUI, "skin", skin_name);
108 }
109 
111  return qApp->settings()->value(APP_CFG_GUI,
112  "skin",
113  APP_SKIN_DEFAULT).toString();
114 }
115 
116 Skin SkinFactory::skinInfo(const QString &skin_name, bool *ok) {
117  Skin skin;
118  QString styles;
119  QFile skin_file(APP_SKIN_PATH + QDir::separator() + skin_name);
120  QDomDocument dokument;
121 
122  if (!skin_file.open(QIODevice::Text | QIODevice::ReadOnly) || !dokument.setContent(&skin_file, true)) {
123  if (ok) {
124  *ok = false;
125  }
126 
127  return skin;
128  }
129 
130  QDomNode skin_node = dokument.namedItem("skin");
131 
132  // Obtain visible skin name.
133  skin.m_visibleName = skin_node.namedItem("name").toElement().text();
134 
135  // Obtain skin raw data.
136  skin.m_rawData = skin_node.namedItem("data").toElement().text();
137  skin.m_rawData = QByteArray::fromBase64(skin.m_rawData.toLocal8Bit());
138 
139  // Obtain style name.
140  styles = skin_node.namedItem("style").toElement().text();
141  skin.m_stylesNames = styles.split(',', QString::SkipEmptyParts);
142 
143  // Obtain author.
144  skin.m_author = skin_node.namedItem("author").namedItem("name").toElement().text();
145 
146  // Obtain email.
147  skin.m_email = skin_node.namedItem("author").namedItem("email").toElement().text();
148 
149  // Obtain version.
150  skin.m_version = skin_node.attributes().namedItem("version").toAttr().value();
151 
152  // Obtain other information.
153  skin.m_baseName = QString(skin_name).replace(QDir::separator(), '/');
154  skin.m_baseFolder = skin.m_baseName.split('/', QString::SkipEmptyParts).at(0);
155 
156  // Obtain simulator image.
157  QString simulator_image = skin_node.namedItem("simulator").
158  namedItem("main").toElement().text();
159 
160  skin.m_simulatorBackgroundMain = APP_SKIN_PATH + '/' + skin.m_baseFolder + '/' + simulator_image;
161  skin.m_simulatorBackgroundMain = skin.m_simulatorBackgroundMain.replace('\\', '/');
162 
163  skin.m_simulatorStyle = skin_node.namedItem("simulator").namedItem("style").toElement().text();
164  skin.m_simulatorStyle = QByteArray::fromBase64(skin.m_simulatorStyle.toLocal8Bit());
165 
166  // Free resources.
167  skin_file.close();
168  skin_file.deleteLater();
169 
170  if (ok) {
171  *ok = !skin.m_author.isEmpty() && !skin.m_version.isEmpty() &&
172  !skin.m_baseName.isEmpty() && !skin.m_email.isEmpty();
173  }
174 
175  return skin;
176 }
177 
179  QList<Skin> skins;
180  bool skin_load_ok;
181  QStringList skin_directories = QDir(APP_SKIN_PATH).entryList(QDir::Dirs |
182  QDir::NoDotAndDotDot |
183  QDir::NoSymLinks |
184  QDir::Readable);
185 
186  foreach (const QString &base_directory, skin_directories) {
187  // Check skins installed in this base directory.
188  QStringList skin_files = QDir(APP_SKIN_PATH + QDir::separator() + base_directory).entryList(QStringList() << "*.xml",
189  QDir::Files | QDir::Readable | QDir::NoDotAndDotDot | QDir::NoSymLinks);
190 
191  foreach (const QString &skin_file, skin_files) {
192  // Check if skin file is valid and add it if it is valid.
193  Skin skin_info = skinInfo(base_directory + QDir::separator() + skin_file,
194  &skin_load_ok);
195 
196  if (skin_load_ok) {
197  skins.append(skin_info);
198  }
199  }
200  }
201 
202  return skins;
203 }
QList< Skin > installedSkins()
Returns list of installed skins.
virtual ~SkinFactory()
Destructor.
Definition: skinfactory.cpp:46
Skin skinInfo(const QString &skin_name, bool *ok=NULL)
Gets skin about a particular skin.
void loadCurrentSkin()
Loads skin name from settings and sets it as active.
Definition: skinfactory.cpp:50
void setCurrentSkinName(const QString &skin_name)
Sets the desired skin as the active one if it exists.
QString selectedSkinName()
Name of this "activated" skin.
SkinFactory(QObject *parent=0)
Constructor.
Definition: skinfactory.cpp:43
Skin representation.
Definition: skinfactory.h:41