home *** CD-ROM | disk | FTP | other *** search
/ ...taking it to the Macs! / ...taking it to the Macs!.iso / Extras / ActiveX Mac SDK / ActiveX SDK / Sample Controls / TextEdit / CTextEditControl.cpp < prev    next >
Encoding:
Text File  |  1996-12-17  |  25.7 KB  |  891 lines  |  [TEXT/CWIE]

  1. // =================================================================================
  2. //
  3. //    CTextEditControl.cpp                ©1996 Microsoft Corporation All rights reserved.
  4. //
  5. // =================================================================================
  6.  
  7. #include <LArray.h>
  8. #include "ocheaders.h"
  9. #include <PlatformControlGuid.h>
  10. #include "CTextEditControl.h"
  11. #include "CTextEditBSC.h"
  12.  
  13. const    Int32    TEIdleTickCount        = 5;
  14. const    Uint32    TEIdleRefCon        = 0;
  15. const    Int32    QueryTickCount        = 60;
  16. const    Uint32    QueryRefCon            = 1;
  17.  
  18. #pragma mark === CTextEditControl Construction & Destruction ===
  19.  
  20. //=--------------------------------------------------------------------------=
  21. //    CTextEditControl::CTextEditControl
  22. //=--------------------------------------------------------------------------=
  23.  
  24. CTextEditControl::CTextEditControl(void) : CBaseControl()
  25. {
  26.     mOwnedFoci = EmptyFocusSet;
  27.  
  28.     mScrollBarInfo.ConnectionPoint = NULL;
  29.     mPostButtonInfo.ConnectionPoint = NULL;
  30.     mScrollBarInfo.Unknown = NULL;
  31.     mPostButtonInfo.Unknown = NULL;
  32.     *(mScrollBarInfo.Name) = 0;
  33.     *(mPostButtonInfo.Name) = 0;
  34.     
  35.     *mID = 0;
  36.     mNewText = NULL;
  37.     mScrollLines = 0;
  38.     mOldScrollPosition = 0;
  39.  
  40.     mFont = 1;
  41.     mSize = 10;
  42.     mFace = 0;
  43. }
  44.  
  45. //=--------------------------------------------------------------------------=
  46. //    CTextEditControl::~CTextEditControl
  47. //=--------------------------------------------------------------------------=
  48.  
  49. CTextEditControl::~CTextEditControl()
  50. {
  51.     ReleaseAllPlatformControls();
  52. }
  53.  
  54.  
  55. #pragma mark === CButtonControl::IUnknown methods ===
  56.  
  57. //=--------------------------------------------------------------------------=
  58. //    CTextEditControl::IUnknown::QueryInterface::
  59. //=--------------------------------------------------------------------------=
  60.  
  61. STDMETHODIMP
  62. CTextEditControl::QueryInterface(REFIID inRefID, void** outObj)
  63. {
  64.     if ( inRefID == IID_IPlatformControlListener )
  65.     {
  66.         *outObj = (void*) (IPlatformControlListener*) this;
  67.         AddRef();
  68.         
  69.         return S_OK;
  70.     }
  71.     else
  72.         return CBaseControl::QueryInterface(inRefID, outObj);
  73. }
  74.  
  75.  
  76. #pragma mark === CTextEditControl::IControl ===
  77.  
  78. //=--------------------------------------------------------------------------=
  79. //  CTextEditControl::IControl::Draw
  80. //=--------------------------------------------------------------------------=
  81.  
  82. STDMETHODIMP
  83. CTextEditControl::Draw( DrawContext* inContext)
  84. {
  85.     CTextEditContextInfo*    TEInfo;
  86.     Rect                    drawRect;
  87.     
  88.     if (inContext->DrawAspect != DVASPECT_CONTENT)
  89.         return DV_E_DVASPECT;
  90.  
  91.     drawRect = inContext->Location;
  92.  
  93.     // Erase and frame the drawing area
  94.     ::EraseRect(&drawRect);
  95.     ::FrameRect(&drawRect);
  96.     ::InsetRect(&drawRect, 2, 2);
  97.  
  98.     if ((TEInfo = (CTextEditContextInfo*)GetContextInfoByID(inContext->ContextID)) != NULL)
  99.         ::TEUpdate(&drawRect, TEInfo->GetTEHandle());
  100. #if BE_STRICT
  101.     else
  102.         DebugStr("\pTextEditControl draw - can't get context info!");
  103. #endif    //    BE_STRICT
  104.  
  105.     return S_OK;
  106. }
  107.  
  108.  
  109. //=--------------------------------------------------------------------------=
  110. //  CTextEditControl::IControl::Draw
  111. //=--------------------------------------------------------------------------=
  112.  
  113. STDMETHODIMP
  114. CTextEditControl::OnContextChange(UInt32 inContextID, ContextCommand inCommand)
  115. {
  116.     ErrorCode    Result;
  117.     Int32        InCount = mContextInfo->GetCount();
  118.     Int32        OutCount;
  119.  
  120.     Result = CBaseControl::OnContextChange(inContextID, inCommand);
  121.  
  122.     OutCount = mContextInfo->GetCount();
  123.  
  124.     //    changing from no to some draw contexts is a good time to re-attach controls
  125.     if (!InCount && OutCount)
  126.         BeginAttachPlatformControls();
  127.     //    and going from some to no draw contexts is a good time to release
  128.     else if (InCount && !OutCount)
  129.         ReleaseAllPlatformControls();
  130.  
  131.     return Result;
  132. }
  133.  
  134.  
  135. //=--------------------------------------------------------------------------=
  136. //    CTextEditControl::IControl::GetID
  137. //=--------------------------------------------------------------------------=
  138.  
  139. STDMETHODIMP
  140. CTextEditControl::GetID(Int32 inBufferSize, Char8* outID)
  141. {
  142.     if (*mID)
  143.     {
  144.         if (*mID < inBufferSize)
  145.             inBufferSize = *mID;
  146.         ::BlockMove(mID + 1, outID, inBufferSize);
  147.         *(outID + inBufferSize) = 0;
  148.     }
  149.     else
  150.         return CBaseControl::GetID(inBufferSize, outID);
  151.  
  152.     return S_OK;
  153. }
  154.  
  155.  
  156. //=--------------------------------------------------------------------------=
  157. //  CTextEditControl::IControl::DoMouse    
  158. //=--------------------------------------------------------------------------=
  159.  
  160. STDMETHODIMP
  161. CTextEditControl::DoMouse(MouseEventType inMouseET, PlatformEvent* inEvent)
  162. {
  163.     Boolean8    NewlyFocused = false;
  164.     ErrorCode    ReturnValue = S_OK;
  165.  
  166.     if (inMouseET == MouseDown)
  167.     {
  168.         //    if we don't have the keyboard focus then attempt to gain it
  169.         if (!(mOwnedFoci & KeyboardFocus) && (mContainerSiteP->RequestFocus(true, KeyboardFocus) == S_OK))
  170.         {
  171.             mOwnedFoci = FocusSet(mOwnedFoci | KeyboardFocus);
  172.             NewlyFocused = true;
  173.         }
  174.  
  175.         //    if we have the keyboard focus then process the click
  176.         if (mOwnedFoci & KeyboardFocus)
  177.         {
  178.             DrawContext    Context = { BeginPortType };
  179.  
  180.             if (mContainerSiteP->AcquireContext(mActiveContext->GetContextID(), &Context) == S_OK)
  181.             {
  182.                 if (NewlyFocused)
  183.                     mActiveContext->Activate(true);
  184.  
  185.                 {
  186.                     CTextEditContextInfo*    OtherContextInfo;
  187.                     Int16                    Index = 1;
  188.                     Point                    localPt;
  189.                     TEHandle                ActiveTEH = ((CTextEditContextInfo*)mActiveContext)->GetTEHandle();
  190.  
  191.                     //    pass the click to the active TEHandle
  192.                     localPt = inEvent->where;
  193.                     ::GlobalToLocal(&localPt);
  194.                     ::TEClick(localPt, (inEvent->modifiers & shiftKey) , ActiveTEH);
  195.                     mStartSelection = (*ActiveTEH)->selStart;
  196.                     mEndSelection = (*ActiveTEH)->selEnd;
  197.  
  198.                     //    pass the click to the other TEHandles
  199.                     mContainerSiteP->ReleaseContext(&Context);
  200.                     while ( (OtherContextInfo = (CTextEditContextInfo*)GetContextInfoByIndex(Index++)) != NULL )
  201.                     {
  202.                         if (OtherContextInfo != mActiveContext)
  203.                         {
  204.                             Uint32        ContextID = OtherContextInfo->GetContextID();
  205.                             if ( mContainerSiteP->AcquireContext(ContextID, &Context) )
  206.                             {
  207.                                 ::TESetSelect(mStartSelection, mEndSelection, OtherContextInfo->GetTEHandle());
  208.                                 mContainerSiteP->ReleaseContext(&Context);
  209.                             }
  210.                         }
  211.                     }
  212.                 }
  213.                 mContainerSiteP->ReleaseContext(&Context);
  214.             }
  215. #if BE_STRICT
  216.             else DebugStr("\pTextEditControl mouseDown - couldn't acquire default context!");
  217. #endif    //    BE_STRICT
  218.         }
  219.     }
  220.  
  221.     return ReturnValue;
  222. }
  223.  
  224.  
  225. //=--------------------------------------------------------------------------=
  226. //  CTextEditControl::IControl::DoKeyEvent    
  227. //=--------------------------------------------------------------------------=
  228.  
  229. STDMETHODIMP
  230. CTextEditControl::DoKey(KeyEventType inKeyET, Char8 inChar, PlatformEvent* inEvent)
  231. {
  232.     ErrorCode    ReturnValue = S_FALSE;
  233.  
  234.     if ((inKeyET == KeyDown) || (inKeyET == AutoKey))
  235.     {
  236.         // If we have the keyboard focus and an active context then do the key
  237.         if (mOwnedFoci & KeyboardFocus && mActiveContext)
  238.         {
  239.             Boolean8    CursorKey = false;
  240.             Boolean8    ExtendSelection = false;
  241.             DrawContext    Context = { BeginPortType };
  242.             Int16        StartSelection;
  243.             Int16        EndSelection;
  244.             Uint32        ActiveContextID = mActiveContext->GetContextID();
  245.  
  246.             //    figure out if we have anything special here
  247.             CursorKey = inChar == 0x1c || inChar == 0x1d || inChar == 0x1e || inChar == 0x1f;
  248.             if (CursorKey)
  249.                 ExtendSelection = (inEvent->modifiers & 0x0200) != 0;
  250.  
  251.             if (mContainerSiteP->AcquireContext(ActiveContextID, &Context) == S_OK)
  252.             {
  253.                 //    pass the key to the active draw context
  254.                 TEHandle    ActiveTEH = ((CTextEditContextInfo*)mActiveContext)->GetTEHandle();
  255.  
  256.                 //    save off the starting selection
  257.                 StartSelection = (*ActiveTEH)->selStart;
  258.                 EndSelection = (*ActiveTEH)->selEnd;
  259.                 //    allow text edit to process the character
  260.                 ::TEKey(inChar, ActiveTEH);
  261.                 //    note the ending selection
  262.                 mStartSelection = (*ActiveTEH)->selStart;
  263.                 mEndSelection = (*ActiveTEH)->selEnd;
  264.                 //    if we have an shift-cursor key then make the selection extend
  265.                 if (ExtendSelection)
  266.                 {
  267.                     if (StartSelection < mStartSelection)
  268.                         mStartSelection = StartSelection;
  269.                     if (EndSelection > mEndSelection)
  270.                         mEndSelection = EndSelection;
  271.                     ::TESetSelect(mStartSelection, mEndSelection, ActiveTEH);
  272.                 }
  273.                 ReturnValue = S_OK;
  274.  
  275.                 //    pass the key to the other draw contexts
  276.                 {
  277.                     CTextEditContextInfo*    OtherContext;
  278.                     Int16                    i = 1;
  279.  
  280.                     mContainerSiteP->ReleaseContext(&Context);
  281.                     
  282.                     while ((OtherContext = ((CTextEditContextInfo*)GetContextInfoByIndex(i++))) != NULL)
  283.                     {
  284.                         if (OtherContext != mActiveContext)
  285.                         {
  286.                             if (mContainerSiteP->AcquireContext(OtherContext->GetContextID(), &Context) == S_OK)
  287.                             {
  288.                                 TEHandle    TextH = OtherContext->GetTEHandle();
  289.  
  290.                                 //    don't pass cursor keys through as it causes a static i-beam to display
  291.                                 if (!CursorKey)
  292.                                 {
  293.                                     ::TESetSelect(StartSelection, EndSelection, TextH);
  294.                                     ::TEKey(inEvent->message & charCodeMask, TextH);
  295.                                 }
  296.                                 ::TESetSelect(mStartSelection, mEndSelection, TextH);
  297.                                 mContainerSiteP->ReleaseContext(&Context);
  298.                             }
  299.                         }
  300.                     }
  301.                 }
  302.             }
  303. #if BE_STRICT
  304.             else DebugStr("\pTextEditControl couldn't acquire active draw context.");
  305. #endif    //    BE_STRICT
  306.         }
  307. #if BE_STRICT
  308.         else DebugStr("\pTextEditControl getting key events without the keyboard focus or active context.");
  309. #endif    //    BE_STRICT
  310.     }
  311.     
  312.     return ReturnValue;
  313. }
  314.  
  315.  
  316. //=--------------------------------------------------------------------------=
  317. //  CTextEditControl::IControl::DoIdle    
  318. //=--------------------------------------------------------------------------=
  319.  
  320. STDMETHODIMP
  321. CTextEditControl::DoIdle(Uint32 IdleRefCon)
  322. {
  323.     ErrorCode    ReturnValue = S_OK;
  324.  
  325.     if (IdleRefCon == TEIdleRefCon)
  326.     {
  327.         //    If we have the focus and an active TEHandle, blink the caret
  328.         if ( mOwnedFoci & KeyboardFocus)
  329.         {
  330.             if (mActiveContext)
  331.             {
  332.                 DrawContext Context = {BeginPortType};
  333.                 if (mContainerSiteP->AcquireContext(mActiveContext->GetContextID(), &Context) == S_OK)
  334.                 {
  335.                     ::TEIdle(((CTextEditContextInfo*)mActiveContext)->GetTEHandle());
  336.                     ReturnValue = S_OK;
  337.                     mContainerSiteP->ReleaseContext(&Context);
  338.                 }
  339. #if BE_STRICT
  340.                 else DebugStr("\pTextEditControl couldn't acquire draw context for idle.");
  341. #endif    //    BE_STRICT
  342.             }
  343. #if BE_STRICT
  344.             else DebugStr("\pTextEditControl has idle, keyboard foci, but no active TEHandle.");
  345. #endif    //    BE_STRICT
  346.         }
  347. #if BE_STRICT
  348.         else DebugStr("\pTextEditControl is being idled when it shouldn't be.");
  349. #endif    //    BE_STRICT
  350.     }
  351.     //    until we find all of our controls, keep polling
  352.     else if (IdleRefCon == QueryRefCon)
  353.     {
  354.         if (!mScrollBarInfo.Unknown && *(mScrollBarInfo.Name))
  355.             AttachPlatformControl(&mScrollBarInfo);
  356.  
  357.         if (!mPostButtonInfo.Unknown && *(mPostButtonInfo.Name))
  358.             AttachPlatformControl(&mPostButtonInfo);
  359.  
  360.         if ((mScrollBarInfo.Unknown || !*(mScrollBarInfo.Name)) &&
  361.             (mPostButtonInfo.Unknown || !*(mPostButtonInfo.Name)))
  362.             mContainerSiteP->SetIdleTime(RemoveIdler, QueryRefCon);
  363.     }
  364. #if BE_STRICT
  365.     else
  366.         DebugStr("\pTextEditControl got unrecognized IdleRefCon.");
  367. #endif
  368.  
  369.  
  370.     return ReturnValue;
  371. }
  372.  
  373.  
  374. //=--------------------------------------------------------------------------=
  375. //  CTextEditControl::IControl::SetFocus    
  376. //=--------------------------------------------------------------------------=
  377. STDMETHODIMP
  378. CTextEditControl::SetFocus(FocusCommand inCommand, FocusSet inFocus)
  379. {
  380.     DrawContext Context = {BeginPortType};
  381.     ErrorCode    ReturnValue = S_OK;
  382.     FocusSet    InOwnedFoci = mOwnedFoci;
  383.  
  384.     //    a TakeNext or TakePrev if we don't have the focus, means take it
  385.     if ((inCommand == TakeNextCommand || inCommand == TakePrevCommand) && !mOwnedFoci)
  386.     {
  387.         //     if the container is offering us the one focus we want, take all of them
  388.         if (inFocus & KeyboardFocus)
  389.             mOwnedFoci = inFocus;
  390.         else
  391.         //    otherwise, say no thanks
  392.             ReturnValue = E_FAIL;
  393.     }
  394.     //    a TakeNext or a TakePrev on a control which doesn't embed and has the focus should fail
  395.     else if (inCommand == TakeNextCommand || inCommand == TakePrevCommand)
  396.     {
  397.         ReturnValue = E_FAIL;
  398.     }
  399.     //    we're being asked/told to release our foci - always comply
  400.     else // if (Spec == ReleaseRequest || Spec == ReleaseCommand)
  401.     {
  402. #if BE_STRICT
  403.         if (inFocus & mOwnedFoci != inFocus)
  404.             DebugStr("\pWhat are you doing asking to release foci TextEditControl doesn't have?");
  405. #endif    //    BE_STRICT
  406.         mOwnedFoci = FocusSet(mOwnedFoci & ~inFocus);    //    really easy for us
  407.     }
  408.  
  409.  
  410.     //    if we gained the foci and we have an active context, then activate the TEHandle
  411.     if ((mOwnedFoci & KeyboardFocus) && !(InOwnedFoci & KeyboardFocus) && mActiveContext)
  412.     {
  413.         if (mContainerSiteP->AcquireContext(mActiveContext->GetContextID(), &Context) == S_OK)
  414.         {
  415.             ::TEActivate(((CTextEditContextInfo*)mActiveContext)->GetTEHandle());
  416.             ::InvalRect(&Context.Location);
  417.             mContainerSiteP->ReleaseContext(&Context);
  418.         }
  419.         mContainerSiteP->SetIdleTime(TEIdleTickCount, TEIdleRefCon);
  420.     }
  421.     //    else if we have an active TEHandle and we lost the keyboard focus, then deactivate the TEHandle
  422.     else if (mActiveContext && (InOwnedFoci & KeyboardFocus) && !(mOwnedFoci & KeyboardFocus))
  423.     {
  424.         if (mContainerSiteP->AcquireContext(mActiveContext->GetContextID(), &Context) == S_OK)
  425.         {
  426.             ::TEDeactivate(((CTextEditContextInfo*)mActiveContext)->GetTEHandle());
  427.             ::InvalRect(&Context.Location);
  428.             mContainerSiteP->ReleaseContext(&Context);
  429.         }
  430.         mContainerSiteP->SetIdleTime(RemoveIdler, TEIdleRefCon);
  431.     }
  432.  
  433.     return ReturnValue;
  434. }
  435.  
  436.  
  437. #pragma mark === CButtonControl::IPersistPropertyBag methods ===
  438.  
  439. //=--------------------------------------------------------------------------=
  440. //    CTextEditControl::IPersistPropertyBag::Load
  441. //=--------------------------------------------------------------------------=
  442.  
  443. STDMETHODIMP
  444. CTextEditControl::Load(IPropertyBag* PropertyBag, IErrorLog* ErrorLog)
  445. {
  446.     VARIANT                v;
  447.  
  448.     v.vt = VT_BSTR;
  449.     v.bstrVal = NULL;
  450.  
  451.     ReleaseAllPlatformControls();    //    a LoadTextState completely resets the controls attached
  452.  
  453.     CBaseControl::Load(PropertyBag, ErrorLog);
  454.  
  455.     if (PropertyBag->Read("start", &v, ErrorLog) == S_OK && v.bstrVal)
  456.     {
  457.         Int16    TextLen = *((Uint32*) v.bstrVal);
  458.  
  459.         mNewText = ::NewHandle(TextLen);
  460.         ::HLock(mNewText);
  461.         ::BlockMove(v.bstrVal + sizeof(Uint32), *mNewText, TextLen);
  462.         ::HUnlock(mNewText);
  463.         TouchAllContexts(TextControlProperty);
  464.     }
  465.  
  466.     if (PropertyBag->Read("postcontrol", &v, ErrorLog) == S_OK && v.bstrVal)
  467.     {
  468.         Int16    NameLen = *((Uint32*) v.bstrVal);
  469.  
  470.         if (NameLen > 255)
  471.             NameLen = 255;
  472.         ::BlockMove(v.bstrVal + sizeof(Uint32), mPostButtonInfo.Name + 1, NameLen);
  473.         *(mPostButtonInfo.Name) = NameLen;
  474.         CoTaskMemFree(v.bstrVal);
  475.     }
  476.  
  477.     if (PropertyBag->Read("scrollcontrol", &v, ErrorLog) == S_OK && v.bstrVal)
  478.     {
  479.         Int16    NameLen = *((Uint32*) v.bstrVal);
  480.  
  481.         if (NameLen > 255)
  482.             NameLen = 255;
  483.         ::BlockMove(v.bstrVal + sizeof(Uint32), mScrollBarInfo.Name + 1, NameLen);
  484.         *(mScrollBarInfo.Name) = NameLen;
  485.         CoTaskMemFree(v.bstrVal);
  486.     }
  487.  
  488.     BeginAttachPlatformControls();
  489.  
  490.     return S_OK;
  491. }
  492.  
  493.  
  494. #pragma mark === CTextEditContextInfo::IPlatformControlListener ===
  495.  
  496. //=--------------------------------------------------------------------------=
  497. //  CTextEditControl::IPlatformControlListener::OnControlValueChange    
  498. //=--------------------------------------------------------------------------=
  499.  
  500. STDMETHODIMP
  501. CTextEditControl::OnControlValueChange(IUnknown* inSource, Int32 ControlValue)
  502. {
  503.     Handle    TextData = NULL;
  504.     OSErr    Error;
  505.     
  506.     if (inSource == mScrollBarInfo.Unknown)
  507.     {
  508.         mScrollLines = ControlValue - mOldScrollPosition;
  509.         mOldScrollPosition = ControlValue;
  510.  
  511.         TouchAllContexts(ScrollControlProperty);
  512.     }
  513.     else if (inSource == mPostButtonInfo.Unknown)
  514.     {
  515.         TEHandle    ActiveTEH = ((CTextEditContextInfo*)mActiveContext)->GetTEHandle();
  516.  
  517.         TextData = ::TEGetText(ActiveTEH);
  518.         Error = ::HandToHand(&TextData);
  519.         if(!Error)
  520.         {
  521.             if(!mPostStream)
  522.                 mPostStream = new CTextEditBSC();
  523.             
  524.             mPostStream->OpenPostStream(mContainerSiteP, (char*)mPostUrl, TextData);
  525.         }
  526.     }
  527.  
  528.     return S_OK;
  529. }
  530.  
  531. #pragma mark === CTextEditContextInfo::CBaseControl ===
  532.  
  533. //=--------------------------------------------------------------------------=
  534. //  CTextEditControl::CBaseControl::NewContext    
  535. //=--------------------------------------------------------------------------=
  536.  
  537. CBaseContextInfo*
  538. CTextEditControl::NewContext(Uint32 inContextID)
  539. {
  540.     CTextEditContextInfo*    ContextInfo = new CTextEditContextInfo(this, inContextID);
  541.  
  542.     if (ContextInfo)
  543.     {
  544.         if (!ContextInfo->GetTEHandle())
  545.         {
  546.             delete ContextInfo;
  547.             ContextInfo = NULL;
  548.         }
  549.     }
  550.  
  551.     return ContextInfo;
  552. }
  553.  
  554.  
  555. //=--------------------------------------------------------------------------=
  556. //  CTextEditControl::TouchAllContexts    
  557. //=--------------------------------------------------------------------------=
  558.  
  559. void
  560. CTextEditControl::TouchAllContexts(ControlPropertyType PropertyType)
  561. {
  562.     Boolean8                UsedTheText = false;
  563.     CTextEditContextInfo*    ContextInfo;
  564.     Int16                    Index = 1;
  565.  
  566.     while ((ContextInfo = (CTextEditContextInfo*)GetContextInfoByIndex(Index++)) != NULL)
  567.     {
  568.         DrawContext    Context = { BeginPortType };
  569.  
  570.         if (mContainerSiteP->AcquireContext(ContextInfo->GetContextID(), &Context) == S_OK)
  571.         {
  572.             TEHandle    TEH = ContextInfo->GetTEHandle();
  573.  
  574.             if (PropertyType & TextControlProperty && mNewText)
  575.             {
  576.                 ::HLock(mNewText);
  577.                 ::TESetText(*mNewText, ::GetHandleSize(mNewText), TEH);
  578.                 ::HUnlock(mNewText);
  579.                 UsedTheText = true;
  580.             }
  581.  
  582.             if (PropertyType & ScrollControlProperty)
  583.                 ::TEScroll(0, (*TEH)->lineHeight * mScrollLines, TEH);
  584.  
  585.             //    don't do SelectionControlProperty here - can't see where it would be useful
  586.  
  587.             mContainerSiteP->ReleaseContext(&Context);
  588.         }
  589.     }
  590.  
  591.     if (UsedTheText && mNewText)
  592.     {
  593.         ::DisposeHandle(mNewText);
  594.         mNewText = NULL;
  595.     }
  596.  
  597.     mScrollLines = 0;
  598. }
  599.  
  600.  
  601. //=--------------------------------------------------------------------------=
  602. //  CTextEditControl::BeginAttachPlatformControls    
  603. //=--------------------------------------------------------------------------=
  604.  
  605. void
  606. CTextEditControl::BeginAttachPlatformControls(void)
  607. {
  608.     Boolean8    SetIdle = false;
  609.  
  610.     if (*mScrollBarInfo.Name && !mScrollBarInfo.Unknown)
  611.         SetIdle = true;
  612.  
  613.     if (*mPostButtonInfo.Name && !mPostButtonInfo.Unknown)
  614.         SetIdle = true;
  615.  
  616.     if (SetIdle)
  617.         mContainerSiteP->SetIdleTime(QueryTickCount, QueryRefCon);
  618. }
  619.  
  620.  
  621. //=--------------------------------------------------------------------------=
  622. //    CTextEditControl::ReleaseAllPlatformControls    
  623. //=--------------------------------------------------------------------------=
  624.  
  625. void
  626. CTextEditControl::ReleaseAllPlatformControls(void)
  627. {
  628.     ReleasePlatformControl(&mScrollBarInfo);
  629.     ReleasePlatformControl(&mPostButtonInfo);
  630. }
  631.  
  632.  
  633. //=--------------------------------------------------------------------------=
  634. //  CTextEditControl::AttachPlatformControl    
  635. //=--------------------------------------------------------------------------=
  636.  
  637. void
  638. CTextEditControl::AttachPlatformControl(PlatformControlInfo* inControlInfo)
  639. {
  640.     Boolean8    Found = false;
  641.  
  642.     //    look for someone who supports IID_IPlatformControl and has the desired name
  643.     if (mContainerSiteP)
  644.     {
  645.         //    if we don't have a container then get one
  646.         if (!mContainerP)
  647.         {
  648.             mContainerSiteP->GetContainer(&mContainerP);
  649.             mContainerP->AddRef();
  650.         }
  651.  
  652.         //    if we have a container continue
  653.         if (mContainerP)
  654.         {
  655.             IEnumUnknown*    UnknownEnum;
  656.  
  657.             //    get an enumerator of other embedded controls
  658.             if (mContainerP->EnumControls(NULL, OLECONTF_EMBEDDINGS, &UnknownEnum) == S_OK)
  659.             {
  660.                 IUnknown*        UnknownP = NULL;
  661.  
  662.                 //    while we have more controls to check
  663.                 while (UnknownEnum->Next(1, &UnknownP, NULL) == S_OK && !Found)
  664.                 {
  665.                     IConnectionPointContainer*    ConPointContainer = NULL;
  666.                     UnknownP->QueryInterface(IID_IConnectionPointContainer, &ConPointContainer);
  667.  
  668.                     //    if the control has a connection point container then see if it has our interface
  669.                     if (ConPointContainer)
  670.                     {
  671.                         IConnectionPoint*    ConPoint = NULL;
  672.                         ConPointContainer->FindConnectionPoint(IID_IPlatformControlListener, &ConPoint);
  673.  
  674.                         //    the control has our interface, see if it has the right name
  675.                         if (ConPoint)
  676.                         {
  677.                             IControl*    ControlP = NULL;
  678.                             UnknownP->QueryInterface(IID_IControl, &ControlP);
  679.                             if (ControlP)
  680.                             {
  681.                                 Str255    ControlName;
  682.                                 if (ControlP->GetID(sizeof(ControlName)-1, (Char8*)ControlName+1) == S_OK)
  683.                                 {
  684.                                     *ControlName = strlen((Char8*)ControlName+1);
  685.                                     if (::EqualString(inControlInfo->Name, ControlName, false, true))
  686.                                     {
  687.                                         IPlatformControl*    PlatformControlP = NULL;
  688.                                         UnknownP->QueryInterface(IID_IPlatformControl, &PlatformControlP);
  689.                                         if (PlatformControlP)
  690.                                         {
  691.                                             Found = true;
  692.                                             ConPoint->Advise((IControl*) this, &inControlInfo->Cookie);
  693.                                             inControlInfo->ConnectionPoint = ConPoint;
  694.                                             inControlInfo->ConnectionPoint->AddRef();
  695.                                             inControlInfo->Unknown = UnknownP;
  696.                                             inControlInfo->Unknown->AddRef();
  697.                                             PlatformControlP->Release();
  698.                                         }
  699.                                     }
  700.                                 }
  701.  
  702.                                 ControlP->Release();
  703.                             }
  704.  
  705.                             ConPoint->Release();
  706.                         }
  707.  
  708.                         ConPointContainer->Release();
  709.                     }
  710.  
  711.                     UnknownP->Release();    // Next does an AddRef()
  712.                 }
  713.                 UnknownEnum->Release();
  714.             }
  715.         }
  716.     }
  717. }
  718.  
  719.  
  720. //=--------------------------------------------------------------------------=
  721. //  CTextEditControl::ReleasePlatformControl    
  722. //=--------------------------------------------------------------------------=
  723.  
  724. void
  725. CTextEditControl::ReleasePlatformControl(PlatformControlInfo* inPCInfo)
  726. {
  727.     if (inPCInfo->Unknown)
  728.     {
  729.         inPCInfo->ConnectionPoint->Unadvise(inPCInfo->Cookie);
  730.         inPCInfo->ConnectionPoint->Release();
  731.         inPCInfo->ConnectionPoint = NULL;
  732.         inPCInfo->Unknown->Release();
  733.         inPCInfo->Unknown = NULL;
  734.         inPCInfo->Cookie = 0;
  735.     }
  736. }
  737.  
  738.  
  739. #pragma mark === CTextEditContextInfo Constructor & Destructor ===
  740.  
  741. //=--------------------------------------------------------------------------=
  742. //  CTextEditContextInfo::CTextEditContextInfo    
  743. //=--------------------------------------------------------------------------=
  744. CTextEditContextInfo::CTextEditContextInfo(CTextEditControl* inControlP, Uint32 inContextID) :
  745.         CBaseContextInfo (inControlP, inContextID)
  746. {
  747.     CTextEditControl*    TEControlP = (CTextEditControl*) mControlP;
  748.     DrawContext            Context = {BeginPortType};
  749.  
  750.     mTextEditH = NULL;
  751.  
  752.     if (TEControlP->mContainerSiteP->AcquireContext(inContextID, &Context) == S_OK)
  753.     {
  754.         Rect        ViewRect, DestRect;
  755.  
  756.         ViewRect = DestRect = Context.Location;
  757.         ::InsetRect(&DestRect, 2, 2);
  758.         ::InsetRect(&ViewRect, 2, 2);
  759.         ::TextFace(TEControlP->mFace);
  760.         ::TextFont(TEControlP->mFont);
  761.         ::TextSize(TEControlP->mSize);
  762.         if ((mTextEditH = ::TENew(&DestRect, &ViewRect)) != NULL)
  763.         {
  764.             CTextEditContextInfo*    AnyOtherContext = (CTextEditContextInfo*)(TEControlP->GetContextInfoByIndex(1));
  765.             Handle                    StartText = TEControlP->mNewText;
  766.  
  767.             //    if there there is start text and no other contexts then install the start text
  768.             if (StartText)
  769.             {
  770.                 if (!AnyOtherContext)
  771.                 {
  772.                     ::HLock(StartText);
  773.                     ::TESetText(*StartText, ::GetHandleSize(StartText), mTextEditH);
  774.                     ::HUnlock(StartText);
  775.                 }
  776.                 ::DisposeHandle(StartText);
  777.                 TEControlP->mNewText = NULL;
  778.             }
  779.             //    if there are already non-empty TERecs, then duplicate the text, sel state, etc
  780.             if ((AnyOtherContext ) != NULL)
  781.             {
  782.                 TEHandle    TextHOrig = AnyOtherContext->GetTEHandle();
  783.                 CharsHandle    CharsH = ::TEGetText(TextHOrig);
  784.                 if (CharsH)
  785.                 {
  786.                     ::HLock(CharsH);
  787.                     ::TESetText(*CharsH, (*TextHOrig)->teLength, mTextEditH);
  788.                     ::HUnlock(CharsH);
  789.                 }
  790.                 else
  791.                 {
  792.                     ::TEDispose(mTextEditH);
  793.                     mTextEditH = NULL;
  794.                 }
  795.             }
  796.         }
  797.  
  798.         TEControlP->mContainerSiteP->ReleaseContext(&Context);
  799.     }
  800. }
  801.  
  802.  
  803. //=--------------------------------------------------------------------------=
  804. //  CTextEditContextInfo::~CTextEditContextInfo    
  805. //=--------------------------------------------------------------------------=
  806. CTextEditContextInfo::~CTextEditContextInfo(void)
  807. {
  808.     if (mTextEditH)
  809.     {
  810.         CTextEditControl*    TEControlP = (CTextEditControl*) mControlP;
  811.         DrawContext            Context = {BeginPortType};
  812.  
  813.         if ((this == TEControlP->mActiveContext) && (TEControlP->mOwnedFoci & KeyboardFocus) &&
  814.             (TEControlP->mContainerSiteP->AcquireContext(mContextID, &Context) == S_OK))
  815.         {
  816.             ::TEDeactivate(mTextEditH);
  817.             TEControlP->mContainerSiteP->SetIdleTime(RemoveIdler, TEIdleRefCon);
  818.             TEControlP->mContainerSiteP->ReleaseContext(&Context);
  819.         }
  820.         ::TEDispose(mTextEditH);
  821.         mTextEditH = NULL;
  822.     }
  823. }
  824.  
  825.  
  826. #pragma mark === CTextEditContextInfo::CBaseContextInfo ===
  827.  
  828. //=--------------------------------------------------------------------------=
  829. //  CTextEditContextInfo::Update    
  830. //=--------------------------------------------------------------------------=
  831. ErrorCode
  832. CTextEditContextInfo::Update(Boolean8 Acquired)
  833. {
  834. #pragma unused (Acquired)
  835.     //    do whatever updating we want to do
  836.     return S_OK;
  837. }
  838.  
  839.  
  840. //=--------------------------------------------------------------------------=
  841. //  CTextEditContextInfo::Activate    
  842. //=--------------------------------------------------------------------------=
  843. ErrorCode
  844. CTextEditContextInfo::Activate(Boolean8 Acquired)
  845. {
  846.     CTextEditControl*    TEControlP = (CTextEditControl*) mControlP;
  847.  
  848.     if (TEControlP->mOwnedFoci & KeyboardFocus)
  849.     {
  850.         DrawContext    Context = { BeginPortType };
  851.  
  852.         if (Acquired || TEControlP->mContainerSiteP->AcquireContext(mContextID, &Context) == S_OK)
  853.         {
  854.             ::TESetSelect(TEControlP->mStartSelection, TEControlP->mEndSelection, mTextEditH);
  855.             ::TEActivate(mTextEditH);
  856.             TEControlP->mContainerSiteP->SetIdleTime(TEIdleTickCount, TEIdleRefCon);
  857.             if (!Acquired)
  858.                 TEControlP->mContainerSiteP->ReleaseContext(&Context);
  859.         }
  860.     }
  861.  
  862.     return S_OK;
  863. }
  864.  
  865.  
  866. //=--------------------------------------------------------------------------=
  867. //  CTextEditContextInfo::CTextEditContextInfo    
  868. //=--------------------------------------------------------------------------=
  869. ErrorCode
  870. CTextEditContextInfo::Deactivate(Boolean8 Acquired)
  871. {
  872.     CTextEditControl*    TEControlP = (CTextEditControl*) mControlP;
  873.  
  874.     if (TEControlP->mOwnedFoci & KeyboardFocus)
  875.     {
  876.         DrawContext    Context = { BeginPortType };
  877.  
  878.         TEControlP->mStartSelection = (*mTextEditH)->selStart;
  879.         TEControlP->mEndSelection = (*mTextEditH)->selEnd;
  880.         TEControlP->mContainerSiteP->SetIdleTime(RemoveIdler, TEIdleRefCon);
  881.         if (Acquired || TEControlP->mContainerSiteP->AcquireContext(mContextID, &Context) == S_OK)
  882.         {
  883.             ::TEDeactivate(mTextEditH);
  884.             if (!Acquired)
  885.                 TEControlP->mContainerSiteP->ReleaseContext(&Context);
  886.         }
  887.     }
  888.  
  889.     return S_OK;
  890. }
  891.