API 0.9.5
AppKit/CPUserDefaultsController.j
Go to the documentation of this file.
00001 /*
00002  * CPUserDefaultsController.j
00003  * AppKit
00004  *
00005  * Portions based on NSUserDefaultsController.m (2009-06-04) in Cocotron (http://www.cocotron.org/)
00006  * Copyright (c) 2006-2007 Christopher J. W. Lloyd
00007  *
00008  * Created by Alexander Ljungberg.
00009  * Copyright 2011, WireLoad Inc.
00010  *
00011  * This library is free software; you can redistribute it and/or
00012  * modify it under the terms of the GNU Lesser General Public
00013  * License as published by the Free Software Foundation; either
00014  * version 2.1 of the License, or (at your option) any later version.
00015  *
00016  * This library is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00019  * Lesser General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU Lesser General Public
00022  * License along with this library; if not, write to the Free Software
00023  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00024  */
00025 
00026 
00027 
00028 var SharedUserDefaultsController = nil;
00029 
00030 @implementation CPUserDefaultsController : CPController
00031 {
00032     CPUserDefaults  _defaults;
00033     CPDictionary    _initialValues;
00034     BOOL            _appliesImmediately;
00035 }
00036 
00037 + (id)sharedUserDefaultsController
00038 {
00039     if (!SharedUserDefaultsController)
00040         SharedUserDefaultsController = [[CPUserDefaultsController alloc] initWithDefaults:nil initialValues:nil];
00041 
00042     return SharedUserDefaultsController;
00043 }
00044 
00045 - (id)initWithDefaults:(CPUserDefaults)someDefaults initialValues:(CPDictionary)initialValues
00046 {
00047     if (self = [super init])
00048     {
00049         if (!someDefaults)
00050             someDefaults = [CPUserDefaults standardUserDefaults];
00051 
00052         _defaults = someDefaults;
00053         _initialValues = [initialValues copy];
00054         _appliesImmediately = YES;
00055         _valueProxy = [[_CPUserDefaultsControllerProxy alloc] initWithController:self];
00056     }
00057 
00058     return self;
00059 }
00060 
00061 - (id)values
00062 {
00063     return _valueProxy;
00064 }
00065 
00066 - (BOOL)hasUnappliedChanges
00067 {
00068     return [_valueProxy hasUnappliedChanges];
00069 }
00070 
00071 - (void)save:(id)sender
00072 {
00073     [_valueProxy save];
00074 }
00075 
00076 - (void)revert:(id)sender
00077 {
00078     [_valueProxy revert];
00079 }
00080 
00081 - (void)revertToInitialValues:(id)sender
00082 {
00083     [_valueProxy revertToInitialValues];
00084 }
00085 
00086 @end
00087 
00088 
00089 var CPUserDefaultsControllerSharedKey = "CPUserDefaultsControllerSharedKey";
00090 
00091 @implementation CPUserDefaultsController (CPCoding)
00092 
00093 - (id)initWithCoder:(CPCoder)aCoder
00094 {
00095     if ([aCoder decodeBoolForKey:CPUserDefaultsControllerSharedKey])
00096         return [CPUserDefaultsController sharedUserDefaultsController];
00097 
00098     self = [super initWithCoder:aCoder];
00099 
00100     if (self)
00101     {
00102         [CPException raise:CPUnsupportedMethodException reason:@"decoding of non-shared CPUserDefaultsController not implemented"];
00103     }
00104 
00105     return self;
00106 }
00107 
00108 - (void)encodeWithCoder:(CPCoder)aCoder
00109 {
00110     [super encodeWithCoder:aCoder];
00111 
00112     if (self === SharedUserDefaultsController)
00113     {
00114         [aCoder encodeBool:YES forKey:CPUserDefaultsControllerSharedKey];
00115         return;
00116     }
00117 
00118     [CPException raise:CPUnsupportedMethodException reason:@"encoding of non-shared CPUserDefaultsController not implemented"];
00119 }
00120 
00121 @end
00122 
00123 
00124 @implementation _CPUserDefaultsControllerProxy : CPObject
00125 {
00126     CPUserDefaultsController    _controller;
00127     // TODO Could be optimised with a JS dict.
00128     CPMutableDictionary         _cachedValues;
00129 }
00130 
00131 - (id)initWithController:(CPUserDefaultsController)aController
00132 {
00133     if (self = [super init])
00134     {
00135         _controller = aController;
00136         _cachedValues = [CPMutableDictionary dictionary];
00137 
00138         [[CPNotificationCenter defaultCenter] addObserver:self selector:@selector(userDefaultsDidChange:) name:CPUserDefaultsDidChangeNotification object:[_controller defaults]];
00139     }
00140 
00141     return self;
00142 }
00143 
00144 - (void)dealloc
00145 {
00146     // FIXME No dealloc in Cappuccino.
00147     [[CPNotificationCenter defaultCenter] removeObserver:self];
00148     [super dealloc];
00149 }
00150 
00151 - (id)valueForKey:(CPString)aKey
00152 {
00153     var value = [_cachedValues objectForKey:aKey];
00154     if (value === nil)
00155     {
00156         value = [[_controller defaults] objectForKey:aKey];
00157         if (value === nil)
00158             value = [[_controller initialValues] objectForKey:aKey];
00159 
00160         if (value !== nil)
00161             [_cachedValues setObject:value forKey:aKey];
00162     }
00163     return value;
00164 }
00165 
00166 - (void)setValue:(id)aValue forKey:(CPString)aKey
00167 {
00168     [self willChangeValueForKey:aKey];
00169     [_cachedValues setObject:aValue forKey:aKey];
00170     if ([_controller appliesImmediately])
00171         [[_controller defaults] setObject:aValue forKey:aKey];
00172     [self didChangeValueForKey:aKey];
00173 }
00174 
00175 
00176 - (void)revert
00177 {
00178     var keys = [_cachedValues allKeys],
00179         keysCount = [keys count];
00180 
00181     while(keysCount--)
00182     {
00183         var key = keys[keysCount];
00184         [self willChangeValueForKey:key];
00185         [_cachedValues removeObjectForKey:key];
00186         [self didChangeValueForKey:key];
00187     }
00188 }
00189 
00190 - (void)save
00191 {
00192     var keys = [_cachedValues allKeys],
00193         keysCount = [keys count];
00194 
00195     while(keysCount--)
00196     {
00197         var key = keys[keysCount];
00198         [[_controller defaults] setObject:[_cachedValues objectForKey:key] forKey:key];
00199     }
00200 }
00201 
00202 - (void)revertToInitialValues
00203 {
00204     var initial = [_controller initialValues],
00205         keys = [_cachedValues allKeys],
00206         keysCount = [keys count];
00207 
00208     while(keysCount--)
00209     {
00210         var key = keys[keysCount];
00211         [self willChangeValueForKey:key];
00212 
00213         var initialValue = [initial objectForKey:key];
00214         if (initialValue !== nil)
00215             [_cachedValues setObject:initialValue forKey:key];
00216         else
00217             [_cachedValues removeObjectForKey:key];
00218 
00219         [self didChangeValueForKey:key];
00220 
00221     }
00222 }
00223 
00224 - (void)userDefaultsDidChange:(CPNotification)aNotification
00225 {
00226     var defaults = [_controller defaults],
00227         keys = [_cachedValues allKeys],
00228         keysCount = [keys count];
00229 
00230     while(keysCount--)
00231     {
00232         var key = keys[keysCount],
00233             value = [_cachedValues objectForKey:key],
00234             newValue = [defaults objectForKey:key];
00235 
00236         if (![value isEqual:newValue])
00237         {
00238             [self willChangeValueForKey:key];
00239             [_cachedValues setObject:newValue forKey:key];
00240             [self didChangeValueForKey:key];
00241         }
00242     }
00243 }
00244 
00245 - (BOOL)hasUnappliedChanges
00246 {
00247     var defaults = [_controller defaults],
00248         keys = [_cachedValues allKeys],
00249         keysCount = [keys count];
00250 
00251     while(keysCount--)
00252     {
00253         var key = keys[keysCount],
00254             value = [_cachedValues objectForKey:key],
00255             newValue = [defaults objectForKey:key];
00256 
00257         if (![value isEqual:newValue])
00258             return YES;
00259     }
00260 
00261     return NO;
00262 }
00263 
00264 @end
00265 
00266 
00267 @implementation CPUserDefaultsController (CPSynthesizedAccessors)
00268 
00272 - (CPUserDefaults)defaults
00273 {
00274     return _defaults;
00275 }
00276 
00280 - (CPDictionary)initialValues
00281 {
00282     return _initialValues;
00283 }
00284 
00288 - (void)setInitialValues:(CPDictionary)aValue
00289 {
00290     _initialValues = aValue;
00291 }
00292 
00296 - (BOOL)appliesImmediately
00297 {
00298     return _appliesImmediately;
00299 }
00300 
00304 - (void)setAppliesImmediately:(BOOL)aValue
00305 {
00306     _appliesImmediately = aValue;
00307 }
00308 
00309 @end
 All Classes Files Functions Variables Defines