#include "stdafx.h"
#include "MainFrame.h"
#include "registryxml.h"
#include "registryxmlDoc.h"
#include "registryxmlTree.h"
#include "baseTypes.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// registryxmlTree
IMPLEMENT_DYNCREATE(registryxmlTree, CTreeView)
BEGIN_MESSAGE_MAP(registryxmlTree, CTreeView)
//{{AFX_MSG_MAP(registryxmlTree)
// NOTE - the ClassWizard will add and remove mapping macros here.
ON_WM_CREATE()
ON_WM_DESTROY()
ON_NOTIFY_REFLECT(TVN_SELCHANGED, OnSelChanged)
ON_NOTIFY_REFLECT(NM_RCLICK, OnRightClick)
ON_NOTIFY_REFLECT(TVN_ITEMEXPANDING, OnExpand)
ON_COMMAND(ID_EDIT_REFRESH, OnRefresh)
ON_COMMAND(ID_EXPORTASXML, OnSaveAsXml)
ON_COMMAND(ID_EXPORTASFAKEDXML, OnSaveAsFakedXml)
ON_COMMAND(ID_IMPORTFROMXML, OnLoadXml)
ON_WM_LBUTTONDOWN()
ON_WM_KEYDOWN()
// DO NOT EDIT what you see in these blocks of generated code!
//}}AFX_MSG_MAP
// Standard printing commands
ON_COMMAND(ID_FILE_PRINT, CTreeView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_DIRECT, CTreeView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW, CTreeView::OnFilePrintPreview)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// registryxmlTree construction/destruction
registryxmlTree::registryxmlTree()
{
// TODO: add construction code here
}
registryxmlTree::~registryxmlTree()
{
}
BOOL registryxmlTree::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
if (!CTreeView::PreCreateWindow(cs)) return FALSE;
cs.style |= TVS_HASLINES | TVS_LINESATROOT | TVS_HASBUTTONS | TVS_SHOWSELALWAYS;
return TRUE;
}
int registryxmlTree::OnCreate(LPCREATESTRUCT lpcs)
{
if (CTreeView::OnCreate(lpcs)==-1) return -1;
CBitmap my_bitmap;
my_bitmap.LoadBitmap(IDB_IMAGELIST);
m_imglDrives.Create(16,16,ILC_COLOR24|ILC_MASK,30,10);
m_imglDrives.Add(&my_bitmap,RGB(255,0,255));
GetTreeCtrl().SetImageList(&m_imglDrives,TVSIL_NORMAL);
m_hItemBOOL = FALSE;
return 0;
}
void registryxmlTree::OnDestroy()
{
}
/////////////////////////////////////////////////////////////////////////////
//
//
// registryxmlTree populating
//
//
void registryxmlTree::OnInitialUpdate()
{
CTreeView::OnInitialUpdate();
Refresh();
}
afx_msg void registryxmlTree::OnRefresh()
{
Refresh();
}
void registryxmlTree::Refresh()
{
GetTreeCtrl().DeleteAllItems();
// add nodes
HTREEITEM hRoot = GetTreeCtrl().InsertItem( "My Computer",
ILI_DEFAULT,
ILI_DEFAULT,
TVI_ROOT,
TVI_LAST);
HTREEITEM h1 = GetTreeCtrl().InsertItem("HKEY_CLASSES_ROOT", ILI_FOLDER, ILI_FOLDERS, hRoot, TVI_LAST);
GetTreeCtrl().InsertItem(FAKEDITEM, ILI_DEFAULT, ILI_DEFAULT, h1, TVI_LAST);
HTREEITEM h2 = GetTreeCtrl().InsertItem("HKEY_CURRENT_USER", ILI_FOLDER, ILI_FOLDERS, hRoot, TVI_LAST);
GetTreeCtrl().InsertItem(FAKEDITEM, ILI_DEFAULT, ILI_DEFAULT, h2, TVI_LAST);
HTREEITEM h3 = GetTreeCtrl().InsertItem("HKEY_LOCAL_MACHINE", ILI_FOLDER, ILI_FOLDERS, hRoot, TVI_LAST);
GetTreeCtrl().InsertItem(FAKEDITEM, ILI_DEFAULT, ILI_DEFAULT, h3, TVI_LAST);
HTREEITEM h4 = GetTreeCtrl().InsertItem("HKEY_USERS", ILI_FOLDER, ILI_FOLDERS, hRoot, TVI_LAST);
GetTreeCtrl().InsertItem(FAKEDITEM, ILI_DEFAULT, ILI_DEFAULT, h4, TVI_LAST);
HTREEITEM h5 = GetTreeCtrl().InsertItem("HKEY_CURRENT_CONFIG", ILI_FOLDER, ILI_FOLDERS, hRoot, TVI_LAST);
GetTreeCtrl().InsertItem(FAKEDITEM, ILI_DEFAULT, ILI_DEFAULT, h5, TVI_LAST);
m_hItemFirstSel = NULL;
m_bCtrlClick = FALSE;
m_hItemBOOL = FALSE;
}
/////////////////////////////////////////////////////////////////////////////
//
//
// registryxmlTree drawing
//
//
void registryxmlTree::OnDraw(CDC* pDC)
{
registryxmlDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
}
BOOL registryxmlTree::IsExpanded(HTREEITEM hItem)
{
BOOL bResult = FALSE;
TVITEM dragItem;
dragItem.mask=TVIF_HANDLE | TVIF_STATE;
dragItem.hItem=hItem;
dragItem.pszText=NULL;
if (GetTreeCtrl().GetItem(&dragItem))
bResult=dragItem.state & TVIS_EXPANDED;
return bResult;
}
/////////////////////////////////////////////////////////////////////////////
//
//
// registryxmlTree message handlers
//
//
//
//
void registryxmlTree::OnSelChanged(NMHDR *pnmh,LRESULT *pResult)
{
NM_TREEVIEW *pnmtv=(NM_TREEVIEW *)pnmh;
CString strPath=GetPathFromNode (pnmtv->itemNew.hItem);
((CMainFrame*)AfxGetMainWnd())->SetMessageText(strPath);
OnSelectionChanged(strPath);
}
void registryxmlTree::OnSelectionChanged(CString &strPath)
{
// red�finir cette fonction dans une classe d�riv�e, afin de
// r�pondre diff�remment aux changements de s�lection.
// Ici, UpdateAllViews sert � mettre � jour le compagnon CListView
GetDocument()->UpdateAllViews(this,(LPARAM) strPath.GetBuffer(0) );
}
// Function name : registryxmlTree::OnRightClick
// Description : NOTIFY clic droit souris : menu contextuel selon type d'item
// Return type : void
// Argument : NMHDR *pnmh
// Argument : LRESULT *pResult = FALSE si cela s'est bien pass�
void registryxmlTree::OnRightClick(NMHDR * pNotifyStruct, LRESULT* pResult)
{
// r�cup�re la souris et met en coordonn�es locales au TreeView
DWORD dwPos=::GetMessagePos();
CPoint point ( (int)LOWORD(dwPos),(int)HIWORD(dwPos));
GetTreeCtrl().ScreenToClient(&point);
// v�rifie qu'on a cliqu� sur un Item du TreeView
UINT nFlags;
m_hItem=FALSE; // m_hItem non significatif a priori
m_hItem=GetTreeCtrl().HitTest(point,&nFlags);
if ( nFlags == TVHT_NOWHERE) return;
m_hItemBOOL=TRUE;
// r�cup�re le coin sup�rieur gauche de mon TreeView
CRect rect;
this->GetWindowRect(&rect);
// balance un des menus (variable d�truite quand on sort de la fonction)
CMenu menu;
if ( menu.LoadMenu ( IDM_TREEITEM ) )
{
CMenu *pContextMenu=menu.GetSubMenu(0);
if (pContextMenu != NULL) pContextMenu->TrackPopupMenu(
TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_RIGHTBUTTON, point.x+rect.left, point.y+rect.top, this);
}
*pResult=FALSE;
}
void registryxmlTree::OnExpand(NMHDR *pnmh,LRESULT *pResult)
{
NM_TREEVIEW *pnmtv=(NM_TREEVIEW *)pnmh;
UINT action = pnmtv->action;
int nExpand = TVE_EXPAND;
int nCollapse = TVE_COLLAPSE;
HTREEITEM hItem = pnmtv->itemNew.hItem;
if (action==TVE_EXPAND) // is being expanded
{
HTREEITEM hChildItem = GetTreeCtrl().GetChildItem(hItem);
if (hChildItem)
{
CString szChildName = GetTreeCtrl().GetItemText(hChildItem);
if ( szChildName.CompareNoCase(FAKEDITEM)==0 ) // there is
{
// remove this child
GetTreeCtrl().DeleteItem(hChildItem);
if (hItem && GetTreeCtrl().GetParentItem(hItem))
{
LockWindowUpdate(); // CWnd member
SetCursor(LoadCursor(NULL, IDC_WAIT)); // hourglass
CString szPath = GetPathFromNode(hItem);
AddChildren(GetTreeCtrl(), hItem, szPath);
SetCursor(LoadCursor (NULL, IDC_ARROW)); // back to normal cursor
((CMainFrame*)AfxGetMainWnd())->SetMessageText(szPath);
UnlockWindowUpdate(); // CWnd member
}
}
}
}
}
CString registryxmlTree::GetPathFromNode(HTREEITEM hItem)
{
CString szPath;
// build path from item name
//
if (hItem==NULL || GetTreeCtrl().GetParentItem(hItem)==NULL) return szPath;
CString szLastKeyname;
HTREEITEM hCurItem = hItem;
HTREEITEM hNextItem;
while ( (hNextItem=GetTreeCtrl().GetParentItem(hCurItem)) )
{
szLastKeyname = GetTreeCtrl().GetItemText(hCurItem);
if (!szLastKeyname.IsEmpty())
{
if (!szPath.IsEmpty())
szPath = "\\" + szPath;
szPath = szLastKeyname + szPath;
}
hCurItem = hNextItem;
} // end while
return szPath;
}
void registryxmlTree::ClearSelection(HTREEITEM hBaseItem)
{
// This can be time consuming for very large trees
// and is called every time the user does a normal selection
// If performance is an issue, it may be better to maintain
// a list of selected items
CTreeCtrl *pTC=&GetTreeCtrl();
if (pTC==NULL) return;
for ( HTREEITEM hItem=hBaseItem;
hItem!=NULL;
hItem=pTC->GetNextItem( hItem, TVGN_NEXT ) )
{
HTREEITEM hChildItem=pTC->GetChildItem(hItem);
if (hChildItem != NULL)
ClearSelection(hChildItem);
if ( pTC->GetItemState( hItem, TVIS_SELECTED ) & TVIS_SELECTED )
pTC->SetItemState( hItem, 0, TVIS_SELECTED );
}
}
// SelectItems - Selects items from hItemFrom to hItemTo. Does not
// - select child item if parent is collapsed. Removes
// - selection from all other items// hItemFrom - item to start selecting from
// hItemTo - item to end selection at.
BOOL registryxmlTree::SelectItems(HTREEITEM hItemFrom, HTREEITEM hItemTo)
{
HTREEITEM hItem = GetTreeCtrl().GetRootItem(); // Clear selection upto the first item
while ( hItem && hItem!=hItemFrom && hItem!=hItemTo )
{
hItem = GetTreeCtrl().GetNextVisibleItem( hItem );
GetTreeCtrl().SetItemState( hItem, 0, TVIS_SELECTED );
}
if ( !hItem )
return FALSE; // Item is not visible
GetTreeCtrl().SelectItem( hItemTo );
// Rearrange hItemFrom and hItemTo so that hItemFirst is at top
if( hItem == hItemTo )
{
hItemTo = hItemFrom;
hItemFrom = hItem;
}
// Go through remaining visible items
BOOL bSelect = TRUE;
while ( hItem )
{
// Select or remove selection depending on whether item
// is still within the range.
GetTreeCtrl().SetItemState( hItem, bSelect ? TVIS_SELECTED : 0, TVIS_SELECTED );
// Do we need to start removing items from selection
if( hItem == hItemTo )
bSelect = FALSE;
hItem = GetTreeCtrl().GetNextVisibleItem( hItem );
}
return TRUE;
}
HTREEITEM registryxmlTree::GetFirstSelectedItem()
{
return GetFirstSelectedItem( GetTreeCtrl().GetRootItem() );
}
HTREEITEM registryxmlTree::GetFirstSelectedItem( HTREEITEM hBaseItem )
{
CTreeCtrl *pTC=&GetTreeCtrl();
for ( HTREEITEM hItem=hBaseItem;
hItem!=NULL;
hItem=pTC->GetNextItem( hItem, TVGN_NEXT ) )
{
if ( pTC->GetItemState( hItem, TVIS_SELECTED ) & TVIS_SELECTED )
return hItem;
HTREEITEM hChildItem=pTC->GetChildItem(hItem);
if (hChildItem != NULL)
{
HTREEITEM hResultItem = GetFirstSelectedItem(hChildItem);
if (hResultItem) return hResultItem;
}
}
return NULL;
}
HTREEITEM registryxmlTree::GetNextSelectedItem( HTREEITEM hItem )
{
if (!hItem) return NULL;
HTREEITEM hChildItem=GetTreeCtrl().GetChildItem(hItem);
if (hChildItem != NULL)
{
HTREEITEM hResultItem = GetFirstSelectedItem(hChildItem);
if (hResultItem) return hResultItem;
}
while (1)
{
HTREEITEM hNextItem = GetTreeCtrl().GetNextItem( hItem, TVGN_NEXT );
if (hNextItem)
{
hItem = hNextItem;
hNextItem = GetFirstSelectedItem(hItem);
if (hNextItem) return hNextItem; // found
}
else
{
hItem = GetTreeCtrl().GetParentItem(hItem);
if (!hItem) return NULL;
}
} // end while
return NULL;
}
int registryxmlTree::GetSelectedCount(HTREEITEM hBaseItem)
{
long nCount=0;
CTreeCtrl *pTC=&GetTreeCtrl();
if (pTC==NULL) return nCount;
for ( HTREEITEM hItem=hBaseItem;
hItem!=NULL;
hItem=pTC->GetNextItem( hItem, TVGN_NEXT ) )
{
HTREEITEM hChildItem=pTC->GetChildItem(hItem);
if (hChildItem != NULL)
nCount+=GetSelectedCount(hChildItem);
if ( pTC->GetItemState( hItem, TVIS_SELECTED ) & TVIS_SELECTED )
nCount++;
}
return nCount;
}
// Function name : registryxmlTree::OnKeyDown
// Description : r�cup�ration du clavier
// Return type : void
// Argument : UINT nChar
// Argument : UINT nRepCnt
// Argument : UINT nFlags
void registryxmlTree::OnKeyDown( UINT nChar, UINT nRepCnt, UINT nFlags)
{
if ( (nChar==VK_UP || nChar==VK_DOWN) )
{
if (GetKeyState( VK_SHIFT )&0x8000)
{
// Initialize the reference item if this is the first shift selection
if( !m_hItemFirstSel )
{
m_hItemFirstSel = GetTreeCtrl().GetSelectedItem();
ClearSelection(GetTreeCtrl().GetRootItem());
} // Find which item is currently selected
HTREEITEM hItemPrevSel = GetTreeCtrl().GetSelectedItem();
HTREEITEM hItemNext;
if ( nChar==VK_UP )
hItemNext = GetTreeCtrl().GetPrevVisibleItem( hItemPrevSel );
else
hItemNext = GetTreeCtrl().GetNextVisibleItem( hItemPrevSel );
if ( hItemNext )
{
// Determine if we need to reselect previously selected item
BOOL bReselect =
!( GetTreeCtrl().GetItemState( hItemNext, TVIS_SELECTED ) & TVIS_SELECTED );
// Select the next item - this will also deselect the previous item
GetTreeCtrl().SelectItem( hItemNext ); // Reselect the previously selected item
if ( bReselect )
GetTreeCtrl().SetItemState( hItemPrevSel, TVIS_SELECTED, TVIS_SELECTED );
}
}
else // simple VK_DOWN VK_UP
{
m_hItem=GetTreeCtrl().GetSelectedItem();
if(m_hItemFirstSel != NULL || m_bCtrlClick)
{
ClearSelection(GetTreeCtrl().GetRootItem());
GetTreeCtrl().SelectItem(m_hItem);
m_hItemFirstSel=NULL;
m_bCtrlClick=FALSE;
}
CTreeView::OnKeyDown(nChar, nRepCnt, nFlags);
}
}
else CTreeView::OnKeyDown(nChar, nRepCnt, nFlags);
}
void registryxmlTree::OnLButtonDown(UINT nFlags, CPoint point)
{
// Set focus to control if key strokes are needed.
// Focus is not automatically given to control on lbuttondown
if(nFlags & MK_CONTROL )
{
// Control key is down
UINT flag;
HTREEITEM hItem = GetTreeCtrl().HitTest( point, &flag );
if( hItem )
{
// Toggle selection state
UINT uNewSelState =
GetTreeCtrl().GetItemState(hItem, TVIS_SELECTED) & TVIS_SELECTED ? 0 : TVIS_SELECTED;
// Get old selected (focus) item and state
HTREEITEM hItemOld = GetTreeCtrl().GetSelectedItem();
UINT uOldSelState = hItemOld ? GetTreeCtrl().GetItemState(hItemOld, TVIS_SELECTED) : 0;
// Select new item
if( GetTreeCtrl().GetSelectedItem() == hItem )
GetTreeCtrl().SelectItem( NULL ); // to prevent edit
CTreeView::OnLButtonDown(nFlags, point);
// Set proper selection (highlight) state for new item
GetTreeCtrl().SetItemState(hItem, uNewSelState, TVIS_SELECTED);
// Restore state of old selected item
if (hItemOld && hItemOld != hItem)
GetTreeCtrl().SetItemState(hItemOld, uOldSelState, TVIS_SELECTED);
m_hItemFirstSel = NULL;
m_bCtrlClick=TRUE;
return;
}
}
else if(nFlags & MK_SHIFT)
{
m_bCtrlClick=FALSE;
// Shift key is down
UINT flag;
HTREEITEM hItem = GetTreeCtrl().HitTest( point, &flag );
// Initialize the reference item if this is the first shift selection
if( !m_hItemFirstSel )
m_hItemFirstSel = GetTreeCtrl().GetSelectedItem();
// Select new item
if( GetTreeCtrl().GetSelectedItem() == hItem )
GetTreeCtrl().SelectItem( NULL ); // to prevent edit
CTreeView::OnLButtonDown(nFlags, point);
if( m_hItemFirstSel )
{
SelectItems( m_hItemFirstSel, hItem );
return;
}
}
else
{
// Normal - remove all selection and let default handler do the rest
if (m_hItemFirstSel!=NULL || m_bCtrlClick)
{
ClearSelection(GetTreeCtrl().GetRootItem());
TRACE ("Clear selection\n");
}
m_hItemFirstSel = NULL;
m_bCtrlClick = FALSE;
}
CTreeView::OnLButtonDown(nFlags, point);
}
/////////////////////////////////////////////////////////////////////////////
//
// registryxmlTree printing
//
//
//
BOOL registryxmlTree::OnPreparePrinting(CPrintInfo* pInfo)
{
// default preparation
return DoPreparePrinting(pInfo);
}
void registryxmlTree::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: add extra initialization before printing
}
void registryxmlTree::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: add cleanup after printing
}
/////////////////////////////////////////////////////////////////////////////
//
// registryxmlTree diagnostics
//
//
//
#ifdef _DEBUG
void registryxmlTree::AssertValid() const
{
CTreeView::AssertValid();
}
void registryxmlTree::Dump(CDumpContext& dc) const
{
CTreeView::Dump(dc);
}
#endif //_DEBUG
registryxmlDoc* registryxmlTree::GetDocument() // non-debug version is inline
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(registryxmlDoc)));
return (registryxmlDoc*)m_pDocument;
}
///////////////////////////////////////////////////////////////////////////
//
//
//
afx_msg void registryxmlTree::OnSaveAsXml()
{
OnSaveAsXml(FALSE); // std xml
}
afx_msg void registryxmlTree::OnSaveAsFakedXml()
{
OnSaveAsXml(TRUE); // faked xml
}
void registryxmlTree::OnSaveAsXml(BOOL bFakedXml)
{
// default filename
CString sDefaultFilename;
if ( GetSelectedCount( GetTreeCtrl().GetRootItem() )==1 )
{
if (!m_hItemBOOL) m_hItem = GetTreeCtrl().GetSelectedItem();
CString szPath = GetPathFromNode(m_hItem);
int nLastSlash = szPath.ReverseFind('\\');
if (nLastSlash>-1)
sDefaultFilename = szPath.Right( szPath.GetLength()-(nLastSlash+1) );
else
sDefaultFilename = szPath;
}
CFileDialog my_dialog(FALSE/*SaveAs*/,_T("xml"),
sDefaultFilename.GetLength()>0 ? sDefaultFilename.GetBuffer(0) : NULL,
OFN_HIDEREADONLY,
_T("XML Files (*.xml)|*.xml|All Files (*.*)|*.*||") );
if (my_dialog.DoModal()!=IDOK) return;
int nNbSelected = GetSelectedCount( GetTreeCtrl().GetRootItem() );
HTREEITEM hItem = NULL;
if (nNbSelected==1)
hItem = m_hItem;
else
{
hItem = GetFirstSelectedItem();
if (hItem==NULL)
{
AfxMessageBox(_T("Please select a tree item before"));
return;
}
}
XmlWriter w;
w.Open( my_dialog.GetPathName() );
XmlElement wroot( CString(XML_ROOT) );
// if we are exporting to the faked xml format, make sure it's not readable as a standard xml
if (bFakedXml) wroot.SetName( CString(">") + CString(XML_ROOT) );
wroot.Write(w,1);
SetCursor(LoadCursor(NULL, IDC_WAIT)); // hourglass cursor
int nbItemsSelectedToWrite = nNbSelected;
while ( (nbItemsSelectedToWrite>0) && hItem )
{
// write item
//
SaveAsXml( w, bFakedXml, GetPathFromNode(hItem) );
if (nNbSelected!=1)
hItem = GetNextSelectedItem( hItem );
nbItemsSelectedToWrite--;
}
SetCursor(LoadCursor (NULL, IDC_ARROW)); // back to normal cursor
wroot.WriteClosingTag(w,-1);
w.Close();
// open the resulting xml file (only if it is not faked)
//
if (!bFakedXml)
::ShellExecute(NULL,
"open", // default verb
my_dialog.GetPathName(), // .xml extension (should be handled by MSIE)
NULL,
NULL,
SW_SHOW);
}
afx_msg void registryxmlTree::OnLoadXml()
{
CFileDialog my_dialog(TRUE/*Load*/,_T("xml"),
NULL,
OFN_HIDEREADONLY,
_T("XML Files (*.xml)|*.xml|All Files (*.*)|*.*||") );
if (my_dialog.DoModal()!=IDOK) return;
CString szFilename = my_dialog.GetPathName();
SetCursor(LoadCursor(NULL, IDC_WAIT)); // hourglass cursor
XmlReader r;
LoadAsXml(r, szFilename);
SetCursor(LoadCursor (NULL, IDC_ARROW)); // back to normal cursor
}