Link to: header | other data directory
Copyright Turtle Creek Software 1996-2006. All Rights Reserved.
Comments
DB_CatNameArrayOwner
owner of an array of category names and status, used for cvs & popups.
We store them in the database, for speed.
The name array includes a status byte and an additional byte. A few
other classes also use this type of name array because of that.
Note that we frequently get category arrays from a Category System
instead of directly. The system builds a restricted list of categories,
and subcategory lists that belong to that category.
This class stores cost categories for the Goldenseal job cost accounting software,
project management software and construction project
estimating software.
SUPERCLASS = DB_PersistentObject
Constructor
/*********************************************************************************
Constructor
*********************************************************************************/
DB_CatNameArrayOwner::DB_CatNameArrayOwner()
{
mEndSafetyTag = tag_endsafetytag; // TCS 9/8/02
// we used to set array sorting and comparator here. Now that's done
// in AddObject TCS 9/20/00
}
Source Code
/*********************************************************************************
GetFileLength 3/22/00
get the file length of the object
*********************************************************************************/
NeoSize DB_CatNameArrayOwner::GetFileLength(const CNeoFormat *aFormat) const
{
return THE_SUPERCLASS::GetFileLength(aFormat) +
ARRAY_FILE_SIZE(mCatNameArray) +
cFileLength;
}
/*********************************************************************************
GetMemberValue
return the value of the member with the given tag
*********************************************************************************/
Boolean DB_CatNameArrayOwner::GetMemberValue(const NeoTag aTag, const NeoTag aType,
void *aValue) const
{
switch (aTag)
{
case tag_menuname: // get the name of the class TCS 9/30/02
{
CTextString className = DB_ClassDescriptor::GetClassNamePlural(GetDBID());
return ConvertMember(&className, type_cstring, aValue, aType);
}
break;
default:
return THE_SUPERCLASS::GetMemberValue(aTag, aType, aValue);
break;
}
}
/*********************************************************************************
ReadObject 3/22/00
read the object from the db stream
*********************************************************************************/
void DB_CatNameArrayOwner::ReadObject(CNeoStream *aStream, const TagType aTag)
{
TCS_FailNILMsg(aStream, TCS_GetErrString(errID_BadStream));
CNeoDebugImport checker(aStream, this, cCheckTooSmall);
THE_SUPERCLASS::ReadObject(aStream, aTag);
if (!IsIOValid()) // TCS 2/5/02
return;
ReadCatNameArrayFromStream(aStream, mCatNameArray, cHasSafetyTag);
mEndSafetyTag = aStream->ReadEndSafetyTag(this); // mfs_sa 20feb2k3
if (!IsValidEndTag(mEndSafetyTag))
ReportDamagedObject(GetDBClassID(), GetDBID());
}/*********************************************************************************
WriteObject 3/22/00
write the object to the db stream
*********************************************************************************/
void DB_CatNameArrayOwner::WriteObject(CNeoStream *aStream, const TagType aTag)
{
TCS_FailNILMsg(aStream, TCS_GetErrString(errID_BadStream));
// make sure we have valid data to write TCS 9/8/02
if (!IsValidEndTag(mEndSafetyTag))
{
ReportDamagedObject(GetDBClassID(), GetDBID());
mEndSafetyTag = tag_endsafetytag; // TCS 11/26/02
}
CNeoDebugExport checker(aStream, this, cCheckTooSmall);
THE_SUPERCLASS::WriteObject(aStream, aTag);
WriteCatNameArrayToStream(aStream, mCatNameArray, cHasSafetyTag);
aStream->WriteEndSafetyTag(mEndSafetyTag, this); // mfs_sa 20feb2k3
}
#if CAN_USE_MARK
#pragma mark -
#endif
/*********************************************************************************
GetAccountNameArray 3/22/00
fill in the array of account item names
*********************************************************************************/
Boolean DB_CatNameArrayOwner::GetCatNameArray(TCatNameArray *array)
{
*array = mCatNameArray;
return true;
}
/*********************************************************************************
GetNameArray TCS 4/21/00
fill in a simple cv array of all item names
*********************************************************************************/
Boolean DB_CatNameArrayOwner::GetNameArray(TNameIDArray *array, const Boolean forPopup)
{
SNameIDInfo menuInfo;
SCatNameInfo catInfo;
TCatNameArrayIterator iterator(mCatNameArray);
TCS_TRY // TCS 1/12/03
{
while (iterator.Next(catInfo))
{
menuInfo.id = catInfo.id;
// equal buffer size so we can do a direct copy
TCS_StringCopy(menuInfo.itemName, catInfo.itemName);
array->Append(menuInfo);
if (forPopup && iterator.GetCurrentIndex() > cMaxPopupCount) // TCS 1/12/03
break;
}
return true;
}
TCS_CATCH {}
return false;
}
/*********************************************************************************
GetActiveObjectArray TCS 9/26/00
fill in a simple object id array of all active transactions
*********************************************************************************/
TObjectIDArray DB_CatNameArrayOwner::GetActiveObjectArray(const Boolean includeIncomplete)
{
TObjectIDArray outArray;
SCatNameInfo catInfo;
TCatNameArrayIterator iterator(mCatNameArray);
UInt8 statusClass;
while (iterator.Next(catInfo))
{
statusClass = DB_ClassDescriptor::GetStatusClass(catInfo.status, GetDBID());
if (statusClass == status_Active || (includeIncomplete && statusClass == status_InUse))
{
outArray.Append(catInfo.id);
}
}
return outArray;
}
/*********************************************************************************
GetMatchingNameArray TCS 12/13/00
fill in a simple object id array of all active transactions
*********************************************************************************/
TNameIDArray DB_CatNameArrayOwner::GetMatchingNameArray(const UInt8 matchValue)
{
TNameIDArray outArray;
TCatNameArrayIterator iterator(mCatNameArray);
SCatNameInfo catInfo;
SNameIDInfo outInfo;
while (iterator.Next(catInfo))
{
if (catInfo.status == matchValue)
{
outInfo.id = catInfo.id;
TCS_StringCopy(outInfo.itemName, catInfo.itemName);
outArray.Append(outInfo);
}
}
return outArray;
}
/*********************************************************************************
GetRangeIDArray TCS 10/30/00
get an array of record ID's in the given range
*********************************************************************************/
TObjectIDArray DB_CatNameArrayOwner::GetRangeIDArray(const UInt8 recordRange) const
{
TObjectIDArray outArray;
SCatNameInfo info;
SInt32 count = 0;
TCatNameArrayIterator iterator(mCatNameArray);
switch (recordRange)
{
case records_allitems:
case records_flaggeditems:
case records_flaggedandfound:
case records_unprinted:
while (iterator.Next(info))
{
outArray.Append(info.id);
}
break;
default:
TCS_DebugAlert("Oops, bad case in DB_CatNameArrayOwner::GetRangeIDArray!");
break;
}
return outArray;
}
/*********************************************************************************
GetIDArray TCS 3/28/99
fill in the array of object id's
*********************************************************************************/
Boolean DB_CatNameArrayOwner::GetIDArray(TObjectIDArray &array)
{
array.RemoveAllItems();
TCatNameArrayIterator iterator(mCatNameArray);
SCatNameInfo info;
while (iterator.Next(info))
{
array.Append(info.id);
}
return true;
}
/*********************************************************************************
GetRecordCount TCS 10/15/00
get the number of records of the given record type
*********************************************************************************/
SInt32 DB_CatNameArrayOwner::GetRecordCount(const UInt8 recordRange) const
{
SCatNameInfo info;
SInt32 count = 0;
TCatNameArrayIterator iterator(mCatNameArray);
switch (recordRange)
{
case records_allitems:
case records_flaggeditems: // we don't use flags or found items
case records_flaggedandfound:
case records_unprinted:
return mCatNameArray.GetCount();
break;
case records_activeitems: // TCS 11/15/00
case records_standard:
while (iterator.Next(info))
{
if (DB_ClassDescriptor::StatusIsActive(info.status, GetDBID()))
count++;
}
return count;
break;
case records_voiditems: // TCS 11/15/00
while (iterator.Next(info))
{
if (DB_ClassDescriptor::StatusIsVoid(info.status, GetDBID()))
count++;
}
return count;
break;
case records_completeditems: // TCS 11/15/00
while (iterator.Next(info))
{
if (DB_ClassDescriptor::StatusIsCompleted(info.status, GetDBID()))
count++;
}
return count;
break;
// these choices don't really apply to categories
// so we'll just return the count of all items
case records_paid:
case records_unpaid:
case records_special:
case records_overdueitems:
case records_openitems:
case records_planneditems:
case records_foundchecks:
case records_flaggedchecks:
case records_unprintedchecks:
return mCatNameArray.GetCount();
break;
default:
TCS_DebugAlert("Oops, bad case in DB_CatNameArrayOwner::GetRecordCount!");
return mCatNameArray.GetCount();
break;
}
}
/*********************************************************************************
SortMenuArray TCS 12/20/02
sort the items in this item's array.
*********************************************************************************/
void DB_CatNameArrayOwner::SortMenuArray()
{
DB_ObjectTempRemover remover(this); // TCS 8/26/03
if (remover.WasRemoved())
{
mCatNameArray.SortWithComparator(NEW CCatNameComparator);
}
}
/*********************************************************************************
ClearArray TCS 12/20/02
remove all items from this item's array.
*********************************************************************************/
void DB_CatNameArrayOwner::ClearArray()
{
DB_ObjectTempRemover remover(this); // TCS 8/26/03
if (remover.WasRemoved())
{
mCatNameArray.RemoveAllItems();
}
}
/*********************************************************************************
FindItemByID TCS 3/22/00
Check if the given ID is already in the array, and return its index
*********************************************************************************/
SInt32 DB_CatNameArrayOwner::FindItemByID(const DBid compareID)
{
SCatNameInfo info;
TCatNameArrayIterator iterator(mCatNameArray);
while (iterator.Next(info))
{
if (info.id == compareID)
return iterator.GetCurrentIndex();
}
// if we got this far, it's not included
return 0;
}
/*********************************************************************************
FetchObjectWithName TCS 7/25/01 rev 1/15/02
Return whether the given name already exists here.
*********************************************************************************/
DBid DB_CatNameArrayOwner::FetchObjectWithName(const CTextString &matchName, const DBid skipID)
{
SCatNameInfo info;
TCatNameArrayIterator iterator(mCatNameArray);
char *matchText = matchName.GetCharPtr();
while (iterator.Next(info))
{
if (info.id != skipID)
{
if (TCS_EqualStrings(matchText, info.itemName))
return info.id;
}
}
// if we got this far, it's not included
return 0;
}
#if CAN_USE_MARK
#pragma mark -
#endif
/*********************************************************************************
AddToArray 3/22/00
add an object to this item's array.
*********************************************************************************/
Boolean DB_CatNameArrayOwner::AddToArray(const DB_PersistentObject *object,
const Boolean sortArray)
{
if (!object->ShouldBeListed())
return false;
DBid id = object->GetDBID();
SInt32 itemIndex = FindItemByID(id);
if (itemIndex) // it's already there
return false;
// do prep work
TCS_FailNILMsg(gDBFile, TCS_GetErrString(errID_BadFile));
SCatNameInfo info;
DB_ObjectTempRemover remover(this); // TCS 8/26/03
if (remover.WasRemoved())
{
// fetch the name (and truncate if necessary)
CTextString menuName = object->GetMenuName();
menuName.Truncate(cMenuTextLen - 1);
TCS_BufferFromText(info.itemName, menuName);
info.id = id;
info.status = object->GetStatusForMenuArray(); // TCS 10/27/00 rev 12/13/00
info.spareByte = object->GetEnumForMenuArray();
// add to the database and sort the array by name
mCatNameArray.Append(info);
if (sortArray) // TCS 12/20/02
mCatNameArray.SortWithComparator(NEW CCatNameComparator);
}
return true;
}/*********************************************************************************
RemoveFromArray
remove an object from this item's array.
*********************************************************************************/
void DB_CatNameArrayOwner::RemoveFromArray(const DB_PersistentObject *object)
{
TCS_FailNILMsg(object, TCS_GetErrString(errID_BadObject));
DBid id = object->GetDBID();
if (id)
RemoveObjectByID(id);
}
/*********************************************************************************
RemoveObjectByID TCS split 10/17/03
remove an object id from this item's array. Use this form directly to remove
an object that doesn't exist
*********************************************************************************/
void DB_CatNameArrayOwner::RemoveObjectByID(const DBid id)
{
SInt32 itemIndex = FindItemByID(id);
if (itemIndex)
{
TCS_FailNILMsg(gDBFile, TCS_GetErrString(errID_BadFile));
DB_ObjectTempRemover remover(this); // TCS 8/26/03
if (remover.WasRemoved())
{
mCatNameArray.RemoveItemAt(itemIndex);
}
}
}
/*********************************************************************************
HandleObjectChanged TCS 3/22/00
update status for an object in this item's array. This is used for an object
change
*********************************************************************************/
void DB_CatNameArrayOwner::HandleObjectChanged(const DB_PersistentObject *object,
const Boolean doSort)
{
if (object->ShouldBeListed()) // currently always true
{
DBid id = object->GetDBID();
SInt32 itemIndex = FindItemByID(id);
if (itemIndex == LArray::index_Bad)
{ // object is not here, so add it
AddToArray(object);
}
else
{ // object is here, so update it. Object length may change,
// so we need to remove temporarily from the dbase TCS 10/3/00
DB_ObjectTempRemover remover(this); // TCS 8/26/03
if (remover.WasRemoved())
{
SCatNameInfo info;
mCatNameArray.FetchItemAt(itemIndex, info);
info.status = object->GetStatusForMenuArray(); // TCS 10/27/00 rev 12/13/00
info.spareByte = object->GetEnumForMenuArray();
CTextString menuName = object->GetMenuName();
menuName.Truncate(cMenuTextLen - 1);
Boolean needsSort = !TCS_EqualStrings(info.itemName, menuName.GetCharPtr());
if (needsSort) // TCS 12/18/02
TCS_BufferFromText(info.itemName, menuName);
mCatNameArray.AssignItemAt(itemIndex, info);
if (doSort && needsSort)
{ // rev TCS 10/3/00
mCatNameArray.SortWithComparator(NEW CCatNameComparator);
}
}
}
}
else // object should not be listed, so remove it
RemoveFromArray(object);
MakeDirty();
}
/*********************************************************************************
HandleStatusChanged TCS 3/22/00
update status for an object in this item's array. This is used when an
account's status is changed remotely(so no need to update name, etc)
*********************************************************************************/
void DB_CatNameArrayOwner::HandleStatusChanged(const DB_PersistentObject *object)
{
if (object->ShouldBeListed())
{
DBid id = object->GetDBID();
SInt32 itemIndex = FindItemByID(id);
if (itemIndex == LArray::index_Bad)
{ // object is not here, so add it
AddToArray(object);
}
else
{ // object is here, so update it
SCatNameInfo info;
mCatNameArray.FetchItemAt(itemIndex, info);
info.status = object->GetStatusForMenuArray(); // TCS 10/27/00 rev 12/13/00
info.spareByte = object->GetEnumForMenuArray();
mCatNameArray.AssignItemAt(itemIndex, info);
MakeDirty();
}
}
else // object should not be listed, so remove it
RemoveFromArray(object);
}
#if CAN_USE_MARK
#pragma mark -
#endif
/*********************************************************************************
FindListMatches TCS 12/18/02
doing a find. For some tags, we can search in the menu array and/or
indexed fields in the object class info (future upgrade). That's much faster
than looking through every object.
*********************************************************************************/
Boolean DB_CatNameArrayOwner::FindListMatches(CTCS_Array &selectorArray,
TObjectIDArray &matchArray, const Boolean matchAny)
{
DB_MemberSelector *selector = nil;
CTCS_ArrayIterator iterator (selectorArray, iter_from_end);
Boolean success = false;
UInt8 matchCount = 0;
// loop through the selectors
while (iterator.Previous(&selector))
{
TCS_FailNILMsg(selector, TCS_GetErrString(errID_BadSelector));
if (selector->IsFromTable()) // TCS 1/16/03
continue;
// we can do a quick find for name, id or status
switch (selector->getSelectTag())
{
case tag_name:
case tag_objectid:
case tag_status:
// we have values here, so fetch them
// from the array
FillListMatches(selector, matchArray, matchAny, matchCount);
success = true;
// remove the selector so we don't
// repeat the search later on
TCS_Forget(selector);
selectorArray.RemoveItemAt(iterator.GetCurrentIndex());
break;
default:
break;
}
}
// sort the list by object ID so we
// stay in the order originally entered TCS 12/23/02
if (matchArray.GetCount() > 0)
matchArray.SortWithComparator(NEW LLongComparator);
return success;
}
/*********************************************************************************
FillListMatches TCS 12/23/02
fill in matches for the given selector
*********************************************************************************/
Boolean DB_CatNameArrayOwner::FillListMatches(DB_MemberSelector *selector,
TObjectIDArray &matchArray, const Boolean matchAny, UInt8 &matchCount)
{
TCS_FailNILMsg(selector, TCS_GetErrString(errID_BadSelector));
TCatNameArrayIterator iterator (mCatNameArray);
SCatNameInfo info;
// we first fill matches into a temporary array
TObjectIDArray tempArray;
matchCount++;
Boolean gaveWarning = false;
NeoTag tag;
while (iterator.Next(info))
{
tag = selector->getSelectTag();
switch (tag)
{
case tag_name:
if (selector->MatchesString(CTextString(info.itemName)))
tempArray.Append(info.id);
break;
case tag_objectid:
if (selector->MatchesLong(info.id))
tempArray.Append(info.id);
break;
case tag_status:
if (selector->MatchesLong(info.status))
tempArray.Append(info.id);
break;
default:
if (!gaveWarning) // TCS 5/20/03
{
TCS_ErrorAlert(CTextString("Oops, bad case in DB_CatNameArrayOwner::FillListMatches ") + TCS_GetTagMessage(tag));
gaveWarning = true;
}
break;
}
}
// fill in the actual match array. How we do that depends
// on the type of match, and whether this is the first match
if (matchCount < 2) // TCS 12/23/02
matchArray = tempArray; // first match
else if (matchAny)
matchArray.Add(tempArray); // do a 'union'
else
matchArray.Collapse(tempArray); // do an 'intersection'
return (matchArray.GetCount() > 0);
}
/*********************************************************************************
FillDataReport TCS 9/7/02
fill in a diagnostic table that shows data field values.
*********************************************************************************/
void DB_CatNameArrayOwner::FillDataReport(CTCS_Table *table, CNeoStream *stream) const
{
TCS_FailNILMsg(table, TCS_GetErrString(errID_BadTable));
TCS_FailNILMsg(stream, TCS_GetErrString(errID_BadStream));
THE_SUPERCLASS::FillDataReport(table, stream);
FillFieldArrayRow(table, stream, "TCatNameArray", mCatNameArray);
FillEndSafetyTag(table, stream, mEndSafetyTag);
}
|