/************************************************************************* * Copyright (c) 2011 AT&T Intellectual Property * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/legal/epl-v10.html * * Contributors: Details at http://www.graphviz.org/ *************************************************************************/ #import "GVAttributeInspectorController.h" #import "GVAttributeSchema.h" #import "GVDocument.h" #import "GVZGraph.h" #import "GVWindowController.h" @implementation GVAttributeInspectorController - (id)init { if (self = [super initWithWindowNibName: @"Attributes"]) { _allSchemas = nil; _allAttributes = [[NSMutableDictionary alloc] init]; _inspectedDocument = nil; _otherChangedGraph = YES; } return self; } - (void)awakeFromNib { /* set component toolbar */ [_allSchemas release]; _allSchemas = [[NSDictionary alloc] initWithObjectsAndKeys: [GVAttributeSchema attributeSchemasWithComponent:@"graph"], [graphToolbarItem itemIdentifier], [GVAttributeSchema attributeSchemasWithComponent:@"node"], [nodeDefaultToolbarItem itemIdentifier], [GVAttributeSchema attributeSchemasWithComponent:@"edge"], [edgeDefaultToolbarItem itemIdentifier], nil]; [componentToolbar setSelectedItemIdentifier:[graphToolbarItem itemIdentifier]]; [self toolbarItemDidSelect:nil]; /* start observing whenever a window becomes main */ [self graphWindowDidBecomeMain:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(graphWindowDidBecomeMain:) name:NSWindowDidBecomeMainNotification object:nil]; } - (IBAction)toolbarItemDidSelect:(id)sender { /* reload the table */ [attributeTable reloadData]; } - (void)graphWindowDidBecomeMain:(NSNotification *)notification { NSWindow* mainWindow = notification ? [notification object] : [NSApp mainWindow]; GVDocument* mainWindowDocument = [[mainWindow windowController] document]; /* update and observe referenced document */ NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter]; if (_inspectedDocument) [defaultCenter removeObserver:self name:@"GVGraphDocumentDidChange" object:_inspectedDocument]; _inspectedDocument = mainWindowDocument; [defaultCenter addObserver:self selector:@selector(graphDocumentDidChange:) name:@"GVGraphDocumentDidChange" object:mainWindowDocument]; [self reloadAttributes]; /* update the UI */ [[self window] setTitle:[NSString stringWithFormat:@"%@ Attributes", [mainWindow title]]]; [attributeTable reloadData]; } - (void)graphDocumentDidChange:(NSNotification *)notification { /* if we didn't instigate the change, update the UI */ if (_otherChangedGraph) { [self reloadAttributes]; [attributeTable reloadData]; } } - (void)reloadAttributes { /* reload the attributes from the inspected document's graph */ [_allAttributes removeAllObjects]; if ([_inspectedDocument respondsToSelector:@selector(graph)]) { GVZGraph *graph = [_inspectedDocument graph]; [_allAttributes setObject:graph.graphAttributes forKey:[graphToolbarItem itemIdentifier]]; [_allAttributes setObject:graph.defaultNodeAttributes forKey:[nodeDefaultToolbarItem itemIdentifier]]; [_allAttributes setObject:graph.defaultEdgeAttributes forKey:[edgeDefaultToolbarItem itemIdentifier]]; } } - (NSArray *)toolbarSelectableItemIdentifiers:(NSToolbar *)toolbar { /* which toolbar items are selectable */ return [NSArray arrayWithObjects: [graphToolbarItem itemIdentifier], [nodeDefaultToolbarItem itemIdentifier], [edgeDefaultToolbarItem itemIdentifier], nil]; } - (NSCell *)tableView:(NSTableView *)tableView dataCellForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row { if ([[tableColumn identifier] isEqualToString:@"value"]) { /* use the row's schema's cell */ NSCell *cell = [[[_allSchemas objectForKey:[componentToolbar selectedItemIdentifier]] objectAtIndex:row] cell]; [cell setEnabled:[_allAttributes count] > 0]; return cell; } else /* use the default cell (usually a text field) for other columns */ return nil; } - (void)tableViewSelectionDidChange:(NSNotification *)aNotification { NSInteger selectedRow = [[aNotification object] selectedRow]; NSString* documentation = selectedRow == -1 ? nil : [[[_allSchemas objectForKey:[componentToolbar selectedItemIdentifier]] objectAtIndex: selectedRow] documentation]; [[documentationWeb mainFrame] loadHTMLString:documentation baseURL:[NSURL URLWithString:@"http://www.graphviz.org/"]]; } - (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView { return [[_allSchemas objectForKey:[componentToolbar selectedItemIdentifier]] count]; } - (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)rowIndex { NSString *selectedComponentIdentifier = [componentToolbar selectedItemIdentifier]; NSString *attributeName = [[[_allSchemas objectForKey:selectedComponentIdentifier] objectAtIndex:rowIndex] name]; if ([[tableColumn identifier] isEqualToString:@"key"]) return attributeName; else if ([[tableColumn identifier] isEqualToString:@"value"]) /* return the inspected graph's attribute value, if any */ return [[_allAttributes objectForKey:selectedComponentIdentifier] valueForKey:attributeName]; else return nil; } - (void)tableView:(NSTableView *)aTableView setObjectValue:(id)anObject forTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)rowIndex { if ([[tableColumn identifier] isEqualToString:@"value"]) { NSString *selectedComponentIdentifier = [componentToolbar selectedItemIdentifier]; NSString *attributeName = [[[_allSchemas objectForKey:selectedComponentIdentifier] objectAtIndex:rowIndex] name]; /* set or remove the key-value on the selected attributes */ /* NOTE: to avoid needlessly reloading the table in graphDocumentDidChange:, we fence this change with _otherChangedGraph = NO */ _otherChangedGraph = NO; @try { [[_allAttributes objectForKey:selectedComponentIdentifier] setValue:anObject forKey:attributeName]; } @finally { _otherChangedGraph = YES; } } } - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowDidBecomeMainNotification object:nil]; [_allSchemas release]; [_allAttributes release]; [super dealloc]; } @end