1 //=============================================================================
2 //
3 //   File : libkvitheme.cpp
4 //   Creation date : Sat 30 Dec 2006 14:54:56 by Szymon Stefanek
5 //
6 //   This file is part of the KVIrc IRC client distribution
7 //   Copyright (C) 2006-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 "ThemeManagementDialog.h"
26 #include "ThemeFunctions.h"
27 
28 #include "KviKvsArrayCast.h"
29 #include "KviMessageBox.h"
30 #include "KviModule.h"
31 #include "KviLocale.h"
32 #include "KviCommandFormatter.h"
33 #include "KviError.h"
34 #include "kvi_out.h"
35 #include "KviMainWindow.h"
36 #include "KviIconManager.h"
37 #include "KviConfigurationFile.h"
38 #include "kvi_sourcesdate.h"
39 #include "KviFileUtils.h"
40 #include "KviFileDialog.h"
41 #include "KviTheme.h"
42 
43 #include <QFileInfo>
44 #include <QMessageBox>
45 
46 QRect g_rectManagementDialogGeometry(0, 0, 0, 0);
47 
48 /*
49 	@doc: theme.install
50 	@type:
51 		command
52 	@title:
53 		theme.install
54 	@short:
55 		Shows the theme management editor
56 	@syntax:
57 		theme.install <package_path:string>
58 	@description:
59 		Attempts to install the themes in the package specified by <package_path>.
60 */
61 
theme_kvs_cmd_install(KviKvsModuleCommandCall * c)62 static bool theme_kvs_cmd_install(KviKvsModuleCommandCall * c)
63 {
64 	QString szThemePackFile;
65 
66 	KVSM_PARAMETERS_BEGIN(c)
67 	KVSM_PARAMETER("package_path", KVS_PT_STRING, 0, szThemePackFile)
68 	KVSM_PARAMETERS_END(c)
69 
70 	QString szError;
71 	if(!ThemeFunctions::installThemePackage(szThemePackFile, szError))
72 	{
73 		c->error(__tr2qs_ctx("Error installing theme package: %Q", "theme"), &szError);
74 		return false;
75 	}
76 
77 	return true;
78 }
79 
80 /*
81 	@doc: theme.apply
82 	@type:
83 		command
84 	@title:
85 		theme.apply
86 	@short:
87 		Apply a theme.
88 	@syntax:
89 		theme.apply [-b] [-e] [-u] <theme:string>
90 	@switches:
91 		!sw: -e | --external
92 		<theme> is an absolute directory containing a theme
93 		!sw: -b | --builtin
94 		<theme> is the name of a builtin theme (a subdirectory of the KVIrc global themes directory)
95 		!sw: -u | --user
96 		<theme> is the name of a user theme (a subdirectory of the KVIrc local themes directory)
97 	@description:
98 		Attempts to apply the global theme specified by <theme>.
99 		If the -b switch is present then <theme> is assumed to be a name of
100 		a builtin installed theme (a subdirectory of the KVIrc global themes directory).
101 		If the -l switch is present then <theme> is assumed to be a name of
102 		a user installed theme (a subdirectory of the KVIrc local themes directory).
103 		If the -e switch is present then <theme> is assumed to be an absolute
104 		directory containing the theme data.
105 		If no switch is present then KVIrc tries to determine automatically the
106 		type of theme (user, builtin or external).
107 */
108 
theme_kvs_cmd_apply(KviKvsModuleCommandCall * c)109 static bool theme_kvs_cmd_apply(KviKvsModuleCommandCall * c)
110 {
111 	QString szTheme;
112 
113 	KVSM_PARAMETERS_BEGIN(c)
114 	KVSM_PARAMETER("theme", KVS_PT_STRING, 0, szTheme)
115 	KVSM_PARAMETERS_END(c)
116 
117 	KviThemeInfo out;
118 	KviThemeInfo::Location eLocation = KviThemeInfo::Auto;
119 
120 	if(c->switches()->find('b', "builtin"))
121 		eLocation = KviThemeInfo::Builtin;
122 	else if(c->switches()->find('e', "external"))
123 		eLocation = KviThemeInfo::External;
124 	else if(c->switches()->find('u', "user"))
125 		eLocation = KviThemeInfo::User;
126 
127 	if(!KviTheme::apply(szTheme, eLocation, out))
128 	{
129 		QString szErr = out.lastError();
130 		c->error(__tr2qs_ctx("Failed to apply theme: %Q", "theme"), &szErr);
131 		return false;
132 	}
133 
134 	return true;
135 }
136 
137 /*
138 	@doc: theme.info
139 	@type:
140 		function
141 	@title:
142 		$theme.info
143 	@short:
144 		Return info about a user defined theme.
145 	@description:
146 		Returns a hash with information about the global theme specified by <theme>.
147 */
148 
theme_kvs_fnc_info(KviKvsModuleFunctionCall * c)149 static bool theme_kvs_fnc_info(KviKvsModuleFunctionCall * c)
150 {
151 	QString szTheme;
152 
153 	KVSM_PARAMETERS_BEGIN(c)
154 	KVSM_PARAMETER("theme", KVS_PT_STRING, 0, szTheme)
155 	KVSM_PARAMETERS_END(c)
156 
157 	KviKvsHash * pHash = new KviKvsHash();
158 	c->returnValue()->setHash(pHash);
159 
160 	KviThemeInfo theme;
161 	if(!theme.load(szTheme, KviThemeInfo::Auto))
162 	{
163 		c->warning(__tr2qs_ctx("The theme package '%Q' doesn't exist", "theme"), &szTheme);
164 		return true;
165 	}
166 
167 	pHash->set("name", new KviKvsVariant(theme.name()));
168 	pHash->set("version", new KviKvsVariant(theme.version()));
169 	pHash->set("author", new KviKvsVariant(theme.author()));
170 	pHash->set("description", new KviKvsVariant(theme.description()));
171 	return true;
172 }
173 
174 /*
175 	@doc: theme.screenshot
176 	@type:
177 		command
178 	@title:
179 		theme.screenshot
180 	@short:
181 		Makes a screenshot of the KVIrc window
182 	@syntax:
183 		theme.screenshot [file_name_path:string]
184 	@description:
185 		Makes a screenshot of the KVIrc main window
186 		and saves it in the specified file. If [file_name_path]
187 		is not specified then a save file dialog is shown.
188 */
189 
theme_kvs_cmd_screenshot(KviKvsModuleCommandCall * c)190 static bool theme_kvs_cmd_screenshot(KviKvsModuleCommandCall * c)
191 {
192 	QString szFileName;
193 
194 	KVSM_PARAMETERS_BEGIN(c)
195 	KVSM_PARAMETER("file_name_path", KVS_PT_STRING, KVS_PF_OPTIONAL, szFileName)
196 	KVSM_PARAMETERS_END(c)
197 
198 	KviFileUtils::adjustFilePath(szFileName);
199 
200 	QString szTmp;
201 	c->enterBlockingSection();
202 
203 	bool bResult = KviFileDialog::askForSaveFileName(
204 	    szTmp,
205 	    __tr2qs_ctx("Enter a Filename - KVIrc", "theme"), //dialog header title
206 	    szFileName,
207 	    "*.png",
208 	    false,
209 	    false,
210 	    true,
211 	    g_pMainWindow);
212 
213 	if(!c->leaveBlockingSection())
214 		return false; // need to stop immediately
215 
216 	if(!bResult)
217 		return true;
218 
219 	szFileName = szTmp;
220 
221 	if(szFileName.isEmpty())
222 		return true; // done
223 
224 	KviFileUtils::adjustFilePath(szFileName);
225 	if(QFileInfo(szFileName).suffix() != "png")
226 		szFileName += ".png";
227 
228 	QString szError;
229 	if(!ThemeFunctions::makeKVIrcScreenshot(szFileName))
230 	{
231 		c->error(__tr2qs_ctx("Error capturing and saving screenshot!", "theme"));
232 		return false;
233 	}
234 
235 	return true;
236 }
237 
238 /*
239 	@doc: theme.dialog
240 	@type:
241 		command
242 	@title:
243 		theme.dialog
244 	@short:
245 		Shows the theme theme management editor
246 	@syntax:
247 		theme.dialog [-t]
248 	@description:
249 		Shows the theme theme management editor[br]
250 		If the [-t] switch is used, the dialog is opened as toplevel window,
251 		otherwise it is opened as part of the current frame window.[br]
252 */
253 
theme_kvs_cmd_dialog(KviKvsModuleCommandCall * c)254 static bool theme_kvs_cmd_dialog(KviKvsModuleCommandCall * c)
255 {
256 	ThemeManagementDialog::display(c->hasSwitch('t', "toplevel"));
257 	return true;
258 }
259 
260 /*
261 	@doc: theme.pack
262 	@type:
263 		command
264 	@title:
265 		theme.pack
266 	@short:
267 		Creates a kvt package containing a set of themes
268 	@syntax:
269 		theme.pack <package_path> <package_name> <package_version> <package_description> <package_author> <package_image> <themes>
270 	@description:
271 		Creates a *.kvt package containing a set of KVIrc themes.[br]
272 		<package_path> is the absolute path and file name of the package that should be saved.[br]
273 		<package_name> is the visible name of the package (something like "My Theme Set").[br]
274 		<package_version> is the version of the package in the form X.Y.Z.[br]
275 		<package_description> is a textual description of the package.
276 		<package_author> is the name of the person that is creating the package (NOT necessarily the themes contained within).
277 		<package_image> is the path of an image to be used as package representative image. If the package is going
278 		to contain a single theme you may specify the theme's screenshot here. Pass an empty string if you
279 		don't want an image to be stored in the package.
280 		<theme> is a either a single path to a directory containing a theme as it's exported by KVIrc,
281 		or an array of such paths.
282 */
283 
theme_kvs_cmd_pack(KviKvsModuleCommandCall * c)284 static bool theme_kvs_cmd_pack(KviKvsModuleCommandCall * c)
285 {
286 	QString szPath, szName, szVersion, szDescription, szAuthor, szImage;
287 
288 	KviKvsArrayCast aCast;
289 
290 	KVSM_PARAMETERS_BEGIN(c)
291 	KVSM_PARAMETER("package_path", KVS_PT_NONEMPTYSTRING, 0, szPath)
292 	KVSM_PARAMETER("package_name", KVS_PT_NONEMPTYSTRING, 0, szName)
293 	KVSM_PARAMETER("package_version", KVS_PT_NONEMPTYSTRING, 0, szVersion)
294 	KVSM_PARAMETER("package_description", KVS_PT_STRING, 0, szDescription)
295 	KVSM_PARAMETER("package_author", KVS_PT_NONEMPTYSTRING, 0, szAuthor)
296 	KVSM_PARAMETER("package_image", KVS_PT_STRING, 0, szImage)
297 	KVSM_PARAMETER("theme", KVS_PT_ARRAYCAST, 0, aCast)
298 	KVSM_PARAMETERS_END(c)
299 
300 	KviKvsArray * pArray = aCast.array();
301 	if((!pArray) || (pArray->size() < 1))
302 	{
303 		c->error(__tr2qs_ctx("No themes specified", "theme"));
304 		return false;
305 	}
306 
307 	kvs_uint_t s = pArray->size();
308 	QStringList lThemeList;
309 
310 	for(kvs_uint_t i = 0; i < s; i++)
311 	{
312 		KviKvsVariant * v = pArray->at(i);
313 		if(!v)
314 			continue; // ?
315 		QString szVal;
316 		v->asString(szVal);
317 		if(szVal.isEmpty())
318 			continue;
319 		lThemeList.append(szVal);
320 	}
321 
322 	KviPointerList<KviThemeInfo> lThemeInfoList;
323 	lThemeInfoList.setAutoDelete(true);
324 
325 	for(const auto & szTheme : lThemeList)
326 	{
327 		KviThemeInfo * pInfo = new KviThemeInfo();
328 		if(!pInfo->load(szTheme, KviThemeInfo::External))
329 		{
330 			QString szErr = pInfo->lastError();
331 			c->error(__tr2qs_ctx("Failed to load theme from directory %Q: %Q", "theme"), &szTheme, &szErr);
332 			delete pInfo;
333 			return false;
334 		}
335 
336 		lThemeInfoList.append(pInfo);
337 	}
338 
339 	if(lThemeInfoList.isEmpty())
340 	{
341 		c->error(__tr2qs_ctx("No themes specified: refusing to create an empty theme package", "theme"));
342 		return false;
343 	}
344 
345 	QString szError;
346 
347 	if(
348 	    ThemeFunctions::packageThemes(
349 	        szPath,
350 	        szName,
351 	        szVersion,
352 	        szDescription,
353 	        szAuthor,
354 	        szImage,
355 	        lThemeInfoList,
356 	        szError))
357 		return true;
358 
359 	c->error(szError);
360 	return false;
361 }
362 
theme_module_init(KviModule * m)363 static bool theme_module_init(KviModule * m)
364 {
365 	KVSM_REGISTER_SIMPLE_COMMAND(m, "dialog", theme_kvs_cmd_dialog);
366 	KVSM_REGISTER_SIMPLE_COMMAND(m, "install", theme_kvs_cmd_install);
367 	KVSM_REGISTER_SIMPLE_COMMAND(m, "apply", theme_kvs_cmd_apply);
368 	KVSM_REGISTER_SIMPLE_COMMAND(m, "screenshot", theme_kvs_cmd_screenshot);
369 	KVSM_REGISTER_SIMPLE_COMMAND(m, "pack", theme_kvs_cmd_pack);
370 
371 	KVSM_REGISTER_FUNCTION(m, "info", theme_kvs_fnc_info);
372 
373 	QString szBuf;
374 	m->getDefaultConfigFileName(szBuf);
375 	KviConfigurationFile cfg(szBuf, KviConfigurationFile::Read);
376 	g_rectManagementDialogGeometry = cfg.readRectEntry("EditorGeometry", QRect(10, 10, 390, 440));
377 
378 	return true;
379 }
380 
theme_module_cleanup(KviModule * m)381 static bool theme_module_cleanup(KviModule * m)
382 {
383 	ThemeManagementDialog::cleanup();
384 
385 	QString szBuf;
386 	m->getDefaultConfigFileName(szBuf);
387 	KviConfigurationFile cfg(szBuf, KviConfigurationFile::Write);
388 	cfg.writeEntry("EditorGeometry", g_rectManagementDialogGeometry);
389 
390 	return true;
391 }
392 
theme_module_can_unload(KviModule *)393 static bool theme_module_can_unload(KviModule *)
394 {
395 	return (!ThemeManagementDialog::instance());
396 }
397 
398 KVIRC_MODULE(
399     "Theme",                                                        // module name
400     "4.0.0",                                                        // module version
401     "Copyright (C) 2006 Szymon Stefanek (pragma at kvirc dot net)", // author & (C)
402     "Theme management functions",
403     theme_module_init,
404     theme_module_can_unload,
405     0,
406     theme_module_cleanup,
407     "theme")
408