home *** CD-ROM | disk | FTP | other *** search
- ///////////////////////////////////////////////////////////////////////////////
- // FILENAME: eTComponent.m
- // SUMMARY: Implementation of a generic external-data-container class.
- // SUPERCLASS: Object
- // INTERFACE: None
- // PROTOCOLS: <ComponentData,
- // ETFDSupport,ASCIISupport,HTMDSupport, LaTeXSupport>
- // AUTHOR: Rohit Khare and Tom Zavisca
- // COPYRIGHT: (c) 1994 California Institure of Technology, eText Project
- ///////////////////////////////////////////////////////////////////////////////
- // IMPLEMENTATION COMMENTS
- // This implementation is a hack: it uses system() calls to have files
- // copied. This avoids setting up our own buffer functions and works
- // for directories, too. This also just a default implementation; subclasses
- // will most likely define their own methods.
- //
- // The revision of 7/19 introduces a new two-phase lifecycle,
- // initInDoc:linked: followed by readComponent from path or Pboard.
- //
- // Eventually, there is room for an eTComponentBinder that will uniq' refs.
- ///////////////////////////////////////////////////////////////////////////////
- // HISTORY
- // 12/23/94: Patched to reset eTDoc everywhere
- // 08/06/94: Added symbolic linking support.
- // 07/19/94: Rewritten/Reorganized as described in Actors/eTComponent.rtf
- // 07/10/94: Created.
- ///////////////////////////////////////////////////////////////////////////////
-
- #import "eTComponent.h"
-
- #define _eTComponentVERSION 20
-
- @implementation eTComponent
- // NXAtom componentName;
- // NXAtom currentPath;
- // BOOL shouldEdit;
- // BOOL isDirty;
- // BOOl isLinked;
- // id etDoc;
- // id icon;
-
- //////////// ACCESSOR METHODS ////////////////
- - setComponentName:(const char*)newComponentName
- {componentName = NXUniqueString(newComponentName); return self;}
- - (const char *) componentName
- {return componentName;}
- - (const char *) currentPath
- {return currentPath;}
- - etDoc
- {return etDoc;}
- - icon
- {
- if (!icon) {
- icon = [[Application workspace] getIconForFile:currentPath];
- if (!icon) icon = [NXImage findImageNamed:"NXdefaulticon"];
- }
- return icon;}
- - (BOOL) isLinked
- {return isLinked;}
- - (BOOL) isMutable // this call checks shouldEdit
- {return (shouldEdit && (!isLinked));}
- - setShouldEdit:(BOOL) newState
- {shouldEdit = newState; return self;}
- - setLinked:(BOOL) newState
- {isLinked = newState; return self;}
- - setDoc:newDoc {
- if (newDoc && [newDoc respondsTo:@selector(registerComponent:)])
- etDoc = newDoc; // Always reset if possible; bugfix for shared images, 12/23
- return self;
- }
- - touch
- {isDirty=YES; return self;}
-
- //////////// LIFECYCLE MANAGEMENT ////////////
- - init // default initializer
- {
- return [self initInDoc:nil linked:NO];
- }
-
- - initInDoc:newDoc linked: (BOOL) linked
- {
- char tmp[128];
-
- [super init];
- isLinked = linked;
- etDoc = newDoc;
- isDirty = NO;
- shouldEdit = YES;
- icon = nil;
- sprintf(tmp, "Untitled-%d", [NXApp uniqueID]);
- componentName = NXUniqueString(tmp);
- currentPath = NXUniqueString("");
- return self;
- }
-
- ////////////// READING/WRITING ///////////////
- - readComponentFromPath:(const char*)newPath
- {
- char *tmp;
-
- // Have we been passed a valid pathname?
- if(!(newPath && (*newPath))) {
- NXLogError("Severe Error, bad path to readComponentFromPath");
- return nil;
- }
- if (access(newPath, F_OK|R_OK)) {
- NXLogError("%s could not access(%s)", [[self class]name],newPath);
- }
- currentPath = NXUniqueString(newPath);
- tmp = rindex(newPath,'/');
- if (tmp && *(tmp+1))
- componentName = NXUniqueString(tmp+1);
- return self;
- }
- - writeComponentToPath:(NXAtom)path inFormat:(int) theFormat
- {
- char target[MAXPATHLEN];
- char cmd[2*MAXPATHLEN];
-
- switch(theFormat) {
- case ETFD_FMT:
- [etDoc registerComponent:componentName]; // always register
- // if it's linked, just return.
- if (isLinked) break;
- sprintf(target,"%s/%s",path,componentName);
- // see if the diskfile already exists
- if ((!isDirty) && (!access(target, F_OK|R_OK))) break;
- // ok, copy the raw bits.
- if (currentPath && *currentPath && target && *target) {
- sprintf(cmd,"cp -rp \"%s\" \"%s\"", currentPath, target);
- system(cmd);
- }
- // since we have saved ETFD, reset the "clean" state
- currentPath = NXUniqueString(target);
- isDirty = NO;
- break;
- case TeXD_FMT: if (isLinked) break;
- case HTMD_FMT:
- // In these formats, we always force copying of the data resource
- [etDoc registerComponent:componentName]; // always register
- sprintf(target,"%s/%s",path,componentName);
- // see if the diskfile already exists
- if ((!isDirty) && (!access(target, F_OK|R_OK))) break;
- if (currentPath && *currentPath && target && *target) {
- sprintf(cmd,"cp -rp \"%s\" \"%s\"", currentPath, target);
- system(cmd);
- }
- break;
- }
- return self;
- }
-
- - linkComponentToPath:(NXAtom)path
- {
- char target[MAXPATHLEN];
- char cmd[2*MAXPATHLEN];
-
- [etDoc registerComponent:componentName]; // always register
- sprintf(target,"%s/%s",path,componentName);
- // see if the diskfile already exists
- if (access(target, F_OK|R_OK)){
- if (currentPath && *currentPath && target && *target) {
- sprintf(cmd,"ln -s \"%s\" \"%s\"", currentPath, target);
- system(cmd);
- }
- }
- return self;
- }
- - readComponentFromPboard:(Pasteboard *)thePboard
- {
- NXAtom foundType;
- NXAtom supportedTypes[2] = {NXFilenamePboardType,
- NXFileContentsPboardType};
-
- foundType = [thePboard findAvailableTypeFrom:supportedTypes num:2];
-
- if (foundType == NXFilenamePboardType) {
- // can we derive a resource name? if not, make path the resource name
- char *path;
- int len;
-
- [thePboard readType:NXFilenamePboardType data:&path length:&len];
- // we only process _ONE_ filename; this defeats the tab-separation
- if (index(path, '\t')) *index(path, '\t')=0;
- if (rindex(path, '/')) {
- componentName = NXUniqueString(rindex(path,'/')+1);
- currentPath = NXUniqueString(path);
- } else {
- currentPath = componentName = NXUniqueString(path);
- }
- [thePboard deallocatePasteboardData:path length:len];
- } else if (foundType == NXFileContentsPboardType) {
- char *path,tmp[MAXPATHLEN];
-
- sprintf(tmp,"/tmp/eTComponent.in.%x", [NXApp uniqueID]);
- path = [thePboard readFileContentsType:NULL toFile:tmp];
- currentPath = NXUniqueString(path);
- componentName = NXUniqueString(rindex(path,'/')+1);
- free(path); // readFile... returns a malloc'd actual path
- }
- return self;
- }
- - writeComponentToPboard:(Pasteboard *)thePboard
- {
- // find out where the file is and encode that to the Pboard.
- if (!(*currentPath) || access(currentPath, F_OK)) return nil;
- [thePboard declareTypes:&NXFilenamePboardType num:1 owner:nil];
- [thePboard writeType:NXFilenamePboardType
- data:currentPath length:strlen(currentPath)];
- return self;
- }
- - addToPboard:thePboard
- {
- if (!(*currentPath) || access(currentPath, F_OK)) return nil;
- [thePboard addTypes:&NXFilenamePboardType num:1 owner:nil];
- [thePboard writeType:NXFilenamePboardType
- data:currentPath length:strlen(currentPath)];
- return self;
- }
- ///////// ADDITIONAL FMT PROTOCOL SUPPORT ////////////
-
- - readRichText:(NXStream *)stream forView:view
- {
- char buf[MAXPATHLEN];
- const char *tmp;
- int i;
- id temp;
-
- temp = [view etDoc];
- if (temp && [temp respondsTo:@selector(registerComponent:)])
- etDoc = temp; // Always reset if possible; bugfix for shared images, 12/23
- NXScanf(stream, "%d ", &i);
- if (i != _eTComponentVERSION) {
- // bad version block.
- NXLogError("eTComponent found unparseable version %d at position %d",
- i, NXTell(stream));
- return nil;
- }
- NXScanf(stream, "%c %c %d", &isLinked, &shouldEdit, &i); NXGetc(stream); // space-eater
- isLinked -= 'A'; shouldEdit -= 'A';
- if (i) NXRead(stream, buf, i);
- buf[i] = 0;
- currentPath = NXUniqueString(buf);
-
- NXScanf(stream, " %d", &i); NXGetc(stream); // space-eater
- if (i) NXRead(stream, buf, i);
- buf[i] = 0;
- componentName = NXUniqueString(buf);
-
- if(!access(currentPath, F_OK|R_OK) || isLinked) return self;
- if(etDoc && (tmp = [[etDoc docInfo] docPath])) {
- sprintf(buf,"%s/%s",tmp,componentName);
- if(!access(buf, F_OK|R_OK)) {
- currentPath = NXUniqueString(buf);
- #ifdef DEBUG
- NXLogError("Found %s at %s not %s/%s", componentName,buf,currentPath,componentName);
- #endif
- return self;
- }
- }
- #ifdef DEBUG
- NXLogError("Could not access %s or %s! %s readRichText: failed!",
- currentPath,buf,[[self class] name]);
- #endif
- return nil;
- }
-
- - writeRichText:(NXStream *)stream forView:view
- {
- // since this method is called before any writeComponents, we attempt
- // to precompute the future currentPath
- // RULE: if (isLinked), currentPath is valid
- // RULE: otherwise, componentName is valid, so precompute currentPath
-
- const char *tmp;
- char target[MAXPATHLEN];
- id temp;
-
- temp = [view etDoc];
- if (temp && [temp respondsTo:@selector(registerComponent:)])
- etDoc = temp; // Always reset if possible; bugfix for shared images, 12/23
- if (isLinked)
- tmp = currentPath;
- else {
- sprintf(target, "%s/%s",[[etDoc docInfo] docPath], componentName);
- tmp = target;
- }
- NXPrintf(stream, "%d %c %c %d %s %d %s",
- _eTComponentVERSION, isLinked+'A', shouldEdit+'A',
- strlen(tmp), tmp, strlen(componentName), componentName);
- return self;
- }
-
- - writeASCIIRef:(NXStream *)stream forView:view
- {
- id temp;
-
- temp = [view etDoc];
- if (temp && [temp respondsTo:@selector(registerComponent:)])
- etDoc = temp; // Always reset if possible; bugfix for shared images, 12/23
- NXPrintf(stream, "A %s%s reference to the file %s\n", (isLinked ? "linked " : ""), [[self class] name], (isLinked ? currentPath : componentName));
- return self;
- }
-
- - writeHTML:(NXStream *)stream forView:view
- {return [self writeHTML:stream forView:view andClose:YES];}
- - writeHTML:(NXStream *)stream forView:view andClose:(BOOL)closeIt
- {
- id temp;
-
- temp = [view etDoc];
- if (temp && [temp respondsTo:@selector(registerComponent:)])
- etDoc = temp; // Always reset if possible; bugfix for shared images, 12/23
- //NXPrintf(stream, "<A HREF=\"%V%V\">%v:%v</A>",
- // (isLinked ? "http://localhost/" : ""),
- // (isLinked ? currentPath : componentName),
- // [[self class] name],(isLinked ? currentPath : componentName));
- // In the NEW scheme of things, HTML component data is _ALWAYS_
- // written out explicitly, so none of this localhost shit.
- NXPrintf(stream,"<A HREF=\"%V\">",componentName);
- if (closeIt)
- NXPrintf(stream,"%v</A>",componentName);
- return self;
- }
-
- - writeLaTeX:(NXStream *)stream forView:view
- {return [self writeLaTeX:stream forView:view andClose:YES];}
- - writeLaTeX:(NXStream *)stream forView:view andClose:(BOOL)closeIt
- {
- id temp;
-
- temp = [view etDoc];
- if (temp && [temp respondsTo:@selector(registerComponent:)])
- etDoc = temp; // Always reset if possible; bugfix for shared images, 12/23
- NXPrintf(stream, "\n\\footnote{A %w%w reference to the file %w.", (isLinked ? "linked " : ""), [[self class] name], (isLinked ? currentPath : componentName));
- if (closeIt)
- NXPrintf(stream, "}\n");
- return self;
- }
- @end