ftp.nice.ch/pub/next/developer/apps/ClassEditor.0.4.NIHS.bsd.tar.gz#/ClassEditor.0.4.NIHS.bsd/Source/CEAppManager.m

This is CEAppManager.m in view mode; [Download] [Up]

/* CEAppManager.m				 
 *
 * This is the basic controller of the App. It manages all big abstraction
 * tasks for the panels, documents and connections to the outside.
 *
 * For interface-info see the header file. The comments in this file mostly
 * cover only the real implementation details.
 *
 * Written by: 		Thomas Engel
 * Created:    		23.10.1993 (Copyleft)
 * Last modified: 	07.05.1994
 */

#import <CEAppManager.h>
#import <CEClassEditor.h>
#import <CEListener.h>
#import <CEInfo.h>
#import <Text_MiscExtensions.h>
#import <MiscEmacsText.h>
#import <MiscCompletionText.h>

#import <misckit/misckit.h>

@implementation CEAppManager

- appWillInit:sender
{
	// This is the init part we need to pass before we get the messages that
	// we have to open some files.
	// To be able to init a class we need the have the Preferences,

	// preferences = [CEPreferencesManager new];
	
	// Now lets load the docu templates
	
	NXStream 	* aStream;
	id			aPath;
	id			ourListener;

	// Setup out own Listener...this is really nasty..anyway.
	
	[[NXApp appListener] free];

	ourListener = [[CEListener alloc] init];
	[ourListener setDelegate:self];
	[ourListener checkInAs:[NXApp appName]];
	[ourListener addPort];

	[NXApp setAppListener:ourListener];	
	
	// Well now this is a litle rough....maybe we should search for those files
	// inside the ~/AppInfo or even *Library/ClassEditor sections..anyway.	
	
	aPath = [MiscString newWithString:
				[(NXBundle *)[NXBundle mainBundle] directory]];
	[aPath cat:"/CEClassDocuTemplate.rtf"];
	if( [aPath doesExistInFileSystem] )
	{
		aStream = NXMapFile( [aPath stringValue], NX_READONLY );
		[classDocTemplateView readRichText:aStream];
		NXCloseMemory( aStream, NX_FREEBUFFER );
	}
	[aPath free];

	aPath = [MiscString newWithString:
				[(NXBundle *)[NXBundle mainBundle] directory]];
	[aPath cat:"/CEMethodDocuTemplate.rtf"];
	if( [aPath doesExistInFileSystem] )
	{
		aStream = NXMapFile( [aPath stringValue], NX_READONLY );
		[methodDocuTemplateView readRichText:aStream];
		NXCloseMemory( aStream, NX_FREEBUFFER );
	}
	[aPath free];
	
	// Here comes the hack...

	// [MiscCompletionText poseAs:[Text class]];
	[MiscEmacsText poseAs:[Text class]];

	// Let's see if we have the necessary defaults at hand !
	// Either hardcode them...or adjust them with a DefaultsEditor
	
	if( ![NXApp knowsDefaultValue:"HeaderDirectories"] )
		[NXApp setDefault:"HeaderDirectories" 
				to:".\t"\
				   "~/Developer/Headers\t"\
				   "/LocalDeveloper/Headers\t"\
				   "/LocalDeveloper/Headers/misckit\t"\
				   "/NextDeveloper/Headers/appkit\t"\
				   "/NextDeveloper/Headers/foundation\t"\
				   "/NextDeveloper/Headers/eoaccess\t"\
				   "/NextDeveloper/Headers/eointerface\t"\
				   "/NextDeveloper/Headers/3Dkit\t"\
				   "/NextDeveloper/Headers/indexing\t"\
				   "/NextDeveloper/Headers/eoaccess\t"\
				   "/NextDeveloper/Headers/nikit\t"\
				   "/NextDeveloper/Headers/remote\t"\
				   "/NextDeveloper/Headers/dbkit\t"\
				   "/NextDeveloper/Headers/soundkit"];

	
	// NOTE: We might use the source pathes for header search too. Should
	// take a  look at it some day..
	
	if( ![NXApp knowsDefaultValue:"SourceDirectories"] )
		[NXApp setDefault:"SourceDirectories" 
				to:".\t"\
				   "~/Developer"];

	if( ![NXApp knowsDefaultValue:"DocumentationDirectories"] )
		[NXApp setDefault:"DocumentationDirectories" 
				to:".\t"\
				   "./Documentation\t"\
				   "/LocalDeveloper/Documentation/MiscKit\t"\
				   "/NextLibrary/Documentation/NextDev/GeneralRef/02_ApplicationKit"];
	
	// Here we will write down the defaults which show the ASCII prettyprinting
	// This DEFINITLY is stupid..it should be customizable.
	
	[NXApp setDefault:"text0" to:"Helvetica \\fs24 \\red0\\green0\\blue0 \\ul0"]; 
	[NXApp setDefault:"text1" to:"Helvetica-Bold \\fs24 \\red0\\green0\\blue0 \\ul0"]; 
	[NXApp setDefault:"text2" to:"Times-Bold \\fs28 \\red0\\green0\\blue0 \\ul0"]; 
	[NXApp setDefault:"text3" to:"Helvetica \\fs24 \\red85\\green85\\blue85 \\ul0"]; 
	[NXApp setDefault:"text4" to:"Ohlfs \\fs20 \\red4\\green8\\blue114 \\ul0"]; 
	[NXApp setDefault:"text5" to:"Courier-Bold \\fs24 \\red0\\green0\\blue0 \\ul0"]; 
	[NXApp setDefault:"text6" to:"Ohlfs \\fs20 \\red0\\green0\\blue0 \\ul0"]; 

	// Now lets get all the Prefs into the real objects
	
	[self _readPreferences];
	return self;
}

- appDidInit:sender
{
	// This is some kind of late init. These object are need for working but
	// not for reading the classes or having a class initialized.

	
	return self;
}

- (int)app:sender openFile:(const char *)path type:(const char *)type
{
	// This method is performed whenever a user opens a document from the
	// Workspace Manager.
	// We use our default file open method with some default params.
	
	return [self openFile:path onHost:"*" atTrueLine:0];
}

- (BOOL)appAcceptsAnotherFile:sender
{
	// Inform the workspace that we can open multiple files.
	return YES;
}

- appDidBecomeActive:sender
{
	return self;
}

- appWillTerminate:sender
{
	// Now lets see what we have...ask every window what is going on.

	BOOL	ready;
	int 	i;
	id	windowList;
	int	count;
	int	result;

	windowList = [NXApp windowList];
	count = 0;

	for( i=0; i<[windowList count]; i++ )
		if( [[windowList objectAt:i] isDocEdited] ) count++;

	// Well if there are windows with unsaved contents we should tell the
	// user about it.
	// We won't leave until the user has decided what to do on the top level.

	if( count == 0 ) return self;

	ready = NO;
	while( !ready )
	{
		result = NXRunAlertPanel( "Quit", "There are edited windows.", 
								"Review Unsaved", "Quit Anyway", "Cancel" );

		if( result == NX_ALERTOTHER )
			return nil;
	
		else if( result == NX_ALERTDEFAULT )
			ready = [self _closeAllWindows];

		else ready = YES;
	}
	return self;
}

- (BOOL)_closeAllWindows
{
	// We will try to close all windows and if we succeed we will let the app
	// know. YES = all closed
	// NOTE: Well this is kind of ugly because the app should maintain a list
	// 		of all the controllers that are responsible for some data. But I
	//		don't want to hack down another list access stuff. So we do it
	// 		this way. Maybe in the future I will change that.

	id	delegateList;
	id	aDelegate;
	int	i;
	id	windowList;
	BOOL	success;

	windowList = [NXApp windowList];
	delegateList = [List new];

	// Lets find all the delegates first.

	for( i=0; i<[windowList count]; i++ )
	{
		aDelegate = [[windowList objectAt:i] delegate];
		if( aDelegate != nil &&
			[aDelegate isKindOf:[CEClassEditor class]] )
			[delegateList addObjectIfAbsent:aDelegate];
	}
	success = YES;

	for( i=0; i<[delegateList count]; i++ )
	{
		if( [[delegateList objectAt:i] close:self] == nil )
		{
			success = NO;
			break;
		}
	}

	return success;
}

- addToReleasePool:anObject
{
	return [NXApp delayedFree:anObject];
}

- (int)openFile:(char *)path onHost:(char *)host atTrueLine:(int *)line;
{
	// This method is performed whenever a user opens a document.
	// It takes care that every file is only opened once.
	
	id	newEditor;
	id	aString;
	id	basename;
	id	filetype;
	id	thePath;
	id	windowList;
	id	aDelegate;
	int	i;
	BOOL	loadIt;

	// First we have to check if we already know this file !
	// Some window delegate should have the same filename (without .h or .m)
	// Using the window list might not be the safest way..but I guess it
	// will work.
	
	aString = [MiscString newWithString:path];
	filetype = [aString fileExtension];
	newEditor = nil;

	if( [filetype cmp:"m"] != 0 &&
		[filetype cmp:"h"] != 0 &&
		[filetype cmp:"rtf"] != 0 )
	{
		// Looks like this is no valid file !
		
		[aString free];
		[filetype free];
		return -1;
	}
	// Now that it is clear that this is a valid file...
	
	[NXApp activateSelf:NO];

	windowList = [NXApp windowList];
	basename = [aString fileBasename];
	thePath = [aString pathName];
	[thePath addChar:[MiscString pathSeparator]];
	[thePath concatenate:basename];
	[basename free];
	[aString free];
	loadIt = YES;

	for( i=0; i<[windowList count]; i++ )
	{
		aDelegate = [[windowList objectAt:i] delegate];

		if( [aDelegate respondsTo:@selector(filename)] &&
			aDelegate != nil )
		{
			if( [thePath cmp:[aDelegate filename]] == 0 )
			{
				// Looks like we have found a delegate that belongs to exactly
				// the same path.
				// We must to ask this delegate now what window we should top.
				
				// If we have to open at a certain line will will skip that.
				// opening at a line will currently bring the cheat window to
				// front anyway...this prevents window cluttter.
				
				if( line == 0 )
					[[aDelegate window] makeKeyAndOrderFront:self];
				loadIt = NO;
				
				// If we have to open at a certain line we should remember
				// who is controlling that window.
				
				newEditor = aDelegate;
			}
		}
	}
	[thePath free];

  	// If we really have a new editor...let the world know about it.
  	
	if( loadIt )
	{
		newEditor = [[CEClassEditor alloc] initFromFile:path];
		if( !newEditor )
		{
			[filetype free];
			return NO;
		}
	}
	
	// Now lets see..do we have to select a certain line ?
	// If there is on ask the editor to do so.
			
	if( line > 0 ) 
	{
		if( [filetype cmp:"m"] == 0 )
			[newEditor selectTrueLine:(int)line inSource:YES];
		else if( [filetype cmp:"h"] == 0 )
			[newEditor selectTrueLine:(int)line inSource:NO];
	}
	[filetype free];
	return YES;
}

- showInfo:sender
{
	if( !info ) info = [CEInfo new];
		
	[info makeKeyAndOrderFront:self];
	return self;
}

- sendSuggestion:sender
{
	id	mailer;
	id	tomiAdr;
	id	subject;
	id	theText;
	
	tomiAdr = [MiscString newWithString:
					"tsengel@cip.informatik.uni-erlangen.de"];
	subject = [MiscString newWithString:
					"ClassEditor v0.4 suggestion"];
	theText = [MiscString newWithString:
					"Here is a little suggestion on ClassEditor v0.4:\n"];

	mailer = [MiscMailApp localMailer];
	[mailer setNoclutter:NO];
	[mailer sendMailTo:tomiAdr subject:subject body:theText];
	
	[theText free];
	[tomiAdr free];
	[subject free];
	
	return self;
}

- showAccessHelper:sender
{
	[accessHelper makeKeyAndOrderFront:self];
	return self;
}

- showPreferences:sender
{
//	if( preferences ) [preferences makeKeyAndOrderFront:self];
	return self;
}

- preferences
{
	return self;
}

- _readPreferences
{
	id	aString;
	id	someString;
	id	aList;
	int	i;
	
	aString = [MiscString newWithString:
					[NXApp defaultValue:"HeaderDirectories"]];
	headerSearchPathes = [aString tokenize:"\t" into:nil];

	[aString setStringValue:[NXApp defaultValue:"SourceDirectories"]];
	sourceSearchPathes = [aString tokenize:"\t" into:nil];

	// We will check the paths plus path/Classes path/Categories and
	// path/Protocols
	
	[aString setStringValue:[NXApp defaultValue:"DocumentationDirectories"]];
	aList = [aString tokenize:"\t" into:nil];
	[aString free];

	docuSearchPathes = [List new];
	
	for( i=0; i<[aList count]; i++ )
	{
		aString = [[aList objectAt:i] copy];
		[docuSearchPathes addObject:aString];

		someString = [aString copy];
		[someString cat:"/Classes"];
		[docuSearchPathes addObject:someString];

		someString = [aString copy];
		[someString cat:"/Categories"];
		[docuSearchPathes addObject:someString];

		someString = [aString copy];
		[someString cat:"/Protocols"];
		[docuSearchPathes addObject:someString];
	}
	[[aList freeObjects] free];
	
	return self;
}

- headerSearchPaths
{
	return headerSearchPathes;
}

- sourceSearchPaths
{
	return sourceSearchPathes;
}

- documentationSearchPaths
{
	return docuSearchPathes;
}

- open:sender
{
	id 		openPanel;
	char 	fullName[MAXPATHLEN];
	const char *const *files;
	const char *const fileType[6] = { "m",
									  "h",
									   NULL};

 	openPanel = [[OpenPanel new] allowMultipleFiles:YES];

 	// Run the open panel, filtering for our type of documents
 	// We try to open every file the panel returns.
  
  	if( [openPanel runModalForTypes:fileType] )
  	{
  		files = [openPanel filenames];
		for( files = [openPanel filenames]; files && *files; files++)
		{
			// Now lets merge the fullFilename from the directory and the
			// current filename and try to init a editor from this file.
			// We use the default open method with some default params.
      		
			sprintf( fullName, "%s/%s", 
					[(OpenPanel *)openPanel directory], *files );
      		[self openFile:fullName onHost:"*" atTrueLine:0];
    		}
	}
  	return self;
}

- new:sender
{
	[CEClassEditor new];
	return self;
}

- save:sender
{
	// [[NXApp keyWindow] save:sender];
	//
	// This is a posible solution
	// But we currently work with a firstResponder solution
	
	return self;
}

- saveAs:sender
{
	return self;
}

- saveTo:sender
{
	return self;
}

- saveAll:sender
{
	return self;
}

- revert:sender
{
	return self;
}

- close:sender
{
	return self;
}

- print:sender
{
	return self;
}

- setTextFontStyle:sender
{
	[self _setSelectionFont:textFontField andColor:textFontColorWell];
	return self;
}

- setMethodNameFontStyle:sender
{
	[self _setSelectionFont:methodNameField andColor:methodNameColorWell];
	return self;
}

- setParameterFontStyle:sender
{
	id firstResponder = [[NXApp mainWindow] firstResponder];
	
	if( [firstResponder respondsTo:@selector(setSelFont:)] )
		[firstResponder setSelFont:[Font newFont:"Times-Italic" size:14]];
	return self;
}

- setMathSymbolFontStyle:sender
{
	id firstResponder = [[NXApp mainWindow] firstResponder];
	
	if( [firstResponder respondsTo:@selector(setSelFont:)] )
		[firstResponder setSelFont:[Font newFont:"Symbol" size:14]];
	return self;
}

- setHeadlinesFontStyle:sender
{
	[self _setSelectionFont:headlinesFontField
				   andColor:headlinesFontColorWell];
	return self;
}

- setExampleCodeFontStyle:sender
{
	[self _setSelectionFont:exampleCodeFontField
				   andColor:exampleCodeFontColorWell];
	return self;
}

- setBlankLinesFontStyle:sender
{
	[self _setSelectionFont:blankLinesFontField
				   andColor:blankLinesFontColorWell];
	return self;
}

- setSourceFontStyle:sender
{
	[self _setSelectionFont:sourceFontField andColor:sourceFontColorWell];
	return self;
}

- setKeywordsFontStyle:sender
{
	[self _setSelectionFont:keywordsFontField andColor:keywordsFontColorWell];
	return self;
}

- setTypecastFontStyle:sender
{
	[self _setSelectionFont:typecastFontField andColor:typecastFontColorWell];
	return self;
}

- setRemarkFontStyle:sender
{
	[self _setSelectionFont:remarkFontField andColor:remarkFontColorWell];
	return self;
}

- setBugNoteFontStyle:sender
{
	[self _setSelectionFont:bugNoteFontField andColor:bugNoteFontColorWell];
	return self;
}

- _setSelectionFont:aFont andColor:aColor
{
	// Well this is a lie...we don't get the font but the TextField that has
	// the right font set !!
	
	id firstResponder = [[NXApp mainWindow] firstResponder];
	
	if( [firstResponder respondsTo:@selector(setSelFont:)] &&
		aFont != nil )
		[firstResponder setSelFont:[aFont font]];
	if( [firstResponder respondsTo:@selector(setSelColor:)] &&
		aColor != nil )
		[firstResponder setSelColor:[aColor color]];

	// This is for letting the delegates know about the changes to
	// be able to track document modification.
	// The first responder must know about the window because the
	// textDidChange might require it.
	
	if( [firstResponder respondsTo:@selector(window)] )
		[[[NXApp mainWindow] delegate] textDidChange:firstResponder];

	return self;
}

- copyClassDocuTemplate
{
	// All we do here is to copy the docu template to the pasteboard.
	
	[classDocTemplateView selectAll:self];
	[classDocTemplateView copyTo:[Pasteboard newName:"CETempPb"]];
	return self;
}

- copyMethodDocuTemplate
{
	// All we do here is to copy the method template to the pasteboard.
	
	[methodDocuTemplateView selectAll:self];
	[methodDocuTemplateView copyTo:[Pasteboard newName:"CETempPb"]];
	return self;
}

- windowDidBecomeKey:sender
{
	// now if our Docu window will become key...we should load the text into
	// it if we havn't yet.

	NXStream 	* aStream;
	id			aPath;
	
	if( sender != docuTemplateWindow ) return self;
	
	if( [docuTemplateTextView textLength] < 10 )
	{
		aPath = [MiscString newWithString:
						[(NXBundle *)[NXBundle mainBundle] directory]];
		[aPath cat:"/DocuTemplate.rtf"];
		if( [aPath doesExistInFileSystem] )
		{
			aStream = NXMapFile( [aPath stringValue], NX_READONLY );
			[docuTemplateTextView readRichText:aStream];
			NXCloseMemory( aStream, NX_FREEBUFFER );
		}
		[aPath free];
	}
	return self;
}

@end

/*
 * History: 13.01.95 Bla.
 *
 *
 * Bugs: No bugs and birds seen....
 */

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.