Click here to Skip to main content
15,885,278 members
Articles / Desktop Programming / MFC

Be Sweet - a set of visual source code browsers

Rate me:
Please Sign up or sign in to vote.
4.85/5 (35 votes)
1 Jul 20038 min read 183.7K   4.9K   122  
A set of source code and project browsers to compliment Visual Studio.
// 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);
  } 
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Switzerland Switzerland
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions