ftp.nice.ch/pub/next/developer/objc/appkit/Lab1234.s.tar.gz#/Lab3/Solution/Controller.m

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

/*  Controller.m --- Main controller object for the TextLab program.
**  Authors: Bruce Blumberg and Ali Ozer, NeXT Developer Support Group
*/

// Controller object is the central object in TextLab.  It manages the
// windows, open/save panels, and menu commands. 

#import "Controller.h"
#import "TextView.h"
#import <appkit/Application.h>
#import <objc/typedstream.h>
#import <appkit/FontManager.h>

// Extension for TextLab archive files and length of the extension

#define EXTENSION    ".tl"
#define EXTENSIONLEN 3

@implementation Controller

// We subclass the Controller "new" so that we can set the application's
// delegate to point to the Controller object. This way open file
// requests from the Workspace get routed to the Controller's 
// appOpenFile:type: and appAcceptsAnotherFile methods.

+ new
{
  self = [super new];
  [NXApp setDelegate:self];
  
  // create instances of support objects
  openReq = [OpenPanel new];
  saveReq = [SavePanel new];
  fontReq = [FontManager new]; 
  
  return self;
}

- showError: (char *)errorMessage
{
  NXRunAlertPanel (NULL,errorMessage,"OK",NULL,NULL);
}

// newTextView: is invoked in response to a new empty window request. It
// creates a new window containing a TextView. Note that we want new windows 
// to be offset from each other by some amount; hence the use of wRect.

#define ORIGX 100.0
#define ORIGY 100.0
static NXRect wRect = {{ORIGX, ORIGY},{500.0,400.0}};

- newTextView:sender
{   
    id newTextView;
    NXOffsetRect(&wRect, 20.0, -20.0);
    if (wRect.origin.y < 0) {wRect.origin.y = ORIGY; wRect.origin.x = ORIGX;}
    newTextView = [TextView newFrame:&wRect];
    [[newTextView window] setDelegate:self];     
    return self;
}

// appAcceptsAnotherFile is an application delegate method which 
// returns whether it is OK for the application to try to open more files
// with the appOpenFile:type: method. TextLab can indeed open multiple
// windows, so we return YES.

-(BOOL) appAcceptsAnotherFile:sender
{
  return (YES);
}


// appOpenFile:type: is called to open the specified file. It is normally
// called by the Application object in response to open requests from the
// Workspace. Here we also route the open requests from the OpenPanel
// to this method (see openRequest:).

-(int) appOpenFile:(char *)fileName type:(char *)fileType
{
   return [self openFile:fileName];  
}

// openRequest: opens a new file. It puts up a open panel, and, if the user
// doesn't cancel, it reads the specified archive file. If the selected file
// is not a proper archive file, then openRequest: will complain.

- openRequest:sender
{
    const char *fileName;
    const char *const types[2] = {"tl",NULL};
    int ok;

    if ([openReq runModalForTypes:types] && (fileName =[openReq filename])) {
	[self openFile:fileName];
    }
    else
	[self showError:"No file chosen or could not open file"];
    return self;
}

-(int) openFile:(const char *)fileName
{
   id win;
   NXTypedStream *typedStream;
   
    if(!(typedStream = NXOpenTypedStreamForFile(fileName,NX_READONLY))){
	[self showError:"error on opening file"];
	return NO;
    }
    else {
	win = NXReadObject(typedStream);
	NXCloseTypedStream(typedStream);
	[win setTitle:fileName];
         [[win display] makeKeyAndOrderFront:self];
	return YES;
    } 
}


// saveRequest: saves the current window under its default name (found in
// the title bar). Note that if the title bar is empty or the default title
// is "Untitled" then saveRequest: will put up a save panel, giving the user
// a chance to specify a real title.

- saveRequest:sender
{
    const char *fileName;
    const char *const types[2] = {"tl",NULL};
    
    id curWin = [NXApp mainWindow];
    [saveReq setRequiredFileType:types[0]];
    
    if (curWin == nil) 
	[self showError:"No active window to save."];
    else {
	// Check to see if the current window is titled and the title is not
	// "Untitled". If so, save the file, else put up a save panel...
	fileName = [curWin title];
	if (strcmp (fileName, "Untitled"))
	    [self saveWindow:curWin inPath:fileName];
	else [self saveInRequest:sender];
    }
    return self;
}

// saveInRequest: gives the user a chance to save the current window
// under a new name. 

- saveInRequest:sender
{
    const char *fileName;
    const char *const types[2] = {"tl",NULL};
    
    id curWin = [NXApp mainWindow];
    [saveReq setRequiredFileType:types[0]];

    if (curWin == nil) 
	[self showError:"No active window to save."];
    else {
	// Get a file name from the user; use title of the window as default.
	if (([saveReq runModalForDirectory:"." file:[curWin title]]) &&
	      (fileName = [saveReq filename])) 
	    [self saveWindow:curWin inPath:fileName];
    }
    return self;
}


// saveWindow writes a window out the archive file whose name is specified
// by the second argument. The title of the current window is also set 
// accordingly. 

- saveWindow:(id)win inPath:(const char *)name
{	
    NXTypedStream *typedStream;
    
    [win setTitle:name];
    typedStream = NXOpenTypedStreamForFile(name,NX_WRITEONLY);
    NXWriteRootObject(typedStream,win);
    NXCloseTypedStream(typedStream);
    return self;
}

// Printing is rather simple; just send printPSCode: to the text view
// you wish to print. The print panel will automatically pop up and unless
// the user cancels the printout the text view will be printed.

- printRequest:sender
{
    id curText = [[[NXApp mainWindow] contentView] docView];

    if (curText == nil) [self showError:"No active window to print."];
    else {
	[[[NXApp printInfo] setHorizCentered:NO] setVertCentered:NO];
        [curText printPSCode:self];
    }
    return self;
}

// closeRequest closes the current window by simulating a click on the
// closebutton. A check should probably be added to give the user the 
// option of saving the window before closing

- closeRequest:sender
{
   [[NXApp mainWindow] performClose:sender];
   return self;
}

// This method will get called before a window is closed and
// will give the user an opportunity to save their file. It then returns
// self indicating that the window may be closed.

- windowWillClose:(id)whichWin
{
    return self;
}
    
@end

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