Link to: header | source code | source
2 | source 3 | tables
directory
Copyright Turtle Creek Software 1996-2006. All Rights Reserved.
Source Code
This class manages accounting report tables for the Goldenseal accounting software,
small business management software, construction
project management software and
construction
accounting software.
/*********************************************************************************
FillSubtotalRow TCS split 2/24/04
fill in a report subtotal row (showing totals for items above it)
*********************************************************************************/
void CReportTable::FillSubtotalRow(const TableIndexT row)
{
// should we skip rows? // TCS 1/29/02 rev 2/24/04
Boolean skipRows = !ShowZeroItems() && SkipsZeroColumns(GetReportClassID());
SColDataInfo colData;
CTextString textString;
for (TableIndexT col = 1; col <= mNumDisplayCols; col++)
{
mColumnData.FetchItemAt(col, colData);
if (colData.subTotal.IsNonZero()) // rev TCS 11/26/02
skipRows = false;
if (colData.showSubtotal)
{
// do rounding and fetch cell text
textString = colData.subTotal.GetRoundedString(colData.totalRounding, GetFieldType(col));
SetCellText(row, col, textString);
// reset the subtotal TCS 5/31/01
colData.subTotal = 0;
mColumnData.AssignItemAt(col, colData);
}
else if (col == 1)
{
SetCellText(row, 1, TCS_GetStockString(stockID_Subtotal));
}
}
// for a few classes we delete rows if there is no subtotal TCS 1/29/02
if (skipRows)
{
if (LastRow() > 3)
RemoveRows(3, cDontRedraw); // remove the subtotal, title and spacer row
else if (LastRow() == 3)
RemoveRows(2, cDontRedraw); // first item doesn't have a spacer row
}
mSubTotalCount = 0;
}
/*********************************************************************************
FillGrandTotalRow TCS split 2/24/04
fill in a report total row (showing totals for subtotals above it)
*********************************************************************************/
void CReportTable::FillGrandTotalRow(const TableIndexT row)
{
SColDataInfo colData;
CTextString textString;
for (TableIndexT col = 1; col <= mNumDisplayCols; col++)
{
mColumnData.FetchItemAt(col, colData);
if (colData.showTotal)
{
// do rounding and fetch cell text rev 11/18/02
textString = colData.grandTotal.GetRoundedString(colData.totalRounding, GetFieldType(col));
SetCellText(row, col, textString);
}
else if (col == 1)
SetCellText(row, 1, TCS_GetStockString(stockID_GrandTotal));
}
}
/*********************************************************************************
FillGroupTotalRow TCS split 2/24/04
fill in a report group total row (showing totals for grand totals above it)
*********************************************************************************/
void CReportTable::FillGroupTotalRow(const TableIndexT row)
{
SColDataInfo colData;
CTextString textString;
for (TableIndexT col = 1; col <= mNumDisplayCols; col++)
{
mColumnData.FetchItemAt(col, colData);
if (colData.showSubtotal)
{
// do rounding and fetch cell text
textString = colData.groupTotal.GetRoundedString(colData.totalRounding, GetFieldType(col));
SetCellText(row, col, textString);
// reset the subtotal
colData.groupTotal = 0;
mColumnData.AssignItemAt(col, colData);
}
else if (col == 1)
{
mGroupName.AppendWithSpace(TCS_GetStockString(stockID_Total)); // rev TCS 2/9/04
SetCellText(row, 1, mGroupName);
}
}
}
/*********************************************************************************
FillCondensedTotalRow TCS split 2/24/04
fill in a report row for a condensed table. Same number as a subtotal in
a breakdown report, but different format since the items are not visible
*********************************************************************************/
void CReportTable::FillCondensedTotalRow(const TableIndexT row, const SReportRowInfo &rowInfo, const UInt8 breakdownType)
{
// should we skip rows? // TCS 1/29/02 rev 2/24/04
Boolean skipRows = !ShowZeroItems() && SkipsZeroColumns(GetReportClassID());
SColDataInfo colData;
CTextString textString;
// fetch text from the object. Note that this also
// allows the subtotal breakdown object to do any prep work
textString = GetSubtitleText(breakdownType, rowInfo);
SetCellText(row, 1, textString);
mLastDataRow = row;
for (TableIndexT col = 2; col <= mNumDisplayCols; col++)
{
mColumnData.FetchItemAt(col, colData);
if (colData.showSubtotal)
{
// do rounding and fetch cell text
textString = colData.subTotal.GetRoundedString(colData.totalRounding, colData.fieldType);
SetCellText(row, col, textString);
// reset the subtotal TCS 5/31/01
colData.subTotal = 0;
mColumnData.AssignItemAt(col, colData);
}
}
mSubTotalCount = 0;
}
/*********************************************************************************
FillJobCostRow TCS moved 4/10/02
fill data into a row in a job cost report
*********************************************************************************/
void CReportTable::FillJobCostRow(const TableIndexT row, const SReportRowInfo &rowInfo,
const UInt8 extraRows)
{
TJobCostCompareArrayIterator iterator(mJobCostCompareArray);
SJobCostCompareInfo compareInfo;
// first fetch the stored cost data for the category displayed in this row
// if we don't find a match we use the last row (unallocated).
while (iterator.Next(compareInfo))
{
if (compareInfo.id == rowInfo.itemID)
break;
}
CMoney estTotal = compareInfo.estLabor + compareInfo.estEquipment +
compareInfo.estMaterials + compareInfo.estSubcontractors +
compareInfo.estOther + compareInfo.estSoft;
CMoney actualTotal = compareInfo.actualLabor + compareInfo.actualEquipment +
compareInfo.actualMaterials + compareInfo.actualSubcontractors +
compareInfo.actualOther + compareInfo.actualSoft;
// if there are no costs, we may skip empty breakdowns
if (estTotal.IsZero() && actualTotal.IsZero() && !ShowZeroItems())
{
RemoveRows(1 + extraRows, LastRow());
return; // exit so we can move on to the next row
}
SLETableColInfo colInfo;
SColDataInfo colData;
CMoney amount;
CTextString textString;
// fill in table columns. We do it by brute force switching,
// since we use the job cost array rather than the object's member fields
for (TableIndexT col = 1; col <= mNumDisplayCols; col++)
{
mColumns.FetchItemAt(col, colInfo);
mColumnData.FetchItemAt(col, colData);
switch (colInfo.tag)
{
case tag_name:
if (rowInfo.rowType == rowtype_unallocatedcat)
textString = TCS_GetStockString(stockID_Unallocated);
else if (!rowInfo.itemID || rowInfo.itemID == cUnallocatedItem)
textString = TCS_GetStockString(stockID_Unallocated);
else if (mReportClassID == id_JobCostLocationReport || mReportClassID == id_JobCostLocationClassReport)
textString = gDBFile->GetObjectName(id_Location, rowInfo.itemID);
else
textString = gDBFile->GetObjectName(id_Category, rowInfo.itemID);
break;
case tag_estimatedlabor:
amount = compareInfo.estLabor;
textString = amount.GetRoundedString(colData.dataRounding, fieldtype_money);
break;
case tag_estimatedequipment:
amount = compareInfo.estEquipment;
textString = amount.GetRoundedString(colData.dataRounding, fieldtype_money);
break;
case tag_estimatedmaterials:
amount = compareInfo.estMaterials;
textString = amount.GetRoundedString(colData.dataRounding, fieldtype_money);
break;
case tag_estimatedsubs:
amount = compareInfo.estSubcontractors;
textString = amount.GetRoundedString(colData.dataRounding, fieldtype_money);
break;
case tag_estimatedother:
amount = compareInfo.estOther;
textString = amount.GetRoundedString(colData.dataRounding, fieldtype_money);
break;
case tag_estimatedtotal:
amount = estTotal;
textString = amount.GetRoundedString(colData.totalRounding, fieldtype_money);
break;
case tag_actuallabor:
amount = compareInfo.actualLabor;
textString = amount.GetRoundedString(colData.dataRounding, fieldtype_money);
break;
case tag_actualequipment:
amount = compareInfo.actualEquipment;
textString = amount.GetRoundedString(colData.dataRounding, fieldtype_money);
break;
case tag_actualmaterials:
amount = compareInfo.actualMaterials;
textString = amount.GetRoundedString(colData.dataRounding, fieldtype_money);
break;
case tag_actualsubs:
amount = compareInfo.actualSubcontractors;
textString = amount.GetRoundedString(colData.dataRounding, fieldtype_money);
break;
case tag_actualother:
amount = compareInfo.actualOther;
textString = amount.GetRoundedString(colData.dataRounding, fieldtype_money);
break;
case tag_actualtotal:
amount = actualTotal;
textString = amount.GetRoundedString(colData.totalRounding, fieldtype_money);
break;
default:
textString.MakeNull();
break;
}
SetCellText(row, col, textString);
// should we update totals and subtotals? TCS 8/6/01
if (colData.showSubtotal || colData.showTotal)
{
colData.subTotal += amount;
colData.groupTotal += amount;
colData.grandTotal += amount;
mColumnData.AssignItemAt(col, colData);
}
}
mSubTotalCount++; // TCS 2/24/04
mGrandTotalCount++;
mGroupTotalCount++;
}
/*********************************************************************************
FillCondensedDataRow TCS moved 4/10/02
for a condensed data row we don't fill a row into the table, but we still
need to update running totals
*********************************************************************************/
void CReportTable::FillCondensedDataRow(const SReportRowInfo &rowInfo)
{
DB_PersistentObject *object = nil;
SLETableColInfo colInfo;
SColDataInfo colData;
CMoney amount;
if (mHideOverhead && rowInfo.isSoftCost) // TCS 2/23/04
object = nil;
else if (rowInfo.classID && rowInfo.itemID)
object = gDBFile->GetOneObject(rowInfo.classID, rowInfo.itemID);
else
object = nil;
if (object)
{
DB_ObjectWatcher watcher(object);
// got the object, let's now loop through the columns in the row
// and update totals and subtotals. We do NOT display any data here.
for (TableIndexT col = 1; col <= mNumDisplayCols; col++)
{
mColumns.FetchItemAt(col, colInfo);
mColumnData.FetchItemAt(col, colData);
// does this column track subtotals or totals?
if (colData.showSubtotal || colData.showTotal)
{
if (object->GetMemberValue(colInfo.tag, type_money, &amount))
{
if (mHideOverhead && object->IsSoftCostMultiplied(colInfo.tag) && mHardCostMultiplier > 0)
{
amount *= mHardCostMultiplier; // TCS 2/23/04
}
colData.subTotal += amount;
colData.groupTotal += amount; // TCS 1/24/02
colData.grandTotal += amount;
mColumnData.AssignItemAt(col, colData);
}
}
}
mSubTotalCount++; // TCS 2/24/04
mGrandTotalCount++;
mGroupTotalCount++;
}
}
#if CAN_USE_MARK
#pragma mark -
#endif
/*********************************************************************************
CreatePrintFormReport TCS 1/3/00
prepare a report based on an array of specific items. This is used to
list breakdowns in a print form.
*********************************************************************************/
void CReportTable::CreatePrintFormReport(const DBid breakdownClass,
TObjectIDArray &breakdownArray, DB_PersistentObject *source)
{
TCS_FailNILMsg(gDBFile, TCS_GetErrString(errID_BadFile));
TCS_FailNILMsg(source, TCS_GetErrString(errID_BadObject));
// We first fill in a report row array struct, which contains an
// object id info for each row of the table.
TReportRowArray *rowArray = NEW TReportRowArray; // rev TCS 1/1/01
TCS_FailNILMsg(rowArray, TCS_GetErrString(errID_BadArray));
mSoftCostAmount = 0;
mHardCostAmount = 0;
TCS_TRY
{
// fill in the title row
FillTitleRow(rowArray);
// fill in data, based on the breakdown type
switch (mBreakdownTag)
{
case breakdown_simplelist: // it's a simple list. Include all items
default: // rev TCS 4/4/02
CreateSimplePrintFormArray(rowArray, breakdownClass, breakdownArray);
break;
case breakdown_category:
case breakdown_location:
case breakdown_subcategory:
CreateItemizedPrintFormArray(rowArray, breakdownClass, breakdownArray, mBreakdownTag);
break;
case breakdown_catsubcat:
CreateCatSubcatPrintForm(rowArray, source, mBreakdownTag);
break;
}
// end with a blank row
SReportRowInfo blankRowInfo;
InitializeRowInfo(blankRowInfo, rowtype_blank);
rowArray->Append(blankRowInfo);
// fill in optional grand total row
AppendGrandTotal(rowArray);
// now that our basic structure has been established,
// fill in the table with actual data from the objects
#if TCS_FOR_WINDOWS // TEMPORARY HACK TCS 3/23/04
FillReportTableFromArray(rowArray, mBreakdownTag, !IsPrinting());
#else
FillReportTableFromArray(rowArray, mBreakdownTag);
#endif
// resize table, since number of rows has probably changed TCS 1/5/00
ResizeFrameToImage();
}
TCS_CATCH {}
TCS_Forget(rowArray); // TCS 1/1/01
ClearJobCostCompareArray(); // TCS 1/29/02
}
/*********************************************************************************
CreateSimplePrintFormArray 1/4/00
fill in an array of simple breakdown items
*********************************************************************************/
void CReportTable::CreateSimplePrintFormArray(TReportRowArray *rowArray,
const DBid breakdownClass, TObjectIDArray &objectArray)
{
TCS_FailNILMsg(rowArray, TCS_GetErrString(errID_BadArray));
TCS_FailNILMsg(gDBFile, TCS_GetErrString(errID_BadFile));
TObjectIDArrayIterator iterator(objectArray);
DBid id;
SReportRowInfo info;
CMoney amount = 0;
InitializeRowInfo(info, rowtype_data);
// we simply add each breakdown object to the array
while (iterator.Next(id))
{
DB_PersistentObject *object = gDBFile->GetOneObject(breakdownClass, id);
if (object)
{
DB_ObjectWatcher watcher(object);
// fill the struct
info.itemID = object->GetDBID();
info.classID = object->GetDBClassID();
info.isSoftCost = object->IsSoftCost();
amount = object->GetAmount();
if (info.isSoftCost)
mSoftCostAmount += amount;
else
mHardCostAmount += amount;
// add to the row array
rowArray->Append(info);
}
}
}
/*********************************************************************************
CreateItemizedPrintFormArray 1/4/00
set up an array of itemized breakdown items
*********************************************************************************/
void CReportTable::CreateItemizedPrintFormArray(TReportRowArray *rowArray,
const DBid breakdownClass, TObjectIDArray &objectArray,
const TagType breakdownType)
{
// sanity check
TCS_FailNILMsg(rowArray, TCS_GetErrString(errID_BadArray));
TCS_FailNILMsg(gDBFile, TCS_GetErrString(errID_BadFile));
// initialize our temp storage array
// we create it on the heap for better memory management
TBreakdownInfoArray *breakdownArray = NEW TBreakdownInfoArray; // rev TCS 4/18/02
TCS_FailNILMsg(breakdownArray, TCS_GetErrString(errID_BadArray));
SBreakdownInfo breakdownInfo;
TagType breakdownTag = 0;
DBid listClassID;
TCS_TRY
{
// get the class to use for the breakdown list
switch (breakdownType)
{
case breakdown_category:
case breakdown_catsubcat:
listClassID = id_Category;
breakdownTag = tag_category;
break;
case breakdown_subcategory:
listClassID = id_Category;
breakdownTag = tag_subcategory;
break;
case breakdown_location:
listClassID = id_Location;
breakdownTag = tag_location;
break;
default:
TCS_DebugAlert("Oops, bad breakdown type in CReportTable:: CreateItemizedPrintFormArray!");
return;
break;
}
// create a list of categories or locations
gDBFile->DoForEach((BooleanActionFunc)Func_PrepBreakdownArray, listClassID, breakdownArray);
// add the 'unallocated' choice
breakdownInfo.classID = listClassID;
breakdownInfo.itemID = cUnallocatedItem; // TCS rev 2/22/00
breakdownInfo.itemArray = NEW TObjectInfoArray;
TCS_FailNILMsg(breakdownInfo.itemArray, TCS_GetErrString(errID_BadArray));
breakdownArray->Append(breakdownInfo);
// now go thru and assign objects to subsections
DBid id;
SObjectInfo info;
CMoney amount;
SInt32 matchValue;
TObjectIDArrayIterator iterator(objectArray);
// we simply add each breakdown object to the array
while (iterator.Next(id))
{
DB_PersistentObject *object = gDBFile->GetOneObject(breakdownClass, id);
if (object)
{
DB_ObjectWatcher watcher(object);
// fill the struct
info.itemID = object->GetDBID();
info.classID = object->GetDBClassID();
info.transactionType = object->IsSoftCost(); // TCS 2/23/04
amount = object->GetAmount();
if (info.transactionType)
mSoftCostAmount += amount;
else
mHardCostAmount += amount;
// fetch data value
object->GetMemberValue(breakdownTag, type_long, &matchValue);
// find the item in the list
SBreakdownInfo breakdownInfo;
Boolean foundIt = false;
TBreakdownInfoArrayIterator iterator(*breakdownArray);
while (iterator.Next(breakdownInfo))
{
if (matchValue == breakdownInfo.itemID)
{
breakdownInfo.itemArray->Append(info);
foundIt = true;
break;
}
}
// if not assigned yet, add it to the last item
if (!foundIt)
breakdownInfo.itemArray->Append(info);
}
}
// create a report array that is itemized by breakdown class
FillRowsFromBreakdownArray(rowArray, breakdownArray, breakdownType);
}
TCS_CATCH
{
}
// clean up the allocated arrays
ClearBreakdownArray(breakdownArray);
}
/*********************************************************************************
CreateCatSubcatPrintForm TCS 1/29/02 rev 7/11/02
set up an array of itemized breakdown items
*********************************************************************************/
void CReportTable::CreateCatSubcatPrintForm(TReportRowArray *rowArray,
DB_PersistentObject *source, const TagType /*breakdownType*/)
{
// sanity check
TCS_FailNILMsg(rowArray, TCS_GetErrString(errID_BadArray));
TCS_FailNILMsg(gDBFile, TCS_GetErrString(errID_BadFile));
TCS_FailNILMsg(source, TCS_GetErrString(errID_BadObject));
// initialize our temp storage array
// we create it on the heap for better memory management
TTwoLevelArray *twoLevelArray = NEW TTwoLevelArray; // rev TCS 4/18/02
TCS_FailNILMsg(twoLevelArray, TCS_GetErrString(errID_BadArray));
TCS_TRY
{
// the source can fill in breakdowns
source->FillCatSubcatArray(id_EstCatSubcatReport, twoLevelArray, mHideOverhead,
mSoftCostAmount, mHardCostAmount);
// finally, fill in the row info array from the breakdown data
FillRowsFromTwoLevelArray(rowArray, twoLevelArray);
}
TCS_CATCH {}
// tidy up the allocated array
ClearTwoLevelArray(twoLevelArray);
}
#if CAN_USE_MARK
#pragma mark -
#endif
/*********************************************************************************
SetColInfo
update column info for the given column
*********************************************************************************/
void CReportTable::SetColInfo(const TableIndexT column, const SLETableColInfo &colInfo,
Boolean redraw)
{
// update the array element
mColumns.AssignItemAt(column, colInfo);
if (redraw)
Refresh();
}/*********************************************************************************
SetColTag
update column tag for the given column
*********************************************************************************/
void CReportTable::SetColTag(const TableIndexT col, const TagType tag)
{
SLETableColInfo colInfo;
if (GetColInfo(col, colInfo))
{
colInfo.tag = tag;
SetColInfo(col, colInfo);
}
}
/*********************************************************************************
SetDisplayDirty TCS rev 6/1/01
respond to a change in report conditions, and return whether a recalc is needed
*********************************************************************************/
Boolean CReportTable::SetDisplayDirty(const UInt8 source)
{
switch (source)
{
case calc_completed: // just recalculated, so we can turn off the flag
mCalcDirty = false;
return false;
break;
default:
mCalcDirty = true;
return true;
break;
}
}
/*********************************************************************************
GetColTag
get the column tag for the given column
*********************************************************************************/
TagType CReportTable::GetColTag(const TableIndexT col) const
{
SLETableColInfo colInfo;
if (GetColInfo(col, colInfo))
return colInfo.tag;
else
return 0;
}
#if CAN_USE_MARK
#pragma mark -
#endif
/*********************************************************************************
GetSubtitleText TCS 8/7/99
fetch the text to put in a subtotal title row
*********************************************************************************/
CTextString CReportTable::GetSubtitleText(const UInt8 breakdownType,
const SReportRowInfo &rowInfo) const
{
CTextString textString;
CDate startDate, endDate;
switch (breakdownType)
{
case breakdown_object: // we fetch the title from a breakdown object
case breakdown_category:
case breakdown_location:
case breakdown_subcategory:
case breakdown_catsubcat: // TCS 7/11/02
if (rowInfo.itemID == cUnallocatedItem) // TCS rev 2/22/00
{
textString = TCS_GetStockString(stockID_Unallocated);
}
else
{
DB_PersistentObject *object = nil;
if (IS_TURTLE_CLASS_ID(rowInfo.classID) && rowInfo.itemID)
object = gDBFile->GetOneObject(rowInfo.classID, rowInfo.itemID);
if (object)
{ // the object exists, let's watch it and fetch its name
DB_ObjectWatcher watcher(object);
textString = object->GetName();
object->DoReportBreakdownPrep(GetReportClassID(), rowInfo);
}
else
textString = TCS_GetStockString(stockID_MissingItem);
}
break;
case breakdown_enum: // we fetch the title from the enum menu
if (rowInfo.itemID == cUnallocatedItem) // TCS rev 2/22/00
textString = TCS_GetStockString(stockID_Unallocated);
else if (!rowInfo.itemID)
textString = TCS_GetStockString(stockID_MissingItem);
else
textString = TCS_NameFromMenuCommand(rowInfo.itemID, rowInfo.classID);
break;
case breakdown_mixed: // can be enum or object ID TCS 10/21/02
if (!rowInfo.itemID)
textString = TCS_GetStockString(stockID_MissingItem);
else if (rowInfo.classID == id_Category)
textString = gDBFile->GetObjectName(id_Category, rowInfo.itemID);
else
textString = TCS_NameFromMenuCommand(rowInfo.itemID, rowInfo.classID);
break;
case breakdown_hour: // subtitle is a hour range TCS 2/19/01
startDate = CDate(rowInfo.itemID);
textString = TCS_GetStockString(stockID_From);
textString.Append(CTextString(" "));
textString.Append(startDate.GetTimeString());
textString.Append(TCS_GetStockString(stockID_DateRangeMiddle));
startDate.AddMinutes(59);
textString.Append(startDate.GetTimeString());
break;
case breakdown_day: // subtitle is a daily range
startDate = CDate(rowInfo.itemID);
textString = startDate.GetCString();
break;
case breakdown_week: // subtitle is a date range TCS 8/26/99
case breakdown_month: // we fetch the dates from raw data
startDate = CDate(rowInfo.itemID);
endDate = CDate(rowInfo.matchValue);
// build the string
textString = TCS_GetStockString(stockID_From);
textString.Append(CTextString(" "));
textString.Append(startDate.GetCString());
textString.Append(TCS_GetStockString(stockID_DateRangeMiddle));
textString.Append(endDate.GetCString());
break;
default:
{
DB_PersistentObject *object = nil;
if (IS_TURTLE_CLASS_ID(rowInfo.classID) && rowInfo.itemID)
object = gDBFile->GetOneObject(rowInfo.classID, rowInfo.itemID);
if (object)
{ // the object exists, let's watch it and fetch its name
DB_ObjectWatcher watcher(object);
textString = object->GetName();
object->DoReportBreakdownPrep(GetReportClassID(), rowInfo);
}
else
textString = TCS_GetStockString(stockID_MissingItem);
}
break;
}
return textString;
}
/*********************************************************************************
ResetTotals TCS 8/7/99
set accumulated totals to zero
*********************************************************************************/
void CReportTable::ResetTotals()
{
SColDataInfo colData;
TColDataInfoArrayIterator iterator(mColumnData);
while (iterator.Next(colData))
{
colData.grandTotal = 0;
colData.subTotal = 0;
colData.groupTotal = 0;
mColumnData.AssignItemAt(iterator.GetCurrentIndex(), colData);
}
mSubTotalCount = 0; // TCS 2/24/04
mGrandTotalCount = 0;
mGroupTotalCount = 0;
}
/*********************************************************************************
GetReportEndDate TCS 8/27/99
find the end date for a report time period
*********************************************************************************/
CDate CReportTable::GetReportEndDate(const CDate periodStart, const CDate endDate,
const TagType breakdownTag)
{
CDate returnDate = periodStart;
// increment the date, depending on the breakdown being used
switch (breakdownTag)
{
case breakdown_hour: // TCS 2/19/01
returnDate.AddHours(1);
break;
case breakdown_day:
returnDate.AddDays(1);
break;
case breakdown_week:
returnDate.AddDays(7);
break;
case breakdown_month:
returnDate.AddSafeMonths(1);
break;
default:
TCS_DebugAlert("Oops, invalid case in CReportTable::GetReportEndDate!");
returnDate = endDate;
returnDate.AddDays(1);
break;
}
// make sure we haven't gone over our max limit
if (returnDate > endDate)
{
returnDate = endDate;
returnDate.AddDays(1);
}
return returnDate;
}
#if CAN_USE_MARK
#pragma mark -
#endif/*********************************************************************************
GetColTitle
return the title of the given column in a report table
*********************************************************************************/
CTextString CReportTable::GetColTitle(const TableIndexT col) const
{
// if we have a user-entered title, use that TCS 7/2/99
SLETableColInfo colInfo;
if (GetColInfo(col, colInfo))
{
if (colInfo.colTitle[0])
{
CTextString colTitle(colInfo.colTitle);
return colTitle;
}
}
// if we got this far, use the stock title
return GetStockColTitle(col);
}/*********************************************************************************
GetStockColTitle
return the default title of the given column in a report table
*********************************************************************************/
CTextString CReportTable::GetStockColTitle(const TableIndexT col) const
{
// sanity check
TCS_FailNILMsg(mDescriptor, TCS_GetErrString(errID_BadDescriptor));
// get the column information for the requested column
SLETableColInfo tableInfo;
TCS_ASSERTMsg(mColumns.FetchItemAt(col, tableInfo),
TCS_GetErrString(errID_BadColumn));
if (tableInfo.tag == tag_totalcolumn)
return TCS_GetStockString(stockID_Total);
else
{
TCS_TRY
{
// get the member information for the column tag
// and extract the name from it
SMemberInfo memberInfo;
TCS_ASSERTMsg(mDescriptor->GetMemberInfo(tableInfo.tag, &memberInfo),
TCS_GetErrString(errID_BadColumn));
return CTextString(memberInfo.memberName);
}
TCS_CATCH
{
}
return TCS_GetStockString(stockID_BadTitle);
}
}
/*********************************************************************************
GetTableMatchTag 1/5/00
fetch the match tag to use for a report
*********************************************************************************/
TagType CReportTable::GetTableMatchTag() const
{
if (mMatchTag == 0) // table default
return mDefaultMatchTag;
else if (mMatchTag == 1) // no item
return 0;
else // entered match tag
return mMatchTag;
}
/*********************************************************************************
GetTableBreakdownTag 1/17/02
fetch the breakdown tag
*********************************************************************************/
TagType CReportTable::GetTableBreakdownTag() const
{
if (mBreakdownTag == breakdown_standard || !mBreakdownTag)
return mDefaultBreakdownTag;
else
return mBreakdownTag;
}
/********************************************************************************
GetCellTextAlignment
Get the text alignment to use for the cell. We set this independently from
regular spreadsheet tables, since we may want to align some things differently
***********************************************************************************/
short CReportTable::GetCellTextAlignment(const TableCellT &inCell)
{
UInt8 colType = GetColType(inCell);
switch (colType)
{
case coltype_checkmark:
return just_center;
break;
case coltype_cv:
case coltype_mixcv:
case coltype_menucv:
case coltype_checklist:
return just_left;
break;
// for other col types, use the field type
default:
switch (GetFieldType(COL(inCell))) // bugfix 1/5/00
{
case fieldtype_string:
case fieldtype_mixstring:
case fieldtype_cv:
case fieldtype_mixcv:
return just_left;
break;
case fieldtype_money:
case fieldtype_emoney:
case fieldtype_number:
case fieldtype_integer:
case fieldtype_posinteger:
case fieldtype_percent:
case fieldtype_time: // moved TCS 1/5/00
return just_right;
break;
case fieldtype_date:
return just_center;
break;
default:
return just_left;
break;
}
break;
}
}
#if CAN_USE_MARK
#pragma mark -
#endif
/******************************************************************************
GetRowType TCS 8/7/99
Get the type of the given row. We fetch info from the hidden offset column
*******************************************************************************/
UInt8 CReportTable::GetRowType(const TableIndexT row) const
{
return GetCellValue(row, mNumDisplayCols + cRowTypeOffset);
}
/*********************************************************************************
GetFieldType TCS 3/17/00 rev 11/18/02
return the field type for the given column
*********************************************************************************/
UInt8 CReportTable::GetFieldType(const TableIndexT col) const
{
UInt8 fieldType = 0;
SColDataInfo colInfo;
if (GetColDataInfo(col, colInfo))
{
fieldType = colInfo.fieldType;
}
if (!fieldType)
{
if (mBreakdownTag == tag_category) // TCS 11/18/02
{
// we use a fixed format for category tables
if (col == 1)
fieldType = fieldtype_string;
else
fieldType = fieldtype_money;
}
}
return fieldType;
}
/******************************************************************************
GetRowClassID TCS 8/7/99
Get the class ID of the given row. We fetch info from the hidden offset column
*******************************************************************************/
UInt8 CReportTable::GetRowClassID(const TableIndexT row) const
{
return GetCellValue(row, mNumDisplayCols + cClassIDOffset);
}
/******************************************************************************
GetRowItemID TCS 8/7/99
Get the item ID of the given row. We fetch info from the hidden offset column
*******************************************************************************/
DBid CReportTable::GetRowItemID(const TableIndexT row) const
{
return GetCellValue(row, mNumDisplayCols + cItemIDOffset);
}
#if CAN_USE_MARK
#pragma mark -
#endif
/******************************************************************************
TextCanOverlap TCS 8/26/99
Return whether text can overlap adjoining cells
*******************************************************************************/
Boolean CReportTable::TextCanOverlap(const TableIndexT row,
const TableIndexT /*col*/)
{
UInt8 rowType = GetRowType(row);
return (rowType == rowtype_title || rowType == rowtype_subtitle ||
rowType == rowtype_notice || rowType == rowtype_noitems);
}
/******************************************************************************
DrawCell TCS 8/7/99 rev 8/30/99
Draw a cell. We override to set alignment, and to draw some items bold
*******************************************************************************/
void CReportTable::DrawCell(const TableCellT &inCell)
{
UInt8 rowType = GetRowType(ROW(inCell));
switch (rowType)
{
case rowtype_title:
THE_SUPERCLASS::DrawCell(inCell, just_center, style_bold);
break;
case rowtype_subtitle:
case rowtype_grouptitle:
THE_SUPERCLASS::DrawCell(inCell, just_left, style_bold);
break;
case rowtype_notice:
case rowtype_noitems:
THE_SUPERCLASS::DrawCell(inCell, just_left, style_plain);
break;
case rowtype_subtotal:
case rowtype_grouptotal:
if (COL(inCell) == 1) // title cell
{
if (mBoldSubtotals) // TCS 12/29/02
THE_SUPERCLASS::DrawCell(inCell, just_left, style_bold);
else
THE_SUPERCLASS::DrawCell(inCell, just_left, style_plain);
}
else // data cells
{
if (mBoldSubtotals) // TCS 12/29/00
THE_SUPERCLASS::DrawCell(inCell, just_right, style_bold);
else
THE_SUPERCLASS::DrawCell(inCell, just_right, style_plain);
}
break;
case rowtype_condensedtotal: // TCS 5/31/01
if (COL(inCell) == 1) // title cell
{
THE_SUPERCLASS::DrawCell(inCell, just_left, style_plain); // rev TCS 12/29/02
}
else // data cells
{
THE_SUPERCLASS::DrawCell(inCell, just_right, style_plain); // rev TCS 4/22/02
}
break;
case rowtype_grandtotal:
if (COL(inCell) == 1) // title cell
{
if (mBoldTotals) // TCS 12/29/02
THE_SUPERCLASS::DrawCell(inCell, just_left, style_bold);
else
THE_SUPERCLASS::DrawCell(inCell, just_left, style_plain);
}
else // data cells
{
if (mBoldTotals) // TCS 12/29/00
THE_SUPERCLASS::DrawCell(inCell, just_right, style_bold);
else
THE_SUPERCLASS::DrawCell(inCell, just_right, style_plain);
}
break;
default:
THE_SUPERCLASS::DrawCell(inCell);
break;
}
}
/*********************************************************************************
HiliteCell
we override, since we don't want any hiliting at all.
*********************************************************************************/
void CReportTable::HiliteCell(const TableCellT &/*inCell*/, const Boolean /*hiliting*/)
{
}
/*********************************************************************************
HandleDoubleClick TCS 8/7/99 rev TCS 7/31/01
if a double-click on a row with a valid object, we open an editor window for it
*********************************************************************************/
void CReportTable::HandleDoubleClick(const TableCellT &inCell)
{
UInt8 rowType = GetRowType(ROW(inCell));
if (rowType == rowtype_subtotal)
{
TCS_SysBeep();
return;
}
else if (rowType == rowtype_subtitle)
{
TCS_SysBeep();
return;
}
else if (rowType == rowtype_condensedtotal)
{
TCS_SysBeep();
return;
}
else if (rowType != rowtype_data)
return;
DBClass objectClass = GetRowClassID(ROW(inCell));
DBid objectID = GetRowItemID(ROW(inCell)); // bugfix TCS 8/25/02
if (!objectID || !IS_TURTLE_CLASS_ID(objectClass)) // rev TCS 6/29/01
return;
TCS_FailNILMsg(gDBFile, TCS_GetErrString(errID_BadFile));
if (DB_ClassDescriptor::IsTransaction(objectClass) ||
DB_ClassDescriptor::IsAccount(objectClass))
{
DB_PersistentObject *object = gDBFile->GetOneObject(objectClass, objectID);
if (object)
{
DB_ObjectWatcher watcher(object);
DB_Editor::ShowEditorWindow(objectClass, object);
}
else
{ // show a 'sorry' message, since the item
// probably was deleted legitimately TCS rev 3/28/00
TCS_ErrorAlert(TCS_GetMsgString(msgID_ItemNotAvailable));
return;
}
}
else if (DB_ClassDescriptor::IsBreakdown(objectClass)) // TCS 6/29/01
{
CBreakdownEntry *breakdown =
TCS_SAFE_CAST(gDBFile->GetOneObject(objectClass, objectID),
CBreakdownEntry);
if (breakdown)
{
DB_ObjectWatcher breakdownWatcher(breakdown);
DBClass ownerClass = breakdown->GetOwnerClass();
DBid ownerID = breakdown->GetOwnerID();
if (!objectID || !IS_TURTLE_CLASS_ID(objectClass))
{
TCS_ErrorAlert(TCS_GetErrString(msgID_ItemNotAvailable));
return;
}
DB_PersistentObject *owner = gDBFile->GetOneObject(ownerClass, ownerID);
if (owner) // show the breakdown's owner transaction
{
DB_ObjectWatcher ownerWatcher(owner);
DB_Editor::ShowEditorWindow(ownerClass, owner);
}
else
{ // show a 'sorry' message
TCS_ErrorAlert(TCS_GetMsgString(msgID_ItemNotAvailable));
return;
}
}
else
{
TCS_ErrorAlert(TCS_GetMsgString(msgID_ItemNotAvailable));
}
}
// otherwise we don't do anything
} |