Accounting Software
Small Business Software Estimating Software
Construction Estimating SoftwareBookkeeping SoftwareInventory SoftwareInventory Control SoftwareInventory Tracking SoftwareInventory Management SoftwareBusiness Management Software

Report Viewers (Source Code)

Link to: header | record viewer directory

Copyright Turtle Creek Software 1996-2006. All Rights Reserved.

This class manages report viewers for the Goldenseal accounting software,
small business management software, construction project management software and
construction estimating software.

Comments

DB_ReportViewer

a viewer that displays a report. This class handles the 'inner' or
lower part of the report window.

Superclass: DB_RecordViewer

Related classes: CReportEditor handles the top portion of window.
CReportTable handles the data display for report tables.
DB_ReportPrinter handles printing.

Constructor

/*********************************************************************************
PP stream constructor
*********************************************************************************/
DB_ReportViewer::DB_ReportViewer(LStream *inStream)
: THE_SUPERCLASS(inStream)
{
mTableCount = 0;
mReportEditor = nil;
mReportTable = nil;

mReportViewerFiller = 0;
mOneItemReport = false;
}/*********************************************************************************
constructor from struct information
*********************************************************************************/
DB_ReportViewer::DB_ReportViewer(const SPaneInfo &inPaneInfo,
const SViewInfo &inViewInfo)
: THE_SUPERCLASS(inPaneInfo, inViewInfo)
{
mTableCount = 0;
mReportEditor = nil;
mReportTable = nil;

mReportViewerFiller = 0;
mOneItemReport = false;
}

Source Code

/*********************************************************************************

DoFinalFieldSetup TCS 8/9/99

do any final setup work.

*********************************************************************************/
void DB_ReportViewer::DoFinalFieldSetup()
{
// sort our internal array in top-to-bottom order TCS 7/16/03
mLayoutPanes.SortWithComparator(NEW CLayoutPanePositionComparator);

// adjust the viewer size so it has room for all tables
StretchImageToFit();

// go through the viewer fields and see if we have a table
TMemberFieldArrayIterator iterator(mFieldInfoArray);
SMemberFieldInfo fieldInfo;
Boolean tableIsCondensed = false;

while (iterator.Next(fieldInfo))
{
TCS_TRY
{
if (fieldInfo.pane && fieldInfo.paneType == pane_table) // rev TCS 4/16/02
{
mTableCount++;

if (mTableCount == 1)
{
// we only reference the first table, and get report
// specs from it.
mReportTable = TCS_SAFE_CAST(fieldInfo.pane, CReportTable);
TCS_FailNILMsg(mReportTable, TCS_GetErrString(errID_BadTable));

mReportTable->GetReportData(mItemRange, mMatchClassID,
mStartDate, mEndDate,
mMatchValue, mReportClassID,
mMatchTag, mBreakdownTag,
mDateFieldType, mGroup, mAccountClassID,
mDateRange);

tableIsCondensed = mReportTable->StartsCondensed();
}
}
}
TCS_CATCH // if a field error, we still can continue the loop
{
}
}
// do we have a condensed table? TCS 6/1/01
SetStartsCondensed(mTableCount == 1 && tableIsCondensed);

// also have the editor do any final setup,
// now that the layout is loaded
TCS_FailNILMsg(mReportEditor, TCS_GetErrString(errID_BadEditor));
mReportEditor->SetIsOneItemReport(IsOneItemReport()); // TCS 6/4/01
mReportEditor->DoFinalFieldSetup();
}
/*********************************************************************************

CreateTablePane // TCS 6/29/99

create a report table pane.

*********************************************************************************/
LPane *DB_ReportViewer::CreateTablePane(const SPaneInfo &paneInfo,
const CTCS_TextInfo &/*textInfo*/,
CInputStream &stream,
const SMemberInfo &/*memberInfo*/,
Boolean /*isBreakdown*/,
const DB_ClassDescriptor */*descriptor*/)
{
// create a table from the stream
CReportTable *table =
NEW CReportTable(paneInfo, CTCS_View::sDefaultViewInfo, stream);
TCS_FailNILMsg(table, TCS_GetErrString(errID_BadTable));

// fill in titles
table->CreateStarterReportArray();

// flag the table so it doesn't get further initializing
table->SetAlreadyInited(true); // TCS 1/27/03

return table;
}/*********************************************************************************

ListenToMessage

listen to a message from one of this object's broadcasters

*********************************************************************************/
void DB_ReportViewer::ListenToMessage(MessageT inMessage, void *ioParam)
{
switch (inMessage)
{
// right now we don't do anything here-- CReportEditor handles the
// various poups and fields at the top. We may need to add code here later,
// e.g. if we start to do something when an object is double-clicked
default:
break;
}
// pass the message up
THE_SUPERCLASS::ListenToMessage(inMessage, ioParam);
}/*********************************************************************************

ObeyCommand

respond to a command, either from a menu or from another object

*********************************************************************************/
Boolean DB_ReportViewer::ObeyCommand(CommandT inCommand, void *ioParam)
{
Boolean cmdHandled = true;

gStopShowingErrors = false; // reset the multiple-error-warning suppresor
gShowOnlyOneError = false; // rev TCS 7/22/03

switch (inCommand)
{
/*case cmd_Print:
DoPrint();
break;*/

default:
cmdHandled = THE_SUPERCLASS::ObeyCommand(inCommand, ioParam);
break;
}

return cmdHandled;
}
/*********************************************************************************

FindCommandStatus TCS 2/8/99

enable/disable menu commands
*********************************************************************************/
void DB_ReportViewer::FindCommandStatus(CommandT inCommand, Boolean &outEnabled,
Boolean &outUsesMark, UInt16 &outMark,
Str255 outName)
{
switch (inCommand)
{
case cmd_Print :
outEnabled = true;
break;

default:
THE_SUPERCLASS::FindCommandStatus(inCommand, outEnabled,
outUsesMark, outMark, outName);
break;
}
}
#if CAN_USE_MARK
#pragma mark -
#endif
/*********************************************************************************

DoPrint v1.0, 04-24-1998 rev TCS 7/21/00

Print a record
*********************************************************************************/
void DB_ReportViewer::DoPrint()
{
DB_ReportPrinter *reportPrinter = NEW DB_ReportPrinter;
TCS_FailNILMsg(reportPrinter, TCS_GetErrString(errID_BadViewer));

TCS_TRY // TCS 1/13/02
{
reportPrinter->SetIsPrinting(true); // TCS 10/19/00
reportPrinter->SetReportEditor(mReportEditor); // TCS 10/19/00

reportPrinter->PrintReport(this);
}
TCS_CATCH {}

// dispose of the temporary print viewer
TCS_Forget(reportPrinter);

// we may have lost focus during print, so take it back TCS 6/25/99
LCommander::SwitchTarget(this);
}
/*********************************************************************************

DoTableSort TCS 4/16/02

Present a dialog and then sort a report table by the given column.
*********************************************************************************/
void DB_ReportViewer::DoTableSort()
{
TCS_ASSERTMsg(mReportTable, TCS_GetErrString(errID_BadTable));

Boolean sortAscending;
TableIndexT colNumber = DoSortDialog(sortAscending);

if (colNumber)
{
mReportTable->SortTableRows(colNumber, sortAscending);
}
}
/*********************************************************************************

DoSortDialog TCS 4/16/02

run the sort dialog

*********************************************************************************/
TableIndexT DB_ReportViewer::DoSortDialog(Boolean &sortAscending)
{
// sanity check
TCS_FailNILMsg(gDocument, TCS_GetErrString(errID_BadDocument));
TCS_ASSERTMsg(mReportTable, TCS_GetErrString(errID_BadTable));

if (!TCS_WindowExistsMsg(DLOG_Sort))
return 0;

// ok, let's prep the dlog
StDialogHandler theHandler(DLOG_Sort, gDocument);
LWindow *dialog = theHandler.GetDialog();
TCS_FailNILMsg(dialog, TCS_GetErrString(errID_BadDialog));

// set up the sort item popup
DB_Popup *itemPopup =
TCS_SAFE_CAST(dialog->FindPaneByID(popup_sortitems),
DB_Popup);
TCS_FailNILMsg(itemPopup, TCS_GetErrString(errID_BadPopup));
itemPopup->SetValue(sort_reporttable);
itemPopup->SetEnabled(false);
itemPopup->Refresh();

// set up the sort order popup
DB_Popup *orderPopup =
TCS_SAFE_CAST(dialog->FindPaneByID(popup_sortorder),
DB_Popup);
TCS_FailNILMsg(orderPopup, TCS_GetErrString(errID_BadPopup));
orderPopup->AddListener(&theHandler);

// get the field list table
CTextListTable *fieldList =
TCS_SAFE_CAST(dialog->FindPaneByID(CTextListTable::class_ID),
CTextListTable);
TCS_FailNILMsg(fieldList, TCS_GetErrString(errID_BadField));

// make sure the dialog listens to the field list
fieldList->AddListener(&theHandler);

// ok, got the desc, let's generate an array of members
// to use as sort criteria. If we search for member matching
// the 0 flag, we'll get them all. Note that we don't need
// to sort the member arrays, since we do that when we fill the table

// fetch column info from the table
SInt32 colCount = mReportTable->GetLastReportingCol();
CTextString colName;
TagType colTag;

// fill in the table
for (TableIndexT col = 1; col <= colCount; col++)
{
colName = mReportTable->GetColTitle(col);
colTag = mReportTable->GetColTag(col);
fieldList->AppendItem(colName, colTag);
}

// prep for modal dialog
Boolean dialogRunning = true;
Boolean success = false;
gInModalDialog = true;
MessageT hitMessage;

TCS_TRY
{
dialog->Show();
while (dialogRunning)
{
hitMessage = theHandler.DoDialog();

if (hitMessage)
switch (hitMessage)
{
case msg_TableDoubleClicked:
case msg_OK:
success = true;
dialogRunning = false;
break;

case msg_Cancel:
dialogRunning = false;
break;

case msg_BroadcasterDied: // we must have shut down
case msg_ShuttingDown:
return 0;
break;

default:
break;
}
}
}
TCS_CATCH
{
}
// we always reset the global
gInModalDialog = false;

if (success)
{ // they clicked ok, so let's fill in the sort params
sortAscending = (orderPopup->GetValue() == sort_ascending);

return fieldList->GetSelectedRow();
}

// if we got this far, return a zero for failure
return 0;
}
/*********************************************************************************

ReadFromLayoutHeader TCS 7/17/00

read in data from a layout header
*********************************************************************************/
void DB_ReportViewer::ReadFromLayoutHeader(const SLayoutHeader &header, const SInt32 format)
{
THE_SUPERCLASS::ReadFromLayoutHeader(header, format);

// set info in the editor
if (mReportEditor)
{
mReportEditor->SetUseDateRange(header.useDateRange);
mReportEditor->SetUseItemRange(header.useItemRange);
mReportEditor->SetUseBreakdown(header.useBreakdown);
}
}
#if CAN_USE_MARK
#pragma mark -
#endif
/******************************************************************************

CreateLayoutPane v1.0, 07-21-97 rev TCS 5/18/00

Create a pane from a layout

*******************************************************************************/
LPane *DB_ReportViewer::CreateLayoutPane(CInputStream &stream, const SInt16 paneType,
const SPaneInfo &paneInfo, const SLayoutInfo &mdInfo,
Boolean &gaveWarning, DB_ClassDescriptor *desc,
const Boolean isPasting)
{
SLayoutPaneInfo layoutInfo;
// Let the inherited method actually create the pane
layoutInfo.thePane = THE_SUPERCLASS::
CreateLayoutPane(stream, paneType, paneInfo,
mdInfo, gaveWarning, desc, isPasting);

// we keep a separate array of pane info, so append it to that
layoutInfo.layoutHeight = paneInfo.height;
layoutInfo.paneType = paneType; // TCS 7/16/03
mLayoutPanes.Append(layoutInfo);

return layoutInfo.thePane;
}
/*********************************************************************************

CreateCVField TCS 5/27/99

create a clairvoyant field for this layout

*********************************************************************************/
LPane *DB_ReportViewer::CreateCVField(const SMemberInfo &memberInfo, const SPaneInfo &paneInfo,
const SLayoutInfo &mdInfo, const CTCS_TextInfo &textInfo,
const FormatType format, const CTextString &/*helpText*/,
const Boolean /*editable*/)
{
// it's a cv field. For these fields, the size stored
// in paneInfo is actually the size of the enclosure. So we must adjust
// the size down to the size of the field itself
SPaneInfo cvPaneInfo = paneInfo;
cvPaneInfo.left += 2;
cvPaneInfo.top += 2;
cvPaneInfo.width -= 20;
cvPaneInfo.height -= 4;
// ok, now that we have the right size we can create the cv
DB_Clairvoyant *cv = DB_Clairvoyant::CreateCV(memberInfo, cvPaneInfo, textInfo,
0, // no popup or enclosure
format);

// if we were successful, do some setup
if (cv)
{
cv->SetLayoutInfo(mdInfo); // TCS 1/11/01

// we don't gray out report text // TCS 11/20/98
cv->SetDontGrayText(true);
}

return cv;
}/******************************************************************************

CalibratePanePositions v1.0, 07-21-97

Adjust pane positions for tables. Currently not used, and probably
not working.

*******************************************************************************/
void DB_ReportViewer::CalibratePanePositions()
{
SLayoutPaneInfo layoutInfo;
SDimension16 paneSize;
SInt32 deltaV = 0;
TLayoutPaneInfoArrayIterator iter (mLayoutPanes);

while (iter.Next(layoutInfo)) // TCS 7/16/03
{
// Strategy:
// -- Adjust the position of this pane by the cumulative
// vertical offset. Update the vertical offset
// -- Update the vertical offset by the difference between
// the current pane height & the previous height of the pane
// -- Save the current pane height as the previous pane height
layoutInfo.thePane->MoveBy(0, deltaV, cRedraw);
layoutInfo.thePane->GetFrameSize(paneSize);
deltaV += paneSize.height - layoutInfo.layoutHeight;
layoutInfo.layoutHeight = paneSize.height;
}
}
#if CAN_USE_MARK
#pragma mark -
#endif
/******************************************************************************

ResetCalculatorPanes TCS 12/19/00

let panes know that parameters have changed

*******************************************************************************/
void DB_ReportViewer::ResetCalculatorPanes(const SInt32 source)
{
// go through the viewer fields and update the object members
TMemberFieldArrayIterator iterator(mFieldInfoArray);
SMemberFieldInfo fieldInfo;
while (iterator.Next(fieldInfo))
{
TCS_TRY
{
if (!fieldInfo.pane)
{ // if the field pane is nil, we just move on to the next item
continue;
}
switch (fieldInfo.paneType)
{
case pane_table:
{
CReportTable *table = TCS_SAFE_CAST(fieldInfo.pane, CReportTable);
TCS_FailNILMsg(table, TCS_GetErrString(errID_BadTable));

// let the table know a change was made. We make it
// dirty for any change
if (source == calc_condensedchange)
table->SetCondensed(IsCondensed());
table->SetDisplayDirty(source);
}
break;

case pane_calcfield:
if (source != calc_condensedchange)
{
CReportCaption *calcPane = TCS_SAFE_CAST(fieldInfo.pane, CReportCaption);
TCS_FailNILMsg(calcPane, TCS_GetErrString(errID_BadPane));

// let the calculator know a change was made. We
// pass along the source of the change so the
// calculator can decide what needs to be done
calcPane->SetDisplayDirty(source);
}
break;

default: // other panes do not need recalc
break;
}
}
TCS_CATCH // if a field error, we still want to continue the loop
{
}
}
}
/******************************************************************************

UpdateCalculatorPanes TCS 6/29/99

update stored values in calculator panes and report tables, and redraw
everything

*******************************************************************************/
void DB_ReportViewer::UpdateCalculatorPanes()
{
// go through the viewer fields and update the object members
TMemberFieldArrayIterator iterator(mFieldInfoArray);
SMemberFieldInfo fieldInfo;
while (iterator.Next(fieldInfo))
{
TCS_TRY
{
if (!fieldInfo.pane)
{ // if the field pane is nil, we just move on to the next item
continue;
}
switch (fieldInfo.paneType)
{
case pane_table:
case pane_calcfield:
{
CReportInfoOwner *layoutObject = nil;
layoutObject = TCS_SAFE_CAST(fieldInfo.pane, CReportInfoOwner);
TCS_FailNILMsg(layoutObject, TCS_GetErrString(errID_BadPane));

layoutObject->SetIsOneItemReport(IsOneItemReport()); // TCS 7/9/01

// fill in data
layoutObject->SetReportData(mItemRange, mMatchClassID,
mStartDate, mEndDate, mMatchValue,
mReportClassID, mMatchTag, mBreakdownTag,
mDateFieldType, mGroup, mAccountClassID,
mDateRange);

// update the display TCS 8/27/99
layoutObject->UpdateReportDisplay();
}
break;

default: // other stuff does not need recalc
break;
}
}
TCS_CATCH // if a field error, we still want to continue the loop
{
}
}
// better reset image size TCS 7/21/99
StretchImageToFit();
}
/******************************************************************************

WriteTextToOutputStream TCS 8/9/99 rev TCS 7/16/03

fill in a text stream for a text export. We loop thru all layout objects
and have them each fill in whatever text they contain

*******************************************************************************/
void DB_ReportViewer::WriteTextToOutputStream(CTextOutputStream &stream)
{
// go through the viewer fields and fetch text from each.
// Note that we use mLayoutPanes instead of mFieldInfoArray.
// That's because we want to order the output top-to-bottom
// instead of back-to-front.
TLayoutPaneInfoArrayIterator iterator(mLayoutPanes);
SLayoutPaneInfo fieldInfo;

while (iterator.Next(fieldInfo))
{
TCS_TRY
{
if (!fieldInfo.thePane)
{ // if the field pane is nil, we just move on to the next item
continue;
}
switch (fieldInfo.paneType)
{
case pane_table:
{
CDataTable *table = nil;
table = TCS_SAFE_CAST(fieldInfo.thePane, CDataTable);
if (table)
table->WriteTextToOutputStream(stream);
}
break;

case pane_caption: // TCS 7/16/03
{
CLayoutTextPane *caption = nil;
caption = TCS_SAFE_CAST(fieldInfo.thePane, CLayoutTextPane);
if (caption)
caption->WriteTextToOutputStream(stream);
}
break;

case pane_calcfield:
{
CTCS_Caption *calcField = nil;
calcField = TCS_SAFE_CAST(fieldInfo.thePane, CTCS_Caption);
if (calcField)
calcField->WriteTextToOutputStream(stream);
}
break;

default: // we don't need to write out anything else
break;
}
}
TCS_CATCH // if a field error, we still want to continue the loop
{
}
}
}
/******************************************************************************

DrawSelf TCS 8/28/99

we want to fill in with white so we cover any buttons we may be hiding

*******************************************************************************/
void DB_ReportViewer::DrawSelf()
{
TStColorPenState penSaver; // TCS 2/20/04
penSaver.Normalize();

TCS_Rect frameR;
CalcLocalFrameRect(frameR);
if (mBackgroundColor != CTCS_RGBColor::GetWhiteColor())
TCS_SetForegroundColor(mBackgroundColor);
else
TCS_SetForegroundColor(CTCS_RGBColor::GetWhiteColor());

TCS_PaintRect(&frameR);
}
#if CAN_USE_MARK
#pragma mark -
#endif
/******************************************************************************

Compare v1.0, 07-21-97

Compare two SLayoutPaneInfo structs. We do that by vertical position

*******************************************************************************/
SInt32 CLayoutPanePositionComparator::Compare(const void *inItemOne,
const void *inItemTwo,
UInt32 inSizeOne,
UInt32 inSizeTwo) const
{
// Validate the input
TCS_ASSERTMsg((inSizeOne == sizeof(SLayoutPaneInfo)) &&
(inSizeTwo == sizeof(SLayoutPaneInfo)),
TCS_GetErrString(errID_ProblemDataSize));
TCS_FailNILMsg(inItemOne, TCS_GetErrString(errID_BadViewer));
TCS_FailNILMsg(inItemTwo, TCS_GetErrString(errID_BadViewer));

// get the structs
SLayoutPaneInfo *structOne = ((SLayoutPaneInfo *)inItemOne);
SLayoutPaneInfo *structTwo = ((SLayoutPaneInfo *)inItemTwo);

TCS_FailNILMsg(structOne, TCS_GetErrString(errID_BadComparator));
TCS_FailNILMsg(structTwo, TCS_GetErrString(errID_BadComparator));
// Compare the vertical position of the two panes
SPoint32 itemOnePos,
itemTwoPos;
LPane *pane1 = structOne->thePane,
*pane2 = structTwo->thePane;

TCS_FailNILMsg(pane1, TCS_GetErrString(errID_BadComparator)); // TCS 12/2/02
TCS_FailNILMsg(pane2, TCS_GetErrString(errID_BadComparator));
pane1->GetFrameLocation(itemOnePos);
pane2->GetFrameLocation(itemTwoPos);

// if the panes are the same vertically, compare the horiz.
if (itemOnePos.v == itemTwoPos.v) // TCS rev 7/16/03
return itemOnePos.h - itemTwoPos.h;
else
return itemOnePos.v - itemTwoPos.v;
}