home *** CD-ROM | disk | FTP | other *** search
/ Nebula 2 / Nebula Two.iso / Apps / DevTools / eText5 / Source / Component.subproj / eTComponent.m < prev    next >
Encoding:
Text File  |  1995-02-11  |  10.6 KB  |  340 lines

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //    FILENAME:    eTComponent.m
  3. //    SUMMARY:    Implementation of a generic external-data-container class.
  4. //    SUPERCLASS:    Object
  5. //    INTERFACE:    None
  6. //    PROTOCOLS:    <ComponentData,
  7. //                ETFDSupport,ASCIISupport,HTMDSupport, LaTeXSupport>
  8. //    AUTHOR:        Rohit Khare and Tom Zavisca
  9. //    COPYRIGHT:    (c) 1994 California Institure of Technology, eText Project
  10. ///////////////////////////////////////////////////////////////////////////////
  11. //    IMPLEMENTATION COMMENTS
  12. //        This implementation is a hack: it uses system() calls to have files
  13. //    copied. This avoids setting up our own buffer functions and works
  14. //    for directories, too. This also just a default implementation; subclasses
  15. //    will most likely define their own methods.
  16. //
  17. //    The revision of 7/19 introduces a new two-phase lifecycle, 
  18. //    initInDoc:linked: followed by readComponent from path or Pboard.
  19. //    
  20. //    Eventually, there is room for an eTComponentBinder that will uniq' refs.
  21. ///////////////////////////////////////////////////////////////////////////////
  22. //    HISTORY
  23. //    12/23/94:    Patched to reset eTDoc everywhere
  24. //    08/06/94:    Added symbolic linking support.
  25. //    07/19/94:    Rewritten/Reorganized as described in Actors/eTComponent.rtf
  26. //    07/10/94:    Created.
  27. ///////////////////////////////////////////////////////////////////////////////
  28.  
  29. #import "eTComponent.h"
  30.  
  31. #define _eTComponentVERSION    20
  32.  
  33. @implementation eTComponent
  34. //    NXAtom    componentName;
  35. //    NXAtom    currentPath;
  36. //    BOOL    shouldEdit;
  37. //    BOOL    isDirty;
  38. //    BOOl    isLinked;
  39. //    id        etDoc;
  40. //    id        icon;
  41.  
  42. //////////// ACCESSOR METHODS ////////////////
  43. - setComponentName:(const char*)newComponentName
  44.     {componentName = NXUniqueString(newComponentName); return self;}
  45. - (const char *) componentName
  46.     {return componentName;}
  47. - (const char *) currentPath
  48.     {return currentPath;}
  49. - etDoc
  50.     {return etDoc;}
  51. - icon
  52. {
  53.     if (!icon) {
  54.         icon = [[Application workspace] getIconForFile:currentPath];
  55.         if (!icon) icon = [NXImage findImageNamed:"NXdefaulticon"];
  56.     }
  57.     return icon;}
  58. - (BOOL) isLinked
  59.     {return isLinked;}
  60. - (BOOL) isMutable        // this call checks shouldEdit
  61.     {return (shouldEdit && (!isLinked));}
  62. - setShouldEdit:(BOOL) newState
  63.     {shouldEdit = newState; return self;}
  64. - setLinked:(BOOL) newState
  65.     {isLinked = newState; return self;}
  66. - setDoc:newDoc {
  67.     if (newDoc && [newDoc respondsTo:@selector(registerComponent:)])
  68.         etDoc = newDoc; // Always reset if possible; bugfix for shared images, 12/23
  69.     return self;
  70. }
  71. - touch
  72.     {isDirty=YES; return self;}
  73.  
  74. //////////// LIFECYCLE MANAGEMENT ////////////
  75. - init        // default initializer
  76. {
  77.     return [self initInDoc:nil linked:NO];
  78. }
  79.  
  80. - initInDoc:newDoc linked: (BOOL) linked
  81. {
  82.     char tmp[128];
  83.     
  84.     [super init];
  85.     isLinked = linked;
  86.     etDoc = newDoc;
  87.     isDirty = NO;
  88.     shouldEdit = YES;
  89.     icon = nil;
  90.     sprintf(tmp, "Untitled-%d", [NXApp uniqueID]);
  91.     componentName = NXUniqueString(tmp);
  92.     currentPath = NXUniqueString("");
  93.     return self;
  94. }
  95.  
  96. ////////////// READING/WRITING ///////////////
  97. - readComponentFromPath:(const char*)newPath
  98. {
  99.     char *tmp;
  100.  
  101.     // Have we been passed a valid pathname?
  102.     if(!(newPath  && (*newPath))) {
  103.         NXLogError("Severe Error, bad path to readComponentFromPath");
  104.         return nil;
  105.     }
  106.     if (access(newPath, F_OK|R_OK)) {
  107.         NXLogError("%s could not access(%s)", [[self class]name],newPath);
  108.     }
  109.     currentPath = NXUniqueString(newPath);
  110.     tmp = rindex(newPath,'/');
  111.     if (tmp && *(tmp+1))
  112.         componentName = NXUniqueString(tmp+1);
  113.     return self;
  114. }
  115. - writeComponentToPath:(NXAtom)path inFormat:(int) theFormat
  116. {
  117.     char target[MAXPATHLEN];
  118.     char cmd[2*MAXPATHLEN];
  119.     
  120.     switch(theFormat) {
  121.         case ETFD_FMT:
  122.             [etDoc registerComponent:componentName];    // always register
  123.             // if it's linked, just return.
  124.             if (isLinked) break;
  125.             sprintf(target,"%s/%s",path,componentName);
  126.             // see if the diskfile already exists
  127.             if ((!isDirty) && (!access(target, F_OK|R_OK))) break;
  128.             // ok, copy the raw bits.
  129.             if (currentPath && *currentPath && target && *target) {
  130.                 sprintf(cmd,"cp -rp \"%s\" \"%s\"", currentPath, target);
  131.                 system(cmd);
  132.             }
  133.             // since we have saved ETFD, reset the "clean" state
  134.             currentPath = NXUniqueString(target);
  135.             isDirty = NO;
  136.             break;
  137.         case TeXD_FMT: if (isLinked) break;
  138.         case HTMD_FMT:
  139.             // In these formats, we always force copying of the data resource
  140.             [etDoc registerComponent:componentName];    // always register
  141.             sprintf(target,"%s/%s",path,componentName);
  142.             // see if the diskfile already exists
  143.             if ((!isDirty) && (!access(target, F_OK|R_OK))) break;
  144.             if (currentPath && *currentPath && target && *target) {
  145.                 sprintf(cmd,"cp -rp \"%s\" \"%s\"", currentPath, target);
  146.                 system(cmd);
  147.             }
  148.             break;
  149.     }
  150.     return self;
  151. }
  152.  
  153. - linkComponentToPath:(NXAtom)path
  154. {
  155.     char target[MAXPATHLEN];
  156.     char cmd[2*MAXPATHLEN];
  157.  
  158.     [etDoc registerComponent:componentName];    // always register
  159.     sprintf(target,"%s/%s",path,componentName);
  160.     // see if the diskfile already exists
  161.     if (access(target, F_OK|R_OK)){
  162.         if (currentPath && *currentPath && target && *target) {
  163.             sprintf(cmd,"ln -s \"%s\" \"%s\"", currentPath, target);
  164.             system(cmd);
  165.         }
  166.     }
  167.     return self;
  168. }
  169. - readComponentFromPboard:(Pasteboard *)thePboard
  170. {
  171.     NXAtom foundType;
  172.     NXAtom supportedTypes[2] = {NXFilenamePboardType,
  173.                                 NXFileContentsPboardType};
  174.  
  175.     foundType = [thePboard findAvailableTypeFrom:supportedTypes num:2];
  176.  
  177.     if (foundType == NXFilenamePboardType) {
  178.         // can we derive a resource name? if not, make path the resource name
  179.         char    *path;
  180.         int        len;
  181.  
  182.         [thePboard readType:NXFilenamePboardType data:&path length:&len];
  183.         // we only process _ONE_ filename; this defeats the tab-separation
  184.         if (index(path, '\t')) *index(path, '\t')=0;
  185.         if (rindex(path, '/')) {
  186.             componentName = NXUniqueString(rindex(path,'/')+1);
  187.             currentPath = NXUniqueString(path);
  188.         } else {
  189.             currentPath = componentName = NXUniqueString(path);
  190.         }
  191.         [thePboard deallocatePasteboardData:path length:len];
  192.     } else if (foundType == NXFileContentsPboardType) {
  193.         char *path,tmp[MAXPATHLEN];
  194.         
  195.         sprintf(tmp,"/tmp/eTComponent.in.%x", [NXApp uniqueID]);
  196.         path = [thePboard readFileContentsType:NULL toFile:tmp];
  197.         currentPath = NXUniqueString(path);
  198.         componentName = NXUniqueString(rindex(path,'/')+1);
  199.         free(path);    // readFile... returns a malloc'd actual path
  200.     }
  201.     return self;
  202. }
  203. - writeComponentToPboard:(Pasteboard *)thePboard
  204. {
  205.     // find out where the file is and encode that to the Pboard.
  206.     if (!(*currentPath) || access(currentPath, F_OK)) return nil;
  207.     [thePboard     declareTypes:&NXFilenamePboardType num:1 owner:nil];
  208.     [thePboard     writeType:NXFilenamePboardType 
  209.                 data:currentPath length:strlen(currentPath)];
  210.     return self;
  211. }
  212. - addToPboard:thePboard
  213. {
  214.     if (!(*currentPath) || access(currentPath, F_OK)) return nil;
  215.     [thePboard     addTypes:&NXFilenamePboardType num:1 owner:nil];
  216.     [thePboard     writeType:NXFilenamePboardType 
  217.                 data:currentPath length:strlen(currentPath)];
  218.     return self;
  219. }
  220. ///////// ADDITIONAL FMT PROTOCOL SUPPORT ////////////
  221.  
  222. - readRichText:(NXStream *)stream forView:view
  223. {    
  224.     char     buf[MAXPATHLEN];
  225.     const char *tmp;
  226.     int        i;
  227.     id temp;
  228.     
  229.     temp = [view etDoc];
  230.     if (temp && [temp respondsTo:@selector(registerComponent:)])
  231.         etDoc = temp; // Always reset if possible; bugfix for shared images, 12/23
  232.     NXScanf(stream, "%d ", &i);
  233.     if (i != _eTComponentVERSION) {
  234.         // bad version block.
  235.         NXLogError("eTComponent found unparseable version %d at position %d",
  236.                     i, NXTell(stream));
  237.         return nil;
  238.     }
  239.     NXScanf(stream, "%c %c %d", &isLinked, &shouldEdit, &i); NXGetc(stream); // space-eater
  240.     isLinked -= 'A'; shouldEdit -= 'A';
  241.     if (i) NXRead(stream, buf, i);
  242.     buf[i] = 0;
  243.     currentPath = NXUniqueString(buf);
  244.     
  245.     NXScanf(stream, " %d", &i); NXGetc(stream); // space-eater
  246.     if (i) NXRead(stream, buf, i);
  247.     buf[i] = 0;
  248.     componentName = NXUniqueString(buf);
  249.     
  250.     if(!access(currentPath, F_OK|R_OK) || isLinked) return self;
  251.     if(etDoc && (tmp = [[etDoc docInfo] docPath])) {
  252.         sprintf(buf,"%s/%s",tmp,componentName);
  253.         if(!access(buf, F_OK|R_OK)) {
  254.             currentPath = NXUniqueString(buf);
  255. #ifdef DEBUG
  256.             NXLogError("Found %s at %s not %s/%s", componentName,buf,currentPath,componentName);
  257. #endif
  258.             return self;
  259.         }
  260.     }
  261. #ifdef DEBUG
  262.     NXLogError("Could not access %s or %s! %s readRichText: failed!",
  263.                  currentPath,buf,[[self class] name]);
  264. #endif
  265.     return nil;
  266. }
  267.  
  268. - writeRichText:(NXStream *)stream forView:view
  269. {
  270.     // since this method is called before any writeComponents, we attempt
  271.     // to precompute the future currentPath
  272.     // RULE: if (isLinked), currentPath is valid
  273.     // RULE: otherwise, componentName is valid, so precompute currentPath
  274.     
  275.     const char *tmp;
  276.     char target[MAXPATHLEN];
  277.     id temp;
  278.     
  279.     temp = [view etDoc];
  280.     if (temp && [temp respondsTo:@selector(registerComponent:)])
  281.         etDoc = temp; // Always reset if possible; bugfix for shared images, 12/23
  282.     if (isLinked) 
  283.         tmp = currentPath;
  284.     else {
  285.         sprintf(target, "%s/%s",[[etDoc docInfo] docPath], componentName);
  286.         tmp = target;
  287.     }
  288.     NXPrintf(stream, "%d %c %c %d %s %d %s", 
  289.         _eTComponentVERSION, isLinked+'A', shouldEdit+'A',
  290.         strlen(tmp), tmp, strlen(componentName), componentName);
  291.     return self;
  292. }
  293.  
  294. - writeASCIIRef:(NXStream *)stream forView:view
  295. {
  296.     id temp;
  297.     
  298.     temp = [view etDoc];
  299.     if (temp && [temp respondsTo:@selector(registerComponent:)])
  300.         etDoc = temp; // Always reset if possible; bugfix for shared images, 12/23
  301.     NXPrintf(stream, "A %s%s reference to the file %s\n", (isLinked ? "linked " : ""), [[self class] name], (isLinked ? currentPath : componentName));
  302.     return self;
  303. }
  304.  
  305. - writeHTML:(NXStream *)stream forView:view
  306.     {return [self writeHTML:stream forView:view andClose:YES];}
  307. - writeHTML:(NXStream *)stream forView:view andClose:(BOOL)closeIt
  308. {
  309.     id temp;
  310.     
  311.     temp = [view etDoc];
  312.     if (temp && [temp respondsTo:@selector(registerComponent:)])
  313.         etDoc = temp; // Always reset if possible; bugfix for shared images, 12/23
  314.     //NXPrintf(stream, "<A HREF=\"%V%V\">%v:%v</A>", 
  315.     //        (isLinked ? "http://localhost/" : ""),
  316.     //        (isLinked ? currentPath : componentName), 
  317.     //        [[self class] name],(isLinked ? currentPath : componentName));
  318.     // In the NEW scheme of things, HTML component data is _ALWAYS_
  319.     //    written out explicitly, so none of this localhost shit.
  320.     NXPrintf(stream,"<A HREF=\"%V\">",componentName);
  321.     if (closeIt)
  322.         NXPrintf(stream,"%v</A>",componentName);
  323.     return self;
  324. }
  325.  
  326. - writeLaTeX:(NXStream *)stream forView:view
  327.     {return [self writeLaTeX:stream forView:view andClose:YES];}
  328. - writeLaTeX:(NXStream *)stream forView:view andClose:(BOOL)closeIt
  329. {
  330.     id temp;
  331.     
  332.     temp = [view etDoc];
  333.     if (temp && [temp respondsTo:@selector(registerComponent:)])
  334.         etDoc = temp; // Always reset if possible; bugfix for shared images, 12/23
  335.     NXPrintf(stream, "\n\\footnote{A %w%w reference to the file %w.", (isLinked ? "linked " : ""), [[self class] name], (isLinked ? currentPath : componentName));
  336.     if (closeIt) 
  337.         NXPrintf(stream, "}\n");
  338.     return self;
  339. }
  340. @end