home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / Think Class Libraries / CHyperText 1.2 / CHyperText Folder / CHyperText.cp < prev    next >
Encoding:
Text File  |  1994-11-30  |  16.2 KB  |  617 lines  |  [TEXT/KAHL]

  1. /******************************************************************************
  2.  CHyperText.cp
  3.  
  4.         
  5.     SUPERCLASS = CStyleText
  6.     
  7.     Copyright © 1994 Johns Hopkins University. All rights reserved.
  8.     
  9.     Original Author:     Martin R. Wachter        email:    mrw@welchgate.welch.jhu.edu
  10.     
  11.     Modified:            4/25/94                    by:        mrw            TCL Version:    1.1.3
  12.     Modified:            4/6/94                    by:        mrw            TCL Version:    1.1.3
  13.     Created:            4/4/94                    by:        mrw            TCL Version:    1.1.3
  14.  
  15.     Version change history:
  16.     
  17.     1.2        Fixed another coordinate bug where we track for the hypercursor.
  18.             Stylize and now converts all text to lowercase when munging so 
  19.             that it does not distinguish the difference between upper and 
  20.             lowercase hyperwords.
  21.             
  22.             Fixed problem with hyperwords which appeared at the start or end
  23.             of a TEXT buffer.
  24.             
  25.             Fixed a Stylize bug where two alphabetically listed hyperwords 
  26.             (e.g. 'Big' and 'Big Mouth') were Stylized would cause the first to 
  27.             be a hyperword but not the second word.  Now 'Big Mouth' will be stylized
  28.             correctly and will be the hyperword.  In version 1.0, 'Big' would have
  29.             been the only hyperword.  Cool?
  30.             
  31.             Fixed a nasty Styize bug where only 1 style was supported.  Now multiple
  32.             styles are taken into consideration when Stylizing hyperwords.
  33.             
  34.             Made the gGoper point directly at this instead of using
  35.             BecomeGopher() calls in DoClick().  This eliminates some text insertion
  36.             caret blinking.
  37.             
  38.     1.1        Fixed a bug in the way I handled the hyperCursor.
  39.     
  40.     1.0        Initial release.
  41.     
  42.  ******************************************************************************/
  43.  
  44. #include <CHyperText.h>
  45. #include <Commands.h>
  46. #include <CPaneBorder.h>
  47. #include <CStringArray.h>
  48. #include <ctype.h>
  49.  
  50. #define kBorderAmount    2        //white space between border and text of edit field
  51. #define kHyperCursorID    1028    // resource id for the magnifying glass hypercursor
  52.  
  53. extern CDesktop        *gDesktop;    // access to global CDesktop object
  54. extern CError        *gError;    // access to global error handler
  55. extern long            gSleepTime;    // access to global sleep time
  56. extern CBureaucrat    *gGopher;    // access to global gGopher
  57.  
  58.  
  59.         /***************     CONSTRUCTION/DESTRUCTION METHODS     ***************/
  60.  
  61. /******************************************************************************
  62.  IHyperText
  63.  
  64.      Initialize a CHyperText pane.
  65. ******************************************************************************/
  66.  
  67. void CHyperText::IHyperText(CView *anEnclosure, CBureaucrat *aSupervisor,
  68.                         short aWidth, short aHeight,
  69.                         short aHEncl, short aVEncl,
  70.                         SizingOption aHSizing, SizingOption aVSizing,
  71.                         short aLineWidth, Boolean hasBorder)
  72. {
  73.     CStyleText::IStyleText( anEnclosure, aSupervisor, aWidth, aHeight,
  74.                 aHEncl, aVEncl, aHSizing, aVSizing, aLineWidth);
  75.  
  76.  
  77.     if (hasBorder)
  78.         MakeBorder();
  79.  
  80.     ownsHyperList = FALSE;
  81.  
  82.     IHyperTextX();
  83. }
  84.  
  85. /******************************************************************************
  86.  IViewTemp
  87.  
  88.      Initialize the CHyperText object from a resource template.
  89. ******************************************************************************/
  90.  
  91. void CHyperText::IViewTemp(CView *anEnclosure, CBureaucrat *aSupervisor,
  92.                             Ptr viewData)
  93. {
  94.     tHyperTextTempP data = (tHyperTextTempP) viewData;
  95.     
  96.     CStyleText::IViewTemp( anEnclosure, aSupervisor, viewData);
  97.  
  98.     itsHyperList = NULL;
  99.         
  100.     if (data->TEXT_Res_ID){
  101.         MoveOffScreen();
  102.         SetTextRes(data->TEXT_Res_ID);
  103.         MoveOnScreen();
  104.     }
  105.  
  106.     if (data->STRlist_Res_ID){
  107.         SetListRes(data->STRlist_Res_ID);
  108.     }
  109.     else{
  110.         ownsHyperList = FALSE;
  111.     }
  112.         
  113.     if (data->makeBorder)
  114.         MakeBorder();
  115.  
  116.     IHyperTextX();
  117. }
  118.  
  119. /******************************************************************************
  120.  IHyperTextX
  121.  
  122.      Perform common initialization for CHyperText panes.
  123. ******************************************************************************/
  124.  
  125. void CHyperText::IHyperTextX( void)
  126. {    
  127.     active = FALSE;
  128.     
  129.     // HyperText by default is not editable, not selectable, but is styleable,
  130.     
  131.     clickCmd = cmdNull;
  132.     CopyPString("\p",lastHyperword);
  133.     numFlashes = 3;                                        // 3 flashes is default
  134.     Specify( kNotEditable, kNotSelectable, kStylable);
  135.     SetWantsClicks( TRUE);
  136. //    SetCanBeGopher(TRUE);
  137.  
  138.     hyperCursor = GetCursor( kHyperCursorID);
  139.     FailNILRes( hyperCursor);
  140.     HNoPurge( (Handle) hyperCursor);
  141.  
  142. }
  143.  
  144. /******************************************************************************
  145.  Dispose
  146.  
  147.      Perform cleanup for CHyperText.
  148.      
  149. ******************************************************************************/
  150.  
  151. void CHyperText::Dispose(void)
  152. {
  153.  
  154.     if (ownsHyperList && itsHyperList)
  155.         ForgetObject(itsHyperList);
  156.     
  157.     CEditText:: Dispose();
  158. }
  159.  
  160.  
  161.         /***************     CURSOR TRACKING METHODS     ***************/
  162.     
  163. /******************************************************************************
  164.  AdjustCursor {OVERRIDE}
  165.  
  166.         Mouse is inside an HyperText Pane. If the cursor is over a hyperword,
  167.         change the cursor to the hyperCursor.
  168.  ******************************************************************************/
  169.  
  170. void    CHyperText::AdjustCursor(
  171.     Point        where,                    /* Mouse location in Window coords    */
  172.     RgnHandle    mouseRgn)
  173. {        
  174.     
  175. LongPt    framePtWhere;
  176.  
  177.     WindToFrame(where, &framePtWhere);
  178.     if (CursorOverHyperword(framePtWhere)){
  179.         SetCursor( *hyperCursor);
  180.     }
  181.     else{
  182.         SetCursor(&arrow);
  183.     }
  184.     
  185.     gSleepTime = 0;
  186. }
  187.  
  188. /******************************************************************************
  189.  CursorOverHyperword
  190.  
  191.         Returns TRUE if the cursor is on top of a Hyperword.
  192.         
  193.         where should be in Frame coords because GetCharOffset uses Frame coords.
  194.         
  195.  ******************************************************************************/
  196.  
  197. Boolean    CHyperText::CursorOverHyperword(LongPt where)
  198. {
  199. long         offset;
  200. LongPt        Pt;
  201. TextStyle    theStyle;
  202.  
  203.     offset = GetCharOffset(&where);
  204.     GetCharStyle(offset,&theStyle);
  205.     if (theStyle.tsFace == bold + underline)
  206.         return TRUE;
  207.     else
  208.         return FALSE;
  209. }
  210.  
  211.  
  212.         /***************    DRAWING METHODS        ***************/
  213.  
  214. /******************************************************************************
  215.  MakeBorder
  216.  
  217.      Make a PaneBorder object for the HyperText.
  218. ******************************************************************************/
  219.  
  220. void CHyperText::MakeBorder( void)
  221. {
  222.     Rect    margin;
  223.     CPaneBorder *border;
  224.     
  225.     Prepare();
  226.     border = new( CPaneBorder);
  227.     border->IPaneBorder( kBorderFrame);
  228.     SetRect( &margin, -kBorderAmount, -kBorderAmount, kBorderAmount, kBorderAmount);
  229.     border->SetMargin( &margin);
  230.     SetBorder( border);
  231.  
  232. }    /* CHyperText::MakeBorder */
  233.  
  234. /******************************************************************************
  235.  MoveOffScreen
  236.  
  237.      Moves the object off the screen 1000 pixels to right and bottom of the 
  238.      desktop.
  239. ******************************************************************************/
  240.  
  241. void CHyperText::MoveOffScreen( void)
  242. {
  243. Rect        deskBounds;
  244.     
  245.     oldH = hEncl;
  246.     oldV = vEncl;
  247.     
  248.     gDesktop->GetBounds(&deskBounds);
  249.     Place(deskBounds.right + 1000, deskBounds.bottom + 1000, FALSE);
  250.  
  251. }    /* CHyperText::MoveOffScreen */
  252.  
  253. /******************************************************************************
  254.  MoveOnScreen
  255.  
  256.      Moves the object back on the screen after inserting text while it was
  257.      offscreen.
  258. ******************************************************************************/
  259.  
  260. void CHyperText::MoveOnScreen( void)
  261. {
  262. Rect    r;
  263.  
  264.     Place(oldH, oldV, FALSE);
  265.  
  266. }    /* CHyperText::MoveOnScreen */
  267.  
  268.  
  269.         /***************     COMMAND METHODS     ***************/
  270.         
  271. /******************************************************************************
  272.  DoKeyDown {OVERRIDE}
  273.  
  274.      Handle keypresses in a HyperText object. Keys that have a special meaning
  275.      in a dialog (tab, return, enter, and Escape) are passed to itsSupervisor,
  276.      all other keys are passed through to the superclass.
  277. ******************************************************************************/
  278.  
  279. void CHyperText::DoKeyDown( char theChar, Byte keyCode, EventRecord *macEvent)
  280. {
  281.     Boolean pass = TRUE;
  282.     short    ID;
  283.     
  284.     switch (theChar)
  285.     {
  286.         case '\t':
  287.         case '\r':
  288.         case kEnterKey:
  289.             pass = FALSE;
  290.             break;
  291.             
  292.         case kEscapeOrClear:
  293.             if (keyCode == KeyEscape) pass = FALSE;
  294.             break;                            
  295.     }
  296.     if (pass)
  297.     {
  298.         inherited::DoKeyDown( theChar, keyCode, macEvent);
  299.                     
  300.         if (itsTypingTask)
  301.         {
  302.             ID = this->ID;
  303.             BroadcastChange( hyperTextChanged, &ID);
  304.         }
  305.     }
  306.     else
  307.         itsSupervisor->DoKeyDown( theChar, keyCode, macEvent);    
  308.  
  309. }    /* CHyperText::DoKeyDown */
  310.  
  311. /******************************************************************************
  312.  DoClick {OVERRIDE}
  313.  
  314.         Respond to a click.
  315.  ******************************************************************************/
  316.  
  317. void    CHyperText::DoClick(
  318.     Point        hitPt,                    /* Mouse location in Frame coords    */
  319.     short        modifierKeys,
  320.     long        when)
  321. {
  322. long         offset, left, right, len, ticks;
  323. LongPt        framePt;
  324. TextStyle    theStyle;
  325. Handle        textH;
  326. CBureaucrat    *oldGopher;
  327.  
  328.     framePt.v = hitPt.v;
  329.     framePt.h = hitPt.h;
  330.     
  331.     if ( CursorOverHyperword(framePt)){
  332.         
  333.         len = GetLength();
  334.         
  335.         // search left of the current char offset, and then right
  336.         // to find the whole hyperword
  337.         
  338.         offset = GetCharOffset(&framePt);
  339.         left = right = offset;
  340.         
  341.         GetCharStyle(offset,&theStyle);
  342.         while (theStyle.tsFace == bold + underline && left >= 0)
  343.             GetCharStyle(--left,&theStyle);
  344.         left++;
  345.         if (left == -1)
  346.             left++;
  347.         GetCharStyle(offset,&theStyle);
  348.         while (theStyle.tsFace == bold + underline && right < len)
  349.             GetCharStyle(++right,&theStyle);
  350.         right--;
  351.         
  352.         // save the hyperword for later use in the lastHyperword data member
  353.         textH = GetTextHandle();
  354.         HLockHi(textH);
  355.         lastHyperword[0] = right - left + 1;
  356.         BlockMove(&(*textH )[left],&lastHyperword[1],lastHyperword[0]);
  357.         HUnlock(textH);
  358.         
  359.         // flash the hyperword for the user numFlashes times
  360.         // must flash at least once
  361.         SetSelection(left, right+1, TRUE);
  362.         Activate();
  363.         
  364.         //off
  365.         Delay(4,&ticks);
  366.         SetSelection(0, 0, TRUE);
  367.         Deactivate();
  368.     
  369.         short i;
  370.         
  371.         for (i=0;i<numFlashes-1;i++){
  372.             //on
  373.             Delay(4,&ticks);
  374.             SetSelection(left, right+1, TRUE);
  375.             Activate();
  376.     
  377.             //off
  378.             Delay(4,&ticks);
  379.             SetSelection(0, 0, TRUE);
  380.             Deactivate();
  381.         }
  382.  
  383.         // make this the gopher so whoever handles the clickCmd 
  384.         // can access lastHyperword by typecasting gGopher like this:
  385.         // ((CHyperText*)gGopher)->lastHyperword
  386.         // then restore the previous gopher
  387.         
  388.         oldGopher = gGopher;
  389.         gGopher = this;
  390.         itsSupervisor->DoCommand(clickCmd);
  391.         gGopher = oldGopher;
  392.         
  393.     }
  394. }    
  395.  
  396.  
  397.         /***************     TEXT METHODS     ***************/
  398.  
  399. /******************************************************************************
  400.  SetTextRes
  401.  
  402.      Sets the text and style for a CHyperText pane froma 'TEXT' an 'styl' 
  403.      resources.
  404. ******************************************************************************/
  405.  
  406. void CHyperText::SetTextRes(short resourceID)
  407. {
  408. Handle            myTextH = NULL;
  409. StScrpHandle     theStyles = NULL;
  410. Size            length;
  411.  
  412.     
  413. // get the styl resource
  414.     theStyles = (StScrpHandle) GetResource( 'styl', resourceID);
  415.     FailNILRes(theStyles);
  416.     HLockHi((Handle)theStyles);
  417.     
  418. // get the TEXT resource
  419.     myTextH = GetResource( 'TEXT', resourceID );
  420.     HLockHi( myTextH );            /* so data won't move */
  421.     
  422. //    remove any old text
  423.     SetSelection(0,MAXINT, FALSE);
  424.     TEDelete(macTE);
  425.     
  426. //    insert new text into the pane
  427.     length = GetHandleSize (myTextH);
  428.     TESetText(*myTextH, length, macTE);
  429.  
  430. //    set the styles
  431.     SetStyleScrap( 0, length, theStyles, FALSE);
  432.     HUnlock( (Handle)theStyles );
  433.     ReleaseResource((Handle) theStyles);
  434.  
  435. //    stylize any hyperwords if we have a HyperList
  436.     if (itsHyperList)
  437.         Stylize();
  438.  
  439. //    get the new style information
  440.     SetSelection(0,MAXINT, FALSE);
  441.     theStyles = GetStyleScrap();
  442.     HLockHi((Handle)theStyles);
  443.  
  444. //    remove the text so we can insert it with InsertWithStyles        
  445.     TEDelete(macTE);
  446.  
  447. //    insert the hyper-styled text
  448.     InsertWithStyles( *myTextH, length, theStyles);
  449.     
  450.     HUnlock( (Handle)theStyles );
  451.     DisposeHandle((Handle) theStyles);
  452.  
  453.     HUnlock( myTextH );
  454.     ReleaseResource(myTextH);
  455.     
  456. }
  457.  
  458. /******************************************************************************
  459.  Stylize
  460.  
  461.      This routine creates the visual representation of the hypertext "hot" 
  462.      words by searching its text and stylizing any word which is found in 
  463.      itsHyperList.
  464. ******************************************************************************/
  465.  
  466. void CHyperText::Stylize(void)
  467. {
  468. short            i,j=0,k;
  469. long             lOffset, offset, findLen, buffLen, numHyperWords, numStyles;
  470. Handle            destStrH, textBuf;
  471. Str255            findStr;
  472. StScrpHandle     theStyles = NULL;
  473.  
  474.     numHyperWords = itsHyperList->GetNumItems();                    // get number of strings to search for
  475.     destStrH = GetTextHandle();                                        // get the text
  476.     buffLen = GetLength();                                            // get the text length
  477.  
  478.     textBuf = destStrH;
  479.         
  480.     if (gError->CheckOSError(HandToHand(&textBuf))){
  481.         HLockHi(textBuf);    
  482.         
  483.         // make the textBuf all lowercase characters
  484.         for (j=0;j<buffLen;j++){
  485.             (*textBuf)[j] = tolower((*textBuf)[j]);
  486.         }
  487.         
  488.         // loop through each string in the HyperList and Munger a lowercase copy
  489.         // of our text.  Any matches are stylized in bold+underline to show that
  490.         // it is "hot".
  491.         
  492.         for (i = 1;i<= numHyperWords;i++){
  493.             itsHyperList->GetItem( findStr, i);
  494.             findLen = findStr[0];
  495.             PtoCstr((unsigned char*)findStr);
  496.             
  497.             // make the findStr all lowercase characters
  498.             for (j=0;j<findLen;j++){
  499.                 (findStr)[j] = tolower((findStr)[j]);
  500.             }
  501.             
  502.             offset = 0;
  503.             lOffset = 1;
  504.             while (lOffset && offset < buffLen){
  505.                 lOffset = Munger(textBuf,offset,findStr,findLen,NULL,0);//search for the findStr
  506.                 if (lOffset >= 0){
  507.                     if ((((*textBuf)[lOffset-1] < 'A') || lOffset == 0)    //ignore punctuation
  508.                         && ((*textBuf)[lOffset+findLen] < 'A')){
  509.                         
  510.                         SetSelection(lOffset, lOffset+findLen,FALSE);    // set the selection range
  511.                         theStyles = GetStyleScrap();                    // get the current styles for the selection
  512.                         HLockHi((Handle)theStyles);    
  513.                         numStyles = (**theStyles).scrpNStyles;            // get the number of styles
  514.                         
  515.                         for (k=0;k<numStyles;k++){
  516.                             (((**theStyles).scrpStyleTab)[k]).scrpFace = normal;        // make it normal
  517.                             SetStyleScrap( lOffset, lOffset+findLen, theStyles, FALSE);
  518.                             (((**theStyles).scrpStyleTab)[k]).scrpFace = bold+underline;// make it bold underline
  519.                             SetStyleScrap( lOffset, lOffset+findLen, theStyles, FALSE);
  520.                         }
  521.                         
  522.                         SetSelection(0, 0,FALSE);                                        // select nothing
  523.                         HUnlock((Handle)theStyles);
  524.                         DisposeHandle((Handle) theStyles);
  525.                         
  526.                     }
  527.                     offset = lOffset + findLen;                            // check the rest of the text
  528.                 }
  529.                 else{
  530.                     offset = buffLen;
  531.                 }
  532.             }
  533.         }
  534.  
  535.         HUnlock(textBuf);    
  536.         DisposeHandle(textBuf);    
  537.     }
  538. }
  539.  
  540.  
  541.         /***************     CLICK COMMAND METHODS     ***************/
  542.  
  543. /******************************************************************************
  544.  SetFlashes
  545.  
  546.         Specify the number of times to flash the clicked hyperword.
  547.  ******************************************************************************/
  548.  
  549. void    CHyperText::SetFlashes(short aFlashTimes)
  550. {
  551.     numFlashes = aFlashTimes;                /* Set instance variable            */
  552. }
  553.  
  554. /******************************************************************************
  555.  SetClickCmd
  556.  
  557.         Specify the command which is sent to a HyperText's supervisor
  558.         after a confirmed click
  559.  ******************************************************************************/
  560.  
  561. void    CHyperText::SetClickCmd(long aClickCmd)
  562. {
  563.     clickCmd = aClickCmd;                /* Set instance variable            */
  564. }
  565.  
  566. /******************************************************************************
  567.  GetClickCmd
  568.  
  569.      Return the command which is sent to a HyperText's supervisor after a
  570.      confirmed click
  571. ******************************************************************************/
  572. long CHyperText::GetClickCmd( void)
  573. {
  574.     return clickCmd;
  575. }
  576.  
  577.  
  578.         /***************     HYPERLIST METHODS     ***************/
  579.         
  580. /******************************************************************************
  581.  SetListRes
  582.  
  583.      Sets from a STR# resource.
  584. ******************************************************************************/
  585.  
  586. void CHyperText::SetListRes(short resourceID)
  587. {
  588.  
  589.     itsHyperList =  new CStringArray;
  590.     itsHyperList->IRes(resourceID, 255);
  591.     ownsHyperList = TRUE;
  592.     if (GetLength()){
  593.         Stylize();
  594.     }
  595. }
  596.  
  597. /******************************************************************************
  598.  SetList
  599.  
  600.      Sets itsHyperList to use an existing CStringArray.
  601. ******************************************************************************/
  602.  
  603. void CHyperText::SetList(CStringArray *aStrList)
  604. {
  605.     itsHyperList = aStrList;
  606. }
  607.  
  608. /******************************************************************************
  609.  GetList
  610.  
  611.      Returns itsHyperList CStringArray.
  612. ******************************************************************************/
  613.  
  614. CStringArray *CHyperText::GetList(void)
  615. {
  616.     return itsHyperList;
  617. }