home *** CD-ROM | disk | FTP | other *** search
-
- #import "TreeController.h"
- #import "NamedTree.h"
- #import "TreeView.h"
-
- @implementation TreeController
-
- - 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 parse
-
- id readToNewline(FILE *file) // used to parse a file; reads a line at a time
- { // 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);
- [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, aString, treeName, rootNode, workingNode, tempNode;
- id newString, stack = [[List alloc] init];
- int indLevel, numSpaces, indent = 0;
- 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 I don't do error checking. Badness.
- file = fopen(name, "r");
- nextChar = fgetc(file); // prime the system
- // first line is tree's name.
- treeName = readToNewline(file);
- aString = readToNewline(file); // get the name of the root node.
- rootNode = [[[NamedTree alloc]
- initLabelString:aString] setTreeName:treeName];
- [stack insertObject:rootNode at:0];
- workingNode = rootNode;
- // figure out the indentation
- while (nextChar == ' ') {
- indent++;
- nextChar = fgetc(file);
- }
- aString = readToNewline(file); // get name of child node
- tempNode = [[[NamedTree alloc]
- initLabelString:aString] setTreeName:treeName];
- [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 = readToNewline(file); // next node name + indentation.
- // find out # of indentation spaces and strip them off
- // *** this like 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];
- [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];
- [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];
- [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 and get rid of the alert
- [[treeView window] moveTo:nextX :(nextY-218)];
- [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
-