|
|
1.1 root 1:
2: /*
3: GraphApp.m
4:
5: GraphApp is the delegate of the Application object. It deals with opening
6: new documents as initiated by the menu commands or messages from the
7: Workspace Manager.
8:
9: You may freely copy, distribute, and reuse the code in this example.
10: NeXT disclaims any warranty of any kind, expressed or implied, as to its
11: fitness for any particular use.
12: */
13:
14: #import "Graph.h"
15:
16: static Window *findDocWindow(const char *name);
17:
18: @implementation GraphApp
19:
20: - appDidInit:sender {
21: /*
22: * If we weren't asked to open any documents at launch time, then we were
23: * launched by double clicking on the application instead of a document.
24: * In this case, we open up a new document for the user.
25: */
26: if (!NXGetDefaultValue([NXApp appName], "NXOpen") &&
27: !NXGetDefaultValue([NXApp appName], "NXOpenTemp") &&
28: !NXGetDefaultValue([NXApp appName], "NXServiceLaunch"))
29: [self new3D:self];
30: return self;
31: }
32:
33: /*
34: * Called as we are quitting. Gives the user a change to save unsaved work.
35: * The Draw example has a more complete implementation of this, since it does
36: * not give the user the "Cancel" option when logging out or powering off.
37: */
38: - appWillTerminate:sender {
39: int response;
40: List *windowList = [NXApp windowList];
41: int count;
42: Window *window;
43: BOOL dirtyDocs = NO;
44: id document;
45: NXStringTable *stringTab;
46:
47: count = [windowList count];
48: while (count--) {
49: if ([[windowList objectAt:count] isDocEdited]) {
50: dirtyDocs = YES;
51: break;
52: }
53: }
54: if (dirtyDocs) {
55: stringTab = [self stringTable];
56: response = NXRunAlertPanel([stringTab valueForStringKey:"quit alert title"],
57: [stringTab valueForStringKey:"quit alert message"],
58: [stringTab valueForStringKey:"review button"],
59: [stringTab valueForStringKey:"quit button"],
60: [stringTab valueForStringKey:"cancel button"]);
61: if (response == NX_ALERTALTERNATE) {
62: return self;
63: } else if (response == NX_ALERTOTHER) {
64: return nil;
65: } else {
66: count = [windowList count];
67: while (count--) {
68: window = [windowList objectAt:count];
69: document = [window delegate];
70: if ([document isKindOfClassNamed:"GraphDoc"] || [document isKindOfClassNamed:"Graph3DDoc"]) {
71: if (![document windowWillClose:sender]) {
72: return nil;
73: }
74: }
75: }
76: return self;
77: }
78: } else {
79: return self;
80: }
81: }
82:
83: /*
84: * This method is performed whenever a user double-clicks on an icon in
85: * the Workspace Manager representing a Draw program document. If the file
86: * is already open, it just orders its window to the front; else, it opens
87: * a new graph document from the file.
88: */
89: - (int)app:sender openFile:(const char *)path type:(const char *)type {
90: BOOL success = NO;
91: Window *win;
92: NXStringTable *stringTab;
93:
94: if (type) {
95: if (win = findDocWindow(path)) {
96: [win makeKeyAndOrderFront:self];
97: success = YES;
98: } else if (!strcmp(type, "xygraph")) {
99: if ([[GraphDoc allocFromZone:[self zone]] initFromFile:path])
100: success = YES;
101: } else if (!strcmp(type, "xyzgraph")) {
102: if ([[Graph3DDoc allocFromZone:[self zone]] initFromFile:path])
103: success = YES;
104: }
105: }
106: if (!success) {
107: stringTab = [self stringTable];
108: NXRunAlertPanel(
109: [stringTab valueForStringKey:"open alert title"],
110: [stringTab valueForStringKey:"open alert message"],
111: [stringTab valueForStringKey:"ok button"],
112: NULL, NULL, path);
113: }
114: return success;
115: }
116:
117: /* This says we can accept any number of app:openFile:type: messages. */
118: - (BOOL)appAcceptsAnotherFile:sender {
119: return YES;
120: }
121:
122: /* action method, called when the user chooses open in the menu */
123: - open:sender {
124: const char *const *files;
125: static const char *const fileType[3] = {"xygraph", "xyzgraph", NULL};
126: OpenPanel *openPanel;
127: char fullName[MAXPATHLEN];
128: const char *suffix;
129:
130: /*
131: * Declare that the user can select multiple files to be opened in the
132: * Open Panel. All apps should do this, since its so easy.
133: */
134: openPanel = [[OpenPanel new] allowMultipleFiles:YES];
135:
136: /* run the open panel, filtering for out types of our documents */
137: if ([openPanel runModalForTypes:fileType]) {
138:
139: /* open all the files returned by the open panel */
140: files = [openPanel filenames];
141: for (files = [openPanel filenames]; files && *files; files++) {
142: strcpy(fullName, [openPanel directory]);
143: strcat(fullName, "/");
144: strcat(fullName, *files);
145: suffix = strrchr(*files, '.');
146: if (suffix)
147: [self app:NXApp openFile:fullName type:++suffix];
148: }
149: }
150: return self;
151: }
152:
153: /* action method, called when the user chooses "New 2D" in the menu */
154: - new2D:sender {
155: [[GraphDoc allocFromZone:[self zone]] init];
156: return self;
157: }
158:
159: /* action method, called when the user chooses "New 3D" in the menu */
160: - new3D:sender {
161: [[Graph3DDoc allocFromZone:[self zone]] init];
162: return self;
163: }
164:
165: /*
166: * Loads the info panel from its separate nib section. We set the version
167: * number in the info panel on the fly, which keeps it up to date
168: * automatically. The VERS_NUM variable is created in the vers.c file, which
169: * is created by the vers_string shell command as part of the build process.
170: */
171: - showInfoPanel:sender {
172: if (!infoPanel) {
173: extern char VERS_NUM[];
174: [NXApp loadNibSection:"Info.nib" owner:self withNames:NO];
175: if (strlen(VERS_NUM) > 0) {
176: char versionBuffer[100];
177: sprintf (versionBuffer, [[self stringTable] valueForStringKey:"version"], VERS_NUM);
178: [versString setStringValue:versionBuffer];
179: } else {
180: [versString setStringValue:""];
181: }
182: }
183: [infoPanel makeKeyAndOrderFront:self];
184: return self;
185: }
186:
187: /* Loads the help panel from its separate nib section. */
188: - showHelpPanel:sender {
189: if (!helpPanel)
190: [NXApp loadNibSection:"Help.nib" owner:self withNames:NO];
191: [helpPanel makeKeyAndOrderFront:self];
192: return self;
193: }
194:
195: /* Loads the 3D panel from its separate nib section. */
196: - showThreeDPanel:sender {
197: if (!threeDPanel) {
198: [NXApp loadNibSection:"ThreeDPanel.nib" owner:self withNames:NO];
199: /*
200: * USE THIS METHOD CAREFULLY. It should only be used for panels that
201: * never or rarely need to become key. Usually this is because they
202: * have no areas for typing (as in this case), or else the user very
203: * rarely types in them (e.g., the Font panel).
204: */
205: [threeDPanel setBecomeKeyOnlyIfNeeded:YES];
206: }
207: [threeDPanel orderFront:self];
208: return self;
209: }
210:
211: /* Returns the 3D Panel */
212: - (ThreeDPanel *)threeDPanel {
213: return threeDPanel;
214: }
215:
216: /* Returns the string table */
217: - (NXStringTable *)stringTable {
218: char path[MAXPATHLEN+1];
219:
220: if (!stringTable && [[NXBundle mainBundle] getPath:path forResource:"Graph" ofType:"strings"]) {
221: stringTable = [[NXStringTable allocFromZone:[self zone]] init];
222: [stringTable readFromFile:path];
223: }
224: return stringTable;
225: }
226:
227: /*
228: * Returns the window for a given filename, if open. We go through the window
229: * list looking for an window with the given file open. Since there are many
230: * more windows in the window list than our document windows (panels, NXImage
231: * caches, the app icon,...), we check the delegate to know if its a document
232: * window. We use realpath() to make sure we aren't fooled by symbolic links
233: * that lead to a file already opened via a different path.
234: */
235: static Window *findDocWindow(const char *name) {
236: int count;
237: id document;
238: Window *window;
239: List *windowList;
240: const char *realPath;
241: const char *otherRealPath;
242: char realPathBuf[MAXPATHLEN+1];
243:
244: windowList = [NXApp windowList];
245: count = [windowList count];
246: realPath = realpath(name, realPathBuf) ? realPathBuf : name;
247: while (count--) {
248: window = [windowList objectAt:count];
249: document = [window delegate];
250: if (document && ([document isKindOf:[GraphDoc class]]
251: || [document isKindOf:[Graph3DDoc class]])) {
252: otherRealPath = [document realFilename];
253: if (otherRealPath && !strcmp(otherRealPath, realPath))
254: return window;
255: }
256: }
257: return nil;
258: }
259:
260: @end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.