API  0.9.9
CPViewController.j
Go to the documentation of this file.
1 /*
2  * CPViewController.j
3  * AppKit
4  *
5  * Created by Nicholas Small and Francisco Tolmasky.
6  * Copyright 2009, 280 North, Inc.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 
23 
24 
25 
26 @global CPApp
27 
28 
30 
63 @implementation CPViewController : CPResponder
64 {
65  CPView _view;
66  BOOL _isLoading;
67  BOOL _isLazy;
68  BOOL _isViewLoaded;
69 
70  id _representedObject;
71  CPString _title;
72 
73  CPString _cibName;
74  CPBundle _cibBundle;
75  CPDictionary _cibExternalNameTable;
76 }
77 
78 + (void)initialize
79 {
80  if (self !== [CPViewController class])
81  return;
82 
84 }
85 
89 - (id)init
90 {
91  return [self initWithCibName:nil bundle:nil];
92 }
93 
94 - (id)initWithCibName:(CPString)aCibNameOrNil bundle:(CPBundle)aCibBundleOrNil
95 {
96  return [self initWithCibName:aCibNameOrNil bundle:aCibBundleOrNil externalNameTable:nil];
97 }
98 
99 - (id)initWithCibName:(CPString)aCibNameOrNil bundle:(CPBundle)aCibBundleOrNil owner:(id)anOwner
100 {
101  return [self initWithCibName:aCibNameOrNil bundle:aCibBundleOrNil externalNameTable:@{ CPCibOwner: anOwner }];
102 }
103 
117 - (id)initWithCibName:(CPString)aCibNameOrNil bundle:(CPBundle)aCibBundleOrNil externalNameTable:(CPDictionary)anExternalNameTable
118 {
119  self = [super init];
120 
121  if (self)
122  {
123  // Don't load the cib until someone actually requests the view. The user may just be intending to use setView:.
124  _cibName = aCibNameOrNil;
125  _cibBundle = aCibBundleOrNil || [CPBundle mainBundle];
126  _cibExternalNameTable = anExternalNameTable || @{ CPCibOwner: self };
127 
128  _isLoading = NO;
129  _isLazy = NO;
130  }
131 
132  return self;
133 }
134 
152 - (void)loadView
153 {
154  if (_view)
155  return;
156 
157  if (_cibName)
158  {
159  // check if a cib is already cached for the current _cibName
160  var cib = [CPViewControllerCachedCibs objectForKey:_cibName];
161 
162  if (!cib)
163  {
164  // if the cib isn't cached yet : fetch it and cache it
165  cib = [[CPCib alloc] initWithCibNamed:_cibName bundle:_cibBundle];
166  [CPViewControllerCachedCibs setObject:cib forKey:_cibName];
167  }
168 
169  [cib instantiateCibWithExternalNameTable:_cibExternalNameTable];
170  }
171  else
172  _view = [CPView new];
173 }
174 
184 - (void)loadViewWithCompletionHandler:(Function/*(view, error)*/)aHandler
185 {
186  if (_view)
187  return;
188 
189  if (_cibName)
190  {
191  // check if a cib is already cached for the current _cibName
192  var cib = [CPViewControllerCachedCibs objectForKey:_cibName];
193 
194  if (!cib)
195  {
196  var cibName = _cibName;
197 
198  if (![cibName hasSuffix:@".cib"])
199  cibName = [cibName stringByAppendingString:@".cib"];
200 
201  // If aBundle is nil, use mainBundle, but ONLY for searching for the nib, not for resources later.
202  var bundle = _cibBundle || [CPBundle mainBundle],
203  url = [bundle _cibPathForResource:cibName];
204 
205  // if the cib isn't cached yet : fetch it and cache it
206  [CPURLConnection sendAsynchronousRequest:[CPURLRequest requestWithURL:url] queue:[CPOperationQueue mainQueue] completionHandler:function(aResponse, aData, anError)
207  {
208  if (anError == nil)
209  {
210  var data = [CPData dataWithRawString:aData],
211  aCib = [[CPCib alloc] _initWithData:data bundle:_cibBundle cibName:_cibName];
212 
213  [CPViewControllerCachedCibs setObject:aCib forKey:_cibName];
214  [aCib instantiateCibWithExternalNameTable:_cibExternalNameTable];
215  aHandler(_view, nil);
216  }
217  else
218  {
219  aHandler(nil, anError);
220  }
221  }];
222  }
223  else
224  {
225  [cib instantiateCibWithExternalNameTable:_cibExternalNameTable];
226  aHandler(_view, nil);
227  }
228  }
229  else
230  {
231  _view = [CPView new];
232  aHandler(_view, nil);
233  }
234 }
235 
244 {
245  if (!_view)
246  {
247  _isLoading = YES;
248 
249  var cibOwner = [_cibExternalNameTable objectForKey:CPCibOwner];
250 
251  if ([cibOwner respondsToSelector:@selector(viewControllerWillLoadCib:)])
252  [cibOwner viewControllerWillLoadCib:self];
253 
254  [self loadView];
255 
256  if (_view === nil && [cibOwner isKindOfClass:[CPDocument class]])
257  [self setView:[cibOwner valueForKey:@"view"]];
258 
259  if (!_view)
260  {
261  var reason = [CPString stringWithFormat:@"View for %@ could not be loaded from Cib or no view specified. Override loadView to load the view manually.", self];
262 
263  [CPException raise:CPInternalInconsistencyException reason:reason];
264  }
265 
266  if ([cibOwner respondsToSelector:@selector(viewControllerDidLoadCib:)])
267  [cibOwner viewControllerDidLoadCib:self];
268 
269  _isLoading = NO;
270  _isLazy = NO;
271  [self _viewDidLoad];
272  }
273  else if (_isLazy)
274  {
275  _isLazy = NO;
276  [self _viewDidLoad];
277  }
278 
279  return _view;
280 }
281 
282 - (void)_viewDidLoad
283 {
284  [self willChangeValueForKey:"isViewLoaded"];
285  [self viewDidLoad];
286  _isViewLoaded = YES;
287  [self didChangeValueForKey:"isViewLoaded"];
288 }
289 
298 - (void)viewDidLoad
299 {
300 
301 }
302 
303 
312 - (void)setView:(CPView)aView
313 {
314  var willChangeIsViewLoaded = (_isViewLoaded == NO && aView != nil) || (_isViewLoaded == YES && aView == nil);
315 
316  if (willChangeIsViewLoaded)
317  [self willChangeValueForKey:"isViewLoaded"];
318 
319  _view = aView;
320  _isViewLoaded = aView !== nil;
321 
322  if (willChangeIsViewLoaded)
323  [self didChangeValueForKey:"isViewLoaded"];
324 }
325 
327 {
328  return NO;
329 }
330 
331 @end
332 
333 
334 var CPViewControllerViewKey = @"CPViewControllerViewKey",
335  CPViewControllerTitleKey = @"CPViewControllerTitleKey",
336  CPViewControllerCibNameKey = @"CPViewControllerCibNameKey",
337  CPViewControllerBundleKey = @"CPViewControllerBundleKey";
338 
340 
346 - (id)initWithCoder:(CPCoder)aCoder
347 {
348  self = [super initWithCoder:aCoder];
349 
350  if (self)
351  {
352  _view = [aCoder decodeObjectForKey:CPViewControllerViewKey];
353  _title = [aCoder decodeObjectForKey:CPViewControllerTitleKey];
354  _cibName = [aCoder decodeObjectForKey:CPViewControllerCibNameKey];
355 
356  var bundlePath = [aCoder decodeObjectForKey:CPViewControllerBundleKey];
357  _cibBundle = bundlePath ? [CPBundle bundleWithPath:bundlePath] : [CPBundle mainBundle];
358 
359  _cibExternalNameTable = @{ CPCibOwner: self };
360  _isLazy = YES;
361  }
362 
363  return self;
364 }
365 
370 - (void)encodeWithCoder:(CPCoder)aCoder
371 {
372  [super encodeWithCoder:aCoder];
373 
374  [aCoder encodeObject:_view forKey:CPViewControllerViewKey];
375  [aCoder encodeObject:_title forKey:CPViewControllerTitleKey];
376  [aCoder encodeObject:_cibName forKey:CPViewControllerCibNameKey];
377  [aCoder encodeObject:[_cibBundle bundlePath] forKey:CPViewControllerBundleKey];
378 }
379 
380 @end
381 
383 
388 {
389  return _view;
390 }
391 
395 - (void)setView:(CPView)aValue
396 {
397  _view = aValue;
398 }
399 
404 {
405  return _isViewLoaded;
406 }
407 
412 {
413  return _representedObject;
414 }
415 
419 - (void)setRepresentedObject:(id)aValue
420 {
421  _representedObject = aValue;
422 }
423 
428 {
429  return _title;
430 }
431 
435 - (void)setTitle:(CPString)aValue
436 {
437  _title = aValue;
438 }
439 
444 {
445  return _cibName;
446 }
447 
452 {
453  return _cibBundle;
454 }
455 
460 {
461  return _cibExternalNameTable;
462 }
463 
464 @end
Used to implement exception handling (creating & raising).
Definition: CPException.h:2
id initWithCoder:(CPCoder aCoder)
Definition: CPResponder.j:373
void willChangeValueForKey:(CPString aKey)
Definition: CPCib.h:2
A Cappuccino wrapper for any data type.
Definition: CPData.h:2
void raise:reason:(CPString aName, [reason] CPString aReason)
Definition: CPException.j:66
Provides loading of a URL request.
var CPViewControllerViewKey
void encodeWithCoder:(CPCoder aCoder)
Definition: CPResponder.j:390
A mutable key-value pair collection.
Definition: CPDictionary.h:2
id requestWithURL:(CPURL aURL)
Definition: CPURLRequest.j:56
var CPViewControllerBundleKey
global CPApp var CPViewControllerCachedCibs
An immutable string (collection of characters).
Definition: CPString.h:2
CPBundle mainBundle()
Definition: CPBundle.j:82
void setView:(CPView aView)
CPData dataWithRawString:(CPString aString)
Definition: CPData.j:45
CPOperationQueue mainQueue()
void didChangeValueForKey:(CPString aKey)
CPURLConnection sendAsynchronousRequest:queue:completionHandler:(CPURLRequest aRequest, [queue] CPOperationQueue aQueue, [completionHandler] Function aHandler)
CPCibOwner
Definition: CPCib.j:25
Defines methods for use when archiving & restoring (enc/decoding).
Definition: CPCoder.h:2
id init()
Definition: CPObject.j:145
BOOL automaticallyNotifiesObserversOfIsViewLoaded()
CPBundle bundleWithPath:(CPString aPath)
Definition: CPBundle.j:54
id stringWithFormat:(CPString format, [,]...)
Definition: CPString.j:166
Contains data obtained during a request made with CPURLConnection.
Definition: CPURLRequest.h:2
id initWithCibName:bundle:externalNameTable:(CPString aCibNameOrNil, [bundle] CPBundle aCibBundleOrNil, [externalNameTable] CPDictionary anExternalNameTable)
id initWithCibName:bundle:(CPString aCibNameOrNil, [bundle] CPBundle aCibBundleOrNil)
var CPViewControllerCibNameKey
var CPViewControllerTitleKey
id initWithCibNamed:bundle:(CPString aName, [bundle] CPBundle aBundle)
Definition: CPCib.j:95
id alloc()
Definition: CPObject.j:130
Represents an operation queue that can run CPOperations.
Definition: CPView.j:131