00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 @import <Foundation/CPObject.j>
00024 @import <Foundation/CPString.j>
00025
00026 @import "CPResponder.j"
00027 @import "CPWindow.j"
00028 @import "CPDocument.j"
00029
00030 #include "Platform/Platform.h"
00031
00032
00042 @implementation CPWindowController : CPResponder
00043 {
00044 CPWindow _window;
00045
00046 CPArray _documents;
00047 CPDocument _document;
00048 BOOL _shouldCloseDocument;
00049 BOOL _supportsMultipleDocuments;
00050
00051 id _cibOwner;
00052 CPString _windowCibName;
00053 CPString _windowCibPath;
00054
00055 CPViewController _viewController;
00056 CPView _viewControllerContainerView;
00057 }
00058
00059 - (id)init
00060 {
00061 return [self initWithWindow:nil];
00062 }
00063
00069 - (id)initWithWindow:(CPWindow)aWindow
00070 {
00071 self = [super init];
00072
00073 if (self)
00074 {
00075 [self setWindow:aWindow];
00076 [self setShouldCloseDocument:NO];
00077
00078 [self setNextResponder:CPApp];
00079
00080 _documents = [];
00081 }
00082
00083 return self;
00084 }
00085
00091 - (id)initWithWindowCibName:(CPString)aWindowCibName
00092 {
00093 return [self initWithWindowCibName:aWindowCibName owner:self];
00094 }
00095
00102 - (id)initWithWindowCibName:(CPString)aWindowCibName owner:(id)anOwner
00103 {
00104 self = [self initWithWindow:nil];
00105
00106 if (self)
00107 {
00108 _cibOwner = anOwner;
00109 _windowCibName = aWindowCibName;
00110 }
00111
00112 return self;
00113 }
00114
00115 - (id)initWithWindowCibPath:(CPString)aWindowCibPath owner:(id)anOwner
00116 {
00117 self = [self initWithWindow:nil];
00118
00119 if (self)
00120 {
00121 _cibOwner = anOwner;
00122 _windowCibPath = aWindowCibPath;
00123 }
00124
00125 return self;
00126 }
00127
00131 - (void)loadWindow
00132 {
00133 if (_window)
00134 return;
00135
00136 [[CPBundle bundleForClass:[_cibOwner class]] loadCibFile:[self windowCibPath] externalNameTable:[CPDictionary dictionaryWithObject:_cibOwner forKey:CPCibOwner]];
00137 }
00138
00143 - (@action)showWindow:(id)aSender
00144 {
00145 var theWindow = [self window];
00146
00147 if ([theWindow respondsToSelector:@selector(becomesKeyOnlyIfNeeded)] && [theWindow becomesKeyOnlyIfNeeded])
00148 [theWindow orderFront:aSender];
00149 else
00150 [theWindow makeKeyAndOrderFront:aSender];
00151 }
00152
00157 - (BOOL)isWindowLoaded
00158 {
00159 return _window !== nil;
00160 }
00161
00165 - (CPWindow)window
00166 {
00167 if (!_window)
00168 {
00169 [self windowWillLoad];
00170 [_document windowControllerWillLoadCib:self];
00171
00172 [self loadWindow];
00173
00174 if (_window === nil && [_cibOwner isKindOfClass:[CPDocument class]])
00175 [self setWindow:[_cibOwner valueForKey:@"window"]];
00176
00177 if (!_window)
00178 {
00179 var reason = [CPString stringWithFormat:@"Window for %@ could not be loaded from Cib or no window specified. \
00180 Override loadWindow to load the window manually.", self];
00181
00182 [CPException raise:CPInternalInconsistencyException reason:reason];
00183 }
00184
00185 [self windowDidLoad];
00186 [_document windowControllerDidLoadCib:self];
00187
00188 [self synchronizeWindowTitleWithDocumentName];
00189 }
00190
00191 return _window;
00192 }
00193
00198 - (void)setWindow:(CPWindow)aWindow
00199 {
00200 [_window setWindowController:nil];
00201
00202 _window = aWindow;
00203
00204 [_window setWindowController:self];
00205 [_window setNextResponder:self];
00206 }
00207
00211 - (void)windowDidLoad
00212 {
00213 }
00214
00218 - (void)windowWillLoad
00219 {
00220 }
00221
00226 - (void)setDocument:(CPDocument)aDocument
00227 {
00228 if (_document === aDocument)
00229 return;
00230
00231 var defaultCenter = [CPNotificationCenter defaultCenter];
00232
00233 if (_document)
00234 {
00235 if (![self supportsMultipleDocuments])
00236 [self removeDocument:_document];
00237
00238 [defaultCenter removeObserver:self
00239 name:CPDocumentWillSaveNotification
00240 object:_document];
00241
00242 [defaultCenter removeObserver:self
00243 name:CPDocumentDidSaveNotification
00244 object:_document];
00245
00246 [defaultCenter removeObserver:self
00247 name:CPDocumentDidFailToSaveNotification
00248 object:_document];
00249 }
00250
00251 _document = aDocument;
00252
00253 if (_document)
00254 {
00255 [self addDocument:_document];
00256
00257 [defaultCenter addObserver:self
00258 selector:@selector(_documentWillSave:)
00259 name:CPDocumentWillSaveNotification
00260 object:_document];
00261
00262 [defaultCenter addObserver:self
00263 selector:@selector(_documentDidSave:)
00264 name:CPDocumentDidSaveNotification
00265 object:_document];
00266
00267 [defaultCenter addObserver:self
00268 selector:@selector(_documentDidFailToSave:)
00269 name:CPDocumentDidFailToSaveNotification
00270 object:_document];
00271
00272 [self setDocumentEdited:[_document isDocumentEdited]];
00273 }
00274
00275 var viewController = [_document viewControllerForWindowController:self];
00276
00277 if (viewController)
00278 [self setViewController:viewController];
00279
00280 [self synchronizeWindowTitleWithDocumentName];
00281 }
00282
00283 - (void)setSupportsMultipleDocuments:(BOOL)shouldSupportMultipleDocuments
00284 {
00285 _supportsMultipleDocuments = shouldSupportMultipleDocuments;
00286 }
00287
00288 - (BOOL)supportsMultipleDocuments
00289 {
00290 return _supportsMultipleDocuments;
00291 }
00292
00293 - (void)addDocument:(CPDocument)aDocument
00294 {
00295 if (aDocument && ![_documents containsObject:aDocument])
00296 [_documents addObject:aDocument];
00297 }
00298
00299 - (void)removeDocument:(CPDocument)aDocument
00300 {
00301 var index = [_documents indexOfObjectIdenticalTo:aDocument];
00302
00303 if (index === CPNotFound)
00304 return;
00305
00306 [_documents removeObjectAtIndex:index];
00307
00308 if (_document === aDocument && [_documents count])
00309 [self setDocument:[_documents objectAtIndex:MIN(index, [_documents count] - 1)]];
00310 }
00311
00312 - (void)removeDocumentAndCloseIfNecessary:(CPDocument)aDocument
00313 {
00314 [self removeDocument:aDocument];
00315
00316 if (![_documents count])
00317 [self close];
00318 }
00319
00320 - (CPArray)documents
00321 {
00322 return _documents;
00323 }
00324
00325 - (void)setViewControllerContainerView:(CPView)aView
00326 {
00327 _viewControllerContainerView = aView;
00328 }
00329
00330 - (void)viewControllerContainerView
00331 {
00332 return _viewControllerContainerView;
00333 }
00334
00335 - (void)setViewController:(CPViewController)aViewController
00336 {
00337 var containerView = [self viewControllerContainerView] || [[self window] contentView],
00338 view = [_viewController view],
00339 frame = view ? [view frame] : [containerView bounds];
00340
00341 [view removeFromSuperview];
00342
00343 _viewController = aViewController;
00344
00345 view = [_viewController view];
00346
00347 if (view)
00348 {
00349 [view setFrame:frame];
00350 [containerView addSubview:view];
00351 }
00352 }
00353
00354 - (CPViewController)viewController
00355 {
00356 return _viewController;
00357 }
00358
00359
00360 - (void)_documentWillSave:(CPNotification)aNotification
00361 {
00362 [[self window] setDocumentSaving:YES];
00363 }
00364
00365
00366 - (void)_documentDidSave:(CPNotification)aNotification
00367 {
00368 [[self window] setDocumentSaving:NO];
00369 }
00370
00371
00372 - (void)_documentDidFailToSave:(CPNotification)aNotification
00373 {
00374 [[self window] setDocumentSaving:NO];
00375 }
00376
00380 - (CPDocument)document
00381 {
00382 return _document;
00383 }
00384
00389 - (void)setDocumentEdited:(BOOL)isEdited
00390 {
00391 [[self window] setDocumentEdited:isEdited];
00392 }
00393
00394 - (void)close
00395 {
00396 [[self window] close];
00397 }
00398
00399 - (void)setShouldCloseDocument:(BOOL)shouldCloseDocument
00400 {
00401 _shouldCloseDocument = shouldCloseDocument;
00402 }
00403
00404 - (BOOL)shouldCloseDocument
00405 {
00406 return _shouldCloseDocument;
00407 }
00408
00409 - (id)owner
00410 {
00411 return _cibOwner;
00412 }
00413
00414 - (CPString)windowCibName
00415 {
00416 if (_windowCibName)
00417 return _windowCibName;
00418
00419 return [[_windowCibPath lastPathComponent] stringByDeletingPathExtension];
00420 }
00421
00422 - (CPString)windowCibPath
00423 {
00424 if (_windowCibPath)
00425 return _windowCibPath;
00426
00427 return [[CPBundle bundleForClass:[_cibOwner class]] pathForResource:_windowCibName + @".cib"];
00428 }
00429
00430
00431
00435 - (void)synchronizeWindowTitleWithDocumentName
00436 {
00437 if (!_document || !_window)
00438 return;
00439
00440
00441 [_window setTitle:[self windowTitleForDocumentDisplayName:[_document displayName]]];
00442 }
00443
00448 - (CPString)windowTitleForDocumentDisplayName:(CPString)aDisplayName
00449 {
00450 return aDisplayName;
00451 }
00452
00453 @end