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.