1/*
2 * Copyright 2008-2010, Stephan Aßmus <superstippi@gmx.de>.
3 * Copyright 1998, Eric Shepherd.
4 * All rights reserved. Distributed under the terms of the Be Sample Code
5 * license.
6 */
7
8//! Be Newsletter Volume II, Issue 35; September 2, 1998 (Eric Shepherd)
9
10#include "SettingsMessage.h"
11
12#include <new>
13
14#include <Autolock.h>
15#include <Entry.h>
16#include <File.h>
17#include <Messenger.h>
18#include <String.h>
19
20
21SettingsMessage::SettingsMessage(directory_which directory,
22		const char* filename)
23	:
24	BMessage('pref'),
25	fListeners(4)
26{
27	fStatus = find_directory(directory, &fPath);
28
29	if (fStatus == B_OK)
30		fStatus = fPath.Append(filename);
31
32	if (fStatus == B_OK)
33		fStatus = Load();
34}
35
36
37SettingsMessage::~SettingsMessage()
38{
39	Save();
40
41	for (int32 i = fListeners.CountItems() - 1; i >= 0; i--)
42		delete reinterpret_cast<BMessenger*>(fListeners.ItemAtFast(i));
43}
44
45
46status_t
47SettingsMessage::InitCheck() const
48{
49	return fStatus;
50}
51
52
53status_t
54SettingsMessage::Load()
55{
56	BAutolock _(this);
57
58	BFile file(fPath.Path(), B_READ_ONLY);
59	status_t status = file.InitCheck();
60
61	if (status == B_OK)
62		status = Unflatten(&file);
63
64	return status;
65}
66
67
68status_t
69SettingsMessage::Save() const
70{
71	BAutolock _(const_cast<SettingsMessage*>(this));
72
73	BFile file(fPath.Path(), B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE);
74	status_t status = file.InitCheck();
75
76	if (status == B_OK)
77		status = Flatten(&file);
78
79	return status;
80}
81
82
83bool
84SettingsMessage::AddListener(const BMessenger& listener)
85{
86	BAutolock _(this);
87
88	BMessenger* listenerCopy = new(std::nothrow) BMessenger(listener);
89	if (listenerCopy && fListeners.AddItem(listenerCopy))
90		return true;
91	delete listenerCopy;
92	return false;
93}
94
95
96void
97SettingsMessage::RemoveListener(const BMessenger& listener)
98{
99	BAutolock _(this);
100
101	for (int32 i = fListeners.CountItems() - 1; i >= 0; i--) {
102		BMessenger* listenerItem = reinterpret_cast<BMessenger*>(
103			fListeners.ItemAtFast(i));
104		if (*listenerItem == listener) {
105			fListeners.RemoveItem(i);
106			delete listenerItem;
107			return;
108		}
109	}
110}
111
112
113// #pragma mark -
114
115
116status_t
117SettingsMessage::SetValue(const char* name, bool value)
118{
119	status_t ret = ReplaceBool(name, value);
120	if (ret != B_OK)
121		ret = AddBool(name, value);
122	if (ret == B_OK)
123		_NotifyValueChanged(name);
124	return ret;
125}
126
127
128status_t
129SettingsMessage::SetValue(const char* name, int8 value)
130{
131	status_t ret = ReplaceInt8(name, value);
132	if (ret != B_OK)
133		ret = AddInt8(name, value);
134	if (ret == B_OK)
135		_NotifyValueChanged(name);
136	return ret;
137}
138
139
140status_t
141SettingsMessage::SetValue(const char* name, int16 value)
142{
143	status_t ret = ReplaceInt16(name, value);
144	if (ret != B_OK)
145		ret = AddInt16(name, value);
146	if (ret == B_OK)
147		_NotifyValueChanged(name);
148	return ret;
149}
150
151
152status_t
153SettingsMessage::SetValue(const char* name, int32 value)
154{
155	status_t ret = ReplaceInt32(name, value);
156	if (ret != B_OK)
157		ret = AddInt32(name, value);
158	if (ret == B_OK)
159		_NotifyValueChanged(name);
160	return ret;
161}
162
163
164status_t
165SettingsMessage::SetValue(const char* name, uint32 value)
166{
167	status_t ret = ReplaceUInt32(name, value);
168	if (ret != B_OK)
169		ret = AddUInt32(name, value);
170	if (ret == B_OK)
171		_NotifyValueChanged(name);
172	return ret;
173}
174
175
176status_t
177SettingsMessage::SetValue(const char* name, int64 value)
178{
179	status_t ret = ReplaceInt64(name, value);
180	if (ret != B_OK)
181		ret = AddInt64(name, value);
182	if (ret == B_OK)
183		_NotifyValueChanged(name);
184	return ret;
185}
186
187
188status_t
189SettingsMessage::SetValue(const char* name, float value)
190{
191	status_t ret = ReplaceFloat(name, value);
192	if (ret != B_OK)
193		ret = AddFloat(name, value);
194	if (ret == B_OK)
195		_NotifyValueChanged(name);
196	return ret;
197}
198
199
200status_t
201SettingsMessage::SetValue(const char* name, double value)
202{
203	status_t ret = ReplaceDouble(name, value);
204	if (ret != B_OK)
205		ret = AddDouble(name, value);
206	if (ret == B_OK)
207		_NotifyValueChanged(name);
208	return ret;
209}
210
211
212status_t
213SettingsMessage::SetValue(const char* name, const char* value)
214{
215	status_t ret = ReplaceString(name, value);
216	if (ret != B_OK)
217		ret = AddString(name, value);
218	if (ret == B_OK)
219		_NotifyValueChanged(name);
220	return ret;
221}
222
223
224status_t
225SettingsMessage::SetValue(const char* name, const BString& value)
226{
227	status_t ret = ReplaceString(name, value);
228	if (ret != B_OK)
229		ret = AddString(name, value);
230	if (ret == B_OK)
231		_NotifyValueChanged(name);
232	return ret;
233}
234
235
236status_t
237SettingsMessage::SetValue(const char* name, const BPoint& value)
238{
239	status_t ret = ReplacePoint(name, value);
240	if (ret != B_OK)
241		ret = AddPoint(name, value);
242	if (ret == B_OK)
243		_NotifyValueChanged(name);
244	return ret;
245}
246
247
248status_t
249SettingsMessage::SetValue(const char* name, const BRect& value)
250{
251	status_t ret = ReplaceRect(name, value);
252	if (ret != B_OK)
253		ret = AddRect(name, value);
254	if (ret == B_OK)
255		_NotifyValueChanged(name);
256	return ret;
257}
258
259
260status_t
261SettingsMessage::SetValue(const char* name, const entry_ref& value)
262{
263	status_t ret = ReplaceRef(name, &value);
264	if (ret != B_OK)
265		ret = AddRef(name, &value);
266	if (ret == B_OK)
267		_NotifyValueChanged(name);
268	return ret;
269}
270
271
272status_t
273SettingsMessage::SetValue(const char* name, const BMessage& value)
274{
275	status_t ret = ReplaceMessage(name, &value);
276	if (ret != B_OK)
277		ret = AddMessage(name, &value);
278	if (ret == B_OK)
279		_NotifyValueChanged(name);
280	return ret;
281}
282
283
284status_t
285SettingsMessage::SetValue(const char* name, const BFlattenable* value)
286{
287	status_t ret = ReplaceFlat(name, const_cast<BFlattenable*>(value));
288	if (ret != B_OK)
289		ret = AddFlat(name, const_cast<BFlattenable*>(value));
290	if (ret == B_OK)
291		_NotifyValueChanged(name);
292	return ret;
293}
294
295
296status_t
297SettingsMessage::SetValue(const char* name, const BFont& value)
298{
299	font_family family;
300	font_style style;
301	value.GetFamilyAndStyle(&family, &style);
302
303	BMessage fontMessage;
304	status_t ret = fontMessage.AddString("family", family);
305	if (ret == B_OK)
306		ret = fontMessage.AddString("style", style);
307	if (ret == B_OK)
308		ret = fontMessage.AddFloat("size", value.Size());
309
310	if (ret == B_OK) {
311		if (ReplaceMessage(name, &fontMessage) != B_OK)
312			ret = AddMessage(name, &fontMessage);
313	}
314	if (ret == B_OK)
315		_NotifyValueChanged(name);
316	return ret;
317}
318
319
320// #pragma mark -
321
322
323bool
324SettingsMessage::GetValue(const char* name, bool defaultValue) const
325{
326	bool value;
327	if (FindBool(name, &value) != B_OK)
328		return defaultValue;
329	return value;
330}
331
332
333int8
334SettingsMessage::GetValue(const char* name, int8 defaultValue) const
335{
336	int8 value;
337	if (FindInt8(name, &value) != B_OK)
338		return defaultValue;
339	return value;
340}
341
342
343int16
344SettingsMessage::GetValue(const char* name, int16 defaultValue) const
345{
346	int16 value;
347	if (FindInt16(name, &value) != B_OK)
348		return defaultValue;
349	return value;
350}
351
352
353int32
354SettingsMessage::GetValue(const char* name, int32 defaultValue) const
355{
356	int32 value;
357	if (FindInt32(name, &value) != B_OK)
358		return defaultValue;
359	return value;
360}
361
362
363uint32
364SettingsMessage::GetValue(const char* name, uint32 defaultValue) const
365{
366	uint32 value;
367	if (FindUInt32(name, &value) != B_OK)
368		return defaultValue;
369	return value;
370}
371
372
373int64
374SettingsMessage::GetValue(const char* name, int64 defaultValue) const
375{
376	int64 value;
377	if (FindInt64(name, &value) != B_OK)
378		return defaultValue;
379	return value;
380}
381
382
383float
384SettingsMessage::GetValue(const char* name, float defaultValue) const
385{
386	float value;
387	if (FindFloat(name, &value) != B_OK)
388		return defaultValue;
389	return value;
390}
391
392
393double
394SettingsMessage::GetValue(const char* name, double defaultValue) const
395{
396	double value;
397	if (FindDouble(name, &value) != B_OK)
398		return defaultValue;
399	return value;
400}
401
402
403BString
404SettingsMessage::GetValue(const char* name, const BString& defaultValue) const
405{
406	BString value;
407	if (FindString(name, &value) != B_OK)
408		return defaultValue;
409	return value;
410}
411
412
413const char*
414SettingsMessage::GetValue(const char* name, const char* defaultValue) const
415{
416	const char* value;
417	if (FindString(name, &value) != B_OK)
418		return defaultValue;
419	return value;
420}
421
422
423BPoint
424SettingsMessage::GetValue(const char *name, BPoint defaultValue) const
425{
426	BPoint value;
427	if (FindPoint(name, &value) != B_OK)
428		return defaultValue;
429	return value;
430}
431
432
433BRect
434SettingsMessage::GetValue(const char* name, BRect defaultValue) const
435{
436	BRect value;
437	if (FindRect(name, &value) != B_OK)
438		return defaultValue;
439	return value;
440}
441
442
443entry_ref
444SettingsMessage::GetValue(const char* name, const entry_ref& defaultValue) const
445{
446	entry_ref value;
447	if (FindRef(name, &value) != B_OK)
448		return defaultValue;
449	return value;
450}
451
452
453BMessage
454SettingsMessage::GetValue(const char* name, const BMessage& defaultValue) const
455{
456	BMessage value;
457	if (FindMessage(name, &value) != B_OK)
458		return defaultValue;
459	return value;
460}
461
462
463BFont
464SettingsMessage::GetValue(const char* name, const BFont& defaultValue) const
465{
466	BMessage fontMessage;
467	if (FindMessage(name, &fontMessage) != B_OK)
468		return defaultValue;
469
470	const char* family;
471	const char* style;
472	float size;
473	if (fontMessage.FindString("family", &family) != B_OK
474		|| fontMessage.FindString("style", &style) != B_OK
475		|| fontMessage.FindFloat("size", &size) != B_OK) {
476		return defaultValue;
477	}
478
479	BFont value;
480	if (value.SetFamilyAndStyle(family, style) != B_OK)
481		return defaultValue;
482
483	value.SetSize(size);
484
485	return value;
486}
487
488
489// #pragma mark - private
490
491
492void
493SettingsMessage::_NotifyValueChanged(const char* name) const
494{
495	BMessage message(SETTINGS_VALUE_CHANGED);
496	message.AddString("name", name);
497
498	// Add the value of that name to the notification.
499	type_code type;
500	if (GetInfo(name, &type) == B_OK) {
501		const void* data;
502		ssize_t numBytes;
503		if (FindData(name, type, &data, &numBytes) == B_OK)
504			message.AddData("value", type, data, numBytes);
505	}
506
507	int32 count = fListeners.CountItems();
508	for (int32 i = 0; i < count; i++) {
509		BMessenger* listener = reinterpret_cast<BMessenger*>(
510			fListeners.ItemAtFast(i));
511		listener->SendMessage(&message);
512	}
513}
514
515