Initial commit.
[jspeed] / src / theme.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 <QtGui/QApplication>
23 #include <QtGui/QDesktopWidget>
24 #include <QtGui/QStackedWidget>
25 #include <QtXml/QDomNode>
26 #include <QtXml/QDomDocument>
27 #include <QtXml/QDomAttr>
28 #include <QMaemo5InformationBox>
29 #include "theme.h"
30 #include "reader.h"
31 #include "zipreader.h"
32 #include "filereader.h"
33 #include "themescreen.h"
34 #include "settings.h"
35
36 namespace
37 {
38     QString const RESOURCE_DIR = ":/resources/themes/";
39     QString const THEME_SUFFIX = ".jspeed";
40 }
41
42 Theme::Theme(QWidget* parent): WidgetScreen(parent),
43 portraitId_(-1), landscapeId_(-1), reader_(0),
44 portrait_(0), landscape_(0), portraitMode_(false)
45 {
46 }
47
48 Theme::~Theme()
49 {
50 }
51
52 bool Theme::load()
53 {
54     if(landscape_)
55     {
56         removeWidget(landscape_);
57         delete landscape_;
58         landscape_ = 0;
59         landscapeId_ = -1;
60     }
61
62     if(portrait_)
63     {
64         removeWidget(portrait_);
65         delete portrait_;
66         portrait_ = 0;
67         portraitId_ = -1;
68     }
69
70     QString theme = Settings::instance().value("theme", "default").toString();
71
72     QString themeDir = getThemeDir();
73
74     if(QFile::exists(themeDir + theme + THEME_SUFFIX))
75     {
76         reader_ = new ZipReader(themeDir + theme + THEME_SUFFIX);
77
78         if(read())
79         {
80             qDebug() << "Ladattiin " << theme;
81             return true;
82         }
83         else
84         {
85             QMaemo5InformationBox::information(this,
86                                                tr("Unable to load theme: %1.").arg(error_),
87                                                QMaemo5InformationBox::NoTimeout);
88         }
89     }
90
91     theme = "default";
92     Settings::instance().setValue("theme", theme);
93
94     if(QFile::exists(RESOURCE_DIR + theme))
95     {
96         if(reader_)
97         {
98             delete reader_;
99         }
100
101         reader_ = new FileReader(RESOURCE_DIR + theme);
102         return read();
103     }
104
105     error_ = "No themes found";
106
107     return false;
108 }
109
110 bool Theme::read()
111 {
112     Q_ASSERT(reader_ != 0);
113
114     if(!reader_->open())
115     {
116         error_ = reader_->errorString();
117         return false;
118     }
119
120     QByteArray xmlData;
121
122     if(!reader_->readFile("theme.xml", xmlData))
123     {
124         error_ = "Unable to find <b>theme.xml</b> from theme file";
125         return false;
126     }
127
128     QDomDocument doc;
129     int line = 0;
130     int column = 0;
131     QString msg;
132
133     if(!doc.setContent(xmlData, false, &msg, &line, &column))
134     {
135         error_ = "Invalid xml file, " + msg + " (line "+line+", column "+column+")";
136         return false;
137     }
138
139     QDomNodeList orientations = doc.elementsByTagName("orientation");
140
141     if(orientations.isEmpty())
142     {
143         error_ = "No <orientation> tags found";
144         return false;
145     }
146
147     bool ok = true;
148
149     for(int i = 0; i < orientations.size(); i++)
150     {
151         QDomNode data = orientations.at(i);
152         QString type = data.attributes().namedItem("name").toAttr().value();
153
154         if(type == "landscape")
155         {
156             if(landscape_)
157             {
158                 error_ = "More than one <orientation name=\"landscape\"> specified";
159                 ok = false;
160             }
161
162             landscape_ = new ThemeScreen();
163             ok = ok && landscape_->load(data, reader_);
164
165         }
166         else if(type == "portrait")
167         {
168             if(portrait_)
169             {
170                 error_ = "More than one <orientation name=\"portrait\"> specified";
171                 ok = false;
172             }
173
174             portrait_ = new ThemeScreen();
175             ok = ok && portrait_->load(data, reader_);
176         }
177         else
178         {
179             error_ = "Invalid orientation: " + type;
180             ok = false;
181         }
182     }
183
184     reader_->close();
185     delete reader_;
186     reader_ = 0;
187
188     if(!portrait_ && !landscape_)
189     {
190         error_ = "No valid orientation tags found";
191         ok = false;
192     }
193
194     if(ok)
195     {
196         if(landscape_)
197         {
198             landscapeId_ = addWidget(landscape_);
199             connectSignals(landscape_);
200         }
201
202         if(portrait_)
203         {
204             portraitId_ = addWidget(portrait_);
205             connectSignals(portrait_);
206         }
207     }
208     else
209     {
210         delete portrait_;
211         portrait_ = 0;
212         delete landscape_;
213         landscape_ = 0;
214     }
215
216     return ok;
217 }
218
219 QString Theme::getThemeDir()
220 {
221     return Settings::getDir() + "themes" + QDir::separator();
222 }
223
224 QString const& Theme::getThemeSuffix()
225 {
226     return THEME_SUFFIX;
227 }
228
229 QString const& Theme::error() const
230 {
231     return error_;
232 }
233
234 bool Theme::portraitEnabled() const
235 {
236     return portraitId_ != -1;
237 }
238
239 bool Theme::landscapeEnabled() const
240 {
241     return landscapeId_ != -1;
242 }
243
244 void Theme::reArrange()
245 {
246     QRect rect = QApplication::desktop()->screenGeometry();
247
248     bool portrait = rect.height() > rect.width();
249
250     if(portrait != portraitMode_)
251     {
252         if((portrait && portraitId_ == -1) ||
253            (!portrait && landscapeId_ == -1))
254         {
255             return;
256         }
257
258         portraitMode_ = portrait;
259
260         if(portrait)
261         {
262             setCurrentIndex(portraitId_);
263             portrait_->reArrange();
264         }
265         else
266         {
267             setCurrentIndex(landscapeId_);
268             landscape_->reArrange();
269         }
270     }
271 }
272
273 void Theme::flip()
274 {
275     if(portrait_)
276     {
277         portrait_->flip();
278     }
279
280     if(landscape_)
281     {
282         landscape_->flip();
283     }
284 }
285
286 void Theme::connectSignals(ThemeScreen* screen)
287 {
288     connect(screen, SIGNAL(minimizePressed()), this, SIGNAL(minimizePressed()));
289     connect(screen, SIGNAL(settingsPressed()), this, SIGNAL(settingsPressed()));
290     connect(screen, SIGNAL(closePressed()), this, SIGNAL(closePressed()));
291     connect(screen, SIGNAL(clicked()), this, SIGNAL(clicked()));
292 }
293