1687 lines
51 KiB
C
1687 lines
51 KiB
C
/*****************************************************************************
|
||
*
|
||
* RptFct.c - This file contains support routines for the Report view.
|
||
* They are moved here because Report.c is getting too big.
|
||
*
|
||
* Microsoft Confidential
|
||
* Copyright (c) 1992-1993 Microsoft Corporation
|
||
*
|
||
* Author -
|
||
*
|
||
* Hon-Wah Chan
|
||
*
|
||
****************************************************************************/
|
||
|
||
#include "perfmon.h"
|
||
#include <stdio.h> // for sprintf
|
||
#include "report.h" // Exported declarations for this file
|
||
|
||
#include "line.h" // for LineAppend
|
||
#include "pmemory.h" // for MemoryXXX (mallloc-type) routines
|
||
#include "system.h" // for SystemGet
|
||
#include "utils.h"
|
||
#include "perfmops.h" // for BuildValueListForSystems
|
||
|
||
// extern defined in Report.c
|
||
|
||
extern TCHAR szSystemFormat [] ;
|
||
extern TCHAR szObjectFormat [] ;
|
||
|
||
|
||
#define szValuePlaceholder TEXT("-999999999.999")
|
||
#define szLargeValueFormat TEXT("%12.0f")
|
||
#define eStatusLargeValueMax ((FLOAT) 999999999.0)
|
||
#define szValueFormat TEXT("%12.3f")
|
||
|
||
//========================
|
||
// Local routines prototypes
|
||
//========================
|
||
|
||
void ColumnRemoveOne (PREPORT pReport,
|
||
POBJECTGROUP pObjectGroup,
|
||
int iColumnNumber) ;
|
||
|
||
BOOL CounterGroupRemove (PCOUNTERGROUP *ppCounterGroupFirst,
|
||
PCOUNTERGROUP pCounterGroupRemove) ;
|
||
|
||
BOOL ObjectGroupRemove (POBJECTGROUP *ppObjectGroupFirst,
|
||
POBJECTGROUP pObjectGroupRemove) ;
|
||
|
||
BOOL SystemGroupRemove (PSYSTEMGROUP *ppSystemGroupFirst,
|
||
PSYSTEMGROUP pSystemGroupRemove) ;
|
||
|
||
PCOUNTERGROUP GetNextCounter (PSYSTEMGROUP pSystemGroup,
|
||
POBJECTGROUP pObjectGroup,
|
||
PCOUNTERGROUP pCounterGroup) ;
|
||
|
||
BOOL ReportLineRemove (PREPORT pReport,
|
||
PLINE pLineRemove)
|
||
{
|
||
PLINE pLine ;
|
||
|
||
if (pReport->pLineFirst == pLineRemove)
|
||
{
|
||
pReport->pLineFirst = (pReport->pLineFirst)->pLineNext ;
|
||
return (TRUE) ;
|
||
}
|
||
|
||
for (pLine = pReport->pLineFirst ;
|
||
pLine->pLineNext ;
|
||
pLine = pLine->pLineNext)
|
||
{ // for
|
||
if (pLine->pLineNext == pLineRemove)
|
||
{
|
||
pLine->pLineNext = pLineRemove->pLineNext ;
|
||
if (pLineRemove == pReport->pLineLast) {
|
||
pReport->pLineLast = pLine;
|
||
}
|
||
return (TRUE) ;
|
||
} // if
|
||
} // for
|
||
|
||
return (FALSE) ;
|
||
} // ReportLineRemove
|
||
|
||
// CheckColumnGroupRemove is used to check if the given
|
||
// column is empty. If it is empty, it is removed from
|
||
// the column link list
|
||
void CheckColumnGroupRemove (PREPORT pReport,
|
||
POBJECTGROUP pObjectGroup,
|
||
int iReportColumn)
|
||
{
|
||
// check if we need to remove the this column
|
||
PLINE pCounterLine ;
|
||
PCOUNTERGROUP pCounterGrp ;
|
||
BOOL bColumnFound = FALSE ;
|
||
|
||
if (iReportColumn < 0 || pObjectGroup->pCounterGroupFirst == NULL)
|
||
{
|
||
// no column for this Counter group, forget it
|
||
return ;
|
||
}
|
||
|
||
|
||
// go thru each Counter group and check if any line in the
|
||
// group matches the given column number
|
||
for (pCounterGrp = pObjectGroup->pCounterGroupFirst ;
|
||
pCounterGrp ;
|
||
pCounterGrp = pCounterGrp->pCounterGroupNext )
|
||
{
|
||
for (pCounterLine = pCounterGrp->pLineFirst ;
|
||
pCounterLine ;
|
||
pCounterLine = pCounterLine->pLineCounterNext)
|
||
{
|
||
if (pCounterLine->iReportColumn == iReportColumn)
|
||
{
|
||
// found one, this column is not empty
|
||
bColumnFound = TRUE ;
|
||
break ;
|
||
}
|
||
} // for pCounterLine
|
||
if (bColumnFound)
|
||
{
|
||
break ;
|
||
}
|
||
} // for pCounterGrp
|
||
|
||
if (bColumnFound == FALSE)
|
||
{
|
||
// we have deleted the last column item, remove this column
|
||
ColumnRemoveOne (pReport,
|
||
pObjectGroup,
|
||
iReportColumn) ;
|
||
}
|
||
} // CheckColumnGroupRemove
|
||
|
||
|
||
//================================
|
||
// Line routine
|
||
//================================
|
||
|
||
void ReportLineValueRect (PREPORT pReport,
|
||
PLINE pLine,
|
||
LPRECT lpRect)
|
||
{ // ReportLineValueRect
|
||
lpRect->left = ValueMargin (pReport) + pLine->xReportPos ;
|
||
lpRect->top = pLine->yReportPos ;
|
||
lpRect->right = lpRect->left + pReport->xValueWidth ;
|
||
lpRect->bottom = lpRect->top + pReport->yLineHeight ;
|
||
} // ReportLineValueRect
|
||
|
||
PLINE LineRemoveItem (PREPORT pReport,
|
||
enum REPORT_ITEM_TYPE *pNewItemType)
|
||
{
|
||
PLINE pLine ;
|
||
PLINE pNextLine = NULL ;
|
||
PLINE pReturnLine = NULL ;
|
||
PLINE pLeftLine = NULL ;
|
||
PSYSTEMGROUP pSystemGroup ;
|
||
POBJECTGROUP pObjectGroup ;
|
||
PCOUNTERGROUP pCounterGroup ;
|
||
PCOUNTERGROUP pNextCounterGroup ;
|
||
BOOL bCreatNewCounterGroup ;
|
||
|
||
|
||
//=============================//
|
||
// Remove line, line's system //
|
||
//=============================//
|
||
|
||
pLine = pReport->CurrentItem.pLine ;
|
||
ReportLineRemove (pReport, pLine) ;
|
||
|
||
// no more line, no more timer...
|
||
if (!pReport->pLineFirst)
|
||
{
|
||
pReport->xWidth = 0 ;
|
||
pReport->yHeight = 0 ;
|
||
pReport->xMaxCounterWidth = 0 ;
|
||
ClearReportTimer (pReport) ;
|
||
}
|
||
|
||
//=============================//
|
||
// Get correct spot; remove line //
|
||
//=============================//
|
||
|
||
pSystemGroup = GetSystemGroup (pReport, pLine->lnSystemName) ;
|
||
pObjectGroup = GetObjectGroup (pSystemGroup, pLine->lnObjectName) ;
|
||
pCounterGroup = GetCounterGroup (pObjectGroup,
|
||
pLine->lnCounterDef.CounterNameTitleIndex,
|
||
&bCreatNewCounterGroup,
|
||
pLine->lnCounterName,
|
||
TRUE) ;
|
||
|
||
if (!pCounterGroup)
|
||
return (NULL) ;
|
||
|
||
LineCounterRemove (pCounterGroup, pLine) ;
|
||
|
||
// check which line to get the focus
|
||
if (pCounterGroup->pLineFirst)
|
||
{
|
||
// simple case, we still have line in the same counter group
|
||
// get the one right after this delete line.
|
||
for (pNextLine = pCounterGroup->pLineFirst ;
|
||
pNextLine ;
|
||
pNextLine = pNextLine->pLineCounterNext)
|
||
{
|
||
if (pNextLine->xReportPos > pLine->xReportPos)
|
||
{
|
||
if (pReturnLine == NULL ||
|
||
pReturnLine->xReportPos > pNextLine->xReportPos)
|
||
{
|
||
pReturnLine = pNextLine ;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (pLeftLine == NULL ||
|
||
pLeftLine->xReportPos < pNextLine->xReportPos)
|
||
{
|
||
pLeftLine = pNextLine ;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (!pReturnLine && pLeftLine)
|
||
{
|
||
// the delete line is the last column, then use the line
|
||
// to its left
|
||
pReturnLine = pLeftLine ;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
pNextCounterGroup = GetNextCounter (
|
||
pSystemGroup,
|
||
pObjectGroup,
|
||
pCounterGroup) ;
|
||
|
||
if (pNextCounterGroup)
|
||
{
|
||
pLeftLine = NULL ;
|
||
for (pNextLine = pNextCounterGroup->pLineFirst ;
|
||
pNextLine ;
|
||
pNextLine = pNextLine->pLineCounterNext)
|
||
{
|
||
// get the line in the first column
|
||
if (pLeftLine == NULL ||
|
||
pNextLine->xReportPos < pLeftLine->xReportPos)
|
||
{
|
||
pLeftLine = pNextLine ;
|
||
}
|
||
}
|
||
pReturnLine = pLeftLine ;
|
||
}
|
||
|
||
// remove this counter group if there is no line
|
||
CounterGroupRemove (&pObjectGroup->pCounterGroupFirst, pCounterGroup) ;
|
||
}
|
||
|
||
// check if we need to remove any empty column
|
||
CheckColumnGroupRemove (pReport, pObjectGroup, pLine->iReportColumn) ;
|
||
|
||
if (!(pObjectGroup->pCounterGroupFirst))
|
||
ObjectGroupRemove (&pSystemGroup->pObjectGroupFirst, pObjectGroup) ;
|
||
|
||
if (!(pSystemGroup->pObjectGroupFirst))
|
||
SystemGroupRemove (&pReport->pSystemGroupFirst, pSystemGroup) ;
|
||
|
||
|
||
LineFree (pLine) ;
|
||
|
||
if (pReturnLine && pNewItemType)
|
||
{
|
||
*pNewItemType = REPORT_TYPE_LINE ;
|
||
}
|
||
|
||
return (pReturnLine) ;
|
||
} // LineRemoveItem
|
||
|
||
//======================================//
|
||
// Column Group routines //
|
||
//======================================//
|
||
|
||
void ReportColumnRect (PREPORT pReport,
|
||
PCOLUMNGROUP pColumnGroup,
|
||
LPRECT lpRect)
|
||
{ // ReportColumnRect
|
||
lpRect->left = ValueMargin (pReport) + pColumnGroup->xPos ;
|
||
lpRect->top = pColumnGroup->yFirstLine ;
|
||
lpRect->right = lpRect->left + pColumnGroup->xWidth ;
|
||
lpRect->bottom = lpRect->top + pReport->yLineHeight ;
|
||
if (pColumnGroup->lpszParentName)
|
||
{
|
||
lpRect->top -= pReport->yLineHeight ;
|
||
}
|
||
} // ReportColumnRect
|
||
|
||
|
||
BOOL ColumnSame (PCOLUMNGROUP pColumnGroup,
|
||
LPTSTR lpszParentName,
|
||
LPTSTR lpszInstanceName,
|
||
DWORD dwIndex)
|
||
{ // ColumnSame
|
||
BOOL bReturn = FALSE;
|
||
|
||
if (dwIndex == pColumnGroup->dwInstanceIndex) {
|
||
if ((!lpszParentName && !pColumnGroup->lpszParentName) ||
|
||
strsame (lpszParentName, pColumnGroup->lpszParentName)) {
|
||
if ((!lpszInstanceName && !pColumnGroup->lpszInstanceName) ||
|
||
strsame (lpszInstanceName, pColumnGroup->lpszInstanceName)) {
|
||
bReturn = TRUE;
|
||
}
|
||
}
|
||
}
|
||
return bReturn;
|
||
} // ColumnSame
|
||
|
||
|
||
PCOLUMNGROUP ColumnGroupCreate (PREPORT pReport,
|
||
int xPos,
|
||
LPTSTR lpszParentName,
|
||
LPTSTR lpszInstanceName,
|
||
int PreviousColumnNumber,
|
||
int yFirstLine,
|
||
DWORD dwIndex)
|
||
{ // ColumnGroupCreate
|
||
PCOLUMNGROUP pColumnGroup ;
|
||
HDC hDC ;
|
||
|
||
hDC = GetDC (pReport->hWnd) ;
|
||
if (!hDC)
|
||
return NULL;
|
||
pColumnGroup = MemoryAllocate (sizeof (COLUMNGROUP)) ;
|
||
|
||
if (pColumnGroup)
|
||
{
|
||
pColumnGroup->pColumnGroupNext = NULL ;
|
||
pColumnGroup->lpszParentName = StringAllocate (lpszParentName) ;
|
||
pColumnGroup->lpszInstanceName = StringAllocate (lpszInstanceName) ;
|
||
pColumnGroup->ParentNameTextWidth = TextWidth (hDC, lpszParentName) ;
|
||
pColumnGroup->InstanceNameTextWidth = TextWidth (hDC, lpszInstanceName) ;
|
||
pColumnGroup->xPos = xPos ;
|
||
pColumnGroup->yFirstLine = yFirstLine ;
|
||
pColumnGroup->ColumnNumber = PreviousColumnNumber + 1 ;
|
||
pColumnGroup->xWidth = max (max (pColumnGroup->ParentNameTextWidth,
|
||
pColumnGroup->InstanceNameTextWidth),
|
||
pReport->xValueWidth) ;
|
||
pColumnGroup->dwInstanceIndex = dwIndex;
|
||
|
||
pReport->xWidth = max (pReport->xWidth,
|
||
RightHandMargin +
|
||
ValueMargin (pReport) +
|
||
pColumnGroup->xPos + pColumnGroup->xWidth +
|
||
xColumnMargin) ;
|
||
} // if
|
||
|
||
ReleaseDC (pReport->hWnd, hDC) ;
|
||
return (pColumnGroup) ;
|
||
} // ColumnGroupCreate
|
||
|
||
PCOLUMNGROUP GetColumnGroup (PREPORT pReport,
|
||
POBJECTGROUP pObjectGroup,
|
||
PLINE pLine)
|
||
/*
|
||
Effect: Return a pointer to the appropriate column group from
|
||
within the groups of pObject. If the line is a counter
|
||
without instances, return NULL. Otherwise, determine
|
||
if the counter's parent/instance pair is already found
|
||
in an existing column and return a pointer to that column.
|
||
|
||
If a column with the appropriate parent/instance isn't
|
||
found, add a new column *at the end*, and return that
|
||
column.
|
||
|
||
Note: This function has multiple return points.
|
||
*/
|
||
{ // GetColumnGroup
|
||
PCOLUMNGROUP pColumnGroup ;
|
||
LPTSTR lpszParentName ;
|
||
LPTSTR lpszInstanceName ;
|
||
DWORD dwIndex;
|
||
|
||
if (!LineInstanceName (pLine))
|
||
return (NULL) ;
|
||
|
||
lpszParentName = LineParentName (pLine) ;
|
||
lpszInstanceName = LineInstanceName (pLine) ;
|
||
dwIndex = pLine->dwInstanceIndex;
|
||
|
||
if (!pObjectGroup->pColumnGroupFirst)
|
||
{
|
||
pObjectGroup->pColumnGroupFirst =
|
||
ColumnGroupCreate (pReport,
|
||
0,
|
||
lpszParentName,
|
||
lpszInstanceName,
|
||
-1,
|
||
pObjectGroup->yFirstLine,
|
||
dwIndex) ;
|
||
|
||
if (pObjectGroup->pColumnGroupFirst)
|
||
{
|
||
pObjectGroup->pColumnGroupFirst->pParentObject =
|
||
pObjectGroup ;
|
||
}
|
||
|
||
return (pObjectGroup->pColumnGroupFirst) ;
|
||
}
|
||
|
||
for (pColumnGroup = pObjectGroup->pColumnGroupFirst ;
|
||
pColumnGroup ;
|
||
pColumnGroup = pColumnGroup->pColumnGroupNext)
|
||
{ // for
|
||
if (ColumnSame (pColumnGroup, lpszParentName, lpszInstanceName, dwIndex))
|
||
return (pColumnGroup) ;
|
||
|
||
else if (!pColumnGroup->pColumnGroupNext)
|
||
{ // if
|
||
pColumnGroup->pColumnGroupNext =
|
||
ColumnGroupCreate (pReport,
|
||
pColumnGroup->xPos + pColumnGroup->xWidth +
|
||
xColumnMargin,
|
||
lpszParentName,
|
||
lpszInstanceName,
|
||
pColumnGroup->ColumnNumber,
|
||
pObjectGroup->yFirstLine,
|
||
dwIndex) ;
|
||
|
||
if (pColumnGroup->pColumnGroupNext)
|
||
{
|
||
(pColumnGroup->pColumnGroupNext)->pParentObject =
|
||
pObjectGroup ;
|
||
|
||
// build the double link-list
|
||
(pColumnGroup->pColumnGroupNext)->pColumnGroupPrevious =
|
||
pColumnGroup ;
|
||
}
|
||
|
||
return (pColumnGroup->pColumnGroupNext) ;
|
||
} // if
|
||
} // for
|
||
|
||
return (NULL) ;
|
||
} // GetColumnGroup
|
||
|
||
// ColumnRemoveOne removes the column with the specified column number
|
||
void ColumnRemoveOne (PREPORT pReport,
|
||
POBJECTGROUP pObjectGroup,
|
||
int iColumnNumber)
|
||
{
|
||
PCOLUMNGROUP pColumnGroup ;
|
||
PCOLUMNGROUP pNextColumnGroup ;
|
||
|
||
if (pObjectGroup->pColumnGroupFirst == NULL)
|
||
{
|
||
// no column group, forget it
|
||
return ;
|
||
}
|
||
|
||
// Find the head list
|
||
if (pObjectGroup->pColumnGroupFirst->ColumnNumber == iColumnNumber)
|
||
{
|
||
pColumnGroup = pObjectGroup->pColumnGroupFirst ;
|
||
pObjectGroup->pColumnGroupFirst = pColumnGroup->pColumnGroupNext ;
|
||
if (pColumnGroup->pColumnGroupNext)
|
||
{
|
||
// set up head of backward link list
|
||
(pColumnGroup->pColumnGroupNext)->pColumnGroupPrevious = NULL ;
|
||
}
|
||
|
||
// free memory for this column group
|
||
MemoryFree (pColumnGroup->lpszParentName) ;
|
||
MemoryFree (pColumnGroup->lpszInstanceName) ;
|
||
MemoryFree (pColumnGroup) ;
|
||
|
||
return ;
|
||
}
|
||
|
||
// go thru the double link list to look for the right column
|
||
for (pColumnGroup = pObjectGroup->pColumnGroupFirst ;
|
||
pColumnGroup ;
|
||
pColumnGroup = pNextColumnGroup)
|
||
{
|
||
pNextColumnGroup = pColumnGroup->pColumnGroupNext ;
|
||
|
||
if (pNextColumnGroup == NULL)
|
||
{
|
||
// forget it if we can't find this column for some reson.
|
||
break ;
|
||
}
|
||
|
||
if (pNextColumnGroup->ColumnNumber == iColumnNumber)
|
||
{
|
||
pColumnGroup->pColumnGroupNext = pNextColumnGroup->pColumnGroupNext ;
|
||
|
||
// build backward link iff it is not the end of list
|
||
if (pColumnGroup->pColumnGroupNext)
|
||
{
|
||
(pColumnGroup->pColumnGroupNext)->pColumnGroupPrevious =
|
||
pColumnGroup ;
|
||
}
|
||
|
||
// free memory for this column group
|
||
MemoryFree (pNextColumnGroup->lpszParentName) ;
|
||
MemoryFree (pNextColumnGroup->lpszInstanceName) ;
|
||
MemoryFree (pNextColumnGroup) ;
|
||
|
||
// Done
|
||
break ;
|
||
}
|
||
}
|
||
} // ColumnRemoveOne
|
||
|
||
// ColumnGroupRemove removes all the columns for a given column list
|
||
void ColumnGroupRemove (PCOLUMNGROUP pColumnGroupFirst)
|
||
{
|
||
PCOLUMNGROUP pColumnGroup ;
|
||
PCOLUMNGROUP pNextColumnGroup ;
|
||
|
||
for (pColumnGroup = pColumnGroupFirst ;
|
||
pColumnGroup ;
|
||
pColumnGroup = pNextColumnGroup)
|
||
{
|
||
pNextColumnGroup = pColumnGroup->pColumnGroupNext ;
|
||
|
||
// free memory for this column group
|
||
MemoryFree (pColumnGroup->lpszParentName) ;
|
||
MemoryFree (pColumnGroup->lpszInstanceName) ;
|
||
MemoryFree (pColumnGroup) ;
|
||
}
|
||
} // ColumnGroupRemove
|
||
|
||
// ColumnRemoveItem is called when user wants to delete a
|
||
// selected column.
|
||
PCOLUMNGROUP ColumnRemoveItem (PREPORT pReport,
|
||
PCOLUMNGROUP pColumnGroup,
|
||
BOOL bCleanUpLink,
|
||
enum REPORT_ITEM_TYPE *pNewItemType)
|
||
{
|
||
PLINE pLine, pNextLine ;
|
||
PSYSTEMGROUP pSystemGroup ;
|
||
POBJECTGROUP pObjectGroup ;
|
||
PCOUNTERGROUP pCounterGroup, pNextCounterGroup ;
|
||
BOOL bColumnFound ;
|
||
PCOLUMNGROUP pRetColumnGroup = NULL ;
|
||
|
||
pObjectGroup = pColumnGroup->pParentObject ;
|
||
pSystemGroup = pObjectGroup->pParentSystem ;
|
||
|
||
// first, get rid of all the counter lines with this column number
|
||
// Note - each Counter group has only 1 line (or 0) with this
|
||
// column number
|
||
for (pCounterGroup = pObjectGroup->pCounterGroupFirst ;
|
||
pCounterGroup ;
|
||
pCounterGroup = pNextCounterGroup )
|
||
{
|
||
pNextCounterGroup = pCounterGroup->pCounterGroupNext ;
|
||
bColumnFound = FALSE ;
|
||
|
||
for (pLine = pCounterGroup->pLineFirst ;
|
||
pLine ;
|
||
pLine = pNextLine)
|
||
{
|
||
pNextLine = pLine->pLineCounterNext ;
|
||
if (pLine->iReportColumn == pColumnGroup->ColumnNumber)
|
||
{
|
||
bColumnFound = TRUE ;
|
||
// delete this line
|
||
ReportLineRemove (pReport, pLine) ;
|
||
LineCounterRemove (pCounterGroup, pLine) ;
|
||
LineFree (pLine) ;
|
||
break ;
|
||
}
|
||
}
|
||
|
||
if (bColumnFound)
|
||
{
|
||
// check if we need delete this counter group
|
||
if (!(pCounterGroup->pLineFirst))
|
||
{
|
||
CounterGroupRemove (&pObjectGroup->pCounterGroupFirst, pCounterGroup) ;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
// determine which column group to go after deleting this
|
||
if (pColumnGroup->pColumnGroupNext)
|
||
{
|
||
// get the Column group after this delete one
|
||
pRetColumnGroup = pColumnGroup->pColumnGroupNext ;
|
||
}
|
||
else
|
||
{
|
||
// get the Counter group before this delete one
|
||
pRetColumnGroup = pColumnGroup->pColumnGroupPrevious ;
|
||
}
|
||
|
||
if (pNewItemType)
|
||
{
|
||
if (pRetColumnGroup)
|
||
{
|
||
*pNewItemType = REPORT_TYPE_COLUMN ;
|
||
}
|
||
else
|
||
{
|
||
// get next counter group
|
||
pNextCounterGroup = GetNextCounter (
|
||
pSystemGroup,
|
||
pObjectGroup,
|
||
NULL) ;
|
||
|
||
if (pNextCounterGroup)
|
||
{
|
||
// we have to return Counter group, so we have to do the
|
||
// dirty casting..
|
||
*pNewItemType = REPORT_TYPE_COUNTER ;
|
||
pRetColumnGroup = (PCOLUMNGROUP) pNextCounterGroup ;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
// remove this column group
|
||
ColumnRemoveOne (pReport, pObjectGroup, pColumnGroup->ColumnNumber) ;
|
||
|
||
// check for further cleanup
|
||
if (bCleanUpLink)
|
||
{
|
||
if (!(pObjectGroup->pCounterGroupFirst))
|
||
ObjectGroupRemove (&pSystemGroup->pObjectGroupFirst, pObjectGroup) ;
|
||
|
||
if (!(pSystemGroup->pObjectGroupFirst))
|
||
SystemGroupRemove (&pReport->pSystemGroupFirst, pSystemGroup) ;
|
||
}
|
||
return (pRetColumnGroup) ;
|
||
} // ColumnRemoveItem
|
||
|
||
|
||
//======================================//
|
||
// Counter Group routines //
|
||
//======================================//
|
||
|
||
void ReportCounterRect (PREPORT pReport,
|
||
PCOUNTERGROUP pCounterGroup,
|
||
LPRECT lpRect)
|
||
{ // ReportCounterRect
|
||
lpRect->left = xCounterMargin ;
|
||
lpRect->top = pCounterGroup->yLine ;
|
||
lpRect->right = lpRect->left + pCounterGroup->xWidth + yScrollHeight / 2 ;
|
||
lpRect->bottom = lpRect->top + pReport->yLineHeight ;
|
||
} // ReportCounterRect
|
||
|
||
|
||
PCOUNTERGROUP CounterGroupCreate (DWORD dwCounterIndex,
|
||
LPTSTR pCounterName)
|
||
{ // CounterGroupCreate
|
||
PCOUNTERGROUP pCounterGroup ;
|
||
HDC hDC ;
|
||
PREPORT pReport ;
|
||
|
||
pCounterGroup = MemoryAllocate (sizeof (COUNTERGROUP)) ;
|
||
|
||
if (pCounterGroup)
|
||
{
|
||
pCounterGroup->pCounterGroupNext = NULL ;
|
||
pCounterGroup->pLineFirst = NULL ;
|
||
pCounterGroup->dwCounterIndex = dwCounterIndex ;
|
||
|
||
if (pCounterName)
|
||
{
|
||
hDC = GetDC (hWndReport) ;
|
||
pReport = ReportData (hWndReport) ;
|
||
if (hDC && pReport) {
|
||
SelectFont (hDC, pReport->hFont) ;
|
||
pCounterGroup->xWidth = TextWidth (hDC, pCounterName) ;
|
||
}
|
||
if (hDC) {
|
||
ReleaseDC (hWndReport, hDC) ;
|
||
}
|
||
}
|
||
} // if
|
||
|
||
return (pCounterGroup) ;
|
||
} // CounterGroupCreate
|
||
|
||
|
||
PCOUNTERGROUP GetCounterGroup (POBJECTGROUP pObjectGroup,
|
||
DWORD dwCounterIndex,
|
||
BOOL *pbCounterGroupCreated,
|
||
LPTSTR pCounterName,
|
||
BOOL bCreateNewGroup)
|
||
{ // GetCounterGroup
|
||
PCOUNTERGROUP pCounterGroup ;
|
||
|
||
*pbCounterGroupCreated = FALSE ;
|
||
if (!pObjectGroup)
|
||
return (FALSE) ;
|
||
|
||
if (!pObjectGroup->pCounterGroupFirst) {
|
||
if (bCreateNewGroup) {
|
||
pObjectGroup->pCounterGroupFirst =
|
||
CounterGroupCreate (dwCounterIndex, pCounterName) ;
|
||
|
||
if (pObjectGroup->pCounterGroupFirst)
|
||
{
|
||
*pbCounterGroupCreated = TRUE ;
|
||
pObjectGroup->pCounterGroupFirst->pParentObject =
|
||
pObjectGroup ;
|
||
}
|
||
|
||
return (pObjectGroup->pCounterGroupFirst) ;
|
||
}
|
||
} else {
|
||
|
||
for (pCounterGroup = pObjectGroup->pCounterGroupFirst ;
|
||
pCounterGroup ;
|
||
pCounterGroup = pCounterGroup->pCounterGroupNext) {
|
||
if (dwCounterIndex && pCounterGroup->dwCounterIndex == dwCounterIndex)
|
||
{
|
||
return (pCounterGroup) ;
|
||
}
|
||
else if (!dwCounterIndex &&
|
||
pCounterGroup->pLineFirst &&
|
||
pstrsame (pCounterGroup->pLineFirst->lnCounterName, pCounterName))
|
||
{
|
||
return (pCounterGroup) ;
|
||
}
|
||
else if (!pCounterGroup->pCounterGroupNext)
|
||
{ // if
|
||
if (bCreateNewGroup) {
|
||
pCounterGroup->pCounterGroupNext =
|
||
CounterGroupCreate (dwCounterIndex, pCounterName) ;
|
||
if (pCounterGroup->pCounterGroupNext)
|
||
{
|
||
*pbCounterGroupCreated = TRUE ;
|
||
(pCounterGroup->pCounterGroupNext)->pParentObject =
|
||
pObjectGroup ;
|
||
|
||
// build backward link
|
||
(pCounterGroup->pCounterGroupNext)->pCounterGroupPrevious =
|
||
pCounterGroup ;
|
||
}
|
||
return (pCounterGroup->pCounterGroupNext) ;
|
||
|
||
}
|
||
} // if
|
||
} // for
|
||
}
|
||
|
||
return (NULL) ;
|
||
} // GetCounterGroup
|
||
|
||
BOOL CounterGroupRemove (PCOUNTERGROUP *ppCounterGroupFirst,
|
||
PCOUNTERGROUP pCounterGroupRemove)
|
||
{
|
||
PCOUNTERGROUP pCounterGroup ;
|
||
|
||
if (*ppCounterGroupFirst == pCounterGroupRemove)
|
||
{
|
||
*ppCounterGroupFirst = (*ppCounterGroupFirst)->pCounterGroupNext ;
|
||
|
||
if (*ppCounterGroupFirst)
|
||
{
|
||
// set up head of backward link list
|
||
(*ppCounterGroupFirst)->pCounterGroupPrevious = NULL ;
|
||
}
|
||
|
||
MemoryFree (pCounterGroupRemove) ;
|
||
return (TRUE) ;
|
||
}
|
||
|
||
for (pCounterGroup = *ppCounterGroupFirst ;
|
||
pCounterGroup->pCounterGroupNext ;
|
||
pCounterGroup = pCounterGroup->pCounterGroupNext)
|
||
{ // for
|
||
if (pCounterGroup->pCounterGroupNext == pCounterGroupRemove)
|
||
{
|
||
pCounterGroup->pCounterGroupNext = pCounterGroupRemove->pCounterGroupNext ;
|
||
if (pCounterGroup->pCounterGroupNext)
|
||
{
|
||
(pCounterGroup->pCounterGroupNext)->pCounterGroupPrevious
|
||
= pCounterGroup ;
|
||
}
|
||
MemoryFree (pCounterGroupRemove) ;
|
||
return (TRUE) ;
|
||
} // if
|
||
} // for
|
||
|
||
return (FALSE) ;
|
||
} // CounterGroupRemove
|
||
|
||
|
||
// CounterRemoveItem is called when user wants to delete a
|
||
// selected counter (row)
|
||
PCOUNTERGROUP CounterRemoveItem (PREPORT pReport,
|
||
PCOUNTERGROUP pCounterGroup,
|
||
BOOL bCleanUpLink,
|
||
enum REPORT_ITEM_TYPE *pNewItemType)
|
||
{
|
||
PLINE pLine, pNextLine ;
|
||
POBJECTGROUP pObjectGroup ;
|
||
PSYSTEMGROUP pSystemGroup ;
|
||
PCOLUMNGROUP pColumnGroup ;
|
||
PCOLUMNGROUP pNextColumnGroup ;
|
||
PCOUNTERGROUP pRetCounterGroup = NULL ;
|
||
|
||
pObjectGroup = pCounterGroup->pParentObject ;
|
||
pSystemGroup = pObjectGroup->pParentSystem ;
|
||
|
||
// first, remove all the counter lines from this counter group
|
||
// and from the Report line link-list
|
||
for (pLine = pCounterGroup->pLineFirst ;
|
||
pLine ;
|
||
pLine = pNextLine)
|
||
{
|
||
pNextLine = pLine->pLineCounterNext ;
|
||
ReportLineRemove (pReport, pLine) ;
|
||
LineFree (pLine) ;
|
||
}
|
||
|
||
// we only need to delete the counter group iff we are deleting
|
||
// this selected Counter.
|
||
if (bCleanUpLink)
|
||
{
|
||
// determine which counter group to go after deleting this
|
||
pRetCounterGroup = GetNextCounter (
|
||
pSystemGroup ,
|
||
pObjectGroup,
|
||
pCounterGroup) ;
|
||
|
||
// remove this counter group from its parent object group
|
||
CounterGroupRemove (&pObjectGroup->pCounterGroupFirst, pCounterGroup) ;
|
||
|
||
if (!(pObjectGroup->pCounterGroupFirst))
|
||
ObjectGroupRemove (&pSystemGroup->pObjectGroupFirst, pObjectGroup) ;
|
||
else
|
||
{
|
||
// Object group not empty, check for any empty column
|
||
for (pColumnGroup = pObjectGroup->pColumnGroupFirst ;
|
||
pColumnGroup ;
|
||
pColumnGroup = pNextColumnGroup)
|
||
{
|
||
pNextColumnGroup = pColumnGroup->pColumnGroupNext ;
|
||
CheckColumnGroupRemove (pReport, pObjectGroup, pColumnGroup->ColumnNumber) ;
|
||
}
|
||
}
|
||
|
||
if (!(pSystemGroup->pObjectGroupFirst))
|
||
{
|
||
SystemGroupRemove (&pReport->pSystemGroupFirst, pSystemGroup) ;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// get rid of this counter's memory
|
||
MemoryFree (pCounterGroup) ;
|
||
}
|
||
|
||
if (pRetCounterGroup && pNewItemType)
|
||
{
|
||
*pNewItemType = REPORT_TYPE_COUNTER ;
|
||
}
|
||
return (pRetCounterGroup) ;
|
||
} // CounterRemoveItem
|
||
|
||
|
||
// GetNextCounter is used to get:
|
||
// If the current system is not empty, then get the
|
||
// (next object first counter) or
|
||
// (previous object last counter. )
|
||
// If the current system is empty, then get the
|
||
// (next system first object first counter) or
|
||
// (previous system last object last counter)
|
||
// Note - Any of the input pointers could be NULL pointer.
|
||
PCOUNTERGROUP GetNextCounter (PSYSTEMGROUP pSystemGroup,
|
||
POBJECTGROUP pObjectGroup,
|
||
PCOUNTERGROUP pCounterGroup)
|
||
{
|
||
PCOUNTERGROUP pRetCounter = NULL ;
|
||
PCOUNTERGROUP pCounterGrp ;
|
||
POBJECTGROUP pObjectGrp ;
|
||
|
||
if (pCounterGroup && pCounterGroup->pCounterGroupNext)
|
||
{
|
||
pRetCounter = pCounterGroup->pCounterGroupNext ;
|
||
}
|
||
else if (pCounterGroup && pCounterGroup->pCounterGroupPrevious)
|
||
{
|
||
pRetCounter = pCounterGroup->pCounterGroupPrevious ;
|
||
}
|
||
else if (pObjectGroup && pObjectGroup->pObjectGroupNext)
|
||
{
|
||
// get the next Object first Counter
|
||
pRetCounter = pObjectGroup->pObjectGroupNext->pCounterGroupFirst ;
|
||
}
|
||
else if (pObjectGroup && pObjectGroup->pObjectGroupPrevious)
|
||
{
|
||
// get the previous object last counter
|
||
pCounterGrp = (pObjectGroup->pObjectGroupPrevious)->pCounterGroupFirst ;
|
||
if (pCounterGrp)
|
||
{
|
||
// get the last counter group of this object
|
||
for (;
|
||
pCounterGrp->pCounterGroupNext ;
|
||
pCounterGrp = pCounterGrp->pCounterGroupNext )
|
||
{
|
||
;
|
||
}
|
||
}
|
||
pRetCounter = pCounterGrp ;
|
||
|
||
}
|
||
else if (pSystemGroup && pSystemGroup->pSystemGroupNext)
|
||
{
|
||
// get next system first object first counter
|
||
pObjectGrp = pSystemGroup->pSystemGroupNext->pObjectGroupFirst ;
|
||
pRetCounter = pObjectGrp->pCounterGroupFirst ;
|
||
}
|
||
else if (pSystemGroup && pSystemGroup->pSystemGroupPrevious)
|
||
{
|
||
// get previous system last object last counter
|
||
pObjectGrp = pSystemGroup->pSystemGroupPrevious->pObjectGroupFirst ;
|
||
if (pObjectGrp)
|
||
{
|
||
// get the last object group of this system
|
||
for (;
|
||
pObjectGrp->pObjectGroupNext ;
|
||
pObjectGrp = pObjectGrp->pObjectGroupNext )
|
||
{
|
||
;
|
||
}
|
||
}
|
||
|
||
if (pObjectGrp)
|
||
{
|
||
pCounterGrp = pObjectGrp->pCounterGroupFirst ;
|
||
if (pCounterGrp)
|
||
{
|
||
// get the last counter group of this object
|
||
for (;
|
||
pCounterGrp->pCounterGroupNext ;
|
||
pCounterGrp = pCounterGrp->pCounterGroupNext )
|
||
{
|
||
;
|
||
}
|
||
}
|
||
pRetCounter = pCounterGrp ;
|
||
}
|
||
}
|
||
|
||
return (pRetCounter) ;
|
||
|
||
} // GetNextCounter
|
||
|
||
|
||
//======================================//
|
||
// Object Group routines //
|
||
//======================================//
|
||
|
||
void ReportObjectRect (PREPORT pReport,
|
||
POBJECTGROUP pObjectGroup,
|
||
LPRECT lpRect)
|
||
{ // ReportObjectRect
|
||
lpRect->left = xObjectMargin ;
|
||
lpRect->top = pObjectGroup->yFirstLine ;
|
||
lpRect->right = lpRect->left + pObjectGroup->xWidth ;
|
||
lpRect->bottom = lpRect->top + pReport->yLineHeight ;
|
||
} // ReportObjectRect
|
||
|
||
|
||
POBJECTGROUP ObjectGroupCreate (LPTSTR lpszObjectName)
|
||
{ // ObjectGroupCreate
|
||
POBJECTGROUP pObjectGroup ;
|
||
HDC hDC ;
|
||
PREPORT pReport ;
|
||
int OldCounterWidth ;
|
||
TCHAR szLine [LongTextLen] ;
|
||
|
||
pObjectGroup = MemoryAllocate (sizeof (OBJECTGROUP)) ;
|
||
|
||
if (pObjectGroup)
|
||
{
|
||
pObjectGroup->pObjectGroupNext = NULL ;
|
||
pObjectGroup->pCounterGroupFirst = NULL ;
|
||
pObjectGroup->pColumnGroupFirst = NULL ;
|
||
pObjectGroup->lpszObjectName = StringAllocate (lpszObjectName) ;
|
||
|
||
hDC = GetDC (hWndReport) ;
|
||
pReport = ReportData (hWndReport) ;
|
||
if (hDC && pReport) {
|
||
SelectFont (hDC, pReport->hFontHeaders) ;
|
||
|
||
TSPRINTF (szLine, szObjectFormat, lpszObjectName) ;
|
||
pObjectGroup->xWidth = TextWidth (hDC, szLine) ;
|
||
|
||
// re-calc. the max. counter group width
|
||
OldCounterWidth = pReport->xMaxCounterWidth ;
|
||
pReport->xMaxCounterWidth =
|
||
max (pReport->xMaxCounterWidth,
|
||
pObjectGroup->xWidth + xObjectMargin) ;
|
||
|
||
if (OldCounterWidth < pReport->xMaxCounterWidth)
|
||
{
|
||
// adjust the report width with the new counter width
|
||
pReport->xWidth +=
|
||
(pReport->xMaxCounterWidth - OldCounterWidth);
|
||
}
|
||
|
||
} // if
|
||
if (hDC) {
|
||
ReleaseDC (hWndReport, hDC) ;
|
||
}
|
||
}
|
||
return (pObjectGroup) ;
|
||
} // ObjectGroupCreate
|
||
|
||
|
||
|
||
POBJECTGROUP GetObjectGroup (PSYSTEMGROUP pSystemGroup,
|
||
LPTSTR lpszObjectName)
|
||
{
|
||
POBJECTGROUP pObjectGroup ;
|
||
|
||
if (!pSystemGroup)
|
||
return (FALSE) ;
|
||
|
||
if (!pSystemGroup->pObjectGroupFirst)
|
||
{
|
||
pSystemGroup->pObjectGroupFirst = ObjectGroupCreate (lpszObjectName) ;
|
||
if (pSystemGroup->pObjectGroupFirst)
|
||
{
|
||
pSystemGroup->pObjectGroupFirst->pParentSystem =
|
||
pSystemGroup ;
|
||
}
|
||
return (pSystemGroup->pObjectGroupFirst) ;
|
||
}
|
||
|
||
for (pObjectGroup = pSystemGroup->pObjectGroupFirst ;
|
||
pObjectGroup ;
|
||
pObjectGroup = pObjectGroup->pObjectGroupNext)
|
||
{ // for
|
||
if (strsame (pObjectGroup->lpszObjectName, lpszObjectName))
|
||
{
|
||
return (pObjectGroup) ;
|
||
}
|
||
else if (!pObjectGroup->pObjectGroupNext)
|
||
{ // if
|
||
pObjectGroup->pObjectGroupNext =
|
||
ObjectGroupCreate (lpszObjectName) ;
|
||
|
||
if (pObjectGroup->pObjectGroupNext)
|
||
{
|
||
(pObjectGroup->pObjectGroupNext)->pParentSystem =
|
||
pSystemGroup ;
|
||
(pObjectGroup->pObjectGroupNext)->pObjectGroupPrevious =
|
||
pObjectGroup ;
|
||
}
|
||
|
||
return (pObjectGroup->pObjectGroupNext) ;
|
||
} // if
|
||
} // for
|
||
// if it falls through (which it shouldn't) at least return a
|
||
// reasonable value
|
||
return (pSystemGroup->pObjectGroupFirst) ;
|
||
} // GetObjectGroup
|
||
|
||
// ObjectGroupRemove removes the specified Object group
|
||
// from the Object double link list
|
||
BOOL ObjectGroupRemove (POBJECTGROUP *ppObjectGroupFirst,
|
||
POBJECTGROUP pObjectGroupRemove)
|
||
{
|
||
POBJECTGROUP pObjectGroup ;
|
||
|
||
if (*ppObjectGroupFirst == pObjectGroupRemove)
|
||
{
|
||
*ppObjectGroupFirst = (*ppObjectGroupFirst)->pObjectGroupNext ;
|
||
if (*ppObjectGroupFirst)
|
||
{
|
||
// set up head of backward link list
|
||
(*ppObjectGroupFirst)->pObjectGroupPrevious = NULL ;
|
||
}
|
||
|
||
// clean up the allocated memory
|
||
ColumnGroupRemove (pObjectGroupRemove->pColumnGroupFirst) ;
|
||
MemoryFree (pObjectGroupRemove->lpszObjectName) ;
|
||
MemoryFree (pObjectGroupRemove) ;
|
||
return (TRUE) ;
|
||
}
|
||
|
||
for (pObjectGroup = *ppObjectGroupFirst ;
|
||
pObjectGroup->pObjectGroupNext ;
|
||
pObjectGroup = pObjectGroup->pObjectGroupNext)
|
||
{ // for
|
||
if (pObjectGroup->pObjectGroupNext == pObjectGroupRemove)
|
||
{
|
||
pObjectGroup->pObjectGroupNext = pObjectGroupRemove->pObjectGroupNext ;
|
||
if (pObjectGroup->pObjectGroupNext)
|
||
{
|
||
(pObjectGroup->pObjectGroupNext)->pObjectGroupPrevious =
|
||
pObjectGroup ;
|
||
}
|
||
|
||
// clean up this object allocated memory and its column groups
|
||
ColumnGroupRemove (pObjectGroupRemove->pColumnGroupFirst) ;
|
||
MemoryFree (pObjectGroupRemove->lpszObjectName) ;
|
||
MemoryFree (pObjectGroupRemove) ;
|
||
return (TRUE) ;
|
||
} // if
|
||
} // for
|
||
|
||
return (FALSE) ;
|
||
} // ObjectGroupRemove
|
||
|
||
|
||
// ObjectRemoveItem is called when user delete the selected object
|
||
PCOUNTERGROUP ObjectRemoveItem (PREPORT pReport,
|
||
POBJECTGROUP pObjectGroup,
|
||
BOOL bCleanUpLink,
|
||
enum REPORT_ITEM_TYPE *pNewItemType)
|
||
{
|
||
PCOUNTERGROUP pCounterGroup, pNextCounterGroup ;
|
||
PSYSTEMGROUP pSystemGroup ;
|
||
PCOUNTERGROUP pRetCounterGroup = NULL ;
|
||
|
||
pSystemGroup = pObjectGroup->pParentSystem ;
|
||
|
||
// remove all counter groups from this object
|
||
for (pCounterGroup = pObjectGroup->pCounterGroupFirst ;
|
||
pCounterGroup ;
|
||
pCounterGroup = pNextCounterGroup )
|
||
{
|
||
pNextCounterGroup = pCounterGroup->pCounterGroupNext ;
|
||
CounterRemoveItem (pReport, pCounterGroup, FALSE, NULL) ;
|
||
}
|
||
|
||
// remove all column groups from this group
|
||
ColumnGroupRemove (pObjectGroup->pColumnGroupFirst) ;
|
||
pObjectGroup->pColumnGroupFirst = NULL;
|
||
|
||
if (bCleanUpLink)
|
||
{
|
||
|
||
// get next counter group to get the focus
|
||
if (pNewItemType)
|
||
{
|
||
pRetCounterGroup = GetNextCounter (
|
||
pSystemGroup,
|
||
pObjectGroup,
|
||
NULL) ;
|
||
|
||
if (pRetCounterGroup)
|
||
{
|
||
*pNewItemType = REPORT_TYPE_COUNTER ;
|
||
}
|
||
}
|
||
|
||
|
||
// remove this object from its parent system group
|
||
ObjectGroupRemove (&pSystemGroup->pObjectGroupFirst, pObjectGroup) ;
|
||
|
||
if (!(pSystemGroup->pObjectGroupFirst))
|
||
{
|
||
SystemGroupRemove (&pReport->pSystemGroupFirst, pSystemGroup) ;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// get rid of this object
|
||
MemoryFree (pObjectGroup->lpszObjectName) ;
|
||
MemoryFree (pObjectGroup) ;
|
||
}
|
||
|
||
return (pRetCounterGroup) ;
|
||
|
||
} // ObjectRemoveItem
|
||
|
||
|
||
//======================================//
|
||
// System Group routines //
|
||
//======================================//
|
||
void ReportSystemRect (PREPORT pReport,
|
||
PSYSTEMGROUP pSystemGroup,
|
||
LPRECT lpRect)
|
||
{ // ReportSystemRect
|
||
lpRect->left = xSystemMargin ;
|
||
lpRect->top = pSystemGroup->yFirstLine ;
|
||
lpRect->right = lpRect->left + pSystemGroup->xWidth ;
|
||
lpRect->bottom = lpRect->top + pReport->yLineHeight ;
|
||
} // ReportSystemRect
|
||
|
||
PSYSTEMGROUP SystemGroupCreate (LPTSTR lpszSystemName)
|
||
{ // SystemGroupCreate
|
||
PSYSTEMGROUP pSystemGroup ;
|
||
HDC hDC ;
|
||
PREPORT pReport ;
|
||
TCHAR szLine [LongTextLen] ;
|
||
|
||
pSystemGroup = MemoryAllocate (sizeof (SYSTEMGROUP)) ;
|
||
|
||
if (pSystemGroup)
|
||
{
|
||
pSystemGroup->pSystemGroupNext = NULL ;
|
||
pSystemGroup->pObjectGroupFirst = NULL ;
|
||
pSystemGroup->lpszSystemName = StringAllocate (lpszSystemName) ;
|
||
|
||
// get width of system name
|
||
hDC = GetDC (hWndReport) ;
|
||
if (hDC) {
|
||
pReport = ReportData (hWndReport) ;
|
||
SelectFont (hDC, pReport->hFontHeaders) ;
|
||
|
||
TSPRINTF (szLine, szSystemFormat, lpszSystemName) ;
|
||
pSystemGroup->xWidth = TextWidth (hDC, szLine) ;
|
||
ReleaseDC (hWndReport, hDC) ;
|
||
}
|
||
} // if
|
||
|
||
return (pSystemGroup) ;
|
||
} // SystemGroupCreate
|
||
|
||
PSYSTEMGROUP GetSystemGroup (PREPORT pReport,
|
||
LPTSTR lpszSystemName)
|
||
/*
|
||
Effect; Return a pointer to the system group of pReport with
|
||
a system name of lpszSystemName. If no system group
|
||
has that name, add a new system group.
|
||
*/
|
||
{ // GetSystemGroup
|
||
PSYSTEMGROUP pSystemGroup ;
|
||
|
||
if (!pReport->pSystemGroupFirst)
|
||
{
|
||
// add this system to the global system list
|
||
SystemAdd (&pReport->pSystemFirst, lpszSystemName, pReport->hWnd) ;
|
||
// now add it to the report
|
||
pReport->pSystemGroupFirst = SystemGroupCreate (lpszSystemName) ;
|
||
return (pReport->pSystemGroupFirst) ;
|
||
}
|
||
|
||
for (pSystemGroup = pReport->pSystemGroupFirst ;
|
||
pSystemGroup ;
|
||
pSystemGroup = pSystemGroup->pSystemGroupNext)
|
||
{ // for
|
||
if (strsamei (pSystemGroup->lpszSystemName, lpszSystemName))
|
||
return (pSystemGroup) ;
|
||
else if (!pSystemGroup->pSystemGroupNext)
|
||
{ // if
|
||
// add this system to the global system list
|
||
SystemAdd (&pReport->pSystemFirst, lpszSystemName, pReport->hWnd) ;
|
||
// and add it to the report list
|
||
pSystemGroup->pSystemGroupNext =
|
||
SystemGroupCreate (lpszSystemName) ;
|
||
if (pSystemGroup->pSystemGroupNext)
|
||
{
|
||
(pSystemGroup->pSystemGroupNext)->pSystemGroupPrevious =
|
||
pSystemGroup ;
|
||
}
|
||
return (pSystemGroup->pSystemGroupNext) ;
|
||
} // if
|
||
} // for
|
||
//if it falls through (which it shouldn't) at least return a
|
||
// reasonable value
|
||
return (pReport->pSystemGroupFirst) ;
|
||
} // GetSystemGroup
|
||
|
||
|
||
BOOL SystemGroupRemove (PSYSTEMGROUP *ppSystemGroupFirst,
|
||
PSYSTEMGROUP pSystemGroupRemove)
|
||
{
|
||
PSYSTEMGROUP pSystemGroup ;
|
||
|
||
if (*ppSystemGroupFirst == pSystemGroupRemove)
|
||
{
|
||
*ppSystemGroupFirst = (*ppSystemGroupFirst)->pSystemGroupNext ;
|
||
if (*ppSystemGroupFirst)
|
||
{
|
||
(*ppSystemGroupFirst)->pSystemGroupPrevious = NULL ;
|
||
}
|
||
MemoryFree (pSystemGroupRemove->lpszSystemName) ;
|
||
MemoryFree (pSystemGroupRemove) ;
|
||
return (TRUE) ;
|
||
}
|
||
|
||
for (pSystemGroup = *ppSystemGroupFirst ;
|
||
pSystemGroup->pSystemGroupNext ;
|
||
pSystemGroup = pSystemGroup->pSystemGroupNext)
|
||
{ // for
|
||
if (pSystemGroup->pSystemGroupNext == pSystemGroupRemove)
|
||
{
|
||
pSystemGroup->pSystemGroupNext = pSystemGroupRemove->pSystemGroupNext ;
|
||
if (pSystemGroup->pSystemGroupNext)
|
||
{
|
||
(pSystemGroup->pSystemGroupNext)->pSystemGroupPrevious =
|
||
pSystemGroup ;
|
||
}
|
||
MemoryFree (pSystemGroupRemove->lpszSystemName) ;
|
||
MemoryFree (pSystemGroupRemove) ;
|
||
return (TRUE) ;
|
||
} // if
|
||
} // for
|
||
|
||
return (FALSE) ;
|
||
} // SystemGroupRemove
|
||
|
||
|
||
// SystemRemoveItem is called when user deletes the selected System
|
||
PCOUNTERGROUP SystemRemoveItem (PREPORT pReport,
|
||
PSYSTEMGROUP pSystemGroup,
|
||
BOOL bCleanUpLink,
|
||
enum REPORT_ITEM_TYPE *pNewItemType)
|
||
{
|
||
POBJECTGROUP pObjectGroup, pNextObjectGroup ;
|
||
PCOUNTERGROUP pRetCounterGroup = NULL ;
|
||
|
||
// remove all object groups from this system
|
||
for (pObjectGroup = pSystemGroup->pObjectGroupFirst ;
|
||
pObjectGroup ;
|
||
pObjectGroup = pNextObjectGroup )
|
||
{
|
||
pNextObjectGroup = pObjectGroup->pObjectGroupNext ;
|
||
ObjectRemoveItem (pReport, pObjectGroup, FALSE, NULL) ;
|
||
}
|
||
|
||
|
||
if (bCleanUpLink)
|
||
{
|
||
if (pNewItemType)
|
||
{
|
||
pRetCounterGroup = GetNextCounter (
|
||
pSystemGroup,
|
||
NULL,
|
||
NULL) ;
|
||
|
||
if (pRetCounterGroup)
|
||
{
|
||
*pNewItemType = REPORT_TYPE_COUNTER ;
|
||
}
|
||
}
|
||
|
||
SystemGroupRemove (&pReport->pSystemGroupFirst, pSystemGroup) ;
|
||
}
|
||
else
|
||
{
|
||
// delete data from this system
|
||
MemoryFree (pSystemGroup->lpszSystemName) ;
|
||
MemoryFree (pSystemGroup) ;
|
||
}
|
||
|
||
return (pRetCounterGroup) ;
|
||
|
||
} // SystemRemoveItem
|
||
|
||
|
||
BOOL ReportChangeFocus (HWND hWnd,
|
||
PREPORT pReport,
|
||
REPORT_ITEM SelectedItem,
|
||
enum REPORT_ITEM_TYPE SelectedItemType,
|
||
int xOffset,
|
||
int yOffset,
|
||
RECT *pRect)
|
||
{
|
||
HDC hDC ;
|
||
BOOL RetCode = FALSE ; // FALSE ==> same item being hit
|
||
RECT Rect ;
|
||
REPORT_ITEM PreviousItem ;
|
||
enum REPORT_ITEM_TYPE PreviousItemType ;
|
||
|
||
if (pReport->CurrentItem.pLine != SelectedItem.pLine)
|
||
{
|
||
// not the same item
|
||
RetCode = TRUE ;
|
||
|
||
PreviousItemType = pReport->CurrentItemType ;
|
||
PreviousItem.pLine = pReport->CurrentItem.pLine ;
|
||
|
||
pReport->CurrentItemType = SelectedItemType ;
|
||
pReport->CurrentItem.pLine = SelectedItem.pLine ;
|
||
|
||
hDC = GetDC (hWnd) ;
|
||
if (!hDC)
|
||
return FALSE;
|
||
|
||
if (SelectedItemType == REPORT_TYPE_LINE)
|
||
{
|
||
SetWindowOrgEx (hDC, xOffset, yOffset, NULL) ;
|
||
SelectFont (hDC, pReport->hFont) ;
|
||
SetTextAlign (hDC, TA_RIGHT) ;
|
||
SetBkColor (hDC, GetSysColor(COLOR_WINDOW)) ;
|
||
DrawReportValue (hDC, pReport, SelectedItem.pLine) ;
|
||
SetWindowOrgEx (hDC, -xOffset, -yOffset, NULL) ;
|
||
}
|
||
else
|
||
{
|
||
Rect = *pRect ;
|
||
Rect.top -= yOffset ;
|
||
Rect.bottom -= yOffset ;
|
||
Rect.right -= xOffset ;
|
||
Rect.left -= xOffset ;
|
||
InvalidateRect (hWnd, &Rect, TRUE) ;
|
||
}
|
||
|
||
if (PreviousItemType == REPORT_TYPE_LINE)
|
||
{
|
||
SetWindowOrgEx (hDC, xOffset, yOffset, NULL) ;
|
||
SelectFont (hDC, pReport->hFont) ;
|
||
SetTextAlign (hDC, TA_RIGHT) ;
|
||
SetBkColor (hDC, GetSysColor(COLOR_WINDOW)) ;
|
||
DrawReportValue (hDC, pReport, PreviousItem.pLine) ;
|
||
}
|
||
else if (PreviousItemType != REPORT_TYPE_NOTHING)
|
||
{
|
||
if (PreviousItemType == REPORT_TYPE_SYSTEM)
|
||
{
|
||
ReportSystemRect (pReport, PreviousItem.pSystem, &Rect) ;
|
||
}
|
||
else if (PreviousItemType == REPORT_TYPE_OBJECT)
|
||
{
|
||
ReportObjectRect (pReport, PreviousItem.pObject, &Rect) ;
|
||
}
|
||
else if (PreviousItemType == REPORT_TYPE_COUNTER)
|
||
{
|
||
ReportCounterRect (pReport, PreviousItem.pCounter, &Rect) ;
|
||
}
|
||
else if (PreviousItemType == REPORT_TYPE_COLUMN)
|
||
{
|
||
ReportColumnRect (pReport, PreviousItem.pColumn, &Rect) ;
|
||
}
|
||
Rect.top -= yOffset ;
|
||
Rect.bottom -= yOffset ;
|
||
Rect.right -= xOffset ;
|
||
Rect.left -= xOffset ;
|
||
InvalidateRect (hWnd, &Rect, TRUE) ;
|
||
}
|
||
ReleaseDC (hWnd, hDC) ;
|
||
}
|
||
|
||
return (RetCode) ;
|
||
} // ReportChangeFocus
|
||
|
||
|
||
BOOL OnReportLButtonDown (HWND hWnd,
|
||
WORD xPos,
|
||
WORD yPos)
|
||
{
|
||
PREPORT pReport ;
|
||
PLINE pLine ;
|
||
REPORT_ITEM PreviousItem ;
|
||
REPORT_ITEM CurrentSelectedItem ;
|
||
enum REPORT_ITEM_TYPE PreviousItemType ;
|
||
RECT rect ;
|
||
POINT pt ;
|
||
int xOffset, yOffset ;
|
||
PSYSTEMGROUP pSystemGroup ;
|
||
POBJECTGROUP pObjectGroup ;
|
||
PCOUNTERGROUP pCounterGroup ;
|
||
PCOLUMNGROUP pColumnGroup ;
|
||
|
||
|
||
pReport = ReportData (hWnd) ;
|
||
if (!pReport)
|
||
return (FALSE) ;
|
||
|
||
xOffset = GetScrollPos (hWnd, SB_HORZ) ;
|
||
yOffset = GetScrollPos (hWnd, SB_VERT) ;
|
||
pt.x = xPos + xOffset ;
|
||
pt.y = yPos + yOffset ;
|
||
PreviousItem = pReport->CurrentItem ;
|
||
PreviousItemType = pReport->CurrentItemType ;
|
||
|
||
for (pLine = pReport->pLineFirst ;
|
||
pLine ;
|
||
pLine = pLine->pLineNext)
|
||
{ // for
|
||
ReportLineValueRect (pReport, pLine, &rect) ;
|
||
if (PtInRect (&rect, pt))
|
||
{
|
||
CurrentSelectedItem.pLine = pLine ;
|
||
return (ReportChangeFocus (
|
||
hWnd,
|
||
pReport,
|
||
CurrentSelectedItem,
|
||
REPORT_TYPE_LINE,
|
||
xOffset,
|
||
yOffset,
|
||
&rect)) ;
|
||
}
|
||
} // for
|
||
|
||
// check on hit on system, object, counter, column (parent+isntance names)
|
||
for (pSystemGroup = pReport->pSystemGroupFirst ;
|
||
pSystemGroup ;
|
||
pSystemGroup = pSystemGroup->pSystemGroupNext)
|
||
{ // for System...
|
||
|
||
ReportSystemRect (pReport, pSystemGroup, &rect) ;
|
||
if (PtInRect (&rect, pt))
|
||
{
|
||
CurrentSelectedItem.pSystem = pSystemGroup ;
|
||
return (ReportChangeFocus (
|
||
hWnd,
|
||
pReport,
|
||
CurrentSelectedItem,
|
||
REPORT_TYPE_SYSTEM,
|
||
xOffset,
|
||
yOffset,
|
||
&rect)) ;
|
||
}
|
||
|
||
|
||
for (pObjectGroup = pSystemGroup->pObjectGroupFirst ;
|
||
pObjectGroup ;
|
||
pObjectGroup = pObjectGroup->pObjectGroupNext)
|
||
{ // for Object...
|
||
|
||
ReportObjectRect (pReport, pObjectGroup, &rect) ;
|
||
if (PtInRect (&rect, pt))
|
||
{
|
||
CurrentSelectedItem.pObject = pObjectGroup ;
|
||
return (ReportChangeFocus (
|
||
hWnd,
|
||
pReport,
|
||
CurrentSelectedItem,
|
||
REPORT_TYPE_OBJECT,
|
||
xOffset,
|
||
yOffset,
|
||
&rect)) ;
|
||
}
|
||
|
||
for (pColumnGroup = pObjectGroup->pColumnGroupFirst ;
|
||
pColumnGroup ;
|
||
pColumnGroup = pColumnGroup->pColumnGroupNext)
|
||
{ // for Column...
|
||
ReportColumnRect (pReport, pColumnGroup, &rect) ;
|
||
if (PtInRect (&rect, pt))
|
||
{
|
||
CurrentSelectedItem.pColumn = pColumnGroup ;
|
||
return (ReportChangeFocus (
|
||
hWnd,
|
||
pReport,
|
||
CurrentSelectedItem,
|
||
REPORT_TYPE_COLUMN,
|
||
xOffset,
|
||
yOffset,
|
||
&rect)) ;
|
||
}
|
||
} // for Column
|
||
|
||
for (pCounterGroup = pObjectGroup->pCounterGroupFirst ;
|
||
pCounterGroup ;
|
||
pCounterGroup = pCounterGroup->pCounterGroupNext)
|
||
{ // for Counter...
|
||
ReportCounterRect (pReport, pCounterGroup, &rect) ;
|
||
if (PtInRect (&rect, pt))
|
||
{
|
||
CurrentSelectedItem.pCounter = pCounterGroup ;
|
||
return (ReportChangeFocus (
|
||
hWnd,
|
||
pReport,
|
||
CurrentSelectedItem,
|
||
REPORT_TYPE_COUNTER,
|
||
xOffset,
|
||
yOffset,
|
||
&rect)) ;
|
||
|
||
}
|
||
} // for Counter...
|
||
} // for Object...
|
||
} // for System...
|
||
|
||
// nothing hit
|
||
return (FALSE) ;
|
||
} // OnReportLButtonDown
|
||
|
||
BOOL ReportDeleteItem (HWND hWnd)
|
||
/*
|
||
Effect: Delete the current selected item.
|
||
|
||
*/
|
||
{ // ReportDeleteItem
|
||
|
||
HDC hDC ;
|
||
PREPORT pReport ;
|
||
REPORT_ITEM NextItem ;
|
||
enum REPORT_ITEM_TYPE NextItemType ;
|
||
|
||
NextItemType = REPORT_TYPE_NOTHING ;
|
||
NextItem.pLine = NULL ;
|
||
|
||
pReport = ReportData (hWnd) ;
|
||
if (pReport->CurrentItemType == REPORT_TYPE_NOTHING)
|
||
{
|
||
// nothing to delete...
|
||
return (TRUE) ;
|
||
}
|
||
else if (pReport->CurrentItemType == REPORT_TYPE_LINE)
|
||
{
|
||
NextItem.pLine = LineRemoveItem (pReport, &NextItemType) ;
|
||
}
|
||
else if (pReport->CurrentItemType == REPORT_TYPE_SYSTEM)
|
||
{
|
||
NextItem.pCounter = SystemRemoveItem (
|
||
pReport,
|
||
pReport->CurrentItem.pSystem,
|
||
TRUE,
|
||
&NextItemType) ;
|
||
}
|
||
else if (pReport->CurrentItemType == REPORT_TYPE_OBJECT)
|
||
{
|
||
NextItem.pCounter = ObjectRemoveItem (
|
||
pReport,
|
||
pReport->CurrentItem.pObject,
|
||
TRUE,
|
||
&NextItemType) ;
|
||
}
|
||
else if (pReport->CurrentItemType == REPORT_TYPE_COUNTER)
|
||
{
|
||
NextItem.pCounter = CounterRemoveItem (
|
||
pReport,
|
||
pReport->CurrentItem.pCounter,
|
||
TRUE,
|
||
&NextItemType) ;
|
||
}
|
||
else if (pReport->CurrentItemType == REPORT_TYPE_COLUMN)
|
||
{
|
||
NextItem.pColumn = ColumnRemoveItem (
|
||
pReport,
|
||
pReport->CurrentItem.pColumn,
|
||
TRUE,
|
||
&NextItemType) ;
|
||
}
|
||
|
||
if (NextItemType != REPORT_TYPE_NOTHING)
|
||
{
|
||
pReport->CurrentItem.pLine = NextItem.pLine ;
|
||
pReport->CurrentItemType = NextItemType ;
|
||
}
|
||
else
|
||
{
|
||
pReport->CurrentItem.pLine = pReport->pLineFirst ;
|
||
pReport->CurrentItemType = REPORT_TYPE_LINE ;
|
||
}
|
||
|
||
if (pReport->pLineFirst)
|
||
{
|
||
BuildValueListForSystems (
|
||
pReport->pSystemFirst,
|
||
pReport->pLineFirst) ;
|
||
}
|
||
else
|
||
{
|
||
// no more line, no more timer...
|
||
pReport->xWidth = 0 ;
|
||
pReport->yHeight = 0 ;
|
||
pReport->xMaxCounterWidth = 0 ;
|
||
ClearReportTimer (pReport) ;
|
||
|
||
FreeSystems (pReport->pSystemFirst) ;
|
||
pReport->pSystemFirst = NULL ;
|
||
pReport->pSystemGroupFirst = NULL ;
|
||
pReport->CurrentItemType = REPORT_TYPE_NOTHING ;
|
||
pReport->CurrentItem.pLine = NULL ;
|
||
|
||
}
|
||
|
||
//=============================//
|
||
// Calculate report positions //
|
||
//=============================//
|
||
|
||
hDC = GetDC (hWnd) ;
|
||
if (hDC) {
|
||
SetReportPositions (hDC, pReport) ;
|
||
|
||
if (!pReport->pLineFirst)
|
||
{
|
||
SelectFont (hDC, pReport->hFont) ;
|
||
pReport->xValueWidth = TextWidth (hDC, szValuePlaceholder) ;
|
||
}
|
||
|
||
ReleaseDC (hWnd, hDC) ;
|
||
}
|
||
WindowInvalidate (hWnd) ;
|
||
|
||
return (TRUE) ;
|
||
} // ReportDeleteItem
|
||
|