home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / VSCPPv8.zip / VACPP / IBMCPP / samples / IOC / LANCELOT / LTIMEPIE.CPP < prev    next >
C/C++ Source or Header  |  1995-04-07  |  21KB  |  483 lines

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