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 general breakdown tables for the Goldenseal accounting software,
small business management software, construction
project management software and
construction
accounting software.
/*********************************************************************************
HandleNonEditCellDblClicked TCS 11/17/99
user has double-clicked in a non-editable cell. If we have a valid transaction
reference, show an editor window for the item.
*********************************************************************************/
void CBreakdownTable::HandleNonEditCellDblClicked(const TableCellT &inCell)
{
DBid transID = GetDetailTransactionID(ROW(inCell));
UInt8 transClass = GetDetailTransactionClass(ROW(inCell));
if (transID && transClass)
{
TCS_FailNILMsg(gDBFile, TCS_GetErrString(errID_BadFile));
TCS_TRY
{
if (DB_ClassDescriptor::IsBankTransaction(transClass)) // rev TCS 6/10/00
{
DB_Editor::ShowBankEditor(transClass, transID);
}
else if (DB_ClassDescriptor::IsTransaction(transClass) ||
DB_ClassDescriptor::IsAccount(transClass))
{
if (mOwnerClass == transClass)
{
// show another record of the same class. This happens
// only for assemblies in an assembly table. We don't
// want to use DB_Editor::ShowEditor since that closes
// the window and destroys this table, which crashes the Win vsn.
if (mEditor) // TCS rev 12/26/02
{
UInt8 success = mEditor->SaveRecord(record_loadinganother);
if (success == save_success || success == save_notneeded)
mEditor->ScrollToID(transID);
}
}
else
DB_Editor::ShowEditor(transClass, transID);
}
else if (DB_ClassDescriptor::IsList(transClass))
{
CListEditor::EditOneItem(transClass, transID); // rev TCS 12/19/01
}
}
TCS_CATCH
{ // no need to pass exception any further
}
}
else
{ // no transaction, so let the superclass have it
THE_SUPERCLASS::HandleNonEditCellDblClicked(inCell);
}
}
/*********************************************************************************
HandleEnterKey TCS 12/4/00
handle the enter key. We pass it along to the editor, which will close
the record. We used to pass it along with a return false, but that wasn't
ever making it to the editor.
*********************************************************************************/
Boolean CBreakdownTable::HandleEnterKey()
{
if (mEditor)
return mEditor->HandleEnterKey(); // rev TCS 12/13/00
else
return false;
}
/*********************************************************************************
HandleCheckmarkChanged TCS 11/10/98
the checkmark has changed, better recalculate the row and table total
*********************************************************************************/
void CBreakdownTable::HandleCheckmarkChanged(const TableIndexT row, const TableIndexT col,
const Boolean /*isChecked*/)
{
// we don't need to recalc if in find mode TCS 12/13/01
if (InFindMode())
return;
TagType colTag = GetColTag(col);
// recalculate the whole row since values have changed
if (NeedsRowRecalc(colTag))
RecalcBreakdownRow(row, tag_checkmark);
// recalculate the entire table, which sends a message to owners
// so they can deal with the change
RecalcTotal();
}
/*********************************************************************************
HandleCellTextChanged TCS split & rev 12/13/01
handle change of a text cell.
*********************************************************************************/
void CBreakdownTable::HandleCellTextChanged(const TableIndexT row,
const TableIndexT col,
const Boolean sendMessage)
{
TagType colTag = GetColTag(col);
switch (colTag)
{
case tag_quantity: // only some columns affect row totals
case tag_unitcost:
case tag_waste:
case tag_contractamount:
case tag_percentcompleted:
case tag_valuecompleted:
case tag_financecharge:
case tag_amount:
case tag_overtimehours:
case tag_adjustment:
case tag_markup: // TCS 7/11/99
case tag_current: // TCS 4/24/01
if (!InFindMode()) // TCS 12/13/01
{
RecalcBreakdownRow(row, colTag);
RefreshRow(row);
RecalcTotal();
}
break;
default:
break;
}
// if the table is locked, we also need to mark the viewer as
// 'forced dirty' so it saves changes in the table. Otherwise
// we don't bother with that. TCS 5/13/02
if (!TableCanBeChanged() && mRecordViewer)
mRecordViewer->SetForcedDirty();
// be sure to pass it along
THE_SUPERCLASS::HandleCellTextChanged(row, col, sendMessage);
}
/*********************************************************************************
HandleCellCVChanged TCS moved code here 12/13/01
handle a clairvoyant change. We handle some cv columns here
*********************************************************************************/
void CBreakdownTable::HandleCellCVChanged(const TableIndexT row, const TableIndexT col,
CTCS_CVField *cv)
{
TagType colTag = GetColTag(col);
TCS_FailNILMsg(cv, TCS_GetErrString(errID_BadClairvoyant));
SInt32 oldValue = cv->GetRecentValue(), // TCS 4/4/04
newValue = cv->GetValue();
switch (colTag)
{
case tag_category:
ResetSubcategory(row);
ResetCostItem(row, oldValue, newValue);
if (!InFindMode()) // TCS 12/13/01
{
UpdateItemDetails(row);
RecalcBreakdownRow(row, colTag);
RecalcTotal();
}
RefreshRow(row);
break;
case tag_costarea:
case tag_subcategory:
ResetCostItem(row, oldValue, newValue);
if (!InFindMode()) // TCS 12/13/01
{
UpdateItemDetails(row);
RecalcBreakdownRow(row, colTag);
RecalcTotal();
}
RefreshRow(row);
break;
case tag_costitem:
if (!InFindMode()) // TCS 12/13/01
{
UpdateItemDetails(row);
RecalcBreakdownRow(row, colTag);
RefreshRow(row);
RecalcTotal();
}
break;
default:
break;
}
// be sure to pass it along
THE_SUPERCLASS::HandleCellCVChanged(row, col, cv);
}
#if CAN_USE_MARK
#pragma mark -
#endif
/*********************************************************************************
PrepareCostAreaCV TCS 9/2/99 removed TCS 6/10/03 (unused)
set up a cost area cv field
*********************************************************************************/
/*void CBreakdownTable::PrepareCostAreaCV()
{
// first find the cost area cv
TableCellT selection = GetSelectedCell();
CCostAreaCV *cv = TCS_SAFE_CAST(FetchCellCVField(selection), CCostAreaCV);
if (cv)
{ // set the owner class
cv->SetOwnerClass(GetOwnerClass());
}
}*/
/*********************************************************************************
PrepareSubcatCV
set up a subcategory cv field
*********************************************************************************/
void CBreakdownTable::PrepareSubcatCV(const DBid catSystemID, const UInt8 jobClass,
const DBid jobID)
{
// first find the subcat cv
TableCellT selection = GetSelectedCell();
CSubcatCV *cv = TCS_SAFE_CAST(FetchCellCVField(selection), CSubcatCV);
if (cv)
{ // set the category system
cv->SetCatSystem(catSystemID);
// now set the category reference
TableIndexT col;
col = GetMemberCol(tag_category);
DBid cat = 0;
if (col)
{ // a category column exists, so set the reference
cat = GetCellValue(ROW(selection), col);
cv->SetCatRef(cat);
}
// now set the job references TCS 12/18/98
cv->SetJobClass(jobClass);
cv->SetJob(jobID);
}
}
/*********************************************************************************
PrepareCostItemCV
set up a cost item cv field
*********************************************************************************/
void CBreakdownTable::PrepareCostItemCV()
{
// first find the cost item cv
TableCellT selection = GetSelectedCell();
CCostItemCV *cv = TCS_SAFE_CAST(FetchCellCVField(selection), CCostItemCV);
if (cv)
{
// we have a cost item cv, so set the filters for it
TableIndexT col;
TableIndexT row = ROW(selection);
// first set the cost area
DBid costArea = 0;
col = GetMemberCol(tag_costarea);
if (col)
costArea = GetCellValue(row, col);
cv->SetCostArea(costArea);
// now set the category reference
DBid cat = 0;
col = GetMemberCol(tag_category);
if (col) // a category column exists
cat = GetCellValue(row, col);
cv->SetCatRef(cat);
// set the subcategory reference rev TCS 3/20/99
DBid subcat = 0;
col = GetMemberCol(tag_subcategory);
if (col)
subcat = GetCellValue(row, col);
cv->SetSubCatRef(subcat);
// set the job id and class refs TCS 3/21/99 rev 2/28/02
cv->SetAccountID(mMainAccount);
cv->SetAccountClass(mMainAccountClass);
// set special order details TCS 2/25/02
cv->SetSpecialOrderOnly(mSpecialOrderOnly);
cv->SetNoSpecialOrder(mNoSpecialOrder);
}
}
/*********************************************************************************
PrepareLocationCV TCS 9/4/98 rev 8/23/99
set up a location cv field
*********************************************************************************/
void CBreakdownTable::PrepareLocationCV()
{
// first find the location cv
TableCellT selection = GetSelectedCell();
CLocationCV *cv = TCS_SAFE_CAST(FetchCellCVField(selection), CLocationCV);
if (cv)
{ // set the job type
cv->SetJobType(mJobType);
cv->SetLocationPackage(mLocationPackage);
}
}
#if CAN_USE_MARK
#pragma mark -
#endif
/*********************************************************************************
UpdateRowFromDBObject
update a row from database object NEW FORM adapted TCS 3/15/99
*********************************************************************************/
void CBreakdownTable::UpdateRowFromDBObject(const TableIndexT row,
DB_PersistentObject *object)
{
// sanity check
TCS_FailNILMsg(row, TCS_GetErrString(errID_BadRow));
TCS_FailNILMsg(object, TCS_GetErrString(errID_BadObject));
SMemberInfo memberInfo;
// fill in object ref TCS 2/7/00
SObjectInfo info;
info.classID = object->GetDBClassID();
info.itemID = object->GetDBID();
info.transactionType = 0;
mBreakdownItemArray.AssignItemAt(row, info);
// go through each column and update the member
for (TableIndexT col = 1; col <= LastCol(); col++)
{
TCS_TRY
{
// based on the member type, set the cell value
// from the object data
TCS_ASSERTMsg(GetColMemberInfo(col, &memberInfo),
TCS_GetErrString(errID_BadColumn));
UpdateCellFromDBObject(row, col, memberInfo, object);
}
TCS_CATCH
{ // catch the assertion so other fields can be written
}
}
// force a redraw
RefreshRow(row);
}
/*********************************************************************************
UpdateCellFromDBObject separated TCS 4/27/00
update a cell from a database object
*********************************************************************************/
void CBreakdownTable::UpdateCellFromDBObject(const TableIndexT row, const TableIndexT col,
SMemberInfo &memberInfo, DB_PersistentObject *object)
{
// sanity check
TCS_FailNILMsg(row, TCS_GetErrString(errID_BadRow));
TCS_FailNILMsg(col, TCS_GetErrString(errID_BadColumn));
TCS_FailNILMsg(object, TCS_GetErrString(errID_BadObject));
TagType colTag = memberInfo.tag;
// we get coltype separately since it may
// vary by row in some tables (TCS 3/16/99)
SInt32 colType = GetColType(row, col);
CTextString cstring;
SInt32 value;
switch (colType)
{
case coltype_caption: // edit fields are filled in based on data type
case coltype_edit:
case coltype_mixedit:
switch (memberInfo.type)
{
case type_enum:
case type_objclass:
case type_objectid:
if (colType == coltype_caption)
{ // if a caption, no need to do anything
}
else // if not a caption, it must be a temp edit cell
{ // rev TCS 7/6/00
object->GetMemberValue(colTag, type_cstring, &cstring);
SetCellText(row, col, cstring);
}
break;
case type_cstringcv: // mixed string / cv value TCS 3/13/99
if (IsMixedCV(row, col))
{
TCS_ASSERTMsg(object->GetMemberValue(colTag, type_long, &value),
TCS_GetValueErrString(colTag));
SetCVCellValue(row, col, value);
}
else
{
TCS_ASSERTMsg(object->GetMemberValue(colTag, type_cstring,
&cstring), TCS_GetValueErrString(colTag));
SetCellText(row, col, cstring);
}
break;
case type_short: // it's an integer
case type_long:
case type_uchar:
// if it's an integer, we fill in the cell field as a number
TCS_ASSERTMsg(object->GetMemberValue(colTag, type_long, &value),
TCS_GetValueErrString(colTag));
SetCellValue(row, col, value);
break;
case type_stringptr: // all other types are filled in as strings
case type_cstring:
case type_longcstring:
case type_date:
case type_time:
case type_timeonly: // TCS 5/30/02
case type_money:
case type_emoney:
case type_percent:
case type_number:
case type_real:
//case type_float:
TCS_ASSERTMsg(object->GetMemberValue(colTag, type_cstring,
&cstring), TCS_GetValueErrString(colTag));
SetCellText(row, col, cstring);
break;
case type_objectidx: // objectidx is shown as a number TCS 7/7/99 rev 7/22/99
TCS_ASSERTMsg(object->GetMemberValue(colTag, type_long, &value),
TCS_GetValueErrString(colTag));
SetCellValue(row, col, value);
break;
default:
TCS_DebugAlert(CTextString("Oops, cannot handle data type ") +
TCS_GetTagMessage(memberInfo.type) + CTextString(" in CBreakdownTable!"));
break;
}
break;
case coltype_menucv: // if it's a cv or menucv,
case coltype_menulookup: // use SetCVCellValue to fill the field
case coltype_cv:
case coltype_lookup:
case coltype_mixcv:
TCS_ASSERTMsg(object->GetMemberValue(colTag, type_long, &value),
TCS_GetValueErrString(colTag));
SetCVCellValue(row, col, value);
break;
case coltype_checkmark: // it's a checkmark, TCS 8/18/98
{
Boolean isChecked;
TCS_ASSERTMsg(object->GetMemberValue(colTag, type_boolean, &isChecked),
TCS_GetValueErrString(colTag));
SetChecked(row, col, isChecked);
}
break;
default:
TCS_DebugAlert("Oops, invalid colType in CBreakdownTable::UpdateCellFromDBObject!");
break;
}
}
/*********************************************************************************
UpdateDBObjectFromRow NEW FORM adapted TCS 3/15/99
update the database object with values from a row in the table
*********************************************************************************/
void CBreakdownTable::UpdateDBObjectFromRow(const TableIndexT row,
DB_PersistentObject *object)
{
// sanity check
TCS_FailNILMsg(row, TCS_GetErrString(errID_BadRow));
TCS_FailNILMsg(object, TCS_GetErrString(errID_BadObject));
// we may want to load some data first, even if it's not in the
// first column. Subclasses can force this to happen by returning
// a value for GetFirstDataTag TCS 12/12/01
TagType startTag = GetFirstDataTag();
SInt32 startCol = 0;
if (startTag)
{
startCol = GetMemberCol(startTag);
if (startCol)
{
UpdateDBObjectField(row, startCol, object);
}
}
// go through each remaining column and update the object member
for (TableIndexT col = 1; col <= LastCol(); col++)
{
if (col != startCol)
{
UpdateDBObjectField(row, col, object);
}
}
}
/*********************************************************************************
UpdateDBObjectField TCS split 12/12/01
update the database object with the data in one table cell
*********************************************************************************/
void CBreakdownTable::UpdateDBObjectField(const TableIndexT row, const TableIndexT col,
DB_PersistentObject *object)
{
TCS_TRY
{
SMemberInfo memberInfo;
SInt32 value;
// get the cell text
CTextString valueText = GetCellText(row, col);
TCS_ASSERTMsg(GetColMemberInfo(col, &memberInfo),
TCS_GetErrString(errID_BadColumn));
TagType colTag = memberInfo.tag;
// we get coltype separately since it may
// vary by row in some tables (TCS 3/16/99)
SInt32 colType = GetColType(row, col);
switch (colType)
{
case coltype_caption:
case coltype_edit:
case coltype_mixedit: // for edit fields, we check the data type
switch (memberInfo.type)
{
case type_cstringcv: // mixed string / cv value TCS 3/13/99
if (IsMixedCV(row, col))
{
if (valueText.Length() == 0) // right now we special case for blank
value = 0; // since it's been giving troubles 4/10/98 TCS
else
value = GetCellValue(row, col);
TCS_ASSERTMsg(object->SetMemberValue(colTag, type_objectid, &value),
TCS_SetValueErrString(colTag));
}
else
{
TCS_ASSERTMsg(object->SetMemberValue(colTag, type_cstring, &valueText),
TCS_SetValueErrString(colTag));
}
break;
case type_short: // it's an integer
case type_long:
case type_uchar:
value = valueText.GetNumberValue(cAllowNegatives); // rev TCS 11/2/99
TCS_ASSERTMsg(object->SetMemberValue(colTag, type_long, &value),
TCS_SetValueErrString(colTag));
break;
/*case type_float: // it's a float
valueText.FormatAsNumber(cAllowDecimals, cAllowNegatives);
TCS_ASSERTMsg(object->SetMemberValue(colTag, type_float, &valueText),
TCS_SetValueErrString(colTag));
break;*/
case type_real: // it's a real(TCS 11/11/98)
valueText.FormatAsNumber(cAllowDecimals, cAllowNegatives);
TCS_ASSERTMsg(object->SetMemberValue(colTag, type_real, &valueText),
TCS_SetValueErrString(colTag));
break;
case type_money: // it's a money
{
valueText.FormatAsNumber(cAllowDecimals, cAllowNegatives);
CMoney moneyValue = CMoney(valueText);
TCS_ASSERTMsg(object->SetMemberValue(colTag, type_money, &moneyValue),
TCS_SetValueErrString(colTag));
}
break;
case type_emoney: // it's an extended money
{
valueText.FormatAsNumber(cAllowDecimals, cAllowNegatives);
CMoney moneyValue = CMoney(valueText);
TCS_ASSERTMsg(object->SetMemberValue(colTag, type_emoney, &moneyValue),
TCS_SetValueErrString(colTag));
}
break;
case type_number: // it's a money-based number
{
valueText.FormatAsNumber(cAllowDecimals, cAllowNegatives);
CMoney numberValue = CMoney(valueText);
TCS_ASSERTMsg(object->SetMemberValue(colTag, type_number, &numberValue),
TCS_SetValueErrString(colTag));
}
break;
case type_percent: // it's a percent
{
valueText.FormatAsNumber(cAllowDecimals, cAllowNegatives);
CMoney percentValue = CMoney(valueText);
TCS_ASSERTMsg(object->SetMemberValue(colTag, type_percent, &percentValue),
TCS_SetValueErrString(colTag));
}
break;
case type_date: // it's a date
{
CDate dateValue;
CDate::StringToDate(valueText, &dateValue);
TCS_ASSERTMsg(object->SetMemberValue(colTag, type_date, &dateValue),
TCS_SetValueErrString(colTag));
}
break;
case type_time: // it's a time
case type_timeonly:
{
CDate dateValue;
CDate::StringToTime(valueText, &dateValue);
TCS_ASSERTMsg(object->SetMemberValue(colTag, type_time, &dateValue),
TCS_SetValueErrString(colTag));
}
break;
case type_stringptr:
case type_cstring:
case type_longcstring:
// we will update all other member types as a string
TCS_ASSERTMsg(object->SetMemberValue(colTag, type_cstring, &valueText),
TCS_SetValueErrString(colTag));
break;
case type_objectidx:
case type_objectid: // we may get OBJI values in an edit field,
// e.g. for a cv that has been disabled by setting to
// coltype_caption. We'll try to fill it anyhow,
// just to be cautious TCS 3/18/99
if (valueText.Length() == 0)
value = 0;
else
value = GetCellValue(row, col);
TCS_ASSERTMsg(object->SetMemberValue(colTag, type_objectid, &value),
TCS_SetValueErrString(colTag));
break;
default:
TCS_DebugAlert(CTextString("Oops, cannot handle field type ") +
TCS_GetTagMessage(memberInfo.type) +
CTextString(" in CBreakdownTable::UpdateDBObjectFromRow!"));
break;
}
break;
case coltype_checkmark: // it's a checkmark, TCS 8/18/98
{
Boolean isChecked = IsChecked(row, col);
TCS_ASSERTMsg(object->SetMemberValue(colTag, type_boolean, &isChecked),
TCS_SetValueErrString(colTag));
}
break;
case coltype_cv: // it's a regular object id cv
case coltype_mixcv:
case coltype_lookup:
if (valueText.Length() == 0) // right now we special case for blank
value = 0; // since it's been giving troubles 4/10/98 TCS
else
value = GetCellValue(row, col);
TCS_ASSERTMsg(object->SetMemberValue(colTag, type_objectid, &value),
TCS_SetValueErrString(colTag));
break;
case coltype_menucv: // it's a popup cv with enum data
case coltype_menulookup:
{
UInt8 enumValue;
if (valueText.Length() == 0) // right now we special case for blank
enumValue = 0; // since it's been giving troubles 4/10/98 TCS
else
enumValue = GetCellValue(row, col);
TCS_ASSERTMsg(object->SetMemberValue(colTag, type_enum, &enumValue),
TCS_SetValueErrString(colTag));
}
break;
default:
TCS_DebugAlert("Oops, invalid colType in CBreakdownTable::UpdateDBObjectFromRow!");
break;
}
}
TCS_CATCH
{ // catch the assertion so other fields can be read
}
}/*********************************************************************************
DoForEachMemberCol NO LONGER USED
apply the given function to each column in the breakdown table.
*********************************************************************************/
/*void CBreakdownTable::DoForEachMemberCol(BreakdownTableColFunc func,
void *param1, void *param2,
void *param3, void *param4)
{
// sanity check
TCS_FailNILMsg(func, TCS_GetErrString(errID_BadFunction));
// walk the members in the row
SMemberInfo memberInfo;
TableIndexT col = 1;
CTmplArrayIterator<SMemberInfo> iterator(mColumnMemberArray);
while (iterator.Next(memberInfo))
{
(*func)(col, memberInfo, this, param1, param2, param3, param4);
col++;
}
}*/
#if CAN_USE_MARK
#pragma mark -
#endif
/*********************************************************************************
DoFillDown TCS 1/20/00
fill values from the row above. We override since we want to recalc the table
*********************************************************************************/
void CBreakdownTable::DoFillDown()
{
THE_SUPERCLASS::DoFillDown();
// recalculate the entire table, which sends a message to owners
// so they can deal with the change
RecalcTotal();
}
/*********************************************************************************
RecalcTotal
recalculate the total of the entire breakdown table and send a message
to owners. Subclasses may override if a different column is used for the total
*********************************************************************************/
CMoney CBreakdownTable::RecalcTotal()
{
CMoney total(0,0);
TableIndexT amountCol = GetAmountCol(); // rev TCS 9/10/99
if (amountCol)
total = GetColumnMoneyTotal(amountCol);
BroadcastMessage(msg_TableTotalChanged, &total);
return total;
}
/*********************************************************************************
ResetSubcategory
erase the subcategory
*********************************************************************************/
void CBreakdownTable::ResetSubcategory(TableIndexT row)
{
TableIndexT col = GetMemberCol(tag_subcategory);
if (col)
ClearCVCell(row, col);
}
/*********************************************************************************
ResetCostItem
erase the cost item
*********************************************************************************/
void CBreakdownTable::ResetCostItem(TableIndexT row, const SInt32 /*oldValue*/,
const SInt32 /*newValue*/)
{
TableIndexT col = GetMemberCol(tag_costitem);
if (col)
ClearCVCell(row, col);
}
#if CAN_USE_MARK
#pragma mark -
#endif
/*********************************************************************************
UpdateFromLayoutStream
update the breakdown table from the layout stream. Currently not
implemented, since we don't have any tables stored that way.
*********************************************************************************/
void CBreakdownTable::UpdateFromLayoutStream(CInputStream &/*stream*/)
{
}
|