Link to: header | other data directory
Copyright Turtle Creek Software 1996-2006. All Rights Reserved.
Comments
DB_Layout
This class manages custom layouts the Goldenseal job cost accounting software,
project management software, construction
estimating software
and construction project estimating software.
DB_Layout is a persistent object which stores a database layout. Layouts control the
contents of data entry windows (accounts, transactions, lists etc), printed
forms, reports, and estimate dimension screens.
We store layout data in a handle which we parse the same as a LAYT resource handle.
For most items we provide stock layouts via a LAYT resource. When users change
the layout, we store it in the company file as a DB_Layout object (or subclass).
We also store new layouts that the user creates for custom reports, new print
forms or new estimate dimensions.
SUPERCLASS = DB_PersistentObject
Constructor
/*********************************************************************************
constructor TCS 6/28/02
*********************************************************************************/
DB_Layout::DB_Layout()
{
mLayoutHandle = nil;
mLayoutSafetyTag = tag_endsafetytag; // TCS 9/17/02
}
/*********************************************************************************
destructor TCS 6/28/02
*********************************************************************************/
DB_Layout::~DB_Layout()
{
TCS_ForgetHandle(&mLayoutHandle);
}
Source Code
/*********************************************************************************
GetFileLength
return the file length used by this object
*********************************************************************************/
NeoSize DB_Layout::GetFileLength(const CNeoFormat *aFormat) const
{
NeoSize baseLength = THE_SUPERCLASS::GetFileLength(aFormat) +
HANDLE_FILE_SIZE(mLayoutHandle) +
mName.FileLength(cMenuTextLen) +
cFileLength;
if (GetDBClassID() == id_ReportLayout) // TCS 9/17/02
return baseLength;
else
return baseLength + sizeof(TagType);
}
/*********************************************************************************
CopyFrom
copy the data members from the passed object. This is used to implement
duplicate. source should be an object of the same class as this object
*********************************************************************************/
void DB_Layout::CopyFrom(DB_PersistentObject *source, const UInt8 /*copyFlags*/)
{
DB_Layout *src = TCS_SAFE_CAST(source, DB_Layout);
TCS_FailNILMsg(src, TCS_GetErrString(errID_BadRecord));
// copy the name
mName = src->mName;
mLayoutHandle = TCS_CopyHandle(src->mLayoutHandle);
}
/*********************************************************************************
GetMemberValue
return the value of the member with the given tag
*********************************************************************************/
Boolean DB_Layout::GetMemberValue(const TagType aTag, const TagType aType,
void *aValue) const
{
switch (aTag)
{
case tag_name:
case tag_menuname: // TCS 2/15/01
return ConvertMember(&mName, type_cstring, aValue, aType);
break;
default:
return THE_SUPERCLASS::GetMemberValue(aTag, aType, aValue);
break;
}
}
/*********************************************************************************
SetMemberValue
set the value of the member with the given tag
*********************************************************************************/
Boolean DB_Layout::SetMemberValue(const TagType aTag, const TagType aType,
const void *aValue)
{
switch (aTag)
{
case tag_name:
return SafeConvertString(aValue, aType, &mName);
break;
default:
return THE_SUPERCLASS::SetMemberValue(aTag, aType, aValue);
break;
}
}
/*********************************************************************************
ReadObject
read the persistent object's data in from a stream
*********************************************************************************/
void DB_Layout::ReadObject(CNeoStream *aStream, const TagType aTag)
{
TCS_FailNILMsg(aStream, TCS_GetErrString(errID_BadStream));
Boolean isReportLayout = (GetDBClassID() == id_ReportLayout); // TCS 9/17/02
CNeoDebugImport checker(aStream, this, !isReportLayout); // TCS 2/24/00
THE_SUPERCLASS::ReadObject(aStream, aTag);
if (!IsIOValid()) // TCS 2/5/02
return;
ReadTextFromStream(aStream, &mName);
if (!mLayoutHandle)
{
// allocate an empty handle, if we don't have one already.
// We do not use TCS_GetNewHandle since we don't want a
// record save or purge now.
mLayoutHandle = TCS_NewHandle();
TCS_FailNILMsg(mLayoutHandle, TCS_GetErrString(errID_BadStream));
}
ReadHandleFromStream(aStream, mLayoutHandle, cHasSafetyTag);
if (!isReportLayout)
{
mLayoutSafetyTag = aStream->ReadEndSafetyTag(this); // rev TCS 4/19/04
if (!IsValidEndTag(mLayoutSafetyTag))
ReportDamagedObject(GetDBClassID(), GetDBID());
}
}
/*********************************************************************************
WriteObject
write the persistent object's data to a stream
*********************************************************************************/
void DB_Layout::WriteObject(CNeoStream *aStream, const TagType aTag)
{
TCS_FailNILMsg(aStream, TCS_GetErrString(errID_BadStream));
Boolean isReportLayout = (GetDBClassID() == id_ReportLayout); // TCS 9/17/02
if (!isReportLayout)
{
if (!IsValidEndTag(mLayoutSafetyTag))
{
ReportDamagedObject(GetDBClassID(), GetDBID());
mLayoutSafetyTag = tag_endsafetytag;
}
}
CNeoDebugExport checker(aStream, this, !isReportLayout);
THE_SUPERCLASS::WriteObject(aStream, aTag);
WriteTextToStream(aStream, mName, cMenuTextLen);
WriteHandleToStream(aStream, mLayoutHandle, cHasSafetyTag);
if (!isReportLayout)
{
aStream->WriteEndSafetyTag(mLayoutSafetyTag, this); // rev TCS 4/19/04
}
}
#if CAN_USE_MARK
#pragma mark -
#endif
/*********************************************************************************
FinishNonViewerCreate TCS 9/20/02
finish creation details. Start with an empty layout handle.
*********************************************************************************/
void DB_Layout::FinishNonViewerCreate()
{
SetNewHandle();
}
#if CAN_USE_MARK
#pragma mark -
#endif
/*********************************************************************************
GetLayoutName (static) rev TCS 9/2/02
return the name of the requested layout. We look in the database, and if
nothing is there, check for a resource name.
*********************************************************************************/
CTextString DB_Layout::GetLayoutName(const DBid layoutID, const DBid layoutType,
const SInt32 layoutResType)
{
CTextString outString;
// first check the database for a layout object
TCS_FailNILMsg(gDBFile, TCS_GetErrString(errID_BadFile));
DB_PersistentObject *layout = gDBFile->GetOneExtendedObject(layoutType, layoutID);
if (layout)
{
DB_ObjectWatcher watcher(layout);
outString = layout->GetName();
}
else
{
outString = TCS_GetResourceName(layoutResType, layoutID);
}
return outString;
}
/*********************************************************************************
GetButtonName rev TCS 9/2/02
return the name of the requested button. The button could be either a
member of the class desc, or a report button.
*********************************************************************************/
CTextString DB_Layout::GetButtonName(DB_ClassDescriptor *desc, const SInt32 buttonID)
{
Boolean isDescButton = false;
if (desc)
{ // we were passed a desc, see if the button belongs to it
SMemberInfo memberInfo;
if (desc->GetMemberInfo(buttonID, &memberInfo) &&
memberInfo.type == type_button)
{
return CTextString(memberInfo.memberName);
}
else
return TCS_GetStockString(stockID_MissingItem);
}
else
{ // it's not a desc button, must be a report button
return GetLayoutName(buttonID, id_ReportLayout);
}
}
/*********************************************************************************
GetLayoutHandle (static)
return a handle to the layout info with the given id.
This routine may return nil, indicating that the requested layout
doesn't exist.
*********************************************************************************/
TCS_Handle DB_Layout::GetLayoutHandle(const SInt32 layoutObjClassID,
const SInt32 layoutID,
const Boolean resourceOnly)
{
TCS_Handle layoutH = nil;
#if TCS_MULTIUSER
if (gIsClient) // TCS 8/12/03
{
CTCS_NetworkMessage ioMessage(msg_GetLayoutHandle);
ioMessage.SetRecordID(layoutID);
ioMessage.SetClassID(layoutObjClassID);
ioMessage.SetFirstByte(resourceOnly);
ioMessage.SetNeedsReply();
if (gApplication->BroadcastNetworkMessage(&ioMessage, cGiveWarning))
{
if (ioMessage.HasData())
{
CTCS_NetworkStream stream(&ioMessage);
if (stream.ReadFromMessage())
{
layoutH = TCS_GetNewHandle(ioMessage.GetDataSize());
TCS_FailNILMsg(layoutH, TCS_GetErrString(errID_BadHandle));
ReadHandleFromStream(&stream, layoutH, cHasSafetyTag);
}
}
}
return layoutH;
}
#endif
// let's get the layout from the dbase first
DB_Layout *layout = nil;
if (!resourceOnly) // TCS rev 6/7/00
{
DB_PersistentObject *object = gDBFile->GetOneExtendedObject(layoutObjClassID, layoutID);
layout = TCS_SAFE_CAST(object, DB_Layout);
}
if (layout)
{ // got the layout, load the layout info
DB_ObjectWatcher watcher(layout);
layoutH = layout->GetLayoutHandle();
}
else
{ // layout doesn't exist, get it from the resource
layoutH = TCS_GetResource(cLayoutResType, layoutID);
if (layoutH)
{ // convert the layout handle from a res to a regular handle
TCS_DetachResource(layoutH);
}
}
// return the handle, which the caller must dispose of
return layoutH;
}
/*********************************************************************************
GetLayoutHandle TCS 7/1/02
return a copy of the layout handle. The caller is responsible for
disposing of the handle
*********************************************************************************/
TCS_Handle DB_Layout::GetLayoutHandle() const
{
if (mLayoutHandle)
{
TCS_Handle outHandle = TCS_CopyHandle(mLayoutHandle);
return outHandle;
}
else
return nil;
}
/*********************************************************************************
SetLayoutHandle TCS 7/1/02
store the given layout handle. We store a copy of it, so the caller is
responsible for disposing of the original.
*********************************************************************************/
void DB_Layout::SetLayoutHandle(const TCS_Handle inHandle)
{
// we should not be in the database while this happens, since the file
// length may change
TCS_ASSERTMsg(!IsInDatabase(), TCS_GetErrString(errID_BadLengthChange));
// get rid of our existing layout
TCS_ForgetHandle(&mLayoutHandle);
mLayoutHandle = TCS_CopyHandle(inHandle);
MakeDirty();
}
/*********************************************************************************
SetNewHandle TCS 8/28/02
store a new (empty) layout handle. This is used for freshly created layouts.
*********************************************************************************/
void DB_Layout::SetNewHandle()
{
// we should not be in the database while this happens, since the file
// length may change. Nor should we have a handle already.
TCS_ASSERTMsg(!IsInDatabase(), TCS_GetErrString(errID_BadLengthChange));
TCS_ASSERTMsg(!mLayoutHandle, TCS_GetErrString(errID_BadHandle));
// create a handle for layout info.
TCS_Handle newHandle = TCS_GetNewHandle(0);
mLayoutHandle = newHandle;
MakeDirty();
}
/*********************************************************************************
GetLayoutIDForForm (static)
return the layout id for the given class and form
*********************************************************************************/
ResIDT DB_Layout::GetLayoutIDForForm(const DBid classID,
const SInt32 formType)
{
Boolean isBankTransaction = DB_ClassDescriptor::IsBankTransaction(classID);
Boolean isBankDetail = DB_ClassDescriptor::IsBankTransDetail(classID);
switch (formType)
{
case form_short:
if (isBankTransaction) // rev TCS 11/17/00
return id_BankCheck + cShortFormBaseID;
else
return classID + cShortFormBaseID;
break;
case form_register:
if (isBankTransaction || isBankDetail)
return id_BankCheck + cRegisterFormBaseID;
else
return classID + cRegisterFormBaseID;
break;
case form_snapshot: // TCS 5/14/01
return classID + cSnapshotIDBase;
break;
default:
// for long and other forms, the layout id is the class id
if (isBankTransaction)
return id_BankCheck; // rev TCS 11/20/01
else
return classID;
break;
}
}
#if CAN_USE_MARK
#pragma mark -
#endif
/*********************************************************************************
LayoutExists (static) Mod JT 5/2/1998. Mod TCS 7/15/98 & 7/21/98
return whether or not a given layout exists.
*********************************************************************************/
Boolean DB_Layout::LayoutExists(const DBid inLayoutID, const DBid inLayoutClassID,
const DBid inLayoutResourceID, const Boolean lookInDB,
const Boolean lookInResource)
{
TCS_FailNILMsg(gDBFile, TCS_GetErrString(errID_BadFile));
#if TCS_MULTIUSER
if (gIsClient)
{
// clients check on the server first TCS 8/12/03
if (LayoutExistsOnServer(inLayoutID, inLayoutClassID, inLayoutResourceID,
lookInDB, lookInResource))
{
return true;
}
else if (lookInResource)
{
return TCS_ResourceExists(inLayoutResourceID, inLayoutID);
}
else
return false;
}
#endif
// Check the dbase first
if (lookInDB)
{
if (gDBFile->ExtendedObjectExists(inLayoutClassID, inLayoutID)) // mod TCS 9/22/98
{
return true;
}
}
// if not in dbase, look to see if a layout resource exists
if (lookInResource) // mod TCS 6/21/00
{
return TCS_ResourceExists(inLayoutResourceID, inLayoutID);
}
else
return false;
}
#if TCS_MULTIUSER
/*********************************************************************************
LayoutExistsOnServer (static) TCS 8/12/03
return whether or not a given layout exists on the server.
*********************************************************************************/
Boolean DB_Layout::LayoutExistsOnServer(const DBid inLayoutID, const DBid inLayoutClassID,
const DBid inLayoutResourceID, const Boolean lookInDB,
const Boolean lookInResource)
{
CTCS_NetworkMessage ioMessage(msg_LayoutExists);
ioMessage.SetRecordID(inLayoutID);
ioMessage.SetClassID(inLayoutClassID);
ioMessage.SetLongValue(inLayoutResourceID);
ioMessage.SetFirstByte(lookInDB);
ioMessage.SetSecondByte(lookInResource);
ioMessage.SetNeedsReply();
if (gApplication->BroadcastNetworkMessage(&ioMessage, cGiveWarning))
{
return ioMessage.GetThirdByte();
}
else
return false;
}
#endif
/*********************************************************************************
LayoutResourceExists (static) TCS 1/27/00
return whether or not a given layout exists in resource form
*********************************************************************************/
Boolean DB_Layout::LayoutResourceExists(const DBid inLayoutID, const DBid inLayoutResourceID)
{
return TCS_ResourceExists(inLayoutResourceID, inLayoutID);
}
/*********************************************************************************
FillDataReport TCS 9/7/02
fill in a diagnostic table that shows data field values.
*********************************************************************************/
void DB_Layout::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);
FillFieldStringRow(table, stream, "Layout name", mName);
SInt32 handleSize = TCS_GetHandleSize(mLayoutHandle);
SInt32 headerSize = sizeof(SLayoutHeader);
// we have some handle info, even if it's empty
FillEndSafetyTag(table, stream, cHandleValidationTag);
FillFieldTableRow(table, stream, "Handle Size", cLongSize, handleSize);
if (handleSize) // if we have a layout handle, show the header info
{
NeoMark oldMark = stream->getMark();
// read in the format, then reset the mark since table fill advances it
SInt32 format = stream->ReadLong();
stream->setMark(oldMark);
FillFieldTableRow(table, stream, "Format version", cLongSize, format);
// read in the header. After we do this, we reset the mark, since the table
// will move through the data again.
oldMark = stream->getMark();
SLayoutHeader header;
stream->ReadChunk(&header, headerSize);
stream->setMark(oldMark);
#if TCS_FOR_WINDOWS
// reverse long values.
TCS_BlockReverse(&header.bgColor, sizeof(header.bgColor)/3, 3);
TCS_BlockReverse(&header.width, sizeof(header.width));
TCS_BlockReverse(&header.height, sizeof(header.height));
TCS_BlockReverse(&header.layoutClass, sizeof(header.layoutClass));
TCS_BlockReverse(&header.layoutID, sizeof(header.layoutID));
#endif
FillFieldStockRow(table, stream, stockID_Expansion, cLongSize, header.expansion);
FillFieldTableRow(table, stream, "Background red", cShortSize, SInt32(header.bgColor.GetRed()));
FillFieldTableRow(table, stream, "Background green", cShortSize, SInt32(header.bgColor.GetGreen()));
FillFieldTableRow(table, stream, "Background blue", cShortSize, SInt32(header.bgColor.GetBlue()));
FillFieldTableRow(table, stream, "Layout width", cLongSize, header.width);
FillFieldTableRow(table, stream, "Layout height", cLongSize, header.height);
FillFieldTableRow(table, stream, "Print placement", cCharSize, SInt32(header.printPlacement));
FillFieldBitRow(table, stream, "Use Date Range", header.useDateRange, true);
FillFieldBitRow(table, stream, "Use Item Range", header.useItemRange);
FillFieldBitRow(table, stream, "Use Breakdown", header.useBreakdown);
FillFieldBitRow(table, stream, "One Item Editor", header.useOneItemEditor);
FillFieldStockRow(table, stream, stockID_Padding, -4, SInt32(header.booleanFiller));
FillFieldTableRow(table, stream, "Transaction class", cCharSize, SInt32(header.transactionClass));
FillFieldStockRow(table, stream, stockID_Padding, cCharSize, SInt32(header.padding));
FillFieldTableRow(table, stream, "Layout class", cLongSize, header.layoutClass);
FillFieldTableRow(table, stream, "Layout ID", cLongSize, header.layoutID);
FillFieldTableRow(table, stream, "Top margin", cCharSize, SInt32(header.topMargin));
FillFieldTableRow(table, stream, "Left margin", cCharSize, SInt32(header.leftMargin));
FillFieldTableRow(table, stream, "Right margin", cCharSize, SInt32(header.rightMargin));
FillFieldTableRow(table, stream, "Bottom margin", cCharSize, SInt32(header.bottomMargin));
FillFieldTableRow(table, stream, "Print margins", cCharSize, SInt32(header.printMargins));
FillFieldTableRow(table, stream, "Print page size", cCharSize, SInt32(header.printPageSize));
FillFieldTableRow(table, stream, "Print columns", cCharSize, SInt32(header.printColumns));
FillFieldTableRow(table, stream, "Print orientation", cCharSize, SInt32(header.printOrientation));
FillFieldTableRow(table, stream, "Rows per page", cCharSize, SInt32(header.rowsPerPage));
FillFieldStockRow(table, stream, stockID_Padding, cCharSize, SInt32(header.morePadding));
FillFieldStockRow(table, stream, stockID_Expansion, cLayoutHeaderSize - sizeof(SLayoutHeader), cTwoDashString);
FillFieldTableRow(table, stream, "Layout contents", handleSize - cLayoutHeaderSize - cLongSize, cTwoDashString);
}
if (GetDBClassID() != id_ReportLayout)
FillEndSafetyTag(table, stream, mLayoutSafetyTag);
}
|