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