// Copyright 1999 (c) by Perforce Software, Inc. All rights reserved. // // p4wMenuProcessorView: // The menu bar processor view. // ------------------------------------- // Includes // #include <stdlib.h> #include <string.h> #include <p4wp4.h> #include "p4wView.h" #include "p4wStrBuf.h" #include "p4wAddPane.h" #include "p4wAddSelectPane.h" #include "p4wBranchPane.h" #include "p4wBranchDiffPane.h" #include "p4wCmdPane.h" #include "p4wChangesPane.h" #include "p4wDeletePane.h" #include "p4wDelConfirmPane.h" #include "p4wEditPane.h" #include "p4wFTypePane.h" #include "p4wIntegPane.h" #include "p4wJobPane.h" #include "p4wLabelFilesPane.h" #include "p4wLabelPane.h" #include "p4wLabelReplacePane.h" #include "p4wLockPane.h" #include "p4wMatchPane.h" #include "p4wSyncPane.h" #include "p4wResolvePane.h" #include "p4wRevertPane.h" #include "p4wUnlockPane.h" #include "changeshelper.h" #include "p4wUpdatePane.h" #include "p4wMenuPane.h" #include "p4wConfigPane.h" #include "p4wMultiUserPane.h" #include "p4wP4CmdPane.h" #include "p4wShowHideColsPane.h" #include "p4wSubmitDefPane.h" #include "p4wPasswdTestPane.h" #include "p4wDiff2DirsPane.h" #include "p4wMenuProcessorView.h" // ------------------------------------- // Constructors and destructor. // p4wMenuProcessorView::p4wMenuProcessorView( p4wRequest & Request, AllCommands cmd ) : p4wView( Request ), fCommand( cmd ) { // // Initialize "from file browser" status and title fIsFromFileBrowser = p4wMenuPane::FromFileBrowser( fCommand ); // // Use the actual menu string for the title, except for // the forms which have an intermediate screen. if( cmd == AC_ADDFRM ) { fMenuTitle.Set( "Select files to add" ); return; } else if( cmd == AC_DELETEJOB ) { fMenuTitle.Set( "Job -d " ); fMenuTitle << fRequest.GetURL() << " Result"; return; } else if( cmd == AC_DELETELABEL ) { fMenuTitle.Set( "Label -d " ); fMenuTitle << fRequest.GetURL() << " Result"; return; } else if( cmd == AC_DELETEBRANCH ) { fMenuTitle.Set( "Branch -d " ); fMenuTitle << fRequest.GetURL() << " Result"; return; } // // Strip off the ellipses from the menu title if found fMenuTitle.Set( p4wMenuPane::GetMenuItem( cmd, fRequest.GetBrowseMode() ) ); char *e = strstr( fMenuTitle.Text(), "..." ); if( e ) fMenuTitle.Set( fMenuTitle.Text(), e - fMenuTitle.Text() ); // // Set the short and long versions of the title fFullTitle << fMenuTitle; // // Pages that show command results display // only Command Results in the info pane title switch( fCommand ) { case AC_REMOVEFILEFRM: case AC_LOCKFILEFRM: case AC_UNLOCKFILEFRM: case AC_REVERTUNCHANGEDFILEFRM: case AC_REVERTFILEFRM: case AC_DELETELABEL: case AC_DELETEBRANCH: case AC_DELETEJOB: fShortTitle << "Command Result"; break; default: fShortTitle << fMenuTitle; break; } } p4wMenuProcessorView::~p4wMenuProcessorView() { } // ------------------------------------- // Menu render functions. // void p4wMenuProcessorView::RenderContent() { switch( fCommand ) { case AC_SYNCFRM: case AC_SYNCFILEFRM: { p4wSyncPane syncPane( *this, fRequest, IsFromFileBrowser(), 0 ); doFstat( &syncPane ); } break; case AC_SYNCCHANGE: case AC_SYNCCHANGERNG: case AC_SYNCLABEL: { p4wSyncPane syncPane( *this, fRequest, IsFromFileBrowser(), 0 ); syncPane.RenderNoFiles(); } break; case AC_EDITFRM: case AC_EDITFILEFRM: { p4wEditPane editPane( *this, fRequest, IsFromFileBrowser() ); doPendingChanges( &editPane ); if( !editPane.FatalError() ) doFstat( &editPane ); } break; case AC_ADDFRM: { p4wAddSelectPane addPane( *this, fRequest ); StrBuf path; path << fRequest.GetPath() << "..."; fRequest.p4Arg( path.Text() ); fRequest.p4( "where", 0, 0, &addPane ); fRequest.p4Wait(); } break; case AC_ADDFILEFRM: { p4wAddPane addFilePane( *this, fRequest, 1, 0 ); doPendingChanges( &addFilePane ); if( !addFilePane.FatalError() ) doFstat( &addFilePane ); } break; case AC_DELETEFRM: case AC_DELETEFILEFRM: { p4wDeletePane deletePane( *this, fRequest, IsFromFileBrowser() ); doPendingChanges( &deletePane ); if( !deletePane.FatalError() ) doFstat( &deletePane ); } break; case AC_FILETYPEFRM: { p4wFTypePane fTypePane( *this, fRequest, 0 ); StrBuf path; path << fRequest.GetPath() << "..."; fRequest.p4Arg( "-W" ); fRequest.p4Arg( "-P" ); fRequest.p4Arg( path.Text() ); fRequest.p4( "fstat", 0, 0, &fTypePane ); fRequest.p4Wait(); } break; case AC_FILETYPEFILEFRM: { p4wFTypePane fTypePane( *this, fRequest, 1 ); doFstat( &fTypePane ); } break; case AC_REMOVEFRM: { p4wSyncPane syncPane( *this, fRequest, IsFromFileBrowser(), 1 ); doFstat( &syncPane ); } break; case AC_REMOVEFILEFRM: { const char *cmdPaneArgs[1]; StrBuf title; StrBuf filePattern; filePattern << fRequest.GetPath() << "#none"; title << "Sync " << filePattern; cmdPaneArgs[0] = filePattern.Text(); p4wCmdPane cmdPane( *this, fRequest, title.Text() ); fRequest.p4( "sync", 1, cmdPaneArgs, &cmdPane ); fRequest.p4Wait(); } break; case AC_INTEGRATEFRM: { if (SEC_DISALLOW_INTEG && !fRequest.isLocalRequest()) { RenderError( "Integrations currently are not allowed." ); break; } p4wIntegPane integPane( *this, fRequest, 0, 0 ); doPendingChanges( &integPane ); } break; case AC_INTEGRATEFILEFRM: { if (SEC_DISALLOW_INTEG && !fRequest.isLocalRequest()) { RenderError( "Integrations currently are not allowed." ); break; } p4wIntegPane integPane( *this, fRequest, 1, 0 ); doPendingChanges( &integPane ); } break; case AC_INTEGRATEBRANCH: { if (SEC_DISALLOW_INTEG && !fRequest.isLocalRequest()) { RenderError( "Integrations currently are not allowed." ); break; } p4wIntegPane integPane( *this, fRequest, 0, 1 ); doPendingChanges( &integPane ); } break; case AC_RESOLVEFRM: { StrBuf path; path << fRequest.GetPath() << "..."; const char *fstatArgs[] = { "-P", "-W", path.Text() }; p4wResolvePane resolvePane( *this, fRequest, 0 ); fRequest.p4( "fstat", 3, fstatArgs, &resolvePane ); fRequest.p4Wait(); } break; case AC_RESOLVEFILEFRM: { p4wResolvePane resolvePane( *this, fRequest, 1 ); doFstat( &resolvePane ); } break; case AC_LOCKFRM: { p4wLockPane lockPane( *this, fRequest ); doPendingChanges( &lockPane ); if( !lockPane.FatalError() ) { StrBuf path; path << fRequest.GetPath() << "..."; const char *openedArgs[] = { path.Text() }; fRequest.p4( "opened", 1, openedArgs, &lockPane ); fRequest.p4Wait(); } } break; case AC_LOCKFILEFRM: { const char *cmdPaneArgs[] = { fRequest.GetPath().Text() }; StrBuf title; title << "Lock " << fRequest.GetPath(); p4wCmdPane cmdPane( *this, fRequest, title.Text() ); fRequest.p4( "lock", 1, cmdPaneArgs, &cmdPane ); fRequest.p4Wait(); } break; case AC_UNLOCKFRM: { p4wUnlockPane unlockPane( *this, fRequest ); doPendingChanges( &unlockPane ); if( !unlockPane.FatalError() ) { StrBuf path; path << fRequest.GetPath() << "..."; const char *openedArgs[] = { path.Text() }; fRequest.p4( "opened", 1, openedArgs, &unlockPane ); fRequest.p4Wait(); } } break; case AC_UNLOCKFILEFRM: { const char *cmdPaneArgs[] = { fRequest.GetPath().Text() }; StrBuf title; title << "Unlock " << fRequest.GetPath(); p4wCmdPane cmdPane( *this, fRequest, title.Text() ); fRequest.p4( "unlock", 1, cmdPaneArgs, &cmdPane ); fRequest.p4Wait(); } break; case AC_DIFF2DIRSOUTPUT: { StrBuf path, path2; const StrPtr *fil1 = fRequest.GetDynArg( "fil1" ); const StrPtr *fil2 = fRequest.GetDynArg( "fil2" ); const StrPtr *rev1 = fRequest.GetDynArg( "rev1" ); const StrPtr *rev2 = fRequest.GetDynArg( "rev2" ); if (fil1) path.Set(fil1); if (rev1) path << "#" << rev1; else { const StrPtr *sr1 = fRequest.GetDynArg( "sr1" ); if (sr1) path << "@" << sr1; } if (fil2) path2.Set(fil2); else path2.Set(fRequest.GetPath()); if (rev2) path2 << "#" << rev2; else { const StrPtr *sr2 = fRequest.GetDynArg( "sr2" ); if (sr2) path2 << "@" << sr2; } // // The -dw & -db flags are only supported for 2002.2+ // servers. If this flag is set, we need to check the // server protocol. int protocol = 0; const StrPtr *server; server = fRequest.GetProtocol( "server2" ); if( !server ) { p4wPasswdTestPane dummyCmd( *this, fRequest ); fRequest.p4( "info", 0, 0, &dummyCmd ); fRequest.p4Wait(); StrPtr clientRoot; clientRoot = dummyCmd.GetClientRoot(); fRequest.SetClientRoot( &clientRoot ); server = fRequest.GetProtocol( "server2" ); } if( server ) protocol = server->Atoi(); StrBuf dwbFlag; const StrPtr *dw = fRequest.GetStateArg( "dw" ); if( dw ) { if( ( protocol > 16 && strpbrk( dw->Text(), "wblncsuO" ) ) || ( protocol < 17 && strpbrk( dw->Text(), "wbncsuO" ) ) ) { dwbFlag << "-d"; dwbFlag << dw; } } if( dwbFlag.Length() && protocol > 13 ) { const StrPtr *dc = fRequest.GetStateArg( "dc" ); char *p = strchr(dwbFlag.Text(), 'c'); if (p) // context now done at output time { int i = dc ? atoi(dc->Text()) : 15; if (i > 0) { strcpy(p, p+1); dwbFlag.SetLength(); fRequest.SetDiffType(i); } } p = strchr(dwbFlag.Text(), 'O'); if (p) // O is p4web's diffs only flag { strcpy(p, p+1); dwbFlag.SetLength(); fRequest.SetDiffType(0); } if (dwbFlag.Length() > 2) fRequest.p4Arg( dwbFlag.Text() ); } // // Send the request p4wDiff2DirsPane diff2DirsPane( *this, fRequest, &path, &path2 ); fRequest.p4Arg( "-q" ); fRequest.p4Arg( path.Text() ); fRequest.p4Arg( path2.Text() ); fRequest.p4( "diff2", 0, 0, &diff2DirsPane ); fRequest.p4Wait(); } break; case AC_REVERTUNCHANGEDFILEFRM: case AC_REVERTFILEFRM: { const char *cmdPaneArgs[] = { NULL, NULL }; int nArgs = 0; StrBuf title; title.Set("Revert "); if( fCommand == AC_REVERTUNCHANGEDFILEFRM ) { title << "-a "; cmdPaneArgs[nArgs++] = "-a"; } title << fRequest.GetPath(); cmdPaneArgs[nArgs++] = fRequest.GetPath().Text(); p4wCmdPane cmdPane( *this, fRequest, title.Text() ); fRequest.p4( "revert", nArgs, cmdPaneArgs, &cmdPane ); fRequest.p4Wait(); } break; case AC_REVERTFRM: { p4wRevertPane revertPane( *this, fRequest ); doPendingChanges( &revertPane ); if( !revertPane.FatalError() ) { StrBuf path; path << fRequest.GetPath() << "..."; const char *fstatArgs[] = { "-P", "-W", path.Text() }; fRequest.p4( "fstat", 3, fstatArgs, &revertPane ); fRequest.p4Wait(); } } break; case AC_FILESMATCHINGFRM: { p4wMatchPane matchPane( *this, fRequest ); matchPane.Render( NULL ); } break; case AC_PENDINGINTEGS: { RenderError( "Pending integrations currently not supported." ); } break; case AC_PENDINGCHANGELISTS: case AC_FIXPENDING: { p4wChangesPane changesPane( *this, fRequest, 1 ); doPendingChanges( &changesPane ); } break; case AC_SUBMITFRM: { p4wSubmitDefPane submitPane( *this, fRequest, 0 ); submitPane.RenderPathOnly(); } break; case AC_SUBMITFILEFRM: { p4wSubmitDefPane submitPane( *this, fRequest, 1 ); fRequest.p4Arg( "-c" ); fRequest.p4Arg( "default" ); fRequest.p4Arg( fRequest.GetPath().Text() ); fRequest.p4( "opened", 0, 0, &submitPane ); fRequest.p4Wait(); } break; case AC_CONFIGURATION: { // // Issue a dummy command so that the protocol // level can be checked later from the settings // page (if we don't already have the protocol) const StrPtr *server = fRequest.GetProtocol( "server2" ); if (!server) { p4wPasswdTestPane dummy( *this, fRequest ); fRequest.p4( "info", 0, 0, &dummy ); fRequest.p4Wait(); } p4wConfigPane configPane( *this, fRequest ); configPane.Render( NULL ); } break; case AC_MULTIUSER: { // // Issue a dummy command so that the protocol // level can be checked later from the settings // page (if we don't already have the protocol) const StrPtr *server = fRequest.GetProtocol( "server2" ); if (!server) { p4wPasswdTestPane dummy( *this, fRequest ); fRequest.p4( "info", 0, 0, &dummy ); fRequest.p4Wait(); } p4wMultiUserPane multiuserPane( *this, fRequest ); if ( server->Atoi() >= 22 ) { fRequest.p4Arg( "-u" ); fRequest.p4Arg( fRequest.GetUser().Text() ); } fRequest.p4( "clients", 0, 0, &multiuserPane ); fRequest.p4Wait(); multiuserPane.SetErrorMsg(fErrorMsg.Text()); multiuserPane.Render( NULL ); } break; case AC_P4CMDPANE: { // // Issue a dummy command so that the protocol // level can be checked later (if necessary) const StrPtr *server = fRequest.GetProtocol( "server2" ); if (!server) { p4wPasswdTestPane dummy( *this, fRequest ); fRequest.p4( "info", 0, 0, &dummy ); fRequest.p4Wait(); } p4wP4CmdPane configPane( *this, fRequest ); configPane.Render( NULL ); } break; case AC_LABELFILES: case AC_LABELFILESTEXT: { p4wLabelFilesPane labelFiles( *this, fRequest ); StrBuf arg; if( fRequest.GetURL().Length() ) { arg << "@" << fRequest.GetURL().Text(); fRequest.p4Arg( arg.Text() ); } fRequest.p4( "files", 0, 0, &labelFiles ); fRequest.p4Wait(); } break; case AC_DELETELABEL: { StrBuf title; title << "Label -d " << fRequest.GetURL(); p4wCmdPane cmd( *this, fRequest, title.Text() ); fRequest.p4Arg( "-d" ); if( fRequest.GetURL().Length() ) fRequest.p4Arg( fRequest.GetURL().Text() ); fRequest.p4( "label", 0, 0, &cmd ); fRequest.p4Wait(); } break; case AC_REPLACELABEL: { p4wLabelReplacePane labelReplace( *this, fRequest ); labelReplace.Render( NULL ); } break; case AC_CREATELABELTMP: { p4wLabelPane labelCreate( *this, fRequest, 1 ); fRequest.p4Arg( "-o" ); fRequest.p4Arg( "-t" ); if( fRequest.GetURL().Length() ) fRequest.p4Arg( fRequest.GetURL().Text() ); fRequest.p4Arg( "xxx_An_Unlikely_SPEC_Name_xxx" ); fRequest.p4( "label", 0, 0, &labelCreate ); fRequest.p4Wait(); } break; case AC_CREATELABEL: { p4wLabelPane labelCreate( *this, fRequest, 1 ); fRequest.p4Arg( "-o" ); fRequest.p4Arg( "xxx_An_Unlikely_SPEC_Name_xxx" ); fRequest.p4( "label", 0, 0, &labelCreate ); fRequest.p4Wait(); } break; case AC_DELETEBRANCH: { StrBuf title; title << "Branch -d " << fRequest.GetURL(); p4wCmdPane cmd( *this, fRequest, title.Text() ); fRequest.p4Arg( "-d" ); if( fRequest.GetURL().Length() ) fRequest.p4Arg( fRequest.GetURL().Text() ); fRequest.p4( "branch", 0, 0, &cmd ); fRequest.p4Wait(); } break; case AC_CREATEBRANCH: { p4wBranchPane branchCreate( *this, fRequest, 1 ); fRequest.p4Arg( "-o" ); fRequest.p4Arg( "xxx_An_Unlikely_BRANCH_Name_xxx" ); fRequest.p4( "branch", 0, 0, &branchCreate ); fRequest.p4Wait(); } break; case AC_BRANCHDIFF: { p4wBranchDiffPane branchDiff( *this, fRequest ); fRequest.p4Arg( "-q" ); // // The -dw & -db flags are only supported for 2002.2+ // servers. The -dl flag is only supported for 2003.2+ // If this flag is set, we need to check the // server protocol after issuing a dummy command. const StrPtr *dw = fRequest.GetStateArg( "dw" ); if( dw && strpbrk( dw->Text(), "wblncsuO" ) ) { const StrPtr *server = fRequest.GetProtocol( "server2" ); if (!server) { p4wPasswdTestPane dummyCmd( *this, fRequest ); fRequest.p4( "info", 0, 0, &dummyCmd ); fRequest.p4Wait(); server = fRequest.GetProtocol( "server2" ); } int protocol; if( server ) protocol = server->Atoi(); if( ( strpbrk( dw->Text(), "wblncsuO" ) && protocol > 16 ) || ( protocol > 13 && strpbrk( dw->Text(), "wbncsuO" ) ) ) { StrBuf flags; flags << "-d" << dw; char *p = strchr(flags.Text(), 'O'); if (p) // O is p4web's diffs only flag; remove it, not relevant here { strcpy(p, p+1); flags.SetLength(); fRequest.SetDiffType(0); // doesn't do anything here yet } if (flags.Length() > 2) fRequest.p4Arg( flags.Text() ); } } fRequest.p4Arg( "-b" ); if( fRequest.GetURL().Length() ) fRequest.p4Arg( fRequest.GetURL().Text() ); fRequest.p4( "diff2", 0, 0, &branchDiff ); fRequest.p4Wait(); } break; case AC_DELETEJOB: { StrBuf title; title << "Job -d " << fRequest.GetURL(); p4wCmdPane cmd( *this, fRequest, title.Text() ); fRequest.p4Arg( "-d" ); if( fRequest.GetURL().Length() ) fRequest.p4Arg( fRequest.GetURL().Text() ); fRequest.p4( "job", 0, 0, &cmd ); fRequest.p4Wait(); } break; case AC_CREATEJOB: { p4wJobPane jobCreate( *this, fRequest, 1 ); fRequest.p4Arg( "-o" ); fRequest.p4( "job", 0, 0, &jobCreate ); fRequest.p4Wait(); } break; case AC_DELETEJOBCONFIRM: case AC_DELETEBRANCHCONFIRM: case AC_DELETELABELCONFIRM: case AC_REVERTCONFIRM: { p4wDelConfirmPane confirm( *this, fRequest ); confirm.RenderConfirm(); } break; case AC_SHOWHIDECOLUMNS: { p4wShowHideColsPane showhide( *this, fRequest ); showhide.RenderShowHide(); } break; default: RenderError( "Requested URL is invalid in this context." ); break; } } void p4wMenuProcessorView::RenderMenu() { // // Set help text based on type of command StrBuf helpText; switch(fCommand) { case AC_SYNCFRM: case AC_SYNCFILEFRM: case AC_SYNCLABEL: case AC_SYNCCHANGE: case AC_SYNCCHANGERNG: helpText.Set( "sync" ); break; case AC_SUBMITFRM: case AC_SUBMITFILEFRM: helpText.Set( "submit" ); break; case AC_EDITFRM: case AC_EDITFILEFRM: helpText.Set( "edit" ); break; case AC_ADDFRM: case AC_ADDFILEFRM: helpText.Set( "addselect" ); break; case AC_DELETEFRM: case AC_DELETEFILEFRM: helpText.Set( "delete" ); break; case AC_FILETYPEFRM: case AC_FILETYPEFILEFRM: helpText.Set( "filetype" ); break; case AC_REMOVEFRM: helpText.Set( "remove" ); break; case AC_REMOVEFILEFRM: case AC_LOCKFILEFRM: case AC_UNLOCKFILEFRM: case AC_REVERTUNCHANGEDFILEFRM: case AC_REVERTFILEFRM: helpText.Set( "result" ); break; case AC_INTEGRATEFRM: case AC_INTEGRATEFILEFRM: case AC_INTEGRATEBRANCH: helpText.Set( "integrate" ); break; case AC_RESOLVEFRM: case AC_RESOLVEFILEFRM: helpText.Set( "resolve" ); break; case AC_LOCKFRM: helpText.Set( "lock" ); break; case AC_UNLOCKFRM: helpText.Set( "unlock" ); break; case AC_REVERTFRM: case AC_REVERTCONFIRM: helpText.Set( "revert" ); break; case AC_FILESMATCHINGFRM: case AC_PENDINGINTEGS: case AC_WORKSPACE: case AC_SHOWHIDECOLUMNS: helpText.Set( "pathbrowser" ); break; case AC_PENDINGCHANGELISTS: helpText.Set( "pendingchangelists" ); break; case AC_FIXPENDING: helpText.Set( "job" ); break; case AC_CONFIGURATION: helpText.Set( "settings" ); break; case AC_MULTIUSER: helpText.Set( "client" ); break; case AC_P4CMDPANE: helpText.Set( "p4cmd" ); break; case AC_LABELFILES: case AC_LABELFILESTEXT: helpText.Set( "label" ); break; case AC_REPLACELABEL: helpText.Set( "labelsync" ); break; case AC_CREATELABEL: case AC_CREATELABELTMP: helpText.Set( "editlabel" ); break; case AC_CREATEBRANCH: helpText.Set( "editbranch" ); break; case AC_CREATEJOB: helpText.Set( "editjob" ); break; case AC_BRANCHDIFF: helpText.Set( "branch" ); break; case AC_DELETELABELCONFIRM: case AC_DELETEJOBCONFIRM: case AC_DELETEBRANCHCONFIRM: helpText.Set( "deletespec" ); break; default: helpText.Set( "result" ); break; } // // Draw the menu bar p4wMenuPane menuPane( *this, fRequest, helpText.Text() ); menuPane.Render( NULL ); } void p4wMenuProcessorView::doPendingChanges( p4wPane *cmdPane ) { // // Request all pending changes const char *changesArgs[] = { "-s", "pending" }; fRequest.p4( "changes", 2, changesArgs, cmdPane ); fRequest.p4Wait(); } void p4wMenuProcessorView::doFstat( p4wPane *cmdPane ) { // // fstat files in current path if command is from path browser, // otherwise just fstat the one file if from file browser. // Use -P option for commands from path browser so that // the clientFile argument can be passed to the command // to improve performance. StrBuf path; if( IsFromFileBrowser() ) { path << fRequest.GetPath(); } else { path << fRequest.GetPath() << "*"; fRequest.p4Arg( "-P" ); } fRequest.p4Arg( path.Text() ); fRequest.p4( "fstat", 0, 0, cmdPane ); fRequest.p4Wait(); } int p4wMenuProcessorView::RenderUpdateOK() { // // Generate the Recent Activity pane for most pages if (!p4wAllCommands::ShowRecentActivity( fCommand )) { // // Confirmation pages and intermediate pages don't // display recent activity. return 1; } p4wView::RenderUpdateOK(); return 1; }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#1 | 12234 | Matt Attaway |
Rejigger P4Web project in preparation for official sunsetting The bin directory contains the last official builds of P4Web from the Perforce download site. P4Web is soon to be completely sunsetted; these builds are here for folks who don't want to build their own. To better handle the archived builds the source code has been moved into a separate src directory. |
||
//guest/perforce_software/p4web/Views/p4wMenuProcessorView.cpp | |||||
#1 | 8914 | Matt Attaway | Initial add of the P4Web source code |