Web page updated.
[jspeed] / src / themeloader.cpp
1 /*
2  * This file is part of jSpeed.
3  *
4  * jSpeed is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * jSpeed is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with jSpeed.  If not, see <http://www.gnu.org/licenses/>.
16  *
17  */
18
19 #include <QtCore/QDir>
20 #include <QtCore/QString>
21 #include <QtCore/QDebug>
22 #include <QtCore/QTimer>
23 #include <QtGui/QStackedWidget>
24 #include <QtXml/QDomNode>
25 #include <QtXml/QDomDocument>
26 #include <QtXml/QDomAttr>
27 #include <QMaemo5InformationBox>
28 #include "themeloader.h"
29 #include "reader.h"
30 #include "zipreader.h"
31 #include "filereader.h"
32 #include "themescreen.h"
33 #include "detailscreen.h"
34 #include "settings.h"
35 #include "widgetscreen.h"
36 #include "themescheduler.h"
37
38 namespace
39 {
40     QString const RESOURCE_DIR = ":/resources/themes/";
41     QString const THEME_SUFFIX = ".jspeed";
42 }
43
44 ThemeLoader::ThemeLoader(WidgetScreen* mainScreen, WidgetScreen* detailScreen, QObject* parent): QObject(parent),
45 reader_(0), mainScreen_(mainScreen), detailScreen_(detailScreen)
46 {
47 }
48
49 ThemeLoader::~ThemeLoader()
50 {
51 }
52
53 bool ThemeLoader::load()
54 {
55     if(theme_.isEmpty())
56     {
57         connect(&(ThemeScheduler::instance()), SIGNAL(themeChanged()), this, SLOT(load()));
58     }
59
60     QString theme = ThemeScheduler::instance().currentTheme();
61
62     if(theme == theme_)
63     {
64         return true;
65     }
66
67     theme_ = theme;
68
69     QString themeDir = getThemeDir();
70
71     if(QFile::exists(themeDir + theme_ + THEME_SUFFIX))
72     {
73         reader_ = new ZipReader(themeDir + theme_ + THEME_SUFFIX);
74
75         if(read())
76         {
77             return true;
78         }
79         else
80         {
81             QMaemo5InformationBox::information(mainScreen_,
82                                                tr("Unable to load theme: %1.").arg(error_),
83                                                QMaemo5InformationBox::NoTimeout);
84         }
85     }
86
87     theme_ = ThemeScheduler::instance().getDefaultTheme();
88     Settings::instance().setValue("theme", theme_);
89
90     if(QFile::exists(RESOURCE_DIR + theme_))
91     {
92         if(reader_)
93         {
94             delete reader_;
95         }
96
97         reader_ = new FileReader(RESOURCE_DIR + theme_);
98         return read();
99     }
100
101     error_ = "No themes found";
102
103     return false;
104 }
105
106 bool ThemeLoader::read()
107 {
108     Q_ASSERT(reader_ != 0);
109
110     if(!reader_->open())
111     {
112         error_ = reader_->errorString();
113         return false;
114     }
115
116     QByteArray xmlData;
117
118     if(!reader_->readFile("theme.xml", xmlData))
119     {
120         error_ = "Unable to find <b>theme.xml</b> from theme file";
121         return false;
122     }
123
124     QDomDocument doc;
125     int line = 0;
126     int column = 0;
127     QString msg;
128
129     if(!doc.setContent(xmlData, false, &msg, &line, &column))
130     {
131         error_ = "Invalid xml file, " + msg + " (line " + QString::number(line)+", column " + QString::number(column) + ")";
132         return false;
133     }
134
135     detailScreen_->clear();
136     detailScreen_->addScreen(new DetailScreen, WidgetScreen::LANDSCAPE);
137     detailScreen_->addScreen(new DetailScreen, WidgetScreen::PORTRAIT);
138     loadScreen("detailscreen", doc, detailScreen_);
139
140     mainScreen_->clear();
141     mainScreen_->addScreen(new ThemeScreen, WidgetScreen::LANDSCAPE);
142     mainScreen_->addScreen(new ThemeScreen, WidgetScreen::PORTRAIT);
143     bool ret = loadScreen("mainscreen", doc, mainScreen_);
144     mainScreen_->removeUnloaded();
145
146     detailScreen_->reArrange();
147     mainScreen_->reArrange();
148
149     reader_->close();
150
151     return ret;
152 }
153
154 bool ThemeLoader::loadScreen(QString const& tag, QDomDocument const& doc, WidgetScreen* screen)
155 {
156     QDomNodeList orientations = doc.elementsByTagName(tag);
157
158     if(orientations.isEmpty())
159     {
160         error_ = "No <"+tag+"> tags found";
161         return false;
162     }
163
164     bool ok = true;
165
166     for(int i = 0; i < orientations.size(); i++)
167     {
168         QDomNode data = orientations.at(i);
169         QString type = data.attributes().namedItem("orientation").toAttr().value();
170         QDomNode color = data.attributes().namedItem("color");
171
172         if(type == "landscape")
173         {
174             if(screen->orientationLoaded(WidgetScreen::LANDSCAPE))
175             {
176                 error_ = "More than one <"+tag+" orientation=\"landscape\"> specified";
177                 ok = false;
178             }
179
180             ok = ok && screen->load(WidgetScreen::LANDSCAPE, data, reader_);
181
182             if(ok && !color.isNull())
183             {
184                 screen->setColor(WidgetScreen::LANDSCAPE, color.toAttr().value());
185             }
186
187         }
188         else if(type == "portrait")
189         {
190             if(screen->orientationLoaded(WidgetScreen::PORTRAIT))
191             {
192                 error_ = "More than one <"+tag+" orientation=\"portrait\"> specified";
193                 ok = false;
194             }
195
196             ok = ok && screen->load(WidgetScreen::PORTRAIT, data, reader_);
197
198             if(ok && !color.isNull())
199             {
200                 screen->setColor(WidgetScreen::PORTRAIT, color.toAttr().value());
201             }
202         }
203         else if(type == "both")
204         {
205             if(screen->orientationLoaded(WidgetScreen::PORTRAIT) ||
206                screen->orientationLoaded(WidgetScreen::LANDSCAPE))
207             {
208                 error_ = "Multiple orientations specified for same screen";
209                 ok = false;
210             }
211
212             ok = ok && screen->load(data, reader_);
213
214             if(ok && !color.isNull())
215             {
216                 screen->setColor(color.toAttr().value());
217             }
218         }
219         else
220         {
221             error_ = "Invalid orientation: " + type;
222             ok = false;
223         }
224     }
225
226     return ok;
227 }
228
229 QString ThemeLoader::getThemeDir()
230 {
231     return Settings::getDir() + "themes" + QDir::separator();
232 }
233
234 QString const& ThemeLoader::getThemeSuffix()
235 {
236     return THEME_SUFFIX;
237 }
238
239 QString const& ThemeLoader::error() const
240 {
241     return error_;
242 }
243