home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 …ember: Reference Library / Apple Developer Reference Library (December 1999) (Disk 1).iso / pc / technical documentation / develop / develop issue 27 / develop issue 27 code / internet config assistant / toolkit / tassistant.cp < prev    next >
Encoding:
Text File  |  1996-06-30  |  14.5 KB  |  615 lines

  1. /*
  2.     File:        TAssistant.cp
  3.  
  4.     Contains:    Base class implementing an assistant
  5.  
  6.     Written by:    Arno Gourdol
  7.  
  8.     Copyright:    © 1996 by Apple Computer, Inc., all rights reserved.
  9.  
  10. */
  11.  
  12. #include "TAssistant.h"
  13. #include "assert.h"
  14.  
  15. #include <Resources.h>
  16. #include <Sound.h>
  17.  
  18.  
  19.  
  20. // --------------------------------------------------------------------
  21. // TAssistant
  22. // --------------------------------------------------------------------
  23.  
  24. TAssistant::TAssistant(SInt16 firstPane, 
  25.                         SInt16 lastPane, 
  26.                         TApplication* application) :
  27.     CMultiDialog(kCommonPane, kLastCommonItem, kSmallFont),
  28.     fShowDetails(false),
  29.     fFirstPane(firstPane),
  30.     fLastPane(lastPane),
  31.     fApplication(application),
  32.     fHistoryIndex(0)
  33. {
  34.     // Initialize the history stack
  35.     fHistory[0] = fFirstPane;
  36.  
  37.     // Display the first pane
  38.     SetDialogPane(fFirstPane);
  39. }
  40.  
  41.  
  42.  
  43. // --------------------------------------------------------------------
  44. // ~TAssistant
  45. // --------------------------------------------------------------------
  46.  
  47. TAssistant::~TAssistant()
  48. {
  49. }
  50.  
  51.  
  52.  
  53. // --------------------------------------------------------------------
  54. // CloseRequested
  55. // --------------------------------------------------------------------
  56. // Hook function called to confirm that closing the window is OK.
  57.  
  58. Boolean TAssistant::CloseRequested(void)
  59. {
  60.     if (fApplication != NULL)
  61.     {
  62.         // If an application was specified at the object creation,
  63.         // ask the application to quit...
  64.         return fApplication->QuitRequested();
  65.     }
  66.     else
  67.     {
  68.         //... otherwise display a confirmation alert
  69.         SInt16 itemHit = StopAlert(kQuitConfirmationDialog, NULL);
  70.  
  71.         return (itemHit == 1);
  72.     }
  73. }
  74.  
  75.  
  76.  
  77. // --------------------------------------------------------------------
  78. // Close
  79. // --------------------------------------------------------------------
  80. // Hook function called when the user closes the dialog
  81. // In our case, we close the dialog and quit the application 
  82. // if we are a stand-alone assistant (i.e. we're our own app <=> 
  83. // fApplication != NULL)
  84.  
  85. void TAssistant::Close(void)
  86. {
  87.     CMultiDialog::Close();
  88.     
  89.     if (fApplication != NULL)
  90.     {
  91.         fApplication->Quit();
  92.     }
  93. }
  94.  
  95.  
  96.  
  97. // --------------------------------------------------------------------
  98. // FindNextPane
  99. // --------------------------------------------------------------------
  100. // Decides what the next pane should be.
  101. // Calls NextPane() and SkipPane() to find out.
  102. // Returns 0 if no more panes
  103.  
  104.  
  105. SInt16 TAssistant::FindNextPane(SInt16 currentPane)
  106. {
  107.     assert(currentPane != kConclusionPane && 
  108.                                         currentPane != kDetailsPane);
  109.  
  110.     SInt16 nextPane = NextPane(currentPane);
  111.     
  112.     // Look for a pane that doesn't have to be skipped
  113.     while (nextPane != 0 && SkipPane(nextPane))
  114.     {
  115.         nextPane = NextPane(nextPane);
  116.     };
  117.     
  118.     // If no more pane, go to the appropriate
  119.     // conclusion pane
  120.     if (nextPane == 0)
  121.     {
  122.         if (fShowDetails)
  123.             nextPane = kDetailsPane;
  124.         else
  125.             nextPane = kConclusionPane;
  126.     }
  127.  
  128.     return nextPane;
  129. }
  130.  
  131.  
  132.  
  133. // --------------------------------------------------------------------
  134. // NextPane
  135. // --------------------------------------------------------------------
  136. // Function called to query the ID of the next pane.
  137. // Returns 0 if no more panes
  138. // Override this function if you need to present panes in non-sequential
  139. // order or if you want to skip a long sub-interview.
  140.  
  141. SInt16 TAssistant::NextPane(SInt16 currentPane)
  142. {
  143.     if (currentPane == fLastPane)
  144.         return 0;
  145.     else
  146.         return currentPane + 1;
  147. }
  148.  
  149.  
  150.  
  151. // --------------------------------------------------------------------
  152. // SkipPane
  153. // --------------------------------------------------------------------
  154. // Hook function called before displaying a pane.
  155. // Returns true if the pane must be skipped, 
  156. // false if the panel can be displayed
  157. // Override to skip portion of an interview based on a user's previous
  158. // answers or on the environment (no network available, etc...)
  159.  
  160. Boolean TAssistant::SkipPane(SInt16 pane)
  161. {
  162. #pragma unused(pane)
  163.     return false;
  164. }
  165.  
  166.  
  167.  
  168. // --------------------------------------------------------------------
  169. // DrawUserItem
  170. // --------------------------------------------------------------------
  171. // Hook function called to draw custom user items
  172. // We use it to draw the banner and the navigation bar
  173.  
  174. void TAssistant::DrawUserItem(TDrawContext& drawContext, 
  175.                                             short item, 
  176.                                             const CRect& frame)
  177. {
  178.     CMultiDialog::DrawUserItem(drawContext, item, frame);
  179.         
  180.     if (item == kBannerBackground)
  181.     {
  182.         DrawBanner(drawContext, frame);
  183.     }
  184.     else if (item == kNavbarBackground)
  185.     {
  186.         DrawNavigationBar(drawContext, frame);
  187.     }
  188. }
  189.  
  190.  
  191.  
  192. // --------------------------------------------------------------------
  193. // DrawBanner
  194. // --------------------------------------------------------------------
  195. // Draw the banner containing the panel title
  196.  
  197. void TAssistant::DrawBanner(TDrawContext& drawContext, 
  198.                                             const CRect& frame)
  199. {
  200.     enum
  201.     {
  202.         kTopicIndent = 16
  203.     };
  204.     
  205.     {
  206.         PixPatHandle backgroundPattern = GetPixPat(128);
  207.         
  208.         if (backgroundPattern != NULL)
  209.         {
  210.             PenPixPat(backgroundPattern);
  211.             drawContext.FillRect(frame);
  212.             PenNormal();
  213.             DisposePixPat(backgroundPattern);
  214.         }
  215.     }
  216.     //    Draw the left and top edges brighter…        
  217.     drawContext.SetHighColor(CColor(0xFFFF));
  218.     drawContext.MovePenTo(frame.LeftBottom());
  219.     drawContext.StrokeLine(frame.LeftTop());
  220.     drawContext.StrokeLine(CPoint(frame.Right() - 1, frame.Top()));
  221.     
  222.     //    Draw the right and bottom edges darker…
  223.     if ((drawContext.GetDepth() >= 8) || 
  224.         (!drawContext.IsColor() && drawContext.GetDepth() == 4))
  225.         drawContext.SetHighColor(CColor(0xAAAA));
  226.     else
  227.         drawContext.SetHighColor(CColor(0));
  228.  
  229.     drawContext.MovePenTo(
  230.                 CPoint(frame.Right() - 1, frame.Bottom()));
  231.     drawContext.StrokeLine(frame.LeftBottom());
  232.     
  233.     //    Position the line of text and draw it…
  234.     //    ??? This will only draw one line of text. 
  235.     //      Make sure all text fits!
  236.     {
  237.         short saveStyle = fDialogFont.GetStyle();
  238.         // ??? Not international friendly
  239.         fDialogFont.SetStyle(bold);            
  240.         
  241.         CRect textBox;
  242.         if (TApplication::gApplication->fEnvironment.IsSystemScriptRTL())
  243.         {
  244.             textBox.SetLeft(frame.Left() + 4);
  245.             textBox.SetRight(frame.Right() - kTopicIndent);
  246.         }
  247.         else
  248.         {
  249.             textBox.SetLeft(frame.Left() + kTopicIndent);
  250.             textBox.SetRight(frame.Right() - 4);
  251.         }
  252.         textBox.SetTop(frame.Top() + 
  253.                         (frame.Height() - fDialogFont.GetLineHeight()) / 2);
  254.         textBox.SetBottom(textBox.Top() + fDialogFont.GetLineHeight());
  255.  
  256.         Str255 paneTitle;
  257.         BlockMoveData(fPaneTitle, paneTitle, sizeof(Str255));
  258.         fDialogFont.TruncString(frame.Width() - kTopicIndent, paneTitle);
  259.         drawContext.SetHighColor(CColor(0));
  260.         fDialogFont.DrawText(paneTitle, textBox);
  261.         
  262.         fDialogFont.SetStyle(saveStyle);
  263.     }
  264. }
  265.  
  266.  
  267.  
  268. // --------------------------------------------------------------------
  269. // DrawNavigationBar
  270. // --------------------------------------------------------------------
  271. // Draw the navigation bar
  272.  
  273. void TAssistant::DrawNavigationBar(TDrawContext& drawContext, 
  274.                                             const CRect& frame)
  275. {
  276.     drawContext.SetHighColor(CColor(0xDDDD));
  277.     // Calculate the background region
  278.     RgnHandle backgroundRgn = NewRgn();
  279.     
  280.     // We need to punch holes in the region of the nav bar...
  281.     
  282.     // Iterate over all the controls intersecting with the nav bar
  283.     OpenRgn();
  284.     drawContext.StrokeRect(frame);
  285.     
  286.     ControlRef control = GetControlListFromWindow(GetWindowRef());
  287.     while (control != NULL)
  288.     {
  289.         CRect controlRect((**control).contrlRect);
  290.         // Substract the control's rectangle from the fill area
  291.         if (controlRect.Intersects(frame))
  292.             drawContext.StrokeRect(controlRect);
  293.         control = (**control).nextControl;
  294.     }
  295.     CloseRgn(backgroundRgn);
  296.     
  297.     // Draw the background of the nav bar with holes
  298.     drawContext.FillRegion(backgroundRgn);
  299.     
  300.     // Draw black separator line
  301.     drawContext.SetHighColor(CColor(0));
  302.     drawContext.MovePenTo(    
  303.                     CPoint(frame.Left(), frame.Top()));
  304.     drawContext.StrokeLine(    
  305.                     CPoint(frame.Right(), frame.Top()));
  306.                     
  307.     // Draw shadow
  308.     drawContext.SetHighColor(CColor(0xAAAA));
  309.     drawContext.MovePenTo(    
  310.                     CPoint(frame.Left() + 1, frame.Bottom() - 1));
  311.     drawContext.StrokeLine(    
  312.                     CPoint(frame.Right() - 1, frame.Bottom() - 1));
  313.     drawContext.StrokeLine(    
  314.                     CPoint(frame.Right() - 1, frame.Top() + 2));
  315.  
  316.     // Draw hilite
  317.     drawContext.SetHighColor(CColor(0xFFFF));
  318.     drawContext.MovePenTo(    
  319.                     CPoint(frame.Left(), frame.Bottom() - 2));
  320.     drawContext.StrokeLine(    
  321.                     CPoint(frame.Left(), frame.Top() + 1));
  322.     drawContext.StrokeLine(    
  323.                     CPoint(frame.Right() - 2, frame.Top() + 1));
  324.     
  325.     // Draw the panel number
  326.     {
  327.         short saveStyle = fDialogFont.GetStyle();
  328.         // ??? Not international friendly
  329.         fDialogFont.SetStyle(bold);            
  330.         
  331.         CRect textBox = GetItemRect(kPaneNumber);
  332.  
  333.         Str255 paneNumber;
  334.         ::NumToString(fHistoryIndex + 1, paneNumber);
  335.         drawContext.SetHighColor(CColor(0));
  336.         fDialogFont.DrawText(paneNumber, textBox);
  337.         
  338.         fDialogFont.SetStyle(saveStyle);
  339.     }
  340.  
  341. }
  342.  
  343.  
  344.  
  345. // --------------------------------------------------------------------
  346. // FilterKey
  347. // --------------------------------------------------------------------
  348. // Hook function called when a key is pressed.
  349. // Return true if the key was handled.
  350. // We use it to handle keyboard navigation of the assistant:
  351. // return/enter => next field or next pane
  352. // command-arrows => next or previous pane
  353.  
  354. Boolean TAssistant::FilterKey(const EventRecord& event, UInt16 key)
  355. {
  356. #pragma unused(event)
  357.  
  358.     Boolean result = true;
  359.     
  360.     if (key == keyReturn || key == keyEnter)
  361.     {
  362.         if (GetDialogPane() == kDetailsPane || 
  363.                                 GetDialogPane() == kConclusionPane)
  364.         {
  365.             FlashButton(kGoAheadButton);
  366.             GoAhead();
  367.             Close();
  368.         }
  369.         else
  370.         {
  371.             Boolean isShiftKeyDown = ((event.modifiers & shiftKey) != 0);
  372.             
  373.             // If the shift key is pressed, reverse direction
  374.             if (isShiftKeyDown)
  375.             {
  376.                 short prevTextField = PreviousTextField();
  377.                 if (prevTextField > 0)
  378.                 {
  379.                     SelectItemText(prevTextField);
  380.                 }
  381.                 else
  382.                 {
  383.                     GoToPreviousPane();
  384.                     // Select the last text field if we are going backwards
  385.                     {
  386.                         short lastTextField = LastTextField();
  387.                         if (lastTextField > 0)
  388.                             SelectItemText(lastTextField);
  389.                     }
  390.                 }
  391.             }
  392.             else
  393.             {
  394.                 short nextTextField = NextTextField();
  395.                 if (nextTextField > 0)
  396.                 {
  397.                     SelectItemText(nextTextField);
  398.                 }
  399.                 else
  400.                 {
  401.                     GoToNextPane();
  402.                 }
  403.             }
  404.         }
  405.         result = true;
  406.     }
  407.     else if (key == keyEscape)
  408.     {
  409.         if (CloseRequested())
  410.             Close();
  411.     }
  412.     else if (key == keyHome)
  413.     {
  414.         GoToPane(fFirstPane);
  415.     }
  416.     else if (key == keyEnd)
  417.     {
  418.         if (fShowDetails)
  419.             GoToPane(kDetailsPane);
  420.         else
  421.             GoToPane(kConclusionPane);
  422.     }
  423.     else if (key == keyPageUp)
  424.     {
  425.         GoToPreviousPane();
  426.     }
  427.     else if (key == keyPageDown)
  428.     {
  429.         GoToNextPane();
  430.     }
  431.     else if (key == keyArrowLeft && (event.modifiers & cmdKey))
  432.     {
  433.         GoToPreviousPane();
  434.     }
  435.     else if (key == keyArrowRight && (event.modifiers & cmdKey))
  436.     {
  437.         GoToNextPane();
  438.     }
  439.     else
  440.     {
  441.         result = false;
  442.     }
  443.     
  444.     return result;
  445. }
  446.  
  447.  
  448.  
  449. // --------------------------------------------------------------------
  450. // ItemHit
  451. // --------------------------------------------------------------------
  452. // Hook function called when an item is selected
  453.  
  454. void TAssistant::ItemHit(UInt16 pane, short item)
  455. {
  456.     assert(fHistory[fHistoryIndex] == pane);
  457.  
  458.     if (pane == kConclusionPane || pane == kDetailsPane)
  459.     {
  460.         if (item == kGoAheadButton)
  461.         {
  462.             GoAhead();
  463.             Close();
  464.         }
  465.         else if (item == kCancelButton)
  466.         {
  467.             Close();
  468.         }
  469.         else if (pane == kConclusionPane && item == kShowDetailsButton)
  470.         {
  471.             fHistory[fHistoryIndex] = kDetailsPane;
  472.             fShowDetails = true;
  473.             SetDialogPane(kDetailsPane);
  474.         }
  475.         else if (pane == kDetailsPane && item == kHideDetailsButton)
  476.         {
  477.             fHistory[fHistoryIndex] = kConclusionPane;
  478.             fShowDetails = false;
  479.             SetDialogPane(kConclusionPane);
  480.         }
  481.     }
  482.  
  483.     if (item == kContinueButton)
  484.     {
  485.         GoToNextPane();
  486.     }
  487.     else if (item == kGoBackButton)
  488.     {
  489.         GoToPreviousPane();
  490.     }
  491.     
  492.     CMultiDialog::ItemHit(pane, item);
  493. }
  494.  
  495.  
  496.  
  497. // --------------------------------------------------------------------
  498. // GoToNextPane
  499. // --------------------------------------------------------------------
  500. // Go tp the next pane,
  501. // push the current pane on the history stack
  502.  
  503. void TAssistant::GoToNextPane(void)
  504. {
  505.     UInt16 pane = GetDialogPane();
  506.     
  507.     if(pane == kDetailsPane || pane == kConclusionPane)
  508.     {
  509.         // If we are at the last pane, just beep
  510.         SysBeep(0);
  511.     }
  512.     else
  513.     {
  514.         // Find the next pane and push it on the history stack
  515.         fHistory[++fHistoryIndex] = FindNextPane(pane);
  516.         GoToPane(fHistory[fHistoryIndex]);
  517.     }
  518. }
  519.  
  520.  
  521.  
  522. // --------------------------------------------------------------------
  523. // GoToPreviousPane
  524. // --------------------------------------------------------------------
  525. // Goes to the previous pane, from the history stack
  526.  
  527. void TAssistant::GoToPreviousPane(void)
  528. {
  529.     if (fHistoryIndex == 0)
  530.     {
  531.         // If we are at the first pane, can't go back
  532.         SysBeep(0);
  533.     }
  534.     else
  535.     {
  536.         // Pop the previous pane from the history stack
  537.         GoToPane(fHistory[--fHistoryIndex]);
  538.     }
  539. }
  540.  
  541.  
  542.  
  543. // --------------------------------------------------------------------
  544. // GoToPane
  545. // --------------------------------------------------------------------
  546. // Goes directly to a pane.
  547. // Doesn't affect the history stack
  548.  
  549. void TAssistant::GoToPane(UInt16 paneID)
  550. {
  551.     SetDialogPane(paneID);
  552.     
  553.     // The banner and pane number changes with each pane...
  554.     // ... make sure they get updated
  555.     ::InvalRect(GetItemRect(kBannerBackground));
  556.     ::InvalRect(GetItemRect(kPaneNumber));
  557. }
  558.  
  559.  
  560.  
  561. // --------------------------------------------------------------------
  562. // PrepareDialog
  563. // --------------------------------------------------------------------
  564. // Hook function called to do any additional preparation to the dialog
  565. // In our case we enable the appropriate go back and continue buttons
  566. // and set-up the banner user item, getting the string from the 
  567. // overlapping static text item.
  568.  
  569. void TAssistant::PrepareDialog(void)
  570. {
  571.     CMultiDialog::PrepareDialog();
  572.     
  573.     EnableItem(kGoBackButton, GetDialogPane() != fFirstPane);
  574.     EnableItem(kContinueButton, (GetDialogPane() != kConclusionPane) 
  575.                                 && (GetDialogPane() != kDetailsPane));
  576.     
  577.     // Search for a label for the pane
  578.     // The label is a static text string inside the banner (third item)
  579.     {
  580.         CRect bannerRect = GetItemRect(kBannerBackground);
  581.         UInt16 itemCount = CountDITL(GetDialogRef());
  582.         
  583.         // Loop thru the items of the dialog
  584.         for (UInt16 item = 1; item <= itemCount; item++)
  585.         {
  586.             // If the banner's bound countain the bounds of this item
  587.             if (bannerRect.Contains(GetItemRect(item)))
  588.             {
  589.                 // ... and this item is a static text
  590.                 if (GetItemType(item) == kStaticTextDialogItem)
  591.                 {
  592.                     // We've found the title of the pane
  593.                     GetItemText(item, fPaneTitle);
  594.                     HideItem(item);
  595.                 }
  596.             }
  597.         }
  598.     }
  599.  
  600. }
  601.  
  602.  
  603.  
  604. // --------------------------------------------------------------------
  605. // GoAhead
  606. // --------------------------------------------------------------------
  607. // Function called when the user click the Go Ahead button in the
  608. // conclusion pane.
  609. // Time for the assistant to get to work.
  610.  
  611. void TAssistant::GoAhead(void)
  612. {
  613. }
  614.  
  615.