This is WoodApp.m in view mode; [Download] [Up]
#import <sys/dir.h> #import <misckit/MiscString.h> #import <misckit/MiscInfoController.h> #import "wooddoc.h" #import "PageMargin.h" #import "WoodBundle.h" #import "ooe_server.h" #import "IPPanel.h" #import "IPFlyPanel.h" #define PAGE_LAYOUTSTR NXLocalizedString("Page_Layout",NULL,Page_Layout) #define HELP_PANELSTR NXLocalizedString("Help_Panel",NULL,Help_Panel) #define NOSTR NXLocalizedString("NO",NULL,NO) #define YESSTR NXLocalizedString("YES",NULL,YES) #define LIBRARYSUBPATH "Wood" #define MODULEEXTENSION "woodfilter" static id docClass; // Class of Document to use static id zoneStorage; // zone storage for zone reuse static BOOL docClassConforms; // YES if docClass conforms to protocol PDocument static BOOL inMsgPrint = NO; // YES if message print (Listener) static const char *versionFormat; // Version Format String static const int classVersion = 110; // Version multiplied by 100 static void initMenu(id menu); static id documentInWindow(id window); static id findDocument(const char *name); static id openFile(const char *directory, const char *name, BOOL display); static BOOL fileNameHasExtension(const char *f, const char *e); @implementation WoodApp:Application + initialize { if (self == [WoodApp class]) { docClass = [WoodDoc class]; docClassConforms = YES; versionFormat = NXLocalizedString("Version %.2f",NULL,Version Format); zoneStorage = [[Storage allocFromZone:[self zone]] initCount:0 elementSize:sizeof(NXZone *) description:@encode(NXZone *)]; } return self; } - setDocClass:aDocClass { docClass = aDocClass; docClassConforms = YES; return self; } - docClass { return docClass; } - inspectorManager { return inspectorManager; } - (BOOL)docClassConforms { return docClassConforms; } - loadLocalNib:(const char *)nibName owner:aOwner { id bundle; char buf[MAXPATHLEN + 1],*temp; NXZone *zone; bundle = [NXBundle bundleForClass:[aOwner class]]; if([bundle getPath:buf forResource:nibName ofType:"nib"]){ zone = NXCreateChildZone([self zone], vm_page_size, vm_page_size, YES); NXNameZone(zone, nibName); if([self loadNibFile:buf owner:aOwner withNames:NO fromZone:zone]){ NXMergeZone(zone); return self; } else { NX_MALLOC(temp,char,strlen(nibName) + 51); sprintf(temp,"%s %s\n",localString("Could not load requested resource"),nibName); Notify(localString("Resource Error"),temp); NX_FREE(temp); return nil; } } else { NX_MALLOC(temp,char,strlen(nibName) + 51); sprintf(temp,"%s %s\n",localString("Could not find requested resource"),nibName); Notify(localString("Resource Error"),temp); NX_FREE(temp); return nil; } } - openFile:(const char *)path file:(const char *)type flag:(BOOL)flag { return openFile(path,type,flag); } - currentDocument { return documentInWindow([self mainWindow]); } - (const char *)currentDirectory { const char *retval; WoodDoc *currentDocument; currentDocument = [self currentDocument]; if([currentDocument directory]) retval = [currentDocument directory]; else retval = defaultDir; return retval; } - (const char *)docExtension { if(docClassConforms) return [docClass docExtension]; else return NULL; } - setDefaultDir:(const char *)dir { sprintf(defaultDir,"%s",dir); return self; } - (BOOL)saveAll { return saveAll; } - setSaveAll:(BOOL)value { saveAll = value; return self; } - (BOOL)dumpAll { return dumpAll; } - setDumpAll:(BOOL)value { dumpAll = value; return self; } - saveAsPanel:sender { id savepanel = [SavePanel new]; [savepanel setAccessoryView:nil]; if(docClassConforms) [savepanel setRequiredFileType:[docClass docExtension]]; return savepanel; } - pageLayout:sender { return pageMargin; } - (NXZone *)newDocZone { NXZone *dummy; if (![zoneStorage count]) { return NXCreateZone(vm_page_size, vm_page_size, YES); } else { dummy = *(NXZone **)[zoneStorage elementAt:[zoneStorage count] - 1]; [zoneStorage removeLastElement]; return dummy; } } - reuseDocZone:(NXZone *)aZone { NXZone *dummy; dummy = aZone; [zoneStorage addElement:(void *)&dummy]; NXNameZone(aZone, "Unused"); return self; } - new:sender { [[docClass allocFromZone:[self newDocZone]] init]; return self; } - open:sender { const char *directory; const char *const *files; const char *const allowedType[2] = {[self docExtension], NULL}; OpenPanel *openpanel = [[OpenPanel new] allowMultipleFiles:YES]; directory = [self currentDirectory]; if (directory && (*directory == '/')) [openpanel setDirectory:directory]; if ([openpanel runModalForTypes:allowedType]) { files = [openpanel filenames]; directory = [openpanel directory]; while (files && *files) { haveOpenedDocument = openFile(directory, *files, YES) || haveOpenedDocument; files++; } } return self; } - saveAll:sender { int count; count = [docList count]; if(docClassConforms) while (count--) { [[docList objectAt:count] save:self]; } return self; } - print:sender { if(docClassConforms) return [[self currentDocument] print:sender]; else return nil; } - samples:sender { NXBundle *bundle; char buf[2048]; bundle = [NXBundle mainBundle]; strcpy(buf,[bundle directory]); strcat(buf,"/Samples"); if(![[Application workspace] openFile:buf]) NXBeep(); return self; } - (BOOL)menuItemUpdate:menuCell { SEL action; id responder, target; BOOL retval = NO; target = [menuCell target]; if(!target){ action = [menuCell action]; responder = [NXApp calcTargetForAction:action]; if([responder respondsTo:@selector(validateCommand:)]){ retval = [responder validateCommand:menuCell]; } else { if(![menuCell isEnabled] && responder){ [menuCell setEnabled:YES]; retval = YES; } else if([menuCell isEnabled] && !responder){ [menuCell setEnabled:NO]; retval = YES; } } } else if(target == self) retval = [self validateCommand:menuCell]; return retval; } - (BOOL)validateCommand:menuCell { SEL action = [menuCell action]; BOOL redraw = NO, enabled = [menuCell isEnabled]; if ((action == @selector(saveAll:)) || (action == @selector(print:))){ if(findDocument(NULL) && !enabled){ redraw = YES; [menuCell setEnabled:YES]; } else if(!findDocument(NULL) && enabled){ redraw = YES; [menuCell setEnabled:NO]; } } return redraw; } - setupPageLayout:(float)lm :(float)rm :(float)tm :(float)bm { if (!pageMargin) { pageMargin = [PageMargin new]; [pageMargin setPlpAccessory:plpAccessory]; [pageMargin setFrameUsingName:PAGE_LAYOUTSTR]; } [pageMargin setValues:lm right:rm top:tm bottom:bm]; [pageMargin writePrintInfo]; return self; } - appWillInit:sender { char temp[MAXPATHLEN+1]; float lm,rm,tm,bm; if (!NXGetDefaultValue(appName,localString("SaveAll"))) sprintf(temp,NOSTR); else sprintf(temp,NXGetDefaultValue(appName,localString("SaveAll"))); if (!strcmp(temp,YESSTR)) saveAll = YES; if (!NXGetDefaultValue(appName,localString("DumpAll"))) sprintf(temp,NOSTR); else sprintf(temp,NXGetDefaultValue(appName,localString("DumpAll"))); if (!strcmp(temp,YESSTR)) dumpAll = YES; if (!NXGetDefaultValue(appName,localString("LeftMargin"))) sprintf(temp,"36.0"); else sprintf(temp,NXGetDefaultValue(appName,localString("LeftMargin"))); sscanf(temp,"%f",&lm); if (!NXGetDefaultValue(appName,localString("RightMargin"))) sprintf(temp,"36.0"); else sprintf(temp,NXGetDefaultValue(appName,localString("RightMargin"))); sscanf(temp,"%f",&rm); if (!NXGetDefaultValue(appName,localString("TopMargin"))) sprintf(temp,"36.0"); else sprintf(temp,NXGetDefaultValue(appName,localString("TopMargin"))); sscanf(temp,"%f",&tm); if (!NXGetDefaultValue(appName,localString("BottomMargin"))) sprintf(temp,"36.0"); else sprintf(temp,NXGetDefaultValue(appName,localString("BottomMargin"))); sscanf(temp,"%f",&bm); [self setupPageLayout:lm :rm :tm :bm]; [self setAutoupdate:YES]; docList = [[List alloc] init]; [self registerAsOOEServer]; return self; } - appDidInit:sender { int i; char buffer[MAXPATHLEN+1], temp[MAXPATHLEN+1]; char *directory, *name, *ext; const char *def; int ooeLaunched = NO; id inspectorPanel; [self setDefaultDir:NXHomeDirectory()]; bundleList = [[List allocFromZone:[self zone]] init]; [self createBundlesAndLoadModules:NO]; if (NXArgc > 1) { for (i = 1; i < NXArgc; i++) { strcpy(buffer, NXArgv[i]); ext = rindex(buffer, '.'); if (!ext) { strcat(buffer,"."); strcat(buffer, [self docExtension]); } if (*buffer == '/') { directory = "/"; name = buffer; name++; } else { name = rindex(buffer, '/'); if (name) { *name++ = '\0'; sprintf(temp,"%s/%s",[(NXBundle *)[NXBundle mainBundle] directory],buffer); directory = temp; } else { name = buffer; directory = NULL; } } haveOpenedDocument = openFile(directory, name, YES) || haveOpenedDocument; } } def = NXReadDefault([self appName], OOE_LAUNCH_DEFAULT); ooeLaunched = (def != NULL && atoi(def) == 1); NXWriteDefault([self appName], OOE_LAUNCH_DEFAULT, "0"); if (!haveOpenedDocument && !ooeLaunched && !NXGetDefaultValue([self appName], "NXServiceLaunch")) [self new:self]; if (NXGetDefaultValue(appName,localString("Quit"))) { [self activateSelf:YES]; NXPing(); [self terminate:self]; } initMenu([self mainMenu]); inspectorPanel = [inspectorManager window]; [inspectorPanel setFrameAutosaveName:"Wood Inspector Frame"]; [inspectorPanel setVisibleAutosaveName:"Wood Inspector Visibility"]; [inspectorPanel setFloatingAutosaveName:"Wood Inspector Floating"]; [inspectorPanel setFrameUsingName:[inspectorPanel frameAutosaveName]]; [inspectorPanel setFloatingUsingName:[inspectorPanel floatingAutosaveName]]; [inspectorPanel setVisibleUsingName:[inspectorPanel visibleAutosaveName]]; if([IPPanel isPanelSavedAsVisible:[inspectorPanel visibleAutosaveName]]) [inspectorManager inspect:nil]; [infoController setLicenseFile:[MiscString newWithString:"/Intro/License.rtfd"]]; [infoController setReleaseNotesFile:[MiscString newWithString:"/Intro/ReleaseNotes.rtfd"]]; return self; } - app:sender willShowHelpPanel:panel { char path[MAXPATHLEN + 1]; [panel setFrameUsingName:HELP_PANELSTR]; sprintf(path, "%s/%s", [panel helpDirectory],"Intro/Intro.rtfd"); [panel showFile:path atMarker:NULL]; return self; } - appWillTerminate:sender { float lm,rm,tm,bm; char temp[100]; id window, document; int choice = 0, count = [docList count]; id inspectorPanel; inspectorPanel = [inspectorManager window]; [inspectorPanel saveFrameUsingName:[inspectorPanel frameAutosaveName]]; [inspectorPanel saveFloatingUsingName:[inspectorPanel floatingAutosaveName]]; [inspectorPanel saveVisibleUsingName:[inspectorPanel visibleAutosaveName]]; [pageMargin saveFrameUsingName:PAGE_LAYOUTSTR]; [pageMargin getValues:&lm right:&rm top:&tm bottom:&bm]; sprintf(temp,"%f",lm); NXWriteDefault([self appName],localString("LeftMargin"),temp); sprintf(temp,"%f",rm); NXWriteDefault([self appName],localString("RightMargin"),temp); sprintf(temp,"%f",tm); NXWriteDefault([self appName],localString("TopMargin"),temp); sprintf(temp,"%f",bm); NXWriteDefault([self appName],localString("BottomMargin"),temp); if (saveAll) { while (count--) { document = [docList objectAt:count]; if ([document respondsTo:@selector(needsSaving)] && [document needsSaving]) { [document save:self]; } } NXWriteDefault(appName,localString("SaveAll"),YESSTR); NXWriteDefault(appName,localString("DumpAll"),NOSTR); } else if (dumpAll) { NXWriteDefault(appName,localString("DumpAll"),YESSTR); NXWriteDefault(appName,localString("SaveAll"),NOSTR); } else { NXWriteDefault(appName,localString("DumpAll"),NOSTR); NXWriteDefault(appName,localString("SaveAll"),NOSTR); while (count--) { document = [docList objectAt:count]; if ([document respondsTo:@selector(needsSaving)] && [document needsSaving]) { choice = NXRunAlertPanel(localString("Quit"), localString("You have unsaved documents."), localString("Review Unsaved"), localString("Quit Anyway"), localString("Cancel")); if (choice == NX_ALERTOTHER) return nil; else if (choice == NX_ALERTALTERNATE) return self; else if (choice == NX_ALERTDEFAULT) { count = 0; choice = [docList count]; while (choice--) { document = [docList objectAt:choice]; window = [document window]; if ([document respondsTo:@selector(windowWillClose:)]) { if ([document windowWillClose:self]) [window close]; else return nil; } } } } } } [[bundleList freeObjects] free]; return self; } - (int)appOpenFile:(const char *)path type:(const char *)type { char *name; char directory[MAXPATHLEN+1]; if (type && !strcmp(type, [self docExtension])) { strcpy(directory, path); name = rindex(directory, '/'); if (name) { if (name != index(directory, '/')) { *name++ = '\0'; if (openFile(directory, name, YES)) { haveOpenedDocument = YES; return YES; } } else { name++; if (openFile("/", name, YES)) { haveOpenedDocument = YES; return YES; } } } } else { sprintf(directory,localString("%s is not a file %s can open. An attempt to filter appropriate data will be made."),path,appName); Notify(localString("File Open Warning"),directory); if ([[docClass allocFromZone:[self newDocZone]] initFromPasteboard:[Pasteboard newByFilteringFile:path]]) return YES; } return NO; } - (BOOL)appAcceptsAnotherFile:sender { return YES; } - (int)app:sender unmounting:(const char *)fullPath { int count = [docList count]; WoodDoc *document = nil; if(!docClassConforms) return 0; while (count--) { document = [docList objectAt:count]; if (!strncmp([document directory],fullPath,strlen(fullPath))) { Notify(fullPath,localString("is being unmounted; documents here will close.")); [[document window] performClose:self]; } } return 1; } - (int)msgDirectory:(const char **)fullPath ok:(int *)flag { *fullPath = [self currentDirectory]; if (*fullPath) *flag = YES; else { *fullPath = ""; *flag = NO; } return 0; } - (int)msgFile:(const char **)fullPath ok:(int *)flag { const char *file; if(!docClassConforms) return 0; file = [(WoodDoc *)[self currentDocument] fileName]; if (file) { *fullPath = file; *flag = YES; } else { *fullPath = ""; *flag = NO; } return 0; } - (int)msgPrint:(const char *)fullPath ok:(int *)flag { BOOL close; id document = nil; char *directory, *name; char temp[MAXPATHLEN+1]; char path[MAXPATHLEN+1]; char buffer[MAXPATHLEN+1]; inMsgPrint = YES; strcpy(buffer, fullPath); name = rindex(buffer, '/'); if (name) { *name++ = '\0'; directory = buffer; } else { name = buffer; getwd(temp); directory = temp; } strcpy(path,directory); strcat(path, "/"); strcat(path, name); document = findDocument(path); if (document) close = NO; else { document = openFile(directory, name, NO); if (document) haveOpenedDocument = YES; close = YES; } if (document && ![document isEmpty]) { [self setPrintInfo:[document printInfo]]; if(docClassConforms) [document print:self]; if (close) [[document window] performClose:self]; *flag = YES; } else *flag = NO; inMsgPrint = NO; return 0; } - (int)msgVersion:(const char **)aString ok:(int *)flag { char buf[20]; sprintf(buf, versionFormat, classVersion); *aString = NXCopyStringBuffer(buf); *flag = YES; return 0; } - (int)msgQuit:(int *)flag { *flag = ([self terminate:self] ? NO : YES); return 0; } - registerDoc:aDoc { [docList addObject:aDoc]; return self; } - freeDoc:aDoc { if([docList count] == 1) [inspectorManager inspect:nil]; [docList removeObject:aDoc]; [aDoc free]; return self; } - docList { return docList; } - createBundlesAndLoadModules:(BOOL)doLoad { char libraryDir[MAXPATHLEN + 1]; int i; id cell, filter; [bundleList freeObjects]; strcpy(libraryDir, NXHomeDirectory()); strcat(libraryDir, "/Library/"); strcat(libraryDir, LIBRARYSUBPATH); [self createBundlesForDirectory:libraryDir loadModules:doLoad]; strcpy(libraryDir, "/LocalLibrary/"); strcat(libraryDir, LIBRARYSUBPATH); [self createBundlesForDirectory:libraryDir loadModules:doLoad]; strcpy(libraryDir, "/NextLibrary/"); strcat(libraryDir, LIBRARYSUBPATH); [self createBundlesForDirectory:libraryDir loadModules:doLoad]; strcpy(libraryDir, [(NXBundle *)[NXBundle mainBundle] directory]); [self createBundlesForDirectory:libraryDir loadModules:doLoad]; [addMenu disableFlushWindow]; for(i = 0; i < [bundleList count]; i++){ filter = [bundleList objectAt:i]; cell = [addMenu addItem:[filter filterName] action:@selector(addFromFilter:) keyEquivalent:0]; [cell setTag:i]; [cell setTarget:[self calcTargetForAction:@selector(addFromFilter:)]]; } [addMenu reenableFlushWindow]; [addMenu flushWindow]; return self; } - loadFilter:sender { const char *fileName; id openpanel = [OpenPanel new], newWoodBundle, cell; const char *const fileTypes[] = {MODULEEXTENSION, NULL}; BOOL shouldAdd; int i, howMany; char buf[MAXPATHLEN + 1], *tailOne, *tailTwo; [openpanel allowMultipleFiles:NO]; if([openpanel runModalForTypes:fileTypes]){ fileName = [openpanel filename]; shouldAdd = YES; i = 0; howMany = [bundleList count]; while(i < howMany && shouldAdd){ tailOne = rindex(fileName,'/') + 1; tailTwo = rindex([(WoodBundle *)[bundleList objectAt:i] directory],'/') + 1; shouldAdd = strcmp(tailOne, tailTwo) ? YES : NO; i++; } if(shouldAdd){ newWoodBundle = [[WoodBundle allocFromZone:[self zone]] initForDirectory:fileName]; [bundleList addObject:newWoodBundle]; if([newWoodBundle getPath:buf forResource:"English" ofType:"lproj"]) [[NXHelpPanel new] addSupplement:"Help" inPath:buf]; [addMenu disableFlushWindow]; cell = [addMenu addItem:[newWoodBundle filterName] action:@selector(addFromFilter:) keyEquivalent:0]; [cell setTag:[bundleList count] - 1]; [cell setTarget:[self calcTargetForAction:@selector(addFromFilter:)]]; [addMenu reenableFlushWindow]; [addMenu flushWindow]; } } return self; } - createBundlesForDirectory:(const char *)dirPath loadModules:(BOOL)doLoad { char modulePath[MAXPATHLEN + 1], buf[MAXPATHLEN + 1]; char *modulePathInsert, *tailOne, *tailTwo; DIR *dir; struct direct *dirEntry; WoodBundle *newWoodBundle; BOOL shouldAdd; int i, howMany; strcpy(modulePath, dirPath); modulePathInsert = modulePath + strlen(modulePath); *modulePathInsert = '/'; modulePathInsert++; dir = opendir(dirPath); if(!dir) return self; while(dirEntry = readdir(dir)){ if((dirEntry->d_name[0] == '.') || !fileNameHasExtension(dirEntry->d_name, MODULEEXTENSION)) continue; strcpy(modulePathInsert, dirEntry->d_name); shouldAdd = YES; i = 0; howMany = [bundleList count]; while(i < howMany && shouldAdd){ tailOne = modulePathInsert; tailTwo = rindex([(WoodBundle *)[bundleList objectAt:i] directory],'/') + 1; shouldAdd = strcmp(tailOne, tailTwo) ? YES : NO; i++; } if(shouldAdd){ newWoodBundle = [[WoodBundle allocFromZone:[self zone]] initForDirectory:modulePath]; if([newWoodBundle getPath:buf forResource:"English" ofType:"lproj"]) [[NXHelpPanel new] addSupplement:"Help" inPath:buf]; [bundleList addObject:newWoodBundle]; if(doLoad) [newWoodBundle filter]; } } closedir(dir); return self; } - filter:(int)nr { return [[bundleList objectAt:nr] filter]; } @end static void initMenu(id menu) { int count; id matrix, cell; id matrixTarget, cellTarget; matrix = [menu itemList]; matrixTarget = [matrix target]; count = [matrix cellCount]; while (count--) { cell = [matrix cellAt:count :0]; cellTarget = [cell target]; if (!matrixTarget && !cellTarget) { [cell setUpdateAction:@selector(menuItemUpdate:) forMenu:menu]; } else if ([cell hasSubmenu]) { initMenu(cellTarget); } else if (cellTarget == [NXApp delegate]) [cell setUpdateAction:@selector(menuItemUpdate:) forMenu:menu]; } } static id documentInWindow(id window) { id document = [window delegate]; if (document) return [document isKindOf:docClass] ? document : nil; else return nil; } static id findDocument(const char *name) { int count; WoodDoc *document; id docList; docList = [NXApp docList]; count = [docList count]; while (count--) { document = [docList objectAt:count]; if (!name || !strcmp([document fileName], name)) return document; } return nil; } static id openFile(const char *directory, const char *name, BOOL display) { id window; char buffer[MAXPATHLEN+1], path[MAXPATHLEN+1], temp[MAXPATHLEN+1]; if (name && *name) { if (!directory) directory = "."; else if (*directory != '/') { strcpy(buffer, "./"); strcat(buffer, directory); directory = buffer; getwd(temp); if (!chdir(directory) && getwd(path)) chdir(temp); else { Notify(localString("Open: path invalid"), directory); return nil; } } else strcpy(path,directory); strcat(path, "/"); strcat(path, name); window = [findDocument(path) window]; if (window) { if (display) [window makeKeyAndOrderFront:window]; return [window delegate]; } else return [[docClass allocFromZone:[NXApp newDocZone]] initFromFile:path]; } return nil; } static BOOL fileNameHasExtension(const char *f, const char *e) { const char *dot; if (f && e && (dot = strrchr(f, '.')) && !strcmp(dot + 1, e)) return YES; else return NO; }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.