Clean up and completion of NSDocumentController.

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@27415 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
fredkiefer 2008-12-25 13:21:22 +00:00
parent 4a710daca9
commit 6cfee381c1
4 changed files with 572 additions and 314 deletions

View file

@ -1,3 +1,13 @@
2008-12-25 Fred Kiefer <FredKiefer@gmx.de>
* Headers/AppKit/NSMenuItem.h: Declare to implement interface
NSValidatedUserInterfaceItem.
* Headers/AppKit/NSDocumentController.h: Change to use NSUInteger and
NSInteger.
* Source/NSDocumentController.m: Implement all Cocoa methods of this
class and clean up the rest of the implementation.
Partly using code by Nikolaus Schaller <hns@computer.org>.
2008-12-21 Adam Fedor <fedor@gnu.org> 2008-12-21 Adam Fedor <fedor@gnu.org>
* Version 0.16.0 * Version 0.16.0

View file

@ -48,7 +48,7 @@
@class NSOpenPanel; @class NSOpenPanel;
@class NSWindow; @class NSWindow;
@interface NSDocumentController : NSObject @interface NSDocumentController : NSObject <NSCoding>
{ {
@private @private
NSMutableArray *_documents; NSMutableArray *_documents;
@ -111,7 +111,7 @@
- (IBAction)newDocument:(id)sender; - (IBAction)newDocument:(id)sender;
- (IBAction)clearRecentDocuments:(id)sender; - (IBAction)clearRecentDocuments:(id)sender;
#if OS_API_VERSION(MAC_OS_X_VERSION_10_4, GS_API_LATEST) #if OS_API_VERSION(MAC_OS_X_VERSION_10_4, GS_API_LATEST)
- (unsigned int) maximumRecentDocumentCount; - (NSUInteger) maximumRecentDocumentCount;
#endif #endif
/*" Recent Documents "*/ /*" Recent Documents "*/
@ -122,7 +122,7 @@
/*" Open panel "*/ /*" Open panel "*/
- (NSArray *)URLsFromRunningOpenPanel; - (NSArray *)URLsFromRunningOpenPanel;
- (NSArray *)fileNamesFromRunningOpenPanel; - (NSArray *)fileNamesFromRunningOpenPanel;
- (int)runModalOpenPanel:(NSOpenPanel *)openPanel forTypes:(NSArray *)openableFileExtensions; - (NSInteger)runModalOpenPanel:(NSOpenPanel *)openPanel forTypes:(NSArray *)openableFileExtensions;
/*" Document management "*/ /*" Document management "*/
- (void)addDocument:(NSDocument *)document; - (void)addDocument:(NSDocument *)document;

View file

@ -35,6 +35,7 @@
#import <GNUstepBase/GSVersionMacros.h> #import <GNUstepBase/GSVersionMacros.h>
#include <Foundation/NSObject.h> #include <Foundation/NSObject.h>
#include <AppKit/NSUserInterfaceValidation.h>
@class NSAttributedString; @class NSAttributedString;
@class NSString; @class NSString;
@ -367,7 +368,7 @@
@end @end
@interface NSMenuItem : NSObject <NSMenuItem> @interface NSMenuItem : NSObject <NSMenuItem, NSValidatedUserInterfaceItem>
{ {
NSMenu *_menu; NSMenu *_menu;
NSString *_title; NSString *_title;

View file

@ -41,6 +41,7 @@
#include "AppKit/NSDocumentController.h" #include "AppKit/NSDocumentController.h"
#include "AppKit/NSOpenPanel.h" #include "AppKit/NSOpenPanel.h"
#include "AppKit/NSApplication.h" #include "AppKit/NSApplication.h"
#include "AppKit/NSMenu.h"
#include "AppKit/NSMenuItem.h" #include "AppKit/NSMenuItem.h"
#include "AppKit/NSWorkspace.h" #include "AppKit/NSWorkspace.h"
#include "NSDocumentFrameworkPrivate.h" #include "NSDocumentFrameworkPrivate.h"
@ -61,8 +62,14 @@ static NSString *CFBundleTypeExtensions = @"CFBundleTypeExtensions";
static NSString *CFBundleTypeName = @"CFBundleTypeName"; static NSString *CFBundleTypeName = @"CFBundleTypeName";
static NSString *CFBundleTypeRole = @"CFBundleTypeRole"; static NSString *CFBundleTypeRole = @"CFBundleTypeRole";
// FIXME: Looks like this was changed to @"NSRecentDocumentRecords"
static NSString *NSRecentDocuments = @"NSRecentDocuments"; static NSString *NSRecentDocuments = @"NSRecentDocuments";
static NSString *NSEditorRole = @"Editor";
static NSString *NSViewerRole = @"Viewer";
//static NSString *NSNoRole = @"None";
//static NSString *NSShellRole = @"Shell";
static NSDocumentController *sharedController = nil; static NSDocumentController *sharedController = nil;
#define TYPE_INFO(name) TypeInfoForName(_types, name) #define TYPE_INFO(name) TypeInfoForName(_types, name)
@ -108,6 +115,14 @@ static NSDictionary *TypeInfoForHumanReadableName (NSArray *types, NSString *typ
return nil; return nil;
} }
@interface NSDocumentController (RecentsMenu)
- (NSMenu *) _recentMenu;
- (void) _updateOpenRecentMenu;
- (IBAction) _openRecentDocument: (id)sender;
@end
/** <p> /** <p>
NSDocumentController is a class that controls a set of NSDocuments NSDocumentController is a class that controls a set of NSDocuments
for an application. As an application delegate, it responds to the for an application. As an application delegate, it responds to the
@ -159,7 +174,8 @@ static NSDictionary *TypeInfoForHumanReadableName (NSArray *types, NSString *typ
{ {
if (sharedController == nil) if (sharedController == nil)
{ {
sharedController = [[self alloc] init]; // -init sets sharedController
[[self alloc] init];
} }
return sharedController; return sharedController;
@ -256,12 +272,13 @@ static NSDictionary *TypeInfoForHumanReadableName (NSArray *types, NSString *typ
IMP meth2; IMP meth2;
meth1 = [self methodForSelector: sel]; meth1 = [self methodForSelector: sel];
meth2 = [[NSDocument class] instanceMethodForSelector: sel]; meth2 = [[NSDocumentController class] instanceMethodForSelector: sel];
return (meth1 != meth2); return (meth1 != meth2);
} }
#define OVERRIDDEN(sel) [self _hasOverridden: @selector(sel)] //#define OVERRIDDEN(sel) [self _hasOverridden: @selector(sel)]
#define OVERRIDDEN(sel) ([self methodForSelector: @selector(sel)] != [[NSDocumentController class] instanceMethodForSelector: @selector(sel)])
- (BOOL) shouldCreateUI - (BOOL) shouldCreateUI
{ {
@ -331,6 +348,13 @@ static NSDictionary *TypeInfoForHumanReadableName (NSArray *types, NSString *typ
error: (NSError **)err error: (NSError **)err
{ {
Class documentClass = [self documentClassForType: type]; Class documentClass = [self documentClassForType: type];
if (documentClass == nil)
{
// FIXME: Set err
return nil;
}
return AUTORELEASE([[documentClass alloc] initForURL: url return AUTORELEASE([[documentClass alloc] initForURL: url
withContentsOfURL: contents withContentsOfURL: contents
ofType: type ofType: type
@ -340,20 +364,40 @@ static NSDictionary *TypeInfoForHumanReadableName (NSArray *types, NSString *typ
- (id) makeDocumentWithContentsOfURL: (NSURL *)url - (id) makeDocumentWithContentsOfURL: (NSURL *)url
ofType: (NSString *)type ofType: (NSString *)type
error: (NSError **)err error: (NSError **)err
{
if (OVERRIDDEN(makeDocumentWithContentsOfFile:ofType:) && [url isFileURL])
{
return [self makeDocumentWithContentsOfFile: [url path] ofType: type];
}
else
{ {
Class documentClass = [self documentClassForType: type]; Class documentClass = [self documentClassForType: type];
if (documentClass == nil)
{
// FIXME: Set err
return nil;
}
return AUTORELEASE([[documentClass alloc] initWithContentsOfURL: url return AUTORELEASE([[documentClass alloc] initWithContentsOfURL: url
ofType: type ofType: type
error: err]); error: err]);
} }
}
- (id) makeUntitledDocumentOfType: (NSString *)type - (id) makeUntitledDocumentOfType: (NSString *)type
error: (NSError **)err error: (NSError **)err
{
if (OVERRIDDEN(makeUntitledDocumentOfType:))
{
return [self makeUntitledDocumentOfType: type];
}
else
{ {
Class documentClass = [self documentClassForType: type]; Class documentClass = [self documentClassForType: type];
return AUTORELEASE([[documentClass alloc] initWithType: type return AUTORELEASE([[documentClass alloc] initWithType: type
error: err]); error: err]);
} }
}
- (BOOL) presentError: (NSError *)error - (BOOL) presentError: (NSError *)error
{ {
@ -383,19 +427,32 @@ static NSDictionary *TypeInfoForHumanReadableName (NSArray *types, NSString *typ
- (NSString*) defaultType - (NSString*) defaultType
{ {
NSString *defaultName = nil; NSString *defaultName = nil;
if ([_types count] == 0) int i, count = [_types count];
{
return nil; // raise exception?
}
defaultName = [(NSDictionary*)[_types objectAtIndex: 0] objectForKey: NSNameKey]; for (i = 0; i < count; i++)
{
NSDictionary *typeInfo = (NSDictionary*)[_types objectAtIndex: i];
NSString *role;
role = [typeInfo objectForKey: NSRoleKey];
if (role == nil)
role = [typeInfo objectForKey: CFBundleTypeRole];
if ([role isEqual: NSEditorRole])
{
defaultName = [typeInfo objectForKey: NSNameKey];
if (defaultName == nil) if (defaultName == nil)
{ {
defaultName = [(NSDictionary*)[_types objectAtIndex: 0] objectForKey: CFBundleTypeName]; defaultName = [typeInfo objectForKey: CFBundleTypeName];
} }
return defaultName; return defaultName;
} }
}
// none found
return nil;
}
- (void) addDocument: (NSDocument *)document - (void) addDocument: (NSDocument *)document
{ {
@ -477,9 +534,7 @@ static NSDictionary *TypeInfoForHumanReadableName (NSArray *types, NSString *typ
if (document == nil) if (document == nil)
{ {
// Should we only do this if [url isFileURL] is YES? NSString *type = [self typeForContentsOfURL: url error: NULL];
NSString *type = [self typeFromFileExtension:
[[url path] pathExtension]];
document = [self makeDocumentWithContentsOfURL: url ofType: type]; document = [self makeDocumentWithContentsOfURL: url ofType: type];
@ -543,12 +598,10 @@ static NSDictionary *TypeInfoForHumanReadableName (NSArray *types, NSString *typ
display: (BOOL)display display: (BOOL)display
error: (NSError **)err error: (NSError **)err
{ {
if (OVERRIDDEN(openDocumentWithContentsOfFile:display:)) if (OVERRIDDEN(openDocumentWithContentsOfFile:display:) && [url isFileURL])
{ {
NSString *fileName; return [self openDocumentWithContentsOfFile: [url path]
display: display];
fileName = [url path];
return [self openDocumentWithContentsOfFile: fileName display: display];
} }
else else
{ {
@ -556,11 +609,16 @@ static NSDictionary *TypeInfoForHumanReadableName (NSArray *types, NSString *typ
if (document == nil) if (document == nil)
{ {
// Should we only do this if [url isFileURL] is YES? NSString *type = [self typeForContentsOfURL: url error: err];
NSString *type = [self typeFromFileExtension:
[[url path] pathExtension]];
document = [self makeDocumentWithContentsOfURL: url ofType: type error: err]; if (type == nil)
{
return nil;
}
document = [self makeDocumentWithContentsOfURL: url
ofType: type
error: err];
if (document == nil) if (document == nil)
{ {
@ -591,12 +649,15 @@ static NSDictionary *TypeInfoForHumanReadableName (NSArray *types, NSString *typ
withContentsOfURL: (NSURL *)contents withContentsOfURL: (NSURL *)contents
error: (NSError **)err error: (NSError **)err
{ {
if ([contents isFileURL]) NSString *type = [self typeForContentsOfURL: contents error: err];
id document;
if (type == nil)
{ {
NSString *type = return NO;
[self typeFromFileExtension: [[contents path] pathExtension]]; }
id document =
[self makeDocumentForURL: url document = [self makeDocumentForURL: url
withContentsOfURL: contents withContentsOfURL: contents
ofType: type ofType: type
error: err]; error: err];
@ -610,12 +671,6 @@ static NSDictionary *TypeInfoForHumanReadableName (NSArray *types, NSString *typ
} }
return YES; return YES;
} }
}
else
{
// FIXME: set error
*err = nil;
}
return NO; return NO;
} }
@ -623,6 +678,7 @@ static NSDictionary *TypeInfoForHumanReadableName (NSArray *types, NSString *typ
- (NSOpenPanel *) _setupOpenPanel - (NSOpenPanel *) _setupOpenPanel
{ {
NSOpenPanel *openPanel = [NSOpenPanel openPanel]; NSOpenPanel *openPanel = [NSOpenPanel openPanel];
[openPanel setDirectory: [self currentDirectory]]; [openPanel setDirectory: [self currentDirectory]];
[openPanel setAllowsMultipleSelection: YES]; [openPanel setAllowsMultipleSelection: YES];
return openPanel; return openPanel;
@ -631,7 +687,7 @@ static NSDictionary *TypeInfoForHumanReadableName (NSArray *types, NSString *typ
/** Invokes [NSOpenPanel-runModalForTypes:] with the NSOpenPanel /** Invokes [NSOpenPanel-runModalForTypes:] with the NSOpenPanel
object openPanel, and passes the openableFileExtensions file types object openPanel, and passes the openableFileExtensions file types
*/ */
- (int) runModalOpenPanel: (NSOpenPanel *)openPanel - (NSInteger) runModalOpenPanel: (NSOpenPanel *)openPanel
forTypes: (NSArray *)openableFileExtensions forTypes: (NSArray *)openableFileExtensions
{ {
return [openPanel runModalForTypes: openableFileExtensions]; return [openPanel runModalForTypes: openableFileExtensions];
@ -645,6 +701,7 @@ static NSDictionary *TypeInfoForHumanReadableName (NSArray *types, NSString *typ
for (i = 0; i < count; i++) for (i = 0; i < count; i++)
{ {
NSDictionary *typeInfo = [_types objectAtIndex: i]; NSDictionary *typeInfo = [_types objectAtIndex: i];
[array addObjectsFromArray: [typeInfo objectForKey: NSUnixExtensionsKey]]; [array addObjectsFromArray: [typeInfo objectForKey: NSUnixExtensionsKey]];
[array addObjectsFromArray: [typeInfo objectForKey: NSDOSExtensionsKey]]; [array addObjectsFromArray: [typeInfo objectForKey: NSDOSExtensionsKey]];
[array addObjectsFromArray: [typeInfo objectForKey: CFBundleTypeExtensions]]; [array addObjectsFromArray: [typeInfo objectForKey: CFBundleTypeExtensions]];
@ -687,7 +744,6 @@ static NSDictionary *TypeInfoForHumanReadableName (NSArray *types, NSString *typ
return nil; return nil;
} }
- (IBAction) saveAllDocuments: (id)sender - (IBAction) saveAllDocuments: (id)sender
{ {
NSDocument *document; NSDocument *document;
@ -702,23 +758,30 @@ static NSDictionary *TypeInfoForHumanReadableName (NSArray *types, NSString *typ
} }
} }
- (IBAction) openDocument: (id)sender - (IBAction) openDocument: (id)sender
{ {
NSEnumerator *fileEnum; NSError *err = nil;
NSString *filename; NSEnumerator *urlEnum;
NSURL *url;
fileEnum = [[self fileNamesFromRunningOpenPanel] objectEnumerator]; urlEnum = [[self URLsFromRunningOpenPanel] objectEnumerator];
while ((url = [urlEnum nextObject]))
while ((filename = [fileEnum nextObject]))
{ {
[self openDocumentWithContentsOfFile: filename display: YES]; [self openDocumentWithContentsOfURL: url display: YES error: &err];
if (err && ![self presentError: err])
{
break;
}
} }
} }
- (IBAction) newDocument: (id)sender - (IBAction) newDocument: (id)sender
{ {
[self openUntitledDocumentOfType: [self defaultType] display: YES]; NSError *err = nil;
[self openUntitledDocumentAndDisplay: YES error: &err];
if (err)
[self presentError: err];
} }
@ -748,11 +811,59 @@ static NSDictionary *TypeInfoForHumanReadableName (NSArray *types, NSString *typ
return YES; return YES;
} }
// FIXME
static BOOL _shouldClose = YES;
- (void) _document: (NSDocument *)doc
shouldClose: (BOOL)shouldClose
contextInfo: (void *)contextInfo
{
_shouldClose = shouldClose;
}
- (void)closeAllDocumentsWithDelegate:(id)delegate - (void)closeAllDocumentsWithDelegate:(id)delegate
didCloseAllSelector:(SEL)didAllCloseSelector didCloseAllSelector:(SEL)didAllCloseSelector
contextInfo:(void *)contextInfo contextInfo:(void *)contextInfo
{ {
//FIXME int count;
BOOL closeAll = YES;
count = [_documents count];
if (count > 0)
{
NSDocument *array[count];
[_documents getObjects: array];
while (count-- > 0)
{
NSDocument *document = array[count];
// Initialize to known state
_shouldClose = YES;
[document canCloseDocumentWithDelegate: self
shouldCloseSelector:
@selector(_document:shouldClose:contextInfo:)
contextInfo: contextInfo];
if (_shouldClose)
{
[document close];
}
else
{
closeAll = NO;
}
}
}
if (delegate != nil && didAllCloseSelector != NULL)
{
void (*meth)(id, SEL, id, BOOL, void*);
meth = (void (*)(id, SEL, id, BOOL, void*))[delegate methodForSelector:
didAllCloseSelector];
if (meth)
meth(delegate, didAllCloseSelector, self, closeAll, contextInfo);
}
} }
/** If there are any unsaved documents, this method displays an alert /** If there are any unsaved documents, this method displays an alert
@ -800,7 +911,34 @@ static NSDictionary *TypeInfoForHumanReadableName (NSArray *types, NSString *typ
didReviewAllSelector: (SEL)didReviewAllSelector didReviewAllSelector: (SEL)didReviewAllSelector
contextInfo: (void *)contextInfo contextInfo: (void *)contextInfo
{ {
NSString *cancelString = (cancellable)? ((NSString *)_(@"Cancel")) : ((NSString *)nil);
int result = YES;
if (![self hasEditedDocuments])
{
if (delegate != nil && didReviewAllSelector != NULL)
{
void (*meth)(id, SEL, id, BOOL, void*);
meth = (void (*)(id, SEL, id, BOOL, void*))[delegate methodForSelector:
didReviewAllSelector];
if (meth)
meth(delegate, didReviewAllSelector, self, result, contextInfo);
}
return;
}
// FIXME // FIXME
NSBeginAlertSheet(title,
_(@"Review Unsaved"),
cancelString,
_(@"Quit Anyway"),
nil,
delegate,
didReviewAllSelector,
contextInfo,
_(@"You have unsaved documents"),
nil);
} }
@ -845,7 +983,6 @@ static NSDictionary *TypeInfoForHumanReadableName (NSArray *types, NSString *typ
[self reviewUnsavedDocumentsWithAlertTitle: _(@"Power Off") cancellable: NO]; [self reviewUnsavedDocumentsWithAlertTitle: _(@"Power Off") cancellable: NO];
} }
/** Returns an array of all open documents */ /** Returns an array of all open documents */
- (NSArray *) documents - (NSArray *) documents
{ {
@ -958,12 +1095,9 @@ static NSDictionary *TypeInfoForHumanReadableName (NSArray *types, NSString *typ
- (id) documentForURL: (NSURL *)url - (id) documentForURL: (NSURL *)url
{ {
if (OVERRIDDEN(documentForFileName:)) if (OVERRIDDEN(documentForFileName:) && [url isFileURL])
{ {
NSString *fileName; return [self documentForFileName: [url path]];
fileName = [url path];
return [self documentForFileName: fileName];
} }
else else
{ {
@ -985,23 +1119,30 @@ static NSDictionary *TypeInfoForHumanReadableName (NSArray *types, NSString *typ
- (BOOL) validateMenuItem: (NSMenuItem *)anItem - (BOOL) validateMenuItem: (NSMenuItem *)anItem
{ {
if ([anItem action] == @selector(saveAllDocuments:)) return [self validateUserInterfaceItem: anItem];
}
- (BOOL) validateUserInterfaceItem: (id <NSValidatedUserInterfaceItem>)anItem
{
if (sel_eq([anItem action], @selector(saveAllDocuments:)))
{ {
return [self hasEditedDocuments]; return [self hasEditedDocuments];
} }
return YES; return YES;
} }
- (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)anItem
{
// FIXME
return YES;
}
- (NSString *) displayNameForType: (NSString *)type - (NSString *) displayNameForType: (NSString *)type
{ {
// FIXME: Is this needed?
NSString *name = [TYPE_INFO(type) objectForKey: NSHumanReadableNameKey]; NSString *name = [TYPE_INFO(type) objectForKey: NSHumanReadableNameKey];
if (!name)
{
name = [[NSBundle mainBundle] localizedStringForKey: type
value: type
table: @"InfoPlist"];
}
return name ? name : type; return name ? name : type;
} }
@ -1021,6 +1162,7 @@ static NSDictionary *TypeInfoForHumanReadableName (NSArray *types, NSString *typ
containsObject: fileExtension]) containsObject: fileExtension])
{ {
NSString *type = [typeInfo objectForKey: NSNameKey]; NSString *type = [typeInfo objectForKey: NSNameKey];
if(type == nil) if(type == nil)
{ {
type = [typeInfo objectForKey: CFBundleTypeName]; type = [typeInfo objectForKey: CFBundleTypeName];
@ -1034,26 +1176,21 @@ static NSDictionary *TypeInfoForHumanReadableName (NSArray *types, NSString *typ
- (NSString *) typeForContentsOfURL: (NSURL *)url error: (NSError **)err - (NSString *) typeForContentsOfURL: (NSURL *)url error: (NSError **)err
{ {
// FIXME // FIXME: open connection and get response to determine mine/type
NSString *extension; // Should we only do this if [url isFileURL] is YES?
return [self typeFromFileExtension: [[url path] pathExtension]];
extension = [[url path] pathExtension];
return [self typeFromFileExtension: extension];
} }
- (NSArray *) fileExtensionsFromType: (NSString *)type - (NSArray *) fileExtensionsFromType: (NSString *)type
{ {
NSDictionary *typeInfo = TYPE_INFO(type); NSDictionary *typeInfo = TYPE_INFO(type);
NSArray *unixExtensions = [typeInfo objectForKey: NSUnixExtensionsKey]; NSMutableArray *array = [NSMutableArray arrayWithCapacity: 3];
NSArray *dosExtensions = [typeInfo objectForKey: NSDOSExtensionsKey];
NSArray *cfFileExtensions = [typeInfo objectForKey: CFBundleTypeExtensions];
if (!dosExtensions && !unixExtensions) return cfFileExtensions; [array addObjectsFromArray: [typeInfo objectForKey: NSUnixExtensionsKey]];
if (!dosExtensions) return unixExtensions; [array addObjectsFromArray: [typeInfo objectForKey: NSDOSExtensionsKey]];
if (!unixExtensions) return dosExtensions; [array addObjectsFromArray: [typeInfo objectForKey: CFBundleTypeExtensions]];
return [[unixExtensions arrayByAddingObjectsFromArray: dosExtensions] return array;
arrayByAddingObjectsFromArray: cfFileExtensions];
} }
- (Class) documentClassForType: (NSString *)type - (Class) documentClassForType: (NSString *)type
@ -1095,18 +1232,19 @@ static NSDictionary *TypeInfoForHumanReadableName (NSArray *types, NSString *typ
[_recent_documents removeAllObjects]; [_recent_documents removeAllObjects];
[[NSUserDefaults standardUserDefaults] [[NSUserDefaults standardUserDefaults]
setObject: _recent_documents forKey: NSRecentDocuments]; setObject: _recent_documents forKey: NSRecentDocuments];
[self _updateOpenRecentMenu];
} }
// The number of remembered recent documents // The number of remembered recent documents
- (unsigned int) maximumRecentDocumentCount - (NSUInteger) maximumRecentDocumentCount
{ {
// FIXME: Should come from user defaults
return 5; return 5;
} }
- (void) noteNewRecentDocument: (NSDocument *)aDocument - (void) noteNewRecentDocument: (NSDocument *)aDocument
{ {
NSString *fileName = [aDocument fileName]; NSURL *anURL = [aDocument fileURL];
NSURL *anURL = [NSURL fileURLWithPath: fileName];
if (anURL != nil) if (anURL != nil)
[self noteNewRecentDocumentURL: anURL]; [self noteNewRecentDocumentURL: anURL];
@ -1129,6 +1267,7 @@ static NSDictionary *TypeInfoForHumanReadableName (NSArray *types, NSString *typ
[_recent_documents addObject: anURL]; [_recent_documents addObject: anURL];
// Save the changed list
a = [_recent_documents mutableCopy]; a = [_recent_documents mutableCopy];
index = [a count]; index = [a count];
while (index-- > 0) while (index-- > 0)
@ -1139,6 +1278,7 @@ static NSDictionary *TypeInfoForHumanReadableName (NSArray *types, NSString *typ
[[NSUserDefaults standardUserDefaults] [[NSUserDefaults standardUserDefaults]
setObject: a forKey: NSRecentDocuments]; setObject: a forKey: NSRecentDocuments];
RELEASE(a); RELEASE(a);
[self _updateOpenRecentMenu];
} }
- (NSArray *) recentDocumentURLs - (NSArray *) recentDocumentURLs
@ -1146,12 +1286,23 @@ static NSDictionary *TypeInfoForHumanReadableName (NSArray *types, NSString *typ
return _recent_documents; return _recent_documents;
} }
//
// NSCoding protocol
//
- (void) encodeWithCoder: (NSCoder*)aCoder
{
// FIXME
}
- (id) initWithCoder: (NSCoder*)aDecoder
{
// FIXME
return self;
}
@end @end
@implementation NSDocumentController (Private) @implementation NSDocumentController (Private)
static NSString *NSEditorRole = @"Editor";
static NSString *NSViewerRole = @"Viewer";
//static NSString *NSNoRole = @"None";
- (NSArray *) _editorAndViewerTypesForClass: (Class)documentClass - (NSArray *) _editorAndViewerTypesForClass: (Class)documentClass
{ {
@ -1177,6 +1328,7 @@ static NSString *NSViewerRole = @"Viewer";
|| [role isEqual: NSViewerRole])) || [role isEqual: NSViewerRole]))
{ {
NSString *name = [typeInfo objectForKey: NSNameKey]; NSString *name = [typeInfo objectForKey: NSNameKey];
if(name == nil) if(name == nil)
{ {
name = [typeInfo objectForKey: CFBundleTypeName]; name = [typeInfo objectForKey: CFBundleTypeName];
@ -1200,10 +1352,17 @@ static NSString *NSViewerRole = @"Viewer";
NSString *className = [typeInfo objectForKey: NSDocumentClassKey]; NSString *className = [typeInfo objectForKey: NSDocumentClassKey];
NSString *role = [typeInfo objectForKey: NSRoleKey]; NSString *role = [typeInfo objectForKey: NSRoleKey];
// if the standard one isn't filled... check the CF key.
if (role == nil)
{
role = [typeInfo objectForKey: CFBundleTypeRole];
}
if ([docClassName isEqualToString: className] && if ([docClassName isEqualToString: className] &&
(role == nil || [role isEqual: NSEditorRole])) (role == nil || [role isEqual: NSEditorRole]))
{ {
NSString *name = [typeInfo objectForKey: NSNameKey]; NSString *name = [typeInfo objectForKey: NSNameKey];
if(name == nil) if(name == nil)
{ {
name = [typeInfo objectForKey: CFBundleTypeName]; name = [typeInfo objectForKey: CFBundleTypeName];
@ -1393,3 +1552,91 @@ static NSString *processName;
} }
@end @end
@implementation NSDocumentController (RecentsMenu)
- (NSMenu *) _recentMenu
{
// FIXME
return nil;
}
// should be handled by making us the delegate of the recent's menu
- (void) _updateOpenRecentMenu
{
NSMenu *recentMenu;
int i;
recentMenu = [self _recentMenu];
if (!recentMenu)
{
return;
}
// don't update (to keep Clear List status consistent)
[recentMenu setAutoenablesItems: NO];
[recentMenu setMenuChangedMessagesEnabled: NO];
while ([recentMenu numberOfItems] > 0)
[recentMenu removeItemAtIndex: 0]; // remove them all
for (i = [_recent_documents count]; i >= -2; i--)
{
// add all items incl. a Clear List item if needed
NSMenuItem *item;
if (i == -1)
{
if ([_recent_documents count] == 0)
continue; // skip if menu is empty
item = (NSMenuItem *) [NSMenuItem separatorItem];
// will release...
RETAIN(item);
}
else if (i == -2)
{
item = [[NSMenuItem alloc] initWithTitle: _(@"Clear List")
action: @selector(clearRecentDocuments:)
keyEquivalent: nil];
// disable for empty list
[item setEnabled: [_recent_documents count] > 0];
}
else
{
// standard item
NSURL *u = [_recent_documents objectAtIndex: i]; // get URL
if ([u isFileURL])
item = [[NSMenuItem alloc] initWithTitle: [[u path] lastPathComponent]
action: @selector(_openRecentDocument:)
keyEquivalent:nil];
else
item = [[NSMenuItem alloc] initWithTitle: [u relativeString]
action: @selector(_openRecentDocument:)
keyEquivalent:nil];
[item setTag: i];
}
[item setTarget: self];
[recentMenu addItem: item];
RELEASE(item);
}
[recentMenu setMenuChangedMessagesEnabled: YES];
}
- (IBAction) _openRecentDocument: (id)sender
{
// action to open recent document by tag index
NSURL *url;
int idx = [sender tag];
if (idx < 0 || idx >= [_recent_documents count])
{
// something went wrong, ignore
[self _updateOpenRecentMenu];
return;
}
url = (NSURL *)[_recent_documents objectAtIndex: idx];
[self openDocumentWithContentsOfURL: url display: YES];
}
@end