home *** CD-ROM | disk | FTP | other *** search
- /*
- * Opens a document. If file is NULL, we open an untitiled document. We also
- * create a NXDataLinkManager and hook ourselves up as its delegate for doing
- * Object Links.
- */
- - initFromFile:(const char *)file
- {
- char realPath[MAXPATHLEN+1];
-
- [super init];
-
- /* load the UI from the nib section and set attributes not available in IB */
- [NXApp loadNibSection:"WW3DTesterDoc.nib" owner:self withNames:NO fromZone:[self zone]];
-
-
-
-
- if (file)
- {
- /* read existing document */
- if ([self _read:file]) {
- name = NXCopyStringBufferFromZone(file, [self zone]);
- if (realpath(name, realPath))
- realName = NXCopyStringBufferFromZone(realPath, [self zone]);
- [window setTitleAsFilename:name];
- [self _updateShape];
- linkMgr = [[NXDataLinkManager allocFromZone:[self zone]] initWithDelegate:self fromFile:file];
- } else {
- [self free]; /* couldn't load file */
- return nil;
- }
- } else {
- /*
- * Create a new document. We initialize it with a trivial expression
- * because that was easier than allowing the state where there is no
- * current expression.
- */
- RtPoint from = {12.0, 8.0, 10.0}, to = {0.0, 0.0, 0.0};
-
- [camera setEyeAt:from toward:to roll:0.0];
- /* set initial shape color to non-white on a color display */
- if ([camera shouldDrawColor])
- [[camera worldShape] setColor:NXConvertRGBToColor(51.0/255.0, 153.0/255.0, 116.0/255.0)];
-
- [window setTitleAsFilename:[[[NXApp delegate] stringTable] valueForStringKey:"untitled doc"]];
- [resolutionSlider setIntValue:DEFAULT_RES];
- [resolutionText setIntValue:DEFAULT_RES];
- [equation[X] setStringValue:"u"];
- [equation[Y] setStringValue:"v"];
- [equation[Z] setStringValue:"A * (u^2 + v^2) + C"];
- for (xyz = X; xyz <= Z; xyz++) {
- [expr[xyz] setResolution:DEFAULT_RES];
- }
- [self _equationChanged];
- [self _setUVRangeOf:U];
- [self _setUVRangeOf:V];
- [self _updateShape];
- linkMgr = [[NXDataLinkManager allocFromZone:[self zone]] initWithDelegate:self];
- }
-
- [[NXApp delegate] showThreeDPanel:self];
- [window makeKeyAndOrderFront:self];
- return self;
- }
-
- - free
- {
- [linkMgr free];
- return [super free];
- }
-
- - (const char *)filename {
- return name;
- }
-
- - (const char *)realFilename {
- return realName;
- }
-
- /*
- * This method is called whenever our window becomes the app's main window.
- * When this happens we get the 3D Panel and set its camera to our camera, so
- * the panel reflects the attributes of our window.
- */
- - windowDidBecomeMain:sender {
- [[[NXApp delegate] threeDPanel] setCamera:camera];
- return self;
- }
-
- /*
- * Copies the current view of the graph into the Pasteboard as Renderman code.
- * This is sent from the Copy Graph menu item.
- */
- - copyGraph:sender {
- Pasteboard *pb;
- const char *types[2];
- NXDataLink *link;
-
- pb = [Pasteboard new];
- types[0] = N3DRIBPboardType;
- types[1] = NXDataLinkPboardType;
- [self _writeRIBToPasteboard:pb types:types num:2];
- link = [[NXDataLink alloc] initLinkedToSourceSelection:[NXSelection allSelection] managedBy:linkMgr supportingTypes:&N3DRIBPboardType count:1];
- [link writeToPasteboard:pb];
- [link free];
- return self;
- }
-
- /*
- * Copies the current view of the graph into the Pasteboard as RIB.
- * This is used by the Copy Graph menu item and to support Object Links.
- *
- * Types must contain N3DRIBPboardType.
- */
- - _writeRIBToPasteboard:(Pasteboard *)pb types:(const char *const *)types num:(int)numTypes {
- NXStream *st;
- char *data;
- int dataLen, maxDataLen;
-
- /* Open a stream on memory where we will collect the PostScript */
- st = NXOpenMemory(NULL, 0, NX_WRITEONLY);
-
- /* Tell the Pasteboard we're going to copy RIB */
- [pb declareTypes:types num:numTypes owner:nil];
-
- /* writes the RIB for the whole graph into the stream */
- [camera copyRIBCode:st];
-
- /* get the buffered up PostScript out of the stream */
- NXGetMemoryBuffer(st, &data, &dataLen, &maxDataLen);
-
- /* put the buffer in the Pasteboard, free the stream (and the buffer) */
- [pb writeType:N3DRIBPboardType data:data length:dataLen];
- NXCloseMemory(st, NX_FREEBUFFER);
- return self;
- }
-
- /*** Object Links support - methods called by the DataLinkManager ***/
-
- /* called by the DataLinkManager when new data is needed for a link */
- - copyToPasteboard:(Pasteboard *)pboard at:(NXSelection *)selection cheapCopyAllowed:(BOOL)flag {
- NX_ASSERT([selection isEqual:[NXSelection allSelection]] || [selection isEqual:[NXSelection currentSelection]], "Funny selection passed to copyToPasteboard:at:");
- [self writeRIBToPasteboard:pboard types:&N3DRIBPboardType num:1];
- return self;
- }
-
- /* returns the window for the given selection */
- - windowForSelection:(NXSelection *)selection {
- return window; /* all our sels are always in our one window */
- }
-
- /*
- * We support continuously updating links by tracking changes to links to
- * us from open documents. This is easy for Graph because all links can
- * only be to the whole graph, so any change in the graph is a change relevant
- * to any link.
- */
- - (BOOL)dataLinkManagerTracksLinksIndividually:(NXDataLinkManager *)sender {
- return YES;
- }
-
- /*
- * Sent when we should start tracking a link. We just keep all links we're
- * tracking in a list, and send them a message whenever the graph is changed.
- */
- - dataLinkManager:(NXDataLinkManager *)sender startTrackingLink:(NXDataLink *)link {
- if (!linksTracked)
- linksTracked = [[List allocFromZone:[self zone]] init];
- [linksTracked addObject:link];
- return self;
- }
-
- /* Sent when we can forget a links we're tracking */
- - dataLinkManager:(NXDataLinkManager *)sender stopTrackingLink:(NXDataLink *)link {
- [linksTracked removeObject:link];
- if ([linksTracked count] == 0) {
- [linksTracked free];
- linksTracked = nil;
- }
- return self;
- }
-
- /*
- * Called by other methods of Graph3DDoc whenever we make a change to the
- * document. We tell the DataLinkManager about the change, and also notify
- * any links we are tracking.
- */
- - docChanged {
- [linkMgr documentEdited];
- [linksTracked makeObjectsPerform:@selector(sourceEdited)];
- [window setDocEdited:YES];
- return self;
- }
-
- /* called by ThreeDPanel when it changes something about the document */
- - threeDPanelDidChangeDoc:(ThreeDPanel *)sender {
- [self docChanged];
- return self;
- }
-
-
- /* called when Save, Save As, or Save To is picked from the menu */
- - save:sender { return [self _doSaveWithNewName:NO retainName:YES]; }
- - saveAs:sender { return [self _doSaveWithNewName:YES retainName:YES]; }
- - saveTo:sender { return [self _doSaveWithNewName:YES retainName:NO]; }
-
- /*
- * All varieties of save go through this routine. It covers all the cases
- * of running the Save Panel and retaining the name chosen.
- */
- - _doSaveWithNewName:(BOOL)doNewName retainName:(BOOL)doRetain {
- SavePanel *savePanel;
- const char *saveName; /* filename to save into */
- NXZone *zone;
- BOOL previouslySaved = (name != NULL);
- char realPath[MAXPATHLEN+1];
-
- /*
- * If the file is untitled or we are saving under a different name,
- * run the save panel to get a new name.
- */
- zone = [self zone];
- if (!name || doNewName) {
- savePanel = [SavePanel new];
- [savePanel setRequiredFileType:"xyzgraph"];
- if ([savePanel runModalForDirectory:NULL file:name]) {
- /* if we want to keep this name, replace any old name */
- if (doRetain) {
- NXZoneFree(zone, name);
- NXZoneFree(zone, realName);
- realName = NULL;
- name = NXCopyStringBufferFromZone([savePanel filename], zone);
- }
- saveName = [savePanel filename];
- } else
- return nil; /* user canceled */
- } else
- /* if we didn't run the Save Panel, save using the existing name */
- saveName = name;
- [self _write:saveName];
- if (!doRetain)
- [linkMgr documentSavedTo:saveName];
- else if (!previouslySaved || doNewName)
- [linkMgr documentSavedAs:saveName];
- else
- [linkMgr documentSaved];
- if (doRetain) {
- [window setDocEdited:NO];
- [window setTitleAsFilename:name];
- if (!realName && realpath(name, realPath)) {
- realName = NXCopyStringBufferFromZone(realPath, [self zone]);
- }
- }
- return self;
- }
-
- - revertToSaved:sender {
- int response;
- NXStringTable *stringTable;
- const char *shortName;
- Graph3DDoc *newDoc;
-
- if ([window isDocEdited] && name) {
- stringTable = [[NXApp delegate] stringTable];
- shortName = strrchr(name, '/') + 1;
- response = NXRunAlertPanel([stringTable valueForStringKey:"revert alert title"],
- [stringTable valueForStringKey:"revert alert message"],
- [stringTable valueForStringKey:"revert button"],
- [stringTable valueForStringKey:"cancel button"],
- NULL, shortName);
- if (response == NX_ALERTDEFAULT) {
- [window setDelegate:nil];
- [window close];
- [NXApp delayedFree:self];
- [linkMgr documentClosed];
- [linkMgr free];
- linkMgr = nil;
- newDoc = [[Graph3DDoc allocFromZone:[self zone]] initFromFile:name];
- if (!newDoc) {
- NXRunAlertPanel(
- [stringTable valueForStringKey:"open alert title"],
- [stringTable valueForStringKey:"open alert message"],
- [stringTable valueForStringKey:"ok button"],
- NULL, NULL, name);
- }
- }
- }
- return self;
- }
-
- /* Called when the window is closing. We free the Graph3DDoc. */
- - windowWillClose:sender {
- int response;
- NXStringTable *stringTable;
- const char *shortName;
-
- if ([window isDocEdited]) {
- stringTable = [[NXApp delegate] stringTable];
- if (name) {
- shortName = strrchr(name, '/') + 1;
- } else {
- shortName = [stringTable valueForStringKey:"untitled doc"];
- }
- response = NXRunAlertPanel([stringTable valueForStringKey:"close alert title"],
- [stringTable valueForStringKey:"close alert message"],
- [stringTable valueForStringKey:"save button"],
- [stringTable valueForStringKey:"dont save button"],
- [stringTable valueForStringKey:"cancel button"],
- shortName);
- if (response != NX_ALERTDEFAULT && response != NX_ALERTALTERNATE) {
- return nil;
- } else {
- if (response == NX_ALERTDEFAULT && ![self save:sender])
- return nil;
- }
- }
- [NXApp delayedFree:self];
- [linkMgr documentClosed];
- return self; /* says its OK to close */
- }
-
- /* Opens a stream on the document regardless of whether its a doc wrapper. */
- static NXTypedStream *openDocStream(const char *filename, int mode) {
- NXTypedStream *ts = NULL;
- struct stat statInfo;
- char buffer[MAXPATHLEN+1];
-
- if (stat(filename, &statInfo) == 0) {
- if (statInfo.st_mode & S_IFDIR) {
- strcpy(buffer, filename);
- strcat(buffer, DOC_NAME);
- ts = NXOpenTypedStreamForFile(buffer, mode);
- } else {
- ts = NXOpenTypedStreamForFile(filename, mode);
- }
- }
- return ts;
- }
-
- /* removes a directory, removing anything inside it. Does not recurse */
- static int removeFile(const char *file) {
- DIR *dirp;
- struct stat st;
- struct direct *dp;
- char *leaf = NULL;
- char path[MAXPATHLEN+1];
-
- if (!stat(file, &st)) {
- if ((st.st_mode & S_IFMT) == S_IFDIR) {
- dirp = opendir(file);
- for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
- if (strcmp(dp->d_name, ".") && strcmp(dp->d_name, "..")) {
- if (!leaf) {
- strcpy(path, file);
- strcat(path, "/");
- leaf = path + strlen(path);
- }
- strcpy(leaf, dp->d_name);
- if (unlink(path)) {
- closedir(dirp);
- return -1;
- }
- }
- }
- return rmdir(file);
- } else {
- return unlink(file);
- }
- }
-
- return -1;
- }
-