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