// // 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, LoadStringResource( IDS_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, LoadStringResource(IDS_DELEMPTYCHANGELIST) ); // Choices relevant only to non-empty change if(HasChildren(currentItem)) { popMenu.AppendMenu( stringsON, ID_CHANGE_REVORIG, LoadStringResource(IDS_REVERTUNCHANGED) ); 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 | |
---|---|---|---|---|---|
#2 | 11450 | brkarpala |
p4win - Fix missing context menu items - Seems for whatever reason some items did not have the string resource set. Seems odd? - This was specifically fixed in: - on changelists - on clientspecs - on depot tree (sync sub menu) |
||
#1 | 11099 | brkarpala | Integrate p4win from //guest/perforce_software/p4win/...@8562 | ||
//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. |