Accounting Software
Small Business Software Estimating Software
Time Tracking SoftwareTime Management SoftwareTime Billing SoftwareContact Management SoftwareCustomer Management SoftwareProject Management SoftwareBusiness Management Software

Breakdown Tables (Source Code)

Link to: header | source code | source 2 | source 4 | tables directory

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

Source Code

This class manages general breakdown tables for the Goldenseal accounting software,
small business management software, construction project management software and
construction accounting software.

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

FillDetailArray TCS 2/7/00 rev 1/4/00

fill in an array of detail ID's. Note that all items in the table should have
the same class ID. This method should not be called for tables that have
a mixture of transaction types

*********************************************************************************/
void CBreakdownTable::FillDetailArray(TObjectIDArray &selectArray,
const DBClass detailClass) const
{
DBid id;
DBClass classID;

for (TableIndexT row = 1; row <= LastRow(); row++)
{
id = GetDetailTransactionID(row);

if (id && detailClass) // if we were passed a class, include only matching items
{
classID = GetDetailTransactionClass(row);

if (classID == detailClass)
selectArray.Append(id);
}
else if (id) // for a single-class table we include everything
selectArray.Append(id);
}
}
/*********************************************************************************

FillDetailArray TCS 2/7/00

fill in an array of detail ID's. This form can be used even with a mixture
of class ID's in the table.

*********************************************************************************/
void CBreakdownTable::FillDetailArray(TObjectInfoArray &selectArray) const
{
SObjectInfo info;
info.transactionType = 0;

for (TableIndexT row = 1; row <= LastRow(); row++)
{
info.classID = GetDetailTransactionClass(row);
info.itemID = GetDetailTransactionID(row);

if (info.classID && info.itemID)
selectArray.Append(info);
}
}
#if CAN_USE_MARK
#pragma mark -
#endif
/*********************************************************************************

GetColTagMoneyTotal TCS 5/17/02

return the sum of the basic amount column. Subclasses may override if
a different column tag is used

*********************************************************************************/
CMoney CBreakdownTable::GetColTagMoneyTotal(const TagType tag)
{
TableIndexT col = GetMemberCol(tag);
if (col)
return GetColumnMoneyTotal(col);
else
return 0;
}
#if CAN_USE_MARK
#pragma mark -
#endif
/*********************************************************************************

SetFindMode TCS rev 10/26/99, moved 12/13/01

We are going into or out of find mode
*********************************************************************************/
void CBreakdownTable::SetFindMode(const Boolean findMode)
{
// the superclass stores a boolean for current find mode status
THE_SUPERCLASS::SetFindMode(findMode);

if (findMode)
{ // Show a blank single row table so users can enter
// find criteria TCS rev 12/13/01
MakeSingleRowTable(cRedraw, true);
}
else
{
// leaving find mode, so clear the table. It will be refilled
// with data later TCS 12/13/01
SetNumRows(0);
}
}
/*********************************************************************************

GetFindSelectors TCS 12/13/01

return a set of selectors based on the current criteria entered
in the table.

Note that for tables, we return the search tag as a negative number.
When we do the actual record finding, that way we can distinguish between
table tags and regular field tags.

*********************************************************************************/
void CBreakdownTable::GetFindSelectors(CTCS_Array *selectorArray) const
{
CTextString cellText, highString, lowString;
CNeoSelect *selector = nil;
Boolean isRange;

// we loop through each cell and check for values
for (SInt32 col = 1; col <= LastCol(); col++)
{
// fetch member info for the column
SMemberInfo memberInfo;
TCS_ASSERTMsg(GetColMemberInfo(col, &memberInfo), TCS_GetErrString(errID_BadColumn));

// fetch the cell text
cellText = GetCellText(1, col);

if (cellText.Length())
{
// does the text include range markers?
isRange = cellText.StripRangeMarkers(lowString, highString);

if (isRange)
{
selector = GetRangeSelector(memberInfo, lowString, highString);
}
else
{
selector = GetSimpleSelector(memberInfo, col, cellText);
}
}

// if we found a selector, add it to the array, and then nil
// out the reference for the next go-round.
if (selector)
{
selectorArray->Append(&selector);
selector = nil;
}
}
}

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

GetSimpleSelector TCS 12/18/01

return a simple selector for a column in this table

*********************************************************************************/
DB_MemberSelector *CBreakdownTable::GetSimpleSelector(const SMemberInfo &memberInfo,
const TableIndexT col, const CTextString &cellText) const
{
CTextString matchString;
SInt32 value;

Boolean useExact, useContains;
NeoOrder order;

DB_MemberSelector *selector = nil;

// First process the text for find markers TCS 12/17/01
cellText.StripFindMarkers(useExact, useContains, order, matchString);

UInt8 fieldType = GetFieldType(1, col); // rev TCS 12/19/01
// create a selector and add it to the array.
// the type of selector depends on the cell type
switch (fieldType)
{
case fieldtype_checkbox: // checkmark col
if (cellText.StartsWith(cCheckMarkChar))
selector = NEW DB_BooleanSelector(memberInfo.tag, true);
else
selector = NEW DB_BooleanSelector(memberInfo.tag, false);
break;

case fieldtype_integer:
case fieldtype_posinteger:
case fieldtype_cv:
case fieldtype_mixcv:
value = GetCellValue(1, col);
selector = NEW DB_LongSelector(memberInfo.tag, value);
break;

case fieldtype_date:
selector = NEW DB_DateSelector(memberInfo.tag, CDate(matchString));
break;

case fieldtype_money:
case fieldtype_emoney:
case fieldtype_percent:
case fieldtype_number:
selector = NEW DB_MoneySelector(memberInfo.tag, CMoney(matchString));
break;

case fieldtype_string:
case fieldtype_mixstring:
selector = NEW DB_CStringSelector(memberInfo.tag, &matchString);

if (selector)
{
if (useExact) // rev TCS 12/19/01
selector->SetSelectType(select_exact);
else if (useContains)
selector->SetSelectType(select_contains);
else
selector->SetSelectType(select_startswith);
}
break;

default:
break;
}

// let the selector know about any order restrictions, e.g. > or <
if (selector)
{
selector->setOrder(order);
selector->SetIsFromTable();
}

return selector;
}
/*********************************************************************************

GetRangeSelector TCS 12/18/01

return a range selector for our current contents. This function should only be
called if the cell has been determined to contain the range selection find code.

*********************************************************************************/
DB_MemberSelector *CBreakdownTable::GetRangeSelector(const SMemberInfo &memberInfo,
const CTextString &lowString, const CTextString &highString) const
{
DB_MemberSelector *lowSelector = nil,
*highSelector = nil,
*rangeSelector = nil;
// create a selector and add it to the array.
// the type of selector depends on the cell type
switch (memberInfo.type)
{
case type_date:
lowSelector = NEW DB_DateSelector(memberInfo.tag, CDate(lowString));
highSelector = NEW DB_DateSelector(memberInfo.tag, CDate(highString));
break;

case type_money:
case type_emoney:
case type_number:
case type_percent:
lowSelector = NEW DB_MoneySelector(memberInfo.tag, CMoney(lowString));
highSelector = NEW DB_MoneySelector(memberInfo.tag, CMoney(highString));
break;

case type_cstring:
lowSelector = NEW DB_CStringSelector(memberInfo.tag, &lowString);
highSelector = NEW DB_CStringSelector(memberInfo.tag, &highString);
break;

default:
break;
}

// we got the top and bottom selectors, so create a range selector
// to use for the search. The range selector will be responsible
// for deleting the two sub-selectors when it's done. It also sets
// the proper search order for each of the sub-selectors
if (lowSelector && highSelector)
{
lowSelector->SetIsFromTable();
highSelector->SetIsFromTable();
rangeSelector = NEW DB_RangeSelector(memberInfo.tag, lowSelector, highSelector);
}

if (rangeSelector)
{
rangeSelector->SetIsFromTable();
return rangeSelector;
}
else
{
TCS_Forget(lowSelector);
TCS_Forget(highSelector);
return nil;
}
}
#if CAN_USE_MARK
#pragma mark -
#endif
/*********************************************************************************

CreateNewCellCVField

create a cv field for the given cell
*********************************************************************************/
CTCS_CVField *CBreakdownTable::CreateNewCellCVField(const TableCellT &inCell,
const SPaneInfo &inPaneInfo)
{
// get the member info from the column
SMemberInfo memberInfo;
TCS_ASSERTMsg(GetColMemberInfo(COL(inCell), &memberInfo), TCS_GetErrString(errID_BadColumn));

// now based on the tag and type, return the appropriate cv
switch (memberInfo.tag)
{
/*case tag_costarea: // bug fix TCS 11/27/98 rev 3/19/99 rev 9/2/99 removed TCS 6/10/03
return NEW CCostAreaCV(inPaneInfo, mTextInfo, GetCellCVClassID(inCell), cHasPopup);
break;*/ // shouldn't be needed here-- it's a menu cv

case tag_location: // TCS 8/23/99
return NEW CShortLocationCV(inPaneInfo, mTextInfo);
break;

case tag_paymentmethod: // TCS 10/11/99
return NEW CShortPaymentMethodCV(inPaneInfo, mTextInfo);
break;

case tag_category:
case tag_subcategory:
case tag_costitem:
return DB_Clairvoyant::CreateCV(memberInfo, inPaneInfo,
mTextInfo, cHasPopup);
break;

default: // for other classes we create a table clairvoyant,
{ // which has a reference to the table
DB_TableClairvoyant *cv =
NEW DB_TableClairvoyant(inPaneInfo, mTextInfo, GetCellCVClassID(inCell), cHasPopup);
TCS_FailNILMsg(cv, TCS_GetErrString(errID_BadClairvoyant));

cv->SetTable(this);

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

CreateNewCellMenuCVField TCS 9/2/99

create a cv field for the given cell
*********************************************************************************/
CMenuCV *CBreakdownTable::CreateNewCellMenuCVField(const TableCellT &inCell,
const SPaneInfo &inPaneInfo)
{ // get the member info from the column
SMemberInfo memberInfo;
TCS_ASSERTMsg(GetColMemberInfo(COL(inCell), &memberInfo), TCS_GetErrString(errID_BadColumn));

// now based on the tag and type, return the appropriate menu cv
switch (memberInfo.tag)
{
case tag_costarea: // bug fix TCS 11/27/98 rev 3/19/99 rev 9/2/99
{
CCostAreaCV *cv = NEW CCostAreaCV(inPaneInfo, mTextInfo, GetMenuCVClassID(inCell), cHasPopup);
if (cv)
cv->SetOwnerClass(GetOwnerClass()); // rev TCS 6/10/03
return cv;
}
break;

default: // changed TCS 10/28/98 so we get DB_ShortClairvoyant
return THE_SUPERCLASS::CreateNewCellMenuCVField(inCell, inPaneInfo);
break;
}
}
/*********************************************************************************

PrepCellCVField TCS 5/6/98

do any prep needed for a cell cv field. This is used when fetching a display
value in SetCVCellValue.
*********************************************************************************/
void CBreakdownTable::PrepCellCVField(const TableIndexT row, const TableIndexT col,
CTCS_CVField *cellField)
{
TagType colTag = GetColTag(col);
if (colTag == tag_category)
{
// let's cast the field to a cat cv
CCategoryCV *catField = TCS_SAFE_CAST(cellField, CCategoryCV);
TCS_FailNILMsg(catField, TCS_GetErrString(errID_BadClairvoyant));

// now we can set its category system
catField->SetCatSystem(GetTableCatSystem());
}
else if (colTag == tag_subcategory) // subcat setup is handled elsewhere
{
// let's cast the field to a subcat cv
CSubcatCV *subcatField = TCS_SAFE_CAST(cellField, CSubcatCV);
TCS_FailNILMsg(subcatField, TCS_GetErrString(errID_BadClairvoyant));

// set its category system
subcatField->SetCatSystem(GetTableCatSystem());

// set its category reference
TableIndexT catCol= GetMemberCol(tag_category);
if (catCol)
subcatField->SetCatRef(GetCellValue(row, catCol));
else
subcatField->SetCatRef(0);
}
else if (colTag == tag_location)
{
// let's cast the field to a location cv
CLocationCV *locationField = TCS_SAFE_CAST(cellField, CLocationCV);
TCS_FailNILMsg(locationField, TCS_GetErrString(errID_BadClairvoyant));

// set its job type and location package
locationField->SetJobType(mJobType);
locationField->SetLocationPackage(mLocationPackage); // TCS 8/23/99
}
else if (colTag == tag_costitem) // TCS 12/24/98
{
// fetch the cost class
SInt32 classCol = GetMemberCol(tag_costarea);
DBid classID = 0;
if (classCol)
classID = GetCellValue(row, classCol);

// set its class ID (needed so text displays properly)
if (classID == costtype_allowance)
cellField->SetDisplayClassID(id_Allowance); // TCS 7/14/99
else if (classID == costtype_assembly || classID == costtype_assmlabor || classID == costtype_assmmaterial)
cellField->SetDisplayClassID(id_Assembly);
else if (classID == costtype_bid)
cellField->SetDisplayClassID(id_Bid);
else if (classID == costtype_changeorder)
cellField->SetDisplayClassID(id_ChangeOrder);
else if (classID == costtype_powo)
cellField->SetDisplayClassID(id_PurchaseWorkOrder); // TCS 2/28/02
else if (classID == costtype_reminder)
cellField->SetDisplayClassID(id_ProjectReminder);
else if (classID == costtype_tool)
cellField->SetDisplayClassID(id_Tool);
else
cellField->SetDisplayClassID(id_CostItem);
}
}
#if CAN_USE_MARK
#pragma mark -
#endif
/*********************************************************************************

AllowNegatives

return whether negatives are allowed in this column

*********************************************************************************/
Boolean CBreakdownTable::AllowNegatives(TableIndexT col) const
{
// get the member info from the column
SMemberInfo memberInfo;
TCS_ASSERTMsg(GetColMemberInfo(col, &memberInfo), TCS_GetErrString(errID_BadColumn));
Boolean allowNegatives = CAN_USE_NEGATIVES(memberInfo);
return allowNegatives;
}
/*********************************************************************************

HasUncheckedRows TCS 10/24/01

return whether some rows are lacking checkmarks

*********************************************************************************/
Boolean CBreakdownTable::HasUncheckedRows() const
{
TagType checkTag = GetCheckmarkTestTag();

if (checkTag)
{
TableIndexT checkCol = GetMemberCol(checkTag);

if (checkCol)
{
for (TableIndexT row = 1; row <= LastRow(); row++)
{
if (!IsChecked(row, checkCol))
return true;
}
}
}

// if we get this far, nothing is unchecked
return false;
}
/*********************************************************************************

HasColumn TCS 1/5/03

return whether or not the table has a column for the given member

*********************************************************************************/
Boolean CBreakdownTable::HasColumn(const TagType tag) const
{
return GetMemberCol(tag);
}
/*********************************************************************************

CanAlwaysChange TCS 5/13/02

return whether we can change a cell. That's generally determined by the
'always change' bit in the MEMB resource.

*********************************************************************************/
Boolean CBreakdownTable::CanAlwaysChange(const TableCellT &cell) const
{
TableIndexT col = COL(cell);

if (col)
{
// get the member info from the column. We don't worry if it's
// not there, since this may be called early in the table's existence
// when the members may not exist yet.
SMemberInfo memberInfo;
if (GetColMemberInfo(col, &memberInfo))
{
Boolean canAlwaysChange = CAN_ALWAYS_CHANGE(memberInfo);

if (canAlwaysChange)
return true;
}
}

// if we get this far, pass it to the superclass
return THE_SUPERCLASS::CanAlwaysChange(cell);
}