home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1994 June / NEBULA_SE.ISO / SourceCode / Palettes / MORegex / MORegexTextCellInspector.m < prev    next >
Encoding:
Text File  |  1993-10-02  |  12.1 KB  |  449 lines

  1. // MORegexTextCellInspector.m
  2. //
  3. // by Mike Ferris
  4. // Part of MOKit - MORegexPalette
  5. // Copyright 1993, all rights reserved.
  6.  
  7. #import "MORegexTextCellInspector.h"
  8. #import "MOKit/MORegexTextCell.h"
  9. #import "MOKit/MOString.h"
  10. #import <objc/objc-runtime.h>
  11.  
  12. #define CLASS_VERSION    0
  13.  
  14. #define ADD_TAG            0
  15. #define CHANGE_TAG        1
  16. #define REMOVE_TAG        2
  17.  
  18. #define BG_NONE_TAG        0
  19. #define BG_BLACK_TAG    1
  20. #define BG_DKGRAY_TAG    2
  21. #define BG_LTGRAY_TAG    3
  22. #define BG_WHITE_TAG    4
  23.  
  24. #define TG_BLACK_TAG    0
  25. #define TG_DKGRAY_TAG    1
  26. #define TG_LTGRAY_TAG    2
  27. #define TG_WHITE_TAG    3
  28.  
  29. #define ALIGN_LEFT_TAG        0
  30. #define ALIGN_CENTER_TAG    1
  31. #define ALIGN_RIGHT_TAG        2
  32.  
  33. #define BORDER_NONE_TAG        0
  34. #define BORDER_LINE_TAG        1
  35. #define BORDER_BEZEL_TAG    2
  36.  
  37. #define EDITABLE_CB_TAG        0
  38. #define SELECTABLE_CB_TAG    1
  39. #define SCROLLABLE_CB_TAG    2
  40.  
  41. #define BUNDLE_TYPE                            "bundle"
  42. #define MOREGEXTEXTCELL_CLASS_NAME            "MORegexTextCell"
  43.  
  44. #define NIB_TYPE                            "nib"
  45. #define NIB_NAME                            "MORegexTextCellInspector"
  46.  
  47. @implementation MORegexTextCellInspector
  48.  
  49. static id MORegexTextCellClass;
  50.  
  51. + MO_loadClassBundle:(const char *)className
  52. // Finds the bundle of the same name as the class, grabs it and loads the
  53. // class from it.
  54. {
  55.     char pathBuff[MAXPATHLEN+1];
  56.     
  57.     // Load the bundle
  58.     if (objc_lookUpClass(className) == nil)  {
  59.         // class is not already loaded... load it.
  60.         id classBundle;
  61.         
  62.         // Look for the bundle in the main bundle first, 
  63.         // else try in this classes bundle.
  64.         if (![[NXBundle mainBundle] getPath:pathBuff forResource:className 
  65.                     ofType:BUNDLE_TYPE])  {
  66.             if (![[NXBundle bundleForClass:[self class]] getPath:pathBuff 
  67.                         forResource:className ofType:BUNDLE_TYPE])  {
  68.                 NXLogError("[MORegexPalette loadClassBundle] failed to "
  69.                         "find %s class bundle.", className);
  70.                 return nil;
  71.             }
  72.         }
  73.         classBundle = [[NXBundle allocFromZone:[self zone]] 
  74.                     initForDirectory:pathBuff];
  75.         if (!classBundle)  {
  76.             NXLogError("[MORegexPalette loadClassBundle] failed to "
  77.                         "create bundle for class %s.", className);
  78.             return nil;
  79.         }
  80.         if (![classBundle classNamed:className])  {
  81.             NXLogError("[MORegexPalette loadClassBundle] failed to "
  82.                         "load %s class from bundle.", className);
  83.             return nil;
  84.         }
  85.     }
  86.     
  87.     return self;
  88. }
  89.  
  90. + initialize
  91. // Set the version.
  92. {
  93.     if (self == [MORegexTextCellInspector class])  {
  94.         [self setVersion:CLASS_VERSION];
  95.  
  96.         // Load the MORegexTextCell class if necessary
  97.         if ((MORegexTextCellClass = 
  98.                     objc_lookUpClass(MOREGEXTEXTCELL_CLASS_NAME)) == nil)  {
  99.             [self MO_loadClassBundle:MOREGEXTEXTCELL_CLASS_NAME];
  100.             MORegexTextCellClass = 
  101.                         objc_lookUpClass(MOREGEXTEXTCELL_CLASS_NAME);
  102.             if (!MORegexTextCellClass)  {
  103.                 NXLogError("[MORegexTextCell initialize]: failed to find "
  104.                             "MORegexTextCell class.");
  105.             }
  106.         }
  107.     }
  108.     return self;
  109. }
  110.  
  111. - init
  112. // Load our nib file.
  113. {
  114.     char buf[MAXPATHLEN+1];
  115.     id bundle;
  116.     
  117.     [super init];
  118.     
  119.     // load our nib file.
  120.     bundle = [NXBundle bundleForClass:[MORegexTextCellInspector class]];
  121.     [bundle getPath:buf forResource:NIB_NAME ofType:NIB_TYPE];
  122.     [NXApp loadNibFile:buf owner:self withNames:NO fromZone:[self zone]];
  123.     
  124.     [patternText setDelegate:self];
  125.     [patternText setCharFilter:NXFieldFilter];
  126.     [patternText setFont:[Font userFixedPitchFontOfSize:0 
  127.                 matrix:NX_FLIPPEDMATRIX]];
  128.     
  129.     return self;
  130. }
  131.  
  132. - (int)browserSelectedRow
  133. // Return the row that is selected in the patternBrowser or -1 if none is.
  134. {
  135.     return [[patternBrowser matrixInColumn:0] selectedRow];
  136. }
  137.  
  138. - (const char *)getPatternText
  139. {
  140.     static char *text=NULL;
  141.     
  142.     if (text) NX_FREE(text);
  143.     NX_MALLOC(text, char, [patternText byteLength]+1);
  144.     [patternText getSubstring:text start:0 length:[patternText textLength]+1];
  145.     return text;
  146. }
  147.  
  148. - enablePatternButtons
  149. // Enables or disables the add, change, remove buttons as appropriate for
  150. // the current state of the inspector.
  151. {
  152.     if ([self browserSelectedRow] == -1)  {
  153.         [[patternButtonMatrix cellAt:0 :CHANGE_TAG] setEnabled:NO];
  154.         [[patternButtonMatrix cellAt:0 :REMOVE_TAG] setEnabled:NO];
  155.     }  else  {
  156.         [[patternButtonMatrix cellAt:0 :CHANGE_TAG] setEnabled:YES];
  157.         [[patternButtonMatrix cellAt:0 :REMOVE_TAG] setEnabled:YES];
  158.     }
  159.     
  160.     if (strlen([self getPatternText])>0)  {
  161.         [[patternButtonMatrix cellAt:0 :ADD_TAG] setEnabled:YES];
  162.     }  else  {
  163.         [[patternButtonMatrix cellAt:0 :ADD_TAG] setEnabled:NO];
  164.         [[patternButtonMatrix cellAt:0 :CHANGE_TAG] setEnabled:NO];
  165.     }
  166.     return self;
  167. }
  168.  
  169. - browserAction:sender
  170. // Copies the string of the currently selected pattern to the pattern text
  171. // field for editing.
  172. {
  173.     int row = [self browserSelectedRow];
  174.     
  175.     // put the text of the selected row's pattern in the patternField.
  176.     if (row >= 0)  {
  177.         [patternText setText:[object regexStrAt:row]];
  178.     }  else  {
  179.         [patternText setText:""];
  180.     }
  181.     [patternText sizeToFit];
  182.     [patternText setSel:0 :[patternText textLength]];
  183.     [self enablePatternButtons];
  184.     return self;
  185. }
  186.  
  187. - patternButtonAction:sender
  188. // Adds the text of patternField to the cell's patterns, or changes the pattern
  189. // currently selected in the patternBrowser to the text in patternField, or 
  190. // removes the pattern in the selected row of the patternBrowser from the
  191. // cell's patterns.
  192. {
  193.     int tag = [[sender selectedCell] tag];
  194.     const char *pattern = [self getPatternText];
  195.     char *pcpy;
  196.     int row = [self browserSelectedRow];
  197.     id matrix = [patternBrowser matrixInColumn:0];
  198.     
  199.     NX_MALLOC(pcpy, char, strlen(pattern)+1);
  200.     strcpy(pcpy, pattern);
  201.     
  202.     if (tag==ADD_TAG)  {
  203.         // add the string in patternField to the object's patterns.
  204.         if (![MORegexTextCellClass isValidRegex:pattern])  {
  205.             NXRunAlertPanel("Regexp Error", "'%s' is not a valid regular "
  206.                         "expression.", "OK", NULL, NULL, pattern);
  207.             NX_FREE(pcpy);
  208.             return self;
  209.         }
  210.         [object addRegexStr:pattern];
  211.     }  else if (tag==CHANGE_TAG)  {
  212.         // change the pattern at the index of the selected row in the 
  213.         // browser to the string in patternField.
  214.         id string = [[object regexStrList] objectAt:row];
  215.         if (![MORegexTextCellClass isValidRegex:pattern])  {
  216.             NXRunAlertPanel("Regexp Error", "'%s' is not a valid regular "
  217.                         "expression.", "OK", NULL, NULL, pattern);
  218.             NX_FREE(pcpy);
  219.             return self;
  220.         }
  221.         [string setStringValue:pattern];
  222.     }  else if (tag==REMOVE_TAG)  {
  223.         // remove the pattern at the index of the selected row in the browser.
  224.         [object removeRegexStrAt:row];
  225.         NX_FREE(pcpy);
  226.         pcpy = NULL;
  227.         pattern = [[matrix cellAt:((row==0)?1:row-1) :0] stringValue];
  228.         if (pattern)  {
  229.             NX_MALLOC(pcpy, char, strlen(pattern)+1);
  230.             strcpy(pcpy, pattern);
  231.         }
  232.     }
  233.     [patternBrowser reloadColumn:0];
  234.     if (pcpy)  {
  235.         char *buff;
  236.         NX_MALLOC(buff, char, strlen(pcpy)+2);
  237.         sprintf(buff, "/%s", pcpy);
  238.         [patternBrowser setPath:buff];
  239.         NX_FREE(buff);
  240.     }
  241.     NX_FREE(pcpy);
  242.     [self browserAction:patternBrowser];
  243.     
  244.     [self enablePatternButtons];
  245.     [self touch:self];
  246.     
  247.     return self;
  248. }
  249.  
  250. - optionsCheckboxAction:sender
  251. {
  252.     id selCell = [sender selectedCell];
  253.     int selTag = [selCell tag];
  254.     
  255.     if (selTag == EDITABLE_CB_TAG)  {
  256.         id selectableCB = [optionsCheckboxMatrix cellAt:SELECTABLE_CB_TAG:0];
  257.         if ([selCell state])  {
  258.             [selectableCB setState:YES];
  259.             [selectableCB setEnabled:NO];
  260.         }  else  {
  261.             [selectableCB setEnabled:YES];
  262.         }
  263.     }
  264.     [optionsCheckboxMatrix display];
  265.     if ([[optionsCheckboxMatrix cellAt:EDITABLE_CB_TAG:0] state])  {
  266.         [object setEditable:YES];
  267.     }  else  {
  268.         [object setEditable:NO];
  269.         if ([[optionsCheckboxMatrix cellAt:SELECTABLE_CB_TAG:0] state])  {
  270.             [object setSelectable:YES];
  271.         }  else  {
  272.             [object setSelectable:NO];
  273.         }
  274.     }
  275.     [object setScrollable:[[optionsCheckboxMatrix 
  276.                 cellAt:0:SCROLLABLE_CB_TAG] state]];
  277.     return self;
  278. }
  279.  
  280. - ok:sender
  281. // set the text field-ish stuff and the allowEmptyString attribute.  
  282. // The patternButtonAction takes care of the regex stuff.  The 
  283. // optionCheckboxAction takes care of editable, selectable, scrollable.
  284. {
  285.     int bgTag = [backgroundGrayMatrix selectedTag];
  286.     int tgTag = [textGrayMatrix selectedTag];
  287.     int alTag = [alignmentMatrix selectedTag];
  288.     int boTag = [borderMatrix selectedTag];
  289.     
  290.     if (bgTag == BG_NONE_TAG)  {
  291.         [object setBackgroundGray:-1.0];
  292.     }  else if (bgTag == BG_BLACK_TAG)  {
  293.         [object setBackgroundGray:NX_BLACK];
  294.     }  else if (bgTag == BG_DKGRAY_TAG)  {
  295.         [object setBackgroundGray:NX_DKGRAY];
  296.     }  else if (bgTag == BG_LTGRAY_TAG)  {
  297.         [object setBackgroundGray:NX_LTGRAY];
  298.     }  else  {
  299.         [object setBackgroundGray:NX_WHITE];
  300.     }
  301.     if (tgTag == TG_BLACK_TAG)  {
  302.         [object setTextGray:NX_BLACK];
  303.     }  else if (tgTag == TG_DKGRAY_TAG)  {
  304.         [object setTextGray:NX_DKGRAY];
  305.     }  else if (tgTag == TG_LTGRAY_TAG)  {
  306.         [object setTextGray:NX_LTGRAY];
  307.     }  else  {
  308.         [object setTextGray:NX_WHITE];
  309.     }
  310.     if (alTag == ALIGN_LEFT_TAG)  {
  311.         [object setAlignment:NX_LEFTALIGNED];
  312.     }  else if (alTag == ALIGN_CENTER_TAG)  {
  313.         [object setAlignment:NX_CENTERED];
  314.     }  else  {
  315.         [object setAlignment:NX_RIGHTALIGNED];
  316.     }
  317.     if (boTag == BORDER_NONE_TAG)  {
  318.         [object setBordered:NO];
  319.         [object setBezeled:NO];
  320.     }  else if (boTag == BORDER_LINE_TAG)  {
  321.         [object setBordered:YES];
  322.     }  else  {
  323.         [object setBezeled:YES];
  324.     }
  325.  
  326.     [object setTag:[tagForm intValueAt:0]];
  327.     [object setAllowEmptyString:[allowEmptyStringButton state]];
  328.     return [super ok:sender];
  329. }
  330.  
  331. - revert:sender
  332. // fill in the inspector with the attributes of "object"
  333. {
  334.     id matrix;
  335.     
  336.     float bg = [object backgroundGray], tg = [object textGray];
  337.     int alignment = [object alignment];
  338.     BOOL isBordered = [object isBordered], isBezeled = [object isBezeled];
  339.     
  340.     if (bg < 0)  {
  341.         [backgroundGrayMatrix selectCellAt:0:BG_NONE_TAG];
  342.     }  else  if ((bg >= 0) && (bg < .2))  {
  343.         [backgroundGrayMatrix selectCellAt:0:BG_BLACK_TAG];
  344.     }  else  if ((bg >= .2) && (bg < .45))  {
  345.         [backgroundGrayMatrix selectCellAt:0:BG_DKGRAY_TAG];
  346.     }  else  if ((bg >= .45) && (bg < .8))  {
  347.         [backgroundGrayMatrix selectCellAt:0:BG_LTGRAY_TAG];
  348.     }  else  if (bg >= .8)  {
  349.         [backgroundGrayMatrix selectCellAt:0:BG_WHITE_TAG];
  350.     }
  351.     [backgroundGrayMatrix display];
  352.     if (tg < .2)  {
  353.         [textGrayMatrix selectCellAt:0:TG_BLACK_TAG];
  354.     }  else  if ((tg >= .2) && (tg < .45))  {
  355.         [textGrayMatrix selectCellAt:0:TG_DKGRAY_TAG];
  356.     }  else  if ((tg >= .45) && (tg < .8))  {
  357.         [textGrayMatrix selectCellAt:0:TG_LTGRAY_TAG];
  358.     }  else  if (tg >= .8)  {
  359.         [textGrayMatrix selectCellAt:0:TG_WHITE_TAG];
  360.     }
  361.     [textGrayMatrix display];
  362.     if (alignment == NX_LEFTALIGNED)  {
  363.         [alignmentMatrix selectCellAt:0:ALIGN_LEFT_TAG];
  364.     }  else if (alignment == NX_CENTERED)  {
  365.         [alignmentMatrix selectCellAt:0:ALIGN_CENTER_TAG];
  366.     }  else  {
  367.         [alignmentMatrix selectCellAt:0:ALIGN_RIGHT_TAG];
  368.     }
  369.     [alignmentMatrix display];
  370.     if (isBezeled)  {
  371.         [borderMatrix selectCellAt:0:BORDER_BEZEL_TAG];
  372.     }  else if (isBordered)  {
  373.         [borderMatrix selectCellAt:0:BORDER_LINE_TAG];
  374.     }  else  {
  375.         [borderMatrix selectCellAt:0:BORDER_NONE_TAG];
  376.     }
  377.     [optionsCheckboxMatrix setState:[object isEditable] 
  378.                 at:EDITABLE_CB_TAG:0];
  379.     [optionsCheckboxMatrix setState:[object isSelectable] 
  380.                 at:SELECTABLE_CB_TAG:0];
  381.     [optionsCheckboxMatrix setState:[object isScrollable] 
  382.                 at:SCROLLABLE_CB_TAG:0];
  383.  
  384.     [allowEmptyStringButton setState:[object doesAllowEmptyString]];
  385.     [tagForm setIntValue:[object tag] at:0];
  386.     
  387.     // browser
  388.     [patternBrowser loadColumnZero];
  389.     
  390.     matrix = [patternBrowser matrixInColumn:0];
  391.     if ([matrix cellCount] > 0)  {
  392.         const char *pattern = [[matrix cellAt:0:0] stringValue];
  393.         char *buff;
  394.         NX_MALLOC(buff, char, strlen(pattern)+2);
  395.         sprintf(buff, "/%s", pattern);
  396.         [patternBrowser setPath:buff];
  397.         NX_FREE(buff);
  398.     }
  399.     [self browserAction:patternBrowser];
  400.     
  401.     [self enablePatternButtons];
  402.     [patternButtonMatrix display];
  403.     
  404.     return [super revert:sender];
  405. }
  406.  
  407. - (BOOL)wantsButtons
  408. // Our inspector does not have OK or Revert buttons.
  409. {
  410.     return NO;
  411. }
  412.  
  413. - (int)browser:sender fillMatrix:matrix inColumn:(int)column
  414. // Fill the browser with the pattern strings from the cell.
  415. {
  416.     int i, c = [object regexStrCount];
  417.     
  418.     for (i=0; i<c; i++)  {
  419.         [matrix renewRows:i+1 cols:1];
  420.         [[matrix cellAt:i :0] setStringValue:[object regexStrAt:i]];
  421.         [[matrix cellAt:i :0] setLoaded:YES];
  422.         [[matrix cellAt:i :0] setLeaf:YES];
  423.     }
  424.     
  425.     return i;
  426. }
  427.  
  428. - textDidGetKeys:sender isEmpty:(BOOL)flag
  429. // Having text in the patternField affects what buttons to enable.
  430. {
  431.     if (sender==patternText)  {
  432.         [self enablePatternButtons];
  433.         [patternButtonMatrix display];
  434.     }
  435.     return self;
  436. }
  437.  
  438. - textDidChange:sender;
  439. // The patternField shouldn't be passed on.
  440. {
  441.     if (sender==patternText)  {
  442.         return self;
  443.     }  else  {
  444.         return [super textDidChange:sender];
  445.     }
  446. }
  447.  
  448. @end
  449.