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(0)
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, uint16 value)
154{
155	status_t ret = ReplaceUInt16(name, value);
156	if (ret != B_OK)
157		ret = AddUInt16(name, value);
158	if (ret == B_OK)
159		_NotifyValueChanged(name);
160	return ret;
161}
162
163
164status_t
165SettingsMessage::SetValue(const char* name, int32 value)
166{
167	status_t ret = ReplaceInt32(name, value);
168	if (ret != B_OK)
169		ret = AddInt32(name, value);
170	if (ret == B_OK)
171		_NotifyValueChanged(name);
172	return ret;
173}
174
175
176status_t
177SettingsMessage::SetValue(const char* name, uint32 value)
178{
179	status_t ret = ReplaceUInt32(name, value);
180	if (ret != B_OK)
181		ret = AddUInt32(name, value);
182	if (ret == B_BAD_TYPE && HasData(name, B_INT32_TYPE)) {
183		// For compatibility with older versions of this class, replace an int32
184		RemoveData(name);
185		ret = AddUInt32(name, value);
186	}
187	if (ret == B_OK)
188		_NotifyValueChanged(name);
189	return ret;
190}
191
192
193status_t
194SettingsMessage::SetValue(const char* name, int64 value)
195{
196	status_t ret = ReplaceInt64(name, value);
197	if (ret != B_OK)
198		ret = AddInt64(name, value);
199	if (ret == B_OK)
200		_NotifyValueChanged(name);
201	return ret;
202}
203
204
205status_t
206SettingsMessage::SetValue(const char* name, uint64 value)
207{
208	status_t ret = ReplaceUInt64(name, value);
209	if (ret != B_OK)
210		ret = AddUInt64(name, value);
211	if (ret == B_OK)
212		_NotifyValueChanged(name);
213	return ret;
214}
215
216
217status_t
218SettingsMessage::SetValue(const char* name, float value)
219{
220	status_t ret = ReplaceFloat(name, value);
221	if (ret != B_OK)
222		ret = AddFloat(name, value);
223	if (ret == B_OK)
224		_NotifyValueChanged(name);
225	return ret;
226}
227
228
229status_t
230SettingsMessage::SetValue(const char* name, double value)
231{
232	status_t ret = ReplaceDouble(name, value);
233	if (ret != B_OK)
234		ret = AddDouble(name, value);
235	if (ret == B_OK)
236		_NotifyValueChanged(name);
237	return ret;
238}
239
240
241status_t
242SettingsMessage::SetValue(const char* name, const char* value)
243{
244	status_t ret = ReplaceString(name, value);
245	if (ret != B_OK)
246		ret = AddString(name, value);
247	if (ret == B_OK)
248		_NotifyValueChanged(name);
249	return ret;
250}
251
252
253status_t
254SettingsMessage::SetValue(const char* name, const BString& value)
255{
256	status_t ret = ReplaceString(name, value);
257	if (ret != B_OK)
258		ret = AddString(name, value);
259	if (ret == B_OK)
260		_NotifyValueChanged(name);
261	return ret;
262}
263
264
265status_t
266SettingsMessage::SetValue(const char* name, const BPoint& value)
267{
268	status_t ret = ReplacePoint(name, value);
269	if (ret != B_OK)
270		ret = AddPoint(name, value);
271	if (ret == B_OK)
272		_NotifyValueChanged(name);
273	return ret;
274}
275
276
277status_t
278SettingsMessage::SetValue(const char* name, const BRect& value)
279{
280	status_t ret = ReplaceRect(name, value);
281	if (ret != B_OK)
282		ret = AddRect(name, value);
283	if (ret == B_OK)
284		_NotifyValueChanged(name);
285	return ret;
286}
287
288
289status_t
290SettingsMessage::SetValue(const char* name, const entry_ref& value)
291{
292	status_t ret = ReplaceRef(name, &value);
293	if (ret != B_OK)
294		ret = AddRef(name, &value);
295	if (ret == B_OK)
296		_NotifyValueChanged(name);
297	return ret;
298}
299
300
301status_t
302SettingsMessage::SetValue(const char* name, const BMessage& value)
303{
304	status_t ret = ReplaceMessage(name, &value);
305	if (ret != B_OK)
306		ret = AddMessage(name, &value);
307	if (ret == B_OK)
308		_NotifyValueChanged(name);
309	return ret;
310}
311
312
313status_t
314SettingsMessage::SetValue(const char* name, const BFlattenable* value)
315{
316	status_t ret = ReplaceFlat(name, const_cast<BFlattenable*>(value));
317	if (ret != B_OK)
318		ret = AddFlat(name, const_cast<BFlattenable*>(value));
319	if (ret == B_OK)
320		_NotifyValueChanged(name);
321	return ret;
322}
323
324
325status_t
326SettingsMessage::SetValue(const char* name, type_code type, const void* data,
327	ssize_t numBytes)
328{
329	status_t ret = ReplaceData(name, type, data, numBytes);
330	if (ret != B_OK)
331		ret = AddData(name, type, data, numBytes);
332	if (ret == B_OK)
333		_NotifyValueChanged(name);
334	return ret;
335}
336
337
338status_t
339SettingsMessage::SetValue(const char* name, const BFont& value)
340{
341	font_family family;
342	font_style style;
343	value.GetFamilyAndStyle(&family, &style);
344
345	BMessage fontMessage;
346	status_t ret = fontMessage.AddString("family", family);
347	if (ret == B_OK)
348		ret = fontMessage.AddString("style", style);
349	if (ret == B_OK)
350		ret = fontMessage.AddFloat("size", value.Size());
351
352	if (ret == B_OK) {
353		if (ReplaceMessage(name, &fontMessage) != B_OK)
354			ret = AddMessage(name, &fontMessage);
355	}
356	if (ret == B_OK)
357		_NotifyValueChanged(name);
358	return ret;
359}
360
361
362// #pragma mark -
363
364
365bool
366SettingsMessage::GetValue(const char* name, bool defaultValue) const
367{
368	bool value;
369	if (FindBool(name, &value) != B_OK)
370		return defaultValue;
371	return value;
372}
373
374
375int8
376SettingsMessage::GetValue(const char* name, int8 defaultValue) const
377{
378	int8 value;
379	if (FindInt8(name, &value) != B_OK)
380		return defaultValue;
381	return value;
382}
383
384
385int16
386SettingsMessage::GetValue(const char* name, int16 defaultValue) const
387{
388	int16 value;
389	if (FindInt16(name, &value) != B_OK)
390		return defaultValue;
391	return value;
392}
393
394
395uint16
396SettingsMessage::GetValue(const char* name, uint16 defaultValue) const
397{
398	uint16 value;
399	if (FindUInt16(name, &value) != B_OK)
400		return defaultValue;
401	return value;
402}
403
404
405int32
406SettingsMessage::GetValue(const char* name, int32 defaultValue) const
407{
408	int32 value;
409	if (FindInt32(name, &value) != B_OK)
410		return defaultValue;
411	return value;
412}
413
414
415uint32
416SettingsMessage::GetValue(const char* name, uint32 defaultValue) const
417{
418	uint32 value;
419	if (FindUInt32(name, &value) == B_OK)
420		return value;
421	// For compatibility with older versions of this class, also accept an int32
422	int32 signedValue;
423	if (FindInt32(name, &signedValue) == B_OK && signedValue >= 0)
424		return signedValue;
425	return defaultValue;
426}
427
428
429int64
430SettingsMessage::GetValue(const char* name, int64 defaultValue) const
431{
432	int64 value;
433	if (FindInt64(name, &value) != B_OK)
434		return defaultValue;
435	return value;
436}
437
438
439uint64
440SettingsMessage::GetValue(const char* name, uint64 defaultValue) const
441{
442	uint64 value;
443	if (FindUInt64(name, &value) != B_OK)
444		return defaultValue;
445	return value;
446}
447
448
449float
450SettingsMessage::GetValue(const char* name, float defaultValue) const
451{
452	float value;
453	if (FindFloat(name, &value) != B_OK)
454		return defaultValue;
455	return value;
456}
457
458
459double
460SettingsMessage::GetValue(const char* name, double defaultValue) const
461{
462	double value;
463	if (FindDouble(name, &value) != B_OK)
464		return defaultValue;
465	return value;
466}
467
468
469BString
470SettingsMessage::GetValue(const char* name, const BString& defaultValue) const
471{
472	BString value;
473	if (FindString(name, &value) != B_OK)
474		return defaultValue;
475	return value;
476}
477
478
479const char*
480SettingsMessage::GetValue(const char* name, const char* defaultValue) const
481{
482	const char* value;
483	if (FindString(name, &value) != B_OK)
484		return defaultValue;
485	return value;
486}
487
488
489BPoint
490SettingsMessage::GetValue(const char *name, BPoint defaultValue) const
491{
492	BPoint value;
493	if (FindPoint(name, &value) != B_OK)
494		return defaultValue;
495	return value;
496}
497
498
499BRect
500SettingsMessage::GetValue(const char* name, BRect defaultValue) const
501{
502	BRect value;
503	if (FindRect(name, &value) != B_OK)
504		return defaultValue;
505	return value;
506}
507
508
509entry_ref
510SettingsMessage::GetValue(const char* name, const entry_ref& defaultValue) const
511{
512	entry_ref value;
513	if (FindRef(name, &value) != B_OK)
514		return defaultValue;
515	return value;
516}
517
518
519BMessage
520SettingsMessage::GetValue(const char* name, const BMessage& defaultValue) const
521{
522	BMessage value;
523	if (FindMessage(name, &value) != B_OK)
524		return defaultValue;
525	return value;
526}
527
528
529BFont
530SettingsMessage::GetValue(const char* name, const BFont& defaultValue) const
531{
532	BMessage fontMessage;
533	if (FindMessage(name, &fontMessage) != B_OK)
534		return defaultValue;
535
536	const char* family;
537	const char* style;
538	float size;
539	if (fontMessage.FindString("family", &family) != B_OK
540		|| fontMessage.FindString("style", &style) != B_OK
541		|| fontMessage.FindFloat("size", &size) != B_OK) {
542		return defaultValue;
543	}
544
545	BFont value;
546	if (value.SetFamilyAndStyle(family, style) != B_OK)
547		return defaultValue;
548
549	value.SetSize(size);
550
551	return value;
552}
553
554
555void*
556SettingsMessage::GetValue(const char* name, type_code type, ssize_t numBytes,
557		const void** defaultValue) const
558{
559	void* value;
560	if (FindData(name, type, (const void**)&value, &numBytes) != B_OK)
561		return defaultValue;
562	return value;
563}
564
565
566// #pragma mark - private
567
568void
569SettingsMessage::_NotifyValueChanged(const char* name) const
570{
571	BMessage message(SETTINGS_VALUE_CHANGED);
572	message.AddString("name", name);
573
574	// Add the value of that name to the notification.
575	type_code type;
576	if (GetInfo(name, &type) == B_OK) {
577		const void* data;
578		ssize_t numBytes;
579		if (FindData(name, type, &data, &numBytes) == B_OK)
580			message.AddData("value", type, data, numBytes);
581	}
582
583	int32 count = fListeners.CountItems();
584	for (int32 i = 0; i < count; i++) {
585		BMessenger* listener = reinterpret_cast<BMessenger*>(
586			fListeners.ItemAtFast(i));
587		listener->SendMessage(&message);
588	}
589}
590