|
|
1.1 ! root 1: /* ! 2: * YapApp.m ! 3: * Author: Ali Ozer ! 4: * Created: Mar 89 for 0.9 ! 5: * Modified: Jul & Aug 89 for 1.0 ! 6: * Modified: Aug 90 for 2.0 ! 7: * Modified: Apr & Jun 91 and Jun 92 for 3.0. Localized Jan 92. ! 8: * ! 9: * YapApp is the application class used in Yap. It implements the ! 10: * central functionality of coordinating the output and document ! 11: * windows, opening documents, managing shared panels, etc... ! 12: * ! 13: * You may freely copy, distribute and reuse the code in this example. ! 14: * NeXT disclaims any warranty of any kind, expressed or implied, ! 15: * as to its fitness for any particular use. ! 16: */ ! 17: ! 18: #import <appkit/appkit.h> ! 19: #import <objc/NXBundle.h> ! 20: #import <objc/zone.h> ! 21: #import <sys/param.h> ! 22: #import "YapApp.h" ! 23: #import "YapDocument.h" ! 24: #import "YapOutput.h" ! 25: ! 26: #define CANTOPENFILE_STRING NXLocalString("Could not open file.", NULL, "The user-specified file could not be opened") ! 27: #define OK_STRING NXLocalString("OK", NULL, "Default response in alert panel") ! 28: #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.") ! 29: #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.") ! 30: #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.") ! 31: #define QUIT_STRING NXLocalString("Quit", NULL, "The operation of exiting the application.") ! 32: #define CANCEL_STRING NXLocalString ("Cancel", NULL, "Button choice allowing user to cancel quit") ! 33: ! 34: ! 35: @implementation YapApp ! 36: ! 37: - outputView ! 38: { ! 39: return outputView; ! 40: } ! 41: ! 42: - outputWindow ! 43: { ! 44: return [outputView window]; ! 45: } ! 46: ! 47: #define DEFAULTWIDTH 612 ! 48: #define DEFAULTHEIGHT 792 ! 49: #define MINSIZE 72 ! 50: #define MAXSIZE 3600 ! 51: ! 52: /* ! 53: * Here we have a handle to the output window, created in IB. We create ! 54: * the scroll and the yap output views and add them to this window. ! 55: */ ! 56: - setOutputWindow:anObject ! 57: { ! 58: NXRect initFrame = {{0.0, 0.0}, {DEFAULTWIDTH, DEFAULTHEIGHT}}; ! 59: ! 60: id scrollView = [ScrollView new]; ! 61: ! 62: outputView = [[YapOutput allocFromZone:[self zone]] initFrame:&initFrame]; ! 63: ! 64: [anObject setBackgroundGray:NX_WHITE]; ! 65: [anObject removeFromEventMask:NX_KEYDOWNMASK|NX_KEYUPMASK]; ! 66: ! 67: [scrollView setBorderType:NX_NOBORDER]; ! 68: [scrollView setHorizScrollerRequired:YES]; ! 69: [scrollView setVertScrollerRequired:YES]; ! 70: ! 71: [anObject setContentView:scrollView]; ! 72: [scrollView setDocView:outputView]; ! 73: ! 74: [anObject setDelegate:self]; // So we can get windowWillResize:toSize: ! 75: [anObject setFrameAutosaveName:"Output Window"]; ! 76: [anObject makeKeyAndOrderFront:nil]; ! 77: ! 78: [NXApp updateOutputWindowSize]; ! 79: ! 80: return self; ! 81: } ! 82: ! 83: /* ! 84: * updateOutputWindowSize should be called after the size of the output view is ! 85: * changed. It simply makes sure the window isn't too big for the view. If the ! 86: * window is indeed to big, it is resized smaller. ! 87: */ ! 88: - updateOutputWindowSize ! 89: { ! 90: NXRect frame, content; ! 91: NXSize maxWindowSize; ! 92: ! 93: // The next few lines allow us to get the window size for the window ! 94: // containing a ScrollView and the yap output view. ! 95: ! 96: [[self outputView] getFrame:&frame]; ! 97: [ScrollView getFrameSize:&maxWindowSize forContentSize:&(frame.size) ! 98: horizScroller:YES vertScroller:YES borderType:NX_NOBORDER]; ! 99: ! 100: // sizeWindow:: wants window size in content area; so we can use the ! 101: // maxWindowSize from above. But to compare it to the window frame, ! 102: // we first need to get the content area for the current frame. ! 103: ! 104: [[self outputWindow] getFrame:&frame]; ! 105: [Window getContentRect:&content forFrameRect:&frame ! 106: style:[[self outputWindow] style]]; ! 107: ! 108: if (content.size.width > maxWindowSize.width || ! 109: content.size.height > maxWindowSize.height) { ! 110: [[self outputWindow] ! 111: sizeWindow:MIN(maxWindowSize.width, content.size.width) ! 112: :MIN(maxWindowSize.height, content.size.height)]; ! 113: } ! 114: ! 115: // Now we go from the content size to the window frame size, which is ! 116: // what we will use in windowWillResize:toSize: ! 117: ! 118: content.size = maxWindowSize; ! 119: [Window getFrameRect:&frame forContentRect:&content ! 120: style:[[self outputWindow] style]]; ! 121: ! 122: maxWindowSize = frame.size; ! 123: [[self outputWindow] setMaxSize:&maxWindowSize]; ! 124: ! 125: return self; ! 126: } ! 127: ! 128: /* ! 129: * newDocument simply creates a new Yap document and displays it. ! 130: */ ! 131: - newDocument:sender ! 132: { ! 133: [YapDocument new]; ! 134: ! 135: return self; ! 136: } ! 137: ! 138: /* ! 139: * openDocument gets a file name from the user, creates a new document window, ! 140: * and loads the specified file into it. ! 141: */ ! 142: - openDocument:sender ! 143: { ! 144: // Allow ps, eps, and any other extension not handled by other apps. ! 145: // Note that "" should come first in the list. ! 146: static const char *const yapTypes[] = {"", "ps", "eps", NULL}; ! 147: ! 148: if ([[OpenPanel new] runModalForTypes:yapTypes]) { ! 149: if ([YapDocument newFromFile:[[OpenPanel new] filename]] == nil) { ! 150: NXRunAlertPanel (NULL, CANTOPENFILE_STRING, OK_STRING, NULL, NULL); ! 151: } ! 152: } ! 153: ! 154: return self; ! 155: } ! 156: ! 157: /* ! 158: * app:openFile:type: is invoked by Workspace when the user double-clicks ! 159: * on a file Yap is prepared to accept. By default, Yap is not prepared to open ! 160: * any files, however, it can easily be made to open files of certain type ! 161: * through Project Builder. ! 162: */ ! 163: - (int)app:app openFile:(const char *)path type:(const char *)type ! 164: { ! 165: if ([YapDocument newFromFile:path] == nil) return NO; ! 166: else return YES; ! 167: } ! 168: ! 169: /* ! 170: * The following method indicates that Yap is ready to open multiple ! 171: * files at one time. ! 172: */ ! 173: - (BOOL)appAcceptsAnotherFile:sender ! 174: { ! 175: return YES; ! 176: } ! 177: ! 178: /* ! 179: * Methods to load .nib files for the various panels. ! 180: */ ! 181: - showInfo:sender ! 182: { ! 183: if (!infoPanel) { ! 184: if (![NXApp loadNibSection:"Info.nib" owner:self withNames:NO fromZone:[self zone]]) { ! 185: NXLogError ("Can't find Info.nib!"); ! 186: } ! 187: } ! 188: [infoPanel makeKeyAndOrderFront:sender]; ! 189: return self; ! 190: } ! 191: ! 192: - showHelp:sender ! 193: { ! 194: if (!helpPanel) { ! 195: if (![NXApp loadNibSection:"Help.nib" owner:self withNames:NO fromZone:[self zone]]) { ! 196: NXLogError ("Can't find Help.nib!"); ! 197: } ! 198: } ! 199: [helpPanel makeKeyAndOrderFront:sender]; ! 200: return self; ! 201: } ! 202: ! 203: - showPrefs:sender ! 204: { ! 205: if (!prefsPanel) { ! 206: if (![NXApp loadNibSection:"Prefs.nib" owner:self withNames:NO fromZone:[self zone]]) { ! 207: NXLogError ("Can't find Prefs.nib!"); ! 208: } ! 209: [self updatePreferencesPanel:sender]; ! 210: } ! 211: [prefsPanel makeKeyAndOrderFront:sender]; ! 212: return self; ! 213: } ! 214: ! 215: /* ! 216: * updatePreferencesPanel: is used to copy the existing situation into ! 217: * the Prefences panel. ! 218: */ ! 219: - updatePreferencesPanel:sender ! 220: { ! 221: NXRect outputFrame; ! 222: ! 223: [[self outputView] getFrame:&outputFrame]; ! 224: [outputWidthField setFloatValue:NX_WIDTH(&outputFrame)]; ! 225: [outputHeightField setFloatValue:NX_HEIGHT(&outputFrame)]; ! 226: [showCacheButton setState:[[self outputView] isCacheShown]]; ! 227: [clearCacheButton setState:[[self outputView] isCacheCleared]]; ! 228: ! 229: [outputWidthField selectText:sender]; ! 230: ! 231: return self; ! 232: } ! 233: ! 234: /* ! 235: * okPreferencesPanel: causes the values in Preferences to be read into the ! 236: * application and applied to the various objects. ! 237: */ ! 238: - okPreferencesPanel:sender ! 239: { ! 240: NXCoord desiredWidth, desiredHeight; ! 241: ! 242: desiredWidth = [outputWidthField floatValue]; ! 243: if (desiredWidth < MINSIZE || desiredWidth > MAXSIZE) { ! 244: desiredWidth = MIN(MAX(desiredWidth, MINSIZE), MAXSIZE); ! 245: [outputWidthField setFloatValue:desiredWidth]; ! 246: } ! 247: desiredHeight = [outputHeightField floatValue]; ! 248: if (desiredHeight < MINSIZE || desiredHeight > MAXSIZE) { ! 249: desiredHeight = MIN(MAX(desiredHeight, MINSIZE), MAXSIZE); ! 250: [outputHeightField setFloatValue:desiredHeight]; ! 251: } ! 252: ! 253: [[self outputView] sizeTo:desiredWidth :desiredHeight]; ! 254: [self updateOutputWindowSize]; ! 255: ! 256: [[self outputView] setCacheShown:[showCacheButton state]]; ! 257: [[self outputView] setCacheCleared:[clearCacheButton state]]; ! 258: ! 259: [[sender window] orderOut:sender]; ! 260: [outputWidthField selectText:sender]; ! 261: ! 262: return self; ! 263: } ! 264: ! 265: /* ! 266: * Make sure all documents are saved before actually terminating the app... ! 267: */ ! 268: - terminate:sender ! 269: { ! 270: int count = [[self windowList] count]; ! 271: BOOL needsSaving = NO; ! 272: ! 273: // Determine if there are any unsaved documents... ! 274: ! 275: while (!needsSaving && count--) { ! 276: id document = [YapDocument documentForWindow:[windowList objectAt:count]]; ! 277: if (document && [document needsSaving]) { ! 278: needsSaving = YES; ! 279: } ! 280: } ! 281: ! 282: if (needsSaving) { ! 283: int choice = NXRunAlertPanel(QUIT_STRING, UNSAVEDDOCS_STRING, REVIEW_STRING, QUITANYWAY_STRING, CANCEL_STRING); ! 284: if (choice == NX_ALERTOTHER) { ! 285: return self; // Cancel ! 286: } else if (choice == NX_ALERTDEFAULT) { ! 287: count = [[self windowList] count]; ! 288: while (count--) { ! 289: id document = [YapDocument documentForWindow:[windowList objectAt:count]]; ! 290: if (document) { ! 291: if (![document closeDocument:QUIT_STRING andWindow:YES]) { ! 292: return self; // Cancel ! 293: } ! 294: } ! 295: } ! 296: } ! 297: } ! 298: ! 299: return [super terminate:sender]; ! 300: } ! 301: ! 302: @end ! 303:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.