API  0.9.10
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 
26 @global CPApp
30 
31 
45 @implementation CPWindowController : CPResponder
46 {
47  CPWindow _window;
48 
49  CPArray _documents;
50  CPDocument _document;
51  BOOL _shouldCloseDocument;
52  BOOL _supportsMultipleDocuments;
53 
54  id _cibOwner;
55  CPString _windowCibName;
56  CPString _windowCibPath;
57 
58  CPViewController _viewController;
59  CPView _viewControllerContainerView;
60 }
61 
62 - (id)init
63 {
64  return [self initWithWindow:nil];
65 }
66 
72 - (id)initWithWindow:(CPWindow)aWindow
73 {
74  self = [super init];
75 
76  if (self)
77  {
78  [self setWindow:aWindow];
79  [self setShouldCloseDocument:NO];
80 
81  [self setNextResponder:CPApp];
82 
83  _documents = [];
84  }
85 
86  return self;
87 }
88 
94 - (id)initWithWindowCibName:(CPString)aWindowCibName
95 {
96  return [self initWithWindowCibName:aWindowCibName owner:self];
97 }
98 
105 - (id)initWithWindowCibName:(CPString)aWindowCibName owner:(id)anOwner
106 {
107  self = [self initWithWindow:nil];
108 
109  if (self)
110  {
111  _cibOwner = anOwner;
112  _windowCibName = aWindowCibName;
113  }
114 
115  return self;
116 }
117 
118 - (id)initWithWindowCibPath:(CPString)aWindowCibPath owner:(id)anOwner
119 {
120  self = [self initWithWindow:nil];
121 
122  if (self)
123  {
124  _cibOwner = anOwner;
125  _windowCibPath = aWindowCibPath;
126  }
127 
128  return self;
129 }
130 
135 - (void)loadWindow
136 {
137  if (_window)
138  return;
139 
140  [[CPBundle mainBundle] loadCibFile:[self windowCibPath] externalNameTable:@{ CPCibOwner: _cibOwner }];
141 }
142 
147 - (@action)showWindow:(id)aSender
148 {
149  var theWindow = [self window];
150 
151  if ([theWindow respondsToSelector:@selector(becomesKeyOnlyIfNeeded)] && [theWindow becomesKeyOnlyIfNeeded])
152  [theWindow orderFront:aSender];
153  else
154  [theWindow makeKeyAndOrderFront:aSender];
155 }
156 
162 {
163  return _window !== nil;
164 }
165 
171 {
172  if (!_window)
173  {
174  [self windowWillLoad];
175  [_document windowControllerWillLoadCib:self];
176 
177  [self loadWindow];
178 
179  if (_window === nil && [_cibOwner isKindOfClass:[CPDocument class]])
180  [self setWindow:[_cibOwner valueForKey:@"window"]];
181 
182  if (!_window)
183  {
184  var reason = [CPString stringWithFormat:@"Window for %@ could not be loaded from Cib or no window specified. Override loadWindow to load the window manually.", self];
185 
186  [CPException raise:CPInternalInconsistencyException reason:reason];
187  }
188 
189  [self windowDidLoad];
190  [_document windowControllerDidLoadCib:self];
191 
193  }
194 
195  return _window;
196 }
197 
202 - (void)setWindow:(CPWindow)aWindow
203 {
204  [_window setWindowController:nil];
205 
206  _window = aWindow;
207 
208  [_window setWindowController:self];
209  [_window setNextResponder:self];
210 }
211 
216 {
217 }
218 
223 {
224 }
225 
230 - (void)setDocument:(CPDocument)aDocument
231 {
232  if (_document === aDocument)
233  return;
234 
235  var defaultCenter = [CPNotificationCenter defaultCenter];
236 
237  if (_document)
238  {
239  if (![self supportsMultipleDocuments])
240  [self removeDocument:_document];
241 
242  [defaultCenter removeObserver:self
243  name:CPDocumentWillSaveNotification
244  object:_document];
245 
246  [defaultCenter removeObserver:self
247  name:CPDocumentDidSaveNotification
248  object:_document];
249 
250  [defaultCenter removeObserver:self
251  name:CPDocumentDidFailToSaveNotification
252  object:_document];
253  }
254 
255  _document = aDocument;
256 
257  if (_document)
258  {
259  [self addDocument:_document];
260 
261  [defaultCenter addObserver:self
262  selector:@selector(_documentWillSave:)
263  name:CPDocumentWillSaveNotification
264  object:_document];
265 
266  [defaultCenter addObserver:self
267  selector:@selector(_documentDidSave:)
268  name:CPDocumentDidSaveNotification
269  object:_document];
270 
271  [defaultCenter addObserver:self
272  selector:@selector(_documentDidFailToSave:)
273  name:CPDocumentDidFailToSaveNotification
274  object:_document];
275 
276  [self setDocumentEdited:[_document isDocumentEdited]];
277  }
278 
279  var viewController = [_document viewControllerForWindowController:self];
280 
281  if (viewController)
282  [self setViewController:viewController];
283 
285 
286  // Change of document means toolbar items may no longer make sense.
287  // FIXME: DOCUMENT ARCHITECTURE Should we setToolbar: as well?
288  [[[self window] toolbar] _autoValidateVisibleItems];
289 }
290 
291 - (void)setSupportsMultipleDocuments:(BOOL)shouldSupportMultipleDocuments
292 {
293  _supportsMultipleDocuments = shouldSupportMultipleDocuments;
294 }
295 
297 {
298  return _supportsMultipleDocuments;
299 }
300 
301 - (void)addDocument:(CPDocument)aDocument
302 {
303  if (aDocument && ![_documents containsObject:aDocument])
304  [_documents addObject:aDocument];
305 }
306 
307 - (void)removeDocument:(CPDocument)aDocument
308 {
309  var index = [_documents indexOfObjectIdenticalTo:aDocument];
310 
311  if (index === CPNotFound)
312  return;
313 
314  [_documents removeObjectAtIndex:index];
315 
316  if (_document === aDocument && [_documents count])
317  [self setDocument:[_documents objectAtIndex:MIN(index, [_documents count] - 1)]];
318 }
319 
320 - (void)removeDocumentAndCloseIfNecessary:(CPDocument)aDocument
321 {
322  [self removeDocument:aDocument];
323 
324  if (![_documents count])
325  [self close];
326 }
327 
328 - (CPArray)documents
329 {
330  return _documents;
331 }
332 
333 - (void)setViewControllerContainerView:(CPView)aView
334 {
335  if (!_viewControllerContainerView && !aView)
336  return;
337 
338  var viewController = [self viewController],
339  viewControllerView = [viewController isViewLoaded] ? [viewController view] : nil,
340  contentView = [[self window] contentView];
341 
342  if (aView)
343  {
344  [aView setFrame:[contentView frame]];
345  [aView setAutoresizingMask:[contentView autoresizingMask]];
346 
347  if (viewControllerView)
348  {
349  [viewControllerView removeFromSuperview];
350  [aView addSubview:viewControllerView];
351  }
352 
353  [[self window] setContentView:aView];
354  }
355  else if (viewControllerView)
356  {
357  [viewControllerView removeFromSuperview];
358  [viewControllerView setFrame:[contentView frame]];
359  [viewControllerView setAutoresizingMask:[contentView autoresizingMask]]
360  [[self window] setContentView:viewControllerView];
361  }
362  else
363  {
364  var view = [[CPView alloc] init];
365  [view setFrame:[contentView frame]];
366  [view setAutoresizingMask:[contentView autoresizingMask]];
367  [[self window] setContentView:view]
368  }
369 
370  _viewControllerContainerView = aView;
371 }
372 
374 {
375  return _viewControllerContainerView;
376 }
377 
378 - (void)setViewController:(CPViewController)aViewController
379 {
380  if (!_viewController && !aViewController)
381  return;
382 
383  var containerView = [self viewControllerContainerView],
384  newView = [aViewController isViewLoaded] ? [aViewController view] : nil;
385 
386  if (containerView)
387  {
388  var oldView = [_viewController isViewLoaded] ? [_viewController view] : nil;
389 
390  if (oldView)
391  {
392  [newView setFrame:[oldView frame]];
393  [newView setAutoresizingMask:[oldView autoresizingMask]];
394  }
395 
396  if (oldView && newView)
397  [containerView replaceSubview:oldView with:newView];
398  else if (oldView)
399  [oldView removeFromSuperview];
400  else if (newView)
401  [containerView addSubview:newView];
402  }
403  else if (newView)
404  {
405  var contentView = [[self window] contentView];
406  [newView setFrame:[contentView frame]];
407  [newView setAutoresizingMask:[contentView autoresizingMask]];
408  [[self window] setContentView:newView];
409  }
410  else
411  {
412  var view = [[CPView alloc] init],
413  contentView = [[self window] contentView];
414 
415  [view setFrame:[contentView frame]];
416  [view setAutoresizingMask:[contentView autoresizingMask]];
417  [[self window] setContentView:view]
418  }
419 
420  _viewController = aViewController;
421 }
422 
424 {
425  return _viewController;
426 }
427 
428 /* @ignore */
429 - (void)_documentWillSave:(CPNotification)aNotification
430 {
431  [[self window] setDocumentSaving:YES];
432 }
433 
434 /* @ignore */
435 - (void)_documentDidSave:(CPNotification)aNotification
436 {
437  [[self window] setDocumentSaving:NO];
438 }
439 
440 /* @ignore */
441 - (void)_documentDidFailToSave:(CPNotification)aNotification
442 {
443  [[self window] setDocumentSaving:NO];
444 }
445 
450 {
451  return _document;
452 }
453 
458 - (void)setDocumentEdited:(BOOL)isEdited
459 {
460  [[self window] setDocumentEdited:isEdited];
461 }
462 
463 - (void)close
464 {
465  [[self window] close];
466 }
467 
468 - (void)setShouldCloseDocument:(BOOL)shouldCloseDocument
469 {
470  _shouldCloseDocument = shouldCloseDocument;
471 }
472 
474 {
475  return _shouldCloseDocument;
476 }
477 
478 - (id)owner
479 {
480  return _cibOwner;
481 }
482 
484 {
485  if (_windowCibName)
486  return _windowCibName;
487 
488  return [[_windowCibPath lastPathComponent] stringByDeletingPathExtension];
489 }
490 
492 {
493  if (_windowCibPath)
494  return _windowCibPath;
495 
496  return [[CPBundle mainBundle] pathForResource:_windowCibName + @".cib"];
497 }
498 
499 // Setting and Getting Window Attributes
500 
505 {
506  if (!_document || !_window)
507  return;
508 
509  // [_window setRepresentedFilename:];
510  [_window setTitle:[self windowTitleForDocumentDisplayName:[_document displayName]]];
511 }
512 
517 - (CPString)windowTitleForDocumentDisplayName:(CPString)aDisplayName
518 {
519  return aDisplayName;
520 }
521 
522 @end
Used to implement exception handling (creating & raising).
Definition: CPException.h:2
CPToolbar toolbar()
Definition: CPWindow.j:2579
void addSubview:(CPView aSubview)
Definition: CPView.j:512
id initWithWindow:(CPWindow aWindow)
CPString windowTitleForDocumentDisplayName:(CPString aDisplayName)
void setDocumentSaving:(BOOL isDocumentSaving)
Definition: CPWindow.j:2217
void setShouldCloseDocument:(BOOL shouldCloseDocument)
void setFrame:(CGRect aFrame)
Definition: CPView.j:996
void setDocument:(CPDocument aDocument)
void raise:reason:(CPString aName, [reason] CPString aReason)
Definition: CPException.j:66
CPNotificationCenter defaultCenter()
void synchronizeWindowTitleWithDocumentName()
void addDocument:(CPDocument aDocument)
CPViewController viewController()
void close()
Definition: CPWindow.j:2393
void setViewController:(CPViewController aViewController)
CPString pathForResource:(CPString aFilename)
Definition: CPBundle.j:158
An immutable string (collection of characters).
Definition: CPString.h:2
CPBundle mainBundle()
Definition: CPBundle.j:82
id initWithWindowCibName:owner:(CPString aWindowCibName, [owner] id anOwner)
CPCib loadCibFile:externalNameTable:(CPString anAbsolutePath, [externalNameTable] CPDictionary aNameTable)
Definition: CPCibLoading.j:41
CPDocumentDidFailToSaveNotification
Definition: CPDocument.j:78
void setAutoresizingMask:(unsigned aMask)
Definition: CPView.j:1487
CPDocumentDidSaveNotification
Definition: CPDocument.j:77
void setWindow:(CPWindow aWindow)
A notification that can be posted to a CPNotificationCenter.
Definition: CPNotification.h:2
void setDocumentEdited:(BOOL isEdited)
CPNotFound
Definition: CPObjJRuntime.j:62
id init()
Definition: CPObject.j:145
Sends messages (CPNotification) between objects.
CPDocumentWillSaveNotification
Definition: CPDocument.j:76
void setNextResponder:(CPResponder aResponder)
Definition: CPResponder.j:83
void removeDocument:(CPDocument aDocument)
CPView contentView()
Definition: CPWindow.j:1211
void setDocumentEdited:(BOOL isDocumentEdited)
Definition: CPWindow.j:2197
void setContentView:(CPView aView)
Definition: CPWindow.j:1187
Definition: CPView.j:136
id stringWithFormat:(CPString format, [,] ...)
Definition: CPString.j:166