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