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