home *** CD-ROM | disk | FTP | other *** search
- /*
- * NeXTSTEP 3.0 mods - This was simply rebuilt with Project Builder.
- * Of course, there is always the new 3.0 Help system, but if you want
- * to try this simple approach, it still works.
- *
- *
- * Author: Julie Zelenski, NeXT Developer Support
- * (This is a simpler, reusable version of the one by Julie in
- * NextDeveloper/Examples/BusyBox. This one leaves out the context-
- * sensitive help. -- John Glover, University of Houston, glover@uh.edu)
- *
- * You may freely copy, distribute and reuse the code in this example.
- * NeXT disclaims any warranty of any kind, expressed or implied, as to
- * its fitness for any particular use.
- *
- * Help.m, a help object to manage and display RTF help files.
- * The help object owns its own nib section "Help.nib" which has a
- * Help panel - with an NXBrowser to display the help topics, and
- * a scrolling text view to display the help files. The help files are
- * all stored as RTF text files in a directory called Help within the
- * app wrapper. At init time, the Help object loads the browser with
- * names of all the files found in the Help directory. When a name is
- * chosen from the browser, the help object opens a stream on that file
- * and read the rich text into the text object. This object is a useful
- * addition to any program, because all users appreciate help!
- *
- * To use this:
- * 1. Copy Help.m, Help.h, and Help.nib to your project directory and add
- * them to the project.
- * 2. In the main .nib file, create Help as a new subclass of Object and parse it.
- * 3. Instantiate a Help object in the main .nib file.
- * 4. Connect your Help... menu item to the generalHelp: method of the
- * help instance.
- * 5. Connect your Print... menu item to the print: method of the
- * help instance.
- * 6. Modify the text at the top of the Help.nib panel to suit your application.
- * 7. Build your application as an .app, and create a Help folder within the .app folder.
- * In that folder, all .rtf filenames will show up as help topics.
- *
- */
-
- // #import <stdio.h>
- #import "Help.h"
- /* #import <appkit/Button.h>
- #import <appkit/Cell.h>
- #import <appkit/Matrix.h>
- #import <appkit/MenuCell.h>
- #import <appkit/NXBrowser.h>
- #import <appkit/NXBrowserCell.h>
- #import <appkit/ScrollView.h>
- #import <appkit/appkit.h>*/
- //#import <dpsclient/wraps.h>
- #import <sys/dir.h> //for getdirentries()
- //#import <libc.h>
- //#import <appkit/Application.h>
- //#import <appkit/defaults.h> // for NXArgv
-
- @implementation Help:Object
-
-
- - init
- /* For newly created help object, loads the nib section with the Help
- * panel which has the topics browser and a scrolling text view for
- * displaying help files. Gets the appDirectory from NXApp, finds help
- * directory in app wrapper.
- */
- {
- sprintf(helpDirectory,"%s/%s",[self appDirectory],"Help");
- helpPanel = [NXApp loadNibSection:"Help.nib" owner:self];
- return self;
- }
-
- /* Copied this from BusyBoxApp with minor changes.
- * I have combined the two methods used there (new and
- * appDirectory) into one.
- */
- - (const char *)appDirectory
- {
- char *suffix;
-
- strcpy(appDirectory, NXArgv[0]);
- if (suffix = rindex(appDirectory,'/'))
- *suffix = '\0';
- if (appDirectory) chdir(appDirectory);
- getwd(appDirectory);
- return appDirectory;
- }
-
- - setHelpBrowser:anObject;
- /* Sets the helpBrowser outlet, and calls on the browser to load up.
- */
- {
- helpBrowser = anObject;
- [helpBrowser setDelegate:self];
- [helpBrowser loadColumnZero];
- return self;
- }
-
- /* TARGET/ACTION METHODS */
-
- - generalHelp:sender;
- /* This is the target/action method for the "Help" menu item. This method
- * will show the "general help" file.
- */
- {
- [self showHelpFile:"General Help"];
- return self;
- }
-
- - browserHit:sender
- /* This is the target/action method from the help topics browser. When
- * a help topic is selected, this method will show the help file for that
- * topic.
- */
- {
- [self showHelpFile:[[[sender matrixInColumn:0] selectedCell] stringValue]];
- return self;
- }
-
-
- - print:sender;
- /* This method is called by the Print menu cell in the main menu. It will
- * print the current help file.
- */
- {
- [[helpScrollView docView] printPSCode:sender];
- return self;
- }
-
-
- /* HELP METHODS */
-
- - showHelpFile:(const char*)filename;
- /* Tries to open a stream for the specified RTF text file in the Help
- * directory so the text object can readRichText. Also selects the
- * filename in the browser of help topics. It also brings the
- * help panel to the front.
- */
- {
- NXStream *stream;
- char helpFile[MAXPATHLEN];
- static NXPoint origin = {0.0,0.0};
-
- [self browser:helpBrowser selectCell:filename inColumn:0];
- sprintf(helpFile,"%s/%s.rtf",helpDirectory,filename);
- stream = NXMapFile(helpFile,NX_READONLY);
- if (stream != NULL) {
- [helpPanel disableFlushWindow];
- [[helpScrollView docView] readRichText:stream];
- [[helpScrollView docView] scrollPoint:&origin];
- [[helpPanel reenableFlushWindow] flushWindow];
- NXCloseMemory(stream,NX_FREEBUFFER);
- }
- [helpPanel orderFront:self];
- return self;
- }
-
-
- /* BROWSER DELEGATE METHODS */
-
-
- #define CHUNK 127
- static char **addFile(const char *file, int length, char **list, int count)
- /* Adds the specified filename to the list of filenames. It allocates
- * more memory in chunks as needed.
- */
- {
- char *suffix;
-
- if (!list) list = (char **)malloc(CHUNK*sizeof(char *));
- if (suffix = rindex(file,'.'))
- *suffix = '\0'; /* strip rtf suffix */
- list[count] = (char *)malloc((length+1)*sizeof(char));
- strcpy(list[count], file);
- count++;
- if (!(count% CHUNK)) {
- list = (char **)realloc(list,(((count/CHUNK)+1)*CHUNK)*sizeof(char *));
- }
- list[count] = NULL;
- return list;
- }
-
- static void freeList(char **list)
- /* Frees the array of filenames
- */
- {
- char **strings;
-
- if (list) {
- strings = list;
- while (*strings) free(*strings++);
- free(list);
- }
- }
-
- static BOOL isOk(const char *s)
- /* checks to make sure the filename is not NULL and to verify that it is
- * not a "dot"--hidden file.
- */
- {
- return (!s[0] || s[0] == '.') ? NO : YES;
- }
-
- static int caseInsensitiveCompare(void *arg1, void *arg2)
- /* Compares the two arguments without regard for case using strcasecmp().
- */
- {
- char *string1, *string2;
-
- string1 = *((char **)arg1);
- string2 = *((char **)arg2);
- return strcasecmp(string1,string2);
- }
-
- static char **fileList;
-
- - (int)browser:sender fillMatrix:matrix inColumn:(int)column
- /* This delegate method goes out to the help directory and gets a list
- * of all the files in that directory. It creates a list of file names
- * for the static variable fileList, and will load the filenames into the
- * browser on demand (lazy loading).
- */
- {
- long basep;
- char *buf;
- struct direct *dp;
- char **list = NULL;
- int cc, fd, fileCount = 0;
- char dirbuf[8192];
-
- if ((fd = open(helpDirectory, O_RDONLY, 0644)) > 0) {
- cc = getdirentries(fd, (buf = dirbuf), 8192, &basep);
- while (cc) {
- dp = (struct direct *)buf;
- if (isOk(dp->d_name)) {
- list = addFile(dp->d_name, dp->d_namlen, list, fileCount++);
- }
- buf += dp->d_reclen;
- if (buf >= dirbuf + cc) {
- cc = getdirentries(fd, (buf = dirbuf), 8192, &basep);
- }
- }
- close(fd);
- if (list) qsort(list,fileCount,sizeof(char *),caseInsensitiveCompare);
- }
- freeList(fileList);
- fileList = list;
- return fileCount;
- }
-
- - browser:sender loadCell:cell atRow:(int)row inColumn:(int)column
- /* This delegate method loads the cell for a given row. The stringValue
- * for that row comes from the fileList.
- */
- {
- if (fileList) {
- [cell setStringValueNoCopy:fileList[row]];
- [cell setLeaf:YES];
- }
- return self;
- }
-
-
- - (BOOL)browser:sender selectCell:(const char *)title inColumn:(int)column
- /* This delegate method selects the cell with the given title. If it finds
- * a cell with that title, it verifies that it has a file entry in the
- * fileList, forces the loading of the cell, selects it (highlights) and
- * scrolls the browser so the cell is visible. It returns a boolean value
- * which indicates whether the cell was found.
- */
- {
- int row;
- id matrix;
-
- if (title) {
- matrix = [sender matrixInColumn:column];
- if (!fileList) return NO;
- for (row = [matrix cellCount]-1; row >= 0; row--) {
- if (fileList[row] && !strcmp(title, fileList[row])) {
- [sender getLoadedCellAtRow:row inColumn:column];
- [matrix selectCellAt:row :0];
- [matrix scrollCellToVisible:row :0];
- return YES;
- }
- }
- }
- return NO;
- }
-
-
- /* WINDOW DELEGATE METHODS */
-
- - windowWillResize:sender toSize:(NXSize *)frameSize;
- /* This method constrains the Help Panel to a reasonable minimum size
- * when the user resizes the panel.
- */
- {
- frameSize->width = MAX(frameSize->width,400.0);
- frameSize->height = MAX(frameSize->height,350.0);
- return self;
- }
-
-
- @end