Accounting Software
Small Business Software Estimating Software
Construction Estimating SoftwareBookkeeping SoftwareInventory SoftwareInventory Control SoftwareInventory Tracking SoftwareInventory Management SoftwareBusiness Management Software

Layout Views (Source Code)

Link to: header | record viewer directory

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

Comments

CLayoutView

This class manages general layout views for the Goldenseal accounting software,
small business management software, construction project management software and
construction estimating software.

a view which displays the contents of a database layout

SUPERCLASS = CEnclosingView

SUBCLASSES CLayoutEditor(layout editor windows)
DB_RecordViewer(inner viewer for lists, accounts, transactions)

This the parent of nearly all window contents for the Goldenseal accounting software

Constructor

/*********************************************************************************
struct constructor
*********************************************************************************/
CLayoutView::CLayoutView(const SPaneInfo &inPaneInfo,
const SViewInfo &inViewInfo)
: CEnclosingView(inPaneInfo, inViewInfo)
{
mLayoutID = 0;
}/*********************************************************************************
stream constructor
*********************************************************************************/
CLayoutView::CLayoutView(LStream *inStream)
: CEnclosingView(inStream)
{
mLayoutID = 0;
}

Source Code

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

LoadLayout moved TCS 5/18/00

load a layout for the given id. The id may or may not be a database
class id (e.g. short form and breakdown ID's are higher than the class id).

*********************************************************************************/
Boolean CLayoutView::LoadLayout(const DBid layoutID, const Boolean resourceOnly)
{
// update our member
mLayoutID = layoutID;

// load the layout handle
if (layoutID)
{ // we have a layout id
TCS_Handle layoutH =
DB_Layout::GetLayoutHandle(GetLayoutClassID(), layoutID, resourceOnly);

TCS_FailNILMsg(layoutH, TCS_GetErrString(errID_BadLayout) +
CTextString(" ") + CTextString(layoutID)); // TCS 6/18/99

CHandleWatcher watcher(layoutH);

TCS_TRY // TCS 6/14/00
{
LoadLayoutHandle(layoutH);
}
TCS_CATCH
{
return false;
}

// make sure the 1st field is active
//RotateTarget(false); // TCS deleted 11/19/99
}

return true; // rev TCS 9/27/00
}
/*********************************************************************************

ParseLayout TCS rev 5/18/00

parse the given layout handle. creatorFunc is a function which will be
called to create a pane in the layout; handlerFunc is a function
which will be called after a pane has been created to initialize it.

Note that the descriptor may be nil.

*********************************************************************************/
void CLayoutView::ParseLayout(TCS_Handle layoutH, Boolean checkPositions,
SLayoutHeader *header, DB_ClassDescriptor *desc,
const Boolean isPasting)
{
// do a sanity check on the params. Note that it's ok
// for the fieldCreatorFunc and header to be nil
TCS_FailNILMsg(layoutH, TCS_GetErrString(errID_BadLayout));

// lock down the handle and create a stream for reading
TStHandleLocker locker(layoutH);
CTCS_HandleContainer buffer(layoutH, cDoesntOwnData);
CInputStream stream(&buffer);

// ok, now we need to read in the layout version. This is
// the first 4 bytes of the layout
SInt32 layoutFormat;
stream.ReadLong(layoutFormat);
if (layoutFormat < cFormat2 || layoutFormat > cFormat16)
{ // it's not a known version number. So we assume that it's
// the very first version, which didn't have a version,
// and rewind the stream to the beginning
layoutFormat = cFormat1;
stream.Back(sizeof(layoutFormat));
}
// set the stream's format so that subsequent functions will
// know what it is
stream.SetFormat(layoutFormat);

// set some range limits TCS 2/9/00
SInt32 rightLimit = cFramePosLimit,
bottomLimit = cFramePosLimit;

// if the header is nil, we don't read it in and we move on to reading the panes.
// So for layouts which do not contain header information, callers should pass a nil header.
// IMPORTANT NOTE: if the layout handle DOES have a header, and the caller passes nil for
// the header, this code will crash, because it will start to read the layout
// header as a pane
if (header)
{
ParseHeader(stream, header);

rightLimit = header->width; // adjust limits to layout size TCS 2/9/00
bottomLimit = header->height;

// give subclasses a chance to fill in their own data members
// from the header rev TCS 7/19/00, moved TCS 11/27/00
ReadFromLayoutHeader(*header, layoutFormat);
}

// done with the header, let's move on to the panes
SInt16 paneType;
SDimension16 frameSize;
SPoint32 frameLoc;
SPaneInfo paneInfo;
SBooleanRect bindings = { 0, 0, 0, 0 };
SLayoutInfo mdInfo;
Boolean gaveWarning = false; // TCS 10/28/02
UInt8 errorCount = 0; // TCS 12/13/02

// initialize those settings which will be the same for all panes
paneInfo.userCon = 0;
paneInfo.visible = paneInfo.enabled = true;
paneInfo.bindings = bindings;
paneInfo.superView = this;

// read from the stream. We'll just keep looping until we
// run out of panes. We also stop if we get more than two errors.
while (!stream.AtEnd() & errorCount < 3)
{
// For all current layout formats, read in the number
// of bytes occupied by this pane's data. Note that this is a
// short value, so it may not be valid for graphics larger than 16K
// We do some fudging later to handle that rev TCS 12/13/02
SInt32 dataSize;
if (layoutFormat > cFormat1)
{
SInt16 shortSize;
stream.ReadShort(shortSize);
dataSize = shortSize;
}
else
dataSize = 0;

// save the stream location
SInt32 oldMark = stream.GetMark();

// read the pane type so we know what kind of pane to create
stream.ReadShort(paneType);

// get frame location & size.
stream.ReadData(&frameLoc, sizeof(frameLoc));
stream.ReadData(&frameSize, sizeof(frameSize));
// mfs_kk 22may2k2
// doing the required byte ordering
#if TCS_FOR_WINDOWS
TCS_BlockReverse(&frameLoc, sizeof(SInt32), 2); // SPoint32 has 2 SInt32's
TCS_BlockReverse(&frameSize, sizeof(SInt16), 2); // SDimension16 has 2 SInt16's
#endif
// get pane id
stream.ReadLong(paneInfo.paneID);

// sanity check the pane location and size TCS 2/9/00
if (checkPositions)
{
Boolean paneIsBad = false;

if (frameLoc.h < cFrameNegLimit || frameLoc.h > rightLimit)
{
frameLoc.h = 1; // reset horiz. location
paneIsBad = true;
}
if (frameLoc.v < cFrameNegLimit || frameLoc.v > bottomLimit)
{
frameLoc.v = 1; // reset vert. location
paneIsBad = true;
}
if (frameSize.width > rightLimit)
{
frameSize.width = rightLimit; // reset width
paneIsBad = true;
}
if (frameSize.height > bottomLimit)
{
frameSize.height = bottomLimit; // reset height
paneIsBad = true;
}

// give an alert if the pane needed moving. We'll continue,
// since this is not a serious problem.
if (paneIsBad)
{
TCS_ErrorAlert(TCS_GetErrString(errID_BadPaneLocation) +
TCS_GetTagString(paneInfo.paneID));
}
}

// construct an SPaneInfo to pass to the pane
paneInfo.width = frameSize.width;
paneInfo.height = frameSize.height;
paneInfo.left = frameLoc.h;
paneInfo.top = frameLoc.v;

// read in the Layout pane info
// removed erroneous branch for cFormat10 TCS 9/25/02
if (layoutFormat >= cFormat3)
{ // we can read it into the md pane info struct
stream.ReadData(&mdInfo, sizeof(mdInfo));
}
else
{ // it's an older format without the pen thickness,
// so we read in an old struct, and initialize
// the pen thickness to 1
SOldLayoutPaneInfo oldMDInfo;
stream.ReadData(&oldMDInfo, sizeof(oldMDInfo));
mdInfo.fillColorIndex = oldMDInfo.fillColorIndex;
mdInfo.edgeColorIndex = oldMDInfo.edgeColorIndex;
mdInfo.fillPatIndex = oldMDInfo.fillPatIndex;
mdInfo.edgePatIndex = oldMDInfo.edgePatIndex;
mdInfo.penSize = 1;
}

// ok, now we can actually go ahead and create this pane. Note
// that we set the commander to us each time so that tabbing
// works properly
LCommander::SetDefaultCommander(this);

if ((paneType == pane_table || paneType == pane_membertable) &&
layoutFormat < cFormat4)
{ // it's the old layout format which doesn't support
// tables, don't create a pane
}
else
{
LPane *newPane = CreateLayoutPane(stream, paneType, paneInfo, mdInfo, gaveWarning, desc, isPasting);

if (newPane)
{
newPane->FinishCreate();

if (paneType == pane_staticpicture)
{
// pasted-in pictures may be larger than the size of a short,
// so let's fetch the actual data size from the pane TCS 12/13/02
CLayoutPicturePane *picturePane = TCS_SAFE_CAST(newPane, CLayoutPicturePane);

if (picturePane)
dataSize = picturePane->GetPictureDataSize();
}
}
}

// done creating the pane, so we can forward the stream
// to the start of the data for the next pane.
if (layoutFormat > cFormat1)
{
// Let's sanity check the data size
if (stream.GetMark() > oldMark + dataSize)
{
TCS_ErrorAlert(CTextString("Oops, read too much data when loading a ") +
CTextString(DB_ClassDescriptor::GetPaneTypeText(paneType))); // rev TCS 10/8/00
errorCount++; // TCS 12/13/02
}
stream.SetMark(oldMark + dataSize);
}
}
}/*********************************************************************************

ParseHeader

parse the given layout handle and fill in the header
*********************************************************************************/
void CLayoutView::ParseHeader(CInputStream &stream, SLayoutHeader *header)
{
// sanity check
TCS_FailNILMsg(header, TCS_GetErrString(errID_BadHeader));

// read in the header, and process it
stream.ReadData(header, sizeof(SLayoutHeader));

// mfs_kk 20may2k2
// we've read from stream so doing the required byte ordering
#if TCS_FOR_WINDOWS
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));
/// bitfields are handled by reversing the order in SLayoutHeader
#endif
ResizeImageTo(header->width, header->height, cRedraw);
// now set the mark to the start of the data; the exact
// location depends on the version
if (stream.GetFormat() > cFormat1)
{ // the format is later than 1, so set it to the end
// of the header plus the end of the four bytes required
// by the version info
stream.SetMark(cLayoutHeaderSize + sizeof(SInt32));
}
else
{ // it's the first format, which doesn't have any
// format information in the first 4 bytes
stream.SetMark(cLayoutHeaderSize);
}
}
/*********************************************************************************

GetLayoutSize (static) TCS 11/20/01

get the size of the stock layout for the given class id. We fetch it from
the layout header.
*********************************************************************************/
TCS_Rect CLayoutView::GetLayoutSize(const DBid id)
{
// fetch the layout handle
TCS_ASSERTMsg(IS_TURTLE_CLASS_ID(id), TCS_GetErrString(errID_BadLayout));

DBid layoutID = DB_Layout::GetLayoutIDForForm(id, form_long);

TCS_Handle layoutH = DB_Layout::GetLayoutHandle(id_Layout, layoutID);
TCS_FailNILMsg(layoutH, TCS_GetErrString(errID_BadLayout) +
CTextString(" ") + CTextString(layoutID));

// watch the handle so it doesn't leak
CHandleWatcher watcher(layoutH);

SLayoutHeader header;

TCS_Rect outRect;

// lock down the handle and create a stream for reading
TStHandleLocker locker(layoutH);
CTCS_HandleContainer buffer(layoutH, cDoesntOwnData);
CInputStream stream(&buffer);

// we usually need to skip the first 4 bytes, which is version number
SInt32 layoutFormat;
stream.ReadLong(layoutFormat);
if (layoutFormat < cFormat2 || layoutFormat > cFormat16)
{ // it's not a known version number. So we assume that it's
// the very first version, which didn't have a version,
// and rewind the stream to the beginning
layoutFormat = cFormat1;
stream.Back(sizeof(layoutFormat));
}

// read in the header
stream.ReadData(&header, sizeof(SLayoutHeader));

// mfs_kk 20may2k2
// we've read from stream so doing the required byte ordering
#if TCS_FOR_WINDOWS
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));
/// TODO - Byte ordering for bit fields in the structure SLayoutHeader
#endif

// set up the rect
outRect.left = 0;
outRect.top = 0;
outRect.right = header.width;
outRect.bottom = header.height;

return outRect;
}
/*********************************************************************************

ReadFromLayoutHeader TCS 7/17/00

fetch data from the header
*********************************************************************************/
void CLayoutView::ReadFromLayoutHeader(const SLayoutHeader &/*header*/, const SInt32 /*format*/)
{
// we don't read anything here. Subclasses may override to fetch info from
// the header.
}
#if CAN_USE_MARK
#pragma mark -
#endif
/*********************************************************************************

IsValidPageSize TCS 10/15/02

is it a valid page size (from menu resource #427)
*********************************************************************************/
Boolean CLayoutView::IsValidPageSize(const UInt8 inSize)
{
switch (inSize)
{
case print_customsize:
case print_pagesetupsize:
case print_usletter:
case print_uslettersmall:
case print_uslegal:
case print_uslegalsmall:
case print_10envelope:
case print_letterenvelope:
case print_singlelabel:
case print_3x5:
case print_postcard:
case print_A4:
case print_A4small:
case print_B5:
return true;
break;

default:
return false;
break;
}
}
#if CAN_USE_MARK
#pragma mark -
#endif
/*********************************************************************************

CreateLayoutPane rev TCS 5/18/00

create a layout pane from the stream
*********************************************************************************/
LPane *CLayoutView::CreateLayoutPane(CInputStream &stream, const SInt16 paneType,
const SPaneInfo &paneInfo, const SLayoutInfo &mdInfo,
Boolean &gaveWarning, DB_ClassDescriptor *desc,
const Boolean isPasting)
{
switch (paneType)
{
case pane_rect:
case pane_roundrect:
case pane_oval:
case pane_line:
case pane_staticpicture:
case pane_caption:
return CreateGraphicPane(stream, paneType, paneInfo, mdInfo);
break;

case pane_logo:
return CreateGraphicPane(stream, paneType, paneInfo, mdInfo);
break;

case pane_editfield:
case pane_numberfield:
case pane_percentfield:
case pane_integerfield:
case pane_moneyfield:
case pane_datefield:
case pane_timefield:
case pane_checkboxfield:
case pane_longtextfield:
case pane_cvfield:
case pane_fixedpopup:
case pane_calcfield:
case pane_mixedfield:
case pane_dimensionfield: // TCS 1/10/01
case pane_calcdimensionfield: // TCS 5/15/01
case pane_iconfield:
case pane_pictfield:
case pane_button:
case pane_membertable:
case pane_table:
return CreateFieldPane(stream, paneType, paneInfo, mdInfo,
gaveWarning, desc, isPasting);
break;

default:
return nil;
break;
}
}
/*********************************************************************************

CreateGraphicPane

create a graphic pane from the stream
*********************************************************************************/
LPane *CLayoutView::CreateGraphicPane(CInputStream &stream,
const SInt16 paneType,
const SPaneInfo &paneInfo,
const SLayoutInfo &mdInfo)
{
switch (paneType)
{
case pane_rect:
return NEW CLayoutRectPane(paneInfo, mdInfo, stream);
break;

case pane_roundrect:
return NEW CLayoutRoundRectPane(paneInfo, mdInfo, stream);
break;

case pane_oval:
return NEW CLayoutOvalPane(paneInfo, mdInfo, stream);
break;

case pane_line:
return NEW CLayoutLinePane(paneInfo, mdInfo, stream);
break;

case pane_staticpicture:
return NEW CLayoutPicturePane(paneInfo, mdInfo, stream); // bugfix TCS 8/29/02
break;

case pane_logo:
return NEW CLayoutLogoPane(paneInfo, mdInfo, stream);
break;

case pane_caption:
case pane_mixedfield: // TCS 10/21/02
return NEW CLayoutTextPane(paneInfo, mdInfo, stream);
break;

default:
return nil;
break;
}
}/*********************************************************************************

GetCurrClassDesc

return the class descriptor for the current layout
*********************************************************************************/
DB_ClassDescriptor *CLayoutView::GetCurrClassDesc() const
{
return DB_ClassDescriptor::GetClassDescriptor(GetLayoutID());
}/*********************************************************************************

StretchImageToFit

stretch the image of the viewer to fit its subviews. This is called after
data is filled in, so the viewer will be large enough to contain tables or other
variable-size contents.

*********************************************************************************/
void CLayoutView::StretchImageToFit()
{
// get a rectangle which includes all the subpanes
TCS_Rect bigRect;
CTCS_View::GetRectEnclosingSubviews(*this, &bigRect);
// set our image size to the newly calculated size
ResizeImageTo(bigRect.right - bigRect.left,
bigRect.bottom - bigRect.top, cDontRedraw);
}
/*********************************************************************************

ShrinkImageToFit

shrink the view to the given size

*********************************************************************************/
void CLayoutView::ShrinkImageToFit(const SInt32 maxWidth, const SInt32 maxHeight)
{
// get a rectangle which includes all the subpanes
SDimension32 imageSize;
GetImageSize(imageSize);
imageSize.width = TCS_MIN(imageSize.width, maxWidth);
imageSize.height = TCS_MIN(imageSize.height, maxHeight);

// set our image size to the newly calculated size
ResizeImageTo(imageSize.width, imageSize.height, cDontRedraw);
}/*********************************************************************************

StretchImageToFitMax TCS 1/25/00

stretch the image of the viewer to fit its subviews. This version restricts
the size to an input limiting rectangle

*********************************************************************************/
void CLayoutView::StretchImageToFitMax(TCS_Rect limitRect)
{
// get a rectangle which includes all the subpanes
TCS_Rect bigRect;
CTCS_View::GetRectEnclosingSubviews(*this, &bigRect);


// don't let it be bigger than the limiting rect
// we shift the rect to match our current frame TCS rev & bugfixes 11/4/00
bigRect.top = TCS_MAX(bigRect.top + mFrameLocation.v, limitRect.top);
bigRect.left = TCS_MAX(bigRect.left + mFrameLocation.h, limitRect.left);
bigRect.right = TCS_MIN(bigRect.right + mFrameLocation.h, limitRect.right);
bigRect.bottom = TCS_MIN(bigRect.bottom + mFrameLocation.v, limitRect.bottom);

// set our image size to the newly calculated size
ResizeImageTo(bigRect.right - bigRect.left,
bigRect.bottom - bigRect.top, cDontRedraw);
}
/*********************************************************************************

GetPrintLayoutClassID rev TCS 5/17/00, moved TCS 5/18/00

we may be printing any kind of layout, so we switch generically
*********************************************************************************/
DBid CLayoutView::GetPrintLayoutClassID(const DBid layoutID) const
{
if (layoutID >= cReportBaseID)
return id_ReportLayout;
else if (layoutID > cPrintFormBaseID && layoutID < cCatBreakdownBaseID)
return id_PrintFormLayout;
else
return id_Layout;
}