BranchListCtrl.cpp. #1

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

#include "stdafx.h"
#include "p4win.h"
#include "BranchListCtrl.h"
#include "MainFrm.h"
#include "P4SpecDlg.h"   
#include "ImageList.h"
#include "FilterByOwnerDlg.h"
#include "Cmd_Delete.h"
#include "Cmd_Describe.h"
#include "Cmd_EditSpec.h"
#include "Cmd_Branches.h"
#include "Cmd_Integrate.h"

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

static LPCTSTR sRegKey_ColumnNames = _T("Branch List");

enum BranchSubItem
{
	BRANCH_NAME,
	BRANCH_OWNER,
	BRANCH_OPTIONS,
	BRANCH_UPDATEDATE,
	BRANCH_DESC,
	BRANCH_MAXCOL
};

/////////////////////////////////////////////////////////////////////////////
// CBranchListCtrl

IMPLEMENT_DYNCREATE(CBranchListCtrl, CP4ListCtrl)

BEGIN_MESSAGE_MAP(CBranchListCtrl, CP4ListCtrl)
	ON_COMMAND(ID_BRANCH_DELETE, OnBranchDelete)
	ON_UPDATE_COMMAND_UI(ID_BRANCH_DELETE, OnUpdateBranchDelete)
	ON_COMMAND(ID_BRANCH_EDITSPEC, OnBranchEditspec)
	ON_UPDATE_COMMAND_UI(ID_BRANCH_EDITSPEC, OnUpdateBranchEditspec)
	ON_COMMAND(ID_BRANCH_NEW, OnBranchNew)
	ON_UPDATE_COMMAND_UI(ID_BRANCH_NEW, OnUpdateBranchNew)
	ON_UPDATE_COMMAND_UI(ID_VIEW_UPDATE_RIGHT, OnUpdateViewUpdate)
	ON_WM_CONTEXTMENU()
	ON_COMMAND(ID_BRANCH_INTEG, OnBranchInteg)
	ON_UPDATE_COMMAND_UI(ID_BRANCH_INTEG, OnUpdateBranchInteg)
	ON_UPDATE_COMMAND_UI(ID_BRANCH_DESCRIBE, OnUpdateBranchDescribe)
	ON_COMMAND(ID_BRANCH_DESCRIBE, OnDescribe)
	ON_UPDATE_COMMAND_UI(ID_FILTERBRANCHBYOWNER, OnUpdateFilterByOwner)
	ON_COMMAND(ID_FILTERBRANCHBYOWNER, OnFilterByOwner)
	ON_UPDATE_COMMAND_UI(ID_CLEARBRANCHOWNERFILTER, OnUpdateClearFilterByOwner)
	ON_COMMAND(ID_CLEARBRANCHOWNERFILTER, OnClearFilterByOwner)
	ON_COMMAND(ID_VIEW_UPDATE_RIGHT, OnViewUpdate)
	ON_NOTIFY_REFLECT(LVN_COLUMNCLICK, OnColumnclick)
	ON_NOTIFY_REFLECT(LVN_DELETEITEM, OnDeleteitem)
	ON_NOTIFY_REFLECT(LVN_ITEMCHANGED, OnItemchanged)
	ON_WM_LBUTTONDBLCLK()
	ON_MESSAGE(WM_P4BRANCHES, OnP4BranchList )
	ON_MESSAGE(WM_P4EDITSPEC, OnP4BranchSpec )
	ON_MESSAGE(WM_P4ENDSPECEDIT, OnP4EndSpecEdit )
	ON_MESSAGE(WM_P4DELETE, OnP4Delete )
	ON_MESSAGE(WM_P4DESCRIBE, OnP4Describe )
    ON_MESSAGE(WM_P4ENDDESCRIBE, OnP4EndDescribe )
	ON_MESSAGE(WM_REQUESTBRANCHLIST, OnRequestBranchesList )
	ON_MESSAGE(WM_NEWUSER, NewUser )
	ON_WM_CREATE()
	ON_WM_ACTIVATE()
END_MESSAGE_MAP()

CBranchListCtrl::CBranchListCtrl()
{
	m_SortAscending=TRUE;
	m_LastSortCol=0;
	m_pNewSpec = NULL;
	m_viewType = P4BRANCH_SPEC;
	m_Need2DoNew = FALSE;
	m_caption = m_captionplain = LoadStringResource(IDS_PERFORCE_BRANCHES);
}

CBranchListCtrl::~CBranchListCtrl()
{
}

/////////////////////////////////////////////////////////////////////////////
// CBranchListCtrl diagnostics

#ifdef _DEBUG
void CBranchListCtrl::AssertValid() const
{
	CP4ListCtrl::AssertValid();
}

void CBranchListCtrl::Dump(CDumpContext& dc) const
{
	CP4ListCtrl::Dump(dc);
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CBranchListCtrl message handlers


void CBranchListCtrl::OnLButtonDblClk(UINT nFlags, CPoint point) 
{
	int index = GetHitItem ( point );
	if( index > -1 )
	{
		SetItemState( index, LVIS_SELECTED|LVIS_FOCUSED, LVIS_SELECTED|LVIS_FOCUSED );
		OnDescribe();
	}
	else
		CP4ListCtrl::OnLButtonDblClk(nFlags, point);
}

LRESULT CBranchListCtrl::NewUser(WPARAM wParam, LPARAM lParam)
{
	if (GET_P4REGPTR()->GetBranchFilteredFlags() & 0x10)
		Clear();
	return 0;
}

void CBranchListCtrl::Clear()
{
	m_Active=GetSelectedItemText();
	if (!m_Active.IsEmpty())
		GET_P4REGPTR()->SetLastBranch(m_Active);

	SetRedraw(FALSE);
	DeleteAllItems();
    SetRedraw(TRUE);

	m_pNotifyWnd= NULL;
	CP4ListCtrl::Clear();
}

void CBranchListCtrl::OnDeleteitem(NMHDR* pNMHDR, LRESULT* pResult) 
{
	NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
	
	delete (CP4Branch *) GetItemData(pNMListView->iItem);
			
	*pResult = 0;
}

void CBranchListCtrl::OnItemchanged(NMHDR* pNMHDR, LRESULT* pResult) 
{
//	NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
	
	CString str=GetSelectedItemText();
	if (!str.IsEmpty())
		GET_P4REGPTR()->SetLastBranch(m_Active = str);

	*pResult = 0;
}

void CBranchListCtrl::OnUpdateBranchDelete(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable( OnUpdateShowMenuItem( pCmdUI, IDS_DELETE_s ) 
					&& !MainFrame()->IsModlessUp() 
					&& !SelectedItemIsLocked(BRANCH_OPTIONS) );
}

void CBranchListCtrl::OnBranchDelete() 
{
	OnDelete( P4BRANCH_DEL ) ;
}

void CBranchListCtrl::OnUpdateBranchEditspec(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable( OnUpdateShowMenuItem( pCmdUI, IDS_EDITSPEC_s )
					&& !MainFrame()->IsModlessUp() && !m_EditInProgress
					&& (!SelectedItemIsLocked(BRANCH_OPTIONS) 
					  || !GetSelectedItemOwner(BRANCH_OWNER).CompareNoCase(GET_P4REGPTR()->GetP4User())) );
}

void CBranchListCtrl::EditTheSpec(CString *name) 
{
	m_Active=*name;
	m_NewBranch=FALSE;
	OnEditSpec( m_Active );
}

void CBranchListCtrl::OnBranchEditspec() 
{
	m_Active=GetSelectedItemText();
	m_NewBranch=FALSE;
	OnEditSpec( m_Active );
}

void CBranchListCtrl::OnUpdateBranchNew(CCmdUI* pCmdUI) 
{
	pCmdUI->SetText ( LoadStringResource( IDS_NEW ) );
	pCmdUI->Enable(!SERVER_BUSY() && ! m_EditInProgress && !MainFrame()->IsModlessUp());	
	m_Need2DoNew = FALSE;
}

void CBranchListCtrl::OnBranchNew() 
{
	MainFrame()->ViewBranches();
	if (SERVER_BUSY())
		m_Need2DoNew = TRUE;
	else
	{
		m_Need2DoNew = FALSE;
		m_Active.Empty();
		m_NewBranch=TRUE;
        //FIXTHIS: string
		OnEditSpec( CString(NEWSPECNAME) );
	}
}

void CBranchListCtrl::OnBranchInteg() 
{
	GET_P4REGPTR()->SetLastBranch(m_Active=GetSelectedItemText());
	
	// Ask the depot window to perform the integrate task, including
	// the fetching of change numbers, branch names, popping the dlg,
	// and getting results displayed
	::SendMessage(m_depotWnd, WM_BRANCHINTEG, (WPARAM) LPCTSTR(m_Active), 0);
}

void CBranchListCtrl::OnUpdateBranchInteg(CCmdUI* pCmdUI) 
{
	CString prompt;
    prompt.FormatMessage(IDS_INTEGRATEUSING_s, TruncateString(GetSelectedItemText(),50));
	pCmdUI->SetText( prompt );
	pCmdUI->Enable( !SERVER_BUSY() && GetItemCount() 
		&& !GetSelectedItemText().IsEmpty( ) 
		&& !MainFrame()->IsModlessUp()
		&& !MainFrame()->IsPendChgEditInProgress() );	
}

void CBranchListCtrl::OnUpdateBranchDescribe(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable( OnUpdateShowMenuItem( pCmdUI, IDS_DESCRIBEIT_s ) );	
}

void CBranchListCtrl::OnUpdateViewUpdate(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable(!SERVER_BUSY() && !MainFrame()->IsModlessUp());
}

void CBranchListCtrl::OnViewUpdate() 
{
	m_Active = GetSelectedItemText();
	SetCaption();
	CCmd_Branches *pCmd= new CCmd_Branches;
	pCmd->Init( m_hWnd, RUN_ASYNC);
	if( pCmd->Run( ) )
	{
		MainFrame()->UpdateStatus( LoadStringResource(IDS_REQUESTING_BRANCH_LISTING) );
		MainFrame()->SetBranchUpdateTime(GetTickCount());
		Clear();
		CP4ListCtrl::OnViewUpdate();
	}
	else
		delete pCmd;
}

CString CBranchListCtrl::SetCaption()
{
	int i = GET_P4REGPTR()->GetBranchFilteredFlags();
	if (i)
    {
        CString filter;
		CString txt;

		if (i & 0x10)
			txt = LoadStringResource(IDS_CURRENT_USER);
		else if (i & 0x01)
			txt = GET_P4REGPTR()->GetBranchFilterOwner();
		filter.FormatMessage(IDS_FILTERED, txt);
		m_caption = LoadStringResource(IDS_PERFORCE_BRANCHES) + filter;
    }
	else
		m_caption = LoadStringResource(IDS_PERFORCE_BRANCHES);

	CP4PaneContent::GetView()->SetCaption();

	return m_caption;
}

void CBranchListCtrl::OnContextMenu(CWnd* pWnd, CPoint point) 
{
	//		make sure window is active
	//
	GetParentFrame()->ActivateFrame();

	///////////////////////////////
	// See ContextMenuRules.txt for order of menu commands!

	//		create an empty context menu 
	//
	CP4Menu popMenu;
	popMenu.CreatePopupMenu();
	    
    int	index;
    SetIndexAndPoint( index, point );
    
	popMenu.AppendMenu(MF_ENABLED | MF_STRING, ID_BRANCH_NEW );
	if( index != -1 )
	{
		// Make sure the item gets selected
		SetItemState( index, LVIS_SELECTED|LVIS_FOCUSED, LVIS_SELECTED|LVIS_FOCUSED );
		
		// Then add menu commands that are relevant
		popMenu.AppendMenu(MF_ENABLED | MF_STRING, ID_BRANCH_EDITSPEC );
		popMenu.AppendMenu(MF_ENABLED | MF_STRING, ID_BRANCH_DESCRIBE );
		popMenu.AppendMenu(MF_ENABLED | MF_STRING, ID_BRANCH_DELETE );
		popMenu.AppendMenu( MF_SEPARATOR );
		popMenu.AppendMenu(MF_ENABLED | MF_STRING, ID_BRANCH_INTEG );
	}
	popMenu.AppendMenu( MF_SEPARATOR );
	popMenu.AppendMenu( MF_ENABLED | MF_STRING, ID_FILTERBRANCHBYOWNER, 
										LoadStringResource(IDS_FILTERBRANCHBYOWNER) );
	popMenu.AppendMenu( MF_ENABLED | MF_STRING, ID_CLEARBRANCHOWNERFILTER, 
										LoadStringResource(IDS_CLEARBRANCHOWNERFILTER) );
	popMenu.AppendMenu( MF_SEPARATOR );
	popMenu.AppendMenu(MF_ENABLED | MF_STRING, ID_VIEW_UPDATE, LoadStringResource(IDS_REFRESH) );

	MainFrame()->AddToolsToContextMenu(&popMenu);

	popMenu.TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON,	point.x, point.y, AfxGetMainWnd());
}

void CBranchListCtrl::InsertBranch(CP4Branch *branch, int index)
{
	LV_ITEM lvItem;
	int iActualItem = 0;
	CString txt;
	m_iImage = CP4ViewImageList::VI_BRANCH;

	ASSERT(branch != NULL);
	BOOL bFilteredOut = MainFrame()->IsBranchFilteredOut(branch);
	
	for(int subItem=0; subItem < BRANCH_MAXCOL; subItem++)
	{
		lvItem.mask=LVIF_TEXT | 
					((subItem==0) ? LVIF_IMAGE : 0) |
					((subItem==0) ? LVIF_PARAM : 0);

		lvItem.iItem= (subItem==0) ? index : iActualItem;
        ASSERT(lvItem.iItem != -1 || bFilteredOut);

		lvItem.iSubItem= subItem;
		lvItem.iImage = CP4ViewImageList::VI_BRANCH;
		lvItem.lParam=(LPARAM) branch;

		switch(subItem)
		{
		case BRANCH_NAME: 
			lvItem.pszText= const_cast<LPTSTR>((LPCTSTR) branch->GetBranchName()); break;
		case BRANCH_OWNER: 
			lvItem.pszText = const_cast<LPTSTR>( (LPCTSTR) branch->GetOwner()); break;
		case BRANCH_OPTIONS: 
			lvItem.pszText = const_cast<LPTSTR>( (LPCTSTR) branch->GetOptions()); break;
		case BRANCH_UPDATEDATE:                              
			lvItem.pszText= const_cast<LPTSTR>((LPCTSTR) branch->GetDate()); break;
		case BRANCH_DESC: 
			txt= PadCRs(branch->GetDescription());
			lvItem.pszText = const_cast<LPTSTR>( (LPCTSTR) txt); break;
		default:
			ASSERT( 0 ); lvItem.pszText = _T("@"); break;
		}
			
		m_ListAll.column[subItem].SetAtGrow(index, lvItem.pszText);
		if (bFilteredOut)
			continue;

		if(subItem==0)
			iActualItem=InsertItem(&lvItem);
		else
			SetItem(&lvItem);
	}
	if (bFilteredOut)
		delete branch;
}


void CBranchListCtrl::UpdateBranch(CP4Branch *branch, int index)
{
	// After a spec edit, update the appropriate list item

	// First, switch the branch data
	CP4Branch *oldBranch= (CP4Branch *) GetItemData(index);
	delete oldBranch;
	SetItemData(index, (LPARAM) branch);

	// Then update the text
	SetItemText(index, BRANCH_NAME, const_cast<LPTSTR>((LPCTSTR) branch->GetBranchName()));
	SetItemText(index, BRANCH_OWNER, const_cast<LPTSTR>((LPCTSTR) branch->GetOwner()));
	SetItemText(index, BRANCH_OPTIONS, const_cast<LPTSTR>((LPCTSTR) branch->GetOptions()));
	SetItemText(index, BRANCH_UPDATEDATE, const_cast<LPTSTR>((LPCTSTR) branch->GetDate()));
	CString	txt= PadCRs(branch->GetDescription());
	SetItemText(index, BRANCH_DESC, const_cast<LPTSTR>((LPCTSTR)txt));
}

void CBranchListCtrl::UpdateBranchAll(CP4Branch *branch, int index)
{
	m_ListAll.column[BRANCH_NAME].SetAt(index, const_cast<LPTSTR>((LPCTSTR)branch->GetBranchName()));
	m_ListAll.column[BRANCH_OWNER].SetAt(index, const_cast<LPTSTR>((LPCTSTR)branch->GetOwner()));
	m_ListAll.column[BRANCH_OPTIONS].SetAt(index, const_cast<LPTSTR>((LPCTSTR)branch->GetOptions()));
	m_ListAll.column[BRANCH_UPDATEDATE].SetAt(index, const_cast<LPTSTR>((LPCTSTR)branch->GetDate()));
	CString	txt= PadCRs(branch->GetDescription());
	m_ListAll.column[BRANCH_DESC].SetAt(index, const_cast<LPTSTR>((LPCTSTR)txt));
}

///////////////////////////////////////////////////
// Support for request of branches list, including delayed notification to
// requesting window

// Return a list of branches if this window is up-to-date and lParam == 0,
// otherwise start a refresh of the branches list, and save the pointer of
// the window to be notified when the list is ready
LRESULT CBranchListCtrl::OnRequestBranchesList(WPARAM wParam, LPARAM lParam)
{
	CWnd *pWnd= (CWnd *) wParam;
	ASSERT_KINDOF(CWnd, pWnd);

	// Clear the branches list
	for( int index= m_BranchesList.GetUpperBound(); index >= 0; index-- )
		delete m_BranchesList.GetAt( index );
	m_BranchesList.RemoveAll();

	if((m_UpdateState != LIST_UPDATED) || lParam)
	{
		// Note: OnViewUpdate() calls Clear(), which resets m_pNotifyWnd to NULL,
		//       so be sure to run OnViewUpdate() BEFORE setting the notify wnd
		OnViewUpdate();
		m_pNotifyWnd= pWnd;
	}
	else
	{
		FillBranchesList();
		m_pNotifyWnd= NULL;
	}

	// Return the branches list, even if it is still empty
	return (LRESULT) &m_BranchesList;
}

void CBranchListCtrl::FillBranchesList()
{
	ASSERT(m_BranchesList.GetSize() == 0);

	// Rummage through the list, adding branch names to stringlist
	for(int index=0; index < GetItemCount(); index++)
	{
		CP4Branch *branch= (CP4Branch *) GetItemData(index);
		
		CP4Branch *newBranch= new CP4Branch;

		newBranch->Create( branch->GetBranchName(), branch->GetOwner(), branch->GetOptions(),
													branch->GetDate(), branch->GetDescription() );
		m_BranchesList.Add( newBranch );
	}
	if (!m_Active.IsEmpty())
		GET_P4REGPTR()->SetLastBranch(m_Active);
}

void CBranchListCtrl::NotifyNewBranchesList()
{
	ASSERT(m_pNotifyWnd != NULL);

	FillBranchesList();
	try
	{
		if(m_pNotifyWnd != NULL && IsWindow(m_pNotifyWnd->m_hWnd))
		{
			m_pNotifyWnd->SendMessage(WM_NEWBRANCHESLIST, (WPARAM) &m_BranchesList, 0);
		}
	}
	catch(...)
	{
		ASSERT(0);
		// It is possible that the window and/or the CWnd object which
		// we were supposed to notify is no longer in existence, so this
		// is an error condition that we can sweep under the rug
	}
}


///////////////////////////////////////////////////
// Messages posted by server thread

LRESULT CBranchListCtrl::OnP4BranchSpec(WPARAM wParam, LPARAM lParam)
{
	CCmd_EditSpec *pCmd= (CCmd_EditSpec *) wParam;

	pCmd->SetIsRequestingNew(m_NewBranch);
	pCmd->SetCaller(DYNAMIC_DOWNCAST(CView, GetParent()));
	if(!pCmd->GetError() && !m_EditInProgress && pCmd->DoSpecDlg(this))
	{
		m_EditInProgress = TRUE;
		m_EditInProgressWnd = pCmd->GetSpecSheet();
	}
	else
	{
		if ( m_pNewSpec )
			delete m_pNewSpec;
		if (pCmd->HaveServerLock())
			pCmd->ReleaseServerLock();
		delete pCmd;
	}
	MainFrame()->ClearStatus();
	return 0;
}

LRESULT CBranchListCtrl::OnP4EndSpecEdit( WPARAM wParam, LPARAM lParam )
{
	BOOL need2Refresh = FALSE;
	CCmd_EditSpec *pCmd= (CCmd_EditSpec *) wParam;

	if (lParam != IDCANCEL && lParam != IDABORT)
	{
		if (m_UpdateState == LIST_UPDATED)
		{
			// we have to set 'index' again in case branch's name got changed
			int index= FindInList(m_pNewSpec->GetBranchName());
			int ixAll= FindInListAll(m_pNewSpec->GetBranchName());
			if (ixAll == -1)	// not in either list
			{
				ASSERT(index == -1);
				InsertBranch(m_pNewSpec, GetItemCount());
				ReSort();
				index= FindInList(m_pNewSpec->GetBranchName());
				if (index == -1)
					index= FindInList(m_Active);
			}
			else if (index > -1)	// in both lists
			{
				ASSERT(ixAll > -1);
				if (MainFrame()->IsBranchFilteredOut(m_pNewSpec))	// should it no longer be shown?
				{
					need2Refresh = TRUE;
					delete m_pNewSpec;
				}
				else
				{
					UpdateBranch(m_pNewSpec, index);
					UpdateBranchAll(m_pNewSpec, ixAll);
				}
			}
			else	// not in visible list; is in list of all
			{
				if (MainFrame()->IsBranchFilteredOut(m_pNewSpec))	// should it now be shown?
					need2Refresh = TRUE;
				else
					UpdateBranchAll(m_pNewSpec, ixAll);
				delete m_pNewSpec;
				index= FindInList(m_Active);
			}
			EnsureVisible( index, TRUE );
			SetItemState( index, LVIS_SELECTED|LVIS_FOCUSED, LVIS_SELECTED|LVIS_FOCUSED );
		}
		else
			if ( m_pNewSpec ) delete m_pNewSpec;
	}
	else
		if ( m_pNewSpec ) delete m_pNewSpec;

	if (lParam != IDABORT)
	{
		MainFrame()->ClearStatus();
		if (pCmd->HaveServerLock())
			pCmd->ReleaseServerLock();
		CDialog *dlg = (CDialog *)pCmd->GetSpecSheet();
		dlg->DestroyWindow();
	}
	delete pCmd;
	m_EditInProgress = FALSE;

	if (need2Refresh)
		OnViewUpdate();
	return 0;
}

LRESULT CBranchListCtrl::OnP4BranchList(WPARAM wParam, LPARAM lParam)
{
	CCmd_Branches *pCmd= (CCmd_Branches *) wParam;
    ASSERT_KINDOF(CCmd_Branches,pCmd);

	if(!pCmd->GetError())
	{
    	CObList *branches= pCmd->GetList();

        SetRedraw(FALSE);
    	int index = 0;
		for(POSITION pos= branches->GetHeadPosition(); pos != NULL; index++)
		{
	        CP4Branch *branch=(CP4Branch *) branches->GetNext(pos);
            ASSERT_KINDOF(CP4Branch,branch);
			InsertBranch(branch, index);
		}
        SetRedraw(TRUE);

		CString msg;
        msg.FormatMessage( IDS_NUMBER_OF_BRANCHES_n, index );
		AddToStatus( msg, SV_COMPLETION );

		ReSort();

		// Make sure previous item is re-selected
		if(branches->GetCount() > 0)
		{
			int i = FindInList(m_Active.IsEmpty() ? GET_P4REGPTR()->GetLastBranch() : m_Active);
			if (i < 0)	i=0;
			SetItemState(i, LVIS_SELECTED|LVIS_FOCUSED, LVIS_SELECTED|LVIS_FOCUSED);
			EnsureVisible(i, FALSE);
			m_Active=GetSelectedItemText();
		}

		// If another window was waiting for a list of branches, send it the list
		if(m_pNotifyWnd != NULL)
			NotifyNewBranchesList();
	
		CP4ListCtrl::SetUpdateDone();
		if (m_Need2DoNew)
			OnBranchNew();
		else
		{
			// Notify the mainframe that we have finished getting the branches,
			// hence the entire set of async command have finished.
			MainFrame()->ExpandDepotIfNeedBe();
		}
		if (m_PostViewUpdateMsg)
			PostMessage(m_PostViewUpdateMsg, m_PostViewUpdateWParam, m_PostViewUpdateLParam);
	}
	else
	{
		CP4ListCtrl::SetUpdateFailed();
		m_Need2DoNew = FALSE;
	}
	
	delete pCmd;
	m_PostViewUpdateMsg = 0;
	MainFrame()->ClearStatus();
	return 0;
}


//////////////////////////////////////////////////////////////////////////
// Sort callback, not in class

int CBranchListCtrl::OnCompareItems(LPARAM lParam1, LPARAM lParam2, int subItem)
{
    ASSERT(lParam1 && lParam2);
    CP4Branch const *branch1 = (CP4Branch const*)lParam1;
    CP4Branch const *branch2 = (CP4Branch const*)lParam2;
    ASSERT_KINDOF(CP4Branch,branch1);
    ASSERT_KINDOF(CP4Branch,branch2);


	CString txt1, txt2;
	switch(subItem)
	{
	case BRANCH_NAME:	 // branch name
		txt1= branch1->GetBranchName();
		txt2= branch2->GetBranchName();
		break;

	case BRANCH_OWNER:	 // branch owner
		txt1= branch1->GetOwner();
		txt2= branch2->GetOwner();
		break;

	case BRANCH_OPTIONS:	 // branch options
		txt1= branch1->GetOptions();
		txt2= branch2->GetOptions();
		break;

	case BRANCH_UPDATEDATE:	 // branch update date
		txt1= branch1->GetDate();
		txt2= branch2->GetDate();
		ConvertDates( txt1, txt2 );
		break;

	case BRANCH_DESC:	 // branch root
		txt1= branch1->GetDescription();
		txt2= branch2->GetDescription();
		break;

	default:
		ASSERT(0);
		return 0;
	}
	txt1.MakeUpper();
	txt2.MakeUpper();

	int rc;

	if(m_SortAscending)
		rc = txt1.Compare(txt2);
	else
		rc = txt2.Compare(txt1);

	return rc;
}

void CBranchListCtrl::OnEditSpec( LPCTSTR sItem )
{
	if (m_EditInProgress)
	{
		CantEditRightNow(IDS_BRANCH);
		return;
	}

	m_pNewSpec = new CP4Branch;

	CCmd_EditSpec *pCmd= new CCmd_EditSpec;
	pCmd->Init( m_hWnd, RUN_ASYNC, TRUE );
	if( pCmd->Run( P4BRANCH_SPEC, sItem, m_pNewSpec ) )
		MainFrame()->UpdateStatus( LoadStringResource(IDS_EDITING_BRANCH_SPEC) ) ;
	else
	{
		delete pCmd;
		delete m_pNewSpec;
	}
}

int CBranchListCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (CP4ListCtrl::OnCreate(lpCreateStruct) == -1)
		return -1;

	CStringArray colnames;
	colnames.Add ( LoadStringResource(IDS_BRANCH) );
	colnames.Add ( LoadStringResource(IDS_OWNER) );
	colnames.Add ( LoadStringResource(IDS_LOCKSTR) );
	colnames.Add ( LoadStringResource(IDS_DATE) );
	colnames.Add ( LoadStringResource(IDS_DESCRIPTION) );
	ASSERT( BRANCH_MAXCOL == colnames.GetSize( ) );
    //FIXTHIS: move default widths into resource
	int width[BRANCH_MAXCOL]={90,90,60,90,250};
	RestoreSavedWidths(width, colnames.GetSize( ), sRegKey_ColumnNames);
	if (width[BRANCH_UPDATEDATE] > 5000 && width[BRANCH_DESC] > 5000)
		width[BRANCH_OPTIONS] = width[BRANCH_UPDATEDATE] = width[BRANCH_DESC] = 90;
	InsertColumnHeaders( colnames, width );

	return 0;
}

void CBranchListCtrl::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized)
{
	CP4ListCtrl::OnActivate(nState, pWndOther, bMinimized);

	if(nState != WA_INACTIVE && m_Active.IsEmpty() && GetItemCount() > 1)
	{
		int i = FindInList(GET_P4REGPTR()->GetLastBranch());
		if (i < 0)	i=0;
		SetItemState(i, LVIS_SELECTED|LVIS_FOCUSED, LVIS_SELECTED|LVIS_FOCUSED);
		EnsureVisible(i, FALSE);
		m_Active=GetSelectedItemText();
	}
	else
	{
		m_Active=GetSelectedItemText();
		if (!m_Active.IsEmpty())
			GET_P4REGPTR()->SetLastBranch(m_Active);
	}
}

void CBranchListCtrl::OnUpdateFilterByOwner(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable( MainFrame()->SetMenuIcon(pCmdUI, !SERVER_BUSY()) );
}

void CBranchListCtrl::OnFilterByOwner()
{
	CFilterByOwnerDlg dlg;
	dlg.m_NotUser = GET_P4REGPTR()->GetBranchFilteredFlags() & 0x01;
	dlg.m_Owner = GET_P4REGPTR()->GetBranchFilterOwner();
	dlg.m_bShowIncBlanks = FALSE;
	if (dlg.DoModal() == IDOK)
	{
		GET_P4REGPTR()->SetBranchFilteredFlags(dlg.m_NotUser ? 0x01 : 0x10);
		GET_P4REGPTR()->SetBranchFilterOwner(dlg.m_Owner);
		OnViewUpdate();
	}
}

void CBranchListCtrl::OnUpdateClearFilterByOwner(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable( MainFrame()->SetMenuIcon(pCmdUI, GET_P4REGPTR()->GetBranchFilteredFlags()
														&& !SERVER_BUSY()) );
}

void CBranchListCtrl::OnClearFilterByOwner()
{
	GET_P4REGPTR()->SetBranchFilteredFlags(0);
	OnViewUpdate();
}
# Change User Description Committed
#1 19924 YourUncleBob Populate -o //guest/perforce_software/p4win/...
//guest/YourUncleBob/p4win/.....
//guest/perforce_software/p4win/main/gui/BranchListCtrl.cpp
#1 16169 perforce_software Move files to follow new path scheme for branches.
//guest/perforce_software/p4win/gui/BranchListCtrl.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.