home *** CD-ROM | disk | FTP | other *** search
/ Power GUI Programming with VisualAge C++ / powergui.iso / trialva / ibmcppw / samples / ioc / lancelot / ltimepie.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1996-02-22  |  20.4 KB  |  484 lines

  1. /******************************************************************************
  2. * .FILE:         ltimepie.cpp                                                 *
  3. *                                                                             *
  4. * .DESCRIPTION:  Lancelot Sample Program:              Class Implementation   *
  5. *                                                                             *
  6. * .CLASSES:      LTimeCardPieChart                                            *
  7. *                                                                             *
  8. * .COPYRIGHT:                                                                 *
  9. *                                                                             *
  10. * .DISCLAIMER:                                                                *
  11. *                                                                             *
  12. * .NOTE: WE RECOMMEND USING A FIXED SPACE FONT TO LOOK AT THE SOURCE          *
  13. *                                                                             *
  14. ******************************************************************************/
  15.  
  16. #ifndef _IBASE_                         //Make sure ibase.hpp is included
  17.   #include <ibase.hpp>                  //  since that is where IC_<environ>
  18. #endif                                  //  is defined.
  19. #include <igrafctx.hpp>
  20. #include <igbundle.hpp>
  21. #include "ltimepie.hpp"
  22. #include "lancelot.h"
  23.  
  24. /******************************************************************************
  25. * Class LTimeCardPieChart :: LTimeCardPieChart - Constructor for the timecard *
  26. *   pie chart.                                                                *
  27. *                                                                             *
  28. * Define yourself as an IDrawingCanvas                                        *
  29. * Store a pointer to the timecard data                                        *
  30. * Create a graph list                                                         *
  31. * Create a resize handler for drawing the pie chart                           *
  32. * Create a font for the pie chart's legend text                               *
  33. * Initialize the number of pie slices to 0                                    *
  34. * Initialize the total hours to 0                                             *
  35. * Get the employee tasks                                                      *
  36. * Define a cursor to the tasks                                                *
  37. ******************************************************************************/
  38. LTimeCardPieChart::LTimeCardPieChart
  39.                            ( unsigned long windowId, IWindow* parent,
  40.                              IWindow* owner, const IRectangle& location,
  41.                              LTimeCardData* tcp )
  42.      :IDrawingCanvas       ( windowId, parent, owner, location ),
  43.       pTimeCardData        ( tcp ),
  44.       graphList            (),
  45.       pieChartResizeHandler( this ),
  46.       legendFont           ( "System Proportional", 10 ),
  47.       numberSlices         ( 0 ),
  48.       totalHours           ( 0 ),
  49.       tasks                (),
  50.       tasksCursor          ( tasks )
  51.  
  52. {
  53. /*-----------------------------------------------------------------------------
  54. | Handle resize events for the drawing canvas so that we can reposition       |
  55. |  the graphics.                                                              |
  56. -----------------------------------------------------------------------------*/
  57.    pieChartResizeHandler.handleEventsFor( this );
  58.    drawPie();
  59. }
  60.  
  61.  
  62. /******************************************************************************
  63. * Class LTimeCardPieChart :: drawPie() - Draw the pie chart.                  *
  64. ******************************************************************************/
  65. LTimeCardPieChart& LTimeCardPieChart::drawPie()
  66. {
  67. /*-----------------------------------------------------------------------------
  68. | Create a graphics bundle.                                                   |
  69. -----------------------------------------------------------------------------*/
  70.    IGraphicBundle
  71.       graphBundle;
  72.  
  73. /*-----------------------------------------------------------------------------
  74. | Set the beginning pie location at angle zero (0).                           |
  75. | Set the beginning pie color to red.                                         |
  76. | Set the beginning pie pattern to filled.                                    |
  77. | Initialize slice count to zero (0).                                         |
  78. | Remove any previous graphics from graph list.                               |
  79. -----------------------------------------------------------------------------*/
  80.    double
  81.       startAngle = 0;
  82.    IColor
  83.       theColor( IColor::red );
  84.    unsigned long
  85.       thePattern = IGraphicBundle::filled;
  86.    unsigned short
  87.       sliceCount = 0;
  88.    graphList.removeAll();
  89.  
  90. /*-----------------------------------------------------------------------------
  91. | Calculate the number of unique task names, unique task hours, and           |
  92. |   total hours.                                                              |
  93. | If no slices needed, leave.                                                 |
  94. -----------------------------------------------------------------------------*/
  95.    calculatePieData();
  96.  
  97.    if ( !numberSlices )
  98.       return *this;
  99.  
  100. /*-----------------------------------------------------------------------------
  101. | Iterate through 13 colors and then                                          |
  102. |   iterate through 5 different patterns as needed.  Possible number of       |
  103. |   unique pie slices is 65 (ie. 13 x 5)                                      |
  104. -----------------------------------------------------------------------------*/
  105.    for ( unsigned short whichPattern = 1;
  106.          whichPattern < 6;
  107.          whichPattern++ )
  108.    {
  109.       switch( whichPattern )
  110.       {
  111.          case 1:
  112.          {
  113.             thePattern = IGraphicBundle::filled;
  114.             break;
  115.          }
  116.          case 2:
  117.          {
  118.             thePattern = IGraphicBundle::horizontal;
  119.             break;
  120.          }
  121.          case 3:
  122.          {
  123.             thePattern = IGraphicBundle::dense1;
  124.             break;
  125.          }
  126.          case 4:
  127.          {
  128.             thePattern = IGraphicBundle::vertical;
  129.             break;
  130.          }
  131.          case 5:
  132.          {
  133.             thePattern = IGraphicBundle::hatchedDiag;
  134.             break;
  135.          }
  136.       }
  137.  
  138.       for ( unsigned short whichColor = 1;
  139.             whichColor < 14;
  140.             whichColor++ )
  141.       {
  142.          switch( whichColor )
  143.          {
  144.             case 1:
  145.             {
  146.                theColor = IColor::red;
  147.                break;
  148.             }
  149.             case 2:
  150.             {
  151.                theColor = IColor::blue;
  152.                break;
  153.             }
  154.             case 3:
  155.             {
  156.                theColor = IColor::green;
  157.                break;
  158.             }
  159.             case 4:
  160.             {
  161.                theColor = IColor::yellow;
  162.                break;
  163.             }
  164.             case 5:
  165.             {
  166.                theColor = IColor::cyan;
  167.                break;
  168.             }
  169.             case 6:
  170.             {
  171.                theColor = IColor::pink;
  172.                break;
  173.             }
  174.             case 7:
  175.             {
  176.                theColor = IColor::darkRed;
  177.                break;
  178.             }
  179.             case 8:
  180.             {
  181.                theColor = IColor::darkBlue;
  182.                break;
  183.             }
  184.             case 9:
  185.             {
  186.                theColor = IColor::darkGreen;
  187.                break;
  188.             }
  189.             case 10:
  190.             {
  191.                theColor = IColor::darkCyan;
  192.                break;
  193.             }
  194.             case 11:
  195.             {
  196.                theColor = IColor::darkPink;
  197.                break;
  198.             }
  199.             case 12:
  200.             {
  201.                theColor = IColor::darkGray;
  202.                break;
  203.             }
  204.             case 13:
  205.             {
  206.                theColor = IColor::brown;
  207.                break;
  208.             }
  209.          }
  210.  
  211. /*-----------------------------------------------------------------------------
  212. | Set the bundle's pen color                                                  |
  213. | Set the bundle's fill color                                                 |
  214. | Set the bundle's fill pattern                                               |
  215. -----------------------------------------------------------------------------*/
  216.          graphBundle.setPenColor( theColor );
  217.          graphBundle.setFillColor( theColor );
  218.          graphBundle.setFillPattern( thePattern );
  219.  
  220. /*-----------------------------------------------------------------------------
  221. | If there are no tasks or no hours worked, leave                             |
  222. -----------------------------------------------------------------------------*/
  223.          if ( !tasksCursor.isValid() || !totalHours )
  224.             break;
  225.  
  226. /*-----------------------------------------------------------------------------
  227. | Get the task name                                                           |
  228. | Get the task hours                                                          |
  229. | Calculate this pie slice's piece of the pie                                 |
  230. -----------------------------------------------------------------------------*/
  231.          IString
  232.             aTaskName = tasksCursor.element().task();
  233.          unsigned short
  234.             aHours = tasksCursor.element().hours();
  235.          double
  236.             newAngle = 360.0 * aHours / totalHours;
  237.  
  238. /*-----------------------------------------------------------------------------
  239. | Create a pie slice                                                          |
  240. | Define the graphics bundle for this pie slice                               |
  241. | Add the pie slice to the graph list                                         |
  242. -----------------------------------------------------------------------------*/
  243.          ppieSlice[sliceCount] =
  244.             new IGPie( IRectangle(), startAngle, newAngle );
  245.          ppieSlice[sliceCount]->setGraphicBundle( graphBundle );
  246.          graphList.addAsLast( *ppieSlice[sliceCount] );
  247.  
  248. /*-----------------------------------------------------------------------------
  249. | Create a graphics rectangle for the color key in the legend                 |
  250. | Define the graphics bundle for this rectangle                               |
  251. | Add the rectangle to the graph list                                         |
  252. -----------------------------------------------------------------------------*/
  253.          ppieLegendKey[sliceCount] = new IGRectangle( IRectangle() );
  254.          ppieLegendKey[sliceCount]->setGraphicBundle( graphBundle );
  255.          graphList.addAsLast( *ppieLegendKey[sliceCount] );
  256.  
  257. /*-----------------------------------------------------------------------------
  258. | Create a graphics string for the text in the legend                         |
  259. | Define the graphics bundle for this graphic string                          |
  260. | Add the graphics string to the graph list                                   |
  261. -----------------------------------------------------------------------------*/
  262.          ppieLegendKeyText[sliceCount] =
  263.             new IGString( tasksCursor.element().task(), IPoint(), legendFont );
  264.          ppieLegendKeyText[sliceCount]->setGraphicBundle( graphBundle );
  265.          graphList.addAsLast( *ppieLegendKeyText[sliceCount] );
  266.  
  267. /*-----------------------------------------------------------------------------
  268. | Increment the starting angle from the previous starting position            |
  269. | Increment the slice count                                                   |
  270. | Increment to the next task in the tasks cursor                              |
  271. | If no more slices needed, leave                                             |
  272. -----------------------------------------------------------------------------*/
  273.          startAngle = startAngle + newAngle;
  274.          sliceCount++;
  275.          tasksCursor.setToNext();
  276.          if ( sliceCount >= numberSlices )
  277.             break;
  278.       }
  279. /*-----------------------------------------------------------------------------
  280. | If no more slices needed, leave                                             |
  281. -----------------------------------------------------------------------------*/
  282.       if ( sliceCount >= numberSlices )
  283.          break;
  284.    }
  285.  
  286. /*-----------------------------------------------------------------------------
  287. | Revalidate tasks cursor to beginning                                        |
  288. | Now begin using our graph list                                              |
  289. | Resize and draw the pie chart                                               |
  290. -----------------------------------------------------------------------------*/
  291.    tasksCursor.setToFirst();
  292.  
  293.    setGraphicList( &graphList );
  294.  
  295.    resizePieChart( size() );
  296.  
  297.    return *this;
  298. }
  299.  
  300.  
  301. /*******************************************************************************
  302. * LTimeCardPieChart :: calculatePieData                                        *
  303. *   Determine the number of unique tasks, hours for each unique task, and      *
  304. *   total hours in timecard data                                               *
  305. *******************************************************************************/
  306. LTimeCardPieChart& LTimeCardPieChart::calculatePieData()
  307. {
  308.    IString
  309.       theTask;
  310.    unsigned short
  311.       entryNumber = 0;
  312.    totalHours = 0;
  313.    numberSlices = 0;
  314.  
  315.    tasks.removeAll();
  316.    tasksCursor.invalidate();
  317.    tasksCursor.setToFirst();
  318.  
  319. /*-----------------------------------------------------------------------------
  320. | Iterate each task name until blank                                          |
  321. -----------------------------------------------------------------------------*/
  322.    while ( ( theTask = pTimeCardData->tcard[entryNumber].taskName() ) != "" )
  323.    {
  324.       unsigned short
  325.          theHours = pTimeCardData->tcard[entryNumber].hours().asInt();
  326.       totalHours += theHours;
  327. /*-----------------------------------------------------------------------------
  328. | If the task name is not in the tasks set, add it.                           |
  329. | Increment number of unique pie slices.                                      |
  330. -----------------------------------------------------------------------------*/
  331.       if ( !tasks.containsElementWithKey( theTask ) )
  332.       {
  333.          tasks.add( TaskElement( theTask, theHours ) );
  334.          numberSlices++;
  335.       }
  336.       else
  337. /*-----------------------------------------------------------------------------
  338. | Since the task name is not unique in the task set, add the hours to the     |
  339. | existing task hours.                                                        |
  340. -----------------------------------------------------------------------------*/
  341.       {
  342.          TaskElement
  343.             theElement = tasks.elementWithKey( theTask );
  344.          tasks.addOrReplaceElementWithKey( TaskElement(
  345.                                            theTask,
  346.                                            theElement.hours() + theHours ) );
  347.       }
  348.       entryNumber++;
  349.    }
  350.    tasksCursor.setToFirst();
  351.  
  352.    return *this;
  353. }
  354.  
  355.  
  356. /*******************************************************************************
  357. * LTimeCardPieChart :: resizePieChart                                          *
  358. *   Redraw the pie chart for any resizing that might occur                     *
  359. *******************************************************************************/
  360. LTimeCardPieChart& LTimeCardPieChart::resizePieChart( const ISize& theSize )
  361. {
  362. /*-----------------------------------------------------------------------------
  363. | If no slices to draw, leave.                                                |
  364. -----------------------------------------------------------------------------*/
  365.    if ( !numberSlices )
  366.       return *this;
  367.  
  368. /*-----------------------------------------------------------------------------
  369. | Pie calculations...                                                         |
  370. -----------------------------------------------------------------------------*/
  371.    IPoint
  372.       pieBegins( 2, theSize.height() / 3 );
  373.    IRectangle
  374.       pieRect( pieBegins,
  375.                IPoint( theSize.width() - 4, theSize.height() - 4 ) );
  376.  
  377.    for ( unsigned short index = 0;
  378.          index < numberSlices;
  379.          index++ )
  380.    {
  381.       ppieSlice[ index ]->setEnclosingRect( pieRect );
  382.    }
  383.  
  384. /*-----------------------------------------------------------------------------
  385. | Legend calculations...                                                      |
  386. -----------------------------------------------------------------------------*/
  387.    IPoint
  388.       legendEnds( theSize.width() - 2, theSize.height() / 3 - 10 );
  389.    IRectangle
  390.       legendRect( IPoint( 2, 2 ), legendEnds );
  391.    unsigned short
  392.       numLegendCols = 2;
  393.    unsigned short
  394.       numLegendRows = numberSlices / numLegendCols
  395.                       + numberSlices % numLegendCols;
  396.    int
  397.       cellWidth = legendEnds.x() / numLegendCols;
  398.    int
  399.       cellHeight = legendEnds.y() / numLegendRows;
  400.  
  401.    for ( index = 0;
  402.          index < numberSlices;
  403.          index++ )
  404.    {
  405.       unsigned short
  406.          theCol = index % numLegendCols;
  407.       unsigned short
  408.          theRow = index / numLegendCols;
  409.       IRectangle
  410.          legendPieceRect( IPoint( theCol * cellWidth,
  411.                           theRow * cellHeight ),
  412.                           ISize( cellWidth, cellHeight ) );
  413.  
  414.       IRectangle
  415.          blockRect( legendPieceRect.bottomLeft(),
  416.                     IPoint( legendPieceRect.left() +
  417.                     ( (legendPieceRect.right() - legendPieceRect.left() ) / 4 ),
  418.                     legendPieceRect.top() ) );
  419.       IPoint
  420.          textPoint( legendPieceRect.left() +
  421.                     ( ( legendPieceRect.right() - legendPieceRect.left() ) / 4) + 2,
  422.                       legendPieceRect.bottom() );
  423.  
  424.       ppieLegendKey[ index ]->setEnclosingRect( blockRect );
  425.       ppieLegendKeyText[ index ]->moveTo( textPoint );
  426.    }
  427.  
  428.    return *this;
  429. }
  430.  
  431.  
  432. /******************************************************************************
  433. * Class LTimeCardPieChart :: ~LTimeCardPieChart - Destructor                  *
  434. ******************************************************************************/
  435. LTimeCardPieChart::~LTimeCardPieChart()
  436. {
  437. /*-----------------------------------------------------------------------------
  438. | Delete all pie slices, legend key rectangles, and legend text.              |
  439. -----------------------------------------------------------------------------*/
  440.    for ( unsigned short index = 0;
  441.          index < numberSlices;
  442.          index++ )
  443.    {
  444.       delete ppieSlice[ index ];
  445.       delete ppieLegendKey[ index ];
  446.       delete ppieLegendKeyText[ index ];
  447.    }
  448. }
  449.  
  450.  
  451.  
  452. /******************************************************************************
  453. * Class LPieChartResizeHandler :: LPieChartResizeHandler - Constructor for    *
  454. *   the timecard's pie chart                                                  *
  455. *                                                                             *
  456. * Define yourself as an IResizeHandler                                        *
  457. * Store a pointer to the pie chart                                            *
  458. ******************************************************************************/
  459. LPieChartResizeHandler::LPieChartResizeHandler( LTimeCardPieChart * pie )
  460.      :IResizeHandler(),
  461.       ppieChart( pie )
  462. {}
  463.  
  464.  
  465. /******************************************************************************
  466. * Class LPieChartResizeHandler :: ~LPieChartResizeHandler - Destructor        *
  467. ******************************************************************************/
  468. LPieChartResizeHandler::~LPieChartResizeHandler( )
  469. {}
  470.  
  471.  
  472. /******************************************************************************
  473. * Class LPieChartResizeHandler :: windowResize() - Called when a resize       *
  474. *   event occurs for the pie chart.                                           *
  475. ******************************************************************************/
  476. Boolean LPieChartResizeHandler::windowResize( IResizeEvent& event )
  477. {
  478. /*-----------------------------------------------------------------------------
  479. | Call our own resizing function.                                             |
  480. -----------------------------------------------------------------------------*/
  481.    ppieChart->resizePieChart( event.newSize() );
  482.    return false;
  483. }
  484.