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.