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