1 //=============================================================================
2 //
3 //   File : KviTheme.cpp
4 //   Creation date : Mon Jan 08 2007 03:23:00 CEST by Szymon Stefanek
5 //
6 //   This file is part of the KVIrc IRC client distribution
7 //   Copyright (C) 2007-2010 Szymon Stefanek (pragma at kvirc dot net)
8 //
9 //   This program is FREE software. You can redistribute it and/or
10 //   modify it under the terms of the GNU General Public License
11 //   as published by the Free Software Foundation; either version 2
12 //   of the License, or (at your option) any later version.
13 //
14 //   This program is distributed in the HOPE that it will be USEFUL,
15 //   but WITHOUT ANY WARRANTY; without even the implied warranty of
16 //   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 //   See the GNU General Public License for more details.
18 //
19 //   You should have received a copy of the GNU General Public License
20 //   along with this program. If not, write to the Free Software Foundation,
21 //   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 //
23 //=============================================================================
24 
25 #include "KviTheme.h"
26 #include "KviFileUtils.h"
27 #include "KviConfigurationFile.h"
28 #include "KviLocale.h"
29 #include "KviMiscUtils.h"
30 #include "kvi_sourcesdate.h"
31 
32 #include <QImage>
33 #include <QDir>
34 #include <QStringList>
35 
36 #define KVI_THEME_SMALL_SCREENSHOT_NAME "screenshot_small.png"
37 #define KVI_THEME_MEDIUM_SCREENSHOT_NAME "screenshot_medium.png"
38 #define KVI_THEME_LARGE_SCREENSHOT_NAME "screenshot.png"
39 
40 #define QIMAGE_SCALE_MIN Qt::KeepAspectRatio
41 
KviThemeInfo()42 KviThemeInfo::KviThemeInfo()
43     : KviHeapObject()
44 {
45 }
46 
47 KviThemeInfo::~KviThemeInfo()
48     = default;
49 
setDirectoryAndLocation(const QString & szDirectory,Location eLocation)50 void KviThemeInfo::setDirectoryAndLocation(const QString & szDirectory, Location eLocation)
51 {
52 	switch(eLocation)
53 	{
54 		case Auto:
55 			g_pApp->getLocalKvircDirectory(m_szDirectory, KviApplication::Themes, szDirectory);
56 			if(KviFileUtils::directoryExists(m_szDirectory))
57 			{
58 				m_eLocation = User;
59 			}
60 			else
61 			{
62 				g_pApp->getGlobalKvircDirectory(m_szDirectory, KviApplication::Themes, szDirectory);
63 				if(KviFileUtils::directoryExists(m_szDirectory))
64 				{
65 					m_eLocation = Builtin;
66 				}
67 				else
68 				{
69 					m_eLocation = External;
70 					m_szDirectory = szDirectory;
71 					m_szSubdirectory = KviFileUtils::extractFileName(szDirectory, false);
72 				}
73 			}
74 			break;
75 		case Builtin:
76 			m_eLocation = eLocation;
77 			m_szSubdirectory = szDirectory;
78 			g_pApp->getGlobalKvircDirectory(m_szDirectory, KviApplication::Themes, m_szSubdirectory);
79 			break;
80 		case User:
81 			m_eLocation = eLocation;
82 			m_szSubdirectory = szDirectory;
83 			g_pApp->getLocalKvircDirectory(m_szDirectory, KviApplication::Themes, m_szSubdirectory);
84 			break;
85 		default: // assume external
86 		{
87 			m_eLocation = External;
88 			m_szDirectory = szDirectory;
89 			m_szSubdirectory = KviFileUtils::extractFileName(szDirectory, false);
90 		}
91 		break;
92 	}
93 
94 	KviQString::ensureLastCharIs(m_szDirectory, QChar(KVI_PATH_SEPARATOR_CHAR));
95 
96 	//qDebug(
97 	//		"[KviTheme::setDirectoryAndLocation] Directory(%s), Subdirectory(%s), Location(%d)",
98 	//		m_szDirectory.toUtf8().data(),
99 	//		m_szSubdirectory.toUtf8().data(),
100 	//		m_eLocation
101 	//	);
102 }
103 
load(const QString & szDirectory,Location eLocation)104 bool KviThemeInfo::load(const QString & szDirectory, Location eLocation)
105 {
106 	setDirectoryAndLocation(szDirectory, eLocation);
107 
108 	QString szThemeInfoFileName = m_szDirectory + KVI_THEMEINFO_FILE_NAME;
109 	QString szThemeDataFileName = m_szDirectory + KVI_THEMEDATA_FILE_NAME;
110 
111 	if(!KviFileUtils::fileExists(szThemeInfoFileName))
112 	{
113 		m_szLastError = __tr2qs("The theme information file does not exist");
114 		return false;
115 	}
116 
117 	if(!KviFileUtils::fileExists(szThemeDataFileName))
118 	{
119 		m_szLastError = __tr2qs("The theme data file does not exist");
120 		return false;
121 	}
122 
123 	KviConfigurationFile cfg(szThemeInfoFileName, KviConfigurationFile::Read);
124 
125 	cfg.setGroup(KVI_THEMEINFO_CONFIG_GROUP);
126 
127 	m_szThemeEngineVersion = cfg.readEntry("ThemeEngineVersion", "1.0.0");
128 	if(KviMiscUtils::compareVersions(m_szThemeEngineVersion, KVI_CURRENT_THEME_ENGINE_VERSION) < 0)
129 	{
130 		m_szLastError = QString(__tr2qs("This KVIrc executable is too old for this theme (minimum theme engine version required is %1 while this theme engine has version %2)")).arg(m_szThemeEngineVersion, KVI_CURRENT_THEME_ENGINE_VERSION);
131 		return false; // incompatible theme engine (will not work)
132 	}
133 
134 	// mandatory fields
135 	m_szName = cfg.readEntry("Name", "");
136 
137 	if(m_szName.isEmpty())
138 	{
139 		m_szLastError = __tr2qs("Theme information file is not valid");
140 		return false;
141 	}
142 
143 	// optional fields
144 	m_szVersion = cfg.readEntry("Version", "");
145 	if(m_szVersion.isEmpty())
146 		m_szVersion = "?.?.?";
147 	m_szAuthor = cfg.readEntry("Author", "");
148 	QString szUnknown = __tr2qs("Unknown");
149 	if(m_szAuthor.isEmpty())
150 		m_szAuthor = szUnknown;
151 	m_szDescription = cfg.readEntry("Description", "");
152 	m_szDate = cfg.readEntry("Date", "");
153 	if(m_szDate.isEmpty())
154 		m_szDate = szUnknown;
155 	m_szApplication = cfg.readEntry("Application", "");
156 	if(m_szApplication.isEmpty())
157 		m_szApplication = szUnknown;
158 
159 	//qDebug(
160 	//		"[KviTheme::load] Directory(%s), Subdirectory(%s), Location(%d)",
161 	//		m_szDirectory.toUtf8().data(),
162 	//		m_szSubdirectory.toUtf8().data(),
163 	//		m_eLocation
164 	//	);
165 
166 	return true;
167 }
168 
save(const QString & szThemeFileName)169 bool KviThemeInfo::save(const QString & szThemeFileName)
170 {
171 	KviConfigurationFile inf(szThemeFileName, KviConfigurationFile::Write);
172 
173 	inf.clear();
174 
175 	inf.setGroup(KVI_THEMEINFO_CONFIG_GROUP);
176 
177 	inf.writeEntry("Name", m_szName);
178 	inf.writeEntry("Version", m_szVersion);
179 	inf.writeEntry("Author", m_szAuthor);
180 	inf.writeEntry("Description", m_szDescription);
181 	inf.writeEntry("Date", m_szDate);
182 	inf.writeEntry("ThemeEngineVersion", KVI_CURRENT_THEME_ENGINE_VERSION);
183 	inf.writeEntry("Application", "KVIrc " KVI_VERSION "." KVI_SOURCES_DATE);
184 
185 	return true;
186 }
187 
smallScreenshotPath()188 QString KviThemeInfo::smallScreenshotPath()
189 {
190 	QString szRet = m_szDirectory;
191 	szRet.append(KVI_THEME_SMALL_SCREENSHOT_NAME);
192 	return szRet;
193 }
194 
smallScreenshot()195 const QPixmap & KviThemeInfo::smallScreenshot()
196 {
197 	if(!m_pixScreenshotSmall.isNull())
198 		return m_pixScreenshotSmall;
199 
200 	QString szFileName = m_szDirectory;
201 	szFileName.append(KVI_THEME_SMALL_SCREENSHOT_NAME);
202 	QPixmap pix(szFileName);
203 	if(!pix.isNull())
204 	{
205 		m_pixScreenshotSmall = pix;
206 		return m_pixScreenshotSmall;
207 	}
208 	// try to scale it from the large one (and save it by the way)
209 	pix = mediumScreenshot();
210 	if(pix.isNull())
211 		return m_pixScreenshotSmall;
212 
213 	if(pix.width() > 300 || pix.height() > 225)
214 	{
215 		QImage sbri = pix.toImage();
216 		pix = QPixmap::fromImage(sbri.scaled(300, 225, QIMAGE_SCALE_MIN, Qt::SmoothTransformation));
217 	}
218 	pix.save(szFileName, "PNG");
219 
220 	m_pixScreenshotSmall = pix;
221 	return m_pixScreenshotSmall;
222 }
223 
mediumScreenshot()224 const QPixmap & KviThemeInfo::mediumScreenshot()
225 {
226 	if(!m_pixScreenshotMedium.isNull())
227 		return m_pixScreenshotMedium;
228 
229 	QString szFileName = m_szDirectory;
230 	szFileName.append(KVI_THEME_MEDIUM_SCREENSHOT_NAME);
231 	QPixmap pix(szFileName);
232 	if(!pix.isNull())
233 	{
234 		m_pixScreenshotMedium = pix;
235 		return m_pixScreenshotMedium;
236 	}
237 	// try to scale it from the large one (and save it by the way)
238 	pix = largeScreenshot();
239 	if(pix.isNull())
240 		return m_pixScreenshotMedium;
241 	if(pix.width() > 600 || pix.height() > 450)
242 	{
243 		QImage sbri = pix.toImage();
244 		pix.fromImage(sbri.scaled(640, 450, QIMAGE_SCALE_MIN, Qt::SmoothTransformation));
245 	}
246 	pix.save(szFileName, "PNG");
247 
248 	m_pixScreenshotMedium = pix;
249 	return m_pixScreenshotMedium;
250 }
251 
largeScreenshot()252 const QPixmap & KviThemeInfo::largeScreenshot()
253 {
254 	if(!m_pixScreenshotLarge.isNull())
255 		return m_pixScreenshotLarge;
256 
257 	QString szFileName = m_szDirectory;
258 	szFileName.append(KVI_THEME_LARGE_SCREENSHOT_NAME);
259 	QPixmap pix(szFileName);
260 	if(pix.isNull())
261 		return m_pixScreenshotLarge;
262 	m_pixScreenshotLarge = pix;
263 	return m_pixScreenshotLarge;
264 }
265 
266 namespace KviTheme
267 {
saveScreenshots(KviThemeInfo & options,const QString & szOriginalScreenshotPath)268 	bool saveScreenshots(KviThemeInfo & options, const QString & szOriginalScreenshotPath)
269 	{
270 		QImage pix(szOriginalScreenshotPath);
271 		if(pix.isNull())
272 		{
273 			options.setLastError(__tr2qs("Failed to load the specified screenshot image"));
274 			return false;
275 		}
276 
277 		QImage out;
278 
279 		QString szScreenshotPath = options.directory();
280 
281 		if(szScreenshotPath.isEmpty())
282 		{
283 			options.setLastError(__tr2qs("Invalid option"));
284 			return false;
285 		}
286 
287 		if(!pix.save(szScreenshotPath + KVI_THEME_LARGE_SCREENSHOT_NAME, "PNG"))
288 		{
289 			options.setLastError(__tr2qs("Failed to save the screenshot image"));
290 			return false;
291 		}
292 
293 		if(pix.width() > 600 || pix.height() > 450)
294 			out = pix.scaled(640, 450, QIMAGE_SCALE_MIN, Qt::SmoothTransformation);
295 		else
296 			out = pix;
297 
298 		if(!out.save(szScreenshotPath + KVI_THEME_MEDIUM_SCREENSHOT_NAME, "PNG"))
299 		{
300 			options.setLastError(__tr2qs("Failed to save the screenshot image"));
301 			return false;
302 		}
303 
304 		if(pix.width() > 300 || pix.height() > 225)
305 			out = pix.scaled(300, 225, QIMAGE_SCALE_MIN, Qt::SmoothTransformation);
306 		else
307 			out = pix;
308 
309 		if(!out.save(szScreenshotPath + KVI_THEME_SMALL_SCREENSHOT_NAME, "PNG"))
310 		{
311 			options.setLastError(__tr2qs("Failed to save the screenshot image"));
312 			return false;
313 		}
314 
315 		return true;
316 	}
317 
installedThemeDirectories(QStringList & slThemes,KviThemeInfo::Location eLocation)318 	void installedThemeDirectories(QStringList & slThemes, KviThemeInfo::Location eLocation)
319 	{
320 		QString szThemePath;
321 		switch(eLocation)
322 		{
323 			case KviThemeInfo::Builtin:
324 				g_pApp->getGlobalKvircDirectory(szThemePath, KviApplication::Themes);
325 				break;
326 			case KviThemeInfo::User:
327 				g_pApp->getLocalKvircDirectory(szThemePath, KviApplication::Themes);
328 				break;
329 			default:
330 				return;
331 				break;
332 		}
333 
334 		QDir d(szThemePath);
335 		QStringList sl = d.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
336 
337 		for(auto & it : sl)
338 			slThemes.append(it);
339 	}
340 };
341