API  0.9.6
 All Classes Files Functions Variables Macros Groups Pages
CPWindowController.j
Go to the documentation of this file.
1 /*
2  * CPWindowController.j
3  * AppKit
4  *
5  * Created by Francisco Tolmasky.
6  * Copyright 2008, 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 
40 @implementation CPWindowController : CPResponder
41 {
42  CPWindow _window;
43 
44  CPArray _documents;
45  CPDocument _document;
46  BOOL _shouldCloseDocument;
47  BOOL _supportsMultipleDocuments;
48 
49  id _cibOwner;
50  CPString _windowCibName;
51  CPString _windowCibPath;
52 
53  CPViewController _viewController;
54  CPView _viewControllerContainerView;
55 }
56 
57 - (id)init
58 {
59  return [self initWithWindow:nil];
60 }
61 
67 - (id)initWithWindow:(CPWindow)aWindow
68 {
69  self = [super init];
70 
71  if (self)
72  {
73  [self setWindow:aWindow];
74  [self setShouldCloseDocument:NO];
75 
76  [self setNextResponder:CPApp];
77 
78  _documents = [];
79  }
80 
81  return self;
82 }
83 
89 - (id)initWithWindowCibName:(CPString)aWindowCibName
90 {
91  return [self initWithWindowCibName:aWindowCibName owner:self];
92 }
93 
100 - (id)initWithWindowCibName:(CPString)aWindowCibName owner:(id)anOwner
101 {
102  self = [self initWithWindow:nil];
103 
104  if (self)
105  {
106  _cibOwner = anOwner;
107  _windowCibName = aWindowCibName;
108  }
109 
110  return self;
111 }
112 
113 - (id)initWithWindowCibPath:(CPString)aWindowCibPath owner:(id)anOwner
114 {
115  self = [self initWithWindow:nil];
116 
117  if (self)
118  {
119  _cibOwner = anOwner;
120  _windowCibPath = aWindowCibPath;
121  }
122 
123  return self;
124 }
125 
130 - (void)loadWindow
131 {
132  if (_window)
133  return;
134 
135  [[CPBundle mainBundle] loadCibFile:[self windowCibPath] externalNameTable:[CPDictionary dictionaryWithObject:_cibOwner forKey:CPCibOwner]];
136 }
137 
142 - (@action)showWindow:(id)aSender
143 {
144  var theWindow = [self window];
145 
146  if ([theWindow respondsToSelector:@selector(becomesKeyOnlyIfNeeded)] && [theWindow becomesKeyOnlyIfNeeded])
147  [theWindow orderFront:aSender];
148  else
149  [theWindow makeKeyAndOrderFront:aSender];
150 }
151 
156 - (BOOL)isWindowLoaded
157 {
158  return _window !== nil;
159 }
160 
165 - (CPWindow)window
166 {
167  if (!_window)
168  {
169  [self windowWillLoad];
170  [_document windowControllerWillLoadCib:self];
171 
172  [self loadWindow];
173 
174  if (_window === nil && [_cibOwner isKindOfClass:[CPDocument class]])
175  [self setWindow:[_cibOwner valueForKey:@"window"]];
176 
177  if (!_window)
178  {
179  var reason = [CPString stringWithFormat:@"Window for %@ could not be loaded from Cib or no window specified. Override loadWindow to load the window manually.", self];
180 
181  [CPException raise:CPInternalInconsistencyException reason:reason];
182  }
183 
184  [self windowDidLoad];
185  [_document windowControllerDidLoadCib:self];
186 
188  }
189 
190  return _window;
191 }
192 
197 - (void)setWindow:(CPWindow)aWindow
198 {
199  [_window setWindowController:nil];
200 
201  _window = aWindow;
202 
203  [_window setWindowController:self];
204  [_window setNextResponder:self];
205 }
206 
210 - (void)windowDidLoad
211 {
212 }
213 
217 - (void)windowWillLoad
218 {
219 }
220 
225 - (void)setDocument:(CPDocument)aDocument
226 {
227  if (_document === aDocument)
228  return;
229 
230  var defaultCenter = [CPNotificationCenter defaultCenter];
231 
232  if (_document)
233  {
234  if (![self supportsMultipleDocuments])
235  [self removeDocument:_document];
236 
237  [defaultCenter removeObserver:self
238  name:CPDocumentWillSaveNotification
239  object:_document];
240 
241  [defaultCenter removeObserver:self
242  name:CPDocumentDidSaveNotification
243  object:_document];
244 
245  [defaultCenter removeObserver:self
246  name:CPDocumentDidFailToSaveNotification
247  object:_document];
248  }
249 
250  _document = aDocument;
251 
252  if (_document)
253  {
254  [self addDocument:_document];
255 
256  [defaultCenter addObserver:self
257  selector:@selector(_documentWillSave:)
258  name:CPDocumentWillSaveNotification
259  object:_document];
260 
261  [defaultCenter addObserver:self
262  selector:@selector(_documentDidSave:)
263  name:CPDocumentDidSaveNotification
264  object:_document];
265 
266  [defaultCenter addObserver:self
267  selector:@selector(_documentDidFailToSave:)
268  name:CPDocumentDidFailToSaveNotification
269  object:_document];
270 
271  [self setDocumentEdited:[_document isDocumentEdited]];
272  }
273 
274  var viewController = [_document viewControllerForWindowController:self];
275 
276  if (viewController)
277  [self setViewController:viewController];
278 
280 
281  // Change of document means toolbar items may no longer make sense.
282  // FIXME: DOCUMENT ARCHITECTURE Should we setToolbar: as well?
283  [[[self window] toolbar] _autoValidateVisibleItems];
284 }
285 
286 - (void)setSupportsMultipleDocuments:(BOOL)shouldSupportMultipleDocuments
287 {
288  _supportsMultipleDocuments = shouldSupportMultipleDocuments;
289 }
290 
291 - (BOOL)supportsMultipleDocuments
292 {
293  return _supportsMultipleDocuments;
294 }
295 
296 - (void)addDocument:(CPDocument)aDocument
297 {
298  if (aDocument && ![_documents containsObject:aDocument])
299  [_documents addObject:aDocument];
300 }
301 
302 - (void)removeDocument:(CPDocument)aDocument
303 {
304  var index = [_documents indexOfObjectIdenticalTo:aDocument];
305 
306  if (index === CPNotFound)
307  return;
308 
309  [_documents removeObjectAtIndex:index];
310 
311  if (_document === aDocument && [_documents count])
312  [self setDocument:[_documents objectAtIndex:MIN(index, [_documents count] - 1)]];
313 }
314 
315 - (void)removeDocumentAndCloseIfNecessary:(CPDocument)aDocument
316 {
317  [self removeDocument:aDocument];
318 
319  if (![_documents count])
320  [self close];
321 }
322 
323 - (CPArray)documents
324 {
325  return _documents;
326 }
327 
328 - (void)setViewControllerContainerView:(CPView)aView
329 {
330  if (!_viewControllerContainerView && !aView)
331  return;
332 
333  var viewController = [self viewController],
334  viewControllerView = [viewController isViewLoaded] ? [viewController view] : nil,
335  contentView = [[self window] contentView];
336 
337  if (aView)
338  {
339  [aView setFrame:[contentView frame]];
340  [aView setAutoresizingMask:[contentView autoresizingMask]];
341 
342  if (viewControllerView)
343  {
344  [viewControllerView removeFromSuperview];
345  [aView addSubview:viewControllerView];
346  }
347 
348  [[self window] setContentView:aView];
349  }
350  else if (viewControllerView)
351  {
352  [viewControllerView removeFromSuperview];
353  [viewControllerView setFrame:[contentView frame]];
354  [viewControllerView setAutoresizingMask:[contentView autoresizingMask]]
355  [[self window] setContentView:viewControllerView];
356  }
357  else
358  {
359  var view = [[CPView alloc] init];
360  [view setFrame:[contentView frame]];
361  [view setAutoresizingMask:[contentView autoresizingMask]];
362  [[self window] setContentView:view]
363  }
364 
365  _viewControllerContainerView = aView;
366 }
367 
368 - (void)viewControllerContainerView
369 {
370  return _viewControllerContainerView;
371 }
372 
373 - (void)setViewController:(CPViewController)aViewController
374 {
375  if (!_viewController && !aViewController)
376  return;
377 
378  var containerView = [self viewControllerContainerView],
379  newView = [aViewController isViewLoaded] ? [aViewController view] : nil;
380 
381  if (containerView)
382  {
383  var oldView = [_viewController isViewLoaded] ? [_viewController view] : nil;
384 
385  if (oldView)
386  {
387  [newView setFrame:[oldView frame]];
388  [newView setAutoresizingMask:[oldView autoresizingMask]];
389  }
390 
391  if (oldView && newView)
392  [containerView replaceSubview:oldView with:newView];
393  else if (oldView)
394  [oldView removeFromSuperview];
395  else if (newView)
396  [containerView addSubview:newView];
397  }
398  else if (newView)
399  {
400  var contentView = [[self window] contentView];
401  [newView setFrame:[contentView frame]];
402  [newView setAutoresizingMask:[contentView autoresizingMask]];
403  [[self window] setContentView:newView];
404  }
405  else
406  {
407  var view = [[CPView alloc] init],
408  contentView = [[self window] contentView];
409 
410  [view setFrame:[contentView frame]];
411  [view setAutoresizingMask:[contentView autoresizingMask]];
412  [[self window] setContentView:view]
413  }
414 
415  _viewController = aViewController;
416 }
417 
418 - (CPViewController)viewController
419 {
420  return _viewController;
421 }
422 
423 /* @ignore */
424 - (void)_documentWillSave:(CPNotification)aNotification
425 {
426  [[self window] setDocumentSaving:YES];
427 }
428 
429 /* @ignore */
430 - (void)_documentDidSave:(CPNotification)aNotification
431 {
432  [[self window] setDocumentSaving:NO];
433 }
434 
435 /* @ignore */
436 - (void)_documentDidFailToSave:(CPNotification)aNotification
437 {
438  [[self window] setDocumentSaving:NO];
439 }
440 
444 - (CPDocument)document
445 {
446  return _document;
447 }
448 
453 - (void)setDocumentEdited:(BOOL)isEdited
454 {
455  [[self window] setDocumentEdited:isEdited];
456 }
457 
458 - (void)close
459 {
460  [[self window] close];
461 }
462 
463 - (void)setShouldCloseDocument:(BOOL)shouldCloseDocument
464 {
465  _shouldCloseDocument = shouldCloseDocument;
466 }
467 
468 - (BOOL)shouldCloseDocument
469 {
470  return _shouldCloseDocument;
471 }
472 
473 - (id)owner
474 {
475  return _cibOwner;
476 }
477 
478 - (CPString)windowCibName
479 {
480  if (_windowCibName)
481  return _windowCibName;
482 
483  return [[_windowCibPath lastPathComponent] stringByDeletingPathExtension];
484 }
485 
486 - (CPString)windowCibPath
487 {
488  if (_windowCibPath)
489  return _windowCibPath;
490 
491  return [[CPBundle mainBundle] pathForResource:_windowCibName + @".cib"];
492 }
493 
494 // Setting and Getting Window Attributes
495 
499 - (void)synchronizeWindowTitleWithDocumentName
500 {
501  if (!_document || !_window)
502  return;
503 
504  // [_window setRepresentedFilename:];
505  [_window setTitle:[self windowTitleForDocumentDisplayName:[_document displayName]]];
506 }
507 
512 - (CPString)windowTitleForDocumentDisplayName:(CPString)aDisplayName
513 {
514  return aDisplayName;
515 }
516 
517 @end