home *** CD-ROM | disk | FTP | other *** search
- /* 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 <appkit/Application.h>
- #import <appkit/Cell.h>
- #import <appkit/OpenPanel.h>
- #import <appkit/Panel.h> /* for NX_ALERTxxx */
- #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)app:sender openFile:(const char *)path type:(const char *)type
- /*
- * This method is performed whenever a user opens a document from the Workspace
- * Manager. (This method has replaced the obsolete method appOpenFile:type:)
- */
- {
- 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
-