diff pkg-src/tree-nx/TreeController.m @ 163:0132846995bd r20-3b8

Import from CVS: tag r20-3b8
author cvs
date Mon, 13 Aug 2007 09:43:35 +0200
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pkg-src/tree-nx/TreeController.m	Mon Aug 13 09:43:35 2007 +0200
@@ -0,0 +1,265 @@
+
+#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;
+	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