This is DocController.m in view mode; [Download] [Up]
/* DocController.m * Purpose: This is the main controlling class for this application. * DocController loads the Info and Help nib files on demand. * DocController also handles the multiple documents that can * be open at any time using the Document class -- including * keeping a count, tracking the current active document, * managing the open and save panels, etc. * * You may freely copy, distribute, and reuse the code in this example. * NeXT disclaims any warranty of any kind, expressed or implied, as to its * fitness for any particular use. * * Written by: R. Dunbar Poor * Created: 28/April/1991 * */ #import "DocController.h" #import "Document.h" #import "Document.h" #import <appkit/Application.h> #import <appkit/Cell.h> #import <appkit/OpenPanel.h> #import <appkit/Panel.h> /* for NX_ALERTxxx */ #import <objc/List.h> #import <strings.h> #import <sys/param.h> @interface DocController(DocControllerPrivate) - _countDocuments:aDocument :sender; - _save:aDocument :sender; - _collectEditedDocuments:aDocument :editedDocuments; - _hide:aDocument :sender; @end @implementation DocController - init { [super init]; return self; } - free { return [super free]; } - showInfo:sender { if (!infoPanel) { [NXApp loadNibSection:"Info.nib" owner:self withNames:NO]; } [infoPanel makeKeyAndOrderFront:sender]; return self; } - showHelp:sender { if (!helpPanel) { [NXApp loadNibSection:"Help.nib" owner:self withNames:NO]; } [helpPanel makeKeyAndOrderFront:sender]; return self; } - activeDocument { return activeDocument; } - setActiveDocument:aDocument { char buf[100]; activeDocument = aDocument; /* display the message of the current document */ [activeDocumentField setStringValue:[activeDocument message]]; /* count and display the number of documents present */ documentCount = 0; [self performForDocuments:@selector(_countDocuments::) with:self]; sprintf(buf,"There %s %d active document%s.", documentCount==1?"is":"are", documentCount, documentCount==1?"":"s"); [documentCountField setStringValue:buf]; /* adjust the menu cells accordingly */ if (activeDocument) { [saveMenu setEnabled:YES]; [saveAsMenu setEnabled:YES]; [saveToMenu setEnabled:YES]; [saveAllMenu setEnabled:YES]; if ([activeDocument isDocEdited]) { [revertMenu setEnabled:YES]; } else { [revertMenu setEnabled:NO]; } [closeMenu setEnabled:YES]; } else { [saveMenu setEnabled:NO]; [saveAsMenu setEnabled:NO]; [saveToMenu setEnabled:NO]; [saveAllMenu setEnabled:NO]; [revertMenu setEnabled:NO]; [closeMenu setEnabled:NO]; } return self; } - _countDocuments:aDocument :sender { documentCount += 1; return self; } - unsetActiveDocument:aDocument { if (activeDocument == aDocument) { activeDocument = nil; } /* force an update of the document count */ [self setActiveDocument:activeDocument]; return self; } - open:sender /* * Open one or more existing documents */ { const char *const *files; static const char *const fileType[2] = {DOCUMENT_TYPE, NULL}; id openPanel; char fullName[MAXPATHLEN]; openPanel = [[OpenPanel new] allowMultipleFiles:YES]; /* run the open panel, filtering for out type of document */ if ([openPanel runModalForTypes:fileType]) { /* open all the files returned by the open panel */ files = [openPanel filenames]; for (files = [openPanel filenames]; files && *files; files++) {\ sprintf(fullName,"%s/%s",[openPanel directory],*files); if (![[Document alloc] initFromFile:fullName]) { NXRunAlertPanel("Open","Can't open %s", "Okay", NULL, NULL, *files); } } } return self; } - new:sender /* * Open a new, empty document */ { [[Document alloc] init]; return self; } - save:sender { return [activeDocument save:sender]; } - saveAs:sender { return [activeDocument saveAs:sender]; } - saveTo:sender { return [activeDocument saveTo:sender]; } - saveAll:sender { return [self performForDocuments:@selector(_save::) with:sender]; } - _save:aDocument :sender { return [aDocument save:sender]; } - revert:sender { return [activeDocument revert:sender]; } - close:sender { return [activeDocument close:sender]; } - performForDocuments:(SEL)aSelector with:anObject /* * Send [self aSelector :aDocument :anObject] for each Document in the * application. We depend on the fact that each Document has an associated * window and that each Document is the delegate of its window. */ { id window, windows = [NXApp windowList]; int i=0; while (window = [windows objectAt:i++]) { id document = [window delegate]; if (document && ([document class] == [Document class])) { [self perform:aSelector with:document with:anObject]; } } return self; } - (int)appOpenFile:(const char *)path type:(const char *)type /* * This method is performed whenever a user opens a document from the Workspace * Manager. (For what it's worth, this method is not explicitly documented * anywhere, but it's used in the Draw app and propogated throughout the * examples.) */ { if (type && !strcmp(type, DOCUMENT_TYPE)) { if (![[Document alloc] initFromFile:path]) { NXRunAlertPanel("Open","Can't open %s","Okay",NULL,NULL,path); return NO; } else { return YES; } } return NO; } - (BOOL)appAcceptsAnotherFile:sender /* * Inform the workspace that we can open multiple files. */ { return YES; } - appDidInit:sender /* * When the app is launched, create an empty document if we haven't opened * a document already. */ { if (!activeDocument) { [self new:self]; } return self; } - appWillTerminate:sender { int i, editedCount, choice; List *editedDocuments = [[List alloc] init]; do { /* * Make a list of edited documents and count how many there are. */ [editedDocuments empty]; [self performForDocuments:@selector(_collectEditedDocuments::) with:editedDocuments]; editedCount = [editedDocuments count]; if (editedCount > 0) { /* * If there is one or more unsaved document, ask the user if they want * to review documents, quit, or abort the quit. */ choice = NXRunAlertPanel( "Quit", "There are unsaved documents.\nReview them?", "Review", /* NX_ALERTDEFAULT */ "Quit Anyway", /* NX_ALERTALTERNATE */ "Cancel"); /* NX_ALERTOTHER */ switch (choice) { case NX_ALERTDEFAULT: /* Give the user the chance to review the edited document(s). */ for (i=0;i<editedCount;i++) { [[editedDocuments objectAt:i] close:self]; } break; case NX_ALERTALTERNATE: /* user selected Quit Anyway, just go to endgame */ editedCount = 0; break; case NX_ALERTOTHER: /* user selected Cancel, return nil to cancel the quit */ [editedDocuments free]; return nil; break; } } } while (editedCount > 0); /* * ENDGAME: * hide all the windows first to avoid the irritation of watching * each window become the main window in turn while we're closing * documents. After all, we simply want to quit... */ [self performForDocuments:@selector(_hide::) with:self]; [editedDocuments free]; /* ...and terminate without any futher ado (or review of docs) */ return self; } - _collectEditedDocuments:aDocument :editedDocuments /* * Collect those documents that have been modified into the editedDocuments * list. Called from performForDocuments:with:. */ { if ([aDocument isDocEdited]) { [editedDocuments addObject:aDocument]; } return self; } - _hide:aDocument :sender /* * hide one document. */ { return [aDocument hideDocument:sender]; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.