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;
}
|