// // Copyright 1998 Perforce Software. All rights reserved. // // // Cmd_ListOpstat.cpp #include "stdafx.h" #include "p4win.h" #include "Cmd_ListOpStat.h" #include "Cmd_Ostat.h" #include "Cmd_ListOp.h" #include "Cmd_Get.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif IMPLEMENT_DYNCREATE(CCmd_ListOpStat, CP4Command) CCmd_ListOpStat::CCmd_ListOpStat(CGuiClient *client) : CP4Command(client) { m_ReplyMsg= WM_P4LISTOPSTAT; m_TaskName= _T("ListOpStat"); m_OutputError = FALSE; m_OpenAfterDelete = FALSE; m_ChkForSyncs = m_Sync2Head = m_WarnIfLocked = m_RevertUnchgAfter = FALSE; m_NbrChgedFilesReverted = 0; } void CCmd_ListOpStat::DeleteStatList() { while(!m_StatList.IsEmpty()) delete (CP4FileStats *) m_StatList.RemoveHead( ); } BOOL CCmd_ListOpStat::Run(CStringList *files, int command, long changeNum/*=0*/, LPCTSTR newType/*=NULL*/) { if ((command == P4VIRTREVERT && GET_SERVERLEVEL() < 20) || (command == P4REVERTUNCHG && GET_SERVERLEVEL() < 14)) { ASSERT(0); return FALSE; } // Store the parms that will be passed to CCmd_ListOp m_pFileSpecs= files; m_Command= command; m_ChangeNumber= changeNum; m_NewType= newType; return CP4Command::Run(); } void CCmd_ListOpStat::PreProcess(BOOL& done) { int i; POSITION pos; CCmd_ListOp cmd1(m_pClient); // Set up and run ListOp synchronously cmd1.Init(NULL, RUN_SYNC); cmd1.SetChkForSyncs(m_ChkForSyncs); cmd1.SetWarnIfLocked(m_WarnIfLocked); if(cmd1.Run(m_pFileSpecs, m_Command, m_ChangeNumber, m_NewType)) { m_FatalError= cmd1.GetError(); done=TRUE; if (m_ChkForSyncs) { CStringList * pSyncList = cmd1.GetSyncList(); if (!pSyncList->IsEmpty()) { for( pos= pSyncList->GetHeadPosition(); pos!= NULL; ) m_Unsynced.AddHead( pSyncList->GetNext(pos) ); CStringList * pEditList = cmd1.GetList(); for( pos= pEditList->GetHeadPosition(); pos!= NULL; ) { CString txt = pEditList->GetNext(pos); if ((i = txt.Find(_T('#'))) != -1) txt = txt.Left(i); m_RevertIfCancel.AddHead( txt ); } } else m_ChkForSyncs = FALSE; } } else { m_ErrorTxt= _T("Unable to Run ListOp"); m_FatalError=TRUE; } // Extract the CStringList from ListOp, which has filtered // results for the command. Note that Errors, warnings and // gee-whiz info have been thrown to the status window and // are not in the list CStringList *strList= cmd1.GetList(); // Check for huge file sets, where incremental screen update can take // a very looong time to complete. We are more tolerant for repoens, // because they involve updates in only one pane if(!m_FatalError && m_Command== P4REOPEN && strList->GetCount() > (3 * MAX_FILESEEKS)) { m_HitMaxFileSeeks= TRUE; TheApp()->StatusAdd(_T("CCmd_ListOpStat/P4REOPEN hit MAX_FILESEEKS - blowing off incremental update"), SV_DEBUG); } else if(!m_FatalError && m_Command!= P4REOPEN && strList->GetCount() > MAX_FILESEEKS) { m_HitMaxFileSeeks= TRUE; TheApp()->StatusAdd(_T("CCmd_ListOpStat hit MAX_FILESEEKS - blowing off incremental update"), SV_DEBUG); } // In the usual case of zero to a few hundred files, gather ostat-like info // for each file so that screen updates can be completed else if(!m_FatalError && strList->GetCount() > 0) { // Save a copy of the stringlist. for( pos= strList->GetHeadPosition(); pos!= NULL; ) m_StrListOut.AddHead( strList->GetNext(pos) ); // See if we need to run Ostat if(m_Command==P4EDIT || m_Command==P4DELETE) { // Set up and run ostat synchronously CCmd_Ostat cmd2(m_pClient); cmd2.Init(NULL, RUN_SYNC); if(cmd2.Run(FALSE, m_ChangeNumber)) m_FatalError= cmd2.GetError(); else { m_ErrorTxt= _T("Unable to Run Ostat"); m_FatalError=TRUE; } CObArray const *array= cmd2.GetArray(); if(!m_FatalError && array->GetSize() > 0) { // Save a copy of the oblist. for( int i=0; i < array->GetSize(); i++ ) m_StatList.AddHead( array->GetAt(i) ); } } else PrepareStatInfo(); } // Post the completion message if(!m_FatalError) { CString message; int already = 0; int reopened = 0; switch(m_Command) { case P4EDIT: for( pos= strList->GetHeadPosition(); pos!= NULL; ) { CString str = strList->GetNext(pos); if (str.Find(_T(" - currently opened ")) != -1) already++; else if (str.Find(_T(" - reopened ")) != -1) reopened++; } message.FormatMessage(IDS_OPENED_n_FILES_FOR_EDIT, strList->GetCount() - already - reopened); if (reopened) message.FormatMessage(IDS_s_n_FILES_REOPENED, message, reopened); if (already) message.FormatMessage(IDS_s_n_FILES_ALREADY_OPENED, message, already); break; case P4REOPEN: message.FormatMessage(IDS_REOPENED_n_FILES, strList->GetCount()); break; case P4REVERT: case P4VIRTREVERT: m_OutputError = cmd1.GetOutputErrFlag(); message.FormatMessage(m_OutputError ? IDS_ERROR_REVERTING_n_FILES : IDS_REVERTED_n_FILES, strList->GetCount()); break; case P4REVERTUNCHG: m_OutputError = cmd1.GetOutputErrFlag(); if (m_OutputError) message.FormatMessage(IDS_ERROR_REVERTING_n_FILES, strList->GetCount()); else if (m_NbrChgedFilesReverted) message.FormatMessage(IDS_REVERTED_n_FILES_n_CHG_n_UNCHG, m_NbrChgedFilesReverted + strList->GetCount(), m_NbrChgedFilesReverted, strList->GetCount()); else message.FormatMessage(IDS_REVERTED_n_FILES, strList->GetCount()); break; case P4LOCK: message.FormatMessage(IDS_LOCKED_n_FILES, strList->GetCount()); break; case P4UNLOCK: message.FormatMessage(IDS_UNLOCKED_n_FILES, strList->GetCount()); break; case P4DELETE: for( pos= strList->GetHeadPosition(); pos!= NULL; ) { CString str = strList->GetNext(pos); if (str.Find(_T(" - currently opened ")) != -1) already++; else if (str.Find(_T(" - reopened ")) != -1) reopened++; } message.FormatMessage(IDS_OPENED_n_FILES_FOR_DELETE, strList->GetCount() - already - reopened); if (reopened) message.FormatMessage(IDS_s_n_FILES_REOPENED, message, reopened); if (already) message.FormatMessage(IDS_s_n_FILES_ALREADY_OPENED, message, already); break; case P4ADD: message.FormatMessage(IDS_OPENED_n_FILES_FOR_ADD, strList->GetCount()); break; default: ASSERT(0); } if(!message.IsEmpty()) TheApp()->StatusAdd( message, SV_COMPLETION ); } done=TRUE; } // PrepareStatInfo() // // For calls other than EDIT and DELETE, we can get the gui's // depot and changes windows updated with the sparse info that // the server has returned. But we need to put that sparse info // into the appropriate CP4FileStat objects, to avoid complexities // in the list process handlers of the depot and changes windows void CCmd_ListOpStat::PrepareStatInfo() { POSITION pos; CString listRow, fname, fRev; int separator; int pound = -1; int lastSlash; int rev = -1; BOOL rowError; for(pos=m_StrListOut.GetHeadPosition(); pos !=NULL; ) { listRow=fname=m_StrListOut.GetNext(pos); rowError=FALSE; ////////////// // Separate the filename from the action description // For all operations but lock and unlock, this amounts to a // quick search for '#'. In the case of the lock commands, // there is no revision number, so search for the action text itself switch(m_Command) { case P4LOCK: // For Lock and Unlock, server doesnt send rev number separator= listRow.Find(_T(" - locking")); if(separator == -1) rowError=TRUE; break; case P4UNLOCK: // For Lock and Unlock, server doesnt send rev number separator= listRow.Find(_T(" - unlocking")); if(separator == -1) rowError=TRUE; break; default: pound= listRow.Find(_T('#')); if(pound == -1) { separator = -1; // this is just to make the compiler shut up rowError=TRUE; break; } separator= pound+1; int len= listRow.GetLength(); for( ; separator < len ; separator++) { if(listRow[separator]==_T(' ') && listRow[separator+1]==_T('-') && listRow[separator+2]==_T(' ')) break; } if(separator==len) rowError=TRUE; } if(rowError) { // doesnt look like a valid row, report it and skip it ASSERT(0); listRow= _T("Invalid listRow: ") + listRow; TheApp()->StatusAdd(listRow, SV_WARNING); continue; } fname=fname.Left(separator); lastSlash=fname.ReverseFind(_T('/')); // For Lock and Unlock, server doesnt send rev number if(m_Command != P4LOCK && m_Command != P4UNLOCK) { fRev=fname.Mid(pound+1); rev=_ttol(fRev); fname=fname.Left(pound); // full name without revision } CP4FileStats *fs= new CP4FileStats; fs->SetDepotPath(fname); switch(m_Command) { case P4EDIT: fs->SetOpenAction(F_EDIT, FALSE); fs->SetHaveRev(rev); fs->SetOpenChangeNum(m_ChangeNumber); break; case P4DELETE: fs->SetOpenAction(F_DELETE, FALSE); fs->SetHaveRev(rev); fs->SetOpenChangeNum(m_ChangeNumber); break; case P4LOCK: fs->SetLocked(TRUE, FALSE); break; case P4UNLOCK: fs->SetLocked(FALSE, FALSE); break; case P4REOPEN: case P4REVERT: case P4VIRTREVERT: case P4REVERTUNCHG: break; case P4ADD: fs->SetOpenAction(F_ADD, FALSE); fs->SetHaveRev(rev); fs->SetOpenChangeNum(m_ChangeNumber); break; default: ASSERT(0); } m_StatList.AddHead(fs); } // for each } void CCmd_ListOpStat::Add2RevertList( CObject const * obj, int iAction ) { CP4FileStats const *stats= (CP4FileStats const *) obj; CString name=stats->GetFullDepotPath(); m_RevertIfCancel.AddHead(name); if (iAction == 1) m_RevertAdds.AddHead(name); }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#1 | 19924 | YourUncleBob |
Populate -o //guest/perforce_software/p4win/... //guest/YourUncleBob/p4win/..... |
||
//guest/perforce_software/p4win/main/gui/p4api/Cmd_ListOpStat.cpp | |||||
#1 | 16169 | perforce_software | Move files to follow new path scheme for branches. | ||
//guest/perforce_software/p4win/gui/p4api/Cmd_ListOpStat.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. |