www.pudn.com > MarkupDemo.rar > MarkupDemoView.cpp
// MarkupDemoView.cpp : implementation of the CMarkupDemoView class
//
#include "stdafx.h"
#include "MarkupDemo.h"
#include "MarkupDemoDoc.h"
#include "MarkupDemoView.h"
#define IDC_MARKUP_TREE 1020
#define IDC_MARKUP_EDIT 1021
#define IDC_MARKUP_DIVIDER 1022
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CMarkupDemoView
IMPLEMENT_DYNCREATE(CMarkupDemoView, CView)
BEGIN_MESSAGE_MAP(CMarkupDemoView, CView)
//{{AFX_MSG_MAP(CMarkupDemoView)
ON_WM_CREATE()
ON_WM_SIZE()
ON_COMMAND(ID_MARKUP_FIND, OnMarkupFind)
ON_COMMAND(ID_MARKUP_ADD, OnMarkupAdd)
ON_COMMAND(ID_MARKUP_ADD_CHILD, OnMarkupAddChild)
ON_COMMAND(ID_MARKUP_ADD_ATTRIB, OnMarkupAddAttrib)
ON_COMMAND(ID_EDIT_COPY, OnEditCopy)
ON_COMMAND(ID_EDIT_CUT, OnEditCut)
ON_COMMAND(ID_EDIT_PASTE, OnEditPaste)
ON_COMMAND(ID_EDIT_UNDO, OnEditUndo)
ON_UPDATE_COMMAND_UI(ID_EDIT_UNDO, OnUpdateEditUndo)
//}}AFX_MSG_MAP
// Standard printing commands
ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)
ON_EN_CHANGE(IDC_MARKUP_EDIT, OnChangeEdit)
ON_MESSAGE( WM_APP, OnAppMessage )
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CMarkupDemoView construction/destruction
CMarkupDemoView::CMarkupDemoView()
{
m_nAddAttrib = 0;
}
CMarkupDemoView::~CMarkupDemoView()
{
}
BOOL CMarkupDemoView::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
return CView::PreCreateWindow(cs);
}
/////////////////////////////////////////////////////////////////////////////
// CMarkupDemoView drawing
void CMarkupDemoView::OnDraw(CDC* pDC)
{
CMarkupDemoDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
}
/////////////////////////////////////////////////////////////////////////////
// CMarkupDemoView printing
BOOL CMarkupDemoView::OnPreparePrinting(CPrintInfo* pInfo)
{
// default preparation
return DoPreparePrinting(pInfo);
}
void CMarkupDemoView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: add extra initialization before printing
}
void CMarkupDemoView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: add cleanup after printing
}
/////////////////////////////////////////////////////////////////////////////
// CMarkupDemoView diagnostics
#ifdef _DEBUG
void CMarkupDemoView::AssertValid() const
{
CView::AssertValid();
}
void CMarkupDemoView::Dump(CDumpContext& dc) const
{
CView::Dump(dc);
}
CMarkupDemoDoc* CMarkupDemoView::GetDocument() // non-debug version is inline
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CMarkupDemoDoc)));
return (CMarkupDemoDoc*)m_pDocument;
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CMarkupDemoView message handlers
void CMarkupDemoView::OnInitialUpdate()
{
m_pXML = &GetDocument()->m_doc;
CView::OnInitialUpdate();
// Maximize first time
static BOOL bFirst = TRUE;
if ( bFirst )
{
bFirst = FALSE;
GetParent()->ShowWindow( SW_MAXIMIZE );
}
// Divider
m_divider.m_nFractionOf1000 = 350;
m_divider.m_enumOrientation = m_divider.MoveHorizontal;
// Initial resize
CRect rect;
GetClientRect( &rect );
CalcSize( rect.Width(), rect.Height() );
// Text
const int nMax = 64000; // Win 95 limit
m_edit.SetLimitText( nMax );
CString csText = GetDocument()->m_csText;
if ( csText.GetLength() > nMax )
AfxMessageBox( _T("Document is larger than edit buffer maximum") );
m_edit.SetWindowText( csText );
GetDocument()->SetParsedFlag( TRUE );
GetDocument()->SetModifiedFlag( FALSE );
}
void CMarkupDemoView::GetEditText( CString& csDoc )
{
if ( m_edit.GetSafeHwnd() )
m_edit.GetWindowText( csDoc );
}
CString CMarkupDemoView::SetEditTextFromDoc()
{
// Set document in rich edit control
CString csDoc = m_pXML->GetDoc();
m_edit.SetWindowText( csDoc );
GetDocument()->m_csText = csDoc;
GetDocument()->SetParsedFlag( TRUE );
return csDoc;
}
int CMarkupDemoView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
int nFlags = WS_VISIBLE|WS_CHILD|WS_GROUP;
if ( ! m_tree.Create( nFlags|TVS_LINESATROOT|TVS_HASLINES|TVS_HASBUTTONS,
CRect(0,0,0,0), this, IDC_MARKUP_TREE ) )
return -1;
m_ilTree.Create(IDB_IL_TREE,16,0,RGB(255,255,255));
m_tree.SetImageList(&m_ilTree,TVSIL_NORMAL);
if ( ! m_divider.CreateEx(WS_EX_DLGMODALFRAME,_T("STATIC"),NULL,nFlags|SS_NOTIFY,
CRect(0,0,0,0),this,IDC_MARKUP_DIVIDER) )
return -1;
nFlags = WS_CHILD|WS_VISIBLE|ES_MULTILINE|ES_WANTRETURN|WS_VSCROLL;
if ( ! m_edit.Create( nFlags, CRect(0,0,0,0), this, IDC_MARKUP_EDIT ) )
return -1;
// Get default system font
HFONT hSystemFont = (HFONT)GetStockObject(SYSTEM_FONT);
LOGFONT systemFont;
VERIFY(::GetObject(hSystemFont, sizeof(LOGFONT), (void*)&systemFont));
// Set a Unicode font as the default
// If you have a font that does not support the unicode characters you
// are trying to view, then the characters appear as blocks or blanks
// If unicode is not desired replace with the following
// m_font.CreateFontIndirect(&systemFont);
LOGFONT logFont; memset(&logFont, 0, sizeof(LOGFONT));
logFont.lfHeight = systemFont.lfHeight + 1;
logFont.lfWeight = FW_NORMAL;
logFont.lfCharSet = DEFAULT_CHARSET;
lstrcpy(logFont.lfFaceName, _T("Lucida Sans Unicode"));
if ( ! m_font.CreateFontIndirect(&logFont) )
m_font.CreateFontIndirect(&systemFont);
m_edit.SetFont( &m_font );
return 0;
}
void CMarkupDemoView::CalcSize( int cx, int cy )
{
CRect rectBorder( 0, 0, cx, cy );
CRect rect( rectBorder );
int nOffset = m_divider.CalculateOffset( rectBorder.Width() );
rect.right = rect.left + nOffset;
m_tree.MoveWindow( &rect );
rect.left += nOffset;
rect.right = rect.left + m_divider.m_nWidth;
m_divider.MoveWindow( &rect );
rect.left = rect.right;
rect.right = rectBorder.right;
m_edit.MoveWindow( &rect );
m_tree.Invalidate();
m_divider.Invalidate();
m_edit.Invalidate();
}
void CMarkupDemoView::OnSize(UINT nType, int cx, int cy)
{
CView::OnSize(nType, cx, cy);
if ( m_tree.GetSafeHwnd() )
CalcSize( cx, cy );
}
void CMarkupDemoView::GetNthWisePos( HTREEITEM hItem, CUIntArray& aNths )
{
// Populate aNths with sibling number on each level
// if it is the first sibling, it is set to 1, etc
while ( hItem )
{
HTREEITEM hParentItem = m_tree.GetParentItem( hItem );
// Calculate Nth position on this level
aNths.InsertAt( 0, 0, 1 );
while ( hItem )
{
if ( m_tree.GetItemData(hItem) == 0 ) // It is Elem? (not attrib)
++aNths[0];
hItem = m_tree.GetPrevSiblingItem( hItem );
}
// Remove if attribute
if ( aNths[0] == 0 )
aNths.RemoveAt( 0 );
// Go to parent item
hItem = hParentItem;
}
}
void CMarkupDemoView::SetPos( HTREEITEM hItem, BOOL bChild )
{
// Synchronize current position in XML document
CUIntArray aNths;
GetNthWisePos( hItem, aNths );
m_pXML->ResetPos();
int nLev = 0;
int nCount = aNths[nLev];
while ( nCount-- )
m_pXML->FindElem();
while ( ++nLev < aNths.GetSize() )
{
nCount = aNths[nLev];
while ( nCount-- )
m_pXML->FindChildElem();
if ( nLev < aNths.GetSize() - 1 || ! bChild )
m_pXML->IntoElem();
}
}
void CMarkupDemoView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint)
{
UNREFERENCED_PARAMETER(pSender);
UNREFERENCED_PARAMETER(pHint);
UNREFERENCED_PARAMETER(lHint);
CWaitCursor wait;
if ( lHint )
{
m_edit.SetWindowText( GetDocument()->m_csText );
GetDocument()->SetParsedFlag( TRUE );
}
// Find selected position
HTREEITEM hSelectedItem = m_tree.GetSelectedItem();
CUIntArray aNths;
GetNthWisePos( hSelectedItem, aNths );
hSelectedItem = NULL;
// Traverse root and immediate children
// plus any elements on path to the selected position
m_tree.DeleteAllItems();
m_pXML->ResetPos();
BOOL bFound = m_pXML->FindElem();
HTREEITEM hItem, hParentItem = TVI_ROOT;
int nLev = 0;
CUIntArray aCurNth;
aCurNth.Add(1);
while ( bFound )
{
hItem = AddElemToTree( hParentItem );
// Select it if this is the correct item
if ( nLev == aNths.GetSize()-1 && aCurNth[nLev] == aNths[nLev] )
hSelectedItem = hItem;
// Is there a child?
bFound = ElemHasSubItems();
// Above 2 levels, leave children blank to be filled on expand
// Set flag indicating whether this element is on path to selection position
BOOL bOnPath = nLev < aNths.GetSize() && aCurNth[nLev] == aNths[nLev];
if ( bFound && nLev > 0 && ! bOnPath )
{
m_tree.InsertItem( _T(""), hItem );
bFound = FALSE;
}
if ( bFound )
{
// Go into child
m_pXML->ResetChildPos();
if ( m_pXML->FindChildElem() )
{
hParentItem = hItem;
m_pXML->IntoElem();
++nLev;
aCurNth.SetAtGrow( nLev, 1 );
}
else
{
bFound = FALSE;
}
}
if ( ! bFound )
{
// Look for more on same level or toward root
while ( (bFound=m_pXML->FindElem()) == 0 && nLev )
{
m_tree.Expand( hParentItem, TVE_EXPAND );
hParentItem = m_tree.GetParentItem(hParentItem);
m_pXML->OutOfElem();
--nLev;
}
++aCurNth[nLev];
}
}
// Was corresponding item to previously selected found?
if ( hSelectedItem )
{
m_tree.SelectItem( hSelectedItem );
m_tree.EnsureVisible( hSelectedItem );
}
}
void CMarkupDemoView::OnChangeEdit()
{
GetDocument()->SetModifiedFlag();
GetDocument()->SetParsedFlag( FALSE );
}
LRESULT CMarkupDemoView::OnAppMessage( WPARAM, LPARAM )
{
// Post WM_APP, then here set focus to m_edit
// So that selection in document is visible
m_edit.SetFocus();
return 0;
}
HTREEITEM CMarkupDemoView::AddElemToTree(HTREEITEM hParentItem)
{
HTREEITEM hItem;
hItem = m_tree.InsertItem( m_pXML->GetTagName(), hParentItem );
m_tree.SetItemData( hItem, 0 );
return hItem;
}
BOOL CMarkupDemoView::ElemHasSubItems()
{
BOOL bElemHasSubItems = FALSE;
if ( m_pXML->FindChildElem() || ! m_pXML->GetChildData().IsEmpty() )
bElemHasSubItems = TRUE;
return bElemHasSubItems;
}
BOOL CMarkupDemoView::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
// NMHDR is { HWND hwndFrom; UINT idFrom; UINT code; }
NMHDR* pNMHDR = (NMHDR*)lParam;
// Double-click on tree
if ( pNMHDR->code == NM_DBLCLK && pNMHDR->idFrom == IDC_MARKUP_TREE )
{
if ( m_tree.GetSelectedItem() )
{
OnMarkupFind();
// Message handled
*pResult = 0;
return TRUE;
}
}
// Right-click on tree
if ( pNMHDR->code == NM_RCLICK && pNMHDR->idFrom == IDC_MARKUP_TREE )
{
// Create popup menu
// From resource, use menu.LoadMenu( IDR_MARKUPTREE );
// and menu.GetSubMenu(0)->TrackPopupMenu()
CMenu menu;
UINT nFlags = MF_STRING;
BOOL bShowMenu = TRUE;
DWORD dwPos = GetMessagePos();
CPoint point(LOWORD(dwPos), HIWORD(dwPos));
ScreenToClient(&point);
if ( GetDocument()->IsParsed() )
{
// Determine item right-clicked on
HTREEITEM hItem = m_tree.HitTest( point );
if ( hItem )
{
// Select item clicked on
m_tree.SelectItem( hItem );
// Is it an attribute?
BOOL bIsAttrib = m_tree.GetItemData( hItem );
// Is this the root element or root element attribute?
BOOL bRootElem = FALSE;
HTREEITEM hParentItem = m_tree.GetParentItem( hItem );
if ( ! hParentItem ||
( ! m_tree.GetParentItem(hParentItem) && m_tree.GetItemData(hItem)==1 ) )
bRootElem = TRUE;
menu.CreatePopupMenu();
if ( bIsAttrib )
{
menu.AppendMenu( nFlags, ID_MARKUP_FIND, _T("&Find Elem") );
menu.AppendMenu( nFlags, ID_MARKUP_ADD_ATTRIB, _T("Add A&ttrib") );
}
else
{
menu.AppendMenu( nFlags, ID_MARKUP_FIND, _T("&Find Elem") );
if ( ! bRootElem )
menu.AppendMenu( nFlags, ID_MARKUP_ADD, _T("&Add Elem") );
menu.AppendMenu( nFlags, ID_MARKUP_ADD_CHILD, _T("Add &Child Elem") );
menu.AppendMenu( nFlags, ID_MARKUP_ADD_ATTRIB, _T("Add A&ttrib") );
}
}
else
bShowMenu = FALSE;
}
else
{
menu.CreatePopupMenu();
menu.AppendMenu( nFlags, ID_FILE_PARSE, _T("&Parse") );
}
if ( bShowMenu )
{
// Run popup menu
ClientToScreen(&point);
menu.TrackPopupMenu(
TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, this );
}
// Message handled
*pResult = 0;
return TRUE;
}
// Expand item in tree
if ( pNMHDR->code == TVN_ITEMEXPANDING && pNMHDR->idFrom == IDC_MARKUP_TREE )
{
NMTREEVIEW* pnmtv = (NMTREEVIEW*)pNMHDR;
if ( pnmtv->action & TVE_EXPAND )
{
// Is the child empty?
HTREEITEM hParentItem = pnmtv->itemNew.hItem;
HTREEITEM hItem = m_tree.GetChildItem( hParentItem );
if ( hItem && m_tree.GetItemText( hItem ).IsEmpty() )
{
// Remove blank child
m_tree.DeleteItem( hItem );
// Add attribs and child elements to tree
SetPos( hParentItem );
while ( m_pXML->FindChildElem() )
{
// Go into child
m_pXML->IntoElem();
// Add to tree control
hItem = AddElemToTree( hParentItem );
// Create empty child under it, if it has data, attribs, or children
if ( ElemHasSubItems() )
m_tree.InsertItem( _T(""), hItem );
// Back to parent to find next child
m_pXML->OutOfElem();
}
}
}
}
return CView::OnNotify(wParam, lParam, pResult);
}
void CMarkupDemoView::OnMarkupFind()
{
if ( GetDocument()->IsParsed() )
{
HTREEITEM hItem = m_tree.GetSelectedItem();
if ( hItem )
{
// Select element
SetPos( hItem );
int nStart, nEnd;
GetDocument()->m_doc.GetOffsets( nStart, nEnd );
m_edit.SetSel( nStart, nEnd + 1 );
// Edit control must have focus to display selection
// Post message so that it gets focus after current message is complete
PostMessage( WM_APP );
}
}
}
void CMarkupDemoView::OnMarkupAdd()
{
if ( GetDocument()->IsParsed() )
{
HTREEITEM hItem = m_tree.GetSelectedItem();
if ( hItem )
{
// Add a new element to the document
SetPos( hItem );
CString csName = m_pXML->GetTagName();
m_pXML->AddElem( csName );
// Add item to tree
HTREEITEM hParentItem = m_tree.GetParentItem( hItem );
hItem = m_tree.InsertItem( csName, hParentItem, hItem );
m_tree.SetItemData( hItem, 0 );
// Set document in edit window
SetEditTextFromDoc();
}
}
}
void CMarkupDemoView::OnMarkupAddChild()
{
if ( GetDocument()->IsParsed() )
{
HTREEITEM hParentItem = m_tree.GetSelectedItem();
if ( hParentItem )
{
// Find last child position
HTREEITEM hItem = m_tree.GetChildItem( hParentItem );
HTREEITEM hItemSet = hParentItem;
BOOL bChild = FALSE;
while ( hItem )
{
hItemSet = hItem;
bChild = TRUE;
hItem = m_tree.GetNextSiblingItem( hItem );
}
SetPos( hItemSet, bChild );
// Add a new element to the document
CString csName = _T("ChildOf") + m_pXML->GetTagName();
m_pXML->AddChildElem( csName );
// Add item to tree
hItem = m_tree.InsertItem( csName, hParentItem );
m_tree.SetItemData( hItem, 0 );
m_tree.Expand( hParentItem, TVE_EXPAND );
// Set document in edit window
SetEditTextFromDoc();
}
}
}
void CMarkupDemoView::OnMarkupAddAttrib()
{
if ( GetDocument()->IsParsed() )
{
HTREEITEM hItem = m_tree.GetSelectedItem();
if ( hItem )
{
// Add a new attrib to the element
SetPos( hItem );
++m_nAddAttrib;
CString csAttribName;
csAttribName.Format( _T("attrib%d"), m_nAddAttrib );
CString csAttribValue;
csAttribValue.Format( _T("val%d"), m_nAddAttrib );
m_pXML->AddAttrib( csAttribName, csAttribValue );
// If selected item is attribute, get element item
if ( m_tree.GetItemData(hItem) == 1 )
hItem = m_tree.GetParentItem( hItem );
// Determine last attribute item
HTREEITEM hAttribItem = TVI_FIRST;
HTREEITEM hNextChildItem = m_tree.GetChildItem( hItem );
// Make sure its not an unexpanded tree item already having children
if ( ! hNextChildItem || ! m_tree.GetItemText(hNextChildItem).IsEmpty() )
{
while ( hNextChildItem && m_tree.GetItemData( hNextChildItem ) == 1 )
{
hAttribItem = hNextChildItem;
hNextChildItem = m_tree.GetNextSiblingItem( hNextChildItem );
}
}
m_tree.Expand( hItem, TVE_EXPAND );
// Set document in edit window
SetEditTextFromDoc();
}
}
}
void CMarkupDemoView::OnEditCopy()
{
m_edit.Copy();
}
void CMarkupDemoView::OnEditCut()
{
m_edit.Cut();
}
void CMarkupDemoView::OnEditPaste()
{
m_edit.Paste();
}
void CMarkupDemoView::OnEditUndo()
{
m_edit.Undo();
}
void CMarkupDemoView::OnUpdateEditUndo(CCmdUI* pCmdUI)
{
pCmdUI->Enable( m_edit.CanUndo() );
}