//
// Copyright 1997 Nicholas J. Irias. All rights reserved.
//
//
// DeltaTreeCtrl.cpp : implementation file
//
#include "stdafx.h"
//#define TRACE_HERE
#include "p4win.h"
#include "DeltaTreeCtrl.h"
#include "resource.h"
#include "MainFrm.h"
#ifdef _ALPHA
#include <winnetwk.h>
#endif // _ALPHA
#include "AddListDlg.h"
#include "RevertListDlg.h"
#include <shlobj.h>
#include "P4change.h"
#include "P4Fix.h"
#include "JobListDlg.h"
#include "AutoResolveDlg.h"
#include "TokenString.h"
#include "merge\GuiClientMerge.h"
#include "merge\Merge2Dlg.h"
#include "merge\Merge3Dlg.h"
#include "SpecDescDlg.h"
#include "FileType.h"
#include "MoveFiles.h"
#include "RemoveViewer.h"
#include "ResolveFlagsDlg.h"
#include "FileInfoDlg.h"
#include "P4SpecDlg.h"
#include "MsgBox.h"
#include "ImageList.h"
#include "OldChgFilterDlg.h"
#include "cmd_add.h"
#include "cmd_autoresolve.h"
#include "cmd_changes.h"
#include "cmd_delete.h"
#include "cmd_editspec.h"
#include "cmd_fstat.h"
#include "cmd_diff.h"
#include "cmd_get.h"
#include "cmd_jobs.h"
#include "cmd_fix.h"
#include "cmd_fixes.h"
#include "cmd_history.h"
#include "cmd_listopstat.h"
#include "cmd_ostat.h"
#include "cmd_opened.h"
#include "cmd_prepbrowse.h"
#include "cmd_resolve.h"
#include "cmd_resolved.h"
#include "cmd_revert.h"
#include "cmd_unresolved.h"
#include "cmd_where.h"
#include "strops.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define WM_GOTDROPLIST (WM_USER+500)
#define WM_GOTMOVELISTS (WM_USER+501)
#define WM_OLEADDFILES (WM_USER+502)
#define CHANGELISTS_MINE 0
#define CHANGELISTS_OTHERS 1
///////////////////////
// Note on use of lParam for tree nodes:
// If its a file, lParam is a CP4FileStats ptr
// Otherwise, lParam is NULL
// DeleteItem() takes care of deleting CP4FileStats as reqd
//////////////////////
/////////////////////////////////////////////////////////////////////////////
// CDeltaTreeCtrl
IMPLEMENT_DYNCREATE(CDeltaTreeCtrl, CMultiSelTreeCtrl)
BEGIN_MESSAGE_MAP(CDeltaTreeCtrl, CMultiSelTreeCtrl)
ON_WM_CREATE()
ON_WM_CONTEXTMENU()
ON_WM_RBUTTONDOWN()
ON_WM_RBUTTONUP()
ON_WM_VSCROLL()
ON_WM_SHOWWINDOW()
ON_UPDATE_COMMAND_UI(ID_CHANGE_EDSPEC, OnUpdateChgEdspec)
ON_UPDATE_COMMAND_UI(ID_CHANGE_DEL, OnUpdateChgDel)
ON_UPDATE_COMMAND_UI(ID_CHANGE_NEW, OnUpdateChgNew)
ON_UPDATE_COMMAND_UI(ID_CHANGE_REVORIG, OnUpdateChgRevorig)
ON_UPDATE_COMMAND_UI(ID_CHANGE_SUBMIT, OnUpdateChgSubmit)
ON_UPDATE_COMMAND_UI(ID_FILE_DIFFHEAD, OnUpdateFileDiffhead)
ON_UPDATE_COMMAND_UI(ID_FILE_REVERT, OnUpdateFileRevert)
ON_COMMAND(ID_CHANGE_DEL, OnChangeDel)
ON_COMMAND(ID_CHANGE_EDSPEC, OnChangeEdspec)
ON_COMMAND(ID_CHANGE_NEW, OnChangeNew)
ON_COMMAND(ID_CHANGE_REVORIG, OnChangeRevorig)
ON_COMMAND(ID_CHANGE_SUBMIT, OnChangeSubmit)
ON_COMMAND(ID_FILE_DIFFHEAD, OnFileDiff)
ON_COMMAND(ID_FILE_REVERT, OnFileRevert)
ON_UPDATE_COMMAND_UI(ID_FILE_AUTORESOLVE, OnUpdateFileAutoresolve)
ON_COMMAND(ID_FILE_AUTORESOLVE, OnFileAutoresolve)
ON_UPDATE_COMMAND_UI(ID_FILE_RESOLVE, OnUpdateFileResolve)
ON_COMMAND(ID_FILE_RESOLVE, OnFileResolve)
ON_UPDATE_COMMAND_UI(ID_FILE_RUNMERGETOOL, OnUpdateFileResolve)
ON_COMMAND(ID_FILE_RUNMERGETOOL, OnFileMerge)
ON_UPDATE_COMMAND_UI(ID_THEIRFILE_FINDINDEPOT, OnUpdateTheirFile)
ON_COMMAND(ID_THEIRFILE_FINDINDEPOT, OnTheirFindInDepot)
ON_UPDATE_COMMAND_UI(ID_THEIRFILE_REVISIONHISTORY, OnUpdateTheirFile)
ON_COMMAND(ID_THEIRFILE_REVISIONHISTORY, OnTheirHistory)
ON_UPDATE_COMMAND_UI(ID_THEIRFILE_PROPERTIES, OnUpdateTheirFile)
ON_COMMAND(ID_THEIRFILE_PROPERTIES, OnTheirProperties)
ON_WM_DESTROY()
ON_UPDATE_COMMAND_UI(ID_JOB_DESCRIBE, OnUpdateJobDescribe)
ON_COMMAND(ID_JOB_DESCRIBE, OnJobDescribe)
ON_UPDATE_COMMAND_UI(ID_JOB_EDITSPEC, OnUpdateJobEditspec)
ON_COMMAND(ID_JOB_EDITSPEC, OnJobEditspec)
ON_UPDATE_COMMAND_UI(ID_CHANGE_REMOVEFIX, OnUpdateRemovefix)
ON_COMMAND(ID_CHANGE_REMOVEFIX, OnRemovefix)
ON_UPDATE_COMMAND_UI(ID_CHANGE_ADDJOBFIX, OnUpdateAddjobfix)
ON_COMMAND(ID_CHANGE_ADDJOBFIX, OnAddjobfix)
ON_WM_DROPFILES()
ON_UPDATE_COMMAND_UI(ID_FILE_AUTOEDIT, OnUpdateFileAutoedit)
ON_UPDATE_COMMAND_UI(ID_FILE_QUICKBROWSE, OnUpdateFileAutobrowse)
ON_COMMAND(ID_FILE_AUTOEDIT, OnFileAutoedit)
ON_COMMAND(ID_FILE_QUICKEDIT, OnFileQuickedit)
ON_COMMAND(ID_FILE_QUICKBROWSE, OnFileQuickbrowse)
ON_WM_LBUTTONDBLCLK()
ON_UPDATE_COMMAND_UI(ID_FILE_LOCK, OnUpdateFileLock)
ON_COMMAND(ID_FILE_LOCK, OnFileLock)
ON_UPDATE_COMMAND_UI(ID_FILE_UNLOCK, OnUpdateFileUnlock)
ON_COMMAND(ID_FILE_UNLOCK, OnFileUnlock)
ON_UPDATE_COMMAND_UI(ID_FILE_GETWHATIF, OnUpdateFileGet)
ON_COMMAND(ID_FILE_GETWHATIF, OnFileGetWhatIf)
ON_UPDATE_COMMAND_UI(ID_FILE_GET, OnUpdateFileGet)
ON_COMMAND(ID_FILE_GET, OnFileGet)
ON_UPDATE_COMMAND_UI(ID_EDIT_SELECT_ALL, OnUpdateEditSelectAll)
ON_COMMAND(ID_EDIT_SELECT_ALL, OnEditSelectAll)
ON_UPDATE_COMMAND_UI(ID_EDIT_COPY, OnUpdateEditCopy)
ON_COMMAND(ID_EDIT_COPY, OnEditCopy)
ON_UPDATE_COMMAND_UI(ID_EDIT_COPYCLIENTPATH, OnUpdateEditCopyclientpath)
ON_COMMAND(ID_EDIT_COPYCLIENTPATH, OnEditCopyclientpath)
ON_UPDATE_COMMAND_UI(ID_FILE_REVISIONHISTORY, OnUpdateFileRevisionhistory)
ON_COMMAND(ID_FILE_REVISIONHISTORY, OnFileRevisionhistory)
ON_UPDATE_COMMAND_UI(ID_FILE_REVISIONTREE, OnUpdateFileRevisionhistory)
ON_COMMAND(ID_FILE_REVISIONTREE, OnFileRevisionTree)
ON_UPDATE_COMMAND_UI(ID_FILE_ANNOTATIONS, OnUpdateFileAnnotate)
ON_COMMAND(ID_FILE_ANNOTATIONS, OnFileTimeLapseView)
ON_UPDATE_COMMAND_UI(ID_FILE_PROPERTIES, OnUpdateFileInformation)
ON_COMMAND(ID_FILE_PROPERTIES, OnFileInformation)
ON_UPDATE_COMMAND_UI(ID_WINEXPLORE, OnUpdateWinExplore)
ON_COMMAND(ID_WINEXPLORE, OnWinExplore)
ON_UPDATE_COMMAND_UI(ID_CMDPROMPT, OnUpdateCmdPrompt)
ON_COMMAND(ID_CMDPROMPT, OnCmdPrompt)
ON_UPDATE_COMMAND_UI(ID_CHANGE_DESCRIBE, OnUpdateChangeDescribe)
ON_COMMAND(ID_CHANGE_DESCRIBE, OnChangeDescribe)
ON_UPDATE_COMMAND_UI(ID_FILE_OPENEDIT, OnUpdateFileOpenedit)
ON_COMMAND(ID_FILE_OPENEDIT, OnFileOpenedit)
ON_UPDATE_COMMAND_UI(ID_FILETYPE, OnUpdateFiletype)
ON_COMMAND(ID_FILETYPE, OnFiletype)
ON_UPDATE_COMMAND_UI(ID_FILE_MV2OTHERCHGLIST, OnUpdateMoveFiles)
ON_COMMAND(ID_FILE_MV2OTHERCHGLIST, OnMoveFiles)
ON_UPDATE_COMMAND_UI(ID_POSITIONDEPOT, OnUpdatePositionDepot)
ON_COMMAND(ID_POSITIONDEPOT, OnPositionDepot)
ON_UPDATE_COMMAND_UI(ID_POSITIONCHGS, OnUpdatePositionOtherChgs)
ON_COMMAND(ID_POSITIONCHGS, OnPositionOtherChgs)
ON_UPDATE_COMMAND_UI(ID_POSITIONTOPATTERN, OnUpdatePositionToPattern)
ON_COMMAND(ID_POSITIONTOPATTERN, OnPositionToPattern)
ON_UPDATE_COMMAND_UI(ID_FILE_SCHEDULE, OnUpdateFileSchedule)
ON_COMMAND(ID_SORTCHGFILESBYNAME, OnSortChgFilesByName)
ON_UPDATE_COMMAND_UI(ID_SORTCHGFILESBYNAME, OnUpdateSortChgFilesByName)
ON_COMMAND(ID_SORTCHGFILESBYEXT, OnSortChgFilesByExt)
ON_UPDATE_COMMAND_UI(ID_SORTCHGFILESBYEXT, OnUpdateSortChgFilesByExt)
ON_COMMAND(ID_SORTCHGFILESBYACTION, OnSortChgFilesByAction)
ON_UPDATE_COMMAND_UI(ID_SORTCHGFILESBYACTION, OnUpdateSortChgFilesByAction)
ON_COMMAND(ID_SORTCHGFILESBYRESOLVE, OnSortChgFilesByResolve)
ON_UPDATE_COMMAND_UI(ID_SORTCHGFILESBYRESOLVE, OnUpdateSortChgFilesByResolve)
ON_COMMAND(ID_SORTCHGSBYUSER, OnSortChgsByUser)
ON_UPDATE_COMMAND_UI(ID_SORTCHGSBYUSER, OnUpdateSortChgsByUser)
ON_COMMAND(ID_FILE_SCHEDULE, OnFileGet)
ON_UPDATE_COMMAND_UI(ID_FILE_QUICKEDIT, OnUpdateFileAutoedit)
ON_UPDATE_COMMAND_UI(ID_USER_SWITCHTOUSER, OnUpdateUserSwitchtouser)
ON_COMMAND(ID_USER_SWITCHTOUSER, OnUserSwitchtouser)
ON_UPDATE_COMMAND_UI(ID_CLIENTSPEC_SWITCH, OnUpdateClientspecSwitch)
ON_COMMAND(ID_CLIENTSPEC_SWITCH, OnClientspecSwitch)
ON_UPDATE_COMMAND_UI(ID_FILE_RMVEDITOR, OnUpdateRemoveViewer)
ON_COMMAND(ID_FILE_RMVEDITOR, OnRemoveViewer)
ON_COMMAND_RANGE(ID_FILE_EDITOR_1, ID_FILE_EDITOR_1+MAX_MRU_VIEWERS-1, OnFileMRUEditor)
ON_COMMAND_RANGE(ID_FILE_BROWSER_1, ID_FILE_BROWSER_1+MAX_MRU_VIEWERS-1, OnFileMRUBrowser)
ON_COMMAND(ID_FILE_NEWEDITOR, OnFileNewEditor)
ON_COMMAND(ID_FILE_NEWBROWSER, OnFileNewBrowser)
ON_UPDATE_COMMAND_UI(ID_VIEW_UPDATE_RIGHT, OnUpdateViewUpdate)
ON_COMMAND(ID_VIEW_UPDATE_RIGHT, OnViewUpdate)
ON_UPDATE_COMMAND_UI(ID_SELECTFILES_CHANGED, OnUpdateSelectChanged)
ON_COMMAND(ID_SELECTFILES_CHANGED, OnSelectChanged)
ON_UPDATE_COMMAND_UI(ID_SELECTFILES_UNCHANGED, OnUpdateSelectChanged)
ON_COMMAND(ID_SELECTFILES_UNCHANGED, OnSelectUnchanged)
ON_COMMAND(ID_PERFORCE_OPTIONS, OnPerforceOptions)
ON_UPDATE_COMMAND_UI(ID_FILTER_SETVIEW, OnUpdateFilterSetview)
ON_COMMAND(ID_FILTER_SETVIEW, OnFilterSetview)
ON_UPDATE_COMMAND_UI(ID_FILTER_CLEARVIEW, OnUpdateFilterClearview)
ON_COMMAND(ID_FILTER_CLEARVIEW, OnFilterClearview)
ON_UPDATE_COMMAND_UI(ID_ADD_BOOKMARK, OnUpdateAddBookmark)
ON_COMMAND(ID_ADD_BOOKMARK, OnAddBookmark)
ON_UPDATE_COMMAND_UI(ID_FILE_ANNOTATE, OnUpdateFileAnnotate)
ON_UPDATE_COMMAND_UI(ID_FILE_ANNOTATEALL, OnUpdateFileAnnotate)
ON_UPDATE_COMMAND_UI(ID_FILE_ANNOTATECHG, OnUpdateFileAnnotate)
ON_UPDATE_COMMAND_UI(ID_FILE_ANNOTATECHGALL, OnUpdateFileAnnotate)
ON_COMMAND(ID_FILE_ANNOTATE, OnFileAnnotate)
ON_COMMAND(ID_FILE_ANNOTATEALL, OnFileAnnotateAll)
ON_COMMAND(ID_FILE_ANNOTATECHG, OnFileAnnotateChg)
ON_COMMAND(ID_FILE_ANNOTATECHGALL, OnFileAnnotateChgAll)
ON_MESSAGE(WM_P4ADD, OnP4Add )
ON_MESSAGE(WM_P4AUTORESOLVE, OnP4AutoResolve )
ON_MESSAGE(WM_P4MERGE2, OnP4Merge2 )
ON_MESSAGE(WM_P4MERGE3, OnP4Merge3 )
ON_MESSAGE(WM_P4RESOLVE, OnP4Resolve )
ON_MESSAGE(WM_P4CHANGES, OnP4Change )
ON_MESSAGE(WM_P4OSTAT, OnP4Ostat )
ON_MESSAGE(WM_P4EDITSPEC, OnP4ChangeSpec )
ON_MESSAGE(WM_P4ENDSPECEDIT, OnP4EndSpecEdit )
ON_MESSAGE(WM_P4DELETE, OnP4ChangeDel )
ON_MESSAGE(WM_P4DIFF, OnP4Diff )
ON_MESSAGE(WM_P4LISTOPSTAT, OnP4ListOp )
ON_MESSAGE(WM_P4GET, OnP4SyncAndEdit )
ON_MESSAGE(WM_P4FIXES, OnP4Fixes )
ON_MESSAGE(WM_P4FIX, OnP4Fix )
ON_MESSAGE(WM_P4DESCRIBE, OnP4Describe )
ON_MESSAGE(WM_P4ENDDESCRIBE, OnP4EndDescribe )
ON_MESSAGE(WM_P4UNRESOLVED, OnP4UnResolved )
ON_MESSAGE(WM_P4RESOLVED, OnP4Resolved )
ON_MESSAGE(WM_P4JOBS, OnP4JobList )
ON_MESSAGE(WM_JOBDELETED, OnP4JobDel )
ON_MESSAGE(WM_UPDATEOPEN, OnP4UpdateOpen )
ON_MESSAGE(WM_REVERTLIST, OnP4UpdateRevert )
ON_MESSAGE(WM_SETUNRESOLVED, OnP4SetUnresolved )
ON_MESSAGE(WM_GOTMOVELISTS, OnGotMoveLists )
ON_MESSAGE(WM_GETDRAGTOCHANGENUM, OnGetDragToChangeNum )
ON_MESSAGE(WM_INITTREE, OnInitTree )
ON_MESSAGE(WM_OLEADDFILES, OnOLEAddFiles )
ON_MESSAGE(WM_GETMYCHANGESLIST, OnGetMyChangesList )
ON_MESSAGE(WM_P4FILEREVERT, OnP4FileRevert )
ON_MESSAGE(WM_P4REVERT, OnP4Revert )
ON_MESSAGE(WM_P4FILEINFORMATION, OnP4FileInformation )
ON_MESSAGE(WM_P4ENDFILEINFORMATION, OnP4EndFileInformation )
ON_MESSAGE(WM_P4DIFFCHANGEEDIT, OnP4DiffChangeEdit )
ON_MESSAGE(WM_THEIRFINDINDEPOT, OnP4TheirFindInDepot )
ON_MESSAGE(WM_THEIRHISTORY, OnP4TheirHistory )
ON_MESSAGE(WM_THEIRPROPERTIES, OnP4TheirProperties )
ON_MESSAGE(WM_SUBCHGOUFC, CallOnUpdateFilterClearview )
ON_MESSAGE( WM_ACTIVATEMODELESS, OnActivateModeless )
END_MESSAGE_MAP()
CDeltaTreeCtrl::CDeltaTreeCtrl()
{
m_OLESource.SetTreeCtrl(this);
m_ItemCount=0;
m_CF_DELTA = RegisterClipboardFormat(LoadStringResource(IDS_DRAGFROMDELTA));
m_CF_DEPOT = RegisterClipboardFormat(LoadStringResource(IDS_DRAGFROMDEPOT));
m_CF_JOB = RegisterClipboardFormat(LoadStringResource(IDS_DRAGFROMJOB));
m_MyRootExpanded= m_OthersRootExpanded= FALSE;
m_SortByFilename = GET_P4REGPTR()->SortChgFilesByName();
m_SortByExtension = GET_P4REGPTR()->SortChgFilesByExt();
m_SortByAction = GET_P4REGPTR()->SortChgFilesByAction();
m_SortByResolveStat = GET_P4REGPTR()->SortChgFilesByResolve();
// Initialize tree state info
m_FirstVisibleNodeGroup= CHANGELISTS_MINE;
m_MyRoot= m_OthersRoot=NULL;
m_ContextPoint.x = m_ContextPoint.y = -1;
m_InContextMenu = FALSE;
m_Need2Edit = m_Need2Refresh = m_EditInProgress = FALSE;
m_DeltaIsDropTarget = FALSE;
m_LastDragDropTime = 0;
m_DragDropCtr = 0;
m_NewChgNbr = m_DragToChangeNum = 0;
m_DragToChange = 0;
m_PositionTo = _T("");
m_caption = LoadStringResource(IDS_PENDING_PERFORCE_CHANGELISTS);
m_RedoExpansion = FALSE;
if (GET_P4REGPTR()->ExpandChgLists())
{
m_PrevExpansion = GET_P4REGPTR()->GetPendChgExpansion();
if (!m_PrevExpansion.IsEmpty() && m_PrevExpansion.GetAt(0) == _T('1'))
m_RedoExpansion = TRUE;
}
}
CDeltaTreeCtrl::~CDeltaTreeCtrl()
{
}
void CDeltaTreeCtrl::OnShowWindow(BOOL bShow, UINT nStatus)
{
if (m_EditInProgress && (bShow || GET_P4REGPTR()->AutoMinEditDlg()))
m_EditInProgressWnd->ShowWindow(bShow ? SW_RESTORE : SW_SHOWMINNOACTIVE);
}
LRESULT CDeltaTreeCtrl::OnActivateModeless(WPARAM wParam, LPARAM lParam)
{
if (m_EditInProgress && wParam == WA_ACTIVE)
::SetFocus(m_EditInProgressWnd->m_hWnd);
return 0;
}
void CDeltaTreeCtrl::SaveExpansion()
{
if (GET_P4REGPTR()->ExpandChgLists())
{
CString exp;
TV_ITEM tvItem;
tvItem.hItem = m_MyRoot;
tvItem.stateMask = TVIS_EXPANDED;
tvItem.mask = TVIF_STATE;
TreeView_GetItem(m_hWnd, &tvItem);
if(tvItem.state & TVIS_EXPANDED)
{
exp = _T("1");
HTREEITEM item = GetChildItem(m_MyRoot);
CString chglit = LoadStringResource(IDS_CHANGE);
int chglgth = chglit.GetLength();
while(item != NULL)
{
tvItem.hItem = item;
tvItem.stateMask = TVIS_EXPANDED;
tvItem.mask = TVIF_STATE;
TreeView_GetItem(m_hWnd, &tvItem);
if(tvItem.state & TVIS_EXPANDED)
{
int i;
CString txt = GetItemText(item);
txt.TrimLeft();
if ((i = txt.Find(chglit)) != -1)
{
txt = txt.Mid(i + chglgth);
txt.TrimLeft();
if ((i = txt.Find(_T(' '), 1)) != -1)
txt = txt.Left(i);
}
exp += _T(",") + txt;
}
item = GetNextSiblingItem(item);
}
}
else
exp = _T("0");
GET_P4REGPTR()->SetPendChgExpansion(exp);
}
}
BOOL CDeltaTreeCtrl::IsAFile(HTREEITEM curr_item)
{
#ifdef _DEBUG
// Caller should already have checked that tree level is correct
BOOL underMyRoot;
ASSERT(GetItemLevel(curr_item, &underMyRoot) == 2);
#endif
if(GetLParam(curr_item) == NULL)
return(FALSE);
else
return(TRUE);
}
UINT CDeltaTreeCtrl::GetItemState(HTREEITEM curr_item)
{
TV_ITEM item;
item.hItem=curr_item;
item.mask=TVIF_STATE | TVIF_HANDLE;
GetItem(&item);
return(item.state);
}
void CDeltaTreeCtrl::SetUnexpanded(HTREEITEM curr_item)
{
TV_ITEM tvItem;
tvItem.hItem=curr_item;
tvItem.stateMask= TVIS_EXPANDED ;
tvItem.state=0;
tvItem.mask=TVIF_STATE | TVIF_HANDLE;
SetItem(&tvItem);
}
BOOL CDeltaTreeCtrl::HasChildren(HTREEITEM curr_item)
{
TV_ITEM item;
item.hItem=curr_item;
item.mask=TVIF_CHILDREN | TVIF_HANDLE;
GetItem(&item);
if(item.cChildren > 0 )
return TRUE;
else
return FALSE;
}
/////////////////////////////////////////////////////////////////////////////
// CDeltaTreeCtrl diagnostics
#ifdef _DEBUG
void CDeltaTreeCtrl::AssertValid() const
{
CMultiSelTreeCtrl::AssertValid();
}
void CDeltaTreeCtrl::Dump(CDumpContext& dc) const
{
CMultiSelTreeCtrl::Dump(dc);
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CDeltaTreeCtrl message handlers
void CDeltaTreeCtrl::Clear()
{
InitList();
}
LRESULT CDeltaTreeCtrl::OnInitTree(WPARAM wParam, LPARAM lParam)
{
InitList();
return 0;
}
void CDeltaTreeCtrl::DeleteItem(HTREEITEM item)
{
ASSERT(item != NULL);
LPARAM lParam=GetLParam(item);
if(lParam > 0)
delete (CP4FileStats *) lParam;
CMultiSelTreeCtrl::DeleteItem(item);
}
void CDeltaTreeCtrl::DeleteLParams(HTREEITEM root)
{
if(root==NULL)
return;
HTREEITEM change= GetChildItem(root);
HTREEITEM file;
LPARAM lParam;
while(change != NULL)
{
file= GetChildItem(change);
while(file != NULL)
{
lParam=GetLParam(file);
if(lParam > 0)
{
ASSERT_KINDOF(CP4FileStats, (CP4FileStats *) lParam);
XTRACE(_T("CDeltaTreeCtrl::DeleteLParams: %s\n"), ((CP4FileStats *) lParam)->GetDepotFilename());
delete (CP4FileStats *) lParam;
}
file=GetNextSiblingItem(file);
}
change=GetNextSiblingItem(change);
}
}
void CDeltaTreeCtrl::InitList()
{
UpdateTreeState(TRUE); // saves the current expansion
// Traverse tree, deleting each item's lParam
DeleteLParams(m_MyRoot);
if (m_OthersRoot)
{
DeleteLParams(m_OthersRoot);
m_OthersRoot = NULL;
}
SetRedraw(FALSE);
// Then delete all tree items and replace root level entries
DeleteAllItems();
CString rootName;
rootName.FormatMessage(IDS_PENDING_CHANGELISTS_MY_CLIENT_s, GET_P4REGPTR()->GetP4Client());
m_MyRoot=Insert(rootName, CP4ViewImageList::VI_YOURPENDING, EXPAND_FOLDER, TVI_ROOT, TRUE);
m_MyDefault=Insert(LoadStringResource(IDS_DEFAULTCHANGELISTNAME), CP4ViewImageList::VI_YOURCHANGE, 0, m_MyRoot, TRUE);
if (!m_DragToChangeNum)
m_DragToChange=m_MyDefault;
if ( GET_P4REGPTR()->GetEnablePendingChgsOtherClients( ) )
{
CString txt;
int i = GET_P4REGPTR()->FilterPendChgsByMyClient();
if (GET_SERVERLEVEL() < 21 && i > 1)
{
OnFilterClearview();
i = 0;
}
switch(i)
{
case 1:
txt.FormatMessage(IDS_PENDING_CHANGELISTS_OTHER_CLIENTS_FILTERED,
CString(_T("//")) + GET_P4REGPTR()->GetP4Client() + CString(_T("/...")));
break;
case 2:
txt.FormatMessage(IDS_PENDING_CHANGELISTS_OTHER_CLIENTS_FILTERED,
GET_P4REGPTR()->FilterPendChgsByPath());
break;
default:
txt = LoadStringResource(IDS_PENDING_CHANGELISTS_OTHER_CLIENTS);
break;
}
// Initialize others root as already expanded so expand attempts during refresh are ignored
// in cases where that refresh will already be fetching the needed ifo (running opened -a)
// The final lParam and child count values are handled after the refresh in UpdateTreeState
if( m_OthersRootExpanded )
m_OthersRoot=Insert(txt, CP4ViewImageList::VI_THEIRPENDING, FOLDER_ALREADY_EXPANDED, TVI_ROOT, TRUE);
else
m_OthersRoot=Insert(txt, CP4ViewImageList::VI_THEIRPENDING, EXPAND_FOLDER, TVI_ROOT, TRUE);
}
SetRedraw(TRUE);
// Select nothing, so there is no focus rect
SelectItem(NULL);
// Clear flag for expanding others pending changelist root
m_ExpandingOthersRoot= FALSE;
}
// During a tree refresh, the expanded states of items are lost, so record
// this info prior to the refresh and apply it to the view after the refresh
void CDeltaTreeCtrl::UpdateTreeState(BOOL saveTreeState)
{
HTREEITEM item;
if(saveTreeState)
{
m_MyRootExpanded= m_OthersRootExpanded= FALSE;
m_ExpandedItems.RemoveAll();
m_SelectedItems.RemoveAll();
// First save selected items
for(int i=-1; ++i < GetSelectedCount(); )
{
int j;
HTREEITEM item= GetSelectedItem(i);
CString txt = GetItemText(item);
if (txt.GetAt(0) == _T('/') && ((j = txt.ReverseFind(_T('#'))) != -1))
txt = txt.Left(j);
m_SelectedItems.AddTail(txt);
}
// Now save the tree expansion
if(GetCount() > 0)
{
// First, save expanded state of root items
if(HasExpandedChildren(m_MyRoot))
m_MyRootExpanded= TRUE;
if (m_OthersRoot)
{
if(HasExpandedChildren(m_OthersRoot))
m_OthersRootExpanded= TRUE;
}
// Then save expaned state of my changes
item= GetChildItem(m_MyRoot);
while(item != NULL)
{
if(HasExpandedChildren(item))
m_ExpandedItems.AddHead(GetItemText(item));
item= GetNextSiblingItem(item);
}
if (m_OthersRoot)
{
// Then save expanded state of other's changes
item= GetChildItem(m_OthersRoot);
while(item != NULL)
{
if(HasExpandedChildren(item))
m_ExpandedItems.AddHead(GetItemText(item));
item= GetNextSiblingItem(item);
}
}
}
// Record the first visible item
m_FirstVisibleNodeGroup= CHANGELISTS_MINE;
m_FirstVisibleNodeChange.Empty();
m_FirstVisibleNodeFile.Empty();
CString nodeText;
HTREEITEM item= GetFirstVisibleItem();
if( item != NULL )
{
BOOL underMyRoot=FALSE;
int level=GetItemLevel(item, &underMyRoot);
// If its a file, record filename minus rev and then set the item to parent
if( level == 2 )
{
if( IsAFile( item ) )
{
nodeText= GetItemText( item );
int pound= nodeText.ReverseFind(_T('#'));
if( pound != -1 )
m_FirstVisibleNodeFile= nodeText.Left(pound);
}
item=GetParentItem(item);
level--;
}
// If item is a change, record change name and then set item to parent
ASSERT( item != NULL && item != TVI_ROOT );
if( level == 1 && item != NULL )
{
nodeText= GetItemText( item );
if( nodeText.Find(LoadStringResource(IDS_DEFAULTCHANGELISTNAME)) == 0 )
m_FirstVisibleNodeChange= nodeText;
else if( underMyRoot )
{
m_FirstVisibleNodeChange= nodeText;
int comment= m_FirstVisibleNodeChange.Find(_T("{"));
if( comment != -1 )
m_FirstVisibleNodeChange= m_FirstVisibleNodeChange.Left(comment);
}
else
{
int separator= nodeText.Find(_T(" - "));
if( separator != -1 )
m_FirstVisibleNodeChange= nodeText.Left(separator);
}
item=GetParentItem(item);
level--;
}
// If item not null, record the node group
ASSERT( item != NULL && item != TVI_ROOT );
if( item != m_MyRoot )
m_FirstVisibleNodeGroup= CHANGELISTS_OTHERS;
}
}
else
{
if(m_MyRootExpanded)
Expand(m_MyRoot, TVE_EXPAND);
if (m_OthersRoot)
{
if(m_OthersRootExpanded && GetChildCount( m_OthersRoot ) )
Expand(m_OthersRoot, TVE_EXPAND);
else
{
// Make it ready for an attempted expand operation
m_OthersRootExpanded= FALSE;
SetLParam( m_OthersRoot, EXPAND_FOLDER );
SetChildCount( m_OthersRoot, 1 );
}
}
POSITION pos= m_ExpandedItems.GetHeadPosition();
for( int i=0; i< m_ExpandedItems.GetCount(); i++)
{
item= FindItemByText(m_ExpandedItems.GetNext(pos));
if(item != NULL)
Expand(item, TVE_EXPAND);
}
// Attempt to scroll previous first item back into view, or at least
// scroll the parent of that item back to the top of screen
//
// First set item to recorded node group
if( m_FirstVisibleNodeGroup == CHANGELISTS_MINE )
item= m_MyRoot;
else
item= m_OthersRoot;
HTREEITEM changeItem= NULL;
CString testtext;
// Then try to set item to recorded change, if any
if(!m_FirstVisibleNodeChange.IsEmpty() )
{
int testlen=m_FirstVisibleNodeChange.GetLength();
changeItem=GetChildItem(item);
while(changeItem !=NULL)
{
testtext=GetItemText(changeItem);
if(m_FirstVisibleNodeChange.Compare(testtext.Left(testlen)) == 0)
break;
changeItem=GetNextSiblingItem(changeItem);
}
if( changeItem != NULL )
item= changeItem;
}
// Finally try to set item to recorded file, if any
if(changeItem != NULL && !m_FirstVisibleNodeFile.IsEmpty() )
{
int testlen=m_FirstVisibleNodeFile.GetLength();
HTREEITEM fileItem=GetChildItem(changeItem);
while(fileItem !=NULL)
{
testtext=GetItemText(fileItem);
if(m_FirstVisibleNodeFile.Compare(testtext.Left(testlen)) == 0 && testtext[testlen]==_T('#') )
break;
fileItem=GetNextSiblingItem(fileItem);
}
if( fileItem != NULL )
item= fileItem;
}
// Then scroll the tree into position
if( item != NULL )
ScrollToFirstItem( item );
// Now reselect any previously selected items that are still in my changelists
if (!m_SelectedItems.IsEmpty())
{
pos= m_SelectedItems.GetHeadPosition();
item = NULL;
for( int i=0; i< m_SelectedItems.GetCount(); i++)
{
CString txt = m_SelectedItems.GetNext(pos);
if (txt.GetAt(0) == _T('/'))
item= FindMyOpenFile(txt, item);
else
item= FindItemByText(txt);
if(item != NULL)
SetSelectState(item, TRUE);
}
m_SelectedItems.RemoveAll();
ApplySelectAtts(GetSelectAtts());
}
}
}
// A message handler to get target change number without having to
// include CDeltaTreeCtrl.h
LRESULT CDeltaTreeCtrl::OnGetDragToChangeNum(WPARAM wParam, LPARAM lParam)
{
CPoint *point= (CPoint *) wParam;
point->x= m_DragToPoint.x;
point->y= m_DragToPoint.y;
XTRACE(_T("OnGetDragToChangeNum change=%d\n"), m_DragToChangeNum);
return (LRESULT) m_DragToChangeNum;
}
// Note: this handler is a stripped down version of OnP4Ostat
// - doesnt need to run 'P4 fixes'
// - doesnt need to forward info to Depot window
// - doesnt need to consider unresolved files
LRESULT CDeltaTreeCtrl::OnP4Add(WPARAM wParam, LPARAM lParam)
{
BOOL bSorted=FALSE;
BOOL chainedCommands=FALSE;
CP4FileStats *stats;
CString text;
POSITION pos;
CCmd_Add *pCmd= (CCmd_Add *) wParam;
ASSERT_KINDOF(CCmd_Add, pCmd);
if( !pCmd->GetError() )
{
text.FormatMessage(IDS_ADDED_n_FILES, pCmd->GetAddedFileCount());
AddToStatus(text, SV_COMPLETION);
}
if ( !pCmd->GetError() && pCmd->GetOpenAction() && !pCmd->GetStr2Edit().IsEmpty() )
{
int key= pCmd->GetServerKey();
chainedCommands= TRUE;
m_StringList.RemoveAll();
pos= pCmd->GetStr2Edit().GetHeadPosition();
while( pos != NULL )
{
// Get the filenames to open for edit
CString txt = pCmd->GetStr2Edit().GetNext(pos);
m_StringList.AddTail(txt);
}
CCmd_ListOpStat *pCmd2= new CCmd_ListOpStat;
pCmd2->Init( m_hWnd, RUN_ASYNC, HOLD_LOCK, key );
pCmd2->SetHitMaxFileSeeks(TRUE); // we will need to do a full refresh at the end
pCmd2->SetChkForSyncs(TRUE);
CObList const * pList = pCmd->GetList();
if (pList->GetCount())
{
for( pos= pList->GetHeadPosition(); pos!= NULL; )
pCmd2->Add2RevertList( pList->GetNext(pos), pCmd->GetOpenAction() );
}
if( pCmd2->Run( &m_StringList, P4EDIT, pCmd->GetChangeNum() ) )
MainFrame()->UpdateStatus( LoadStringResource(IDS_OPENING_FILES_FOR_EDIT) );
else
delete pCmd2;
// delete the stats in the pCmd's main list
// because we are now done with them
CObList const *list= pCmd->GetList();
if (!list->IsEmpty())
{
for( pos= list->GetHeadPosition(); pos!= NULL; )
delete (CP4FileStats *) list->GetNext(pos);
}
}
else if ( !pCmd->GetError() && (pCmd->GetOpenAction() == 1) && !pCmd->GetList()->IsEmpty() )
{ // user requested Edit only, but nothing to edit - must reverts any adds
int key= pCmd->GetServerKey();
chainedCommands= TRUE;
m_StringList.RemoveAll();
CObList const * pList = pCmd->GetList();
for( pos= pList->GetHeadPosition(); pos!= NULL; )
{
CP4FileStats *stats= (CP4FileStats *)(pList->GetNext(pos));
CString name=stats->GetFullDepotPath();
m_StringList.AddTail(name);
}
CCmd_ListOpStat *pCmd2= new CCmd_ListOpStat;
pCmd2->Init( m_hWnd, RUN_ASYNC, HOLD_LOCK, key );
pCmd2->SetHitMaxFileSeeks(TRUE); // we will need to do a full refresh at the end
if( pCmd2->Run( &m_StringList, P4REVERT ) )
MainFrame()->UpdateStatus( LoadStringResource(IDS_REQUESTING_REVERT) );
else
delete pCmd2;
}
else if (!pCmd->GetError()
&& (pCmd->HitMaxFileSeeks()
|| (GET_P4REGPTR( )->ShowEntireDepot( ) == SDF_LOCALTREE)))
{
// Too much was added for seeking out each file for an att update
// to be efficient (or we need to refresh the local view).
// Just start a full update.
int key= pCmd->GetServerKey();
chainedCommands= TRUE;
MainFrame()->UpdateDepotandChangeViews(REDRILL, key);
// Clean up any 'stats' in the pCmd's list because this pCmd is soon deleted
CObList const * pList = pCmd->GetList();
for( pos= pList->GetHeadPosition(); pos!= NULL; )
{
CP4FileStats *stats= (CP4FileStats *)(pList->GetNext(pos));
delete stats;
}
}
else if( !pCmd->GetError() )
{
// Get the filelist
CObList const *list= pCmd->GetList();
HTREEITEM currentItem = NULL;
SetRedraw(FALSE);
if(list->GetCount() > 0)
{
// then get the list contents into the tree
POSITION pos= list->GetHeadPosition();
while( pos != NULL )
{
// Get the cursed filename
stats= (CP4FileStats *) list->GetNext(pos);
// Find the change this file is under. Create change if reqd.
currentItem=InsertChange(stats, TRUE);
if(currentItem!=NULL)
{
Insert(stats->GetFormattedChangeFile(GET_P4REGPTR()->ShowFileType(), GET_P4REGPTR()->ShowOpenAction()),
TheApp()->GetFileImageIndex(stats,TRUE), (LPARAM) stats, currentItem, FALSE);
}
} //while
} // if
if( currentItem != NULL && GetChildItem(currentItem) != NULL )
{
SetChildCount(currentItem, 1);
if (GET_P4REGPTR()->ExpandChgLists( ))
Expand(currentItem, TVE_EXPAND);
}
SetRedraw(TRUE);
SortTree();
bSorted = TRUE;
RedrawWindow();
MainFrame()->SetLastUpdateTime(UPDATE_SUCCESS);
MainFrame()->ClearStatus();
}
else
MainFrame()->ClearStatus();
if( !chainedCommands || MainFrame()->IsQuitting() )
{
pCmd->ReleaseServerLock();
if (!bSorted && (m_SortByExtension || m_SortByResolveStat
|| m_SortByAction || m_SortByFilename))
SortTree();
}
delete pCmd;
return 0;
}
LRESULT CDeltaTreeCtrl::OnP4AutoResolve(WPARAM wParam, LPARAM lParam)
{
CCmd_AutoResolve *pCmd= (CCmd_AutoResolve *) wParam;
if( !pCmd->GetError() && !MainFrame()->IsQuitting() )
{
CStringList *list= pCmd->GetList();
CString temp;
if(pCmd->IsPreview())
temp.FormatMessage(IDS_n_FILES_WOULD_BE_RESOLVED, list->GetCount());
else
temp.FormatMessage(IDS_n_FILES_RESOLVED, list->GetCount());
AddToStatus(temp, SV_COMPLETION);
if(!pCmd->IsPreview())
{
// 1) Hold onto the key
// 2) Clear all unresolved attributes
// 3) Run resolved -n with the key
int key= pCmd->GetServerKey();
ClearUnresolvedFlags();
CCmd_Unresolved *pCmd2= new CCmd_Unresolved;
pCmd2->Init( m_hWnd, RUN_ASYNC, HOLD_LOCK, key );
if( !pCmd2->Run() )
{
ASSERT(0);
delete pCmd2;
}
}
else
pCmd->ReleaseServerLock();
}
else
pCmd->ReleaseServerLock();
MainFrame()->ClearStatus();
delete pCmd;
return 0;
}
void CDeltaTreeCtrl::SetCorrectChglistImage(HTREEITEM change)
{
HTREEITEM file= GetChildItem(change);
while(file != NULL)
{
LPARAM lParam=GetLParam(file);
if(lParam > 0)
{
CP4FileStats *stats= (CP4FileStats *) lParam;
ASSERT_KINDOF(CP4FileStats, stats);
if (stats->IsUnresolved())
{
int ix = stats->IsOtherUserMyClient() ? CP4ViewImageList::VI_YOUROTHERCHGUNRES
: CP4ViewImageList::VI_YOURCHGUNRES;
SetImage(change, ix, ix);
return;
}
}
file=GetNextSiblingItem(file);
}
SetImage(change, CP4ViewImageList::VI_YOURCHANGE, CP4ViewImageList::VI_YOURCHANGE);
}
void CDeltaTreeCtrl::ClearUnresolvedFlags( )
{
HTREEITEM change= GetChildItem(m_MyRoot);
HTREEITEM file;
LPARAM lParam;
while(change != NULL)
{
SetImage(change, CP4ViewImageList::VI_YOURCHANGE, CP4ViewImageList::VI_YOURCHANGE);
file= GetChildItem(change);
while(file != NULL)
{
lParam=GetLParam(file);
if(lParam > 0)
{
CP4FileStats *stats= (CP4FileStats *) lParam;
ASSERT_KINDOF(CP4FileStats, stats);
stats->SetUnresolved(FALSE);
int img=TheApp()->GetFileImageIndex(stats,TRUE);
SetImage(file, img, img);
}
file=GetNextSiblingItem(file);
}
change=GetNextSiblingItem(change);
}
}
LRESULT CDeltaTreeCtrl::OnP4Merge2(WPARAM wParam, LPARAM lParam)
{
MainFrame()->ClearStatus();
if(wParam !=0)
{
MainFrame()->DoNotAutoPoll();
CGuiClientMerge *merge= (CGuiClientMerge *) wParam;
CMerge2Dlg dlg;
dlg.SetKey(lParam);
dlg.SetMergeInfo(merge);
if (dlg.DoModal() == IDC_CANCEL_ALL)
m_ResolveList.RemoveAll();
merge->Signal();
MainFrame()->ResumeAutoPoll();
}
return 0;
}
LRESULT CDeltaTreeCtrl::OnP4Merge3(WPARAM wParam, LPARAM lParam)
{
MainFrame()->ClearStatus();
if(wParam !=0)
{
MainFrame()->DoNotAutoPoll();
CGuiClientMerge *merge= (CGuiClientMerge *) wParam;
CMerge3Dlg dlg;
dlg.SetMergeInfo(merge);
dlg.SetForceFlag(m_ForcedResolve);
dlg.SetTextualFlag(m_TextualMerge);
dlg.SetRunMerge(m_bRunMerge);
dlg.SetKey(lParam);
if (dlg.DoModal() == IDC_CANCEL_ALL)
m_ResolveList.RemoveAll();
merge->Signal();
// can't use MainFrame()-> construct
// because mainfram might have closed.
CMainFrame * mainWnd = MainFrame();
if (mainWnd)
mainWnd->ResumeAutoPoll();
}
return 0;
}
LRESULT CDeltaTreeCtrl::OnP4Resolve(WPARAM wParam, LPARAM lParam)
{
CCmd_Resolve *pCmd= (CCmd_Resolve *) wParam;
if(!pCmd->GetError())
{
if(pCmd->GetResolved())
{
CP4FileStats *stats= (CP4FileStats *) GetLParam(m_ActiveItem);
ASSERT_KINDOF(CP4FileStats, stats);
stats->SetUnresolved(FALSE);
stats->SetResolved(TRUE);
int img=TheApp()->GetFileImageIndex(stats,TRUE);
SetImage(m_ActiveItem, img, img);
SetCorrectChglistImage(TreeView_GetParent(m_hWnd, m_ActiveItem));
}
}
delete pCmd;
MainFrame()->ClearStatus();
// if there are more items to resolve, fire up a resolve on the next one
if (!m_ResolveList.IsEmpty())
{
HTREEITEM item = (HTREEITEM)(m_ResolveList.RemoveHead());
ResolveItem(item);
}
else if (m_SortByExtension || m_SortByResolveStat || m_SortByAction || m_SortByFilename)
SortTree();
return 0;
}
LRESULT CDeltaTreeCtrl::OnP4UnResolved(WPARAM wParam, LPARAM lParam)
{
CCmd_Unresolved *pCmd= (CCmd_Unresolved *) wParam;
if(!pCmd->GetError() && !MainFrame()->IsQuitting())
{
SET_BUSYCURSOR();
HTREEITEM item = NULL;
CObArray const *pArray= pCmd->GetArray();
for( int i=0; i < pArray->GetSize(); i++ )
{
CP4FileStats *stats= (CP4FileStats *) pArray->GetAt(i);
item= FindMyOpenFile( stats->GetFullDepotPath(), item );
if( item != NULL )
{
int lParam= GetLParam(item);
if( lParam > 0 )
{
CP4FileStats *fs= (CP4FileStats *) lParam;
fs->SetUnresolved(TRUE);
int img=TheApp()->GetFileImageIndex(fs,TRUE);
SetImage(item, img, img);
int ix = fs->IsOtherUserMyClient() ? CP4ViewImageList::VI_YOUROTHERCHGUNRES
: CP4ViewImageList::VI_YOURCHGUNRES;
SetImage(TreeView_GetParent(m_hWnd, item), ix, ix);
}
else
ASSERT(0);
}
delete stats;
}
int key= pCmd->GetServerKey();
CCmd_Resolved *pCmd2= new CCmd_Resolved;
pCmd2->Init( m_hWnd, RUN_ASYNC, LOSE_LOCK, key );
if( !pCmd2->Run() )
{
ASSERT(0);
delete pCmd2;
::SetCursor(::LoadCursor(NULL, IDC_ARROW));
}
}
else pCmd->ReleaseServerLock();
delete pCmd;
MainFrame()->ClearStatus();
return 0;
}
LRESULT CDeltaTreeCtrl::OnP4Resolved(WPARAM wParam, LPARAM lParam)
{
CCmd_Resolved *pCmd= (CCmd_Resolved *) wParam;
if(!pCmd->GetError())
{
SET_BUSYCURSOR();
HTREEITEM item = NULL;
CObArray const *pArray= pCmd->GetArray();
for( int i=0; i < pArray->GetSize(); i++ )
{
CP4FileStats *stats= (CP4FileStats *) pArray->GetAt(i);
item= FindMyOpenFile( stats->GetFullDepotPath(), item );
if( item != NULL )
{
int lParam= GetLParam(item);
if( lParam > 0 )
{
CP4FileStats *fs= (CP4FileStats *) lParam;
fs->SetResolved(TRUE);
}
else
ASSERT(0);
}
delete stats;
}
if (m_SortByExtension || m_SortByResolveStat || m_SortByAction || m_SortByFilename)
SortTree();
::SetCursor(::LoadCursor(NULL, IDC_ARROW));
}
delete pCmd;
MainFrame()->ClearStatus();
return 0;
}
LRESULT CDeltaTreeCtrl::OnP4Diff(WPARAM wParam, LPARAM lParam)
{
CCmd_Diff *pCmd= (CCmd_Diff *) wParam;
BOOL chainedCommands= FALSE;
if(!pCmd->GetError())
{
CStringList *list= pCmd->GetList();
if(m_DoRevert)
{
chainedCommands = DoRevert(list, pCmd->GetServerKey());
}
else // not m_DoRevert
{
int cnt;
if ((cnt = pCmd->GetDiffRunCount()) == 0)
{
if (pCmd->GetDiffNbrFiles() == 1)
{
CString msg;
msg.FormatMessage(IDS_CLIENT_FILE_s_DOES_NOT_DIFFER_FROM_DEPOT_FILE,
pCmd->GetDiffFileName());
AddToStatus(msg, SV_COMPLETION);
}
else if (pCmd->GetDiffErrCount() == 0)
AddToStatus(LoadStringResource(IDS_NONE_OF_THE_SELECTED_CLIENT_FILES_DIFFER), SV_COMPLETION);
}
else if (cnt < pCmd->GetDiffNbrFiles())
{
CString txt;
int i = pCmd->GetDiffNbrFiles() - cnt;
if(i == 1)
txt.FormatMessage(IDS_ONECLIENTFILEDOESNOTDIFFER);
else
txt.FormatMessage(IDS_SEVERALCLIENTFILESDONOTDIFFER_n, i);
AddToStatus(txt, SV_COMPLETION);
}
}
}
if( !chainedCommands || MainFrame()->IsQuitting() )
{
// Error, so make sure server lock is released
if(pCmd->HaveServerLock())
pCmd->ReleaseServerLock();
MainFrame()->ClearStatus();
}
delete pCmd;
return 0;
}
BOOL CDeltaTreeCtrl::DoRevert(CStringList *list, int key/*=0*/, BOOL bUnChg/*=FALSE*/)
{
BOOL chainedCommands= FALSE;
POSITION pos;
if(!list->IsEmpty()) // Some filenames in the list
{
HTREEITEM currItem=GetLastSelection();
CRevertListDlg listDlg;
listDlg.Init(list);
if(listDlg.DoModal() == IDOK)
{
// first check to see if they want to delete all unchanged files in this chg
// if so, we can do it quickly using p4 revert -a -c [chg#]
// however if there are only 1 or 2 files, we do them individually
if (!listDlg.AnyRowsDeleted() && GET_SERVERLEVEL() >= 14
&& currItem && list->GetCount() > 2)
{
CCmd_Revert *pCmd= new CCmd_Revert;
pCmd->Init( m_hWnd, RUN_ASYNC, HOLD_LOCK);
CString chgnbr;
m_EditChangeNum=GetChangeNumber(currItem);
if (m_EditChangeNum)
chgnbr.Format(_T("%ld"), m_EditChangeNum);
else
chgnbr = _T("default");
pCmd->SetChgName(chgnbr);
if( pCmd->Run( chgnbr, TRUE, TRUE, FALSE ) )
m_DoRevert=FALSE;
else
{
MainFrame()->ClearStatus();
delete pCmd;
}
}
else if(!list->IsEmpty())
{
// Copy the stringlist to our list and then delete, so we dont have
// to keep track of the list pointer and when to delete it
for(pos=list->GetHeadPosition(); pos!=NULL; )
{
CString str = list->GetNext(pos);
if (GET_SERVERLEVEL() < 14) // pre 2002.2?
{
if (str.FindOneOf(_T("@#%*")) != -1)
{
StrBuf b;
StrBuf f;
f << CharFromCString(str);
StrPtr *p = &f;
StrOps::WildToStr(*p, b);
str = CharToCString(b.Value());
}
}
else
{
int i;
if ((i = str.ReverseFind(_T('#'))) != -1)
str = str.Left(i);
}
m_StringList.AddHead(str);
}
// Then start the revert
CCmd_ListOpStat *pCmdRevert= new CCmd_ListOpStat;
pCmdRevert->Init( m_hWnd, RUN_ASYNC, HOLD_LOCK, key);
if( pCmdRevert->Run( &m_StringList, bUnChg ? P4REVERTUNCHG : P4REVERT ) )
{
MainFrame()->UpdateStatus( LoadStringResource(IDS_REVERTING_FILES) );
chainedCommands= TRUE;
}
else
delete pCmdRevert;
}
}
}
else
AddToStatus(LoadStringResource(IDS_NO_FILES_WILL_BE_REVERTED_BECAUSE), SV_WARNING);
return chainedCommands;
}
void CDeltaTreeCtrl::OnP4Reopen(CStringList *list)
{
POSITION pos;
CString fileName;
CString info;
CString temp;
BOOL isReopenByType= FALSE;
HTREEITEM item = NULL;
int imageIndex = -1;
int ix = 0;
LPARAM param;
CP4FileStats *stats;
SetRedraw(FALSE);
for(pos=list->GetHeadPosition(); pos!=NULL;)
{
// Get the 'filename#n - reopened; change x' text
// or the 'filename#n - reopened; type x' text
fileName=list->GetNext(pos);
// Find the space after filename
int separator= fileName.Find(_T(" - reopened; "));
info=fileName.Mid(separator+13);
if(info.Find(_T("type")) != -1)
{
isReopenByType= TRUE;
// Then find the file and update the file type info
int pound=fileName.ReverseFind(_T('#'));
if( pound != -1 )
fileName=fileName.Left(pound);
item=FindMyOpenFile(fileName, item);
ASSERT(item != NULL);
if(item != NULL)
{
stats= (CP4FileStats *) GetLParam(item);
stats->SetType(info.Mid(lstrlen(_T("type "))));
SetItemText(item, stats->GetFormattedChangeFile(GET_P4REGPTR()->ShowFileType(), GET_P4REGPTR()->ShowOpenAction()));
int img=TheApp()->GetFileImageIndex(stats,TRUE);
SetImage(item, img, img);
}
}
else
{
// Then find and remove the file from beneath m_DragFromChange
int i;
fileName=fileName.Left(separator);
if ((i = fileName.ReverseFind(_T('#'))) != -1)
fileName = fileName.Left(i);
item=GetChildItem(m_DragFromChange);
param=NULL;
while(item != NULL)
{
if(IsAFile(item))
{
param= GetLParam(item);
ASSERT(param != 0);
stats= (CP4FileStats *) param;
ASSERT_KINDOF(CP4FileStats, stats);
temp= stats->GetFullDepotPath();
if(temp == fileName)
{
imageIndex=GetImage(item);
stats->SetOpenChangeNum( m_DragToChangeNum );
ix = stats->IsOtherUserMyClient() ? CP4ViewImageList::VI_YOUROTHERCHANGE
: CP4ViewImageList::VI_YOURCHANGE;
// reopen and update open file info
//
if(stats->GetOtherOpens())
{
if (GET_SERVERLEVEL() < 19) // earlier than 2005.1?
{
if(stats->IsOtherLock())
stats->SetLocked(TRUE, FALSE);
stats->SetOpenAction( stats->GetOtherOpenAction(), FALSE);
stats->SetOpenAction( 0, TRUE );
stats->SetOtherUsers(_T(""));
}
imageIndex= TheApp()->GetFileImageIndex(stats, TRUE);
}
temp= stats->GetFormattedChangeFile(
GET_P4REGPTR()->ShowFileType(),
GET_P4REGPTR()->ShowOpenAction());
// Do NOT call DeltaTreeCtrl::DeleteItem() because
// that will nuke the lParam. All we want to do here
// is remove the item from the tree control.
CMultiSelTreeCtrl::DeleteItem(item);
break;
}
}
item=GetNextSiblingItem(item);
}
ASSERT(item != NULL); // just reopened an item that wasnt in tree!
// And add under m_DragToChange
if(item != NULL && imageIndex >= 0)
{
item=Insert(temp, imageIndex, param, m_DragToChange, TRUE);
// we may have to reset the icon on the dragtochange because
// the Insert() is looking at data for the drag from change
// which might have been our client/other user. But we know
// the dragtochange is ours - so force it for unresolved files.
stats= (CP4FileStats *) GetLParam(item);
if (stats->IsUnresolved())
SetImage(m_DragToChange, CP4ViewImageList::VI_YOURCHGUNRES,
CP4ViewImageList::VI_YOURCHGUNRES);
}
ASSERT(item != NULL);
}// if reopen by type or change
}
if( !isReopenByType && list->GetCount() )
{
int img;
// Make sure the source change is closed if it was just emptied
if( GetChildItem(m_DragFromChange) == NULL )
{
SetUnexpanded(m_DragFromChange);
SetChildCount(m_DragFromChange, 0);
SetLParam(m_DragFromChange, EXPAND_FOLDER);
SetImage(m_DragFromChange, ix, ix);
}
else if ((img = GetImage(m_DragFromChange)) == CP4ViewImageList::VI_YOURCHGUNRES
|| img == CP4ViewImageList::VI_YOUROTHERCHGUNRES)
{
SetCorrectChglistImage(m_DragFromChange);
}
// Make sure the target change is openable if it contains children
if( GetChildItem(m_DragToChange) != NULL )
{
SetChildCount(m_DragToChange, 1);
if (GET_P4REGPTR()->ExpandChgLists( ))
Expand(m_DragToChange, TVE_EXPAND);
}
if (m_SortByExtension || m_SortByResolveStat || m_SortByAction || m_SortByFilename)
SortTree();
}
SetRedraw(TRUE);
// Make sure all selected items got cleared and window repainted correctly
UnselectAll();
RedrawWindow();
MainFrame()->ClearStatus();
}
LRESULT CDeltaTreeCtrl::OnP4ListOp(WPARAM wParam, LPARAM lParam)
{
int key = -1;
POSITION pos;
BOOL chainedCommands=FALSE;
BOOL bNeed2Sync = FALSE;
BOOL bNeed2Revert = FALSE;
BOOL bRevertAdds = FALSE;
int iRedoOpenedFilter = 0;
CCmd_ListOpStat *pCmd= (CCmd_ListOpStat *) wParam;
if(!pCmd->GetError())
{
iRedoOpenedFilter = pCmd->GetRedoOpenedFilter();
if( pCmd->GetChkForSyncs() )
{
int rc;
key = pCmd->GetServerKey();
chainedCommands = TRUE;
if((rc = MsgBox(IDS_ONE_OR_MORE_FILES_IS_NOT_THE_HEAD_REVISION,
MB_ICONEXCLAMATION | MB_DEFBUTTON3)) == IDC_BUTTON1)
{
if(pCmd->GetRevertAdds()->GetCount())
bRevertAdds = TRUE;
else
MainFrame()->UpdateDepotandChangeViews(REDRILL, key);
}
else if (rc == IDC_BUTTON2) // Sync then edit
{
bNeed2Sync = TRUE;
bNeed2Revert = TRUE;
if(pCmd->GetRevertAdds()->GetCount())
bRevertAdds = TRUE;
}
else // (rc == IDC_BUTTON3) // Cancel
bNeed2Revert = TRUE;
}
else if( pCmd->GetSync2Head() )
{
key = pCmd->GetServerKey();
chainedCommands = TRUE;
CStringList *pSyncList = pCmd->GetUnsynced(); // the files to sync to head
SyncList2Head(pSyncList, key);
}
else if( pCmd->GetRevertAdds()->GetCount() )
{
key = pCmd->GetServerKey();
chainedCommands = TRUE;
bRevertAdds = TRUE;
}
else if( pCmd->HitMaxFileSeeks() )
{
// Too much was added for seeking out each file for an att update
// to be efficient. Just start a full update.
key = pCmd->GetServerKey();
chainedCommands = TRUE;
if (pCmd->GetRevertUnchgAfter())
{
CCmd_ListOpStat *pCmd2= new CCmd_ListOpStat;
pCmd2->Init( m_hWnd, RUN_ASYNC, HOLD_LOCK, key );
pCmd2->SetRedoOpenedFilter(pCmd->GetRedoOpenedFilter());
pCmd2->SetHitMaxFileSeeks(TRUE);
if( pCmd2->Run( &m_StringList2, P4REVERTUNCHG ) )
{
MainFrame()->UpdateStatus( LoadStringResource(IDS_REQUESTING_REVERT) );
iRedoOpenedFilter = 0;
}
else
{
delete pCmd2;
MainFrame()->UpdateDepotandChangeViews(REDRILL, key);
}
}
else
MainFrame()->UpdateDepotandChangeViews(REDRILL, key);
m_Need2Refresh = FALSE;
}
else if(pCmd->GetCommand() == P4REVERT
|| pCmd->GetCommand() == P4REVERTUNCHG
|| pCmd->GetCommand() == P4VIRTREVERT)
{
chainedCommands = OnP4RevertFile(pCmd->GetList(), TRUE,
pCmd->GetOutputErrFlag(), pCmd->GetRevertUnchgAfter(),
pCmd->GetServerKey(), pCmd->GetRedoOpenedFilter());
if (chainedCommands)
iRedoOpenedFilter = 0;
}
else if(pCmd->GetCommand() == P4REOPEN)
{
OnP4Reopen(pCmd->GetList());
}
else if(pCmd->GetCommand() == P4EDIT)
{
CStringList *pList = pCmd->GetList();
// An empty output list coming back from the server
// can occur if a file has been branched and is then
// opened for edit (which opens it for add, of course).
// So if we arrive here with an empty list, just do a
// full refresh since we have no data to work with.
if (pList->IsEmpty())
{
key = pCmd->GetServerKey();
chainedCommands = TRUE;
MainFrame()->UpdateDepotandChangeViews(REDRILL, key);
}
else OnP4EditFile(pList);
}
else
ASSERT(0);
}
// For the above commands, we do not need any ostat type
// info that CCmd_ListOpStat may have collected, so just
// delete it to avoid leakage
pCmd->DeleteStatList();
if( !chainedCommands || MainFrame()->IsQuitting() )
pCmd->ReleaseServerLock();
BOOL bOutputError = pCmd->GetOutputErrFlag();
if (bNeed2Revert || bRevertAdds)
{
m_StringList.RemoveAll();
CStringList * pNewList = 0;
CStringList * pRevertList;
CStringList * pSyncList = pCmd->GetUnsynced(); // the files to revert, then sync
CCmd_ListOpStat *pCmd2= new CCmd_ListOpStat;
if (bNeed2Sync)
pNewList = pCmd2->GetUnsynced(); // a place to save the files to sync to head
else if (bNeed2Revert)
{
pRevertList = pCmd->GetRevertIfCancel();
for( pos= pRevertList->GetHeadPosition(); pos!= NULL; )
m_StringList.AddTail( pRevertList->GetNext(pos) );
}
if (bRevertAdds)
{
pRevertList = pCmd->GetRevertAdds();
for( pos= pRevertList->GetHeadPosition(); pos!= NULL; )
m_StringList.AddTail( pRevertList->GetNext(pos) );
}
if (bNeed2Sync)
{
for( pos= pSyncList->GetHeadPosition(); pos!= NULL; )
{
CString txt = pSyncList->GetNext(pos);
m_StringList.AddTail( txt );
ASSERT(pNewList);
pNewList->AddTail( txt );
}
}
ASSERT(key != -1);
pCmd2->Init( m_hWnd, RUN_ASYNC, HOLD_LOCK, key );
if (bNeed2Sync)
pCmd2->SetSync2Head(TRUE); // they want to sync to head afterwards
else pCmd2->SetHitMaxFileSeeks(TRUE); // we will need to do a full refresh at the end
if( pCmd2->Run( &m_StringList, P4REVERT ) )
MainFrame()->UpdateStatus( LoadStringResource(IDS_REQUESTING_REVERT) );
else
delete pCmd2;
}
delete pCmd;
if (m_Need2Edit)
{
m_Need2Edit = FALSE;
::SendMessage(m_depotWnd, m_Msg2Send, (WPARAM) &m_ClientPath, m_SavelParam);
}
if (iRedoOpenedFilter)
::SendMessage(m_depotWnd, WM_REDOOPENEDFILTER, (WPARAM)iRedoOpenedFilter, 0);
else if (bOutputError)
::PostMessage(m_depotWnd, WM_COMMAND, ID_VIEW_UPDATE_LEFT, 0);
return 0;
}
void CDeltaTreeCtrl::SyncList2Head(CStringList *pSyncList, int key)
{
POSITION pos;
m_StringList.RemoveAll();
for( pos= pSyncList->GetHeadPosition(); pos!= NULL; )
m_StringList.AddTail( pSyncList->GetNext(pos) + _T("#head") );
CCmd_Get *pCmd= new CCmd_Get;
pCmd->Init( m_hWnd, RUN_ASYNC, HOLD_LOCK, key);
if( pCmd->Run( &m_StringList, FALSE, TRUE ) )
MainFrame()->UpdateStatus( LoadStringResource(IDS_FILE_SYNC) );
else
delete pCmd;
}
LRESULT CDeltaTreeCtrl::OnP4SyncAndEdit(WPARAM wParam, LPARAM lParam)
{
CCmd_Get *pCmd= (CCmd_Get *) wParam;
int i;
int key= pCmd->GetServerKey();
POSITION pos;
m_StringList.RemoveAll();
CStringList *pSyncList = pCmd->GetGetList();
for( pos= pSyncList->GetHeadPosition(); pos!= NULL; )
{
// Get the filenames to open for edit
CString txt = pSyncList->GetNext(pos);
if ((i = txt.Find(_T('#'))) != -1)
txt = txt.Left(i);
m_StringList.AddTail(txt);
}
CCmd_ListOpStat *pCmd2= new CCmd_ListOpStat;
pCmd2->Init( m_hWnd, RUN_ASYNC, HOLD_LOCK, key );
pCmd2->SetHitMaxFileSeeks(TRUE); // we will need to do a full refresh at the end
if( pCmd2->Run( &m_StringList, P4EDIT, 0 ) )
MainFrame()->UpdateStatus( LoadStringResource(IDS_OPENING_FILES_FOR_EDIT) );
else
delete pCmd2;
delete pCmd;
return 0;
}
// Message handler to allow the depot window to pass a result
// set from 'p4 revert'
LRESULT CDeltaTreeCtrl::OnP4UpdateRevert(WPARAM wParam, LPARAM lParam)
{
CStringList *list= (CStringList *) wParam;
OnP4RevertFile(list, FALSE);
return 0;
}
BOOL CDeltaTreeCtrl::OnP4RevertFile(CStringList *list, BOOL notifyDepotWnd/*=TRUE*/,
BOOL errs/*=FALSE*/, BOOL revertUnchgAfter/*=FALSE*/,
int key/*=0*/, BOOL redoOpenedFilter/*=FALSE*/)
{
POSITION pos;
CString fileName;
int pound;
// Temporarily disable redraws for both windows
SetRedraw(FALSE);
::SendMessage(m_depotWnd, WM_SETREDRAW, FALSE, 0);
for(pos=list->GetHeadPosition(); pos!=NULL;)
{
fileName=list->GetNext(pos);
// Strip revision number if present
pound=fileName.ReverseFind(_T('#'));
if(pound != -1)
fileName=fileName.Left(pound);
// Let the depot view know what happened
if(notifyDepotWnd)
::SendMessage(m_depotWnd, WM_UPDATEOPEN, (WPARAM) &fileName, 0);
// And finally, delete it from this tree
HTREEITEM item=FindMyOpenFile(fileName);
if(item != NULL)
{
HTREEITEM change= GetParentItem(item);
DeleteItem(item);
// Make sure the source change is closed if it was just emptied
if( change != NULL && GetChildItem(change) == NULL && !errs)
{
SetUnexpanded(change);
SetChildCount(change, 0);
SetLParam(change, EXPAND_FOLDER);
}
SetCorrectChglistImage(change);
}
else
ASSERT(0);
}
SetRedraw(TRUE);
::SendMessage(m_depotWnd, WM_SETREDRAW, TRUE, 0);
RedrawWindow();
::RedrawWindow( m_depotWnd, NULL, NULL, RDW_INVALIDATE );
if (revertUnchgAfter)
{
CCmd_ListOpStat *pCmd2= new CCmd_ListOpStat;
pCmd2->Init( m_hWnd, RUN_ASYNC, HOLD_LOCK, key );
pCmd2->SetNbrChgedFilesReverted(list->GetCount());
pCmd2->SetRedoOpenedFilter(redoOpenedFilter);
if( pCmd2->Run( &m_StringList2, P4REVERTUNCHG ) )
{
MainFrame()->UpdateStatus( LoadStringResource(IDS_REQUESTING_REVERT) );
return TRUE;
}
else
{
delete pCmd2;
MainFrame()->UpdateDepotandChangeViews(REDRILL, key);
}
}
else
MainFrame()->ClearStatus();
return FALSE;
}
void CDeltaTreeCtrl::OnP4EditFile(CStringList *list)
{
POSITION pos;
CString fileName;
int pound;
// Temporarily disable redraws for windows
SetRedraw(FALSE);
for(pos=list->GetHeadPosition(); pos!=NULL;)
{
fileName=list->GetNext(pos);
// Strip revision number if present
pound=fileName.ReverseFind(_T('#'));
if(pound != -1)
fileName=fileName.Left(pound);
// And finally, update the item's status
HTREEITEM item=FindMyOpenFile(fileName);
if(item != NULL)
{
CP4FileStats *newStats;
CP4FileStats *stats= (CP4FileStats *) GetLParam(item);
HTREEITEM change= GetParentItem(item);
newStats= new CP4FileStats;
newStats->Create(stats);
newStats->SetOpenAction(F_EDIT, FALSE);
DeleteItem(item);
Insert(newStats->GetFormattedChangeFile(GET_P4REGPTR()->ShowFileType(),
GET_P4REGPTR()->ShowOpenAction()),
TheApp()->GetFileImageIndex(newStats, TRUE), (LPARAM) newStats, change, TRUE);
}
else
ASSERT(0);
}
SetRedraw(TRUE);
RedrawWindow();
MainFrame()->ClearStatus();
}
// A change description was sent to the server, 'P4 change -i".
// This should be a confirming message.
LRESULT CDeltaTreeCtrl::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();
DragAcceptFiles(FALSE);
}
else
{
if (pCmd->HaveServerLock())
pCmd->ReleaseServerLock();
if( !TheApp()->m_SubmitPath.IsEmpty() )
MainFrame()->PostMessage(WM_COMMAND, ID_APP_EXIT, 0);
delete pCmd;
}
return 0;
}
LRESULT CDeltaTreeCtrl::OnP4EndSpecEdit( WPARAM wParam, LPARAM lParam )
{
CCmd_EditSpec *pCmd= (CCmd_EditSpec *) wParam;
BOOL chainedCommands=FALSE;
if (lParam != IDCANCEL && lParam != IDABORT)
{
if(pCmd->GetSpecDlgExit() == IDALTERNATE || m_EditChangeNum == 0 || pCmd->EditedLists())
{
if (TheApp()->m_SubmitPath.IsEmpty())
{
// Get the lock and start the update process w/out dropping the lock
int key= pCmd->HaveServerLock() ? pCmd->GetServerKey( ) : 0;
MainFrame()->UpdateDepotandChangeViews(REDRILL, key);
chainedCommands=TRUE;
}
CString txt;
if(pCmd->GetSpecDlgExit() == IDALTERNATE)
{
txt.FormatMessage(IDS_CHANGE_n_SUBMITTED, pCmd->GetNewChangeNum());
AddToStatus(txt, SV_COMPLETION);
MainFrame()->SetOldChgUpdateTime(0);
MainFrame()->SetJobUpdateTime(0);
}
UnselectAll();
}
else
{
if(pCmd->GetSpecDlgExit() == IDNEEDTOREFRESH)
{
// We need to do a resolve so update our internal stats
// Get the lock and start the update process w/out dropping the lock
int key= pCmd->HaveServerLock() ? pCmd->GetServerKey( ) : 0;
MainFrame()->UpdateDepotandChangeViews(REDRILL, key);
chainedCommands=TRUE;
// If we got here via a cmd line -S flag,
// restore the main window and clear the submit path
if (!TheApp()->m_SubmitPath.IsEmpty())
{
MainFrame()->ShowWindow(SW_RESTORE);
TheApp()->m_SubmitPath.Empty();
}
}
else // we need to update the screen to reflect the new description
{
// The change description is always changed, so put together the
// new item text for the change node. Note that the change number
// must be correctly formatted to avoid bungling the sort order
CString txt;
CString desctxt=PadCRs(pCmd->GetChangeDesc());
if(GET_P4REGPTR()->ShowChangeDesc())
{
int trunc = (GET_SERVERLEVEL() >= 19)
? GET_P4REGPTR()->GetUseLongChglistDesc() : 31;
CString shorttxt = TruncateString(desctxt, trunc);
txt.FormatMessage(
shorttxt == desctxt ? IDS_CHANGE_n_s
: IDS_CHANGE_n_s_TRUNC,
pCmd->GetNewChangeNum(),
shorttxt);
}
else
txt.FormatMessage(IDS_CHANGE_n, pCmd->GetNewChangeNum());
if(m_EditChangeNum == 0)
{
// The default change was edited, so rename the change, and
// insert a new default change in the tree
SetItemText(m_MyDefault, txt);
m_MyDefault=Insert(LoadStringResource(IDS_DEFAULTCHANGELISTNAME), CP4ViewImageList::VI_YOURCHANGE, NULL, m_MyRoot, TRUE);
if (!m_DragToChangeNum)
m_DragToChange=m_MyDefault;
}
else
// We just edited an existing change, so just update the
// description text
SetItemText(m_EditChange, txt);
txt.FormatMessage(IDS_CHANGE_n_UPDATED, (long) pCmd->GetNewChangeNum());
AddToStatus(txt);
}
}
}
if (lParam != IDABORT)
{
MainFrame()->ClearStatus();
if( !chainedCommands || MainFrame()->IsQuitting() )
{
if (pCmd->HaveServerLock())
pCmd->ReleaseServerLock();
if( !chainedCommands && !TheApp()->m_SubmitPath.IsEmpty() )
MainFrame()->PostMessage(WM_COMMAND, ID_APP_EXIT, 0);
}
CDialog *dlg = (CDialog *)pCmd->GetSpecSheet();
dlg->DestroyWindow();
}
delete pCmd;
m_EditInProgress = FALSE;
DragAcceptFiles(TRUE);
return 0;
}
LRESULT CDeltaTreeCtrl::OnP4ChangeDel(WPARAM wParam, LPARAM lParam)
{
CCmd_Delete *pCmd= (CCmd_Delete *) wParam;
if(!pCmd->GetError())
{
CString text=pCmd->GetCompletionData();
int offset= text.Find(_T("deleted"));
if(offset >= 7 && offset < 18)
{
// Completion looks like "Change 5000 deleted."
AddToStatus( pCmd->GetCompletionMessage(), SV_COMPLETION);
// No need to delete children since its an empty change
if (!pCmd->IgnoreActiveItem())
DeleteItem(m_ActiveItem);
// Make sure the updated window draws correctly
UnselectAll();
RedrawWindow();
}
else
{
// Completion looks like "Change 5000 has 4 open files and can't be deleted."
AddToStatus( pCmd->GetCompletionMessage(), SV_WARNING);
ASSERT(0);
}
}
delete pCmd;
MainFrame()->ClearStatus();
return 0;
}
LRESULT CDeltaTreeCtrl::OnP4Ostat(WPARAM wParam, LPARAM lParam)
{
CP4FileStats *stats;
CCmd_Ostat *pCmd= (CCmd_Ostat *) wParam;
// Get the filelist
CObArray const *array= pCmd->GetArray();
ASSERT_KINDOF(CObArray,array);
if(pCmd->GetError() || MainFrame()->IsQuitting())
{
// Something went wrong, so delete the command and the result list
if(array->GetSize() > 0)
{
for( int i=0; i < array->GetSize(); i++)
delete (CP4FileStats *) array->GetAt(i);
}
pCmd->ReleaseServerLock();
delete pCmd;
RedrawWindow();
MainFrame()->SetLastUpdateTime(UPDATE_FAILED);
MainFrame()->ClearStatus();
return 0;
}
// Change-verification parameters used to avoid searching for
// the same change repeatedly
HTREEITEM changeItem=NULL;
int lastChangeNum= -1;
CString lastOtherUser;
if(array->GetSize() > 0)
{
// Temporarily disable redraws
SetRedraw(FALSE);
BOOL needExpand=FALSE;
// Array of filestats open for Add - may need to pass this list to the Depot pane
CObList lAdds;
// then get the list contents into the tree
for( int i=0; i<array->GetSize(); i++ )
{
// Get the cursed filename
stats= (CP4FileStats *) array->GetAt(i);
if( m_ExpandingOthersRoot && ( stats->IsMyOpen() || stats->IsOtherUserMyClient() ) )
{
delete stats;
continue;
}
else if( m_ExpandingOthersRoot )
needExpand=TRUE;
// Find/create the change this file is under if the change number or user@client has changed
// Otherwise, use the cached changeItem, because verifying that a change exists is slow as
// a MUNI light rail car
if( lastChangeNum != stats->GetOpenChangeNum() || Compare(lastOtherUser, stats->GetOtherUsers()) != 0 )
{
if( !stats->IsMyOpen() && stats->GetOpenChangeNum() == 0
&& stats->GetOtherOpens() != 0)
{
// Someone else's default change; insert it without checking, because it can't be
// in the tree yet. Note this only works because CCmd_Ostat has sorted the
// results by ismyopen+changenum+user@client
changeItem=InsertChange(stats, FALSE);
}
else
changeItem=InsertChange(stats, TRUE);
lastChangeNum = stats->GetOpenChangeNum();
lastOtherUser = !lastChangeNum && stats->IsMyOpen()
? _T("") : stats->GetOtherUsers();
}
if(changeItem!=NULL)
{
// Insert the file under the change
Insert(stats->GetFormattedChangeFile(GET_P4REGPTR()->ShowFileType(), GET_P4REGPTR()->ShowOpenAction()),
TheApp()->GetFileImageIndex(stats, TRUE), (LPARAM) stats, changeItem, FALSE);
}
else
ASSERT(0);
// if we are showing local files in client tree,
// save the stats of any adds for passing to the depot pane
if ((GET_P4REGPTR( )->ShowEntireDepot( ) == SDF_LOCALTREE)
&& (stats->GetMyOpenAction() == F_ADD || stats->GetOtherOpenAction() == F_ADD
|| stats->GetMyOpenAction() == F_BRANCH || stats->GetOtherOpenAction() == F_BRANCH))
lAdds.AddTail(stats);
if ( !PumpMessages( ) || MainFrame()->IsQuitting() )
{
pCmd->ReleaseServerLock();
delete pCmd;
SetRedraw(TRUE);
::SendMessage(m_depotWnd, WM_SETREDRAW, TRUE, 0);
return 0;
}
} // for entire array
#if 0 // the if() is not quite right yet
if( m_OthersRoot && needExpand && GET_P4REGPTR()->FilterPendChgsByMyClient() )
{
// walk all other client changes and remove empty ones
HTREEITEM item= m_OthersRoot;
item=GetChildItem(item); // Search for the second level node
while(item != NULL)
{
HTREEITEM nextitem = GetNextSiblingItem(item);
HTREEITEM firstchild = GetChildItem(item);
if (!firstchild)
DeleteItem(item);
// else
// {
// CString childStr=GetItemText(firstchild);
// int ii = 0;
// }
item = nextitem;
}
}
#endif
if( m_OthersRoot && needExpand )
{
SetLParam( m_OthersRoot, FOLDER_ALREADY_EXPANDED);
Expand( m_OthersRoot, TVE_EXPAND );
}
// if there were any files opend for add
// (and we save their fstats because we are showing all local files in client tree)
// pass those fstat info to the depot pane
if (lAdds.GetCount())
::SendMessage(m_depotWnd, WM_SETADDFSTATS, (BOOL)m_ExpandingOthersRoot, (LPARAM)&lAdds);
} // if
// Expand the tree again
SetRedraw(FALSE);
SortTree();
if( !m_ExpandingOthersRoot )
{
// First time only - should we re-expand the tree to the previous execution's state?
if (m_RedoExpansion)
{
int i = 2;
m_MyRootExpanded = TRUE;
m_ExpandedItems.RemoveAll();
if ((i = m_PrevExpansion.Find(_T(','))) != -1)
{
CString txt;
CString testtext;
HTREEITEM item;
m_PrevExpansion = m_PrevExpansion.Mid(i+1);
while ((i = m_PrevExpansion.Find(_T(','))) != -1)
{
txt = _T(' ') + m_PrevExpansion.Left(i);
item=GetChildItem(m_MyRoot);
while (item)
{
testtext=GetItemText(item);
if(testtext.Find(txt) != -1)
{
m_ExpandedItems.AddTail(testtext);
break;
}
item=GetNextSiblingItem(item);
}
m_PrevExpansion = m_PrevExpansion.Mid(i+1);
}
if (!m_PrevExpansion.IsEmpty())
{
txt = _T(' ') + m_PrevExpansion;
item=GetChildItem(m_MyRoot);
while (item)
{
testtext=GetItemText(item);
if(testtext.Find(txt) != -1)
{
m_ExpandedItems.AddTail(testtext);
break;
}
item=GetNextSiblingItem(item);
}
}
}
m_RedoExpansion = FALSE;
}
UpdateTreeState(FALSE);
}
// And finally, make sure both windows redraw. This is the last step in a multi-step
// process, so it is a good place to verify that everything displays properly. These
// two lines are not inside the above if{} because we want to make sure that redraw
// is turned on, even if there are no open files
SetRedraw(TRUE);
::SendMessage(m_depotWnd, WM_SETREDRAW, TRUE, 0);
RedrawWindow();
if( !m_ExpandingOthersRoot )
{
::RedrawWindow( m_depotWnd, NULL, NULL, RDW_INVALIDATE );
MainFrame()->SetFullRefresh(FALSE);
}
MainFrame()->SetLastUpdateTime(UPDATE_SUCCESS);
pCmd->ReleaseServerLock();
MainFrame()->UpdateStatus(_T(" "));
if( m_OthersRoot && m_ExpandingOthersRoot )
{
m_ExpandingOthersRoot= FALSE;
if (!m_PositionTo.IsEmpty())
{
PositionToFileInChg(m_PositionTo, m_OthersRoot, m_OthersRoot, TRUE);
m_PositionTo.Empty();
}
}
else
{
// Notify the mainframe that we have finished dealing with changlists,
// hence the entire set of port connection async command have finished.
MainFrame()->FinishedGettingChgs(TRUE);
}
delete pCmd;
return 0;
}
// Support for fetching fixes as numbered changes are opened:
//
// 1) When changes are added via OnP4Changes() or VerifyChange(),
// they are added with LParam==0
// 2) If we have fetched the fixes info for a given numbered change,
// they have LParam==FOLDER_ALREADY_EXPANDED
BOOL CDeltaTreeCtrl::ExpandTree( const HTREEITEM item )
{
if( APP_HALTED() || !item )
return FALSE;
int lParam= GetLParam( item );
// A) See if OtherPendingChanges just got expanded for first time, and
// if so, go handle that special case
if( item == m_OthersRoot && lParam == EXPAND_FOLDER && !m_OthersRootExpanded )
return ExpandOthersRoot( );
// B) Test to see if it's a numbered change that we havent already expanded
// If it's my root and it has not been previously expanded,
// expand each of my changelists with no files to remove the
// plus sign, or show that it has only jobs
if ( item == m_MyRoot && lParam != FOLDER_ALREADY_EXPANDED )
{
ExpandEmptyChglists();
SetLParam(m_MyRoot, FOLDER_ALREADY_EXPANDED);
}
if ( item == m_MyRoot || item == m_OthersRoot || lParam == FOLDER_ALREADY_EXPANDED )
return TRUE;
// C) Get the change number, and bail if it's somebody's
// default change, since there wont be any fixes
int changeNum= GetChangeNumber(item);
if ( changeNum <= 0 )
return TRUE;
// D) And finally fire up fixes
CCmd_Fixes *pCmdFixes= new CCmd_Fixes;
pCmdFixes->Init( m_hWnd, RUN_ASYNC);
if( pCmdFixes->Run(changeNum, item) )
{
MainFrame()->UpdateStatus( LoadStringResource(IDS_UPDATING_JOB_FIXES) );
}
else
{
delete pCmdFixes;
RedrawWindow();
MainFrame()->ClearStatus();
}
return TRUE;
}
BOOL CDeltaTreeCtrl::ExpandOthersRoot()
{
// If server is busy, ignore the request
if( SERVER_BUSY() )
{
Sleep(0);
SET_BUSYCURSOR();
// wait a bit in 1/10 sec intervals to see if the prev request finishes
int t=GET_P4REGPTR()->BusyWaitTime();
do
{
Sleep(50);
t -= 50;
} while (SERVER_BUSY() && t > 0);
if( SERVER_BUSY() )
{
MessageBeep(0);
return FALSE;
}
}
CCmd_Ostat *pCmdOstat= new CCmd_Ostat;
pCmdOstat->Init( m_hWnd, RUN_ASYNC, HOLD_LOCK );
if( pCmdOstat->Run( TRUE ) )
{
MainFrame()->UpdateStatus( LoadStringResource(IDS_CHECKING_OPEN_FILES) );
m_ExpandingOthersRoot=TRUE;
return TRUE;
}
else
{
delete pCmdOstat;
return FALSE;
}
}
LRESULT CDeltaTreeCtrl::OnP4Fixes(WPARAM wParam, LPARAM lParam)
{
CCmd_Fixes *pCmd= (CCmd_Fixes *) wParam;
if(!pCmd->GetError())
{
// The fixes command has the HTREEITEM that it was launched with,
// and that item is 99.9% likely to still be valid and still point
// to the right changelist. But look up the change number anyway,
// since that 0.1% of cases may happen.
HTREEITEM item= FindChange(pCmd->GetFixedChangeNumber());
if( item != NULL )
{
SetLParam( item, FOLDER_ALREADY_EXPANDED);
if( pCmd->GetList()->GetCount() == 0 )
{
if( GetChildItem( item ) == NULL )
SetChildCount( item, 0 );
}
else
{
OnFixes( item, pCmd->GetList());
Expand( item, TVE_EXPAND );
}
}
}
MainFrame()->ClearStatus();
delete pCmd;
return 0;
}
void CDeltaTreeCtrl::OnFixes(HTREEITEM activeItem, CObList *fixes)
{
ASSERT_KINDOF(CObList,fixes);
CP4Fix *fix;
CString text;
HTREEITEM changeItem = NULL;
if( !fixes->GetCount() )
return;
// Turn off redraw and record the top item before we start, so
// we can undo any spurious scrolling before user sees it
SetRedraw(FALSE);
HTREEITEM oldTop= GetFirstVisibleItem();
POSITION pos;
for(pos= fixes->GetHeadPosition(); pos != NULL; )
{
fix=(CP4Fix *) fixes->GetNext(pos);
ASSERT_KINDOF(CP4Fix,fix);
changeItem = FindChange(fix->GetChangeNum());
if( changeItem != NULL )
{
// Insert the fix under the change
text= fix->GetJobName();
if(FindFix(fix->GetChangeNum(), fix->GetJobName()) == NULL)
Insert(text, CP4ViewImageList::VI_JOB, NULL, changeItem, TRUE);
}
delete fix;
} //for
// Make sure the target change is openable if it contains children
if( changeItem != NULL && GetChildItem(changeItem) != NULL )
{
SetChildCount(changeItem, 1);
if (GET_P4REGPTR()->ExpandChgLists( ))
Expand(changeItem, TVE_EXPAND);
}
// Scroll back to old top row, and then redraw
SetRedraw(TRUE);
if( oldTop != NULL )
ScrollToFirstItem( oldTop );
}
LRESULT CDeltaTreeCtrl::OnP4JobDel(WPARAM wParam, LPARAM lParam)
{
// A job was just deleted, so we need to verify that the
// job does not exist in this view as a fix or fixes
// wParam is an LPCTSTR that contains the job name
ASSERT((LPCTSTR) wParam != NULL && lstrlen((LPCTSTR) wParam) <256);
CString jobName= (LPCTSTR) wParam;
int compareLen=jobName.GetLength();
HTREEITEM subItem;
HTREEITEM delItem;
HTREEITEM item=GetChildItem(m_MyRoot);
while(item !=NULL)
{
subItem=GetChildItem(item);
while(subItem != NULL)
{
delItem=subItem;
subItem=GetNextSiblingItem(subItem);
if(jobName==(GetItemText(delItem)).Left(compareLen))
DeleteItem(delItem);
}
item=GetNextSiblingItem(item);
}
if (m_OthersRoot)
{
item=GetChildItem(m_OthersRoot);
while(item !=NULL)
{
subItem=GetChildItem(item);
while(subItem != NULL)
{
delItem=subItem;
subItem=GetNextSiblingItem(subItem);
if(jobName==(GetItemText(delItem)).Left(compareLen))
DeleteItem(delItem);
}
item=GetNextSiblingItem(item);
}
}
RedrawWindow();
return 0;
}
LRESULT CDeltaTreeCtrl::OnP4Fix(WPARAM wParam, LPARAM lParam)
{
CP4Fix *fix;
CString text;
HTREEITEM currentItem;
int change=0;
CCmd_Fix *pCmd= (CCmd_Fix *) wParam;
if(pCmd->IsUnfixing() && !pCmd->GetError())
{
CObList *list= pCmd->GetList();
if(list->GetCount() > 0)
{
POSITION pos= list->GetHeadPosition();
while( pos != NULL )
{
fix= (CP4Fix *) list->GetNext(pos);
// Find the fix and delete it
currentItem=FindFix(fix->GetChangeNum(), fix->GetJobName());
change= fix->GetChangeNum();
if(currentItem!=NULL)
DeleteItem(currentItem);
else
ASSERT(0); // Should have been in tree!
delete fix;
} //while
} // if
// Make sure the source change looks empty if it was just emptied
if( change > 0 )
{
HTREEITEM parentItem= FindChange( change );
if( parentItem != NULL && GetChildItem(parentItem) == NULL )
{
SetUnexpanded( parentItem );
SetChildCount( parentItem, 0);
SetLParam( parentItem, EXPAND_FOLDER );
}
}
RedrawWindow();
}
else
{
// Add new fixes to display
OnFixes(m_ActiveItem, pCmd->GetList());
RedrawWindow();
}
MainFrame()->ClearStatus();
delete pCmd;
return 0;
}
LRESULT CDeltaTreeCtrl::OnP4JobDescribe(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->SetItemName(pCmd->GetReference());
dlg->SetDescription(desc);
dlg->SetCaption( LoadStringResource(IDS_PERFORCE_FIXED_JOB_DESCRIPTION) );
dlg->SetViewType(P4JOB_SPEC);
dlg->SetShowEditBtn(!key ? TRUE : FALSE);
if (!dlg->Create(IDD_SPECDESC, this)) // display the description dialog box
{
dlg->DestroyWindow(); // some error! clean up
delete dlg;
}
}
delete pCmd;
MainFrame()->ClearStatus();
return 0;
}
LRESULT CDeltaTreeCtrl::OnP4EndJobDescribe( WPARAM wParam, LPARAM lParam )
{
CSpecDescDlg *dlg = (CSpecDescDlg *)lParam;
if (wParam == IDC_EDITIT) // which button did they click to close the box?
{
CString jobname = dlg->GetItemName();
ASSERT(!jobname.IsEmpty());
MainFrame()->EditJobSpec(&jobname);
}
dlg->DestroyWindow();
return TRUE;
}
LRESULT CDeltaTreeCtrl::OnP4UpdateOpen(WPARAM wParam, LPARAM lParam)
{
// This message is SENDMESSAGE'd by DepotView when a file's open status
// is changed. Only three types of status updates are possible:
// 1) file was locked
// 2) file was unlocked
// 3) file was opened for edit, delete, integ or branch
// The command is in lParam, and a CP4FileStats obj is in wParam
CP4FileStats *stats= (CP4FileStats *) wParam;
CP4FileStats *newStats, *oldStats;
// First step is to try finding the item
HTREEITEM item = FindMyOpenFile(stats->GetFullDepotPath());
switch(lParam)
{
case P4LOCK:
case P4UNLOCK:
if(item != NULL)
{
oldStats= (CP4FileStats *) GetLParam(item);
// update image and stats values
oldStats->SetLocked(stats->IsMyLock(), FALSE);
oldStats->SetLocked(FALSE, TRUE);
int img=TheApp()->GetFileImageIndex(oldStats, TRUE);
SetImage(item, img, img);
}
else
// How did we just lock a file that we previously did not
// have open?
ASSERT(0);
break;
case P4ADD:
case P4EDIT:
case P4DELETE:
case P4INTEG:
if(item != NULL)
{
oldStats= (CP4FileStats *) GetLParam(item);
if(stats->GetMyOpenAction() > 0) // Its in the tree and still open
{
// update image and stats values
oldStats->SetLocked(stats->IsMyLock(), FALSE);
if(stats->IsMyLock())
// If I have a lock, no other user can
oldStats->SetLocked(FALSE, TRUE);
int img=TheApp()->GetFileImageIndex(oldStats, TRUE);
if ((oldStats->GetMyOpenAction() == F_INTEGRATE)
&& (stats->GetMyOpenAction() == F_EDIT))
{
HTREEITEM change;
if(stats->GetOpenChangeNum() == m_DragToChangeNum)
change=m_DragToChange;
else
{
change= InsertChange(stats,TRUE);
m_DragToChange= change;
m_DragToChangeNum= stats->GetOpenChangeNum();
}
DeleteItem(item);
newStats= new CP4FileStats;
newStats->Create(stats);
Insert(newStats->GetFormattedChangeFile(GET_P4REGPTR()->ShowFileType(),
GET_P4REGPTR()->ShowOpenAction()),
TheApp()->GetFileImageIndex(newStats, TRUE), (LPARAM) newStats, change, TRUE);
}
else if ((lParam == P4INTEG) && stats->IsUnresolved()
&& (oldStats->GetMyOpenAction() == F_EDIT)
&& (stats->GetMyOpenAction() == F_EDIT))
{
oldStats->SetUnresolved(TRUE);
img=TheApp()->GetFileImageIndex(oldStats, TRUE);
SetImage(item, img, img);
int ix = stats->IsOtherUserMyClient() ? CP4ViewImageList::VI_YOUROTHERCHGUNRES
: CP4ViewImageList::VI_YOURCHGUNRES;
SetImage(TreeView_GetParent(m_hWnd, item), ix, ix);
}
else
SetImage(item, img, img);
}
else
{
// There is probably something wrong if we are here, because we should
// not be processing reverted files here. But if the file has no open
// action and we found it here, deleted it from the tree
if(stats->GetOtherOpenAction() == 0) // Do the delete if no one else has it open
{
ASSERT(0);
DeleteItem(item);
}
}
}
else // item not found in tree
{
// File was just opened for edit
if(stats->GetMyOpenAction() > 0)
{
HTREEITEM change;
if(stats->GetOpenChangeNum() > 0)
{
// Two ways to get here:
if(stats->GetOpenChangeNum() == m_DragToChangeNum)
// 1) we opened file as a result of drag-drop
change=m_DragToChange;
else
{
// 2) we specified the target change during an integrate command
// so we need to find the change
change= InsertChange(stats,TRUE);
// Even though this isnt a drag-drop operation, cache the change info
// into the drag-drop variables, so we dont need to do this lookup for
// every file that was just integrated
m_DragToChange= change;
m_DragToChangeNum= stats->GetOpenChangeNum();
}
}
else
{
// Two ways to get here: 1) right click on a file in depot view, or 2) drag a
// file from depot view to default change in this view
change=m_MyDefault;
}
newStats= new CP4FileStats;
newStats->Create(stats);
if (GET_SERVERLEVEL() < 19) // earlier than 2005.1?
newStats->SetOtherOpens(FALSE); // be consistent w/ data returned by ostat
Insert(newStats->GetFormattedChangeFile(GET_P4REGPTR()->ShowFileType(),
GET_P4REGPTR()->ShowOpenAction()),
TheApp()->GetFileImageIndex(newStats, TRUE), (LPARAM) newStats, change, TRUE);
if( GetChildItem(change) != NULL )
{
SetChildCount(change, 1);
if (GET_P4REGPTR()->ExpandChgLists( ))
Expand(change, TVE_EXPAND);
}
}
//else (don't assert! the likely reason we didnt find an open file under
// our changes is that the file is open by another user on my client
} // if item found
break;
default:
ASSERT(0);
} // switch(command)
if (m_SortByExtension || m_SortByResolveStat || m_SortByAction || m_SortByFilename)
m_Timer = ::SetTimer( m_hWnd, SORT_TIMER, 100, NULL );
return 0;
}
LRESULT CDeltaTreeCtrl::OnP4SetUnresolved(WPARAM wParam, LPARAM lParam)
{
// This message is SENDMESSAGE'd by DepotView when an open file is gotten
// at a different revision.
// Find the file
CP4FileStats *stats= (CP4FileStats *) wParam;
HTREEITEM item=FindMyOpenFile(stats->GetFullDepotPath());
if(item != NULL)
{
// Found it, so see if unresolved
CP4FileStats *oldStats= (CP4FileStats *) GetLParam(item);
if(oldStats->GetHaveRev() < stats->GetHaveRev())
oldStats->SetUnresolved(TRUE);
oldStats->SetHaveRev(stats->GetHaveRev());
int img=TheApp()->GetFileImageIndex(oldStats, TRUE);
// And update image and text
SetImage(item, img, img);
SetItemText(item, oldStats->GetFormattedChangeFile(GET_P4REGPTR()->ShowFileType(), GET_P4REGPTR()->ShowOpenAction()));
SetCorrectChglistImage(TreeView_GetParent(m_hWnd, item));
}
// else
// Not a fatal error, could just be that our instance of
// the gui doesnt yet have this item in the changes window
//ASSERT(0);
return 0;
}
// Get a list of all of my open changes
LRESULT CDeltaTreeCtrl::OnGetMyChangesList(WPARAM wParam, LPARAM lParam)
{
CStringList *list= (CStringList *) wParam;
ASSERT_KINDOF(CStringList,list);
GetMyChangesList(list);
return 0;
}
HTREEITEM CDeltaTreeCtrl::FindChange(long changeNum)
{
HTREEITEM item, currentItem;
// Directly assign the root node
currentItem= m_MyRoot;
// Search for the second level node
item=GetChildItem(currentItem);
if(item != NULL) // there is at least one child
{
while(GetChangeNumber(item) != changeNum)
{
item=GetNextSiblingItem(item);
if(item==NULL)
break;
}
}
if(item != NULL)
return item; // node exists - return the HTREEITEM
if (m_OthersRoot)
{
// Directly assign the root node
currentItem= m_OthersRoot;
// Search for the second level node
item=GetChildItem(currentItem);
if(item != NULL) // there is at least one child
{
while(GetChangeNumber(item) != changeNum)
{
item=GetNextSiblingItem(item);
if(item==NULL)
break;
}
}
}
// return the item if found, otherwise will return NULL
return item;
}
HTREEITEM CDeltaTreeCtrl::FindFix(long changeNum, LPCTSTR jobName)
{
HTREEITEM change= FindChange(changeNum);
if(change == NULL)
return NULL;
HTREEITEM item= GetChildItem(change);
CString temp;
while(item != NULL)
{
if(!IsAFile(item))
{
temp= GetItemText(item);
temp.TrimLeft(); // lose the leading space
if(temp.Compare(jobName)==0)
break;
}
item=GetNextSiblingItem(item);
}
return item;
}
HTREEITEM CDeltaTreeCtrl::FindMyOpenFile(LPCTSTR fileName, HTREEITEM lastfound/*=NULL*/)
{
// Search for a filename (no rev#)
int fileNameLen = lstrlen(fileName);
if (lastfound) // we have a guess as to where to start looking - check the next item
{
HTREEITEM subItem=GetNextSiblingItem(lastfound);
if (subItem)
{
CString subItemText= GetItemText(subItem);
int subItemTextLen= subItemText.ReverseFind(_T('#'));
if( fileNameLen == subItemTextLen &&
!lstrcmp(fileName, GetItemText(subItem).Left(fileNameLen)) )
return subItem;
}
}
BOOL found=FALSE;
HTREEITEM subItem = NULL;
HTREEITEM item=GetChildItem(m_MyRoot);
while(item !=NULL && !found)
{
subItem=GetChildItem(item);
while(subItem != NULL)
{
// Compare the fileName with the portion of the
// item text that precedes the revision '#'
CString subItemText= GetItemText(subItem);
int subItemTextLen= subItemText.ReverseFind(_T('#'));
if( fileNameLen == subItemTextLen &&
!lstrcmp(fileName, GetItemText(subItem).Left(fileNameLen)) )
{
found=TRUE;
break;
}
subItem=GetNextSiblingItem(subItem);
}
item=GetNextSiblingItem(item);
}
if(found)
return subItem;
else
return NULL;
}
HTREEITEM CDeltaTreeCtrl::FindItemByText(LPCTSTR text)
{
// Search for text
BOOL found=FALSE;
CString testtext;
HTREEITEM item=GetChildItem(m_MyRoot);
while(item !=NULL && !found)
{
testtext=GetItemText(item);
if(lstrcmp(text, testtext) == 0)
{
found=TRUE;
break;
}
item=GetNextSiblingItem(item);
}
if(!found && m_OthersRoot)
{
item=GetChildItem(m_OthersRoot);
while(item !=NULL && !found)
{
testtext=GetItemText(item);
if(lstrcmp(text, testtext) == 0)
{
found=TRUE;
break;
}
item=GetNextSiblingItem(item);
}
}
if(found)
return item;
else
return NULL;
}
// InsertChange()
// Insert the change associated with the given file. Optionally search for that
// change and skip the insert if it is found. Return tree node for the change.
HTREEITEM CDeltaTreeCtrl::InsertChange(CP4FileStats *stats, BOOL searchFirst /*=TRUE*/)
{
HTREEITEM item, currentItem;
int imageIndex;
BOOL sort = FALSE;
// Directly assign the root node, based on change category
if( stats->IsOtherUserMyClient() )
{
currentItem= m_MyRoot;
imageIndex = CP4ViewImageList::VI_YOUROTHERCHANGE;
}
else if(stats->IsMyOpen())
{
currentItem= m_MyRoot;
imageIndex = CP4ViewImageList::VI_YOURCHANGE;
}
else if( m_OthersRoot )
{
currentItem= m_OthersRoot;
imageIndex = CP4ViewImageList::VI_THEIRCHANGE;
}
else return NULL;
// Format the text for the second level node
CString changeName;
int changeNumber;
if((changeNumber = stats->GetOpenChangeNum())==0)
{
if(stats->IsMyOpen() && !stats->IsOtherUserMyClient())
changeName.FormatMessage(IDS_CHANGE_DEFAULT);
else if(GET_P4REGPTR()->SortChgsByUser())
changeName.FormatMessage(IDS_CHANGE_USER_s_DEFAULT, stats->GetOtherUsers());
else
changeName.FormatMessage(IDS_CHANGE_DEFAULT_USER_s, stats->GetOtherUsers());
}
else
{
if(stats->IsMyOpen() && !stats->IsOtherUserMyClient())
changeName.FormatMessage(IDS_CHANGE_n, changeNumber);
else
{
if (GET_P4REGPTR()->SortChgsByUser())
changeName.FormatMessage(IDS_CHANGE_USER_s_n, stats->GetOtherUsers(), changeNumber);
else
changeName.FormatMessage(IDS_CHANGE_n_USER_s, changeNumber, stats->GetOtherUsers());
}
}
if( searchFirst )
{
// Search for the second level node
item=GetChildItem(currentItem);
if(item != NULL) // there is at least one child
{
while(_tcsncmp(GetItemText(item), changeName, changeName.GetLength()) != 0)
{
item=GetNextSiblingItem(item);
if(item==NULL)
break;
}
}
if(item != NULL)
{
if (m_DragToChangeNum == changeNumber)
m_DragToChange = item;
return item; // node exists - return the HTREEITEM
}
sort = TRUE; // node doesn't exists - fall thru to insert it and sort the tree
if (changeNumber && (changeNumber==m_NewChgNbr)
&& !m_NewDesc.IsEmpty() && GET_P4REGPTR()->ShowChangeDesc())
{
CString desctxt=PadCRs(m_NewDesc);
int trunc = (GET_SERVERLEVEL() >= 19) ? GET_P4REGPTR()->GetUseLongChglistDesc() : 31;
CString shorttxt = TruncateString(desctxt, trunc);
changeName.FormatMessage(shorttxt == desctxt ? IDS_CHANGE_n_s
: IDS_CHANGE_n_s_TRUNC,
changeNumber, shorttxt);
}
}
item = Insert( changeName, imageIndex, 0, currentItem, sort);
if (m_DragToChangeNum == changeNumber)
m_DragToChange = item;
return item; // return the HTREEITEM
}
HTREEITEM CDeltaTreeCtrl::Insert(LPCTSTR text, int imageIndex, LPARAM lParam,
HTREEITEM hParent, BOOL sort)
{
XTRACE(_T("CDeltaTreeCtrl::Insert txt=%s\n"), text);
if( lParam > 0 )
{
CP4FileStats *fs= (CP4FileStats *) lParam;
if (fs->IsUnresolved())
{
int ix = fs->IsOtherUserMyClient() ? CP4ViewImageList::VI_YOUROTHERCHGUNRES
: CP4ViewImageList::VI_YOURCHGUNRES;
SetImage(hParent, ix, ix);
}
}
// Add an entry to the tree
TV_INSERTSTRUCT tree_insert;
tree_insert.hInsertAfter= sort ? TVI_SORT : TVI_FIRST;
tree_insert.hParent=hParent;
tree_insert.item.mask= TVIF_TEXT | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
tree_insert.item.iImage=imageIndex;
tree_insert.item.lParam=lParam;
tree_insert.item.iSelectedImage=imageIndex;
tree_insert.item.pszText=const_cast<LPTSTR>(text);
tree_insert.item.cchTextMax=lstrlen(text);
return(InsertItem(&tree_insert));
}
void CDeltaTreeCtrl::OnUpdateSortChgFilesByName(CCmdUI* pCmdUI)
{
pCmdUI->Enable(!SERVER_BUSY());
pCmdUI->SetCheck(GET_P4REGPTR()->SortChgFilesByName());
}
void CDeltaTreeCtrl::OnUpdateSortChgFilesByExt(CCmdUI* pCmdUI)
{
pCmdUI->Enable(!SERVER_BUSY());
pCmdUI->SetCheck(GET_P4REGPTR()->SortChgFilesByExt());
}
void CDeltaTreeCtrl::OnUpdateSortChgFilesByAction(CCmdUI* pCmdUI)
{
pCmdUI->Enable(!SERVER_BUSY());
pCmdUI->SetCheck(GET_P4REGPTR()->SortChgFilesByAction());
}
void CDeltaTreeCtrl::OnSortChgFilesByName()
{
m_SortByFilename = !GET_P4REGPTR()->SortChgFilesByName();
GET_P4REGPTR()->SetSortChgFilesByName( m_SortByFilename );
::SendMessage(m_depotWnd, WM_COMMAND, ID_VIEW_UPDATE_LEFT, 0);
}
void CDeltaTreeCtrl::OnSortChgFilesByExt()
{
m_SortByExtension = !GET_P4REGPTR()->SortChgFilesByExt();
GET_P4REGPTR()->SetSortChgFilesByExt( m_SortByExtension );
::SendMessage(m_depotWnd, WM_COMMAND, ID_VIEW_UPDATE_LEFT, 0);
}
void CDeltaTreeCtrl::OnSortChgFilesByAction()
{
m_SortByAction = !GET_P4REGPTR()->SortChgFilesByAction();
GET_P4REGPTR()->SetSortChgFilesByAction( m_SortByAction );
::SendMessage(m_depotWnd, WM_COMMAND, ID_VIEW_UPDATE_LEFT, 0);
}
void CDeltaTreeCtrl::OnUpdateSortChgFilesByResolve(CCmdUI* pCmdUI)
{
pCmdUI->Enable(!SERVER_BUSY());
pCmdUI->SetCheck(GET_P4REGPTR()->SortChgFilesByResolve());
}
void CDeltaTreeCtrl::OnSortChgFilesByResolve()
{
m_SortByResolveStat = !GET_P4REGPTR()->SortChgFilesByResolve();
GET_P4REGPTR()->SetSortChgFilesByResolve( m_SortByResolveStat );
SortTree();
}
void CDeltaTreeCtrl::OnUpdateSortChgsByUser(CCmdUI* pCmdUI)
{
pCmdUI->Enable(!SERVER_BUSY() && GET_P4REGPTR()->GetEnablePendingChgsOtherClients());
pCmdUI->SetCheck(GET_P4REGPTR()->SortChgsByUser());
}
void CDeltaTreeCtrl::OnSortChgsByUser()
{
BOOL sortChgsByUser = !GET_P4REGPTR()->SortChgsByUser();
GET_P4REGPTR()->SetSortChgsByUser( sortChgsByUser );
::SendMessage(m_depotWnd, WM_COMMAND, ID_VIEW_UPDATE_LEFT, 0);
}
LRESULT CDeltaTreeCtrl::OnP4Change(WPARAM wParam, LPARAM lParam)
{
XTRACE(_T("OnP4Change() wParam=%ld lParam=%ld\n"), wParam, lParam);
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->IsPending())
{
HTREEITEM item;
if(change->IsMyChange())
{
// Its my client, but maybe not my user
if( Compare( change->GetUser(), GET_P4REGPTR()->GetMyID()) == 0 )
item=Insert(change->GetFormattedChange(GET_P4REGPTR()->ShowChangeDesc(),
GET_P4REGPTR()->SortChgsByUser()),
CP4ViewImageList::VI_YOURCHANGE, NULL, m_MyRoot, TRUE);
else
item=Insert(change->GetFormattedChange(GET_P4REGPTR()->ShowChangeDesc(),
GET_P4REGPTR()->SortChgsByUser()),
CP4ViewImageList::VI_YOUROTHERCHANGE, NULL, m_MyRoot, TRUE);
}
else if (m_OthersRoot)
{
item=Insert(change->GetFormattedChange(GET_P4REGPTR()->ShowChangeDesc(),
GET_P4REGPTR()->SortChgsByUser()),
CP4ViewImageList::VI_THEIRCHANGE, NULL, m_OthersRoot, TRUE);
}
else item = NULL;
if( change->GetChangeNumber() > 0 && item )
SetChildCount( item, 1 );
}
delete change;
}
SetRedraw(TRUE);
delete list;
}
else
{
CCmd_Changes *pCmd= (CCmd_Changes *) wParam;
ASSERT_KINDOF(CCmd_Changes,pCmd);
if(pCmd->GetError() || MainFrame()->IsQuitting())
{
MainFrame()->ClearStatus();
MainFrame()->SetLastUpdateTime(UPDATE_FAILED);
pCmd->ReleaseServerLock();
}
else
{
int key= pCmd->GetServerKey( );
CCmd_Ostat *pCmdOstat= new CCmd_Ostat;
pCmdOstat->Init( m_hWnd, RUN_ASYNC, HOLD_LOCK, key);
// Only run 'p4 opened -a' if other pending changes root was expanded at
// the time the refresh was initiated
if( pCmdOstat->Run( m_OthersRoot && m_OthersRootExpanded ) )
{
MainFrame()->UpdateStatus( LoadStringResource(IDS_CHECKING_OPEN_FILES) );
MainFrame()->SetDeltaUpdateTime(GetTickCount());
}
else
{
delete pCmdOstat;
MainFrame()->ClearStatus();
pCmd->ReleaseServerLock();
MainFrame()->SetLastUpdateTime(UPDATE_FAILED);
}
}
delete pCmd;
}
return 0;
}
DROPEFFECT CDeltaTreeCtrl::OnDragEnter(COleDataObject* pDataObject, DWORD dwKeyState, CPoint point)
{
STGMEDIUM stg;
m_DropEffect=DROPEFFECT_NONE;
m_DragDataFormat=0;
m_DragLastOver=NULL;
m_DragLastHighlite=NULL;
CString fname;
// Dont allow a drop if the server is busy, since a drop immediately attempts to
// invoke a server command
if(SERVER_BUSY() || m_EditInProgress)
return DROPEFFECT_NONE;
m_DeltaIsDropTarget = TRUE;
if(pDataObject->IsDataAvailable( (unsigned short) m_CF_DELTA))
{
// Set the display of the drag-from items
m_DropEffect=DROPEFFECT_MOVE;
m_DragDataFormat=m_CF_DELTA;
}
else if(pDataObject->IsDataAvailable( (unsigned short) m_CF_DEPOT))
{
m_DragFromChange=NULL;
m_DropEffect=DROPEFFECT_COPY;
m_DragDataFormat=m_CF_DEPOT;
}
else if(pDataObject->IsDataAvailable( (unsigned short) m_CF_JOB))
{
m_DragFromChange=NULL;
m_DropEffect=DROPEFFECT_COPY;
m_DragDataFormat=m_CF_JOB;
}
else if(pDataObject->GetData(CF_HDROP, &stg, NULL))
{
if(stg.tymed==TYMED_HGLOBAL)
{
// Note: df.pFiles is offset in bytes to LPCWSTR filename list, a sequence of
// wide char null terminated strings followed by an additional null char
void *buf=GlobalLock(stg.hGlobal);
_DROPFILES *df=(DROPFILES *) buf;
if(df->fWide)
{
// NT uses wide char set for file drag-drop
fname=(LPCWSTR) ((char *)buf+df->pFiles); // points to first filename
}
else
{
// NT-lite uses single byte chars for file drag-drop
fname=(LPCSTR) ((char *)buf+df->pFiles); // points to first filename
}
// Perform a crude check on string to see if it looks like a filename
if(fname[1] == ':')
{
m_DropEffect=DROPEFFECT_COPY;
m_DragDataFormat=CF_HDROP;
}
else if ((fname[0] == '\\') && (fname[1] == '\\'))
{
m_DropEffect = DROPEFFECT_NONE; // we don't handle UNC filename yet, so ignore it
}
else
{
AddToStatus(LoadStringResource(IDS_DATA_WAS_NOT_CF_HDROP_FILES), SV_ERROR);
AddToStatus(fname, SV_ERROR);
}
GlobalUnlock(buf);
}
else
AddToStatus(LoadStringResource(IDS_NO_GLOBAL_CF_HDROP_DATA_RECEIVED), SV_ERROR);
ReleaseStgMedium(&stg);
m_DragFromChange=NULL;
}
else
AddToStatus(LoadStringResource(IDS_UNEXPECTED_CLIPBOARD_FORMAT));
m_DeltaIsDropTarget = FALSE;
return m_DropEffect;
}
void CDeltaTreeCtrl::OnDragLeave()
{
m_PendingDeselect=FALSE;
// Undo drop target highlite, if any
SelectDropTarget(NULL);
}
DROPEFFECT CDeltaTreeCtrl::OnDragOver(COleDataObject* pDataObject, DWORD dwKeyState, CPoint point)
{
BOOL isDeltaWndDrag= pDataObject->IsDataAvailable( (unsigned short) m_CF_DELTA);
if( isDeltaWndDrag )
{
// Left-drag support. Dont clear pending deselect until the cursor
// actually moves!
CPoint pt= point;
ClientToScreen( &pt );
if( !m_DragSourceRect.PtInRect( pt ) )
m_PendingDeselect=FALSE;
}
// If there are valid files to drop, drop effect is DROPEFFECT_COPY
// Where is the drag?
TV_HITTESTINFO hitTest;
hitTest.pt=point;
hitTest.flags=TVHT_ONITEM|TVHT_ONITEMRIGHT;
HitTest(&hitTest);
// Dont allow a drop if the server is busy, since a drop immediately attempts to
// invoke a server command
if(SERVER_BUSY())
{
m_DragLastOver=NULL;
SelectDropTarget(NULL);
return DROPEFFECT_NONE;
}
// Same as last time?
if(hitTest.hItem == m_DragLastOver && hitTest.hItem != NULL )
return m_DropEffect;
// Find which item gets the drop highlite
HTREEITEM dropItem;
if( hitTest.hItem == m_MyRoot )
{
// Crack open the root to show default change if reqd
EnsureVisible(m_MyDefault);
dropItem=m_MyDefault;
}
else if( hitTest.hItem == NULL )
dropItem=NULL;
else
{
if( IsMyPendingChange(hitTest.hItem ) )
// Its my change, so its drop-able
dropItem=hitTest.hItem;
else if( IsMyPendingChangeFile( hitTest.hItem ) )
// Its within my change - drop-able on that change
dropItem=GetParentItem(hitTest.hItem);
else
dropItem=NULL;
}
// Finally, make sure we dont show a drop highlite if its a file being dragged
// fromt the current change to the current change
if(m_DragFromChange == dropItem)
dropItem=NULL;
// Update the highlited item. If highlite item is NULL, any highlite is cleared
if(m_DragLastHighlite != dropItem)
{
m_DragLastHighlite=dropItem;
SelectDropTarget(m_DragLastHighlite);
}
return m_DropEffect;
}
int CDeltaTreeCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CMultiSelTreeCtrl::OnCreate(lpCreateStruct) == -1)
return -1;
SetIndent(15);
SetScrollTime(10);
SetImageList( TheApp()->GetImageList(), TVSIL_NORMAL );
// Register that we accept file mangler files
DragAcceptFiles(TRUE);
return 0;
}
// Files can be added three ways:
// Method 1) Drop from MS Exploder - handled in this::OnDrop()
// Method 2) File-AddToSourceControl on menu
// Method 3) Drop from File Mangler - see this::OnDropFiles()
//
// Provide a public member to take the added files from methods 2 and 3
void CDeltaTreeCtrl::AddFileList(int changeNum, CStringList *list, BOOL bDropped/*=FALSE*/)
{
int key=0;
if(SERVER_BUSY() || m_EditInProgress || !GET_SERVER_LOCK(key))
{
if (m_EditInProgress)
CantDoItRightNow(IDS_ADDEDIT_FILE);
else
ASSERT(0);
return;
}
ASSERT_KINDOF(CStringList, list);
ASSERT(changeNum >= 0);
MainFrame()->ClearStatus();
CStringList demangledList;
// Demangle the file list
POSITION pos= list->GetHeadPosition();
while(pos != NULL)
demangledList.AddHead(DemanglePath(list->GetNext(pos)));
m_DragToChangeNum= changeNum;
m_DragToChange= FindChange(changeNum);
CString changeTxt;
if(changeNum)
changeTxt.Format(_T("%ld"), changeNum);
else
changeTxt = LoadStringResource(IDS_DEFAULTCHANGELISTNAME);
// Get a list of my changes
CStringList changeList;
GetMyChangesList(&changeList);
CAddListDlg dlg;
dlg.Init(&demangledList, &changeList, changeTxt, bDropped, key);
if(dlg.DoModal() != IDCANCEL)
{
int action = dlg.GetAction();
// Get a copy of the file list, since the list that the
// dialog has will go out of scope while Cmd_Add runs
CStringList *enumList= dlg.GetEnumeratedList();
m_StringList.RemoveAll();
POSITION pos= enumList->GetHeadPosition();
while (pos != NULL)
{
CString filename = enumList->GetNext(pos);
if ((action == 3) && (filename.FindOneOf(_T("@#%")) != -1))
{
StrBuf b;
StrBuf f;
f << CharFromCString(filename);
StrPtr *p = &f;
StrOps::WildToStr(*p, b);
filename = CharToCString(b.Value());
}
m_StringList.AddHead(filename);
}
m_DragToChangeNum = dlg.GetSelectedChange();
m_DragToChange = m_DragToChangeNum ? FindChange(m_DragToChangeNum) : m_MyDefault;
if (action == 3)
{
// Start the delete operation
CCmd_ListOpStat *pCmd= new CCmd_ListOpStat;
pCmd->Init( m_depotWnd, RUN_ASYNC, HOLD_LOCK, key );
if( pCmd->Run( &m_StringList, P4DELETE, m_DragToChangeNum ) )
MainFrame()->UpdateStatus( LoadStringResource(IDS_REQUESTING_DELETE) );
else
delete pCmd;
}
else
{
// Start the add and/or edit operation(s)
CCmd_Add *pCmd= new CCmd_Add;
pCmd->Init(m_hWnd, RUN_ASYNC, HOLD_LOCK, key);
pCmd->SetOpenAction(action);
pCmd->SetHitMaxFileSeeks(m_DragToChange ? dlg.GetNeed2Refresh() : TRUE);
if( pCmd->Run( m_DragToChangeNum, &m_StringList ) )
MainFrame()->UpdateStatus( LoadStringResource(IDS_ADDING_FILES) );
else
delete pCmd;
}
}
else
RELEASE_SERVER_LOCK(key);
}
// File mangler file drop
void CDeltaTreeCtrl::OnDropFiles(HDROP hDropInfo)
{
TCHAR buf[1024];
UINT bufsize=1024;
UINT index=0xFFFFFFFF;
CStringList list;
// m_LastDragDropTime contains the time the last drag from this window was dropped.
// If the current time is REALLY CLOSE (1/2 second) to the same time as when that
// drop was done, then OnDropFiles() is being called as a result of that drop and
// we don't have anything to do because this is NOT a drop from File Mangler,
// so just return and don't try to add files.
// However, if m_LastDragDropTime is not close to the current time, this is a drop
// from an external window (probably File Mangler) and we need to add the files that
// were dropped.
if ((m_LastDragDropTime + 500) > GetTickCount())
return;
POINT pt;
if(!DragQueryPoint(hDropInfo, &pt))
return; // got dropped outside client area
// Use pt to mark where the drop was
m_DragToPoint.x = pt.x;
m_DragToPoint.y = pt.y;
ClientToScreen(&m_DragToPoint);
// Get the item from the tree
m_DragToChange = GetDropHilightItem();
if (m_DragToChange != NULL)
m_DragToChangeNum = GetChangeNumber(m_DragToChange);
else
{
m_DragToChangeNum = 0;
m_DragToChange = m_MyDefault;
}
XTRACE(_T("OnDropFiles change=%d\n"), m_DragToChangeNum);
// Get the actual file list
UINT numFiles=DragQueryFile(hDropInfo, index, buf, bufsize);
for(index=0; index<numFiles; index++)
{
DragQueryFile(hDropInfo, index, buf, bufsize);
list.AddHead(buf);
}
// Release the memory allocated for the drag-drop operation
DragFinish(hDropInfo);
// And perform the add operation
if(numFiles > 0)
AddFileList(m_DragToChangeNum, &list, TRUE);
}
BOOL CDeltaTreeCtrl::OnDrop(COleDataObject* pDataObject, DROPEFFECT dropEffect, CPoint point)
{
STGMEDIUM stg;
BOOL success=FALSE;
CString fname;
HTREEITEM item;
if(SERVER_BUSY() || m_EditInProgress)
{
// OnDragEnter() and OnDragOver() should avoid a drop at
// the wrong time!
ASSERT(0);
return FALSE;
}
// OnDragOver has already updated current selection
m_DragToPoint.x=point.x;
m_DragToPoint.y=point.y;
ClientToScreen(&m_DragToPoint);
m_DragToChange=GetDropHilightItem();
if(m_DragToChange !=NULL)
m_DragToChangeNum=GetChangeNumber(m_DragToChange);
else
{
m_DragToChangeNum=0;
m_DragToChange=m_MyDefault;
}
XTRACE(_T("OnDrop change=%d\n"), m_DragToChangeNum);
m_DeltaIsDropTarget = TRUE;
if(m_DragDataFormat == m_CF_DELTA)
{
// File(s) and or job(s) being being moved from one change to here
if(m_DragLastHighlite == NULL)
success=TRUE; // No work to do since dropped into originating change (but must say we did work to prevent unnecessary fstat!)
else
{
// Build a list of changes and a list of jobs
m_DroppedFileList.RemoveAll();
m_DroppedJobList.RemoveAll();
for(int i=GetSelectedCount()-1; i>=0; i--)
{
item=GetSelectedItem(i);
if(!IsAFile(item))
m_DroppedJobList.AddHead(GetItemText(item));
else
{
fname=GetItemText(item);
fname=fname.Left(fname.ReverseFind(_T('#')));
m_DroppedFileList.AddHead(fname);
}
}
PostMessage(WM_GOTMOVELISTS, 0, 0);
success=TRUE;
}
}
else if (m_DragDataFormat == m_CF_DEPOT)
{
// File(s) being added from depot to this window - work will be done by
// CDepotView. But do let CDepotView know it was dropped in CDeltaTreeCtrl.
::SendMessage(m_depotWnd, WM_DROPTARGET, PENDINGCHG,
MAKELPARAM(m_DragToPoint.x, m_DragToPoint.y));
success=TRUE;
}
else if (m_DragDataFormat == m_CF_JOB)
{
m_EditChangeNum = m_DragToChangeNum;
if (m_EditChangeNum)
{
CStringList jobnames;
jobnames.AddHead(MainFrame()->GetDragFromJob());
AddJobFixes(&jobnames, NULL);
success=TRUE;
}
else
{
AddToStatus(LoadStringResource(IDS_CANT_ADD_JOB_TO_DEFAULT_CHG), SV_WARNING);
success=FALSE;
}
}
else if(m_DragDataFormat == CF_HDROP)
{
m_DroppedFileList.RemoveAll();
// Its a list of files from MS Exploder
if(pDataObject->GetData(CF_HDROP, &stg, NULL))
{
if(stg.tymed==TYMED_HGLOBAL)
{
// Notes:
// 1) df.pFiles is offset in bytes to LPCWSTR filename list, a sequence of
// wide char null terminated strings followed by an additional null char
// 2) fortunately, CString assignment operator will eat unicode and conver to chars
// 3) just grab the info and then release the drag operation so exploder isnt frozen
// a WM_GOTDROPLIST posted back to ourselves handles the list processing
void *buf=GlobalLock(stg.hGlobal);
_DROPFILES *df=(DROPFILES *) buf;
MainFrame()->UpdateStatus( LoadStringResource(IDS_ENUMERATING_FILES), TRUE );
// NT and Win95 will provide unicode and bytechars, respectively, for drop list
if(df->fWide)
{
LPCWSTR tPtr=(LPCWSTR) ((char *)buf+df->pFiles); // points to first filename
while(*tPtr != 0) // Not at double null terminator
{
// Add to list, do NOT recurse directories here so gui doesnt
// get frozen w/ large recurse operations
#ifdef UNICODE
fname=tPtr;
tPtr += lstrlen(tPtr)+1;
#else
int bufSize = WideCharToMultiByte(CP_ACP, 0, tPtr, -1, 0, 0, 0, 0);
LPTSTR buf = fname.GetBufferSetLength(bufSize);
WideCharToMultiByte(CP_ACP, 0, tPtr, -1, buf, bufSize, 0, 0);
fname.ReleaseBuffer();
tPtr += wcslen(tPtr)+1;
#endif
m_DroppedFileList.AddHead(fname);
}
}
else
{
LPCSTR tPtr=(LPCSTR) ((char *)buf+df->pFiles); // points to first filename
while(*tPtr != 0) // Not at double null terminator
{
// Add to list, do NOT recurse directories here so gui doesnt
// get frozen w/ large recurse operations
fname=tPtr;
m_DroppedFileList.AddHead(fname);
tPtr+=(fname.GetLength()+1); // Advance a number of wide chars
}
}
success=TRUE;
}
ReleaseStgMedium(&stg);
// Post a message so we can return from this OLE nightmare
// before processing the file list
if(m_DroppedFileList.GetCount())
PostMessage(WM_OLEADDFILES, 0, 0);
else
MainFrame()->ClearStatus();
}
}
else
ASSERT(0); // Dropped unknown data somehow
m_DeltaIsDropTarget = FALSE;
// Dont leave drop target selected
SelectDropTarget(NULL);
return success;
}
// A message handler to queue file enumeration work after an OLE drag-drop
// operation, allowing the OLE operation to complete before we start this
LRESULT CDeltaTreeCtrl::OnOLEAddFiles(WPARAM wParam, LPARAM lParam)
{
AddFileList( m_DragToChangeNum, &m_DroppedFileList, TRUE);
return 0;
}
LRESULT CDeltaTreeCtrl::OnGotMoveLists(WPARAM wParam, LPARAM lParam)
{
if(m_DroppedJobList.GetCount() > 0)
{
AfxMessageBox(IDS_UNABLE_TO_DRAG_JOBS_BETWEEN_CHANGES, MB_ICONINFORMATION);
}
if(m_DroppedFileList.GetCount() > 0)
{
CCmd_ListOpStat *pCmd= new CCmd_ListOpStat;
pCmd->Init( m_hWnd, RUN_ASYNC, HOLD_LOCK );
if (m_Need2Refresh)
pCmd->SetHitMaxFileSeeks(TRUE); // we will need to do a full refresh at the end
if( pCmd->Run( &m_DroppedFileList, P4REOPEN, m_DragToChangeNum ) )
MainFrame()->UpdateStatus( LoadStringResource(IDS_REOPENING_FILES) );
else
delete pCmd;
}
return 0;
}
BOOL CDeltaTreeCtrl::OnScroll(UINT nScrollCode, UINT nPos, BOOL bDoScroll, BOOL *bScrolled)
{
BYTE vScroll = HIBYTE(nScrollCode);
if(m_DropEffect==DROPEFFECT_COPY || m_DropEffect==DROPEFFECT_MOVE)
{
if(vScroll==0) // LINEUP
{
*bScrolled = ScrollTree(1);
return TRUE;
}
else if(vScroll==1) //LINEDOWN
{
*bScrolled = ScrollTree(-1);
return TRUE;
}
}
return FALSE;
}
// Utility function to fill a stringlist with the names
// of all of My Changes, for use in file add and integrate dialogs
void CDeltaTreeCtrl::GetMyChangesList(CStringList *changeList)
{
if (m_EditInProgress)
{
changeList->AddHead(LoadStringResource(IDS_DEFAULTCHANGELISTNAME));
return;
}
CString changeLabel = LoadStringResource(IDS_CHANGE);
int lgthChgLabel = changeLabel.GetLength();
HTREEITEM item=GetChildItem(m_MyRoot);
while(item !=NULL)
{
CString changeName= GetItemText(item);
if(changeName.Find(changeLabel)!= -1)
{
changeName=changeName.Mid(lgthChgLabel);
changeName.TrimLeft();
int blank=changeName.Find(_T(' '));
if(blank != -1)
{
// check for different user: "NNNN - otheruser@myclient {Description ...}"
if ((changeName.Find(_T(" - ")) == blank) && (changeName.Find(_T('@')) != -1))
{
item=GetNextSiblingItem(item); // if other user, skip it - can't use it
continue;
}
changeName.Replace(_T('{'), _T(' '));
changeName.TrimRight(_T(" }"));
}
}
else if (changeName == LoadStringResource(IDS_DEFAULTCHANGELISTNAME))
{
changeList->AddHead(LoadStringResource(IDS_DEFAULTCHANGELISTNAME));
changeName = LoadStringResource(IDS_NEWCHANGELISTNAME);
}
else // if not a numbered change and not my Default - must be another user's Default
{
item=GetNextSiblingItem(item); // skip it - can't use it
continue;
}
changeList->AddHead(changeName);
item=GetNextSiblingItem(item);
}
}
// Utility function will all of my changelists that have no files
// This will result in the + going away for empty changelists
void CDeltaTreeCtrl::ExpandEmptyChglists()
{
CString changeLabel = LoadStringResource(IDS_CHANGE);
HTREEITEM item=GetChildItem(m_MyRoot);
while(item !=NULL)
{
CString changeName= GetItemText(item);
if(changeName.Find(changeLabel)!= -1)
{
changeName=changeName.Mid(7);
changeName.TrimLeft();
int blank=changeName.Find(_T(' '));
if(blank != -1)
{
// check for different user: "NNNN - otheruser@myclient {Description ...}"
if ((changeName.Find(_T(" - ")) == blank) && (changeName.Find(_T('@')) != -1))
{
item=GetNextSiblingItem(item); // if other user, skip it - only expand ours
continue;
}
}
}
else // not a numbered change
{
item=GetNextSiblingItem(item);
continue;
}
if (!GetChildItem(item))
ExpandTree(item);
item=GetNextSiblingItem(item);
}
}
long CDeltaTreeCtrl::GetChangeNumber(HTREEITEM item)
{
ASSERT(item != NULL);
BOOL underMyRoot;
if ((GetItemLevel(item, &underMyRoot) == 2) && IsAFile(item))
item = GetParentItem(item);
long changeNo= -1L;
CString itemStr= GetItemText(item);
if(itemStr.Find(LoadStringResource(IDS_DEFAULTCHANGELISTNAME)) == 0)
changeNo= 0;
else if (GET_P4REGPTR()->SortChgsByUser()
&& ((itemStr.Find(_T(" - Default")) + (int)(sizeof(_T(" - Default"))/sizeof(TCHAR) - 1)) == itemStr.GetLength()))
changeNo= 0;
else
{
int i;
CString ChgLit = LoadStringResource(IDS_CHANGE_n);
i = ChgLit.Find(_T('%'));
ASSERT(i != -1);
ChgLit = ChgLit.Left(i);
ChgLit.TrimRight();
i = itemStr.Find(ChgLit);
i += (i == -1) ? 1 : ChgLit.GetLength();
for(; i< itemStr.GetLength(); i++)
{
if(_istdigit(itemStr[i]))
break;
}
if(i<itemStr.GetLength())
{
itemStr=itemStr.Mid(i);
changeNo=_ttol(itemStr);
}
}
// Shouldnt be calling this function unless user was on a change!
ASSERT(changeNo >= 0);
return changeNo;
}
long CDeltaTreeCtrl::GetSelectedChangeNumber()
{
HTREEITEM item=GetLastSelection();
return GetChangeNumber(item);
}
void CDeltaTreeCtrl::OnChangeDel()
{
HTREEITEM item=GetLastSelection();
if (item == NULL)
{ ASSERT(0); return; }
long changeNo=GetSelectedChangeNumber();
if(changeNo == 0)
{
AfxMessageBox(IDS_DEFAULT_CHANGELIST_MAY_NOT_BE_DELETED, MB_ICONEXCLAMATION);
return;
}
CString txt;
txt.FormatMessage(IDS_ARE_YOU_SURE_YOU_WANT_TO_DELETE_CHANGELIST_n, changeNo);
if(AfxMessageBox(txt, MB_ICONQUESTION|MB_YESNO) != IDYES)
return;
CCmd_Delete *pCmd= new CCmd_Delete;
txt.Format(_T("%ld"), changeNo);
pCmd->Init( m_hWnd, RUN_ASYNC);
if( pCmd->Run( P4CHANGE_DEL, txt ) )
{
m_ActiveItem=item;
txt.FormatMessage(IDS_DELETING_n, changeNo);
MainFrame()->UpdateStatus(txt);
}
else
delete pCmd;
}
void CDeltaTreeCtrl::OnChangeDescribe()
{
HTREEITEM item=GetLastSelection();
if (item == NULL)
{ ASSERT(0); return; }
m_EditChange= item;
long changeNumber= GetSelectedChangeNumber();
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;
}
}
LRESULT CDeltaTreeCtrl::OnP4Describe(WPARAM wParam, LPARAM lParam)
{
CCmd_Describe *pCmd= (CCmd_Describe *) wParam;
if(pCmd->GetSpecType() != P4JOB_SPEC)
return OnP4ChangeDescribe( wParam, lParam);
else
return OnP4JobDescribe( wParam, lParam);
}
LRESULT CDeltaTreeCtrl::OnP4EndDescribe(WPARAM wParam, LPARAM lParam)
{
CSpecDescDlg *dlg = (CSpecDescDlg *)lParam;
if(dlg->GetViewType() != P4JOB_SPEC)
return OnP4EndChgDescribe( wParam, lParam);
else
return OnP4EndJobDescribe( wParam, lParam);
}
LRESULT CDeltaTreeCtrl::OnP4ChangeDescribe(WPARAM wParam, LPARAM lParam)
{
CCmd_Describe *pCmd= (CCmd_Describe *) wParam;
if(!pCmd->GetError())
{
// Get the descriptive text
CString desc= MakeCRs(pCmd->GetDescription());
// If we are talking to a pre 2002.2 server,
// Then add the section about affected files
if (GET_SERVERLEVEL() < 14)
{
HTREEITEM child= GetChildItem(m_EditChange);
if( child != NULL && IsAFile(child) )
{
desc += LoadStringResource(IDS_AFFECTEDFILES);
}
CString fileText;
while( child != NULL )
{
if( IsAFile( child ) )
{
CP4FileStats *fs= (CP4FileStats *) GetLParam(child);
if( fs->IsMyOpen() )
fileText.Format(_T("\r\n%s#%d %s"), fs->GetFullDepotPath(),
fs->GetHaveRev(),
fs->GetActionStr( fs->GetMyOpenAction() ) );
else
fileText.Format(_T("\r\n%s#%d %s"), fs->GetFullDepotPath(),
fs->GetHaveRev(),
fs->GetActionStr( fs->GetOtherOpenAction() ) );
// do reallocs in large chunks, rather than letting CString::operator +=() do it
// in little bits. This makes a huge speed difference if the number if items is large.
if(desc.GetLength() + fileText.GetLength() + 1 > desc.GetAllocLength())
{
// grow the buffer 16k at a time, adjusting the first time to get an even 4k multiple
int newSize = desc.GetAllocLength() + 16384;
newSize -= newSize % 16384;
desc.GetBuffer(newSize);
desc.ReleaseBuffer();
}
desc+= fileText;
}
child= GetNextSiblingItem(child);
}
}
int key;
CSpecDescDlg *dlg = new CSpecDescDlg(this);
dlg->SetIsModeless(TRUE);
dlg->SetKey(key = pCmd->HaveServerLock()? pCmd->GetServerKey() : 0);
dlg->SetItemName(pCmd->GetReference());
dlg->SetDescription(desc);
dlg->SetCaption(LoadStringResource(IDS_PERFORCE_CHANGELIST_DESCRIPTION));
dlg->SetShowEditBtn(!key && IsMyPendingChange(m_EditChange));
dlg->SetViewType(P4CHANGE_SPEC);
if (!dlg->Create(IDD_SPECDESC, this)) // display the description dialog box
{
dlg->DestroyWindow(); // some error! clean up
delete dlg;
}
}
delete pCmd;
MainFrame()->ClearStatus();
return 0;
}
LRESULT CDeltaTreeCtrl::OnP4EndChgDescribe( WPARAM wParam, LPARAM lParam )
{
CSpecDescDlg *dlg = (CSpecDescDlg *)lParam;
if (wParam == IDC_EDITIT) // which button did they click to close the box?
{
CString ref = dlg->GetItemName();
ASSERT(!ref.IsEmpty());
int i;
BOOL found = FALSE;
long chgnbr = _ttol(ref);
// find the HTREEITEM - user might have chged the selection
HTREEITEM item=GetChildItem(m_MyRoot);
while(item !=NULL && !found)
{
CString testtext=GetItemText(item);
if ((i = testtext.Find(' ')) != -1)
{
testtext = testtext.Mid(i);
testtext.TrimLeft();
if ((i = testtext.Find(' ')) != -1)
testtext = testtext.Left(i);
}
if(lstrcmp(ref, testtext) == 0)
{
found=TRUE;
break;
}
item=GetNextSiblingItem(item);
}
if (found)
{
m_ChangeIsSelected=TRUE;
m_EnableChangeSubmit=FALSE;
m_SubmitOnlyChged=m_SubmitOnlySeled=FALSE;
ChangeEdit(chgnbr, item);
}
else
{
CString txt;
txt.FormatMessage(IDS_SE_ERR_FNF, ref);
AddToStatus(txt, SV_WARNING);
}
}
dlg->DestroyWindow();
return TRUE;
}
// Following handlers for change spec editing and submitting
void CDeltaTreeCtrl::OnChangeSubmit()
{
m_ChangeIsSelected=TRUE;
m_EnableChangeSubmit=TRUE;
m_SubmitOnlyChged=GET_P4REGPTR()->GetSubmitOnlyChged();
m_SubmitOnlySeled=IsSelectionInSubmittableChange();
ChangeEdit();
}
void CDeltaTreeCtrl::OnChangeEdspec()
{
m_ChangeIsSelected=TRUE;
m_EnableChangeSubmit=FALSE;
m_SubmitOnlyChged=m_SubmitOnlySeled=FALSE;
ChangeEdit();
}
void CDeltaTreeCtrl::OnChangeNew()
{
m_ChangeIsSelected=FALSE;
m_EnableChangeSubmit=FALSE;
m_SubmitOnlyChged=m_SubmitOnlySeled=FALSE;
ChangeEdit();
}
void CDeltaTreeCtrl::CallOnChangeNew()
{
OnChangeNew();
}
void CDeltaTreeCtrl::ChangeEdit(long chgnum /*= -1*/, HTREEITEM chgItem /*= 0*/)
{
if (m_EditInProgress)
{
CantDoItRightNow(IDS_EDITSTRING);
return;
}
HTREEITEM item;
// Get the relevant change number and the list of files under the change
if (chgnum != -1)
{
m_EditChangeNum = chgnum;
m_EditChange = chgItem;
}
else if(m_ChangeIsSelected)
{
item=GetLastSelection();
if(!IsMyPendingChange(item))
item=GetParentItem(item);
if (item == NULL)
{ ASSERT(0); return; }
m_EditChangeNum=GetChangeNumber(item);
if(m_EditChangeNum < 0L)
{ ASSERT(0); return; }
m_EditChange=item;
}
else
{
m_EditChangeNum=0;
m_EditChange=m_MyDefault;
}
// Empty lists
m_FileList.RemoveAll();
m_SelectionList.RemoveAll();
m_FileListDefinitive = FALSE;
// If they want to only set the check on changed files,
// we must get a list of edited files into m_FileList.
// Also if they are submitting a selection of files from the chglist
// we must get a list of the selected files into m_SelectionList
if (m_EnableChangeSubmit
&& (m_SubmitOnlyChged || m_SubmitOnlySeled || GET_SERVERLEVEL() >= 21))
{
CString fileName;
int files=0;
BOOL b20051 = FALSE;
CP4Command *pcmd = 0;
CGuiClient *client = 0;
if (GET_SERVERLEVEL() >= 19) // 2005.1 or later?
{
Error e;
pcmd = new CP4Command;
client = pcmd->GetClient();
client->SetTrans();
client->Init(&e);
if( !e.Test() )
b20051 = TRUE;
else
delete pcmd;
}
item=GetChildItem(m_EditChange);
while(item!=NULL)
{
if(IsAFile(item))
{
fileName=GetItemText(item);
if ((m_SubmitOnlyChged || GET_SERVERLEVEL() >= 21) //always build list for 6.1+
&& (!m_SubmitOnlySeled || IsSelected(item)))
{
if (fileName.Find(_T("<edit>")) != -1)
{
if (b20051) // working with good 2005.1 or later server?
{
LPARAM lParam=GetLParam(item);
CP4FileStats *stats = (CP4FileStats *) lParam;
if (TheApp()->digestIsSame(stats, FALSE, client)
&& stats->GetType() == stats->GetHeadType())
m_FileList.AddTail(stats->GetFullDepotPath());
}
else
{
m_FileList.AddTail(fileName.Left(fileName.ReverseFind(_T('#'))));
++files;
}
}
if ((files > 32000) && !m_SubmitOnlySeled)
break;
}
if (m_SubmitOnlySeled && IsSelected(item))
m_SelectionList.AddTail(fileName.Left(fileName.ReverseFind(_T('#'))));
}
item=GetNextSiblingItem(item);
}
if (b20051)
{
delete pcmd;
m_FileListDefinitive = TRUE;
RunChangeEdit(0);
return;
}
if (m_FileList.GetCount())
{
if (GET_SERVERLEVEL() >= 14) // 2002.2 or later?
{
if (files <= 32000)
{
CCmd_Revert *pCmd= new CCmd_Revert;
pCmd->Init( m_hWnd, RUN_ASYNC, HOLD_LOCK);
pCmd->SetAlternateReplyMsg( WM_P4DIFFCHANGEEDIT );
CString chgnbr;
if (m_EditChangeNum)
chgnbr.Format(_T("%ld"), m_EditChangeNum);
else
chgnbr = _T("default");
if( pCmd->Run( chgnbr, TRUE, TRUE, TRUE ) )
{
MainFrame()->UpdateStatus(LoadStringResource(IDS_RUNNING_DIFF));
return;
}
else
delete pCmd;
}
else
{
CString msg;
msg.FormatMessage(IDS_TOOMANYFILE4SUBMITONLYCHGED, files);
if (IDNO == AfxMessageBox(msg, MB_YESNO | MB_ICONEXCLAMATION))
return;
}
}
}
}
RunChangeEdit(0);
}
LRESULT CDeltaTreeCtrl::OnP4DiffChangeEdit(WPARAM wParam, LPARAM lParam)
{
CCmd_Revert *pCmd= (CCmd_Revert *) wParam;
if(!pCmd->GetError())
{
m_FileList.RemoveAll();
CStringList *list= pCmd->GetFileList();
POSITION pos;
if(!list->IsEmpty()) // Some filenames in the list
{
int i;
for(pos=list->GetHeadPosition(); pos!=NULL;)
{
CString str = list->GetNext(pos);
if (str.Find(_T(", not reverted")) != -1)
continue;
if ((i = str.Find(_T('#'))) != -1)
str = str.Left(i);
m_FileList.AddHead(str);
}
}
m_FileListDefinitive = TRUE;
}
int key= pCmd->GetServerKey();
delete pCmd;
RunChangeEdit(key);
return 0;
}
void CDeltaTreeCtrl::RunChangeEdit(int key)
{
// At this point, context has been saved in m_EditChangeNum, m_EnableChangeSubmit,
// and m_FileList members. So start the spec edit process. The dialog
// is 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, key );
if( pCmd->Run( m_EditChangeNum, m_EnableChangeSubmit, FALSE, m_SubmitOnlyChged,
m_SubmitOnlySeled) )
MainFrame()->UpdateStatus( LoadStringResource(IDS_EDITING_CHANGELIST_SPEC) );
else
delete pCmd;
}
BOOL CDeltaTreeCtrl::IsAMemeberOfFileList(CString &fileName)
{
for (POSITION pos= m_FileList.GetHeadPosition(); pos!=NULL; )
if (m_FileList.GetNext( pos ) == fileName)
return TRUE;
return FALSE;
}
BOOL CDeltaTreeCtrl::IsAMemeberOfSelectionList(CString &fileName)
{
for (POSITION pos= m_SelectionList.GetHeadPosition(); pos!=NULL; )
if (m_SelectionList.GetNext( pos ) == fileName)
return TRUE;
return FALSE;
}
// TODO: allow this function to be called for selected file level in addition to
// change level
void CDeltaTreeCtrl::OnChangeRevorig()
{
if( SERVER_BUSY() )
{
ASSERT(0);
return;
}
HTREEITEM currItem=GetLastSelection();
// no selected item - menu enables should have prevented
if (currItem == NULL)
{ ASSERT(0); return; }
// selected item not one of my changes - fix menu enables should have prevented
if(GetParentItem(currItem) != m_MyRoot)
{ ASSERT(0); return; }
// Empty list
m_StringList.RemoveAll();
SET_BUSYCURSOR();
MainFrame()->UpdateStatus(LoadStringResource(IDS_DIFFFILES));
int files=0;
HTREEITEM item=GetChildItem(currItem);
while(item!=NULL)
{
if(IsAFile(item))
{
if(++files > 32000)
{
AfxMessageBox(IDS_UNABLE_TO_DIFF_MORE_THAN_32000_FILES, MB_ICONEXCLAMATION);
return;
}
if (GET_SERVERLEVEL() < 14) // pre 2002.2?
{
CString fileName=GetItemText(item);
fileName=fileName.Left(fileName.ReverseFind(_T('#'))); // Strip revision number
m_StringList.AddTail(fileName);
}
}
item=GetNextSiblingItem(item);
}
if (GET_SERVERLEVEL() >= 14) // 2002.2 or later? If so we can use p4 revert -an
{
CCmd_Revert *pCmd= new CCmd_Revert;
pCmd->Init( m_hWnd, RUN_ASYNC, HOLD_LOCK);
CString chgnbr;
m_EditChangeNum=GetChangeNumber(currItem);
if (m_EditChangeNum)
chgnbr.Format(_T("%ld"), m_EditChangeNum);
else
chgnbr = _T("default");
if( pCmd->Run( chgnbr, TRUE, TRUE, TRUE ) )
m_DoRevert=TRUE;
else
{
MainFrame()->ClearStatus();
delete pCmd;
}
return;
}
CCmd_Diff *pCmd= new CCmd_Diff;
pCmd->Init( m_hWnd, RUN_ASYNC, HOLD_LOCK);
if( pCmd->Run( &m_StringList, _T("-sr") ) )
{
if(files > 5)
MainFrame()->UpdateStatus(LoadStringResource(IDS_RUNNING_MASSIVE_DIFF));
else
MainFrame()->UpdateStatus(LoadStringResource(IDS_RUNNING_DIFF));
m_DoRevert=TRUE;
}
else
delete pCmd;
}
void CDeltaTreeCtrl::OnFileDiff()
{
// should always have something selected
if(GetSelectedCount()==0)
{
ASSERT(0);
return;
}
// see if it's a chglist or file(s) that's selected
HTREEITEM initialItem = GetSelectedItem(0);
BOOL root;
int level = GetItemLevel(initialItem, &root);
if (level == 1)
{
// a chglist is selected, so select its files
if (GET_SERVERLEVEL() >= 19) // 2005.1 or later? Then select only chged files
{
int tot;
if (SelectChgUnchg(TRUE, &tot)) // any file(s) get selected?
{
int i = tot - GetSelectedCount(); // compute nbr not selected (i.e. unchged)
if (i) // any unchanged? if so, tell user
{
CString txt;
if(i == 1)
txt.FormatMessage(IDS_ONECLIENTFILEDOESNOTDIFFER);
else
txt.FormatMessage(IDS_SEVERALCLIENTFILESDONOTDIFFER_n, i);
AddToStatus(txt, SV_MSG);
}
}
else // all unchanged; tell user and return
{
AddToStatus(LoadStringResource(IDS_NONE_OF_THE_SELECTED_CLIENT_FILES_DIFFER), SV_COMPLETION);
return;
}
}
else
SelectAllFilesInChange(initialItem, 0); // older server: Sellect all the chglist files
if (GetSelectedCount() < 1)
{
UnselectAll();
SetSelectState(initialItem, TRUE);
return;
}
}
// get a stringlist of files and deal with any adds
BOOL bFoundAdd = AssembleStringList( NULL, FALSE );
if (bFoundAdd)
{
if ((level != 1) || m_StringList.IsEmpty())
AddToStatus(LoadStringResource(IDS_CANTDIFFADDEDFILES), SV_WARNING);
if (m_StringList.IsEmpty())
return;
}
// see if we are diffing "a whole buncha files"
if (m_StringList.GetCount() > _ttoi(GET_P4REGPTR()->GetWarnLimitDiff()))
{
CString txt;
txt.FormatMessage(IDS_DIFF_WARNLIMIT_EXCEEDED_d, m_StringList.GetCount());
if (IDYES != AfxMessageBox(txt, MB_YESNO))
return;
}
// If the server is busy because we triggered an expand of a changelist
// and are getting the attached jobs, wait for the server to finish
if (level == 1)
{
UnselectAll();
SetSelectState(initialItem, TRUE); // reselect original chglist
if (SERVER_BUSY())
{
int t=GET_P4REGPTR()->BusyWaitTime();
do
{
Sleep(50);
t -= 50;
} while (SERVER_BUSY() && t > 0);
}
}
// finally run the diff command against the selected file(s)
m_DoRevert=FALSE;
CCmd_Diff *pCmd= new CCmd_Diff;
pCmd->Init( m_hWnd, RUN_ASYNC);
if( pCmd->Run( &m_StringList ) )
MainFrame()->UpdateStatus( LoadStringResource(IDS_DIFFING_FILE) );
else
delete pCmd;
}
void CDeltaTreeCtrl::OnFiletype()
{
HTREEITEM item=GetLastSelection();
if (item == NULL)
ASSERT(0);
else if (!IsAFile(item))
AfxMessageBox(IDS_CANTCHGFILETYPE4JOB);
else
{
CFileType dlg;
CP4FileStats *stats;
stats= (CP4FileStats *) GetLParam(item);
dlg.m_itemStr = stats->GetFormattedChangeFile(TRUE, TRUE);
int i=GetSelectedCount();
if (i > 1)
{
CString str = GetItemText(item);
str = str.Mid(str.ReverseFind(_T('#')));
str = str.Mid(str.Find(_T("<")));
str = str.Left(str.Find(_T(">")));
while(--i >= 0)
{
item=GetSelectedItem(i);
if(!IsAFile(item))
continue;
CString fname=GetItemText(item);
CString type =fname.Mid(fname.ReverseFind(_T('#')));
type = type.Mid(type.Find(_T("<")));
type = type.Left(type.Find(_T(">")));
if (type != str)
{
dlg.m_Action = 1;
break;
}
}
}
if (dlg.DoModal() == IDOK)
ReopenAs(dlg.m_fileType);
}
}
void CDeltaTreeCtrl::OnMoveFiles()
{
HTREEITEM item=GetLastSelection();
if (item == NULL)
ASSERT(0);
else
{
CMoveFiles dlg;
// Get a list of my changes
CStringList list;
GetMyChangesList(&list);
// Get current change item and save in m_DragFromChange
HTREEITEM currentItem=GetLastSelection();
m_DragFromChange=GetParentItem(currentItem);
// Get current change number and convert to string
long changeNo=GetChangeNumber(m_DragFromChange);
CString curChg;
if (!changeNo)
curChg = LoadStringResource(IDS_CHANGE_DEFAULT);
else
curChg.Format(_T("%ld"), changeNo);
// Remove current change number from list
// as the list is copied to the dlg
POSITION pos;
for( pos = list.GetHeadPosition(); pos != NULL; )
{
int i;
CString changeStr = dlg.m_ChangeList.GetNext( pos );
CString chg = ((i = changeStr.Find(_T(' '), 2)) != -1)
? changeStr.Left(i) : changeStr;
if (chg != curChg)
dlg.m_ChangeList.AddHead(changeStr);
}
// display the dialog
if (dlg.DoModal() == IDOK)
{
// Save the change number to move to
m_DragToChangeNum=dlg.m_SelectedChange;
m_DragToChange = m_DragToChangeNum ? FindChange(m_DragToChangeNum) : m_MyDefault;
m_Need2Refresh = m_DragToChange ? dlg.m_Need2Refresh : TRUE;
// Build a list of files and a list of jobs
m_DroppedFileList.RemoveAll();
m_DroppedJobList.RemoveAll();
for(int i=GetSelectedCount()-1; i>=0; i--)
{
item=GetSelectedItem(i);
if(!IsAFile(item))
m_DroppedJobList.AddHead(GetItemText(item));
else
{
CString fname=GetItemText(item);
fname=fname.Left(fname.ReverseFind(_T('#')));
m_DroppedFileList.AddHead(fname);
}
}
// And finally do the actual move
OnGotMoveLists(0, 0);
}
}
}
/*
_________________________________________________________________
*/
void CDeltaTreeCtrl::OnFileLock()
{
LockOrUnlock( P4LOCK );
}
void CDeltaTreeCtrl::OnFileUnlock()
{
LockOrUnlock( P4UNLOCK );
}
void CDeltaTreeCtrl::LockOrUnlock( int which )
{
if(GetSelectedCount()==0)
{
ASSERT(0);
return;
}
AssembleStringList( );
// Run the command for the depot window
CCmd_ListOpStat *pCmd= new CCmd_ListOpStat;
pCmd->Init( m_depotWnd, RUN_ASYNC, HOLD_LOCK );
if( pCmd->Run( &m_StringList, which ) )
MainFrame()->UpdateStatus( LoadStringResource(which == P4LOCK ?
IDS_REQUESTINGLOCK : IDS_REQUESTINGUNLOCK));
else
delete pCmd;
}
/*
_________________________________________________________________
*/
void CDeltaTreeCtrl::OnUpdateFileSchedule(CCmdUI* pCmdUI)
{
BOOL root;
BOOL rc = FALSE;
if (!SERVER_BUSY() && GetSelectedCount() > 0)
{
int level = GetItemLevel(GetSelectedItem(0), &root);
if (level == 2)
rc = (IsMyPendingChangeFile( GetSelectedItem(0) ) && IsAFile( GetSelectedItem(0)) );
else if (level == 1)
rc = (IsMyPendingChange(GetSelectedItem(0))
&& HasChildren(GetSelectedItem(0))
&& GetSelectedCount()==1);
}
pCmdUI->Enable(rc);
}
void CDeltaTreeCtrl::OnFileGetWhatIf()
{
FileGet(TRUE);
}
void CDeltaTreeCtrl::OnFileGet()
{
FileGet(FALSE);
}
void CDeltaTreeCtrl::FileGet(BOOL whatIf)
{
BOOL root;
if(GetSelectedCount()==0)
{
ASSERT(0);
return;
}
if (GetItemLevel(GetSelectedItem(0), &root) == 2)
AssembleStringList( );
else
{
int files = 0;
CString fileName;
m_StringList.RemoveAll();
HTREEITEM item=GetChildItem(GetSelectedItem(0));
while(item!=NULL)
{
if(IsAFile(item))
{
fileName=GetItemText(item);
fileName=fileName.Left(fileName.ReverseFind(_T('#'))); // Strip revision number
m_StringList.AddTail(fileName);
if(files++ > 32000)
{
AfxMessageBox(IDS_UNABLE_TO_RESOLVE_MORE_THAN_32000_FILES, MB_ICONEXCLAMATION);
return;
}
}
item=GetNextSiblingItem(item);
}
}
CCmd_Get *pCmd= new CCmd_Get;
pCmd->Init( m_depotWnd, RUN_ASYNC);
if( pCmd->Run( &m_StringList, whatIf ) )
MainFrame()->UpdateStatus( LoadStringResource(IDS_FILE_SYNC) );
else
delete pCmd;
}
void CDeltaTreeCtrl::OnFileRevisionhistory()
{
HTREEITEM currentItem=GetLastSelection();
if( IsAFile(currentItem) && !SERVER_BUSY() )
{
CString fname= GetItemText( currentItem );
int pound= fname.Find(_T('#'));
if( pound != -1 )
fname= fname.Left( pound );
CCmd_History *pCmd= new CCmd_History;
pCmd->Init( m_depotWnd, RUN_ASYNC);
pCmd->SetCallingWnd(m_hWnd);
if( pCmd->Run(fname) )
{
MainFrame()->UpdateStatus( LoadStringResource(IDS_REQUESTING_HISTORY) );
}
else
delete pCmd;
}
}
void CDeltaTreeCtrl::OnFileRevisionTree()
{
HTREEITEM currentItem=GetLastSelection();
if( IsAFile(currentItem) && !SERVER_BUSY() )
{
int i, j;
CString path = GetItemText( currentItem );
if ((i = path.Find(_T('#'))) != -1)
{
if ((j = path.Find(_T(' '), i)) != -1)
path = path.Left(j);
if (path[i+1] == _T('0'))
path = path.Left(i);
}
TheApp()->CallP4RevisionTree( path );
}
}
void CDeltaTreeCtrl::OnFileTimeLapseView()
{
HTREEITEM currentItem=GetLastSelection();
if( IsAFile(currentItem) && !SERVER_BUSY() && MainFrame()->HaveTLV() )
{
int i;
CString path = GetItemText( currentItem );
if (((i = path.Find(_T('#'))) != -1) && ((i = path.Find(_T(' '), i)) != -1))
path = path.Left(i);
TheApp()->CallP4A( path, _T(""), 0 );
}
}
void CDeltaTreeCtrl::OnFileAnnotate()
{
FileAnnotate(FALSE);
}
void CDeltaTreeCtrl::OnFileAnnotateAll()
{
FileAnnotate(TRUE);
}
void CDeltaTreeCtrl::OnFileAnnotateChg()
{
FileAnnotate(FALSE, TRUE);
}
void CDeltaTreeCtrl::OnFileAnnotateChgAll()
{
FileAnnotate(TRUE, TRUE);
}
void CDeltaTreeCtrl::FileAnnotate(BOOL bAll, BOOL bChg/*=FALSE*/)
{
HTREEITEM currentItem=GetLastSelection();
if (currentItem == NULL || !IsAFile(currentItem))
ASSERT(0);
else
{
CP4FileStats *fs= (CP4FileStats *) GetLParam(currentItem);
CString itemStr= fs->GetFullDepotPath();
CCmd_PrepBrowse *pCmd= new CCmd_PrepBrowse;
pCmd->Init( m_depotWnd, RUN_ASYNC);
pCmd->SetFileType(fs->IsTextFile() ? FST_TEXT : FST_BINARY);
CString fType = fs->GetHeadType();
::SendMessage(m_depotWnd, WM_SETVIEWER, 0, (LPARAM)GET_P4REGPTR()->GetEditApp());
if( pCmd->Run( FALSE, itemStr, fType, bAll, bChg, FALSE, fs->GetHaveRev(),
GET_P4REGPTR()->GetAnnotateWhtSpace(),
bChg ? GET_P4REGPTR()->GetAnnotateIncInteg() : FALSE) )
{
MainFrame()->UpdateStatus( LoadStringResource(IDS_FETCHING_FILE) );
}
else
delete pCmd;
}
}
// If user right clicks on a file and chooses 'Explore', run Windows Explorer
// in the directory where that file resides on the client machine.
// We can only do this for a specific file - not for multiple selected files
// since they may map to different directories.
void CDeltaTreeCtrl::OnWinExplore()
{
BOOL root;
if (GetSelectedCount() &&
GetItemLevel(GetSelectedItem(0), &root)== 2 &&
IsMyPendingChangeFile(GetSelectedItem(0)) )
{
HTREEITEM item = NULL;
if (m_ContextPoint.x != -1 && m_ContextPoint.y != -1)
{
// find out what item was clicked to generate the last context menu
TV_HITTESTINFO ht;
ht.pt=m_ContextPoint;
ScreenToClient(&ht.pt);
ht.flags=TVHT_ONITEMLABEL | TVHT_ONITEMICON | TVHT_ONITEMBUTTON;
item=HitTest( &ht );
}
if (!item || !IsSelected(item) || !IsAFile(item))
{
item = GetSelectedItem(0);
if (!IsAFile(item))
return;
}
CString clientPath;
if(GetClientPath(item, clientPath))
{
int i;
CString switches;
clientPath.Replace('/', '\\');
if (GET_P4REGPTR()->GetExplorer() // not using Win Explorer
|| (::GetFileAttributes(clientPath) == -1)) // file not found
{
switches = _T("");
if ((i = clientPath.ReverseFind('\\')) != -1)
clientPath = clientPath.Left(i);
}
else
{
switches = _T("/select,");
}
if (clientPath.FindOneOf(_T(" &()[]{}^=;!'+,`~")) != -1)
{
clientPath.TrimLeft();
clientPath.TrimRight();
clientPath = _T('\"') + clientPath + _T('\"');
}
STARTUPINFO si;
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
PROCESS_INFORMATION pi;
CreateProcess(NULL, const_cast<LPTSTR>((LPCTSTR)(TheApp()->GetExplorer()
+ switches + clientPath)),
NULL, NULL,
#ifdef UNICODE
FALSE, DETACHED_PROCESS | NORMAL_PRIORITY_CLASS | CREATE_UNICODE_ENVIRONMENT,
#else
FALSE, DETACHED_PROCESS | NORMAL_PRIORITY_CLASS,
#endif
MainFrame()->P4GetEnvironmentStrings(),
NULL, &si, &pi);
}
}
}
// If user right clicks on a file and chooses 'Command Prompt', run a Command Prompt
// in the directory where that file resides on the client machine.
// We can only do this for a specific file - not for multiple selected files
// since they may map to different directories; otherwise run MainFrame's OnCmdPrompt()
void CDeltaTreeCtrl::OnCmdPrompt()
{
BOOL root;
if (GetSelectedCount() &&
GetItemLevel(GetSelectedItem(0), &root)== 2 &&
IsMyPendingChangeFile(GetSelectedItem(0)) )
{
HTREEITEM item = NULL;
if (m_ContextPoint.x != -1 && m_ContextPoint.y != -1)
{
// find out what item was clicked to generate the last context menu
TV_HITTESTINFO ht;
ht.pt=m_ContextPoint;
ScreenToClient(&ht.pt);
ht.flags=TVHT_ONITEMLABEL | TVHT_ONITEMICON | TVHT_ONITEMBUTTON;
item=HitTest( &ht );
}
if (!item || !IsSelected(item) || !IsAFile(item))
{
item = GetSelectedItem(0);
if (!IsAFile(item))
{
MainFrame()->OnCmdPromptPublic();
return;
}
}
CString clientPath;
if(GetClientPath(item, clientPath))
{
int i;
clientPath.Replace('/', '\\');
if ((i = clientPath.ReverseFind(_T('\\'))) != -1)
clientPath = clientPath.Left(i);
TCHAR cmd[MAX_PATH+1];
GetEnvironmentVariable(_T("ComSpec"), cmd, MAX_PATH);
STARTUPINFO si;
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
PROCESS_INFORMATION pi;
CreateProcess(NULL, cmd,
NULL, NULL,
#ifdef UNICODE
FALSE, CREATE_NEW_CONSOLE | NORMAL_PRIORITY_CLASS | CREATE_UNICODE_ENVIRONMENT,
#else
FALSE, CREATE_NEW_CONSOLE | NORMAL_PRIORITY_CLASS,
#endif
MainFrame()->P4GetEnvironmentStrings(),
clientPath, &si, &pi);
}
}
else
MainFrame()->OnCmdPromptPublic();
}
void CDeltaTreeCtrl::OnJobDescribe()
{
HTREEITEM item=GetLastSelection();
if (item == NULL)
ASSERT(0);
else
{
CString itemStr=GetItemText(item);
itemStr.TrimLeft();
CCmd_Describe *pCmd= new CCmd_Describe;
pCmd->Init( m_hWnd, RUN_ASYNC);
if( pCmd->Run( P4JOB_SPEC, itemStr ) )
MainFrame()->UpdateStatus( LoadStringResource(IDS_FETCHING_JOB_SPEC) );
else
delete pCmd;
}
}
void CDeltaTreeCtrl::OnJobEditspec()
{
HTREEITEM item=GetLastSelection();
if (item == NULL)
ASSERT(0);
else
{
CString itemStr=GetItemText(item);
itemStr.TrimLeft();
MainFrame()->EditJobSpec(&itemStr);
}
}
void CDeltaTreeCtrl::OnAddjobfix()
{
if( SERVER_BUSY() )
{
EnumChildWindows(AfxGetMainWnd()->m_hWnd, ChildSetRedraw, TRUE);
ASSERT(0);
return;
}
HTREEITEM currItem=GetLastSelection();
if(!IsMyPendingChange(currItem))
currItem=GetParentItem(currItem);
// no selected item - menu enables should have prevented
if (currItem == NULL)
{ EnumChildWindows(AfxGetMainWnd()->m_hWnd, ChildSetRedraw, TRUE); ASSERT(0); return; }
// selected item not one of my changes - fix menu enables should have prevented
if(GetParentItem(currItem) != m_MyRoot)
{ EnumChildWindows(AfxGetMainWnd()->m_hWnd, ChildSetRedraw, TRUE); ASSERT(0); return; }
// Record the change that is involved
m_ActiveItem=currItem;
m_EditChangeNum=GetSelectedChangeNumber();
if(m_EditChangeNum < 0L)
{ 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)m_EditChangeNum, (LPARAM)m_hWnd);
}
LRESULT CDeltaTreeCtrl::OnP4JobList(WPARAM wParam, LPARAM lParam)
{
m_EditChangeNum= wParam;
// Get the list of jobs
CObList *jobs= (CObList *) ::SendMessage( m_jobWnd, WM_QUERYJOBS, 0, 0);
ASSERT(jobs);
ASSERT_KINDOF(CObList,jobs);
CString *spec= (CString *) ::SendMessage( m_jobWnd, WM_QUERYJOBSPEC, 0, 0);
ASSERT(spec);
CStringArray *cols= (CStringArray *) ::SendMessage( m_jobWnd, WM_QUERYJOBCOLS, 0, 0);
ASSERT(cols);
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, dlg.m_JobStatusValue.GetLength()
? (LPCTSTR)dlg.m_JobStatusValue : NULL);
else if (retcode == IDRETRY)
{
::SendMessage( m_jobWnd, WM_CLEARLIST, 0, 0);
PostMessage(WM_COMMAND, ID_CHANGE_ADDJOBFIX, 0);
}
MainFrame()->ClearStatus();
return 0;
}
void CDeltaTreeCtrl::AddJobFixes(CStringList *jobnames, 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, m_EditChangeNum, FALSE, jobstatusvalue ) )
{
MainFrame()->UpdateStatus( LoadStringResource(IDS_FIXING_JOBS) );
}
else
delete pCmdFix;
}
void CDeltaTreeCtrl::OnRemovefix()
{
HTREEITEM item=GetLastSelection();
m_ActiveItem=item;
if (item == NULL)
ASSERT(0);
else
{
// Get the change number
BOOL underMyRoot;
int level=GetItemLevel(item, &underMyRoot);
if(level==2)
{
HTREEITEM change=GetParentItem(item);
ASSERT(change != NULL);
long changeNum= GetChangeNumber(change);
ASSERT(changeNum);
CString itemStr=GetItemText(item);
itemStr.TrimLeft(); // Strip leading space
m_StringList.RemoveAll();
m_StringList.AddHead(itemStr);
CCmd_Fix *pCmd= new CCmd_Fix;
pCmd->Init( m_hWnd, RUN_ASYNC);
if( pCmd->Run( &m_StringList, changeNum, TRUE ) )
MainFrame()->UpdateStatus( LoadStringResource(IDS_UNFIXING_JOB) );
else
delete pCmd;
}
}
}
void CDeltaTreeCtrl::OnChgListRevert()
{
if (GET_SERVERLEVEL() < 19) // if server is before 2005.1, don't try to diff - just warn
{
if (IDYES != AfxMessageBox(IDS_REVERTING_FILES_WILL_OVERWRITE_EDITS,
MB_YESNO|MB_ICONQUESTION))
return;
}
else // for 2005.2 and later servers, we can locally check to see if any files have changed
{
CString text;
HTREEITEM currentItem = GetSelectedItem(0);
int tot;
BOOL b = SelectChgUnchg(TRUE, &tot);
if (b)
{
int n = GetSelectionSetSize();
text.FormatMessage(IDS_n_CHGED_REVERT_YESNO, n);
}
UnselectAll();
SetSelectState( currentItem, TRUE );
if (IDYES != AfxMessageBox(b ? text : LoadStringResource(IDS_ALL_UNCHGED_REVERT_YESNO),
MB_YESNO|MB_ICONQUESTION))
return;
}
CString chg;
long l = GetSelectedChangeNumber();
if (l)
chg.Format(_T("%ld"), l);
else
chg = _T("default");
m_SelectionList.RemoveAll();
m_SelectionList.AddHead(chg);
m_SelectionList.AddTail(_T("//..."));
m_DoRevert = FALSE;
CCmd_Revert *pCmd= new CCmd_Revert;
pCmd->Init( m_hWnd, RUN_ASYNC, HOLD_LOCK);
if( pCmd->Run(&m_SelectionList , TRUE ) )
MainFrame()->UpdateStatus( LoadStringResource(IDS_REQUESTING_REVERT) );
else
delete pCmd;
}
void CDeltaTreeCtrl::OnFileRevert()
{
int cnt = GetSelectedCount();
if(!cnt)
{
ASSERT(0);
return;
}
if (GET_P4REGPTR()->AlwaysWarnOnRevert())
{
AssembleStringList( );
OnP4FileRevert(0, 0);
return;
}
if(cnt == 1 && IsMyPendingChange(GetSelectedItem(0)))
{
if (AnyFilesInChange(GetSelectedItem(0)))
OnChgListRevert();
return;
}
AssembleStringList( );
if (GET_SERVERLEVEL() >= 14)
{
// Make a new list of selected files, but don't include those opened for add.
// We can't use the list above from AssembleStringList()
// because this list will be cleared by the Revert -an command
// plus we don't have to ask about any adds.
AssembleStringList(&m_SelectionList, FALSE);
// Run the p4 revert -an command on all the selected files not opened for add
CCmd_Revert *pCmd= new CCmd_Revert;
pCmd->Init( m_hWnd, RUN_ASYNC);
pCmd->SetAlternateReplyMsg( WM_P4FILEREVERT );
pCmd->SetNbrNonEdits(m_StringList.GetCount() - m_SelectionList.GetCount());
if (m_SelectionList.IsEmpty())
{
pCmd->ClearError();
OnP4FileRevert((WPARAM)pCmd, 0);
}
else if( pCmd->Run( &m_SelectionList, FALSE, TRUE, TRUE, FALSE, TRUE ) )
MainFrame()->UpdateStatus(LoadStringResource(IDS_RUNNING_DIFF));
else
delete pCmd;
}
else
{
CCmd_Opened *pCmd= new CCmd_Opened;
pCmd->Init( m_hWnd, RUN_ASYNC);
pCmd->SetAlternateReplyMsg( WM_P4FILEREVERT );
if( pCmd->Run( FALSE, FALSE, -1, &m_StringList ) )
MainFrame()->UpdateStatus( LoadStringResource(IDS_REQUESTING_FILE_INFORMATION) );
else
delete pCmd;
}
}
LRESULT CDeltaTreeCtrl::OnP4Revert( WPARAM wParam, LPARAM lParam )
{
BOOL chainedCommands=FALSE;
CCmd_Revert *pCmd= (CCmd_Revert *) wParam;
ASSERT_KINDOF(CCmd_Revert, pCmd);
if( !pCmd->GetError() )
{
if(m_DoRevert)
{
chainedCommands = DoRevert(pCmd->GetFileList(),
pCmd->GetServerKey(), pCmd->OnlyUnChgd());
}
else
{
int cnt = pCmd->GetFileList()->GetCount();
if (cnt > MAX_FILESEEKS)
{
int key= pCmd->GetServerKey();
chainedCommands= TRUE;
MainFrame()->UpdateDepotandChangeViews(REDRILL, key);
}
else
OnP4RevertFile(pCmd->GetFileList());
CString chg;
CString text;
if (pCmd->OnlyUnChgd() && !(chg = pCmd->GetChgName()).IsEmpty() && !pCmd->IsPreview())
text.FormatMessage(IDS_REVERTEDALL_n_FILES, cnt, chg);
else
text.FormatMessage(IDS_REVERTED_n_FILES, cnt);
AddToStatus(text, SV_COMPLETION);
}
}
if( !chainedCommands || MainFrame()->IsQuitting() )
pCmd->ReleaseServerLock();
delete pCmd;
return (0);
}
LRESULT CDeltaTreeCtrl::OnP4FileRevert( WPARAM wParam, LPARAM lParam )
{
BOOL bBox = TRUE;
BOOL bUseDashA = FALSE;
if (!GET_P4REGPTR()->AlwaysWarnOnRevert())
{
if (GET_SERVERLEVEL() >= 14)
{
// m_StringList still contains our revert list
CCmd_Revert *pCmd= (CCmd_Revert *) wParam;
if(!pCmd->GetError()
&& pCmd->GetFileList()->GetCount() + pCmd->NbrNonEdits() == m_StringList.GetCount())
{
bBox = FALSE;
if (pCmd->NbrNonEdits() == 0)
bUseDashA = TRUE;
}
delete pCmd;
}
else
{
CCmd_Opened *pCmd= (CCmd_Opened *) wParam;
if(!pCmd->GetError())
{
bBox = FALSE;
m_StringList.RemoveAll();
CObList *list = pCmd->GetList( );
ASSERT_KINDOF( CObList, list );
for(POSITION pos= list->GetHeadPosition(); pos!=NULL; )
{
CP4FileStats *stats = ( CP4FileStats * )list->GetNext( pos );
ASSERT_KINDOF( CP4FileStats, stats );
m_StringList.AddHead(stats->GetFullDepotPath( ));
if (stats->GetMyOpenAction() != F_ADD)
bBox = TRUE;
delete stats;
}
}
else AssembleStringList( );
delete pCmd;
}
}
if (bBox)
{
if(AfxMessageBox(IDS_REVERTING_FILES_WILL_OVERWRITE_EDITS, MB_ICONQUESTION|MB_YESNO) != IDYES)
{
MainFrame()->ClearStatus();
return (0);
}
}
CCmd_ListOpStat *pCmd2= new CCmd_ListOpStat;
pCmd2->Init( m_hWnd, RUN_ASYNC, HOLD_LOCK );
// MUST use a temp variable or the release version
// will return garbage from SendMessage!
int iFlag;
::SendMessage(m_depotWnd, WM_ISFILTEREDONOPEN, 0, (LPARAM)&iFlag);
pCmd2->SetRedoOpenedFilter(iFlag);
if( pCmd2->Run( &m_StringList, bUseDashA ? P4REVERTUNCHG : P4REVERT ) )
MainFrame()->UpdateStatus( LoadStringResource(IDS_REQUESTING_REVERT) );
else
delete pCmd2;
return (0);
}
int CDeltaTreeCtrl::GetItemLevel(HTREEITEM currentItem, BOOL *underMyRoot)
{
if (currentItem == NULL)
return 0;
int Level=0;
// get its parent and grandparent (tree is only 3 layers deep)
HTREEITEM parentItem=GetParentItem(currentItem);
HTREEITEM rootItem;
if(parentItem != NULL)
{
Level++;
rootItem=GetParentItem(parentItem);
if(rootItem!=NULL)
Level++;
}
else
rootItem=NULL;
// is the item at or under m_MyRoot?
if(currentItem != m_MyRoot && parentItem != m_MyRoot && rootItem != m_MyRoot)
*underMyRoot=FALSE;
else
*underMyRoot=TRUE;
return Level;
}
BOOL CDeltaTreeCtrl::OKToAddSelection( HTREEITEM currentItem )
{
if (GetParentItem(currentItem) != GetLastSelectionParent())
return FALSE;
BOOL underMyRoot;
int Level=GetItemLevel(currentItem, &underMyRoot);
// Multi-select of files and jobs is OK. All other
// multi-select is illegal
if(Level==2)
return TRUE;
else
return FALSE;
}
/*
_________________________________________________________________
Called by MSTreeView during OnLButtonDown to see if the user is
dragging before letting the mouse button up, which would indicate
a drag drop operation.
_________________________________________________________________
*/
BOOL CDeltaTreeCtrl::TryDragDrop( HTREEITEM currentItem )
{
// Only files are draggable
BOOL underMyRoot;
if( GetItemLevel( currentItem, &underMyRoot ) != 2 )
return FALSE;
// Store the change this is from
m_DragFromChange=GetParentItem(currentItem);
// Dont actually send data - clipboard format is all the info target requires
/*(DYNAMIC_DOWNCAST(CDeltaView,GetView()))->*/m_OLESource.DelayRenderData( (unsigned short) m_CF_DELTA); // for P4WIN
/*(DYNAMIC_DOWNCAST(CDeltaView,GetView()))->*/m_OLESource.DelayRenderData( (unsigned short) CF_HDROP); // for external programs (dragging to an editor)
// We lie here and tell it we will only do COPY, but actually we will really do a MOVE
// if we drop the selection on another changelist. This lie is done to prevent other
// external programs that can accept a drag&drop from MOVing the files; they will only
// COPY the files, never MOVE them. Note that this means if you drag a file to
// Explorer, you will copy it to the new location, not move it.
m_DragDropCtr++;
if(/*(DYNAMIC_DOWNCAST(CDeltaView,GetView()))->*/m_OLESource.DoDragDrop(DROPEFFECT_COPY, &m_DragSourceRect, NULL) == DROPEFFECT_MOVE)
{
// this code is probably now obsolete since we don't call DoDragDrop() with
// DROPEFFECT_MOVE anymore. But I'll leave it, just in case....
m_LastDragDropTime = GetTickCount();// record the time so we can distinguish between CF_HDROP's from this window and CF_HDROP's from an external window
UnselectAll();
return TRUE;
}
else
{
m_LastDragDropTime = GetTickCount();// record the time so we can distinguish between CF_HDROP's from this window and CF_HDROP's from an external window
return FALSE;
}
}
// This rountine provides a list of dropped file names for CF_HDROP format drag and drop
// when the Changelist pane is the source of the drag and drop.
// The return value is the length of all the file names plus number of files (this is one less
// than the length of the memory needed to render the file names). If there is nothing to
// render, the return value is 0.
// Call this routine with a NULL to just obtain the length needed for the buffer; call it
// with a pointer to the addr of a buffer in order to load that buffer with the file names.
int CDeltaTreeCtrl::RenderFileNames(LPTSTR p)
{
static LPTSTR pFN = 0; // ptr to buffer to store file names to be rendered
static DWORD lFN = 0; // lgth of buffer at pFN
static DWORD uFN = 0; // amt of buffer at pFN actually in use
static DWORD ddCtr = 0; // counter to validate contents of buffer at pFN
LPTSTR ptr;
int i;
// If the change list pane is the drop target, don't provide a list of files
// because files from the chglist pane to the chglist pane are NOT in CF_HDROP format.
if ( m_DeltaIsDropTarget )
return 0;
if (!pFN)
{
pFN = (LPTSTR)::VirtualAlloc(NULL, lFN = 4096*sizeof(TCHAR), MEM_COMMIT, PAGE_READWRITE);
if (!pFN)
return(0); // out of memory!
}
else if (ddCtr == m_DragDropCtr) // is this D&D the same as the one we have stored?
{
if (p)
memcpy(p, pFN, uFN*sizeof(TCHAR));
return uFN;
}
for(i=GetSelectedCount()-1, ptr = pFN, uFN = 0; i>=0; i--)
{
HTREEITEM item= GetSelectedItem(i);
if( IsMyPendingChangeFile( item ) )
{
CString clientPath;
if(GetClientPath(item, clientPath))
{
if ((ptr + clientPath.GetLength() + (2*sizeof(TCHAR)))
>= (pFN + (lFN/sizeof(TCHAR)))) // running out of room?
{
LPTSTR sav = (LPTSTR)::VirtualAlloc(NULL, (lFN + 4096)*sizeof(TCHAR), MEM_COMMIT, PAGE_READWRITE);
if (!sav)
return(0); // we're in trouble - out of memory!
memcpy(sav, pFN, uFN*sizeof(TCHAR));
ptr = sav + (ptr - pFN);
::VirtualFree(pFN, 0, MEM_RELEASE);
pFN = sav;
lFN += 4096;
}
lstrcpy(ptr, clientPath);
ptr += clientPath.GetLength() + 1;
uFN += clientPath.GetLength() + 1;
}
}
}
*ptr = _T('\0');
ddCtr = m_DragDropCtr;
if (p)
memcpy(p, pFN, uFN*sizeof(TCHAR));
return uFN;
}
// Render CF_HDROP format drag and drop data. Note that this routine is NOT a CDeltaTreeCtrl
// routine - it is an override of COleDataSource for m_OLESource. It calls back to
// CDeltaTreeCtrl::RenderFileNames() to render the files names - it just sets up the structure
// that will hold the rendered file names.
BOOL CP4OleDataSource::OnRenderData( LPFORMATETC lpFormatEtc, LPSTGMEDIUM lpStgMedium )
{
int lgth;
if ((lgth = m_deltaTree->RenderFileNames(NULL)) == 0)
return FALSE;
lpStgMedium->tymed = TYMED_HGLOBAL;
lpStgMedium->hGlobal = GlobalAlloc(GHND, sizeof(_DROPFILES) + (lgth + 2)*sizeof(TCHAR));
LPDROPFILES lpdropfiles = (LPDROPFILES)GlobalLock(lpStgMedium->hGlobal);
lpdropfiles->pFiles = sizeof(_DROPFILES);
lpdropfiles->pt.x = 0;
lpdropfiles->pt.y = 0;
lpdropfiles->fNC = FALSE;
#ifdef UNICODE
lpdropfiles->fWide = TRUE;
#else
lpdropfiles->fWide = FALSE;
#endif
BOOL rc = m_deltaTree->RenderFileNames((LPTSTR)((char*)lpdropfiles + lpdropfiles->pFiles))
? TRUE : FALSE;
GlobalUnlock(lpStgMedium->hGlobal);
if (!rc) // if there were no file names rendered, clean up
{
GlobalFree(lpStgMedium->hGlobal);
lpStgMedium->hGlobal = 0;
}
return rc;
}
//////////////////////////////////////////////////////////////////////////////////
// Context menu implementation. Due to an apparent MFC bug, two mouse click handlers
// are included to make this work. Prolly in the next release of MFC, the default
// OnCOntextMenu linkage can be used.
void CDeltaTreeCtrl::OnContextMenu(CWnd* pWnd, CPoint point)
{
BOOL defChange;
m_ContextPoint = point;
GetParentFrame()->ActivateFrame();
m_Need2Edit = FALSE;
HTREEITEM currentItem;
SetItemAndPoint( currentItem, point );
ClientToScreen( &point );
BOOL underMyRoot=FALSE;
int Level=0;
if(currentItem != NULL)
Level=GetItemLevel(currentItem, &underMyRoot);
// Create the empty menus
CP4Menu popMenu;
popMenu.CreatePopupMenu();
CP4Menu editMenu;
editMenu.CreatePopupMenu();
CP4Menu viewMenu;
CP4Menu annotateMenu;
CP4Menu resolveMenu;
resolveMenu.CreatePopupMenu( );
// make a new selection new if reqd
if(!IsSelected(currentItem))
{
UnselectAll();
SetSelectState(currentItem, TRUE);
}
// Most options only relevant for my own open files
if( currentItem == NULL || (!IsMyPendingChange( currentItem ) && !IsMyPendingChangeItem( currentItem )) )
{
if( currentItem != NULL && Level == 1)
{
popMenu.AppendMenu( stringsON, ID_CHANGE_DESCRIBE, LoadStringResource( IDS_DESCRIBEIT ) );
if(HasChildren(currentItem))
popMenu.AppendMenu( stringsON, ID_POSITIONDEPOT, LoadStringResource(IDS_FINDCHGFILESINDEPOT_F));
}
goto EndContext;
}
defChange= (Level==1 && GetChangeNumber(currentItem)==0);
if(Level==1) // Its a change
{
// for all changelists with files in them. put submit first
//
if(HasChildren(currentItem))
{
popMenu.AppendMenu( stringsON, ID_CHANGE_SUBMIT );
popMenu.AppendMenu(MF_SEPARATOR);
}
// for numbered changelists only
//
if( !defChange)
{
popMenu.AppendMenu( stringsON, ID_CHANGE_EDSPEC, LoadStringResource( IDS_EDITSPEC ) );
popMenu.AppendMenu( stringsON, ID_CHANGE_DESCRIBE, LoadStringResource( IDS_DESCRIBEIT ) );
popMenu.AppendMenu( stringsON, ID_CHANGE_ADDJOBFIX, LoadStringResource( IDS_ADDJOBFIX ) );
}
// Choice for empty changes if not default
if(!HasChildren(currentItem) && !defChange)
popMenu.AppendMenu( stringsON, ID_CHANGE_DEL );
// Choices relevant only to non-empty change
if(HasChildren(currentItem))
{
popMenu.AppendMenu( stringsON, ID_CHANGE_REVORIG );
popMenu.AppendMenu( stringsON, ID_FILE_DIFFHEAD, LoadStringResource(IDS_DIFFFILESAGAINSTDEPOT));
popMenu.AppendMenu( stringsON, ID_POSITIONDEPOT, LoadStringResource(IDS_FINDCHGFILESINDEPOT_F));
}
}
if(Level==2) // Its a file or job (jobs not supported yet)
{
if(AnyMyPendingChangeFiles())
{
if ( AnyMyInteg() || AnyMyBranch() )
{
if(!SERVER_BUSY() && IsEditableFile())
{
viewMenu.CreatePopupMenu();
viewMenu.AppendMenu( stringsON, ID_FILE_QUICKBROWSE,
LoadStringResource( IDS_ASSOCVIEWER ));
int actualMRUs=0;
for(int i=0; i < MAX_MRU_VIEWERS; i++)
{
if( GET_P4REGPTR()->GetMRUViewerName(i).GetLength() > 0 )
{
viewMenu.AppendMenu( stringsON, ID_FILE_BROWSER_1+i,
CString ( _T("&") + GET_P4REGPTR()->GetMRUViewerName(i)) );
actualMRUs++;
}
}
viewMenu.AppendMenu( stringsON, ID_FILE_NEWBROWSER,
LoadStringResource ( IDS_OTHERVIEWER ) );
if(!SERVER_BUSY() && viewMenu.GetMenuItemCount() > 0)
{
popMenu.AppendMenu(MF_POPUP, (UINT) viewMenu.GetSafeHmenu(),
LoadStringResource( IDS_VIEWUSING ));
}
}
}
if(!SERVER_BUSY() && IsEditableFile())
{
editMenu.AppendMenu( stringsON, ID_FILE_QUICKEDIT,
LoadStringResource( IDS_ASSOCEDITOR ));
int actualMRUs=0;
for(int i=0; i < MAX_MRU_VIEWERS; i++)
{
if( GET_P4REGPTR()->GetMRUViewerName(i).GetLength() > 0 )
{
editMenu.AppendMenu( stringsON, ID_FILE_EDITOR_1+i,
CString ( _T("&") + GET_P4REGPTR()->GetMRUViewerName(i)) );
actualMRUs++;
}
}
editMenu.AppendMenu( stringsON, ID_FILE_NEWEDITOR, LoadStringResource ( IDS_OTHEREDITOR ) );
editMenu.AppendMenu( stringsON, ID_FILE_RMVEDITOR, LoadStringResource ( IDS_RMVEDITOR ));
}
if(!SERVER_BUSY() && editMenu.GetMenuItemCount() > 0)
{
popMenu.AppendMenu(MF_POPUP, (UINT) editMenu.GetSafeHmenu(),
LoadStringResource( IDS_EDITUSING ));
}
if ( AnyMyInteg() || AnyMyBranch() )
popMenu.AppendMenu( stringsON, ID_FILE_OPENEDIT, LoadStringResource( IDS_REOPENFOREDIT ) );
popMenu.AppendMenu( stringsON, ID_FILE_DIFFHEAD,
LoadStringResource(GetSelectedCount() > 1 ? IDS_DIFFFILESAGAINSTDEPOT : IDS_DIFFFILEAGAINSTDEPOT) );
if(!SERVER_BUSY())
{
popMenu.AppendMenu(stringsON, ID_FILETYPE, LoadStringResource( IDS_CHANGEFILETYPE) );
popMenu.AppendMenu(stringsON, ID_FILE_MV2OTHERCHGLIST, LoadStringResource( IDS_FILE_MV2OTHERCHGLIST) );
}
if(AnyMyUnLocked())
popMenu.AppendMenu( stringsON, ID_FILE_LOCK, LoadStringResource( IDS_LOCK ) );
if(AnyMyLock())
popMenu.AppendMenu( stringsON, ID_FILE_UNLOCK, LoadStringResource( IDS_UNLOCK ) );
}
}
if (((Level==1) && HasChildren(currentItem)) || ((Level==2) && AnyMyPendingChangeFiles())) // for both changes and files
{
resolveMenu.AppendMenu( stringsON, ID_FILE_RESOLVE, LoadStringResource( IDS_INTERACTIVELY ) );
resolveMenu.AppendMenu( stringsON, ID_FILE_AUTORESOLVE, LoadStringResource( IDS_AUTORESOLVE ) );
resolveMenu.AppendMenu( stringsON, ID_FILE_RUNMERGETOOL, LoadStringResource( IDS_RUNMERGETOOL ) );
resolveMenu.AppendMenu( stringsON, ID_FILE_SCHEDULE,
LoadStringResource(((Level==1) || (GetSelectedCount() > 1)) ? IDS_SCHEDULEFILESFORRESOLVE
: IDS_SCHEDULEFILEFORRESOLVE) );
if (Level==2 && IsAFile(currentItem) && GetSelectedCount()==1 && !SERVER_BUSY()
&& IsMyPendingChangeItem(currentItem))
{
CP4FileStats *stats= (CP4FileStats *) GetLParam(currentItem);
if(stats != NULL && (stats->IsUnresolved() || stats->IsResolved()))
{
resolveMenu.AppendMenu(MF_SEPARATOR);
resolveMenu.AppendMenu( stringsON, ID_THEIRFILE_PROPERTIES, LoadStringResource( IDS_THEIRFILE_PROPERTIES ) );
resolveMenu.AppendMenu( stringsON, ID_THEIRFILE_REVISIONHISTORY, LoadStringResource( IDS_THEIRFILE_REVISIONHISTORY ) );
resolveMenu.AppendMenu( stringsON, ID_THEIRFILE_FINDINDEPOT, LoadStringResource( IDS_THEIRFILE_FINDINDEPOT ) );
}
}
if(!SERVER_BUSY())
popMenu.AppendMenu(MF_POPUP, (UINT) resolveMenu.GetSafeHmenu(),
LoadStringResource ( (Level==1) ? IDS_MENU_RESOLVE_FILES : IDS_MENU_RESOLVE ) );
}
if (Level == 2) // rest of a file or job
{
if( IsAFile(currentItem) )
{
if (!SERVER_BUSY() && GET_SERVERLEVEL() >= 14 && GetSelectedCount()==1)
{
CP4FileStats *fs= (CP4FileStats *) GetLParam( GetSelectedItem(0) );
BOOL enable = ( fs->GetHaveRev() <= 1
&& ( fs->GetMyOpenAction() == F_ADD
|| fs->GetMyOpenAction() == F_BRANCH ) ) ? FALSE : TRUE;
if (enable)
{
CString fileType = fs->GetHeadType();
enable = ((fileType.Find(_T("text")) != -1)
|| (fileType.Find(_T("symlink")) != -1)) ? TRUE : FALSE;
}
if (enable)
{
annotateMenu.CreatePopupMenu();
annotateMenu.AppendMenu( stringsON, ID_FILE_ANNOTATE, LoadStringResource ( IDS_FILE_ANNOTATE ) );
annotateMenu.AppendMenu( stringsON, ID_FILE_ANNOTATEALL, LoadStringResource ( IDS_FILE_ANNOTATEALL ) );
annotateMenu.AppendMenu( stringsON, ID_FILE_ANNOTATECHG, LoadStringResource ( IDS_FILE_ANNOTATECHG ) );
annotateMenu.AppendMenu( stringsON, ID_FILE_ANNOTATECHGALL, LoadStringResource ( IDS_FILE_ANNOTATECHGALL ) );
popMenu.AppendMenu(MF_POPUP, (UINT) annotateMenu.GetSafeHmenu(),
LoadStringResource( IDS_ANNOTATEFILE ));
}
}
popMenu.AppendMenu( stringsON, ID_FILE_PROPERTIES, LoadStringResource( IDS_PROPERTIES ) );
if (MainFrame()->HaveP4QTree())
popMenu.AppendMenu( stringsON, ID_FILE_REVISIONTREE,LoadStringResource( IDS_REVISIONTREE ) );
if (MainFrame()->HaveTLV())
popMenu.AppendMenu( stringsON, ID_FILE_ANNOTATIONS, LoadStringResource( IDS_ANNOTATIONS ));
popMenu.AppendMenu( stringsON, ID_FILE_REVISIONHISTORY, LoadStringResource( IDS_REVISIONHISTORY ) );
if (!GetChangeNumber(currentItem)) // is it the default change?
{
popMenu.AppendMenu( MF_SEPARATOR );
popMenu.AppendMenu( stringsON, ID_CHANGE_SUBMIT, LoadStringResource( IDS_SUBMIT_SELECTED ) );
}
popMenu.AppendMenu( MF_SEPARATOR);
popMenu.AppendMenu( stringsON, ID_POSITIONDEPOT, LoadStringResource( IDS_POSITIONDEPOT ) );
BOOL b = TRUE;
if (GET_SERVERLEVEL() >= 19) // 2005.1 or later?
{
CP4FileStats *stats= (CP4FileStats *) GetLParam(currentItem);
if (stats->GetOtherOpenAction() == 0)
b = FALSE;
}
if (b)
popMenu.AppendMenu( stringsON, ID_POSITIONCHGS, LoadStringResource( IDS_POSITIONOTHERCHG ) );
if (GetSelectedCount()==1)
popMenu.AppendMenu( stringsON, ID_ADD_BOOKMARK, LoadStringResource(IDS_ADD_BOOKMARK) );
popMenu.AppendMenu( stringsON, ID_WINEXPLORE, LoadStringResource( IDS_EXPLORE ) );
popMenu.AppendMenu( stringsON, ID_CMDPROMPT, LoadStringResource( IDS_CMDPROMPT ) );
}
if(AnyJobs())
{
// job options
popMenu.AppendMenu( stringsON, ID_JOB_DESCRIBE, LoadStringResource( IDS_DESCRIBEFIXEDJOB ) );
popMenu.AppendMenu( stringsON, ID_JOB_EDITSPEC, LoadStringResource( ID_JOB_EDITSPEC ) );
popMenu.AppendMenu( stringsON, ID_CHANGE_REMOVEFIX, LoadStringResource( IDS_UNFIXJOB ) );
}
else
{
popMenu.AppendMenu( MF_SEPARATOR );
popMenu.AppendMenu( stringsON, ID_FILE_REVERT, LoadStringResource( IDS_REVERT ) );
}
}
EndContext:
if( currentItem != NULL && !IsMyPendingChangeItem( currentItem ) && Level == 2)
{
if ( IsAFile(currentItem) )
{
popMenu.AppendMenu( stringsON, ID_FILE_PROPERTIES, LoadStringResource( IDS_PROPERTIES ) );
popMenu.AppendMenu( stringsON, ID_FILE_REVISIONHISTORY, LoadStringResource( IDS_REVISIONHISTORY ) );
popMenu.AppendMenu( stringsON, ID_POSITIONDEPOT, LoadStringResource( IDS_POSITIONDEPOT ) );
popMenu.AppendMenu( stringsON, ID_POSITIONCHGS, LoadStringResource( IDS_POSITIONOTHERCHG ) );
}
else
popMenu.AppendMenu( stringsON, ID_JOB_DESCRIBE, LoadStringResource( IDS_DESCRIBEFIXEDJOB ));
}
if ( Level == 1 && popMenu.GetMenuItemCount( ) > 0 )
popMenu.AppendMenu(MF_SEPARATOR);
if ( Level != 2 )
{
popMenu.AppendMenu( stringsON, ID_CHANGE_NEW, LoadStringResource( IDS_NEWCHANGELIST ) );
popMenu.AppendMenu( stringsON, ID_SORTCHGFILESBYNAME, LoadStringResource( IDS_SORTCHGFILESBYNAME ) );
popMenu.AppendMenu( stringsON, ID_SORTCHGFILESBYEXT, LoadStringResource( IDS_SORTCHGFILESBYEXT ) );
popMenu.AppendMenu( stringsON, ID_SORTCHGFILESBYACTION, LoadStringResource( IDS_SORTCHGFILESBYACTION ) );
popMenu.AppendMenu( stringsON, ID_SORTCHGFILESBYRESOLVE, LoadStringResource( IDS_SORTCHGFILESBYRESOLVE ) );
popMenu.AppendMenu( stringsON, ID_SORTCHGSBYUSER, LoadStringResource( IDS_SORTCHGSBYUSER ) );
if( currentItem != NULL && !IsMyPendingChange( currentItem ) && Level == 1)
{
popMenu.AppendMenu( MF_SEPARATOR );
popMenu.AppendMenu( stringsON, ID_USER_SWITCHTOUSER, LoadStringResource(IDS_USER_SWITCHTOUSER));
}
if( currentItem != NULL && !underMyRoot && Level == 1)
popMenu.AppendMenu( stringsON, ID_CLIENTSPEC_SWITCH, LoadStringResource(IDS_CLIENTSPEC_SWITCH));
if( currentItem != NULL && !underMyRoot && Level == 0)
{
popMenu.AppendMenu( MF_SEPARATOR );
popMenu.AppendMenu(MF_ENABLED | MF_STRING, ID_FILTER_SETVIEW, LoadStringResource(IDS_FILTER_PCO_SETVIEW));
popMenu.AppendMenu(MF_ENABLED | MF_STRING, ID_FILTER_CLEARVIEW, LoadStringResource(IDS_FILTER_PCO_CLEARVIEW));
}
popMenu.AppendMenu( MF_SEPARATOR );
popMenu.AppendMenu( stringsON, ID_VIEW_UPDATE, LoadStringResource( IDS_REFRESH ) );
}
MainFrame()->AddToolsToContextMenu(&popMenu);
// Finally blast the menu onto the screen
m_InContextMenu = TRUE;
popMenu.TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, AfxGetMainWnd());
m_InContextMenu = FALSE;
}
void CDeltaTreeCtrl::OnRButtonDown(UINT nFlags, CPoint point)
{
// Do nothing
}
void CDeltaTreeCtrl::OnRButtonUp(UINT nFlags, CPoint point)
{
//CTreeView::OnRButtonUp(nFlags, point);
CPoint screenPt=point;
ClientToScreen(&screenPt);
m_ContextContext= MOUSEHIT;
OnContextMenu(NULL, screenPt);
}
//////////////////////////////////////////////////////////////////
// Handlers for OnUpdateUI
void CDeltaTreeCtrl::OnUpdateChangeDescribe(CCmdUI* pCmdUI)
{
long chgnbr = 0;
BOOL underMyRoot;
BOOL b = GetSelectedCount()==1 &&
GetItemLevel( GetSelectedItem(0), &underMyRoot ) == 1 &&
(chgnbr = GetSelectedChangeNumber()) > 0;
CString txt;
if (b)
txt.FormatMessage(IDS_DESCRIBEPENDING_d, chgnbr);
else
txt.LoadString(IDS_DESCRIBESUBMITTED);
pCmdUI->SetText ( txt );
pCmdUI->Enable(!SERVER_BUSY() && b);
}
void CDeltaTreeCtrl::OnUpdateChgEdspec(CCmdUI* pCmdUI)
{
pCmdUI->Enable(!SERVER_BUSY() && !m_EditInProgress &&
( IsSelectionSubmittableChange() ||
IsSelectionInSubmittableChange() ||
( GetSelectedCount()==1 &&
IsMyPendingChange(GetSelectedItem(0)) &&
GetChangeNumber(GetSelectedItem(0)) != 0) )
);
}
void CDeltaTreeCtrl::OnUpdateChgDel(CCmdUI* pCmdUI)
{
pCmdUI->SetText( LoadStringResource ( IDS_DELEMPTYCHANGELIST ) );
pCmdUI->Enable(!SERVER_BUSY() && GetSelectedCount()==1 &&
IsMyPendingChange(GetSelectedItem(0)) &&
!HasChildren(GetSelectedItem(0))
&& GetChangeNumber(GetSelectedItem(0)) != 0 );
}
void CDeltaTreeCtrl::OnUpdateChgNew(CCmdUI* pCmdUI)
{
pCmdUI->Enable(!SERVER_BUSY() && !m_EditInProgress);
}
void CDeltaTreeCtrl::OnUpdateChgRevorig(CCmdUI* pCmdUI)
{
pCmdUI->SetText( LoadStringResource ( IDS_REVERTUNCHANGED ) );
pCmdUI->Enable(!SERVER_BUSY() && GetSelectedCount()==1 &&
IsMyPendingChange(GetSelectedItem(0)) &&
AnyFilesInChange(GetSelectedItem(0)) );
}
void CDeltaTreeCtrl::OnUpdateChgSubmit(CCmdUI* pCmdUI)
{
pCmdUI->SetText( LoadStringResource ( IDS_SUBMIT ) );
pCmdUI->Enable( MainFrame()->SetMenuIcon(pCmdUI, !SERVER_BUSY() && !m_EditInProgress
&& ( IsSelectionSubmittableChange()
|| IsSelectionInSubmittableChange() ) ) );
}
void CDeltaTreeCtrl::OnUpdateFileLock(CCmdUI* pCmdUI)
{
pCmdUI->Enable( MainFrame()->SetMenuIcon(pCmdUI, !SERVER_BUSY() && AnyMyUnLocked()) );
}
void CDeltaTreeCtrl::OnUpdateFileUnlock(CCmdUI* pCmdUI)
{
pCmdUI->Enable( MainFrame()->SetMenuIcon(pCmdUI, !SERVER_BUSY() && AnyMyLock()) );
}
void CDeltaTreeCtrl::OnUpdateFileRevisionhistory(CCmdUI* pCmdUI)
{
BOOL root;
BOOL enable= (!SERVER_BUSY() && GetSelectedCount() == 1 &&
GetItemLevel(GetSelectedItem(0), &root)== 2 &&
IsAFile( GetSelectedItem(0)) );
if( enable )
{
CP4FileStats *fs= (CP4FileStats *) GetLParam( GetSelectedItem(0) );
if( fs->GetHaveRev() <= 1 &&
( fs->GetMyOpenAction() == F_ADD || fs->GetMyOpenAction() == F_BRANCH ) )
enable= FALSE;
}
pCmdUI->Enable( MainFrame()->SetMenuIcon(pCmdUI, enable) );
}
void CDeltaTreeCtrl::OnUpdateFileAnnotate(CCmdUI* pCmdUI)
{
BOOL root;
BOOL enable = !SERVER_BUSY() && GET_SERVERLEVEL() >= 14
&& GetSelectedCount()==1
&& GetItemLevel(GetSelectedItem(0), &root)== 2
&& IsAFile( GetSelectedItem(0) );
if( enable )
{
CP4FileStats *fs= (CP4FileStats *) GetLParam( GetSelectedItem(0) );
if( fs->GetHaveRev() <= 1 &&
( fs->GetMyOpenAction() == F_ADD || fs->GetMyOpenAction() == F_BRANCH ) )
enable= FALSE;
if (enable)
{
CString fileType = fs->GetHeadType();
enable = ((fileType.Find(_T("text")) != -1)
|| (fileType.Find(_T("symlink")) != -1)) ? TRUE : FALSE;
}
}
pCmdUI->Enable( MainFrame()->SetMenuIcon(pCmdUI, enable) );
}
void CDeltaTreeCtrl::OnUpdateWinExplore(CCmdUI* pCmdUI)
{
BOOL root;
pCmdUI->Enable(GetSelectedCount() &&
GetItemLevel(GetSelectedItem(0), &root)== 2 &&
IsMyPendingChangeFile( GetSelectedItem(0)) );
}
void CDeltaTreeCtrl::OnUpdateCmdPrompt(CCmdUI* pCmdUI)
{
BOOL root;
pCmdUI->Enable(GetSelectedCount() &&
GetItemLevel(GetSelectedItem(0), &root)== 2 &&
IsMyPendingChangeFile( GetSelectedItem(0)) );
}
void CDeltaTreeCtrl::OnUpdateFileGet(CCmdUI* pCmdUI)
{
pCmdUI->Enable( MainFrame()->SetMenuIcon(pCmdUI, !SERVER_BUSY()
&& GetSelectedCount() > 0
&& IsMyPendingChangeFile(GetSelectedItem(0))) );
}
void CDeltaTreeCtrl::OnUpdateFileDiffhead(CCmdUI* pCmdUI)
{
pCmdUI->Enable(MainFrame()->SetMenuIcon(pCmdUI, !SERVER_BUSY()
&& GetSelectedCount() > 0
&& (IsMyPendingChangeFile(GetSelectedItem(0))
|| (IsMyPendingChange(GetSelectedItem(0))
&& AnyFilesInChange(GetSelectedItem(0))))));
}
void CDeltaTreeCtrl::OnUpdateFiletype(CCmdUI* pCmdUI)
{
pCmdUI->Enable(!SERVER_BUSY() && GetSelectedCount() > 0 &&
AnyMyPendingChangeFiles() );
}
void CDeltaTreeCtrl::OnUpdateMoveFiles(CCmdUI* pCmdUI)
{
pCmdUI->Enable(!SERVER_BUSY() && GetSelectedCount() > 0
&& AnyMyPendingChangeFiles()
&& !m_EditInProgress );
}
void CDeltaTreeCtrl::OnUpdateJobDescribe(CCmdUI* pCmdUI)
{
pCmdUI->Enable( OnUpdateJob(pCmdUI, IDS_DESCRIBEIT_s) );
}
void CDeltaTreeCtrl::OnUpdateJobEditspec( CCmdUI* pCmdUI )
{
pCmdUI->Enable( OnUpdateJob(pCmdUI, IDS_EDITSPEC_s) );
}
BOOL CDeltaTreeCtrl::OnUpdateJob(CCmdUI* pCmdUI, int msgnbr)
{
BOOL bEnable = FALSE;
int cnt = GetSelectedCount();
if (!SERVER_BUSY() && cnt >= 1 && AnyJobs())
{
HTREEITEM item= GetSelectedItem(0);
int i = 0;
if (cnt > 1)
{
BOOL underMyRoot;
int level= GetItemLevel(item, &underMyRoot);
if(level ==2)
{
for( ; i < cnt; i++)
{
if(GetLParam(GetSelectedItem(i)) == NULL)
{
item= GetSelectedItem(i);
break;
}
}
}
}
if (item == NULL || GetLParam(item) != NULL)
ASSERT(0);
else
{
CString itemStr=GetItemText(item);
itemStr.TrimLeft();
if (!itemStr.IsEmpty( ))
{
CString txt;
txt.FormatMessage(msgnbr, TruncateString(itemStr, 50));
pCmdUI->SetText ( txt );
bEnable = TRUE;
}
}
}
return bEnable ;
}
void CDeltaTreeCtrl::OnUpdateAddjobfix(CCmdUI* pCmdUI)
{
pCmdUI->Enable(!SERVER_BUSY() &&
( (GetSelectedCount() == 1 && IsMyPendingChange(GetSelectedItem(0)) &&
GetChangeNumber(GetSelectedItem(0)) ) ||
IsSelectionInMyNumberedChange()) );
}
void CDeltaTreeCtrl::OnUpdateRemovefix(CCmdUI* pCmdUI)
{
pCmdUI->Enable(!SERVER_BUSY() && GetSelectedCount() == 1 &&
AnyJobs() );
}
void CDeltaTreeCtrl::OnUpdateFileRevert(CCmdUI* pCmdUI)
{
int cnt = GetSelectedCount();
HTREEITEM currentItem = GetSelectedItem(0);
pCmdUI->Enable( MainFrame()->SetMenuIcon(pCmdUI, !SERVER_BUSY() && cnt > 0
&& (AnyMyPendingChangeFiles() || (cnt == 1
&& IsMyPendingChange(currentItem)
&& AnyFilesInChange(currentItem)))) );
}
//////////////////////////////////////////////////////////////
// Funcions for use in OnUpdateUI handlers and OnContextMenu()
BOOL CDeltaTreeCtrl::IsMyPendingChange(HTREEITEM currentItem)
{
BOOL myChange= FALSE;
BOOL underMyRoot;
int level= GetItemLevel(currentItem, &underMyRoot);
if(level==1 && underMyRoot)
{
if( GetImage( currentItem) != CP4ViewImageList::VI_YOUROTHERCHANGE )
myChange= TRUE;
}
return myChange;
}
BOOL CDeltaTreeCtrl::IsOpenedForInteg(HTREEITEM currentItem)
{
BOOL opened4integ= FALSE;
BOOL underMyRoot;
int level= GetItemLevel(currentItem, &underMyRoot);
if(level==2 && underMyRoot && GetLParam(currentItem) != NULL)
{
CP4FileStats *fs= (CP4FileStats *) GetLParam(currentItem);
if(fs->GetMyOpenAction()==F_INTEGRATE && fs->GetHaveRev() != 0)
{
opened4integ=TRUE;
}
}
return opened4integ;
}
BOOL CDeltaTreeCtrl::IsOpenedForBranch(HTREEITEM currentItem)
{
BOOL opened4branch= FALSE;
BOOL underMyRoot;
int level= GetItemLevel(currentItem, &underMyRoot);
if(level==2 && underMyRoot && GetLParam(currentItem) != NULL)
{
CP4FileStats *fs= (CP4FileStats *) GetLParam(currentItem);
if(fs->GetMyOpenAction()==F_BRANCH && fs->GetHaveRev() != 0)
{
opened4branch=TRUE;
}
}
return opened4branch;
}
BOOL CDeltaTreeCtrl::IsMyPendingChangeFile(HTREEITEM currentItem)
{
BOOL myFile= FALSE;
BOOL underMyRoot;
int level= GetItemLevel(currentItem, &underMyRoot);
if(level==2 && underMyRoot && GetLParam(currentItem) != NULL)
{
CP4FileStats *fs= (CP4FileStats *) GetLParam(currentItem);
if( !fs->IsOtherUserMyClient() )
myFile= TRUE;
}
return myFile;
}
BOOL CDeltaTreeCtrl::IsMyPendingChangeItem(HTREEITEM currentItem)
{
BOOL myItem= FALSE;
BOOL underMyRoot;
int level= GetItemLevel(currentItem, &underMyRoot);
if(level==2 && underMyRoot)
{
HTREEITEM changeItem= GetParentItem(currentItem);
if( GetImage( changeItem ) != CP4ViewImageList::VI_YOUROTHERCHANGE )
myItem= TRUE;
}
return myItem;
}
BOOL CDeltaTreeCtrl::IsSelectionSubmittableChange()
{
// True if only one item is selected and that item is a change
// that I can be submit
return ( GetSelectedCount()==1 &&
IsMyPendingChange(GetSelectedItem(0)) &&
AnyFilesInChange(GetSelectedItem(0)) );
}
BOOL CDeltaTreeCtrl::IsSelectionInSubmittableChange()
{
// True if item(s) selected are in a change
// that I can be submit
return ( GetSelectedCount() > 0 &&
IsMyPendingChangeItem(GetSelectedItem(0)) &&
AnyFilesInChange( GetParentItem(GetSelectedItem(0)) ) );
}
BOOL CDeltaTreeCtrl::IsSelectionInMyNumberedChange()
{
// True if item(s) selected are in my numbered (not default) change
if( GetSelectedCount() == 0 )
return FALSE;
HTREEITEM parentItem=GetParentItem(GetSelectedItem(0));
if(parentItem == NULL)
return FALSE;
return( IsMyPendingChange(parentItem) && GetChangeNumber(parentItem) > 0 );
}
BOOL CDeltaTreeCtrl::AnyMyPendingChangeFiles()
{
BOOL myChangeFile=FALSE;
for(int i=GetSelectedCount()-1; i>=0; i--)
{
if(IsMyPendingChangeFile(GetSelectedItem(i)))
{
myChangeFile=TRUE;
break;
}
}
return myChangeFile;
}
BOOL CDeltaTreeCtrl::AnyJobs()
{
BOOL anyJobs=FALSE;
if(GetSelectedCount() ==0 )
{ return FALSE; }
HTREEITEM firstItem= GetSelectedItem(0);
BOOL underMyRoot;
int level= GetItemLevel(firstItem, &underMyRoot);
if(level ==2)
{
for(int i=GetSelectedCount()-1; i>=0; i--)
{
if(GetLParam(GetSelectedItem(i)) == NULL)
{
anyJobs=TRUE;
break;
}
}
}
return anyJobs;
}
BOOL CDeltaTreeCtrl::AnyFilesInChange( HTREEITEM changeItem )
{
BOOL anyFiles=FALSE;
if( changeItem == NULL )
{ return FALSE; }
HTREEITEM child= GetChildItem( changeItem );
while( child != NULL )
{
if( GetLParam( child ) > 0 )
{
anyFiles= TRUE;
break;
}
child= GetNextSiblingItem( child );
}
return anyFiles;
}
BOOL CDeltaTreeCtrl::AnyMyInteg()
{
BOOL anyMyInteg=FALSE;
if(GetSelectedCount() ==0 )
{ return FALSE; }
HTREEITEM firstItem= GetSelectedItem(0);
if(IsMyPendingChangeItem( firstItem ))
{
for(int i=GetSelectedCount()-1; i>=0; i--)
{
if(IsOpenedForInteg(GetSelectedItem(i)))
{
anyMyInteg=TRUE;
break;
}
}
}
return anyMyInteg;
}
BOOL CDeltaTreeCtrl::AnyMyBranch()
{
BOOL anyMyBranch=FALSE;
if(GetSelectedCount() ==0 )
{ return FALSE; }
HTREEITEM firstItem= GetSelectedItem(0);
if(IsMyPendingChangeItem( firstItem ))
{
for(int i=GetSelectedCount()-1; i>=0; i--)
{
if(IsOpenedForBranch(GetSelectedItem(i)))
{
anyMyBranch=TRUE;
break;
}
}
}
return anyMyBranch;
}
BOOL CDeltaTreeCtrl::AnyMyLock()
{
BOOL anyMyLock=FALSE;
if(GetSelectedCount() ==0 )
{ return FALSE; }
HTREEITEM firstItem= GetSelectedItem(0);
CP4FileStats *stats;
if(IsMyPendingChangeItem( firstItem ))
{
for(int i=GetSelectedCount()-1; i>=0; i--)
{
stats= (CP4FileStats *) GetLParam(GetSelectedItem(i));
if(stats != NULL)
{
if(stats->IsMyLock())
{
anyMyLock=TRUE;
break;
}
}
}
}
return anyMyLock;
}
BOOL CDeltaTreeCtrl::AnyMyUnLocked()
{
BOOL anyMyUnLocked=FALSE;
if(GetSelectedCount() ==0 )
{ return FALSE; }
HTREEITEM firstItem= GetSelectedItem(0);
CP4FileStats *stats;
if(IsMyPendingChangeItem(firstItem))
{
for(int i=GetSelectedCount()-1; i>=0; i--)
{
stats= (CP4FileStats *) GetLParam(GetSelectedItem(i));
if(stats != NULL)
{
if(!stats->IsMyLock())
{
anyMyUnLocked=TRUE;
break;
}
}
}
}
return anyMyUnLocked;
}
// A file is consider binary (as far as this routine is concerned)
// if its base type is "binary"
// or its base type is "text" plus its storage type is C or F
BOOL CDeltaTreeCtrl::AnyBinaryFiles(BOOL bAnyResolvable/*=FALSE*/)
{
BOOL anyMyFilesBinary=FALSE;
if(GetSelectedCount() ==0 )
{ return FALSE; }
HTREEITEM firstItem= GetSelectedItem(0);
if(IsMyPendingChangeItem( firstItem ))
{
int baseType;
int storeType;
BOOL typeK;
BOOL typeW;
BOOL typeX;
BOOL typeO;
BOOL typeM;
BOOL typeL;
BOOL typeS;
int nbrrevs;
BOOL unknown;
for(int i=GetSelectedCount()-1; i>=0; i--)
{
TheApp()->GetFileType(GetItemText(GetSelectedItem(i)),
baseType, storeType, typeK, typeW, typeX,
typeO, typeM, typeL, typeS, nbrrevs, unknown);
if ((baseType == 1)
|| (baseType == 0 && (storeType == 1 || storeType == 3))
|| (baseType == 5 && (storeType == 1 || storeType == 3)))
{
if (bAnyResolvable)
{
CP4FileStats *stats = (CP4FileStats *) GetLParam(GetSelectedItem(i));
if(stats != NULL)
{
if (!stats->IsUnresolved() && !stats->IsResolved())
continue;
}
}
anyMyFilesBinary=TRUE;
break;
}
}
}
return anyMyFilesBinary;
}
BOOL CDeltaTreeCtrl::AnyUnresolvedFiles()
{
BOOL anyUnresolved=FALSE;
if(GetSelectedCount() ==0 )
{ return FALSE; }
HTREEITEM firstItem= GetSelectedItem(0);
CP4FileStats *stats;
if(IsMyPendingChangeItem(firstItem))
{
for(int i=GetSelectedCount()-1; i>=0; i--)
{
stats= (CP4FileStats *) GetLParam(GetSelectedItem(i));
if(stats != NULL)
{
if(stats->IsUnresolved())
{
anyUnresolved=TRUE;
break;
}
}
}
}
return anyUnresolved;
}
BOOL CDeltaTreeCtrl::AnyResolvedFiles(BOOL bList/*=FALSE*/)
{
BOOL anyResolved=FALSE;
if (bList)
m_StringList.RemoveAll();
if(GetSelectedCount() ==0 )
{ return FALSE; }
HTREEITEM firstItem= GetSelectedItem(0);
CP4FileStats *stats;
if(IsMyPendingChangeItem(firstItem))
{
for(int i=GetSelectedCount()-1; i>=0; i--)
{
stats= (CP4FileStats *) GetLParam(GetSelectedItem(i));
if(stats != NULL)
{
if(stats->IsResolved())
{
anyResolved=TRUE;
if (bList)
m_StringList.AddHead(stats->GetFullDepotPath());
else break;
}
}
}
}
return anyResolved;
}
BOOL CDeltaTreeCtrl::AnyUnresolvedFilesInChg(HTREEITEM chgitem)
{
BOOL anyUnresolved=FALSE;
CP4FileStats *stats;
HTREEITEM item=GetChildItem(chgitem);
while(item!=NULL)
{
if(IsAFile(item))
{
stats= (CP4FileStats *) GetLParam(item);
if(stats != NULL)
{
if(stats->IsUnresolved())
{
anyUnresolved=TRUE;
break;
}
}
}
item=GetNextSiblingItem(item);
}
return anyUnresolved;
}
BOOL CDeltaTreeCtrl::AnyResolvedFilesInChg(HTREEITEM chgitem)
{
BOOL anyResolved=FALSE;
CP4FileStats *stats;
HTREEITEM item=GetChildItem(chgitem);
while(item!=NULL)
{
if(IsAFile(item))
{
stats= (CP4FileStats *) GetLParam(item);
if(stats != NULL)
{
if(stats->IsResolved())
{
anyResolved=TRUE;
break;
}
}
}
item=GetNextSiblingItem(item);
}
return anyResolved;
}
BOOL CDeltaTreeCtrl::AnyMyFilesUnresolved( )
{
BOOL anyUnresolved=FALSE;
HTREEITEM change= GetChildItem(m_MyRoot);
HTREEITEM file;
LPARAM lParam;
while(change != NULL && !anyUnresolved)
{
file= GetChildItem(change);
while(file != NULL && !anyUnresolved)
{
lParam=GetLParam(file);
if(lParam > 0)
{
CP4FileStats *stats= (CP4FileStats *) lParam;
ASSERT_KINDOF(CP4FileStats, stats);
if(stats->IsUnresolved())
{
anyUnresolved=TRUE;
break;
}
}
file=GetNextSiblingItem(file);
}
change=GetNextSiblingItem(change);
}
return anyUnresolved;
}
BOOL CDeltaTreeCtrl::AnyMyFilesResolved(BOOL bList/*=FALSE*/)
{
BOOL anyResolved=FALSE;
if (bList)
m_StringList.RemoveAll();
HTREEITEM change= GetChildItem(m_MyRoot);
HTREEITEM file;
LPARAM lParam;
while(change != NULL && (!anyResolved || bList))
{
file= GetChildItem(change);
while(file != NULL && (!anyResolved || bList))
{
lParam=GetLParam(file);
if(lParam > 0)
{
CP4FileStats *stats= (CP4FileStats *) lParam;
ASSERT_KINDOF(CP4FileStats, stats);
if(stats->IsResolved())
{
anyResolved=TRUE;
if (bList)
m_StringList.AddHead(stats->GetFullDepotPath());
else break;
}
}
file=GetNextSiblingItem(file);
}
change=GetNextSiblingItem(change);
}
return anyResolved;
}
void CDeltaTreeCtrl::OnUpdateFileAutoresolve(CCmdUI* pCmdUI)
{
BOOL root;
BOOL rc = FALSE;
if (!SERVER_BUSY() && GetSelectedCount() > 0)
{
HTREEITEM item = GetSelectedItem(0);
int level = GetItemLevel(item, &root);
if (level == 2)
rc = ((AnyMyFilesUnresolved() || AnyMyFilesResolved())
&& IsMyPendingChangeFile(item)
&& IsAFile( item) );
else if (level == 1)
rc = (IsMyPendingChange(item)
&& (AnyUnresolvedFilesInChg(item) || AnyResolvedFilesInChg(item))
&& GetSelectedCount()==1);
}
pCmdUI->Enable(rc);
}
void CDeltaTreeCtrl::OnUpdateFileResolve(CCmdUI* pCmdUI)
{
BOOL root;
BOOL rc = FALSE;
if (!SERVER_BUSY() && GetSelectedCount() > 0)
{
HTREEITEM item = GetSelectedItem(0);
int level = GetItemLevel(item, &root);
if (level == 2)
rc = ((AnyUnresolvedFiles() || AnyResolvedFiles())
&& IsMyPendingChangeFile(item) );
else if (level == 1)
rc = (IsMyPendingChange(GetSelectedItem(0))
&& (AnyUnresolvedFilesInChg(item) || AnyResolvedFilesInChg(item))
&& GetSelectedCount()==1);
}
pCmdUI->Enable(rc);
}
void CDeltaTreeCtrl::OnUpdateTheirFile(CCmdUI* pCmdUI)
{
BOOL root;
HTREEITEM item = GetSelectedItem(0);
if (!SERVER_BUSY() && GetSelectedCount() == 1 && GetItemLevel(item, &root) == 2)
OnUpdateFileResolve(pCmdUI);
else
pCmdUI->Enable(FALSE);
}
void CDeltaTreeCtrl::OnFileAutoresolve()
{
BOOL root;
HTREEITEM initialItem = GetSelectedItem(0);
int level = GetItemLevel(initialItem, &root);
if (level == 1)
{
SelectAllFilesInChange(initialItem, 2);
if (GetSelectedCount() < 1)
{
UnselectAll();
SetSelectState(initialItem, TRUE);
return;
}
else if (GetSelectedCount() > 32000)
{
AfxMessageBox(IDS_UNABLE_TO_RESOLVE_MORE_THAN_32000_FILES, MB_ICONEXCLAMATION);
UnselectAll();
SetSelectState(initialItem, TRUE);
return;
}
}
MainFrame()->DoNotAutoPoll();
CAutoResolveDlg dlg;
BOOL u = AnyUnresolvedFiles();
BOOL r = AnyResolvedFiles();
dlg.m_NoSel2Res = (GetSelectedCount() && (u || r)) ? FALSE : TRUE;
if (!u && r)
dlg.m_ReResolve = TRUE;
dlg.m_SelResolved = r;
dlg.m_AnyResolved = AnyMyFilesResolved();
dlg.m_ResolveFromChgList = (level == 1);
dlg.m_pDeltaTreeCtrl = this;
SetAppearance(TRUE, FALSE, FALSE);
InvalidateRect( NULL, FALSE );
UpdateWindow( );
SetSelectAtts(TVIS_SELECTED); // Clear the flag we set in call to SetAppearance() above
if (dlg.DoModal() == IDOK)
{
if (dlg.m_AllFiles)
m_StringList.RemoveAll();
else
{
if ((level == 1) && r && !dlg.m_ReResolve)
{
SelectAllFilesInChange(initialItem, 1);
SetAppearance(TRUE, FALSE, FALSE);
InvalidateRect( NULL, FALSE );
UpdateWindow( );
SetSelectAtts(TVIS_SELECTED); // Clear the flag we set in call to SetAppearance() above
if (GetSelectedCount() < 1)
{
UnselectAll();
SetSelectState(initialItem, TRUE);
AddToStatus(_T("0 files resolved"), SV_COMPLETION);
MainFrame()->ResumeAutoPoll();
return;
}
}
AssembleStringList( );
}
CCmd_AutoResolve *pCmd= new CCmd_AutoResolve;
pCmd->Init( m_hWnd, RUN_ASYNC, HOLD_LOCK );
if( pCmd->Run( &m_StringList, dlg.m_ResolveType,
dlg.m_Preview, dlg.m_ReResolve, dlg.m_TextMerge, dlg.m_ResolveWhtSp ) )
MainFrame()->UpdateStatus( LoadStringResource(IDS_AUTO_RESOLVING) );
else
delete pCmd;
}
if (level == 1)
{
UnselectAll();
SetSelectState(initialItem, TRUE);
}
MainFrame()->ResumeAutoPoll();
}
void CDeltaTreeCtrl::OnFileResolve()
{
OnFileMergeResolve(FALSE);
}
void CDeltaTreeCtrl::OnFileMerge()
{
OnFileMergeResolve(TRUE);
}
void CDeltaTreeCtrl::OnFileMergeResolve(BOOL bRunMerge)
{
int r, b, havehead;
if (!GetSelectedCount())
return;
m_bRunMerge = bRunMerge;
HTREEITEM initialItem = GetSelectedItem(0);
BOOL root;
int level = GetItemLevel(initialItem, &root);
if (level == 1)
{
SelectAllFilesInChange(initialItem, 2);
if (GetSelectedCount() < 1)
{
UnselectAll();
SetSelectState(initialItem, TRUE);
return;
}
else if (GetSelectedCount() > 32000)
{
AfxMessageBox(IDS_UNABLE_TO_RESOLVE_MORE_THAN_32000_FILES, MB_ICONEXCLAMATION);
UnselectAll();
SetSelectState(initialItem, TRUE);
return;
}
}
if (!IsMyPendingChangeItem(GetSelectedItem(0)))
{
if (level == 1)
{
UnselectAll();
SetSelectState(initialItem, TRUE);
}
return;
}
SetAppearance(TRUE, FALSE, FALSE);
InvalidateRect( NULL, FALSE );
UpdateWindow( );
SetSelectAtts(TVIS_SELECTED); // Clear the flag we set in call to SetAppearance() above
HTREEITEM item;
BOOL textualMerge = FALSE;
r = AnyResolvedFiles();
b = AnyBinaryFiles(TRUE);
if (b)
{
b = FALSE;
textualMerge = TRUE;
CString appName;
for(int i=GetSelectedCount()-1; i>=0; i--)
{
int baseType;
int storeType;
BOOL typeK;
BOOL typeW;
BOOL typeX;
BOOL typeO;
BOOL typeM;
BOOL typeL;
BOOL typeS;
int nbrrevs;
BOOL unknown;
int j;
appName.Empty();
CString filename = GetItemText(item = GetSelectedItem(i));
TheApp()->GetFileType(filename, baseType, storeType, typeK, typeW, typeX,
typeO, typeM, typeL, typeS, nbrrevs, unknown);
if ((baseType == 1)
|| (baseType == 0 && (storeType == 1 || storeType == 3))
|| (baseType == 5 && (storeType == 1 || storeType == 3)))
{
CP4FileStats *stats = (CP4FileStats *) GetLParam(item);
if(stats != NULL)
{
if (!stats->IsUnresolved() && !stats->IsResolved())
continue;
}
CString extension = GetFilesExtension(filename);
if ((j = extension.Find(_T('#'))) != -1)
extension = extension.Left(j);
if(!extension.IsEmpty())
appName= GET_P4REGPTR()->GetAssociatedMerge(extension);
if (appName.IsEmpty())
{
b = TRUE;
textualMerge = FALSE;
break;
}
}
}
}
if (r || b)
{
if (GetSelectedCount() == 1)
{
CP4FileStats *stats= (CP4FileStats *) GetLParam(GetSelectedItem(0));
if(stats != NULL)
havehead = (stats->GetHeadRev() == stats->GetHaveRev()) ? 1 : 0;
else havehead = 0;
}
else havehead = 0;
if (r && !b && havehead && !AnyUnresolvedFiles())
{
m_ReResolve = TRUE;
m_TextualMerge = FALSE;
}
else
{
CResolveFlagsDlg dlg;
dlg.m_ReResolve = r;
dlg.m_TextualMerge = b;
if (dlg.DoModal() == IDOK)
{
m_ReResolve = dlg.m_ReResolve;
m_TextualMerge = b ? dlg.m_TextualMerge : textualMerge;
}
else return;
}
}
else
{
m_ReResolve = FALSE;
m_TextualMerge = textualMerge;
}
if (level == 1)
{
if (AnyResolvedFiles() && !m_ReResolve)
{
SelectAllFilesInChange(initialItem, 1);
SetAppearance(TRUE, FALSE, FALSE);
InvalidateRect( NULL, FALSE );
UpdateWindow( );
SetSelectAtts(TVIS_SELECTED); // Clear the flag we set in call to SetAppearance() above
if (GetSelectedCount() < 1)
{
UnselectAll();
SetSelectState(initialItem, TRUE);
AddToStatus(_T("0 files resolved"), SV_COMPLETION);
return;
}
}
// If the server is busy because we triggered an expand of a changelist
// and are getting the attached jobs, wait for the server to finish
if (SERVER_BUSY())
{
int t=GET_P4REGPTR()->BusyWaitTime();
do
{
Sleep(50);
t -= 50;
} while (SERVER_BUSY() && t > 0);
}
}
m_ResolveList.RemoveAll();
for(int i=GetSelectedCount()-1; i>=0; i--)
{
item = GetSelectedItem(i);
m_ResolveList.AddHead((CObject *)item);
}
// fire up a resolve on the first item
item = (HTREEITEM)(m_ResolveList.RemoveHead());
ResolveItem(item);
if (level == 1)
{
UnselectAll();
SetSelectState(initialItem, TRUE);
}
}
void CDeltaTreeCtrl::ResolveItem(HTREEITEM item)
{
BOOL bHeadIsText = FALSE;
m_ForcedResolve = FALSE;
m_ActiveItem=item;
CString itemStr = GetItemText(item);
itemStr=itemStr.Left(itemStr.ReverseFind(_T('#'))); // Strip revision number
CP4FileStats *stats = (CP4FileStats *) GetLParam(item);
if (stats != NULL)
{
bHeadIsText = stats->GetHeadType().Find(_T("text")) != -1 ? TRUE : FALSE;
if (m_ReResolve)
{
if (stats->IsResolved())
m_ForcedResolve = TRUE;
}
}
CCmd_Resolve *pCmd= new CCmd_Resolve;
pCmd->Init( m_hWnd, RUN_ASYNC);
pCmd->SetHeadIsText(bHeadIsText);
if( pCmd->Run( itemStr, m_ForcedResolve, m_TextualMerge ) )
MainFrame()->UpdateStatus( LoadStringResource(IDS_RESOLVE) );
else
delete pCmd;
}
void CDeltaTreeCtrl::SelectAllFilesInChange(HTREEITEM changeitem, int resolveFlag/*=0*/)
{
UnselectAll();
HTREEITEM item=GetChildItem(changeitem);
while(item!=NULL)
{
BOOL bOK = IsAFile(item);
if (resolveFlag && bOK)
{
bOK = FALSE;
CP4FileStats *stats = (CP4FileStats *) GetLParam(item);
if(stats != NULL)
{
if (stats->IsUnresolved() || ((resolveFlag == 2) && stats->IsResolved()))
bOK = TRUE;
}
}
if(bOK)
SetSelectState(item, TRUE);
item=GetNextSiblingItem(item);
}
}
void CDeltaTreeCtrl::OnDestroy()
{
// Traverse tree, deleting each item's lParam
// Cant wait till destructor, because Treeview items
// are deleted by common ctrl before the destructor is called
DeleteLParams(m_MyRoot);
if (m_OthersRoot)
{
DeleteLParams(m_OthersRoot);
m_OthersRoot = NULL;
}
CMultiSelTreeCtrl::OnDestroy();
}
void CDeltaTreeCtrl::ReopenAs(LPCTSTR newtype)
{
if(GetSelectedCount()==0)
{
ASSERT(0);
return;
}
AssembleStringList( );
CCmd_ListOpStat *pCmd= new CCmd_ListOpStat;
pCmd->Init( m_hWnd, RUN_ASYNC, HOLD_LOCK );
if( pCmd->Run( &m_StringList, P4REOPEN, -1, newtype ) )
MainFrame()->UpdateStatus( LoadStringResource(IDS_REOPENING_FILES) );
else
delete pCmd;
}
///////////////////////////////////////////////////////////////////////////////////////////////
// Support for file editing
///////////////////////////////////////////////////////////////////////////////////////////////
//
// Command UI update functions:
// OnUpdateFileAutoedit(CCmdUI* pCmdUI)
//
// Main Menu command handlers
// OnFileQuickedit() (will use associated app)
// OnFileAutoedit() (will start with chooser dialog)
// ----> EditFile()
//
// Context Menu command handlers
// OnFileMRUEditor(UINT nID)
// OnFileNewEditor()
// OnFileQuickedit()
// ----> EditFile()
//
// Command goes to depot window
// EditFile()
// ----> SendMessage WM_FILEEDITTXT (or WM_FILEEDITBIN) to depot wnd,
// wparam= CString *path
// lparam= 0-(MAX_MRU-1) for MRU,
// 10 for quick edit,
// 100 for chooser dialog
// 1000 for new editor
//
///////////////////////////////////////////////////////////////////////////////////////////////
void CDeltaTreeCtrl::OnUpdateFileAutoedit(CCmdUI* pCmdUI)
{
pCmdUI->Enable(MainFrame()->SetMenuIcon(pCmdUI, !SERVER_BUSY() && IsEditableFile()));
}
void CDeltaTreeCtrl::OnUpdateFileAutobrowse(CCmdUI* pCmdUI)
{
pCmdUI->Enable(MainFrame()->SetMenuIcon(pCmdUI, !SERVER_BUSY() && IsEditableFile()));
}
BOOL CDeltaTreeCtrl::IsEditableFile()
{
BOOL isEditable=FALSE;
if(GetSelectedCount() == 1 && AnyMyPendingChangeFiles())
isEditable=TRUE;
return isEditable;
}
void CDeltaTreeCtrl::OnFileMRUEditor(UINT nID)
{
EditFile(nID - ID_FILE_EDITOR_1, TRUE);
}
void CDeltaTreeCtrl::OnFileMRUBrowser(UINT nID)
{
EditFile(nID - ID_FILE_BROWSER_1, FALSE);
}
void CDeltaTreeCtrl::OnFileQuickedit()
{
EditFile(EDIT_ASSOCVIEWER, TRUE);
}
void CDeltaTreeCtrl::OnFileQuickbrowse()
{
EditFile(EDIT_ASSOCVIEWER, FALSE);
}
void CDeltaTreeCtrl::OnFileAutoedit()
{
EditFile(EDIT_CHOOSEVIEWER, TRUE);
}
void CDeltaTreeCtrl::OnFileNewEditor()
{
EditFile(EDIT_FINDNEWVIEWER, TRUE);
}
void CDeltaTreeCtrl::OnFileNewBrowser()
{
EditFile(EDIT_FINDNEWVIEWER, FALSE);
}
void CDeltaTreeCtrl::EditFile(int lparam, BOOL editing)
{
HTREEITEM item= GetLastSelection();
ASSERT(item!=NULL);
m_Need2Edit = FALSE;
if(item != NULL)
{
if(GetClientPath(item, m_ClientPath))
{
CP4FileStats *fs=(CP4FileStats *) GetLParam( item );
if (editing && (IsOpenedForInteg(item) || IsOpenedForBranch(item)))
{
m_Msg2Send = fs->IsTextFile() ? WM_FILEEDITTXT : WM_FILEEDITBIN;
m_Need2Edit = TRUE;
m_SavelParam = lparam;
OnFileOpenedit();
}
else
{
if (fs->GetMyOpenAction() == F_INTEGRATE)
m_Msg2Send = fs->IsTextFile() ? WM_FILEBROWSETXT : WM_FILEBROWSEBIN;
else m_Msg2Send = fs->IsTextFile() ? WM_FILEEDITTXT : WM_FILEEDITBIN;
::SendMessage(m_depotWnd, m_Msg2Send, (WPARAM) &m_ClientPath, lparam);
}
}
}
}
void CDeltaTreeCtrl::OnUpdateRemoveViewer(CCmdUI* pCmdUI)
{
BOOL b = FALSE;
for(int i=0; i < MAX_MRU_VIEWERS; i++)
{
if( GET_P4REGPTR()->GetMRUViewerName(i).GetLength() > 0 )
{
b = TRUE;
break;
}
}
pCmdUI->Enable( b );
}
void CDeltaTreeCtrl::OnRemoveViewer()
{
CRemoveViewer dlg;
dlg.DoModal();
}
/*
_________________________________________________________________
*/
BOOL CDeltaTreeCtrl::GetClientPath(HTREEITEM item, CString& clientPath)
{
int key=0;
CP4FileStats *stats= (CP4FileStats *) GetLParam( item );
ASSERT(stats);
ASSERT_KINDOF(CP4FileStats,stats);
if(GET_SERVERLEVEL() >= 19) // 2005.1 or later?
{
clientPath = stats->GetFullClientPath( );
if( !clientPath.IsEmpty() )
return TRUE;
}
BOOL addingFile= (stats->GetMyOpenAction() == F_ADD || stats->GetMyOpenAction() == F_BRANCH );
// The server must be available, must be capable of returning a useable path,
// and our attempt to get a server lock must succeed, else we bail
if( SERVER_BUSY() || ( GET_SERVERLEVEL() < 4 && addingFile ) ||
!GET_SERVER_LOCK(key))
{
return FALSE;
}
CCmd_Fstat *pCmd= new CCmd_Fstat;
BOOL success = FALSE;
CString itemStr= GetItemText(item);
itemStr.TrimRight();
int pound= itemStr.ReverseFind(_T('#'));
if(pound == -1)
{
ASSERT(0);
goto GetClientPathEnd;
}
itemStr = itemStr.Left( pound );
// file open for edit. we can't get the client path from the
// depot window anymore since the new p4 dirs/fstat doesnt get
// all the files, but only those under the expanded subdirectory
// tree. and we cant use p4 where (see below) since p4 where
// returns the path of where the file would be if the server
// had gotten it. so the only save way of getting the client
// path is to call p4 fstat ( run it synchronously )
//
pCmd->Init(NULL, RUN_SYNC, HOLD_LOCK, key);
if ( !PumpMessages( ) )
goto GetClientPathEnd;
pCmd->SetIncludeAddedFiles( TRUE );
if( pCmd->Run( FALSE, itemStr, 0 ) && !pCmd->GetError() )
{
CObList *list = pCmd->GetFileList ( );
ASSERT_KINDOF( CObList, list );
ASSERT( list->GetCount() <= 1 );
POSITION pos = list->GetHeadPosition( );
if( pos != NULL )
{
CP4FileStats *stats = ( CP4FileStats * )list->GetNext( pos );
ASSERT_KINDOF( CP4FileStats, stats );
clientPath = stats->GetFullClientPath( );
if( !clientPath.IsEmpty() )
success = TRUE;
delete stats;
}
}
GetClientPathEnd:
RELEASE_SERVER_LOCK(key);
delete pCmd;
return success;
}
/*
_________________________________________________________________
Double click action is to attempt to edit the file if its our open file
Note that GetClientPath will fail if the server is busy
_________________________________________________________________
*/
void CDeltaTreeCtrl::OnLButtonDblClk(UINT nFlags, CPoint point)
{
CTreeCtrl::OnLButtonDblClk(nFlags, point);
if(nFlags & (MK_CONTROL | MK_MBUTTON| MK_RBUTTON | MK_SHIFT))
return;
// find out what was hit
TV_HITTESTINFO ht;
ht.pt=point;
HTREEITEM currentItem=HitTest( &ht);
if( currentItem != NULL && (ht.flags & TVHT_ONITEM) && currentItem == m_LastLButtonDown)
OnLButtonDblClk(currentItem);
}
void CDeltaTreeCtrl::OnLButtonDblClk(HTREEITEM currentItem)
{
// make a new selection new if reqd
if(!IsSelected(currentItem))
{
UnselectAll();
if(currentItem != NULL)
SetSelectState(currentItem, TRUE);
}
if(!SERVER_BUSY() && IsEditableFile())
{
switch (GET_P4REGPTR()->GetDoubleClickOption())
{
case 0: // Edit
case 1: // open
case 2: // open and edit
case 3: // view head revision
case 4: // sync to head revision
default:
{
CString clientPath;
if(GetClientPath(currentItem, clientPath))
{
CP4FileStats *fs=(CP4FileStats *) GetLParam( currentItem );
if (fs->GetMyOpenAction() == F_INTEGRATE)
m_Msg2Send = fs->IsTextFile() ? WM_FILEBROWSETXT : WM_FILEBROWSEBIN;
else m_Msg2Send = fs->IsTextFile() ? WM_FILEEDITTXT : WM_FILEEDITBIN;
::SendMessage(m_depotWnd, m_Msg2Send, (WPARAM) &clientPath, EDIT_ASSOCVIEWER);
return;
}
}
case 5: // diff versus head revision
PostMessage(WM_COMMAND, ID_FILE_DIFFHEAD, 0);
break;
case 6: // display Properties dialogbox
PostMessage(WM_COMMAND, ID_FILE_PROPERTIES, 0);
break;
case 7: // display Revision History dialogbox
PostMessage(WM_COMMAND, ID_FILE_REVISIONHISTORY, 0);
break;
}
}
else if(!HasChildren(currentItem))
{
BOOL underMyRoot=FALSE;
int level = GetItemLevel(currentItem, &underMyRoot);
if((GetLParam(currentItem) == NULL) && (level == 2))
OnJobDescribe();
else
MessageBeep(MB_OK);
}
}
/*
_________________________________________________________________
at least one file is selected, user is sure, so put all selected
file names sans revision number in the string list.
_________________________________________________________________
*/
BOOL CDeltaTreeCtrl::AssembleStringList( CStringList *list /*=NULL*/, BOOL includeAdds /*=TRUE*/ )
{
CString itemStr;
BOOL bFoundFileOpenedForAdd = FALSE;
if (!list)
list = &m_StringList;
list->RemoveAll();
for( int i = GetSelectedCount()-1; i >= 0; i--)
{
itemStr = GetItemText( GetSelectedItem( i ) );
if (itemStr.Right(5) == _T("<add>"))
{
bFoundFileOpenedForAdd = TRUE;
if (!includeAdds)
continue;
}
int sep = itemStr.ReverseFind( _T('#') );
if (sep != -1)
{
itemStr = itemStr.Left( sep );
list->AddHead( itemStr );
}
}
return bFoundFileOpenedForAdd;
}
BOOL CDeltaTreeCtrl::GetSelectedFiles( CStringList *list )
{
list->RemoveAll();
HTREEITEM cItem;
CString itemStr;
CString clientPath;
for( int i = GetSelectedCount() - 1; i >= 0; i-- )
{
cItem = GetSelectedItem( i );
itemStr = GetItemText( cItem );
// if it's not a changelist, add it to the list
//
if( !HasChildren( cItem ) && (itemStr.ReverseFind( _T('#') ) != -1) )
{
if(GetClientPath(cItem, clientPath))
list->AddHead( clientPath );
else
return FALSE;
}
}
return TRUE;
}
/*
_________________________________________________________________
for commands that will run synchronously.
_________________________________________________________________
*/
BOOL CDeltaTreeCtrl::PumpMessages( )
{
if (MainFrame()->IsQuitting())
return FALSE;
MSG msg;
while ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
{
// get out if app is terminating
//
if ( msg.message == WM_QUIT )
return FALSE;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return TRUE;
}
// Support for quick copy of depot path or client path to the clipboard
//
void CDeltaTreeCtrl::OnUpdateEditCopy(CCmdUI* pCmdUI)
{
pCmdUI->Enable( GetSelectedCount()>=1 && IsMyPendingChangeFile( GetSelectedItem(0)));
}
void CDeltaTreeCtrl::OnUpdateEditCopyclientpath(CCmdUI* pCmdUI)
{
pCmdUI->Enable( GetSelectedCount()>=1 && IsMyPendingChangeFile( GetSelectedItem(0)));
}
void CDeltaTreeCtrl::OnUpdateEditSelectAll(CCmdUI* pCmdUI)
{
BOOL selectable=FALSE;
if( GetSelectedCount() > 0 )
{
if( IsMyPendingChangeItem( GetSelectedItem(0)) )
selectable= TRUE;
else if( IsMyPendingChange( GetSelectedItem(0)) )
{
UINT state= CTreeCtrl::GetItemState( GetSelectedItem(0), TVIS_EXPANDED );
if( (state & TVIS_EXPANDED) == TVIS_EXPANDED )
selectable=TRUE;
}
}
pCmdUI->Enable( selectable );
}
void CDeltaTreeCtrl::OnEditCopyclientpath()
{
CString txt;
for(int i=-1; ++i < GetSelectedCount(); )
{
HTREEITEM item= GetSelectedItem(i);
if( IsMyPendingChangeFile( item ) )
{
CString clientPath;
if(GetClientPath(item, clientPath))
{
if (i)
txt += _T("\r\n");
txt += clientPath;
}
}
}
if (txt.IsEmpty())
MessageBeep(MB_ICONEXCLAMATION);
else
CopyTextToClipboard( txt );
}
void CDeltaTreeCtrl::OnEditCopy()
{
CString txt;
for(int i=-1; ++i < GetSelectedCount(); )
{
HTREEITEM item= GetSelectedItem(i);
BOOL underMyRoot=FALSE;
int level= GetItemLevel(item, &underMyRoot);
if( level == 2 && IsAFile( item ) )
{
// Fetch the filename for ANY file
CString itemStr = GetItemText( item );
itemStr = itemStr.Left( itemStr.ReverseFind( _T('#') ) );
if (i)
txt += _T("\r\n");
txt += itemStr;
}
}
if (txt.IsEmpty())
MessageBeep(MB_ICONEXCLAMATION);
else
CopyTextToClipboard( txt );
}
void CDeltaTreeCtrl::OnEditSelectAll()
{
if( GetSelectedCount() > 0 &&
( IsMyPendingChangeItem( GetSelectedItem(0) ) ||
IsMyPendingChange( GetSelectedItem(0)) ) )
{
HTREEITEM parent;
if( IsMyPendingChange( GetSelectedItem(0)) )
parent= GetSelectedItem(0);
else
parent= GetParentItem( GetSelectedItem(0) );
UnselectAll();
SetMultiSelect(TRUE);
HTREEITEM child= GetChildItem( parent );
while( child != NULL )
{
SetSelectState( child, TRUE );
child= GetNextSiblingItem(child);
}
SetMultiSelect(FALSE);
ShowNbrSelected();
}
}
void CDeltaTreeCtrl::OnUpdateFileOpenedit(CCmdUI* pCmdUI)
{
pCmdUI->Enable( MainFrame()->SetMenuIcon(pCmdUI, !SERVER_BUSY()
&& (AnyMyInteg() || AnyMyBranch())) );
}
void CDeltaTreeCtrl::OnFileOpenedit()
{
if(GetSelectedCount()==0)
{
ASSERT(0);
return;
}
CString itemStr;
m_StringList.RemoveAll();
for( int i = GetSelectedCount()-1; i >= 0; i--)
{
if(IsOpenedForInteg(GetSelectedItem(i)) || IsOpenedForBranch(GetSelectedItem(i)))
{
itemStr = GetItemText( GetSelectedItem( i ) );
itemStr = itemStr.Left( itemStr.ReverseFind( _T('#') ) );
m_StringList.AddHead( itemStr );
}
}
if (m_StringList.IsEmpty())
return;
CCmd_ListOpStat *pCmd= new CCmd_ListOpStat;
pCmd->Init( m_hWnd, RUN_ASYNC, HOLD_LOCK );
if( pCmd->Run( &m_StringList, P4EDIT, 0 ) )
MainFrame()->UpdateStatus( LoadStringResource(IDS_OPENING_FILES_FOR_EDIT) );
else
delete pCmd;
}
void CDeltaTreeCtrl::OnUpdatePositionDepot(CCmdUI* pCmdUI)
{
BOOL underMyRoot=FALSE;
int level = GetItemLevel(GetSelectedItem(0), &underMyRoot);
int n = GetSelectedCount();
BOOL b = pCmdUI->m_pParentMenu == MainFrame()->GetMenu();
if (level == 1)
{
if (b)
pCmdUI->SetText(LoadStringResource(IDS_FINDCHGFILESINDEPOT));
pCmdUI->Enable( n == 1 && AnyFilesInChange(GetSelectedItem(0)));
}
else
{
if (b)
pCmdUI->SetText(LoadStringResource(n < 2 ? IDS_FINDSELFILEINDEPOT
: IDS_FINDSELFILESINDEPOT));
pCmdUI->Enable( n >= 1 && (level == 2) && IsAFile(GetSelectedItem(0)) );
}
}
// User clicked on "Find in Depot" menu item
// Expand the Depot Treeview to the location of that file
//
void CDeltaTreeCtrl::OnPositionDepot()
{
// see if it's a chglist or file(s) that's selected
HTREEITEM initialItem = GetSelectedItem(0);
BOOL root;
int level = GetItemLevel(initialItem, &root);
if (level == 1)
{
// a chglist is selected, so select all its files
SelectAllFilesInChange(initialItem, 0);
if (GetSelectedCount() < 1)
{
UnselectAll();
SetSelectState(initialItem, TRUE);
return;
}
}
int n;
int count = 0;
if( (n = GetSelectedCount()) >=1 )
{
MainFrame()->SetAdd2ExpandItemList(TRUE);
for (int i=-1; ++i < n; )
{
HTREEITEM item= GetSelectedItem(i);
if( GetItemLevel(item, &root) == 2 && IsAFile( item ) )
{
// Fetch the filename for ANY file
CString itemStr = GetItemText( item );
itemStr = itemStr.Left( itemStr.ReverseFind( _T('#') ) ); // trim off rev# info
MainFrame()->ExpandDepotString( itemStr, TRUE );
while (MainFrame()->IsExpandDepotContinuing() || SERVER_BUSY())
{
if ( !MainFrame()->PumpMessages( ) )
break;
Sleep(250);
}
count++;
}
}
}
if (level == 1)
{
UnselectAll();
SetSelectState(initialItem, TRUE);
}
if (count)
{
MainFrame()->SetAdd2ExpandItemList(FALSE);
MainFrame()->SelectExpandItemList();
if (MainFrame()->GetExpandItemListCount() < count)
{
CString txt;
n = count - MainFrame()->GetExpandItemListCount();
txt.FormatMessage(IDS_NOTALLFILESSELECTED_d, n, n==1 ? _T("") : _T("s"));
TheApp()->StatusAdd( txt, SV_WARNING );
}
}
else
MessageBeep(MB_ICONEXCLAMATION); // unexpected problem - should never happen
}
// this returns -1 if the change is not found or is not MY change
// if the chg is found and it is mine, its number is returned
long CDeltaTreeCtrl::PositionChgs(const CString &path,
BOOL lookInMine,
BOOL lookInOthers/*=TRUE*/,
BOOL addToSelectionSet/*=FALSE*/)
{
long chg;
// clear the previous position request string
m_PositionTo = _T("");
// first look thru my client's changes, if requested
if (lookInMine && ((chg = PositionToFileInChg(path, m_MyRoot,
m_MyRoot, FALSE, addToSelectionSet)) !=-1))
return chg;
if (!lookInOthers)
return -1;
chg = -1;
if (m_OthersRoot)
{
// If we get here, we didn't find it among my clients,
// so look thru the other clients.
// First expand the Other Clients node - which might fail,
// and thereby trigger a p4 opened -a
Expand(m_OthersRoot, TVE_EXPAND);
if ((chg = PositionToFileInChg(path, m_OthersRoot,
m_OthersRoot, FALSE, addToSelectionSet)) == -1)
{
// We didn't find it, we might have triggered a p4 opened -a,
// so save off the name of the thing we are seeking
m_PositionTo = path;
}
}
return chg;
}
void CDeltaTreeCtrl::OnUpdatePositionOtherChgs(CCmdUI* pCmdUI)
{
m_PositionTo.Empty();
if (!m_InContextMenu)
pCmdUI->SetText( LoadStringResource(IDS_POSITIONCHGS_CHGPANE) );
BOOL underMyRoot=FALSE;
BOOL b = GetSelectedCount()==1 &&
GetItemLevel(GetSelectedItem(0), &underMyRoot) == 2 &&
IsAFile(GetSelectedItem(0));
if (b && GET_SERVERLEVEL() >= 19) // 2005.1 or later?
{
CP4FileStats *stats= (CP4FileStats *) GetLParam(GetSelectedItem(0));
if (stats->GetOtherOpenAction() == 0)
b = FALSE;
}
pCmdUI->Enable(b);
}
void CDeltaTreeCtrl::OnPositionOtherChgs()
{
m_PositionTo.Empty();
if ( !IsAFile(GetSelectedItem(0)) || !m_OthersRoot )
return;
HTREEITEM file = GetSelectedItem(0);
LPARAM lParam=GetLParam(file);
if(lParam > 0)
{
HTREEITEM start = GetParentItem(file);
HTREEITEM root = GetParentItem(start);
start = (root == m_MyRoot) ? m_OthersRoot
: GetNextSiblingItem(start);
if (!start)
return;
CP4FileStats *stats= (CP4FileStats *) lParam;
ASSERT_KINDOF(CP4FileStats, stats);
CString path = stats->GetFullDepotPath();
// First expand the Other Clients node - which might fail,
// and thereby trigger a p4 opened -a
Expand(m_OthersRoot, TVE_EXPAND);
// then try and find the file
if (PositionToFileInChg(path, start, m_OthersRoot) == -1)
{
// We didn't find it, we might have triggered a p4 opened -a,
// so save off the name of the thing we are seeking
m_PositionTo = path;
}
}
}
long CDeltaTreeCtrl::PositionToFileInChg(const CString &path,
HTREEITEM start, HTREEITEM root,
BOOL afterExpand/*=FALSE*/,
BOOL addToSelectionSet/*=FALSE*/)
{
HTREEITEM change = !start || (start == root)
? GetChildItem(root) : start;
HTREEITEM file;
LPARAM lParam;
BOOL bFile = FALSE;
while(change != NULL)
{
file= GetChildItem(change);
while(file != NULL)
{
lParam=GetLParam(file);
if(lParam > 0)
{
CP4FileStats *stats= (CP4FileStats *) lParam;
ASSERT_KINDOF(CP4FileStats, stats);
if(stats->GetFullDepotPath() == path)
{
Expand(root, TVE_EXPAND);
Expand(change, TVE_EXPAND);
if (!addToSelectionSet)
UnselectAll();
SetSelectState( file, TRUE );
// set focus to pending chglist pane
MainFrame()->SetActiveView(DYNAMIC_DOWNCAST(CView,GetParent()), TRUE);
long chg = stats->GetOpenChangeNum();
CString txt;
txt.FormatMessage(chg ? IDS_FILE_FOUND_IN_CHG_d : IDS_FILE_FOUND_IN_DEFCHG, chg);
MainFrame()->SetMessageText(txt);
return chg;
}
bFile = TRUE;
}
file=GetNextSiblingItem(file);
}
change=GetNextSiblingItem(change);
}
if (bFile)
MainFrame()->SetMessageText(LoadStringResource(afterExpand ? IDS_FILE_NOT_FOUND_IN_OTHERS
: IDS_CHGFILE_NOT_FOUND));
return -1;
}
void CDeltaTreeCtrl::OnUpdatePositionToPattern(CCmdUI* pCmdUI)
{
CString txt = LoadStringResource(IDS_POSITIONTOPATTERN);
pCmdUI->SetText ( txt );
pCmdUI->Enable(!SERVER_BUSY());
}
void CDeltaTreeCtrl::OnPositionToPattern()
{
::PostMessage(m_depotWnd, WM_COMMAND, ID_POSITIONTOPATTERN, 0);
}
BOOL CDeltaTreeCtrl::AnyInDefault()
{
return GetChildItem(m_MyDefault) ? TRUE : FALSE;
}
BOOL CDeltaTreeCtrl::AnyNbredChg()
{
return GetNextSiblingItem(m_MyDefault) ? TRUE : FALSE;
}
void CDeltaTreeCtrl::OnUpdateUserSwitchtouser(CCmdUI* pCmdUI)
{
BOOL underMyRoot;
pCmdUI->Enable( !SERVER_BUSY() && GetSelectedCount() == 1
&& GetItemLevel(GetSelectedItem(0), &underMyRoot) == 1
&& !IsMyPendingChange( GetSelectedItem(0) )
&& GetUserFromChange() != GET_P4REGPTR()->GetP4User());
}
void CDeltaTreeCtrl::OnUserSwitchtouser()
{
BOOL underMyRoot;
if ( !SERVER_BUSY() && GetSelectedCount() == 1
&& GetItemLevel(GetSelectedItem(0), &underMyRoot) == 1)
{
CString user = GetUserFromChange();
if (!user.IsEmpty())
{
GET_P4REGPTR()->SetP4User(user, TRUE, FALSE, FALSE);
MainFrame()->OnPerforceOptions(FALSE, FALSE);
}
}
}
void CDeltaTreeCtrl::OnUpdateClientspecSwitch(CCmdUI* pCmdUI)
{
BOOL underMyRoot;
pCmdUI->Enable( !SERVER_BUSY() && GetSelectedCount() == 1
&& GetItemLevel(GetSelectedItem(0), &underMyRoot) == 1
&& !underMyRoot);
}
void CDeltaTreeCtrl::OnClientspecSwitch()
{
BOOL underMyRoot;
if ( !SERVER_BUSY() && GetSelectedCount() == 1
&& GetItemLevel(GetSelectedItem(0), &underMyRoot) == 1
&& !underMyRoot)
{
CString client = GetClientFromChange();
if (!client.IsEmpty())
MainFrame()->ClientSpecSwitch(client);
}
}
CString CDeltaTreeCtrl::GetClientFromChange()
{
BOOL underMyRoot;
TCHAR buf[2050];
int i;
if ( GetSelectedCount() == 1
&& GetItemLevel(GetSelectedItem(0), &underMyRoot) == 1)
{
TV_ITEM item;
item.hItem=GetSelectedItem(0);
item.mask=TVIF_TEXT;
item.pszText = buf;
item.cchTextMax = sizeof(buf)/sizeof(TCHAR)-1;
if (GetItem(&item ))
{
CString txt = buf;
if ((i = txt.Find(_T('@'))) != -1)
{
txt = txt.Right(txt.GetLength() - i - 1);
if ((i = txt.Find(_T(' '))) != -1)
txt = txt.Left(i);
return txt;
}
}
}
return _T("");
}
CString CDeltaTreeCtrl::GetUserFromChange()
{
BOOL underMyRoot;
TCHAR buf[2050];
int i;
if ( GetSelectedCount() == 1
&& GetItemLevel(GetSelectedItem(0), &underMyRoot) == 1)
{
TV_ITEM item;
item.hItem=GetSelectedItem(0);
item.mask=TVIF_TEXT;
item.pszText = buf;
item.cchTextMax = sizeof(buf)/sizeof(TCHAR)-1;
if (GetItem(&item ))
{
CString txt = buf;
if ((i = txt.Find(_T('@'))) != -1)
{
txt = txt.Left(i);
if ((i = txt.ReverseFind(_T(' '))) != -1)
txt = txt.Right(txt.GetLength() - i - 1);
return txt;
}
}
}
return _T("");
}
void CDeltaTreeCtrl::OnUpdateFileInformation(CCmdUI* pCmdUI)
{
BOOL root;
BOOL enable= (!SERVER_BUSY() && GetSelectedCount() == 1 &&
GetItemLevel(GetSelectedItem(0), &root)== 2 &&
IsAFile( GetSelectedItem(0)) );
if( enable )
{
CP4FileStats *fs= (CP4FileStats *) GetLParam( GetSelectedItem(0) );
if( fs->GetHaveRev() <= 1 &&
( fs->GetMyOpenAction() == F_ADD || fs->GetMyOpenAction() == F_BRANCH ) )
enable= FALSE;
}
pCmdUI->Enable( enable );
}
void CDeltaTreeCtrl::OnFileInformation()
{
HTREEITEM item=GetLastSelection();
CString itemStr= GetItemText(item);
itemStr.TrimRight();
int pound= itemStr.ReverseFind(_T('#'));
if(pound == -1)
{
ASSERT(0);
return;
}
itemStr = itemStr.Left( pound );
m_StringList.RemoveAll();
m_StringList.AddHead(itemStr);
CCmd_Opened *pCmd= new CCmd_Opened;
pCmd->Init( m_hWnd, RUN_ASYNC, HOLD_LOCK, 0);
pCmd->SetAlternateReplyMsg( WM_P4FILEINFORMATION );
if( pCmd->Run( TRUE, FALSE, -1, &m_StringList ) )
MainFrame()->UpdateStatus( LoadStringResource(IDS_REQUESTING_FILE_INFORMATION) );
else
delete pCmd;
}
LRESULT CDeltaTreeCtrl::OnP4FileInformation( WPARAM wParam, LPARAM lParam )
{
CCmd_Opened *pCmd= (CCmd_Opened *) wParam;
m_StringList.RemoveAll();
if(!pCmd->GetError())
{
CString thisuser=GET_P4REGPTR()->GetMyID();
// Initialize the file info dialog
CFileInfoDlg *dlg = new CFileInfoDlg(this);
CString itemStr = *pCmd->GetDepotPath();
if (itemStr.IsEmpty())
{
HTREEITEM item=GetLastSelection();
itemStr= GetItemText(item);
itemStr.TrimRight();
int pound= itemStr.ReverseFind(_T('#'));
if(pound == -1)
{
ASSERT(0);
return -1;
}
itemStr = itemStr.Left( pound );
}
dlg->m_DepotPath = itemStr;
int key= pCmd->GetServerKey();
CCmd_Fstat *pCmd2= new CCmd_Fstat;
pCmd2->Init(NULL, RUN_SYNC, HOLD_LOCK, key);
if ( !PumpMessages( ) )
goto CantGetFStat;
pCmd2->SetIncludeAddedFiles( TRUE );
if( pCmd2->Run( FALSE, itemStr, 0 ) && !pCmd2->GetError() )
{
CObList *list = pCmd2->GetFileList ( );
ASSERT_KINDOF( CObList, list );
ASSERT( list->GetCount() <= 1 );
POSITION pos = list->GetHeadPosition( );
if( pos != NULL )
{
CP4FileStats *stats = ( CP4FileStats * )list->GetNext( pos );
ASSERT_KINDOF( CP4FileStats, stats );
dlg->m_ClientPath = stats->GetFullClientPath( );
if(dlg->m_ClientPath.GetLength() == 0)
dlg->m_ClientPath= LoadStringResource(IDS_NOT_IN_CLIENT_VIEW);
dlg->m_HeadRev.Format(_T("%ld"), stats->GetHeadRev());
dlg->m_HaveRev.Format(_T("%ld"), stats->GetHaveRev());
dlg->m_HeadAction= stats->GetActionStr(stats->GetHeadAction());
dlg->m_HeadChange.Format(_T("%ld"), stats->GetHeadChangeNum());
dlg->m_HeadType= stats->GetHeadType();
dlg->m_ModTime= stats->GetFormattedHeadTime();
dlg->m_FileSize= stats->GetFileSize();
// Check for open/lock by this user
if(stats->IsMyLock())
dlg->m_LockedBy= thisuser;
delete stats;
}
else dlg->m_ClientPath= LoadStringResource(IDS_NOT_IN_CLIENT_VIEW);
}
CantGetFStat:
RELEASE_SERVER_LOCK(key);
delete pCmd2;
CObList *list= pCmd->GetList();
ASSERT_KINDOF(CObList, list);
POSITION pos= list->GetHeadPosition();
while(pos != NULL)
{
CP4FileStats *fs= (CP4FileStats *) list->GetNext(pos);
CString str, strUser, strAction;
strUser= fs->GetOtherUsers();
if( fs->IsMyOpen() && strUser.IsEmpty() )
{
strUser= thisuser;
strAction= fs->GetActionStr(fs->GetMyOpenAction());
}
else
strAction= fs->GetActionStr(fs->GetOtherOpenAction());
if( fs->GetOpenChangeNum() == 0 )
str.FormatMessage(IDS_CHANGE_DEFAULT_USER_s, strUser);
else
str.FormatMessage(IDS_CHANGE_n_USER_s, fs->GetOpenChangeNum(), strUser);
str += _T(" (") + strAction + _T(")");
if( fs->IsOtherLock() )
str += LoadStringResource(IDS_STAR_LOCKED);
dlg->m_StrList.AddHead( str );
delete fs;
}
// Display the info
if (!dlg->Create(IDD_FILE_INFORMATION, this)) // display the description dialog box
{
dlg->DestroyWindow(); // some error! clean up
delete dlg;
}
}
MainFrame()->ClearStatus();
delete pCmd;
return 0;
}
LRESULT CDeltaTreeCtrl::OnP4EndFileInformation( WPARAM wParam, LPARAM lParam )
{
CFileInfoDlg *dlg = (CFileInfoDlg *)lParam;
dlg->DestroyWindow();
return TRUE;
}
void CDeltaTreeCtrl::OnSetFlyoverMessage(HTREEITEM currentItem)
{
if( !GET_P4REGPTR()->ShowClientPath() || GET_SERVERLEVEL() < 19) // earlier than 2005.1
return;
ASSERT( currentItem != NULL );
LPARAM lParam= GetLParam(currentItem);
// Bail out if its a changelist or a job
if( lParam <= 0 )
{
ShowNbrSelected();
}
else
{
if( IsMyPendingChangeFile( currentItem ) )
{
CP4FileStats *fs= (CP4FileStats *) lParam;
CString msg = fs->GetFullClientPath();
if (msg.IsEmpty())
{
GetClientPath(currentItem, msg);
fs->SetClientPath(msg);
}
if (!msg.IsEmpty())
{
CString itemStr = GetItemText(currentItem);
CString type;
int baseType;
int storeType;
BOOL typeK = FALSE;
BOOL typeW = FALSE;
BOOL typeX = FALSE;
BOOL typeO = FALSE;
BOOL typeM = FALSE;
BOOL typeL = FALSE;
BOOL typeS = FALSE;
int nbrrevs = 1;
BOOL unknown = FALSE;
// convert the GetItemText() string to 5 flags
TheApp()->GetFileType(itemStr, baseType, storeType,
typeK, typeW, typeX, typeO,
typeM, typeL, typeS, nbrrevs, unknown);
// determine the base file type
switch(baseType)
{
case 0:
type = _T(" <text");
break;
case 1:
type = _T(" <binary");
break;
case 2:
type = _T(" <symlink");
break;
case 3:
type = _T(" <resource");
break;
case 4:
type = _T(" <apple");
break;
case 5:
type = _T(" <unicode");
break;
case 6:
type = _T(" <utf16");
break;
default:
type = _T(" <unknown");
break;
}
// determine storage type - if it's the default for the base type, do nothing
switch(storeType)
{
case 1: // +C
if (baseType != 1)
type += LoadStringResource(IDS_comma_FULL_COMPRESSED_VERSION_STORED);
break;
case 2: // +D
if (baseType != 0)
type += LoadStringResource(IDS_comma_RCS_DELTAS_STORED);
break;
case 3: // +F
type += LoadStringResource(IDS_comma_FULL_FILE_STORED_PER_REV);
break;
default:
break;
}
// Warning: if more of these modifier types are added, we may need to
// shorten these strings so that all will fit in the status bar window.
// Already there is a possible overflow if the local path name is long!
if (typeO)
type += LoadStringResource(IDS_comma_LIMITED_RCS_KEYWORD_EXPANSION);
else if (typeK)
type += LoadStringResource(IDS_comma_RCS_KEYWORD_EXPANSION);
if (typeW)
type += LoadStringResource(IDS_comma_ALWAYS_WRITABLE);
if (typeX)
type += LoadStringResource(IDS_comma_EXECUTABLE);
if (typeL)
type += LoadStringResource(IDS_comma_LOCKED);
if (typeS)
{
if (nbrrevs < 2)
type += LoadStringResource(IDS_comma_ONLY_HEAD_REV_STORED);
else
{
CString str;
str.FormatMessage(IDS_comma_ONLY_n_REVS_STORED, nbrrevs);
type += str;
}
}
if (unknown)
type += LoadStringResource(IDS_PLUS_UNKNOWN);
type += _T(">");
if (type != LoadStringResource(IDS_ONLY_UNKNOWN))
msg += type;
if (fs->GetMyOpenAction() > 0)
msg += _T("<") + fs->GetActionStr( fs->GetMyOpenAction() ) + _T(">");
if( fs->IsUnresolved() )
msg += LoadStringResource(IDS_UNRESOLVED);
if(fs->IsMyLock())
msg += LoadStringResource(IDS_LOCKED);
if((fs->GetOtherOpens() > 0) || fs->IsOtherLock())
{
msg += LoadStringResource(IDS_OTHERUSER);
if(fs->GetOtherOpens() > 0)
{
CString otherAction;
otherAction.FormatMessage(IDS_OPENFOR_s,
fs->GetActionStr(fs->GetOtherOpenAction()));
msg += otherAction + _T(" by ") + fs->GetOtherUsers();
}
if(fs->IsOtherLock())
msg += _T(" ") + LoadStringResource(IDS_LOCKED);
}
// write the local path and the file type to the status bar
MainFrame()->SetMessageText(msg);
}
else
MainFrame()->SetMessageText(LoadStringResource(IDS_FILE_NOT_IN_CLIENT_VIEW));
}
else
MainFrame()->SetMessageText(LoadStringResource(IDS_FOR_HELP_PRESS_F1));
}
}
int CDeltaTreeCtrl::CreateNewChangeList(int key, CString *description/*=NULL*/, BOOL autoOK/*=FALSE*/)
{
BOOL bReleaseLock;
if (!key)
{
if(SERVER_BUSY() || !GET_SERVER_LOCK(key))
{
ASSERT(0);
return -1;
}
bReleaseLock = TRUE;
}
else
bReleaseLock = FALSE;
m_NewChgNbr = -1;
m_NewDesc.Empty();
CCmd_Describe *pCmd = new CCmd_Describe;
pCmd->Init( NULL, RUN_SYNC, HOLD_LOCK, key );
BOOL cmdStarted= pCmd->Run( P4CHANGE_SPEC, NULL );
if(cmdStarted && !pCmd->GetError())
{
// if we are passed a description, insert it
if (description && *description)
{
int i;
CString cmdDesc = pCmd->GetDescription();
if ((i = cmdDesc.Find(CCmd_EditSpec::g_blankDesc)) != -1)
{
cmdDesc = cmdDesc.Left(i) + *description + cmdDesc.Mid(i + lstrlen(CCmd_EditSpec::g_blankDesc));
pCmd->SetDescription(cmdDesc);
m_NewDesc = *description;
}
}
// we create a dummy CCmd_EditSpec; it is never run,
// it just hold the lock's key and receives the new chglist number
CCmd_EditSpec callingCmd;
callingCmd.Init( NULL, RUN_SYNC, HOLD_LOCK, key );
callingCmd.SetSpecIn(pCmd->GetDescription());
callingCmd.PreprocessChgSpec();
CP4SpecSheet SpecSheet;
SpecSheet.m_P4SpecDlg.SetCallingCommand(&callingCmd);
SpecSheet.m_P4SpecDlg.SetSpec(callingCmd.GetSpecIn(), pCmd->GetSpecStr(),
P4CHANGE_SPEC, FALSE);
SpecSheet.m_P4SpecDlg.SetChangeParms(FALSE, FALSE, FALSE, FALSE, FALSE, autoOK);
if (SpecSheet.DoModal() == IDOK)
{
m_NewChgNbr = callingCmd.GetNewChangeNum();
m_NewDesc = callingCmd.GetChangeDesc();
}
else
{
m_NewChgNbr = -1;
m_NewDesc.Empty();
}
}
delete pCmd;
if (bReleaseLock)
RELEASE_SERVER_LOCK(key);
return m_NewChgNbr;
}
void CDeltaTreeCtrl::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
MainFrame()->WaitAWhileToPoll( );
CMultiSelTreeCtrl::OnVScroll(nSBCode, nPos, pScrollBar);
}
void CDeltaTreeCtrl::OnUpdateViewUpdate(CCmdUI* pCmdUI)
{
pCmdUI->Enable(!SERVER_BUSY() && !MainFrame()->IsModlessUp());
}
void CDeltaTreeCtrl::OnViewUpdate()
{
// somewhat unexpected maybe, but refreshing the pending changes view
// actually just sends a request to the depot view for a full refresh
::PostMessage(m_depotWnd, WM_COMMAND, ID_VIEW_UPDATE_LEFT, 0);
}
void CDeltaTreeCtrl::OnPerforceOptions()
{
MainFrame()->OnPerforceOptions(TRUE, FALSE, IDS_PAGE_CHANGELIST);
}
void CDeltaTreeCtrl::OnTheirFindInDepot()
{
ASSERT(GetSelectedCount() == 1);
AssembleStringList( );
CCmd_AutoResolve *pCmd= new CCmd_AutoResolve;
pCmd->Init( m_hWnd, RUN_ASYNC );
pCmd->SetAlternateReplyMsg( WM_THEIRFINDINDEPOT );
if( pCmd->Run( &m_StringList, 0, TRUE, TRUE, FALSE, 0 ) )
MainFrame()->UpdateStatus( LoadStringResource(IDS_FINDING_THEIR_FILE) );
else
delete pCmd;
}
LRESULT CDeltaTreeCtrl::OnP4TheirFindInDepot(WPARAM wParam, LPARAM lParam)
{
CCmd_AutoResolve *pCmd= (CCmd_AutoResolve *) wParam;
if( !pCmd->GetError() && !MainFrame()->IsQuitting() )
{
CStringList *list= pCmd->GetList();
if (list->GetCount())
{
int i;
CString theirStr = list->GetHead();
if ((i = theirStr.Find( _T(" - vs "))) != -1)
{
theirStr = theirStr.Mid(i + sizeof(_T(" - vs "))/sizeof(TCHAR) -1 );
theirStr.TrimLeft();
theirStr = theirStr.Left( theirStr.ReverseFind( _T('#') ) ); // trim off rev# info
MainFrame()->ExpandDepotString( theirStr, TRUE );
}
}
}
MainFrame()->ClearStatus();
delete pCmd;
return 0;
}
void CDeltaTreeCtrl::OnTheirHistory()
{
ASSERT(GetSelectedCount() == 1);
AssembleStringList( );
CCmd_AutoResolve *pCmd= new CCmd_AutoResolve;
pCmd->Init( m_hWnd, RUN_ASYNC, HOLD_LOCK );
pCmd->SetAlternateReplyMsg( WM_THEIRHISTORY );
if( pCmd->Run( &m_StringList, 0, TRUE, TRUE, FALSE, 0 ) )
MainFrame()->UpdateStatus( LoadStringResource(IDS_FINDING_THEIR_FILE) );
else
delete pCmd;
}
LRESULT CDeltaTreeCtrl::OnP4TheirHistory(WPARAM wParam, LPARAM lParam)
{
CCmd_AutoResolve *pCmd= (CCmd_AutoResolve *) wParam;
if( !pCmd->GetError() && !MainFrame()->IsQuitting() )
{
CStringList *list= pCmd->GetList();
if (list->GetCount())
{
int i;
int rev = -1;
CString theirStr = list->GetHead();
if ((i = theirStr.Find( _T(" - vs "))) != -1)
{
theirStr = theirStr.Mid(i + sizeof(_T(" - vs "))/sizeof(TCHAR) -1 );
theirStr.TrimLeft();
i = theirStr.Find( _T('#') );
if (i != -1)
{
rev = _ttoi(theirStr.Right(theirStr.GetLength() - i - 1));
if (!rev)
rev = -1;
theirStr = theirStr.Left(i); // trim off rev# info
}
CCmd_History *pCmd2= new CCmd_History;
pCmd2->Init( m_depotWnd, RUN_ASYNC, LOSE_LOCK, pCmd->GetServerKey());
pCmd2->SetInitialRev(rev, theirStr);
pCmd2->SetCallingWnd(m_hWnd);
if( pCmd2->Run(theirStr) )
{
MainFrame()->UpdateStatus( LoadStringResource(IDS_REQUESTING_HISTORY) );
}
else
{
delete pCmd2;
pCmd->ReleaseServerLock();
}
}
else
pCmd->ReleaseServerLock();
}
else
pCmd->ReleaseServerLock();
}
else
pCmd->ReleaseServerLock();
MainFrame()->ClearStatus();
delete pCmd;
return 0;
}
void CDeltaTreeCtrl::OnTheirProperties()
{
ASSERT(GetSelectedCount() == 1);
AssembleStringList( );
CCmd_AutoResolve *pCmd= new CCmd_AutoResolve;
pCmd->Init( m_hWnd, RUN_ASYNC, HOLD_LOCK );
pCmd->SetAlternateReplyMsg( WM_THEIRPROPERTIES );
if( pCmd->Run( &m_StringList, 0, TRUE, TRUE, FALSE, 0 ) )
MainFrame()->UpdateStatus( LoadStringResource(IDS_FINDING_THEIR_FILE) );
else
delete pCmd;
}
LRESULT CDeltaTreeCtrl::OnP4TheirProperties(WPARAM wParam, LPARAM lParam)
{
CCmd_AutoResolve *pCmd= (CCmd_AutoResolve *) wParam;
if( !pCmd->GetError() && !MainFrame()->IsQuitting() )
{
CStringList *list= pCmd->GetList();
if (list->GetCount())
{
int i;
CString theirStr = list->GetHead();
if ((i = theirStr.Find( _T(" - vs "))) != -1)
{
theirStr = theirStr.Mid(i + sizeof(_T(" - vs "))/sizeof(TCHAR) -1 );
theirStr.TrimLeft();
if ((i = theirStr.Find(_T('#'))) != -1)
theirStr = theirStr.Left(i); // trim off rev# info
m_StringList.RemoveAll();
m_StringList.AddHead(theirStr);
CCmd_Opened *pCmd2= new CCmd_Opened;
pCmd2->Init( m_hWnd, RUN_ASYNC, HOLD_LOCK, pCmd->GetServerKey());
pCmd2->SetAlternateReplyMsg( WM_P4FILEINFORMATION );
pCmd2->SetDepotPath(theirStr);
if( pCmd2->Run( TRUE, FALSE, -1, &m_StringList ) )
MainFrame()->UpdateStatus( LoadStringResource(IDS_REQUESTING_FILE_INFORMATION) );
else
{
delete pCmd2;
pCmd->ReleaseServerLock();
}
}
else
pCmd->ReleaseServerLock();
}
else
pCmd->ReleaseServerLock();
}
else
pCmd->ReleaseServerLock();
MainFrame()->ClearStatus();
delete pCmd;
return 0;
}
void CDeltaTreeCtrl::CantDoItRightNow(int type)
{
CString msg;
msg.FormatMessage(IDS_CANTEDITCHG_INPROGRESS, LoadStringResource(type));
AddToStatus( msg, SV_WARNING );
}
void CDeltaTreeCtrl::OnUpdateSelectChanged(CCmdUI* pCmdUI)
{
BOOL selectable=FALSE;
if( GET_SERVERLEVEL() >= 19 )
{
int cnt;
BOOL underMyRoot;
HTREEITEM curitem = GetSelectedItem(0);
if( (cnt = GetSelectedCount()) == 1 && IsMyPendingChange( curitem ))
{
selectable=TRUE;
}
else if (cnt > 0 && GetItemLevel( curitem, &underMyRoot ) == 2
&& underMyRoot && IsAFile( curitem ) )
{
selectable=TRUE;
}
}
pCmdUI->Enable( selectable );
}
void CDeltaTreeCtrl::OnSelectChanged()
{
SelectChgUnchg(TRUE);
}
void CDeltaTreeCtrl::OnSelectUnchanged()
{
SelectChgUnchg(FALSE);
}
// returns TRUE if any file(s) selected
BOOL CDeltaTreeCtrl::SelectChgUnchg(BOOL bChged, int *totfiles/*=NULL*/)
{
BOOL b = FALSE;
if (totfiles)
*totfiles = 0;
BOOL underMyRoot;
HTREEITEM curitem = GetSelectedItem(0);
if( GetItemLevel(curitem, &underMyRoot) == 2 && underMyRoot && IsAFile(curitem) )
{
UnselectAll();
SetSelectState( GetParentItem(curitem), TRUE );
}
if( GetSelectedCount() == 1 && IsMyPendingChange( GetSelectedItem(0) ) )
{
SET_BUSYCURSOR();
MainFrame()->UpdateStatus(LoadStringResource(IDS_DIFFFILES));
HTREEITEM parent = GetSelectedItem(0);
UnselectAll();
SetMultiSelect(TRUE);
UINT state= CTreeCtrl::GetItemState( curitem, TVIS_EXPANDED );
if( (state & TVIS_EXPANDED) != TVIS_EXPANDED )
CTreeCtrl::Expand( curitem, TVE_EXPAND );
Error e;
CP4Command *pcmd = new CP4Command;
CGuiClient *client = pcmd->GetClient();
client->SetTrans();
client->Init(&e);
if( e.Test() )
{
delete pcmd;
return FALSE;
}
HTREEITEM child= GetChildItem( parent );
while( child != NULL )
{
LPARAM lParam=GetLParam(child);
if(lParam > 0)
{
BOOL chg = FALSE;
CP4FileStats *stats = (CP4FileStats *) lParam;
if (stats->GetMyOpenAction() == F_ADD || stats->GetMyOpenAction() == F_BRANCH)
chg = TRUE;
else if (!TheApp()->digestIsSame(stats, FALSE, client)
|| stats->GetType() != stats->GetHeadType())
chg = TRUE;
if (chg == bChged)
{
SetSelectState( child, TRUE );
b = TRUE;
}
if (totfiles)
++*totfiles;
}
child= GetNextSiblingItem(child);
}
delete pcmd;
SetMultiSelect(FALSE);
if (!b)
{
if (!totfiles)
MessageBeep(0);
SetSelectState( parent, TRUE );
MainFrame()->SetMessageText(LoadStringResource(bChged ? IDS_NOFILESCHGED : IDS_ALLFILESCHGED));
}
else
ShowNbrSelected();
SetCursor(LoadCursor(NULL, IDC_ARROW));
}
MainFrame()->ClearStatus();
return b;
}
LRESULT CDeltaTreeCtrl::CallOnUpdateFilterClearview(WPARAM wParam, LPARAM lParam)
{
OnUpdateFilterClearview((CCmdUI *)lParam);
return 0;
}
void CDeltaTreeCtrl::OnUpdateFilterClearview(CCmdUI* pCmdUI)
{
pCmdUI->SetText(LoadStringResource(IDS_FILTER_PCO_CLEARVIEW));
pCmdUI->Enable(MainFrame()->SetMenuIcon(pCmdUI, !SERVER_BUSY() &&
GET_P4REGPTR()->GetEnablePendingChgsOtherClients() &&
(GET_P4REGPTR()->FilterPendChgsByMyClient()
// || m_FilteredByClient || m_FilteredByUser
)));
}
void CDeltaTreeCtrl::OnUpdateFilterSetview(CCmdUI* pCmdUI)
{
pCmdUI->SetText(LoadStringResource(IDS_FILTER_PCO_SETVIEW));
pCmdUI->Enable( MainFrame()->SetMenuIcon(pCmdUI, !SERVER_BUSY()) &&
GET_P4REGPTR()->GetEnablePendingChgsOtherClients());
}
void CDeltaTreeCtrl::OnFilterSetview()
{
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 = FALSE;
dlg.m_bPending = TRUE;
// 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
i = GET_P4REGPTR()->FilterPendChgsByMyClient();
if (i == 0)
dlg.m_filterFiles = 0;
else if (i == 1)
dlg.m_filterFiles = 1;
else
{
CString currentTxt = GET_P4REGPTR()->FilterPendChgsByPath();
if(currentTxt.IsEmpty() || (GET_SERVERLEVEL() < 21))
dlg.m_filterFiles = 0;
else
{
if(currentTxt == selectedTxt)
dlg.m_filterFiles = 3;
else
dlg.m_filterFiles = 2;
}
}
if(dlg.DoModal() == IDCANCEL)
return;
#if 0
// 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);
}
#endif
// get the filter view
switch(dlg.m_filterFiles)
{
case 0: // all files
GET_P4REGPTR()->SetFilterPendChgsByMyClient(0);
break;
case 1: // my client files
GET_P4REGPTR()->SetFilterPendChgsByMyClient(1);
break;
case 2: // filespec
{
// convert filespec into view stringlist
CString filespec = dlg.m_filespec;
if (!filespec.IsEmpty())
{
GET_P4REGPTR()->SetFilterPendChgsByMyClient(2);
GET_P4REGPTR()->SetFilterPendChgsByPath(filespec);
GET_P4REGPTR()->AddMRUChgFilter( filespec ); // save as most recently used in Reg
}
break;
}
case 3: // selected files
{
CString filterView;
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)
filterView += list->GetNext(pos2) + _T(' ');
}
else // p4 where failed - use depot syntax after all
filterView += str + _T(' ');
delete pCmd1;
}
else
filterView += str + _T(' ');
}
filterView.TrimRight();
if (!filterView.IsEmpty())
{
GET_P4REGPTR()->SetFilterPendChgsByMyClient(2);
GET_P4REGPTR()->SetFilterPendChgsByPath(filterView);
GET_P4REGPTR()->AddMRUChgFilter( filterView ); // save as most recently used in Reg
}
break;
}
}
OnViewUpdate();
}
void CDeltaTreeCtrl::OnFilterClearview()
{
GET_P4REGPTR()->SetFilterPendChgsByMyClient(0);
OnViewUpdate();
}
void CDeltaTreeCtrl::OnUpdateAddBookmark(CCmdUI* pCmdUI)
{
BOOL root;
BOOL rc = FALSE;
if (!SERVER_BUSY() && GetSelectedCount() == 1)
{
HTREEITEM item;
if (GetItemLevel((item = GetSelectedItem(0)), &root) == 2 && IsAFile(item))
rc = TRUE;
}
pCmdUI->Enable(rc);
}
void CDeltaTreeCtrl::OnAddBookmark()
{
BOOL root;
HTREEITEM item;
if (GetSelectedCount() != 1
|| GetItemLevel((item = GetSelectedItem(0)), &root) != 2
|| !IsAFile(item))
{
ASSERT(0);
return;
}
int j;
CString txt = GetItemText(item);
if (txt.GetAt(0) == _T('/') && ((j = txt.ReverseFind(_T('#'))) != -1))
txt = txt.Left(j);
::SendMessage(m_depotWnd, WM_ADDBOOKMARK, 0, (LPARAM)(&txt));
}
| # | Change | User | Description | Committed | |
|---|---|---|---|---|---|
| #1 | 19924 | YourUncleBob |
Populate -o //guest/perforce_software/p4win/... //guest/YourUncleBob/p4win/..... |
||
| //guest/perforce_software/p4win/main/gui/DeltaTreeCtrl.cpp | |||||
| #1 | 16169 | perforce_software | Move files to follow new path scheme for branches. | ||
| //guest/perforce_software/p4win/gui/DeltaTreeCtrl.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. |
||