2397 lines
56 KiB
C++
2397 lines
56 KiB
C++
// 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("<empty>");
|
|
}
|
|
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 = "<empty>";
|
|
}
|
|
|
|
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=="<empty>";
|
|
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;
|
|
|
|
}
|
|
}
|
|
|