|
|
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.