Rev 3858 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
/** R.app : a Cocoa front end to: "R A Computer Language for Statistical Data Analysis"** R.app Copyright notes:* Copyright (C) 2004-5 The R Foundation* written by Stefano M. Iacus and Simon Urbanek* RDocumentController written by Rob Goedman*** R Copyright notes:* Copyright (C) 1995-1996 Robert Gentleman and Ross Ihaka* Copyright (C) 1998-2001 The R Development Core Team* Copyright (C) 2002-2004 The R Foundation** This program is free software; you can redistribute it and/or modify* it under the terms of the GNU General Public License as published by* the Free Software Foundation; either version 2 of the License, or* (at your option) any later version.** This program is distributed in the hope that it will be useful,* but WITHOUT ANY WARRANTY; without even the implied warranty of* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the* GNU General Public License for more details.** A copy of the GNU General Public License is available via WWW at* http://www.gnu.org/copyleft/gpl.html. You can also obtain it by* writing to the Free Software Foundation, Inc., 59 Temple Place,* Suite 330, Boston, MA 02111-1307 USA.*/#import "RGUI.h"#import "RDocumentController.h"#import "RController.h"#import "Preferences.h"#import "PreferenceKeys.h"// R defines "error" which is deadly as we use open ... with ... error: where error then gets replaced by Rf_error#ifdef error#undef error#endif@interface RDocumentController (Private)int docListLimit = 128; // limit for the number of transitions storedint docListPos = 0; // active position in the listNSDocument **docList; // list of activated documentsNSDocument *mainDoc; // dummy document representing the main R window in the list@end@implementation RDocumentController- (id)init {self = [super init];SLog(@"RDocumentController%@.init", self);mainDoc = [[NSDocument alloc] init];docList = (NSDocument**) malloc(sizeof(NSDocument*) * docListLimit);memset(docList, 0, sizeof(NSDocument*) * docListLimit);[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(windowDidBecomeKeyNotifications:) name:NSWindowDidBecomeKeyNotification object:nil];return self;}- (void) dealloc {[[NSNotificationCenter defaultCenter] removeObserver:self];free(docList);[mainDoc release];[super dealloc];}- (void)windowDidBecomeKeyNotifications:(NSNotification*) aNotification{NSWindow *w = [aNotification object];if (w) {SLog(@"RDocumentController%@.windowDidBecomeKeyNotifications:%@", self, w);NSDocument *d = [self documentForWindow:w];if (!d && w == [[RController sharedController] window]) d = mainDoc;if (d) {SLog(@" - document: %@", d);if (docList[docListPos] && docList[docListPos]!=d) {docListPos++;if (docListPos<0 || docListPos>=docListLimit) docListPos=0;}docList[docListPos]=d;}}}- (NSWindow*) walkKeyListBack{docListPos--;if (docListPos<0) {docListPos = docListLimit - 1;while (docListPos>=0 && !docList[docListPos]) docListPos--;if (docListPos<0) docListPos=0;}NSDocument *d = docList[docListPos];NSWindow *w = nil;SLog(@" - walkKeyListBack: doc=%@", d);if (!d || d==mainDoc) return [[RController sharedController] window];NSArray *a = [d windowControllers];if (a && [a count]>0)w = [[a objectAtIndex:0] window];elsew = [[RController sharedController] window];return w;}- (NSWindow*) findLastDocType: (NSString*) aType{SLog(@"RDocumentController%@.findLastDocType: %@", self, aType);int i=docListPos;while(1) {i--;if (i<0) {i = docListLimit - 1;while (i>=0 && !docList[i]) i--;if (i<0) i=0;}if (i==docListPos) break; // we're in a loopNSString *dt = [docList[i] fileType];if (dt) {SLog(@" * %@ -> %@", docList[i], dt);if ([dt isEqualToString:aType]) break;}}NSDocument *d = docList[i];if (!d || d==mainDoc) return [[RController sharedController] window];NSArray *a = [d windowControllers];if (a && [a count]>0)return [[a objectAtIndex:0] window];return [[RController sharedController] window];}- (NSWindow*) walkKeyListForward{docListPos++;if (docListPos >= docListLimit) docListPos=0;NSDocument *d = docList[docListPos];NSWindow *w = nil;if (!d || d==mainDoc) return [[RController sharedController] window];NSArray *a = [d windowControllers];if (a && [a count]>0)w = [[a objectAtIndex:0] window];elsew = [[RController sharedController] window];return w;}- (IBAction)newDocument:(id)sender {BOOL useInternalEditor = [Preferences flagForKey:internalOrExternalKey withDefault: YES];if (!useInternalEditor) {[self invokeExternalForFile: @""];return;}[super newDocument:sender];}- (id) openDocumentWithContentsOfURL:(NSURL *)absoluteURL display:(BOOL)displayDocument error:(NSError **)theError {if (absoluteURL == nil) {SLog(@"RDocumentController.openDocumentWithContentsOfURL with null URL. Nothing to do.");return nil;}NSString *aFile = [[absoluteURL path] stringByExpandingTildeInPath];SLog(@"RDocumentController.openDocumentWithContentsOfURL: %@", aFile);int res = [[RController sharedController] isImageData: aFile];if (res == 0 ) {SLog(@" - detected save image, invoking load instead of the editor");[[RController sharedController] sendInput: [NSString stringWithFormat:@"load(\"%@\")", aFile]];return nil;}BOOL useInternalEditor = [Preferences flagForKey:internalOrExternalKey withDefault: YES];if (!useInternalEditor) {SLog(@" - external editor is enabled, passing over to invokeExternalForFile");[self invokeExternalForFile:aFile];return nil;}SLog(@" - call super -> openDocumentWithContentsOfURL: %@", aFile);NSDocument *doc = nil;doc = [super openDocumentWithContentsOfURL:absoluteURL display:displayDocument error:theError];if (doc == nil) {/* WARNING: this is a hack for cases where the document typecannot be determined. Since we're replicating Cocoa functionality this may breakwith future versions of Cocoa. */SLog(@" - creating manually");doc = [self makeDocumentWithContentsOfFile:aFile ofType:defaultDocumentType];if (doc) {SLog(@" - succeeded by calling makeDocument.. ofType: %@", defaultDocumentType);[self addDocument:doc];[doc makeWindowControllers];if (displayDocument && [self shouldCreateUI]) [doc showWindows];} else {SLog(@" * failed, returning nil");}}return doc;}- (void) invokeExternalForFile:(NSString*)aFile{NSString *externalEditor = [NSString stringWithFormat:@"\"%@\"", [Preferences stringForKey:externalEditorNameKey withDefault: @"TextEdit"]];NSString *cmd;BOOL editorIsApp = [Preferences flagForKey:appOrCommandKey withDefault: YES];if (!aFile) aFile=@"";if (editorIsApp) {cmd = [@"open -a " stringByAppendingString:externalEditor];if (![aFile isEqualToString:@""])cmd = [cmd stringByAppendingString: [NSString stringWithFormat:@" \"%@\"", aFile]];} else {cmd = externalEditor;if (![aFile isEqualToString:@""])cmd = [cmd stringByAppendingString: [NSString stringWithString: [NSString stringWithFormat:@" \"%@\"", aFile]]];}SLog(@" - call external: \"%@\"", cmd);system([cmd UTF8String]);}- (void)removeDocument:(NSDocument *)document {int i=0, j=0, newPos=0;SLog(@"RDocumentController(%@).removeDocument: %@\n", self, document);// remove all references of the document from the doc listwhile (i<docListLimit) {if (i==docListPos)newPos=(docList[i]==document)?j-1:j;if (docList[i] != document &&(j==0 || docList[j-1] != document)) { docList[j]=docList[i]; j++; };i++;}if (newPos<0) newPos=0;while (j<docListLimit) docList[j++]=nil;docListPos=newPos;[super removeDocument:document];}@end