2025-04-27 07:49:33 -04:00

4134 lines
98 KiB
C++

// Copyright (c) 1997-2001 Microsoft Corporation, All Rights Reserved
#include "precomp.h"
#ifndef _wbemidl_h
#define _wbemidl_h
#include <wbemidl.h>
#endif //_wbemidl_h
#include "resource.h"
#include "notify.h"
#include "props.h"
#include "utils.h"
#include "PpgQualifiers.h"
#include "PsQualifiers.h"
#include "SingleViewCtl.h"
#include "icon.h"
#include "hmomutil.h"
#include "globals.h"
#include "hmmverr.h"
#include "path.h"
//#include "DlgObjectEditor.h"
//#include "DlgArray.h"
// The default column widths. Note that the width of some columns
// may be computed at runtime and that the default value may not
// be used.
#define CX_COL_PROPKEY 19 // Room for a 16X16 property marker plus a margin of two pixels
#define CX_COL_PROPMARKER 19 // Room for a 16X16 property marker plus a margin of two pixels
#define CX_COL_NAME 180
#define CX_COL_VALUE 180
#define CX_COL_TYPE 115
#define CXMIN_COL_VALUE 50
#define CXMIN_COL_TYPE 32
#define IX_COL_NAME 0
#define IX_COL_TYPE (IX_COL_NAME + CX_COL_NAME)
#define IX_COL_VALUE (IX_COL_TYPE + CX_COL_TYPE)
#define FIRST_SYNTESIZED_PROP_ID 1
BEGIN_MESSAGE_MAP(CPropGrid, CGrid)
//{{AFX_MSG_MAP(CGrid)
ON_COMMAND(ID_CMD_GOTO_OBJECT, OnCmdGotoObject)
//}}AFX_MSG_MAP
ON_WM_SIZE()
ON_WM_SETFOCUS()
ON_WM_KILLFOCUS()
ON_COMMAND(ID_CMD_SHOW_OBJECT_ATTRIBUTES, OnCmdShowObjectQualifiers)
ON_COMMAND(ID_CMD_SHOW_PROP_ATTRIBUTES, OnCmdShowPropQualifiers)
ON_COMMAND(ID_CMD_SHOW_SELECTED_PROP_ATTRIBUTES, OnCmdShowSelectedPropQualifiers)
ON_COMMAND(ID_CMD_SET_CELL_TO_NULL, OnCmdSetCellToNull)
ON_COMMAND(ID_CMD_CREATE_VALUE, OnCmdCreateValue)
ON_WM_CONTEXTMENU()
END_MESSAGE_MAP()
CDisableModifyCreate::CDisableModifyCreate(CPropGrid* pPropGrid)
{
m_pPropGrid = pPropGrid;
m_bModifyCanCreateProp = pPropGrid->m_bModifyCanCreateProp;
pPropGrid->m_bModifyCanCreateProp = FALSE;
}
CDisableModifyCreate::~CDisableModifyCreate()
{
m_pPropGrid->m_bModifyCanCreateProp = m_bModifyCanCreateProp;
}
//***************************************************************
// CPropGrid::CPropGrid
//
// Construct the properties grid.
//
// Parameters:
// CSingleViewCtrl* psv
// Backpointer to the main control.
//
// Returns:
// Nothing.
//
//**************************************************************
CPropGrid::CPropGrid(CSingleViewCtrl* psv, bool doColumns,
bool bNotifyEnabled)
{
m_bNotifyEnabled = bNotifyEnabled;
m_bHasEmptyRow = FALSE;
m_bIsSystemClass = FALSE;
m_bUIActive = FALSE;
m_bDidInitialResize = FALSE;
m_bShowingInvalidCellMessage = FALSE;
m_psv = psv;
m_bModified = FALSE;
m_iCurrentRow = NULL_INDEX;
m_iCurrentCol = NULL_INDEX;
m_bDiscardOldObject = FALSE;
m_bModifyCanCreateProp = TRUE;
CString sTitle;
m_lNewPropID = FIRST_SYNTESIZED_PROP_ID;
m_lNewMethID = FIRST_SYNTESIZED_PROP_ID;
AddColumn(CX_COL_PROPKEY, _T(""));
AddColumn(CX_COL_PROPMARKER, _T(""));
sTitle.LoadString(IDS_HEADER_TITLE_PROPS_NAME);
AddColumn(CX_COL_NAME, sTitle);
if(doColumns)
{
sTitle.LoadString(IDS_HEADER_TITLE_PROPS_TYPE);
AddColumn(CX_COL_TYPE, sTitle);
sTitle.LoadString(IDS_HEADER_TITLE_PROPS_VALUE);
AddColumn(CX_COL_VALUE, sTitle);
}
ToBSTR(m_varCurrentName);
}
//**************************************************************
// CPropGrid::~CPropGrid
//
// Destructor for the property grid.
//
// Parameters:
// None.
//
// Returns:
// Nothing.
//
//***************************************************************
CPropGrid::~CPropGrid()
{
m_psv->GetGlobalNotify()->RemoveClient((CNotifyClient*) this);
}
//*************************************************************
// CPropGrid::CurrentObject
//
// Get the current object from the generic view.
//
// Parameters:
// None.
//
// Returns:
// A pointer to the current object.
//
//*************************************************************
IWbemClassObject* CPropGrid::CurrentObject()
{
CSelection& sel = m_psv->Selection();
IWbemClassObject* pco = (IWbemClassObject*) sel;
return pco;
}
//***********************************************************
// CPropGrid::Create
//
// We override the create method of the base class so that
// we can initialize the column widths to fill the client
// area.
//
// Parameters:
// CRect& rc
// The client rectangle
//
// CWnd* pwndParent
// The parent window
//
// BOOL bVisible
// TRUE if the window should be visible after creation.
//
// Returns:
// TRUE if successful, otherwise FALSE.
//
//************************************************************
BOOL CPropGrid::Create(CRect& rc, CWnd* pwndParent, UINT nId, BOOL bVisible)
{
// Set the column widths of those columns who's width is computed from
// the client rectangle instead of using the default width. For the
// properties grid, only the "Value" column width is computed.
int cxClient = rc.Width() - GetRowHandleWidth();
int cxCol = CXMIN_COL_VALUE;
if (cxClient > IX_COL_VALUE ) {
cxCol = cxClient - IX_COL_VALUE;
}
SetColumnWidth(ICOL_PROP_VALUE, cxCol, FALSE);
BOOL bDidCreate = CGrid::Create(rc, pwndParent, nId, bVisible);
if (bDidCreate) {
m_psv->GetGlobalNotify()->AddClient((CNotifyClient*) this);
}
return bDidCreate;
}
//********************************************************************
// CPropGrid::LoadProperty
//
// Load the specified property into the specified grid row.
//
// Parameters:
// [in] const LONG lRowDst
// The index of the row where the property will be stored.
//
// [in] BSTR bstrPropName
// The name of the property to get.
//
// Returns:
// SCODE sc
// S_OK if the property was loaded, a failure code if not.
//
//*********************************************************************
SCODE CPropGrid::LoadProperty(const LONG lRowDst, BSTR bstrPropName)
{
BOOL bEditValueOnly = !m_psv->ObjectIsClass() || !IsInSchemaStudioMode();
SCODE sc = LoadProperty(lRowDst, bstrPropName, bEditValueOnly);
return sc;
}
//*********************************************************************
// CPropGrid::Refresh
//
// Load the properties of the currently selected object.
//
// Parameters:
// None.
//
// Returns:
// Nothing.
//
//*********************************************************************
void CPropGrid::Refresh()
{
SCODE sc;
m_bHasEmptyRow = FALSE;
sc = m_psv->IsSystemClass(m_bIsSystemClass);
CRect rcClient;
if (::IsWindow(m_hWnd)) {
GetClientRect(rcClient);
InvalidateRect(rcClient);
}
m_bShowingInvalidCellMessage = FALSE;
CDisableModifyCreate DisableModifyCreate(this);
m_bDiscardOldObject = TRUE;
Empty();
m_bDiscardOldObject = FALSE;
// Load the properties of the new object.
if (!CurrentObject()) {
return;
}
CMosNameArray aPropNames;
sc = aPropNames.LoadPropNames(CurrentObject());
if (sc != S_OK) {
ASSERT(FALSE); // Should never fail.
HmmvErrorMsg(IDS_ERR_GET_PROP_NAMES, sc, FALSE, NULL, _T(__FILE__), __LINE__);
}
ClearRows();
BOOL bEditValueOnly = CanEditValuesOnly();
IWbemClassObject* pco = CurrentObject();
if (pco == NULL) {
ASSERT(FALSE);
return;
}
long nProps = aPropNames.GetSize();
for (long lProp=0; lProp < nProps; ++lProp) {
BSTR bstrPropname = aPropNames[lProp];
long lRow = GetRows();
InsertRowAt(lRow);
sc = LoadProperty(lRow, bstrPropname, bEditValueOnly);
if (FAILED(sc)) {
DeleteRowAt(lRow, FALSE);
}
}
int nRows = GetRows();
if (m_psv->ObjectIsClass() && IsInSchemaStudioMode() && !m_bIsSystemClass) {
// When viewing a class,
// Add an empty row at the bottom.
InsertRowAt(nRows);
RedrawRow(nRows);
m_bHasEmptyRow = TRUE;
}
if (nRows > 0) {
SetHeaderSortIndicator(ICOL_PROP_NAME, TRUE);
SortGrid(0, nRows-1, ICOL_PROP_NAME);
}
UpdateScrollRanges();
if(::IsWindow(m_hWnd))
{
// This is a total hack to get the redraws to work properly.
// Someone should eventually figure out how to do this properly
// when we're not so close to shipping!.
if ((nRows<=1 && m_bHasEmptyRow) || ((nRows == 1) && !m_bHasEmptyRow)) {
GetClientRect(rcClient);
InvalidateRect(rcClient);
}
}
}
//*********************************************************
// CPropGrid::HasEmptyKey
//
// Check to see if any property is an empty key.
//
// Parameters:
// None.
//
// Returns:
// Nothing.
//
//*********************************************************
BOOL CPropGrid::HasEmptyKey()
{
SyncCellEditor();
// Search through each of the property markers
long nProps = GetRows();
for (long lProp=0; lProp < nProps; ++lProp) {
CGridCell* pgcKey = &GetAt(lProp, ICOL_PROP_KEY);
if (pgcKey->GetPropmarker() == PROPMARKER_KEY) {
CGridCell* pgcValue = &GetAt(lProp, ICOL_PROP_VALUE);
if (pgcValue->IsNull()) {
return TRUE;
}
}
}
return FALSE;
}
//-----------------------------------------------
HRESULT CPropGrid::DoGet(IWbemClassObject* pco,
CGridRow* pRow,
BSTR bstrName,
long lFlags,
VARIANT *pvarVal,
CIMTYPE *pcimtype,
long *plFlavor)
{
if (pco == NULL)
{
ASSERT(FALSE);
return E_FAIL;
}
else
{
SCODE sc;
sc = pco->Get(bstrName, lFlags, pvarVal, pcimtype, plFlavor);
return sc;
}
}
//-----------------------------------------------
HRESULT CPropGrid::DoPut(IWbemClassObject* pco,
CGridRow* pRow,
BSTR bstrName,
long lFlags,
VARIANT* pvarVal,
CIMTYPE cimtype)
{
if (pco == NULL)
{
ASSERT(FALSE);
return E_FAIL;
}
else
{
// Remove any leading white space from the name;
while (*bstrName && iswspace( *bstrName )) {
++bstrName;
}
SCODE sc;
// deal with amended qualifiers: prevent them from being written to the main namespace
lFlags |= WBEM_FLAG_USE_AMENDED_QUALIFIERS;
sc = pco->Put(bstrName, lFlags, pvarVal, cimtype);
return sc;
}
}
//-----------------------------------------------
HRESULT CPropGrid::DoDelete(IWbemClassObject* pco,
BSTR bstrName)
{
if (pco == NULL)
{
ASSERT(FALSE);
return E_FAIL;
}
else
{
// Remove any leading white space from the name;
while (*bstrName && iswspace( *bstrName )) {
++bstrName;
}
return pco->Delete(bstrName);
}
}
//-----------------------------------------------
HRESULT CPropGrid::DoGetQualifierSet(IWbemClassObject* pco,
IWbemQualifierSet **ppQualSet)
{
if (pco == NULL)
{
ASSERT(FALSE);
return E_FAIL;
}
else
{
return pco->GetQualifierSet(ppQualSet);
}
}
//-----------------------------------------------
HRESULT CPropGrid::DoGetPropertyQualifierSet(IWbemClassObject* pco,
BSTR pProperty,
IWbemQualifierSet **ppQualSet)
{
if (pco == NULL)
{
ASSERT(FALSE);
return E_FAIL;
}
else
{
return pco->GetPropertyQualifierSet(pProperty, ppQualSet);
}
}
//-----------------------------------------------------------
SCODE CPropGrid::GetCimtype(IWbemClassObject* pco,
BSTR bstrPropname,
CString& sCimtype)
{
// use the hmomutil version.
return ::GetCimtype(pco, bstrPropname, sCimtype);
}
// bug#57334 - Adjust meaning of local for instances
long GetFlavor2(long lFlavor, IWbemClassObject *pco, BSTR bstrPropName)
{
long lFlavor2 = lFlavor;
if(!IsClass(pco) && (WBEM_FLAVOR_ORIGIN_SYSTEM & lFlavor)==0)
{
BSTR bstrOrigin = NULL;
HRESULT hrT = pco->GetPropertyOrigin(bstrPropName, &bstrOrigin);
if(SUCCEEDED(hrT) && bstrOrigin)
{
VARIANT v;
VariantInit(&v);
pco->Get(L"__CLASS", 0, &v, NULL, NULL);
if(v.vt == VT_BSTR)
{
if(0 == lstrcmp(bstrOrigin, v.bstrVal))
{
lFlavor2 |= WBEM_FLAVOR_ORIGIN_LOCAL;
lFlavor2 &= ~WBEM_FLAVOR_ORIGIN_PROPAGATED;
}
else
{
lFlavor2 |= WBEM_FLAVOR_ORIGIN_PROPAGATED;
lFlavor2 &= ~WBEM_FLAVOR_ORIGIN_LOCAL;
}
}
VariantClear(&v);
}
}
return lFlavor2;
}
//********************************************************************
// CPropGrid::LoadProperty
//
// Load the specified property into the specified grid row.
//
// Parameters:
// [in] const LONG lRowDst
// The index of the row where the property will be stored.
//
// [in] BSTR bstrPropName
// The name of the property to get.
//
// [in] const BOOL bEditValueOnly
// TRUE if the property should be marked so that only its value field
// can be edited.
//
// Returns:
// SCODE sc
// S_OK if the property was loaded, a failure code if not.
//
//
//*********************************************************************
SCODE CPropGrid::LoadProperty(const LONG lRowDst,
BSTR bstrPropName,
BOOL bEditValueOnly,
IWbemClassObject* clsObj,
long filter)
{
IWbemClassObject* pco = NULL;
if (clsObj == NULL)
{
pco = CurrentObject();
}
else
{
pco = clsObj;
}
if (pco == NULL) {
ASSERT(FALSE);
return E_FAIL;
}
SCODE sc;
ASSERT(bstrPropName != NULL);
if (bstrPropName == NULL) {
return E_FAIL;
}
COleVariant varValue;
CIMTYPE cimtype = 0;
long lFlavor = 0;
CGridRow& row = GetRowAt(lRowDst);
sc = DoGet(pco, (CGridRow *)&row, bstrPropName, 0, &varValue, &cimtype, &lFlavor);
if (sc != WBEM_S_NO_ERROR) {
ASSERT(FAILED(sc));
if (FAILED(sc)) {
CString sName = bstrPropName;
if (sName == "__PATH") {
// CIMOM has a bug that causes __PATH to be returned as a
// property name for embedded objects, but a get can not be done on it.
return E_FAIL;
}
varValue.Clear();
CString sFormat;
sFormat.LoadString(IDS_ERR_PROPERTY_GET_FAILED);
LPTSTR pszMessage = m_psv->MessageBuffer();
_stprintf(pszMessage, (LPCTSTR) sFormat, (LPCTSTR) sName);
HmmvErrorMsgStr(pszMessage, sc, FALSE, NULL, _T(__FILE__), __LINE__);
return E_FAIL;
}
}
CString sCimtype;
if (((cimtype & ~CIM_FLAG_ARRAY) == CIM_OBJECT) ||
((cimtype & ~CIM_FLAG_ARRAY) == CIM_REFERENCE)) {
// For objects and references we need to get the
// cimtype string to know the objects class or the
// class that the reference points to.
sc = GetCimtype(pco, bstrPropName, sCimtype);
if (FAILED(sc)) {
// System properties do not have a cimtype qualifier, so it
// is necessary to use the properties cimtype to generate the
// cimtyhpe string.
sc = MapCimtypeToString(sCimtype, cimtype);
ASSERT(SUCCEEDED(sc));
}
}
else {
// For properties that are not objects or references
// we don't need any additional type information, so
// we can do a simple lookup.
sc = MapCimtypeToString(sCimtype, cimtype);
ASSERT(SUCCEEDED(sc));
}
// Use the filter flags to filter out any properties
// that should not be displayed. Returning a failure
// code will prevent the property from being added to
// the grid.
long lPropFilter;
if(filter == -1)
{
lPropFilter = m_psv->GetPropertyFilter();
}
else
{
lPropFilter = filter;
}
BOOL bIsSystemProperty = FALSE;
switch(GetFlavor2(lFlavor, pco, bstrPropName)) {
case WBEM_FLAVOR_ORIGIN_SYSTEM:
if (!(lPropFilter & PROPFILTER_SYSTEM)) {
return E_FAIL;
}
// Only the value of a system property can be edited.
bIsSystemProperty = TRUE;
break;
case WBEM_FLAVOR_ORIGIN_PROPAGATED:
bEditValueOnly = TRUE;
if (!(lPropFilter & PROPFILTER_INHERITED)) {
return E_FAIL;
}
break;
}
if (bIsSystemProperty) {
bEditValueOnly = TRUE;
}
CGridCell* pgcName;
CGridCell* pgcType;
CGridCell* pgcValue;
CGridCell* pgcFlavor;
CGridCell* pgcKey;
pgcKey = &GetAt(lRowDst, ICOL_PROP_KEY);
pgcFlavor = &GetAt(lRowDst, ICOL_PROP_FLAVOR);
pgcName = &GetAt(lRowDst, ICOL_PROP_NAME);
pgcType = &GetAt(lRowDst, ICOL_PROP_TYPE);
pgcValue = &GetAt(lRowDst, ICOL_PROP_VALUE);
pgcKey->SetType(CELLTYPE_PROPMARKER);
pgcFlavor->SetType(CELLTYPE_PROPMARKER);
pgcName->SetValue(CELLTYPE_NAME, bstrPropName, CIM_STRING);
pgcName->SetTagValue(CELL_TAG_EXISTS_IN_DATABASE);
pgcName->SetFlags(CELLFLAG_READONLY, bEditValueOnly ? CELLFLAG_READONLY : 0);
BOOL bIsReadOnly = ValueShouldBeReadOnly(bstrPropName);
if (bIsSystemProperty) {
bIsReadOnly = TRUE;
}
sc = pgcValue->SetValue(CELLTYPE_VARIANT, varValue, cimtype, sCimtype);
if (FAILED(sc)) {
if (!m_bShowingInvalidCellMessage) {
m_bShowingInvalidCellMessage = TRUE;
HmmvErrorMsg(IDS_ERR_INVALID_CELL_VALUE, sc, FALSE, NULL, _T(__FILE__), __LINE__);
m_bShowingInvalidCellMessage = FALSE;
}
}
CBSTR bstrQualifier;
bstrQualifier = _T("not_null");
if (!bIsSystemProperty) {
BOOL bNotNull = ::GetBoolPropertyQualifier(sc, pco, bstrPropName, (BSTR) bstrQualifier);
if (SUCCEEDED(sc)) {
pgcValue->SetFlags(CELLFLAG_NOTNULL, bNotNull ? CELLFLAG_NOTNULL : 0);
}
}
pgcValue->SetFlags(CELLFLAG_READONLY, bIsReadOnly ? CELLFLAG_READONLY : 0);
pgcValue->SetFlags(CELLFLAG_ARRAY, (cimtype & CIM_FLAG_ARRAY) ? CELLFLAG_ARRAY : 0);
// for date-time types, check for interval qualifier.
if(cimtype == CIM_DATETIME)
{
BOOL bIsInterval = FALSE;
bstrQualifier = _T("Subtype");
CBSTR bstrValue(_T("Interval"));
bIsInterval = GetbstrPropertyQualifier(sc, pco,
bstrPropName,
(BSTR)bstrQualifier,
(BSTR)bstrValue);
pgcValue->SetFlags(CELLFLAG_INTERVAL, bIsInterval ? CELLFLAG_INTERVAL : 0);
}
CString sDisplayType;
pgcValue->type().DisplayTypeString(sDisplayType);
pgcType->SetValue(CELLTYPE_CIMTYPE, sDisplayType, CIM_STRING);
pgcType->SetBuddy(ICOL_PROP_VALUE);
pgcType->SetFlags(CELLFLAG_READONLY, (bEditValueOnly || bIsReadOnly) ? CELLFLAG_READONLY : 0);
if ((varValue.vt == VT_UNKNOWN) && (varValue.pdispVal != NULL)) {
pgcValue->SetTagValue(CELL_TAG_EMBEDDED_OBJECT_IN_DATABASE);
}
row.SetFlavor(lFlavor);
// When editing a class, it is possible to have a property that
// is marked read-only and still be able to edit the value.
// Thus, we want the property marker to show up as read-only
// even though it may be possible to edit the value while editing
// a class.
BOOL bReadonlyTemp = PropertyIsReadOnly(pco, bstrPropName);
row.SetReadonly(bReadonlyTemp | m_bIsSystemClass);
row.SetModified(FALSE);
SetPropmarkers(lRowDst, pco);
return S_OK;
}
//*********************************************************************
// CPropGrid::SetPropmarkers
//
// Load the properties of the currently selected object.
//
// Parameters:
// [in] int iRow
// The row where the property lives.
//
// [in] BOOL bRedrawCell
// TRUE if the cell should be redrawn.
//
// Returns:
// Nothing.
//
//*********************************************************************
void CPropGrid::SetPropmarkers(int iRow, IWbemClassObject* clsObj, BOOL bRedrawCell)
{
CGridRow& row = GetRowAt(iRow);
CGridCell* pgcFlavor = &GetAt(iRow, ICOL_PROP_FLAVOR);
CGridCell* pgcKey = &GetAt(iRow, ICOL_PROP_KEY);
IWbemClassObject* pco;
if(clsObj == NULL)
{
pco= CurrentObject();
}
else
{
pco = clsObj;
}
PropMarker marker;
CGridCell* pgcName = &GetAt(iRow, ICOL_PROP_NAME);
COleVariant varName;
CIMTYPE cimtype = 0;
pgcName->GetValue(varName, cimtype);
SCODE sc;
BOOL bIsKey = PropIsKey(sc, pco, varName.bstrVal);
if (bIsKey) {
marker = PROPMARKER_KEY;
}
else {
marker = PROPMARKER_NONE;
}
if (marker != pgcKey->GetPropmarker())
{
pgcKey->SetPropmarker(marker);
RedrawCell(iRow, ICOL_PROP_KEY);
}
BOOL bReadonly = row.IsReadonly();
switch(GetFlavor2(row.GetFlavor(), pco, varName.bstrVal)) {
case WBEM_FLAVOR_ORIGIN_SYSTEM:
marker = PROPMARKER_RSYS;
break;
case WBEM_FLAVOR_ORIGIN_PROPAGATED:
if (bReadonly) {
marker = PROPMARKER_RINHERITED;
}
else {
marker = PROPMARKER_INHERITED;
}
break;
case WBEM_FLAVOR_ORIGIN_LOCAL:
if (bReadonly) {
marker = PROPMARKER_RLOCAL;
}
else {
marker = PROPMARKER_LOCAL;
}
break;
default:
marker = PROPMARKER_LOCAL;
break;
}
if (marker != pgcFlavor->GetPropmarker()) {
pgcFlavor->SetPropmarker(marker);
if (bRedrawCell) {
RedrawCell(iRow, ICOL_PROP_FLAVOR);
}
}
}
//**************************************************************
// CPropGrid::Empty
//
// Discard the entire contents of the grid.
//
// Parameters:
// None.
//
// Returns:
// Nothing.
//
//***************************************************************
void CPropGrid::Empty()
{
ClearAllSortDirectionFlags();
SelectCell(NULL_INDEX, NULL_INDEX);
ClearRows();
m_lNewPropID = FIRST_SYNTESIZED_PROP_ID;
m_lNewMethID = FIRST_SYNTESIZED_PROP_ID;
}
//***************************************************************
// CPropGrid::Serialize
//
// Write the modified properties back to the object. Note that this
// method should be obsolete as a put should be done on modified
// properties as soon as the focus changes to a new cell.
//
// Parameters:
// None.
//
// Returns:
// Nothing.
//
//****************************************************************
SCODE CPropGrid::Serialize()
{
CDisableModifyCreate DisableModifyCreate(this);
CGridSync sync(this);
if (FAILED(sync.m_sc)) {
if (!m_bShowingInvalidCellMessage) {
m_bShowingInvalidCellMessage = TRUE;
HmmvErrorMsg(IDS_ERR_INVALID_CELL_VALUE, sync.m_sc, FALSE, NULL, _T(__FILE__), __LINE__);
m_bShowingInvalidCellMessage = FALSE;
}
return E_FAIL;
}
BOOL bPutFailed = FALSE;
SCODE sc = S_OK;
int nRows = GetRows();
for (int iRow=0; iRow < nRows; ++iRow) {
BOOL bRowModified = GetRowModified(iRow);
if (bRowModified) {
sc = PutProperty(iRow);
if (FAILED(sc)) {
bPutFailed = TRUE;
}
else {
SetRowModified(iRow, FALSE);
}
}
}
if (bPutFailed) {
return E_FAIL;
}
RefreshCellEditor();
SetModified(FALSE);
RedrawWindow();
return S_OK;
}
//**************************************************************
// CPropGrid::OnCellDoubleClicked
//
// This virtual method is called by the CGrid base class to notify
// derived classes when a cell has been double clicked. If a property
// is double-clicked, the qualifiers of that property are displayed.
//
// Parameters:
// int iRow
// The row index of the clicked cell.
//
// int iCol
// The column index of the clicked cell.
//
// Returns:
// Nothing.
//
//****************************************************************
void CPropGrid::OnCellDoubleClicked(int iRow, int iCol)
{
if (m_bShowingInvalidCellMessage) {
return;
}
CGridCell* pgcName;
SCODE sc;
int iEmptyRow = IndexOfEmptyRow();
if (iEmptyRow != NULL_INDEX && iRow == iEmptyRow) {
// Create a new row.
int iEmptyRow = IndexOfEmptyRow();
if (iEmptyRow != NULL_INDEX && iRow == iEmptyRow) {
if (!m_bIsSystemClass) {
SelectCell(NULL_INDEX, NULL_INDEX);
CreateNewProperty();
sc = PutProperty(iRow);
}
SelectCell(iRow, iCol);
}
m_iCurrentRow = iRow;
m_iCurrentCol = iCol;
if (iRow!=NULL_INDEX && iCol!=NULL_INDEX) {
pgcName = &GetAt(iRow, ICOL_PROP_NAME);
CIMTYPE cimtype = 0;
pgcName->GetValue(m_varCurrentName, cimtype);
ASSERT(cimtype == CIM_STRING);
}
}
else {
// Display the attributes of an existing row.
pgcName = &GetAt(iRow, ICOL_PROP_NAME);
// Copy the cell editor to the grid by declaring an instance of CGridSync.
CGridSync sync(this);
if (iRow == m_iCurrentRow && PropertyNeedsRenaming(iRow)) {
// If the row name was modified, call PutProperty to do the renaming so
// that ShowPropertyQualifiers can find the correct property.
sc = PutProperty(iRow);
if (FAILED(sc)) {
return;
}
}
SelectRow(iRow);
ShowPropertyQualifiers(iRow);
}
}
//**********************************************************************
// CPropGrid::OnRowHandleDoubleClicked
//
// This virtual method is called by the base class when a double click is
// detected on a row handle.
//
// Parameters:
// int iRow
// The row index.
//
// Returns:
// Nothing.
//
//**********************************************************************
void CPropGrid::OnRowHandleDoubleClicked(int iRow)
{
if (m_bShowingInvalidCellMessage) {
return;
}
CGridCell* pgcName;
int iEmptyRow = IndexOfEmptyRow();
if (iEmptyRow != NULL_INDEX && iRow == iEmptyRow) {
OnCellDoubleClicked(iRow, ICOL_PROP_NAME);
}
else {
// Display the attributes of an existing row.
pgcName = &GetAt(iRow, ICOL_PROP_NAME);
// Copy the cell editor to the grid by declaring an instance of CGridSync.
CGridSync sync(this);
if (iRow == m_iCurrentRow && PropertyNeedsRenaming(iRow)) {
// If the row name was modified, call PutProperty to do the renaming so
// that ShowPropertyQualifiers can find the correct property.
SCODE sc = PutProperty(iRow);
if (FAILED(sc)) {
return;
}
}
ShowPropertyQualifiers(iRow);
}
}
//****************************************************************
// CPropGrid::PropertyNeedsRenaming
//
// Check to see if the name of the selected property has been changed.
//
// Parameters:
// [in] int iRow
//
// Returns:
// BOOL
// TRUE if the currently selected property needs to be renamed.
//
//*****************************************************************
BOOL CPropGrid::PropertyNeedsRenaming(int iRow)
{
// If no property is selected, it doesn't make sense to rename it.
if (m_iCurrentRow == NULL_INDEX) {
return FALSE;
}
if (iRow != m_iCurrentRow) {
return FALSE;
}
CGridCell* pgcName = &GetAt(m_iCurrentRow, ICOL_PROP_NAME);
// If the property has not been put to the database yet, it isn't
// necessary to rename it.
if ((pgcName->GetTagValue() & CELL_TAG_NEEDS_INITIAL_PUT)!=0) {
return FALSE;
}
// If the name has been modified and it is not the same as its
// initial value when the focus was changed to the name cell,
// then it needs to be renamed.
if (pgcName->GetModified()) {
COleVariant varName;
CIMTYPE cimtype = 0;
pgcName->GetValue(varName, cimtype);
ASSERT(cimtype == CIM_STRING);
if (!IsEqualNoCase(varName.bstrVal, m_varCurrentName.bstrVal)) {
return TRUE;
}
}
return FALSE;
}
//********************************************************************
// CPropGrid::PutProperty
//
// Put the property in the specified row to the database.
//
// Parameters:
// int iRow
// The index of the row containing the property.
//
// Returns:
// SCODE
// S_OK if successful, otherwise a failure code.
//
//********************************************************************
SCODE CPropGrid::PutProperty(int iRow, IWbemClassObject* clsObj)
{
IWbemClassObject* pco = NULL;
if(clsObj != NULL)
{
pco = clsObj;
}
else
{
pco = CurrentObject();
}
if (pco == NULL) {
HmmvErrorMsg(IDS_ERR_TRANSPORT_FAILURE, WBEM_E_TRANSPORT_FAILURE, TRUE, NULL, _T(__FILE__), __LINE__);
return E_FAIL;
}
BOOL bIsClass = ::IsClass(pco);
CGridSync sync(this);
SCODE sc = S_OK;
CGridCell* pgcName = &GetAt(iRow, ICOL_PROP_NAME);
//CGridCell* pgcType = &GetAt(iRow, ICOL_PROP_TYPE);
CGridCell* pgcValue = NULL;
if(HasCol(ICOL_PROP_VALUE))
{
pgcValue = &GetAt(iRow, ICOL_PROP_VALUE);
}
COleVariant varName;
CIMTYPE cimtype = 0;
pgcName->GetValue(varName, cimtype);
ASSERT(cimtype == CIM_STRING);
RemoveLeadingWhiteSpace(varName);
RemoveTrailingWhiteSpace(varName);
if (*varName.bstrVal == 0) {
HmmvErrorMsg(IDS_ERR_EMPTY_PROP_NAME, S_OK, FALSE, NULL, _T(__FILE__), __LINE__);
SelectCell(iRow, ICOL_PROP_NAME);
return E_FAIL;
}
COleVariant varValue;
CIMTYPE cimtypeValue = 0;
if(pgcValue)
{
pgcValue->GetValue(varValue, cimtypeValue);
if (cimtypeValue == CIM_EMPTY) {
// Values returned by HMOM should never have a type of VT_EMPTY.
cimtypeValue = CIM_STRING;
}
}
CString sMessage;
CString sFormat;
CString sName;
LPTSTR pszMessage = m_psv->MessageBuffer();
BOOL bDoRename = PropertyNeedsRenaming(iRow);
if (bDoRename) {
DWORD_PTR dwTag = pgcName->GetTagValue();
if ((dwTag & CELL_TAG_EXISTS_IN_DATABASE)!=0) {
sc = RenameProperty(pco, varName.bstrVal, m_varCurrentName.bstrVal);
if (FAILED(sc)) {
// Restore the property's name to its original value so that the user
// doesn't get stuck in a "fix the name" mode forever.
pgcName->SetValue(CELLTYPE_NAME, m_varCurrentName, CIM_STRING);
pgcName->SetModified(FALSE);
RefreshCellEditor();
SelectCell(iRow, ICOL_PROP_NAME);
return sc;
}
}
else {
BOOL bExists;
bExists = PropertyExists(sc, pco, varName.bstrVal);
CString sNewName;
CString sOldName;
if (FAILED(sc)) {
sNewName = varName.bstrVal;
sOldName = m_varCurrentName.bstrVal;
sFormat.LoadString(IDS_ERR_RENAME_PROPERTY_FAILED);
_stprintf(pszMessage, (LPCTSTR) sFormat, (LPCTSTR) sOldName, (LPCTSTR) sNewName);
HmmvErrorMsgStr(pszMessage, sc, FALSE, NULL, _T(__FILE__), __LINE__);
}
else {
if (bExists) {
// Duplicate property name.
sNewName = varName.bstrVal;
sFormat.LoadString(IDS_ERR_DUPLICATE_PROPERTY_NAME);
_stprintf(pszMessage, (LPCTSTR) sFormat, (LPCTSTR) sNewName);
HmmvErrorMsgStr(pszMessage, S_OK, FALSE, NULL, _T(__FILE__), __LINE__);
return E_FAIL;
}
}
CGridRow &row = GetRowAt(iRow);
CString sCimtype;
if (bIsClass) {
sc = DoPut(pco, (CGridRow *)&row, varName.bstrVal, 0,&varValue, cimtypeValue);
}
else {
sc = DoPut(pco, (CGridRow *)&row, varName.bstrVal, 0,&varValue, 0);
}
if (FAILED(sc)) {
HmmvErrorMsg(IDS_ERR_PUT_PROPERTY_FAILED, sc, FALSE, NULL, _T(__FILE__), __LINE__);
return sc;
}
}
m_varCurrentName = varName;
pgcName->SetTagValue(CELL_TAG_EXISTS_IN_DATABASE);
}
else if (RowWasModified(iRow)) {
// Control comes here the properties name did not change.
if(pgcValue)
{
BOOL bIsArray = pgcValue->IsArray();
if (bIsArray) {
cimtypeValue |= CIM_FLAG_ARRAY;
}
}
CGridRow &row = GetRowAt(iRow);
if (bIsClass) {
sc = DoPut(pco, (CGridRow *)&row, varName.bstrVal, 0, &varValue, cimtypeValue);
}
else {
sc = DoPut(pco, (CGridRow *)&row, varName.bstrVal, 0, &varValue, 0);
}
if (SUCCEEDED(sc)) {
pgcName->SetTagValue(CELL_TAG_EXISTS_IN_DATABASE);
}
else {
HmmvErrorMsg(IDS_ERR_PUT_PROPERTY_FAILED, sc, FALSE, NULL, _T(__FILE__), __LINE__);
return sc;
}
}
if (SUCCEEDED(sc)) {
if (bIsClass) {
CString sCimtype;
switch(cimtypeValue & ~CIM_FLAG_ARRAY) {
case CIM_OBJECT:
case CIM_REFERENCE:
// Strongly typed objects and references need to set the full
// cimtype qualifier string.
if (pgcValue) {
sCimtype = pgcValue->type().CimtypeString();
if (!sCimtype.IsEmpty()) {
IWbemQualifierSet* pqs = NULL;
sc = DoGetPropertyQualifierSet(pco, varName.bstrVal, &pqs);
if (FAILED(sc)) {
// !!!CR: we need an error message here.
}
else {
long lFlavor = 0;
CBSTR bsCimtype(_T("CIMTYPE"));
COleVariant varValue;
varValue = sCimtype;
sc = pqs->Put((BSTR) bsCimtype, &varValue, lFlavor);
pqs->Release();
if (FAILED(sc)) {
ASSERT(FALSE);
// !!!CR: We need an error message here
}
}
}
}
break;
}
}
pgcName->SetTagValue(pgcName->GetTagValue() & ~ CELL_TAG_NEEDS_INITIAL_PUT);
if (pgcValue &&(varValue.vt == VT_UNKNOWN) && (varValue.pdispVal!=NULL)) {
pgcValue->SetTagValue(CELL_TAG_EMBEDDED_OBJECT_IN_DATABASE);
}
// If the name changed, the flavor of the property might have changed.
CIMTYPE cimtype = 0;
long lFlavor = 0;
CGridRow& row = GetRowAt(iRow);
sc = DoGet(pco, (CGridRow *)&row, varName.bstrVal, 0, &varValue, &cimtype, &lFlavor);
if (SUCCEEDED(sc)) {
row.SetFlavor(lFlavor);
SetPropmarkers(iRow, pco);
}
}
return sc;
}
//********************************************************************
// CPropGrid::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 CPropGrid::OnCellFocusChange(int iRow, int iCol, int iNextRow, int iNextCol, BOOL bGotFocus)
{
SCODE sc;
if (!bGotFocus) {
if (!m_bDiscardOldObject) {
// The current cell is losing focus, so put the row to the
// database. However, it isn't necessary to save the current
// properties when if the grid is being cleared.
if ((m_iCurrentRow != NULL_INDEX) && (m_iCurrentCol != NULL_INDEX)) {
sc = SyncCellEditor();
if (FAILED(sc)) {
if (!m_bShowingInvalidCellMessage) {
m_bShowingInvalidCellMessage = TRUE;
HmmvErrorMsg(IDS_ERR_INVALID_CELL_VALUE, sc, FALSE, NULL, _T(__FILE__), __LINE__);
m_bShowingInvalidCellMessage = FALSE;
}
return FALSE;
}
if (RowWasModified(m_iCurrentRow)) {
sc = PutProperty(m_iCurrentRow);
if (FAILED(sc)) {
return FALSE;
}
}
}
}
m_iCurrentRow = NULL_INDEX;
m_iCurrentCol = NULL_INDEX;
m_varCurrentName = _T("");
}
else {
m_iCurrentRow = iRow;
m_iCurrentCol = iCol;
if (iRow!=NULL_INDEX) {
CGridCell* pgcName = &GetAt(iRow, ICOL_PROP_NAME);
CIMTYPE cimtype = 0;
pgcName->GetValue(m_varCurrentName, cimtype);
ASSERT(cimtype == CIM_STRING);
}
}
return TRUE;
}
//*************************************************************
// CPropGrid::CreateNewProperty
//
// Create a new property by adding a row to the grid.
//
// Parameters:
// [in] BOOL bGenerateName
// TRUE to generate a default name for the property.
//
// Returns:
// Nothing.
//
//*************************************************************
void CPropGrid::CreateNewProperty(BOOL bGenerateName)
{
CDisableModifyCreate DisableModifyCreate(this);
IWbemClassObject* pco = CurrentObject();
if (pco == NULL) {
return;
}
SCODE sc;
EndCellEditing();
// We are editing the new row, what should we do?
// If the user clicked column zero, change the type
// of the other cells in the row and allow the user to
// enter the name.
// If the user clicked any other column, then make up a
// name.
int iRow = GetRows() - 1;
CString sSynthesizedPropName;
if (bGenerateName) {
TCHAR szBuffer[32];
COleVariant varTempName;
COleVariant varTempValue;
while(TRUE)
{
if(HasCol(ICOL_PROP_TYPE))
{
sSynthesizedPropName.LoadString(IDS_NEW_PROPERTY_BASE_NAME);
_stprintf(szBuffer, _T("%05d"), m_lNewPropID);
++m_lNewPropID;
}
else // its the method grid...
{
sSynthesizedPropName.LoadString(IDS_NEW_METHOD_BASE_NAME);
_stprintf(szBuffer, _T("%05d"), m_lNewMethID);
++m_lNewMethID;
}
sSynthesizedPropName = sSynthesizedPropName + szBuffer;
varTempName = sSynthesizedPropName;
CGridRow& row = GetRowAt(iRow);
sc = DoGet(pco, (CGridRow *)&row, varTempName.bstrVal, 0, &varTempValue, NULL, NULL);
if (FAILED(sc)) {
break;
}
}
}
else {
sSynthesizedPropName = _T("");
}
CGridCell* pgcKey = &GetAt(iRow, ICOL_PROP_KEY);
CGridCell* pgcFlavor = &GetAt(iRow, ICOL_PROP_FLAVOR);
CGridCell* pgcName = &GetAt(iRow, ICOL_PROP_NAME);
CGridCell* pgcType = NULL;
CGridCell* pgcValue = NULL;
if(HasCol(ICOL_PROP_TYPE))
{
pgcType = &GetAt(iRow, ICOL_PROP_TYPE);
}
if(HasCol(ICOL_PROP_VALUE))
{
pgcValue = &GetAt(iRow, ICOL_PROP_VALUE);
}
pgcKey->SetType(CELLTYPE_PROPMARKER);
pgcFlavor->SetType(CELLTYPE_PROPMARKER);
pgcFlavor->SetPropmarker(PROPMARKER_NONE);
pgcName->SetValue(CELLTYPE_NAME, sSynthesizedPropName, CIM_STRING);
pgcName->SetModified(TRUE);
SetCellModified(iRow, ICOL_PROP_NAME, TRUE);
pgcName->SetTagValue(pgcName->GetTagValue());
COleVariant varValue;
varValue.ChangeType(VT_BSTR);
// The property value
if(pgcValue)
{
pgcValue->SetValue(CELLTYPE_VARIANT, varValue, CIM_STRING);
pgcValue->SetToNull();
pgcValue->SetModified(TRUE);
SetCellModified(iRow, ICOL_PROP_VALUE, TRUE);
}
// The property type
CString sCimtype;
sCimtype.LoadString(IDS_CIMTYPE_STRING);
if(pgcType)
{
pgcType->SetValue(CELLTYPE_CIMTYPE, sCimtype, CIM_STRING);
pgcType->SetBuddy(ICOL_PROP_VALUE);
pgcType->SetModified(TRUE);
SetCellModified(iRow, ICOL_PROP_VALUE, TRUE);
}
// Syncronize the state of the grid with, the cell editor and this class.
if (iRow == m_iCurrentRow) {
CIMTYPE cimtype = 0;
pgcName->GetValue(m_varCurrentName, cimtype);
}
RefreshCellEditor();
SetPropmarkers(iRow, pco);
// Create a new "empty" row in the grid, and insert the property into the
// HMOM class object.
int iEmptyRow = GetRows();
InsertRowAt(iEmptyRow);
EnsureRowVisible(iEmptyRow);
pgcFlavor = &GetAt(iEmptyRow, ICOL_PROP_FLAVOR);
pgcFlavor->SetType(CELLTYPE_PROPMARKER);
pgcKey->SetType(CELLTYPE_PROPMARKER);
OnRowCreated(iRow);
RedrawWindow();
m_psv->NotifyDataChange();
}
void CPropGrid::OnRowCreated(int iRow)
{
}
//*************************************************************
// CPropGrid::OnCellContentChange
//
// This method is called by the CGrid base class when the content
// of the specified cell changes.
//
// Parameters:
// int iRow
// The cell's row index.
//
// int iCol
// The cell's column index.
//
// Returns:
// Nothing.
//
//*************************************************************
void CPropGrid::OnCellContentChange(int iRow, int iCol)
{
if (iRow != NULL_INDEX) {
int iEmptyRow = IndexOfEmptyRow();
if (iRow == iEmptyRow) {
if (m_bModifyCanCreateProp) {
CDisableModifyCreate DisableModifyCreate(this);
SyncCellEditor();
CGridCell& gc = GetAt(iRow, iCol);
COleVariant varValue;
CIMTYPE cimtypeValue = 0;
gc.GetValue(varValue, cimtypeValue);
int iEmptyRow = IndexOfEmptyRow();
if (iEmptyRow != NULL_INDEX && m_iCurrentRow == iEmptyRow) {
BOOL bGenerateDefaultName = iCol != ICOL_PROP_NAME;
SelectCell(NULL_INDEX, NULL_INDEX);
CreateNewProperty(bGenerateDefaultName);
SelectCell(iRow, iCol);
}
if (iCol != ICOL_PROP_TYPE) {
CellType type = gc.GetType();
gc.SetValue(type, varValue, cimtypeValue);
RefreshCellEditor();
}
}
}
}
if(m_bNotifyEnabled)
m_psv->GetGlobalNotify()->SendEvent(NOTIFY_GRID_MODIFICATION_CHANGE);
}
//********************************************************************
// CPropGrid::OnChangedCimtype
//
// The CGrid base class calls this virtual method when the user changes
// the value of a cell with CELLTYPE_CIMTYPE. By hooking this method out,
// we can change the other cells in the same row to reflect that fact
// that a new CIMTYPE has been selected for the property.
//
// Parameters:
// [in] int iRow
// The row index of the cell containing the CIMTYPE.
//
// [in] int iCol
// The column index of the cell containing the CIMTYHPE.
//
// Returns:
// Nothing.
//
//********************************************************************
void CPropGrid::OnChangedCimtype(int iRow, int iCol)
{
if (iRow==NULL_INDEX || iCol == NULL_INDEX) {
return;
}
CString sCimtype;
SCODE sc;
CGridCell& gc = GetAt(iRow, iCol);
CellType celltype = gc.GetType();
if (celltype == CELLTYPE_CIMTYPE) {
// When the cimtype is changed, the property's qualifiers will all
// be lost unless we "save" them in a temporary property and then
// copy them back to the original property after a "put" is done
// on it.
IWbemClassObject* pco = CurrentObject();
COleVariant varTempName;
varTempName = "ObscureActiveXSuiteTempProperty";
CGridCell& gcSrcName = GetAt(iRow, ICOL_PROP_NAME);
COleVariant varSrcName;
CIMTYPE cimtypeSrcName = 0;
gcSrcName.GetValue(varSrcName, cimtypeSrcName);
RemoveLeadingWhiteSpace(varSrcName);
RemoveTrailingWhiteSpace(varSrcName);
sc = CopyProperty(pco, varTempName.bstrVal, varSrcName.bstrVal);
sc = PutProperty(iRow);
sc = CopyQualifierSets(pco, varSrcName.bstrVal, varTempName.bstrVal);
ASSERT(SUCCEEDED(sc));
// Destroy the destination property if it exists
sc = DoDelete(pco, varTempName.bstrVal);
ASSERT(SUCCEEDED(sc));
SyncCellEditor();
if(HasCol(ICOL_PROP_VALUE))
{
RefreshCellEditor();
RedrawCell(iRow, ICOL_PROP_TYPE);
RedrawCell(iRow, ICOL_PROP_VALUE);
}
}
}
//**********************************************************
// CPropGrid::OnCellClicked
//
// 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 CPropGrid::OnCellClicked(int iRow, int iCol)
{
const int iEmptyRow = IndexOfEmptyRow();
if (iRow == iEmptyRow) {
OnCellDoubleClicked(iRow, iCol);
return;
}
// If this is the second click on the property name, then start editing the
// name.
if (iCol == ICOL_PROP_KEY) {
KeyCellClicked(iRow);
}
else if ((iCol == ICOL_PROP_NAME) &&
(iRow == m_iCurrentRow) &&
(iCol == m_iCurrentCol)) {
// Start editing the property name if we are not already editing it.
if (!IsEditingCell()) {
BeginCellEditing();
}
}
}
//*****************************************************************************
// CPropGrid::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 CPropGrid::OnRowKeyDown(
/* in */ int iRow,
/* in */ UINT nChar,
/* in */ UINT nRepCnt,
/* in */ UINT nFlags)
{
switch(nChar) {
case VK_DELETE:
if (CanEditValuesOnly()) {
MessageBeep(MB_ICONEXCLAMATION);
}
else {
DeleteProperty(iRow);
}
return TRUE;
}
// We don't handle this event.
return FALSE;
}
//***********************************************************
// CPropGrid::DeleteProperty
//
// Delete the specified property if one is selected, otherwise
// do nothing.
//
// Parameters:
// [in] const int iRow
// The index of the row containing the property to delete.
//
// Returns:
// Nothing.
//
//************************************************************
void CPropGrid::DeleteProperty(const int iRow)
{
IWbemClassObject* pco = CurrentObject();
if (pco == NULL) {
return;
}
SCODE sc = S_OK;
CString sHmmStatus;
if (m_bIsSystemClass) {
CString sMessage;
sMessage.LoadString(IDS_ERR_SYSCLASS_EDIT);
HmmvErrorMsgStr(sMessage, E_FAIL, FALSE, NULL, _T(__FILE__), __LINE__);
return;
}
// Check to see if we're deleting a property
int iLastRow = LastRowContainingData();
if (iLastRow == NULL_INDEX || m_iCurrentRow > iLastRow) {
// The selection may be on the empty row at the bottom of the grid.
// If this is so, do nothing.
return;
}
CGridCell* pgcName = &GetAt(iRow, ICOL_PROP_NAME);
COleVariant varName;
CIMTYPE cimtypeName = 0;
pgcName->GetValue(varName, cimtypeName);
ASSERT(cimtypeName == CIM_STRING);
BSTR bstrName = varName.bstrVal;
if (IsSystemProperty(bstrName)) {
HmmvErrorMsg(IDS_ERR_CANT_DELETE_SYSTEM_PROPERTY, sc, FALSE, NULL, _T(__FILE__), __LINE__);
return;
}
CString sName;
sName = bstrName;
BOOL bDeleteModifiedGrid = FALSE;
CString sFormat;
LPTSTR pszMessage = m_psv->MessageBuffer();
sFormat.LoadString(IDS_PROMPT_OK_TO_DELETE_PROPERTY);
_stprintf(m_psv->MessageBuffer(), (LPCTSTR)sFormat, (LPCTSTR) sName);
int iResult = HmmvMessageBox(pszMessage, MB_OKCANCEL | MB_SETFOREGROUND);
if (iResult == IDOK) {
ASSERT(varName.vt == VT_BSTR);
sc = DoDelete(pco, varName.bstrVal);
switch(sc) {
case WBEM_S_RESET_TO_DEFAULT:
LoadProperty(iRow, varName.bstrVal);
bDeleteModifiedGrid = TRUE;
sFormat.LoadString(IDS_ERR_OBJECT_DELETE_RESET_TO_DEFAULT);
_stprintf(pszMessage, (LPCTSTR) sFormat, (LPCTSTR) sName);
HmmvErrorMsgStr(pszMessage, sc, FALSE, NULL, _T(__FILE__), __LINE__);
m_bModified = TRUE;
m_psv->NotifyDataChange();
break;
case WBEM_S_NO_ERROR:
default:
if (FAILED(sc)) {
// Generate the "can't delete" message, then append the status info.
sFormat.LoadString(IDS_ERR_OBJECT_DELETE_FAILED);
_stprintf(pszMessage, (LPCTSTR) sFormat, (LPCTSTR) sName);
HmmvErrorMsgStr(pszMessage, sc, FALSE, NULL, _T(__FILE__), __LINE__);
}
else {
DeleteRowAt(iRow);
iLastRow = LastRowContainingData();
if (iLastRow == NULL_INDEX) {
m_iCurrentRow = NULL_INDEX;
m_iCurrentCol = NULL_INDEX;
}
else if (m_iCurrentRow > iLastRow) {
m_iCurrentRow = iLastRow;
}
SelectCell(m_iCurrentRow, m_iCurrentCol);
bDeleteModifiedGrid = TRUE;
}
break;
}
}
if (bDeleteModifiedGrid) {
m_psv->NotifyViewModified();
RedrawWindow();
m_bModified = TRUE;
m_psv->NotifyDataChange();
}
}
//*****************************************************************************
// CPropGrid::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 CPropGrid::OnCellChar(int iRow, int iCol, UINT nChar, UINT nRepCnt, UINT nFlags)
{
EnsureRowVisible(iRow);
// Check to see if we are on the "empty" row at the bottom of the grid.
// If so, then create a new property.
int iEmptyRow = IndexOfEmptyRow();
if (iEmptyRow != NULL_INDEX && m_iCurrentRow == iEmptyRow) {
CDisableModifyCreate DisableModifyCreate(this);
BOOL bGenerateDefaultName = iCol != ICOL_PROP_NAME;
CreateNewProperty(bGenerateDefaultName);
}
// We don't handle this event.
return FALSE;
}
//****************************************************************
// CPropGrid::OnCellEditContextMenu
//
// This method is called when an OnContextMenu event is handled by
// the cell editor. This is useful because the cell editor will pass
// commands to the CGrid class that appear in customized context menus
// for commands it does not directly handle.
//
// Parameters:
// [in] CWnd* pwnd
//
// [in] CPoint ptContextMenu
// The point where the context menu click occurred in screen
// coordinates.
//
// Returns:
// BOOL
// TRUE if this class will track the context menu, FALSE if the CellEditor
// should track the context menu and pass commands from the context menu
// on to the CGrid class if the user selects a command from the context
// menu that the cell editor doesn't handle directly.
//
//******************************************************************
BOOL CPropGrid::OnCellEditContextMenu(CWnd* pwnd, CPoint ptContextMenu)
{
SyncCellEditor();
m_ptContextMenu = ptContextMenu;
ScreenToClient(&m_ptContextMenu);
// Let the cell editor track the context menu and handle commands such
// as cut, copy and paste directly.
return FALSE;
}
//*******************************************************************
// CPropGrid::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 CPropGrid::OnContextMenu(CWnd* pwnd, CPoint ptContextMenu)
{
// CG: This function was added by the Pop-up Menu component
SyncCellEditor();
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;
}
CMenu menu;
VERIFY(menu.LoadMenu(CG_IDR_POPUP_PROP_GRID));
CMenu* pPopup = menu.GetSubMenu(0);
ASSERT(pPopup != NULL);
if (iRow == NULL_INDEX) {
// If no object is selected, then there is nothing to do.
if (CurrentObject() == NULL) {
return;
}
// Remove all the property specific items
pPopup->RemoveMenu( ID_CMD_SET_CELL_TO_NULL, MF_BYCOMMAND);
pPopup->RemoveMenu(ID_CMD_CREATE_OBJECT, MF_BYCOMMAND);
pPopup->RemoveMenu(ID_CMD_CREATE_VALUE, MF_BYCOMMAND);
pPopup->EnableMenuItem(ID_CMD_SHOW_PROP_ATTRIBUTES, MF_DISABLED | MF_GRAYED);
pPopup->RemoveMenu(ID_CMD_GOTO_OBJECT, MF_BYCOMMAND);
OnBuildContextMenuEmptyRegion(pPopup, iRow);
}
else {
if ((iCol != ICOL_PROP_VALUE) || (iRow == NULL_INDEX)) {
pPopup->RemoveMenu( ID_CMD_SET_CELL_TO_NULL, MF_BYCOMMAND);
}
else {
if (iCol != NULL_INDEX) {
ASSERT(iCol == ICOL_PROP_VALUE);
CGridCell& gc = GetAt(iRow, iCol);
if (gc.IsNull() || (gc.GetFlags() & CELLFLAG_READONLY) || (gc.GetFlags() & CELLFLAG_NOTNULL)) {
pPopup->EnableMenuItem(ID_CMD_SET_CELL_TO_NULL, MF_DISABLED | MF_GRAYED);
}
}
}
BOOL bCanShowPropQualifiers = FALSE;
if ((iRow != NULL_INDEX)) {
CGridCell& gc = GetAt(iRow, ICOL_PROP_NAME);
COleVariant varPropName;
CIMTYPE cimtype = 0;
gc.GetValue(varPropName, cimtype);
if (varPropName.vt == VT_BSTR) {
if (!IsSystemProperty(varPropName.bstrVal)) {
bCanShowPropQualifiers = TRUE;
}
}
}
if (!bCanShowPropQualifiers) {
pPopup->EnableMenuItem(ID_CMD_SHOW_PROP_ATTRIBUTES, bCanShowPropQualifiers ? MF_ENABLED : MF_DISABLED | MF_GRAYED);
}
SetMenuDefaultItem(pPopup->GetSafeHmenu(),
ID_CMD_SHOW_PROP_ATTRIBUTES,
FALSE);
// store for the cmd handlers.
m_curRow = &GetRowAt(iRow);
OnBuildContextMenu(pPopup, iRow);
} // if (iRow == NULL_INDEX)
pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON,
ptContextMenu.x, ptContextMenu.y,
this);
}
//--------------------------------------------------------------------------------
void CPropGrid::OnBuildContextMenu(CMenu *pPopup,
int iRow)
{
CGridCell *gcValue = NULL;
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 (bIsReadonly || !(bCanCreateObject || bCanCreateArray))
{
pPopup->RemoveMenu(ID_CMD_CREATE_VALUE, MF_BYCOMMAND);
}
CGridCell* pgcValue = &GetAt(iRow, ICOL_PROP_VALUE);
COleVariant varObjectPath;
CIMTYPE cimtype = 0;
pgcValue->GetValue(varObjectPath, cimtype);
BOOL bObjectPathIsEmpty = TRUE;
if (varObjectPath.vt == VT_BSTR) {
CString sObjectPath;
sObjectPath = varObjectPath.bstrVal;
if (!sObjectPath.IsEmpty()) {
bObjectPathIsEmpty = FALSE;
}
}
if (bIsReadonly || !(cimtype == CIM_REFERENCE) || bObjectPathIsEmpty) {
pPopup->RemoveMenu(ID_CMD_GOTO_OBJECT, MF_BYCOMMAND);
}
}
else
{
pPopup->RemoveMenu(ID_CMD_CREATE_VALUE, MF_BYCOMMAND);
}
}
void CPropGrid::OnBuildContextMenuEmptyRegion(CMenu *pPopup, int iRow)
{
// This virtual method allows derived classes to override the context
// menu that is displayed when the user clicks over an empty part of
// the grid.
// Do nothing, but allow derived classes to override
}
//************************************************************************
// CPropGrid::PreTranslateMessage
//
// PreTranslateMessage is hooked out to detect the OnContextMenu event.
//
// Parameters:
// See the MFC documentation.
//
// Returns:
// TRUE if the message is handled here.
//
//*************************************************************************
BOOL CPropGrid::PreTranslateMessage(MSG* pMsg)
{
#if 0
// 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;
}
}
#endif //0
return CGrid::PreTranslateMessage(pMsg);
}
//************************************************************
// CPropGrid::ShowPropertyQualifiers
//
// Display the property qualifiers dialog.
//
// Parameters:
// int iRow
// The row containing the desired property.
//
// Returns:
// Nothing.
//
//************************************************************
bool CPropGrid::ReadOnlyQualifiers()
{
return false;
}
void CPropGrid::ShowPropertyQualifiers(int iRow)
{
IWbemClassObject* pco = CurrentObject();
if (pco == NULL)
{
HmmvErrorMsg(IDS_ERR_TRANSPORT_FAILURE,
WBEM_E_TRANSPORT_FAILURE,
TRUE, NULL, _T(__FILE__), __LINE__);
return;
}
CGridSync sync(this);
SCODE sc;
sc = SyncCellEditor();
if (FAILED(sc)) {
if (!m_bShowingInvalidCellMessage) {
m_bShowingInvalidCellMessage = TRUE;
HmmvErrorMsg(IDS_ERR_INVALID_CELL_VALUE, sc,
FALSE, NULL, _T(__FILE__), __LINE__);
m_bShowingInvalidCellMessage = FALSE;
}
return;
}
if (m_iCurrentRow != NULL_INDEX) {
PutProperty(m_iCurrentRow);
}
// Get the property name, then, the property
IWbemQualifierSet* pqs = NULL;
COleVariant varPropName;
CIMTYPE cimtypePropName = 0;
GetAt(iRow, ICOL_PROP_NAME).GetValue(varPropName, cimtypePropName);
ASSERT(cimtypePropName == CIM_STRING);
// Get the initial cimtype so that we can see if it changed during the edit.
sc = DoGetPropertyQualifierSet(pco, varPropName.bstrVal, &pqs);
if (FAILED(sc)) {
// !!!CR: We need an error message here.
return;
}
CString sCimtypePreEdit;
sc = ::GetCimtype(pqs, sCimtypePreEdit);
BOOL bWasReadOnly = TRUE;
CGridCell* pgcValue = NULL;
if(HasCol(ICOL_PROP_VALUE))
{
pgcValue = &GetAt(iRow, ICOL_PROP_VALUE);
bWasReadOnly = pgcValue->GetFlags() & CELLFLAG_READONLY;
}
HWND hwndFocus1 = ::GetFocus();
// Note that the current object will change unless the user clicks the cancel
// button. This is because a clone of the current object is actually edited within
// the property sheet and the clone replaces the current object if OK or APPLY is
// clicked.
// CPsQualifiers sheet(m_psv, NULL, !HasCol(ICOL_PROP_TYPE), this);
INT_PTR iResult = DoEditRowQualifier(varPropName.bstrVal, ReadOnlyQualifiers(), pco);
pqs->Release();
pqs = NULL;
// Restore the focus to where it was before we put up the
// dialog.
if (::IsWindow(hwndFocus1)) {
::SetFocus(hwndFocus1);
}
pco = CurrentObject();
if (pco == NULL) {
return;
}
// Get the initial cimtype so that we can see if it changed during the edit.
sc = DoGetPropertyQualifierSet(pco, varPropName.bstrVal, &pqs);
if (FAILED(sc)) {
// !!!CR: We need an error message here.
return;
}
CString sCimtypePostEdit;
sc = ::GetCimtype(pqs, sCimtypePostEdit);
if (sCimtypePreEdit.CompareNoCase(sCimtypePostEdit) != 0) {
// The property's cimtype changed, so update the type field
// and change its VT_TYPE.
if(HasCol(ICOL_PROP_TYPE))
{
CGridCell* pgcType = &GetAt(iRow, ICOL_PROP_TYPE);
pgcType->SetValue(CELLTYPE_CIMTYPE, sCimtypePostEdit, CIM_STRING);
RefreshCellEditor();
OnChangedCimtype(iRow, ICOL_PROP_TYPE);
RedrawCell(iRow, ICOL_PROP_TYPE);
RedrawCell(iRow, ICOL_PROP_VALUE);
}
}
pqs->Release();
m_psv->NotifyViewModified();
// Check to see if the flag's read-only qualifier changed. If so,
// update the read-only characteristics of the cell.
BOOL bIsReadOnly = ValueShouldBeReadOnly(varPropName.bstrVal);
if (pgcValue && ((bIsReadOnly && !bWasReadOnly) || (!bIsReadOnly && bWasReadOnly)))
{
pgcValue->SetFlags(CELLFLAG_READONLY, bIsReadOnly ? CELLFLAG_READONLY : 0);
RefreshCellEditor();
}
CBSTR bstrQualifier;
bstrQualifier = _T("not_null");
BOOL bNotNull = ::GetBoolPropertyQualifier(sc, pco, varPropName.bstrVal, (BSTR) bstrQualifier);
if (SUCCEEDED(sc)) {
pgcValue->SetFlags(CELLFLAG_NOTNULL, bNotNull ? CELLFLAG_NOTNULL : 0);
}
// for date-time types, check for interval qualifier.
if(pgcValue)
{
CIMTYPE cimtypeValue = (CIMTYPE) pgcValue->type();
if(cimtypeValue == CIM_DATETIME)
{
BOOL bIsInterval = FALSE;
CBSTR bstrQualifier(_T("Subtype"));
CBSTR bstrValue(_T("Interval"));
bIsInterval = GetbstrPropertyQualifier(sc, pco,
varPropName.bstrVal,
(BSTR)bstrQualifier,
(BSTR)bstrValue);
pgcValue->SetFlags(CELLFLAG_INTERVAL, bIsInterval ? CELLFLAG_INTERVAL : 0);
}
}
// When editing a class, it is possible to have a property that
// is marked read-only and still be able to edit the value.
// Thus, we want the property marker to show up as read-only
// even though it may be possible to edit the value while editing
// a class.
CGridRow& row = GetRowAt(iRow);
row.SetReadonly(bIsReadOnly);
BOOL bReadonlyTemp = PropertyIsReadOnly(pco, varPropName.bstrVal);
row.SetReadonly(bReadonlyTemp);
SetPropmarkers(iRow, pco, TRUE);
}
//*******************************************************************
// CPropGrid::DoEditRowQualifier
//
// Edit the qulifiers for a row in the grid. This is a virtual function
// that you can override for different grid types. For example, the method parameter
// grid overrides this method so that method parameter qualifier editing can be
// done properly.
//
// Parameters:
// [in] BSTR bstrPropName
// The name of the property being edited.
//
// [in] BOOL bReadOnly
// TRUE if the property is read only.
//
// [in] IWbemClassObject* pco
// Pointer to the WBEM class object being edited.
//
// Returns:
// int
// Status indicating whether or not the property sheet was canceled.
//
//*************************************************************************
INT_PTR CPropGrid::DoEditRowQualifier(BSTR bstrPropName, BOOL bReadOnly, IWbemClassObject* pco)
{
CPsQualifiers sheet(m_psv, NULL, !HasCol(ICOL_PROP_TYPE), this);
BOOL bMethod = (MEHOD_GRID == GetPropGridType());
INT_PTR iResult = sheet.EditPropertyQualifiers(bstrPropName, bMethod,
ReadOnlyQualifiers(),
pco);
return iResult;
}
//**************************************************************
// CPropGrid::KeyCellClicked
//
// Control comes here when the user clicks the mouse in the
// cell that contains the key icon. This is taken as a request
// to flip key qualifier on or off, but we display a message box
// to verify that this is in fact what the user wants to do.
//
// Parameters:
// [in] int iRow
// The row where the user clicked.
//
// Returns:
// Nothing.
//
//*************************************************************
void CPropGrid::KeyCellClicked(int iRow)
{
int iEmptyRow = IndexOfEmptyRow();
if (iRow == iEmptyRow) {
return;
}
CGridCell* pgc = &GetAt(iRow, ICOL_PROP_KEY);
CellType type = pgc->GetType();
if (type != CELLTYPE_PROPMARKER) {
return;
}
if (!IsInSchemaStudioMode()) {
return;
}
if (!m_psv->ObjectIsClass()) {
return;
}
// Can't edit system properties.
CGridCell* pgcFlavor = &GetAt(iRow, ICOL_PROP_FLAVOR);
PropMarker markerFlavor = pgcFlavor->GetPropmarker();
BOOL bIsSystemProp = FALSE;
switch(markerFlavor) {
case PROPMARKER_RSYS:
case PROPMARKER_SYS:
bIsSystemProp = TRUE;
}
CString sMessage;
CString sTitle;
sTitle.LoadString(IDS_EDIT_KEY_QUALIFIER);
CWnd* pwndFocus;
// Editing the key qualifier is allowed only in schema studio mode.
BOOL bCanEdit = TRUE;
int iResult;
if (!m_psv->ObjectIsClass() ||
m_bIsSystemClass ||
bIsSystemProp) {
sMessage.LoadString(IDS_PREVENT_KEY_QUAL_EDIT);
pwndFocus = GetFocus();
iResult = MessageBox(sMessage, sTitle, MB_OK);
if (pwndFocus != NULL) {
pwndFocus->SetFocus();
}
return;
}
PropMarker marker = pgc->GetPropmarker();
if (marker == PROPMARKER_NONE) {
sMessage.LoadString(IDS_QUERY_ADD_KEY_QUALIFIER);
pwndFocus = GetFocus();
iResult = MessageBox(sMessage, sTitle, MB_OKCANCEL);
if (pwndFocus != NULL) {
pwndFocus->SetFocus();
}
if (iResult == IDCANCEL) {
return;
}
AddKeyQualifier(iRow);
}
else {
sMessage.LoadString(IDS_QUERY_REMOVE_KEY_QUALIFIER);
pwndFocus = GetFocus();
iResult = MessageBox(sMessage, sTitle, MB_OKCANCEL);
if (pwndFocus != NULL) {
pwndFocus->SetFocus();
}
if (iResult == IDCANCEL) {
return;
}
RemoveKeyQualifier(iRow);
}
CSelection& sel = m_psv->Selection();
sel.UpdateCreateDeleteFlags();
}
//**************************************************************
// CPropGrid::RemoveKeyQualifier
//
// Remove the "key" qualifier from this property's qualifiers.
//
// Parameters:
// [in] int iRow
// The row containing the property.
//
// Returns:
// Nothing.
//
//*************************************************************
void CPropGrid::RemoveKeyQualifier(int iRow)
{
IWbemClassObject* pco = CurrentObject();
if (pco == NULL) {
ASSERT(FALSE);
return;
}
CGridCell* pgc = &GetAt(iRow, ICOL_PROP_KEY);
CGridCell* pgcName = &GetAt(iRow, ICOL_PROP_NAME);
COleVariant varName;
CIMTYPE cimtype = 0;
pgcName->GetValue(varName, cimtype);
SCODE sc;
IWbemQualifierSet* pqs = NULL;
sc = DoGetPropertyQualifierSet(pco, varName.bstrVal, &pqs);
CString sMessage;
if (FAILED(sc)) {
sMessage.LoadString(IDS_ERR_NO_QUALIFIER_ACCESS);
HmmvErrorMsgStr(sMessage, sc, FALSE, NULL, _T(__FILE__), __LINE__);
return;
}
CString sQualName(_T("key"));
CBSTR bsQualName(_T("key"));
sc = pqs->Delete((BSTR) bsQualName);
pqs->Release();
if (FAILED(sc)) {
sMessage.LoadString(IDS_ERR_DELETE_KEY_QUALIFIER);
HmmvErrorMsgStr(sMessage, sc, FALSE, NULL, _T(__FILE__), __LINE__);
return;
}
pgc->SetPropmarker(PROPMARKER_NONE);
m_psv->NotifyDataChange();
RedrawCell(iRow, ICOL_PROP_KEY);
}
//**************************************************************
// CPropGrid::AddKeyQualifier
//
// Add the "key" qualifier to this property's qualifiers.
//
// Parameters:
// [in] int iRow
// The row containing the property.
//
// Returns:
// Nothing.
//
//*************************************************************
void CPropGrid::AddKeyQualifier(int iRow)
{
IWbemClassObject* pco = CurrentObject();
if (pco == NULL) {
ASSERT(FALSE);
return;
}
CGridCell* pgc = &GetAt(iRow, ICOL_PROP_KEY);
CGridCell* pgcName = &GetAt(iRow, ICOL_PROP_NAME);
COleVariant varName;
CIMTYPE cimtype = 0;
pgcName->GetValue(varName, cimtype);
IWbemQualifierSet* pqs = NULL;
SCODE sc;
sc = DoGetPropertyQualifierSet(pco, varName.bstrVal, &pqs);
CString sMessage;
if (FAILED(sc)) {
sMessage.LoadString(IDS_ERR_NO_QUALIFIER_ACCESS);
HmmvErrorMsgStr(sMessage, sc, FALSE, NULL, _T(__FILE__), __LINE__);
return;
}
CString sQualName("key");
COleVariant varQualName;
varQualName = "key";
COleVariant varQualValue;
varQualValue.vt = VT_BOOL;
varQualValue.boolVal = VARIANT_TRUE;
long lFlavor = WBEM_FLAVOR_FLAG_PROPAGATE_TO_DERIVED_CLASS |
WBEM_FLAVOR_FLAG_PROPAGATE_TO_INSTANCE;
sc = pqs->Put(varQualName.bstrVal, &varQualValue, lFlavor);
pqs->Release();
if (FAILED(sc)) {
sMessage.LoadString(IDS_ERR_ADD_KEY_QUALIFIER);
HmmvErrorMsgStr(sMessage, sc, FALSE, NULL, _T(__FILE__), __LINE__);
return;
}
m_psv->NotifyDataChange();
pgc->SetPropmarker(PROPMARKER_KEY);
RedrawCell(iRow, ICOL_PROP_KEY);
}
void CPropGrid::OnCmdSetCellToNull()
{
int iRow = NULL_INDEX;
int iCol = NULL_INDEX;
if (!PointToCell(m_ptContextMenu, iRow, iCol)) {
return;
}
if (iCol != ICOL_PROP_VALUE) {
return;
}
if (iRow == IndexOfEmptyRow()) {
return;
}
SyncCellEditor();
CGridCell& gc = GetAt(iRow, iCol);
if (!gc.IsNull()) {
gc.SetToNull();
gc.SetModified(TRUE);
// RedrawWindow();
}
RefreshCellEditor();
RedrawCell(iRow, iCol);
}
void CPropGrid::OnCmdCreateValue()
{
int iRow = NULL_INDEX;
int iCol = NULL_INDEX;
if (!PointToCell(m_ptContextMenu, iRow, iCol)) {
return;
}
if (iRow == IndexOfEmptyRow()) {
return;
}
SyncCellEditor();
CGridCell& gc = GetAt(iRow, ICOL_PROP_VALUE);
BOOL bIsNull = gc.IsNull();
BOOL bIsArray = gc.IsArray();
BOOL bIsObject = gc.IsObject();
if (!bIsNull) {
return;
}
if (bIsArray) {
gc.EditArray();
}
else if (bIsObject) {
gc.EditObject();
}
RedrawCell(iRow, ICOL_PROP_VALUE);
}
//************************************************************
// CPropGrid::ShowObjectQualifiers
//
// Display the object qualifiers dialog.
//
// Parameters:
// int iRow
// The row containing the desired property.
//
// Returns:
// Nothing.
//
//************************************************************
void CPropGrid::OnCmdShowObjectQualifiers()
{
m_psv->ShowObjectQualifiers();
}
//**************************************************************
// CPropGrid::OnCmdShowPropQualifiers
//
// Display the property qualifiers for the property at the mouse
// location.
//
// Parameters:
// None.
//
// Returns:
// Nothing.
//
//**************************************************************
void CPropGrid::OnCmdShowPropQualifiers()
{
int iRow, iCol;
BOOL bClickedCell;
bClickedCell = PointToCell(m_ptContextMenu, iRow, iCol);
if (!bClickedCell) {
BOOL bClickedRowHandle = PointToRowHandle(m_ptContextMenu, iRow);
if (!bClickedRowHandle) {
return;
}
}
if (iRow == IndexOfEmptyRow()) {
return;
}
ShowPropertyQualifiers(iRow);
}
//**************************************************************
// CPropGrid::OnCmdShowSelectedPropQualifiers
//
// Display the property qualifiers for the property at selected
// row.
//
// Parameters:
// None.
//
// Returns:
// Nothing.
//
//**************************************************************
void CPropGrid::OnCmdShowSelectedPropQualifiers()
{
int iRow = GetSelectedRow();
if (iRow == NULL_INDEX) {
return;
}
ShowPropertyQualifiers(iRow);
}
//***************************************************************
// CPropGrid::LastRowContainingData
//
// Return the index of the last row in the grid containing data.
//
// Parameters:
// None.
//
// Returns:
// Nothing.
//
//****************************************************************
long CPropGrid::LastRowContainingData()
{
long lMaxIndex = GetRows() - 1;
if (lMaxIndex < 0) {
return NULL_INDEX;
}
if (m_bHasEmptyRow) {
// We are in edit mode, so decrement the max index to adjust for
// the "empty" row at the bottom.
--lMaxIndex;
}
return lMaxIndex;
}
//************************************************************
// CPropGrid::Sync
//
// Put the property to the class object. This syncronizes what the
// user sees on the screen with what is in the HMOM class object.
//
// Parameters:
// None.
//
// Returns:
// SCODE
// S_OK if successful.
// HMOM status code if a failure occurs.
//
//**************************************************************
SCODE CPropGrid::Sync()
{
SCODE sc = S_OK;
if (CurrentObject()) {
if (SelectedRowWasModified()) {
sc = PutProperty(m_iCurrentRow);
}
}
return sc;
}
//*************************************************************
// CPropGrid::SomeCellIsSelected
//
// Check to see whether or not a cell is selected.
//
// Parameters:
// None.
//
// Returns:
// BOOL
// TRUE if some cell is selected, otherwise FALSE.
//
//*************************************************************
BOOL CPropGrid::SomeCellIsSelected()
{
return m_iCurrentRow!=NULL_INDEX && m_iCurrentCol!=NULL_INDEX;
}
//*********************************************************
// CPropGrid::SelectedRowWasModified
//
// Check to see whether or not the selected row was modified.
//
// Parameters:
// None.
//
// Returns:
// TRUE if the selected row was modified, FALSE otherwise. If no
// row is selected, return FALSE.
//
//**********************************************************
BOOL CPropGrid::SelectedRowWasModified()
{
if (m_iCurrentRow == NULL_INDEX) {
return FALSE;
}
else {
return RowWasModified(m_iCurrentRow);
}
}
//*****************************************************************
// CPropGrid::RowWasModified
//
// Check to see if the specified row was modified.
//
// Parameters:
// int iRow.
//
// Returns:
// TRUE if the selected row was modified, FALSE otherwise.
//*****************************************************************
BOOL CPropGrid::RowWasModified(int iRow)
{
CGridRow &gr = GetRowAt(iRow);
return gr.GetModified();
/* int nCols = GetCols();
for (int iCol=0; iCol<nCols; ++iCol) {
if (GetAt(iRow, iCol).GetModified()) {
return TRUE;
}
}
return FALSE; */
}
//*****************************************************************
// CPropGrid::IndexOfEmptyRow
//
// Return the index of the empty row at the bottom of the grid when
// the control is in edit mode.
//
// Parameters:
// None.
//
// Returns:
// long
// The index of the empty row if it exists, otherwise NULL_INDEX.
//
//******************************************************************
long CPropGrid::IndexOfEmptyRow()
{
if (m_bIsSystemClass) {
return NULL_INDEX;
}
if (m_psv->ObjectIsClass() && IsInSchemaStudioMode()) {
return GetRows() - 1;
}
return NULL_INDEX;
}
//*******************************************************************
// CPropGrid::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 CPropGrid::CompareRows(int iRow1, int iRow2, int iSortColumn)
{
int iResult;
switch (iSortColumn) {
case ICOL_PROP_KEY:
// Sort first by key
iResult = CompareCells(iRow1, iRow2, ICOL_PROP_KEY);
if (iResult != 0) {
return iResult;
}
// Then by name
iResult = CompareCells(iRow1, iRow2, ICOL_PROP_NAME);
if (iResult != 0) {
return iResult;
}
// Then by flavor
iResult = CompareCells(iRow1, iRow2, ICOL_PROP_FLAVOR);
if (iResult != 0) {
return iResult;
}
// Then by type
iResult = CompareCells(iRow1, iRow2, ICOL_PROP_TYPE);
if (iResult != 0) {
return iResult;
}
// Then by value.
iResult = CompareCells(iRow1, iRow2, ICOL_PROP_VALUE);
return iResult;
break;
case ICOL_PROP_FLAVOR:
// First by flavor
iResult = CompareCells(iRow1, iRow2, ICOL_PROP_FLAVOR);
if (iResult != 0) {
return iResult;
}
// Then by name
iResult = CompareCells(iRow1, iRow2, ICOL_PROP_NAME);
if (iResult != 0) {
return iResult;
}
// Then by key
iResult = CompareCells(iRow1, iRow2, ICOL_PROP_KEY);
if (iResult != 0) {
return iResult;
}
// Then by type
iResult = CompareCells(iRow1, iRow2, ICOL_PROP_TYPE);
if (iResult != 0) {
return iResult;
}
// Then by value.
iResult = CompareCells(iRow1, iRow2, ICOL_PROP_VALUE);
return iResult;
break;
case ICOL_PROP_NAME:
// Sort first by name
iResult = CompareCells(iRow1, iRow2, ICOL_PROP_NAME);
if (iResult != 0) {
return iResult;
}
// Then by key
iResult = CompareCells(iRow1, iRow2, ICOL_PROP_KEY);
if (iResult != 0) {
return iResult;
}
// Then by flavor
iResult = CompareCells(iRow1, iRow2, ICOL_PROP_FLAVOR);
if (iResult != 0) {
return iResult;
}
// Then by type
iResult = CompareCells(iRow1, iRow2, ICOL_PROP_TYPE);
if (iResult != 0) {
return iResult;
}
// Then by value.
iResult = CompareCells(iRow1, iRow2, ICOL_PROP_VALUE);
return iResult;
break;
case ICOL_PROP_TYPE:
// Sort first by type
iResult = CompareCells(iRow1, iRow2, ICOL_PROP_TYPE);
if (iResult != 0) {
return iResult;
}
// Then by name
iResult = CompareCells(iRow1, iRow2, ICOL_PROP_NAME);
if (iResult != 0) {
return iResult;
}
// Then by key
iResult = CompareCells(iRow1, iRow2, ICOL_PROP_KEY);
if (iResult != 0) {
return iResult;
}
// Then by flavor
iResult = CompareCells(iRow1, iRow2, ICOL_PROP_FLAVOR);
if (iResult != 0) {
return iResult;
}
// Then by value.
iResult = CompareCells(iRow1, iRow2, ICOL_PROP_VALUE);
return iResult;
break;
case ICOL_PROP_VALUE:
// Sort first by value
iResult = CompareCells(iRow1, iRow2, ICOL_PROP_VALUE);
if (iResult != 0) {
return iResult;
}
// Then by name
iResult = CompareCells(iRow1, iRow2, ICOL_PROP_NAME);
if (iResult != 0) {
return iResult;
}
// Then by key
iResult = CompareCells(iRow1, iRow2, ICOL_PROP_KEY);
if (iResult != 0) {
return iResult;
}
// Then by flavor
iResult = CompareCells(iRow1, iRow2, ICOL_PROP_FLAVOR);
if (iResult != 0) {
return iResult;
}
// Then by type
iResult = CompareCells(iRow1, iRow2, ICOL_PROP_TYPE);
return iResult;
break;
}
return 0;
}
//**********************************************************************
// CPropGrid::OnHeaderItemClick
//
// Catch the "header item clicked" notification message by overriding
// the base class' virtual method.
//
// Parameters:
// int iColumn
// The index of the column that was clicked.
//
// Returns:
// Nothing.
//
//***********************************************************************
void CPropGrid::OnHeaderItemClick(int iColumn)
{
BOOL bAscending;
int iLastRow = LastRowContainingData();
if (iLastRow > 0) {
SyncCellEditor();
SortGrid(0, iLastRow, iColumn);
bAscending = ColumnIsAscending(iColumn);
switch(iColumn) {
case ICOL_PROP_NAME:
case ICOL_PROP_TYPE:
case ICOL_PROP_VALUE:
SetHeaderSortIndicator(iColumn, bAscending);
break;
default:
SetHeaderSortIndicator(iColumn, bAscending, TRUE);
break;
}
m_iCurrentRow = GetSelectedRow();
}
}
//*********************************************************************
// CPropGrid::GetNotify
//
// This virtual method overrides the CGrid's GetNotify method. This
// gives the derived class a way to control what gets notified when
// events such as grid modification occur.
//
// Other classes need to be notified when the content of the grid
// changes and so on. We will distribute such events globally via
// the main control's global notification structure.
//
// The notification classes are used so that the grid doesn't have
// to have any knowledge of the classes that want to be notified.
//
// Parameters:
// None.
//
// Returns:
// CDistributeEvent*
// A pointer to the main control's global notification class.
//
//*********************************************************************
CDistributeEvent* CPropGrid::GetNotify()
{
return m_psv->GetGlobalNotify();
}
//**********************************************************
// CPropGrid::CatchEvent
//
// Catch events so that the association graph is notified
// when there are changes to properties and so on so that
// the graph knows when it needs to be updated.
//
// Parameters:
// long lEvent
// The event id.
//
// Returns:
// Nothing.
//
//**********************************************************
void CPropGrid::CatchEvent(long lEvent)
{
int nRows, iRow;
CGridCell* pgcValue;
CGridCell* pgcName;
CIMTYPE cimtypeName = 0;
BOOL bReadOnly;
BOOL bWasReadOnly;
COleVariant varPropName;
int iSelectedRow;
int iSelectedCol;
switch(lEvent) {
case NOTIFY_OBJECT_SAVE_SUCCESSFUL:
nRows = GetRows();
for (iRow=0; iRow < nRows; ++iRow) {
SetCellModified(iRow, ICOL_PROP_VALUE, FALSE);
SetCellModified(iRow, ICOL_PROP_TYPE, FALSE);
SetCellModified(iRow, ICOL_PROP_NAME, FALSE);
pgcName = &GetAt(iRow, ICOL_PROP_NAME);
pgcName->GetValue(varPropName, cimtypeName);
bReadOnly = ValueShouldBeReadOnly(varPropName.bstrVal);
pgcValue = &GetAt(iRow, ICOL_PROP_VALUE);
bWasReadOnly = pgcValue->GetFlags() & CELLFLAG_READONLY;
if ((bWasReadOnly && !bReadOnly) || (!bWasReadOnly && bReadOnly) ) {
pgcValue->SetFlags(CELLFLAG_READONLY, bReadOnly ? CELLFLAG_READONLY : 0);
GetSelectedCell(iSelectedRow, iSelectedCol);
if (iRow == iSelectedRow && ICOL_PROP_VALUE==iSelectedCol) {
RefreshCellEditor();
}
}
}
RedrawWindow();
break;
}
}
//**************************************************************
// CPropGrid::CanEditValuesOnly
//
// Check to see whether or not the user is allowed to do more
// than just edit values.
//
// Parameters:
// None.
//
// Returns:
// BOOL
// TRUE if the user is restricted to editing values only.
//
//***************************************************************
BOOL CPropGrid::CanEditValuesOnly()
{
BOOL bEditValuesOnly = !m_psv->ObjectIsClass() || !IsInSchemaStudioMode();
return bEditValuesOnly;
}
//*******************************************************
// CPropGrid::ValueShouldBeReadOnly
//
// Check to see whether or not the value should be read-only.
//
// 1. System properties are always read-only.
// 2. Properties with a "READ" qualifier set to TRUE are read-only if this
// is not a newly created object.
// 3. Properties with a "key" qualifier set to TRUE are read-only if this
// is not a newly created object.
//
// Parameters:
// [in] BSTR bstrPropName
// The property name
//
// Returns:
// BOOL
// TRUE if the property value should be read-only.
//
//********************************************************
BOOL CPropGrid::ValueShouldBeReadOnly(BSTR bstrPropName)
{
if (IsSystemProperty(bstrPropName)) {
return TRUE;
}
if (m_psv->ObjectIsClass()) {
return FALSE;
}
if (m_psv->GetEditMode() == EDITMODE_READONLY) {
return TRUE;
}
SCODE sc;
BOOL bIsNewlyCreatedObject = m_psv->ObjectIsNewlyCreated(sc);
ASSERT(SUCCEEDED(sc));
if (bIsNewlyCreatedObject) {
return FALSE;
}
BOOL bIsReadOnly = FALSE;
IWbemQualifierSet* pqs = NULL;
sc = CurrentObject()->GetPropertyQualifierSet(bstrPropName, &pqs);
if (SUCCEEDED(sc) && (pqs!=NULL)) {
LONG lFlavor;
COleVariant varValue;
CBSTR bsPropname;
bsPropname = _T("read");
sc = pqs->Get((CBSTR) bsPropname, 0, &varValue, &lFlavor);
if (SUCCEEDED(sc)) {
if (varValue.vt == VT_BOOL) {
if (!bIsNewlyCreatedObject) {
bIsReadOnly = varValue.boolVal;
if (bIsReadOnly) {
// We now know that the property was marked with a "read" capability.
// If it also has a "write" capability, then it is read/write.
varValue.Clear();
lFlavor = 0;
CBSTR bsQualName;
bsQualName = _T("write");
sc = pqs->Get((BSTR) bsQualName, 0, &varValue, &lFlavor);
if (SUCCEEDED(sc)) {
if (varValue.vt == VT_BOOL) {
if (varValue.boolVal) {
// The property is read/write and not just "read".
bIsReadOnly = FALSE;
}
}
}
} // bIsReadOnly
}
}
}
CBSTR bsQualName;
bsQualName = _T("key");
sc = pqs->Get((BSTR) bsQualName, 0, &varValue, &lFlavor);
if (SUCCEEDED(sc)) {
ASSERT(varValue.vt == VT_BOOL);
if (varValue.vt == VT_BOOL) {
if (varValue.boolVal) {
bIsReadOnly = TRUE;
}
}
}
pqs->Release();
}
return bIsReadOnly;
}
BOOL CPropGrid::GetCellEditContextMenu(int iRow, int iCol, CWnd*& pwndTarget, CMenu& menu, BOOL& bWantEditCommands)
{
bWantEditCommands = FALSE;
VERIFY(menu.LoadMenu(CG_IDR_CELL_EDIT_EXTEND1));
pwndTarget = this;
return TRUE;
}
void CPropGrid::ModifyCellEditContextMenu(int iRow, int iCol, CMenu& menu)
{
CMenu* pPopup = menu.GetSubMenu(0);
ASSERT(pPopup != NULL);
if (iRow == IndexOfEmptyRow()) {
pPopup->EnableMenuItem(ID_CMD_SHOW_SELECTED_PROP_ATTRIBUTES, MF_DISABLED | MF_GRAYED);
pPopup->RemoveMenu( ID_CMD_SET_CELL_TO_NULL, MF_BYCOMMAND);
pPopup->RemoveMenu(ID_CMD_GOTO_OBJECT, MF_BYCOMMAND);
// store for the cmd handlers.
m_curRow = &GetRowAt(iRow);
OnBuildContextMenu(pPopup, iRow);
return;
}
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);
SetMenuDefaultItem(pPopup->GetSafeHmenu(),
ID_CMD_SHOW_SELECTED_PROP_ATTRIBUTES,
FALSE);
CGridCell *gcValue = NULL;
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 = TRUE;
CGridCell& gc = GetAt(iRow, iCol);
DWORD dwFlags = gc.GetFlags();
if ((dwFlags & CELLFLAG_READONLY) || (dwFlags & CELLFLAG_NOTNULL))
{
bCanSetToNull = FALSE;
}
if (gc.IsNull()) {
bCanSetToNull = FALSE;
}
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);
}
BOOL CPropGrid::IsInSchemaStudioMode()
{
return m_psv->CanEdit();
}
void CPropGrid::OnGetIWbemServices(LPCTSTR szNamespace, VARIANT FAR* pvarUpdatePointer, VARIANT FAR* pvarServices, VARIANT FAR* pvarSc, VARIANT FAR* pvarUserCancel)
{
m_psv->GetWbemServices(szNamespace, pvarUpdatePointer, pvarServices, pvarSc, pvarUserCancel);
}
#if 0
void CPropGrid::EditCellObject(CGridCell* pgc, int iRow, int iCol)
{
ASSERT(iRow != NULL_INDEX);
ASSERT(iCol == ICOL_PROP_VALUE);
CSelection& sel = m_psv->Selection();
IWbemClassObject* pco = sel.GetClassObject();
if (pco == NULL) {
ASSERT(FALSE);
return;
}
CDlgObjectEditor dlg;
if (pgc->IsNull()) {
CString sCimtype;
SCODE sc = GetCimtype(iRow, sCimtype);
dlg.CreateEmbeddedObject(sCimtype, m_psv, pco, pgc);
RedrawCell(iRow, ICOL_PROP_VALUE);
}
else {
dlg.EditEmbeddedObject(m_psv, pco, pgc);
}
}
#endif //0
//*********************************************************
// CPropGrid::GetQualifierSet
//
// Get the qualifier set for the property stored at the
// given row.
//
// Parameters:
// [in] int iRow
//
// Returns:
// IWbemQualifierSet*
// A pointer to the qualifier set. NULL if the cimom
// failed to get the qualifier set.
//
//**********************************************************
IWbemQualifierSet* CPropGrid::GetQualifierSet(int iRow)
{
SCODE sc;
CGridCell& gcName = GetAt(iRow, ICOL_PROP_NAME);
COleVariant varPropname;
CIMTYPE cimtype = 0;
gcName.GetValue(varPropname, cimtype);
CSelection& sel = m_psv->Selection();
IWbemClassObject* pco = sel.GetClassObject();
IWbemQualifierSet* pqs = NULL;
sc = DoGetPropertyQualifierSet(pco, varPropname.bstrVal, &pqs);
if (SUCCEEDED(sc)) {
return pqs;
}
else {
return NULL;
}
}
SCODE CPropGrid::GetCimtype(int iRow, CString& sCimtype)
{
IWbemQualifierSet* pqs = GetQualifierSet(iRow);
if (pqs == NULL) {
return E_FAIL;
}
SCODE sc = ::GetCimtype(pqs, sCimtype);
pqs->Release();
return sc;
}
BOOL CPropGrid::PropertyExists(SCODE& sc, IWbemClassObject* pco, BSTR bstrPropName)
{
BOOL bExists = FALSE;
COleVariant var;
sc = DoGet(pco, NULL, bstrPropName, 0, &var, NULL, NULL);
if (SUCCEEDED(sc)) {
return TRUE;
}
if (sc == WBEM_E_NOT_FOUND) {
sc = S_OK;
}
return FALSE;
}
SCODE CPropGrid::CopyQualifierSets(IWbemClassObject* pco, BSTR bstrDst, BSTR bstrSrc)
{
IWbemQualifierSet* pqsSrc = NULL;
SCODE sc = DoGetPropertyQualifierSet(pco, bstrSrc, &pqsSrc);
if (FAILED(sc)) {
return E_FAIL;
}
IWbemQualifierSet* pqsDst = NULL;
sc = DoGetPropertyQualifierSet(pco, bstrDst, &pqsDst);
if (FAILED(sc)) {
pqsSrc->Release();
return E_FAIL;
}
HRESULT hr;
hr = pqsSrc->BeginEnumeration(0);
ASSERT(SUCCEEDED(hr));
BSTR bstrName;
COleVariant varValue;
LONG lFlavor;
while (TRUE) {
bstrName = NULL;
varValue.Clear();
lFlavor = 0;
hr = pqsSrc->Next(0, &bstrName, &varValue, &lFlavor);
if (hr == WBEM_S_NO_MORE_DATA) {
break;
}
ASSERT(SUCCEEDED(hr));
if (::IsEqualNoCase(bstrName, L"CIMTYPE")) {
continue;
}
hr = pqsDst->Put(bstrName, &varValue, lFlavor);
::SysFreeString(bstrName);
ASSERT(SUCCEEDED(hr));
}
pqsSrc->Release();
pqsDst->Release();
return S_OK;
}
//*********************************************************
// CPropGrid::CopyProperty
//
// Copy the specified property along with its qualifiers.
//
// Parameters:
// [in] IWbemClassObject* pco
// Pointer to the IWbemClassObject containing the property.
//
// [in] BSTR bstrDst
// The name of the destination property.
//
// [in] BSTR bstrSrc
// The name of the source property.
//
// Returns:
// SCODE
// S_OK if successful, a failure code otherwise.
//
//**********************************************************
SCODE CPropGrid::CopyProperty(IWbemClassObject* pco, BSTR bstrDst, BSTR bstrSrc)
{
COleVariant varValue;
CIMTYPE cimtypeValue;
SCODE sc = DoGet(pco, NULL, bstrSrc, 0, &varValue, &cimtypeValue, NULL);
if (FAILED(sc)) {
return E_FAIL;
}
// Destroy the destination property if it exists
sc = DoDelete(pco, bstrDst);
if (FAILED(sc)) {
if (sc != WBEM_E_NOT_FOUND) {
return sc;
}
}
// Copy the property's value, creating the property if it doesn't
// currently exist.
if (::IsClass(pco)) {
sc = DoPut(pco, NULL, bstrDst, 0,&varValue, cimtypeValue);
}
else {
sc = DoPut(pco, NULL, bstrDst, 0,&varValue, 0);
}
if (FAILED(sc)) {
return sc;
}
sc = CopyQualifierSets(pco, bstrDst, bstrSrc);
if (FAILED(sc)) {
DoDelete(pco, bstrDst);
}
return sc;
}
SCODE CPropGrid::RenameProperty(IWbemClassObject* pco, BSTR bstrNewName, BSTR bstrOldName)
{
CString sNewName;
CString sOldName;
sNewName = bstrNewName;
sOldName = bstrOldName;
COleVariant varTemp;
SCODE sc;
CString sFormat;
LPTSTR pszMessage = m_psv->MessageBuffer();
BOOL bExistsNew = PropertyExists(sc, pco, bstrNewName);
if (FAILED(sc)) {
ASSERT(FALSE);
return sc;
}
if (bExistsNew) {
// Duplicate property name.
sFormat.LoadString(IDS_ERR_DUPLICATE_PROPERTY_NAME);
_stprintf(pszMessage, (LPCTSTR) sFormat, (LPCTSTR) sNewName);
HmmvErrorMsgStr(pszMessage, S_OK, FALSE, NULL, _T(__FILE__), __LINE__);
return E_FAIL;
}
sc = CopyProperty(pco, bstrNewName, bstrOldName);
if (FAILED(sc)) {
sFormat.LoadString(IDS_ERR_RENAME_PROPERTY_FAILED);
_stprintf(pszMessage, (LPCTSTR) sFormat, (LPCTSTR) sOldName, (LPCTSTR) sNewName);
HmmvErrorMsgStr(pszMessage, sc, FALSE, NULL, _T(__FILE__), __LINE__);
return E_FAIL;
}
sc = DoDelete(pco, bstrOldName);
if (FAILED(sc)) {
// Failed to delete the old property. This is probably because
// the old property was inherited from its base class. In this
// event, we want to restore things back to their initial state.
DoDelete(pco, bstrNewName);
sFormat.LoadString(IDS_ERR_RENAME_PROPERTY_FAILED);
_stprintf(pszMessage, (LPCTSTR) sFormat, (LPCTSTR) sOldName, (LPCTSTR) sNewName);
HmmvErrorMsgStr(pszMessage, sc, FALSE, NULL, _T(__FILE__), __LINE__);
return sc;
}
return S_OK;
}
void CPropGrid::OnRequestUIActive()
{
m_psv->OnRequestUIActive();
}
void CPropGrid::OnSetFocus(CWnd* pOldWnd)
{
CWnd::OnSetFocus(pOldWnd);
// TODO: Add your message handler code here
if (!m_bUIActive)
{
m_bUIActive = TRUE;
OnRequestUIActive();
}
}
void CPropGrid::OnKillFocus(CWnd* pNewWnd)
{
CWnd::OnKillFocus(pNewWnd);
// TODO: Add your message handler code here
m_bUIActive = FALSE;
}
//*****************************************************************
// CPropGrid::GetWbemServicesForObject
//
// The grid calls this method just prior to invoking the object editor
// when editing an embedded object.
//
// Parameters:
// [in] int iRow
// The row index of the cell that contains the object pointer.
//
// [in] int iCol
// The column index of the cell that contains the object pointer.
//
// Returns:
// The WBEM services pointer for the server and namespace appropriate
// for the object.
//
//*******************************************************************
IWbemServices* CPropGrid::GetWbemServicesForObject(int iRow, int iCol)
{
CSelection& sel = m_psv->Selection();
IWbemServices* psvc = sel.GetWbemServicesForEmbeddedObject();
return psvc;
}
void CPropGrid::GetWbemServices(LPCTSTR szNamespace, VARIANT FAR* pvarUpdatePointer, VARIANT FAR* pvarServices, VARIANT FAR* pvarSc, VARIANT FAR* pvarUserCancel)
{
m_psv->GetWbemServices(szNamespace, pvarUpdatePointer, pvarServices, pvarSc, pvarUserCancel);
}
SCODE CPropGrid::GetObjectClass(CString& sClass, int iRow, int iCol)
{
sClass = "";
CIMTYPE cimtype = 0;
CString sCimtype;
CGridCell& gcType = GetAt(iRow, ICOL_PROP_TYPE);
gcType.GetValue(sCimtype, cimtype);
CString sObjectPrefix;
sObjectPrefix.LoadString(IDS_CIMTYPE_OBJECT_PREFIX);
if (IsPrefix(sObjectPrefix, sCimtype)) {
int nchClassname = sCimtype.GetLength() - sObjectPrefix.GetLength();
sClass = sCimtype.Right(nchClassname);
return S_OK;
}
else {
return E_FAIL;
}
}
SCODE CPropGrid::GetArrayName(CString& sName, int iRow, int iCol)
{
CIMTYPE cimtype = 0;
CGridCell& gc = GetAt(iRow, ICOL_PROP_NAME);
gc.GetValue(sName, cimtype);
return S_OK;
}
//**************************************************
// CPropGrid::PreModalDialog
//
// The grid class calls this method just prior to
// putting up a modal dialog. This has the
// potential for screwing up the COleControl unless
// you call COleControl::PreModalDialog.
//
// Parameters:
// None.
//
// Returns:
// Nothing.
//
//**************************************************
void CPropGrid::PreModalDialog()
{
if (m_psv) {
m_psv->PreModalDialog();
}
}
//**************************************************
// CPropGrid::PostModalDialog
//
// The grid class calls this method just after
// putting up a modal dialog. This has the
// potential for screwing up the COleControl unless
// you call COleControl::PostModalDialog.
//
// Parameters:
// None.
//
// Returns:
// Nothing.
//
//**************************************************
void CPropGrid::PostModalDialog()
{
if (m_psv) {
m_psv->PostModalDialog();
}
}
//**************************************************************
// CPropGrid::OnSize
//
// When the size of the window changes, the width of the columns
// need to be recalculated. The idea here is to make the grid
// appear to be a piece of paper where the size change just uncovers
// more of it when the window grows, or obscures part of it when the
// window shrinks.
//
// The first time the window is resized, the initial column widths
// should be set so that the name and value columns are given a
// reasonable portion of the available realestate.
//
//
// Paramters:
// See the MFC documentation.
//
// Returns:
// Nothing.
//
//*************************************************************
void CPropGrid::OnSize(UINT nType, int cx, int cy)
{
// Do nothing if no columns have been added yet or the width is zero or there
// is no window yet.
if ((!::IsWindow(m_hWnd)) || (cx <= 0) || (GetCols() != COLUMN_COUNT_PROPS)) {
CGrid::OnSize(nType, cx, cy);
return;
}
CRect rcClient;
GetClientRect(rcClient);
int cxPrev = rcClient.Width();
// Get the current values of all the column widths. We will
// modify some of them along the way and then resize all of
// the columns to the current value stored in these variables.
int cxPropKeyCol = ColWidth(ICOL_PROP_KEY);
int cxFlavorCol = ColWidth(ICOL_PROP_FLAVOR);
int cxNameCol = ColWidth(ICOL_PROP_NAME);
int cxTypeCol = ColWidth(ICOL_PROP_TYPE);
int cxValueCol = ColWidth(ICOL_PROP_VALUE);
int cxRowHandles = GetRowHandleWidth();
int cxColsTotal = cx;
if (cxColsTotal < 0) {
cxColsTotal = 0;
}
// First set the width of the name value columns.
// Give three quarters of the available space to the
// name and value fields. This space is split so that
// two-thirds of it is given to the value and one-third
// is given to the name.
float fx = (float) (((double) cxColsTotal) * 3.0 / 4.0);
cxNameCol = (int) (fx / 3.0);
cxValueCol = (int) (fx * (2.0 / 3.0));
// Now compute the width of the remaining columns. We try to
// keep the marker columns (key and flavor) the normal marker
// width, however if the type column is too narrow, take some
// space away from the markers.
int cxMiscCol = cxColsTotal - (cxNameCol + cxValueCol);
cxTypeCol = cxMiscCol - (CX_COL_PROPKEY + CX_COL_PROPMARKER);
if (cxTypeCol > CX_COL_TYPE) {
// The "type" column is wider than necessary, so give the extra
// space to the value column.
cxValueCol += cxTypeCol - CX_COL_TYPE;
}
else if (cxTypeCol < CX_COL_TYPE) {
// The type column is less than the ideal width, so distribute
// the available width between the property markers and the
// type column as best we can.
if (cxTypeCol < CX_COL_PROPMARKER) {
int cxMarker = cxMiscCol / 3;
cxTypeCol = cxMiscCol - (2 * cxMarker);
}
}
// We want to avoid resizing the columns when the user as set the column
// widths manually, however we may have set some column widths so small
// initially that they are virtually useless, so should then resize the
// the columns if the user grows the window.
BOOL bResizeCols = FALSE;
if ((ColWidth(ICOL_PROP_KEY) < CX_COL_PROPKEY) && (cxPropKeyCol >= CX_COL_PROPKEY)) {
bResizeCols = TRUE;
}
if ((ColWidth(ICOL_PROP_FLAVOR) < CX_COL_PROPMARKER) && (cxFlavorCol >= CX_COL_PROPMARKER)) {
bResizeCols = TRUE;
}
if ((ColWidth(ICOL_PROP_TYPE) < CX_COL_TYPE) && (cxTypeCol >= CX_COL_TYPE)) {
bResizeCols = TRUE;
}
if (!m_bDidInitialResize || bResizeCols)
{
SetColumnWidth(ICOL_PROP_NAME, cxNameCol, FALSE);
SetColumnWidth(ICOL_PROP_KEY, cxPropKeyCol, FALSE);
SetColumnWidth(ICOL_PROP_FLAVOR, cxFlavorCol, FALSE);
SetColumnWidth(ICOL_PROP_TYPE, cxTypeCol, FALSE);
SetColumnWidth(ICOL_PROP_VALUE, cxValueCol, FALSE);
}
m_bDidInitialResize = TRUE;
CGrid::OnSize(nType, cx, cy);
}
void CPropGrid::OnCmdGotoObject()
{
int iRow = NULL_INDEX;
int iCol = NULL_INDEX;
if (!PointToCell(m_ptContextMenu, iRow, iCol)) {
iCol = NULL_INDEX;
BOOL bClickedRowHandle = PointToRowHandle(m_ptContextMenu, iRow);
if (!bClickedRowHandle) {
return;
}
}
if (iRow == IndexOfEmptyRow()) {
return;
}
CGridCell* pgc = &GetAt(iRow, ICOL_PROP_VALUE);
COleVariant varObjectPath;
CIMTYPE cimtype = 0;
pgc->GetValue(varObjectPath, cimtype);
ASSERT(cimtype == CIM_REFERENCE);
if (cimtype != CIM_REFERENCE) {
return;
}
BOOL bNeedsSave = m_psv->QueryNeedsSave();
if (bNeedsSave) {
SCODE sc = m_psv->Save(TRUE, TRUE);
if (sc == E_FAIL) {
return;
}
}
// TODO: Add your command handler code here
m_psv->JumpToObjectPath(varObjectPath.bstrVal, TRUE);
}