home *** CD-ROM | disk | FTP | other *** search
/ Stone Design / Stone Design.iso / Stone_Friends / Wave / WavesWorld / Source / Applications / BuildaDudeII / example < prev    next >
Encoding:
Text File  |  1995-03-22  |  11.2 KB  |  373 lines

  1. /*
  2.  * Opens a document.  If file is NULL, we open an untitiled document.  We also
  3.  * create a NXDataLinkManager and hook ourselves up as its delegate for doing
  4.  * Object Links.
  5.  */
  6. - initFromFile:(const char *)file 
  7. {
  8.     char realPath[MAXPATHLEN+1];
  9.  
  10.     [super init];
  11.  
  12.   /* load the UI from the nib section and set attributes not available in IB */
  13.     [NXApp loadNibSection:"WW3DTesterDoc.nib" owner:self withNames:NO fromZone:[self zone]];
  14.  
  15.  
  16.  
  17.  
  18.     if (file) 
  19.     {
  20.       /* read existing document */
  21.     if ([self _read:file]) {
  22.         name = NXCopyStringBufferFromZone(file, [self zone]);
  23.         if (realpath(name, realPath))
  24.         realName = NXCopyStringBufferFromZone(realPath, [self zone]);
  25.         [window setTitleAsFilename:name];
  26.         [self _updateShape];
  27.         linkMgr = [[NXDataLinkManager allocFromZone:[self zone]] initWithDelegate:self fromFile:file];
  28.     } else {
  29.         [self free];    /* couldn't load file */
  30.         return nil;
  31.     }
  32.     } else {
  33.       /*
  34.        * Create a new document.  We initialize it with a trivial expression
  35.        * because that was easier than allowing the state where there is no
  36.        * current expression.
  37.        */
  38.     RtPoint from = {12.0, 8.0, 10.0}, to = {0.0, 0.0, 0.0};
  39.  
  40.     [camera setEyeAt:from toward:to roll:0.0];
  41.       /* set initial shape color to non-white on a color display */
  42.     if ([camera shouldDrawColor])
  43.         [[camera worldShape] setColor:NXConvertRGBToColor(51.0/255.0, 153.0/255.0, 116.0/255.0)];
  44.  
  45.     [window setTitleAsFilename:[[[NXApp delegate] stringTable] valueForStringKey:"untitled doc"]];
  46.     [resolutionSlider setIntValue:DEFAULT_RES];
  47.     [resolutionText setIntValue:DEFAULT_RES];
  48.     [equation[X] setStringValue:"u"];
  49.     [equation[Y] setStringValue:"v"];
  50.     [equation[Z] setStringValue:"A * (u^2 + v^2) + C"];
  51.     for (xyz = X; xyz <= Z; xyz++) {
  52.         [expr[xyz] setResolution:DEFAULT_RES];
  53.     }
  54.     [self _equationChanged];
  55.     [self _setUVRangeOf:U];
  56.     [self _setUVRangeOf:V];
  57.     [self _updateShape];
  58.     linkMgr = [[NXDataLinkManager allocFromZone:[self zone]] initWithDelegate:self];
  59.     }
  60.  
  61.     [[NXApp delegate] showThreeDPanel:self];
  62.     [window makeKeyAndOrderFront:self];
  63.     return self;
  64. }
  65.  
  66. - free 
  67. {
  68.     [linkMgr free];
  69.     return [super free];
  70. }
  71.  
  72. - (const char *)filename {
  73.     return name;
  74. }
  75.  
  76. - (const char *)realFilename {
  77.     return realName;
  78. }
  79.  
  80. /*
  81.  * This method is called whenever our window becomes the app's main window.
  82.  * When this happens we get the 3D Panel and set its camera to our camera, so
  83.  * the panel reflects the attributes of our window.
  84.  */
  85. - windowDidBecomeMain:sender {
  86.     [[[NXApp delegate] threeDPanel] setCamera:camera];
  87.     return self;
  88. }
  89.  
  90. /*
  91.  * Copies the current view of the graph into the Pasteboard as Renderman code.
  92.  * This is sent from the Copy Graph menu item.
  93.  */
  94. - copyGraph:sender {
  95.     Pasteboard *pb;
  96.     const char *types[2];
  97.     NXDataLink *link;
  98.  
  99.     pb = [Pasteboard new];
  100.     types[0] = N3DRIBPboardType;
  101.     types[1] = NXDataLinkPboardType;
  102.     [self _writeRIBToPasteboard:pb types:types num:2];
  103.     link = [[NXDataLink alloc] initLinkedToSourceSelection:[NXSelection allSelection] managedBy:linkMgr supportingTypes:&N3DRIBPboardType count:1];
  104.     [link writeToPasteboard:pb];
  105.     [link free];
  106.     return self;
  107. }
  108.  
  109. /*
  110.  * Copies the current view of the graph into the Pasteboard as RIB.
  111.  * This is used by the Copy Graph menu item and to support Object Links.
  112.  *
  113.  * Types must contain N3DRIBPboardType.
  114.  */
  115. - _writeRIBToPasteboard:(Pasteboard *)pb types:(const char *const *)types num:(int)numTypes {
  116.     NXStream *st;
  117.     char *data;
  118.     int dataLen, maxDataLen;
  119.  
  120.   /* Open a stream on memory where we will collect the PostScript */
  121.     st = NXOpenMemory(NULL, 0, NX_WRITEONLY);
  122.  
  123.   /* Tell the Pasteboard we're going to copy RIB */
  124.     [pb declareTypes:types num:numTypes owner:nil];
  125.  
  126.   /* writes the RIB for the whole graph into the stream */
  127.     [camera copyRIBCode:st];
  128.  
  129.   /* get the buffered up PostScript out of the stream */
  130.     NXGetMemoryBuffer(st, &data, &dataLen, &maxDataLen);
  131.  
  132.   /* put the buffer in the Pasteboard, free the stream (and the buffer) */
  133.     [pb writeType:N3DRIBPboardType data:data length:dataLen];
  134.     NXCloseMemory(st, NX_FREEBUFFER);
  135.     return self;
  136. }
  137.  
  138. /*** Object Links support - methods called by the DataLinkManager ***/
  139.  
  140. /* called by the DataLinkManager when new data is needed for a link */
  141. - copyToPasteboard:(Pasteboard *)pboard at:(NXSelection *)selection cheapCopyAllowed:(BOOL)flag {
  142.     NX_ASSERT([selection isEqual:[NXSelection allSelection]] || [selection isEqual:[NXSelection currentSelection]], "Funny selection passed to copyToPasteboard:at:");
  143.     [self writeRIBToPasteboard:pboard types:&N3DRIBPboardType num:1];
  144.     return self;
  145. }
  146.  
  147. /* returns the window for the given selection */
  148. - windowForSelection:(NXSelection *)selection {
  149.     return window;        /* all our sels are always in our one window */
  150. }
  151.  
  152. /*
  153.  * We support continuously updating links by tracking changes to links to
  154.  * us from open documents.  This is easy for Graph because all links can
  155.  * only be to the whole graph, so any change in the graph is a change relevant
  156.  * to any link.
  157.  */
  158. - (BOOL)dataLinkManagerTracksLinksIndividually:(NXDataLinkManager *)sender {
  159.     return YES;
  160. }
  161.  
  162. /*
  163.  * Sent when we should start tracking a link.  We just keep all links we're
  164.  * tracking in a list, and send them a message whenever the graph is changed.
  165.  */
  166. - dataLinkManager:(NXDataLinkManager *)sender startTrackingLink:(NXDataLink *)link {
  167.     if (!linksTracked)
  168.     linksTracked = [[List allocFromZone:[self zone]] init];
  169.     [linksTracked addObject:link];
  170.     return self;
  171. }
  172.  
  173. /* Sent when we can forget a links we're tracking */
  174. - dataLinkManager:(NXDataLinkManager *)sender stopTrackingLink:(NXDataLink *)link {
  175.     [linksTracked removeObject:link];
  176.     if ([linksTracked count] == 0) {
  177.     [linksTracked free];
  178.     linksTracked = nil;
  179.     }
  180.     return self;
  181. }
  182.  
  183. /*
  184.  * Called by other methods of Graph3DDoc whenever we make a change to the
  185.  * document.  We tell the DataLinkManager about the change, and also notify
  186.  * any links we are tracking.
  187.  */
  188. - docChanged {
  189.     [linkMgr documentEdited];
  190.     [linksTracked makeObjectsPerform:@selector(sourceEdited)];
  191.     [window setDocEdited:YES];
  192.     return self;
  193. }
  194.  
  195. /* called by ThreeDPanel when it changes something about the document */
  196. - threeDPanelDidChangeDoc:(ThreeDPanel *)sender {
  197.     [self docChanged];
  198.     return self;
  199. }
  200.  
  201.  
  202. /* called when Save, Save As, or Save To is picked from the menu */
  203. - save:sender   {  return [self _doSaveWithNewName:NO retainName:YES];  }
  204. - saveAs:sender {  return [self _doSaveWithNewName:YES retainName:YES]; }
  205. - saveTo:sender {  return [self _doSaveWithNewName:YES retainName:NO];  }
  206.  
  207. /*
  208.  * All varieties of save go through this routine.  It covers all the cases
  209.  * of running the Save Panel and retaining the name chosen.
  210.  */
  211. - _doSaveWithNewName:(BOOL)doNewName retainName:(BOOL)doRetain {
  212.     SavePanel *savePanel;
  213.     const char *saveName;    /* filename to save into */
  214.     NXZone *zone;
  215.     BOOL previouslySaved = (name != NULL);
  216.     char realPath[MAXPATHLEN+1];
  217.  
  218.   /*
  219.    * If the file is untitled or we are saving under a different name,
  220.    * run the save panel to get a new name.
  221.    */
  222.     zone = [self zone];
  223.     if (!name || doNewName) {
  224.     savePanel = [SavePanel new];
  225.     [savePanel setRequiredFileType:"xyzgraph"];
  226.     if ([savePanel runModalForDirectory:NULL file:name]) {
  227.       /* if we want to keep this name, replace any old name */    
  228.         if (doRetain) {
  229.         NXZoneFree(zone, name);
  230.         NXZoneFree(zone, realName);
  231.         realName = NULL;
  232.         name = NXCopyStringBufferFromZone([savePanel filename], zone);
  233.         }
  234.         saveName = [savePanel filename];
  235.     } else
  236.         return nil;        /* user canceled */
  237.     } else
  238.       /* if we didn't run the Save Panel, save using the existing name */
  239.     saveName = name;
  240.     [self _write:saveName];
  241.     if (!doRetain)
  242.     [linkMgr documentSavedTo:saveName];
  243.     else if (!previouslySaved || doNewName)
  244.     [linkMgr documentSavedAs:saveName];
  245.     else
  246.     [linkMgr documentSaved];
  247.     if (doRetain) {
  248.     [window setDocEdited:NO];
  249.     [window setTitleAsFilename:name];
  250.     if (!realName && realpath(name, realPath)) {
  251.         realName = NXCopyStringBufferFromZone(realPath, [self zone]);
  252.     }
  253.     }
  254.     return self;
  255. }
  256.  
  257. - revertToSaved:sender {
  258.     int response;
  259.     NXStringTable *stringTable;
  260.     const char *shortName;
  261.     Graph3DDoc *newDoc;
  262.  
  263.     if ([window isDocEdited] && name) {
  264.     stringTable = [[NXApp delegate] stringTable];
  265.     shortName = strrchr(name, '/') + 1;
  266.     response =  NXRunAlertPanel([stringTable valueForStringKey:"revert alert title"],
  267.             [stringTable valueForStringKey:"revert alert message"],
  268.             [stringTable valueForStringKey:"revert button"],
  269.             [stringTable valueForStringKey:"cancel button"],
  270.             NULL, shortName);
  271.     if (response == NX_ALERTDEFAULT) {
  272.         [window setDelegate:nil];
  273.         [window close];
  274.         [NXApp delayedFree:self];
  275.         [linkMgr documentClosed];
  276.         [linkMgr free];
  277.         linkMgr = nil;
  278.         newDoc = [[Graph3DDoc allocFromZone:[self zone]] initFromFile:name];
  279.         if (!newDoc) {
  280.         NXRunAlertPanel(
  281.             [stringTable valueForStringKey:"open alert title"],
  282.             [stringTable valueForStringKey:"open alert message"],
  283.             [stringTable valueForStringKey:"ok button"],
  284.             NULL, NULL, name);
  285.         }
  286.     }
  287.     }
  288.     return self;
  289. }
  290.  
  291. /* Called when the window is closing.  We free the Graph3DDoc. */
  292. - windowWillClose:sender {
  293.     int response;
  294.     NXStringTable *stringTable;
  295.     const char *shortName;
  296.  
  297.     if ([window isDocEdited]) {
  298.     stringTable = [[NXApp delegate] stringTable];
  299.     if (name) {
  300.         shortName = strrchr(name, '/') + 1;
  301.     } else {
  302.         shortName = [stringTable valueForStringKey:"untitled doc"];
  303.     }
  304.     response =  NXRunAlertPanel([stringTable valueForStringKey:"close alert title"],
  305.             [stringTable valueForStringKey:"close alert message"],
  306.             [stringTable valueForStringKey:"save button"],
  307.             [stringTable valueForStringKey:"dont save button"],
  308.             [stringTable valueForStringKey:"cancel button"],
  309.             shortName);
  310.     if (response != NX_ALERTDEFAULT && response != NX_ALERTALTERNATE) {
  311.         return nil;
  312.     } else {
  313.         if (response == NX_ALERTDEFAULT && ![self save:sender])
  314.         return nil;
  315.     }
  316.     }
  317.     [NXApp delayedFree:self];
  318.     [linkMgr documentClosed];
  319.     return self;            /* says its OK to close */
  320. }
  321.  
  322. /*  Opens a stream on the document regardless of whether its a doc wrapper. */
  323. static NXTypedStream *openDocStream(const char *filename, int mode) {
  324.     NXTypedStream *ts = NULL;
  325.     struct stat statInfo;
  326.     char buffer[MAXPATHLEN+1];
  327.  
  328.     if (stat(filename, &statInfo) == 0) {
  329.     if (statInfo.st_mode & S_IFDIR) {
  330.         strcpy(buffer, filename);
  331.         strcat(buffer, DOC_NAME);
  332.         ts = NXOpenTypedStreamForFile(buffer, mode);
  333.     } else {
  334.         ts = NXOpenTypedStreamForFile(filename, mode);
  335.     }
  336.     }
  337.     return ts;
  338. }
  339.  
  340. /* removes a directory, removing anything inside it.  Does not recurse */
  341. static int removeFile(const char *file) {
  342.     DIR *dirp;
  343.     struct stat st;
  344.     struct direct *dp;
  345.     char *leaf = NULL;
  346.     char path[MAXPATHLEN+1];
  347.  
  348.     if (!stat(file, &st)) {
  349.     if ((st.st_mode & S_IFMT) == S_IFDIR) {
  350.         dirp = opendir(file);
  351.         for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
  352.         if (strcmp(dp->d_name, ".") && strcmp(dp->d_name, "..")) {
  353.             if (!leaf) {
  354.             strcpy(path, file);
  355.             strcat(path, "/");
  356.             leaf = path + strlen(path);
  357.             }
  358.             strcpy(leaf, dp->d_name);
  359.             if (unlink(path)) {
  360.             closedir(dirp);
  361.             return -1;
  362.             }
  363.         }
  364.         }
  365.         return rmdir(file);
  366.     } else {
  367.         return unlink(file);
  368.     }
  369.     }
  370.  
  371.     return -1;
  372. }
  373.