home *** CD-ROM | disk | FTP | other *** search
- /*
- *
- * Report creation
- *
- * (C) 1990 Vision Software
- *
- * $Id: report.c 1.2002 91/05/04 16:24:47 pcalvin beta $
- *
- * Comments:
- *
- * Generates trivial reports from a specific database.
- * Non-trivial reports (i.e relations etc) are not yet supported.
- *
- * Bugs:
- *
- * None documented
- */
- #include <string.h>
-
- #include <stdhdr.h>
-
- #include <adl.h>
- #include <report.h>
-
- #include "lowlevel.h"
-
- /*
- * Virtual Base class for report output. Right now, we may
- * send reports to screen or printer.
- */
- class OUTPUT
- {
- public:
- OUTPUT(SZ szText,SZ szBar,PTL ptl,CCH cchMac);
- VIRTUAL ~OUTPUT();
- VIRTUAL VOID SendSz(SZ sz) = 0;
- BOOL FContinue();
- protected:
- VOID Title();
- VOID Terminate();
- ROW crowMac;
- ROW crowCurrent;
- SZ szTitleText;
- SZ szTitleBar;
- PTL ptlFirst;
- private:
- CCH cchReportWidthMac;
- BOOL fContinueReport;
- };
-
- /*
- * Screen reports.
- */
- class SCREEN_OUTPUT : public OUTPUT
- {
- public:
- SCREEN_OUTPUT(SZ szText,SZ szBar,PTL ptl,CCH cchWidthMac,CTL ctl);
- VIRTUAL ~SCREEN_OUTPUT();
- VIRTUAL VOID SendSz(SZ sz);
- private:
- WINDOW wnd;
- };
-
- /*
- * Printer reports.
- */
- class PRINTER_OUTPUT : public OUTPUT
- {
- public:
- PRINTER_OUTPUT(SZ szText,SZ szBar,PTL ptl,CCH cchWidthMac);
- VIRTUAL ~PRINTER_OUTPUT();
- VIRTUAL VOID SendSz(SZ sz);
- };
-
-
- /*
- * Simple creation, we just need a database to start report from
- */
- REPORT::REPORT(DATABASE &rdtbReport) : rdtb(rdtbReport)
- {
- penFirst = penNil;
- penCurrent = penNil;
- ptlFirst = ptlNil;
- ptlCurrent = ptlNil;
- ctlCurrent = ctlNil;
- cchReportWidthMac = cchNil;
- pfnFUsePdb = Nil;
- }
-
- REPORT::~REPORT()
- {
- PEN pen = penFirst;
- PTL ptl = ptlFirst;
-
- /*
- * Simply unload all the entries..
- */
- while (pen != penNil)
- {
- PEN penNext = pen->penNext;
-
- delete pen;
-
- pen = penNext;
- }
-
- /*
- * And the titles..
- */
- while (ptl != ptlNil)
- {
- PTL ptlNext = ptl->ptlNext;
-
- delete ptl;
-
- ptl = ptlNext;
- }
- }
-
- /*
- * Set filter for this report..
- */
- VOID REPORT::SetFilterTo(BOOL (*pfnFUse)(DBASE *pdb))
- {
- pfnFUsePdb = pfnFUse;
- }
-
- /*
- * Create a new title for this report
- */
- VOID REPORT::Title(SZ sz,AL al)
- {
- PointerAssert(sz);
-
- PTL ptl = new TL;
-
- /*
- * Create..
- */
- ptl->ptlNext = ptlNil;
- ptl->sz = sz;
- ptl->al = al;
-
- /*
- * Now, link in with the current list..
- */
- if (ptlFirst == ptlNil)
- ptlFirst = ptl;
-
- if (ptlCurrent != ptlNil)
- ptlCurrent->ptlNext = ptl;
-
- ptlCurrent = ptl;
- ctlCurrent++;
- }
-
- /*
- * Create a new report column
- */
- VOID REPORT::Entry(COL col,SZ sz,CCH cch,SZ szTitle)
- {
- Assert(sz != szNil);
-
- PEN pen = new EN;
-
- /*
- * Initialize the new Entry and then link with the rest..
- */
- pen->penPrev = penCurrent;
- pen->penNext = penNil;
- pen->col = col;
- pen->sz = sz;
- pen->cch = cch;
- pen->szTitle = szTitle;
-
- /*
- * Allow for creation of the first in the chain..
- */
- if (penFirst == penNil)
- penFirst = pen;
-
- if (penCurrent != penNil)
- penCurrent->penNext = pen;
-
- /*
- * Keep track of the maximum width..
- */
- cchReportWidthMac = Max(cchReportWidthMac,col+cch);
-
- penCurrent = pen;
- }
-
- /*
- * Creates the report..
- */
- VOID REPORT::Generate(BOOL fForward,BOOL fPrinter)
- {
- SZTEMP sz;
- OUTPUT *popt;
- BOOL (DATABASE:: *pfnInit)() = fForward ? DATABASE::FFirst : DATABASE::FLast;
- BOOL (DATABASE:: *pfnTraverse)() = fForward ? DATABASE::FNext : DATABASE::FPrevious;
-
- /*
- * Create Title bar..
- */
- CreateTitle(szTitleText,szTitleBar);
-
- /*
- * Creates and Initializes the output device.
- */
- if (fPrinter)
- popt = new PRINTER_OUTPUT(szTitleText,szTitleBar,ptlFirst,cchReportWidthMac);
- else
- popt = new SCREEN_OUTPUT(szTitleText,szTitleBar,ptlFirst,cchReportWidthMac,ctlCurrent);
-
- /*
- * Now, just traverse the database outputting each line
- */
- Verify((rdtb.*pfnInit)());
-
- do
- {
- /*
- * Must check filter first..
- */
- if (pfnFUsePdb == Nil || pfnFUsePdb(rdtb.PdbQuery()))
- {
- CreateOutput(sz);
-
- popt->SendSz(sz);
- }
- }
- while ((rdtb.*pfnTraverse)() && popt->FContinue());
-
- /*
- * Be sure to clean up our output device
- */
- delete popt;
- }
-
- /*
- * Creates the title bar and matching underline..
- */
- VOID REPORT::CreateTitle(SZ szText,SZ szBar)
- {
- CCH cchMac = cchNil;
-
- memset(szText,' ',cchSzTempMax);
- memset(szBar,' ',cchSzTempMax);
-
- for (PEN pen = penFirst; pen != penNil; pen = pen->penNext)
- {
- if (pen->sz != szNil)
- {
- strncpy(szText+pen->col,pen->szTitle,pen->cch);
- memset(szBar+pen->col,'=',Max(pen->cch,strlen(pen->szTitle)));
- }
-
- if (pen->cch + pen->col > cchMac)
- cchMac = pen->cch + pen->col;
- }
-
- OutputFix(szText,cchMac);
- OutputFix(szBar,cchMac);
- }
-
- /*
- * Output line. Called for each record..
- */
- VOID REPORT::CreateOutput(SZ sz)
- {
- CCH cchMac = cchNil;
-
- memset(sz,' ',cchSzTempMax);
-
- /*
- * Build output line..
- */
- for (PEN pen = penFirst; pen != penNil; pen = pen->penNext)
- {
- strncpy(sz+pen->col,pen->sz,pen->cch);
-
- if (pen->cch + pen->col > cchMac)
- cchMac = pen->cch + pen->col;
- }
-
- OutputFix(sz,cchMac);
- }
-
- /*
- * Removes any embedded \0 up to cchMac. Places \0 there
- */
- VOID REPORT::OutputFix(SZ sz,CCH cchMac)
- {
- /*
- * Place Nil at end..
- */
- sz[cchMac] = chNil;
-
- /*
- * Assert that any \0s within the text are removed..
- */
- for (CCH cch = cchNil; cch < cchMac; cch++)
- {
- if (sz[cch] == chNil)
- sz[cch] = chSpace;
- }
- }
-
- /*
- * Report Implementations.
- */
- OUTPUT::OUTPUT(SZ szText,SZ szBar,PTL ptl,CCH cchMac)
- {
- szTitleText = szText;
- szTitleBar = szBar;
- ptlFirst = ptl;
- fContinueReport = fTrue;
- cchReportWidthMac = cchMac;
- }
-
- /*
- * Place holder for the destructor
- */
- OUTPUT::~OUTPUT()
- {
- }
-
- /*
- * Answer if the report should be Continued..
- */
- BOOL OUTPUT::FContinue()
- {
- return (fContinueReport);
- }
-
- /*
- * Signals the termination of the report.
- */
- VOID OUTPUT::Terminate()
- {
- fContinueReport = fFalse;
- }
-
- /*
- * Report titles..
- */
- VOID OUTPUT::Title()
- {
- PTL ptl = ptlFirst;
-
- /*
- * Output the title..
- */
- while (ptl != ptlNil)
- {
- SZTEMP sz;
- CCH cchLength = strlen(ptl->sz);
- CCH cchOffset = cchNil;
-
- /*
- * Build the string/left/cented right
- */
- memset(sz,' ',cchSzTempMax);
-
- switch (ptl->al)
- {
- case alLeft:
- cchOffset = cchNil;
- break;
- case alCentre:
- cchOffset = (cchReportWidthMac >> 1) - (cchLength >> 1);
- break;
- case alRight:
- cchOffset = cchReportWidthMac - cchLength;
- break;
- }
-
- /*
- * Now, pad the string with amount of spaces and output it..
- */
- strcpy(sz+cchOffset,ptl->sz);
- SendSz(sz);
-
- ptl = ptl->ptlNext;
- }
-
- /*
- * Output title/bar and reset cursor position
- */
- SendSz(szTitleText);
- SendSz(szTitleBar);
- }
-
- /*
- * Screen output initialization. Opens the window and displays
- * the first title/headings.
- */
- SCREEN_OUTPUT::SCREEN_OUTPUT(SZ szText,SZ szBar,PTL ptl,CCH cchWidthMac,CTL ctl) : OUTPUT(szText,szBar,ptl,cchWidthMac)
- {
- crowMac = rowGlobalWindowBottom - 9 - ctl;
- crowCurrent = rowNil;
- wnd = WINDOW(4,3,rowGlobalWindowBottom-4,colGlobalWindowRight-3,coBlack,coCyan,szNil,fTrue);
-
- /*
- * Initialize window. Set scroll region so that title bar appears
- * all the time..
- */
- wnd.Open();
- wnd.SetScrollRow(6+ctl,rowGlobalWindowBottom-4);
-
- /*
- * Output the title if any
- */
- Title();
-
- /*
- * Since the TITLE is Fixed (I.e the window scrolls around it, reset
- * the row counter here.
- */
- crowCurrent = rowNil;
- }
-
- /*
- * Remove the window..
- */
- SCREEN_OUTPUT::~SCREEN_OUTPUT()
- {
- HELP hlp("Report finished, Press any key to continue");
-
- (VOID)CdInput();
-
- wnd.Close();
- }
-
- /*
- * A single line of the report..
- */
- VOID SCREEN_OUTPUT::SendSz(SZ sz)
- {
- /*
- * Output the report line.
- */
- wnd.Say(sz);
-
- /*
- * For output to the screen, give the users a screenful at a time
- */
- if (++crowCurrent >= crowMac)
- {
- HELP hlp("Press ESC to Quit, any other key to continue");
-
- if (CdInput() == cdEscape)
- Terminate();
-
- crowCurrent = rowNil;
- }
-
- /*
- * If report is to continue, place the NL at the end
- */
- if (FContinue())
- wnd.PutCh(chReturn);
- }
-
- /*
- * Printer initialization
- */
- PRINTER_OUTPUT::PRINTER_OUTPUT(SZ szText,SZ szBar,PTL ptl,CCH cchWidthMac) : OUTPUT(szText,szBar,ptl,cchWidthMac)
- {
- crowMac = 60;
- crowCurrent = rowNil;
-
- /*
- * Output the title if any
- */
- Title();
- }
-
- /*
- * Not much to do after the printer is finished
- */
- PRINTER_OUTPUT::~PRINTER_OUTPUT()
- {
- }
-
- /*
- * Send a single line to the printer.
- */
- VOID PRINTER_OUTPUT::SendSz(SZ sz)
- {
- fprintf(stdprn,"%s\n",sz);
-
- if (++crowCurrent >= crowMac)
- {
- fprintf(stdprn,"\n\n\n\n\n\n");
- fprintf(stdprn,"%s\n",szTitleText);
- fprintf(stdprn,"%s\n",szTitleBar);
- crowCurrent = 0;
- }
- }
-