1 /*
2  * theme.cpp - base class for any theme
3  * Copyright (C) 2010 Justin Karneges, Michail Pishchagin, Rion (Sergey Ilinyh)
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18  *
19  */
20 
21 #include "theme.h"
22 
23 #include <QFileInfo>
24 #include <QDir>
25 #include <QDirIterator>
26 #include <QStringList>
27 
28 #ifndef NO_Theme_ZIP
29 #define Theme_ZIP
30 #endif
31 
32 #ifdef Theme_ZIP
33 #	include "zip/zip.h"
34 #endif
35 
36 #ifndef HAVE_QT5
37 # define QLatin1Literal QLatin1String
38 #endif
39 
40 #include "psithemeprovider.h"
41 #include "theme_p.h"
42 
43 
44 
45 
46 //--------------------------------------
47 // Theme
48 //--------------------------------------
Theme()49 Theme::Theme()
50 {
51 
52 }
53 
Theme(ThemePrivate * priv)54 Theme::Theme(ThemePrivate *priv) :
55     d(priv)
56 {
57 
58 }
59 
Theme(const Theme & other)60 Theme::Theme(const Theme &other) :
61 	d(other.d)
62 {
63 
64 }
65 
operator =(const Theme & other)66 Theme &Theme::operator=(const Theme &other)
67 {
68 	d = other.d;
69 	return *this;
70 }
71 
~Theme()72 Theme::~Theme()
73 {
74 
75 }
76 
isValid() const77 bool Theme::isValid() const
78 {
79 	return d;
80 }
81 
state() const82 Theme::State Theme::state() const
83 {
84 	if (!d) {
85 		return Invalid;
86 	}
87 	return d->state;
88 }
89 
exists()90 bool Theme::exists()
91 {
92 	return d && d->exists();
93 }
94 
load()95 bool Theme::load()
96 {
97 	if (!d) {
98 		return false;
99 	}
100 	return d->load();
101 }
102 
load(std::function<void (bool)> loadCallback)103 bool Theme::load(std::function<void (bool)> loadCallback)
104 {
105 	return d->load(loadCallback);
106 }
107 
hasPreview() const108 bool Theme::hasPreview() const
109 {
110 	return d->hasPreview();
111 }
112 
previewWidget()113 QWidget* Theme::previewWidget()
114 {
115 	return d->previewWidget();
116 }
117 
isCompressed(const QFileInfo & fi)118 bool Theme::isCompressed(const QFileInfo &fi)
119 {
120 	QString sfx = fi.suffix();
121 	return fi.isDir() && (sfx == QLatin1Literal("jisp") ||
122 	                      sfx == QLatin1Literal("zip") ||
123 	                      sfx == QLatin1Literal("theme"));
124 }
125 
isCompressed() const126 bool Theme::isCompressed() const
127 {
128 	return isCompressed(QFileInfo(d->filepath));
129 }
130 
loadData(const QString & fileName,const QString & themePath,bool caseInsensetive)131 QByteArray Theme::loadData(const QString &fileName, const QString &themePath, bool caseInsensetive)
132 {
133 	QByteArray ba;
134 	//qDebug("loading %s from %s", qPrintable(fileName), qPrintable(dir));
135 	QFileInfo fi(themePath);
136 	if ( fi.isDir() ) {
137 		QFile file(themePath + '/' + fileName);
138 		if (caseInsensetive && !file.exists()) {
139 			QDir d(themePath);
140 			foreach (const QString &name, fileName.toLower().split('/')) {
141 				if (name.isEmpty()) { // force relative path and drop double slahses
142 					continue;
143 				}
144 				QDirIterator di(d);
145 				QFileInfo fi;
146 				bool found = false;
147 				while (di.hasNext()) {
148 					di.next();
149 					if (di.fileName().compare(name, Qt::CaseInsensitive) == 0) {
150 						found = true;
151 						fi = di.fileInfo();
152 						break;
153 					}
154 				}
155 				if (!found) {
156 					qDebug("%s Not found: %s/%s", __FUNCTION__, qPrintable(d.path()), qPrintable(name));
157 					return ba;
158 				}
159 				if (fi.isFile()) {
160 					file.setFileName(fi.filePath());
161 					break;
162 				}
163 				d.cd(fi.fileName()); // so that was directory. go into.
164 			}
165 		}
166 		//qDebug("read data from %s", qPrintable(file.fileName()));
167 		if (!file.open(QIODevice::ReadOnly)) {
168 			qDebug("%s Failed to open: %s", __FUNCTION__, qPrintable(file.fileName()));
169 			return ba;
170 		}
171 
172 		ba = file.readAll();
173 	}
174 #ifdef Theme_ZIP
175 	else if ( fi.suffix() == "jisp" || fi.suffix() == "zip" || fi.suffix() == "theme" ) {
176 		UnZip z(themePath);
177 		if ( !z.open() )
178 			return ba;
179 		if (caseInsensetive) {
180 			z.setCaseSensitivity(UnZip::CS_Insensitive);
181 		}
182 
183 		QString n = fi.completeBaseName() + '/' + fileName;
184 		if ( !z.readFile(n, &ba) ) {
185 			n = "/" + fileName;
186 			z.readFile(n, &ba);
187 		}
188 	}
189 #endif
190 
191 	return ba;
192 }
193 
loadData(const QString & fileName) const194 QByteArray Theme::loadData(const QString &fileName) const
195 {
196 	return d->loadData(fileName);
197 }
198 
resourceLoader() const199 Theme::ResourceLoader *Theme::resourceLoader() const
200 {
201 	return d->resourceLoader();
202 }
203 
id() const204 const QString Theme::id() const
205 {
206 	return d? d->id : QString();
207 }
208 
setId(const QString & id)209 void Theme::setId(const QString &id)
210 {
211 	d->id = id;
212 }
213 
name() const214 const QString &Theme::name() const
215 {
216 	return d->name;
217 }
218 
setName(const QString & name)219 void Theme::setName(const QString &name)
220 {
221 	d->name = name;
222 }
223 
version() const224 const QString &Theme::version() const
225 {
226 	return d->version;
227 }
228 
description() const229 const QString &Theme::description() const
230 {
231 	return d->description;
232 }
233 
234 /**
235  * Returns the Theme authors list.
236  */
authors() const237 const QStringList &Theme::authors() const
238 {
239 	return d->authors;
240 }
241 
242 /**
243  * Returns the Theme creation date.
244  */
creation() const245 const QString &Theme::creation() const
246 {
247 	return d->creation;
248 }
249 
homeUrl() const250 const QString &Theme::homeUrl() const
251 {
252 	return d->homeUrl;
253 }
254 
themeProvider() const255 PsiThemeProvider *Theme::themeProvider() const
256 {
257 	return d->provider;
258 }
259 
260 /**
261  * Returns directory (or .zip/.jisp archive) name from which Theme was loaded.
262  */
filePath() const263 const QString &Theme::filePath() const
264 {
265 	return d->filepath;
266 }
267 
268 /**
269  * Sets the Theme directory (.zip archive) name.
270  */
setFilePath(const QString & f)271 void Theme::setFilePath(const QString &f)
272 {
273 	d->filepath = f;
274 }
275 
276 /**
277  * Returns additional Theme information.
278  * \sa setInfo()
279  */
info() const280 const QHash<QString, QString> Theme::info() const
281 {
282 	return d->info;
283 }
284 
285 /**
286  * Sets additional Theme information.
287  * \sa info()
288  */
setInfo(const QHash<QString,QString> & i)289 void Theme::setInfo(const QHash<QString, QString> &i)
290 {
291 	d->info = i;
292 }
293 
setCaseInsensitiveFS(bool state)294 void Theme::setCaseInsensitiveFS(bool state)
295 {
296 	d->caseInsensitiveFS = state;
297 }
298 
caseInsensitiveFS() const299 bool Theme::caseInsensitiveFS() const
300 {
301 	return d->caseInsensitiveFS;
302 }
303 
304 /**
305  * Title suitable to display in options dialog
306  */
title() const307 QString Theme::title() const
308 {
309 	return d->name.isEmpty()? d->id : d->name;
310 }
311 
setState(Theme::State state)312 void Theme::setState(Theme::State state)
313 {
314 	d->state = state;
315 }
316 
~ResourceLoader()317 Theme::ResourceLoader::~ResourceLoader()
318 {
319 
320 }
321