xref: /haiku/src/apps/terminal/PrefHandler.cpp (revision 25a7b01d15612846f332751841da3579db313082)
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()
102 	:
103 	fContainer('Pref')
104 {
105 	_LoadFromDefault(kTermDefaults);
106 
107 	BPath path;
108 	GetDefaultPath(path);
109 	OpenText(path.Path());
110 
111 	_ConfirmFont(be_fixed_font);
112 }
113 
114 
115 PrefHandler::PrefHandler(const PrefHandler* p)
116 {
117 	fContainer = p->fContainer;
118 }
119 
120 
121 PrefHandler::~PrefHandler()
122 {
123 }
124 
125 
126 /* static */
127 PrefHandler *
128 PrefHandler::Default()
129 {
130 	if (sPrefHandler == NULL)
131 		sPrefHandler = new PrefHandler();
132 	return sPrefHandler;
133 }
134 
135 
136 /* static */
137 void
138 PrefHandler::DeleteDefault()
139 {
140 	delete sPrefHandler;
141 	sPrefHandler = NULL;
142 }
143 
144 
145 /* static */
146 void
147 PrefHandler::SetDefault(PrefHandler *prefHandler)
148 {
149 	DeleteDefault();
150 	sPrefHandler = prefHandler;
151 }
152 
153 
154 /* static */
155 status_t
156 PrefHandler::GetDefaultPath(BPath& path)
157 {
158 	status_t status;
159 	status = find_directory(B_USER_SETTINGS_DIRECTORY, &path, true);
160 	if (status != B_OK)
161 		return status;
162 
163 	status = path.Append("Terminal");
164 	if (status != B_OK)
165 		return status;
166 
167 	// Just create the directory. Harmless if already there
168 	status = create_directory(path.Path(), 0755);
169 	if (status != B_OK)
170 		return status;
171 
172 	return path.Append("Default");
173 }
174 
175 
176 status_t
177 PrefHandler::OpenText(const char *path)
178 {
179 	return _LoadFromTextFile(path);
180 }
181 
182 
183 void
184 PrefHandler::SaveDefaultAsText()
185 {
186 	BPath path;
187 	if (GetDefaultPath(path) == B_OK)
188 		SaveAsText(path.Path(), PREFFILE_MIMETYPE);
189 }
190 
191 
192 void
193 PrefHandler::SaveAsText(const char *path, const char *mimetype,
194 	const char *signature)
195 {
196 	// make sure the target path exists
197 #if 0
198 	BPath directoryPath(path);
199 	if (directoryPath.GetParent(&directoryPath) == B_OK)
200 		create_directory(directoryPath.Path(), 0755);
201 #endif
202 
203 	BFile file(path, B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE);
204 	char buffer[512];
205 	type_code type;
206 	const char *key;
207 
208 	for (int32 i = 0;
209 #ifdef B_BEOS_VERSION_DANO
210 			fContainer.GetInfo(B_STRING_TYPE, i, &key, &type) == B_OK;
211 #else
212 			fContainer.GetInfo(B_STRING_TYPE, i, (char**)&key, &type) == B_OK;
213 #endif
214 			i++) {
215 		int len = snprintf(buffer, sizeof(buffer), "\"%s\" , \"%s\"\n",
216 				key, getString(key));
217 		file.Write(buffer, len);
218 	}
219 
220 	if (mimetype != NULL) {
221 		BNodeInfo info(&file);
222 		info.SetType(mimetype);
223 		info.SetPreferredApp(signature);
224 	}
225 }
226 
227 
228 int32
229 PrefHandler::getInt32(const char *key)
230 {
231 	const char *value = fContainer.FindString(key);
232 	if (value == NULL)
233 		return 0;
234 
235 	return atoi(value);
236 }
237 
238 
239 float
240 PrefHandler::getFloat(const char *key)
241 {
242 	const char *value = fContainer.FindString(key);
243 	if (value == NULL)
244 		return 0;
245 
246 	return atof(value);
247 }
248 
249 
250 #undef B_TRANSLATION_CONTEXT
251 #define B_TRANSLATION_CONTEXT "Terminal getString"
252 
253 const char*
254 PrefHandler::getString(const char *key)
255 {
256 	const char *buffer;
257 	if (fContainer.FindString(key, &buffer) != B_OK)
258 		buffer = B_TRANSLATE("Error!");
259 
260 	//printf("%x GET %s: %s\n", this, key, buf);
261 	return buffer;
262 }
263 
264 
265 bool
266 PrefHandler::getBool(const char *key)
267 {
268 	const char *value = fContainer.FindString(key);
269 	if (value == NULL)
270 		return false;
271 
272 	return strcmp(value, PREF_TRUE) == 0;
273 }
274 
275 
276 int
277 PrefHandler::getCursor(const char *key)
278 {
279 	const char *value = fContainer.FindString(key);
280 	if (value != NULL && strcmp(value, PREF_BLOCK_CURSOR) != 0) {
281 		if (strcmp(value, PREF_UNDERLINE_CURSOR) == 0)
282 			return UNDERLINE_CURSOR;
283 		if (strcmp(value, PREF_IBEAM_CURSOR) == 0)
284 			return IBEAM_CURSOR;
285 	}
286 	return BLOCK_CURSOR;
287 }
288 
289 
290 #undef B_TRANSLATION_CONTEXT
291 #define B_TRANSLATION_CONTEXT "Terminal getRGB"
292 
293 /** Returns RGB data from given key. */
294 
295 rgb_color
296 PrefHandler::getRGB(const char *key)
297 {
298 	rgb_color col;
299 	int r, g, b;
300 
301 	if (const char *s = fContainer.FindString(key)) {
302 		sscanf(s, "%d, %d, %d", &r, &g, &b);
303 	} else {
304 		fprintf(stderr,
305 			"PrefHandler::getRGB(%s) - key not found\n", key);
306 		r = g = b = 0;
307 	}
308 
309 	col.red = r;
310 	col.green = g;
311 	col.blue = b;
312 	col.alpha = 255;
313 	return col;
314 }
315 
316 
317 /** Setting Int32 data with key. */
318 
319 void
320 PrefHandler::setInt32(const char *key, int32 data)
321 {
322 	char buffer[32];
323 	snprintf(buffer, sizeof(buffer), "%d", (int)data);
324 	setString(key, buffer);
325 }
326 
327 
328 /** Setting Float data with key */
329 
330 void
331 PrefHandler::setFloat(const char *key, float data)
332 {
333 	char buffer[32];
334 	snprintf(buffer, sizeof(buffer), "%g", data);
335 	setString(key, buffer);
336 }
337 
338 
339 /** Setting Bool data with key */
340 
341 void
342 PrefHandler::setBool(const char *key, bool data)
343 {
344 	if (data)
345 		setString(key, PREF_TRUE);
346 	else
347 		setString(key, PREF_FALSE);
348 }
349 
350 
351 /** Setting CString data with key */
352 
353 void
354 PrefHandler::setString(const char *key, const char *data)
355 {
356 	//printf("%x SET %s: %s\n", this, key, data);
357 	fContainer.RemoveName(key);
358 	fContainer.AddString(key, data);
359 }
360 
361 
362 /** Setting RGB data with key */
363 
364 void
365 PrefHandler::setRGB(const char *key, const rgb_color data)
366 {
367 	char buffer[32];
368 	snprintf(buffer, sizeof(buffer), "%d, %d, %d", data.red, data.green, data.blue);
369 	setString(key, buffer);
370 }
371 
372 
373 /** Check any peference stored or not. */
374 
375 bool
376 PrefHandler::IsEmpty() const
377 {
378 	return fContainer.IsEmpty();
379 }
380 
381 
382 void
383 PrefHandler::_ConfirmFont(const BFont *fallbackFont)
384 {
385 	font_family family;
386 	font_style style;
387 
388 	const char *prefFamily = getString(PREF_HALF_FONT_FAMILY);
389 	int32 familiesCount = (prefFamily != NULL) ? count_font_families() : 0;
390 
391 	for (int32 i = 0; i < familiesCount; i++) {
392 		if (get_font_family(i, &family) != B_OK
393 			|| strcmp(family, prefFamily) != 0)
394 			continue;
395 
396 		const char *prefStyle = getString(PREF_HALF_FONT_STYLE);
397 		int32 stylesCount = (prefStyle != NULL) ? count_font_styles(family) : 0;
398 
399 		for (int32 j = 0; j < stylesCount; j++) {
400 			// check style if we can safely use this font
401 			if (get_font_style(family, j, &style) == B_OK
402 				&& strcmp(style, prefStyle) == 0)
403 				return;
404 		}
405 	}
406 
407 	// use fall-back font
408 	fallbackFont->GetFamilyAndStyle(&family, &style);
409 	setString(PREF_HALF_FONT_FAMILY, family);
410 	setString(PREF_HALF_FONT_STYLE, style);
411 }
412 
413 
414 status_t
415 PrefHandler::_LoadFromDefault(const pref_defaults* defaults)
416 {
417 	if (defaults == NULL)
418 		return B_ERROR;
419 
420 	while (defaults->key) {
421 		setString(defaults->key, defaults->item);
422 		++defaults;
423 	}
424 
425 	return B_OK;
426 }
427 
428 
429 /**	Text is "key","Content"
430  *	Comment : Start with '#'
431  */
432 
433 status_t
434 PrefHandler::_LoadFromTextFile(const char * path)
435 {
436 	char buffer[1024];
437 	char key[B_FIELD_NAME_LENGTH], data[512];
438 	int n;
439 	FILE *file;
440 
441 	file = fopen(path, "r");
442 	if (file == NULL)
443 		return B_ENTRY_NOT_FOUND;
444 
445 	while (fgets(buffer, sizeof(buffer), file) != NULL) {
446 		if (*buffer == '#')
447 			continue;
448 
449 		n = sscanf(buffer, "%*[\"]%[^\"]%*[\"]%*[^\"]%*[\"]%[^\"]", key, data);
450 		if (n == 2)
451 			setString(key, data);
452 	}
453 
454 	fclose(file);
455 	return B_OK;
456 }
457