
/* Generated by Interface Builder, modified by the author */

/* File: Browser.m */

#include <stdio.h>
#include <string.h>

#include <mach.h>

#import "Browser.h"
#import "ClassTable.h"
#import "MethodTable.h"
#import "NeXTGraphic.h"

#import <defaults.h>
#import <streams/streams.h>

#import <objc/NXStringTable.h>

#import <appkit/ActionCell.h>
#import <appkit/Application.h>
#import <appkit/Cell.h>
#import <appkit/ClipView.h>
#import <appkit/Font.h>
#import <appkit/Form.h>
#import <appkit/Listener.h>
#import <appkit/Speaker.h>
#import <appkit/Text.h>
#import <appkit/Window.h>

@implementation Browser

+ initialize /* initialize object */
{
	static NXDefaultsVector BrowserDefaults =
	{
		{ "SystemBrowsePath", 
			"/usr/include/appkit:/usr/include/objc" },
		{ "CustomBrowsePath", 
			""},
		{ NULL}
	};
	
	NXRegisterDefaults( "Browser", BrowserDefaults); /* load register table */
	
	[Text registerDirective:"NeXTGraphic" forClass:[NeXTGraphic class]]; /* new RTF command */
	
	return self;
}

- init /* init object */
{
	[super init];
	
	isInterface= isFactory= YES;
	
	return self;
}

- startup /* startup object */
{
	float fontSize;
	
	[[[[[[[classMatrix allowEmptySel:YES] removeRowAt:0 andFree:YES] sizeToCells] display]
		setAutoscroll:YES] prototype] setWrap:NO]; /* setup classMatrix */
	
	[[[[[[[methodMatrix allowEmptySel:YES] removeRowAt:0 andFree:YES] sizeToCells] display]
		setAutoscroll:YES] prototype] setWrap:NO]; /* setup methodMatrix */
	
	sscanf( (char *)NXGetDefaultValue( "Browser", "NXFontSize"), "%f", &fontSize);
	[displayText= [displayView docView]
		setFont:[Font newFont:(char *)NXGetDefaultValue( "Browser", "NXFont")
		size:fontSize]]; /* set text font */
	
	helpText= [helpText docView]; /* replace scroll view by text */
	
	[[[self renewClassView] newClassSelected:self] newMethodSelected:self]; /* update */
	
	return self;
}

- renewClassView /* renew the class window */
{
	int count;
	char *pointer;
	
	[classTable reset]; /* reset the classTable */
	
	[classMatrix allowEmptySel:YES]; /* allow none to be selected */
	for( count=[classMatrix cellCount]-1; count >= 0; count--)
	{
		[classMatrix removeRowAt:0 andFree:YES]; /* remove all buttons in classMatrix */
	}
	[[[classMatrix sizeToCells] setEnabled:YES] display]; /* display it */
	
	if( strlen( pointer= (char *)NXGetDefaultValue( "Browser", "SystemBrowsePath")))
	{
		[classTable readClassesAtPath:pointer];
	}
	if( strlen( pointer= (char *)NXGetDefaultValue( "Browser", "CustomBrowsePath")))
	{
		[classTable readClassesAtPath:pointer];
	}
	
	if( [classTable fillMatrix:classMatrix] > 0) /* files found ? */
	{
		[[[classMatrix allowEmptySel:NO] sizeToCells] display]; /* display it */
		[printClassListMenu setEnabled:YES]; /* enable menu */
	}
	else
	{
		[[[[[classMatrix addRow] setTitle:[stringTable valueForStringKey:"noFiles"]
			at:0:0] sizeToCells] setEnabled:NO] display];
		[printClassListMenu setEnabled:NO]; /* disable menu */
	}
	
	return self;
}

- renewMethodView /* renew the method window */
{
	int count;
	
	[methodTable reset]; /* reset the methodTable */
	
	for( count=[methodMatrix cellCount]-1; count >= 0; count--)
	{
		[methodMatrix removeRowAt:0 andFree:YES]; /* remove all buttons in methodMatrix */
	}
	[[[methodMatrix sizeToCells] setEnabled:YES] display]; /* display it */
	
	[methodTable scanFile:[classTable getPathAtPosition: [classMatrix selectedRow]]
		mode:(isFactory ? '+' : '-')];
	
	if( [methodTable fillMatrix:methodMatrix] > 0) /* methods found ? */
	{
		[[methodMatrix sizeToCells] display]; /* display it */
		[printMethodListMenu setEnabled:YES]; /* enable menu */
	}
	else
	{
		[[[[[methodMatrix addRow] setTitle:[stringTable valueForStringKey:"noMethods"]
			at:0:0] sizeToCells] setEnabled:NO] display];
		[printMethodListMenu setEnabled:NO]; /* disable menu */
	}
	
	return self;
}

- renewDisplayView /* renew the display window */
{
	char currentFilename[1024];
	int position;
	NXStream *stream;
	
	if( (position= [classMatrix selectedRow]) >= 0) /* class selected ? */
	{
		strcpy( currentFilename, [classTable getPathAtPosition:position]);
		if( !isInterface)
		{
			strcpy( rindex( currentFilename, '.'), ".m");
		}
		
		if( (stream= NXMapFile( currentFilename, NX_READONLY)) != NULL)
		{
			[displayText readText:stream]; /* read text */
			NXClose( stream);
			[printDisplayTextMenu setEnabled:YES]; /* enable menu */
		}
		else
		{
			[displayText setText:""]; /* empty text */
			[printDisplayTextMenu setEnabled:NO]; /* disable menu */
		}
	}
	else
	{
		[displayText setText:""]; /* empty text */
		[printDisplayTextMenu setEnabled:NO]; /* disable menu */
	}
	
	return self;
}

- newClassSelected:sender /* new class has been selected */
{
	BOOL hasSuperclass;
	char *superclass;
	
	[self renewMethodView]; /* renew the method window */
	
	[superclassButton setEnabled:
		(hasSuperclass= strcmp( superclass= [methodTable getSuperclass], "???"))]; /* show it */
	[superclassName setStringValue:
		(hasSuperclass ? superclass : [stringTable valueForStringKey:"noSuperclass"])];
	
	[self renewDisplayView]; /* renew the display window */
	[[displayText selectNull] scrollSelToVisible]; /* scroll to beginning of text */
	
	return self;
}

- newMethodSelected:sender /* new method has been selected */
{
	int start, end, method;
	
	if( (method= [methodMatrix selectedRow]) >= 0)
	{
		[methodTable scanFile:[classTable getPathAtPosition:[classMatrix selectedRow]]
			lookAfter:method isInterface:isInterface start:&start end:&end];
		[[displayText setSel:start:end] scrollSelToVisible];
	}
	else
	{
		[displayText selectNull];
	}
	
	return self;
}

- switchToSuperclass:sender /* switch to superclass */
{
	int position;
	
	if( (position= [classTable getPositionOfClass:[methodTable getSuperclass]]) >= 0)
	{
		[[classMatrix selectCellAt:position:0] scrollCellToVisible:position:0]; /* show it */
		[[self newClassSelected:self] newMethodSelected:self]; /* update */
	}
	
	return self;
}

- setToFactory:sender /* show the factory methods */
{
	isFactory= YES;
	
	[[self renewMethodView] newMethodSelected:self]; /* update */
	
    return self;
}

- setToInstance:sender /* show the instance methods */
{
	isFactory= NO;
	
	[[self renewMethodView] newMethodSelected:self]; /* update */
	
    return self;
}

- setToInterface:sender /* show the interface file */
{
	isInterface= YES;
	
	[[self renewDisplayView] newMethodSelected:self]; /* update */
	
    return self;
}

- setToImplementation:sender /* show the implementation file */
{
	isInterface= NO;
	
	[[self renewDisplayView] newMethodSelected:self]; /* update */
	
    return self;
}

- (BOOL)openFileInEdit:(char *)aFilename /* open file in Edit */
{
	int ok;
	id speaker;
	port_t workspacePort;
	
	[[speaker= [NXApp appSpeaker]
		setSendPort:workspacePort= NXPortFromName( NX_WORKSPACEREQUEST, NULL)]
		openFile:aFilename ok:&ok]; /* send the request */
	[speaker setSendPort:PORT_NULL];
	port_deallocate( task_self(), workspacePort); /* deallocate port */
	
    return (BOOL)ok;
}

- (BOOL)openTableFileInEdit:aTable /* open file from table in Edit */
{
	char tempfile[30];
	BOOL ok;
	
	strcpy( tempfile, "/tmp/tempfile      .tmp");
	NXGetTempFilename( tempfile, 13); /* get unique filename */

	if( ok= [aTable fillFile:tempfile]) /* create tempfile */
	{
		[self openFileInEdit:tempfile];
	}
	
	return ok;
}

- printClassList:sender /* print the class list */
{
	[self openTableFileInEdit:classTable]; /* open file in Edit */
	
    return self;
}

- printMethodList:sender /* print the method list */
{
	[self openTableFileInEdit:methodTable]; /* open file in Edit */
	
    return self;
}

- printDisplayText:sender /* print the display text */
{
	char currentFilename[1024];
	int position;
	
	if( (position= [classMatrix selectedRow]) >= 0) /* class selected ? */
	{
		strcpy( currentFilename, [classTable getPathAtPosition:position]);
		if( !isInterface)
		{
			strcpy( rindex( currentFilename, '.'), ".m");
		}
		
		[self openFileInEdit:currentFilename]; /* open file in Edit */
	}
	
	return self;
}

- showHelp:sender; /* show the help window */
{
	static BOOL flag = YES;
	char *text;
	NXStream *stream;
	
	if( flag)
	{
		text= (char *)[stringTable valueForStringKey:"helpText"];
		if( (stream= NXOpenMemory( text, strlen( text), NX_READONLY)) != NULL)
		{
			[helpText readRichText:stream]; /* read text */
			NXCloseMemory( stream, NX_SAVEBUFFER); /* close */
		}
		
		flag= NO;
	}
	
	[helpWindow makeKeyAndOrderFront:self]; /* show help window */
	
	return self;
}

- showPreferences:sender /* show the preference window */
{
	if( ![preferenceWindow isVisible]) /* reset only if not visible */
	{
		[self resetPreferences:self];
	}
	
	[preferenceWindow makeKeyAndOrderFront:self]; /* show preferences window */
	
	return self;
}

- resetPreferences:sender /* reset values from database */
{
	NXUpdateDefaults(); /* use newest values */
	
	[systemPath setStringValue: NXGetDefaultValue( "Browser", "SystemBrowsePath") at:0];
	[customPath setStringValue: NXGetDefaultValue( "Browser", "CustomBrowsePath") at:0];
	
    return self;
}

- savePreferences:sender /* save values in database */
{
	NXWriteDefault( "Browser", "SystemBrowsePath", [systemPath stringValueAt: 0]);
	NXWriteDefault( "Browser", "CustomBrowsePath", [customPath stringValueAt: 0]);
	
	[[[self renewClassView] newClassSelected:self] newMethodSelected:self]; /* update */
	
    return self;
}

- usePreferences:sender /* use values */
{
	NXSetDefault( "Browser", "SystemBrowsePath", [systemPath stringValueAt: 0]);
	NXSetDefault( "Browser", "CustomBrowsePath", [customPath stringValueAt: 0]);
	
	[[[self renewClassView] newClassSelected:self] newMethodSelected:self]; /* update */
	
    return self;
}

- windowDidBecomeKey:sender /* window becomes key window */ 
{
	if( sender == browserWindow)
	{
		[miniaturizeMenu setEnabled:YES];
		[closeMenu setEnabled:NO];
	}
	
	if( sender == infoWindow)
	{
		[miniaturizeMenu setEnabled:NO];
		[closeMenu setEnabled:YES];
	}
	
	if( sender == helpWindow)
	{
		[miniaturizeMenu setEnabled:YES];
		[closeMenu setEnabled:YES];
	}
	
	if( sender == preferenceWindow)
	{
		[miniaturizeMenu setEnabled:NO];
		[closeMenu setEnabled:YES];
	}
	
	return self;
}

- windowWillResize:sender toSize:(NXSize *)frameSize /* allow only a minimal window size */
{
	if( sender == browserWindow)
	{
		if( frameSize->width < 514.0) /* contens x coordinate plus 2 */
		{
			frameSize->width= 514.0;
		}
		
		if( frameSize->height < 528.0) /* contens y coordinate plus 32 */
		{
			frameSize->height= 528.0;
		}
	}
	
	return self;
}


@end
