xref: /haiku/src/apps/terminal/PrefHandler.cpp (revision 9760dcae2038d47442f4658c2575844c6cf92c40)
1 /*
2  * Copyright 2003-2007, 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 
10 
11 #include "Encoding.h"
12 #include "PrefHandler.h"
13 #include "TermConst.h"
14 
15 #include <Directory.h>
16 #include <Entry.h>
17 #include <File.h>
18 #include <FindDirectory.h>
19 #include <Font.h>
20 #include <GraphicsDefs.h>
21 #include <Message.h>
22 #include <NodeInfo.h>
23 #include <Path.h>
24 
25 #include <stdio.h>
26 #include <unistd.h>
27 #include <stdlib.h>
28 #include <string.h>
29 
30 /*
31  * Startup preference settings.
32  */
33 static const pref_defaults kTermDefaults[] = {
34 	{ PREF_COLS,				"80" },
35 	{ PREF_ROWS,				"25" },
36 
37 	{ PREF_HALF_FONT_FAMILY,	"Courier10 BT" },
38 	{ PREF_HALF_FONT_STYLE,		"Regular" },
39 	{ PREF_HALF_FONT_SIZE,		"12" },
40 
41 	{ PREF_TEXT_FORE_COLOR,		"  0,   0,   0" },
42 	{ PREF_TEXT_BACK_COLOR,		"255, 255, 255" },
43 	{ PREF_SELECT_FORE_COLOR,	"255, 255, 255" },
44 	{ PREF_SELECT_BACK_COLOR,	"  0,   0,   0" },
45 	{ PREF_CURSOR_FORE_COLOR,	"255, 255, 255" },
46 	{ PREF_CURSOR_BACK_COLOR,	"  0,   0,   0" },
47 
48 	{ PREF_IM_FORE_COLOR,		"  0,   0,   0" },
49 	{ PREF_IM_BACK_COLOR,		"152, 203, 255" },
50 	{ PREF_IM_SELECT_COLOR,		"255, 152, 152" },
51 
52 	{ PREF_SHELL,				"/bin/sh -login" },
53 	{ PREF_HISTORY_SIZE,		"10000" },
54 
55 	{ PREF_TEXT_ENCODING,		"UTF-8" },
56 
57 	{ PREF_GUI_LANGUAGE,		"English"},
58 	{ PREF_IM_AWARE,			"0"},
59 	{ NULL, NULL},
60 };
61 
62 
63 PrefHandler *PrefHandler::sPrefHandler = NULL;
64 
65 
66 PrefHandler::PrefHandler()
67 	:
68 	fContainer('Pref')
69 {
70 	_LoadFromDefault(kTermDefaults);
71 
72 	BPath path;
73 	GetDefaultPath(path);
74 	OpenText(path.Path());
75 
76 	_ConfirmFont(PREF_HALF_FONT_FAMILY, be_fixed_font);
77 }
78 
79 
80 PrefHandler::PrefHandler(const PrefHandler* p)
81 {
82 	fContainer = p->fContainer;
83 }
84 
85 
86 PrefHandler::~PrefHandler()
87 {
88 }
89 
90 
91 /* static */
92 PrefHandler *
93 PrefHandler::Default()
94 {
95 	if (sPrefHandler == NULL)
96 		sPrefHandler = new PrefHandler();
97 	return sPrefHandler;
98 }
99 
100 
101 /* static */
102 void
103 PrefHandler::DeleteDefault()
104 {
105 	delete sPrefHandler;
106 	sPrefHandler = NULL;
107 }
108 
109 
110 /* static */
111 void
112 PrefHandler::SetDefault(PrefHandler *prefHandler)
113 {
114 	DeleteDefault();
115 	sPrefHandler = prefHandler;
116 }
117 
118 
119 /* static */
120 status_t
121 PrefHandler::GetDefaultPath(BPath& path)
122 {
123 	if (find_directory(B_USER_SETTINGS_DIRECTORY, &path, true) != B_OK)
124 		return B_ERROR;
125 
126 #ifdef HAIKU_TARGET_PLATFORM_HAIKU
127 	path.Append("Terminal_settings");
128 #else
129 	path.Append("HaikuTerminal_settings");
130 #endif
131 
132 	return B_OK;
133 }
134 
135 
136 status_t
137 PrefHandler::Open(const char *path)
138 {
139 	return _LoadFromFile(path);
140 }
141 
142 
143 status_t
144 PrefHandler::OpenText(const char *path)
145 {
146 	return _LoadFromTextFile(path);
147 }
148 
149 
150 status_t
151 PrefHandler::Save(const char *path)
152 {
153 	// make sure the target path exists
154 #if 0
155 	// TODO: currently not needed as we're reusing the standard directory
156 	BPath directoryPath(path);
157 	if (directoryPath.GetParent(&directoryPath) == B_OK)
158 		create_directory(directoryPath.Path(), 0755);
159 #endif
160 
161 	BFile file(path, B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE);
162 	return fContainer.Flatten(&file);
163 }
164 
165 
166 void
167 PrefHandler::SaveDefaultAsText()
168 {
169 	BPath path;
170 	if (GetDefaultPath(path) == B_OK)
171 		SaveAsText(path.Path(), PREFFILE_MIMETYPE);
172 }
173 
174 
175 void
176 PrefHandler::SaveAsText(const char *path, const char *mimetype,
177 	const char *signature)
178 {
179 	// make sure the target path exists
180 #if 0
181 	BPath directoryPath(path);
182 	if (directoryPath.GetParent(&directoryPath) == B_OK)
183 		create_directory(directoryPath.Path(), 0755);
184 #endif
185 
186 	BFile file(path, B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE);
187 	char buffer[512];
188 	type_code type;
189 	const char *key;
190 
191 	for (int32 i = 0;
192 #ifdef B_BEOS_VERSION_DANO
193 			fContainer.GetInfo(B_STRING_TYPE, i, &key, &type) == B_OK;
194 #else
195 			fContainer.GetInfo(B_STRING_TYPE, i, (char**)&key, &type) == B_OK;
196 #endif
197 			i++) {
198 		int len = snprintf(buffer, sizeof(buffer), "\"%s\" , \"%s\"\n", key, getString(key));
199 		file.Write(buffer, len);
200 	}
201 
202 	if (mimetype != NULL){
203 		BNodeInfo info(&file);
204 		info.SetType(mimetype);
205 		info.SetPreferredApp(signature);
206 	}
207 }
208 
209 
210 int32
211 PrefHandler::getInt32(const char *key)
212 {
213 	const char *value = fContainer.FindString(key);
214 	if (value == NULL)
215 		return 0;
216 
217 	return atoi(value);
218 }
219 
220 
221 float
222 PrefHandler::getFloat(const char *key)
223 {
224 	const char *value = fContainer.FindString(key);
225 	if (value == NULL)
226 		return 0;
227 
228 	return atof(value);
229 }
230 
231 
232 const char*
233 PrefHandler::getString(const char *key)
234 {
235 	const char *buffer;
236 	if (fContainer.FindString(key, &buffer) != B_OK)
237 		buffer = "Error!";
238 
239 	//printf("%x GET %s: %s\n", this, key, buf);
240 	return buffer;
241 }
242 
243 
244 bool
245 PrefHandler::getBool(const char *key)
246 {
247 	const char *value = fContainer.FindString(key);
248 	if (value == NULL)
249 		return false;
250 
251 	return !strcmp(value, PREF_TRUE);
252 }
253 
254 
255 /** Returns RGB data from given key. */
256 
257 rgb_color
258 PrefHandler::getRGB(const char *key)
259 {
260 	rgb_color col;
261 	int r, g, b;
262 
263 	if (const char *s = fContainer.FindString(key)) {
264 		sscanf(s, "%d, %d, %d", &r, &g, &b);
265 	} else {
266 		fprintf(stderr, "PrefHandler::getRGB(%s) - key not found\n", key);
267 		r = g = b = 0;
268 	}
269 
270 	col.red = r;
271 	col.green = g;
272 	col.blue = b;
273 	col.alpha = 255;
274 	return col;
275 }
276 
277 
278 /** Setting Int32 data with key. */
279 
280 void
281 PrefHandler::setInt32(const char *key, int32 data)
282 {
283 	char buffer[32];
284 	snprintf(buffer, sizeof(buffer), "%d", (int)data);
285 	setString(key, buffer);
286 }
287 
288 
289 /** Setting Float data with key */
290 
291 void
292 PrefHandler::setFloat(const char *key, float data)
293 {
294 	char buffer[32];
295 	snprintf(buffer, sizeof(buffer), "%g", data);
296 	setString(key, buffer);
297 }
298 
299 
300 /** Setting Bool data with key */
301 
302 void
303 PrefHandler::setBool(const char *key, bool data)
304 {
305 	if (data)
306 		setString(key, PREF_TRUE);
307 	else
308 		setString(key, PREF_FALSE);
309 }
310 
311 
312 /** Setting CString data with key */
313 
314 void
315 PrefHandler::setString(const char *key, const char *data)
316 {
317 	//printf("%x SET %s: %s\n", this, key, data);
318 	fContainer.RemoveName(key);
319 	fContainer.AddString(key, data);
320 }
321 
322 
323 /** Setting RGB data with key */
324 
325 void
326 PrefHandler::setRGB(const char *key, const rgb_color data)
327 {
328 	char buffer[32];
329 	snprintf(buffer, sizeof(buffer), "%d, %d, %d", data.red, data.green, data.blue);
330 	setString(key, buffer);
331 }
332 
333 
334 /** Check any peference stored or not. */
335 
336 bool
337 PrefHandler::IsEmpty() const
338 {
339 	return fContainer.IsEmpty();
340 }
341 
342 
343 void
344 PrefHandler::_ConfirmFont(const char *key, const BFont *fallback)
345 {
346 	int32 count = count_font_families();
347 	const char *font = getString(key);
348 	if (font == NULL)
349 		count = 0;
350 
351 	font_family family;
352 
353 	for (int32 i = 0; i < count; i++) {
354 		if (get_font_family(i, &family) != B_OK)
355 			continue;
356 
357 		if (!strcmp(family, font)) {
358 			// found font family: we can safely use this font
359 			return;
360 		}
361 	}
362 
363 	// use fall-back font
364 
365 	fallback->GetFamilyAndStyle(&family, NULL);
366 	setString(key, family);
367 }
368 
369 
370 status_t
371 PrefHandler::_LoadFromFile(const char* path)
372 {
373 	// Future: It would be nice if we could simply use a flatened BMessage to
374 	// save the settings. (Who cares about compatibility in this case anyway?)
375 
376 	BFile file(path, B_READ_ONLY);
377 	status_t status = file.InitCheck();
378 	if (status != B_OK)
379 		return status;
380 
381 	//fContainer.MakeEmpty();
382 	//fContainer.Unflatten(&file);
383 
384 	off_t size;
385 	if (file.GetSize(&size) != B_OK || size != sizeof(struct termprefs))
386 		return B_ERROR;
387 
388 	struct termprefs prefs;
389 	file.Read(&prefs, size);
390 	if (prefs.magic != TP_MAGIC || prefs.version != TP_VERSION)
391 		return B_ERROR;
392 
393 	// Valid settings file!
394 
395 	setInt32(PREF_COLS, prefs.cols);
396 	setInt32(PREF_ROWS, prefs.rows);
397 	setInt32(PREF_HALF_FONT_SIZE, prefs.font_size);
398 	char *font_family = strtok(prefs.font, "/");
399 	char *font_style = strtok(NULL, "");
400 	setString(PREF_HALF_FONT_FAMILY, font_family);
401 	setString(PREF_HALF_FONT_STYLE, font_style);
402 	setRGB(PREF_TEXT_BACK_COLOR, prefs.bg);
403 	setRGB(PREF_TEXT_FORE_COLOR, prefs.fg);
404 	setRGB(PREF_CURSOR_BACK_COLOR, prefs.curbg);
405 	setRGB(PREF_CURSOR_FORE_COLOR, prefs.curfg);
406 	setRGB(PREF_SELECT_BACK_COLOR, prefs.selbg);
407 	setRGB(PREF_SELECT_FORE_COLOR, prefs.selfg);
408 	setString(PREF_TEXT_ENCODING, EncodingAsString(prefs.encoding));
409 
410 	return B_OK;
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