// HierarchyBrowserRenderer.cpp : implementation file
//
#include "stdafx.h"
#include "resource.h"
#include "HierarchyBrowserRenderer.h"
#include <Model/CppTagModel.h>
#include <Controller/Browsers/HierarchyBrowser.h>
#include <Renderer/MFC/ESBImageList.h>
#include <Renderer/MFC/TreeCtrlHelper.h>
#include <Renderer/LabelBroker.h>
#include <list>
using namespace std;
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// HierarchyBrowserRenderer dialog
const size_t FIRST_HISTORY_ENTRY = 10000;
const size_t MAX_HISTORY_SIZE = 10;
BEGIN_MESSAGE_MAP(HierarchyBrowserRenderer, RaisableDialog)
//{{AFX_MSG_MAP(HierarchyBrowserRenderer)
ON_NOTIFY(TVN_ITEMEXPANDING, IDC_HIERARCHY, onExpandHierarchy)
ON_COMMAND(ID_HIERARCHY_FOCUSON, onFocusOn)
ON_COMMAND(ID_HIERARCHY_FOCUSONX, onFocusOnX)
ON_NOTIFY(NM_CLICK, IDC_HIERARCHY, mouseClickedHierarchy)
ON_NOTIFY(NM_DBLCLK, IDC_HIERARCHY, mouseClickedHierarchy)
//}}AFX_MSG_MAP
ON_BN_CLICKED(IDC_TYPE_HIERARCHY, onShowTypeHierarchy)
ON_BN_CLICKED(IDC_SUBTYPE_HIERARCHY, onShowSubtypeHierarchy)
ON_BN_CLICKED(IDC_SUPERTYPE_HIERARCHY, onShowSupertypeHierarchy)
ON_BN_CLICKED(IDC_LOCK_HIERARCHY, onLockHierarchy)
ON_BN_CLICKED(IDC_INHERITED_MEMBERS, onShowInheritedMembers)
ON_COMMAND_RANGE(FIRST_HISTORY_ENTRY, FIRST_HISTORY_ENTRY+MAX_HISTORY_SIZE, onHistory)
END_MESSAGE_MAP()
HierarchyBrowserRenderer::HierarchyBrowserRenderer(HierarchyBrowser *controller, CWnd* pParent /*=NULL*/)
: RaisableDialog(HierarchyBrowserRenderer::IDD, pParent), mController(controller)
{
//{{AFX_DATA_INIT(HierarchyBrowserRenderer)
//}}AFX_DATA_INIT
setIcon(IDI_HIERARCHY);
setPositionKey("browsers.hierarchy.pos");
setRaiseCornerKey("browsers.hierarchy.raisecorner");
}
void HierarchyBrowserRenderer::DoDataExchange(CDataExchange* pDX)
{
RaisableDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(HierarchyBrowserRenderer)
DDX_Control(pDX, IDC_OUTLINE_ICON, mOutlineIcon);
DDX_Control(pDX, IDC_HIERARCHY, mHierarchyRenderer);
//}}AFX_DATA_MAP
}
/////////////////////////////////////////////////////////////////////////////
// HierarchyBrowserRenderer message handlers
size_t HierarchyBrowserRenderer::getStyle()
{
return WS_CHILD | WS_VISIBLE | WS_GROUP | WS_TABSTOP | BS_BITMAP | BS_AUTOCHECKBOX;
}
BCMenu* HierarchyBrowserRenderer::getSubMenu(size_t pos)
{
return dynamic_cast<BCMenu*>(mPreviousHierarchies.GetMenu().GetSubMenu(pos));
}
void HierarchyBrowserRenderer::setupHierarchyView()
{
CSize size(22,23);
CRect rect;
GetWindowRect(rect);
ScreenToClient(rect);
rect.SetRect(CPoint(rect.right-size.cx, 0), CPoint(rect.right, size.cy));
rect.OffsetRect(-5, 0);
mShowSupertypeHierarchy.Create(_T(""), getStyle(), rect, this, IDC_SUPERTYPE_HIERARCHY);
mShowSupertypeHierarchy.SetBitmaps(IDB_SUPERTYPE_HIERARCHY_A, RGB(0,0,0), IDB_SUPERTYPE_HIERARCHY_F);
mShowSupertypeHierarchy.SetTooltipText("Show the Supertype Hierarchy");
AddControl(IDC_SUPERTYPE_HIERARCHY,sizeRepos,sizeNone);
rect.OffsetRect(-size.cx, 0);
mShowSubtypeHierarchy.Create(_T(""),getStyle(), rect, this, IDC_SUBTYPE_HIERARCHY);
mShowSubtypeHierarchy.SetBitmaps(IDB_SUBTYPE_HIERARCHY_A, RGB(0,0,0), IDB_SUBTYPE_HIERARCHY_F);
mShowSubtypeHierarchy.SetTooltipText("Show the Subtype Hierarchy");
AddControl(IDC_SUBTYPE_HIERARCHY,sizeRepos,sizeNone);
rect.OffsetRect(-size.cx, 0);
mShowTypeHierarchy.Create(_T(""),getStyle(), rect, this, IDC_TYPE_HIERARCHY);
mShowTypeHierarchy.SetBitmaps(IDB_TYPE_HIERARCHY_A, RGB(0,0,0), IDB_TYPE_HIERARCHY_F);
mShowTypeHierarchy.SetTooltipText("Show the Type Hierarchy");
AddControl(IDC_TYPE_HIERARCHY,sizeRepos,sizeNone);
size = CSize(40, size.cy);
rect.OffsetRect(-size.cx, 0);
rect.SetRect(rect.TopLeft(), CPoint(rect.TopLeft().x + size.cx , size.cy));
mPreviousHierarchies.Create(_T(""),WS_CHILD | WS_VISIBLE | WS_GROUP | WS_TABSTOP | BS_BITMAP, rect, this, IDC_PREVIOUS_HIERARCHIES);
mPreviousHierarchies.SetBitmaps(IDB_PREVIOUS_HIERARCHIES_A, RGB(0,0,0), IDB_PREVIOUS_HIERARCHIES_F);
mPreviousHierarchies.SetTooltipText("Previous Type Hierarchies");
AddControl(IDC_PREVIOUS_HIERARCHIES,sizeRepos,sizeNone);
mPreviousHierarchies.SetMenu(IDR_PREVIOUS_HIERARCHIES_POPUPMENU, *this, true);
mPreviousHierarchies.GetMenu().RemoveMenu(0, MF_BYPOSITION);
BCMenu *popup = mPreviousHierarchies.GetMenu().AppendODPopupMenuA("Previous Type Hierarchies");
AddControl(IDC_HIERARCHY,sizeResize,sizeResize);
mShowTypeHierarchy.SetCheck(true);
getHierarchyPanel().SetImageList(&ESBImageList::instance(), TVSIL_NORMAL);
getHierarchyPanel().ModifyStyle(0, TVS_SHOWSELALWAYS, 0);
}
void HierarchyBrowserRenderer::setupMemberView()
{
int border = 2;
CSize size(22,23);
CRect hierarchyRect;
getHierarchyPanel().GetWindowRect(&hierarchyRect);
ScreenToClient(hierarchyRect);
CRect rect(CPoint(hierarchyRect.right-size.cx, 0), CPoint(hierarchyRect.right, size.cy));
rect.OffsetRect(-border -4/*buttons*/*size.cx, hierarchyRect.bottom+border);
mShowInheritedMembers.Create(_T(""), getStyle(), rect, this, IDC_INHERITED_MEMBERS);
mShowInheritedMembers.SetBitmaps(IDB_INHERITED_MEMBERS_A, RGB(0,0,0), IDB_INHERITED_MEMBERS_F);
mShowInheritedMembers.SetTooltipText("Show All Inherited Members");
AddControl(IDC_INHERITED_MEMBERS,sizeRepos,sizeRepos);
rect.OffsetRect(-size.cx, 0);
mLockHierarchy.Create(_T(""), getStyle(), rect, this, IDC_LOCK_HIERARCHY);
mLockHierarchy.SetBitmaps(IDB_LOCK_HIERARCHY_A, RGB(0,0,0), IDB_LOCK_HIERARCHY_F);
mLockHierarchy.SetTooltipText("Lock View and Show Members in Hierarchy");
AddControl(IDC_LOCK_HIERARCHY,sizeRepos,sizeRepos);
mLockHierarchy.SetWindowPos(&mShowInheritedMembers, 0,0,0,0, SWP_NOSIZE | SWP_NOMOVE);
///////member outline descriptor (icon & label)
rect.OffsetRect(-size.cx, 0);
GetDlgItem(IDC_OUTLINE_LABEL)->SetWindowPos(&mShowInheritedMembers, 25, rect.top, rect.right-25, rect.Height(), 0);
AddControl(IDC_OUTLINE_LABEL, sizeResize, sizeRepos);
int iconSize = 16;
GetDlgItem(IDC_OUTLINE_ICON)->SetWindowPos(&mShowInheritedMembers, border, rect.top+((rect.Height()-iconSize)/2), border+iconSize, iconSize, 0);
AddControl(IDC_OUTLINE_ICON, sizeNone, sizeRepos);
///////member outline view
CWnd *outline = const_cast<CWnd*>(dynamic_cast<CWnd const*>(&getController().getOutlineRenderer()));
outline->SetParent(this);
CRect thisWnd;
GetClientRect(&thisWnd);
outline->SetWindowPos(&mLockHierarchy, 0, hierarchyRect.bottom+2, thisWnd.Width(), thisWnd.Height()-hierarchyRect.bottom-2, 0);
AddControl(outline->GetDlgCtrlID(),sizeResize,sizeRepos);
outline->ShowWindow(SW_SHOW);
outline->ModifyStyle(0, WS_BORDER, 0);
// mSplitter.BindWithControl(this, IDC_SPLITTER);
// mSplitter.AttachAsAbovePane(IDC_HIERARCHY);
// mSplitter.AttachAsBelowPane(1001);
// mSplitter.RecalcLayout();
// AddControl(mSplitter.GetDlgCtrlID(), sizeResize, sizeRepos);
}
void HierarchyBrowserRenderer::setOutlineDescriptor(const Inheritable &i)
{
LabelBroker broker("");
GetDlgItem(IDC_OUTLINE_LABEL)->SetWindowText(broker.getLabel(i).c_str());
int icon = ESBImageList::instance().getIcon(i);
mOutlineIcon.SetIcon(ESBImageList::instance().ExtractIcon(icon));
}
BOOL HierarchyBrowserRenderer::OnInitDialog()
{
RaisableDialog::OnInitDialog();
AllowSizing(sizeResize,sizeResize);
HideSizeIcon();
setupHierarchyView();
setupMemberView();
getController().hierarchyFilterChanged(getSelectedHierachyType());
setFocusableWindow(&getHierarchyPanel());
return TRUE;
}
void HierarchyBrowserRenderer::render()
{
getHierarchyPanel().SetRedraw(false);
getHierarchyPanel().DeleteAllItems();
//SetWindowText(("Hierarchy: " + hierarchy.getFQN().toString()).c_str());
render(getController().getHierarchyOf(NULL), TVI_ROOT);
getHierarchyPanel().SetFocus();
getHierarchyPanel().SetRedraw(true);
}
void HierarchyBrowserRenderer::render(const std::list<smart_ptr<CppTag> > &elements, HTREEITEM parent)
{
LabelBroker broker("");
typedef std::list<smart_ptr<CppTag> > TagList;
//for_each(outline.begin(), outline.end(), bind(&CppTag::acceptVisitor, _1, &outliner));
for(TagList::const_iterator element = elements.begin(); element != elements.end(); element++) {
HTREEITEM x = getHierarchyPanel().InsertItem(broker.getLabel(*(*element)).c_str(), parent);
int icon = ESBImageList::instance().getIcon(**element);
getHierarchyPanel().SetItemImage(x, icon, icon);
getHierarchyPanel().SetItemData(x, (long)element->get());
int select = getController().getSelectionState(**element);
if(select & 0x02) {
icon = getSelectedIcon(**element);
getHierarchyPanel().SetItemImage(x, icon, icon);
}
if(select & 0x01) {
getHierarchyPanel().SelectItem(x);
}
render(getController().getHierarchyOf(element->get()), x);
getHierarchyPanel().Expand(x, TVE_EXPAND);
}
}
void HierarchyBrowserRenderer::onShowTypeHierarchy()
{
if(emulateRadioButton(mShowTypeHierarchy, mShowSubtypeHierarchy, mShowSupertypeHierarchy)) {
getController().hierarchyFilterChanged(eFullHierarchy);
}
}
void HierarchyBrowserRenderer::onShowSubtypeHierarchy()
{
if(emulateRadioButton(mShowSubtypeHierarchy, mShowTypeHierarchy, mShowSupertypeHierarchy)) {
getController().hierarchyFilterChanged(eSubtypesOnly);
}
}
void HierarchyBrowserRenderer::onShowSupertypeHierarchy()
{
if(emulateRadioButton(mShowSupertypeHierarchy, mShowTypeHierarchy, mShowSubtypeHierarchy)) {
getController().hierarchyFilterChanged(eSupertypesOnly);
}
}
void HierarchyBrowserRenderer::onFocusOn()
{
try {
getController().focusOn(getController().getSelection());
} catch(std::exception &e) {
AfxMessageBox(e.what());
}
}
void HierarchyBrowserRenderer::onFocusOnX()
{
try {
getController().focusOn(NULL);
} catch(std::exception &e) {
AfxMessageBox(e.what());
}
}
int HierarchyBrowserRenderer::getSelectedIcon(const CppTag &tag)
{
IconDescriptor descriptor;
const_cast<CppTag&>(tag).acceptVisitor(&descriptor);
descriptor.decorators.isSelected = true;
return ESBImageList::instance().getIcon(descriptor);
}
void HierarchyBrowserRenderer::onLockHierarchy()
{
try {
bool isLocked = mLockHierarchy.GetCheck() == 1;
HTREEITEM item = getHierarchyPanel().GetSelectedItem();
if(isLocked && item) {
CppTag *tag = TagRetriever(&getHierarchyPanel()).getTag(item);
int icon = getSelectedIcon(*tag);
getHierarchyPanel().SetItemImage(item, icon, icon);
}
getController().hierarchyLockChanged(isLocked);
} catch(std::exception &e) {
AfxMessageBox(e.what());
}
}
void HierarchyBrowserRenderer::onShowInheritedMembers()
{
try {
getController().memberFilterChanged(mShowInheritedMembers.GetCheck() == 1);
} catch(std::exception &e) {
AfxMessageBox(e.what());
}
}
bool HierarchyBrowserRenderer::emulateRadioButton(CButtonST& check, CButtonST &uncheck1, CButtonST &uncheck2)
{
uncheck1.SetCheck(false);
uncheck2.SetCheck(false);
if(check.GetCheck()) {
return true;
} else {
check.SetCheck(true);
return false;
}
}
HierarchyViewType HierarchyBrowserRenderer::getSelectedHierachyType()
{
if(mShowTypeHierarchy.GetCheck()) {
return eFullHierarchy;
}else if(mShowSupertypeHierarchy.GetCheck()) {
return eSupertypesOnly;
}else if(mShowSubtypeHierarchy.GetCheck()) {
return eSubtypesOnly;
}
//this should never happen !
throw runtime_error("no hierarchy type selected ?!?!");
}
void HierarchyBrowserRenderer::show()
{
ShowWindow(SW_SHOW);
//getController().hierarchyFilterChanged(getSelectedHierachyType());
}
MouseEvent HierarchyBrowserRenderer::makeMouseEvent(CWnd *wnd, NMHDR* pNMHDR)
{
MSG msg;
if(!PeekMessage(&msg, *this, WM_MOUSEFIRST , WM_MOUSELAST , PM_NOREMOVE)){
msg.wParam = 0;
}
MouseEvent::MouseButton button = MouseEvent::eLeftButton;
size_t clickCount = 0;
switch(pNMHDR->code) {
case NM_CLICK: button = MouseEvent::eLeftButton; clickCount = 1; break;
case NM_DBLCLK: button = MouseEvent::eLeftButton; clickCount = 2; break;
case NM_RCLICK: button = MouseEvent::eRightButton; clickCount = 1; break;
case NM_RDBLCLK: button = MouseEvent::eRightButton; clickCount = 2; break;
}
return MouseEvent(MouseEvent::eClicked, button | msg.wParam, wnd, GetMessagePos(), clickCount);
}
void HierarchyBrowserRenderer::mouseClickedHierarchy(NMHDR* pNMHDR, LRESULT* pResult)
{
try {
*pResult = 0;
mouseClicked(makeMouseEvent(&getHierarchyPanel(), pNMHDR));
} catch(std::exception &e) {
AfxMessageBox(e.what());
}
}
void HierarchyBrowserRenderer::mouseClicked(const MouseEvent &e)
{
TagRetriever retriever(&getHierarchyPanel());
CppTag *tag = retriever.getTagAt(e.getPoint(), true);
getController().hierarchySelectionChanged(tag, e);
if(e.getButton() == MouseEvent::eMiddleButton) {
CMenu menu;
menu.LoadMenu(IDR_HIERARCHY_BROWSER_POPUPMENU);
CMenu* pPopup = menu.GetSubMenu(0);
if(tag == NULL) {
HTREEITEM ti = getHierarchyPanel().GetSelectedItem();
tag = reinterpret_cast<CppTag*>(getHierarchyPanel().GetItemData(ti));
}
LabelBroker broker("");
string label = "Focus on '" + broker.getLabel(*tag) + "'";
pPopup->ModifyMenu(ID_HIERARCHY_FOCUSON, 0, ID_HIERARCHY_FOCUSON, label.c_str());
pPopup->EnableMenuItem(ID_HIERARCHY_FOCUSONX, MF_GRAYED);
pPopup->TrackPopupMenu(TPM_LEFTALIGN, e.getPoint().first, e.getPoint().second, this);
}
}
void HierarchyBrowserRenderer::onExpandHierarchy(NMHDR* pNMHDR, LRESULT* pResult)
{
try {
NM_TREEVIEW* tree = (NM_TREEVIEW*)pNMHDR;
CPoint pos = /*tree->ptDrag;//*/GetMessagePos();
getHierarchyPanel().ScreenToClient(&pos);
UINT flags;
HTREEITEM htItem = getHierarchyPanel().HitTest(pos, &flags);
//*pResult = flags & TVHT_ONITEMBUTTON ? 0 : 1/*no expand*/;
*pResult = flags & TVHT_ONITEMICON || flags & TVHT_ONITEMLABEL ? 1 : 0;
} catch(std::exception &e) {
AfxMessageBox(e.what());
}
}
void HierarchyBrowserRenderer::onHistory(UINT id)
{
try {
getController().historyEntrySelectionChanged(id-FIRST_HISTORY_ENTRY);
} catch(std::exception &e) {
AfxMessageBox(e.what());
}
}
void HierarchyBrowserRenderer::setHistory(const std::list<smart_ptr<Inheritable> > &history)
{
BCMenu *popup = dynamic_cast<BCMenu*>(mPreviousHierarchies.GetMenu().GetSubMenu(0));
for(size_t cnt = popup->GetMenuItemCount(); cnt > 0; --cnt) {
popup->RemoveMenu(0, MF_BYPOSITION);
}
LabelBroker broker("");
typedef std::list<smart_ptr<Inheritable> > History;
int i = 0;
for(History::const_iterator x = history.begin(); x != history.end(); ++x, ++i) {
int selected = getController().getSelectionState(**x);
int icon = selected ? getSelectedIcon(**x) : ESBImageList::instance().getIcon(**x);
popup->AppendMenu(MF_OWNERDRAW, FIRST_HISTORY_ENTRY+i, broker.getLabel(**x).c_str(), &ESBImageList::instance(), icon);
}
}