2025-11-28 00:35:46 +09:00

607 lines
16 KiB
C++

//-----------------------------------------------------------------------------
// Microsoft OLE DB RowsetViewer
// Copyright (C) 1994 - 1999 By Microsoft Corporation.
//
// @doc
//
// @module COBJTREE.CPP
//
//-----------------------------------------------------------------------------------
/////////////////////////////////////////////////////////////////
// Includes
//
/////////////////////////////////////////////////////////////////
#include "Headers.h"
#include "CObjTree.h"
////////////////////////////////////////////////////////////////
// CObjTree::CObjTree
//
/////////////////////////////////////////////////////////////////
CObjTree::CObjTree(CMainWindow* pCMainWindow)
{
//Data
ASSERT(pCMainWindow);
m_pCMainWindow = pCMainWindow;
}
////////////////////////////////////////////////////////////////
// CObjTree::~CObjTree
//
/////////////////////////////////////////////////////////////////
CObjTree::~CObjTree()
{
}
////////////////////////////////////////////////////////////////
// CObjTree::OnRButtonDown
//
/////////////////////////////////////////////////////////////////
BOOL CObjTree::OnRButtonDown(WPARAM fwKeys, REFPOINTS pts)
{
//NOTE: The right mouse button doesn't automatically activate the MDI window...
m_pCMainWindow->MDIActivate(m_hWndParent);
//NOTE: The right mouse doesn't automatically select the tree item
//so we have to find where the mouse clicked and determine the inteneded item...
HTREEITEM hItem = HitTest(pts, NULL);
if(hItem)
SelectItem(hItem);
//Display the Context Menu (for this object)
CBase* pCBase = (CBase*)GetItemParam(hItem);
if(pCBase)
{
UINT nIDMenu = pCBase->GetObjectMenu();
if(nIDMenu)
{
//xPos, yPos are Relative to the Client Area...
DisplayContextMenu(
m_hWnd,
nIDMenu,
pts,
m_pCMainWindow->GetWnd(),
TRUE
);
}
}
return TRUE;
}
////////////////////////////////////////////////////////////////
// CObjTree::OnContextMenu
//
/////////////////////////////////////////////////////////////////
BOOL CObjTree::OnContextMenu(HWND hWnd, REFPOINTS pts)
{
CBase* pCBase = GetSelectedObject();
if(pCBase)
{
UINT nIDMenu = pCBase->GetObjectMenu();
if(nIDMenu)
{
DisplayContextMenu(
hWnd,
nIDMenu,
pts,
m_pCMainWindow->GetWnd()
);
}
}
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// CObjTree::OnUpdateCommand
//
/////////////////////////////////////////////////////////////////////////////
BOOL CObjTree::OnUpdateCommand(HMENU hMenu, UINT nID, DWORD* pdwFlags)
{
//Is this command meant for the Child Window?
CBase* pCBase = GetSelectedObject();
if(pCBase && pCBase->m_pCMDIChild)
if(pCBase->m_pCMDIChild->OnUpdateCommand(hMenu, nID, pdwFlags))
return TRUE;
return FALSE;
}
/////////////////////////////////////////////////////////////////////
// CObjTree::OnCommand
//
/////////////////////////////////////////////////////////////////////
BOOL CObjTree::OnCommand(UINT iID, HWND hWndCtrl)
{
//Is this command meant for the Child Window?
CBase* pCBase = GetSelectedObject();
if(pCBase && pCBase->m_pCMDIChild)
if(pCBase->m_pCMDIChild->OnCommand(iID, hWndCtrl))
return TRUE;
return FALSE;
}
/////////////////////////////////////////////////////////////////////////////
// CObjTree::OnDblclk
//
/////////////////////////////////////////////////////////////////////////////
BOOL CObjTree::OnDblclk(WPARAM fwKeys, REFPOINTS pts)
{
UINT uFlags = 0;
HTREEITEM hItem = HitTest(pts, &uFlags);
if(hItem)
{
CBase* pCBase = (CBase*)GetItemParam(hItem);
if(pCBase)
{
//If there is a child assoicated with this object, then let it perform what it should
//do on a double click operation (which by default activates the child window)
pCBase->OnDefOperation();
return TRUE;
}
}
return FALSE;
}
/////////////////////////////////////////////////////////////////////////////
// CObjTree::OnKeyDown
//
/////////////////////////////////////////////////////////////////////////////
BOOL CObjTree::OnKeyDown(WPARAM nVirtKey, LPARAM lKeyData)
{
switch(nVirtKey)
{
case VK_RETURN:
{
CBase* pCBase = GetSelectedObject();
if(pCBase)
{
//NOTE: Not all objects in the tree will have an assiocate child Window
if(pCBase->m_pCMDIChild)
{
//Activate the MDIChild window assoicated with this object
m_pCMainWindow->MDIActivate(pCBase->m_pCMDIChild->m_hWnd);
}
return TRUE;
}
break;
}
};
return FALSE;
}
/////////////////////////////////////////////////////////////////////////////
// CObjTree::AddObject
//
/////////////////////////////////////////////////////////////////////////////
BOOL CObjTree::AddObject(CBase* pCSource, CBase* pCBase)
{
if(pCBase)
{
WCHAR* pwszDesc = pCBase->GetObjectDesc();
WCHAR* pwszName = pCBase->GetObjectName();
//Obtain the icon/image for the object
INT iImage = pCBase->GetObjectImage();
if(pCBase->m_pIAggregate)
iImage = IMAGE_INTERFACE;
if(pwszDesc)
{
static WCHAR wszBuffer[MAX_NAME_LEN] = {0};
if(pCBase->m_dwCLSCTX == CLSCTX_INPROC_SERVER)
StringFormat(wszBuffer, NUMELE(wszBuffer), L"%s (%s)", pwszName, pwszDesc);
else
StringFormat(wszBuffer, NUMELE(wszBuffer), L"%s%s (%s)", L"Remote ", pwszName, pwszDesc);
pwszName = wszBuffer;
}
//Insert the Item (if not already)
if(pCBase->m_hTreeItem == NULL)
{
pCBase->m_hTreeItem = InsertItem(pCSource ? pCSource->m_hTreeItem : NULL, NULL, pwszName, (INT_PTR)pCBase, iImage, iImage);
}
else
{
//Otherwise it probably just needs to have the item updated...
SetItemText(pCBase->m_hTreeItem, pwszName);
SetItemParam(pCBase->m_hTreeItem, (INT_PTR)pCBase);
SetItemImage(pCBase->m_hTreeItem, iImage, iImage);
}
SelectObject(pCBase);
}
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// CObjTree::RemoveObject
//
/////////////////////////////////////////////////////////////////////////////
BOOL CObjTree::RemoveObject(CBase* pCBase)
{
//No-op
if(!m_hWnd || !pCBase || !pCBase->m_hTreeItem)
return TRUE;
//Make a copy, since RemoveNode will null the objects members...
HTREEITEM hParentItem = GetParentItem(pCBase->m_hTreeItem);
//First try and remove this node (and possibly any children)
if(RemoveNode(pCBase->m_hTreeItem))
{
pCBase->m_hTreeItem = NULL;
//If we were able to remove this node, then maybe we should
//try and "garbage-collect" any parent nodes now that this is gone...
if(hParentItem)
GarbageCollectNode(hParentItem);
return TRUE;
}
return FALSE;
}
/////////////////////////////////////////////////////////////////////////////
// CObjTree::GarbageCollectNode
//
/////////////////////////////////////////////////////////////////////////////
BOOL CObjTree::GarbageCollectNode(HTREEITEM hTreeItem)
{
//No-op
if(!m_hWnd || !hTreeItem)
return TRUE;
HTREEITEM hHighestItem = NULL;
//Try to find the "highest" un-used parent node.
while(hTreeItem)
{
//As soon as one of the nodes has a (non-empty) object, its no longer "un-used"
CBase* pCBase = (CBase*)GetItemParam(hTreeItem);
if(pCBase && pCBase->m_pIUnknown)
break;
hHighestItem = hTreeItem;
hTreeItem = GetParentItem(hTreeItem);
}
//Have we found "un-used" parents, that can be garbage-collected
if(hHighestItem)
{
//Garbage Collect the usued nodes...
return RemoveNode(hHighestItem);
}
return FALSE;
}
/////////////////////////////////////////////////////////////////////////////
// CObjTree::RemoveNode
//
/////////////////////////////////////////////////////////////////////////////
BOOL CObjTree::RemoveNode(HTREEITEM hTreeItem)
{
//No-op
if(!m_hWnd || !hTreeItem)
return TRUE;
BOOL bSafeToRemove = TRUE;
CBase* pCBase = (CBase*)GetItemParam(hTreeItem);
CMDIChild* pCMDIChild = pCBase ? pCBase->m_pCMDIChild : NULL;
//First, make sure this node is safe to remove...
if(pCBase && pCBase->m_pIUnknown)
bSafeToRemove = FALSE;
//If it is before deleting it from the tree, we need to make there are no child nodes
//that depend upon it
if(bSafeToRemove)
{
HTREEITEM hChildItem = GetChildItem(hTreeItem);
while(hChildItem)
{
//NOTE: Before deleting this node of the tree, obtain the next sibling (if there is one...)
//Since we can't do this after the node has been deleted!
HTREEITEM hNextSibling = GetNextItem(hChildItem);
//Recurse
if(!RemoveNode(hChildItem))
{
bSafeToRemove = FALSE;
break;
}
//Go to the next sibling...
hChildItem = hNextSibling;
}
}
if(bSafeToRemove)
{
//Completely safe to delete this node (and all children)
DeleteItem(hTreeItem);
if(pCBase)
pCBase->m_hTreeItem = NULL;
}
return bSafeToRemove;
}
/////////////////////////////////////////////////////////////////////////////
// CObjTree::SelectObject
//
/////////////////////////////////////////////////////////////////////////////
BOOL CObjTree::SelectObject(CBase* pCBase)
{
if(pCBase && pCBase->m_hTreeItem)
SelectItem(pCBase->m_hTreeItem);
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// CObjTree::GetSelectedObject
//
/////////////////////////////////////////////////////////////////////////////
CBase* CObjTree::GetSelectedObject()
{
//Obtain the selected item
return (CBase*)GetItemParam(GetSelectedItem());
}
////////////////////////////////////////////////////////////////
// CMDIObjects::CMDIObjects
//
/////////////////////////////////////////////////////////////////
CMDIObjects::CMDIObjects(CMainWindow* pCMainWindow)
{
//Objects
ASSERT(pCMainWindow);
m_pCMainWindow = pCMainWindow;
//Controls
m_pCObjTree = new CObjTree(pCMainWindow);
}
////////////////////////////////////////////////////////////////
// CMDIObjects::~CMDIObjects
//
/////////////////////////////////////////////////////////////////
CMDIObjects::~CMDIObjects()
{
//Controls
SAFE_DELETE(m_pCObjTree);
}
////////////////////////////////////////////////////////////////
// CMDIObjects::PreCreateWindow
//
/////////////////////////////////////////////////////////////////
BOOL CMDIObjects::PreCreateWindow(CREATESTRUCTW& cs)
{
//Load Saved Window Positions
memset(&m_wndPlacement, 0, sizeof(m_wndPlacement));
GetRegEntry(HKEY_ROWSETVIEWER, wszOBJECTS_KEY, L"WinPosition", &m_wndPlacement, sizeof(m_wndPlacement), NULL);
//Window Hidden?
if(m_wndPlacement.length)
{
if(m_wndPlacement.showCmd == SW_HIDE)
cs.style &= ~WS_VISIBLE;
}
return TRUE;
}
////////////////////////////////////////////////////////////////
// CMDIObjects::AutoPosition
//
/////////////////////////////////////////////////////////////////
BOOL CMDIObjects::AutoPosition(BOOL fDefaultPosition)
{
if(fDefaultPosition || m_wndPlacement.length == 0)
{
//Default setting, left corner (1/4 of the client area)...
SIZE sizeClient = GetClientSize(m_pCMainWindow->m_hWndMDIClient);
return MoveWindow(m_hWnd, 0, 0, (INT)((float)sizeClient.cx * 0.25), sizeClient.cy, TRUE);
}
else
{
return SetWindowPlacement();
}
}
////////////////////////////////////////////////////////////////
// CMDIObjects::OnCreate
//
/////////////////////////////////////////////////////////////////
BOOL CMDIObjects::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
//Create Object Tree
SIZE size = GetClientSize(m_hWnd);
m_pCObjTree->Create(m_hWnd, WC_TREEVIEWW, NULL, ID_OBJECTTREE,
WS_CHILD | WS_VISIBLE | WS_BORDER | WS_HSCROLL | WS_VSCROLL | WS_TABSTOP | /*TVS_EDITLABELS |*/ TVS_LINESATROOT | TVS_HASBUTTONS | TVS_HASLINES | TVS_SHOWSELALWAYS, WS_EX_CLIENTEDGE,
0, 0, size.cx, size.cy);
TreeView_SetImageList(m_pCObjTree->m_hWnd, ImageList_LoadImage(GetAppLite()->m_hInstance, MAKEINTRESOURCE(IDB_IMAGE), 16, 16, CLR_DEFAULT , IMAGE_BITMAP, LR_DEFAULTCOLOR), TVSIL_NORMAL);
m_pCObjTree->OnCreate(NULL);
//Window Position
AutoPosition(m_wndPlacement.length == 0/*fDefaultPosition*/);
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// CMDIObjects::OnDestroy
//
/////////////////////////////////////////////////////////////////////////////
BOOL CMDIObjects::OnDestroy()
{
//Save Window Positions
if(GetWindowPlacement())
SetRegEntry(HKEY_ROWSETVIEWER, wszOBJECTS_KEY, L"WinPosition", &m_wndPlacement, sizeof(m_wndPlacement));
//Delegate
return CMDIChildLite::OnDestroy();
}
/////////////////////////////////////////////////////////////////////////////
// CMDIObjects::OnClose
//
/////////////////////////////////////////////////////////////////////////////
BOOL CMDIObjects::OnClose()
{
//NOTE: OnClose only gets hit for MDI Child Windows when the user actually
//closes the window. If the mainframe window is closed directly then OnClose is never fired...
//Due to this, if the user has closed the window before exiting the app, then all we really
//want to do is make the window not-visible, so if they bring the window up again it has all
//the info saved.
ShowWindow(SW_HIDE);
//NOTE: Don't delegate the call, since we don't want to "DestroyWindow"
return TRUE;
}
////////////////////////////////////////////////////////////////
// CMDIObjects::OnInitialUpdate
//
/////////////////////////////////////////////////////////////////
BOOL CMDIObjects::OnInitialUpdate()
{
return TRUE;
}
/////////////////////////////////////////////////////////////////////
// CMDIObjects::OnMDIActivate
//
/////////////////////////////////////////////////////////////////////
BOOL CMDIObjects::OnMDIActivate(BOOL bActivate, HWND hWndActivate, HWND hWndDeactivate)
{
//So see if this window is being activated or deactivated
if(hWndActivate == m_hWnd)
{
//Refresh all Controls
UpdateControls();
}
return TRUE;
}
////////////////////////////////////////////////////////////////
// CMDIObjects::UpdateControls
//
/////////////////////////////////////////////////////////////////
BOOL CMDIObjects::UpdateControls()
{
//ToolBar Buttons
m_pCMainWindow->UpdateControls();
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// CMDIObjects::OnUpdateCommand
//
/////////////////////////////////////////////////////////////////////////////
BOOL CMDIObjects::OnUpdateCommand(HMENU hMenu, UINT nID, DWORD* pdwFlags)
{
return m_pCObjTree->OnUpdateCommand(hMenu, nID, pdwFlags);
}
/////////////////////////////////////////////////////////////////////
// CMDIObjects::OnNotify
//
/////////////////////////////////////////////////////////////////////
BOOL CMDIObjects::OnNotify(INT idCtrl, NMHDR* pNMHDR)
{
return m_pCObjTree->OnNotify(idCtrl, pNMHDR);
}
/////////////////////////////////////////////////////////////////////
// CMDIObjects::OnCommand
//
/////////////////////////////////////////////////////////////////////
BOOL CMDIObjects::OnCommand(UINT iID, HWND hWndCtrl)
{
return m_pCObjTree->OnCommand(iID, hWndCtrl);
}
/////////////////////////////////////////////////////////////////////
// CMDIObjects::OnSize
//
/////////////////////////////////////////////////////////////////////
BOOL CMDIObjects::OnSize(WPARAM nType, REFPOINTS pts)
{
ASSERT(m_pCObjTree->m_hWnd);
switch(nType)
{
case SIZE_RESTORED:
case SIZE_MAXIMIZED:
{
if(pts.x && pts.y)
{
//Obtain window sizes...
MoveWindow(m_pCObjTree->m_hWnd, 0, 0, pts.x, pts.y, TRUE);
//Call default procedure first,
//to let MDI position the child & then move its children
//We simply do this by returning false, to indicate we didn't handle it...
return FALSE;
}
break;
}
};
return FALSE;
}
/////////////////////////////////////////////////////////////////////////////
// CMDIObjects::OnSetFocus
//
/////////////////////////////////////////////////////////////////////////////
BOOL CMDIObjects::OnSetFocus(HWND hWndPrevFocus)
{
m_pCObjTree->SetFocus();
return TRUE;
}