Accounting Software
Small Business Software Estimating Software
Inventory SoftwareInventory Control SoftwareInventory Tracking SoftwareInventory Management SoftwareConstruction Management SoftwareProject Management SoftwareBusiness Management Software

Custom Layouts (Source Code)

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);
}