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