1214 lines
27 KiB
C++
1214 lines
27 KiB
C++
// Copyright (c) 1997-2001 Microsoft Corporation, All Rights Reserved
|
|
//***************************************************************************
|
|
//
|
|
// (c) 1996, 1997 by Microsoft Corporation
|
|
//
|
|
// ArrayGrid.cpp
|
|
//
|
|
// This file contains the implementation for the array grid that is
|
|
// displayed for cells containing arrays.
|
|
//
|
|
// a-larryf 08-May-97 Created.
|
|
//
|
|
//***************************************************************************
|
|
|
|
#include "precomp.h"
|
|
#include "globals.h"
|
|
#include "gc.h"
|
|
#include "gca.h"
|
|
#include "gridhdr.h"
|
|
#include "grid.h"
|
|
#include "resource.h"
|
|
#include "ArrayGrid.h"
|
|
#include "hmmverr.h"
|
|
#include "utils.h"
|
|
#include "DlgObjectEditor.h"
|
|
|
|
|
|
|
|
#define CX_COLUMN 200
|
|
|
|
|
|
|
|
BEGIN_MESSAGE_MAP(CArrayGrid, CGrid)
|
|
//{{AFX_MSG_MAP(CGrid)
|
|
ON_WM_CHAR()
|
|
//}}AFX_MSG_MAP
|
|
ON_COMMAND(ID_CMD_CREATE_VALUE, OnCmdCreateValue)
|
|
ON_WM_CONTEXTMENU()
|
|
END_MESSAGE_MAP()
|
|
|
|
|
|
CArrayGrid::CArrayGrid(BOOL bNumberRows)
|
|
{
|
|
m_psvc = NULL;
|
|
AddColumn(CX_COLUMN, _T("Value"));
|
|
m_bModified = FALSE;
|
|
NumberRows(bNumberRows, FALSE);
|
|
SetNullCellDrawMode(FALSE);
|
|
}
|
|
|
|
|
|
|
|
CArrayGrid::~CArrayGrid()
|
|
{
|
|
if (m_psvc != NULL) {
|
|
m_psvc->Release();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//************************************************************
|
|
// CArrayGrid::GetValueAt
|
|
//
|
|
// Copy a value from the safe array to the a variant.
|
|
//
|
|
// Parameters:
|
|
// SAFEARRAY* psa
|
|
// Pointer to the source SAFEARRAY containing the value.
|
|
//
|
|
// long lIndex
|
|
// The element's index.
|
|
//
|
|
// COleVariant& var
|
|
// The variant to copy the value to.
|
|
//
|
|
// Returns:
|
|
// SCODE
|
|
// S_OK if successful, E_FAIL if the operation could not
|
|
// be done because of an invalid type, etc.
|
|
//
|
|
//***************************************************************
|
|
SCODE CArrayGrid::GetValueAt(SAFEARRAY* psa, long lIndex, COleVariant& var)
|
|
{
|
|
var.Clear();
|
|
|
|
HRESULT hr;
|
|
VARTYPE vt = VtFromCimtype(m_cimtype);
|
|
switch(vt) {
|
|
case VT_BOOL:
|
|
hr = SafeArrayGetElement(psa, &lIndex, &var.boolVal);
|
|
var.vt = VT_BOOL;
|
|
break;
|
|
case VT_BSTR:
|
|
hr = SafeArrayGetElement(psa, &lIndex, &var.bstrVal);
|
|
var.vt = VT_BSTR;
|
|
break;
|
|
case VT_I2:
|
|
hr = SafeArrayGetElement(psa, &lIndex, &var.iVal);
|
|
var.vt = VT_I2;
|
|
break;
|
|
case VT_I4:
|
|
hr = SafeArrayGetElement(psa, &lIndex, &var.lVal);
|
|
var.vt = VT_I4;
|
|
break;
|
|
case VT_R4:
|
|
hr = SafeArrayGetElement(psa, &lIndex, &var.fltVal);
|
|
var.vt = VT_R4;
|
|
break;
|
|
case VT_R8:
|
|
hr = SafeArrayGetElement(psa, &lIndex, &var.dblVal);
|
|
var.vt = VT_R8;
|
|
break;
|
|
case VT_UI1:
|
|
hr = SafeArrayGetElement(psa, &lIndex, &var.bVal);
|
|
var.vt = VT_UI1;
|
|
break;
|
|
case VT_UNKNOWN:
|
|
hr = SafeArrayGetElement(psa, &lIndex, &var.punkVal);
|
|
if (SUCCEEDED(hr)) {
|
|
var.punkVal->AddRef();
|
|
var.vt = VT_UNKNOWN;
|
|
}
|
|
break;
|
|
default:
|
|
ASSERT(FALSE);
|
|
return E_FAIL;
|
|
break;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
//**************************************************************
|
|
// CArrayGrid::SaveValueAt
|
|
//
|
|
// Copy the value at the specified cell to the corresponding
|
|
// element in the safe array.
|
|
//
|
|
// Parameters:
|
|
// SAFEARRAY* psa
|
|
// Pointer to the destination safe array.
|
|
//
|
|
// long lRow
|
|
// The row index of the cell (the column index is assumed to
|
|
// be zero).
|
|
//
|
|
// Returns:
|
|
// SCODE
|
|
// S_OK if the value was copied successfully, FALSE otherwise.
|
|
//
|
|
//**************************************************************
|
|
SCODE CArrayGrid::SaveValueAt(SAFEARRAY* psa, long lRow)
|
|
{
|
|
CGridCell& gc = GetAt(lRow, 0);
|
|
|
|
COleVariant var;
|
|
CIMTYPE cimtype;
|
|
HRESULT hr;
|
|
|
|
gc.GetValue(var, cimtype);
|
|
VARTYPE vt = VtFromCimtype(cimtype);
|
|
if (var.vt == VT_NULL) {
|
|
switch(vt) {
|
|
case VT_BSTR:
|
|
var = "";
|
|
break;
|
|
default:
|
|
var.ChangeType(vt);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
switch(vt) {
|
|
case VT_BOOL:
|
|
hr = SafeArrayPutElement(psa, &lRow, &var.boolVal);
|
|
break;
|
|
case VT_BSTR:
|
|
hr = SafeArrayPutElement(psa, &lRow, var.bstrVal);
|
|
break;
|
|
case VT_I2:
|
|
hr = SafeArrayPutElement(psa, &lRow, &var.iVal);
|
|
break;
|
|
case VT_I4:
|
|
hr = SafeArrayPutElement(psa, &lRow, &var.lVal);
|
|
break;
|
|
case VT_R4:
|
|
hr = SafeArrayPutElement(psa, &lRow, &var.fltVal);
|
|
break;
|
|
case VT_R8:
|
|
hr = SafeArrayPutElement(psa, &lRow, &var.dblVal);
|
|
break;
|
|
case VT_UI1:
|
|
hr = SafeArrayPutElement(psa, &lRow, &var.bVal);
|
|
break;
|
|
case VT_UNKNOWN:
|
|
if (var.vt != VT_NULL) {
|
|
var.punkVal->AddRef();
|
|
hr = SafeArrayPutElement(psa, &lRow, var.punkVal);
|
|
}
|
|
break;
|
|
default:
|
|
ASSERT(FALSE);
|
|
break;
|
|
}
|
|
|
|
// !!!CR: Should test the "hr" value above at this point.
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
//**************************************************************
|
|
// CArrayGrid::Save
|
|
//
|
|
// Copy the array from the grid into the variant.
|
|
//
|
|
// Parameters:
|
|
// None.
|
|
//
|
|
// Returns:
|
|
// SCODE
|
|
// S_OK if the copy is successful, otherwise E_FAIL if
|
|
// the grid contains an invalid value.
|
|
//
|
|
//**************************************************************
|
|
SCODE CArrayGrid::Save()
|
|
{
|
|
SCODE sc;
|
|
sc = SyncCellEditor();
|
|
if (FAILED(sc)) {
|
|
HmmvErrorMsg(IDS_INVALID_CELL_VALUE, sc, FALSE, NULL, _T(__FILE__), __LINE__);
|
|
return E_FAIL;
|
|
}
|
|
|
|
|
|
SAFEARRAY *psaDst;
|
|
LONG nRows = GetRows() - 1;
|
|
VARTYPE vt = VtFromCimtype(m_cimtype);
|
|
MakeSafeArray(&psaDst, vt, nRows);
|
|
|
|
m_pgcEdit->m_varValue.Clear();
|
|
m_pgcEdit->m_varValue.vt = VT_ARRAY | vt;
|
|
m_pgcEdit->m_varValue.parray = psaDst;
|
|
|
|
for (LONG lRow = 0; lRow < nRows; ++lRow) {
|
|
SaveValueAt(psaDst, lRow);
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
//********************************************************
|
|
// CArrayGrid::Load
|
|
//
|
|
// Load the array from the variant into this grid.
|
|
//
|
|
// Parameters:
|
|
// [in] CGidCell* pgcEdit
|
|
// The grid cell to edit.
|
|
//
|
|
// Returns:
|
|
// Nothing.
|
|
//
|
|
//********************************************************
|
|
SCODE CArrayGrid::Load(CGridCell* pgcEdit)
|
|
{
|
|
m_pgcEdit = pgcEdit;
|
|
m_cimtype = pgcEdit->GetCimtype() & CIM_TYPEMASK;
|
|
m_bReadOnly = pgcEdit->IsReadonly();
|
|
m_bModified = FALSE;
|
|
|
|
COleVariant varValue;
|
|
CGridCell* pgc;
|
|
|
|
|
|
if (!m_bReadOnly) {
|
|
// Insert an "empty" row at the bottom if we allow editing.
|
|
AddRow();
|
|
}
|
|
|
|
if (pgcEdit->IsArray() && !pgcEdit->IsNull()) {
|
|
COleVariant var;
|
|
CIMTYPE cimtype;
|
|
|
|
// !!!CR: If getting the variant copies it, we should find a more
|
|
// !!!CR: efficient way to do this.
|
|
pgcEdit->GetValue(var, cimtype);
|
|
|
|
|
|
SAFEARRAY* psa = var.parray;
|
|
long lLBound;
|
|
long lUBound;
|
|
SafeArrayGetLBound(psa, 1, &lLBound);
|
|
SafeArrayGetUBound(psa, 1, &lUBound);
|
|
|
|
|
|
int nValues = lUBound - lLBound + 1;
|
|
int iRowDst = 0;
|
|
for (int iIndex=0; iIndex < nValues; ++iIndex) {
|
|
AddRow();
|
|
pgc = &GetAt(iRowDst, 0);
|
|
|
|
SCODE sc = GetValueAt(psa, iIndex, varValue);
|
|
if (FAILED(sc)) {
|
|
DeleteRowAt(iRowDst, FALSE);
|
|
continue;
|
|
}
|
|
++iRowDst;
|
|
|
|
pgc->SetValue(CELLTYPE_VARIANT, varValue, m_cimtype);
|
|
if (m_bReadOnly) {
|
|
pgc->SetFlags(CELLFLAG_READONLY, CELLFLAG_READONLY);
|
|
}
|
|
pgc->SetModified(FALSE);
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
//*******************************************************
|
|
// CArrayGrid::AddRow
|
|
//
|
|
// Add a row to the array grid.
|
|
//
|
|
// Parameters:
|
|
// None.
|
|
//
|
|
// Returns:
|
|
// Nothing.
|
|
//
|
|
//******************************************************
|
|
void CArrayGrid::AddRow()
|
|
{
|
|
int iEmptyRow = IndexOfEmptyRow();
|
|
|
|
if (iEmptyRow != NULL_INDEX) {
|
|
if (IsBooleanCell(iEmptyRow, 0)) {
|
|
CGridCell* pgcEmpty = &GetAt(iEmptyRow, 0);
|
|
if (pgcEmpty->IsNull()) {
|
|
SetBooleanCellValue(iEmptyRow, 0, FALSE);
|
|
RefreshCellEditor();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
int nRows = GetRows();
|
|
InsertRowAt(nRows);
|
|
|
|
const CGcType& typeEdit = m_pgcEdit->type();
|
|
|
|
CGcType type;
|
|
type.SetCellType((CellType) typeEdit);
|
|
type.SetCimtype(((CIMTYPE) typeEdit) & ~CIM_FLAG_ARRAY);
|
|
|
|
CGridCell* pgc = &GetAt(nRows, 0);
|
|
pgc->SetToNull();
|
|
pgc->ChangeType(type);
|
|
|
|
|
|
int iLastRow = GetRows() - 1;
|
|
if (iLastRow >= 0) {
|
|
EnsureRowVisible(iLastRow);
|
|
}
|
|
|
|
RedrawWindow();
|
|
}
|
|
|
|
BOOL CArrayGrid::IsBooleanCell(int iRow, int iCol)
|
|
{
|
|
ASSERT(iRow != NULL_INDEX);
|
|
ASSERT(iCol != NULL_INDEX);
|
|
|
|
// Initialize the boolean value that we're editing to true
|
|
CGridCell* pgc = &GetAt(iRow, iCol);
|
|
CGcType type = pgc->type();
|
|
CIMTYPE cimtype = (CIMTYPE) type;
|
|
|
|
BOOL bIsBoolean = ((cimtype & ~CIM_FLAG_ARRAY) == CIM_BOOLEAN);
|
|
return bIsBoolean;
|
|
}
|
|
|
|
|
|
void CArrayGrid::SetBooleanCellValue(int iRow, int iCol, BOOL bValue)
|
|
{
|
|
ASSERT(iRow != NULL_INDEX);
|
|
ASSERT(iCol != NULL_INDEX);
|
|
ASSERT(IsBooleanCell(iRow, iCol));
|
|
|
|
// Initialize the boolean value that we're editing to true
|
|
CGridCell* pgc = &GetAt(iRow, iCol);
|
|
CGcType type = pgc->type();
|
|
CIMTYPE cimtype = (CIMTYPE) type;
|
|
COleVariant varValue;
|
|
varValue.ChangeType(VT_BOOL);
|
|
varValue.boolVal = bValue ? VARIANT_TRUE : VARIANT_FALSE;
|
|
pgc->SetValue(type, varValue);
|
|
}
|
|
|
|
|
|
BOOL CArrayGrid::OnCellKeyDown(int iRow, int iCol, UINT nChar, UINT nRepCnt, UINT nFlags)
|
|
{
|
|
int iSelectedRow;
|
|
int iSelectedCol;
|
|
GetSelectedCell(iSelectedRow, iSelectedCol);
|
|
if (iRow!=iSelectedRow || iCol!=iSelectedCol) {
|
|
OnCellClicked(iRow, iCol);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//**********************************************************
|
|
// CArrayGrid::OnCellClickedEpilog
|
|
//
|
|
// The grid class calls this method when a cell is clicked.
|
|
//
|
|
// Parameters:
|
|
// int iRow
|
|
// The row index of the clicked cell.
|
|
//
|
|
// int iCol
|
|
// The column index of the clicked cell.
|
|
//
|
|
// Returns:
|
|
// Nothing.
|
|
//
|
|
//***********************************************************
|
|
void CArrayGrid::OnCellClicked(int iRow, int iCol)
|
|
{
|
|
OnCellDoubleClicked(iRow, iCol);
|
|
}
|
|
|
|
|
|
//********************************************************************
|
|
// CArrayGrid::OnCellFocusChange
|
|
//
|
|
// This virtual method is called by the CGrid base class to notify
|
|
// derived classes when the focus is about to change from one cell
|
|
// to another.
|
|
//
|
|
// Paramters:
|
|
// [in] int iRow
|
|
// The row index of the cell.
|
|
//
|
|
// [in] int iCol
|
|
// The column index of the cell. If iCol is NULL_INDEX and
|
|
// iRow is valid, then an entire row is being selected.
|
|
//
|
|
// [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 the cell is getting the focus, FALSE if the cell is
|
|
// about to loose the focus.
|
|
//
|
|
// Returns:
|
|
// TRUE if it is OK for the CGrid class to complete the focus change
|
|
// FALSE if the focus change should be aborted.
|
|
//
|
|
//*********************************************************************
|
|
BOOL CArrayGrid::OnCellFocusChange(int iRow, int iCol, int iNextRow, int iNextCol, BOOL bGotFocus)
|
|
{
|
|
SCODE sc;
|
|
if (!bGotFocus) {
|
|
sc = SyncCellEditor();
|
|
if (FAILED(sc)) {
|
|
HmmvErrorMsg(IDS_INVALID_CELL_VALUE, sc, FALSE, NULL, _T(__FILE__), __LINE__);
|
|
return FALSE;
|
|
}
|
|
|
|
if ((iRow != NULL_INDEX ) && (iCol != NULL_INDEX)) {
|
|
CGridCell* pgc = &GetAt(iRow, iCol);
|
|
if (pgc->IsNull()) {
|
|
// Null cells are now allowed.
|
|
int iEmptyRow = IndexOfEmptyRow();
|
|
if (iRow != iEmptyRow) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
|
|
//******************************************************
|
|
// CArrayGrid::OnCellDoubleClicked
|
|
//
|
|
// This method overrides CGrid equivallent so that a new
|
|
// row can be created when the used double-clicks the
|
|
// empty row at the bottom of the grid if it exists.
|
|
//
|
|
// Parameters:
|
|
// int iRow
|
|
// The row index.
|
|
//
|
|
// int iCol
|
|
// The column index.
|
|
//
|
|
// Returns:
|
|
// Nothing.
|
|
//
|
|
//*******************************************************
|
|
void CArrayGrid::OnCellDoubleClicked(int iRow, int iCol)
|
|
{
|
|
int iEmptyRow = IndexOfEmptyRow();
|
|
if (!m_bReadOnly && iRow==iEmptyRow) {
|
|
|
|
SCODE sc = SyncCellEditor();
|
|
if (FAILED(sc)) {
|
|
HmmvErrorMsg(IDS_INVALID_CELL_VALUE, sc, FALSE, NULL, _T(__FILE__), __LINE__);
|
|
return;
|
|
}
|
|
|
|
EndCellEditing();
|
|
SelectCell(iEmptyRow, 0, TRUE);
|
|
|
|
CGridCell* pgcEmpty = &GetAt(iEmptyRow, 0);
|
|
|
|
switch((CIMTYPE) pgcEmpty->type()) {
|
|
case CIM_OBJECT:
|
|
case CIM_DATETIME:
|
|
if (pgcEmpty->IsNull()) {
|
|
return;
|
|
}
|
|
break;
|
|
default:
|
|
if (pgcEmpty->IsNull()) {
|
|
pgcEmpty->SetDefaultValue();
|
|
RefreshCellEditor();
|
|
}
|
|
break;
|
|
}
|
|
|
|
// Add a new empty row with a null value.
|
|
if (((m_cimtype & ~CIM_FLAG_ARRAY))!=CIM_OBJECT || (m_psvc != NULL)) {
|
|
SelectCell(NULL_INDEX, NULL_INDEX);
|
|
AddRow();
|
|
RedrawCell(iEmptyRow, 0);
|
|
}
|
|
SelectCell(iRow, iCol);
|
|
}
|
|
}
|
|
|
|
|
|
//*********************************************************
|
|
// CArrayGrid::ClearEmptyRow()
|
|
//
|
|
// Clear the emtpy row to an empty string with CELLTYPE_VOID.
|
|
// Doing so gives the user the appearance of an empty cell that
|
|
// he or she can set the cursor on.
|
|
//
|
|
// This is useful after editing a new row and then aborting the
|
|
// edit.
|
|
//
|
|
// Parameters:
|
|
// None.
|
|
//
|
|
// Returns:
|
|
// Nothing.
|
|
//
|
|
//**********************************************************
|
|
void CArrayGrid::ClearEmptyRow()
|
|
{
|
|
int iEmptyRow = IndexOfEmptyRow();
|
|
if (iEmptyRow == NULL_INDEX) {
|
|
return;
|
|
}
|
|
|
|
CGcType type(CELLTYPE_VARIANT, CIM_STRING);
|
|
CGridCell& gc = GetAt(iEmptyRow, 0);
|
|
gc.SetValue(type, _T(""));
|
|
}
|
|
|
|
//**********************************************************
|
|
// CArrayGrid::OnRowHandleDoubleClicked
|
|
//
|
|
// Override the CGrid method to create a new row when the
|
|
// row handle of the empty row is double-clicked.
|
|
//
|
|
// Parameters:
|
|
// None.
|
|
//
|
|
// Returns:
|
|
// Nothing.
|
|
//
|
|
//**********************************************************
|
|
void CArrayGrid::OnRowHandleDoubleClicked(int iRow)
|
|
{
|
|
OnCellDoubleClicked(iRow, 0);
|
|
|
|
#if 0
|
|
int iEmptyRow = IndexOfEmptyRow();
|
|
if (iEmptyRow == NULL_INDEX || (iRow < iEmptyRow)) {
|
|
return;
|
|
}
|
|
|
|
AddRow();
|
|
|
|
CGridCell* pgc = &GetAt(iEmptyRow, 0);
|
|
if (pgc->RequiresSpecialEditing()) {
|
|
BeginCellEditing();
|
|
pgc->DoSpecialEditing();
|
|
if (pgc->IsNull()) {
|
|
DeleteRowAt(IndexOfEmptyRow(), TRUE);
|
|
ClearEmptyRow();
|
|
}
|
|
EndCellEditing();
|
|
SelectCell(iEmptyRow, 0);
|
|
RedrawCell(iEmptyRow, 0);
|
|
}
|
|
#endif //0
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//*****************************************************************************
|
|
// CArrayGrid::OnCellChar
|
|
//
|
|
// This is a virtual method that the CGrid base class calls to notify derived
|
|
// classes that a WM_CHAR message was recieved.
|
|
//
|
|
// Parameters:
|
|
// int iRow
|
|
// The row index of the cell that the keystroke occurred in.
|
|
//
|
|
// int iCol
|
|
// The column index of the cell that the keystroke occurred in.
|
|
//
|
|
// UINT nChar
|
|
// The nChar parameter from window's OnKeyDown message.
|
|
//
|
|
// UINT nRepCnt
|
|
// The nRepCnt parameter from window's OnKeyDown message.
|
|
//
|
|
// UINT nFlags
|
|
// The nFlags parameter from window's OnKeyDown message.
|
|
//
|
|
// Returns:
|
|
// BOOL
|
|
// TRUE if this method handles the keydown message, FALSE otherwise.
|
|
//
|
|
//**********************************************************************
|
|
BOOL CArrayGrid::OnCellChar(int iRow, int iCol, UINT nChar, UINT nRepCnt, UINT nFlags)
|
|
{
|
|
// Check to see if we are on the "empty" row at the bottom of the grid.
|
|
// If so, then create a new property.
|
|
EnsureRowVisible(iRow);
|
|
|
|
int iEmptyRow = IndexOfEmptyRow();
|
|
if (iEmptyRow != NULL_INDEX && iRow==iEmptyRow) {
|
|
AddRow();
|
|
CGridCell* pgc = &GetAt(iRow, iCol);
|
|
if (pgc->RequiresSpecialEditing()) {
|
|
BeginCellEditing();
|
|
pgc->DoSpecialEditing();
|
|
if (pgc->IsNull()) {
|
|
if (((CIMTYPE) pgc->type()) == CIM_OBJECT) {
|
|
DeleteRowAt(IndexOfEmptyRow(), TRUE);
|
|
ClearEmptyRow();
|
|
}
|
|
}
|
|
EndCellEditing();
|
|
SelectCell(iEmptyRow, 0);
|
|
RedrawCell(iEmptyRow, 0);
|
|
}
|
|
}
|
|
|
|
|
|
// We don't handle this event.
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
|
|
//***********************************************************
|
|
// CArrayGrid::IndexOfEmptyRow
|
|
//
|
|
// Return the index of the empty row at the bottom of the grid.
|
|
// If the array is read-only, then return NULL_INDEX.
|
|
//
|
|
// Parameters:
|
|
// None.
|
|
//
|
|
// Returns:
|
|
// int
|
|
// The index of the empty row at the bottom of the grid
|
|
// or NULL_INDEX if there is no empty row.
|
|
//
|
|
//***********************************************************
|
|
int CArrayGrid::IndexOfEmptyRow()
|
|
{
|
|
if (m_bReadOnly) {
|
|
return NULL_INDEX;
|
|
}
|
|
else {
|
|
return GetRows() - 1;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//***********************************************************
|
|
// CArrayGrid::GetModified
|
|
//
|
|
// Check to see if the grid has been modified.
|
|
//
|
|
// Parameters:
|
|
// None.
|
|
//
|
|
// Returns:
|
|
// BOOL
|
|
// TRUE if the grid was modified, FALSE otherwise.
|
|
//
|
|
//************************************************************
|
|
BOOL CArrayGrid::GetModified()
|
|
{
|
|
return m_bModified;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//************************************************************
|
|
// CArrayGrid::SetModified
|
|
//
|
|
// Set the modified flag of all the grid cells to the given value.
|
|
//
|
|
// Parameters:
|
|
// BOOL bModified
|
|
// The new value to set the modified flag to.
|
|
//
|
|
// Returns:
|
|
// BOOL
|
|
// The previous value of the m_bModified flag.
|
|
//
|
|
//************************************************************
|
|
BOOL CArrayGrid::SetModified(BOOL bModified)
|
|
{
|
|
BOOL bInitialValue = m_bModified;
|
|
|
|
int nRows = m_bReadOnly ? GetRows() : GetRows() -1;
|
|
for (int iRow = 0; iRow < nRows; ++iRow) {
|
|
CGridCell* pgc = &GetAt(iRow, 0);
|
|
pgc->SetModified(bModified);
|
|
}
|
|
bModified = bModified;
|
|
return bInitialValue;
|
|
}
|
|
|
|
|
|
|
|
//*******************************************************************
|
|
// CArrayGrid::OnCellContentChange
|
|
//
|
|
// Override this virtual method in CGrid to detect changes to a grid
|
|
// cell.
|
|
//
|
|
// Parameters:
|
|
// int iRow
|
|
// The row index of the cell modified.
|
|
//
|
|
// int iCol
|
|
// The column index of the cell modified.
|
|
//
|
|
// Returns:
|
|
// Nothing.
|
|
//
|
|
//*******************************************************************
|
|
void CArrayGrid::OnCellContentChange(int iRow, int iCol)
|
|
{
|
|
if (!m_bReadOnly) {
|
|
int iEmptyRow = IndexOfEmptyRow();
|
|
if (iRow == iEmptyRow) {
|
|
SCODE sc = SyncCellEditor();
|
|
if (SUCCEEDED(sc)) {
|
|
CGridCell* pgc = &GetAt(iRow, iCol);
|
|
if (!pgc->IsNull() && (m_psvc != NULL)) {
|
|
AddRow();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
m_bModified = TRUE;
|
|
}
|
|
|
|
|
|
|
|
|
|
//*****************************************************************************
|
|
// CArrayGrid::OnRowKeyDown
|
|
//
|
|
// This is a virtual method that the CGrid base class calls to notify derived
|
|
// classes that a key was pressed while the focus was set to a grid cell.
|
|
//
|
|
// Parameters:
|
|
// [in] int iRow
|
|
// The row index of the cell that the keystroke occurred in.
|
|
//
|
|
// [in] UINT nChar
|
|
// The nChar parameter from window's OnKeyDown message.
|
|
//
|
|
// [in] UINT nRepCnt
|
|
// The nRepCnt parameter from window's OnKeyDown message.
|
|
//
|
|
// [in] UINT nFlags
|
|
// The nFlags parameter from window's OnKeyDown message.
|
|
//
|
|
// Returns:
|
|
// BOOL
|
|
// TRUE if this method handles the keydown message, FALSE otherwise.
|
|
//
|
|
//**********************************************************************
|
|
BOOL CArrayGrid::OnRowKeyDown(
|
|
/* in */ int iRow,
|
|
/* in */ UINT nChar,
|
|
/* in */ UINT nRepCnt,
|
|
/* in */ UINT nFlags)
|
|
{
|
|
|
|
switch(nChar) {
|
|
case VK_DELETE:
|
|
if (m_bReadOnly) {
|
|
MessageBeep(MB_ICONEXCLAMATION);
|
|
}
|
|
else {
|
|
int iEmptyRow = IndexOfEmptyRow();
|
|
if ((iRow != NULL_INDEX) && (iRow != iEmptyRow)) {
|
|
DeleteRowAt(iRow);
|
|
m_bModified = TRUE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
// We don't handle this event.
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
//*******************************************************************
|
|
// CArrayGrid::CompareRows
|
|
//
|
|
// This is a virtual method override that compares two rows in the grid
|
|
// using the column index as the sort criteria.
|
|
//
|
|
// Parameters:
|
|
// int iRow1
|
|
// The index of the first row.
|
|
//
|
|
// int iRow2
|
|
// The index of the second row.
|
|
//
|
|
// int iSortColumn
|
|
// The column index.
|
|
//
|
|
// 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 CArrayGrid::CompareRows(int iRow1, int iRow2, int iSortColumn)
|
|
{
|
|
int iResult;
|
|
|
|
switch (iSortColumn) {
|
|
case 0:
|
|
// Sort first by name
|
|
iResult = CompareCells(iRow1, iRow2, 0);
|
|
return iResult;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
//*********************************************************************
|
|
// CPropGrid::GetCellEditContextMenu
|
|
//
|
|
// Get the context menu for the specified cell.
|
|
//
|
|
// Parameters:
|
|
// [in] int iRow
|
|
//
|
|
// [in] int iCol
|
|
// The column index for the specified cell.
|
|
//
|
|
// [out] CWnd*& pwndTarget
|
|
// The target window
|
|
//
|
|
// [out] CMenu& menu
|
|
// This CMenu object is loaded with the desired menu.
|
|
//
|
|
// [in] BOOL& bWantEditCommands
|
|
// TRUE if the caller wants the commands for editing a cell.
|
|
//
|
|
// Returns:
|
|
// BOOL
|
|
// TRUE if a context menu exists for the specified cell.
|
|
//
|
|
//********************************************************************
|
|
BOOL CArrayGrid::GetCellEditContextMenu(int iRow, int iCol, CWnd*& pwndTarget, CMenu& menu, BOOL& bWantEditCommands)
|
|
{
|
|
bWantEditCommands = FALSE;
|
|
VERIFY(menu.LoadMenu(IDR_ARRAYEDIT_MENU));
|
|
|
|
pwndTarget = this;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
|
|
//***********************************************************************
|
|
// CArrayGrid::ModifyCellEditContextMenu
|
|
//
|
|
// The cell editor calls this method just prior to displaying the context
|
|
// menu when the user right-clicks. This method gives classes derived from
|
|
// CGrid a chance to modify the context menu depending on the current situation.
|
|
//
|
|
// Parameters:
|
|
// [in] int iRow
|
|
// The row index of the cell that was right-clicked.
|
|
//
|
|
// [in] int iCol
|
|
// The column index of the cell that was right-clicked.
|
|
//
|
|
// [in/out] CMenu& menu
|
|
// A reference to the context menu that you can modify.
|
|
//
|
|
// Returns:
|
|
// Nothing.
|
|
//
|
|
//************************************************************************
|
|
void CArrayGrid::ModifyCellEditContextMenu(int iRow, int iCol, CMenu& menu)
|
|
{
|
|
|
|
CMenu* pPopup = menu.GetSubMenu(0);
|
|
ASSERT(pPopup != NULL);
|
|
|
|
if (iRow == IndexOfEmptyRow()) {
|
|
pPopup->RemoveMenu(ID_CMD_CREATE_VALUE, MF_BYCOMMAND);
|
|
}
|
|
|
|
return;
|
|
|
|
#if 0
|
|
// We may want to put the following code back in someday, so I didn't delete it yet.
|
|
|
|
|
|
BOOL bIsSystemProperty = FALSE;
|
|
COleVariant varPropName;
|
|
CIMTYPE cimtype = 0;
|
|
|
|
CGridCell& gc = GetAt(iRow, ICOL_PROP_NAME);
|
|
gc.GetValue(varPropName, cimtype);
|
|
|
|
BOOL bCanShowPropQualifiers = TRUE;
|
|
if (iRow == IndexOfEmptyRow()) {
|
|
bCanShowPropQualifiers = FALSE;
|
|
}
|
|
else
|
|
{
|
|
if (cimtype != CIM_STRING || varPropName.vt != VT_BSTR)
|
|
{
|
|
bCanShowPropQualifiers = FALSE;
|
|
}
|
|
else
|
|
{
|
|
if (IsSystemProperty(varPropName.bstrVal))
|
|
{
|
|
bCanShowPropQualifiers = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
pPopup->EnableMenuItem(ID_CMD_SHOW_SELECTED_PROP_ATTRIBUTES, bCanShowPropQualifiers ? MF_ENABLED : MF_DISABLED | MF_GRAYED);
|
|
|
|
CGridCell *gcValue = NULL;
|
|
if (m_psvc == NULL) {
|
|
pPopup->RemoveMenu(ID_CMD_CREATE_VALUE, MF_BYCOMMAND);
|
|
}
|
|
else {
|
|
|
|
if(HasCol(ICOL_PROP_VALUE))
|
|
{
|
|
gcValue = &GetAt(iRow, ICOL_PROP_VALUE);
|
|
BOOL bCanCreateObject = gcValue->IsObject() && gcValue->IsNull();
|
|
BOOL bCanCreateArray = gcValue->IsArray() && gcValue->IsNull();
|
|
BOOL bIsReadonly = gcValue->IsReadonly();
|
|
|
|
if(gcValue && (bIsReadonly || !(bCanCreateObject || bCanCreateArray)))
|
|
{
|
|
pPopup->RemoveMenu(ID_CMD_CREATE_VALUE, MF_BYCOMMAND);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pPopup->RemoveMenu(ID_CMD_CREATE_VALUE, MF_BYCOMMAND);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (iCol != ICOL_PROP_VALUE)
|
|
{
|
|
pPopup->RemoveMenu( ID_CMD_SET_CELL_TO_NULL, MF_BYCOMMAND);
|
|
}
|
|
else
|
|
{
|
|
BOOL bCanSetToNull = FALSE;
|
|
if (!(gc.GetFlags() & CELLFLAG_READONLY))
|
|
{
|
|
bCanSetToNull = TRUE;
|
|
}
|
|
pPopup->EnableMenuItem(ID_CMD_SET_CELL_TO_NULL, bCanSetToNull ? MF_ENABLED : MF_DISABLED | MF_GRAYED);
|
|
}
|
|
|
|
// store for the cmd handlers.
|
|
m_curRow = &GetRowAt(iRow);
|
|
OnBuildContextMenu(pPopup, iRow);
|
|
#endif //0
|
|
|
|
}
|
|
|
|
|
|
|
|
void CArrayGrid::OnCmdCreateValue()
|
|
{
|
|
if (m_psvc == NULL) {
|
|
return;
|
|
}
|
|
|
|
int iRow = NULL_INDEX;
|
|
int iCol = NULL_INDEX;
|
|
if (!PointToCell(m_ptContextMenu, iRow, iCol)) {
|
|
return;
|
|
}
|
|
if (iCol != 0) {
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
if (iRow != IndexOfEmptyRow()) {
|
|
return;
|
|
}
|
|
|
|
EndCellEditing();
|
|
SyncCellEditor();
|
|
SelectCell(iRow, 0);
|
|
AddRow();
|
|
|
|
|
|
|
|
CGridCell& gc = GetAt(iRow, 0);
|
|
BOOL bIsNull = gc.IsNull();
|
|
BOOL bIsArray = gc.IsArray();
|
|
BOOL bIsObject = gc.IsObject();
|
|
|
|
if (!bIsNull) {
|
|
return;
|
|
}
|
|
|
|
if (bIsArray) {
|
|
gc.EditArray();
|
|
}
|
|
else if (bIsObject) {
|
|
|
|
LPUNKNOWN lpunk = gc.GetObject();
|
|
if (lpunk != NULL) {
|
|
lpunk->Release();
|
|
return;
|
|
}
|
|
|
|
COleVariant varPropname;
|
|
CDlgObjectEditor dlg;
|
|
dlg.CreateEmbeddedObject(m_psvc, m_sClassname, &gc);
|
|
|
|
RedrawCell(iRow, 0);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//*******************************************************************
|
|
// CArrayGrid::OnContextMenu
|
|
//
|
|
// This method is called to display the context menu (right button menu).
|
|
//
|
|
// Parameters:
|
|
// CWnd*
|
|
//
|
|
// CPoint ptContextMenu
|
|
// The place where the right moust button was clicked.
|
|
//
|
|
// Returns:
|
|
// Nothing.
|
|
//
|
|
//*****************************************************************
|
|
void CArrayGrid::OnContextMenu(CWnd* pwnd, CPoint ptContextMenu)
|
|
{
|
|
// CG: This function was added by the Pop-up Menu component
|
|
|
|
|
|
m_ptContextMenu = ptContextMenu;
|
|
ScreenToClient(&m_ptContextMenu);
|
|
|
|
int iRow;
|
|
int iCol;
|
|
BOOL bClickedCell = PointToCell(m_ptContextMenu, iRow, iCol);
|
|
if (!bClickedCell) {
|
|
iCol = NULL_INDEX;
|
|
BOOL bClickedRowHandle = PointToRowHandle(m_ptContextMenu, iRow);
|
|
if (!bClickedRowHandle) {
|
|
iRow = NULL_INDEX;
|
|
}
|
|
}
|
|
|
|
|
|
if (iRow == IndexOfEmptyRow()) {
|
|
iRow = NULL_INDEX;
|
|
iCol = NULL_INDEX;
|
|
}
|
|
else {
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
CMenu menu;
|
|
VERIFY(menu.LoadMenu(IDR_ARRAYEDIT_MENU1));
|
|
|
|
CMenu* pPopup = menu.GetSubMenu(0);
|
|
ASSERT(pPopup != NULL);
|
|
|
|
if ((m_cimtype & ~CIM_FLAG_ARRAY) != CIM_OBJECT) {
|
|
pPopup->RemoveMenu( ID_CMD_SET_CELL_TO_NULL, MF_BYCOMMAND);
|
|
}
|
|
|
|
|
|
if (iRow == NULL_INDEX) {
|
|
pPopup->RemoveMenu(ID_CMD_CREATE_VALUE, MF_BYCOMMAND);
|
|
}
|
|
|
|
|
|
|
|
pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, ptContextMenu.x, ptContextMenu.y,
|
|
this);
|
|
}
|
|
|
|
|
|
SCODE CArrayGrid::GetObjectClass(CString& sClassname, int iRow, int iCol)
|
|
{
|
|
sClassname = m_sClassname;
|
|
if (sClassname.IsEmpty()) {
|
|
return E_FAIL;
|
|
}
|
|
else {
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void CArrayGrid::SetObjectParams(IWbemServices* psvc, CString& sClassname)
|
|
{
|
|
if (m_psvc != NULL) {
|
|
m_psvc->Release();
|
|
}
|
|
if (psvc != NULL) {
|
|
psvc->AddRef();
|
|
}
|
|
m_psvc = psvc;
|
|
m_sClassname = sClassname;
|
|
}
|
|
|
|
|
|
|
|
|
|
|