API  0.9.6
 All Classes Files Functions Variables Macros Groups Pages
CPUserDefaultsController.j
Go to the documentation of this file.
1 /*
2  * CPUserDefaultsController.j
3  * AppKit
4  *
5  * Portions based on NSUserDefaultsController.m (2009-06-04) in Cocotron (http://www.cocotron.org/)
6  * Copyright (c) 2006-2007 Christopher J. W. Lloyd
7  *
8  * Created by Alexander Ljungberg.
9  * Copyright 2011, WireLoad Inc.
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2.1 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24  */
25 
26 
27 
29 
30 @implementation CPUserDefaultsController : CPController
31 {
32  CPUserDefaults _defaults;
33  CPDictionary _initialValues;
34  BOOL _appliesImmediately;
35 }
36 
37 + (id)sharedUserDefaultsController
38 {
41 
43 }
44 
45 - (id)initWithDefaults:(CPUserDefaults)someDefaults initialValues:(CPDictionary)initialValues
46 {
47  if (self = [super init])
48  {
49  if (!someDefaults)
50  someDefaults = [CPUserDefaults standardUserDefaults];
51 
52  _defaults = someDefaults;
53  _initialValues = [initialValues copy];
54  _appliesImmediately = YES;
55  _valueProxy = [[_CPUserDefaultsControllerProxy alloc] initWithController:self];
56  }
57 
58  return self;
59 }
60 
61 - (id)values
62 {
63  return _valueProxy;
64 }
65 
66 - (BOOL)hasUnappliedChanges
67 {
68  return [_valueProxy hasUnappliedChanges];
69 }
70 
71 - (void)save:(id)sender
72 {
73  [_valueProxy save];
74 }
75 
76 - (void)revert:(id)sender
77 {
78  [_valueProxy revert];
79 }
80 
81 - (void)revertToInitialValues:(id)sender
82 {
83  [_valueProxy revertToInitialValues];
84 }
85 
86 @end
87 
88 
89 var CPUserDefaultsControllerSharedKey = "CPUserDefaultsControllerSharedKey";
90 
92 
93 - (id)initWithCoder:(CPCoder)aCoder
94 {
95  if ([aCoder decodeBoolForKey:CPUserDefaultsControllerSharedKey])
97 
98  self = [super initWithCoder:aCoder];
99 
100  if (self)
101  {
102  [CPException raise:CPUnsupportedMethodException reason:@"decoding of non-shared CPUserDefaultsController not implemented"];
103  }
104 
105  return self;
106 }
107 
108 - (void)encodeWithCoder:(CPCoder)aCoder
109 {
110  [super encodeWithCoder:aCoder];
111 
112  if (self === SharedUserDefaultsController)
113  {
114  [aCoder encodeBool:YES forKey:CPUserDefaultsControllerSharedKey];
115  return;
116  }
117 
118  [CPException raise:CPUnsupportedMethodException reason:@"encoding of non-shared CPUserDefaultsController not implemented"];
119 }
120 
121 @end
122 
123 
124 @implementation _CPUserDefaultsControllerProxy : CPObject
125 {
126  CPUserDefaultsController _controller;
127  // TODO Could be optimised with a JS dict.
128  CPMutableDictionary _cachedValues;
129 }
130 
131 - (id)initWithController:(CPUserDefaultsController)aController
132 {
133  if (self = [super init])
134  {
135  _controller = aController;
136  _cachedValues = [CPMutableDictionary dictionary];
137 
138  [[CPNotificationCenter defaultCenter] addObserver:self selector:@selector(userDefaultsDidChange:) name:CPUserDefaultsDidChangeNotification object:[_controller defaults]];
139  }
140 
141  return self;
142 }
143 
144 - (void)dealloc
145 {
146  // FIXME No dealloc in Cappuccino.
148  [super dealloc];
149 }
150 
151 - (id)valueForKey:(CPString)aKey
152 {
153  var value = [_cachedValues objectForKey:aKey];
154  if (value === nil)
155  {
156  value = [[_controller defaults] objectForKey:aKey];
157  if (value === nil)
158  value = [[_controller initialValues] objectForKey:aKey];
159 
160  if (value !== nil)
161  [_cachedValues setObject:value forKey:aKey];
162  }
163  return value;
164 }
165 
166 - (void)setValue:(id)aValue forKey:(CPString)aKey
167 {
168  [self willChangeValueForKey:aKey];
169  [_cachedValues setObject:aValue forKey:aKey];
170  if ([_controller appliesImmediately])
171  [[_controller defaults] setObject:aValue forKey:aKey];
172  [self didChangeValueForKey:aKey];
173 }
174 
175 
176 - (void)revert
177 {
178  var keys = [_cachedValues allKeys],
179  keysCount = [keys count];
180 
181  while (keysCount--)
182  {
183  var key = keys[keysCount];
184  [self willChangeValueForKey:key];
185  [_cachedValues removeObjectForKey:key];
186  [self didChangeValueForKey:key];
187  }
188 }
189 
190 - (void)save
191 {
192  var keys = [_cachedValues allKeys],
193  keysCount = [keys count];
194 
195  while (keysCount--)
196  {
197  var key = keys[keysCount];
198  [[_controller defaults] setObject:[_cachedValues objectForKey:key] forKey:key];
199  }
200 }
201 
202 - (void)revertToInitialValues
203 {
204  var initial = [_controller initialValues],
205  keys = [_cachedValues allKeys],
206  keysCount = [keys count];
207 
208  while (keysCount--)
209  {
210  var key = keys[keysCount];
211  [self willChangeValueForKey:key];
212 
213  var initialValue = [initial objectForKey:key];
214  if (initialValue !== nil)
215  [_cachedValues setObject:initialValue forKey:key];
216  else
217  [_cachedValues removeObjectForKey:key];
218 
219  [self didChangeValueForKey:key];
220 
221  }
222 }
223 
224 - (void)userDefaultsDidChange:(CPNotification)aNotification
225 {
226  var defaults = [_controller defaults],
227  keys = [_cachedValues allKeys],
228  keysCount = [keys count];
229 
230  while (keysCount--)
231  {
232  var key = keys[keysCount],
233  value = [_cachedValues objectForKey:key],
234  newValue = [defaults objectForKey:key];
235 
236  if (![value isEqual:newValue])
237  {
238  [self willChangeValueForKey:key];
239  [_cachedValues setObject:newValue forKey:key];
240  [self didChangeValueForKey:key];
241  }
242  }
243 }
244 
245 - (BOOL)hasUnappliedChanges
246 {
247  var defaults = [_controller defaults],
248  keys = [_cachedValues allKeys],
249  keysCount = [keys count];
250 
251  while (keysCount--)
252  {
253  var key = keys[keysCount],
254  value = [_cachedValues objectForKey:key],
255  newValue = [defaults objectForKey:key];
256 
257  if (![value isEqual:newValue])
258  return YES;
259  }
260 
261  return NO;
262 }
263 
264 @end
265 
266 
268 
272 - (CPUserDefaults)defaults
273 {
274  return _defaults;
275 }
276 
280 - (CPDictionary)initialValues
281 {
282  return _initialValues;
283 }
284 
288 - (void)setInitialValues:(CPDictionary)aValue
289 {
290  _initialValues = aValue;
291 }
292 
296 - (BOOL)appliesImmediately
297 {
298  return _appliesImmediately;
299 }
300 
304 - (void)setAppliesImmediately:(BOOL)aValue
305 {
306  _appliesImmediately = aValue;
307 }
308 
309 @end