xref: /haiku/src/apps/terminal/PrefHandler.cpp (revision 83b732c7328f1c4601e1a64ce234b93615c0ddc8)
1 /*
2  * Copyright 2003-2013, Haiku, Inc. All Rights Reserved.
3  * Copyright (c) 2004 Daniel Furrer <assimil8or@users.sourceforge.net>
4  * Copyright (c) 2003-4 Kian Duffy <myob@users.sourceforge.net>
5  * Copyright (c) 1998,99 Kazuho Okui and Takashi Murai.
6  *
7  * Distributed unter the terms of the MIT License.
8  *
9  * Authors:
10  *		Kian Duffy, myob@users.sourceforge.net
11  *		Daniel Furrer, assimil8or@users.sourceforge.net
12  *		Siarzhuk Zharski, zharik@gmx.li
13  */
14 
15 
16 #include "PrefHandler.h"
17 
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <unistd.h>
22 
23 #include <Catalog.h>
24 #include <Directory.h>
25 #include <Entry.h>
26 #include <File.h>
27 #include <FindDirectory.h>
28 #include <Font.h>
29 #include <GraphicsDefs.h>
30 #include <Locale.h>
31 #include <Message.h>
32 #include <NodeInfo.h>
33 #include <Path.h>
34 
35 #include "TermConst.h"
36 
37 
38 /*
39  * Startup preference settings.
40  */
41 static const pref_defaults kTermDefaults[] = {
42 	{ PREF_COLS,				"80" },
43 	{ PREF_ROWS,				"25" },
44 
45 //	No need for PREF_HALF_FONT_FAMILY/_STYLE defaults here,
46 //	these entries will be filled with corresponding params
47 //	of the current system fixed font if they are not
48 //	available in the settings file
49 
50 	{ PREF_HALF_FONT_SIZE,		"12" },
51 
52 	{ PREF_TEXT_FORE_COLOR,		"  0,   0,   0" },
53 	{ PREF_TEXT_BACK_COLOR,		"255, 255, 255" },
54 	{ PREF_CURSOR_FORE_COLOR,	"255, 255, 255" },
55 	{ PREF_CURSOR_BACK_COLOR,	"  0,   0,   0" },
56 	{ PREF_SELECT_FORE_COLOR,	"255, 255, 255" },
57 	{ PREF_SELECT_BACK_COLOR,	"  0,   0,   0" },
58 
59 	{ PREF_IM_FORE_COLOR,		"  0,   0,   0" },
60 	{ PREF_IM_BACK_COLOR,		"152, 203, 255" },
61 	{ PREF_IM_SELECT_COLOR,		"255, 152, 152" },
62 
63 	{ PREF_ANSI_BLACK_COLOR,	" 40,  40,  40" },
64 	{ PREF_ANSI_RED_COLOR,		"204,   0,   0" },
65 	{ PREF_ANSI_GREEN_COLOR,	" 78, 154,   6" },
66 	{ PREF_ANSI_YELLOW_COLOR,	"218, 168,   0" },
67 	{ PREF_ANSI_BLUE_COLOR,		" 51, 102, 152" },
68 	{ PREF_ANSI_MAGENTA_COLOR,	"115,  68, 123" },
69 	{ PREF_ANSI_CYAN_COLOR,		"  6, 152, 154" },
70 	{ PREF_ANSI_WHITE_COLOR,	"245, 245, 245" },
71 
72 	{ PREF_ANSI_BLACK_HCOLOR,	"128, 128, 128" },
73 	{ PREF_ANSI_RED_HCOLOR,		"255,   0,   0" },
74 	{ PREF_ANSI_GREEN_HCOLOR,	"  0, 255,   0" },
75 	{ PREF_ANSI_YELLOW_HCOLOR,	"255, 255,   0" },
76 	{ PREF_ANSI_BLUE_HCOLOR,	"  0,   0, 255" },
77 	{ PREF_ANSI_MAGENTA_HCOLOR,	"255,   0, 255" },
78 	{ PREF_ANSI_CYAN_HCOLOR,	"  0, 255, 255" },
79 	{ PREF_ANSI_WHITE_HCOLOR,	"255, 255, 255" },
80 
81 	{ PREF_HISTORY_SIZE,		"10000" },
82 
83 	{ PREF_TEXT_ENCODING,		"UTF-8" },
84 
85 	{ PREF_IM_AWARE,			"0"},
86 
87 	{ PREF_TAB_TITLE,			"%1d: %p" },
88 	{ PREF_WINDOW_TITLE,		"%T %i: %t" },
89 	{ PREF_BLINK_CURSOR,		PREF_TRUE },
90 	{ PREF_WARN_ON_EXIT,		PREF_TRUE },
91 	{ PREF_CURSOR_STYLE,		PREF_BLOCK_CURSOR },
92 	{ PREF_EMULATE_BOLD,		PREF_FALSE },
93 
94 	{ NULL, NULL},
95 };
96 
97 
98 PrefHandler *PrefHandler::sPrefHandler = NULL;
99 
100 
101 PrefHandler::PrefHandler(bool loadSettings)
102 	:
103 	fContainer('Pref')
104 {
105 	_LoadFromDefault(kTermDefaults);
106 
107 	if (loadSettings) {
108 		BPath path;
109 		GetDefaultPath(path);
110 		OpenText(path.Path());
111 	}
112 
113 	_ConfirmFont(be_fixed_font);
114 }
115 
116 
117 PrefHandler::PrefHandler(const PrefHandler* p)
118 {
119 	fContainer = p->fContainer;
120 }
121 
122 
123 PrefHandler::~PrefHandler()
124 {
125 }
126 
127 
128 /* static */
129 PrefHandler *
130 PrefHandler::Default()
131 {
132 	if (sPrefHandler == NULL)
133 		sPrefHandler = new PrefHandler();
134 	return sPrefHandler;
135 }
136 
137 
138 /* static */
139 void
140 PrefHandler::DeleteDefault()
141 {
142 	delete sPrefHandler;
143 	sPrefHandler = NULL;
144 }
145 
146 
147 /* static */
148 void
149 PrefHandler::SetDefault(PrefHandler *prefHandler)
150 {
151 	DeleteDefault();
152 	sPrefHandler = prefHandler;
153 }
154 
155 
156 /* static */
157 status_t
158 PrefHandler::GetDefaultPath(BPath& path)
159 {
160 	status_t status;
161 	status = find_directory(B_USER_SETTINGS_DIRECTORY, &path, true);
162 	if (status != B_OK)
163 		return status;
164 
165 	status = path.Append("Terminal");
166 	if (status != B_OK)
167 		return status;
168 
169 	// Just create the directory. Harmless if already there
170 	status = create_directory(path.Path(), 0755);
171 	if (status != B_OK)
172 		return status;
173 
174 	return path.Append("Default");
175 }
176 
177 
178 status_t
179 PrefHandler::OpenText(const char *path)
180 {
181 	return _LoadFromTextFile(path);
182 }
183 
184 
185 void
186 PrefHandler::SaveDefaultAsText()
187 {
188 	BPath path;
189 	if (GetDefaultPath(path) == B_OK)
190 		SaveAsText(path.Path(), PREFFILE_MIMETYPE);
191 }
192 
193 
194 void
195 PrefHandler::SaveAsText(const char *path, const char *mimetype,
196 	const char *signature)
197 {
198 	// make sure the target path exists
199 #if 0
200 	BPath directoryPath(path);
201 	if (directoryPath.GetParent(&directoryPath) == B_OK)
202 		create_directory(directoryPath.Path(), 0755);
203 #endif
204 
205 	BFile file(path, B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE);
206 	char buffer[512];
207 	type_code type;
208 	const char *key;
209 
210 	for (int32 i = 0;
211 #ifdef B_BEOS_VERSION_DANO
212 			fContainer.GetInfo(B_STRING_TYPE, i, &key, &type) == B_OK;
213 #else
214 			fContainer.GetInfo(B_STRING_TYPE, i, (char**)&key, &type) == B_OK;
215 #endif
216 			i++) {
217 		int len = snprintf(buffer, sizeof(buffer), "\"%s\" , \"%s\"\n",
218 				key, getString(key));
219 		file.Write(buffer, len);
220 	}
221 
222 	if (mimetype != NULL) {
223 		BNodeInfo info(&file);
224 		info.SetType(mimetype);
225 		info.SetPreferredApp(signature);
226 	}
227 }
228 
229 
230 int32
231 PrefHandler::getInt32(const char *key)
232 {
233 	const char *value = fContainer.FindString(key);
234 	if (value == NULL)
235 		return 0;
236 
237 	return atoi(value);
238 }
239 
240 
241 float
242 PrefHandler::getFloat(const char *key)
243 {
244 	const char *value = fContainer.FindString(key);
245 	if (value == NULL)
246 		return 0;
247 
248 	return atof(value);
249 }
250 
251 
252 #undef B_TRANSLATION_CONTEXT
253 #define B_TRANSLATION_CONTEXT "Terminal getString"
254 
255 const char*
256 PrefHandler::getString(const char *key)
257 {
258 	const char *buffer;
259 	if (fContainer.FindString(key, &buffer) != B_OK)
260 		buffer = B_TRANSLATE("Error!");
261 
262 	//printf("%x GET %s: %s\n", this, key, buf);
263 	return buffer;
264 }
265 
266 
267 bool
268 PrefHandler::getBool(const char *key)
269 {
270 	const char *value = fContainer.FindString(key);
271 	if (value == NULL)
272 		return false;
273 
274 	return strcmp(value, PREF_TRUE) == 0;
275 }
276 
277 
278 int
279 PrefHandler::getCursor(const char *key)
280 {
281 	const char *value = fContainer.FindString(key);
282 	if (value != NULL && strcmp(value, PREF_BLOCK_CURSOR) != 0) {
283 		if (strcmp(value, PREF_UNDERLINE_CURSOR) == 0)
284 			return UNDERLINE_CURSOR;
285 		if (strcmp(value, PREF_IBEAM_CURSOR) == 0)
286 			return IBEAM_CURSOR;
287 	}
288 	return BLOCK_CURSOR;
289 }
290 
291 
292 #undef B_TRANSLATION_CONTEXT
293 #define B_TRANSLATION_CONTEXT "Terminal getRGB"
294 
295 /** Returns RGB data from given key. */
296 
297 rgb_color
298 PrefHandler::getRGB(const char *key)
299 {
300 	rgb_color col;
301 	int r, g, b;
302 
303 	if (const char *s = fContainer.FindString(key)) {
304 		sscanf(s, "%d, %d, %d", &r, &g, &b);
305 	} else {
306 		fprintf(stderr,
307 			"PrefHandler::getRGB(%s) - key not found\n", key);
308 		r = g = b = 0;
309 	}
310 
311 	col.red = r;
312 	col.green = g;
313 	col.blue = b;
314 	col.alpha = 255;
315 	return col;
316 }
317 
318 
319 /** Setting Int32 data with key. */
320 
321 void
322 PrefHandler::setInt32(const char *key, int32 data)
323 {
324 	char buffer[32];
325 	snprintf(buffer, sizeof(buffer), "%d", (int)data);
326 	setString(key, buffer);
327 }
328 
329 
330 /** Setting Float data with key */
331 
332 void
333 PrefHandler::setFloat(const char *key, float data)
334 {
335 	char buffer[32];
336 	snprintf(buffer, sizeof(buffer), "%g", data);
337 	setString(key, buffer);
338 }
339 
340 
341 /** Setting Bool data with key */
342 
343 void
344 PrefHandler::setBool(const char *key, bool data)
345 {
346 	if (data)
347 		setString(key, PREF_TRUE);
348 	else
349 		setString(key, PREF_FALSE);
350 }
351 
352 
353 /** Setting CString data with key */
354 
355 void
356 PrefHandler::setString(const char *key, const char *data)
357 {
358 	//printf("%x SET %s: %s\n", this, key, data);
359 	fContainer.RemoveName(key);
360 	fContainer.AddString(key, data);
361 }
362 
363 
364 /** Setting RGB data with key */
365 
366 void
367 PrefHandler::setRGB(const char *key, const rgb_color data)
368 {
369 	char buffer[32];
370 	snprintf(buffer, sizeof(buffer), "%d, %d, %d", data.red, data.green, data.blue);
371 	setString(key, buffer);
372 }
373 
374 
375 /** Check any peference stored or not. */
376 
377 bool
378 PrefHandler::IsEmpty() const
379 {
380 	return fContainer.IsEmpty();
381 }
382 
383 
384 void
385 PrefHandler::_ConfirmFont(const BFont *fallbackFont)
386 {
387 	font_family family;
388 	font_style style;
389 
390 	const char *prefFamily = getString(PREF_HALF_FONT_FAMILY);
391 	int32 familiesCount = (prefFamily != NULL) ? count_font_families() : 0;
392 
393 	for (int32 i = 0; i < familiesCount; i++) {
394 		if (get_font_family(i, &family) != B_OK
395 			|| strcmp(family, prefFamily) != 0)
396 			continue;
397 
398 		const char *prefStyle = getString(PREF_HALF_FONT_STYLE);
399 		int32 stylesCount = (prefStyle != NULL) ? count_font_styles(family) : 0;
400 
401 		for (int32 j = 0; j < stylesCount; j++) {
402 			// check style if we can safely use this font
403 			if (get_font_style(family, j, &style) == B_OK
404 				&& strcmp(style, prefStyle) == 0)
405 				return;
406 		}
407 	}
408 
409 	// use fall-back font
410 	fallbackFont->GetFamilyAndStyle(&family, &style);
411 	setString(PREF_HALF_FONT_FAMILY, family);
412 	setString(PREF_HALF_FONT_STYLE, style);
413 }
414 
415 
416 status_t
417 PrefHandler::_LoadFromDefault(const pref_defaults* defaults)
418 {
419 	if (defaults == NULL)
420 		return B_ERROR;
421 
422 	while (defaults->key) {
423 		setString(defaults->key, defaults->item);
424 		++defaults;
425 	}
426 
427 	return B_OK;
428 }
429 
430 
431 /**	Text is "key","Content"
432  *	Comment : Start with '#'
433  */
434 
435 status_t
436 PrefHandler::_LoadFromTextFile(const char * path)
437 {
438 	char buffer[1024];
439 	char key[B_FIELD_NAME_LENGTH], data[512];
440 	int n;
441 	FILE *file;
442 
443 	file = fopen(path, "r");
444 	if (file == NULL)
445 		return B_ENTRY_NOT_FOUND;
446 
447 	while (fgets(buffer, sizeof(buffer), file) != NULL) {
448 		if (*buffer == '#')
449 			continue;
450 
451 		n = sscanf(buffer, "%*[\"]%[^\"]%*[\"]%*[^\"]%*[\"]%[^\"]", key, data);
452 		if (n == 2)
453 			setString(key, data);
454 	}
455 
456 	fclose(file);
457 	return B_OK;
458 }
459