home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1 (1993) / nebula.bin / SourceCode / MiniExamples / WhatsUpDoc / DocController.m < prev    next >
Encoding:
Text File  |  1991-08-02  |  7.6 KB  |  340 lines

  1. /* DocController.m
  2.  * Purpose:  This is the main controlling class for this application.
  3.  *    DocController loads the Info and Help nib files on demand.
  4.  *    DocController also handles the multiple documents that can
  5.  *    be open at any time using the Document class -- including
  6.  *    keeping a count, tracking the current active document, 
  7.  *    managing the open and save panels, etc.
  8.  *
  9.  * You may freely copy, distribute, and reuse the code in this example.
  10.  * NeXT disclaims any warranty of any kind, expressed or  implied, as to its
  11.  * fitness for any particular use.
  12.  *
  13.  * Written by: R. Dunbar Poor
  14.  * Created: 28/April/1991
  15.  *
  16.  */
  17. #import "DocController.h"
  18. #import "Document.h"
  19. #import "Document.h"
  20. #import <appkit/Application.h>
  21. #import <appkit/Cell.h>
  22. #import <appkit/OpenPanel.h>
  23. #import <appkit/Panel.h>    /* for NX_ALERTxxx */
  24. #import <objc/List.h>
  25. #import <strings.h>
  26. #import <sys/param.h>
  27.  
  28. @interface DocController(DocControllerPrivate)
  29. - _countDocuments:aDocument :sender;
  30. - _save:aDocument :sender;
  31. - _collectEditedDocuments:aDocument :editedDocuments;
  32. - _hide:aDocument :sender;
  33. @end
  34.  
  35. @implementation DocController
  36.  
  37. - init
  38. {
  39.   [super init];
  40.   return self;
  41. }
  42.  
  43. - free
  44. {
  45.   return [super free];
  46. }
  47.  
  48. - showInfo:sender
  49. {
  50.   if (!infoPanel) {
  51.     [NXApp loadNibSection:"Info.nib" owner:self withNames:NO];
  52.   }
  53.   [infoPanel makeKeyAndOrderFront:sender];
  54.   return self;
  55. }
  56.  
  57. - showHelp:sender
  58. {
  59.   if (!helpPanel) {
  60.     [NXApp loadNibSection:"Help.nib" owner:self withNames:NO];
  61.   }
  62.   [helpPanel makeKeyAndOrderFront:sender];
  63.   return self;
  64. }
  65.  
  66. - activeDocument
  67. {
  68.   return activeDocument;
  69. }
  70.  
  71. - setActiveDocument:aDocument
  72. {
  73.   char buf[100];
  74.   
  75.   activeDocument = aDocument;
  76.  
  77.   /* display the message of the current document */
  78.   [activeDocumentField setStringValue:[activeDocument message]];
  79.  
  80.   /* count and display the number of documents present */
  81.   documentCount = 0;
  82.   [self performForDocuments:@selector(_countDocuments::) with:self];
  83.   sprintf(buf,"There %s %d active document%s.",
  84.         documentCount==1?"is":"are",
  85.       documentCount,
  86.       documentCount==1?"":"s");
  87.   [documentCountField setStringValue:buf];
  88.  
  89.   /* adjust the menu cells accordingly */
  90.   if (activeDocument) {
  91.     [saveMenu setEnabled:YES];
  92.     [saveAsMenu setEnabled:YES];
  93.     [saveToMenu setEnabled:YES];
  94.     [saveAllMenu setEnabled:YES];
  95.     if ([activeDocument isDocEdited]) {
  96.       [revertMenu setEnabled:YES];
  97.     } else {
  98.       [revertMenu setEnabled:NO];
  99.     }
  100.     [closeMenu setEnabled:YES];
  101.   } else {
  102.     [saveMenu setEnabled:NO];
  103.     [saveAsMenu setEnabled:NO];
  104.     [saveToMenu setEnabled:NO];
  105.     [saveAllMenu setEnabled:NO];
  106.     [revertMenu setEnabled:NO];
  107.     [closeMenu setEnabled:NO];
  108.   }      
  109.  
  110.   return self;
  111. }
  112.  
  113. - _countDocuments:aDocument :sender
  114. {
  115.   documentCount += 1;
  116.   return self;
  117. }
  118.  
  119. - unsetActiveDocument:aDocument
  120. {
  121.   if (activeDocument == aDocument) {
  122.     activeDocument = nil;
  123.   }
  124.   /* force an update of the document count */
  125.   [self setActiveDocument:activeDocument];
  126.   return self;
  127. }
  128.  
  129. - open:sender
  130. /*
  131.  * Open one or more existing documents
  132.  */
  133. {
  134.   const char *const *files;
  135.   static const char *const fileType[2] = {DOCUMENT_TYPE, NULL};
  136.   id openPanel;
  137.   char fullName[MAXPATHLEN];
  138.  
  139.   openPanel = [[OpenPanel new] allowMultipleFiles:YES];
  140.  
  141.   /* run the open panel, filtering for out type of document */
  142.   if ([openPanel runModalForTypes:fileType]) {
  143.     /* open all the files returned by the open panel */
  144.     files = [openPanel filenames];
  145.     for (files = [openPanel filenames]; files && *files; files++) {\
  146.       sprintf(fullName,"%s/%s",[openPanel directory],*files);
  147.       if (![[Document alloc] initFromFile:fullName]) {
  148.         NXRunAlertPanel("Open","Can't open %s", "Okay", NULL, NULL, *files);
  149.       }
  150.     }
  151.   }
  152.   return self;
  153. }
  154.  
  155. - new:sender
  156. /*
  157.  * Open a new, empty document
  158.  */
  159. {
  160.   [[Document alloc] init];
  161.   return self;
  162. }
  163.  
  164. - save:sender
  165. {
  166.   return [activeDocument save:sender];
  167. }
  168.  
  169. - saveAs:sender
  170. {
  171.   return [activeDocument saveAs:sender];
  172. }
  173.  
  174. - saveTo:sender
  175. {
  176.   return [activeDocument saveTo:sender];
  177. }
  178.  
  179. - saveAll:sender
  180. {
  181.   return [self performForDocuments:@selector(_save::) with:sender];
  182. }
  183.  
  184. - _save:aDocument :sender
  185. {
  186.   return [aDocument save:sender];
  187. }
  188.  
  189. - revert:sender
  190. {
  191.   return [activeDocument revert:sender];
  192. }
  193.  
  194. - close:sender
  195. {
  196.   return [activeDocument close:sender];
  197. }
  198.  
  199.  
  200. - performForDocuments:(SEL)aSelector with:anObject
  201. /*
  202.  * Send [self aSelector :aDocument :anObject] for each Document in the
  203.  * application.  We depend on the fact that each Document has an associated
  204.  * window and that each Document is the delegate of its window.
  205.  */
  206. {
  207.   id window, windows = [NXApp windowList];
  208.   int i=0;
  209.   
  210.   while (window = [windows objectAt:i++]) {
  211.     id document = [window delegate];
  212.     if (document && ([document class] == [Document class])) {
  213.       [self perform:aSelector with:document with:anObject];
  214.     }
  215.   }
  216.   return self;
  217. }
  218.  
  219.  
  220.  
  221. - (int)appOpenFile:(const char *)path type:(const char *)type
  222. /*
  223.  * This method is performed whenever a user opens a document from the Workspace
  224.  * Manager. (For what it's worth, this method is not explicitly documented
  225.  * anywhere, but it's used in the Draw app and propogated throughout the
  226.  * examples.)
  227.  */
  228. {
  229.   if (type && !strcmp(type, DOCUMENT_TYPE)) {
  230.     if (![[Document alloc] initFromFile:path]) {
  231.       NXRunAlertPanel("Open","Can't open %s","Okay",NULL,NULL,path);
  232.       return NO;
  233.     } else {
  234.       return YES;
  235.     }
  236.   }
  237.   return NO;
  238. }
  239.  
  240. - (BOOL)appAcceptsAnotherFile:sender
  241. /*
  242.  * Inform the workspace that we can open multiple files.
  243.  */
  244. {
  245.   return YES;
  246. }
  247.  
  248. - appDidInit:sender
  249. /*
  250.  * When the app is launched, create an empty document if we haven't opened
  251.  * a document already.
  252.  */
  253. {
  254.   if (!activeDocument) {
  255.     [self new:self];
  256.   }
  257.   return self;
  258. }
  259.  
  260. - appWillTerminate:sender
  261. {
  262.   int i, editedCount, choice;
  263.   List *editedDocuments = [[List alloc] init];
  264.  
  265.   do {
  266.     /*
  267.      * Make a list of edited documents and count how many there are.
  268.      */
  269.     [editedDocuments empty];
  270.     [self performForDocuments:@selector(_collectEditedDocuments::)
  271.       with:editedDocuments];
  272.     editedCount = [editedDocuments count];
  273.  
  274.     if (editedCount > 0) {
  275.       /*
  276.        * If there is one or more unsaved document, ask the user if they want
  277.        * to review documents, quit, or abort the quit.
  278.        */
  279.       choice = NXRunAlertPanel(
  280.           "Quit",
  281.           "There are unsaved documents.\nReview them?",
  282.           "Review",        /* NX_ALERTDEFAULT */
  283.           "Quit Anyway",    /* NX_ALERTALTERNATE */
  284.           "Cancel");        /* NX_ALERTOTHER */
  285.   
  286.       switch (choice) {
  287.       case NX_ALERTDEFAULT:
  288.     /* Give the user the chance to review the edited document(s). */
  289.     for (i=0;i<editedCount;i++) {
  290.       [[editedDocuments objectAt:i] close:self];
  291.     }
  292.         break;
  293.       case NX_ALERTALTERNATE:
  294.         /* user selected Quit Anyway, just go to endgame */
  295.     editedCount = 0;
  296.         break;
  297.       case NX_ALERTOTHER:
  298.         /* user selected Cancel, return nil to cancel the quit */
  299.     [editedDocuments free];
  300.     return nil;
  301.     break;
  302.       }
  303.     }
  304.   } while (editedCount > 0);
  305.  
  306.   /*
  307.    * ENDGAME:
  308.    * hide all the windows first to avoid the irritation of watching
  309.    * each window become the main window in turn while we're closing
  310.    * documents.  After all, we simply want to quit...
  311.    */
  312.   [self performForDocuments:@selector(_hide::) with:self];
  313.   [editedDocuments free];
  314.   /* ...and terminate without any futher ado (or review of docs) */
  315.   return self;
  316. }
  317.  
  318. - _collectEditedDocuments:aDocument :editedDocuments
  319. /*
  320.  * Collect those documents that have been modified into the editedDocuments
  321.  * list.  Called from performForDocuments:with:.
  322.  */ 
  323. {
  324.   if ([aDocument isDocEdited]) {
  325.     [editedDocuments addObject:aDocument];
  326.   }
  327.   return self;
  328. }
  329.  
  330. - _hide:aDocument :sender
  331. /*
  332.  * hide one document.
  333.  */
  334. {
  335.   return [aDocument hideDocument:sender];
  336. }
  337.  
  338.  
  339. @end
  340.