home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Demos / OOFILE / Buildable, limited OOFILE / OOFILE partial source / oofrw.cpp < prev    next >
Encoding:
Text File  |  1995-09-18  |  13.5 KB  |  523 lines  |  [TEXT/CWIE]

  1. // COPYRIGHT 1994 A.D. Software, All rights reserved
  2.  
  3. // report-writer layer of OOFILE database
  4.  
  5. // NOTE inline definitions included at end of this header file
  6.  
  7. #include "oof3.hpp"  // knows a bit about fields
  8. #include "oofrw.hpp"
  9. #include <string.h>
  10.  
  11. unsigned int dbRepLine::mWidth;
  12.  
  13. // -------------------------------------------------------
  14. //             d b R e p O v e r R u n
  15. // -------------------------------------------------------
  16.  
  17. // -------------------------------------------------------
  18. //                d b R e p L i n e
  19. // -------------------------------------------------------
  20.  
  21. dbRepLine::~dbRepLine()
  22. {
  23.     delete[] mLine;
  24. }
  25.  
  26. void dbRepLine::prepare()
  27. // Generate a new Line and fill it with whitespace
  28. //
  29. {
  30.     if(!mLine){
  31.         mLine = new char[mWidth+1];        // We'll null-terminate just to be safe
  32.         assert(mLine);
  33.         mLine[mWidth]='\0';
  34.         memset(mLine, 0x20, mWidth);    // 0x20 is ASCII for space
  35. #ifdef OOF_SmartHeap
  36.     MemPoolCheck(MemDefaultPool);
  37. #endif
  38.     }
  39. }
  40.  
  41. void dbRepLine::clear()
  42. {
  43.     delete[] mLine;
  44.     mLine = 0;
  45. }
  46.  
  47. void dbRepLine::drawNCharsAt(unsigned int hPos, char* theChars, unsigned int len)
  48. {
  49.     prepare();                // Make sure we have some space to draw on
  50.     unsigned long memLen=strlen(theChars);
  51.     if(memLen>len)
  52.         memLen=len;
  53.     memcpy(&mLine[hPos],theChars,memLen);
  54. #ifdef OOF_SmartHeap
  55.     MemPoolCheck(MemDefaultPool);
  56. #endif
  57. }
  58.  
  59. void dbRepLine::fillNCharsAt(unsigned int hPos, char theChar, unsigned int len)
  60. {
  61.     prepare();                // Make sure we have some space to draw on
  62.     memset(&mLine[hPos],theChar,len);
  63. #ifdef OOF_SmartHeap
  64.     MemPoolCheck(MemDefaultPool);
  65. #endif
  66. }
  67.  
  68. void dbRepLine::drawToStream(unsigned int hPos, unsigned int len, ostream& os)
  69. {
  70.     if(mLine)
  71.         os.write(&mLine[hPos],len);
  72. }
  73.  
  74. // -------------------------------------------------------
  75. //               d b R e p S i z e r
  76. // -------------------------------------------------------
  77.  
  78.  
  79. // -------------------------------------------------------
  80. //                d b R e p P a g e
  81. // -------------------------------------------------------
  82.  
  83. dbRepPage::dbRepPage() : 
  84.                                         mPageMap(0),
  85.                                         mFieldPos(0),
  86.                                         mPageStart(0)
  87. {
  88. // Do nothing - We are built by the appropriate FormatFor... routine.
  89. //
  90. //   At present, only CharStream is supported
  91. };
  92.  
  93.  
  94. dbRepPage::~dbRepPage()
  95. {
  96.     delete[] mPageMap;
  97. }
  98.  
  99. void dbRepPage::draw(dbRepSizer Sizer, ostream& os)
  100. {
  101.     for(unsigned int pageNum=0;pageNum<mNumPages;pageNum++)
  102.     {
  103.         for(unsigned int i=0;i<Sizer.mTopMargin;i++)          // Top Margin
  104.             os << endl;
  105.         
  106.         unsigned int thispageWidth;                                                // Work out how much we have to draw
  107.         if (pageNum+1==mNumPages) {
  108.             thispageWidth=mWidth-mPageBreak[pageNum];
  109.         } else {
  110.             thispageWidth=mPageBreak[pageNum+1]-mPageBreak[pageNum];
  111.         }
  112.         for(unsigned int lineNum=0;lineNum<mNumLines;lineNum++)
  113.         {
  114.             for(unsigned int l=0;l<Sizer.mLeftMargin;l++)
  115.                 os << ' ';
  116.             mPageMap[lineNum].drawToStream(mPageBreak[pageNum],thispageWidth,os);    // draw the stuff
  117.             os << endl;
  118.         }
  119.         for(unsigned int k=0;k<Sizer.mBottomMargin;k++)        // Bottom Margin
  120.             os << endl;
  121.         
  122.         endPage(os);
  123.     }
  124. }
  125.  
  126. void dbRepPage::clearLines(unsigned int start, unsigned int end)
  127. {
  128.     assert(end>=start);
  129.     assert(start<mNumLines);
  130.     
  131.     for(unsigned int i=start;i<=end;i++)
  132.         mPageMap[i].clear();
  133. }
  134.  
  135. void dbRepPage::endPage(ostream& os)
  136. {
  137.     os << "---cut here---" << endl;
  138. }
  139.  
  140. // -------------------------------------------------------
  141. //                    d b R e p
  142. // -------------------------------------------------------
  143.  
  144. void dbRep::setStyle(const ReportStyles style)
  145. {
  146.     mReportStyle = style;
  147. }
  148.  
  149.  
  150.  
  151. void dbRep::formatForCharStream()
  152. // Builds the contents of our dbRepPage for Character Stream.
  153. //
  154. {
  155.     unsigned int numfields;
  156.     
  157.     switch(mReportStyle) {
  158.         case columnar: numfields = mFields.count();
  159.                                         break;
  160.                                         
  161.         case pageWise: numfields = 2;
  162.                                         break;
  163.         
  164.         default: assert(false);
  165.     }
  166.     
  167.     mPage.mFieldPos = new unsigned int[numfields];
  168.  
  169.     unsigned int Printable = mSizer.mPageWidth - (mSizer.mLeftMargin + mSizer.mRightMargin);        // Actual Printable Width
  170.     
  171.     mPage.mWidth = 0;
  172.     int FirstOnPage = true;
  173.     unsigned int CurrpageWidth = 0;
  174.     mPage.mNumPages = 1;
  175.     mPage.mPageBreak.append(0);
  176.     for (unsigned int i=0; i<numfields; i++)
  177.     {
  178.         mPage.mFieldPos[i] = mPage.mWidth;
  179.         if (CurrpageWidth + mColWidths[i] <= Printable) {            // Can we fit the next field in this page ?
  180.             mPage.mWidth+=mColWidths[i];
  181.             CurrpageWidth+=mColWidths[i];
  182.             FirstOnPage = false;
  183.             if (CurrpageWidth + mSizer.mColSepWidth <= Printable) {        // Add space between columns
  184.                 mPage.mWidth+=mSizer.mColSepWidth;
  185.                 CurrpageWidth+=mSizer.mColSepWidth;
  186.             } else {
  187.                 if(i!=numfields-1) {                                                                // If there are any more fields...
  188.                     mPage.mNumPages++;                                                                // Time for a new page
  189.                     if(mReportStyle==pageWise)
  190.                         assert(false);
  191.                     mPage.mPageBreak.append(mPage.mWidth);
  192.                     FirstOnPage = true;
  193.                     CurrpageWidth = 0;
  194.                 }
  195.             }
  196.         } else {
  197.             if (FirstOnPage) {
  198.                 mColWidths[i] = Printable;                                                // We're the only field on this page - We'll have to squeeze in
  199.                 CurrpageWidth+=Printable;
  200.                 mPage.mWidth+=Printable;
  201.                 FirstOnPage = false;
  202.             } else {
  203.                 i--;                                                                                            // Go back and fetch this one again on a new page
  204.                 mPage.mNumPages++;                                                                // Time for a new page
  205.                 mPage.mPageBreak.append(mPage.mWidth);
  206.                 FirstOnPage = true;
  207.                 CurrpageWidth = 0;
  208.             }
  209.         }
  210.     }
  211.  
  212.     mPage.mNumLines = mSizer.mPageHeight - (mSizer.mTopMargin + mSizer.mBottomMargin);                        // Actual Printable Height
  213.     assert(mPage.mNumLines>0);
  214.     mPage.mPageMap = new dbRepLine[mPage.mNumLines];
  215.     
  216.     dbRepLine::mWidth = mPage.mWidth;
  217. }
  218.  
  219.  
  220. void dbRep::drawHeader(ostream& os)
  221. {
  222.     switch(mReportStyle) {
  223.         case columnar: {    unsigned int numFields = mFields.count();
  224.                                 for(unsigned int i=0;i<numFields;i++)
  225.                                         {
  226.                                             dbField  *theField = (dbField  *) mFields[i];  // safe downcast (Or so the Guru tells me !)
  227.                                             mPage.mPageMap[0].drawNCharsAt(mPage.mFieldPos[i],theField->fieldName(),mColWidths[i]);
  228.                                             mPage.mPageMap[1].fillNCharsAt(mPage.mFieldPos[i],'-',mColWidths[i]);
  229.                                         }
  230.                                         mPage.mBodyStart = 3;
  231.                                         break;
  232.                                         }
  233.                                         
  234.         case pageWise: mPage.mBodyStart = 0;            // PageWise has no header.]
  235.                                       break;
  236.         
  237.         default:assert(false);
  238.     }
  239. }
  240.  
  241. unsigned int dbRep::drawWrappedChars(unsigned int line,unsigned int hPos,unsigned int width,char **theString)
  242. {
  243.         unsigned long dataLen = strlen(*theString);
  244.         unsigned int numLines = 0;
  245.         
  246.         while((dataLen>0)&&(line+numLines<mPage.mNumLines)) {
  247.         
  248.             unsigned int i=0;
  249.             
  250.             char *simpleStr=*theString;
  251.             
  252.             for(;((simpleStr[i]!='\0')&&(simpleStr[i]!='\n')&&(i<width));i++)
  253.                 ;
  254.                     // Hunt down and kill carriage returns
  255.                     // Perhaps we should convert tabs to spaces as well ?
  256.                     
  257.             if (i==width) {                        // we ran out of room - back up to the end of the last word.
  258.                 for(;((simpleStr[i]!=' ')&&(i>0));i--)
  259.                     ;
  260.                 if(i==0)
  261.                     i=width;                            // the word was too long for the field width - so we'll just chop it !
  262.             }
  263.             
  264.             *theString+=i;
  265.             dataLen-=i;
  266.             if ((simpleStr[i]=='\n')||(simpleStr[i]==' '))    {
  267.                 *theString+=1;                    // skip over the CR or the space
  268.                 dataLen--;
  269.             }
  270.  
  271.             mPage.mPageMap[line+numLines].drawNCharsAt(hPos,simpleStr,i);                // draw the stuff !
  272.             
  273.             numLines++;
  274.         }
  275.  
  276.         if (dataLen>0)        // It won't fit !
  277.             numLines=0xff;        
  278.         
  279.         return(numLines);
  280. }
  281.  
  282. void dbRep::drawColumnar(ostream& os)
  283. {
  284. // NOTE: mFields.table = the database/selection
  285. // mFields = ordered list of fields to report
  286.  
  287.     int FirstOnPage = true;
  288.     
  289.   dbRepOverRun *recOverRun = new dbRepOverRun[mFields.count()];
  290.     
  291.     unsigned int currentLine = mPage.mBodyStart;
  292.     char *theString;
  293.     char *deleteMe;
  294.     int IsOverRun = false;
  295.     int OverRunning = false;
  296.  
  297.     unsigned int numFields = mFields.count();
  298.     mFields.source()->start();        // start record iteration (vertical)
  299.     while (mFields.source()->more()) {
  300.  
  301.         int Advance = true;
  302.         unsigned int maxLines = 0;
  303.  
  304.         for (unsigned int i=0; i<numFields; i++) {        // start field iteration (horizontal)
  305.             dbField  *theField = (dbField  *) mFields[i];           // safe downcast
  306.             
  307.             if(IsOverRun)
  308.             {
  309.                 if(!recOverRun[i].OverRun)
  310.                     continue;
  311.                 theString = recOverRun[i].OverRun;
  312.                 deleteMe = recOverRun[i].DeleteMe;
  313.                 recOverRun[i].OverRun=0;
  314.             } else {
  315.                 theString = theField->copyAsChars();                    // retrieve the field data as a char*
  316.                 deleteMe = theString;                                                    // keep track of our original pointer
  317.             }
  318.             
  319.             unsigned int linesUsed = drawWrappedChars(currentLine,mPage.mFieldPos[i],mColWidths[i],&theString);
  320.             // WARNING - drawWrappedChars WILL change the value of theString !
  321.             
  322.             if (linesUsed==0xff)
  323.                 if (FirstOnPage) {
  324.                     recOverRun[i].OverRun=theString;
  325.                     recOverRun[i].DeleteMe=deleteMe;
  326.                     Advance = false;
  327.                     OverRunning = true;
  328.                     linesUsed = mPage.mNumLines-currentLine;
  329.                 } else {
  330.                     mPage.clearLines(currentLine,mPage.mNumLines-1);
  331.                     currentLine = mPage.mNumLines;
  332.                     delete[] deleteMe;
  333.                     Advance = false;
  334.                     break;
  335.                 }
  336.             
  337.             if (linesUsed>maxLines)
  338.                 maxLines=linesUsed;
  339.             
  340.             if((!OverRunning)||(OverRunning&&(recOverRun[i].DeleteMe!=deleteMe)))
  341.                 delete[] deleteMe;                                                                    // throw it away now that we're done
  342.         }
  343.         IsOverRun = OverRunning;
  344.         OverRunning = false;
  345.  
  346.         currentLine+=(mSizer.mBlockVertSep + maxLines);
  347.         
  348.         FirstOnPage = false;
  349.         
  350.         if(currentLine>=mPage.mNumLines) {                                    // time to start a new page
  351.             mPage.draw(mSizer,os);
  352.             mPage.clearLines(mPage.mBodyStart,mPage.mNumLines-1);
  353.             currentLine = mPage.mBodyStart;
  354.             FirstOnPage = true;
  355.         }
  356.         if (Advance)
  357.             mFields.source()->next();
  358.     }
  359.     
  360.     if(currentLine != mPage.mBodyStart)
  361.         mPage.draw(mSizer, os);
  362. }
  363.  
  364. void dbRep::drawPageWise(ostream& os)
  365. {
  366. // NOTE: mFields.table = the database/selection
  367. // mFields = ordered list of fields to report
  368.  
  369.     int FirstOnPage = true;
  370.     
  371.     unsigned int currentLine = mPage.mBodyStart;
  372.     char *theString;
  373.     char *deleteMe;
  374.     unsigned int fNum;
  375.  
  376.   dbRepOverRun *recOverRun = new dbRepOverRun[2];    
  377.     int IsOverRun = false;
  378.     int OverRunning = false;
  379.  
  380.    unsigned int numFields = mFields.count();
  381.     mFields.source()->start();        // start record iteration (vertical)
  382.     while (mFields.source()->more()) {
  383.     
  384.         unsigned int recordStart = currentLine;
  385.         int Advance = true;
  386.         if (!IsOverRun)
  387.             fNum=0;                                                                                                            // start field iteration (horizontal)
  388.         
  389.         while (fNum<numFields) {
  390.             dbField  *theField = (dbField  *) mFields[fNum];                       // safe downcast
  391.             
  392.             unsigned int maxLines = 0;
  393.  
  394.             for (unsigned int i=0; i<2; i++) {                                                // page left->right
  395.                 if(IsOverRun)
  396.                 {
  397.                     if(!recOverRun[i].OverRun)
  398.                         continue;
  399.                     theString = recOverRun[i].OverRun;
  400.                     deleteMe = recOverRun[i].DeleteMe;
  401.                     recOverRun->OverRun=0;
  402.                 } else {
  403.                     if (i==0)
  404.                         theString = copyStr(theField->fieldName());    // retrieve the field name as a separate char*
  405.                     else
  406.                         theString = theField->copyAsChars();                // retrieve the field data as a char*
  407.                     deleteMe = theString;                                                    // keep track of our original pointer
  408.                 }
  409.                 
  410.                 unsigned int linesUsed = drawWrappedChars(currentLine,mPage.mFieldPos[i],mColWidths[i],&theString);
  411.                 // WARNING - drawWrappedChars WILL change the value of theString !
  412.                 
  413.                 if (linesUsed==0xff)
  414.                     if (FirstOnPage) {
  415.                         recOverRun[i].OverRun=theString;
  416.                         recOverRun[i].DeleteMe=deleteMe;
  417.                         Advance = false;
  418.                         OverRunning = true;
  419.                         currentLine = mPage.mNumLines;
  420.                     } else {
  421.                         mPage.clearLines(recordStart,mPage.mNumLines-1);
  422.                         currentLine = mPage.mNumLines;
  423.                         delete[] deleteMe;
  424.                         Advance = false;
  425.                         break;
  426.                     }
  427.                 
  428.                 if (linesUsed>maxLines)
  429.                     maxLines=linesUsed;
  430.                 
  431.                 if((!OverRunning)||(OverRunning&&(recOverRun[i].DeleteMe!=deleteMe)))
  432.                     delete[] deleteMe;                                                                    // throw it away now that we're done
  433.  
  434.             }
  435.             IsOverRun = OverRunning;
  436.             OverRunning = false;
  437.  
  438.             if(IsOverRun)
  439.                 break;
  440.                 
  441.             currentLine+=(mSizer.mBlockVertSep + maxLines);
  442.             
  443.             fNum++;                                                                                // Go on to the next field - We won't get here if we're OverRun
  444.         }
  445.         
  446.         FirstOnPage = false;
  447.         
  448.         if(currentLine>=mPage.mNumLines) {                                    // time to start a new page
  449.             mPage.draw(mSizer,os);
  450.             mPage.clearLines(mPage.mBodyStart,mPage.mNumLines-1);
  451.             currentLine = mPage.mBodyStart;
  452.             FirstOnPage = true;
  453.         }
  454.         if (Advance)
  455.             mFields.source()->next();
  456.     }
  457.     
  458.     if(currentLine != mPage.mBodyStart)
  459.         mPage.draw(mSizer, os);
  460. }
  461.  
  462. void dbRep::draw(ostream& os)
  463. {
  464.     drawHeader(os);
  465.  
  466.     switch(mReportStyle)  {
  467.         case columnar: drawColumnar(os);
  468.                                         break;
  469.         
  470.         case pageWise: drawPageWise(os);
  471.                                         break;
  472.         
  473.         default:assert(false);
  474.                          break;
  475.     }
  476. }
  477.  
  478. void dbRep::dumpFieldList(ostream& os)
  479. {
  480.     os << "title:" << mSizer.mReportTitle << endl;
  481.     os << "LineWidth:" <<mPage.mWidth << endl;
  482.     os << "Page Breaks: ";
  483.     for (unsigned int j=0; j<mPage.mNumPages; j++)
  484.         os << mPage.mPageBreak[j] << "\t";
  485.     os << endl;
  486.     unsigned int numFields = mFields.count();
  487.     for (unsigned int i=0; i<numFields; i++)
  488.     {
  489.             dbField  *theField = (dbField  *) mFields[i];  // safe downcast
  490.             os << theField->fieldName() << endl;  
  491.     }
  492. }
  493.  
  494.  
  495. void dbRep::extract(ostream& os)
  496. {
  497.   unsigned int rNum=1;
  498.  
  499.     unsigned int numFields = mFields.count();
  500.     mFields.source()->start();        // start record iteration (vertical)
  501.     while (mFields.source()->more()) {
  502.         os << endl << "Record# " << rNum++ << endl;
  503.         for (unsigned int i=0; i<numFields; i++) {        // start field iteration (horizontal)
  504.             dbField  *theField = (dbField  *) mFields[i];           // safe downcast
  505.             char *theString = theField->copyAsChars();
  506.             os << theField->fieldName() << " : " << theString << endl;
  507.             delete theString;
  508.         }
  509.     
  510.         mFields.source()->next();    
  511.     }
  512. }
  513.  
  514. char *dbRep::copyStr(char *theString)
  515. {
  516.     unsigned long dataLen = strlen(theString);
  517.  
  518.     char *retStr = new char[dataLen+1];
  519.     
  520.     strcpy(retStr,theString);
  521.     
  522.     return(retStr);
  523. }