This is YapApp.m in view mode; [Download] [Up]
/*
* YapApp.m
* Author: Ali Ozer
* Created: Mar 89 for 0.9
* Modified: Jul & Aug 89 for 1.0
* Modified: Aug 90 for 2.0
* Modified: Apr & Jun 91 and Jun 92 for 3.0. Localized Jan 92.
*
* YapApp is the application class used in Yap. It implements the
* central functionality of coordinating the output and document
* windows, opening documents, managing shared panels, etc...
*
* You may freely copy, distribute and reuse the code in this example.
* NeXT disclaims any warranty of any kind, expressed or implied,
* as to its fitness for any particular use.
*/
#import <appkit/appkit.h>
#import <objc/NXBundle.h>
#import <objc/zone.h>
#import <sys/param.h>
#import "YapApp.h"
#import "YapDocument.h"
#import "YapOutput.h"
#define CANTOPENFILE_STRING NXLocalString("Could not open file.", NULL, "The user-specified file could not be opened")
#define OK_STRING NXLocalString("OK", NULL, "Default response in alert panel")
#define UNSAVEDDOCS_STRING NXLocalString("You have unsaved documents.", NULL, "Message given to user when he tries to quit the application without saving all of his documents.")
#define REVIEW_STRING NXLocalString("Review Unsaved", NULL, "Choice (on a button) given to user which allows him/her to review all unsaved documents if he/she quits the application without saving them all first.")
#define QUITANYWAY_STRING NXLocalString("Quit Anyway", NULL, "Choice (on a button) given to user which allows him/her to quit the application even though there are unsaved documents.")
#define QUIT_STRING NXLocalString("Quit", NULL, "The operation of exiting the application.")
#define CANCEL_STRING NXLocalString ("Cancel", NULL, "Button choice allowing user to cancel quit")
@implementation YapApp
- outputView
{
return outputView;
}
- outputWindow
{
return [outputView window];
}
#define DEFAULTWIDTH 612
#define DEFAULTHEIGHT 792
#define MINSIZE 72
#define MAXSIZE 3600
/*
* Here we have a handle to the output window, created in IB. We create
* the scroll and the yap output views and add them to this window.
*/
- setOutputWindow:anObject
{
NXRect initFrame = {{0.0, 0.0}, {DEFAULTWIDTH, DEFAULTHEIGHT}};
id scrollView = [ScrollView new];
outputView = [[YapOutput allocFromZone:[self zone]] initFrame:&initFrame];
[anObject setBackgroundGray:NX_WHITE];
[anObject removeFromEventMask:NX_KEYDOWNMASK|NX_KEYUPMASK];
[scrollView setBorderType:NX_NOBORDER];
[scrollView setHorizScrollerRequired:YES];
[scrollView setVertScrollerRequired:YES];
[anObject setContentView:scrollView];
[scrollView setDocView:outputView];
[anObject setDelegate:self]; // So we can get windowWillResize:toSize:
[anObject setFrameAutosaveName:"Output Window"];
[anObject makeKeyAndOrderFront:nil];
[NXApp updateOutputWindowSize];
return self;
}
/*
* updateOutputWindowSize should be called after the size of the output view is
* changed. It simply makes sure the window isn't too big for the view. If the
* window is indeed to big, it is resized smaller.
*/
- updateOutputWindowSize
{
NXRect frame, content;
NXSize maxWindowSize;
// The next few lines allow us to get the window size for the window
// containing a ScrollView and the yap output view.
[[self outputView] getFrame:&frame];
[ScrollView getFrameSize:&maxWindowSize forContentSize:&(frame.size)
horizScroller:YES vertScroller:YES borderType:NX_NOBORDER];
// sizeWindow:: wants window size in content area; so we can use the
// maxWindowSize from above. But to compare it to the window frame,
// we first need to get the content area for the current frame.
[[self outputWindow] getFrame:&frame];
[Window getContentRect:&content forFrameRect:&frame
style:[[self outputWindow] style]];
if (content.size.width > maxWindowSize.width ||
content.size.height > maxWindowSize.height) {
[[self outputWindow]
sizeWindow:MIN(maxWindowSize.width, content.size.width)
:MIN(maxWindowSize.height, content.size.height)];
}
// Now we go from the content size to the window frame size, which is
// what we will use in windowWillResize:toSize:
content.size = maxWindowSize;
[Window getFrameRect:&frame forContentRect:&content
style:[[self outputWindow] style]];
maxWindowSize = frame.size;
[[self outputWindow] setMaxSize:&maxWindowSize];
return self;
}
/*
* newDocument simply creates a new Yap document and displays it.
*/
- newDocument:sender
{
[YapDocument new];
return self;
}
/*
* openDocument gets a file name from the user, creates a new document window,
* and loads the specified file into it.
*/
- openDocument:sender
{
// Allow ps, eps, and any other extension not handled by other apps.
// Note that "" should come first in the list.
static const char *const yapTypes[] = {"", "ps", "eps", NULL};
if ([[OpenPanel new] runModalForTypes:yapTypes]) {
if ([YapDocument newFromFile:[[OpenPanel new] filename]] == nil) {
NXRunAlertPanel (NULL, CANTOPENFILE_STRING, OK_STRING, NULL, NULL);
}
}
return self;
}
/*
* app:openFile:type: is invoked by Workspace when the user double-clicks
* on a file Yap is prepared to accept. By default, Yap is not prepared to open
* any files, however, it can easily be made to open files of certain type
* through Project Builder.
*/
- (int)app:app openFile:(const char *)path type:(const char *)type
{
if ([YapDocument newFromFile:path] == nil) return NO;
else return YES;
}
/*
* The following method indicates that Yap is ready to open multiple
* files at one time.
*/
- (BOOL)appAcceptsAnotherFile:sender
{
return YES;
}
/*
* Methods to load .nib files for the various panels.
*/
- showInfo:sender
{
if (!infoPanel) {
if (![NXApp loadNibSection:"Info.nib" owner:self withNames:NO fromZone:[self zone]]) {
NXLogError ("Can't find Info.nib!");
}
}
[infoPanel makeKeyAndOrderFront:sender];
return self;
}
- showHelp:sender
{
if (!helpPanel) {
if (![NXApp loadNibSection:"Help.nib" owner:self withNames:NO fromZone:[self zone]]) {
NXLogError ("Can't find Help.nib!");
}
}
[helpPanel makeKeyAndOrderFront:sender];
return self;
}
- showPrefs:sender
{
if (!prefsPanel) {
if (![NXApp loadNibSection:"Prefs.nib" owner:self withNames:NO fromZone:[self zone]]) {
NXLogError ("Can't find Prefs.nib!");
}
[self updatePreferencesPanel:sender];
}
[prefsPanel makeKeyAndOrderFront:sender];
return self;
}
/*
* updatePreferencesPanel: is used to copy the existing situation into
* the Prefences panel.
*/
- updatePreferencesPanel:sender
{
NXRect outputFrame;
[[self outputView] getFrame:&outputFrame];
[outputWidthField setFloatValue:NX_WIDTH(&outputFrame)];
[outputHeightField setFloatValue:NX_HEIGHT(&outputFrame)];
[showCacheButton setState:[[self outputView] isCacheShown]];
[clearCacheButton setState:[[self outputView] isCacheCleared]];
[outputWidthField selectText:sender];
return self;
}
/*
* okPreferencesPanel: causes the values in Preferences to be read into the
* application and applied to the various objects.
*/
- okPreferencesPanel:sender
{
NXCoord desiredWidth, desiredHeight;
desiredWidth = [outputWidthField floatValue];
if (desiredWidth < MINSIZE || desiredWidth > MAXSIZE) {
desiredWidth = MIN(MAX(desiredWidth, MINSIZE), MAXSIZE);
[outputWidthField setFloatValue:desiredWidth];
}
desiredHeight = [outputHeightField floatValue];
if (desiredHeight < MINSIZE || desiredHeight > MAXSIZE) {
desiredHeight = MIN(MAX(desiredHeight, MINSIZE), MAXSIZE);
[outputHeightField setFloatValue:desiredHeight];
}
[[self outputView] sizeTo:desiredWidth :desiredHeight];
[self updateOutputWindowSize];
[[self outputView] setCacheShown:[showCacheButton state]];
[[self outputView] setCacheCleared:[clearCacheButton state]];
[[sender window] orderOut:sender];
[outputWidthField selectText:sender];
return self;
}
/*
* Make sure all documents are saved before actually terminating the app...
*/
- terminate:sender
{
int count = [[self windowList] count];
BOOL needsSaving = NO;
// Determine if there are any unsaved documents...
while (!needsSaving && count--) {
id document = [YapDocument documentForWindow:[windowList objectAt:count]];
if (document && [document needsSaving]) {
needsSaving = YES;
}
}
if (needsSaving) {
int choice = NXRunAlertPanel(QUIT_STRING, UNSAVEDDOCS_STRING, REVIEW_STRING, QUITANYWAY_STRING, CANCEL_STRING);
if (choice == NX_ALERTOTHER) {
return self; // Cancel
} else if (choice == NX_ALERTDEFAULT) {
count = [[self windowList] count];
while (count--) {
id document = [YapDocument documentForWindow:[windowList objectAt:count]];
if (document) {
if (![document closeDocument:QUIT_STRING andWindow:YES]) {
return self; // Cancel
}
}
}
}
}
return [super terminate:sender];
}
- yapSelection:pasteboard userData:(const char *)userData error:(char **)msg
{
const NXAtom *types;
char *posting;
int postingLength;
char buf[MAXPATHLEN+1];
NXStream *ts;
id filterboard;
/* get the message */
filterboard = [Pasteboard newByFilteringTypesInPasteboard:pasteboard];
[filterboard types];
if ([filterboard readType:NXAsciiPboardType data:&posting length:&postingLength])
{
ts = NXOpenMemory(NULL, 0, NX_READWRITE);
NXWrite(ts, posting, postingLength);
NXSeek(ts,0,NX_FROMSTART);
[YapDocument newFromStream:ts name:NULL];
//NXCloseMemory(ts, NX_FREEBUFFER);
[filterboard deallocatePasteboardData:posting length:postingLength];
}
else
{*msg = "Could not read selection"; return nil;}
[filterboard free];
return self;
};
- appDidInit:sender
{
[[NXApp appListener] setServicesDelegate:self];
return self;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.