Win32-GUI
view release on metacpan or search on metacpan
Win32-GUI_Grid/MFCGrid/GridCtrl.cpp view on Meta::CPAN
// - Optional WYSIWYG printing
// - Awareness of hidden (0 width/height) rows and columns for
// key movements, cut, copy, paste, and autosizing
// - CGridCell can make title tips display any text rather than
// cell text only
// - Minor vis bug fixes
// - CGridCtrl now works with CGridCellBase instead of CGridCell
// This is a taste of things to come.
//
// 2.20 30 Jul 2000 - Chris Maunder
// - Font storage optimised (suggested by Martin Richter)
// - AutoSizeColumn works on either column header, data or both
// - EnsureVisible. The saga continues... (Ken)
// - Rewrote exception handling
// - Added TrackFocusCell and FrameFocusCell properties, as well as
// ExpandLastColumn (suggested by Bruce E. Stemplewski).
// - InsertColumn now allows you to insert columns at the end of the
// column range (David Weibel)
// - Shift-cell-selection more intuitive
// - API change: Set/GetGridColor now Set/GetGridLineColor
// - API change: Set/GetBkColor now Set/GetGridBkColor
// - API change: Set/GetTextColor, Set/GetTextBkColor depricated
// - API change: Set/GetFixedTextColor, Set/GetFixedBkColor depricated
// - Stupid DDX_GridControl workaround removed.
// - Added "virtual mode" via Set/GetVirtualMode
// - Added SetCallbackFunc to allow callback functions in virtual mode
// - Added Set/GetAutoSizeStyle
// - AutoSize() bug fixed
// - added GVIS_FIXEDROW, GVIS_FIXEDCOL states
// - added Get/SetFixed[Row|Column]Selection
// - cell "Get" methods now const'd. Sorry folks...
// - GetMouseScrollLines now uses win98/W2K friendly code
// - WS_EX_CLIENTEDGE style now implicit
//
// [ Only the latest version and major version changes will be shown ]
//
// 2.24 13 Jul 2002 - Chris Maunder
// - Optimised OnDraw for invisible cells.
//
// 2.25 13 Mar 2004 - Chris Maunder
// - Minor changes so it will compile in VS.NET (inc. Whidbey)
// - Fixed minor bug in EnsureVisible - Junlin Xu
// - Changed AfxGetInstanceHandle for AfxGetResourceHandle in RegisterWindowClass
//
// TODO: 1) Implement sparse grids (super easy now)
// 2) Fix it so that as you drag select, the speed of selection increases
// with time.
// 3) Scrolling is still a little dodgy (too much grey area). I know there
// is a simple fix but it's been a low priority
// 4) Get some sleep
//
// ISSUES: 2) WindowFromPoint seems to do weird things in W2K. Causing problems for
// the rigt-click-on-titletip code.
//
/////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "MemDC.h"
#include "GridCtrl.h"
// OLE stuff for clipboard operations
#include <afxadv.h> // For CSharedFile
#include <afxconv.h> // For LPTSTR -> LPSTR macros
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
// Spit out some messages as a sanity check for programmers
#ifdef GRIDCONTROL_NO_TITLETIPS
#pragma message(" -- CGridCtrl: No titletips for cells with large data")
#endif
#ifdef GRIDCONTROL_NO_DRAGDROP
#pragma message(" -- CGridCtrl: No OLE drag and drop")
#endif
#ifdef GRIDCONTROL_NO_CLIPBOARD
#pragma message(" -- CGridCtrl: No clipboard support")
#endif
#ifdef GRIDCONTROL_NO_PRINTING
#pragma message(" -- CGridCtrl: No printing support")
#endif
IMPLEMENT_DYNCREATE(CGridCtrl, CWnd)
// Get the number of lines to scroll with each mouse wheel notch
// Why doesn't windows give us this function???
UINT GetMouseScrollLines()
{
int nScrollLines = 3; // reasonable default
#ifndef _WIN32_WCE
// Do things the hard way in win95
OSVERSIONINFO VersionInfo;
VersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
if (!GetVersionEx(&VersionInfo) ||
(VersionInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS && VersionInfo.dwMinorVersion == 0))
{
HKEY hKey;
if (RegOpenKeyEx(HKEY_CURRENT_USER, _T("Control Panel\\Desktop"),
0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
{
TCHAR szData[128];
DWORD dwKeyDataType;
DWORD dwDataBufSize = sizeof(szData);
if (RegQueryValueEx(hKey, _T("WheelScrollLines"), NULL, &dwKeyDataType,
(LPBYTE) &szData, &dwDataBufSize) == ERROR_SUCCESS)
{
nScrollLines = _tcstoul(szData, NULL, 10);
}
RegCloseKey(hKey);
}
}
// win98 or greater
else
SystemParametersInfo (SPI_GETWHEELSCROLLLINES, 0, &nScrollLines, 0);
#endif
return nScrollLines;
}
/////////////////////////////////////////////////////////////////////////////
// CGridCtrl
CGridCtrl::CGridCtrl(int nRows, int nCols, int nFixedRows, int nFixedCols)
{
RegisterWindowClass();
#if !defined(GRIDCONTROL_NO_DRAGDROP) || !defined(GRIDCONTROL_NO_CLIPBOARD)
_AFX_THREAD_STATE* pState = AfxGetThreadState();
if (!pState->m_bNeedTerm && !AfxOleInit())
AfxMessageBox(_T("OLE initialization failed. Make sure that the OLE libraries are the correct version"));
#endif
// Store the system colours in case they change. The gridctrl uses
Win32-GUI_Grid/MFCGrid/GridCtrl.cpp view on Meta::CPAN
{
if (!IsCellEditable(nRow, nCol))
return;
if (SendMessageToParent(nRow, nCol, GVN_BEGINLABELEDIT) >= 0)
{
CString strCurrentText = GetItemText(nRow, nCol);
if (strCurrentText != strText)
{
SetItemText(nRow, nCol, strText);
if (ValidateEdit(nRow, nCol, strText) &&
SendMessageToParent(nRow, nCol, GVN_ENDLABELEDIT) >= 0)
{
SetModified(TRUE, nRow, nCol);
RedrawCell(nRow, nCol);
}
else
{
SetItemText(nRow, nCol, strCurrentText);
}
}
}
}
void CGridCtrl::ClearCells(CCellRange Selection)
{
for (int row = Selection.GetMinRow(); row <= Selection.GetMaxRow(); row++)
{
for (int col = Selection.GetMinCol(); col <= Selection.GetMaxCol(); col++)
{
// don't clear hidden cells
if ( m_arRowHeights[row] > 0 && m_arColWidths[col] > 0 )
{
ValidateAndModifyCellContents(row, col, _T(""));
}
}
}
Refresh();
}
#ifndef GRIDCONTROL_NO_CLIPBOARD
////////////////////////////////////////////////////////////////////////////////////////
// Clipboard functions
// Deletes the contents from the selected cells
void CGridCtrl::CutSelectedText()
{
if (!IsEditable())
return;
for (POSITION pos = m_SelectedCellMap.GetStartPosition(); pos != NULL; )
{
DWORD key;
CCellID cell;
m_SelectedCellMap.GetNextAssoc(pos, key, (CCellID&)cell);
ValidateAndModifyCellContents(cell.row, cell.col, _T(""));
}
}
// Copies text from the selected cells to the clipboard
COleDataSource* CGridCtrl::CopyTextFromGrid()
{
USES_CONVERSION;
CCellRange Selection = GetSelectedCellRange();
if (!IsValid(Selection))
return NULL;
if (GetVirtualMode())
SendCacheHintToParent(Selection);
// Write to shared file (REMEBER: CF_TEXT is ANSI, not UNICODE, so we need to convert)
CSharedFile sf(GMEM_MOVEABLE | GMEM_DDESHARE | GMEM_ZEROINIT);
// Get a tab delimited string to copy to cache
CString str;
CGridCellBase *pCell;
for (int row = Selection.GetMinRow(); row <= Selection.GetMaxRow(); row++)
{
// don't copy hidden cells
if( m_arRowHeights[row] <= 0 )
continue;
str.Empty();
for (int col = Selection.GetMinCol(); col <= Selection.GetMaxCol(); col++)
{
// don't copy hidden cells
if( m_arColWidths[col] <= 0 )
continue;
pCell = GetCell(row, col);
if (pCell &&(pCell->GetState() & GVIS_SELECTED))
{
// if (!pCell->GetText())
// str += _T(" ");
// else
str += pCell->GetText();
}
if (col != Selection.GetMaxCol())
str += _T("\t");
}
if (row != Selection.GetMaxRow())
str += _T("\r\n");
sf.Write(T2A(str.GetBuffer(1)), str.GetLength());
str.ReleaseBuffer();
}
char c = '\0';
sf.Write(&c, 1);
if (GetVirtualMode())
SendCacheHintToParent(CCellRange(-1,-1,-1,-1));
DWORD dwLen = (DWORD) sf.GetLength();
HGLOBAL hMem = sf.Detach();
if (!hMem)
return NULL;
hMem = ::GlobalReAlloc(hMem, dwLen, GMEM_MOVEABLE | GMEM_DDESHARE | GMEM_ZEROINIT);
if (!hMem)
return NULL;
// Cache data
COleDataSource* pSource = new COleDataSource();
pSource->CacheGlobalData(CF_TEXT, hMem);
return pSource;
}
// Pastes text from the clipboard to the selected cells
BOOL CGridCtrl::PasteTextToGrid(CCellID cell, COleDataObject* pDataObject,
BOOL bSelectPastedCells /*=TRUE*/)
{
if (!IsValid(cell) || !IsCellEditable(cell) || !pDataObject->IsDataAvailable(CF_TEXT))
return FALSE;
// Get the text from the COleDataObject
HGLOBAL hmem = pDataObject->GetGlobalData(CF_TEXT);
CMemFile sf((BYTE*) ::GlobalLock(hmem), ::GlobalSize(hmem));
// CF_TEXT is ANSI text, so we need to allocate a char* buffer
// to hold this.
LPTSTR szBuffer = new TCHAR[::GlobalSize(hmem)];
if (!szBuffer)
return FALSE;
sf.Read(szBuffer, ::GlobalSize(hmem));
::GlobalUnlock(hmem);
// Now store in generic TCHAR form so we no longer have to deal with
// ANSI/UNICODE problems
CString strText = szBuffer;
delete szBuffer;
// Parse text data and set in cells...
strText.LockBuffer();
CString strLine = strText;
int nLine = 0;
// Find the end of the first line
CCellRange PasteRange(cell.row, cell.col,-1,-1);
int nIndex;
do
{
int nColumn = 0;
nIndex = strLine.Find(_T("\n"));
// Store the remaining chars after the newline
CString strNext = (nIndex < 0)? _T("") : strLine.Mid(nIndex + 1);
// Remove all chars after the newline
if (nIndex >= 0)
strLine = strLine.Left(nIndex);
int nLineIndex = strLine.FindOneOf(_T("\t,"));
CString strCellText = (nLineIndex >= 0)? strLine.Left(nLineIndex) : strLine;
// skip hidden rows
int iRowVis = cell.row + nLine;
while( iRowVis < GetRowCount())
{
if( GetRowHeight( iRowVis) > 0)
break;
nLine++;
iRowVis++;
}
while (!strLine.IsEmpty())
{
// skip hidden columns
Win32-GUI_Grid/MFCGrid/GridCtrl.cpp view on Meta::CPAN
ValidateAndModifyCellContents(TargetCell.row, TargetCell.col, strCellText);
// Make sure cell is not selected to avoid data loss
SetItemState(TargetCell.row, TargetCell.col,
GetItemState(TargetCell.row, TargetCell.col) & ~GVIS_SELECTED);
if (iRowVis > PasteRange.GetMaxRow()) PasteRange.SetMaxRow(iRowVis);
if (iColVis > PasteRange.GetMaxCol()) PasteRange.SetMaxCol(iColVis);
}
strLine = (nLineIndex >= 0)? strLine.Mid(nLineIndex + 1) : _T("");
nLineIndex = strLine.FindOneOf(_T("\t,"));
strCellText = (nLineIndex >= 0)? strLine.Left(nLineIndex) : strLine;
nColumn++;
}
strLine = strNext;
nLine++;
} while (nIndex >= 0);
strText.UnlockBuffer();
if (bSelectPastedCells)
SetSelectedRange(PasteRange, TRUE);
else
{
ResetSelectedRange();
Refresh();
}
return TRUE;
}
#endif
#ifndef GRIDCONTROL_NO_DRAGDROP
// Start drag n drop
void CGridCtrl::OnBeginDrag()
{
if (!m_bAllowDragAndDrop)
return;
COleDataSource* pSource = CopyTextFromGrid();
if (pSource)
{
SendMessageToParent(GetSelectedCellRange().GetTopLeft().row,
GetSelectedCellRange().GetTopLeft().col,
GVN_BEGINDRAG);
m_MouseMode = MOUSE_DRAGGING;
m_bLMouseButtonDown = FALSE;
DROPEFFECT dropEffect = pSource->DoDragDrop(DROPEFFECT_COPY | DROPEFFECT_MOVE);
if (dropEffect & DROPEFFECT_MOVE)
CutSelectedText();
if (pSource)
delete pSource; // Did not pass source to clipboard, so must delete
}
}
// Handle drag over grid
DROPEFFECT CGridCtrl::OnDragOver(COleDataObject* pDataObject, DWORD dwKeyState,
CPoint point)
{
// Any text data available for us?
if (!m_bAllowDragAndDrop || !IsEditable() || !pDataObject->IsDataAvailable(CF_TEXT))
return DROPEFFECT_NONE;
// Find which cell we are over and drop-highlight it
CCellID cell = GetCellFromPt(point, FALSE);
// If not valid, set the previously drop-highlighted cell as no longer drop-highlighted
if (!IsValid(cell))
{
OnDragLeave();
m_LastDragOverCell = CCellID(-1,-1);
return DROPEFFECT_NONE;
}
if (!IsCellEditable(cell))
return DROPEFFECT_NONE;
// Have we moved over a different cell than last time?
if (cell != m_LastDragOverCell)
{
// Set the previously drop-highlighted cell as no longer drop-highlighted
if (IsValid(m_LastDragOverCell))
{
UINT nState = GetItemState(m_LastDragOverCell.row, m_LastDragOverCell.col);
SetItemState(m_LastDragOverCell.row, m_LastDragOverCell.col,
nState & ~GVIS_DROPHILITED);
RedrawCell(m_LastDragOverCell);
}
m_LastDragOverCell = cell;
// Set the new cell as drop-highlighted
if (IsValid(m_LastDragOverCell))
{
UINT nState = GetItemState(m_LastDragOverCell.row, m_LastDragOverCell.col);
SetItemState(m_LastDragOverCell.row, m_LastDragOverCell.col,
nState | GVIS_DROPHILITED);
RedrawCell(m_LastDragOverCell);
}
}
// Return an appropraite value of DROPEFFECT so mouse cursor is set properly
if (dwKeyState & MK_CONTROL)
return DROPEFFECT_COPY;
else
return DROPEFFECT_MOVE;
}
// Something has just been dragged onto the grid
DROPEFFECT CGridCtrl::OnDragEnter(COleDataObject* pDataObject, DWORD dwKeyState,
CPoint point)
{
Win32-GUI_Grid/MFCGrid/GridCtrl.cpp view on Meta::CPAN
void CGridCtrl::OnEditCut()
{
if (!IsEditable())
return;
COleDataSource* pSource = CopyTextFromGrid();
if (!pSource)
return;
pSource->SetClipboard();
CutSelectedText();
}
void CGridCtrl::OnEditCopy()
{
COleDataSource* pSource = CopyTextFromGrid();
if (!pSource)
return;
pSource->SetClipboard();
}
void CGridCtrl::OnEditPaste()
{
if (!IsEditable())
return;
CCellRange cellRange = GetSelectedCellRange();
// Get the top-left selected cell, or the Focus cell, or the topleft (non-fixed) cell
CCellID cell;
if (cellRange.IsValid())
{
cell.row = cellRange.GetMinRow();
cell.col = cellRange.GetMinCol();
}
else
{
cell = GetFocusCell();
if (!IsValid(cell))
cell = GetTopleftNonFixedCell();
if (!IsValid(cell))
return;
}
// If a cell is being edited, then call it's edit window paste function.
if ( IsItemEditing(cell.row, cell.col) )
{
CGridCellBase* pCell = GetCell(cell.row, cell.col);
ASSERT(pCell);
if (!pCell) return;
CWnd* pEditWnd = pCell->GetEditWnd();
if ( pEditWnd && pEditWnd->IsKindOf(RUNTIME_CLASS(CEdit)) )
{
((CEdit*)pEditWnd)->Paste();
return;
}
}
// Attach a COleDataObject to the clipboard and paste the data to the grid
COleDataObject obj;
if (obj.AttachClipboard())
PasteTextToGrid(cell, &obj);
}
#endif
void CGridCtrl::OnEditSelectAll()
{
SendMessageToParent(m_LeftClickDownCell.row, m_LeftClickDownCell.col, GVN_SELCHANGING);
SelectAllCells();
SendMessageToParent(m_idCurrentCell.row, m_idCurrentCell.col, GVN_SELCHANGED);
}
#ifndef GRIDCONTROL_NO_CLIPBOARD
void CGridCtrl::OnUpdateEditCopy(CCmdUI* pCmdUI)
{
pCmdUI->Enable(GetSelectedCount() > 0); // - Thomas Haase
//CCellRange Selection = GetSelectedCellRange();
//pCmdUI->Enable(Selection.Count() && IsValid(Selection));
}
void CGridCtrl::OnUpdateEditCut(CCmdUI* pCmdUI)
{
pCmdUI->Enable(IsEditable() && GetSelectedCount() > 0); // - Thomas Haase
//CCellRange Selection = GetSelectedCellRange();
//pCmdUI->Enable(IsEditable() && Selection.Count() && IsValid(Selection));
}
void CGridCtrl::OnUpdateEditPaste(CCmdUI* pCmdUI)
{
CCellID cell = GetFocusCell();
BOOL bCanPaste = IsValid(cell) && IsCellEditable(cell) &&
::IsClipboardFormatAvailable(CF_TEXT);
pCmdUI->Enable(bCanPaste);
}
#endif
void CGridCtrl::OnUpdateEditSelectAll(CCmdUI* pCmdUI)
{
pCmdUI->Enable(m_bEnableSelection);
}
////////////////////////////////////////////////////////////////////////////////////////
// hittest-like functions
// TRUE if the mouse is over a row resize area
BOOL CGridCtrl::MouseOverRowResizeArea(CPoint& point)
{
if (point.x >= GetFixedColumnWidth())
return FALSE;
CCellID idCurrentCell = GetCellFromPt(point);
CPoint start;
if (!GetCellOrigin(idCurrentCell, &start))
return FALSE;
int endy = start.y + GetRowHeight(idCurrentCell.row);
( run in 0.578 second using v1.01-cache-2.11-cpan-81fc1098f69 )