This is Controller.m in view mode; [Download] [Up]
/* Controller.m --- Main controller object for the TextLab program. ** Authors: Bruce Blumberg and Ali Ozer, NeXT Developer Support Group */ // Controller object is the central object in TextLab. It manages the // windows, open/save panels, and menu commands. #import "Controller.h" #import "TextView.h" #import <appkit/Application.h> #import <objc/typedstream.h> @implementation Controller // We subclass the Controller "new" so that we can set the application's // delegate to point to the Controller object. This way open file // requests from the Workspace get routed to the Controller's // appOpenFile:type: and appAcceptsAnotherFile methods. + new { self = [super new]; [NXApp setDelegate:self]; // create instances of support objects openReq = [OpenPanel new]; saveReq = [SavePanel new]; return self; } - showError: (char *)errorMessage { NXRunAlertPanel (NULL, errorMessage,"OK",NULL,NULL); } // newTextView: is invoked in response to a new empty window request. It // creates a new window containing a TextView. Note that we want new windows // to be offset from each other by some amount; hence the use of wRect. #define ORIGX 100.0 #define ORIGY 100.0 static NXRect wRect = {{ORIGX, ORIGY},{500.0,400.0}}; - newTextView:sender { id newTextView; NXOffsetRect(&wRect, 20.0, -20.0); if (wRect.origin.y < 0) {wRect.origin.y = ORIGY; wRect.origin.x = ORIGX;} newTextView = [TextView newFrame:&wRect]; [[newTextView window] setDelegate:self]; return self; } // appAcceptsAnotherFile is an application delegate method which // returns whether it is OK for the application to try to open more files // with the appOpenFile:type: method. TextLab can indeed open multiple // windows, so we return YES. -(BOOL) appAcceptsAnotherFile:sender { return (YES); } // appOpenFile:type: is called to open the specified file. It is normally // called by the Application object in response to open requests from the // Workspace. Here we also route the open requests from the OpenPanel // to this method (see openRequest:). -(int) appOpenFile:(char *)fileName type:(char *)fileType { return [self openFile:fileName]; } // openRequest: opens a new file. It puts up a open panel, and, if the user // doesn't cancel, it reads the specified archive file. If the selected file // is not a proper archive file, then openRequest: will complain. - openRequest:sender { const char *fileName; const char *const types[2] = {"tl", NULL}; int ok; if ([openReq runModalForTypes:types] && (fileName =[openReq filename])) { [self openFile:fileName]; } else [self showError:"Not a valid textlab file."]; return self; } -(int) openFile:(const char *)fileName { id win; NXTypedStream *typedStream; if(!(typedStream = NXOpenTypedStreamForFile(fileName,NX_READONLY))){ [self showError:"error on opening file"]; return NO; } else { win = NXReadObject(typedStream); NXCloseTypedStream(typedStream); [win setTitle:fileName]; [[win display] makeKeyAndOrderFront:self]; return YES; } } // saveRequest: saves the current window under its default name (found in // the title bar). Note that if the title bar is empty or the default title // is "Untitled" then saveRequest: will put up a save panel, giving the user // a chance to specify a real title. - saveRequest:sender { const char *fileName; id curWin = [NXApp mainWindow]; if (curWin == nil) [self showError:"No active window to save."]; else { // Check to see if the current window is titled and the title is not // "Untitled". If so, save the file, else put up a save panel... fileName = [curWin title]; if (strcmp (fileName, "Untitled")) [self saveWindow:curWin inPath:fileName]; else [self saveInRequest:sender]; } return self; } // saveInRequest: gives the user a chance to save the current window // under a new name. - saveInRequest:sender { const char *fileName; id curWin; /* EXERCISE #4a * * Add code to respond to an saveInRequest * * Hint: Use a SavePanel to get the file name and * * directory where the document should be saved. * * You will note that the saveReq instance variable * * was initialized in the +new method of Controller * * to point to a SavePanel. SavePanels will automatically * * append an extension on the file name specified by the * * the user if you have previously sent it the * * setRequiredFileType: message passing it the appropriate * * extension. Once you have done this, you should send it a* * a method called runModalForDirectory:file: which * * makes theSavePanel visible and which make it * * a modal window. Once that method returns you can * * query the SavePanel for the file name * * selected (look in the spec sheets for SavePanel). * * Assuming you used setRequiredFileType: earlier the file * * name returned will have the appropriate extension * * Finally you should call the saveWindow:inPath: * * method of Controller which will actually save the * * document. Note the first argument to saveWindow is * * the id of the window containing the document to be * * saved. Look at the specSheets for the Application * * object to see what method to use to get the id of the * * current main window. In fact you will probably want to * * get the id of the main window first thing in here so * * you can use its title as the default file name for * * the file in which the window will be stored */ return self; } // saveWindow writes a window out the archive file whose name is specified // by the second argument. The title of the current window is also set // accordingly. - saveWindow:(id)win inPath:(const char *)name { NXTypedStream *typedStream; [win setTitle:name]; /* EXERCISE #4b * * Add code to store win and its contents * * in an file called name.Hint: you will want to * * use typedStreams to write out the window and its * * contents. The code to do this will look similar to the * * code in openFile: so be sure to look at that code. You * * will need to do 3 things. 1) Open a typedStream on a * * file named name using NXOpenTypedStreamForFile() * * 2) Write out the window to the typedStream using * * NXWriteRootObject(). 3) Close the typedStream. */ return self; } // Printing is rather simple; just send printPSCode: to the text view // you wish to print. The print panel will automatically pop up and unless // the user cancels the printout the text view will be printed. - printRequest:sender { /* EXERCISE 5 * * Add code to assign curText to point to * * view which should be printed. Hint: it is the * * docView of the TextView in the application's * * mainWindow. Look at the spec sheets for the * * Application class to see how to get the id of * * the current main window */ id curText = nil; if (curText == nil) [self showError:"No active window to print."]; else { /* EXERCISE 5b * * Add code to print view * * * * */ } return self; } // closeRequest closes the current window by simulating a click on the // closebutton. A check should probably be added to give the user the // option of saving the window before closing - closeRequest:sender { [[NXApp mainWindow] performClose:sender]; return self; } // This method will get called before a window is closed and // will give the user an opportunity to save their file. It then returns // self indicating that the window may be closed. - windowWillClose:(id)whichWin { return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.