// Copyright (c) 1997-2001 Microsoft Corporation, All Rights Reserved //*************************************************************************** // // (c) 1996 by Microsoft Corporation // // CellEdit.cpp // // This file implements a grid cell editor for the CGrid class used in hmmv // (the HMOM object viewer). This GridCell editor is customized for hmmv such // that it understands certain datatypes. // // This class could be generalized such that it could be used as a "generic" cell // editor base class so that different types of cell editors could be plugged // into the grid class. // // // a-larryf 17-Sept-96 Created. // //*************************************************************************** #include "precomp.h" #include "resource.h" #include "globals.h" #include "CellEdit.h" #include "grid.h" #include "gca.h" #include "gridhdr.h" #include "globals.h" #include "core.h" #include "utils.h" #include "notify.h" #include "DlgObjectType.h" #define CX_COMBO_DROP 16 // Width of the combo-drop button #define CX_COMBO_DROP_MARGIN 1 // Margin on right side of combo drop button #define CY_COMBO_DROP_MARGIN 1 // Margin on bottom side of combo drop botton #define CY_EDIT_LISTBOX_MAX 100 // The maximum height of the combo listbox #define CY_EDIT_LISTBOX_MIN 30 // The minimum height of the combo listbox #define CX_EDIT_LISTBOX_MIN 90 // The minimum width of the listbox #define CX_EDIT_LISTBOX_EXTEND 110 // The width of the listbox when extended #define CTL_C 3 //************************************************************************ // Define how the strings in the combo box are mapped back to variant type // values. This is necessary so that the type of buddy cells can be changed // when a cell containing a type is changed. // //************************************************************************ TMapStringToLong amapAttribType[] = { {IDS_ATTR_TYPE_BSTR, CIM_STRING}, {IDS_ATTR_TYPE_BOOL, CIM_BOOLEAN}, {IDS_ATTR_TYPE_I4, CIM_SINT32}, {IDS_ATTR_TYPE_R8, CIM_REAL64}, {IDS_ATTR_TYPE_BSTR_ARRAY, CIM_STRING | CIM_FLAG_ARRAY}, {IDS_ATTR_TYPE_BOOL_ARRAY, CIM_BOOLEAN | CIM_FLAG_ARRAY}, {IDS_ATTR_TYPE_I4_ARRAY, CIM_SINT32 | CIM_FLAG_ARRAY}, {IDS_ATTR_TYPE_R8_ARRAY, CIM_REAL64 | CIM_FLAG_ARRAY} }; CMapStringToLong mapAttribType; // CMapStringToLong mapCimType; //************************************************************* // String arrays for the strings that appear in the drop-down // combo for cells that have enumerated values. // // The strings in these arrays are loaded from the string table // by passing an array of the strings resource IDs to the CXStringArray // constructor. // //************************************************************* UINT auiCimtypeStrings[] = { IDS_CIMTYPE_UINT8, IDS_CIMTYPE_SINT8, // I2 IDS_CIMTYPE_UINT16, // VT_I4 Unsigned 16-bit integer IDS_CIMTYPE_CHAR16, // VT_I2 16 bit character. IDS_CIMTYPE_SINT16, // VT_I2 Signed 16-bit integer IDS_CIMTYPE_UINT32, // VT_I4 Unsigned 32-bit integer IDS_CIMTYPE_SINT32, // VT_I4 Signed 32-bit integer IDS_CIMTYPE_UINT64, // VT_BSTR Unsigned 64-bit integer IDS_CIMTYPE_SINT64, // VT_BSTR Signed 64-bit integer IDS_CIMTYPE_STRING, // VT_BSTR UCS-2 string IDS_CIMTYPE_BOOL, // VT_BOOL Boolean IDS_CIMTYPE_REAL32, // VT_R4 IEEE 4-byte floating-point IDS_CIMTYPE_REAL64, // VT_R8 IEEE 8-byte floating-point IDS_CIMTYPE_DATETIME, // VT_BSTR A string containing a date-time IDS_CIMTYPE_REF, // VT_BSTR Weakly-typed reference IDS_CIMTYPE_UINT8_ARRAY, IDS_CIMTYPE_SINT8_ARRAY, // I2 IDS_CIMTYPE_UINT16_ARRAY, // VT_I4 Unsigned 16-bit integer IDS_CIMTYPE_CHAR16_ARRAY, // VT_I2 16 bit character. IDS_CIMTYPE_SINT16_ARRAY, // VT_I2 Signed 16-bit integer IDS_CIMTYPE_UINT32_ARRAY, // VT_I4 Unsigned 32-bit integer IDS_CIMTYPE_SINT32_ARRAY, // VT_I4 Signed 32-bit integer IDS_CIMTYPE_UINT64_ARRAY, // VT_BSTR Unsigned 64-bit integer IDS_CIMTYPE_SINT64_ARRAY, // VT_BSTR Signed 64-bit integer IDS_CIMTYPE_STRING_ARRAY, // VT_BSTR UCS-2 string IDS_CIMTYPE_BOOL_ARRAY, // VT_BOOL Boolean IDS_CIMTYPE_REAL32_ARRAY, // VT_R4 IEEE 4-byte floating-point IDS_CIMTYPE_REAL64_ARRAY, // VT_R8 IEEE 8-byte floating-point IDS_CIMTYPE_DATETIME_ARRAY, // VT_BSTR A string containing a date-time IDS_CIMTYPE_REF_ARRAY, // VT_BSTR Weakly-typed reference IDS_CIMTYPE_OBJECT_ARRAY, // VT_UNKNOWN Weakly-typed embedded instance IDS_CIMTYPE_OBJECT_DLG }; UINT auiCimtypeScalarStrings[] = { IDS_CIMTYPE_UINT8, IDS_CIMTYPE_SINT8, // I2 IDS_CIMTYPE_UINT16, // VT_I4 Unsigned 16-bit integer IDS_CIMTYPE_CHAR16, // VT_I2 16 bit character IDS_CIMTYPE_SINT16, // VT_I2 Signed 16-bit integer IDS_CIMTYPE_UINT32, // VT_I4 Unsigned 32-bit integer IDS_CIMTYPE_SINT32, // VT_I4 Signed 32-bit integer IDS_CIMTYPE_UINT64, // VT_BSTR Unsigned 64-bit integer IDS_CIMTYPE_SINT64, // VT_BSTR Signed 64-bit integer IDS_CIMTYPE_STRING, // VT_BSTR UCS-2 string IDS_CIMTYPE_BOOL, // VT_BOOL Boolean IDS_CIMTYPE_REAL32, // VT_R4 IEEE 4-byte floating-point IDS_CIMTYPE_REAL64, // VT_R8 IEEE 8-byte floating-point IDS_CIMTYPE_DATETIME, // VT_BSTR A string containing a date-time IDS_CIMTYPE_REF, // VT_BSTR Weakly-typed reference // IDS_CIMTYPE_OBJECT, // VT_UNKNOWN Weakly-typed embedded instance IDS_CIMTYPE_OBJECT_DLG }; UINT auiAttrTypeStrings[] = { IDS_ATTR_TYPE_BSTR, IDS_ATTR_TYPE_BOOL, IDS_ATTR_TYPE_I4, IDS_ATTR_TYPE_R8, IDS_ATTR_TYPE_BSTR_ARRAY, IDS_ATTR_TYPE_BOOL_ARRAY, IDS_ATTR_TYPE_I4_ARRAY, IDS_ATTR_TYPE_R8_ARRAY }; UINT auiBoolStrings[] = { IDS_TRUE, IDS_FALSE }; CXStringArray saAttrType; CXStringArray saCimType; CXStringArray saCimtypeScalar; CXStringArray saScope; CXStringArray saBoolValues; ///////////////////////////////////////////////////////////////////////////// // CCellEdit //*********************************************************** // CCellEdit::CCellEdit // // Construct the CellEdit class. CellEdit is used for // editing cells in the grid. The cell type determines the // edit mode that will be used. // // Currently, only two edit modes are supported. A CEdit is used // for generic text. Combo-box editing is used for any type that // has an enumeration. Note that combo-box editing is implemented // using a separate drop-down button, edit box, and list box to // get the correct look and feel (the standard combo-box always // draws an ugly border within the cell) // // // Parameters: // See the MFC documentation for header control notification // messages. // // Returns: // Nothing. // //************************************************************ CCellEdit::CCellEdit() : m_btnCombo(NOTIFY_CELL_EDIT_COMBO_DROP_CLICKED) { m_clrTextDirty = COLOR_DIRTY_CELL_TEXT; // Modified text is drawn in blue m_clrTextClean = COLOR_CLEAN_CELL_TEXT; // Unmodified text is drawn in black m_clrBkgnd = RGB( 255, 255, 255 ); m_brBkgnd.CreateSolidBrush( m_clrBkgnd ); m_bWasInitiallyDirty = FALSE; m_pGrid = NULL; m_pwndParent = NULL; m_btnCombo.m_pClient = this; m_lbCombo.m_pClient = this; m_pgc = NULL; m_iRow = NULL_INDEX; m_iCol = NULL_INDEX; m_lGridClickTime = 0; m_pwndContextMenuTarget = NULL; m_bPropagateChange = NULL; m_bUIActive = FALSE; m_bEditWithComboOnly = FALSE; m_pgcCopy = NULL; m_ptypeSave = new CGcType; // Initialize the type maps if they haven't been initialized yet. mapAttribType.Load(amapAttribType, sizeof(amapAttribType) / sizeof(TMapStringToLong)); // mapCimType.Load(amapCimType, sizeof(amapCimType) / sizeof(TMapStringToLong)); // Initialize the string tables if they haven't been initialized yet. saAttrType.Load(auiAttrTypeStrings, sizeof(auiAttrTypeStrings)/sizeof(UINT)); saBoolValues.Load(auiBoolStrings, sizeof(auiBoolStrings)/sizeof(UINT)); saCimType.Load(auiCimtypeStrings, sizeof(auiCimtypeStrings)/sizeof(UINT)); saCimtypeScalar.Load(auiCimtypeScalarStrings, sizeof(auiCimtypeScalarStrings)/sizeof(UINT)); } CCellEdit::~CCellEdit() { delete m_ptypeSave; delete m_pgcCopy; } BEGIN_MESSAGE_MAP(CCellEdit, CEdit) //{{AFX_MSG_MAP(CCellEdit) ON_WM_CTLCOLOR_REFLECT() ON_WM_CHAR() ON_WM_LBUTTONDOWN() ON_WM_LBUTTONDBLCLK() ON_WM_KEYDOWN() ON_WM_SETFOCUS() ON_WM_CONTEXTMENU() ON_COMMAND(ID_EDIT_CLEAR, OnEditClear) ON_COMMAND(ID_EDIT_COPY, OnEditCopy) ON_COMMAND(ID_EDIT_CUT, OnEditCut) ON_COMMAND(ID_EDIT_PASTE, OnEditPaste) ON_COMMAND(ID_EDIT_SELECT_ALL, OnEditSelectAll) ON_COMMAND(ID_EDIT_UNDO, OnEditUndo) ON_COMMAND(ID_CMD_SET_CELL_TO_NULL, OnCmdSetCellToNull) ON_CONTROL_REFLECT(EN_CHANGE, OnChange) ON_WM_KILLFOCUS() //}}AFX_MSG_MAP ON_MESSAGE(WM_PASTE, OnPaste) END_MESSAGE_MAP() LRESULT CCellEdit::OnPaste(WPARAM wParam, LPARAM lParam) { // bug#58239 if (IsNull()) m_bIsNull = FALSE; return CEdit::Default(); } //*************************************************************** // CCellEdit::SetCell // // Set the editor's contents to the given cell. // // Parameters: // CGridCell* pGridCell // Pointer to the grid cell to set the editor's contents to. // // int iRow // The row index of the cell in the grid. // // int iCol // The column index of the cell in the grid. // // Returns: // BOOL // TRUE if the cell editor wants the focus, FALSE otherwise. // //**************************************************************** BOOL CCellEdit::SetCell(CGridCell* pGridCell, int iRow, int iCol) { ShowCombo(SW_HIDE); m_bPropagateChange = FALSE; m_iRow = iRow; m_iCol = iCol; m_pgc = pGridCell; m_pwndContextMenuTarget = NULL; SetReadOnly(FALSE); // Set or remove the enumereration that will be shown in the // drop-down combo. SetEnumeration(); BOOL bReadOnly = TRUE; // Set the value that appears in the CEdit if (pGridCell == NULL) { m_menuContext.DestroyMenu(); SetWindowText(_T(""), FALSE); SetReadOnly(TRUE); m_bIsNull = TRUE; } else { bReadOnly = pGridCell->IsReadonly() || (pGridCell->GetFlags() &CELLFLAG_READONLY); // Save a copy of the current state of the grid cell so that the // state can be restored if the user hits escape. if (m_pgcCopy) { delete m_pgcCopy; } m_pgcCopy = new CGridCell(*pGridCell); m_bIsNull = pGridCell->IsNull(); if (m_bIsNull) { CString sEmpty; if (m_pGrid->ShowNullAsEmpty()) { sEmpty = _T(""); } SetWindowText(sEmpty, FALSE); } else { CString sValue; CIMTYPE cimtype; pGridCell->GetValue(sValue, cimtype); SetWindowText(sValue, pGridCell->GetModified()); } SetReadOnly(bReadOnly | m_bEditWithComboOnly); } BOOL bWantsFocus; int nComboCount = m_lbCombo.GetCount(); if (!bReadOnly && m_lbCombo.m_hWnd!=NULL && nComboCount > 0) { m_btnCombo.ShowWindow(SW_SHOW); switch(m_pgc->GetType()) { case CELLTYPE_ATTR_TYPE: case CELLTYPE_CIMTYPE: case CELLTYPE_CIMTYPE_SCALAR: // Don't show any caret when doing combo style editing. SetSel(-1, 0); bWantsFocus = FALSE; break; default: SetSel(0, -1); bWantsFocus = TRUE; }; } else { // Select everything when doing normal editing. SetSel(GetWindowTextLength( ), 0); bWantsFocus = TRUE; } m_bPropagateChange = TRUE; return bWantsFocus; } //********************************************************** // CCellEdit::SetEnumeration // // This method examines the cell being edited and sets up the // enumeration listbox if an enumeration is required to edit the // cell. An enumeration will be displayed if the combo listbox // is not empty. // // Parameters: // CGridCell* m_pgc // The grid cell is passed in via this class member. // // Returns: // Nothing. // //********************************************************** void CCellEdit::SetEnumeration() { // If there is no grid cell, then there is no enumeration. m_bEditWithComboOnly = FALSE; m_lbCombo.ResetContent(); if ((m_pgc == NULL) || (m_pgc->GetFlags() & CELLFLAG_READONLY) || m_pgc->IsReadonly()) { ShowCombo(SW_HIDE); Layout(); return; } CStringArray saEnumValues; BOOL bProhibitEditing = TRUE; // Setup enumerations for the following: // 1. Boolean values // 2. Attribute type names. // 3. HMOM attribute scope. // 4. Variant type names. switch(m_pgc->GetType()) { case CELLTYPE_CIMTYPE: LoadListBox(saCimType); break; case CELLTYPE_CIMTYPE_SCALAR: LoadListBox(saCimtypeScalar); break; case CELLTYPE_CHECKBOX: case CELLTYPE_PROPMARKER: case CELLTYPE_VOID: break; default: switch(m_pgc->GetVariantType()) { case VT_BOOL: LoadListBox(saBoolValues); break; case VT_BSTR: switch(m_pgc->GetType()) { case CELLTYPE_ATTR_TYPE: LoadListBox(saAttrType); break; case CELLTYPE_CIMTYPE: LoadListBox(saCimType); break; case CELLTYPE_CIMTYPE_SCALAR: LoadListBox(saCimtypeScalar); break; default: m_pGrid->GetCellEnumStrings(m_iRow, m_iCol, saEnumValues); if (saEnumValues.GetSize() > 0) { LoadListBox(saEnumValues); bProhibitEditing = FALSE; } break; } break; default: ShowCombo(SW_HIDE); break; } } if (m_lbCombo.GetCount() > 0) { if (bProhibitEditing) { m_bEditWithComboOnly = TRUE; } } Layout(); } //********************************************************* // CCellEdit::LoadListBox // // Load the listbox with the enumeration strings. // // Parameters: // CStringArray& sa // A string array containing the strings to fill // the listbox with. // // Returns: // Nothing. // //********************************************************* void CCellEdit::LoadListBox(CStringArray& sa) { LONG nStrings = (LONG) sa.GetSize(); for (LONG iString=0; iString < nStrings; ++iString) { m_lbCombo.AddString(sa[iString]); } } //********************************************************** // CCellEdit::GetEditRect // // Calculate the rectangle that will be used to display // the CEdit part of the cell editor. Note that the cell editor // may consist of the CEdit, the listbox for the drop-down combo // and the combo-drop button. // // Parameters: // [out] RECT& rcEdit // The place to return the rectangle for the CEdit portion // of the cell editor. // // [in] BOOL bNeedsComboButton // TRUE if a combo button needs to be displayed in the cell // and the CEdit part of the cell should be reduced in size // so that it doesn't overlap the button. // // [in] CRect& rcComboButton // The rectangle where the combo button will be placed. This // is valid only if bNeedsComboButton is TRUE. // // Returns: // Nothing. // //********************************************************** void CCellEdit::GetEditRect(RECT& rcEdit, BOOL bNeedsComboButton, CRect& rcComboButton) { rcEdit.left = m_rcCell.left + CX_CELL_MARGIN; if (rcEdit.left > m_rcCell.right) { rcEdit.left = m_rcCell.right; } rcEdit.right = m_rcCell.right - CX_CELL_MARGIN; if (m_lbCombo.m_hWnd && (m_lbCombo.GetCount() > 0)) { // A combo is being displayed, so make room for the drop-down button. rcEdit.right -= CX_COMBO_DROP + CX_COMBO_DROP_MARGIN; } if (rcEdit.right < rcEdit.left) { rcEdit.right = rcEdit.left; } rcEdit.top = m_rcCell.top + CY_CELL_MARGIN; if (rcEdit.top > m_rcCell.bottom) { rcEdit.top = m_rcCell.bottom; } rcEdit.bottom = m_rcCell.bottom - CY_CELL_MARGIN; if (rcEdit.bottom < rcEdit.top) { rcEdit.bottom = rcEdit.top; } if (bNeedsComboButton) { if (rcEdit.right > rcComboButton.left) { rcEdit.right = rcComboButton.left; } } else { CRect rcParent; m_pwndParent->GetClientRect(rcParent); if (rcEdit.right > rcParent.right) { rcEdit.right = rcParent.right; } } } //********************************************************** // CCellEdit::GetListBoxRect // // Calculate the rectangle that will be used to display // the CListBox part of the cell editor. Note that the cell editor // may consist of the CEdit, the listbox for the drop-down combo // and the combo-drop button. // // Parameters: // RECT& rcListBox // The place to return the rectangle for the CListBox portion // of the cell editor. // // Returns: // Nothing. // //********************************************************** void CCellEdit::GetListBoxRect(RECT& rcListBox) { CRect rcParent; m_pwndParent->GetClientRect(rcParent); // Figure out what the desired and the minimum sizes are for // the listbox. cyText is the desired size. cyMin is the // minimum size. int cyText = 0; if (m_lbCombo.m_hWnd != NULL ) { cyText = m_lbCombo.GetCount() * CY_FONT; } if (cyText > CY_EDIT_LISTBOX_MAX) { cyText = CY_EDIT_LISTBOX_MAX; } int cyMin = CY_EDIT_LISTBOX_MIN; if (cyMin > cyText) { cyMin = cyText; } // Make sure the listbox doesn't go beyond the parent's client area rcListBox.left = m_rcCell.left; rcListBox.right = m_rcCell.right; if ((rcListBox.right - rcListBox.left) < CX_EDIT_LISTBOX_MIN) { rcListBox.right = m_rcCell.left + CX_EDIT_LISTBOX_EXTEND; } if (rcListBox.right > rcParent.right) { rcListBox.right = rcParent.right; rcListBox.left = rcParent.right - CX_EDIT_LISTBOX_EXTEND; } if (rcListBox.left < rcParent.left) { rcListBox.left = rcParent.left; } if ((m_rcCell.bottom + cyMin) > rcParent.bottom) { // Place the listbox above the cell rectangle rcListBox.top = m_rcCell.top - cyText; if (rcListBox.top < rcParent.top) { rcListBox.top = rcParent.top; } rcListBox.bottom = m_rcCell.top + 1; } else { // Place the listbox below the cell rectangle rcListBox.top = m_rcCell.bottom - 1; rcListBox.bottom = m_rcCell.bottom + cyText; if (rcListBox.bottom > rcParent.bottom) { rcListBox.bottom = rcParent.bottom; } } } //********************************************************** // CCellEdit::GetComboButtonRect // // Calculate the rectangle that will be used to display // the CButton part of the cell editor. Note that the cell editor // may consist of the CEdit, the listbox for the drop-down combo // and the combo-drop button. // // Parameters: // RECT& rcButton // The place to return the rectangle for the CButton portion // of the cell editor. // // Returns: // Nothing. // //********************************************************** void CCellEdit::GetComboButtonRect(RECT& rcButton) { rcButton.left = m_rcCell.right - CX_COMBO_DROP - CX_COMBO_DROP_MARGIN; if (rcButton.left < m_rcCell.left) { rcButton.left = m_rcCell.left; } rcButton.top = m_rcCell.top; rcButton.right = m_rcCell.right - CX_COMBO_DROP_MARGIN; rcButton.bottom = m_rcCell.bottom - CY_COMBO_DROP_MARGIN; // If the cell is entirely to the right of the parent's client rectangle, // just return the button rectangle that we've calculated. CRect rcParent; m_pwndParent->GetClientRect(rcParent); if (m_rcCell.left > rcParent.right) { // ASSERT(FALSE); return; } // If the right side of the cell is obscured by the right edge of the // window, move the button left so that it is visible. int cxButton = rcButton.right - rcButton.left; if (rcButton.right > rcParent.right) { // Fix up the boundary conditions to prevent the button from // extending outside of the cell. rcButton.left = rcParent.right - cxButton; if (rcButton.left < m_rcCell.left) { rcButton.left = m_rcCell.left; } rcButton.right = rcButton.left + cxButton; if (rcButton.right > m_rcCell.right) { rcButton.right = m_rcCell.right; } } } //********************************************************** // CCellEdit::FixBuddyCell // // When a cell containing the "type" of buddy cell changes, then // it may be necessary fix the value of the buddy cell to // reflect the type change. // // Parameters: // None // // Returns: // Nothing // //********************************************************** void CCellEdit::FixBuddyCell() { // If there is no buddy for the cell being edited, then // there is nothing to do. int iColBuddy = m_pgc->GetBuddy(); if (iColBuddy == NULL_INDEX) { return; } CGridCell* pgcBuddy = &m_pGrid->GetAt(m_iRow, iColBuddy); // Get the value of this cell and map the value to a variant type. BOOL bFoundType; CString sType; GetWindowText(sType); CGcType typeBuddy = pgcBuddy->type(); CGcType type = m_pgc->type(); long lTemp; switch((CellType) type) { case CELLTYPE_ATTR_TYPE: bFoundType = mapAttribType.Lookup(sType, lTemp); typeBuddy.SetCimtype((CIMTYPE) lTemp); ASSERT(bFoundType); break; case CELLTYPE_CIMTYPE: case CELLTYPE_CIMTYPE_SCALAR: MapDisplayTypeToGcType(typeBuddy, sType); typeBuddy.SetCellType(CELLTYPE_VARIANT); // MapDisplayTypeToGcType modifies the CellType bFoundType = TRUE; break; default: ASSERT(FALSE); return; break; } // If the new type is different from the buddy's current type, // then change the type of the buddy to the new type and redraw it. if (typeBuddy != pgcBuddy->type()) { pgcBuddy->ChangeType(typeBuddy); m_pGrid->DrawCell(m_iRow, iColBuddy); } } //**************************************************************** // CCellEdit::GetStrongDisplayType // // When the user selects a type from //************************************************************** // CCellEdit::GetGcTypeFromCombo // // This method is called when the user releases the mouse button // when selecting a type from the drop-down combo. The type is // returned as a CGcType value that will carry with it the necessary // information for strongly typed references and objects, strongly // typed arrays of references and strongly typed arrays of objects. // // The CGcType value can then be mapped back into a displayable type // that the user sees, and so on. // // Parameters: // [out] CGcType& type // The type value is returned here. // // Returns: // SCODE // S_OK if successful, E_FAIL otherwise. // //************************************************************** SCODE CCellEdit::ComboSelectDisplayType(CGcType& type, LPCTSTR pszDisplayType) { MapDisplayTypeToGcType(type, pszDisplayType); CIMTYPE cimtype = (CIMTYPE) type; CIMTYPE cimtypeT = cimtype & ~CIM_FLAG_ARRAY; switch(cimtypeT) { case CIM_OBJECT: case CIM_REFERENCE: break; default: return S_OK; } // The type selected from the combo box may be "object" or "ref". In the // event that the buddy (value) cell is already of type "object" or "ref", // we want to get the cimtype string from the buddy so that we can preserve // the classname for strongly typed references and objects. CString sCimtype; int iColBuddy = m_pgc->GetBuddy(); if (iColBuddy == NULL_INDEX) { sCimtype = type.CimtypeString(); } else { CGridCell* pgcBuddy = &m_pGrid->GetAt(m_iRow, iColBuddy); CGcType typeBuddy = pgcBuddy->type(); CIMTYPE cimtypeBuddy = (CIMTYPE) typeBuddy; CIMTYPE cimtypeTBuddy = cimtypeBuddy & ~CIM_FLAG_ARRAY; if (cimtypeT == cimtypeTBuddy) { // Get the cimtype string from the buddy since it is the // same basic type (object or reference). This is done // to preserve the class name when the buddy cell is // strongly typed. sCimtype = typeBuddy.CimtypeString(); } else { // Changing an object to a reference or vice versa, so just use // the basic "object" or "reference" for the cimtype string since // it doesn't really make sense to preserve the classname if the // buddy is strongly typed. sCimtype = type.CimtypeString(); } } CDlgObjectType dlg; switch (cimtypeT) { case CIM_OBJECT: dlg.EditObjType(m_pgc->Grid(), sCimtype); type.SetCimtype(cimtype, sCimtype); break; case CIM_REFERENCE: dlg.EditRefType(m_pgc->Grid(), sCimtype); type.SetCimtype(cimtype, sCimtype); break; default: ASSERT(FALSE); return E_FAIL; } return S_OK; } //********************************************************** // CCellEdit::CatchEvent // // Catch events sent from the listbox or the combo-drop button. // // Parameters: // long lEvent // The event id. // // Returns: // Nothing. // //********************************************************** void CCellEdit::CatchEvent(long lEvent) { int iItem; CString sText; BOOL bChangedCimtype = FALSE; CGcType type; switch(lEvent) { case NOTIFY_CELL_EDIT_COMBO_DROP_CLICKED: // Control comes here when the user clicks the combo-drop // button. When this happens, the listbox is shown and the // focus is set to the listbox, etc. if (m_lbCombo.IsWindowVisible()) { m_lbCombo.ShowWindow(SW_HIDE); SetFocus(); } else { CEdit::GetWindowText(sText); CellType celltype = m_pgc->GetType(); switch(celltype) { case CELLTYPE_CIMTYPE_SCALAR: case CELLTYPE_CIMTYPE: *m_ptypeSave = m_pgc->type(); if (HasObjectPrefix(sText)) { sText.LoadString(IDS_CIMTYPE_OBJECT_DLG); } else if (::IsPrefix(_T("ref"), sText)) { sText = "ref"; } break; } iItem = m_lbCombo.FindString(-1, sText); if (iItem >= 0) { m_lbCombo.SetCurSel(iItem); } m_lbCombo.ShowWindow(SW_SHOW); m_lbCombo.SetFocus(); } break; case NOTIFY_CELL_EDIT_LISTBOX_LBUTTON_UP: m_lbCombo.ShowWindow(SW_HIDE); ComboSelectionChanged(); SetFocus(); #if 0 // Control comes here when the user completes // a selection of a value in the list box. // Now it is necessary to hide the list box // and set the cell's value to the selection bModifyPrev = GetModify(); // Hide the list box and copy the selected value to the edit box. iItem = m_lbCombo.GetCurSel(); if (iItem >= 0) { m_lbCombo.GetText(iItem, sText); CellType celltype = m_pgc->GetType(); if ((celltype == CELLTYPE_CIMTYPE) || (celltype == CELLTYPE_CIMTYPE_SCALAR)) { //SelectCimtypeFromCombo(); sc = ComboSelectDisplayType(type, sText); if (FAILED(sc)) { return; } bChangedCimtype = (type != *m_ptypeSave); ::MapGcTypeToDisplayType(sText, type); } m_bIsNull = FALSE; CEdit::SetWindowText(sText); SetModify(TRUE); } bModified = GetModify(); // If the modification flag changed, then redraw the window // so that the text appears in the correct color. FixBuddyCell(); if (bChangedCimtype) { m_pGrid->OnChangedCimtype(m_iRow, m_iCol); } if (GetModify() != bModifyPrev) { if (m_pgc) { m_pgc->SetModified(bModified); } if (m_pGrid) { m_pGrid->SyncCellEditor(); m_pGrid->NotifyCellModifyChange(); RedrawWindow(); } } m_pGrid->SyncCellEditor(); m_pGrid->OnEnumSelection(m_iRow, m_iCol); SetFocus(); #endif //0 break; } } void CCellEdit::ComboSelectionChanged() { // Control comes here when the user completes // a selection of a value in the list box. // Now it is necessary to hide the list box // and set the cell's value to the selection SCODE sc; BOOL bModifyPrev = GetModify(); BOOL bChangedCimtype = FALSE; int iItem; CString sText; CGcType type; // Hide the list box and copy the selected value to the edit box. m_lbCombo.ShowWindow(SW_HIDE); iItem = m_lbCombo.GetCurSel(); if (iItem >= 0) { m_lbCombo.GetText(iItem, sText); CellType celltype = m_pgc->GetType(); if ((celltype == CELLTYPE_CIMTYPE) || (celltype == CELLTYPE_CIMTYPE_SCALAR)) { //SelectCimtypeFromCombo(); sc = ComboSelectDisplayType(type, sText); if (FAILED(sc)) { return; } bChangedCimtype = (type != *m_ptypeSave); ::MapGcTypeToDisplayType(sText, type); } m_bIsNull = FALSE; CEdit::SetWindowText(sText); SetModify(TRUE); } BOOL bModified = GetModify(); // If the modification flag changed, then redraw the window // so that the text appears in the correct color. FixBuddyCell(); if (bChangedCimtype) { m_pGrid->OnChangedCimtype(m_iRow, m_iCol); } if (GetModify() != bModifyPrev) { if (m_pgc) { m_pgc->SetModified(bModified); } if (m_pGrid) { m_pGrid->SyncCellEditor(); m_pGrid->NotifyCellModifyChange(); RedrawWindow(); } } m_pGrid->SyncCellEditor(); m_pGrid->OnEnumSelection(m_iRow, m_iCol); SetFocus(); } BOOL CCellEdit::EditRefType(BOOL& bChangedReftype) { bChangedReftype = FALSE; #if 0 CString sCurrentText; GetWindowText(sCurrentText); SCODE sc; CString sClass; CDlgObjectType dlg; sc = ClassFromReftype(sCurrentText, sClass); if (SUCCEEDED(sc)) { sText = sCurrentText; dlg.SetReftype(sCurrentText); bChangedReftype = TRUE; } int iResult = dlg.DoModal(); switch(iResult) { case IDOK: sText = dlg.Cimtype(); if (sText.CompareNoCase(sCurrentText)==0) { return; } bChangedReftype = TRUE; break; case IDCANCEL: return FALSE; break; } #endif //0 return bChangedReftype; } //********************************************************** // CCellEdit::RedrawWindow // // Redraw this window and its siblings (the combo listbox and button). // // Parameters: // None // // Returns: // Nothing. // //********************************************************** void CCellEdit::RedrawWindow() { CEdit::RedrawWindow(); if (m_btnCombo.IsWindowVisible()) { m_btnCombo.RedrawWindow(); } if (m_lbCombo.IsWindowVisible()) { m_lbCombo.RedrawWindow(); } } //************************************************************************* // CCellEdit::Create // // Create the cell editor window. // // Parameters: // DWORD dwStyle // The window style. // // RECT& rcCell // The rectangle that the editor is to occupy in the grid. // // CWnd* pwndParent // The parent window. // // UINT nID // The window ID // // Returns: // BOOL // TRUE if the window was successfully created, FALSE otherwise. // //************************************************************************** BOOL CCellEdit::Create( DWORD dwStyle, const RECT& rcCell, CWnd* pwndParent, UINT nID ) { m_rcCell = rcCell; m_pwndParent = pwndParent; CRect rcComboButton; BOOL bNeedsComboButton = UsesComboEditing(); if (bNeedsComboButton) { GetComboButtonRect(rcComboButton); } CRect rcEdit; GetEditRect(rcEdit, bNeedsComboButton, rcComboButton); BOOL bDidCreate; bDidCreate = CEdit::Create(dwStyle | ES_LEFT /* | ES_AUTOHSCROLL */ , rcEdit, pwndParent, nID); if (!bDidCreate) { return FALSE; } DWORD dwListBoxStyle; dwListBoxStyle = WS_CHILD | LBS_STANDARD | LBS_WANTKEYBOARDINPUT ; CRect rcListBox; GetListBoxRect(rcListBox); bDidCreate = m_lbCombo.Create(dwListBoxStyle, rcListBox, pwndParent, GenerateWindowID()); // Create the combo button DWORD dwButtonStyle = (dwStyle & WS_VISIBLE) | WS_CHILD | BS_PUSHBUTTON; bDidCreate = m_btnCombo.Create(NULL, dwButtonStyle, rcComboButton, pwndParent, GenerateWindowID()); if (bDidCreate) { m_bmComboDrop.LoadBitmap(MAKEINTRESOURCE(IDB_COMBO_DROP)); m_btnCombo.ModifyStyle(0, BS_BITMAP); m_btnCombo.SetBitmap((HBITMAP) m_bmComboDrop); } return bDidCreate; } //******************************************************* // CCellEdit::Layout // // Layout the cell editors parts. This include the CEdit, // the CButton for the combo-drop button, and the CListBox // for the enumeration. Each of these windows are moved to // the desired position in the grid. However, it may be the // case that one or more of these siblings are not visible. // For example, the CListBox portion of the window is visible // only if the combo-drop button was clicked and there is // an enumeration to show. // // Parameters: // BOOL bRepaint // TRUE if the windows should be repainted. // // Returns: // Nothing. // //******************************************************* void CCellEdit::Layout(BOOL bRepaint) { CRect rc; CRect rcCurrent; CRect rcComboButton; BOOL bNeedsComboButton = UsesComboEditing(); if (bNeedsComboButton) { GetComboButtonRect(rcComboButton); } if (m_hWnd) { GetEditRect(rc, bNeedsComboButton, rcComboButton); CEdit::GetWindowRect(rcCurrent); m_pwndParent->ScreenToClient(rcCurrent); if (!rc.EqualRect(&rcCurrent)) { CEdit::MoveWindow(rc, bRepaint); } } if (m_btnCombo.m_hWnd) { GetComboButtonRect(rc); m_btnCombo.GetWindowRect(rcCurrent); m_pwndParent->ScreenToClient(rcCurrent); if (!rc.EqualRect(&rcCurrent)) { m_btnCombo.MoveWindow(rc, bRepaint); } } if (m_lbCombo.m_hWnd) { GetListBoxRect(rc); m_lbCombo.GetWindowRect(rcCurrent); m_lbCombo.ClientToScreen(rcCurrent); if (!rc.EqualRect(&rcCurrent)) { m_lbCombo.MoveWindow(rc, bRepaint); } } } //****************************************************** // CCellEdit::SetFont // // Set the font to the specified font. // // Parameters: // CFont* pfont // The font to select. // // BOOL bRedraw // TRUE if the windows should be redrawn. // // Returns: // Nothing. // //******************************************************* void CCellEdit::SetFont(CFont* pfont, BOOL bRedraw) { if (m_hWnd) { CEdit::SetFont(pfont, bRedraw); } if (m_lbCombo.m_hWnd) { m_lbCombo.SetFont(pfont, bRedraw); } } //********************************************************* // CCellEdit::ShowWindow // // Show or hide the cell editor. // // Parameters: // int nCmdShow // See the MFC documentation for CWnd::ShowWindow // // Return: // BOOL // TRUE if the window was previously visible. // //********************************************************** BOOL CCellEdit::ShowWindow( int nCmdShow ) { BOOL bWasVisible = CEdit::ShowWindow(nCmdShow); // If the listbox is empty, then this is not an enumeration, // so keep the combo button and listbox hidden. if (nCmdShow == SW_SHOW) { if ((m_lbCombo.m_hWnd!=NULL) && (m_lbCombo.GetCount() == 0)) { return bWasVisible; } } #if 0 // Pass the show command on to the listbox and combo button. if (nCmdShow != SW_SHOW) { if (m_lbCombo.m_hWnd) { m_lbCombo.ShowWindow(nCmdShow); } } if (m_btnCombo.m_hWnd) { m_btnCombo.ShowWindow(nCmdShow); } #endif //0 if (nCmdShow == SW_HIDE) { ShowCombo(SW_HIDE); if ((m_iRow != NULL_INDEX ) && (m_iCol != NULL_INDEX)) { m_pGrid->DrawCell(m_iRow, m_iCol); } } return bWasVisible; } void CCellEdit::ShowCombo(int nCmdShow) { int i = 0; if (nCmdShow == SW_SHOW) { i = 2; } if (m_lbCombo.m_hWnd != NULL) { m_lbCombo.ShowWindow(nCmdShow); } if (m_btnCombo.m_hWnd != NULL) { m_btnCombo.ShowWindow(nCmdShow); } } //************************************************************** // CCellEdit::MoveWindow // // Move the cell editor to a new location on the grid. // // Parameters: // LPRECT lpRect // A pointer to the destination rectangle. // // BOOL bRepaint // TRUE if the cell editor should be repainted. // // Returns: // Nothing. // //************************************************************* void CCellEdit::MoveWindow( LPCRECT lpRect, BOOL bRepaint) { m_rcCell = *lpRect; Layout(bRepaint); } //************************************************************ // CCellEdit::CtlColor // // Method for WM_CTLCOLOR to select the colors for this CCellEdit // control. // // Parameters: // See the MFC documentation for OnCtlColor // // Returns: // HBRUSH // The brush handle that the background will be painted with. // A NULL value means use the parent's handler for CtlColor(). // //*************************************************************** HBRUSH CCellEdit::CtlColor(CDC* pDC, UINT nCtlColor) { if (GetModify()) { pDC->SetTextColor(m_clrTextDirty); } else { pDC->SetTextColor(m_clrTextClean); } pDC->SetBkColor( m_clrBkgnd ); // text bkgnd return m_brBkgnd; // ctl bkgnd } //*************************************************************** // CCellEdit::RevertToInitialValue // // Revert the cell to its initial value. This method is called // when an ESC cahracter is entered. // // Parameters: // None. // // Returns: // Nothing. // //*************************************************************** void CCellEdit::RevertToInitialValue() { if (m_pgcCopy) { *m_pgc = *m_pgcCopy; } SetCell(m_pgc, m_iRow, m_iCol); FixBuddyCell(); } BOOL CCellEdit::IsBooleanCell() { if (m_pgc == NULL) { return FALSE; } CGcType type = m_pgc->type(); CIMTYPE cimtype = (CIMTYPE) type; BOOL bIsBoolean = ((cimtype & ~CIM_FLAG_ARRAY) == CIM_BOOLEAN); return bIsBoolean; } void CCellEdit::SetBooleanCellValue(BOOL bValue) { ASSERT(IsBooleanCell()); // Initialize the boolean value that we're editing to true CGcType type = m_pgc->type(); CIMTYPE cimtype = (CIMTYPE) type; COleVariant varValue; varValue.ChangeType(VT_BOOL); varValue.boolVal = bValue ? VARIANT_TRUE : VARIANT_FALSE; m_pgc->SetValue(type, varValue); m_bIsNull = FALSE; } BOOL CCellEdit::GetBooleanCellValue() { ASSERT(IsBooleanCell()); if (m_pgc != NULL) { COleVariant var; CIMTYPE cimtype; m_pgc->GetValue(var, cimtype); if (var.vt != VT_BOOL) { return FALSE; } return var.boolVal; } return FALSE; } //*************************************************************** // CCellEdit::OnChar // // Called for each character entered into the edit box. // // We trap this message so that we can correct the "modify" flag // to reflect the possibility that the initial text value was // dirty to start with. // // Parameters: // See the MFC documentation. // // Returns: // Nothing. // //*************************************************************** void CCellEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) { BOOL bModifyInitial = GetModify(); SCODE sc; switch (nChar) { case VK_TAB: case ESC_CHAR: case CTL_C: break; default: if (m_pgc && (m_pgc->GetFlags() & CELLFLAG_READONLY)) { Beep(1700, 40); return; } break; } switch (nChar) { case VK_TAB: return; case ESC_CHAR: RevertToInitialValue(); return; } CString sText; if (IsBooleanCell()) { BOOL bVal = TRUE; switch (nChar) { case ' ': // Toggle the value. bVal = GetBooleanCellValue(); bVal = !bVal; break; case 'N': case 'n': case 'f': case 'F': case '0': bVal = FALSE; break; default: break; } SetBooleanCellValue(bVal); if (bVal) { sText.LoadString(IDS_TRUE); } else { sText.LoadString(IDS_FALSE); } SetWindowText(sText, TRUE); } else if (UsesComboEditing()) { GetWindowText(sText); if (m_bEditWithComboOnly) { sc = m_lbCombo.MapCharToItem(sText, nChar); if (SUCCEEDED(sc)) { SetWindowText(sText, TRUE); int iItem = m_lbCombo.FindString(0, sText); ASSERT(iItem >= 0); m_lbCombo.SetCurSel(iItem); ComboSelectionChanged(); } } } // Notify the grid that a WM_CHAR occurred in the cell. if (m_pGrid) { m_pGrid->OnCellChar(m_iRow, m_iCol, nChar, nRepCnt, nFlags); } if (m_lbCombo.GetCount()>0) { // If this cell contains an enumeration, it doesn't make sense to // allow the user to directly enter the value. They should use the // drop-down instead. switch(m_pgc->GetType()) { case CELLTYPE_ATTR_TYPE: case CELLTYPE_CIMTYPE: case CELLTYPE_CIMTYPE_SCALAR: return; }; } BOOL bModifyPrev = GetModify(); if (IsNull()) { SetWindowText(_T(""), TRUE); m_bIsNull = FALSE; RedrawWindow(); } CEdit::OnChar(nChar, nRepCnt, nFlags); if ((nChar == CONTROL_Z_CHAR)) { CString sText; GetWindowText(sText); if (sText != m_sInitialText) { SetModify(TRUE); } else { SetModify(FALSE); } } // If the modification flag changed, then redraw the window // so that the text appears in the correct color. if (m_pGrid) { if (GetModify() != bModifyInitial) { m_pGrid->NotifyCellModifyChange(); } } if (GetModify() != bModifyPrev) { RedrawWindow(); } } //****************************************************************** // CCellEdit::SetWindowText // // This version of SetWindowText has an extra parameter to indicate // whether or not the text value should be displayed in the "dirty" // color. // // Parameters: // CString& sText // The text to display. // // BOOL bIsDirtyText // TRUE if the text is initially dirty. This could happen if // the user edits a field, thus making it dirty, selects another // field and then comes back to the same "dirty" field. // //***************************************************************** void CCellEdit::SetWindowText(LPCTSTR pszText, BOOL bIsDirtyText) { m_bWasInitiallyDirty = bIsDirtyText; m_sInitialText = pszText; CEdit::SetWindowText(pszText); SetModify(bIsDirtyText); RedrawWindow(); } //********************************************************** // CCellEdit::ReplaceSel // // This version of ReplaceSel marks the text as "dirty" and // the redraws the window in the new color if the previous // text was clean. // // Parameters: // LPCTSTR pszText // Pointer to the new window text. // // BOOL bCanUndo // TRUE if undo operations are allowed. // // Returns: // Nothing. // //*********************************************************** void CCellEdit::ReplaceSel(LPCTSTR pszText, BOOL bCanUndo) { BOOL bModifyPrev = GetModify(); CEdit::ReplaceSel(pszText, bCanUndo); SetModify(TRUE); if (GetModify() != bModifyPrev) { if (m_pGrid) { m_pGrid->NotifyCellModifyChange(); } RedrawWindow(); } } //****************************************************************** // CCellEdit::OnLButtonDown // // When the mouse is clicked on the CEdit part of the cell editor, // hide the drop-down list if it is not already hidden. // // Parameters: // See the MFC documentation for WM_LBUTTONDOWN // // Returns: // Nothing. // //***************************************************************** void CCellEdit::OnLButtonDown(UINT nFlags, CPoint point) { // TODO: Add your message handler code here and/or call default CEdit::OnLButtonDown(nFlags, point); // Check to see if the cell editor was double clicked. If so, // tell the parent that a double click occurred. UINT uiDblClickTime = ::GetDoubleClickTime(); LONG lClickTime = GetMessageTime(); LONG ldtClick; if (lClickTime > m_lGridClickTime) { ldtClick = lClickTime - m_lGridClickTime; } else { ldtClick = m_lGridClickTime - lClickTime; } if (ldtClick < (LONG) ::GetDoubleClickTime()) { // Double click detected. CPoint ptGrid = point; ClientToScreen(&ptGrid); m_pGrid->ScreenToClient(&ptGrid); m_pGrid->SetFocus(); m_pGrid->NotifyDoubleClk(nFlags, ptGrid); } if (UsesComboEditing()) { switch(m_pgc->GetType()) { case CELLTYPE_ATTR_TYPE: case CELLTYPE_CIMTYPE: case CELLTYPE_CIMTYPE_SCALAR: // Remove the selection. SetSel(-1, 0); return; }; } if (m_lbCombo.IsWindowVisible()) { m_lbCombo.ShowWindow(SW_HIDE); } } //****************************************************************** // CCellEdit::OnLButtonDown // // When the mouse is double-clicked on the CEdit part of the cell editor, // hide the drop-down list if it is not already hidden then pass the double-click // on to the grid control. // // Parameters: // See the MFC documentation for WM_LBUTTONDBLCLICK // // Returns: // Nothing. // //***************************************************************** void CCellEdit::OnLButtonDblClk(UINT nFlags, CPoint point) { if (m_lbCombo.IsWindowVisible()) { m_lbCombo.ShowWindow(SW_HIDE); } if (m_pGrid) { ClientToScreen(&point); m_pGrid->ScreenToClient(&point); m_pGrid->NotifyDoubleClk(nFlags, point); } } //**************************************************************** // CCellEdit::UsesComboEditing // // Check to see if a combo box is used for the editing. // // Parameters: // See the MFC documentation. // // Returns: // Nothing. // //*************************************************************** BOOL CCellEdit::UsesComboEditing() { if (!::IsWindow(m_lbCombo.m_hWnd)) { return FALSE; } BOOL bUseComboEditing = m_lbCombo.GetCount() > 0; return bUseComboEditing; } BOOL CCellEdit::PreTranslateMessage(MSG* pMsg) { switch (pMsg->message) { case WM_KEYDOWN: switch (pMsg->wParam) { case VK_TAB: m_pGrid->OnTabKey(GetKeyState(VK_SHIFT) < 0); return TRUE; } break; } return CEdit::PreTranslateMessage(pMsg); } ///////////////////////////////////////////////////////////////////////////// // CLbCombo // // This class is the listbox that drops down when the combo-drop button is // clicked in the cell editor. This class exists for the sole purpose of // notifying its sibling (the CEdit part of the cell editor) when a selection // is made in the combo box. // ///////////////////////////////////////////////////////////////////////////// CLbCombo::CLbCombo() { m_pClient = NULL; m_bUIActive = FALSE; } CLbCombo::~CLbCombo() { } BEGIN_MESSAGE_MAP(CLbCombo, CListBox) //{{AFX_MSG_MAP(CLbCombo) ON_WM_LBUTTONUP() ON_WM_SETFOCUS() ON_WM_KILLFOCUS() ON_WM_CHAR() //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CLbCombo message handlers //**************************************************************** // CLbCombo::OnLButtonUp // // When the mouse button is released, send a message to the sibling // window so that it can get the current selection. // // Parameters: // See the MFC documentation. // // Returns: // Nothing. // //*************************************************************** void CLbCombo::OnLButtonUp(UINT nFlags, CPoint point) { // TODO: Add your message handler code here and/or call default CListBox::OnLButtonUp(nFlags, point); m_pClient->CatchEvent(NOTIFY_CELL_EDIT_LISTBOX_LBUTTON_UP); } void CCellEdit::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { CEdit::OnKeyDown(nChar, nRepCnt, nFlags); BOOL bWasModified = GetModify(); if (m_pGrid) { if (m_pGrid->OnCellKeyDown(m_iRow, m_iCol, nChar, nRepCnt, nFlags)) { // The derived class handled the keydown, // so just set the modified state. BOOL bIsModified = GetModify(); if (!bWasModified && bIsModified) { if (m_pGrid) { m_pGrid->NotifyCellModifyChange(); } } return; } } // The derived class, did not handle this keydown // event. switch(nChar) { case VK_UP: m_pGrid->OnRowUp(); return; case VK_DOWN: m_pGrid->OnRowDown(); return; case VK_TAB: m_pGrid->OnTabKey(GetKeyState(VK_SHIFT) < 0); return; case VK_DELETE: if (m_pgc && (m_pgc->GetFlags() & CELLFLAG_READONLY)) { Beep(1700, 40); } return; } BOOL bIsModified = GetModify(); if (!bWasModified && bIsModified) { if (m_pGrid) { m_pGrid->NotifyCellModifyChange(); } } } //********************************************************* // CCellEdit::OnSetFocus // // Hook out OnSetFocus so that we can prevent the focus from // ever being set to the combo box. In the future it might // be nice to allow the user to select the text in the combo // box so that it can be copied, etc. // // Parameters: // CWnd* pOldWnd // Pointer to the window loosing the focus. // // Returns: // Nothing. // //********************************************************** void CCellEdit::OnSetFocus(CWnd* pOldWnd) { if (m_lbCombo.m_hWnd!=NULL && m_lbCombo.GetCount() > 0) { // Don't allow the focus to be set on a combo box. switch(m_pgc->GetType()) { case CELLTYPE_ATTR_TYPE: case CELLTYPE_CIMTYPE: case CELLTYPE_CIMTYPE_SCALAR: return; break; }; } CEdit::OnSetFocus(pOldWnd); if (!m_bUIActive) { m_bUIActive = TRUE; RequestUIActive(); } } void CCellEdit::OnKillFocus(CWnd* pNewWnd) { CEdit::OnKillFocus(pNewWnd); // TODO: Add your message handler code here m_bUIActive = FALSE; } void CCellEdit::OnContextMenu(CWnd* pWnd, CPoint pt) { m_menuContext.DestroyMenu(); BOOL bUseCustomMenu = m_pGrid->GetCellEditContextMenu (m_iRow, m_iCol, m_pwndContextMenuTarget, m_menuContext, m_bContextMenuTargetWantsEditCommands); // Pass the coordinates of the context menu click on to the grid. Also // check to see if it wants to display and track the context menu directly. if (m_pGrid->OnCellEditContextMenu(pWnd, pt)) { return; } if (bUseCustomMenu) { CMenu* pPopup = m_menuContext.GetSubMenu(0); ASSERT(pPopup != NULL); DWORD dwStyle = GetStyle(); BOOL bIsReadonly = dwStyle & ES_READONLY; BOOL bEnableCopy = TRUE; BOOL bEnableCut = TRUE; BOOL bEnablePaste = TRUE; BOOL bEnableSelectAll = TRUE; BOOL bEnableClear = TRUE; int nStartChar; int nEndChar; GetSel(nStartChar, nEndChar ); if (nStartChar >= nEndChar) { // There is nothing to select, so disable the appropriate menu items bEnableCopy = FALSE; bEnableCut = FALSE; bEnableClear = FALSE; } if (!CanUndo()) { pPopup->EnableMenuItem(ID_EDIT_UNDO, MF_DISABLED | MF_GRAYED); } CString sText; GetWindowText(sText); if (sText.GetLength() == 0) { // There is no text to select bEnableSelectAll = FALSE; } COleDataObject *pdata = new COleDataObject; BOOL bDidAttach = pdata->AttachClipboard(); BOOL bCanPaste = FALSE; if (bDidAttach) { if (pdata->IsDataAvailable(CF_TEXT)) { bCanPaste = TRUE; } } if (!bCanPaste) { // There is no text available for pasting. pPopup->EnableMenuItem(ID_EDIT_PASTE, MF_DISABLED | MF_GRAYED); } if (bIsReadonly) { bEnableCut = FALSE; bEnablePaste = FALSE; bEnableClear = FALSE; } pPopup->EnableMenuItem(ID_EDIT_COPY, bEnableCopy ? MF_ENABLED : MF_DISABLED | MF_GRAYED); pPopup->EnableMenuItem(ID_EDIT_CUT, bEnableCut ? MF_ENABLED : MF_DISABLED | MF_GRAYED); pPopup->EnableMenuItem(ID_EDIT_PASTE, bEnablePaste ? MF_ENABLED : MF_DISABLED | MF_GRAYED); pPopup->EnableMenuItem(ID_EDIT_CLEAR, bEnableClear ? MF_ENABLED : MF_DISABLED | MF_GRAYED); pPopup->EnableMenuItem(ID_EDIT_SELECT_ALL, bEnableSelectAll ? MF_ENABLED : MF_DISABLED | MF_GRAYED); m_pGrid->ModifyCellEditContextMenu(m_iRow, m_iCol, m_menuContext); pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, this); } else { m_pwndContextMenuTarget = NULL; CEdit::OnContextMenu(pWnd, pt); } } void CCellEdit::OnEditClear() { Clear(); } void CCellEdit::OnEditCopy() { Copy(); } void CCellEdit::OnEditCut() { Cut(); } void CCellEdit::OnEditPaste() { Paste(); } void CCellEdit::OnEditSelectAll() { SetSel(0, -1); } void CCellEdit::OnEditUndo() { Undo(); } BOOL CCellEdit::OnCommand( WPARAM wParam, LPARAM lParam ) { if (m_pwndContextMenuTarget) { CMenu* pPopup = m_menuContext.GetSubMenu(0); ASSERT(pPopup != NULL); UINT nItems = pPopup->GetMenuItemCount( ); for (UINT iItem =0; iItem < nItems; ++iItem) { UINT uiMenuItem = pPopup->GetMenuItemID(iItem); if (uiMenuItem == wParam) { if (m_bContextMenuTargetWantsEditCommands) { // Send all commands to the target, even the editing commands. m_pwndContextMenuTarget->SendMessage(WM_COMMAND, wParam, lParam); return TRUE; } switch(uiMenuItem) { case ID_EDIT_CUT: case ID_EDIT_COPY: case ID_EDIT_PASTE: case ID_EDIT_CLEAR: case ID_EDIT_SELECT_ALL: case ID_EDIT_UNDO: case ID_CMD_SET_CELL_TO_NULL: break; default: m_pwndContextMenuTarget->SendMessage(WM_COMMAND, wParam, lParam); return TRUE; } } } } return CEdit::OnCommand(wParam, lParam); } //******************************************************************** // CCellEdit::SetToNull // // Set the value of the current cell to NULL. // // Parameters: // None. // // Returns: // Nothing. // //******************************************************************** void CCellEdit::SetToNull() { DWORD dwStyle = GetStyle(); BOOL bIsReadonly = dwStyle & ES_READONLY; if (bIsReadonly) { return; } if (IsNull()) { return; } BOOL bModified = GetModify(); CString sEmpty; if (m_pGrid->ShowNullAsEmpty()) { sEmpty = ""; } SetWindowText(sEmpty, TRUE); m_bIsNull = TRUE; // If the modification flag changed, then redraw the window // so that the text appears in the correct color. FixBuddyCell(); if (GetModify() != bModified) { if (m_pgc) { m_pgc->SetModified(bModified); } if (m_pGrid) { m_pGrid->NotifyCellModifyChange(); RedrawWindow(); } } } BOOL CCellEdit::IsNull() { #if 0 if (m_bIsNull) { CString sText; GetWindowText(sText); BOOL bTextIsEmpty = sText==""; if (!bTextIsEmpty) { m_bIsNull = FALSE; } } #endif //0 return m_bIsNull; } void CCellEdit::OnCmdSetCellToNull() { SetToNull(); } void CCellEdit::OnChange() { if (m_pGrid) { if (m_bPropagateChange) { m_pGrid->NotifyCellModifyChange(); } } } void CCellEdit::RequestUIActive() { if (m_pGrid) { m_pGrid->OnRequestUIActive(); } } void CLbCombo::OnSetFocus(CWnd* pOldWnd) { CListBox::OnSetFocus(pOldWnd); // TODO: Add your message handler code here if (!m_bUIActive) { m_bUIActive = TRUE; m_pClient->RequestUIActive(); } } void CLbCombo::OnKillFocus(CWnd* pNewWnd) { CListBox::OnKillFocus(pNewWnd); // TODO: Add your message handler code here m_bUIActive = FALSE; } void CLbCombo::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) { // TODO: Add your message handler code here and/or call default switch(nChar) { case ESC_CHAR: m_pClient->CatchEvent(NOTIFY_CELL_EDIT_LISTBOX_LBUTTON_UP); return; case VK_TAB: return; } CListBox::OnChar(nChar, nRepCnt, nFlags); } //******************************************************************** // CLbCombo::MapCharToItem // // Map a character to an item in the list. This is used when the // user types a character to cycle through the values in the list // that start with the given character. // // Parameters: // CString& sValue // // UINT nChar // // Returns: // Nothing. // //******************************************************************** SCODE CLbCombo::MapCharToItem(CString& sValue, UINT nChar) { nChar = toupper(nChar); UINT nCharItem; int nItems = GetCount(); int iItem; // If the user repeatedly hits the same character, cycle through the values // that start with that character. int iValue = -1; if (sValue.GetLength() > 0) { UINT nCharValue = (UINT) toupper(sValue[0]); if (nCharValue == nChar) { ASSERT(LB_ERR < 0); iValue = FindString(-1, sValue); } } CString sItem; if (iValue >= 0) { // The value string was found in the list, so start looking at the // first item past this value for another one that starts with the // same given character. for (iItem = iValue + 1; iItem < nItems; ++iItem) { GetText(iItem, sItem); if (sItem.GetLength() > 0) { nCharItem = (UINT) toupper(sItem[0]); if (nCharItem == nChar) { sValue = sItem; return S_OK; } } } // Start over at the beginning of the list and continue up the // the current value looking for an item that starts with the specified // character. for (iItem = 0; iItem < iValue; ++iItem) { GetText(iItem, sItem); if (sItem.GetLength() > 0) { nCharItem = (UINT) toupper(sItem[0]); if (nCharItem == nChar) { sValue = sItem; return S_OK; } } } sValue = ""; return E_FAIL; } else { // No string in the list matches the current value, so look through the // entire list from the beginning for an item that starts with the given // character. for (iItem = 0; iItem < nItems; ++iItem) { GetText(iItem, sItem); if (sItem.GetLength() > 0) { nCharItem = (UINT) toupper(sItem[0]); if (nCharItem == nChar) { sValue = sItem; return S_OK; } } } sValue = ""; return E_FAIL; } }