This is YapDocument.m in view mode; [Download] [Up]
/*
* YapDocument.m
* Author: Ali Ozer
* Created: Aug 28, 1988
* Modified for 0.8: Sep 1988
* Modified for 0.9 and revised: Feb & Mar 1989
* Modified for 1.0 and nibified: Jun & Jul 1989
* Modified for 2.0 and zonified: Aug 1990
* Modified: Jan 92 for 3.0. Localized.
*
* YapDocument class implements the Yap documents --- for every open
* window, we have another instance of the YapDocument class. Each instance
* loads itself into a separate zone.
*
* 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/error.h>
#import <libc.h>
#import <string.h>
#import <sys/file.h>
#import "YapDocument.h"
#import "PSText.h"
#import "YapApp.h"
#import "YapOutput.h"
#import "FindPanel.h"
#import <objc/NXBundle.h>
#import <objc/List.h>
#import <objc/zone.h>
#import <streams/streams.h>
#import <defaults/defaults.h>
#import <mach/mach.h>
#import <libc.h>
#import <string.h>
#define UNTITLED NXLocalString ("UNTITLED", NULL, "Name of default document")
#define CANTWRITEFILE_STRING NXLocalString ("Can't write file.", NULL, "Document could not be saved")
#define CLOSEWINDOW_STRING NXLocalString("Close", NULL, "Request to close window containing unsaved document from menu or close button.")
#define SAVECHANGES_STRING NXLocalString("%s has changes. Save them?", NULL, "Question asked of user when he/she tries to close a window containing an unsaved document. The %s is the name of the document.")
#define SAVE_STRING NXLocalString("Save", NULL, "Button choice which allows the user to save the document.")
#define DONTSAVE_STRING NXLocalString("Don't Save", NULL, "Button choice which allows the user to abort the save of a document which is being closed.")
#define OK_STRING NXLocalString ("OK", NULL, "Default response in alert panel")
#define CANCEL_STRING NXLocalString ("Cancel", NULL, "Button choice allowing user to cancel the request to close a window")
#define XOFFSET 5.0 // Offset of subsequent windows
#define YOFFSET -20.0
#define MAXSIZE 1.0e38 // Maximum size of a text object
@implementation YapDocument
/*
* The next two methods allow us to cache/reuse zones.
*/
static id zoneList = nil;
+ (NXZone *)newZone
{
if (!zoneList || ![zoneList count]) {
return NXCreateZone(vm_page_size, vm_page_size, YES);
} else {
return (NXZone *)[zoneList removeLastObject];
}
}
+ (void)reuseZone:(NXZone *)aZone
{
if (!zoneList) zoneList = [List new];
[zoneList addObject:(id)aZone];
}
/*
* Return the document in the specified window.
*/
+ documentForWindow:window
{
id del = [window delegate];
return (del && [del isKindOf:[YapDocument class]]) ? del : nil;
}
/*
* Create a new instance of YapDocument with the specified stream in the
* buffer. If the file cannot be opened, no document is created and nil
* is returned.
*/
+ newFromStream:(NXStream *)stream name:(const char *)fileName
{
id docWin; /* Window belonging to this document. */
id textObj; /* The text object we put in the window. */
NXRect textFrame; /* The frame of the text object in our window */
self = [[self allocFromZone:[self newZone]] init];
if (![NXApp loadNibSection:"Document.nib" owner:self withNames:NO fromZone:[self zone]]) {
NXLogError ("Can't find Document.nib!");
NXCloseMemory (stream, NX_FREEBUFFER);
[self free];
return nil;
}
/*
* Loading the nib file above sets the document outlet to the
* scrollview; so we can use this outlet to get at the window & such.
*/
docWin = [document window];
[[document docView] getFrame:&textFrame];
/*
* Put the window offset from the previous document window... If no
* previous window exists, or the main window is undetermined, then
*/
if ([NXApp mainWindow]) {
NXRect winFrame, winLoc;
[[NXApp mainWindow] getFrame:&winFrame];
[[docWin class] getContentRect:&winLoc forFrameRect:&winFrame style:[docWin style]];
[docWin moveTo:NX_X(&winLoc) + XOFFSET :NX_Y(&winLoc) + YOFFSET];
}
[self setName:UNTITLED];
[docWin setDelegate:self];
if (stream) {
char *text;
int len, maxLen;
NXGetMemoryBuffer (stream, &text, &len, &maxLen);
textObj = [[PSText allocFromZone:[self zone]] initFrame:&textFrame text:text alignment:NX_LEFTALIGNED];
if (fileName)
[self setName:fileName];
else
{
[self setName:UNTITLED];
[[document window] setDocEdited:YES];
};
NXCloseMemory (stream, NX_FREEBUFFER);
} else {
textObj = [[PSText allocFromZone:[self zone]] initFrame:&textFrame];
[self setName:UNTITLED];
}
/*
* Put this new text object in the window and free the IB-created one.
*/
[[document setDocView:textObj] free];
/*
* Set various parameters.
*/
[document setAutoresizeSubviews:YES];
[textObj setVertResizable:YES]; // Grow down as you type
[textObj setHorizResizable:NO]; // But not sideways
[textObj setAutosizing:NX_WIDTHSIZABLE]; // Size horizontally when resized
[textObj setMonoFont:YES];
[textObj setOpaque:YES];
[textObj setMinSize:&textFrame.size];
NX_WIDTH(&textFrame) = NX_HEIGHT(&textFrame) = MAXSIZE;
[textObj setMaxSize:&textFrame.size]; // Can grow
[textObj setSel:0:0]; // Set the selection
[textObj setDelegate:self];
[textObj sizeToFit];
[docWin makeKeyAndOrderFront:self];
[self initializePrintInfo];
return self;
}
/*
* Create a new instance of YapDocument with the specified file in the
* buffer. If the file cannot be opened, no document is created and nil
* is returned.
*/
+ newFromFile:(const char *)fileName
{
NXStream *stream = NULL;
id docWin; /* Window belonging to this document. */
id textObj; /* The text object we put in the window. */
NXRect textFrame; /* The frame of the text object in our window */
if (fileName && !(stream = NXMapFile(fileName, NX_READONLY)))
{
return nil;
}
return [self newFromStream:stream name:fileName];
}
+ new
{
return [self newFromFile:NULL];
}
- initializePrintInfo
{
static BOOL printInfoInitialized = NO;
if (!printInfoInitialized) {
[[NXApp printInfo] setVertCentered:NO];
[[NXApp printInfo] setHorizCentered:NO];
[[NXApp printInfo] setHorizPagination:NX_FITPAGINATION];
[[NXApp printInfo] setMarginLeft:36.0 right:36.0 top:72.0 bottom:72.0];
printInfoInitialized = YES;
}
return self;
}
/*
* Checks to see if the window has been edited...
*/
- (BOOL)needsSaving
{
return [[document window] isDocEdited];
}
/*
* Delegate method for the document Text object. We use this method
* to detect when the text in the window is modified.
*/
- text:text isEmpty:(BOOL)empty
{
if (![[document window] isDocEdited]) {
[[document window] setDocEdited:YES];
}
return NO;
}
/*
* Delegate method for the document Text object. We use this method
* to detect when the font is changed so we an write it out as the default.
*/
- textWillConvert:textObject fromFont:oldFont toFont:newFont
{
if (newFont) {
char str[80];
sprintf (str, "%f", [newFont pointSize]);
NXWriteDefault ([NXApp appName], "NXFontSize", str);
NXWriteDefault ([NXApp appName], "NXFont", [newFont name]);
[Text setDefaultFont:newFont];
}
return newFont;
}
/*
* saveDocument: will write out the contents of the document
* to the specified file.
*
* If fileName is NULL, asks user for a file name.
* Returns NO if the user decides to cancel the operation.
* Otherwise returns YES (whether or not the document could be saved),
* modifying the needsSaving state.
*/
- (BOOL)saveDocument:(const char *)fileName
{
int fd; // File descriptor
NXStream *stream = NULL;
BOOL saveOK;
if (!fileName || !strcmp (fileName, UNTITLED) || !strcmp (fileName, "")) {
if (!(fileName = [[SavePanel new] runModalForDirectory:"." file:UNTITLED] ? [[SavePanel new] filename] : NULL)) {
return NO;
}
}
if (saveOK =
(((fd = open (fileName, O_WRONLY|O_CREAT|O_TRUNC, 0644)) != -1) &&
(stream = NXOpenFile (fd, NX_WRITEONLY))))
[[document docView] writeText:stream];
if (stream) NXClose (stream);
if (fd != -1) close (fd);
if (saveOK) {
[self setName:fileName];
[[document window] setDocEdited:NO];
} else {
NXRunAlertPanel (NULL, CANTWRITEFILE_STRING, OK_STRING, NULL, NULL);
}
return YES;
}
/*
* Set/Get the name of the document. This is the same as the title.
* Free the old name after the new one is set, because sometimes this
* routine might be called as the old name as the argument...
*/
- setName:(const char *)documentName
{
documentName = documentName ? documentName : "";
if (documentName != name) {
free(name);
name = NXCopyStringBufferFromZone (documentName, [self zone]);
[[document window] setTitleAsFilename:name];
}
return self;
}
-(const char *)name
{
return name;
}
/*
* windowWillClose: gets called by windows who have this instance of
* YapDocument as delegate. We call closeDocument:andWindow: to see if the
* document needs saving and take the appropriate action if so. If the user
* cancels the save, closeDocument:andWindow: returns NO and we return nil.
* This prevents the window from closing...
*/
- windowWillClose:sender
{
return [self closeDocument:CLOSEWINDOW_STRING andWindow:NO] ? self : nil;
}
/*
* Closes the document. If document needs saving, asks user he/she'd like the doc
* saved. Returns NO if the user cancels out of the save operation, otherwise returns YES.
* flag determines if the window should also be closed with the document.
*/
- (BOOL)closeDocument:(const char *)message andWindow:(BOOL)flag
{
if ([self needsSaving]) {
int save = NXRunAlertPanel(message, SAVECHANGES_STRING, SAVE_STRING, DONTSAVE_STRING, CANCEL_STRING, [self name]);
if (save == NX_ALERTOTHER) { // Cancel
return NO;
} else if (save == NX_ALERTDEFAULT) {
[self save:nil];
}
}
[[document window] setDelegate:nil];
if (flag) [[document window] close];
[self free];
return YES;
}
- free
{
NXZone *docZone = [self zone];
if (name) free(name);
[super free];
[YapDocument reuseZone:docZone];
return nil;
}
/*
* save: saves the current document. If the document is untitled, it
* puts up a savePanel to get the user to enter a file name. saveAs:
* saves the document under a new name by putting up a savePanel.
*/
- save:sender
{
(void)[self saveDocument:[self name]];
return self;
}
- saveAs:sender
{
if ([[SavePanel new] runModalForDirectory:"." file:[self name]]) {
(void)[self saveDocument:[[SavePanel new] filename]];
}
return self;
}
- execute:sender
{
[[NXApp outputView] executeCodeFrom:[document docView]];
return self;
}
/*
* To get around the problem of printPSCode: going up the responder chain and
* causing print panel to come back after Cancel, we use the following glue.
*/
- print:sender
{
[[document docView] printPSCode:sender];
return self;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.