home *** CD-ROM | disk | FTP | other *** search
-
- #import <stdio.h>
-
- #import "TreeController.h"
- #import "NamedTree.h"
- #import "TreeView.h"
-
- @implementation TreeController
-
- - appDidInit:(Application *)sender
- {
- BOOL haveOpenedDocument = NO; // whether we have opened a document
-
- // // Gets the public port for SomeApp
- // port_t thePort = NXPortFromName("Emacs", NULL);
- //
- // if (thePort != PORT_NULL)
- // // Sets the Speaker to send its next message to SomeApp's port
- // [[NXApp appSpeaker] setSendPort:thePort];
-
- if (NXArgc > 1)
- {
- int i;
-
- for (i = 1; i < NXArgc; i++)
- {
- haveOpenedDocument = [self openFile: NXArgv[i]] || haveOpenedDocument;
- }
- }
-
- return self;
- }
-
- - init
- {
- [super init];
- first = YES;
- nextX = 200;
- nextY = 600;
- return self;
- }
-
- - info:sender // bring up the info panel, obviously
- {
- if(!infoPanel)
- [NXApp loadNibSection:"InfoPanel.nib" owner:self withNames:NO];
- return [infoPanel orderFront:sender];
- }
-
- - open:sender
- { // use open panel to select a file -- only with .tree extension.
- // only one file may be loaded at a time.
- const char *const *files;
- char *file;
- const char *dir;
- static const char *const ft[2] = {"tree", NULL};
-
- id openPanel = [OpenPanel new];
- [openPanel allowMultipleFiles:NO];
- if (first) {
- [openPanel runModalForDirectory:[[NXBundle mainBundle] directory]
- file:NULL types:ft];
- first = NO;
- } else [openPanel runModalForTypes:ft];
- files = [openPanel filenames];
- dir = [openPanel directory];
- file = malloc(strlen(files[0]) + strlen(dir) + 8);
- strcpy(file, dir);
- strcat(file,"/");
- strcat(file, files[0]);
- strcat(file, "\0");
- [self openFile:file];
- return self;
- }
-
- char nextChar; // This allows me to do single character lookahead in scan
-
- id readToNewline(FILE *file) // used to parse a file; reads until a newline
- { // returns a string object... reads until EOL to get string value.
- id newString = [[String alloc] init];
- char *buffer = (char *)malloc(1024); // should be plenty big
- char *spot = buffer;
-
- while (nextChar != '\n')
- {
- spot[0] = nextChar; spot++; nextChar = fgetc(file);
- }
- spot[0] = '\0'; // terminate the string
- nextChar = fgetc(file); // Get next char for next invocation of this function
- [newString setString:buffer];
- free(buffer);
- return newString;
- }
-
- char prevChar; // This allows me to do single character lookback in scan
-
- id readToSep(FILE *file) // used to parse a file; reads until a newline or a "^^" sequence
- { // returns a string object... reads until EOL to get string value.
- id newString = [[String alloc] init];
- char *buffer = (char *)malloc(1024); // should be plenty big
- char *spot = buffer;
- int c;
-
- while (nextChar != '\n')
- {
- if (nextChar == '^')
- if ((c = fgetc(file)) == '^')
- break;
- else
- ungetc(c, file);
- spot[0] = nextChar; spot++; nextChar = fgetc(file);
- }
- spot[0] = '\0'; // terminate the string
- prevChar = nextChar;
- nextChar = fgetc(file); // Get next char for next invocation of this function
- [newString setString:buffer];
- free(buffer);
- return newString;
- }
-
- // This actually opens a file. WorkSpace and Open panel methods both
- // eventually get to here to do the real work. This code is pretty much
- // worth ignoring, unless you _really_ care about how I read in the
- // files. It's mostly specific to the file format so it's not
- // generally useful. The framework for this code came from the
- // code in my "Viewer.app" that is in with some PD raytracers I ported
- // to the NeXT--allows viewing an rgb bitmap file; I wrote it before
- // GW and ImageViewer existed... (See raytracers.tar.Z on sonata/orst)
- - (BOOL)openFile:(const char *)name
- {
- // id alert;
- id aString, treeName, rootNode, workingNode, tempNode;
- id newString, stack = [[List alloc] init];
- int indLevel, numSpaces, indent = 0;
- const char *tempString;
- BOOL rStat = YES;
- FILE *file;
- // for debugging:
- //NXStream *out = NXOpenFile(fileno(stdout), NX_WRITEONLY);
-
- // get a new doc window.
- [NXApp loadNibSection:"DocWindow.nib" owner:self withNames:NO];
- [[treeView window] setTitleAsFilename:name];
- // put up an alert panel to let user know we're busy
- // alert = NXGetAlertPanel(NULL, "Reading tree and creating image.",
- // NULL, NULL, NULL);
- // [alert makeKeyAndOrderFront:self];
- // Read the tree file. NOTE THAT THIS DOES NOT DO ERROR CHECKING.
- file = fopen(name, "r");
- nextChar = fgetc(file); // prime the system
- treeName = readToNewline(file); // first line is tree's name
- aString = readToSep(file); // Get the name of the root node.
- rootNode = [[[NamedTree alloc]
- initLabelString:aString] setTreeName:treeName];
- if (prevChar != '\n')
- [rootNode setValue: readToSep(file)]; // Set the node's value.
- [stack insertObject:rootNode at:0];
- workingNode = rootNode;
- // figure out the indentation
- while (nextChar == ' ') {
- indent++;
- nextChar = fgetc(file);
- }
- aString = readToSep(file); // get name of child node
- tempNode = [[[NamedTree alloc]
- initLabelString:aString] setTreeName:treeName];
- if (prevChar != '\n')
- [tempNode setValue: readToSep(file)]; // Set the node's value.
- [workingNode addBranch:tempNode];
- [stack insertObject:tempNode at:0];
- workingNode = tempNode;
- // now that we know the file's char's, we read in the other nodes
- // I use a List object as if it were a stack and push parent nodes on
- // it while working on children rather than doing a recursive function.
- // the comments are sparse, just know that it's mostly pushing and
- // popping from the stack to get at the right parent to add a child to.
- while (!feof(file)) {
- aString = readToSep(file); // next node name + indentation.
- // find out # of indentation spaces and strip them off
- // *** This gives a warning: ignore it, it's unimportant here.
- tempString = [aString stringValue]; numSpaces = 0;
- while (tempString[0] == ' ') {
- numSpaces++; tempString++;
- }
- indLevel = numSpaces / indent;
- if (indLevel == ([stack count] - 1)) // same level as last object
- {
- [stack removeObjectAt:0];
- workingNode = [stack objectAt:0];
- newString = [[String alloc] initString:tempString];
- [aString free];
- tempNode = [[[NamedTree alloc]
- initLabelString:newString] setTreeName:treeName];
- if (prevChar != '\n')
- [tempNode setValue: readToSep(file)]; // Set the node's value.
- [workingNode addBranch:tempNode];
- [stack insertObject:tempNode at:0];
- workingNode = tempNode;
- } else if (indLevel == ([stack count])) { // child of last node
- newString = [[String alloc] initString:tempString];
- [aString free];
- tempNode = [[[NamedTree alloc]
- initLabelString:newString] setTreeName:treeName];
- if (prevChar != '\n')
- [tempNode setValue: readToSep(file)]; // Set the node's value.
- [workingNode addBranch:tempNode];
- [stack insertObject:tempNode at:0];
- workingNode = tempNode;
- } else if (indLevel < [stack count]) { // higher level, so pop
- while (indLevel < [stack count]) { // pop until at right level
- [stack removeObjectAt:0];
- workingNode = [stack objectAt:0];
- } // now add new node since we're at the level
- newString = [[String alloc] initString:tempString];
- [aString free];
- tempNode = [[[NamedTree alloc]
- initLabelString:newString] setTreeName:treeName];
- if (prevChar != '\n')
- [tempNode setValue: readToSep(file)]; // Set the node's value.
- [workingNode addBranch:tempNode];
- [stack insertObject:tempNode at:0];
- workingNode = tempNode;
- } else { // typically, if user goes in two levels at once, which
- // doesn't make any sense semantically
- fprintf(stderr, "Error: level too deep!\n");
- rStat = NO;
- }
- }
- // Debugging code to pretty print the parsed tree. If this output
- // is correct, then we know that the parse was OK.
- //printf("\nHere's the parsed tree:\n");
- //printf("Tree name: \"%s\".", [treeName stringValue]);
- //[rootNode dumpTree:out level:0 indent:" "];
- //printf("\n\n");
- //NXClose(out);
- // end debug code
- // rStat = return status of tree reader YES = success
- // Now attach the Tree to the TreeView...
- [treeView attachTree:rootNode];
- // and now bring up the window for the user
- [[treeView window] moveTo:nextX :(nextY-218)];
- // Get rid of the alert
- // [alert orderOut:self];
- // [alert free];
- nextX += 22; nextY -= 25;
- if (nextX > 370)
- {
- nextX = 200; nextY = 600;
- }
- [[treeView window] makeKeyAndOrderFront:self];
- return rStat;
- }
-
-
- // The next two methods allow the WorkSpace to open a .tree file when
- // it is double-clicked. (Or any file that's cmd-dragged over our icon.)
-
- - (BOOL)appAcceptsAnotherFile:sender { return YES; }
- - (int)app:sender openFile:(const char *)file type:(const char *)type
- {
- return [self openFile:file];
- }
-
-
- @end
-