OldChgListCtrl.cpp. #1

  • //
  • guest/
  • YourUncleBob/
  • p4win/
  • main/
  • gui/
  • OldChgListCtrl.cpp.
  • View
  • Commits
  • Open Download .zip Download (54 KB)
//
// Copyright 1997 Nicholas J. Irias.  All rights reserved.
//
//

// OldChgListCtrl.cpp : implementation file
//

#include "stdafx.h"
#include "p4win.h"
#include "Cmd_Changes.h"
#include "Cmd_EditSpec.h"
#include "Cmd_MaxChange.h"
#include "OldChgView.h"
#include "SpecDescDlg.h"
#include "MainFrm.h"
#include "JobListDlg.h"
#include "DeleteFixes.h"
#include "P4Fix.h"
#include "ChgDescribe.h"
#include "Cmd_Fix.h"
#include "cmd_fixes.h"
#include "cmd_get.h"
#include "cmd_jobs.h"
#include "cmd_where.h"
#include "RegKeyEx.h"
#include "newclientdlg.h"
#include "OldChgFilterDlg.h"
#include "ImageList.h"

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

#define IMG_INDEX(x) (x-IDB_PERFORCE)

#define NUMFORMAT _T("%05d")

static LPCTSTR sRegValue_SubmittedChanges = _T("Submitted Changes");

enum OldChgSubItem
{
	OLDCHG_NAME,
	OLDCHG_DATE,
	OLDCHG_USER,
	OLDCHG_DESC,
	OLDCHG_MAXCOL
};

/////////////////////////////////////////////////////////////////////////////
// COldChgListCtrl

IMPLEMENT_DYNCREATE(COldChgListCtrl, CP4ListCtrl)

BEGIN_MESSAGE_MAP(COldChgListCtrl, CP4ListCtrl)
	ON_UPDATE_COMMAND_UI(ID_VIEW_UPDATE_RIGHT, OnUpdateViewUpdate)
	ON_UPDATE_COMMAND_UI(ID_CHANGE_DESCRIBE, OnUpdateDescribe)
	ON_COMMAND(ID_CHANGE_DESCRIBE, OnDescribe)
	ON_UPDATE_COMMAND_UI(ID_SYNC_CHANGE, OnUpdateSyncChg)
	ON_COMMAND(ID_SYNC_CHANGE, OnSyncChg)
	ON_WM_CONTEXTMENU()
	ON_COMMAND(ID_VIEW_RELOADALL, OnViewReloadall)
	ON_UPDATE_COMMAND_UI(ID_VIEW_RELOADALL, OnUpdateViewReloadall)
	ON_WM_LBUTTONDBLCLK()
	ON_COMMAND(ID_FILTER_SETVIEW, OnFilterSetview)
	ON_COMMAND(ID_FILTER_SETVIEW_DROP, OnFilterSetviewDrop)
	ON_UPDATE_COMMAND_UI(ID_FILTER_SETVIEW, OnUpdateFilterSetview)
	ON_WM_CREATE()
	ON_UPDATE_COMMAND_UI(ID_FILTER_CLEARVIEW, OnUpdateFilterClearview)
	ON_COMMAND(ID_FILTER_CLEARVIEW, OnFilterClearview)
	ON_UPDATE_COMMAND_UI(ID_CHANGE_EDSPEC, OnUpdateChangeEdspec)
	ON_COMMAND(ID_CHANGE_EDSPEC, OnChangeEdspec)
	ON_UPDATE_COMMAND_UI(ID_CHANGE_ADDJOBFIX, OnUpdateAddjobfix)
	ON_NOTIFY_REFLECT(LVN_COLUMNCLICK, OnColumnclick)
	ON_COMMAND(ID_VIEW_UPDATE_RIGHT, OnViewReloadall)
	ON_NOTIFY_REFLECT(LVN_DELETEITEM, OnDeleteitem)
	ON_COMMAND(ID_CHANGE_ADDJOBFIX, OnAddjobfix)
	ON_COMMAND(ID_FILE_INTEGRATE, OnFileIntegrate)
	ON_UPDATE_COMMAND_UI(ID_FILE_INTEGRATE, OnUpdateFileIntegrate)
	ON_COMMAND(ID_FILE_INTEGSPEC, OnFileIntegspec)
	ON_UPDATE_COMMAND_UI(ID_FILE_INTEGSPEC, OnUpdateFileIntegrate)
	ON_COMMAND(ID_PERFORCE_OPTIONS, OnPerforceOptions)
	ON_UPDATE_COMMAND_UI(ID_POSITIONDEPOT, OnUpdatePositionDepot)
	ON_COMMAND(ID_POSITIONDEPOT, OnPositionDepot)
	ON_UPDATE_COMMAND_UI(ID_CHANGE_REMOVEFIX, OnUpdateRemovefix)
	ON_COMMAND(ID_CHANGE_REMOVEFIX, OnRemovefix)
	ON_MESSAGE(WM_P4FIXES, OnP4Fixes )
	ON_MESSAGE(WM_P4FIX, OnP4Fix )
	ON_MESSAGE(WM_ONDODELETEFIXES, OnDoDeleteFixes )
	ON_MESSAGE(WM_RUNUPDATE, OnUpdateRequest )
	ON_MESSAGE(WM_P4CHANGES, OnP4Change)
	ON_MESSAGE(WM_P4DESCRIBE, OnP4Describe )
    ON_MESSAGE(WM_P4ENDDESCRIBE, OnP4EndDescribe )
	ON_MESSAGE(WM_P4MAXCHANGE, OnP4MaxChange )
	ON_MESSAGE(WM_P4EDITSPEC, OnP4ChangeSpec )
	ON_MESSAGE(WM_P4ENDSPECEDIT, OnP4EndSpecEdit )
    ON_MESSAGE(WM_P4JOBS, OnP4JobList )
    ON_MESSAGE(WM_P4GET, OnP4Get )
	ON_MESSAGE(WM_DOCUSTOMGET, OnDoSyncChg )
	ON_MESSAGE(WM_P4INTEGCHG, OnIntegChg )
	ON_MESSAGE(WM_SUBCHGOUFC, CallOnUpdateFilterClearview )
	ON_MESSAGE(WM_P4CHGROLLBACK, OnP4ChgRollback )
	ON_MESSAGE(WM_P4CHGROLLBACKPREVIEW, OnP4ChgRollbackPreview )
	ON_MESSAGE(WM_P4DESCRIBEALT, OnP4ChgSelectAll )
END_MESSAGE_MAP()

COldChgListCtrl::COldChgListCtrl()
{
    m_viewType = P4CHANGE_SPEC;
	m_MaxChange=0;
	m_ItemCount=0;
	m_LastUpdateTime=0;
	m_SortAscending=FALSE;
	m_FilterInteg = m_FilterSpecial = m_ForceFocusHere = FALSE;
	m_FilteredByUser = GET_P4REGPTR()->GetFilteredByUser();
	m_UserFilter = GET_P4REGPTR()->GetUserFilter();
	m_FilteredByClient = GET_P4REGPTR()->GetFilteredByClient();
	m_ClientFilter = GET_P4REGPTR()->GetClientFilter();
	m_LastSortCol=0;
	m_LastDescNbr=_T("");
	m_captionplain = LoadStringResource(IDS_SUBMITTED_PERFORCE_CHANGELISTS);
	m_DeleteFixesDlg = 0;

	m_CF_DEPOT = RegisterClipboardFormat(LoadStringResource(IDS_DRAGFROMDEPOT));
	m_CF_CLIENT= RegisterClipboardFormat(LoadStringResource(IDS_DRAGFROMCLIENT));
	m_CF_USER  = RegisterClipboardFormat(LoadStringResource(IDS_DRAGFROMUSER));
	m_CF_JOB   = RegisterClipboardFormat(LoadStringResource(IDS_DRAGFROMJOB));
}

COldChgListCtrl::~COldChgListCtrl()
{
}

/////////////////////////////////////////////////////////////////////////////
// COldChgListCtrl diagnostics

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

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

/////////////////////////////////////////////////////////////////////////////
// COldChgListCtrl message handlers


void COldChgListCtrl::OnLButtonDblClk(UINT nFlags, CPoint point) 
{
	// Find out what item was clicked and then run describe
	CPoint local = point;
	
	// find out what was hit
	LV_HITTESTINFO ht;
	ht.pt=local;
	ht.flags=LVHT_ONITEMICON | LVHT_ONITEMLABEL;
	int index=HitTest( &ht	);

	if(index != -1)
	{
		// If on an item, so select it and run edit
		SetItemState( index, LVIS_SELECTED|LVIS_FOCUSED, LVIS_SELECTED|LVIS_FOCUSED );
		OnDescribe();
	}
	else
		CP4ListCtrl::OnLButtonDblClk(nFlags, point);}


void COldChgListCtrl::Clear()
{
	// Clear the list view
    SetRedraw(FALSE);
	DeleteAllItems();
    SetRedraw(TRUE);
	m_ItemCount=0;
	m_MaxChange=0;
	m_LastUpdateTime=0;
	CP4ListCtrl::Clear();
}


void COldChgListCtrl::ClearFilter()
{
	Clear();
	GET_P4REGPTR()->SetFilteredByUser(FALSE);
	GET_P4REGPTR()->SetFilteredByClient(FALSE);
	m_FilterInteg = m_FilterSpecial = m_FilteredByUser = m_FilteredByClient = FALSE;
	m_FilterView.RemoveAll(); 
	SetCaption();
	PersistentChgFilter( KEY_WRITE );
}

void COldChgListCtrl::InsertChange(CP4Change *change, int index)
{
	// Add the data
	LV_ITEM lvItem;
	int iActualItem = -1;
	CString txt, txtout;
	int i;

	ASSERT(change != NULL);
	m_iImage = CP4ViewImageList::VI_OLDCHANGE;

	if (GET_SERVERLEVEL() < 12)
	{
		// Are we filtering by user on an old server?
		// (on a new server we don't have anything to do 
		//  because p4 changes -u did it for us)
		if (m_FilteredByUser)
		{
			txt = const_cast<LPTSTR>((LPCTSTR)change->GetUser());
			if ((i = txt.Find(_T('@'))) != -1)
				txt = txt.Left(i);
			// is this the user we want?
			if (txt != m_UserFilter)
			{
				// no - so we must delete the change because no one 
				// will know about it now that it is not in the list
				delete change;
				return;
			}
		}
		// Are we filtering by client on an old server?
		// (on a new server we don't have anything to do 
		//  because p4 changes -u did it for us)
		if (m_FilteredByClient)
		{
			txt = const_cast<LPTSTR>((LPCTSTR)change->GetUser());
			if ((i = txt.Find(_T('@'))) != -1)
				txt = txt.Mid(i+1);
			// is this the client we want?
			if (txt != m_ClientFilter)
			{
				// no - so we must delete the change because no one 
				// will know about it now that it is not in the list
				delete change;
				return;
			}
		}
	}
	
	for(int subItem=0; subItem < 4; 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);
		lvItem.iSubItem= subItem;
		lvItem.iImage = CP4ViewImageList::VI_OLDCHANGE;
		lvItem.lParam=(LPARAM) change;

		switch(subItem)
		{
		case 0: 
			txt.Format(NUMFORMAT, change->GetChangeNumber());
			lvItem.pszText= const_cast<LPTSTR>((LPCTSTR)txt); break;
		case 1: 
			lvItem.pszText= const_cast<LPTSTR>((LPCTSTR)change->GetChangeDate()); break;
		case 2: 
			lvItem.pszText= const_cast<LPTSTR>((LPCTSTR)change->GetUser()); break;
		case 3: 
			txt= change->GetDescription(); 
			// Dont display cr-lf and tab chars
			int len=txt.GetLength();
			LPTSTR ptr=txt.GetBuffer(len);
			LPTSTR ptrout=txtout.GetBuffer(len);
			for(int i=0; i<len; i++)
			{
				if(*ptr==_T('\r'))
				{
					*ptrout=_T(' ');
					ptrout++;
				}
				else if(*ptr!=_T('\n') && *ptr!=_T('\t'))
				{
					*ptrout=*ptr;
					ptrout++;
				}
				ptr++;
			}
			*ptrout=_T('\0');
			txtout.ReleaseBuffer();
			lvItem.pszText=const_cast<LPTSTR>((LPCTSTR)txtout);
			break;
		}
			
		if(subItem==0)
			iActualItem=InsertItem(&lvItem);
		else
			SetItem(&lvItem);
		
	}
}


LRESULT COldChgListCtrl::OnP4Change(WPARAM wParam, LPARAM lParam)
{
	// Note:  Output of 'P4 changes' arrives highest change number to
	//        lowest change number, so use m_NewMaxChange as a temp value
	//        and only update m_MaxChange at the end of the operation.
	if (lParam)
	{
		// Just got a list of changes
		CObList *list= (CObList *) wParam;
		ASSERT_KINDOF(CObList, list);

		POSITION pos= list->GetHeadPosition();
        SetRedraw(FALSE);
		while(pos != NULL)
		{
			CP4Change *change= (CP4Change *) list->GetNext(pos);
			ASSERT_KINDOF(CP4Change, change);

			if(change->GetChangeNumber() > m_MaxChange)
			{
				// Note: Do not delete change if inserted in list, because  
				//       DeleteItem() will get rid of the change later.
				if(change->GetChangeNumber() > m_NewMaxChange)
					m_NewMaxChange=change->GetChangeNumber();
				InsertChange(change, m_ItemCount);
				m_ItemCount++;
			}
			else
				delete change;
			
		}
        SetRedraw(TRUE);
		delete list;
	}
	else
	{
		CCmd_Changes *pCmd= (CCmd_Changes *) wParam;
		ASSERT_KINDOF(CCmd_Changes, pCmd);

		if(!pCmd->GetError())
		{
			CP4ListCtrl::SetUpdateDone();
			m_LastUpdateTime=GetTickCount();
			if (!m_ItemCount)
				m_UpdateState = LIST_CLEAR;
		}
		else
		{
			CP4ListCtrl::SetUpdateFailed();
			m_ForceFocusHere = FALSE;
		}

        // Record the new max change
		if (m_NewMaxChange > m_MaxChange)
			m_MaxChange = m_NewMaxChange;

		// Sort the view
		ReSort();
		
		if( m_ItemCount > 0)
		{
			int i = FindInList(m_Active);
			if (i < 0)	i=0;
			SetItemState( i, LVIS_SELECTED|LVIS_FOCUSED, LVIS_SELECTED|LVIS_FOCUSED );
			EnsureVisible(i, FALSE);
		}

		CString msg;
		msg.FormatMessage( IDS_NUMBER_OF_SUBMITTED_CHANGELISTS_n, m_ItemCount );
		AddToStatus( msg, SV_DEBUG );

		if( pCmd->HaveServerLock() )
            pCmd->ReleaseServerLock();
		delete pCmd;

		MainFrame()->ClearStatus();

		// Notify the mainframe that we have finished getting the submitted changlists,
		// hence the entire set of port connection async command have finished.
		MainFrame()->FinishedGettingChgs(FALSE);

		// and we are done - must explicitly call this in case filter yielded 0 chglists
		CP4ListCtrl::SetUpdateDone();

		// if we did this update to fill a Browse listbox, call back to fill the listbox.
		if (m_PostViewUpdateMsg)
		{
			PostMessage(m_PostViewUpdateMsg, m_PostViewUpdateWParam, m_PostViewUpdateLParam);
			m_PostViewUpdateMsg = 0;
		}

		// if we just finished processing a Drop, force the focus to this pane
		if (m_ForceFocusHere)
		{
			m_ForceFocusHere = FALSE;
			MainFrame()->OnViewSubmitted();
		}
	}

	return 0;
}


LRESULT COldChgListCtrl::OnP4Describe(WPARAM wParam, LPARAM lParam)
{
	CCmd_Describe *pCmd= (CCmd_Describe *) wParam;

	if(!pCmd->GetError())
	{
		CString desc= MakeCRs(pCmd->GetDescription());
		
		int key;
		CSpecDescDlg *dlg = new CSpecDescDlg(this);
		dlg->SetIsModeless(TRUE);
		dlg->SetKey(key = pCmd->HaveServerLock()? pCmd->GetServerKey() : 0);
		dlg->SetDescription(LPCTSTR(desc));
		dlg->SetItemName( pCmd->GetReference() );
		dlg->SetCaption(LoadStringResource(IDS_PERFORCE_CHANGELIST_DESCRIPTION));
		dlg->SetShowNextPrev(m_ItemCount ? TRUE : FALSE);
		dlg->SetShowShowDiffs(TRUE);
		dlg->SetDiffFlag(pCmd->GetFlag());
		dlg->SetShowEditBtn(!key && !m_EditInProgress ? TRUE : FALSE);
		dlg->SetViewType(P4CHANGE_SPEC);
		if (!dlg->Create(IDD_SPECDESC, this))	// display the description dialog box
		{
			EnumChildWindows(AfxGetMainWnd()->m_hWnd, ChildSetRedraw, TRUE);
			dlg->DestroyWindow();	// some error! clean up
			delete dlg;
		}
	}
	else	// had an error - need to turn painting back on
	{
		EnumChildWindows(AfxGetMainWnd()->m_hWnd, ChildSetRedraw, TRUE);
	}
	
	delete pCmd;
	MainFrame()->ClearStatus();
	return 0;
}

LRESULT COldChgListCtrl::OnP4EndDescribe( WPARAM wParam, LPARAM lParam )
{
	CSpecDescDlg *dlg = (CSpecDescDlg *)lParam;
	CString ref = dlg->GetItemName();
	ASSERT(!ref.IsEmpty());

	switch(wParam)				// which button did they click to close the box?
	{
	case ID_SHOWDIFFS_NORMAL:
	case ID_SHOWDIFFS_SUMMARY:
	case ID_SHOWDIFFS_UNIFIED:
	case ID_SHOWDIFFS_CONTEXT:
	case ID_SHOWDIFFS_RCS:
	case ID_SHOWDIFFS_NONE:
	{
		long l = _ttol(ref);
		OnDescribeLong(l, wParam);
		break;
	}
	case IDC_NEXTITEM:
	case IDC_PREVITEM:
	{
		long l = _ttol(ref);
		ref.Format(_T("%05d"), l);
		if (SetToNextPrevItem(ref, wParam == IDC_NEXTITEM ? 1 : -1, this))
		{
			OnDescribe();	// display the next/prev in the list on the screen
			break;
		}
	}
	case IDC_EDITIT:
		if (wParam == IDC_EDITIT)	// note fall-thru from above!
		{
			CString name = ref;
			BOOL uFlag = FALSE;
			if (GET_SERVERLEVEL() >= 23)	// 2007.2 or later?
			{
				int i;
				CString desc = dlg->GetDescription();
				if ((i = desc.Find(_T('@'))) != -1)
				{
					CString str = desc.Left(i);
					if ((i = str.ReverseFind(_T(' '))) != -1)
					{
						CString user = str.Mid(i+1);
						uFlag = !Compare(user, GET_P4REGPTR()->GetP4User());
					}
				}
			}
			EditTheSpec(&name, uFlag);
		}
	default:	// clicked OK, pressed ESC or ENTER - need to turn painting back on
		EnumChildWindows(AfxGetMainWnd()->m_hWnd, ChildSetRedraw, TRUE);
		break;
	}
	dlg->DestroyWindow();
	return TRUE;
}

void COldChgListCtrl::OnUpdateViewUpdate(CCmdUI* pCmdUI) 
{
//	pCmdUI->SetText ( SetTextToRefresh( ) );
	pCmdUI->Enable(!SERVER_BUSY() && !MainFrame()->IsModlessUp());
}

void COldChgListCtrl::OnUpdateViewReloadall(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable(!SERVER_BUSY());
}


LRESULT COldChgListCtrl::OnUpdateRequest(WPARAM wParam, LPARAM lParam)
{
	OnViewUpdate();
	return 0;
}

void COldChgListCtrl::OnViewReloadall() 
{
	m_Active = GetSelectedItemText();
	m_MaxChange=0;
	Clear();
	OnViewUpdate();
}

void COldChgListCtrl::OnViewUpdate() 
{
	MainFrame()->SetOldChgUpdateTime(GetTickCount());
	CString str = GetSelectedItemText();
	if (!str.IsEmpty())
		m_Active = str;

	// For a full refresh, proceed to GetChanges
	if(m_MaxChange == 0)
    {
        int numChanges;
        if( GET_P4REGPTR()->GetFetchAllChanges() )
            numChanges= 0;
        else
            numChanges= GET_P4REGPTR()->GetFetchChangeCount();
	
		GetChanges(numChanges);
    }
	else
	{
		// If it has been over 20 minutes since we updated, run MaxChange
		long time=GetTickCount();
		long elapsedTime= time-m_LastUpdateTime;
		if(elapsedTime < 0 || elapsedTime > 1200000L)
		{
			CCmd_MaxChange *pCmd= new CCmd_MaxChange;
			pCmd->Init( m_hWnd, RUN_ASYNC, HOLD_LOCK);
			if( pCmd->Run() )
			{
				MainFrame()->UpdateStatus(LoadStringResource(IDS_VERIFYING_HEAD_CHANGELIST));
			}
			else
			{
				delete pCmd;
				MainFrame()->ClearStatus();
			}
		}
		else
		{
			// Make a conservative estimate of changes submitted since last update
			int numchanges=20 + 10 * (elapsedTime/60000);
            if( !GET_P4REGPTR()->GetFetchAllChanges() &&
                numchanges > GET_P4REGPTR()->GetFetchChangeCount() )
            {
                numchanges = GET_P4REGPTR()->GetFetchChangeCount();
                Clear();
            }
            GetChanges(numchanges);
		}
	}
}

LRESULT COldChgListCtrl::OnP4MaxChange(WPARAM wParam, LPARAM lParam)
{
	CCmd_MaxChange *pCmd= (CCmd_MaxChange *) wParam;
	if(pCmd->GetError() || MainFrame()->IsQuitting())
	{
        pCmd->ReleaseServerLock();
		delete pCmd;
		MainFrame()->ClearStatus();
		return 0;
	}

    int key= pCmd->GetServerKey();

	// Get the new max change, for use if the update is a success
	long headChange= pCmd->GetMaxChange();
	
	if(headChange == m_MaxChange)
	{
		// No work to do
		pCmd->ReleaseServerLock();
		MainFrame()->ClearStatus();
	}
	else if(headChange < m_MaxChange)
	{
		// How did max change number go down??
		ASSERT(0);  
		Clear();
        int numChanges;
        if( GET_P4REGPTR()->GetFetchAllChanges() )
            numChanges= 0;
        else
            numChanges= GET_P4REGPTR()->GetFetchChangeCount();
	
		GetChanges(numChanges, key);
	}
	else
	{
		// Add 10 changes worth of "padding" in case a change is submitted between 
		// the MaxChange and Changes commands
		GetChanges(10 + headChange-m_MaxChange, key);
	}
    delete pCmd;
	return 0;
}

void COldChgListCtrl::GetChanges(long numToFetch, int key/*=0*/)
{	
	m_NewMaxChange=0;
	CCmd_Changes *pCmd= new CCmd_Changes;
    if( key==0 )
	    pCmd->Init( m_hWnd, RUN_ASYNC);
    else
        pCmd->Init( m_hWnd, RUN_ASYNC, LOSE_LOCK, key);

	// Make a copy of the filter view, because CCmdChanges will
	// destroy that copy
	POSITION pos=m_FilterView.GetHeadPosition();
	m_StrList.RemoveAll();
	while(pos != NULL)
		m_StrList.AddTail(m_FilterView.GetNext(pos));

	if( pCmd->Run(SUBMITTED_CHANGES, 
		(GET_SERVERLEVEL() >= 19 && GET_P4REGPTR()->GetUseShortSubmittedDesc()) ? 2 : 1, 
		&m_StrList, numToFetch, m_FilterInteg, 
		!m_FilteredByUser || m_UserFilter.IsEmpty() ? NULL : &m_UserFilter, 
		!m_FilteredByClient || m_ClientFilter.IsEmpty() ? NULL : &m_ClientFilter) )
	{
		MainFrame()->UpdateStatus(LoadStringResource(IDS_REQUESTING_CHANGES));
		CP4ListCtrl::OnViewUpdate();
	}
	else
	{
        if(pCmd->HaveServerLock())
            pCmd->ReleaseServerLock();
		delete pCmd;
		MainFrame()->ClearStatus();
	}
}

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

	int	index;
    SetIndexAndPoint( index, point );

	// If on an item, make sure it's selected
	if(index != -1)
		SetItemState( index, LVIS_SELECTED|LVIS_FOCUSED, LVIS_SELECTED|LVIS_FOCUSED );
	
	///////////////////////////////
	// See ContextMenuRules.txt for order of menu commands!

	// create an empty context menu
	CP4Menu popMenu;
	popMenu.CreatePopupMenu();

	CP4Menu integMenu;
	integMenu.CreatePopupMenu();

	if(index != -1)
	{
		popMenu.AppendMenu(MF_ENABLED | MF_STRING, ID_CHANGE_EDSPEC, LoadStringResource( IDS_EDIT ) );
		popMenu.AppendMenu(MF_ENABLED | MF_STRING, ID_CHANGE_DESCRIBE );
		popMenu.AppendMenu(MF_ENABLED | MF_STRING, ID_CHANGE_ADDJOBFIX, LoadStringResource( IDS_ADDJOBFIX ) );
		popMenu.AppendMenu(MF_ENABLED | MF_STRING, ID_CHANGE_REMOVEFIX, LoadStringResource( IDS_CHANGE_REMOVEFIX ) );	
		popMenu.AppendMenu(MF_ENABLED | MF_STRING, ID_SYNC_CHANGE, LoadStringResource( IDS_SYNC_CHANGE ) );
		popMenu.AppendMenu(MF_ENABLED | MF_STRING, ID_POSITIONDEPOT, LoadStringResource( IDS_FINDCHGFILESINDEPOT ) );
		integMenu.AppendMenu( stringsON, ID_FILE_INTEGSPEC, LoadStringResource( IDS_USINGFILESPEC ) );
		integMenu.AppendMenu( stringsON, ID_FILE_INTEGRATE, LoadStringResource( IDS_USINGBRANCHSPEC ) );
		popMenu.AppendMenu(MF_POPUP, (UINT) integMenu.GetSafeHmenu(), LoadStringResource( IDS_INTEGRATE ) );
		popMenu.AppendMenu(MF_SEPARATOR);
	}

	popMenu.AppendMenu(MF_ENABLED | MF_STRING, ID_FILTER_SETVIEW, LoadStringResource(IDS_FILTER_SETVIEW));
	UINT flags = (m_FilterView.GetCount() || m_FilteredByClient || m_FilteredByUser) 
		? MF_ENABLED | MF_STRING : MF_DISABLED | MF_STRING;
	popMenu.AppendMenu(flags, ID_FILTER_CLEARVIEW, LoadStringResource(IDS_CLEARFILTER));

	popMenu.AppendMenu( MF_SEPARATOR );
	popMenu.AppendMenu(MF_ENABLED | MF_STRING, ID_VIEW_UPDATE, LoadStringResource(IDS_REFRESH));

	MainFrame()->AddToolsToContextMenu(&popMenu);

	// Finally blast the menu onto the screen
	popMenu.TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON,	point.x, point.y, AfxGetMainWnd());
}


void COldChgListCtrl::OnUpdateSyncChg(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable( OnUpdateShowMenuItem( pCmdUI, IDS_SYNC_CHANGE_s ) 
						&& !MainFrame()->IsModlessUp() );	
}

void COldChgListCtrl::OnSyncChg() 
{
	if(!GetSelectedChange())
		return;

	m_SyncChangeDlg = new CSyncChange(this);
	if (!m_SyncChangeDlg)
	{
		ASSERT(0);
		AfxMessageBox(IDS_COULD_NOT_CREATE_CUSTOM_SYNC_DIALOG_BOX, MB_ICONSTOP);
		return;
	}

	MainFrame()->SetModelessUp(TRUE);
	if (!m_SyncChangeDlg->Create(IDD_CHANGE_SYNC, this))
	{
		delete m_SyncChangeDlg;
		MainFrame()->SetModelessUp(FALSE);
	}
}

LRESULT COldChgListCtrl::OnDoSyncChg(WPARAM wParam, LPARAM lParam)
{
	BOOL preview=FALSE;
	long changeNumber= GetSelectedChange();

	switch(wParam)
	{
	case IDCANCEL:
		break;
	case IDGETPREVIEW:
		preview=TRUE;
		// fall thru
	case IDGET:
		if (changeNumber)
		{
			CString syncTxt;
			if (lParam == 2)
			{
				// They want to roll back the files in this chg, so get the chg description
				CString changeTxt;
				changeTxt.Format(_T("%ld"), changeNumber);
				CCmd_Describe *pCmd= new CCmd_Describe;
				pCmd->Init( m_hWnd, RUN_ASYNC);
				pCmd->SetAlternateReplyMsg(preview ? WM_P4CHGROLLBACKPREVIEW : WM_P4CHGROLLBACK);
				if( pCmd->Run( P4DESCRIBE, changeTxt) )
					MainFrame()->UpdateStatus(LoadStringResource(IDS_FETCHING_CHANGELIST_DESCRIPTION));
				else
					delete pCmd;
			}
			else if (lParam)
			{
				if (GET_SERVERLEVEL() >= 17)
					syncTxt.Format(_T("@=%ld"), changeNumber);
				else
					syncTxt.Format(_T("@%ld,%ld"), changeNumber,changeNumber);
			}
			else
				syncTxt.Format(_T("@%ld"), changeNumber);
			m_StrList.RemoveAll();
			m_StrList.AddHead(syncTxt);
			CCmd_Get *pCmd= new CCmd_Get;
			pCmd->Init( m_hWnd, RUN_ASYNC);
			if( pCmd->Run( &m_StrList, preview ) )
				MainFrame()->UpdateStatus( LoadStringResource(IDS_FILE_SYNC) );
			else
				delete pCmd;
			break;
		}
	default:
		ASSERT(0);
		break;
	}
	if (m_SyncChangeDlg && (wParam != IDGETPREVIEW))
	{
		m_SyncChangeDlg->DestroyWindow();
		delete m_SyncChangeDlg;
		MainFrame()->SetModelessUp(FALSE);
	}
	return 0;
}
	
void COldChgListCtrl::OnUpdateDescribe(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable( OnUpdateShowMenuItem( pCmdUI, IDS_DESCRIBESUBMITTED_s ) );	
}

LRESULT COldChgListCtrl::OnP4Get(WPARAM wParam, LPARAM lParam)
{
	MainFrame()->ClearStatus();
	::SendMessage(m_depotWnd, WM_P4GET, wParam, lParam);
	return 0;
}


void COldChgListCtrl::OnDescribeLong(long changeNumber /*= 0*/, int flag  /*= 0*/) 
{
	if (!changeNumber)
		changeNumber= GetSelectedChange();
	
	if(changeNumber != 0)
	{
		CString changeTxt;
		changeTxt.Format(_T("%ld"), changeNumber);

		CCmd_Describe *pCmd= new CCmd_Describe;
		pCmd->Init( m_hWnd, RUN_ASYNC);
		if( pCmd->Run( P4DESCRIBELONG, changeTxt, NULL, FALSE, flag) )
			MainFrame()->UpdateStatus(LoadStringResource(IDS_FETCHING_CHANGELIST_DESCRIPTION));
		else
			delete pCmd;
	}
	else
		AfxMessageBox ( IDS_PLEASE_SELECT_A_CHANGELIST );
}

void COldChgListCtrl::OnDescribe() 
{
	long changeNumber= GetSelectedChange();
	
	if(changeNumber != 0)
	{
		CString changeTxt;
		changeTxt.Format(_T("%ld"), changeNumber);

		CCmd_Describe *pCmd= new CCmd_Describe;
		pCmd->Init( m_hWnd, RUN_ASYNC);
		if( pCmd->Run( P4DESCRIBE, changeTxt) )
			MainFrame()->UpdateStatus(LoadStringResource(IDS_FETCHING_CHANGELIST_DESCRIPTION));
		else
			delete pCmd;
	}
	else
		AfxMessageBox ( IDS_PLEASE_SELECT_A_CHANGELIST );
}

void COldChgListCtrl::OnDescribeChg() 
{
	//		let user type in the changelist number. if it's blank the user bailed.
	//
	CChgDescribe dlg;
	dlg.SetNbr(m_LastDescNbr);
	if( dlg.DoModal( ) == IDCANCEL )
		return;

	CString nbr = dlg.GetNbr( ) ;
	if ( nbr.IsEmpty( ) )
		return;

	m_LastDescNbr = nbr;
	CCmd_Describe *pCmd= new CCmd_Describe;
	pCmd->Init( m_hWnd, RUN_ASYNC);
	if( pCmd->Run( P4DESCRIBE, nbr) )
		MainFrame()->UpdateStatus(LoadStringResource(IDS_FETCHING_CHANGELIST_DESCRIPTION));
	else
		delete pCmd;
}

void COldChgListCtrl::OnUpdateChangeEdspec(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable(!m_EditInProgress);
}

void COldChgListCtrl::OnChangeEdspec() 
{
	BOOL uFlag = FALSE;
	if (GET_SERVERLEVEL() >= 23)	// 2007.2 or later?
	{
		CString usercli;
		GetUserClientForSelectedChg(&usercli);
		int i;
		if ((i = usercli.Find(_T('@'))) != -1)
		{
			CString user = usercli.Left(i);
			uFlag = !Compare(user, GET_P4REGPTR()->GetP4User());
		}
	}
	EditChangeSpec(GetSelectedChange(), uFlag);
}

void COldChgListCtrl::EditChangeSpec(long changeNumber, BOOL uFlag) 
{
	if (m_EditInProgress)
	{
		CantEditRightNow(IDS_CHANGELIST);
		return;
	}

	if(changeNumber != 0)
	{
		// Fire up CCmd_EditSpec. The spec edit dialog will be invoked by CCmd_EditSpec.
		MainFrame()->UpdateStatus( LoadStringResource(IDS_RETRIEVING_CHANGELIST_SPEC) );
		CCmd_EditSpec *pCmd= new CCmd_EditSpec;
		pCmd->Init( m_hWnd, RUN_ASYNC, HOLD_LOCK );
		if( pCmd->Run( changeNumber, FALSE, !uFlag, FALSE, FALSE, uFlag) )
			MainFrame()->UpdateStatus( LoadStringResource(IDS_EDITING_CHANGELIST_SPEC) );	
		else
			delete pCmd;
	}
}

void COldChgListCtrl::EditTheSpec(CString *name, BOOL uFlag)
{
	EditChangeSpec(_ttol(*name), uFlag);
}

long COldChgListCtrl::GetSelectedChange()
{
	int index = CP4ListCtrl::GetSelectedItem();

	if (index==-1)
		return 0;
	else
	{
		TCHAR str[255];
		GetItemText(index, 0, str, 254);
		return _ttol(str);
	}
}

BOOL COldChgListCtrl::GetUserClientForSelectedChg(CString *user)
{
	int index = CP4ListCtrl::GetSelectedItem();

	if (index==-1)
		return FALSE;
	TCHAR str[255];
	GetItemText(index, 2, str, 254);
	*user = str;
	return TRUE;
}


// A change description was sent to the server, 'P4 change -i".  This should be a confirming
// message. 
LRESULT COldChgListCtrl::OnP4ChangeSpec(WPARAM wParam, LPARAM lParam)
{
	CCmd_EditSpec *pCmd= (CCmd_EditSpec *) wParam;
    MainFrame()->ClearStatus();

	if(!pCmd->GetError() && !m_EditInProgress
	 && pCmd->PreprocessChgSpec() && pCmd->DoSpecDlg(this))
	{
		m_EditInProgress = TRUE;
		m_EditInProgressWnd = pCmd->GetSpecSheet();
	}
	else
	{
		if (pCmd->HaveServerLock())
			pCmd->ReleaseServerLock();
   		delete pCmd;
	}
	return 0;
}

LRESULT COldChgListCtrl::OnP4EndSpecEdit( WPARAM wParam, LPARAM lParam )
{
	CCmd_EditSpec *pCmd= (CCmd_EditSpec *) wParam;

	if (lParam != IDCANCEL && lParam != IDABORT)
    {
		// The change description may have changed, so update the display.
		CString desctxt=PadCRs(pCmd->GetChangeDesc());

		int changeNum= pCmd->GetNewChangeNum();
		CString search;
		search.Format( NUMFORMAT, changeNum );

		int index= FindInList( search );
		if( index > -1 )
		{
			SetItemText( index, 3, desctxt );
			CP4Change *change= (CP4Change *) GetItemData(index);
			change->SetDescription(desctxt);
		}

		CString txt;
		txt.FormatMessage(IDS_CHANGE_n_UPDATED, (long) pCmd->GetNewChangeNum());
		AddToStatus(txt);
	}

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


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

int COldChgListCtrl::OnCompareItems(LPARAM lParam1, LPARAM lParam2, int subItem)
{
    ASSERT(lParam1 && lParam2);
    CP4Change const *change1 = (CP4Change const *)lParam1;
    CP4Change const *change2 = (CP4Change const *)lParam2;


	CString txt1, txt2;
	switch(subItem)
	{
	case OLDCHG_NAME:
		if(m_SortAscending)
			return( change1->GetChangeNumber() -
					change2->GetChangeNumber() );
		else
			return( change2->GetChangeNumber() -
					change1->GetChangeNumber() );
		break;

	case OLDCHG_DATE:
		txt1= change1->GetChangeDate();
		txt2= change2->GetChangeDate();
		ConvertDates( txt1, txt2 );
		break;

	case OLDCHG_USER:
		txt1= change1->GetUser();
		txt2= change2->GetUser();
		break;

	case OLDCHG_DESC:
		txt1= change1->GetDescription();
		txt2= change2->GetDescription();
		break;

	default:
		ASSERT(0);
		return 0;
	}

	int rc;

	if(m_SortAscending)
	{
		if ( subItem == OLDCHG_USER )
			rc = Compare(txt1, txt2);
		else
			rc = txt1.Compare(txt2);
	}
	else
	{
		if ( subItem == OLDCHG_USER )
			rc = Compare(txt2, txt1);
		else
			rc = txt2.Compare(txt1);
	}

	return rc;
}

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

/////////////////////////////////////////////////////////////////////
// Handlers for setting filters for submitted changes view
/////////////////////////////////////////////////////////////////////

void COldChgListCtrl::OnFilterClearview() 
{
    if( SERVER_BUSY() )
		return;

	ClearFilter();
	OnViewReloadall();
}

void COldChgListCtrl::OnFilterSetviewDrop()
{
    ::SendMessage(m_depotWnd, WM_GETSELLIST, (WPARAM) &m_FilterView, (LPARAM)TRUE);
	if (m_FilterView.GetCount())
	{
		// save filter changes and update views
		PersistentChgFilter( KEY_WRITE );
		SetCaption();
		OnViewReloadall();
	}
	else
		TheApp()->StatusAdd(LoadStringResource(IDS_NO_SELECTED_FILES_IN_LOCAL_DEPOTS), SV_WARNING);
}

void COldChgListCtrl::OnFilterSetview() 
{
//FIXTHIS need to enable include integ using this?:	GET_P4REGPTR()->GetEnableSubChgIntegFilter( )
	COldChgFilterDlg dlg;

	// initialize filter vars
	dlg.m_useClient = m_FilteredByClient;
	dlg.m_client = m_ClientFilter;
	dlg.m_useUser = m_FilteredByUser;
	dlg.m_user = m_UserFilter;
	dlg.m_includeIntegrations = m_FilterInteg;

	// get selected files from depot view and convert to string
	CStringList selected;
    ::SendMessage(m_depotWnd, WM_GETSELLIST, (WPARAM) &selected, 0);
	CString selectedTxt;
	POSITION pos = selected.GetHeadPosition();
	int i;
	for(i=0; pos != NULL; i++)
	{
		CString sel = selected.GetNext(pos);
		selectedTxt += sel + _T(" ");
		dlg.m_selected.AddTail(sel);
	}
	selectedTxt.TrimRight();
	dlg.m_selectedFiles = selectedTxt;

	// make a radio button selection based on various strings
	if(m_FilterView.IsEmpty())
		dlg.m_filterFiles = 0;
	else
	{
		// convert current view to a string
		CString currentTxt;
		pos = m_FilterView.GetHeadPosition();
		for(i=0; pos != NULL; i++)
			currentTxt += m_FilterView.GetNext(pos) + _T(" ");
		currentTxt.TrimRight();
		if(currentTxt == selectedTxt)
			dlg.m_filterFiles = 3;
		else
			dlg.m_filterFiles = 2;
	}

	if(dlg.DoModal() == IDCANCEL)
		return;

	// get client and user filter settings
	m_FilteredByClient = dlg.m_useClient;
	GET_P4REGPTR()->SetFilteredByClient(m_FilteredByClient);
	if(m_FilteredByClient)
	{
        m_ClientFilter = dlg.m_client;
		GET_P4REGPTR()->SetClientFilter(m_ClientFilter);
	}

	m_FilteredByUser = dlg.m_useUser;
	GET_P4REGPTR()->SetFilteredByUser(m_FilteredByUser);
	if(m_FilteredByUser)
	{
		m_UserFilter = dlg.m_user;
		GET_P4REGPTR()->SetUserFilter(m_UserFilter);
	}

	// get include integrations option
	m_FilterInteg = dlg.m_includeIntegrations;

	// get the filter view
	switch(dlg.m_filterFiles)
	{
	case 0:	// all files
		m_FilterView.RemoveAll();
		break;
	case 1:	// my client files
		m_FilterView.RemoveAll();
		m_FilterView.AddTail(CString(_T("//")) + GET_P4REGPTR()->GetP4Client( ) + _T("/..."));
		break;
	case 2:	// filespec
		{
		// convert filespec into view stringlist
		m_FilterView.RemoveAll();
		CString filespec = dlg.m_filespec;
		int i;
		while ((i = filespec.Find(_T("//"), 2)) != -1)
		{
			if (filespec.GetAt(i-1) == _T('\"'))
				i--;
			CString txt = filespec.Left(i);
			txt.TrimRight();
			txt.TrimRight(_T('\"'));
			txt.TrimLeft(_T('\"'));
			m_FilterView.AddTail(txt);
			filespec = filespec.Mid(i);
		}
		filespec.TrimRight();
		filespec.TrimRight(_T('\"'));
		filespec.TrimLeft(_T('\"'));
		if (!filespec.IsEmpty())
			m_FilterView.AddTail(filespec);
		}
		break;
	case 3:	// selected files
	  {
		m_FilterView.RemoveAll();
		POSITION pos = selected.GetHeadPosition();
		while (pos != NULL)
		{
			CString str = selected.GetNext(pos);
			if (dlg.m_UseClientSyntax)
			{
				// user wants to convert to client syntax
				CCmd_Where *pCmd1 = new CCmd_Where;
				pCmd1->Init(NULL, RUN_SYNC);
				if ( pCmd1->Run(str) && !pCmd1->GetError() 
				  && pCmd1->GetClientFiles()->GetCount() )
				{
					CStringList * list = pCmd1->GetClientFiles();
					POSITION pos2 = list->GetHeadPosition();
					while (pos2 != NULL)
						m_FilterView.AddTail(list->GetNext(pos2));
				}
				else	// p4 where failed - use depot syntax after all
					m_FilterView.AddTail(str);
				delete pCmd1;
			}
			else
				m_FilterView.AddTail(str);
		}

		// get the filter rev range, if any was set
		CString revRange;
		dlg.GetFilterRevRange(revRange);

		// apply the filter range to the view if applicable
		if (!revRange.IsEmpty())
		{
			POSITION pos=m_FilterView.GetHeadPosition();
			m_StrList.RemoveAll();
			while(pos != NULL)
				m_StrList.AddTail(m_FilterView.GetNext(pos) + revRange);
			pos=m_StrList.GetHeadPosition();
			m_FilterView.RemoveAll();
			while(pos != NULL)
				m_FilterView.AddTail(m_StrList.GetNext(pos));
		}
		break;
	  }
	}


	// save filter changes and update views
	PersistentChgFilter( KEY_WRITE );
	SetCaption();
	OnViewReloadall();
}

LRESULT COldChgListCtrl::CallOnUpdateFilterClearview(WPARAM wParam, LPARAM lParam)
{
	OnUpdateFilterClearview((CCmdUI *)lParam);
	return 0;
}

void COldChgListCtrl::OnUpdateFilterClearview(CCmdUI* pCmdUI) 
{
	pCmdUI->SetText(LoadStringResource(IDS_FILTER_CLEARVIEW));
	pCmdUI->Enable(MainFrame()->SetMenuIcon(pCmdUI, !SERVER_BUSY() && 
		(m_FilterView.GetCount() || m_FilteredByClient || m_FilteredByUser)));
}

void COldChgListCtrl::OnUpdateFilterSetview(CCmdUI* pCmdUI) 
{
	pCmdUI->SetText(LoadStringResource(IDS_FILTER_SETVIEW));
	pCmdUI->Enable( MainFrame()->SetMenuIcon(pCmdUI, !SERVER_BUSY()) );
}

void COldChgListCtrl::PersistentChgFilter( REGSAM accessmask )
{
	LPCTSTR sKey = _T("Software\\Perforce\\P4Win\\");
	LPCTSTR sEntry = _T("ChgFilter");
	LPCTSTR sType  = _T("ChgFiltype");
	LPCTSTR sPort  = _T("ChgFilPort");

    CRegKeyEx key;
    if(ERROR_SUCCESS == key.Create(HKEY_CURRENT_USER, sKey, REG_NONE, REG_OPTION_NON_VOLATILE, accessmask))
    {
        if(accessmask == KEY_WRITE)
        {
			POSITION pos=m_FilterView.GetHeadPosition();
            CString filter;
            CString txt;
			while(pos != NULL)
			{
				txt = m_FilterView.GetNext(pos);
				filter += txt + _T('\t');
			}

            key.SetValueString(filter, sEntry);
			if (filter.GetLength() > 0)						// if filter is not blank
				GET_P4REGPTR()->AddMRUChgFilter( filter );	// save as most recently used in Reg


			txt.Format(_T("%d"), m_FilterInteg);
            key.SetValueString(txt, sType);
            key.SetValueString(GET_P4REGPTR()->GetP4Port(), sPort);
        }
		else
		{
			m_FilterView.RemoveAll();
			m_FilterInteg = m_FilterSpecial = FALSE;
			
            CString port = key.QueryValueString(sPort);
            if(!port.IsEmpty() && port == GET_P4REGPTR()->GetP4Port())
			{
				// in older versions, filter elements were written to the 
				// registry using '@' as a separator.  Now we use '\t', but 
				// we have to handle finding an older setting.  It's easy, 
				// since the whole thing will be terminated with the separator 
				// character.
                CString entry = key.QueryValueString(sEntry);
				bool oldVersion = entry.Right(1) == _T("@");
				m_FilterSpecial = !oldVersion && (entry.FindOneOf(_T("@#")) != -1);
				CString separator = oldVersion ? _T("@") : _T("\t");
                while(!entry.IsEmpty())
				{
                    CString elem = entry.SpanExcluding(separator);

                    if(!elem.IsEmpty())
                    {
                        m_FilterView.AddTail(elem);
                        entry = entry.Mid(elem.GetLength()+1);
                    }
                }
                CString type = key.QueryValueString(sType);
                if(!type.IsEmpty())
				{
					m_FilterInteg = type[0] & 0x01;
					m_FilterSpecial += m_FilterInteg;
				}
			}
			else
			{
				GET_P4REGPTR()->SetFilteredByUser(m_FilteredByUser = FALSE);
				GET_P4REGPTR()->SetFilteredByUser(m_FilteredByClient = FALSE);
			}
			SetCaption();
		}
    }
}

void COldChgListCtrl::SetCaption()
{
	if (m_FilterView.GetCount() > 0 || m_FilteredByUser || m_FilteredByClient)
	{
		CString txt = _T("");
		if (m_FilteredByClient)
			txt = LoadStringResource(IDS_CLIENT) + _T(' ') + m_ClientFilter;
		if (m_FilteredByUser)
		{
			if (!txt.IsEmpty())
				txt += _T("; ");
			txt += LoadStringResource(IDS_USER) + _T(' ') + m_UserFilter;
		}
		if (m_FilterView.GetCount() > 0)
		{
			if (!txt.IsEmpty())
				txt += _T("; ");
			txt += m_FilterView.GetHead();
			if (m_FilterView.GetCount() > 1)
			{
				POSITION pos= m_FilterView.GetHeadPosition();
				m_FilterView.GetNext(pos);
				while( pos != NULL )
					txt += _T(", ") + m_FilterView.GetNext(pos);
			}
		}
		m_caption.FormatMessage(IDS_SUBMITTED_PERFORCE_CHANGELISTS_FILTERED, txt);
	}
	else
		m_caption = LoadStringResource(IDS_SUBMITTED_PERFORCE_CHANGELISTS);

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

/////////////////////////////////////////////////////////////////////
// OLE drag-drop support, to accept depot files or folders
// or accept user or client names which will
// define a view to be used to filter the submitted
// changes that this window displays.
// Also can drop Jobs to be Fixed.
/////////////////////////////////////////////////////////////////////

DROPEFFECT COldChgListCtrl::OnDragEnter(COleDataObject* pDataObject, DWORD dwKeyState, CPoint point) 
{
	m_DropEffect=DROPEFFECT_NONE;
	m_DragDataFormat=0;

	// Dont allow a drop if the server is busy, since a drop immediately attempts to
	// invoke a server command
	if(SERVER_BUSY())
		return DROPEFFECT_NONE;
		
	if(pDataObject->IsDataAvailable( (unsigned short) m_CF_DEPOT))
	{
		m_DropEffect=DROPEFFECT_COPY;
		m_DragDataFormat=m_CF_DEPOT;
	}
	else if(pDataObject->IsDataAvailable( (unsigned short) m_CF_JOB))
	{
		// Set the display of the drag-from items
		m_DropEffect=DROPEFFECT_COPY;
		m_DragDataFormat=m_CF_JOB;
		// Set the scrolling data
	    RECT rc;
		GetItemRect(0, &rc, LVIR_BOUNDS);
		m_ItemHeight = rc.bottom - rc.top;
		HWND hwnd = GetHeaderCtrl()->m_hWnd;
		if (hwnd)
		{
			::GetWindowRect(hwnd, &rc);
			m_HdrHeight = rc.bottom - rc.top;
		}
		else
			m_HdrHeight = m_ItemHeight;
		m_BottomOfPage = GetCountPerPage() * m_ItemHeight + m_HdrHeight;
		m_bStarting = TRUE;
	}
	else if(pDataObject->IsDataAvailable( (unsigned short) m_CF_CLIENT))
	{
		m_DropEffect=DROPEFFECT_COPY;
		m_DragDataFormat=m_CF_CLIENT;
	}
	else if(pDataObject->IsDataAvailable( (unsigned short) m_CF_USER))
	{
		m_DropEffect=DROPEFFECT_COPY;
		m_DragDataFormat=m_CF_USER;
	}
#ifdef UNICODE
	else if(pDataObject->IsDataAvailable( (unsigned short) CF_UNICODETEXT))
	{
		m_DropEffect=DROPEFFECT_COPY;
		m_DragDataFormat=CF_UNICODETEXT;
	}
#else
	else if(pDataObject->IsDataAvailable( (unsigned short) CF_TEXT))
	{
		m_DropEffect=DROPEFFECT_COPY;
		m_DragDataFormat=CF_TEXT;
	}
#endif

	return m_DropEffect;
}


DROPEFFECT COldChgListCtrl::OnDragOver(COleDataObject* pDataObject, DWORD dwKeyState, CPoint point) 
{
	// Dont allow a drop if the server is busy, since a drop immediately attempts to
	// invoke a server command
	if(SERVER_BUSY())
		m_DropEffect= DROPEFFECT_NONE;
		
	if(pDataObject->IsDataAvailable( (unsigned short) m_CF_JOB))
	{
		if (point.y > (m_HdrHeight + m_ItemHeight*2))
			m_bStarting = FALSE;
		if (!m_bStarting)
		{
			if (point.y < (m_HdrHeight + m_ItemHeight/2))
				Scroll(CSize(0, -m_ItemHeight));
			else if (point.y > (m_BottomOfPage - m_ItemHeight/2))
				Scroll(CSize(0, m_ItemHeight));
		}
	}
	return m_DropEffect;
}


BOOL COldChgListCtrl::OnDrop(COleDataObject* pDataObject, DROPEFFECT dropEffect, CPoint point) 
{
	CString fname;
	
	if(SERVER_BUSY())
	{
		// OnDragEnter() and OnDragOver() should avoid a drop at 
		// the wrong time!
		ASSERT(0);
		return FALSE;
	}
	
	if(m_DragDataFormat == m_CF_DEPOT)
	{
		ClientToScreen(&point);
		::SendMessage(m_depotWnd, WM_DROPTARGET, SUBMITTEDCHG, MAKELPARAM(point.x,point.y));
		m_ForceFocusHere = TRUE;
		return TRUE;
	}
	if(m_DragDataFormat == m_CF_JOB)
	{
		int i = GetSelectedItem( );
		if ( i > -1 )
			SetItemState( i, 0, LVIS_DROPHILITED|LVIS_SELECTED|LVIS_FOCUSED );
		ClientToScreen(&point);
		int index= GetContextItem( point );
		if (index > -1)
			SetItemState( index, LVIS_SELECTED|LVIS_FOCUSED,
												  LVIS_SELECTED|LVIS_FOCUSED );
		CString jobname;
		CStringList jobnames;
		jobnames.AddHead(jobname = MainFrame()->GetDragFromJob());
		long changeNumber = _tstol(GetSelectedItemText());
		TCHAR str[ LISTVIEWNAMEBUFSIZE + 1 ];
		GetItemText( index, 3, str, LISTVIEWNAMEBUFSIZE );

		CString txt;
		txt.FormatMessage(IDS_ADD_JOB_FIX, jobname, changeNumber, str);
		if (IDYES == AfxMessageBox(txt, MB_ICONQUESTION|MB_YESNO))
			AddJobFixes(&jobnames, changeNumber, NULL);
		return TRUE;
	}
	if(m_DragDataFormat == m_CF_CLIENT)
	{
		FilterByClient(MainFrame()->GetDragFromClient());
		return TRUE;
	}
	if(m_DragDataFormat == m_CF_USER)
	{
		FilterByUser(MainFrame()->GetDragFromUser());
		return TRUE;
	}
#ifdef UNICODE
	if(m_DragDataFormat == CF_UNICODETEXT)
	{
		HGLOBAL hGlob = pDataObject->GetGlobalData(CF_UNICODETEXT);
#else
	if(m_DragDataFormat == CF_TEXT)
	{
		HGLOBAL hGlob = pDataObject->GetGlobalData(CF_TEXT);
#endif
		LPCTSTR p;

		if ((hGlob != NULL)	&& ((p = (LPCTSTR)::GlobalLock(hGlob)) != NULL))
		{
			CString itemStr = p;
			::GlobalUnlock(hGlob);
			itemStr.Format(_T("%05d"), _ttoi(itemStr));
			OnEditPaste( itemStr );
		}
		return TRUE;
	}
	// Return false, so depot window doesnt start a file-open operation
	return FALSE;
}

int COldChgListCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	if (CP4ListCtrl::OnCreate(lpCreateStruct) == -1)
		return -1;
	
	SetImageList(TheApp()->GetImageList(), LVSIL_SMALL);
	
	// Insert the columns 
	int headers[OLDCHG_MAXCOL]={IDS_CHANGELIST, IDS_DATE, IDS_P4USER, IDS_DESCRIPTION};
	int width[OLDCHG_MAXCOL]={90,90,130,200};
	RestoreSavedWidths(width, OLDCHG_MAXCOL, sRegValue_SubmittedChanges);
	
	int retval;
	LV_COLUMN lvCol;
	for(int subItem=0; subItem < 4; subItem++)
	{
		lvCol.mask= LVCF_FMT | LVCF_SUBITEM | LVCF_TEXT |LVCF_WIDTH;
		lvCol.fmt=LVCFMT_LEFT;
        CString header = LoadStringResource(headers[subItem]);
		lvCol.pszText=const_cast<LPTSTR>((LPCTSTR)header);
		lvCol.iSubItem=subItem;
		lvCol.cx=width[subItem];
		
		retval= InsertColumn(subItem, &lvCol);
	}
    
    m_ColsInited = TRUE;

	return 0;
}


void COldChgListCtrl::OnUpdateAddjobfix(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable(!SERVER_BUSY());
}

void COldChgListCtrl::OnAddjobfix() 
{
	long changeNumber= GetSelectedChange();
	
    if (SERVER_BUSY() || (changeNumber == 0))
	{
		EnumChildWindows(AfxGetMainWnd()->m_hWnd, ChildSetRedraw, TRUE);
        ASSERT(0);
        return;
    }
	
    // Ask jobs window to update itself (if required) and send WM_P4JOBS when done
    // The reply message will be handled below
    SET_APP_HALTED(TRUE);
    ::SendMessage( m_jobWnd, WM_FETCHJOBS, (WPARAM)changeNumber, (LPARAM)m_hWnd);
}

LRESULT COldChgListCtrl::OnP4JobList(WPARAM wParam, LPARAM lParam)
{
    long changeNumber= wParam;

    // Get the list of jobs
    CObList *jobs= (CObList *) ::SendMessage( m_jobWnd, WM_QUERYJOBS, 0, 0);

	CString *spec= (CString *) ::SendMessage( m_jobWnd, WM_QUERYJOBSPEC, 0, 0);

	CStringArray *cols= (CStringArray *) ::SendMessage( m_jobWnd, WM_QUERYJOBCOLS, 0, 0);

	CString *curr= (CString *) ::SendMessage( m_jobWnd, WM_QUERYJOBSELECTION, 0, 0);

	CJobListDlg dlg;
	dlg.SetJobFont(GetFont());
	dlg.SetJobList(jobs);
	dlg.SetJobSpec(spec);
	dlg.SetJobCols(cols);
	dlg.SetJobCurr(curr);
	CStringList *jobnames= dlg.GetSelectedJobs();

	EnumChildWindows(AfxGetMainWnd()->m_hWnd, ChildSetRedraw, TRUE);
	int retcode= dlg.DoModal();
    SET_APP_HALTED(FALSE);

	// Delete the job list
	for(POSITION pos=jobs->GetHeadPosition(); pos!=NULL; )
		delete (CP4Job *) jobs->GetNext(pos);
    delete jobs;

	if(retcode == IDOK && jobnames->GetCount() > 0)
	{
		AddJobFixes(jobnames, changeNumber, 
			dlg.m_JobStatusValue.GetLength() ? LPCTSTR(dlg.m_JobStatusValue) : NULL);
    } // if IDOK
	else if (retcode == IDRETRY)
	{
	    ::SendMessage( m_jobWnd, WM_CLEARLIST, 0, 0);
		PostMessage(WM_COMMAND, ID_CHANGE_ADDJOBFIX, 0);
	}

	MainFrame()->ClearStatus();
    return 0;
}

void COldChgListCtrl::AddJobFixes(CStringList *jobnames, long changeNumber, LPCTSTR jobstatusvalue)
{
    POSITION pos;
    CString str;
    
	// Copy the joblist
	m_JobList.RemoveAll();
	for(pos= jobnames->GetHeadPosition(); pos != NULL; )
	{
		str= jobnames->GetNext(pos);
		m_JobList.AddHead(str);
	}

	CCmd_Fix *pCmdFix= new CCmd_Fix;
	pCmdFix->Init( m_hWnd, RUN_ASYNC, LOSE_LOCK);
	if( pCmdFix->Run( &m_JobList, changeNumber, FALSE, jobstatusvalue ) )
	{
	    MainFrame()->UpdateStatus( LoadStringResource(IDS_FIXING_JOBS) );	
	}	
	else
		delete pCmdFix;
}

void COldChgListCtrl::OnUpdateFileIntegrate(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable(!SERVER_BUSY());	
}

void COldChgListCtrl::OnFileIntegspec() 
{
	OnIntegrate(FALSE);
}

void COldChgListCtrl::OnFileIntegrate() 
{
	CString str = _T("");;
//	long changeNumber = GetSelectedChange();
//	str.Format(_T("@%ld,%ld"), changeNumber, changeNumber);
	CStringList stringlist;
	stringlist.AddHead(str);

	INTEGCHG integChg;
	integChg.useBranch = TRUE;
	integChg.changeList= GetSelectedChange();
	integChg.filelist  = &stringlist;
	::SendMessage(m_depotWnd, WM_CHANGELISTINTEG, 0, (LPARAM)&integChg);
}

void COldChgListCtrl::OnIntegrate(BOOL useBranch)
{
	if (MainFrame()->IsModlessUp())
		return;

	long changeNumber= GetSelectedChange();
	
	if(changeNumber != 0)
	{
		m_UseBranch = useBranch;
		CString changeTxt;
		changeTxt.Format(_T("%ld"), changeNumber);

		CCmd_Describe *pCmd= new CCmd_Describe;
		pCmd->Init( m_hWnd, RUN_ASYNC);
		pCmd->SetAlternateReplyMsg(WM_P4INTEGCHG);
		if( pCmd->Run( P4DESCRIBE, changeTxt) )
			MainFrame()->UpdateStatus(LoadStringResource(IDS_FETCHING_CHANGELIST_DESCRIPTION));
		else
			delete pCmd;
	}
	else
		AfxMessageBox ( IDS_PLEASE_SELECT_A_CHANGELIST );
}

LRESULT COldChgListCtrl::OnIntegChg(WPARAM wParam, LPARAM lParam)
{
	CCmd_Describe *pCmd= (CCmd_Describe *) wParam;

	if(!pCmd->GetError())
	{
		int i, j;
		CString desc= MakeCRs(pCmd->GetDescription());
		CString temp;
		CStringList stringlist;
		if ((i = desc.Find(_T("\nAffected files"))) != -1)
		{
			while ((j = desc.Find(_T("//"), i)) != -1)
			{
				if ((i = desc.Find(_T('#'), j)) == -1)
				{
					AfxMessageBox(_T("Unable to parse filenames from changelist - Integrate fails."));
					goto breakout;
				}
				temp = desc.Mid(j, i-j);
				stringlist.AddTail(temp);
			}
			if (stringlist.GetCount() > 0)
			{
				INTEGCHG integChg;
				integChg.useBranch = m_UseBranch;
				integChg.changeList= GetSelectedChange();
				integChg.filelist  = &stringlist;
				::SendMessage(m_depotWnd, WM_CHANGELISTINTEG, 0, (LPARAM)&integChg);
			}
		}
	}	
breakout:
	delete pCmd;
	MainFrame()->ClearStatus();
	return 0;
}

void COldChgListCtrl::FilterByUser(CString user)
{
	GET_P4REGPTR()->SetUserFilter(m_UserFilter = user);
	GET_P4REGPTR()->SetFilteredByUser(m_FilteredByUser = m_UserFilter.IsEmpty( ) ? FALSE : TRUE);
	PersistentChgFilter( KEY_WRITE );
	SetCaption();
	OnViewReloadall();
}

void COldChgListCtrl::FilterByClient(CString client)
{
	GET_P4REGPTR()->SetClientFilter(m_ClientFilter = client);
	GET_P4REGPTR()->SetFilteredByClient(m_FilteredByClient = m_ClientFilter.IsEmpty( ) ? FALSE : TRUE);
	PersistentChgFilter( KEY_WRITE );
	SetCaption();
	OnViewReloadall();
}

void COldChgListCtrl::OnUpdatePositionDepot(CCmdUI* pCmdUI) 
{
	if (pCmdUI->m_pParentMenu == MainFrame()->GetMenu())
		pCmdUI->SetText(LoadStringResource(IDS_FINDCHGFILESINDEPOT));
	pCmdUI->Enable(!SERVER_BUSY());
}

void COldChgListCtrl::OnPositionDepot()
{
	CString changeTxt;
	changeTxt.Format(_T("%ld"), GetSelectedChange());
	CCmd_Describe *pCmd= new CCmd_Describe;
	pCmd->Init( m_hWnd, RUN_ASYNC);
	pCmd->SetAlternateReplyMsg(WM_P4DESCRIBEALT);
	if( pCmd->Run( P4DESCRIBE, changeTxt) )
		MainFrame()->UpdateStatus(LoadStringResource(IDS_FETCHING_CHANGELIST_DESCRIPTION));
	else
		delete pCmd;
}

void COldChgListCtrl::OnPerforceOptions()
{
	MainFrame()->OnPerforceOptions(TRUE, FALSE, IDS_PAGE_CHANGELIST);
}

LRESULT COldChgListCtrl::OnP4ChgRollback(WPARAM wParam, LPARAM lParam)
{
	return OnP4DescribeAlt(wParam, 0);
}

LRESULT COldChgListCtrl::OnP4ChgRollbackPreview(WPARAM wParam, LPARAM lParam)
{
	return OnP4DescribeAlt(wParam, 1);
}

LRESULT COldChgListCtrl::OnP4ChgSelectAll(WPARAM wParam, LPARAM lParam)
{
	return OnP4DescribeAlt(wParam, 2);
}

LRESULT COldChgListCtrl::OnP4DescribeAlt(WPARAM wParam, LPARAM lParam)
{
	CCmd_Describe *pCmd= (CCmd_Describe *) wParam;

	if(!pCmd->GetError())
	{
		int i, j, count=0;
		BOOL preview = lParam==1;
		BOOL selectAll = lParam==2;
		CString desc= MakeCRs(pCmd->GetDescription());
		MainFrame()->SetAdd2ExpandItemList(selectAll);
		m_StrList.RemoveAll();
		CString temp;
		if ((i = desc.Find(_T("\nAffected files"))) != -1)
		{
			while ((j = desc.Find(_T("//"), i)) != -1)
			{
				if ((i = desc.Find(_T('#'), j)) == -1)
				{
					AfxMessageBox(_T("Unable to parse filenames from changelist - Rollback fails."));
					goto breakout;
				}
				if (selectAll)
				{
					MainFrame()->ExpandDepotString( desc.Mid(j, i-j), TRUE );
					while (MainFrame()->IsExpandDepotContinuing()
							|| SERVER_BUSY())
					{
						if ( !MainFrame()->PumpMessages( ) )
							break;
						Sleep(250);
					}
					count++;
				}
				else
				{
					int rev = _tstoi(desc.Mid(i+1));
					if (rev > 1)
						temp.Format(_T("%s#%d"), desc.Mid(j, i-j), rev-1);
					else
						temp.Format(_T("%s#none"), desc.Mid(j, i-j));
					m_StrList.AddTail(temp);
				}
			}
			if (selectAll)
			{
				MainFrame()->SetAdd2ExpandItemList(FALSE);
				MainFrame()->SelectExpandItemList();
				if (MainFrame()->GetExpandItemListCount() < count)
				{
					CString txt;
					int n = count - MainFrame()->GetExpandItemListCount();
					txt.FormatMessage(IDS_NOTALLITEMSSELECTED_d, n, n==1 ? _T("") : _T("s"));
					TheApp()->StatusAdd( txt, SV_WARNING );
				}
			}
			else if (m_StrList.GetCount() > 0)
			{
				CCmd_Get *pCmd2= new CCmd_Get;
				pCmd2->Init( m_hWnd, RUN_ASYNC);
				if( pCmd2->Run( &m_StrList, preview ) )
					MainFrame()->UpdateStatus( LoadStringResource(IDS_FILE_SYNC) );
				else
					delete pCmd2;
			}
		}
	}	
breakout:
	delete pCmd;
	MainFrame()->ClearStatus();
	return 0;
}

void COldChgListCtrl::OnUpdateRemovefix(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable(!m_DeleteFixesDlg && !SERVER_BUSY() && GetSelectedChange());	
}

void COldChgListCtrl::OnRemovefix() 
{
	int changeNum = GetSelectedChange();
	if (!changeNum || m_DeleteFixesDlg)
		return;

	// Now fire off the request for all the fixes for the changelist
	CCmd_Fixes *pCmdFixes= new CCmd_Fixes;
	pCmdFixes->Init( m_hWnd, RUN_ASYNC);
	if( pCmdFixes->Run(changeNum, NULL) )
	{
		MainFrame()->UpdateStatus( LoadStringResource(IDS_UPDATING_JOB_FIXES) );
	}
	else
	{
		delete pCmdFixes;
		RedrawWindow();
       	MainFrame()->ClearStatus();
	}
}

LRESULT COldChgListCtrl::OnP4Fixes(WPARAM wParam, LPARAM lParam)
{
	CCmd_Fixes *pCmd= (CCmd_Fixes *) wParam;
	CString txt;

	if(!pCmd->GetError())
	{
		m_DelFixesChgNbr = pCmd->GetFixedChangeNumber();
		CObList *fixes = pCmd->GetList();

		if (fixes->GetCount() > 0 && !m_DeleteFixesDlg)
		{
			m_DelFixesList.RemoveAll();
			for(POSITION pos= fixes->GetHeadPosition(); pos != NULL; )
			{
				CP4Fix *fix=(CP4Fix *) fixes->GetNext(pos);
				ASSERT_KINDOF(CP4Fix,fix);
				ASSERT(fix->GetChangeNum() == m_DelFixesChgNbr);
				txt.FormatMessage(IDS_s_FIXED_BY_s_ON_s, fix->GetJobName(), 
									fix->GetUser(), fix->GetFixDate());
				m_DelFixesList.AddTail(txt);
				delete fix;
			}

			m_DeleteFixesDlg = new CDeleteFixes(this);
			if (!m_DeleteFixesDlg)
			{
				ASSERT(0);
				AfxMessageBox(IDS_COULD_NOT_CREATE_DELFIX_DIALOG_BOX, MB_ICONSTOP);
				delete pCmd;
				return 0;
			}

			m_pJobSpec = (CString *) ::SendMessage( m_jobWnd, WM_QUERYJOBSPEC, 0, 0);
			if (!m_pJobSpec || m_pJobSpec->IsEmpty())
			{
				CCmd_JobSpec *pCmd = new CCmd_JobSpec;
				pCmd->Init( m_hWnd, RUN_SYNC );
				if( !pCmd->Run() || pCmd->GetError() )
				{
					AddToStatus(_T("Unable to obtain the JobSpec"), SV_WARNING);	//FIXME!
				}
				else
				{
					pCmd->GetSpec( m_JobSpec );
					m_DeleteFixesDlg->SetJobSpec(&m_JobSpec);
					m_pJobSpec = NULL;
				}
				delete pCmd;
			}
			else
				m_DeleteFixesDlg->SetJobSpec(m_pJobSpec);

			txt.FormatMessage(IDS_REMOVE_FIXES_FROM_CHGLIST_d, m_DelFixesChgNbr);
			m_DeleteFixesDlg->SetCaption(txt);
			m_DeleteFixesDlg->SetSelected(&m_DelFixesList);
			m_DeleteFixesDlg->SetOutputList(&m_DelFixesList);
			m_DeleteFixesDlg->SetOutputStatus(&m_DelFixesStatus);
			m_DeleteFixesDlg->SetReturnMsg(WM_ONDODELETEFIXES);
			if (!m_DeleteFixesDlg->Create(IDD_DELETEFIXES, this))	// display the rm fixes dialog
			{
				delete m_DeleteFixesDlg;
				MainFrame()->SetModelessUp(FALSE);
			}
		}
		else
		{
			txt.FormatMessage(IDS_CHGLIST_d_HAS_NO_JOBS, m_DelFixesChgNbr);
			AddToStatus(txt);
		}
	}
	
   	MainFrame()->ClearStatus();
		
	delete pCmd;
	return 0;
}

LRESULT COldChgListCtrl::OnDoDeleteFixes(WPARAM wParam, LPARAM lParam)
{
	if (wParam == IDOK)
	{
		if (m_DelFixesList.GetCount())
		{
			int i;
			CString job;
			m_JobList.RemoveAll();
			for (POSITION pos = m_DelFixesList.GetHeadPosition(); pos != NULL; )
			{
				job = m_DelFixesList.GetNext(pos);
				if ((i = job.Find(_T(' '))) != -1)
				{
					job = job.Left(i);
					m_JobList.AddTail(job);
				}
			}

			CCmd_Fix *pCmd= new CCmd_Fix;
			pCmd->Init( m_hWnd, RUN_ASYNC, LOSE_LOCK);
			if( pCmd->Run( &m_JobList, m_DelFixesChgNbr, TRUE, 
					m_DelFixesStatus.IsEmpty() ? NULL : m_DelFixesStatus.GetBuffer(40) ) )
				MainFrame()->UpdateStatus( LoadStringResource(IDS_UNFIXING_JOB) );	
			else
				delete pCmd;

			m_DelFixesList.RemoveAll();
		}
		else
			AddToStatus(LoadStringResource(IDS_NOTHING_SELECTED_NOTHING_TO_DO));
	}
	if (m_DeleteFixesDlg)
	{
		m_DeleteFixesDlg->DestroyWindow();	// deletes m_DelSyncDlg
		m_DeleteFixesDlg = 0;
		MainFrame()->SetModelessUp(FALSE);
	}
	return 0;
}

LRESULT COldChgListCtrl::OnP4Fix(WPARAM wParam, LPARAM lParam)
{
	CP4Fix *fix;
	CString text;
	BOOL b = FALSE;
	
	m_JobList.RemoveAll();
	CCmd_Fix *pCmd= (CCmd_Fix *) wParam;
	if(!pCmd->GetError())
	{
		CObList *list= pCmd->GetList();
	
		if(list->GetCount() > 0)
		{
			b = pCmd->IsUnfixing() && pCmd->IsNewStatus();
			POSITION pos= list->GetHeadPosition();
			while( pos != NULL )
			{
				fix= (CP4Fix *) list->GetNext(pos);

				UINT	msgnbr;
				if (b)
				{
					m_JobList.AddTail(fix->GetJobName());
					msgnbr = IDS_s_STATUSCHGED;
				}
				else if (pCmd->IsUnfixing())
				{
					msgnbr = IDS_s_REMOVEDFROM_s;
				}
				else
				{
					msgnbr = IDS_s_ADDEDTO_s;
				}

				// Find the fix and display a message
				CString txt;
				txt.FormatMessage(msgnbr, fix->GetJobName(), fix->GetChangeNum());
				AddToStatus(txt);

				delete fix;
			} //while
		} // if
	}
	
   	MainFrame()->ClearStatus();
	delete pCmd;

	if (b && !m_JobList.IsEmpty())
	{
		pCmd= new CCmd_Fix;
		pCmd->Init( m_hWnd, RUN_ASYNC, LOSE_LOCK );
		if( pCmd->Run( &m_JobList, m_DelFixesChgNbr, TRUE ) )
			MainFrame()->UpdateStatus( LoadStringResource(IDS_UNFIXING_JOB) );	
		else
			delete pCmd;
	}
	return 0;
}
# Change User Description Committed
#1 19924 YourUncleBob Populate -o //guest/perforce_software/p4win/...
//guest/YourUncleBob/p4win/.....
//guest/perforce_software/p4win/main/gui/OldChgListCtrl.cpp
#1 16169 perforce_software Move files to follow new path scheme for branches.
//guest/perforce_software/p4win/gui/OldChgListCtrl.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.