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() ); 
}