// // Copyright 2002 Perforce Software. All rights reserved. // // This file is part of Perforce - the FAST SCM System. // // p4wFileBrowserView: // Issues the command used to generate the file browser page. // This command corresponds to one of the Show menu items on // the file browser page, with the default as filelog. #include <stdlib.h> #include <string.h> #include <p4wp4.h> #include "p4wI18n.h" #include "p4wView.h" #include "p4wFileBrowserView.h" #include "changeshelper.h" #include "p4wUpdatePane.h" #include "p4wDiffPane.h" #include "p4wDiff2FilesPane.h" #include "p4wFilelogPane.h" #include "p4wMenuPane.h" #include "p4wPrintPane.h" #include "p4wReadLocalPane.h" #include "p4wEditLocalPane.h" #include "p4wUploadLocalPane.h" #include "p4wClientRootPane.h" #include "p4wResolveIAendPane.h" #include "p4wCmdPane.h" #include "p4wAnnotatePane.h" #include "p4wAnnFilelogPane.h" #include "p4wPasswdTestPane.h" #include "p4wFileBrowserPane.h" #include <fstathelper.h> # ifdef OS_QNX # define EXECVCAST(x) ((const char * const *)(x)) # else # define EXECVCAST(x) (x) # endif // // ------------------------------------- // Constructors and destructor. // p4wFileBrowserView::p4wFileBrowserView( p4wRequest & Request, AllCommands cmd ) : p4wView( Request ), fCommand( cmd ), fSentCmd( 0 ) { fIsFromFileBrowser = 1; fRequest.ReplaceBase( "cdf", fRequest.GetPath().Text() ); fClientRoot.Set(""); // // Set the short and the long versions of the title fShortTitle.Set( "Files" ); fFullTitle.Set( fRequest.GetPath() ); } p4wFileBrowserView::~p4wFileBrowserView() { } // ------------------------------------- // Control item render functions. // int p4wFileBrowserView::RenderUpdateOK() { // // Create and send the update pane containing last five changes StrBuf path; path = fRequest.GetPath().Text(); if ( !fIsFromFileBrowser ) { path << "..."; } p4wUpdatePane updatePane( *this, fRequest, path ); updatePane.DrawPane(); // // We need to know later if we have issued a p4 command. fSentCmd = 1; return 1; } void p4wFileBrowserView::RenderContent() { // // Create and send the filebrowser pane. Pass on any rev arguments // to the fstat commands. const StrPtr *rev1 = fRequest.GetDynArg( "rev1" ); const StrPtr *rev2 = fRequest.GetDynArg( "rev2" ); const StrPtr *srev = fRequest.GetDynArg( "sr" ); const StrPtr *srev2 = fRequest.GetDynArg( "sr2" ); const StrPtr *srevState = fRequest.GetStateArg( "sr" ); const StrPtr *fl = fRequest.GetDynArg( "fl" ); const StrPtr *dw = fRequest.GetStateArg( "dw" ); const StrPtr *dc = fRequest.GetStateArg( "dc" ); const StrPtr *mx = fRequest.GetDynArg( "mx" ); const StrPtr *server; int protocol = 0; StrBuf path; StrBuf path2; StrBuf dwbFlag; // // If both state and dynamic parameters for sr are set, dynamic // parameter wins. Set srev to the value that wins. if( !srev && srevState ) srev = srevState; // // Check the server protocol level before using newer // server features. Server protocol 13 supports -P flag // which gives all 3 fstat mappings. Server protocol 17 // supports diff -dl. We can't check protocol until a // command has been issued. Issue a dummy cmd if needed. // While we have the info, save the client's root. fClientRoot = fRequest.GetClientRoot(); server = fRequest.GetProtocol( "server2" ); if( !*(fClientRoot.Text()) || !server ) { p4wPasswdTestPane dummyCmd( *this, fRequest ); fRequest.p4( "info", 0, 0, &dummyCmd ); fRequest.p4Wait(); fClientRoot = dummyCmd.GetClientRoot(); fRequest.SetClientRoot( &fClientRoot ); server = fRequest.GetProtocol( "server2" ); } if( server ) protocol = server->Atoi(); // // Check the dw arg, and set the flag if the arg is // correct if( dw ) { if( ( protocol > 16 && strpbrk( dw->Text(), "wblncsuO" ) ) || ( protocol < 17 && strpbrk( dw->Text(), "wbncsuO" ) ) ) { dwbFlag << "-d"; dwbFlag << dw; } } p4wFileBrowserPane fileBrowserPane( *this, fRequest, fClientRoot ); // // Don't continue unless this is a file, not a path if( HasDirPattern( fRequest.GetPath().Text() ) ) { StrBuf errMsg; errMsg.Set( p4wMenuPane::GetMenuItem( fRequest.GetCmd(), fRequest.GetBrowseMode() ) ); errMsg << " not available for multiple files."; fileBrowserPane.RenderError( errMsg.Text(), 1 ); return; } // // Don't continue if running Edit File in Browser and -a flag set if( (fRequest.GetCmd() == AC_EDITTEXTLOCAL || fRequest.GetCmd() == AC_UPLOADTOLOCAL) && !fRequest.GetBrowseMode() && fRequest.BypassAuth() ) { StrBuf errMsg; errMsg.Set( p4wMenuPane::GetMenuItem( fRequest.GetCmd(), fRequest.GetBrowseMode() ) ); errMsg << " not available with -a command line flag."; fileBrowserPane.RenderError( errMsg.Text(), 1 ); return; } // // First command is always fstat path.Set( fRequest.GetPath() ); if( srev ) { if (srev2 && ((fCommand == AC_CHGLISTANNOTATE) || (fCommand == AC_CHGLISTFULLANNOTATE))) path << "@" << srev2; else path << "@" << srev; } if( fRequest.GetViewMode() != VM_DEPOT ) fRequest.p4Arg( "-C" ); // // Server protocol 13 supports -P flag which gives // all 3 fstat mappings. if( protocol > 12 ) fRequest.p4Arg( "-P" ); if( fRequest.GetCmd() == AC_BROWSEFILE && protocol > 19 && !fRequest.HideThumbnails() ) { // this will get the head rev thumbnail if there is one // and enable use to know whether we need to run // p4 fstat -Oaef -A thumb (i.e. run again with -Of) // [we can't run -Of initially because resolve status will be lost] fRequest.p4Arg( "-Odae" ); fRequest.p4Arg( "-A" ); fRequest.p4Arg( "thumb" ); } if ( protocol > 18 ) fRequest.p4Arg( "-Ol" ); fRequest.p4Arg( path.Text() ); fRequest.p4( "fstat", 0, 0, &fileBrowserPane ); fRequest.p4Wait(); if( fileBrowserPane.FatalError() ) return; // // If requesting Revision History from workspace mode, // but the file is not in the depot, switch to File State // instead. if( fCommand == AC_BROWSEFILE && fRequest.GetViewMode() == VM_WORKSPACE && !fileBrowserPane.InDepot() ) fCommand = AC_FILESTATE; char *etlMsg = 0; if ( fCommand == AC_LAUNCHEDITOR && !fRequest.isLocalRequest() ) { fRequest.SetCmd(fCommand = AC_EDITTEXTLOCAL); etlMsg = "\"Open workspace file in editor\" is not available unless the browser and P4Web are hosted on the same machine;<br>running \"Edit workspace file in browser\" instead.<br>"; } switch( fCommand ) { case AC_FILETEXTDEPOT: { // // File text at head rev unless we have revision argument. Don't test if file // is writeable if requesting file at a revision because the fstat was not // issued for the revision: it was issued at the head. path.Set( fRequest.GetPath() ); if( rev1 ) { path << "#" << rev1; } else if( srev ) { path << "@" << srev; } if( !rev1 && !fileBrowserPane.IsWriteable() ) { if( !fileBrowserPane.HasHeadType() ) fileBrowserPane.RenderError( (char*)( SEC_DONT_SHOW_REVHIST ? " Use the links above to view this file" : " Operation not allowed on this file"), 0 ); else fileBrowserPane.RenderError( (char*)( SEC_DONT_SHOW_REVHIST ? " Use the links above to view this non-text file" : " Operation not allowed on non-text file"), 0 ); return; } p4wPrintPane printPane( *this, fRequest ); const char *printPaneArgs[] = { "-q", path.Text() }; fRequest.p4( "print", 2, printPaneArgs, &printPane ); fRequest.p4Wait(); } break; case AC_FILETEXTLOCAL: { if( !fileBrowserPane.IsWriteable() ) { fileBrowserPane.RenderError( (char*)( fileBrowserPane.HasHeadType() ? " Operation not allowed on non-text file" : " Operation not allowed on this file"), 0 ); return; } p4wReadLocalPane readLocalPane( *this, fRequest ); const char *readLocalPaneArgs[] = { fRequest.GetPath().Text() }; fRequest.p4( "fstat", 1, readLocalPaneArgs, &readLocalPane ); fRequest.p4Wait(); } break; case AC_EDITTEXTLOCAL: case AC_EDITTEXTLOCALPROCESSOR: { if( !fileBrowserPane.IsWriteable() ) { fileBrowserPane.RenderError( (char*)( fileBrowserPane.HasHeadType() ? " Operation not allowed on non-text file" : " Operation not allowed on this file"), 0 ); return; } if( !fileBrowserPane.IsEditable() ) { p4wHtml htm(1); p4wURL urlMaker; StrBuf url; StrBuf baseWPath; fRequest.UseNewBase( baseWPath, NULL, "path", fRequest.GetPath().Text() ); urlMaker.ConstructURL( url, baseWPath.Text(), AC_EDITFILEFRM, NULL, fRequest.GetUnicode() ); htm << "<div class=\"fNormal\"> You must "; htm.beginLink( url.Text() ); htm << "open the file for edit"; htm.endLink(); htm << " before you can edit the workspace file in your browser.</div>"; fileBrowserPane.RenderError( htm.Text(), 0 ); return; } p4wClientRootPane clientRootPane(*this, fRequest); const char *cliArgs[] = { "-o" }; fRequest.p4("client", 1, cliArgs, &clientRootPane); fRequest.p4Wait(); if (clientRootPane.GetIsLockedAway()) { fileBrowserPane.RenderError( " Locked client may only be used by its owner", 1 ); return; } if (clientRootPane.IsInvalidClient()) { fileBrowserPane.RenderError( clientRootPane.GetErrorMsg().Text(), 1 ); return; } if (!SEC_ALLOW_ALL_CLIENTS && !fRequest.isLocalRequest()) { if (strcmp(clientRootPane.GetOwner().Text(), fRequest.GetUser().Text())) { if (SEC_ALLOW_UNOWNED_CLIENTS && clientRootPane.GetOwner().Length() == 0) ; else { fileBrowserPane.RenderError( " Client may only be used by its owner", 1 ); return; } } if (!clientRootPane.GetHost().Length() && !SEC_ALLOW_NOHOST_CLIENTS) { fileBrowserPane.RenderError( " Clients without a Host may not be used", 1 ); return; } } p4wEditLocalPane editLocalPane( *this, fRequest ); if (etlMsg) editLocalPane.fMsg = etlMsg; const char *editLocalPaneArgs[] = { fRequest.GetPath().Text() }; fRequest.p4( "fstat", 1, editLocalPaneArgs, &editLocalPane ); fRequest.p4Wait(); } break; case AC_UPLOADTOLOCAL: case AC_UPLOADTOLOCALPROCESSOR: { if( !fileBrowserPane.IsEditable() ) { p4wHtml htm(1); p4wURL urlMaker; StrBuf url; StrBuf baseWPath; fRequest.UseNewBase( baseWPath, NULL, "path", fRequest.GetPath().Text() ); urlMaker.ConstructURL( url, baseWPath.Text(), AC_EDITFILEFRM, NULL, fRequest.GetUnicode() ); htm << "<div class=\"fNormal\"> You must "; htm.beginLink( url.Text() ); htm << "open the file for edit"; htm.endLink(); htm << " before you can upload to your workspace.</div>"; fileBrowserPane.RenderError( htm.Text(), 0 ); return; } p4wClientRootPane clientRootPane(*this, fRequest); const char *cliArgs[] = { "-o" }; fRequest.p4("client", 1, cliArgs, &clientRootPane); fRequest.p4Wait(); if (clientRootPane.GetIsLockedAway()) { fileBrowserPane.RenderError( "Locked client may only be used by its owner", 1 ); return; } if (!SEC_ALLOW_ALL_CLIENTS && !fRequest.isLocalRequest()) { if (strcmp(clientRootPane.GetOwner().Text(), fRequest.GetUser().Text())) { if (SEC_ALLOW_UNOWNED_CLIENTS && clientRootPane.GetOwner().Length() == 0) ; else { fileBrowserPane.RenderError( " Client may only be used by its owner", 1 ); return; } } if (!clientRootPane.GetHost().Length() && !SEC_ALLOW_NOHOST_CLIENTS) { fileBrowserPane.RenderError( " Clients without a Host may not be used", 1 ); return; } } p4wUploadLocalPane uploadLocalPane( *this, fRequest ); const char *uploadLocalPaneArgs[] = { fRequest.GetPath().Text() }; fRequest.p4( "fstat", 1, uploadLocalPaneArgs, &uploadLocalPane ); fRequest.p4Wait(); } break; case AC_RESOLVEIAPROCESSOR: { p4wResolveIAendPane resolveIAendPane( *this, fRequest, fRC ); const char *resolveIAendPaneArgs[] = { fRequest.GetPath().Text() }; fRequest.p4( "fstat", 1, resolveIAendPaneArgs, &resolveIAendPane ); fRequest.p4Wait(); } break; case AC_ANNOTATE: case AC_FULLANNOTATE: case AC_CHGLISTANNOTATE: case AC_CHGLISTFULLANNOTATE: { // // Annotate at head rev unless we have revision argument. path.Set( fRequest.GetPath() ); // // Check server protocol as this command is only // available for 2002.2+ servers if( protocol < 14 ) { fileBrowserPane.RenderError( "Command not supported by pre-2002.2 servers.", 1 ); return; } // Don't test if file // is writeable if requesting file at a revision // because the fstat was not issued for the revision: // it was issued at the head. if( !rev1 && !fileBrowserPane.IsWriteable() ) { fileBrowserPane.RenderError( (char*)( fileBrowserPane.HasHeadType() ? " Operation not allowed on non-text file" : " Operation not allowed on this file"), 0 ); return; } // // Issue filelog command and save results for Detailed Annotates p4wHtml htm( 1 ); StrBuf filelog; int chgWidth; int usrWidth; if( (fCommand == AC_CHGLISTANNOTATE) || (fCommand == AC_CHGLISTFULLANNOTATE) ) { p4wAnnFilelogPane annfilelogPane( *this, fRequest, &filelog, &chgWidth, &usrWidth, &htm); if( protocol >= 19 ) // 2005.1 or later? fRequest.p4Arg( "-L" ); const StrPtr *fl = fRequest.GetDynArg( "fl" ); if (fl) fRequest.p4Arg( fl->Text() ); StrBuf filelogPath; filelogPath << path; if ( rev2 ) filelogPath << "#" << rev2; else if( rev1 ) filelogPath << "#" << rev1; else if ( srev2 ) filelogPath << "@" << srev2; else if( srev ) filelogPath << "@" << srev; fRequest.p4Arg( filelogPath.Text() ); fRequest.p4( "filelog", 0, 0, &annfilelogPane ); fRequest.p4Wait(); } // // Handle revision or back-in-time browse revision // by appending rev to the path if( rev1 ) { path << "#" << rev1; if ( rev2 ) path << "," << rev2; } else if( srev ) { path << "@" << srev; if ( srev2 ) path << "," << srev2; } // // Issue the annotate command & send to the annotate pane p4wAnnotatePane printPane( *this, fRequest, fileBrowserPane.GetHeadRev(), fileBrowserPane.GetHeadChange() ); fRequest.p4Arg( "-q" ); if( fCommand == AC_FULLANNOTATE ) fRequest.p4Arg( "-a" ); else if( fCommand == AC_CHGLISTANNOTATE || fCommand == AC_CHGLISTFULLANNOTATE ) { printPane.SetFileLog(&filelog); printPane.SetChgWidth(chgWidth); printPane.SetUsrWidth(usrWidth); if ( fCommand == AC_CHGLISTFULLANNOTATE ) fRequest.p4Arg( "-a" ); fRequest.p4Arg( "-c" ); const StrPtr *fl = fRequest.GetDynArg( "fl" ); if (fl) fRequest.p4Arg( fl->Text() ); if ( srev && srev2 ) { char *p = strrchr(path.Text(), '@'); if (p) { *p = '\0'; path.SetLength(); path << "@" << srev << "," << srev2; } } } fRequest.p4Arg( path.Text() ); fRequest.p4( "annotate", 0, 0, &printPane ); fRequest.p4Wait(); if( (fCommand == AC_CHGLISTANNOTATE) || (fCommand == AC_CHGLISTFULLANNOTATE) ) fRequest << htm; } break; case AC_DIFFWVC: { StrBuf file1; StrBuf file2; file1 << fRequest.GetPath() << "#have"; file2 << fileBrowserPane.GetWorkspaceFile(); p4wDiffPane diffPane( *this, fRequest, &file1, &file2 ); // // The -dw & -db flags are only supported for 2002.2+ // servers. If this flag is set, we need to check the // server protocol. if( dwbFlag.Length() && protocol > 13 ) { 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() ); } fRequest.p4Arg( "-f" ); fRequest.p4Arg( file1.Text() ); fRequest.p4( "diff", 0, 0, &diffPane ); fRequest.p4Wait(); if (diffPane.GetState()) { diffPane.IncState(); const char *printArgs[] = { "-q", file1.Text() }; fRequest.p4( "print", 2, printArgs, &diffPane ); fRequest.p4Wait(); } } break; case AC_DIFFCVH: { StrBuf file1; StrBuf file2; file1 << fRequest.GetPath() << "#have"; if( srev ) file2 << fRequest.GetPath() << "@" << srev; else file2 << fRequest.GetPath() << "#head"; p4wDiffPane diffPane( *this, fRequest, &file1, &file2 ); // // The -dw & -db flags are only supported for 2002.2+ // servers. If this flag is set, we need to check the // server protocol. if( dwbFlag.Length() && protocol > 13 ) { 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() ); } fRequest.p4Arg( file1.Text() ); fRequest.p4Arg( file2.Text() ); fRequest.p4( "diff2", 0, 0, &diffPane ); fRequest.p4Wait(); if (diffPane.GetState()) { diffPane.IncState(); const char *printArgs[] = { "-q", file1.Text() }; fRequest.p4( "print", 2, printArgs, &diffPane ); fRequest.p4Wait(); } } break; case AC_DIFFWVH: case AC_DIFFRVW: { path.Set( fRequest.GetPath() ); if (fCommand == AC_DIFFRVW) { // // If rev1 is missing we have to bail if( !rev1 ) { fileBrowserPane.RenderError( "Requested URL is invalid in this context.", 1 ); return; } path << "#" << rev1; } else { if( srev ) path << "@" << srev; else path << "#head"; } path2 << fileBrowserPane.GetWorkspaceFile(); p4wDiffPane diffPane( *this, fRequest, &path, &path2 ); // // The -dw & -db flags are only supported for 2002.2+ // servers. If this flag is set, we need to check the // server protocol. if( dwbFlag.Length() && protocol > 13 ) { 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() ); } fRequest.p4Arg( "-f" ); fRequest.p4Arg( path.Text() ); fRequest.p4( "diff", 0, 0, &diffPane ); fRequest.p4Wait(); if (diffPane.GetState()) { diffPane.IncState(); const char *printArgs[] = { "-q", path.Text() }; fRequest.p4( "print", 2, printArgs, &diffPane ); fRequest.p4Wait(); } } break; case AC_DIFF2: case AC_DIFF21: case AC_DIFF22: { char *p = strrchr(path.Text(), '@'); if (p) { *p = '\0'; path.SetLength(); } if (fCommand == AC_DIFF2) { // // If either rev1 or rev2 are missing we have to bail if( !rev1 || !rev2 ) { fileBrowserPane.RenderError( " Requested URL is invalid in this context.", 0 ); return; } if( atoi(rev1->Text()) == atoi(rev2->Text()) ) { fileBrowserPane.RenderError( " You attempted to compare a file with itself. Before choosing the \"Diff vs. Selected Revision\" option, you must select one of the other revisions by clicking its radio button.", 0 ); return; } // // If rev1 starts with a minus, the format is // -[revnbr][path] // Example: // -4//depot/dir/filename.ext // this means run // p4 diff2 //depot/dir/filename.ext#4 fRequest.GetPath()#rev2 if (*(rev1->Text()) == '-') { p = rev1->Text(); while (*++p && isdigit(*p)) ; path.Clear(); path << p ; p = rev1->Text(); if (isdigit(*++p)) path << "#"; while (*p && isdigit(*p)) path.Append(p++, 1); } else path << "#" << rev1; // // Similiarly for rev 2: minus means -[revnbr][path] if (*(rev2->Text()) == '-') { p = rev2->Text(); while (*++p && isdigit(*p)) ; path2 << p; p = rev2->Text(); if (isdigit(*++p)) path2 << "#"; while (*p && isdigit(*p)) path2.Append(p++, 1); } else path2 << fRequest.GetPath() << "#" << rev2; } else if (fCommand == AC_DIFF21) { if( !rev1 ) { fileBrowserPane.RenderError( " Requested URL is invalid in this context.", 0 ); return; } StrBuf temp; temp << atoi(rev1->Text()) - 1; path << "#" << temp; path2 << fRequest.GetPath() << "#" << rev1; } else // fCommand == AC_DIFF22 { const StrPtr *fil1 = fRequest.GetDynArg( "fil1" ); const StrPtr *fil2 = fRequest.GetDynArg( "fil2" ); 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. if( dwbFlag.Length() && protocol > 13 ) { 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 p4wDiffPane diffPane( *this, fRequest, &path, &path2 ); fRequest.p4Arg( path.Text() ); fRequest.p4Arg( path2.Text() ); fRequest.p4( "diff2", 0, 0, &diffPane ); fRequest.p4Wait(); if (diffPane.GetState()) { diffPane.IncState(); const char *printArgs[] = { "-q", path.Text() }; fRequest.p4( "print", 2, printArgs, &diffPane ); fRequest.p4Wait(); } } break; case AC_DIFF2FILES: { p4wDiff2FilesPane diff2PaneFiles( *this, fRequest ); diff2PaneFiles.Begin(); diff2PaneFiles.RenderContent(); diff2PaneFiles.End(); } break; case AC_BROWSEFILE: { if (fRequest.GetHasThumbs()) // TRUE -> protocol > 19 && !fRequest.HideThumbnails() { path.Set( fRequest.GetPath() ); fRequest.p4Arg( "-Oaef" ); fRequest.p4Arg( "-A" ); fRequest.p4Arg( "thumb" ); fRequest.p4Arg( path.Text() ); fRequest.p4( "fstat", 0, 0, &fileBrowserPane ); fRequest.p4Wait(); } path.Set( fRequest.GetPath() ); if( rev1 ) { path << "#" << rev1; } else if( srev ) { path << "@" << srev; } if( mx ) { fRequest.p4Arg( "-m" ); fRequest.p4Arg( mx->Text() ); } if (SEC_DISALLOW_REVHIST_INTEG && !fRequest.isLocalRequest()) { fRequest.p4Arg( "-l" ); fRequest.p4Arg( path.Text() ); } else if( fl && *fl == "-h" && protocol >= 24 ) { // 2007.3 or later? fRequest.p4Arg( "-l" ); fRequest.p4Arg( "-h" ); fRequest.p4Arg( path.Text() ); } else if( fl && (*fl == "-i" || *fl == "-h") ) { fRequest.p4Arg( "-l" ); fRequest.p4Arg( "-i" ); fRequest.p4Arg( path.Text() ); } else { fRequest.p4Arg( "-l" ); fRequest.p4Arg( path.Text() ); } p4wFilelogPane filelogPane( *this, fRequest ); fRequest.p4( "filelog", 0, 0, &filelogPane ); fRequest.p4Wait(); } break; case AC_LAUNCHEDITOR: { DoLaunchEditor( path ); } break; case AC_SYNCCMD: case AC_SYNCREV: case AC_SYNCFILE: case AC_SYNCPROCESSOR: case AC_SYNCFILEFRM: case AC_EDITFILE: case AC_EDITFILEFRM: case AC_EDITPROCESSOR: case AC_ADDFILE: case AC_ADDFILEFRM: case AC_ADDPROCESSOR: case AC_DELETEFILE: case AC_DELETEFILEFRM: case AC_DELETEPROCESSOR: case AC_FILETYPEFILEFRM: case AC_FTYPEPROCESSOR: case AC_REMOVEFILEFRM: case AC_INTEGRATEFILEFRM: case AC_INTEGPROCESSOR: case AC_RESOLVEFILEFRM: case AC_RESOLVEPROCESSOR: case AC_LOCKFILEFRM: case AC_UNLOCKFILEFRM: case AC_REVERTUNCHANGEDFILEFRM: case AC_REVERTFILEFRM: case AC_REVERTCMD: case AC_REVERTFILE: case AC_SUBMITFILEFRM: { fRequest << fRequest.fLater; fRequest.fLater.Clear(); } break; case AC_FILESTATE: break; default: { path.Set( fRequest.GetPath() ); if( srev ) path << "@" << srev; const char *filelogPaneArgs[] = { "-l", path.Text() }; p4wFilelogPane filelogPane( *this, fRequest ); fRequest.p4( "filelog", 2, filelogPaneArgs, &filelogPane ); fRequest.p4Wait(); } break; } } void p4wFileBrowserView::RenderMenu() { // // Draw the menu bar p4wMenuPane menuPane( *this, fRequest, "filebrowser" ); menuPane.Render( NULL ); } const char * p4wFileBrowserView::GetDefaultEditor( Enviro & enviro ) { // // Returns the default editor. If P4EDITOR is not set, // return a default editor based on OS. const char *editor; // // If this process is an NT service, try to get the P4EDITOR // from the services area of the registry #ifdef OS_NT if( fRequest.IsNTService() ) { enviro.BeServer( fRequest.GetSvcName() ); } #endif if( !( editor = enviro.Get( "P4EDITOR" ) ) ) editor = getenv( "EDITOR" ); # ifdef OS_NT if( !editor && !getenv( "SHELL" ) ) editor = "notepad"; # endif # ifdef OS_VMS if( !editor && !getenv( "POSIX$SHELL" ) ) editor = "edit"; # endif # ifdef OS_AS400 if( !editor ) editor = "edtf"; # endif // Bill Joy rules, Emacs maggots! if( !editor ) { // // Insure that using the default editor on Unix // systems (vi) always works. Therefore we will // launch an xterm window for it if the environment // variable DISPLAY is set. if( getenv( "DISPLAY" ) ) editor = "xterm -e vi"; else editor = "vi"; } return editor; } void p4wFileBrowserView::DoLaunchEditor( StrBuf &path ) { // // Run the default editor to edit the specified file // only if it makes sense. FstatHelper helper( path, fRequest.GetClientApi() ); Enviro enviro; StrBuf errMsg; CharSetCvt *cvt; char *cvtPath = NULL; enviro.Config( fRequest.GetCwd() ); // // Fstat does not have file type info for files // opened for add. If the file type is unknown, // give the user the benefit of a doubt and invoke // the editor. Otherwise, bail if the file is not // a text file. if ( !helper.IsTextFile() && !helper.FileTypeUnknown() ) { errMsg << "File: " << path << " is not a text file."; fRequest << " "; RenderError( errMsg.Text() ); return; } // // The browser and p4web need to run on the same // machine to launch the editor on mac and NT. # if defined( OS_MACOSX ) || defined( OS_NT ) if ( !fRequest.isLocalRequest() ) { fRequest << " "; RenderError( "Currently, this feature will not work unless the browser and P4Web are hosted on the same machine." ); return; } # endif Error e; StrPtr * localPath = helper.GetLocalPath(); // // The file must be mapped on the client workspace or // exist on disk if ( !localPath && fRequest.GetViewMode() != VM_WORKSPACE ) { errMsg << "File: " << path; errMsg << " could not be found on your client workspace."; fRequest << " "; RenderError( errMsg.Text() ); return; } if( !localPath ) localPath = (StrPtr *)&fRequest.GetPath(); // // If we are in unicode mode, the filename must be converted from // UTF-8 to the P4CHARSET-specified file type int dp = 0; if( fRequest.GetUnicode() ) { cvt = CharSetCvt::FindCvt( CharSetCvt::UTF_8, CharSetCvt::Lookup( fRequest.GetClientApi().GetCharset().Text() ) ); cvtPath = p4wI18n::convertText( cvt, localPath->Text() ); if( !cvtPath ) { cvtPath = localPath->Text(); } else { ++dp; } delete cvt; } else { cvtPath = localPath->Text(); } // // We've met all the criteria, now launch the editor // // Construct the edit command, // parse out the process name, and put the // process arguments into an argument vector. RunArgs cmd; cmd << GetDefaultEditor( enviro ); cmd.AddArg( cvtPath ); if( dp ) delete [] cvtPath; RunCommand().RunInWindow( cmd, &e ); // // If the file is open for edit,yet does not exist on disk, // put up a warning message. StrPtr * action = helper.GetAction(); if (action && *action != "edit") return; FileSys * fsys = helper.GetLocalFile(); if (!fsys->Stat() & FSF_EXISTS) { fRequest << " "; RenderError( "Warning: This file does not exist on the local system where P4Web is running." ); } }
# | 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/p4wFileBrowserView.cpp | |||||
#1 | 8914 | Matt Attaway | Initial add of the P4Web source code |