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