xref: /haiku/src/add-ons/translators/shared/TranslatorSettings.cpp (revision 4c8e85b316c35a9161f5a1c50ad70bc91c83a76f)
1 /*****************************************************************************/
2 // TranslatorSettings
3 // Written by Michael Wilber, Haiku Translation Kit Team
4 //
5 // TranslatorSettings.cpp
6 //
7 // This class manages (saves/loads/locks/unlocks) the settings
8 // for a Translator.
9 //
10 //
11 // Copyright (c) 2004 Haiku Project
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining a
14 // copy of this software and associated documentation files (the "Software"),
15 // to deal in the Software without restriction, including without limitation
16 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
17 // and/or sell copies of the Software, and to permit persons to whom the
18 // Software is furnished to do so, subject to the following conditions:
19 //
20 // The above copyright notice and this permission notice shall be included
21 // in all copies or substantial portions of the Software.
22 //
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 // DEALINGS IN THE SOFTWARE.
30 /*****************************************************************************/
31 
32 #include <string.h>
33 #include <File.h>
34 #include <FindDirectory.h>
35 #include <TranslatorFormats.h>
36 	// for B_TRANSLATOR_EXT_*
37 #include "TranslatorSettings.h"
38 
39 // ---------------------------------------------------------------
40 // Constructor
41 //
42 // Sets the default settings, location for the settings file
43 // and sets the reference count to 1
44 //
45 // Preconditions:
46 //
47 // Parameters:
48 //
49 // Postconditions:
50 //
51 // Returns:
52 // ---------------------------------------------------------------
53 TranslatorSettings::TranslatorSettings(const char *settingsFile,
54 	const TranSetting *defaults, int32 defCount)
55 	: fLock("TranslatorSettings Lock")
56 {
57 	if (find_directory(B_USER_SETTINGS_DIRECTORY, &fSettingsPath))
58 		fSettingsPath.SetTo("/tmp");
59 	fSettingsPath.Append(settingsFile);
60 
61 	fRefCount = 1;
62 
63 	if (defCount > 0) {
64 		fDefaults = defaults;
65 		fDefCount = defCount;
66 	} else {
67 		fDefaults = NULL;
68 		fDefCount = 0;
69 	}
70 
71 	// Add Default Settings
72 	// (Used when loading from the settings file or from
73 	// a BMessage fails)
74 	const TranSetting *defs = fDefaults;
75 	for (int32 i = 0; i < fDefCount; i++) {
76 		switch (defs[i].dataType) {
77 			case TRAN_SETTING_BOOL:
78 				fSettingsMsg.AddBool(defs[i].name,
79 					static_cast<bool>(defs[i].defaultVal));
80 				break;
81 
82 			case TRAN_SETTING_INT32:
83 				fSettingsMsg.AddInt32(defs[i].name, defs[i].defaultVal);
84 				break;
85 
86 			default:
87 				// ASSERT here? Erase the bogus setting entry instead?
88 				break;
89 		}
90 	}
91 }
92 
93 // ---------------------------------------------------------------
94 // Acquire
95 //
96 // Returns a pointer to the TranslatorSettings and increments
97 // the reference count.
98 //
99 // Preconditions:
100 //
101 // Parameters:
102 //
103 // Postconditions:
104 //
105 // Returns: pointer to this TranslatorSettings object
106 // ---------------------------------------------------------------
107 TranslatorSettings *
108 TranslatorSettings::Acquire()
109 {
110 	TranslatorSettings *psettings = NULL;
111 
112 	fLock.Lock();
113 	fRefCount++;
114 	psettings = this;
115 	fLock.Unlock();
116 
117 	return psettings;
118 }
119 
120 // ---------------------------------------------------------------
121 // Release
122 //
123 // Decrements the reference count and deletes the
124 // TranslatorSettings if the reference count is zero.
125 //
126 // Preconditions:
127 //
128 // Parameters:
129 //
130 // Postconditions:
131 //
132 // Returns: pointer to this TranslatorSettings object if
133 // the reference count is greater than zero, returns NULL
134 // if the reference count is zero and the TranslatorSettings
135 // object has been deleted
136 // ---------------------------------------------------------------
137 TranslatorSettings *
138 TranslatorSettings::Release()
139 {
140 	TranslatorSettings *psettings = NULL;
141 
142 	fLock.Lock();
143 	fRefCount--;
144 	if (fRefCount > 0) {
145 		psettings = this;
146 		fLock.Unlock();
147 	} else
148 		delete this;
149 			// delete this object and
150 			// release locks
151 
152 	return psettings;
153 }
154 
155 // ---------------------------------------------------------------
156 // Destructor
157 //
158 // Does nothing!
159 //
160 // Preconditions:
161 //
162 // Parameters:
163 //
164 // Postconditions:
165 //
166 // Returns:
167 // ---------------------------------------------------------------
168 TranslatorSettings::~TranslatorSettings()
169 {
170 }
171 
172 // ---------------------------------------------------------------
173 // LoadSettings
174 //
175 // Loads the settings by reading them from the default
176 // settings file.
177 //
178 // Preconditions:
179 //
180 // Parameters:
181 //
182 // Postconditions:
183 //
184 // Returns: B_OK if there were no errors or an error code from
185 // BFile::SetTo() or BMessage::Unflatten() if there were errors
186 // ---------------------------------------------------------------
187 status_t
188 TranslatorSettings::LoadSettings()
189 {
190 	status_t result;
191 
192 	fLock.Lock();
193 
194 	// Don't try to open the settings file if there are
195 	// no settings that need to be loaded
196 	if (fDefCount > 0) {
197 		BFile settingsFile;
198 		result = settingsFile.SetTo(fSettingsPath.Path(), B_READ_ONLY);
199 		if (result == B_OK) {
200 			BMessage msg;
201 			result = msg.Unflatten(&settingsFile);
202 			if (result == B_OK)
203 				result = LoadSettings(&msg);
204 		}
205 	} else
206 		result = B_OK;
207 
208 	fLock.Unlock();
209 
210 	return result;
211 }
212 
213 // ---------------------------------------------------------------
214 // LoadSettings
215 //
216 // Loads the settings from a BMessage passed to the function.
217 //
218 // Preconditions:
219 //
220 // Parameters:	pmsg	pointer to BMessage that contains the
221 //						settings
222 //
223 // Postconditions:
224 //
225 // Returns: B_BAD_VALUE if pmsg is NULL or invalid options
226 // have been found, B_OK if there were no
227 // errors or an error code from BMessage::FindBool() or
228 // BMessage::ReplaceBool() if there were other errors
229 // ---------------------------------------------------------------
230 status_t
231 TranslatorSettings::LoadSettings(BMessage *pmsg)
232 {
233 	if (pmsg == NULL)
234 		return B_BAD_VALUE;
235 
236 	fLock.Lock();
237 	const TranSetting *defaults = fDefaults;
238 	for (int32 i = 0; i < fDefCount; i++) {
239 		switch (defaults[i].dataType) {
240 			case TRAN_SETTING_BOOL:
241 			{
242 				bool value;
243 				if (pmsg->FindBool(defaults[i].name, &value) != B_OK) {
244 					if (fSettingsMsg.HasBool(defaults[i].name))
245 						break;
246 					else
247 						value = static_cast<bool>(defaults[i].defaultVal);
248 				}
249 
250 				fSettingsMsg.ReplaceBool(defaults[i].name, value);
251 				break;
252 			}
253 
254 			case TRAN_SETTING_INT32:
255 			{
256 				int32 value;
257 				if (pmsg->FindInt32(defaults[i].name, &value) != B_OK) {
258 					if (fSettingsMsg.HasInt32(defaults[i].name))
259 						break;
260 					else
261 						value = defaults[i].defaultVal;
262 				}
263 
264 				fSettingsMsg.ReplaceInt32(defaults[i].name, value);
265 				break;
266 			}
267 
268 			default:
269 				// TODO: ASSERT here? Erase the bogus setting entry instead?
270 				break;
271 		}
272 	}
273 
274 	fLock.Unlock();
275 	return B_OK;
276 }
277 
278 // ---------------------------------------------------------------
279 // SaveSettings
280 //
281 // Saves the settings as a flattened BMessage to the default
282 // settings file
283 //
284 // Preconditions:
285 //
286 // Parameters:
287 //
288 // Postconditions:
289 //
290 // Returns: B_OK if no errors or an error code from BFile::SetTo()
291 // or BMessage::Flatten() if there were errors
292 // ---------------------------------------------------------------
293 status_t
294 TranslatorSettings::SaveSettings()
295 {
296 	status_t result;
297 
298 	fLock.Lock();
299 
300 	// Only write out settings file if there are
301 	// actual settings stored by this object
302 	if (fDefCount > 0) {
303 		BFile settingsFile;
304 		result = settingsFile.SetTo(fSettingsPath.Path(),
305 			B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE);
306 		if (result == B_OK)
307 			result = fSettingsMsg.Flatten(&settingsFile);
308 	} else
309 		result = B_OK;
310 
311 	fLock.Unlock();
312 
313 	return result;
314 }
315 
316 // ---------------------------------------------------------------
317 // GetConfigurationMessage
318 //
319 // Saves the current settings to the BMessage passed to the
320 // function
321 //
322 // Preconditions:
323 //
324 // Parameters:	pmsg	pointer to BMessage where the settings
325 //						will be stored
326 //
327 // Postconditions:
328 //
329 // Returns: B_OK if there were no errors or an error code from
330 // BMessage::RemoveName() or BMessage::AddBool() if there were
331 // errors
332 // ---------------------------------------------------------------
333 status_t
334 TranslatorSettings::GetConfigurationMessage(BMessage *pmsg)
335 {
336 	status_t result = B_BAD_VALUE;
337 
338 	if (pmsg) {
339 		int32 i;
340 		for (i = 0; i < fDefCount; i++) {
341 			result = pmsg->RemoveName(fDefaults[i].name);
342 			if (result != B_OK && result != B_NAME_NOT_FOUND)
343 				break;
344 		}
345 		if (i == fDefCount) {
346 			fLock.Lock();
347 			result = B_OK;
348 
349 			const TranSetting *defs = fDefaults;
350 			for (i = 0; i < fDefCount && result >= B_OK; i++) {
351 				switch (defs[i].dataType) {
352 					case TRAN_SETTING_BOOL:
353 						result = pmsg->AddBool(defs[i].name,
354 							SetGetBool(defs[i].name));
355 						break;
356 
357 					case TRAN_SETTING_INT32:
358 						result = pmsg->AddInt32(defs[i].name,
359 							SetGetInt32(defs[i].name));
360 						break;
361 
362 					default:
363 						// ASSERT here? Erase the bogus setting entry instead?
364 						break;
365 				}
366 			}
367 
368 			fLock.Unlock();
369 		}
370 	}
371 
372 	return result;
373 }
374 
375 // ---------------------------------------------------------------
376 // FindTranSetting
377 //
378 // Returns a pointer to the TranSetting with the given name
379 //
380 //
381 // Preconditions:
382 //
383 // Parameters:	name	name of the TranSetting to find
384 //
385 //
386 // Postconditions:
387 //
388 // Returns: NULL if the TranSetting cannot be found, or a pointer
389 //          to the desired TranSetting if it is found
390 // ---------------------------------------------------------------
391 const TranSetting *
392 TranslatorSettings::FindTranSetting(const char *name)
393 {
394 	for (int32 i = 0; i < fDefCount; i++) {
395 		if (!strcmp(fDefaults[i].name, name))
396 			return fDefaults + i;
397 	}
398 	return NULL;
399 }
400 
401 // ---------------------------------------------------------------
402 // SetGetBool
403 //
404 // Sets the state of the bool setting identified by the given name
405 //
406 //
407 // Preconditions:
408 //
409 // Parameters:	name	identifies the setting to set or get
410 //
411 //				pbool	the new value for the bool, or, if null,
412 //						it indicates that the caller wants to Get
413 //						rather than Set
414 //
415 // Postconditions:
416 //
417 // Returns: the prior value of the setting
418 // ---------------------------------------------------------------
419 bool
420 TranslatorSettings::SetGetBool(const char *name, bool *pbool)
421 {
422 	bool bprevValue;
423 
424 	fLock.Lock();
425 
426 	const TranSetting *def = FindTranSetting(name);
427 	if (def) {
428 		fSettingsMsg.FindBool(def->name, &bprevValue);
429 		if (pbool)
430 			fSettingsMsg.ReplaceBool(def->name, *pbool);
431 	} else
432 		bprevValue = false;
433 
434 	fLock.Unlock();
435 
436 	return bprevValue;
437 }
438 
439 // ---------------------------------------------------------------
440 // SetGetInt32
441 //
442 // Sets the state of the int32 setting identified by the given name
443 //
444 //
445 // Preconditions:
446 //
447 // Parameters:	name	identifies the setting to set or get
448 //
449 //				pint32	the new value for the setting, or, if null,
450 //						it indicates that the caller wants to Get
451 //						rather than Set
452 //
453 // Postconditions:
454 //
455 // Returns: the prior value of the setting
456 // ---------------------------------------------------------------
457 int32
458 TranslatorSettings::SetGetInt32(const char *name, int32 *pint32)
459 {
460 	int32 prevValue;
461 
462 	fLock.Lock();
463 
464 	const TranSetting *def = FindTranSetting(name);
465 	if (def) {
466 		fSettingsMsg.FindInt32(def->name, &prevValue);
467 		if (pint32)
468 			fSettingsMsg.ReplaceInt32(def->name, *pint32);
469 	} else
470 		prevValue = 0;
471 
472 	fLock.Unlock();
473 
474 	return prevValue;
475 }
476 
477