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 BBFig by Izumi Ohzawa (izumi@pinoko.berkeley.edu) * * 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 <defaults/defaults.h> #import <appkit/nextstd.h> #import <appkit/Application.h> #import <appkit/Font.h> #import <appkit/PrintInfo.h> #import <appkit/SavePanel.h> #import <appkit/ScrollView.h> #import <appkit/Window.h> #import <appkit/TextField.h> #import <appkit/Button.h> #import <appkit/Panel.h> #import <appkit/Text.h> #import <objc/List.h> #import <streams/streams.h> #import <mach/mach.h> #import <string.h> #import <objc/zone.h> #import "PSText.h" #import "YapDocument.h" #import "YapApp.h" #import "YapOutput.h" #define XOFFSET 5.0 // Offset of subsequent windows #define YOFFSET -20.0 #define MAXSIZE 1.0e38 // Maximum size of a text object #define UNTITLED "UNTITLED" @implementation YapDocument static char strbuf[128]; /* * 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]; } /* * 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; } self = [[self allocFromZone:[self newZone]] init]; if (![NXApp loadNibSection:"Document.nib" owner:self withNames:NO fromZone:[self zone]]) { NXCloseMemory (stream, NX_FREEBUFFER); [self free]; return nil; } /* * Loading the nib file above sets the document outlet to the * scrollview that contains PS code; * 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]; [self setName:fileName]; 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. */ outputView = [NXApp outputView]; [document setAutoresizeSubviews:YES]; [textObj setVertResizable:YES]; // Grow down as you type [textObj setHorizResizable:NO]; // Let it do sideways too [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]; [computeBBSwitch setState:[outputView isFigureBB]]; [gridEnableSwitch setState:[outputView isMeshON]]; [blueEnableSwitch setState:[outputView isBlueON]]; [docWin makeKeyAndOrderFront:self]; [self initializePrintInfo]; return self; } + 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; } /* * 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; } // This fixes the problem of messed up text when you resize the // document window. - windowDidResize:sender { id docText; docText = [document docView]; [docText calcLine]; [docText sizeToFit]; return self; } /* * saveDocument: will write out the contents of the document * to the specified file. The best (perhaps not the cleanest but the * most efficient) way to dump a Text object to a file seems to be * to open the file (with open()), then to use NXOpenFile(), and * finally use writeText: to dump the contents out. */ - (int)saveDocument:(const char *)fileName { BOOL saveOK; int fd; // File descriptor int retval = 0; NXStream *stream = NULL; 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 { if(NXRunAlertPanel(NULL, "Can't write file.", "OK", "Save As", NULL) == NX_ALERTALTERNATE) retval = -1; } return retval; } /* * Set/Get the name of the document. This is the same as the title. */ // There was a bug in the original Yap v19, where filename changes for // no reason whan saved without executed (happens when multiple files open. // The bug has been fixed. The problem was that "name" and "documentName" // are the identical pointers to the same memory for "Save". And the orig // code was freeing "name" before documentName was copied to a new location. - setName:(const char *)documentName { char *temp; documentName = documentName ? documentName : ""; temp = NXCopyStringBufferFromZone (documentName, [self zone]); if (name) free(name); name = temp; [[document window] setTitleAsFilename:name]; return self; } -(const char *)name { return name; } /* * windowWillClose: gets called by windows who have this instance of * YapDocument as delegate. The document simply marks itself and its zone * to be free and lets the window know it can close. A more sophisticated * program might want to put up an alert if the document was edited but not * saved. */ - windowWillClose:sender action:(const char *)action { if([[document window] isDocEdited]) { int dstatus = NXRunAlertPanel(action, "Save edited document: %s ?", "Save", "Don't Save", "Cancel", name); if(dstatus == NX_ALERTDEFAULT) /* save */ [self save:self]; else if(dstatus == NX_ALERTOTHER) /* cancel */ return nil; } [outputView setCurrentDocument: nil]; [sender setDelegate:nil]; [self free]; return sender; // We need to return a non-nil value --- here's one. } - windowWillClose:sender { return [self windowWillClose:sender action:"Close"]; } /* - textWillChange:sender { [[document window] setDocEdited:YES]; return sender; } */ - 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 { const char *fileName = [self name]; if ((fileName == NULL) || (strcmp (fileName, UNTITLED) == 0) || (strcmp (fileName, "") == 0)) { /* fileName is not valid, get a new one */ if ([[SavePanel new] runModalForDirectory:"." file:UNTITLED] == NO) return self; else fileName = [[SavePanel new] filename]; } if (fileName) if([self saveDocument:fileName]) [self saveAs:self]; /* Couldn't save -- try another name */ return self; } - saveAs:sender { again: if ([[SavePanel new] runModalForDirectory:"." file:[self name]]) { if([self saveDocument:[[SavePanel new] filename]]) goto again; } return self; } - execute:sender { float llx, lly, urx, ury, bbm; int utime; [computeBBSwitch setState:[outputView isFigureBB]]; [gridEnableSwitch setState:[outputView isMeshON]]; NXPing(); [[NXApp outputView] executeCodeFrom: self andReturnBB: &llx : &lly : &urx : &ury usertime: &utime]; bbm = (float)[NXApp bbMargin]; if(utime >= 0) { llx -= bbm; lly -= bbm; urx += bbm; ury += bbm; sprintf(strbuf, "%%%%BoundingBox: %.0f %.0f %.0f %.0f", llx, lly, urx, ury); } else strcpy(strbuf,""); [bbTextField setStringValue: strbuf]; return self; } - document { return document; } - setBBoxField:(float)llx :(float)lly :(float)urx :(float)ury { sprintf(strbuf, "%%%%BoundingBox: %.0f %.0f %.0f %.0f", llx, lly, urx, ury); [bbTextField setStringValue: strbuf]; 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; } /* * Insert %%BoundigBox comment in "bbTextField" into PSText */ - insertBB:sender { id docText; // int selstart,selend; docText = [document docView]; // [docText getSel: &selstart : &selend]; strncpy(strbuf, [bbTextField stringValue], 80); strcat(strbuf, "\n"); [[document window] setDocEdited:YES]; [docText replaceSel: strbuf]; return self; } /* * Insert %!PS-Adobe-2.0 EPSF-2.0 comment in "versionField" into PSText */ - insertVersion:sender { id docText; docText = [document docView]; [docText setSel:0 :0]; strncpy(strbuf, [versionField stringValue], 40); strcat(strbuf,"\n"); [[document window] setDocEdited:YES]; [docText replaceSel: strbuf]; return self; } /* Insert both of the above at the Top of the PSText */ - insertBoth:sender { id docText; docText = [document docView]; [docText setSel:0 :0]; strncpy(strbuf, [versionField stringValue], 40); strcat(strbuf,"\n"); strncat(strbuf, [bbTextField stringValue], 80); strcat(strbuf, "\n"); [[document window] setDocEdited:YES]; [docText replaceSel: strbuf]; return self; } - setComputeBB:sender { [outputView setFigureBB:[sender state]]; return self; } - setMeshEnable:sender { [outputView setMeshON:[sender state]]; return self; } - setBlueEnable:sender { [outputView setBlueON:[sender state]]; return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.