Annotation of Examples/AppKit/Yap/YapDocument.m, revision 1.1

1.1     ! root        1: /*
        !             2:  *  YapDocument.m
        !             3:  *  Author: Ali Ozer
        !             4:  *  Created: Aug 28, 1988
        !             5:  *  Modified for 0.8: Sep 1988
        !             6:  *  Modified for 0.9 and revised: Feb & Mar 1989
        !             7:  *  Modified for 1.0 and nibified: Jun & Jul 1989
        !             8:  *  Modified for 2.0 and zonified: Aug 1990
        !             9:  *  Modified: Jan 92 for 3.0. Localized.
        !            10:  *
        !            11:  *  YapDocument class implements the Yap documents --- for every open 
        !            12:  *  window, we have another instance of the YapDocument class. Each instance
        !            13:  *  loads itself into a separate zone.
        !            14:  *
        !            15:  *  You may freely copy, distribute and reuse the code in this example.
        !            16:  *  NeXT disclaims any warranty of any kind, expressed or implied,
        !            17:  *  as to its fitness for any particular use.
        !            18:  */
        !            19: 
        !            20: #import <appkit/appkit.h>
        !            21: #import <objc/NXBundle.h>
        !            22: #import <objc/error.h>
        !            23: #import <libc.h>
        !            24: #import <string.h>
        !            25: #import <sys/file.h>
        !            26: 
        !            27: #import "YapDocument.h"
        !            28: #import "PSText.h"
        !            29: #import "YapApp.h"
        !            30: #import "YapOutput.h"
        !            31: #import "FindPanel.h"
        !            32: 
        !            33: #import <objc/NXBundle.h>
        !            34: #import <objc/List.h>
        !            35: #import <objc/zone.h>
        !            36: #import <streams/streams.h>
        !            37: #import <defaults/defaults.h>
        !            38: #import <mach/mach.h>
        !            39: #import <libc.h>
        !            40: #import <string.h>
        !            41: 
        !            42: #define UNTITLED NXLocalString ("UNTITLED", NULL, "Name of default document")
        !            43: #define CANTWRITEFILE_STRING NXLocalString ("Can't write file.", NULL, "Document could not be saved")
        !            44: #define CLOSEWINDOW_STRING NXLocalString("Close", NULL, "Request to close window containing unsaved document from menu or close button.")
        !            45: #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.")
        !            46: #define SAVE_STRING NXLocalString("Save", NULL, "Button choice which allows the user to save the document.")
        !            47: #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.")
        !            48: #define OK_STRING NXLocalString ("OK", NULL, "Default response in alert panel")
        !            49: #define CANCEL_STRING NXLocalString ("Cancel", NULL, "Button choice allowing user to cancel the request to close a window")
        !            50: 
        !            51: #define XOFFSET 5.0    // Offset of subsequent windows
        !            52: #define YOFFSET -20.0
        !            53: #define MAXSIZE 1.0e38 // Maximum size of a text object
        !            54: 
        !            55: @implementation YapDocument
        !            56: 
        !            57: /*
        !            58:  * The next two methods allow us to cache/reuse zones.
        !            59:  */
        !            60: static id zoneList = nil;
        !            61: 
        !            62: + (NXZone *)newZone
        !            63: {
        !            64:     if (!zoneList || ![zoneList count]) {
        !            65:        return NXCreateZone(vm_page_size, vm_page_size, YES);
        !            66:     } else {
        !            67:        return (NXZone *)[zoneList removeLastObject];
        !            68:     }
        !            69: }
        !            70: 
        !            71: + (void)reuseZone:(NXZone *)aZone
        !            72: {
        !            73:     if (!zoneList) zoneList = [List new];
        !            74:     [zoneList addObject:(id)aZone];
        !            75: }
        !            76: 
        !            77: /*
        !            78:  * Return the document in the specified window.
        !            79:  */
        !            80: + documentForWindow:window
        !            81: {
        !            82:     id del = [window delegate];
        !            83:     return (del && [del isKindOf:[YapDocument class]]) ? del : nil;
        !            84: }
        !            85: 
        !            86: /*
        !            87:  * Create a new instance of YapDocument with the specified file in the
        !            88:  * buffer.  If the file cannot be opened, no document is created and nil
        !            89:  * is returned.
        !            90:  */
        !            91: + newFromFile:(const char *)fileName
        !            92: {
        !            93:     NXStream *stream = NULL;
        !            94:     id docWin;         /* Window belonging to this document. */
        !            95:     id textObj;                /* The text object we put in the window. */
        !            96:     NXRect textFrame;  /* The frame of the text object in our window */
        !            97: 
        !            98:     if (fileName && !(stream = NXMapFile(fileName, NX_READONLY))) {
        !            99:        return nil;
        !           100:     }
        !           101: 
        !           102:     self = [[self allocFromZone:[self newZone]] init];
        !           103:     
        !           104:     if (![NXApp loadNibSection:"Document.nib" owner:self withNames:NO fromZone:[self zone]]) {
        !           105:        NXLogError ("Can't find Document.nib!");        
        !           106:        NXCloseMemory (stream, NX_FREEBUFFER);
        !           107:         [self free];
        !           108:        return nil;
        !           109:     }
        !           110: 
        !           111:     /*
        !           112:      * Loading the nib file above sets the document outlet to the
        !           113:      * scrollview; so we can use this outlet to get at the window & such.
        !           114:      */
        !           115:     docWin = [document window];
        !           116:     [[document docView] getFrame:&textFrame];
        !           117:  
        !           118:     /*
        !           119:      * Put the window offset from the previous document window... If no
        !           120:      * previous window exists, or the main window is undetermined, then
        !           121:      */ 
        !           122:     if ([NXApp mainWindow]) {
        !           123:        NXRect winFrame, winLoc;
        !           124:        [[NXApp mainWindow] getFrame:&winFrame];
        !           125:        [[docWin class] getContentRect:&winLoc
        !           126:                        forFrameRect:&winFrame
        !           127:                        style:[docWin style]];
        !           128:        [docWin moveTo:NX_X(&winLoc) + XOFFSET :NX_Y(&winLoc) + YOFFSET];
        !           129:     }
        !           130:        
        !           131:     [self setName:UNTITLED];
        !           132:     [docWin setDelegate:self];
        !           133: 
        !           134:     if (stream) {
        !           135:        char *text;
        !           136:        int len, maxLen;
        !           137:        NXGetMemoryBuffer (stream, &text, &len, &maxLen);
        !           138:        textObj = [[PSText allocFromZone:[self zone]] initFrame:&textFrame text:text alignment:NX_LEFTALIGNED];
        !           139:        [self setName:fileName];
        !           140:        NXCloseMemory (stream, NX_FREEBUFFER);
        !           141:     } else {
        !           142:        textObj = [[PSText allocFromZone:[self zone]] initFrame:&textFrame];
        !           143:        [self setName:UNTITLED];
        !           144:     }
        !           145: 
        !           146:     /*
        !           147:      * Put this new text object in the window and free the IB-created one.
        !           148:      */
        !           149:     [[document setDocView:textObj] free];
        !           150: 
        !           151:     /*
        !           152:      * Set various parameters.
        !           153:      */
        !           154:     [document setAutoresizeSubviews:YES];
        !           155:     [textObj setVertResizable:YES];            // Grow down as you type
        !           156:     [textObj setHorizResizable:NO];            // But not sideways 
        !           157:     [textObj setAutosizing:NX_WIDTHSIZABLE];   // Size horizontally when resized
        !           158:     [textObj setMonoFont:YES];
        !           159:     [textObj setOpaque:YES];
        !           160:     [textObj setMinSize:&textFrame.size];
        !           161:     NX_WIDTH(&textFrame) = NX_HEIGHT(&textFrame) = MAXSIZE;
        !           162:     [textObj setMaxSize:&textFrame.size];      // Can grow
        !           163:     [textObj setSel:0:0];                      // Set the selection
        !           164:     [textObj setDelegate:self];
        !           165:     [textObj sizeToFit];
        !           166: 
        !           167:     [docWin makeKeyAndOrderFront:self];
        !           168: 
        !           169:     [self initializePrintInfo];
        !           170: 
        !           171:     return self;
        !           172: }
        !           173: 
        !           174: + new
        !           175: {
        !           176:     return [self newFromFile:NULL];
        !           177: }
        !           178: 
        !           179: - initializePrintInfo
        !           180: {
        !           181:     static BOOL printInfoInitialized = NO;
        !           182:     if (!printInfoInitialized) {
        !           183:        [[NXApp printInfo] setVertCentered:NO];
        !           184:        [[NXApp printInfo] setHorizCentered:NO];
        !           185:        [[NXApp printInfo] setHorizPagination:NX_FITPAGINATION];
        !           186:        [[NXApp printInfo] setMarginLeft:36.0 right:36.0 top:72.0 bottom:72.0];
        !           187:        printInfoInitialized = YES;
        !           188:     }
        !           189:     return self;
        !           190: }
        !           191: 
        !           192: /*
        !           193:  * Checks to see if the window has been edited...
        !           194:  */
        !           195: - (BOOL)needsSaving
        !           196: {
        !           197:     return [[document window] isDocEdited];
        !           198: }
        !           199: 
        !           200: /*
        !           201:  * Delegate method for the document Text object. We use this method
        !           202:  * to detect when the text in the window is modified.
        !           203:  */
        !           204: - text:text isEmpty:(BOOL)empty
        !           205: {
        !           206:     if (![[document window] isDocEdited]) {
        !           207:        [[document window] setDocEdited:YES];
        !           208:     }
        !           209:     return NO;
        !           210: }
        !           211: 
        !           212: /*
        !           213:  * Delegate method for the document Text object. We use this method
        !           214:  * to detect when the font is changed so we an write it out as the default.
        !           215:  */
        !           216: - textWillConvert:textObject fromFont:oldFont toFont:newFont
        !           217: {
        !           218:     if (newFont) {
        !           219:         char str[80];
        !           220:        sprintf (str, "%f", [newFont pointSize]);
        !           221:        NXWriteDefault ([NXApp appName], "NXFontSize", str);
        !           222:        NXWriteDefault ([NXApp appName], "NXFont", [newFont name]);
        !           223:        [Text setDefaultFont:newFont];
        !           224:     }
        !           225: 
        !           226:     return newFont;
        !           227: }
        !           228: 
        !           229: /*
        !           230:  * saveDocument: will write out the contents of the document
        !           231:  * to the specified file. 
        !           232:  * 
        !           233:  * If fileName is NULL, asks user for a file name.
        !           234:  * Returns NO if the user decides to cancel the operation.
        !           235:  * Otherwise returns YES (whether or not the document could be saved),
        !           236:  * modifying the needsSaving state.
        !           237:  */
        !           238: - (BOOL)saveDocument:(const char *)fileName
        !           239: {
        !           240:     int fd;     // File descriptor
        !           241:     NXStream *stream = NULL;
        !           242:     BOOL saveOK;
        !           243: 
        !           244:     if (!fileName || !strcmp (fileName, UNTITLED) || !strcmp (fileName, "")) {
        !           245:        if (!(fileName = [[SavePanel new] runModalForDirectory:"." file:UNTITLED] ? [[SavePanel new] filename] : NULL)) {
        !           246:            return NO;
        !           247:        }
        !           248:     }
        !           249: 
        !           250:     if (saveOK = 
        !           251:            (((fd = open (fileName, O_WRONLY|O_CREAT|O_TRUNC, 0644)) != -1) &&
        !           252:            (stream = NXOpenFile (fd, NX_WRITEONLY))))
        !           253:        [[document docView] writeText:stream];
        !           254:     if (stream) NXClose (stream);
        !           255:     if (fd != -1) close (fd);
        !           256: 
        !           257:     if (saveOK) {
        !           258:        [self setName:fileName];
        !           259:        [[document window] setDocEdited:NO];
        !           260:     } else {
        !           261:        NXRunAlertPanel (NULL, CANTWRITEFILE_STRING, OK_STRING, NULL, NULL);
        !           262:     }
        !           263:     return YES;
        !           264: }
        !           265: 
        !           266: /*
        !           267:  * Set/Get the name of the document. This is the same as the title.
        !           268:  * Free the old name after the new one is set, because sometimes this
        !           269:  * routine might be called as the old name as the argument...
        !           270:  */
        !           271: - setName:(const char *)documentName
        !           272: {
        !           273:     documentName = documentName ? documentName : "";
        !           274:     if (documentName != name) {
        !           275:        free(name);
        !           276:        name = NXCopyStringBufferFromZone (documentName, [self zone]); 
        !           277:        [[document window] setTitleAsFilename:name];
        !           278:     }
        !           279:     return self;
        !           280: }
        !           281: 
        !           282: -(const char *)name
        !           283: {
        !           284:     return name;
        !           285: }
        !           286: 
        !           287: /*
        !           288:  * windowWillClose: gets called by windows who have this instance of 
        !           289:  * YapDocument as delegate.  We call closeDocument:andWindow: to see if the
        !           290:  * document needs saving and take the appropriate action if so. If the user
        !           291:  * cancels the save, closeDocument:andWindow: returns NO and we return nil.
        !           292:  * This prevents the window from closing...
        !           293:  */
        !           294: - windowWillClose:sender
        !           295: {
        !           296:     return [self closeDocument:CLOSEWINDOW_STRING andWindow:NO] ? self : nil;
        !           297: }
        !           298: 
        !           299: /*
        !           300:  * Closes the document. If document needs saving, asks user he/she'd like the doc
        !           301:  * saved. Returns NO if the user cancels out of the save operation, otherwise returns YES.
        !           302:  * flag determines if the window should also be closed with the document.
        !           303:  */
        !           304: - (BOOL)closeDocument:(const char *)message andWindow:(BOOL)flag
        !           305: {
        !           306:     if ([self needsSaving]) {
        !           307:        int save = NXRunAlertPanel(message, SAVECHANGES_STRING, SAVE_STRING, DONTSAVE_STRING, CANCEL_STRING, [self name]);
        !           308:        if (save == NX_ALERTOTHER) {    // Cancel
        !           309:            return NO;
        !           310:        } else if (save == NX_ALERTDEFAULT) {
        !           311:            [self save:nil];
        !           312:        }
        !           313:     }
        !           314:     [[document window] setDelegate:nil];
        !           315:     if (flag) [[document window] close];
        !           316:     [self free];
        !           317:     return YES;
        !           318: }
        !           319: 
        !           320: - free
        !           321: {
        !           322:     NXZone *docZone = [self zone];
        !           323:     if (name) free(name);
        !           324:     [super free];
        !           325:     [YapDocument reuseZone:docZone];
        !           326:     return nil;
        !           327: }
        !           328:     
        !           329: /*
        !           330:  * save: saves the current document. If the document is untitled, it 
        !           331:  * puts up a savePanel to get the user to enter a file name. saveAs:
        !           332:  * saves the document under a new name by putting up a savePanel.
        !           333:  */
        !           334: - save:sender 
        !           335: {
        !           336:     (void)[self saveDocument:[self name]];
        !           337:     return self;
        !           338: }
        !           339:   
        !           340: - saveAs:sender 
        !           341: {
        !           342:     if ([[SavePanel new] runModalForDirectory:"." file:[self name]]) {
        !           343:        (void)[self saveDocument:[[SavePanel new] filename]];
        !           344:     }
        !           345:     return self;
        !           346: }
        !           347: 
        !           348: - execute:sender
        !           349: {
        !           350:     [[NXApp outputView] executeCodeFrom:[document docView]];
        !           351: 
        !           352:     return self;
        !           353: }   
        !           354: 
        !           355: /*
        !           356:  * To get around the problem of printPSCode: going up the responder chain and
        !           357:  * causing print panel to come back after Cancel, we use the following glue.
        !           358:  */
        !           359: - print:sender
        !           360: {
        !           361:     [[document docView] printPSCode:sender];
        !           362:     return self;
        !           363: }
        !           364: 
        !           365: @end

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.