2086 lines
47 KiB
C++
2086 lines
47 KiB
C++
// Copyright (c) 1997-2001 Microsoft Corporation, All Rights Reserved
|
|
//***************************************************************************
|
|
//
|
|
// (c) 1996 by Microsoft Corporation
|
|
//
|
|
// grid.cpp
|
|
//
|
|
// This file contains the implementation for the HMOM object viewer grid.
|
|
//
|
|
// a-larryf 17-Sept-96 Created.
|
|
//
|
|
//***************************************************************************
|
|
|
|
|
|
#include "precomp.h"
|
|
#include "resource.h"
|
|
#include "grid.h"
|
|
#include "globals.h"
|
|
#include "notify.h"
|
|
#include "gca.h"
|
|
#include "gridhdr.h"
|
|
#include "celledit.h"
|
|
#include "core.h"
|
|
#include "utils.h"
|
|
#include "globals.h"
|
|
#include <afxctl.h>
|
|
#include <afxcmn.h>
|
|
|
|
|
|
#define CY_HEADER 16
|
|
#define CY_BORDER_MERGE 0
|
|
|
|
#define GS_TRUE _T("TRUE")
|
|
#define GS_FALSE _T("FALSE")
|
|
#define GS_EMPTY_STRING _T("<empty>")
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CGridSync
|
|
//
|
|
// This class provides you with a simple way to syncronize the grid cell editor
|
|
// before making changes to the grid or accessing the values in the grid.
|
|
//
|
|
// To syncronize the grid with the grid cell editor, just declare an instance of
|
|
// the CGridSync class in the method that will be doing the editing.
|
|
|
|
CGridSync::CGridSync(CGrid* pGrid)
|
|
{
|
|
m_pGrid = pGrid;
|
|
m_sc = pGrid->BeginSerialize();
|
|
}
|
|
|
|
CGridSync::~CGridSync()
|
|
{
|
|
m_pGrid->EndSerialize();
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CGrid
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CGrid
|
|
//
|
|
// This is grid class that most clients will want to use. It contains
|
|
// both CGridHdr and a CGridCore client windows.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
CGrid::CGrid()
|
|
{
|
|
m_bUIActive = FALSE;
|
|
m_pcore = new CGridCore;
|
|
m_phdr = new CHdrWnd(this);
|
|
m_cxHeaderScrollOffset = 0;
|
|
m_phdr->Header().m_pGrid = this;
|
|
m_cxRowHandles = 0;
|
|
m_pcore->SetParent(this);
|
|
m_bmAscendingIndicator.LoadBitmap(IDB_ASCENDING_INDICATOR);
|
|
m_bmDescendingIndicator.LoadBitmap(IDB_DESCENDING_INDICATOR);
|
|
m_icolSortIndicator = NULL_INDEX;
|
|
}
|
|
|
|
CGrid::~CGrid()
|
|
{
|
|
delete m_pcore;
|
|
delete m_phdr;
|
|
}
|
|
|
|
|
|
BEGIN_MESSAGE_MAP(CGrid, CWnd)
|
|
//{{AFX_MSG_MAP(CGrid)
|
|
ON_WM_SHOWWINDOW()
|
|
ON_WM_SIZE()
|
|
ON_WM_PAINT()
|
|
ON_WM_SETFOCUS()
|
|
ON_WM_KILLFOCUS()
|
|
//}}AFX_MSG_MAP
|
|
|
|
END_MESSAGE_MAP()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//*************************************************************
|
|
// CGrid::Create
|
|
//
|
|
// Create the CGrid window.
|
|
//
|
|
// Parameters:
|
|
// CRect& rc
|
|
// The rectangle in the parent's client area where this
|
|
// CGrid window will be placed.
|
|
//
|
|
// CWnd* pwndParent
|
|
// A pointer to the parent window.
|
|
//
|
|
// UINT nId
|
|
// The window ID
|
|
//
|
|
// BOOL bVisible
|
|
// TRUE if the CGrid window should be initially visible, FALSE
|
|
// otherwise.
|
|
//
|
|
// Returns:
|
|
// BOOL
|
|
// TRUE if the window was created successfully.
|
|
//
|
|
//***************************************************************
|
|
BOOL CGrid::Create(CRect& rc, CWnd* pwndParent, UINT nId, BOOL bVisible)
|
|
{
|
|
|
|
DWORD dwStyle = WS_BORDER | WS_CHILD;
|
|
if (bVisible) {
|
|
dwStyle |= WS_VISIBLE;
|
|
}
|
|
|
|
|
|
// Create this window. It will be the parent of the header control and
|
|
// the CGridCore windows.
|
|
BOOL bDidCreate = CWnd::Create(NULL, _T("CGridCore"), dwStyle, rc, pwndParent, nId);
|
|
if (!bDidCreate) {
|
|
return FALSE;
|
|
}
|
|
|
|
// Create the header control as a child window.
|
|
CRect rcHeader;
|
|
rcHeader.left = 0;
|
|
rcHeader.top = 0;
|
|
rcHeader.right = rc.right - rc.left;
|
|
rcHeader.bottom = CY_HEADER;
|
|
|
|
|
|
dwStyle = WS_CHILD | HDS_BUTTONS | HDS_HORZ;
|
|
if (bVisible) {
|
|
dwStyle |= WS_VISIBLE;
|
|
}
|
|
|
|
bDidCreate = m_phdr->Create(dwStyle, rcHeader, this, nId);
|
|
if (!bDidCreate) {
|
|
return FALSE;
|
|
}
|
|
|
|
InitializeHeader();
|
|
|
|
// Create the CGridCore window as a child of this window.
|
|
CRect rcGridCore = rcHeader;
|
|
rcGridCore.top = rcHeader.bottom + CY_BORDER_MERGE;
|
|
rcGridCore.bottom = rc.bottom;
|
|
|
|
bDidCreate = m_pcore->Create(rcGridCore, nId, bVisible);
|
|
if (!bDidCreate) {
|
|
return FALSE;
|
|
}
|
|
|
|
SizeChildren();
|
|
return bDidCreate;
|
|
}
|
|
|
|
|
|
CGridCore* CGrid::GridCore()
|
|
{
|
|
return m_pcore;
|
|
}
|
|
|
|
void CGrid::UpdateScrollRanges()
|
|
{
|
|
m_pcore->UpdateScrollRanges();
|
|
}
|
|
|
|
|
|
|
|
void CGrid::OnCellContentChange(int iRow, int iCol)
|
|
{
|
|
// The default behavior for this virtual function is to do nothing.
|
|
}
|
|
|
|
void CGrid::OnCellClicked(int iRow, int iCol)
|
|
{
|
|
// The default behavior for this virtual function is to do nothing.
|
|
}
|
|
|
|
void CGrid::OnCellClickedEpilog(int iRow, int iCol)
|
|
{
|
|
// The default behavior for this virtual function is to do nothing.
|
|
}
|
|
|
|
BOOL CGrid::OnCellKeyDown(int iRow, int iCol, UINT nChar, UINT nRepCnt, UINT nFlags)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL CGrid::OnCellChar(int iRow, int iCol, UINT nChar, UINT nRepCnt, UINT nFlags)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL CGrid::OnRowKeyDown(int iRow, UINT nChar, UINT nRepCnt, UINT nFlags)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL CGrid::OnBeginCellEditing(int iRow, int iCol)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL CGrid::OnQueryRowExists(int iRow)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
void CGrid::OnHeaderItemClick(int iItem)
|
|
{
|
|
}
|
|
|
|
|
|
BOOL CGrid::GetCellEditContextMenu(int iRow, int iCol, CWnd*& pwndTarget, CMenu& menu, BOOL& bWantEditCommands)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
void CGrid::ModifyCellEditContextMenu(int iRow, int iCol, CMenu& menu)
|
|
{
|
|
}
|
|
|
|
BOOL CGrid::OnCellEditContextMenu(CWnd* pwnd, CPoint ptContextMenu)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
int CGrid::CompareRows(int iRow1, int iRow2, int iSortOrder)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
void CGrid::BeginCellEditing()
|
|
{
|
|
m_pcore->BeginCellEditing();
|
|
}
|
|
|
|
|
|
void CGrid::EndCellEditing()
|
|
{
|
|
m_pcore->EndCellEditing();
|
|
}
|
|
|
|
BOOL CGrid::IsEditingCell()
|
|
{
|
|
return m_pcore->IsEditingCell();
|
|
}
|
|
|
|
|
|
|
|
void CGrid::RefreshCellEditor()
|
|
{
|
|
m_pcore->RefreshCellEditor();
|
|
}
|
|
|
|
|
|
SCODE CGrid::BeginSerialize()
|
|
{
|
|
return m_pcore->SyncCellEditor();
|
|
}
|
|
|
|
void CGrid::EndSerialize()
|
|
{
|
|
}
|
|
|
|
|
|
SCODE CGrid::SyncCellEditor()
|
|
{
|
|
return m_pcore->SyncCellEditor();
|
|
}
|
|
|
|
int CGrid::RowHeight()
|
|
{
|
|
return m_pcore->RowHeight();
|
|
}
|
|
|
|
void CGrid::SelectCell(int iRow, int iCol, BOOL bForceBeginEdit)
|
|
{
|
|
m_pcore->SelectCell(iRow, iCol, bForceBeginEdit);
|
|
}
|
|
|
|
void CGrid::SelectRow(int iRow)
|
|
{
|
|
m_pcore->SelectRow(iRow);
|
|
}
|
|
|
|
|
|
|
|
|
|
void CGrid::EnsureRowVisible(int iRow)
|
|
{
|
|
m_pcore->EnsureRowVisible(iRow);
|
|
}
|
|
|
|
CGridCell& CGrid::GetAt(int iRow, int iCol)
|
|
{
|
|
return m_pcore->GetAt(iRow, iCol);
|
|
}
|
|
|
|
int CGrid::GetRows()
|
|
{
|
|
return m_pcore->GetRows();
|
|
}
|
|
|
|
|
|
int CGrid::GetCols()
|
|
{
|
|
return m_pcore->GetCols();
|
|
}
|
|
|
|
|
|
int CGrid::GetSelectedRow()
|
|
{
|
|
return m_pcore->GetSelectedRow();
|
|
}
|
|
|
|
|
|
void CGrid::GetSelectedCell(int& iRow, int& iCol)
|
|
{
|
|
m_pcore->GetSelectedCell(iRow, iCol);
|
|
}
|
|
|
|
|
|
BOOL CGrid::EntireRowIsSelected()
|
|
{
|
|
return m_pcore->EntireRowIsSelected();
|
|
}
|
|
|
|
|
|
void CGrid::InsertRowAt(int iRow)
|
|
{
|
|
m_pcore->InsertRowAt(iRow);
|
|
}
|
|
|
|
|
|
int CGrid::AddRow()
|
|
{
|
|
return m_pcore->AddRow();
|
|
}
|
|
|
|
|
|
void CGrid::DeleteRowAt(int iRow, BOOL bUpdateWindow)
|
|
{
|
|
m_pcore->DeleteRowAt(iRow, bUpdateWindow);
|
|
}
|
|
|
|
|
|
//void CGrid::InsertColumnAt(int iCol, int iWidth, LPCTSTR pszTitle );
|
|
// void Clear(BOOL bUpdateWindow=TRUE);
|
|
|
|
void CGrid::ClearRows(BOOL bUpdateWindow)
|
|
{
|
|
m_pcore->ClearRows(bUpdateWindow);
|
|
}
|
|
|
|
|
|
BOOL CGrid::WasModified()
|
|
{
|
|
return m_pcore->WasModified();
|
|
}
|
|
|
|
void CGrid::SetModified(BOOL bWasModified)
|
|
{
|
|
m_pcore->SetModified(bWasModified);
|
|
}
|
|
|
|
int CGrid::ColWidth(int iCol)
|
|
{
|
|
return m_pcore->ColWidth(iCol);
|
|
}
|
|
|
|
int CGrid::ColWidthFromHeader(int iCol)
|
|
{
|
|
return m_phdr->Header().ColWidthFromHeader(iCol);
|
|
}
|
|
|
|
CString& CGrid::ColTitle(int iCol)
|
|
{
|
|
return m_pcore->ColTitle(iCol);
|
|
}
|
|
|
|
|
|
void CGrid::SetCellModified(int iRow, int iCol, BOOL bWasModified)
|
|
{
|
|
m_pcore->SetCellModified(iRow, iCol, bWasModified);
|
|
}
|
|
|
|
|
|
int CGrid::GetRowHandleWidth()
|
|
{
|
|
return m_pcore->GetRowHandleWidth();
|
|
}
|
|
|
|
|
|
int CGrid::CompareCells(int iRow1, int iRow2, int iCol)
|
|
{
|
|
return CompareCells(iRow1, iCol, iRow2, iCol);
|
|
}
|
|
|
|
|
|
void CGrid::NotifyCellModifyChange()
|
|
{
|
|
m_pcore->NotifyCellModifyChange();
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//*********************************************************
|
|
// CGrid::AddColumn
|
|
//
|
|
// Add a column to the grid header.
|
|
//
|
|
// Parameters:
|
|
// int iWidth
|
|
// The column width
|
|
//
|
|
// LPCTSTR pszTitle
|
|
// A pointer to the column title.
|
|
//
|
|
// Returns:
|
|
// Nothing.
|
|
//
|
|
//********************************************************
|
|
void CGrid::AddColumn(int iWidth, LPCTSTR pszTitle)
|
|
{
|
|
InsertColumnAt(GetCols(), iWidth, pszTitle);
|
|
|
|
}
|
|
|
|
|
|
|
|
//********************************************************
|
|
// CGrid::Clear
|
|
//
|
|
// Delete all rows and columns from the grid.
|
|
//
|
|
// Parameters:
|
|
// [in] BOOL bUpdateWindow
|
|
// TRUE if the window should be updated after clearing the grid.
|
|
//
|
|
// Returns:
|
|
// Nothing.
|
|
//
|
|
//**********************************************************
|
|
void CGrid::Clear(BOOL bUpdateWindow)
|
|
{
|
|
m_pcore->Clear(bUpdateWindow);
|
|
|
|
int nCols = m_phdr->Header().GetItemCount();
|
|
while (--nCols >= 0) {
|
|
m_phdr->Header().DeleteItem(nCols);
|
|
}
|
|
|
|
m_phdr->Header().SelectColumn(0);
|
|
m_aSortAscending.RemoveAll();
|
|
|
|
if (bUpdateWindow) {
|
|
if (m_phdr->m_hWnd) {
|
|
m_phdr->RedrawWindow();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//********************************************************
|
|
// CGrid::InsertColumnAt
|
|
//
|
|
// Insert a new column at the specified index.
|
|
//
|
|
// Parameters:
|
|
// int iCol
|
|
// The column index where the new column will be inserted.
|
|
//
|
|
// int iWidth
|
|
// The width of the column.
|
|
//
|
|
// LPCTSTR pszTitle
|
|
// Pointer to the column's title.
|
|
//
|
|
// Returns:
|
|
// Nothing.
|
|
//
|
|
//********************************************************
|
|
void CGrid::InsertColumnAt(int iCol, int iWidth, LPCTSTR pszTitle )
|
|
{
|
|
ASSERT(m_aSortAscending.GetSize() == GetCols());
|
|
m_aSortAscending.InsertAt(iCol, TRUE);
|
|
m_pcore->InsertColumnAt(iCol, iWidth, pszTitle);
|
|
ASSERT(m_aSortAscending.GetSize() == GetCols());
|
|
|
|
// If the header doesn't exist or doesn't have a window
|
|
// yet, then we must delay adding the title to the header
|
|
// until it is initialized later.
|
|
if (m_phdr->m_hWnd!=NULL) {
|
|
HD_ITEM item;
|
|
item.mask = HDI_FORMAT | HDI_TEXT | HDI_WIDTH | HDI_LPARAM | HDI_BITMAP;
|
|
item.hbm = NULL;
|
|
item.fmt = HDF_LEFT;
|
|
item.lParam = MAKELPARAM(TRUE,iWidth);
|
|
|
|
item.cxy = iWidth;
|
|
item.pszText = (LPTSTR) (void*) pszTitle;
|
|
item.cchTextMax = _tcslen(pszTitle);
|
|
m_phdr->Header().InsertItem(iCol, &item);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//********************************************************
|
|
// CGrid::InitializeHeader
|
|
//
|
|
// Initialize the header control with the column titles.
|
|
//
|
|
// Parameters:
|
|
// None.
|
|
//
|
|
// Returns:
|
|
// Nothing.
|
|
//
|
|
//*********************************************************
|
|
void CGrid::InitializeHeader()
|
|
{
|
|
HD_ITEM item;
|
|
item.mask = HDI_FORMAT | HDI_TEXT | HDI_WIDTH | HDI_LPARAM | HDI_BITMAP;
|
|
item.hbm = NULL;
|
|
item.fmt = HDF_LEFT;
|
|
item.lParam = FALSE;
|
|
|
|
m_phdr->Header().SetFont(&m_pcore->GetFont());
|
|
int nCols = GetCols();
|
|
for (int iCol = 0; iCol < nCols; ++iCol) {
|
|
item.cxy = ColWidth(iCol);
|
|
|
|
item.lParam = MAKELPARAM(TRUE,item.cxy);
|
|
|
|
CString* psTitle = &ColTitle(iCol);
|
|
|
|
item.pszText = (LPTSTR) (void*) (LPCTSTR) *psTitle;
|
|
item.cchTextMax = psTitle->GetLength();
|
|
m_phdr->Header().InsertItem(iCol, &item);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
//***********************************************************
|
|
// CGrid::SetHeaderSortIndicator
|
|
//
|
|
// Set the sort indicator on the column header to show whether
|
|
// the column is sorted in ascending or descending order.
|
|
//
|
|
// Parameters:
|
|
// int iCol
|
|
// The column index of the cell that was double clicked.
|
|
//
|
|
// BOOL bAscending
|
|
// TRUE if the ASCENDING sort indicator should be shown,
|
|
// FALSE if the DESCENDING sort indicator should be shown.
|
|
//
|
|
// BOOL bNone
|
|
// TRUE if no sort indicator should be displayed for the
|
|
// specified column.
|
|
//
|
|
// Returns:
|
|
// Nothing.
|
|
//
|
|
//************************************************************
|
|
void CGrid::SetHeaderSortIndicator(int iCol, BOOL bAscending, BOOL bNone)
|
|
{
|
|
|
|
HD_ITEM item;
|
|
CHeaderCtrl* phdr = &m_phdr->Header();
|
|
|
|
TCHAR szTitle[128];
|
|
|
|
|
|
// Remove the sort indicator from the current sort indicator column
|
|
// by deleting the header item and then inserting a header item with
|
|
// just the text. Don't do this if the column hasn't changed because
|
|
// we will just delete it and insert it again anyway.
|
|
static CString sTitle;
|
|
if (m_icolSortIndicator!=NULL_INDEX) {
|
|
if (iCol != m_icolSortIndicator) {
|
|
|
|
item.mask = HDI_TEXT | HDI_WIDTH | HDI_LPARAM;
|
|
szTitle[0] = 0;
|
|
ASSERT(m_icolSortIndicator != -1);
|
|
item.pszText = szTitle;
|
|
// a-judypo fix
|
|
item.cchTextMax = sizeof(szTitle) - 1;
|
|
phdr->GetItem(m_icolSortIndicator, &item);
|
|
|
|
item.mask = HDI_TEXT | HDI_FORMAT | HDI_WIDTH | HDI_LPARAM | HDI_BITMAP;
|
|
item.pszText = szTitle;
|
|
item.cchTextMax = sizeof(szTitle) - 1;
|
|
item.cchTextMax = _tcslen(szTitle);
|
|
item.fmt = HDF_LEFT;
|
|
item.hbm = NULL;
|
|
|
|
ASSERT(m_icolSortIndicator != -1);
|
|
phdr->DeleteItem(m_icolSortIndicator);
|
|
ASSERT(m_icolSortIndicator != -1);
|
|
phdr->InsertItem(m_icolSortIndicator, &item);
|
|
}
|
|
}
|
|
|
|
if (bNone) {
|
|
return;
|
|
}
|
|
|
|
|
|
// At this point, the previous sort indicator has been
|
|
// removed. Now insert a new one.
|
|
item.pszText = szTitle;
|
|
item.cchTextMax = sizeof(szTitle) - 1;
|
|
|
|
|
|
sTitle.Empty();
|
|
item.mask = HDI_TEXT | HDI_WIDTH | HDI_FORMAT | HDI_LPARAM;
|
|
item.fmt = HDF_LEFT;
|
|
phdr->GetItem(iCol, &item);
|
|
|
|
|
|
item.mask = HDI_TEXT | HDI_FORMAT | HDI_LPARAM;
|
|
item.cchTextMax = _tcslen(szTitle);
|
|
|
|
phdr->DeleteItem(iCol);
|
|
CBitmap* pbm = NULL;
|
|
|
|
if (!bNone) {
|
|
item.mask = item.mask | HDI_BITMAP;
|
|
item.fmt = item.fmt | HDF_BITMAP_ON_RIGHT;
|
|
|
|
if (bAscending) {
|
|
item.hbm = (HBITMAP) m_bmAscendingIndicator;
|
|
}
|
|
else {
|
|
item.hbm = (HBITMAP) m_bmDescendingIndicator;
|
|
}
|
|
}
|
|
|
|
int iColInsert = phdr->InsertItem(iCol, &item);
|
|
m_icolSortIndicator = iCol;
|
|
phdr->RedrawWindow();
|
|
|
|
}
|
|
|
|
|
|
//***********************************************************
|
|
// CGrid::OnCellDoubleClicked
|
|
//
|
|
// This is the default handler for double clicking a cell. It
|
|
// does nothing, but derived classes can override this method
|
|
// to do something more interesting.
|
|
//
|
|
// Parameters:
|
|
// int iRow
|
|
// The row index of the cell that was double clicked.
|
|
//
|
|
// int iCol
|
|
// The column index of the cell that was double clicked.
|
|
//
|
|
// Returns:
|
|
// Nothing.
|
|
//
|
|
//************************************************************
|
|
void CGrid::OnCellDoubleClicked(int iRow, int iCol)
|
|
{
|
|
}
|
|
|
|
|
|
//***********************************************************
|
|
// CGrid::OnRowHandleDoubleClicked
|
|
//
|
|
// This is the default handler for double clicking a row handle. It
|
|
// does nothing, but derived classes can override this method
|
|
// to do something more interesting.
|
|
//
|
|
// Parameters:
|
|
// int iRow
|
|
// The row index of the cell that was double clicked.
|
|
//
|
|
// Returns:
|
|
// Nothing.
|
|
//
|
|
//************************************************************
|
|
void CGrid::OnRowHandleDoubleClicked(int iRow)
|
|
{
|
|
}
|
|
|
|
|
|
|
|
//***********************************************************
|
|
// CGrid::OnRowhandleClicked
|
|
//
|
|
// This is the default handler for clicking a row handle. It
|
|
// does nothing, but derived classes can override this method
|
|
// to do something more interesting.
|
|
//
|
|
// Parameters:
|
|
// int iRow
|
|
// The row index of the cell that was double clicked.
|
|
//
|
|
// Returns:
|
|
// Nothing.
|
|
//
|
|
//************************************************************
|
|
void CGrid::OnRowHandleClicked(int iRow)
|
|
{
|
|
}
|
|
|
|
|
|
|
|
//***********************************************************
|
|
// CGrid::OnShowWindow
|
|
//
|
|
// Handle the ShowWindow command. Since CGrid contains two sibling
|
|
// windows (CGridCore and CHeaderCtrl) it is necessary to pass
|
|
// the ShowWindow command on to both siblings.
|
|
//
|
|
// Parameters:
|
|
// See the MFC documentation for CWnd::ShowWindow
|
|
//
|
|
// Returns:
|
|
// Nothing.
|
|
//
|
|
//************************************************************
|
|
void CGrid::OnShowWindow(BOOL bShow, UINT nStatus)
|
|
{
|
|
CWnd::OnShowWindow(bShow, nStatus);
|
|
|
|
int nShowCmd = bShow ? SW_SHOW : SW_HIDE;
|
|
|
|
if (m_pcore->m_hWnd) {
|
|
m_pcore->ShowWindow(nShowCmd);
|
|
}
|
|
|
|
if (m_phdr->m_hWnd) {
|
|
m_phdr->ShowWindow(nShowCmd);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//***********************************************************
|
|
// CGrid::OnSize
|
|
//
|
|
// Handle the WM_SIZE command. Since CGrid contains two sibling
|
|
// windows (CGridCore and CHeaderCtrl) it is necessary to pass
|
|
// the WM_SIZE command on to both siblings.
|
|
//
|
|
// Parameters:
|
|
// See the MFC documentation for CWnd::OnSize
|
|
//
|
|
// Returns:
|
|
// Nothing.
|
|
//
|
|
//************************************************************
|
|
void CGrid::OnSize(UINT nType, int cx, int cy)
|
|
{
|
|
CWnd::OnSize(nType, cx, cy);
|
|
SizeChildren();
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
// CGrid::GetColumnPos
|
|
//
|
|
// Get the position of the left edge of the specified column.
|
|
//
|
|
// Parameters:
|
|
// int iCol
|
|
// The index of the desired column.
|
|
//
|
|
// Returns:
|
|
// The position of the left edge of the column.
|
|
//
|
|
//******************************************************************
|
|
int CGrid::GetColumnPos(int iCol)
|
|
{
|
|
int ix = 0;
|
|
for (int iLoop=0; iLoop < iCol; ++iLoop) {
|
|
ix += ColWidth(iLoop);
|
|
}
|
|
return ix;
|
|
}
|
|
|
|
|
|
|
|
|
|
//*****************************************************************
|
|
// CGrid::SizeChildren
|
|
//
|
|
// Size the child windows of this grid.
|
|
//
|
|
// Parameters:
|
|
// None.
|
|
//
|
|
// Returns:
|
|
// Nothing.
|
|
//
|
|
//*****************************************************************
|
|
void CGrid::SizeChildren()
|
|
{
|
|
CRect rcClient;
|
|
GetClientRect(rcClient);
|
|
|
|
int cx = rcClient.Width();
|
|
int cy = rcClient.Height();
|
|
|
|
|
|
// At this point in time, we haven't decided whether the row handles
|
|
// should go in the CGrid or CGridCore, but regardless of where they
|
|
// are drawn, we want to have the corner stub.
|
|
int cxRowHandles = m_cxRowHandles;
|
|
if (cxRowHandles == 0) {
|
|
cxRowHandles = m_pcore->GetRowHandleWidth();
|
|
}
|
|
|
|
// Adjust the width of the header control, but not its height
|
|
CRect rc(0, 0, cx, CY_HEADER);
|
|
if (m_phdr->m_hWnd) {
|
|
CRect rcHeader;
|
|
rcHeader.left = cxRowHandles;
|
|
rcHeader.right = rcClient.right;
|
|
rcHeader.top = 0;
|
|
rcHeader.bottom = CY_HEADER;
|
|
|
|
m_phdr->MoveWindow(rcHeader);
|
|
m_phdr->OnGridSizeChanged();
|
|
}
|
|
|
|
// Adjust the size of the CGridCore window to be the entire client
|
|
// area minus the rectangle consumed by the header control.
|
|
rc.top = rc.bottom - CY_BORDER_MERGE;
|
|
rc.bottom = cy;
|
|
rc.left = m_cxRowHandles;
|
|
if (m_pcore->m_hWnd) {
|
|
m_pcore->MoveWindow(rc);
|
|
}
|
|
}
|
|
|
|
//*************************************************************
|
|
// CGrid::OnCellFocusChange
|
|
//
|
|
// This is a virtual method that may be overridden in derived
|
|
// classes to catch the "focus" change event.
|
|
//
|
|
// Parameters:
|
|
// [in] int iRow
|
|
// The row index of the affected cell.
|
|
//
|
|
// [in] int iCol
|
|
// The column index of the affected cell.
|
|
//
|
|
// [in] int iNextRow
|
|
// The next row that will be selected. This parameter is provided
|
|
// as a hint and is valid only if bGotFocus is FALSE.
|
|
//
|
|
// [in] int iNextCol
|
|
// The column index of the next cell that will get the focus when the
|
|
// current cell is loosing focus. This parameter is provided as a hint and
|
|
// is valid only if bGotFocus is FALSE.
|
|
//
|
|
// [in] BOOL bGotFocus
|
|
// TRUE if focus is being changed to the specified cell.
|
|
// FALSE if this is a request for the current cell to
|
|
// release the focus.
|
|
//
|
|
// Returns:
|
|
// If bGotFocus is TRUE, then return TRUE to allow the focus to
|
|
// be set to the new cell or return FALSE to prevent the focus
|
|
// from being set to the new cell.
|
|
//
|
|
// If bGotFocus is FALSE, then this is a request to release the
|
|
// focus from the specified cell. Return TRUE to allow the specified
|
|
// cell to loose the focus. Return FALSE to prevent the specified cell
|
|
// from loosing the focus.
|
|
//
|
|
//*******************************************************************
|
|
BOOL CGrid::OnCellFocusChange(int iRow, int iCol, int iNextRow, int iNextCol, BOOL bGotFocus)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void CGrid::SetHeaderScrollOffset(int iCol, int cxOffset)
|
|
{
|
|
// Adjust the width of the header control, but not its height
|
|
int dxScroll = cxOffset + m_cxHeaderScrollOffset;
|
|
m_cxHeaderScrollOffset = cxOffset;
|
|
if (m_phdr->m_hWnd) {
|
|
m_phdr->SetScrollOffset(iCol, cxOffset);
|
|
m_phdr->UpdateWindow();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//******************************************************************
|
|
// CGrid::PointToCell
|
|
//
|
|
// Convert a point in CGrid's client coordinates to corresponding
|
|
// grid cell's coordinates.
|
|
//
|
|
// Parameters:
|
|
// [in] CPoint pt
|
|
// The point in CGrid's client coordinate space.
|
|
//
|
|
// [out] int& iRow
|
|
// The place where the cell's row index is returned.
|
|
//
|
|
// [out] int& iCol
|
|
// The place where the cell's column index is returned.
|
|
//
|
|
// Returns:
|
|
// TRUE if the point hit a cell, otherwise FALSE.
|
|
//
|
|
//*******************************************************************
|
|
BOOL CGrid::PointToCell(CPoint pt, int& iRow, int& iCol)
|
|
{
|
|
// GridCore's version of PointToCell works in its own client
|
|
// coordinates, so we need to offset the vertical coordinate
|
|
// to account for the space consumed by CGrid's header control.
|
|
pt.y = pt.y - ( CY_HEADER + CY_BORDER_MERGE );
|
|
|
|
|
|
return m_pcore->PointToCell(pt, iRow, iCol);
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
// CGrid::PointToRow
|
|
//
|
|
// Convert a point in CGrid's client coordinates to corresponding
|
|
// row index.
|
|
//
|
|
// Parameters:
|
|
// [in] CPoint pt
|
|
// The point in CGrid's client coordinate space.
|
|
//
|
|
// [out] int& iRow
|
|
// The place where the row index is returned.
|
|
//
|
|
//
|
|
// Returns:
|
|
// TRUE if the point hit a row, otherwise FALSE.
|
|
//
|
|
//*******************************************************************
|
|
BOOL CGrid::PointToRow(CPoint pt, int& iRow)
|
|
{
|
|
// GridCore's version of PointToRow works in its own client
|
|
// coordinates, so we need to offset the vertical coordinate
|
|
// to account for the space consumed by CGrid's header control.
|
|
pt.y = pt.y - ( CY_HEADER + CY_BORDER_MERGE );
|
|
|
|
|
|
return m_pcore->PointToRow(pt, iRow);
|
|
}
|
|
|
|
|
|
|
|
//******************************************************************
|
|
// CGrid::PointToRowHandle
|
|
//
|
|
// Convert a point in CGrid's client coordinates to corresponding
|
|
// row handle index.
|
|
//
|
|
// Parameters:
|
|
// [in] CPoint pt
|
|
// The point in CGrid's client coordinate space.
|
|
//
|
|
// [out] int& iRow
|
|
// The place where the row index is returned.
|
|
//
|
|
//
|
|
// Returns:
|
|
// TRUE if the point hit a row handle, otherwise FALSE.
|
|
//
|
|
//*******************************************************************
|
|
BOOL CGrid::PointToRowHandle(CPoint pt, int& iRow)
|
|
{
|
|
// GridCore's version of PointToHandle works in its own client
|
|
// coordinates, so we need to offset the vertical coordinate
|
|
// to account for the space consumed by CGrid's header control.
|
|
pt.y = pt.y - ( CY_HEADER + CY_BORDER_MERGE );
|
|
|
|
|
|
return m_pcore->PointToRowHandle(pt, iRow);
|
|
}
|
|
|
|
|
|
//********************************************************************
|
|
// CGrid::DrawCornerStub
|
|
//
|
|
// Draw the "stub" in the top-left corner of the window when row handles
|
|
// are displayed.
|
|
//
|
|
// Parameters:
|
|
// CDC* pdc
|
|
// Pointer to the display context.
|
|
//
|
|
// Returns:
|
|
// Nothing.
|
|
//
|
|
//*******************************************************************
|
|
void CGrid::DrawCornerStub(CDC* pdc)
|
|
{
|
|
// Check to see if the grid has row handles. If so, draw the little rectangle
|
|
// at the top left corner that is bordered on the right by the grid header and
|
|
// bordered on the bottom by the row handles.
|
|
|
|
int cxRowHandles = m_cxRowHandles;
|
|
if (cxRowHandles == 0) {
|
|
cxRowHandles = m_pcore->GetRowHandleWidth();
|
|
}
|
|
if (cxRowHandles == 0) {
|
|
return;
|
|
}
|
|
|
|
|
|
CRect rcFill;
|
|
CBrush br3DSHADOW(GetSysColor(COLOR_3DSHADOW));
|
|
CBrush br3DFACE(GetSysColor(COLOR_3DFACE));
|
|
CBrush br3DHILIGHT(GetSysColor(COLOR_3DHILIGHT));
|
|
|
|
// Draw a two-pixel 3D highlight along the top edge.
|
|
rcFill.left = 0;
|
|
rcFill.right = cxRowHandles - 1;
|
|
rcFill.top = 0;
|
|
rcFill.bottom = 2;
|
|
pdc->FillRect(rcFill, &br3DHILIGHT);
|
|
|
|
// Draw a two-pixel 3D highlight along the left edge.
|
|
rcFill.left = 0;
|
|
rcFill.right = 2;
|
|
rcFill.top = 0;
|
|
rcFill.bottom = CY_HEADER - 1;
|
|
pdc->FillRect(rcFill, &br3DHILIGHT);
|
|
|
|
|
|
// Fill the face of the button.
|
|
rcFill.left = 2;
|
|
rcFill.right = cxRowHandles - 2;
|
|
rcFill.top = 2;
|
|
rcFill.bottom = CY_FONT - 2;
|
|
pdc->FillRect(rcFill, &br3DFACE);
|
|
|
|
// Draw a one-pixel shadow on the bottom edge.
|
|
rcFill.left = 2;
|
|
rcFill.right = cxRowHandles - 1;
|
|
rcFill.top = CY_FONT - 2;
|
|
rcFill.bottom = CY_FONT - 1;
|
|
pdc->FillRect(rcFill, &br3DSHADOW);
|
|
|
|
rcFill.left = 1;
|
|
rcFill.right = cxRowHandles - 1;
|
|
rcFill.top = CY_FONT - 1;
|
|
rcFill.bottom = CY_FONT;
|
|
pdc->FillRect(rcFill, &br3DSHADOW);
|
|
|
|
|
|
// Draw a one-pixel shadow on the right edge.
|
|
rcFill.left = cxRowHandles - 3;
|
|
rcFill.right = cxRowHandles - 2;
|
|
rcFill.top = 2;
|
|
rcFill.bottom = CY_FONT - 2;
|
|
pdc->FillRect(rcFill, &br3DSHADOW);
|
|
|
|
// Draw the second vertical part of the shadow on the right.
|
|
rcFill.left = cxRowHandles - 2;
|
|
rcFill.right = cxRowHandles - 1;
|
|
rcFill.top = 1;
|
|
rcFill.bottom = CY_FONT - 1;
|
|
pdc->FillRect(rcFill, &br3DSHADOW);
|
|
|
|
|
|
// Draw a one-pixel black border on the right edge.
|
|
rcFill.left = cxRowHandles - 1;
|
|
rcFill.right = cxRowHandles;
|
|
rcFill.top = 0;
|
|
rcFill.bottom = CY_FONT;
|
|
pdc->FillRect(rcFill, CBrush::FromHandle((HBRUSH)GetStockObject(BLACK_BRUSH)));
|
|
|
|
|
|
// Draw a one-pixel black border on the bottom edge.
|
|
rcFill.left = 0;
|
|
rcFill.right = cxRowHandles;
|
|
rcFill.top = CY_FONT;
|
|
rcFill.bottom = CY_FONT + 1;
|
|
pdc->FillRect(rcFill, CBrush::FromHandle((HBRUSH)GetStockObject(BLACK_BRUSH)));
|
|
}
|
|
|
|
|
|
//********************************************************************
|
|
// CGrid::DrawRowhandles
|
|
//
|
|
// Draw the row handles along the left side of the grid.
|
|
//
|
|
// Parameters:
|
|
// CDC* pdc
|
|
// Pointer to the display context.
|
|
//
|
|
// Returns:
|
|
// Nothing.
|
|
//
|
|
//*******************************************************************
|
|
void CGrid::DrawRowHandles(CDC* pdc)
|
|
{
|
|
// If there are no row handles, do nothing.
|
|
int cxHandle = m_cxRowHandles;
|
|
if (cxHandle <= 0) {
|
|
return;
|
|
}
|
|
|
|
// If the row doesn't have a height, do nothing.
|
|
int cyRow = m_pcore->RowHeight();
|
|
if (cyRow <= 0) {
|
|
return;
|
|
}
|
|
|
|
|
|
CRect rcClient;
|
|
GetClientRect(rcClient);
|
|
|
|
|
|
CRect rcClientChild;
|
|
m_pcore->GetClientRect(rcClientChild);
|
|
|
|
CRect rcRowHandles;
|
|
GetClientRect(rcRowHandles);
|
|
rcRowHandles.top += CY_HEADER;
|
|
rcRowHandles.right = m_cxRowHandles;
|
|
rcRowHandles.bottom = rcRowHandles.top + rcClientChild.Height();
|
|
|
|
pdc->IntersectClipRect(rcRowHandles);
|
|
|
|
// If the row handles are completely clipped out, then do nothing.
|
|
CRect rcPaint;
|
|
if (pdc->GetClipBox(rcPaint) != NULLREGION ) {
|
|
// The top and bottom of the paint rectangle need to be aligned with the top and
|
|
// bottom edges of partially obscured row handles.
|
|
rcPaint.top = ((rcPaint.top - CY_HEADER) / cyRow) * cyRow + CY_HEADER;
|
|
rcPaint.bottom = ((rcPaint.bottom - CY_HEADER) + (cyRow - 1))/cyRow * cyRow + CY_HEADER;
|
|
}
|
|
else {
|
|
rcPaint = rcRowHandles;
|
|
}
|
|
|
|
// Draw the vertical line on the right that separates the row handles from
|
|
// the data.
|
|
CRect rcFill;
|
|
rcFill.left = rcRowHandles.right - 1;
|
|
rcFill.right = rcRowHandles.right;
|
|
rcFill.top = rcRowHandles.top;
|
|
rcFill.bottom = rcRowHandles.bottom;
|
|
pdc->FillRect(rcFill, CBrush::FromHandle((HBRUSH)GetStockObject(BLACK_BRUSH)));
|
|
|
|
|
|
// Define a rectangle for a handle that slides from the top to
|
|
// the bottom of the stack of row handles as they are drawn.
|
|
CRect rcHandle(rcRowHandles);
|
|
rcHandle.top = rcRowHandles.top;
|
|
rcHandle.bottom = rcHandle.top + cyRow;
|
|
|
|
|
|
CBrush br3DSHADOW(GetSysColor(COLOR_3DSHADOW));
|
|
CBrush br3DFACE(GetSysColor(COLOR_3DFACE));
|
|
CBrush br3DHILIGHT(GetSysColor(COLOR_3DHILIGHT));
|
|
|
|
|
|
int nHandles = rcPaint.Height() / cyRow;
|
|
|
|
while (--nHandles >= 0) {
|
|
|
|
// The horizontal divider at the bottom of the row handle.
|
|
rcFill.left = rcHandle.left;
|
|
rcFill.right = rcHandle.right;
|
|
rcFill.top = rcHandle.bottom - 1;
|
|
rcFill.bottom = rcHandle.bottom;
|
|
pdc->FillRect(rcFill, CBrush::FromHandle((HBRUSH)GetStockObject(BLACK_BRUSH)));
|
|
|
|
|
|
// The horizontal highlight across the top of the row handle.
|
|
rcFill.left = rcHandle.left;
|
|
rcFill.right = rcHandle.right - 1;
|
|
rcFill.top = rcHandle.top;
|
|
rcFill.bottom = rcHandle.top + 1;
|
|
pdc->FillRect(rcFill, &br3DHILIGHT);
|
|
|
|
// The vertical highlight on the left of the row handle.
|
|
rcFill.left = rcHandle.left;
|
|
rcFill.right = rcHandle.left + 1;
|
|
rcFill.top = rcHandle.top + 1;
|
|
rcFill.bottom = rcHandle.bottom - 1;
|
|
pdc->FillRect(rcFill, &br3DHILIGHT);
|
|
|
|
|
|
// The face of the row handle.
|
|
rcFill.left = rcHandle.left + 1;
|
|
rcFill.right = rcHandle.right - 1;
|
|
rcFill.top = rcHandle.top + 1;
|
|
rcFill.bottom = rcHandle.bottom - 1;
|
|
pdc->FillRect(rcFill, &br3DFACE);
|
|
|
|
// Increment to the next row.
|
|
rcHandle.top += cyRow;
|
|
rcHandle.bottom += cyRow;
|
|
}
|
|
|
|
|
|
// don't clip.
|
|
pdc->SelectClipRgn(NULL, RGN_COPY);
|
|
|
|
|
|
// If the CGridCore displays a horizontal scroll bar, then the
|
|
// CGrid must fill in the "empty" area just to the left of the
|
|
// horizontal scroll bar.
|
|
//
|
|
// The CGridCore displays the horizontal scroll bar, then the
|
|
// height of m_GridCore will be less that the height of the
|
|
// client area plus the header height.
|
|
int cyHScrollBarChild = (rcClient.Height() - CY_HEADER) - rcClientChild.Height();
|
|
if (cyHScrollBarChild <= 0) {
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
// CBrush brScrollBar(GetSysColor(COLOR_SCROLLBAR));
|
|
CRect rcStub;
|
|
|
|
|
|
rcStub.left = 0;
|
|
rcStub.right = m_cxRowHandles;
|
|
rcStub.bottom = rcClient.bottom;
|
|
rcStub.top = rcClient.bottom - cyHScrollBarChild;
|
|
pdc->FillRect(rcStub, &br3DFACE);
|
|
|
|
rcFill.top = rcStub.top;
|
|
rcFill.left = rcStub.left;
|
|
rcFill.right = rcStub.right;
|
|
rcFill.bottom = rcStub.top + 1;
|
|
pdc->FillRect(rcFill, CBrush::FromHandle((HBRUSH)GetStockObject(BLACK_BRUSH)));
|
|
|
|
|
|
rcFill.top = rcStub.top;
|
|
rcFill.bottom = rcStub.bottom;
|
|
rcFill.left = rcStub.right - 1;
|
|
rcFill.right = rcStub.right;
|
|
pdc->FillRect(rcFill, CBrush::FromHandle((HBRUSH)GetStockObject(BLACK_BRUSH)));
|
|
|
|
// The dark gray line on the left
|
|
rcFill.top = rcStub.top + 3;
|
|
rcFill.bottom = rcStub.bottom - 2;
|
|
rcFill.left = rcStub.left + 2;
|
|
rcFill.right = rcStub.left + 3;
|
|
pdc->FillRect(rcFill, &br3DSHADOW);
|
|
|
|
|
|
// The dark gray line on the top
|
|
rcFill.top = rcStub.top + 3;
|
|
rcFill.bottom = rcStub.top + 4;
|
|
rcFill.left = rcStub.left + 1;
|
|
rcFill.right = rcStub.right - 2;
|
|
pdc->FillRect(rcFill, &br3DSHADOW);
|
|
|
|
// The highlight on the bottom
|
|
rcFill.top = rcStub.bottom - 3;
|
|
rcFill.bottom = rcStub.bottom - 2;
|
|
rcFill.left = rcStub.left + 2;
|
|
rcFill.right = rcStub.right - 2;;
|
|
pdc->FillRect(rcFill, &br3DHILIGHT);
|
|
|
|
// The highlight on the right
|
|
rcFill.top = rcStub.top + 2;
|
|
rcFill.bottom = rcStub.bottom - 2;
|
|
rcFill.left = rcStub.right - 4;
|
|
rcFill.right = rcStub.right - 3;;
|
|
pdc->FillRect(rcFill, &br3DHILIGHT);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//******************************************************************
|
|
// CGrid::ColumnIsAscending
|
|
//
|
|
// Return the sort order flag for the specified column.
|
|
//
|
|
// Parameters:
|
|
// [in] const int iCol
|
|
// The index of the desired column.
|
|
//
|
|
// Returns:
|
|
// BOOL
|
|
// TRUE if the specified column's sort order is ascending, FALSE
|
|
// if it is descending.
|
|
//
|
|
//******************************************************************
|
|
//
|
|
BOOL CGrid::ColumnIsAscending(const int iCol) const
|
|
{
|
|
ASSERT(iCol>= 0 && iCol < m_aSortAscending.GetSize());
|
|
if (iCol <0 || iCol >= m_aSortAscending.GetSize()) {
|
|
return TRUE;
|
|
}
|
|
|
|
return m_aSortAscending[iCol];
|
|
}
|
|
|
|
|
|
|
|
//****************************************************************
|
|
// CGrid::SetSortDirection
|
|
//
|
|
// Set the sort direction for the given column. Note that this does
|
|
// not actually resort any of the grid rows. To resort the grid, you
|
|
// must call SortGrid.
|
|
//
|
|
// Parameters:
|
|
// const int iCol
|
|
// The column who's sort order flag will be changed.
|
|
//
|
|
// const BOOL bSortAscending
|
|
// TRUE to set the sort direction for the column to ascending,
|
|
// FALSE to set the sort direction to descending.
|
|
//
|
|
// Returns:
|
|
// Nothing.
|
|
//
|
|
//******************************************************************
|
|
void CGrid::SetSortDirection(const int iCol, const BOOL bSortAscending)
|
|
{
|
|
ASSERT( iCol >=0 && iCol < m_aSortAscending.GetSize());
|
|
if (iCol < 0 || iCol >= m_aSortAscending.GetSize()) {
|
|
return;
|
|
}
|
|
|
|
m_aSortAscending[iCol] = (WORD) bSortAscending;
|
|
}
|
|
|
|
|
|
|
|
//*******************************************************************
|
|
// CGrid::ClearAllSortDirectionFlags
|
|
//
|
|
// Clears the sort direction flags for all of the columns. The
|
|
// sort order for each column is set to ascending. Note that this
|
|
// changes the state of the sort order flags, but does not resort the
|
|
// grid. Call SortGrid to resort the grid.
|
|
//
|
|
// Parameters:
|
|
// None.
|
|
//
|
|
// Returns:
|
|
// Nothing.
|
|
//
|
|
//*******************************************************************
|
|
void CGrid::ClearAllSortDirectionFlags()
|
|
{
|
|
INT_PTR nFlags = m_aSortAscending.GetSize();
|
|
for (INT_PTR iFlag=0; iFlag<nFlags; ++iFlag) {
|
|
m_aSortAscending[iFlag] = TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//********************************************************************
|
|
// CGrid::SortGrid
|
|
//
|
|
// Sort the specified rows of the grid using the current sor order for the
|
|
// specified column.
|
|
//
|
|
// Parameters:
|
|
// [in] int iRowFirst
|
|
// The first row in the range of rows to sort.
|
|
//
|
|
// [in] int iRowLast
|
|
// The last row in the range of rows to sort.
|
|
//
|
|
// [in] int iSortColumn
|
|
// The index of the column to use as the primary sort key.
|
|
//
|
|
// [in] BOOL bRedrawWindow=FALSE
|
|
// TRUE to redraw the window.
|
|
//
|
|
// Returns:
|
|
// Nothing.
|
|
//
|
|
//*********************************************************************
|
|
void CGrid::SortGrid(int iRowFirst, int iRowLast, int iSortColumn, BOOL bRedrawWindow)
|
|
{
|
|
m_phdr->Header().SelectColumn(iSortColumn);
|
|
BOOL bColumnIsAscending = ColumnIsAscending(iSortColumn);
|
|
m_pcore->SortGrid(iRowFirst, iRowLast, iSortColumn, bColumnIsAscending, bRedrawWindow);
|
|
}
|
|
|
|
|
|
//*******************************************************************
|
|
// CGrid::CompareCells
|
|
//
|
|
// This method compares two cells in different rows but the same column.
|
|
//
|
|
// Parameters:
|
|
// int iRow1
|
|
// The row index of the first cell.
|
|
//
|
|
// int iCol1
|
|
// The column index of the first cell.
|
|
//
|
|
// int iRow2
|
|
// The row index of the second row.
|
|
//
|
|
// int iCol2
|
|
// The column index of the second cell.
|
|
//
|
|
// Returns:
|
|
// >0 if row 1 is greater than row 2
|
|
// 0 if row 1 equal zero
|
|
// <0 if row 1 is less than zero.
|
|
//
|
|
//********************************************************************
|
|
int CGrid::CompareCells(int iRow1, int iCol1, int iRow2, int iCol2)
|
|
{
|
|
CGridCell* pgc1 = &GetAt(iRow1, iCol1);
|
|
CGridCell* pgc2 = &GetAt(iRow2, iCol2);
|
|
|
|
int iResult = pgc1->Compare(pgc2);
|
|
return iResult;
|
|
|
|
#if 0
|
|
CString sValue1;
|
|
CString sValue2;
|
|
int iResult;
|
|
|
|
VARTYPE vt1;
|
|
VARTYPE vt2;
|
|
GetAt(iRow1, iCol1).GetValue(sValue1, vt1);
|
|
GetAt(iRow2, iCol2).GetValue(sValue2, vt2);
|
|
iResult = sValue1.Compare(sValue2);
|
|
if (iResult == 0) {
|
|
iResult = vt1 > vt2;
|
|
}
|
|
#endif //0
|
|
|
|
return iResult;
|
|
}
|
|
|
|
|
|
|
|
void CGrid::OnPaint()
|
|
{
|
|
CPaintDC dc(this); // device context for painting
|
|
|
|
DrawCornerStub(&dc);
|
|
DrawRowHandles(&dc);
|
|
|
|
// Do not call CWnd::OnPaint() for painting messages
|
|
}
|
|
|
|
|
|
|
|
//**********************************************************
|
|
// CGrid::RedrawRow
|
|
//
|
|
// Redraw the specified row of the grid.
|
|
//
|
|
// Parameters:
|
|
// [in] int iRow
|
|
// The row index.
|
|
//
|
|
// Returns:
|
|
// Nothing.
|
|
//
|
|
//**********************************************************
|
|
void CGrid::RedrawRow(int iRow)
|
|
{
|
|
ASSERT(iRow < GetRows());
|
|
|
|
CGridRow& row = GetRowAt(iRow);
|
|
row.Redraw();
|
|
}
|
|
|
|
//**********************************************************
|
|
// CGrid::RedrawCell
|
|
//
|
|
// Redraw the specified grid cell.
|
|
//
|
|
// Parameters:
|
|
// [in] int iRow
|
|
// The row index.
|
|
//
|
|
// [in] iCol
|
|
// The column index.
|
|
//
|
|
// Returns:
|
|
// Nothing.
|
|
//
|
|
//**********************************************************
|
|
void CGrid::RedrawCell(int iRow, int iCol)
|
|
{
|
|
if (!::IsWindow(m_hWnd)) {
|
|
return;
|
|
}
|
|
|
|
m_pcore->DrawCell(iRow, iCol);
|
|
}
|
|
|
|
|
|
|
|
|
|
void CGrid::SetColumnWidth(int iCol, int cx, BOOL bRedraw)
|
|
{
|
|
m_phdr->Header().SetColumnWidth(iCol, cx, FALSE);
|
|
m_pcore->SetColumnWidth(iCol, cx, FALSE);
|
|
if (bRedraw && (m_hWnd!=NULL)) {
|
|
RedrawWindow();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//************************************************************************
|
|
// CGrid::PreTranslateMessage
|
|
//
|
|
// PreTranslateMessage is hooked out to detect the OnContextMenu event.
|
|
//
|
|
// Parameters:
|
|
// See the MFC documentation.
|
|
//
|
|
// Returns:
|
|
// TRUE if the message is handled here.
|
|
//
|
|
//*************************************************************************
|
|
BOOL CGrid::PreTranslateMessage(MSG* pMsg)
|
|
{
|
|
// CG: This block was added by the Pop-up Menu component
|
|
{
|
|
// Shift+F10: show pop-up menu.
|
|
if ((((pMsg->message == WM_KEYDOWN || pMsg->message == WM_SYSKEYDOWN) && // If we hit a key and
|
|
(pMsg->wParam == VK_F10) && (GetKeyState(VK_SHIFT) & ~1)) != 0) || // it's Shift+F10 OR
|
|
(pMsg->message == WM_CONTEXTMENU)) // Natural keyboard key
|
|
{
|
|
CRect rect;
|
|
GetClientRect(rect);
|
|
ClientToScreen(rect);
|
|
|
|
CPoint point = rect.TopLeft();
|
|
point.Offset(5, 5);
|
|
OnContextMenu(NULL, point);
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return CWnd::PreTranslateMessage(pMsg);
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
//***************************************************************
|
|
// CGrid::FindCellPosition
|
|
//
|
|
// Given a cell pointer, find its row and column indexes. This is
|
|
// required because the cell has no other way to directly determine
|
|
// its position.
|
|
//
|
|
// Parameters:
|
|
// [in] CGridCell* pgc
|
|
// Pointer to the grid cell to find.
|
|
//
|
|
// [out] int& iRow
|
|
// The row index of the cell if found, NULL_INDEX if the
|
|
// cell is not found.
|
|
//
|
|
// [out] int& iCol
|
|
// The column index of the cell if found, NULL_INDEX if the cell
|
|
// is not found.
|
|
//
|
|
// Returns:
|
|
// The row and column indexes of the cell by reference.
|
|
//
|
|
//***************************************************************
|
|
void CGrid::FindCellPosition(CGridCell* pgc, int& iRow, int& iCol)
|
|
{
|
|
pgc->FindCellPos(iRow, iCol);
|
|
|
|
}
|
|
|
|
#endif //0
|
|
|
|
|
|
|
|
BOOL CGrid::NumberRows(BOOL bNumberRows, BOOL bRedraw)
|
|
{
|
|
BOOL bWasNumberingRows = m_pcore->NumberRows(bNumberRows, FALSE);
|
|
if (bRedraw && m_hWnd!=NULL) {
|
|
RedrawWindow();
|
|
}
|
|
return bWasNumberingRows;
|
|
}
|
|
|
|
BOOL CGrid::IsNumberingRows()
|
|
{
|
|
return m_pcore->IsNumberingRows();
|
|
}
|
|
|
|
|
|
|
|
|
|
CFont& CGrid::GetGridFont()
|
|
{
|
|
return m_pcore->GetFont();
|
|
}
|
|
|
|
|
|
void CGrid::NotifyRowHandleWidthChanged()
|
|
{
|
|
SizeChildren();
|
|
|
|
}
|
|
|
|
|
|
void CGrid::OnGetIWbemServices(LPCTSTR szNamespace, VARIANT FAR* pvarUpdatePointer, VARIANT FAR* pvarServices, VARIANT FAR* pvarSc, VARIANT FAR* pvarUserCancel)
|
|
{
|
|
// Do nothing unless this virtual function is overridden. If nothing is done
|
|
// it just means that no one was listening to the event.
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
//*******************************************************
|
|
// CGrid::EditCellObject
|
|
//
|
|
// Edit a cell containing an embedded object.
|
|
//
|
|
// Parameters:
|
|
// [in] CGridCell* pgc
|
|
// The grid cell to edit.
|
|
//
|
|
// [in] int iRow
|
|
// The row index of the cell to edit.
|
|
//
|
|
// [in] int iCol
|
|
// The column index of the cell to edit.
|
|
//
|
|
// Returns:
|
|
// Nothing.
|
|
//
|
|
//********************************************************
|
|
void CGrid::EditCellObject(CGridCell* pgc, int iRow, int iCol)
|
|
{
|
|
|
|
}
|
|
|
|
|
|
//*******************************************************
|
|
// CGrid::EditCellObject
|
|
//
|
|
// Edit a cell containing an embedded object.
|
|
//
|
|
// Parameters:
|
|
// [in] int iRow
|
|
// The row index of the cell to edit.
|
|
//
|
|
// [in] int iCol
|
|
// The column index of the cell to edit.
|
|
//
|
|
// Returns:
|
|
// Nothing.
|
|
//
|
|
//********************************************************
|
|
void CGrid::OnChangedCimtype(int iRow, int iCol)
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
//*******************************************************
|
|
// CGrid::OnRequestUIActive()
|
|
//
|
|
// Notify the derived class that there is a request to
|
|
// become UI active.
|
|
//
|
|
// Parameters:
|
|
// None.
|
|
//
|
|
// Returns:
|
|
// Nothing.
|
|
//
|
|
//********************************************************
|
|
void CGrid::OnRequestUIActive()
|
|
{
|
|
}
|
|
|
|
void CGrid::OnSetFocus(CWnd* pOldWnd)
|
|
{
|
|
CWnd::OnSetFocus(pOldWnd);
|
|
|
|
// TODO: Add your message handler code here
|
|
if (!m_bUIActive)
|
|
{
|
|
m_bUIActive = TRUE;
|
|
OnRequestUIActive();
|
|
if (m_pcore && ::IsWindow(m_pcore->m_hWnd)) {
|
|
m_pcore->SetFocus();
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
void CGrid::OnKillFocus(CWnd* pNewWnd)
|
|
{
|
|
CWnd::OnKillFocus(pNewWnd);
|
|
|
|
// TODO: Add your message handler code here
|
|
m_bUIActive = FALSE;
|
|
|
|
}
|
|
|
|
|
|
//**********************************************************
|
|
// CGrid::GetCellEnumStrings
|
|
//
|
|
// The cell editor calls this method to get any enumeration
|
|
// strings that should be displayed for the grid cell in a
|
|
// drop-down combo.
|
|
//
|
|
// Parameters:
|
|
// [in] int iRow
|
|
// The cell's row index.
|
|
//
|
|
// [in] int iCol
|
|
// The cell's column index.
|
|
//
|
|
// [out] CStringArray& sa
|
|
// The enumeration strings are returned in this string array.
|
|
//
|
|
// Returns;
|
|
// Nothing.
|
|
//
|
|
//***********************************************************
|
|
void CGrid::GetCellEnumStrings(int iRow, int iCol, CStringArray& sa)
|
|
{
|
|
sa.RemoveAll();
|
|
}
|
|
|
|
|
|
//**********************************************************
|
|
// CGrid::OnEnumSelection
|
|
//
|
|
// The cell editor calls this method when the user makes a
|
|
// selection from a drop-down combo.
|
|
//
|
|
// Parameters:
|
|
// [in] int iRow
|
|
// The cell's row index.
|
|
//
|
|
// [in] int iCol
|
|
// The cell's column index.
|
|
//
|
|
//
|
|
// Returns;
|
|
// Nothing.
|
|
//
|
|
//***********************************************************
|
|
void CGrid::OnEnumSelection(int iRow, int iCol)
|
|
{
|
|
}
|
|
|
|
|
|
|
|
|
|
//**********************************************************
|
|
// CGrid::PreModalDialog
|
|
//
|
|
// The grid calls this method just prior to putting up a modal
|
|
// dialog. OleControls can hook this virtual function out to
|
|
// call COleControl::PreModalDialog when necessary.
|
|
//
|
|
// Parameters:
|
|
// None.
|
|
//
|
|
// Returns:
|
|
// Nothing.
|
|
//
|
|
//**********************************************************
|
|
void CGrid::PreModalDialog()
|
|
{
|
|
}
|
|
|
|
|
|
//**********************************************************
|
|
// CGrid::PostModalDialog
|
|
//
|
|
// The grid calls this method just after putting up a modal
|
|
// dialog. OleControls can hook this virtual function out to
|
|
// call COleControl::PostModalDialog when necessary.
|
|
//
|
|
// Parameters:
|
|
// None.
|
|
//
|
|
// Returns:
|
|
// Nothing.
|
|
//
|
|
//**********************************************************
|
|
void CGrid::PostModalDialog()
|
|
{
|
|
}
|
|
|
|
|
|
|
|
//**********************************************************
|
|
// CGrid::GetRowAt
|
|
//
|
|
// The cell editor calls this method when the user makes a
|
|
// selection from a drop-down combo.
|
|
//
|
|
// Parameters:
|
|
// [in] int iRow
|
|
// The row index.
|
|
//
|
|
// Returns;
|
|
// CGridRow&
|
|
// A reference to the specified grid row.
|
|
//
|
|
//***********************************************************
|
|
CGridRow& CGrid::GetRowAt(int iRow)
|
|
{
|
|
return m_pcore->GetRowAt(iRow);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//**********************************************************
|
|
// CGrid::SetRowModified
|
|
//
|
|
// This method marks a row as modified or unmodified depending
|
|
// on the bModified parameter.
|
|
//
|
|
// Parameters:
|
|
// [in] int iRow
|
|
// The row index.
|
|
//
|
|
// [in] BOOL bModified
|
|
// TRUE if the row should be marked as "modified".
|
|
//
|
|
// Returns;
|
|
// Nothing.
|
|
//
|
|
//***********************************************************
|
|
void CGrid::SetRowModified(int iRow, BOOL bModified)
|
|
{
|
|
CGridRow& row = GetRowAt(iRow);
|
|
row.SetModified(bModified);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//**********************************************************
|
|
// CGrid::GetRowModified
|
|
//
|
|
// This method gets the "modified" state of a given row.
|
|
//
|
|
// Parameters:
|
|
// [in] int iRow
|
|
// The row index.
|
|
//
|
|
// Returns;
|
|
// BOOL
|
|
// TRUE if the row was modified.
|
|
//
|
|
//***********************************************************
|
|
BOOL CGrid::GetRowModified(int iRow)
|
|
{
|
|
CGridRow& row = GetRowAt(iRow);
|
|
BOOL bModified = row.GetModified();
|
|
return bModified;
|
|
}
|
|
|
|
|
|
|
|
//**********************************************************
|
|
// CGrid::GetWbemServices
|
|
//
|
|
// Get the WBEM services pointer for a given namespace.
|
|
//
|
|
// This method is called when editing an embedded object and
|
|
// the embedded object contains a property with an embedded
|
|
// object. The SingleView control that lives on the object
|
|
// editor dialog will fire a GetWbemServices event which is
|
|
// propagated up through the control hierarchy.
|
|
//
|
|
// Parameters:
|
|
// [in] LPCTSTR szNamespace
|
|
// The namespace.
|
|
//
|
|
// [out] VARIANT FAR* pvarUpdatePointer
|
|
//
|
|
// [out] VARIANT FAR* pvarServices
|
|
//
|
|
// [out] VARIANT FAR* pvarSc
|
|
// The status code is returned here.
|
|
//
|
|
// [out] VARIANT FAR* pvarUserCancel
|
|
// A boolean flag indicating whether or not the
|
|
// user cancelled the login.
|
|
//
|
|
//
|
|
// Returns;
|
|
// BOOL
|
|
// TRUE if the row was modified.
|
|
//
|
|
//***********************************************************
|
|
void CGrid::GetWbemServices(LPCTSTR szNamespace, VARIANT FAR* pvarUpdatePointer, VARIANT FAR* pvarServices, VARIANT FAR* pvarSc, VARIANT FAR* pvarUserCancel)
|
|
{
|
|
|
|
|
|
}
|
|
|
|
|
|
void CGrid::SetColTagValue(int iCol, DWORD dwTagValue)
|
|
{
|
|
m_pcore->SetColTagValue(iCol, dwTagValue);
|
|
}
|
|
|
|
DWORD CGrid::GetColTagValue(int iCol)
|
|
{
|
|
return m_pcore->GetColTagValue(iCol);
|
|
}
|
|
void CGrid::SetRowTagValue(int iRow, DWORD dwTagValue)
|
|
{
|
|
m_pcore->SetRowTagValue(iRow, dwTagValue);
|
|
}
|
|
|
|
DWORD CGrid::GetRowTagValue(int iRow)
|
|
{
|
|
return m_pcore->GetRowTagValue(iRow);
|
|
}
|
|
|
|
void CGrid::SetColVisibility(int iCol, BOOL bVisible)
|
|
{
|
|
m_phdr->Header().SetColVisibility(iCol, bVisible);
|
|
}
|
|
|
|
void CGrid::SetNullCellDrawMode(BOOL bShowEmptyText)
|
|
{
|
|
m_pcore->SetNullCellDrawMode(bShowEmptyText);
|
|
}
|
|
|
|
BOOL CGrid::ShowNullAsEmpty()
|
|
{
|
|
return m_pcore->ShowNullAsEmpty();
|
|
}
|
|
|
|
|
|
|
|
int CGrid::GetMaxValueWidth(int iCol)
|
|
{
|
|
return m_pcore->GetMaxValueWidth(iCol);
|
|
}
|
|
|
|
void CGrid::SwapRows(int iRow1, int iRow2, BOOL bRedraw)
|
|
{
|
|
m_pcore->SwapRows(iRow1, iRow2);
|
|
if (bRedraw) {
|
|
RedrawRow(iRow1);
|
|
RedrawRow(iRow2);
|
|
UpdateWindow();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void CGrid::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
|
|
{
|
|
// TODO: Add your message handler code here and/or call default
|
|
int iSelectedRow;
|
|
|
|
CWnd::OnChar(nChar, nRepCnt, nFlags);
|
|
switch (nChar) {
|
|
case VK_TAB:
|
|
iSelectedRow = GetSelectedRow();
|
|
if (GetKeyState(VK_SHIFT) < 0) {
|
|
// Tab forward should move to the next row.
|
|
if (iSelectedRow == NULL_INDEX) {
|
|
SelectRow(0);
|
|
}
|
|
else if (iSelectedRow < (GetRows() - 1)) {
|
|
SelectRow(iSelectedRow + 1);
|
|
}
|
|
}
|
|
else {
|
|
// Shift tab moves the row up one.
|
|
if (iSelectedRow == NULL_INDEX) {
|
|
SelectRow(0);
|
|
}
|
|
else if (iSelectedRow > 0) {
|
|
SelectRow(iSelectedRow - 1);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
}
|