home *** CD-ROM | disk | FTP | other *** search
/ Power GUI Programming with VisualAge C++ / powergui.iso / powergui / slider / progind / progind.cpp < prev    next >
Text File  |  1996-10-29  |  10KB  |  367 lines

  1. //*********************************************************
  2. // Sliders - Progress Indicator Example
  3. //
  4. // Copyright (C) 1994, Law, Leong, Love, Olson, Tsuji.
  5. // Copyright (c) 1997 John Wiley & Sons, Inc. 
  6. // All Rights Reserved.
  7. //*********************************************************
  8. #include <iapp.hpp>
  9. #include <ipoint.hpp>
  10. #include <irect.hpp>
  11. #include <irefcnt.hpp>
  12. #include <istring.hpp>
  13. #include <icconst.h>
  14. #include "progind.hpp"
  15.  
  16. #define ID_START_TASK_CMD  200
  17. #define ID_STOP_CMD        300
  18.  
  19. void main ( )
  20. {
  21.   // Create the primary window.
  22.   PrimaryWindow
  23.     mainWindow;
  24.  
  25.   // Give the window the input focus and show it.
  26.   mainWindow
  27.    .setFocus()
  28.    .show();
  29.  
  30.   IApplication::current().run();
  31. }
  32.  
  33. PrimaryWindow::PrimaryWindow ( )
  34.   : IFrameWindow( "Progress Indicator Example" ),
  35.     canvas( IC_FRAME_CLIENT_ID, this, this ),
  36.     instructions( 100, &canvas, &canvas ),
  37.     startButton( ID_START_TASK_CMD, &canvas, &canvas ),
  38.     cmdHdr( *this ),
  39.     progressWindowHandle( 0 )
  40. {
  41.   this->setClient( &canvas );
  42.   cmdHdr.handleEventsFor( this );
  43.  
  44.   instructions
  45.    .setText( "Select the Start task button to display the progress indicator." );
  46.   startButton
  47.    .enableDefault()
  48.    .setText( "Start task" )
  49.    .enableTabStop()
  50.    .enableGroup();
  51.  
  52.   // Define the rules for positioning controls on the multicell
  53.   // canvas and adding white space when growing the canvas.
  54.   canvas
  55.    .addToCell( &instructions, 2, 2 )
  56.    .addToCell( &startButton,  2, 4 );
  57.   canvas
  58.    .setRowHeight( 2, 1, true )
  59.    .setRowHeight( 5, IMultiCellCanvas::defaultCell().height() )
  60.    .setColumnWidth( 2, 1, true )
  61.    .setColumnWidth( 3, IMultiCellCanvas::defaultCell().width() );
  62. }
  63.  
  64. PrimaryWindow& PrimaryWindow::startTask ( )
  65. {
  66.   startButton
  67.    .disable();
  68.  
  69.   // Start a thread representing a time-consuming operation.
  70.   LongRunningTask
  71.    *task = new LongRunningTask( *this );
  72.   IThread
  73.     taskThread( task, true );
  74.  
  75.   // Create and show the window with the progress indicator.
  76.   ProgressWindow
  77.    *progressWindow = new ProgressWindow( this,
  78.                                          "Status of a Long-Running Task",
  79.                                          task );
  80.   progressWindowHandle = progressWindow->handle();
  81.   (*progressWindow)
  82.    .setAutoDeleteObject();
  83.   (*progressWindow)
  84.    .setDestroyOnClose()
  85.    .setFocus()
  86.    .show();
  87.  
  88.   return *this;
  89. }
  90.  
  91. PrimaryWindow&
  92.   PrimaryWindow::setPercentComplete ( unsigned long percent )
  93. {
  94.   unsigned long
  95.     newPercent = percent;
  96.   if ( newPercent > 100 )
  97.   {
  98.      newPercent = 100;
  99.   }
  100.  
  101.   // Update the progress indicator if we have one.
  102.   ProgressWindow
  103.    *progressWindow = 0;
  104.   if ( progressWindowHandle  &&  progressWindowHandle.isValid() )
  105.   {
  106.      progressWindow = (ProgressWindow*)
  107.                IWindow::windowWithHandle( progressWindowHandle );
  108.      if ( progressWindow )
  109.      {
  110.         (*progressWindow)
  111.          .setPercentDone( newPercent );
  112.      }
  113.      else
  114.      {
  115.         progressWindowHandle = 0;
  116.      }
  117.   }
  118.   else
  119.   {
  120.      progressWindowHandle = 0;
  121.   }
  122.  
  123.   if ( newPercent == 100 )
  124.   {       // The long-running task is finished.
  125.      this->cleanupTask();
  126.   }
  127.   return *this;
  128. }
  129.  
  130. PrimaryWindow& PrimaryWindow::cleanupTask ( )
  131. {
  132.   // Update the progress indicator if we have one.
  133.   ProgressWindow
  134.    *progressWindow = 0;
  135.   if ( progressWindowHandle  &&  progressWindowHandle.isValid() )
  136.   {
  137.      progressWindow = (ProgressWindow*)
  138.                IWindow::windowWithHandle( progressWindowHandle );
  139.      if ( progressWindow )
  140.      {
  141.         progressWindow->close();
  142.         progressWindowHandle = 0;
  143.      }
  144.      else
  145.      {
  146.         progressWindowHandle = 0;
  147.      }
  148.   }
  149.   else
  150.   {
  151.      progressWindowHandle = 0;
  152.   }
  153.   startButton
  154.    .enable();
  155.  
  156.   return *this;
  157. }
  158.  
  159. PrimaryWindow::StartThreadHdr::StartThreadHdr ( PrimaryWindow& window )
  160.   : ICommandHandler( ),
  161.     primaryWindow( window )
  162. { }
  163.  
  164. IBase::Boolean
  165.   PrimaryWindow::StartThreadHdr::command ( ICommandEvent& event )
  166. {
  167.   Boolean stopProcessing = false;
  168.   if ( event.commandId() == ID_START_TASK_CMD )
  169.   {
  170.      primaryWindow.startTask();
  171.      stopProcessing = true;
  172.   }
  173.   return stopProcessing;
  174. }
  175.  
  176. LongRunningTask::LongRunningTask ( PrimaryWindow& primary )
  177.   : IThreadFn( ),
  178.     primaryWindow( primary ),
  179.     timer( ),
  180.     count( 0 ),
  181.     percentComplete( 0 )
  182. { }
  183.  
  184. void LongRunningTask::run ( )
  185. {
  186.   // Start a timer to substitute for a real time-consuming task.
  187.   // Have this object's portionComplete function called every
  188.   // .5 seconds.
  189.   timer
  190.    .setInterval( 500 )
  191.    .start( new ITimerMemberFn< LongRunningTask >
  192.                   ( *this, LongRunningTask::portionComplete ) );
  193.  
  194.   // Let the thread execute for as long as the timer is running.
  195.   // The processMsgs call will end when the timer stops and no
  196.   // primary windows exist on this thread.
  197.   IThread::current().processMsgs();
  198. }
  199.  
  200. void LongRunningTask::portionComplete ( unsigned long )
  201. {
  202.   count++;
  203.   unsigned long
  204.     percent( 0 );
  205.   switch ( count % 5 )
  206.   {    // Generate a pseudo-random value to represent how
  207.        // much of the task has completed.
  208.      case 0:
  209.        percent = 4;
  210.        break;
  211.      case 1:
  212.        percent = 8;
  213.        break;
  214.      case 2:
  215.        percent = 3;
  216.        break;
  217.      case 3:
  218.        percent = 6;
  219.        break;
  220.      case 4:
  221.      default:
  222.        percent = 5;
  223.        break;
  224.   }
  225.  
  226.   percentComplete += percent;
  227.   if ( percentComplete >= 100 )
  228.   {
  229.      percentComplete = 100;
  230.   }
  231.   primaryWindow
  232.    .setPercentComplete( percentComplete );
  233.  
  234.   if ( percentComplete == 100 )
  235.   {      // End this thread by stopping the timer.
  236.      timer
  237.       .stop();
  238.   }
  239. }
  240.  
  241. void LongRunningTask::stop ( )
  242. {
  243.   // Stop the timer, which is our long-running task.
  244.   timer
  245.    .stop();
  246.   primaryWindow
  247.    .cleanupTask();
  248. }
  249.  
  250. ProgressWindow::ProgressWindow ( IWindow*         owner,
  251.                                  const char*      title,
  252.                                  LongRunningTask* task )
  253.   : IFrameWindow( 1000, 0, owner, IRectangle(),
  254.                   IFrameWindow::classDefaultStyle,
  255.                   title ),
  256.     canvasClient( IC_FRAME_CLIENT_ID, this, this ),
  257.     progressIndicator( 100, &canvasClient, &canvasClient,
  258.                        IRectangle(), 5, 0,
  259.                        ( IProgressIndicator::defaultStyle()
  260.                            & ~IProgressIndicator::alignCentered )
  261.                          | IProgressIndicator::alignBottom ),
  262.     label( 200, &canvasClient, &canvasClient ),
  263.     stopButton( ID_STOP_CMD, &canvasClient, &canvasClient ),
  264.     stopCmdHandler( task )
  265. {
  266.   stopCmdHandler
  267.    .handleEventsFor( this );
  268.  
  269.   progressIndicator
  270.    .setShaftBreadth( progressIndicator.shaftSize().height() * 3 / 2 );
  271.  
  272.   // Set the length of the tick marks and define the tick text for
  273.   // the progress indicator.  We minimize the number of ticks to
  274.   // avoid sizing problems and to avoid clipping or overlapping
  275.   // the tick text.
  276.   progressIndicator
  277.    .setTickLength( 10 );
  278.   for ( int i = 0; i <= 4; i++ )
  279.   {
  280.       progressIndicator
  281.        .setTickText( i, IString( i * 25 ) );
  282.               // Label ticks with "0," "25," "50," "75," "100."
  283.   }
  284.  
  285.   // Replace the minimum size of the progress indicator because
  286.   // IProgressIndicator does not return a reliable one.
  287.   progressIndicator
  288.    .setMinimumSize( ISize( 350, 70 ) );
  289.  
  290.   label
  291.    .setAlignment( IStaticText::centerCenter )
  292.    .setText( "Percentage complete" );
  293.  
  294.   stopButton
  295.    .enableDefault()
  296. #ifdef IC_WIN
  297.    .setText( "&Stop" )
  298. #else
  299.    .setText( "~Stop" )
  300. #endif
  301.    .enableTabStop()
  302.    .enableGroup();
  303.  
  304.   // Define the rules for positioning controls on the multicell
  305.   // canvas and adding white space when growing the canvas.
  306.   canvasClient
  307.    .addToCell( &progressIndicator, 2, 2, 2 )
  308.    .addToCell( &label,             2, 4, 2 )
  309.    .addToCell( &stopButton,        2, 6 )
  310.    .setRowHeight( 1, IMultiCellCanvas::defaultCell().height(), true )
  311.    .setRowHeight( 5, IMultiCellCanvas::defaultCell().height(), true )
  312.    .setRowHeight( 7, IMultiCellCanvas::defaultCell().height() )
  313.    .setColumnWidth( 3, 0, true )
  314.    .setColumnWidth( 4, IMultiCellCanvas::defaultCell().width() );
  315.  
  316.   // Size the frame window and center it on the screen.
  317.   ISize
  318.     clientSize( canvasClient.minimumSize() );
  319.   (*this)
  320.    .setClient( &canvasClient )
  321.    .moveSizeToClient( IRectangle( IPoint(), clientSize ) );
  322.   IRectangle
  323.     frameRect = this->rect();
  324.   frameRect
  325.    .centerAt( IWindow::desktopWindow()->rect().center() );
  326.   this->moveTo( frameRect.minXMinY() );
  327. }
  328.  
  329. ProgressWindow& ProgressWindow::setPercentDone ( unsigned long percent )
  330. {
  331.   // Some basic error checking.
  332.   unsigned long
  333.     percentToUse = percent;
  334.   if ( percentToUse > 100 )
  335.   {
  336.      percentToUse = 100;
  337.   }
  338.  
  339.   // We need to deal with pixel offsets instead of ticks because we
  340.   // only have five ticks but need to appear that we support 101.
  341.   unsigned long
  342.     totalPixels = progressIndicator.armRange() - 1,
  343.     newArmOffset = totalPixels * percentToUse / 100;
  344.   progressIndicator
  345.    .moveArmToPixel( newArmOffset );
  346.  
  347.   return *this;
  348. }
  349.  
  350. ProgressWindow::StopCmdHandler::StopCmdHandler ( LongRunningTask* task )
  351.   : ICommandHandler( ),
  352.     runningTask( task )
  353. { }
  354.  
  355. IBase::Boolean
  356.   ProgressWindow::StopCmdHandler::command ( ICommandEvent& event )
  357. {
  358.   Boolean
  359.     stopProcessing = false;
  360.   if ( event.commandId() == ID_STOP_CMD )
  361.   {
  362.      runningTask->stop();
  363.      stopProcessing = true;
  364.   }
  365.   return stopProcessing;
  366. }
  367.