123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203 |
- /*************************************************************************
- * 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 "GVZGraph.h"
- #import "GVGraphArguments.h"
- #import "GVGraphDefaultAttributes.h"
- NSString *const GVGraphvizErrorDomain = @"GVGraphvizErrorDomain";
- extern double PSinputscale;
- static GVC_t *_graphContext = nil;
- @implementation GVZGraph
- @synthesize graph = _graph;
- @synthesize arguments = _arguments;
- @synthesize graphAttributes = _graphAttributes;
- @synthesize defaultNodeAttributes = _defaultNodeAttributes;
- @synthesize defaultEdgeAttributes = _defaultEdgeAttributes;
- extern char *gvplugin_list(GVC_t * gvc, api_t api, const char *str);
- + (void)initialize
- {
- _graphContext = gvContext();
- }
- + (NSArray *)pluginsWithAPI:(api_t)api
- {
- NSMutableSet *plugins = [NSMutableSet set];
-
- /* go through each non-empty plugin in the list, ignoring the package part */
- char *pluginList = gvplugin_list(_graphContext, api, ":");
- char *restOfPlugins;
- char *nextPlugin;
- for (restOfPlugins = pluginList; (nextPlugin = strsep(&restOfPlugins, " "));) {
- if (*nextPlugin) {
- char *lastColon = strrchr(nextPlugin, ':');
- if (lastColon) {
- *lastColon = '\0';
- [plugins addObject:[NSString stringWithCString:nextPlugin encoding:NSUTF8StringEncoding]];
- }
- }
- }
- free(pluginList);
- return [[plugins allObjects] sortedArrayUsingSelector:@selector(compare:)];
- }
- - (id)initWithURL:(NSURL *)URL error:(NSError **)outError
- {
- char *parentDir,*ptr;
- if (self = [super init]) {
- if ([URL isFileURL]) {
- /* open a FILE* on the file URL */
- FILE *file = fopen([[URL path] fileSystemRepresentation], "r");
- if (!file) {
- if (outError)
- *outError = [NSError errorWithDomain:NSPOSIXErrorDomain code:errno userInfo:nil];
- [self autorelease];
- return nil;
- }
-
- _graph = agread(file,0);
- if (!_graph) {
- if (outError)
- *outError = [NSError errorWithDomain:GVGraphvizErrorDomain code:GVFileParseError userInfo:nil];
- [self autorelease];
- return nil;
- }
- if(!agget(_graph,"imagepath")){
- parentDir = (char *)[[URL path] fileSystemRepresentation];
- ptr = strrchr(parentDir,'/');
- *ptr = 0;
- agattr(_graph,AGRAPH,"imagepath",parentDir);
- }
- fclose(file);
- }
- else {
- /* read the URL into memory */
- NSMutableData *memory = [NSMutableData dataWithContentsOfURL:URL options:0 error:outError];
- if (!memory) {
- [self autorelease];
- return nil;
- }
-
- /* null terminate the data */
- char nullByte = '\0';
- [memory appendBytes:&nullByte length:1];
-
- _graph = agmemread((char*)[memory bytes]);
- if (!_graph) {
- if (outError)
- *outError = [NSError errorWithDomain:GVGraphvizErrorDomain code:GVFileParseError userInfo:nil];
- [self autorelease];
- return nil;
- }
- }
- _freeLastLayout = NO;
- _arguments = [[GVGraphArguments alloc] initWithGraph:self];
- _graphAttributes = [[GVGraphDefaultAttributes alloc] initWithGraph:self prototype:AGRAPH];
- _defaultNodeAttributes = [[GVGraphDefaultAttributes alloc] initWithGraph:self prototype:AGNODE];
- _defaultEdgeAttributes = [[GVGraphDefaultAttributes alloc] initWithGraph:self prototype:AGEDGE];
- }
-
- return self;
- }
- - (BOOL)writeToURL:(NSURL *)URL error:(NSError **)outError
- {
- if ([URL isFileURL]) {
- /* open a FILE* on the file URL */
- FILE *file = fopen([[URL path] fileSystemRepresentation], "w");
- if (!file) {
- if (outError)
- *outError = [NSError errorWithDomain:NSPOSIXErrorDomain code:errno userInfo:nil];
- return NO;
- }
-
- /* write it out */
- if (agwrite(_graph, file) != 0) {
- if (outError)
- *outError = [NSError errorWithDomain:NSPOSIXErrorDomain code:errno userInfo:nil];
- return NO;
- }
-
- fclose(file);
- return YES;
- }
- else
- /* can't write out to non-file URL */
- return NO;
- }
- - (void)noteChanged:(BOOL)relayout
- {
- /* if we need to layout, apply globals and then relayout */
- if (relayout) {
- NSString* layout = [_arguments objectForKey:@"layout"];
- if (layout) {
- if (_freeLastLayout)
- gvFreeLayout(_graphContext, _graph);
-
- /* apply scale */
- NSString* scale = [_arguments objectForKey:@"scale"];
- PSinputscale = scale ? [scale doubleValue] : 0.0;
- if (PSinputscale == 0.0)
- PSinputscale = 72.0;
-
- if (gvLayout(_graphContext, _graph, (char*)[layout UTF8String]) != 0)
- @throw [NSException exceptionWithName:@"GVException" reason:@"bad layout" userInfo:nil];
- _freeLastLayout = YES;
- }
- }
-
- [[NSNotificationCenter defaultCenter] postNotificationName: @"GVGraphDidChange" object:self];
- }
- - (NSData*)renderWithFormat:(NSString *)format
- {
- char *renderedData = NULL;
- unsigned int renderedLength = 0;
- if (gvRenderData(_graphContext, _graph, (char*)[format UTF8String], &renderedData, &renderedLength) != 0)
- @throw [NSException exceptionWithName:@"GVException" reason:@"bad render" userInfo:nil];
- return [NSData dataWithBytesNoCopy:renderedData length:renderedLength freeWhenDone:YES];
- }
- - (void)renderWithFormat:(NSString *)format toURL:(NSURL *)URL
- {
- if ([URL isFileURL]) {
- if (gvRenderFilename(_graphContext, _graph, (char*)[format UTF8String], (char*)[[URL path] UTF8String]) != 0)
- @throw [NSException exceptionWithName:@"GVException" reason:@"bad render" userInfo:nil];
- }
- else
- [[self renderWithFormat:format] writeToURL:URL atomically:NO];
- }
- - (void)dealloc
- {
- if (_graph)
- agclose(_graph);
-
- [_arguments release];
- [_graphAttributes release];
- [_defaultNodeAttributes release];
- [_defaultEdgeAttributes release];
- [super dealloc];
- }
- @end
|