#import "dotGraphWatcher.h" #import "utils.h" #import "tamsutils.h" #import "prefBoss.h" #import "MGWPopUpButton.h" int moveInArray(id who, NSMutableArray *theArray, int row) { int dndNdx; dndNdx = [theArray indexOfObject: who]; if(row > dndNdx) { [theArray insertObject: who atIndex: row]; [theArray removeObjectAtIndex: dndNdx]; return row; } else if (row < dndNdx) { [theArray removeObject: who]; [theArray insertObject: who atIndex: row]; return row +1; } return row; } NSString *seDirNames [] = { @"Both", @"Forward", @"Backward" }; NSString *nodeShapes[]={ @"plaintext", @"box", @"ellipse", @"hexagon", @"house", @"point"}; NSString *edgeType[]={ @"both", @"forward", @"back", @"none"}; NSString *edgeStyle[]= { @"solid", @"dotted", @"dashed", @"invis"}; NSString *borderStyle[] = { @"solid", @"bold", @"dotted", @"filled"}; @implementation dotGraphWatcher -(id) init { [super init]; dndList = [[NSMutableArray alloc] init]; colList = [[NSMutableArray alloc] init]; pairList = [[NSMutableArray alloc] init]; pairCount = [[MWDoubleDictionary alloc] init]; return self; } -(void) onExit { [colList release]; [pairList release]; [pairCount release]; [attribs release]; [pairAttribs release]; [edgeAttribs release]; [seDict release]; [snDict release]; } -(void) dealloc { [dndList release]; [super dealloc]; } - (IBAction)addDotGraph:(id)sender { } -(int) codeLevel { return [codeLevel intValue]; } //NSPRINTF(X) appendString: [NSString stringWithFormat: X] -(NSString *) properNameForVariable: (NSString *) X Value: (NSString *) Y { //is this _code? if([X isEqualToString: @"_code"] && [codeLevelSwitch state] == NSOnState) { int lvl; NSString *nc; lvl = [self codeLevel]; nc = codeToLevel(Y, lvl); return nc; } else return Y; } -(NSString *) nodeNameForVariable: (NSString *) X Value: (NSString *) Y { //is this _code? if([X isEqualToString: @"_code"] && [codeLevelSwitch state] == NSOnState) { int lvl; NSString *nc; lvl = [self codeLevel]; nc = codeToLevel(Y, lvl); return [NSString stringWithFormat: @"%@:%@",X, nc]; } else return [NSString stringWithFormat: @"%@:%@",X, Y]; } #define NODENAME(X,Y) [self nodeNameForVariable: X Value: Y] #define PROPERNAME(X,Y) [self properNameForVariable: X Value: Y] -(void) savePanelDidEnd: (NSSavePanel *) sheet returnCode: (int) returnCode contextInfo: (void *) contextInfo { if(returnCode == NSOKButton) { [self openGraphviz: [sheet filename]]; } else { } } -(void) projectGraphviz: (NSString *) theName { NSTask *mytask; mytask = [[NSTask alloc] init]; [mytask setLaunchPath: [gPrefBoss dotDir]]; [mytask setArguments: [NSArray arrayWithObjects: @"-Tps", [NSString stringWithFormat: @"-o%@.ps",theName],theName, nil]]; /* [[NSFileManager defaultManager] createFileAtPath: [NSString stringWithFormat: @"%@.ps", theName] contents: @"" attributes: [NSDictionary dictionary]]; [mytask setStandardOutput: [NSFileHandle fileHandleForWritingAtPath: [NSString stringWithFormat: @"%@.ps", theName]]]; */ [mytask launch]; //[mytask waitUntilExit]; if([gPrefBoss useGV] == 1) { NSLog(@"Using gv\n"); [NSTask launchedTaskWithLaunchPath: [gPrefBoss gvDir] arguments: [NSArray arrayWithObjects: [NSString stringWithFormat: @"%@.ps",theName], nil]]; } else if([[NSWorkspace sharedWorkspace] openFile: [NSString stringWithFormat: @"%@.ps", theName]] == NO) { NSString *mywarn, *mygraphfile; mygraphfile = [NSString stringWithFormat: @"%@.ps", theName]; mywarn = [NSString stringWithFormat: @"Could not open application for file \"%@\"", mygraphfile]; NSWARNING(mywarn); } } -(void) openGraphviz: (NSString *) theName { { // NSString *theName = [NSString stringWithFormat: @"/tmp/tams %@%@.dot", [nameField stringValue], uniqueFileName()]; //NSString *theName = @"/Users/Matthew/out.dot" NSMutableString *ans = [[NSMutableString alloc] init]; NSArray *data; int i,j, k,cnt, cnt2, cnt3; NSMutableArray *fieldValues = [[NSMutableArray alloc] init]; //set the open [ans setString: [NSString stringWithFormat: @"digraph \"%@\" {\ngraph[overlap=no]\n", [nameField stringValue]]]; [ans appendString: [NSString stringWithFormat: @"edge[dir=%@ style=%@]\n", edgeType[[[arrowDirMenu selectedItem] tag]], edgeStyle[[[lineTypeMenu selectedItem] tag]]]]; //get the selected cols //assemble the scale { if([[levelMenu selectedItem] tag] == 0) { [ans appendString: [NSString stringWithFormat: @"{\nedge[color=white]\nnode[shape=plaintext]\n"]]; cnt = [colList count]; for(i = 0; i < cnt; i++) { if(i == 0)[ans appendString: [NSString stringWithFormat: @"\"%@\"",[colList objectAtIndex: i]]]; else [ans appendString: [NSString stringWithFormat:@"->\"%@\"", [colList objectAtIndex: i]]]; } [ans appendString: @"\n}\n\n"]; } } //get the data data = [theBoss hotData]; //go through and for each column assemble the data and { cnt = [colList count]; cnt2 = [data count]; for(i = 0; i < cnt; i++) { for(j = 0; j < cnt2; j++) { id thisRec; thisRec = [data objectAtIndex: j]; addUniqueToArray(fieldValues, PROPERNAME([colList objectAtIndex: i], [thisRec objectForKey: [colList objectAtIndex: i]])); } //then create a "same" if([[levelMenu selectedItem] tag] == 0) { [ans appendString: [NSString stringWithFormat: @"{rank=same; \"%@\";", [colList objectAtIndex: i]]]; cnt3 = [fieldValues count]; for(j=0; j < cnt3; j++) { [ans appendString: [NSString stringWithFormat: @" \"%@\"", NODENAME([colList objectAtIndex: i], [fieldValues objectAtIndex: j])]]; } [ans appendString: @"}\n"]; } //at the same time we should do the boxes!! FORALL(fieldValues) { NSString *a;//, *aa; a = [self findAttrib: [colList objectAtIndex: i] forWhat: temp]; [ans appendString: [NSString stringWithFormat: @"\"%@\"[label=\"%@\"]\n", NODENAME([colList objectAtIndex: i], temp), PROPERNAME([colList objectAtIndex:i], temp)]]; /* if((aa = [nsDict objectForKey: NODENAME([colList objectAtIndex: i], temp)]) != nil) { [ans appendString: [NSString stringWithFormat: @"\"%@\"%@\n", NODENAME([colList objectAtIndex: i], temp), aa]]; } */ if([a isEqualToString: @""] == NO) { [ans appendString: a]; [ans appendString: @"\n"]; } } ENDFORALL; [fieldValues removeAllObjects]; } } [fieldValues release]; //go through and count the # of maps { NSArray *fk, *sk; NSString *ea; int xcnt; int ycnt; ycnt = xcnt = cnt; if([[typeMenu selectedItem] tag] == 0) xcnt = 1; [edgeAttribs removeAllObjects]; [pairCount removeAllObjects]; for(i = 0; i < xcnt; i++) { if([[typeMenu selectedItem] tag] == 2) { ycnt = i+2; //kludge to make the this for loop only go one time if( ycnt > cnt) continue; } for(j=i+1; j < ycnt; j++) { for(k=0; k\"%@\"[label=\"%d\"]", temp, currVal, [pairCount intForKey1: temp key2: currVal]]]; else [ans appendString: [NSString stringWithFormat: @"\"%@\"->\"%@\"", temp, currVal]]; if((eans = [seDict objectForKey1: temp key2: @"Backward"]) != nil) { //first [ans appendString: eans]; } else if((eans = [seDict objectForKey1: temp key2: @"Both"]) != nil) { //first [ans appendString: eans]; } else if((eans = [seDict objectForKey1: currVal key2: @"Forward"]) != nil) [ans appendString: eans]; else if((eans = [seDict objectForKey1: currVal key2: @"Forward"]) != nil) [ans appendString: eans]; else if([edgeAttribs objectExistsForKey1: temp key2: currVal]) { [ans appendString: [edgeAttribs objectForKey1: temp key2: [sk objectAtIndex: i]]]; } [ans appendString: @"\n"]; } } ENDFORALL; } [ans appendString: @"}\n"]; [ans writeToFile: theName atomically: YES]; if(saveFlag == NO) [self projectGraphviz: theName]; // [[NSWorkspace sharedWorkspace] openFile:theName withApplication: @"Graphviz.app"]; } } - (IBAction)cancel:(id)sender { [thePane orderOut: sender]; [NSApp endSheet: thePane returnCode: 0]; } - (IBAction)delAllDotGraph:(id)sender { } - (IBAction)delDotGraph:(id)sender { } -(void) dotGraphDidEnd: (NSWindow *) mySheet returnCode: (int) returnCode contextInfo: (void *) contextInfo { if(returnCode) { } [self onExit]; } - (IBAction)writeDotGraph:(id)sender { NSSavePanel *msp; NSEnumerator *nnn; NSNumber *ndx; nnn = [fieldList selectedRowEnumerator]; [colList removeAllObjects]; while((ndx = [nnn nextObject]) != nil) { [colList addObject: [colPool objectAtIndex: [ndx intValue]]]; } if([colList count] <= 1) { NSWARNING(@"Select fields for graphing"); return; } if(saveFlag == YES) { msp = [NSSavePanel savePanel]; [msp setDelegate: self]; [msp setRequiredFileType: @"dot"]; [msp beginSheetForDirectory: nil file: nil modalForWindow: thePane modalDelegate: self didEndSelector: @selector(savePanelDidEnd:returnCode:contextInfo:) contextInfo: nil]; } else { NSString *theName = [NSString stringWithFormat: @"/tmp/tams %@ %@.dot", [nameField stringValue], uniqueFileName()]; [self openGraphviz: theName]; } //[thePane orderOut: sender]; //[NSApp endSheet: thePane returnCode: 1]; } -(IBAction) override: (id) sender { if([overrideSwitch state] == NSOffState) { saveFlag = NO; /* if(graphvizInstalled == NO) { NSWARNING(@"Graphviz is not properly installed, will prompt for file to save"); [overrideSwitch setState: NSOnState]; saveFlag = YES; } else saveFlag = NO; */ } else { saveFlag = YES; } if(saveFlag == YES) [saveButton setTitle: @"Save graph"]; else [saveButton setTitle: @"Show graph"]; } -(void) doDotGraph { id columns; int n; /* if([[NSWorkspace sharedWorkspace] fullPathForApplication: @"Graphviz"] == nil) graphvizInstalled = NO; else graphvizInstalled = YES; */ graphvizInstalled = YES; if([gPrefBoss saveGraphviz] == 0 && graphvizInstalled ==NO) { // NSWARNING(@"Graphviz is not properly installed, will prompt for file to save"); // saveFlag = YES; saveFlag = NO; } else if (graphvizInstalled == NO) { saveFlag = YES; } else if ([gPrefBoss saveGraphviz] == 1) saveFlag = YES; else saveFlag = NO; [codeLevel setIntValue: [theBoss codeLevel]]; if(saveFlag == YES) [overrideSwitch setState: NSOnState]; else [overrideSwitch setState: NSOffState]; [dndList removeAllObjects]; // [fieldList setVerticalMotionCanBeginDrag: YES]; [fieldList registerForDraggedTypes: [NSArray arrayWithObjects: NSStringPboardType, nil]]; NSLog(@"register drags\n"); attribs = [[NSMutableArray alloc] init]; colList = [[NSMutableArray alloc] init]; colPool = [[NSMutableArray alloc] init]; pairList = [[NSMutableArray alloc] init]; pairCount = [[MWDoubleDictionary alloc] init]; pairAttribs = [[MWDoubleDictionary alloc] init]; edgeAttribs = [[MWDoubleDictionary alloc] init]; snDict = [[NSMutableDictionary alloc] init]; seDict = [[MWDoubleDictionary alloc] init]; columns = [theBoss tableColumns]; [nGroupMenu removeAllItems]; [fromMenu removeAllItems]; [toMenu removeAllItems]; [snVarMenu removeAllItems]; [snValMenu removeAllItems]; [seVarMenu removeAllItems]; [seValMenu removeAllItems]; FORALL(columns) { NSString *idfr = [temp identifier]; if([idfr isEqualToString: @"#"]) continue; else if([idfr isEqualToString: @"_code"]) [colPool addObject: [[idfr copy] autorelease]]; else if([idfr characterAtIndex: 0] == '_') continue; else [colPool addObject: [[idfr copy] autorelease]]; /* OLD code if([theBoss fieldType: [temp identifier]] > 0) { [colPool addObject: [temp identifier]]; } else { if([[temp identifier] isEqualToString: @"_code"] || [[temp identifier] isEqualToString: @"_doc"] ) [colPool addObject: [temp identifier]]; } */ } ENDFORALL; n = [colPool count]; //[snVarMenu setDelegate: self]; //[seVarMenu setDelegate: self]; /* for(i = 0 ; i < n; i++) { [ snVarMenu addItemWithTitle: [colPool objectAtIndex: i] action: @selector(snValHandler) keyEquivalent: @""]; [ seVarMenu addItemWithTitle: [colPool objectAtIndex: i] action: @selector(seValHandler) keyEquivalent: @""]; } */ [snVarMenu addItemsWithTitles: colPool]; [snVarMenu setAction: @selector(snValHandler:)]; [snVarMenu setEnabled: YES]; NSLog(@"added snVal\n"); [seVarMenu addItemsWithTitles: colPool]; [seVarMenu setAction: @selector(seValHandler:)]; [seVarMenu setEnabled: YES]; NSLog(@"added seVal\n"); [self seValHandler: nil]; [self snValHandler: nil]; [nGroupMenu addItemsWithTitles: colPool]; NSLog(@"ngroupmenu\n"); [fromMenu addItemsWithTitles: colPool]; NSLog(@"fromMenu \n"); [toMenu addItemsWithTitles: colPool]; NSLog(@"added menus\n"); [fieldList reloadData]; [attribTable reloadData]; [edgeAttribTable reloadData]; [seTable reloadData]; [snTable reloadData]; NSLog(@"tables reloaded\n"); if([gPrefBoss saveGraphviz]) [saveButton setTitle: @"Save graph"]; else [saveButton setTitle: @"Show graph"]; [NSApp beginSheet: thePane modalForWindow: nil modalDelegate: self didEndSelector: @selector(dotGraphDidEnd:returnCode:contextInfo:) contextInfo: nil]; } -(IBAction) addAttrib:(id)sender { NSMutableDictionary *tmp; int n; NSString *wh; n = [[nShapeMenu selectedItem] tag]; wh =nodeShapes[n]; tmp = [[NSMutableDictionary alloc] init]; [tmp setObject: [[[nGroupMenu titleOfSelectedItem] copy] autorelease] forKey: @"name"]; [tmp setObject: [[wh copy] autorelease] forKey: @"shape"]; [tmp setObject: [[borderStyle[[[nBorderMenu selectedItem] tag]] copy] autorelease] forKey: @"border"]; [attribs addObject: [tmp autorelease]]; [attribTable reloadData]; } - (int)numberOfRowsInTableView:(NSTableView *) tt { if(tt == fieldList) return [colPool count]; if(tt == attribTable) return [attribs count]; if(tt == edgeAttribTable) return [pairAttribs count]; if(tt == snTable) return [[snDict allKeys] count]; if(tt == seTable) return [seDict count]; } -(IBAction) delAttrib: (id) sender { int n; n = [attribTable selectedRow]; if( n >= 0) [attribs removeObjectAtIndex: n]; [attribTable reloadData]; } -(IBAction) delAllAttrib: (id) sender { [attribs removeAllObjects]; [attribTable reloadData]; } -(NSString *) attribNdx: (int) rowIndex { NSDictionary *who = [attribs objectAtIndex: rowIndex]; return [NSString stringWithFormat: @"\"%@\"[shape=%@ style=%@]", [who objectForKey: @"name"], [who objectForKey: @"shape"], [who objectForKey: @"border"]]; } -(NSString *) findAttrib: (NSString *) who forWhat: (NSString *) what { NSString *pn; NSString *ans; NSString *nn; pn = PROPERNAME(who, what); nn = NODENAME(who, pn); if((ans = [snDict objectForKey: nn]) != nil) return ans; FORALL(attribs) { if([[temp objectForKey: @"name"] isEqualToString: who]) return [NSString stringWithFormat: @"\"%@:%@\"[shape=%@ style=%@]", who,pn, [temp objectForKey: @"shape"], [temp objectForKey: @"border"]]; } ENDFORALL; return @""; } - (NSDragOperation)tableView:(NSTableView *)tableView validateDrop:(id)info proposedRow:(int)row proposedDropOperation:(NSTableViewDropOperation)operation { if(tableView == fieldList) return NSDragOperationMove;//NSDragOperationEvery else return NSDragOperationNone ; } - (BOOL)tableView:(NSTableView *)tableView acceptDrop:(id )info row:(int)row dropOperation:(NSTableViewDropOperation)operation { int n; if(tableView == fieldList) { int currSpot; /* [colPool removeObjectsInArray: dndList]; FORALL(dndList) { [colPool insertObject: temp atIndex: row + __i]; } ENDFORALL; return YES; */ #ifdef SINGLEDRAG if(row > dndNdx) { NSString *tmp; tmp = [colPool objectAtIndex: dndNdx]; [colPool insertObject: tmp atIndex: row]; [colPool removeObjectAtIndex: dndNdx]; } else if (row < dndNdx) { NSString *tmp; tmp = [colPool objectAtIndex: dndNdx]; [colPool insertObject: tmp atIndex: row]; [colPool removeObjectAtIndex: dndNdx + 1]; } [tableView reloadData]; return YES; #else n = [dndList count]; currSpot = row; FORALL(dndList) { currSpot = moveInArray(temp, colPool, currSpot); } ENDFORALL; [tableView reloadData]; [tableView deselectAll: nil]; FORALL(dndList) { [tableView selectRow: [colPool indexOfObject: temp] byExtendingSelection: YES]; } ENDFORALL; [dndList removeAllObjects]; return YES; #endif } else return NO; } - (BOOL)tableView:(NSTableView *)tableView writeRows:(NSArray *)rows toPasteboard:(NSPasteboard *)pboard { id testid; testid = fieldList; if(tableView == fieldList) { /* [dndList removeAllObjects]; FORALL(rows) { [dndList addObject: [colPool objectAtIndex: [temp intValue]]]; } ENDFORALL; [pboard setString: [dndList objectAtIndex: 0] forType: NSStringPboardType]; return YES; */ #ifdef SINGLEDRAG if([rows count] != 1) return NO; dndNdx = [[rows objectAtIndex: 0] intValue]; [pboard setString: [colPool objectAtIndex: [[rows objectAtIndex: 0] intValue]] forType: NSStringPboardType]; return YES; #else [dndList removeAllObjects]; FORALL(rows) { [dndList addObject: [colPool objectAtIndex: [temp intValue]]]; } ENDFORALL; [pboard declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:self]; [pboard setString: [colPool objectAtIndex: [[rows objectAtIndex: 0] intValue]] forType: NSStringPboardType]; return YES; #endif } else return NO; } - (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex { if(aTableView == fieldList) return [colPool objectAtIndex: rowIndex]; if(aTableView == attribTable) { return [self attribNdx: rowIndex]; } if(aTableView == edgeAttribTable) { NSArray *aa; NSDictionary *dd; aa = [pairAttribs toArray]; dd = [aa objectAtIndex: rowIndex]; return [NSString stringWithFormat: @"%@->%@%@", [dd objectForKey: @"key1"], [dd objectForKey: @"key2"], [dd objectForKey: @"object"]]; } if(aTableView == snTable) { NSString *who; who = [[snDict allKeys] objectAtIndex: rowIndex]; return [NSString stringWithFormat: @"%@%@", who, [snDict objectForKey: who]]; } if(aTableView == seTable) { NSArray *aa; NSDictionary *rr; aa = [seDict toArray]; rr = [aa objectAtIndex: rowIndex]; return [NSString stringWithFormat: @"%@%@ %@", [rr objectForKey: @"key1"], [rr objectForKey: @"object"], [rr objectForKey: @"key2"]]; } } /* -(NSString *) edgeAttribsForFrom: (NSString *) from To: (NSString *) to { NSString *ans; if((ans = [seDict objectForKey: from]) != nil) return ans; else if((ans = [seDict objectForKey: to]) != nil) return ans; else return [pairAttribs objectForKey1: from key2: to]; } */ -(IBAction) addEdgeAttrib: (id)sender { NSString *sss; sss = [NSString stringWithFormat: @"[dir=%@ style=%@]", edgeType[[[ftDirMenu selectedItem] tag]], edgeStyle[[[ftStyleMenu selectedItem] tag]]]; [pairAttribs setObject: sss forKey1: [fromMenu titleOfSelectedItem] key2: [toMenu titleOfSelectedItem]]; [edgeAttribTable reloadData]; } -(IBAction) delEdgeAttrib: (id) sender { NSArray *aa; NSDictionary *dd; int n; n = [edgeAttribTable selectedRow]; if(n < 0) return; aa = [pairAttribs toArray]; dd = [aa objectAtIndex: n]; [pairAttribs removeObjectForKey1: [dd objectForKey: @"key1"] key2: [dd objectForKey: @"key2"]]; [edgeAttribTable reloadData]; } -(IBAction) delAllEdgeAttrib: (id) sender { [pairAttribs removeAllObjects]; [edgeAttribTable reloadData]; } -(void) buildVarMenuFrom: (NSPopUpButton *) varMenu to: (NSPopUpButton *) valMenu { NSMutableArray *vals = [NSMutableArray array]; NSArray *arr = [theBoss hotData]; NSString *varName; if([varMenu indexOfSelectedItem] < 0) return; varName = [varMenu titleOfSelectedItem]; [valMenu removeAllItems]; FORALL(arr) { NSString *rn = PROPERNAME(varName, [temp objectForKey: varName]); addUniqueToArray(vals, rn); } ENDFORALL; [valMenu addItemsWithTitles: vals]; } -(IBAction) snValHandler: (id) sender { [self buildVarMenuFrom: snVarMenu to: snValMenu]; } -(IBAction) snAdd: (id) sender { if([snValMenu count] == 0) return; [snDict setObject: [NSString stringWithFormat: @"[shape=%@ style=%@]", nodeShapes[[[snShapeMenu selectedItem] tag]], borderStyle[[[snStyleMenu selectedItem] tag]]] forKey: NODENAME([snVarMenu titleOfSelectedItem], [snValMenu titleOfSelectedItem])]; [snTable reloadData]; } -(IBAction) snDel: (id) sender{ int n; NSString *who; n = [snTable selectedRow]; who = [[snDict allKeys] objectAtIndex: n]; [snDict removeObjectForKey: who]; [snTable reloadData]; } -(IBAction) snDelAll: (id) sender{ [snDict removeAllObjects]; [snTable reloadData]; } -(IBAction) seValHandler: (id) sender { [self buildVarMenuFrom: seVarMenu to: seValMenu]; } -(IBAction) seAdd: (id) sender { if([seValMenu count] == 0) return; [seDict setObject: [NSString stringWithFormat: @"[dir=%@ style=%@]", edgeType[[[seShapeMenu selectedItem] tag]], edgeStyle[[[seStyleMenu selectedItem] tag]]] forKey1: NODENAME([seVarMenu titleOfSelectedItem], [seValMenu titleOfSelectedItem]) key2: seDirNames[[[seDirMenu selectedItem] tag]]]; [seTable reloadData]; } -(IBAction) seDel: (id) sender{ int n; NSDictionary *dd; NSArray *aa; aa = [seDict toArray]; n = [seTable selectedRow]; dd = [aa objectAtIndex: n]; [seDict removeObjectForKey1: [dd objectForKey: @"key1"] key2: [dd objectForKey: @"key2"]]; [seTable reloadData]; } -(IBAction) seDelAll: (id) sender { [seDict removeAllObjects]; [seTable reloadData]; } @end