This is NibFile.m in view mode; [Download] [Up]
/* NibList - A program to list the contents of nib files. Copyright (C) 1991 Oceania Healthcare Systems This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program, in a file called COPYING; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* This is where the action is. A few of the methods in this file are copied from * NeXT's very helpful TextLab example. The NibFile object is responsible for parsing * and printing the contents of a nib file in its own window. */ #import <appkit/appkit.h> #import <objc/List.h> #import <objc/Storage.h> #import <objc/StreamTable.h> #import <objc/typedstream.h> #import <string.h> #import "libnib.h" #import "Categories.h" #import "NibFile.h" #import <zone.h> #import <mach.h> char cbuff[1024]; @implementation NibFile - initFrame:(const NXRect *)frameRect { NXRect rect = {0.0, 0.0, 0.0, 0.0}; /* initialize view */ [super initFrame:frameRect]; /* specify scrollbars */ [[self setVertScrollerRequired:YES] setHorizScrollerRequired:NO]; [self getContentSize:&(rect.size)]; mainText = [self newText:&rect]; [self setDocView:mainText]; [mainText setSel:0 :0]; // The following two lines allow the resizing of the scrollview // to be passed down to the docView (in this case, the text view // itself). [contentView setAutoresizeSubviews:YES]; [contentView setAutosizing:NX_HEIGHTSIZABLE | NX_WIDTHSIZABLE]; // Create enclosing and bring it upfront [self makeEnclosingWindow:frameRect]; [[[window setTitle:"Untitled"] display] makeKeyAndOrderFront:self]; return self; } - initFile:(const char *)fileName { #define ORIGX 80.0 #define ORIGY 300.0 static NXRect wRect = {{ORIGX, ORIGY},{700.0,500.0}}; id theText = mainText; int textMark = [theText textLength]; NXTypedStream *inStream; NXOffsetRect(&wRect, 25.0, -25.0); if (wRect.origin.y < 0) { wRect.origin.y = ORIGY; wRect.origin.x = ORIGX; } [self initFrame:&wRect]; [theText setSel: 0 : textMark]; [theText replaceSel:""]; [[mainText window] setTitle:"Loading..."]; if( (inStream = NXOpenTypedStreamForFile( fileName, NX_READONLY )) == NULL ) { [self print:"Error opening "]; [self print:fileName]; [self print:"\n"]; return NO; } NXSetTypedStreamZone(inStream, [self zone]); table = NXReadObject( inStream ); runData = [table valueForStreamKey:(void *)NIBFILE_RUNTIME_DATA]; nibDataInst = [runData valueForKey:(void *)NIBRUNTIME_NIBDATA]; objects = [nibDataInst objectList]; object_getInstanceVariable( nibDataInst, "connectList", & (void *)connects ); icons = [runData valueForKey:(void *)NIBRUNTIME_ICONS]; sounds = [runData valueForKey:(void *)NIBRUNTIME_SOUNDS]; [[mainText window] setTitle:"Analyzing..."]; [self print:"NIBFileName: "]; [self print:fileName]; [self print:"\n"]; sprintf(cbuff, "Contains %d objects with %d connections,\n", [objects count], [connects count]); [self print:cbuff]; sprintf(cbuff, "%d icons, and %d sounds.", [icons count], [sounds count]); [self print:cbuff]; [self buildHash]; [[mainText window] disableFlushWindow]; [self print:"\n\n-----------OBJECTS------------\n"]; [self dumpNibObjectFromTree:tree]; [self print:"\n\n-----------ICONS------------\n"]; [self dumpRootObj:icons]; [self print:"\n\n-----------SOUNDS------------\n"]; [self dumpRootObj:sounds]; [self print:"" withFlush:YES]; [[mainText window] reenableFlushWindow]; [[mainText window] flushWindow]; if( !NXEndOfTypedStream( inStream ) ) [self print:"WHOAAA! There's more in the typed stream!\n\n\n"]; NXCloseTypedStream( inStream); [[mainText window] setTitleAsFilename:fileName]; [[mainText window] makeKeyAndOrderFront:self]; return self; } - makeEnclosingWindow:(const NXRect *)rect { id textWindow; textWindow = [[Window allocFromZone:[self zone]] initContent:rect style:NX_TITLEDSTYLE backing:NX_BUFFERED buttonMask:NX_ALLBUTTONS defer:NO]; [[textWindow setContentView:self] free]; [textWindow setBackgroundGray:NX_WHITE]; [textWindow setFreeWhenClosed:YES]; [textWindow setDelegate:self]; return self; } - newText:(const NXRect *)frameRect { id text; NXSize aSize = {1.0E38, 1.0E38}; text = [[Text allocFromZone:[self zone]] initFrame:frameRect text:NULL alignment:NX_LEFTALIGNED]; [text setOpaque:YES]; [[[[[[text notifyAncestorWhenFrameChanged:YES] setVertResizable:YES] setHorizResizable:NO] setMonoFont:NO] setEditable:NO] setDelegate:self]; [text setMinSize:&(frameRect->size)]; [text setMaxSize:&aSize]; [text setAutosizing:NX_HEIGHTSIZABLE | NX_WIDTHSIZABLE]; [text setCharFilter:NXEditorFilter]; return text; } /*========================== Delegate methods from Window ====================================*/ /* This will be a routine to free all the data malloc'ed and alloc'ed by the NibFile object. */ - windowWillClose:sender { return self; } /* The following routines make output to the text object quick, easy and efficient. * A 1K buffer is kept of text going out to the text object. This reduces the * number of calls to replaceSel:, which seems to be pretty slow when dealing * with lot of little chunks of text. The addition of the buffer sped up the * application by about 10X overall. */ - print:(const char *)output withFlush:(BOOL)flag { #define BSIZE (1024) static int i = 0; static char buff[BSIZE]; id theText; int textMark, len; if( ((len = strlen(output)) + i >= BSIZE -1) || flag ) { buff[i] = '\0'; theText = mainText; textMark = [theText textLength]; [theText setSel: textMark : textMark]; [theText replaceSel:buff]; i = 0; } strcpy( &(buff[i]), output ); i += len; return self; } - print:(const char *)output { if( output ) return [self print:output withFlush:NO]; else return [self print:"<<NULL pointer>>" withFlush:NO]; } - printTab:(const char *)output { int i; for( i = 0; i < numTabs; i++ ) [self print:" "]; [self print:output]; return self; } - enTab { numTabs++; return self; } - unTab { numTabs--; return self; } /* This routine cross-indexes the data from the nib file in a number of ways. * A tree of ownership relations is built, which facilitates the heirarchical * format of the output. In order to move between the tree and the objects * themselves, three hash tables are built. */ - buildHash; { struct nibObj *elem; /*These structs defined in libnib.h */ struct nibCon *celem; unsigned count = [objects count], i; unsigned ccount = [connects count]; List *curList, *parentList; Storage *curCons; tree = [[List allocFromZone:[self zone]] init]; treeByObj = [[HashTable allocFromZone:[self zone]] initKeyDesc:"@" valueDesc:"@"]; nameByObj = [[HashTable allocFromZone:[self zone]] initKeyDesc:"@" valueDesc:"*"]; connByObj = [[HashTable allocFromZone:[self zone]] initKeyDesc:"@" valueDesc:"@"]; elem = [objects elementAt:0]; [nameByObj insertKey:(elem->obj) value:(char *)(elem->name)]; [tree addObject:elem->obj]; [treeByObj insertKey:elem->obj value:tree]; for( i = 1; i < count; i++ ) { elem = [objects elementAt:i]; [nameByObj insertKey:(elem->obj) value:(char *)(elem->name)]; curList = [[List allocFromZone:[self zone]] init]; [curList addObject:elem->obj]; [treeByObj insertKey:elem->obj value:curList]; parentList = [treeByObj valueForKey:elem->parent]; [parentList addObject:curList]; } for( i = 0; i < ccount; i++ ) { celem = [connects elementAt:i]; curCons = [connByObj valueForKey:celem->from]; if( curCons == nil ) { curCons = [[Storage allocFromZone:[self zone]] initCount:0 elementSize:sizeof(struct nibCon) description: @encode(struct nibCon)]; [connByObj insertKey:celem->from value:curCons]; } [curCons addElement:celem]; } return self; } /* This routine prints just enough information about an object to * identify it uniquely. */ - summarizeObj:target { const char *c; if( target ) { [self print:"<"]; if( (c = [nameByObj valueForKey:target]) ) [self print:c]; [self print:">"]; if( [target respondsTo:@selector(className)] ) { [self print:[target className]]; } sprintf( cbuff, "(%08x)", (int)target ); [self print:cbuff]; } else [self print:"nil"]; return self; } /* This routine recursively prints all the objects in the ownership * tree. It is called once for the root object by the initFile: method */ - dumpNibObjectFromTree:target { unsigned count = [target count], i; id elem; elem = [target objectAt:0]; [self printTab:""]; [self summarizeObj:elem]; [self dumpObj:elem]; [self print:"\n"]; numTabs++; [self dumpNibConnectionsforObject:elem]; if( count > 1 ) { [self printTab:"Owns:\n"]; numTabs++; for( i = 1; i < count; i++ ) { [self dumpNibObjectFromTree:[target objectAt:i]]; } numTabs--; } numTabs--; return self; } /* This routine is called by dumpNibObjectFromTree:. It lists all * connections FROM the object it is passed. */ - dumpNibConnectionsforObject:anObject { struct nibCon *elem; /* This struct defined in libnib.h */ unsigned count, i; Storage *curCons; curCons = [connByObj valueForKey:anObject]; if( curCons != nil ) { [self printTab:"Connections:\n"]; numTabs++; count = [curCons count]; for( i = 0; i < count; i++ ) { elem = (struct nibCon *)[curCons elementAt:i]; [self printTab:""]; switch( elem->type ) { case NIBDATA_CONNECT_TARG: [self print:"target to action "]; [self print:elem->name]; [self print:" of "]; [self summarizeObj:elem->to]; break; case NIBDATA_CONNECT_OUTLET: [self print:"outlet "]; [self print:elem->name]; [self print:" to "]; [self summarizeObj:elem->to]; break; default: [self print:"****** Unknown connection type ******\n"]; break; } [self print:"\n"]; } numTabs--; } return self; } - dumpRootObj:target { numTabs = 0; [self dumpObj:target]; return self; } - dumpObj:target { if( !target ) { [self printTab:"Object: NULL\n"]; return self; } numTabs++; [target dump:self]; numTabs--; return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.