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