P4PaneView.cpp. #1

  • //
  • guest/
  • YourUncleBob/
  • p4win/
  • main/
  • gui/
  • P4PaneView.cpp.
  • View
  • Commits
  • Open Download .zip Download (17 KB)
// P4PaneView.cpp : implementation file
//

#include "stdafx.h"
#include "p4win.h"
#include "P4PaneView.h"
#include "P4PaneContent.h"
#include "MainFrm.h"
#include "ImageList.h"
#include <afxpriv.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CP4PaneView

const int ID_CAPTION = 222;

IMPLEMENT_DYNCREATE(CP4PaneView, CView)

BEGIN_MESSAGE_MAP(CP4PaneView, CView)
	ON_WM_SETFOCUS()
	ON_WM_SIZE()
	ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW, 0, 0xFFFF, OnToolTipText)
	ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTA, 0, 0xFFFF, OnToolTipText)
	ON_WM_CREATE()
	ON_MESSAGE( WM_FINDPATTERN, OnFindPattern )
	ON_BN_CLICKED( ID_CAPTION, LButtonClk )
	ON_BN_DOUBLECLICKED( ID_CAPTION, LButtonDblClk )
	ON_WM_SYSCOLORCHANGE()
	ON_MESSAGE( WM_ACTIVATEMODELESS, OnActivateModeless )
END_MESSAGE_MAP()

CP4PaneView::CP4PaneView() 
	: m_content(0)
{
}

CP4PaneView::~CP4PaneView() {}

void CP4PaneView::SetBranchWnd(CWnd *wnd) { m_content->SetBranchWnd(wnd); }
void CP4PaneView::SetChangeWnd(CWnd *wnd) { m_content->SetChangeWnd(wnd); }
void CP4PaneView::SetClientWnd(CWnd *wnd) { m_content->SetClientWnd(wnd); }
void CP4PaneView::SetDepotWnd(CWnd *wnd) { m_content->SetDepotWnd(wnd); }
void CP4PaneView::SetJobWnd(CWnd *wnd) { m_content->SetJobWnd(wnd); }
void CP4PaneView::SetLabelWnd(CWnd *wnd) { m_content->SetLabelWnd(wnd); }
void CP4PaneView::SetOldChgWnd(CWnd *wnd) { m_content->SetOldChgWnd(wnd); }
void CP4PaneView::SetUserWnd(CWnd *wnd) { m_content->SetUserWnd(wnd); }

void CP4PaneView::OnInitialUpdate()
{
	CView::OnInitialUpdate();

	// for some reason, list views end up with client edge style set
	// and we don't want it for any views
	ModifyStyleEx(WS_EX_CLIENTEDGE, 0);

	// want tooltips for caption
	m_reBar.SetBarStyle(CBRS_ALIGN_TOP |CBRS_TOOLTIPS);
	// don't want separator bar between caption and toolbar bands
	m_reBar.ModifyStyle(RBS_BANDBORDERS, 0);

	// put dropdown arrows on dropdown buttons
	m_toolBar.GetToolBarCtrl().SetExtendedStyle(TBSTYLE_EX_DRAWDDARROWS);
	// set owner to mainframe so tooltips status bar messages will work
	m_toolBar.SetOwner(AfxGetApp()->m_pMainWnd); 
	// make it flat and transparent so it looks good on XP
	m_toolBar.ModifyStyle(0, TBSTYLE_FLAT|TBSTYLE_TRANSPARENT);
	// get rid of extra space around buttons
	m_toolBar.SetBorders();
	// set style to get tooltips working
	m_toolBar.SetBarStyle(CBRS_ALIGN_TOP | CBRS_TOOLTIPS | CBRS_FLYBY);
	// created non-visible so styles could be set before showing, so show now
	m_toolBar.ShowWindow(SW_SHOW);

	// set image list(s) for the toolbar
	m_toolBar.GetToolBarCtrl().SetImageList(
		TheApp()->GetToolBarImageList());
	m_toolBar.GetToolBarCtrl().SetDisabledImageList(
		TheApp()->GetToolBarImageList()->GetDisabled());

	// must set button size before adding buttons
	CSize sizeImage(18, 16);
	CSize sizeButton(18 + 7, 16 + 7);
	m_toolBar.SetSizes(sizeButton, sizeImage);

	// add the buttons to the toolbar
	SetToolBarButtons();

	// make the caption control transparent so the rebar will
	// draw the background under it
	m_captionCtrl.ModifyStyleEx(0, WS_EX_TRANSPARENT);

	// put the bands into the rebar
	// the ' ' text for the caption provides a little space on the left
	m_reBar.AddBar(&m_captionCtrl, _T(" "), NULL, RBBS_NOGRIPPER);
	m_reBar.AddBar(&m_toolBar, NULL, NULL, RBBS_NOGRIPPER|RBBS_FIXEDBMP);

	// determine how tall the bar should be to fit the taller of
	// the caption band or the toolbar band
	CRect r;
	r.SetRectEmpty();
	m_reBar.CalcInsideRect(r, TRUE);
	m_barHeight = max(16 + 7, GetSystemMetrics(SM_CYCAPTION));
	m_barHeight -= r.Height();
	m_contentTop = m_barHeight + GetSystemMetrics(SM_CYEDGE);

	// set up min/max sizes and ideal sizes for pieces of the rebar
	REBARBANDINFO rbbi;
	rbbi.cbSize = sizeof(rbbi);

	// set title band so it will be as wide as possible
	// and with a min size of one, it will never disappear
	// since the caption control will use the standard caption
	// font, it should be as tall as a standard caption.
	rbbi.fMask = RBBIM_CHILDSIZE | RBBIM_IDEALSIZE | RBBIM_SIZE;
	rbbi.cxMinChild = 1;
	rbbi.cyMinChild = GetSystemMetrics(SM_CYCAPTION);
	rbbi.cx = rbbi.cxIdeal = 20000;	// want to be really big!
	m_reBar.GetReBarCtrl().SetBandInfo(0, &rbbi);

	// set max size for toolbar band to it's actual size
	// and min size to same so it won't be crowded out by
	// caption.
	m_toolBar.GetWindowRect(&r);
	rbbi.fMask = RBBIM_CHILDSIZE | RBBIM_IDEALSIZE | RBBIM_SIZE;
	rbbi.cxMinChild = r.Width();
	rbbi.cyMinChild = 16 + 7;
	rbbi.cx = rbbi.cxIdeal = r.Width();
	m_reBar.GetReBarCtrl().SetBandInfo(1, &rbbi);

	// reposition the bars, now that their sizes have been set
	GetClientRect(&r);
	r.bottom = m_barHeight;
	RepositionBars(AFX_IDW_CONTROLBAR_FIRST, AFX_IDW_CONTROLBAR_LAST, 1,
		reposDefault, NULL, &r);
	// and reposition the content, allowing space for the rebar edge
	GetContentWnd()->MoveWindow(0,m_contentTop,
		r.Width(),r.Height() - m_contentTop,TRUE);

	EnableToolTips();

	if (GET_P4REGPTR( )->SwapButtonPosition())
		SwapButtonPosition();
}

void CP4PaneView::OnSize(UINT nType, int cx, int cy)
{
	CView::OnSize(nType, cx, cy);

	// don't do other sizing until created
	if(!IsWindow(m_toolBar.m_hWnd) || !m_reBar.GetReBarCtrl().GetBandCount())
		return;

	// put toolbar at top, list below it
	CRect r;
	r.SetRect(0, 0, cx, m_barHeight);
	RepositionBars(AFX_IDW_CONTROLBAR_FIRST, AFX_IDW_CONTROLBAR_LAST, 1,
		reposDefault, NULL, &r);
	// RepositionBars won't leave space between the rebar and the content
	// so we need to re-move the content to make space needed for the border
	GetContentWnd()->MoveWindow(0, m_contentTop,	cx, cy - m_contentTop, TRUE);
}

void CP4PaneView::OnDraw(CDC* pDC) 
{
	// just draw an edget between the toolbar and the content
	CRect r;
	GetClientRect(&r);
	r.bottom = r.top + m_contentTop;
	pDC->DrawEdge(&r, EDGE_RAISED, BF_RECT);
}

void CP4PaneView::OnSetFocus(CWnd* pOldWnd)
{
	CView::OnSetFocus(pOldWnd);

	if(GetContentWnd() && IsWindow(GetContentWnd()->m_hWnd))
		GetContentWnd()->SetFocus();
}

BOOL CP4PaneView::OnCmdMsg(UINT nID, int nCode, void* pExtra,
	AFX_CMDHANDLERINFO* pHandlerInfo)
{
	if(GetContentWnd()->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
		return TRUE;

	return CView::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
}

BOOL CP4PaneView::OnToolTipText( UINT id, NMHDR * pNMHDR, LRESULT * pResult )
{
	// first, check for special case of caption control
	// and handle it here
    TOOLTIPTEXT *pTTT = (TOOLTIPTEXT *)pNMHDR;    
    UINT nID =pNMHDR->idFrom;
    if (pTTT->uFlags & TTF_IDISHWND)    
    {
        // idFrom is actually the HWND of the tool
        nID = ::GetDlgCtrlID((HWND)nID);
		if(nID == ID_CAPTION)
		{
			m_captionCtrl.GetWindowText(m_captionTxt);
			pTTT->lpszText = (LPTSTR)(LPCTSTR)m_captionTxt;
            pTTT->hinst = NULL;
			return TRUE;
		}
	}
	// for other cases, just pass it along to mainframe
	CMainFrame *mainFrame = (CMainFrame *) AfxGetApp()->m_pMainWnd;
    return mainFrame->OnToolTipText(id, pNMHDR, pResult);
}

int CP4PaneView::GetSelectedItem()
{
	CP4ListCtrl * pList = DYNAMIC_DOWNCAST(CP4ListCtrl, GetContentWnd());
	ASSERT(pList);
	if(pList)
		return pList->GetSelectedItem();
	return 0;
}

void CP4PaneView::OnEditPaste( const CString &Name )
{
	CP4ListCtrl * pList = DYNAMIC_DOWNCAST(CP4ListCtrl, GetContentWnd());
	ASSERT(pList);
	if(pList)
		pList->OnEditPaste(Name);
}

CString CP4PaneView::GetSelectedItemText( )
{
	CP4ListCtrl * pList = DYNAMIC_DOWNCAST(CP4ListCtrl, GetContentWnd());
	ASSERT(pList);
	if(pList)
		return pList->GetSelectedItemText();
	return "";
}

HTREEITEM CP4PaneView::GetSelectedItem(int index)
{
	CMultiSelTreeCtrl * pTree = DYNAMIC_DOWNCAST(CMultiSelTreeCtrl, GetContentWnd());
	ASSERT(pTree);
	if(pTree)
		return pTree->GetSelectedItem(index);
	return 0;
}

CString CP4PaneView::GetItemText(HTREEITEM curr_item)
{
	CMultiSelTreeCtrl * pTree = DYNAMIC_DOWNCAST(CMultiSelTreeCtrl, GetContentWnd());
	ASSERT(pTree);
	if(pTree)
		return pTree->GetItemText(curr_item);
	return "";
}

void CP4PaneView::SetCaption()
{
	m_captionCtrl.SetWindowText(m_content->GetCaption());

	// Getting this updated is a bit complicated since the caption
	// control is transparent (to allow the rebar background to
	// show through).  First, redraw the rebar, then the caption control.
	m_reBar.InvalidateRect(NULL);
	m_reBar.UpdateWindow();
	m_captionCtrl.InvalidateRect(NULL);
	m_captionCtrl.UpdateWindow();
}

int CP4PaneView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (CView::OnCreate(lpCreateStruct) == -1)
		return -1;

	if(!m_reBar.Create(this))
		return -1;
	if(!m_toolBar.Create(this,WS_CHILD | CBRS_ALIGN_TOP))
		return -1;
	if(!m_captionCtrl.Create(_T(""),WS_CHILD|WS_VISIBLE|BS_OWNERDRAW|BS_NOTIFY,
		CRect(0,0,1,1),this,ID_CAPTION))
		return -1;
	if(!CreateContent())
		return -1;

	LOGFONT lf;
	m_reBar.GetFont()->GetLogFont(&lf);
	m_inactiveFont.CreateFontIndirect(&lf);
	lf.lfWeight = FW_BOLD;
	m_activeFont.CreateFontIndirect(&lf);

	// Register that we accept Exploder files
	try
	{
		m_DropTarget.Register(this);
	}
	catch(...)
	{
		return 0;
	}

	return 0;
}

void CP4PaneView::OnActivateView(BOOL bActivate, CView* pActivateView, CView* pDeactiveView)
{
	if(GetContentWnd() && IsWindow(GetContentWnd()->m_hWnd))
	{
		// force UI update right away, so if activation is caused by
		// click on toolbar dropdown, it can be enabled before the
		// toolbar gets the click message.  Without this, it takes
		// one click to activate and another to drop down.
		m_toolBar.SendMessage(WM_IDLEUPDATECMDUI, (WPARAM)TRUE, 0);

		if(bActivate)
		{
			m_captionCtrl.SetFont(&m_activeFont);
		}
		else
		{
			m_captionCtrl.SetFont(&m_inactiveFont);
		}
		// The size of the caption text will change with the font change
		// so force an update
		SetCaption();
	}

	CView::OnActivateView(bActivate, pActivateView, pDeactiveView);
}

DROPEFFECT CP4PaneView::OnDragEnter(COleDataObject* pDataObject, DWORD dwKeyState, CPoint point)
{
	MapWindowPoints(GetContentWnd(), &point, 1);
	return m_content->OnDragEnter(pDataObject, dwKeyState, point);
}

void CP4PaneView::OnDragLeave()
{
	m_content->OnDragLeave();
}

DROPEFFECT CP4PaneView::OnDragOver(COleDataObject* pDataObject, DWORD dwKeyState, CPoint point)
{
	MapWindowPoints(GetContentWnd(), &point, 1);
	return m_content->OnDragOver(pDataObject, dwKeyState, point);
}

BOOL CP4PaneView::OnDrop(COleDataObject* pDataObject, DROPEFFECT dropEffect, CPoint point)
{
	MapWindowPoints(GetContentWnd(), &point, 1);
	return m_content->OnDrop(pDataObject, dropEffect, point);
}

void CP4PaneView::SwapButtonPosition()
{
	// swap the bands
	m_reBar.GetReBarCtrl().MoveBand(1, 0);
	// for some inexplicable reason, MoveBand doesn't update the bar
	// immediately.  It takes some other action to make it actually update
	// and this seems like the least disruptive thing to do:
	m_reBar.GetReBarCtrl().ShowBand(0, FALSE);
	m_reBar.GetReBarCtrl().ShowBand(0, TRUE);
}

// This is required in order to make the LButtonDblClk() work!
void CP4PaneView::LButtonClk()
{
	SetFocus();
}

void CP4PaneView::LButtonDblClk()
{
	// by default, do nothing
}

LRESULT CP4PaneView::OnFindPattern(WPARAM wParam, LPARAM lParam)
{
	CP4ListCtrl * pList = DYNAMIC_DOWNCAST(CP4ListCtrl, GetContentWnd());
	ASSERT(pList);
	if(pList)
		return pList->OnFindPattern(wParam, lParam);
	return Default();
}

IMPLEMENT_DYNCREATE(CCaptionTextControl, CButton)

BEGIN_MESSAGE_MAP(CCaptionTextControl, CButton)
	ON_WM_CTLCOLOR_REFLECT()
END_MESSAGE_MAP()

HBRUSH CCaptionTextControl::CtlColor(CDC* pDC, UINT /*nCtlColor*/)
{
	// we don't want any background drawn; we're supposed to be transparent
	pDC->SetBkMode(TRANSPARENT);
	return (HBRUSH)GetStockObject(NULL_BRUSH);
}

void CCaptionTextControl::DrawItem(LPDRAWITEMSTRUCT di) 
{
	// Just draw the text.  If it's too long, it will be shortened, since
	// we're using the DT_END_ELLIPSIS style.  This also means the string
	// passed to DrawText may be modified, so we use a temp copy.
	CDC dc;
	dc.Attach(di->hDC);
	const int maxCaption = 256;
	TCHAR txt[maxCaption];
	GetWindowText(txt,maxCaption);
	txt[maxCaption-1] = 0;
	TCHAR mtxt[maxCaption];
	lstrcpy(mtxt,txt);
	dc.DrawText(mtxt, lstrlen(mtxt), &di->rcItem, DT_END_ELLIPSIS | DT_SINGLELINE|DT_VCENTER | DT_MODIFYSTRING);
	m_textTruncated = lstrcmp(mtxt,txt) != 0;
	dc.Detach();
}

int CCaptionTextControl::OnToolHitTest(CPoint point, TOOLINFO* pTI) const
{
	// CWnd implementation won't do us any good, so we have to handle
	// this.
	// watch out!  sometimes get called with null pointer
	if(pTI == 0)
		return -1;

	// don't want to show tooltip if nothing is hidden
	// the tooltip is only there to show truncated text
	if(!m_textTruncated)
		return -1;

	// we want to show a tooltip, so set up for the normal callback
	pTI->hwnd = GetParent()->GetParent()->m_hWnd;	// our parent
	pTI->uId = (UINT_PTR)m_hWnd;		// us
	pTI->uFlags |= TTF_IDISHWND;		// uId is HWND, not ID
	pTI->lpszText = LPSTR_TEXTCALLBACK;

	return 1;
}

DROPEFFECT CP4OleDropTarget::OnDragScroll(CWnd* pWnd, DWORD dwKeyState,
	CPoint point)
{
	// We need special handling of autoscrolling because we want
	// it to behave as though the CP4PaneView's content window is
	// doing the autoscroll.  Without this, it looks like you are
	// dragging over the caption to autoscroll the content.

	// This code is only slightly modified from the base implementation,
	// as needed to get the correct window's client rect for determining
	// the autoscroll inset region.  Also, code for synchronized
	// scrolling of splitters has been stripped out.

	ASSERT_VALID(this);
	ASSERT_VALID(pWnd);

	// if it's not a CP4PaneView, just use the default handler
	CP4PaneView * pView = DYNAMIC_DOWNCAST(CP4PaneView,pWnd);
	if(!pView)
		return COleDropTarget::OnDragScroll(pWnd, dwKeyState, point);

	DROPEFFECT dropEffect = pView->OnDragScroll(dwKeyState, point);

	// DROPEFFECT_SCROLL means do the default
	if (dropEffect != DROPEFFECT_SCROLL)
		return dropEffect;

	// get client rectangle of destination window
	CRect rectClient;
	pView->GetContentWnd()->GetClientRect(&rectClient);
	pView->GetContentWnd()->MapWindowPoints(pView, &rectClient);
	CRect rect = rectClient;

	// hit-test against inset region
	UINT nTimerID = 0xffff;
	rect.InflateRect(-nScrollInset, -nScrollInset);
	if (rectClient.PtInRect(point) && !rect.PtInRect(point))
	{
		// determine which way to scroll along both X & Y axis
		if (point.x < rect.left)
			nTimerID = MAKEWORD(SB_LINEUP, HIBYTE(nTimerID));
		else if (point.x >= rect.right)
			nTimerID = MAKEWORD(SB_LINEDOWN, HIBYTE(nTimerID));
		if (point.y < rect.top)
			nTimerID = MAKEWORD(LOBYTE(nTimerID), SB_LINEUP);
		else if (point.y >= rect.bottom)
			nTimerID = MAKEWORD(LOBYTE(nTimerID), SB_LINEDOWN);
		ASSERT(nTimerID != 0xffff);

		// we don't do synchronized splitter scrolling, so this part is
		// somewhat simplified
		BOOL bEnableScroll = pView->OnScroll(nTimerID, 0, FALSE);
		if (!bEnableScroll)
			nTimerID = 0xffff;
	}

	if (nTimerID == 0xffff)
	{
		if (m_nTimerID != 0xffff)
		{
			// send fake OnDragEnter when transition from scroll->normal
			COleDataObject dataObject;
			dataObject.Attach(m_lpDataObject, FALSE);
			OnDragEnter(pWnd, &dataObject, dwKeyState, point);
			m_nTimerID = 0xffff;
		}
		return DROPEFFECT_NONE;
	}

	// save tick count when timer ID changes
	DWORD dwTick = GetTickCount();
	if (nTimerID != m_nTimerID)
	{
		m_dwLastTick = dwTick;
		m_nScrollDelay = nScrollDelay;
	}

	// scroll if necessary
	if (dwTick - m_dwLastTick > m_nScrollDelay)
	{
		pView->OnScroll(nTimerID, 0, TRUE);
		m_dwLastTick = dwTick;
		m_nScrollDelay = nScrollInterval;
	}
	if (m_nTimerID == 0xffff)
	{
		// send fake OnDragLeave when transitioning from normal->scroll
		OnDragLeave(pWnd);
	}

	m_nTimerID = nTimerID;
	// check for force link
	if ((dwKeyState & (MK_CONTROL|MK_SHIFT)) == (MK_CONTROL|MK_SHIFT))
		dropEffect = DROPEFFECT_SCROLL|DROPEFFECT_LINK;
	// check for force copy
	else if ((dwKeyState & MK_CONTROL) == MK_CONTROL)
		dropEffect = DROPEFFECT_SCROLL|DROPEFFECT_COPY;
	// check for force move
	else if ((dwKeyState & MK_ALT) == MK_ALT ||
		(dwKeyState & MK_SHIFT) == MK_SHIFT)
		dropEffect = DROPEFFECT_SCROLL|DROPEFFECT_MOVE;
	// default -- recommended action is move
	else
		dropEffect = DROPEFFECT_SCROLL|DROPEFFECT_MOVE;
	return dropEffect;
}

void CP4PaneView::OnSysColorChange()
{
	CView::OnSysColorChange();

	m_toolBar.GetToolBarCtrl().SetImageList(
		TheApp()->GetToolBarImageList());
	m_toolBar.GetToolBarCtrl().SetDisabledImageList(
		TheApp()->GetToolBarImageList()->GetDisabled());

	CP4ListCtrl * pList = DYNAMIC_DOWNCAST(CP4ListCtrl, GetContentWnd());
	if(pList)
		pList->SetImageList(TheApp()->GetViewImageList(), LVSIL_SMALL);
	CMultiSelTreeCtrl * pTree = DYNAMIC_DOWNCAST(CMultiSelTreeCtrl, GetContentWnd());
	if(pTree)
		pTree->SetImageList(TheApp()->GetViewImageList(), TVSIL_NORMAL);
}

LRESULT CP4PaneView::OnActivateModeless(WPARAM wParam, LPARAM lParam)
{
	CP4ListCtrl * pList = DYNAMIC_DOWNCAST(CP4ListCtrl, GetContentWnd());
	if(pList)
		pList->SendMessage(WM_ACTIVATEMODELESS, WA_ACTIVE, NULL);
	else
	{
		CMultiSelTreeCtrl * pTree = DYNAMIC_DOWNCAST(CMultiSelTreeCtrl, GetContentWnd());
		if(pTree)
			pTree->SendMessage(WM_ACTIVATEMODELESS, WA_ACTIVE, NULL);
	}
	return 0;
}
# Change User Description Committed
#1 19924 YourUncleBob Populate -o //guest/perforce_software/p4win/...
//guest/YourUncleBob/p4win/.....
//guest/perforce_software/p4win/main/gui/P4PaneView.cpp
#1 16169 perforce_software Move files to follow new path scheme for branches.
//guest/perforce_software/p4win/gui/P4PaneView.cpp
#1 8562 Matt Attaway These feet never stop running.

Initial commit of the P4Win source code.  To the best of our knowledge this
compiles and runs using the 2013.3 P4 API and VS 2010. Expect a few changes
as we refine the build process. Please post any build issues to the forums.