EasyReport.cpp
上传用户:jimmy1212
上传日期:2020-11-02
资源大小:40k
文件大小:27k
源码类别:

Static控件

开发平台:

Visual C++

  1. /*******************************************************************************
  2.  * EasyReport.cpp: implementation of the CEasyReport class.
  3.  *
  4.  * MFC Easy! Report class
  5.  *
  6.  * Written by Vipul Lal <VipulLal@hotmail.com> or <vipul@del2.vsnl.net.in>
  7.  * Copyright (c) 2000-2002. All Rights Reserved.
  8.  *
  9.  * This code may be used in compiled form in any way you desire. This
  10.  * file may be redistributed unmodified by any means PROVIDING it is 
  11.  * not sold for profit without the authors written consent, and 
  12.  * providing that this notice and the authors name and all copyright 
  13.  * notices remains intact. 
  14.  *
  15.  * An email letting me know how you are using it would be nice. 
  16.  *
  17.  * This file is provided "as is" with no expressed or implied warranty.
  18.  * The author accepts no liability for any damage/loss of business that
  19.  * this product may cause.
  20.  *
  21.  * Description:
  22.  * This class encapsulates the functionality required for most reports. 
  23.  * We could have derived this class from CDocument, but that would not 
  24.  * have been as flexible as a stand alone class. 
  25.  *
  26.  *
  27.  *
  28.  *******************************************************************************/
  29. #include "stdafx.h"
  30. #include "EasyReport.h"
  31. #include "RepElement.h"
  32. #ifdef _DEBUG
  33. #undef THIS_FILE
  34. static char THIS_FILE[]=__FILE__;
  35. #define new DEBUG_NEW
  36. #endif
  37. IMPLEMENT_SERIAL(CEasyReport, CObject,1);
  38. void CEasyReport::Serialize(CArchive & inAr)
  39. {
  40. // no serialize yet !
  41. }
  42. /*****************************************************************
  43.  * 
  44.  * method :CEasyReport::CEasyReport()
  45.  *
  46.  * parameters : None
  47.  *
  48.  * returns : Nothing
  49.  *
  50.  * description: Constructor. Set up page sizes, initalize pointers
  51.  * to null etc.
  52.  *
  53.  ****************************************************************/
  54. CEasyReport::CEasyReport()
  55. {
  56. int i;
  57. for(i=0;i < eMaxStyles ;i++)
  58. {
  59. m_Fonts[i]= NULL;
  60. }
  61. // print device context...
  62. m_PrinterDC = NULL;
  63. // No data columns as yet..
  64. m_NumDataCols = 0;
  65. m_DataCols = NULL;
  66. // setup page defaults. Note: The report used the LO_METRIC
  67. // unit of measurement. Thus, 1 inch = 2.54 cms = 25.4 mm =
  68. // 254 LO_METRIC units.
  69. m_PageHeight = 11 * 254; // height of the entire page
  70. m_PageWidth = (int)(8.5 * 254);
  71. m_TopMargin = 127; // Half inch margin all around
  72. m_BottomMargin = 127;
  73. m_LeftMargin = 127;
  74. m_RightMargin = 127;
  75. // headers and footers. By default, ReportHeader and ReportFooter
  76. // are set to .5". The default report header consists of the 
  77. // company name centered on the page. The default page header
  78. // contains the report name and the date. The default page
  79. // footer contains the page number centered within the margins.
  80. // These are defaults. You can override these in derived classes
  81. // or set these directly. For instance, to customize the default 
  82. // report header, override the WriteReportHeader() virtual. Ditto 
  83. // for other headers and footers.
  84. m_PageHdrHt = 100; // height of the page header is 1cm
  85. m_PageFtrHt = 100; // height of the page footer is 1cm
  86. m_CurPage = m_PageCount = 0;
  87. // The m_SuppressBlankTbl, if true, will suppress a table header from 
  88. // appearing on the report unless something is written to one of the 
  89. // columns. The RepeatTblHdr flag forces the system to repeat the 
  90. // column headings on every page.
  91. m_SuppressBlankTbl = true; // do not write the column headings if no data is written to the column
  92. m_RepeatTblHdr = false; // do not repeat column headings on every page
  93. // Default report heading contains the company name
  94. m_CompanyName = "Power Play Software"; // replace with your company name !
  95. m_ReportHdrHt = 200; // 2 cm high
  96. m_ReportFtrHt = 0; // no report footer
  97. m_StdPen.CreatePen(PS_SOLID,2, RGB(0,0,0));
  98. }
  99. /*****************************************************************
  100.  * 
  101.  * method :void CEasyReport::SetupTextStyles(CDC *inDC)
  102.  *
  103.  * parameters : inDC: Handle to the printer device context
  104.  *
  105.  * returns : Nothing.
  106.  *
  107.  * description: Set up the fonts required for the report. This is a
  108.  * virtual function, so if you override in derived classes, you can 
  109.  * modify the default fonts. Actually, it might have been better if
  110.  * we had individual virtual functions, like "CreateHeadingFont" etc
  111.  * which would enable the user to override individual font styles
  112.  * per report. Maybe we can implement this in a later version!
  113.  *
  114.  * The Caption font is used for the report title.
  115.  * The ColHeading font is used for column headings.
  116.  * The DataFont is used for the data in columns
  117.  * The TextFont is used for paragraphs of text.
  118.  *
  119.  ****************************************************************/
  120. void CEasyReport::SetupTextStyles(HDC  inDC)
  121. {
  122. // create default fonts...
  123. LOGFONT aFont;
  124. CPoint aPoint;
  125. // The caption font is 20 point bold, italics
  126. aPoint.y = (20 * GetDeviceCaps(inDC, LOGPIXELSY))/72;
  127. DPtoLP(inDC, &aPoint,1);
  128. memset(&aFont,0,sizeof(aFont));
  129. aFont.lfHeight = aPoint.y;
  130. aFont.lfWeight = FW_BOLD;
  131. aFont.lfItalic = 1;
  132. aFont.lfOutPrecision = OUT_STROKE_PRECIS; // Truetype font
  133. aFont.lfQuality = PROOF_QUALITY;
  134. aFont.lfPitchAndFamily = FF_ROMAN | VARIABLE_PITCH;
  135. m_Fonts[ eCaptionFont ] = new CFont();
  136. m_Fonts[ eCaptionFont ]->CreateFontIndirect(&aFont);
  137. // the column heading font is 10-point bold, italic
  138. aPoint.y = (10 * GetDeviceCaps(inDC,LOGPIXELSY))/72;
  139. DPtoLP(inDC,&aPoint,1);
  140. memset(&aFont,0,sizeof(aFont));
  141. aFont.lfHeight = aPoint.y;
  142. aFont.lfItalic = 1;
  143. aFont.lfWeight = FW_BOLD;
  144. aFont.lfOutPrecision = OUT_TT_PRECIS ; // Truetype font
  145. aFont.lfQuality = PROOF_QUALITY;
  146. aFont.lfPitchAndFamily = FF_SWISS | VARIABLE_PITCH;
  147. m_Fonts[ eColHeadingFont ] = new CFont();
  148. m_Fonts[ eColHeadingFont ]->CreateFontIndirect(&aFont);
  149. // the data font is 10 point regular
  150. aPoint.y = (10 * GetDeviceCaps(inDC,LOGPIXELSY))/72;
  151. ::DPtoLP(inDC,&aPoint,1);
  152. memset(&aFont,0,sizeof(aFont));
  153. aFont.lfHeight = aPoint.y;
  154. aFont.lfWeight = FW_REGULAR;
  155. aFont.lfOutPrecision = OUT_TT_PRECIS; // Truetype font
  156. aFont.lfQuality = PROOF_QUALITY;
  157. aFont.lfPitchAndFamily = FF_ROMAN | FIXED_PITCH;
  158. m_Fonts[ eDataFont ] = new CFont();
  159. m_Fonts[ eDataFont ]->CreateFontIndirect(&aFont);
  160. // the text font is ansi variable font
  161. m_Fonts[ eTextFont ] = new CFont();
  162. m_Fonts[ eTextFont ]->CreateStockObject(ANSI_VAR_FONT);
  163. // determine the cell sizes for the fonts...
  164. TEXTMETRIC aTM;
  165. SelectObject(inDC,(HFONT)m_Fonts[eCaptionFont]);
  166. GetTextMetrics( inDC, &aTM );
  167. m_TextSizes[ eCaptionFont].cx = aTM.tmAveCharWidth;
  168. m_TextSizes[ eCaptionFont].cy = aTM.tmHeight;
  169. SelectObject(inDC,(HFONT)m_Fonts[eColHeadingFont]);
  170. GetTextMetrics( inDC, &aTM );
  171. m_TextSizes[ eColHeadingFont].cx = aTM.tmAveCharWidth;
  172. m_TextSizes[ eColHeadingFont].cy = aTM.tmHeight;
  173. SelectObject(inDC,(HFONT)m_Fonts[eDataFont]);
  174. GetTextMetrics(inDC,&aTM );
  175. m_TextSizes[ eDataFont].cx = aTM.tmAveCharWidth;
  176. m_TextSizes[ eDataFont].cy = aTM.tmHeight;
  177. SelectObject(inDC,(HFONT)m_Fonts[eTextFont]);
  178. GetTextMetrics(inDC,&aTM );
  179. m_TextSizes[ eTextFont].cx = aTM.tmAveCharWidth;
  180. m_TextSizes[ eTextFont].cy = aTM.tmHeight+ aTM.tmExternalLeading;
  181. m_BreakChar = aTM.tmBreakChar;
  182. }
  183. /*****************************************************************
  184.  * 
  185.  * method :CEasyReport::~CEasyReport()
  186.  *
  187.  * parameters : 
  188.  *
  189.  * returns : 
  190.  *
  191.  * description: Destructor. Clean up the resources we allocated.
  192.  *
  193.  ****************************************************************/
  194. CEasyReport::~CEasyReport()
  195. {
  196. DoCleanup();
  197. }
  198. /*****************************************************************
  199.  * 
  200.  * method :void CEasyReport::DoCleanup()
  201.  *
  202.  * parameters : 
  203.  *
  204.  * returns : 
  205.  *
  206.  * description: Clean up all the resources we allocated
  207.  *
  208.  *
  209.  ****************************************************************/
  210. void CEasyReport::DoCleanup()
  211. {
  212. int i;
  213. CElement *aElem;
  214. for(i=0; i< m_ReportItems.GetSize();i++)
  215. {
  216. aElem = (CElement *) m_ReportItems[i];
  217. delete aElem;
  218. }
  219. m_ReportItems.RemoveAll(); // clear counts...
  220. for(i=0;i< eMaxStyles;i++)
  221. {
  222. delete m_Fonts[i];
  223. m_Fonts[i]=NULL;
  224. }
  225. m_PageItems.RemoveAll();
  226. }
  227. /*****************************************************************
  228.  * 
  229.  * method :void SetupRectForCol(int inTabStop, CRect &outRect)
  230.  *
  231.  * parameters : 
  232.  *
  233.  * returns : 
  234.  *
  235.  * description: set up rectangle so that the printing can happen only 
  236.  * within the tab stop and the next tab stop, or up the edge of the 
  237.  * right margin
  238.  *
  239.  ****************************************************************/
  240. void CEasyReport::SetupRectForCol(int inTabStop, CRect &outRect)
  241. {
  242. outRect.top = m_DataTop;
  243. outRect.bottom = outRect.top + m_TextSizes[eDataFont].cy;
  244. if( inTabStop <= 0 )
  245. {
  246. // rectangle extends from the left edge upto the first tab stop
  247. outRect.left = m_LeftMargin;
  248. outRect.right = m_TabStops[1];
  249. return;
  250. }
  251. // If inTab is after the last valid tab, trim it to be within the right margin.
  252. if( inTabStop > m_TabStops.GetSize()-1)
  253. {
  254. // inTabStop = m_TabStops.GetSize()-1;
  255. // set to the last tab
  256. outRect.left = m_TabStops[ m_TabStops.GetSize() - 2 ];
  257. outRect.right = m_PageWidth - m_RightMargin;
  258. return;
  259. }
  260. outRect.left = m_TabStops[inTabStop];
  261. outRect.right = m_TabStops[inTabStop+1];
  262. }
  263. /*****************************************************************
  264.  * 
  265.  * method :void WriteParagraph(const char *inText)
  266.  *
  267.  * parameters : inText: Long text which may be word wrapped
  268.  *
  269.  * returns : nothing
  270.  *
  271.  * description: Write a paragraph of text. If the text extends 
  272.  * beyond the right edge, the text is wrapped around. Note: This 
  273.  * function is not called directly, but through AtTab with tabs
  274.  * set to NULL.
  275.  *
  276.  ****************************************************************/
  277. void CEasyReport::WriteParagraph(const char *inText)
  278. {
  279. int aAbsBottom, aAbsWidth;
  280. int aCurPos, aLen, aRight;
  281. char aTempStr[128]; // non portable (should be TCHAR etc)!
  282. CRect aRect;
  283. CSize aSize;
  284. CTextBox *aBox;
  285. aRect.left = m_LeftMargin;
  286. aRect.right = m_PageWidth - m_RightMargin;
  287. aAbsBottom = m_PageHeight - ( m_BottomMargin + m_PageFtrHt );
  288. aAbsWidth = m_PageWidth - ( m_LeftMargin + m_RightMargin);
  289. aLen = strlen(inText);
  290. aCurPos = 0;
  291. ::SelectObject(m_PrinterDC,(HFONT)m_Fonts[eTextFont]);
  292. ::SetTextCharacterExtra(m_PrinterDC,0);
  293. while(inText[aCurPos])
  294. {
  295. if( m_DataTop + m_TextSizes[eTextFont].cy > aAbsBottom )
  296. {
  297. EjectPage(false);
  298. aAbsBottom = m_PageHeight - ( m_BottomMargin + m_PageFtrHt );
  299. }
  300. // see if the remainder of the string will fit into the right margin
  301. ::SetTextJustification(m_PrinterDC,0,0);
  302. ::GetTextExtentExPoint(m_PrinterDC, inText + aCurPos, aLen - aCurPos, aAbsWidth, &aRight,NULL, &aSize);
  303. if( inText[aCurPos+aRight] != 0 )
  304. {
  305. while( inText [aCurPos + aRight ] != m_BreakChar )
  306. {
  307. --aRight;
  308. if( aRight <= 0 )
  309. {
  310. // Hopeless, the entire string is one big word !
  311. ::GetTextExtentExPoint(m_PrinterDC, inText + aCurPos, aLen - aCurPos, aAbsWidth, &aRight,NULL, &aSize);
  312. --aRight;
  313. break;
  314. }
  315. }
  316. }
  317. ASSERT(aRight < sizeof(aTempStr)); // Warning ! this check is at compile time only !
  318. strncpy( aTempStr, inText + aCurPos, aRight);
  319. aTempStr[aRight] = 0;
  320. aRect.top = m_DataTop;
  321. aRect.bottom = aRect.top + m_TextSizes[eTextFont].cy;
  322. aBox = new CTextBox(&aRect, aTempStr, eTextFont);
  323. aBox->SetDocPtr( this );
  324. m_ReportItems.Add(aBox);
  325. if( inText[ aCurPos + aRight] == m_BreakChar)
  326. ++aRight;
  327. aCurPos += aRight;
  328. m_DataTop += m_TextSizes[eTextFont].cy;
  329. }
  330. }
  331. /*****************************************************************
  332.  * 
  333.  * method :void CEasyReport::AtTab(int inTabStop, const char *inText)
  334.  *
  335.  * parameters : inTabStop
  336.  * char *inText: text to display
  337.  *
  338.  * returns : nothing
  339.  *
  340.  * description: If a tabular section is in place (ie if m_NumDataCols
  341.  * is non-zero, then we assume that this is a text area and we write
  342.  * out a paragraph. If a tabular section is in place, we write the
  343.  * data into the indicated column.
  344.  *
  345.  *
  346.  ****************************************************************/
  347. void CEasyReport::AtTab(int inTabStop, const char *inText)
  348. {
  349. CRect aRect;
  350. if( m_NumDataCols == 0)
  351. {
  352. WriteParagraph(inText);
  353. }
  354. else
  355. {
  356. if( m_RedrawTblHdr )
  357. {
  358. if( m_DataTop + m_TableHeadingHt + GetDataFontSize().cy > (GetBottomEdge() - m_PageFtrHt) )
  359. EjectPage(false);
  360. if( !m_RepeatTblHdr )
  361. WriteTableHeader();
  362. m_RedrawTblHdr = false;
  363. }
  364. SetupRectForCol(inTabStop, aRect);
  365. CTextBox *aBox = new CTextBox(&aRect,inText,eDataFont);
  366. aBox->SetDocPtr(this);
  367. ASSERT( inTabStop < m_NumDataCols);
  368. switch( m_DataCols[inTabStop].m_align)
  369. {
  370. case CColInfo::eLeft:
  371. aBox->SetAlign(DT_LEFT);
  372. break;
  373. case CColInfo::eDecimal:
  374. case CColInfo::eRight:
  375. // for fixed width fonts, if you control the format of data, then
  376. // simply aligning the text right aligns the decimal places. For 
  377. // propotional fonts, you will have to adjust the left edge of
  378. // the box.
  379. aBox->SetAlign(DT_RIGHT);
  380. break;
  381. case CColInfo::eCenter:
  382. aBox->SetAlign( DT_CENTER );
  383. break;
  384. }
  385. m_ReportItems.Add( aBox );
  386. }
  387. }
  388. /*****************************************************************
  389.  * 
  390.  * method :void CEasyReport::SetDataCols(CColInfo  *inCols, int inColCount)
  391.  *
  392.  * parameters : inCols : Array of CColInfo structur
  393.  * inColCount: # of columns.
  394.  *
  395.  * returns : Nothing
  396.  *
  397.  * description: Use this function to start a new tabular section
  398.  * on the report. If inCols == NULL (ie if the user wants a non tabular
  399.  * section) the tab stops are set to every 8 characters and the word
  400.  * wrap feature is enabled. 
  401.  *
  402.  * If inCols is not NULL, then the colum start positions are 
  403.  * calculated based on the character counts of the column. 
  404.  * 
  405.  * The algorithm supports multiple row headings - simply put a
  406.  * 'n' into the heading string. See example in SampleReportDoc.cpp
  407.  *
  408.  * Note: The colum width is in number of characters, which is easy,
  409.  * since typically, a database column width is specified in # of 
  410.  * characters. However, with True-type fonts and propotional spacing,
  411.  * the display may be truncated. To eliminate this problem, you might
  412.  * want to modify the code to either use MaxCharWidth for the font or
  413.  * you might want to specify the column with in LogicalUnits. Since 
  414.  * MM_LOMETRIC unit is used in the report, the column width would be 
  415.  * the size in mm * 10.
  416.  *
  417.  ****************************************************************/
  418. void CEasyReport::SetDataCols(CColInfo  *inCols, int inColCount)
  419. {
  420. int i, aLeft, aMax, aCharWidth;
  421. int nRows,nMaxRows;
  422. const char *s;
  423. CColInfo *aCol;
  424. m_TabStops.RemoveAll();
  425. if( inCols == NULL || inColCount == 0)
  426. {
  427. aCharWidth = m_TextSizes[ eTextFont].cx;
  428. m_DataCols = NULL;
  429. m_NumDataCols = 0;
  430. m_TableHeadingHt = 0;
  431. // Set up tabs at every 8 characters...
  432. aMax = (m_PageWidth - m_RightMargin) / 8;
  433. for(i=0; i <= aMax; i++)
  434. m_TabStops.Add((WORD)(m_LeftMargin + i * 8 * aCharWidth) );
  435. return;
  436. }
  437. aCharWidth = m_TextSizes[ eDataFont].cx;
  438. m_DataCols = inCols;
  439. m_NumDataCols = inColCount;
  440. nRows = nMaxRows = 1;
  441. aLeft = m_LeftMargin;
  442. aMax = m_PageWidth - m_RightMargin;
  443. i = 0;
  444. do
  445. {
  446. m_TabStops.Add( (WORD)aLeft );
  447. aCol = inCols + i;
  448. aLeft += aCol->m_CharCount * m_TextSizes[eDataFont].cx;
  449. ASSERT(aLeft < aMax); // check that we do not overflow the right edge
  450. // Calculate the height of this heading text...
  451. nRows = 1;
  452. s = aCol->m_Heading;
  453. if( s)
  454. {
  455. do
  456. {
  457. s = strchr(s,TCHAR('n'));
  458. if(s==NULL)
  459. break;
  460. ++s; // past the 'n'
  461. ++nRows; // bump row count
  462. }
  463. while(1);
  464. }
  465. if( nRows > nMaxRows )
  466. nMaxRows = nRows;
  467. ++i;
  468. }
  469. while(i < inColCount );
  470. m_TabStops.Add( (WORD)aLeft );
  471. m_TableHeadingHt = nMaxRows * m_TextSizes[ eColHeadingFont ].cy;
  472. if( !m_SuppressBlankTbl )
  473. {
  474. // We need to draw the heading. Check if there is enough room
  475. // on this page to draw the headings.
  476. if( m_DataTop + m_TableHeadingHt + GetDataFontSize().cy > (GetBottomEdge() - m_PageFtrHt) )
  477. EjectPage(false);
  478. if( !m_RepeatTblHdr )
  479. WriteTableHeader();
  480. }
  481. else
  482. {
  483. // deffer drawing the columns till something is written to this table
  484. m_RedrawTblHdr = true; 
  485. }
  486. }
  487. /*****************************************************************
  488.  * 
  489.  * method :void CEasyReport::EjectPage(bool inIsLastPage)
  490.  *
  491.  * parameters : inIsLastPage : true if this is the last page
  492.  * of the report.
  493.  *
  494.  * returns : nothing
  495.  *
  496.  * description: Call this function to eject the current page. if this
  497.  * is the last page, we print the report footer. If there
  498.  * is a page footer defined, it will be printed before starting the 
  499.  * new page. 
  500.  *
  501.  ****************************************************************/
  502. bool CEasyReport::EjectPage(bool inIsLastPage)
  503. {
  504. CRect aRect;
  505. int aRequiredHt, aAbsBottom;
  506. bool aAllPrinted = true;
  507. aRect.left = m_LeftMargin;
  508. aRect.right = m_PageWidth - m_RightMargin;
  509. aAbsBottom = m_PageHeight - m_BottomMargin;
  510. if(inIsLastPage)
  511. {
  512. // check to see if the PageFooter and the ReportFooter 
  513. // will fit on to the remaining area on this page. If so, 
  514. // print the page footer and the report footer. 
  515. aRequiredHt = m_PageFtrHt + m_ReportFtrHt;
  516. if( m_DataTop + aRequiredHt <= aAbsBottom )
  517. {
  518. aRect.top = aAbsBottom - (m_PageFtrHt+ m_ReportFtrHt);
  519. aRect.bottom = aRect.top + m_PageFtrHt;
  520. WritePageFooter(aRect);
  521. if( m_ReportFtrHt)
  522. {
  523. aRect.top = aRect.bottom;
  524. aRect.bottom += m_ReportFtrHt;
  525. WriteReportFooter(aRect);
  526. }
  527. }
  528. else
  529. {
  530. aRect.top = aAbsBottom - m_PageFtrHt;
  531. aRect.bottom = aRect.top + m_PageFtrHt;
  532. WritePageFooter(aRect);
  533. aAllPrinted = (m_ReportFtrHt >0 ? false : true);
  534. }
  535. }
  536. else
  537. {
  538. // not the last page of the report. Simply draw the page 
  539. // footer bottom aligned on the page
  540. if(m_PageFtrHt > 0 )
  541. {
  542. // bottom align the page footer on the page
  543. aRect.top = aAbsBottom - m_PageFtrHt;
  544. aRect.bottom = aRect.top + m_PageFtrHt;
  545. WritePageFooter(aRect);
  546. }
  547. }
  548. m_PageItems.Add(m_ReportItems.GetSize());
  549. ++m_PageCount;
  550. m_DataTop = m_TopMargin;
  551. // If not the last page, then print the page header if there
  552. // is a page header.
  553. if( !inIsLastPage && m_PageHdrHt > 0 )
  554. {
  555. aRect.top = m_DataTop;
  556. aRect.bottom = aRect.top + m_PageHdrHt;
  557. WritePageHeader(aRect);
  558. m_DataTop += m_PageHdrHt;
  559. }
  560. // Print the table header only if needed
  561. // m_RedrawTblHdr = false;
  562. if( !inIsLastPage && m_RepeatTblHdr && m_NumDataCols != 0 )
  563. {
  564. if( !m_SuppressBlankTbl )
  565. WriteTableHeader();
  566. else
  567. m_RedrawTblHdr = true;
  568. }
  569. return aAllPrinted;
  570. }
  571. /*****************************************************************
  572.  * 
  573.  * method :void CEasyReport::WriteTableHeader(void)
  574.  *
  575.  * parameters : 
  576.  *
  577.  * returns : 
  578.  *
  579.  * description: If a tabular section is in place, write the table
  580.  * header.
  581.  *
  582.  ****************************************************************/
  583. void CEasyReport::WriteTableHeader(void)
  584. {
  585. int i;
  586. CRect aRect;
  587. m_RedrawTblHdr = false;
  588. aRect.top = aRect.bottom = m_DataTop;
  589. aRect.bottom += m_TableHeadingHt;
  590. aRect.left= m_LeftMargin;
  591. for(i=0;i < m_NumDataCols; i++)
  592. {
  593. CColInfo *aCol = m_DataCols+i;
  594. aRect.right = aRect.left + aCol->m_CharCount * m_TextSizes[eDataFont].cx;
  595. CTextBox *aBox = new CTextBox(&aRect, aCol->m_Heading, eColHeadingFont);
  596. switch( aCol->m_align)
  597. {
  598. case CColInfo::eLeft:
  599. aBox->SetAlign(DT_LEFT);
  600. break;
  601. case CColInfo::eDecimal:
  602. case CColInfo::eRight:
  603. // for fixed width fonts, if you control the format of data, then
  604. // simply aligning the text right aligns the decimal places. For 
  605. // propotional fonts, you will have to adjust the left edge of
  606. // the box. Decimal cols will be supported in a later version
  607. aBox->SetAlign(DT_RIGHT);
  608. break;
  609. case CColInfo::eCenter:
  610. aBox->SetAlign( DT_CENTER );
  611. break;
  612. }
  613. aBox->SetDocPtr(this);
  614. m_ReportItems.Add(aBox);
  615. aRect.left = aRect.right;
  616. }
  617. m_DataTop += m_TableHeadingHt;
  618. }
  619. /*****************************************************************
  620.  * 
  621.  * method :void CEasyReport::NextRow()
  622.  *
  623.  * parameters : 
  624.  *
  625.  * returns : 
  626.  *
  627.  * description: Advance the current point by one row height
  628.  * If this moves the current point below the page margin, call 
  629.  * EjectPage. EjectPage will automatically write the page footer 
  630.  * and start a new page
  631.  *
  632.  ****************************************************************/
  633. void CEasyReport::NextRow()
  634. {
  635. m_DataTop += m_TextSizes[eDataFont].cy;
  636. // see if at least one data row will fit into the remaining
  637. // space on the page. If it does not, call EjectPage
  638. if( m_DataTop + m_TextSizes[eDataFont].cy + m_PageFtrHt > GetBottomEdge())
  639. EjectPage();
  640. }
  641. /*****************************************************************
  642.  * 
  643.  * method :void CEasyReport::Start(void)
  644.  *
  645.  * parameters : none
  646.  *
  647.  * returns : 
  648.  *
  649.  * description: Start the report generation. Create all the fonts, etc
  650.  * Try and get the printer device context, If no printer is set up as 
  651.  * the default printer on the system, create a screen device context. 
  652.  *
  653.  ****************************************************************/
  654. void CEasyReport::Start()
  655. {
  656. ASSERT( m_PrinterDC == NULL );
  657. DoCleanup();
  658. // set up a print date ..
  659. CTime aNow = CTime::GetCurrentTime();
  660. m_ReportDate.Format("Date: %2d/%2d/%4d", aNow.GetMonth(), aNow.GetDay(), aNow.GetYear());
  661. // NOTE: The following is most certainly not correct if there is 
  662. // no default printer defined ! If you do not have ANY printer, then
  663. // you might install a Fax printer (eg Microsoft Fax or Bitware etc)
  664. CPrintDialog aPD(false);
  665. if(aPD.GetDefaults())
  666. {
  667. m_PrinterDC = aPD.m_pd.hDC;
  668. }
  669. else
  670. {
  671. m_PrinterDC = ::GetDC(NULL); // get the screen device context
  672. }
  673. //::SetMapMode(m_PrinterDC, MM_ANISOTROPIC);
  674. //::SetWindowExtEx( m_PrinterDC, 254,254,NULL);
  675. //::SetViewportExtEx(m_PrinterDC, GetDeviceCaps(m_PrinterDC,LOGPIXELSX),GetDeviceCaps(m_PrinterDC,LOGPIXELSY),NULL);
  676. SetMapMode( m_PrinterDC, MM_LOMETRIC);
  677. SetupTextStyles( m_PrinterDC );
  678. m_DataTop = m_TopMargin;
  679. m_PageCount = 0;
  680. m_CurPage = 0;
  681. CRect aRect;
  682. // Write the report header...
  683. if( m_ReportHdrHt > 0 )
  684. {
  685. aRect.SetRect(m_LeftMargin, m_TopMargin, m_PageWidth - m_RightMargin,m_TopMargin + m_ReportHdrHt );
  686. aRect.bottom = aRect.top + m_ReportHdrHt;
  687. WriteReportHeader(aRect);
  688. m_DataTop += m_ReportHdrHt;
  689. }
  690. if( m_PageHdrHt > 0)
  691. {
  692. aRect.SetRect(m_LeftMargin, m_DataTop, m_PageWidth - m_RightMargin, m_DataTop + m_PageHdrHt);
  693. WritePageHeader(aRect);
  694. m_DataTop += m_PageHdrHt;
  695. }
  696. }
  697. /*****************************************************************
  698.  * 
  699.  * method :void CEasyReport::End()
  700.  *
  701.  * parameters : 
  702.  *
  703.  * returns : 
  704.  *
  705.  * description: End the report
  706.  *
  707.  ****************************************************************/
  708. void CEasyReport::End()
  709. {
  710. EjectPage(true);
  711. m_CurPage = 0;
  712. DeleteDC(m_PrinterDC);
  713. }
  714. /*****************************************************************
  715.  * 
  716.  * method :void WriteReportHeader(CRect inRect)
  717.  *
  718.  * parameters : 
  719.  *
  720.  * returns : 
  721.  *
  722.  * description: Write the default report header, which is a 
  723.  * simply the CompanyName centered across the page. You might 
  724.  * want to add the address, etc.
  725.  *
  726.  ****************************************************************/
  727. void CEasyReport::WriteReportHeader(CRect inRect)
  728. {
  729. CTextBox *aBox = new CTextBox(&inRect, m_CompanyName, eCaptionFont, DT_CENTER);
  730. aBox->SetDocPtr(this);
  731. m_ReportItems.Add(aBox);
  732. }
  733. /*****************************************************************
  734.  * 
  735.  * method :void CEasyReport::WriteReportFooter(CRect inRect)
  736.  *
  737.  * parameters : 
  738.  *
  739.  * returns : 
  740.  *
  741.  * description: Write the report footer. The default Report footer
  742.  * is blank.
  743.  *
  744.  *
  745.  ****************************************************************/
  746. void CEasyReport::WriteReportFooter(CRect inRect)
  747. {
  748. // CTextBox *aBox = new CTextBox(&inRect, "Report Footer", eCaptionFont);
  749. // aBox->SetDocPtr(this);
  750. // m_ReportItems.Add(aBox);
  751. }
  752. /*****************************************************************
  753.  * 
  754.  * method :void WritePageHeader(CRect inRect)
  755.  *
  756.  * parameters : 
  757.  *
  758.  * returns : 
  759.  *
  760.  * description: Write the default page header. By default, this
  761.  * contains the report title (centered) and date field, 
  762.  * right aligned
  763.  *
  764.  ****************************************************************/
  765. void CEasyReport::WritePageHeader(CRect inRect)
  766. {
  767. CRect aRect(inRect);
  768. CTextBox *aBox;
  769. aRect.bottom = aRect.top + GetHeadingFontSize().cy;
  770. aBox = new CTextBox(&aRect,m_ReportTitle,eColHeadingFont);
  771. aBox->SetDocPtr(this);
  772. m_ReportItems.Add(aBox);
  773. // make a text area 1/4 of the page width
  774. aRect.right = inRect.right;
  775. aRect.left = inRect.right - inRect.Width()/4;
  776. aBox = new CTextBox(&aRect, m_ReportDate, eColHeadingFont, DT_LEFT);
  777. aBox->SetDocPtr(this);
  778. m_ReportItems.Add(aBox);
  779. aRect.top = inRect.bottom-10; // 1mm from the bottom
  780. aRect.bottom = inRect.bottom;
  781. aRect.left = inRect.left;
  782. aRect.right = inRect.right;
  783. CHline *aLine = new CHline(&aRect,0);
  784. aLine->SetDocPtr(this);
  785. m_ReportItems.Add(aLine);
  786. }
  787. /*****************************************************************
  788.  * 
  789.  * method :void CEasyReport::WritePageFooter(CRect inRect)
  790.  *
  791.  * parameters : 
  792.  *
  793.  * returns : 
  794.  *
  795.  * description: Write the page footer
  796.  *
  797.  ****************************************************************/
  798. void CEasyReport::WritePageFooter(CRect inRect)
  799. {
  800. CRect aRect(inRect);
  801. aRect.top = aRect.bottom = inRect.top +10; // 1mm below 
  802. CHline *aLine = new CHline(&aRect,0);
  803. aLine->SetDocPtr(this);
  804. m_ReportItems.Add(aLine);
  805. aRect.top += 10; // 1mm
  806. aRect.bottom = aRect.top + GetHeadingFontSize().cy;
  807. CPageNum *aPgNumField = new CPageNum(&aRect,eColHeadingFont);
  808. aPgNumField->SetDocPtr(this);
  809. m_ReportItems.Add(aPgNumField);
  810. }
  811. /*****************************************************************
  812.  * 
  813.  * method :void DrawCurrentPage(CDC *inDC)
  814.  *
  815.  * parameters : inCDC a device context
  816.  *
  817.  * returns : nothing
  818.  *
  819.  * description: Draw the current page
  820.  *
  821.  *
  822.  ****************************************************************/
  823. void CEasyReport::DrawCurrentPage(CDC *inDC)
  824. {
  825. int i,aStart, aMax;
  826. CElement *aElem;
  827. if( m_CurPage != 0 )
  828. aStart = m_PageItems[m_CurPage-1];
  829. else
  830. aStart = 0;
  831. aMax = m_PageItems[m_CurPage];
  832. for( i =aStart;i< aMax;i++)
  833. {
  834. aElem = (CElement *)m_ReportItems[i];
  835. aElem->Draw(inDC);
  836. }
  837. /*
  838. CRect aRect(m_LeftMargin, -m_TopMargin, 
  839. m_PageWidth - m_RightMargin, -(m_PageHeight-m_BottomMargin));
  840. inDC->MoveTo(aRect.left, aRect.top);
  841. inDC->LineTo(aRect.right,aRect.top);
  842. inDC->LineTo(aRect.right, aRect.bottom);
  843. inDC->LineTo(aRect.left, aRect.bottom);
  844. inDC->LineTo(aRect.left, aRect.top);
  845. */
  846. }
  847. /*****************************************************************
  848.  * 
  849.  * method :const CFont *GetStyle(int inStyleIndex)
  850.  *
  851.  * parameters : inStyleIndex: integer 
  852.  *
  853.  * returns : CFont *
  854.  *
  855.  * description: Return a pointer to the font, NULL if the index
  856.  * is out of range.
  857.  *
  858.  *
  859.  ****************************************************************/
  860. const CFont *CEasyReport::GetStyle(int inStyleIndex)
  861. {
  862. ASSERT(inStyleIndex >=0 && inStyleIndex < eMaxStyles );
  863. if( inStyleIndex < eMaxStyles )
  864. return m_Fonts[ inStyleIndex ];
  865. else
  866. return NULL;
  867. }
  868. //**** end of EasyReport.cpp