// // Copyright 1999 Perforce Software. All rights reserved. // // This file is part of Perforce - the FAST SCM System. // // p4wChangePendingEditPane: // Displays a form to edit a pending changelist #include <p4wp4.h> #include "p4wStrBuf.h" #include "p4wHtml.h" #include "p4wJs.h" #include "p4wRunPane.h" #include "p4wChangePendingEditPane.h" p4wChangePendingEditPane::p4wChangePendingEditPane( p4wView & ParentView, p4wRequest & Request, int submit, int displayButton, int unchecked ) : p4wRunPane( ParentView, Request, unchecked ), isSubmit(submit), fRedisplayButton(displayButton), fIsFirstChange(1), fIsFirstFile(1), fState(gettingChange), fReadOnly(0), fCurCli(0) { // // Set unchecked flag if unchecked variable was set in // url. This is used to determine if checkboxes in Files // section are checked. If this contradicts the value // chosen from the form, the url wins. const StrPtr *uch = fRequest.GetDynArg( "uch" ); const StrPtr *bp = fRequest.GetDynArg( "bp" ); fUnchecked = 0; fByPath = 0; if( uch && *uch == "1" ) fUnchecked = 1; if( bp && *bp == "1" ) fByPath = 1; } p4wChangePendingEditPane::~p4wChangePendingEditPane() { } // ------------------------------------- // Overrides for spec panes. // void p4wChangePendingEditPane::Begin() { // // Only the first state (getting the change description) is // processed here. if( fState != gettingChange ) return; // // Begin the pane by calling the superclass. p4wSpecPane::Begin(); } void p4wChangePendingEditPane::Render( StrDict * varList ) { // // Process this data appropriately based on state StrPtr *noCase = fRequest.GetProtocol( "nocase" ); p4wHtml htm(1); if( fState == gettingChange ) { // // Call base class to process data from change. Check the owner // field: if this owner doesn't match the user who started p4web, // this will be a read-only form. StrPtr *owner = varList->GetVar("User"); if( !isSubmit && ( ( noCase && owner->CCompare( fRequest.GetUser() ) ) || ( !noCase && owner->XCompare( fRequest.GetUser() ) ) ) ) fReadOnly = 1; p4wSpecPane::Render(varList); } else if( fState == gettingFiles) { // // List of files from opened command. If this is not a read-only // form, skip files not owned by the current owner. StrPtr *owner = varList->GetVar("user"); if( !fReadOnly && ( ( noCase && owner->CCompare( fRequest.GetUser() ) ) || ( !noCase && owner->XCompare( fRequest.GetUser() ) ) ) ) return; // // If page content limit in bytes has been exceeded, don't // generate this entry if( PageLimitExceeded() ) return; if( fIsFirstFile ) { StrBuf tag; tag << "Files:"; htm.beginTRow(); htm.beginCol( "top" ); htm.text( tag.Text(), "b" ); htm.endCol(); if( !fReadOnly ) htm.checkboxselectall("spec", NULL, !fUnchecked); htm.beginCol( NULL, NULL, "3" ); fIsFirstFile = 0; } // // Output what we've generated so far fRequest << htm; htm.Clear(); // // Fetch some information about this file. StrPtr *action = varList->GetVar("action"); StrPtr *rev2 = varList->GetVar("rev"); StrPtr *depotFile = varList->GetVar("depotFile"); StrPtr *type = varList->GetVar("type"); // // Generate the url in depot syntax. // The value passed back must be depot mode for submit. // If we are in workspace mode, we need to mess with the // base to change to depot mode. StrBuf newBase; StrBuf url, url2; StrBuf clearIcon; p4wURL urlMaker; urlMaker.ConstructURL( clearIcon, "/clearpixelIcon", AC_ICON, NULL ); if( fRequest.GetViewMode() != VM_WORKSPACE ) { fRequest.ConstructSafeURL( url, depotFile->Text() + 2, AC_BROWSEFILE, NULL ); } else { fRequest.UseNewBase( newBase, NULL, "md", "d" ); fRequest.UseNewBase( newBase, newBase.Text(), "cd", "//" ); fRequest.UseNewBase( newBase, newBase.Text(), "wr", NULL ); fRequest.UseNewBase( newBase, newBase.Text(), "path", depotFile->Text() ); urlMaker.ConstructURL( url, newBase.Text(), AC_BROWSEFILE, NULL, fRequest.GetUnicode() ); } int isWriteable; if( type && ( strstr(type->Text(), "text") || strstr(type->Text(), "symlink") || strstr(type->Text(), "unicode") || strstr(type->Text(), "utf16") ) ) { isWriteable = 1; } else { isWriteable = 0; } int doDiff = 0; int doText = ( fCurCli && isWriteable && ( strcmp( action->Text(), "delete" ) ) ); if (fCurCli) { int revNo = atoi( rev2->Text() ); if( ( revNo ) && ( ( !strcmp( action->Text(), "edit" ) ) || ( !strcmp( action->Text(), "integrate" ) ) ) ) doDiff = 1; } if( doText ) { StrBuf textIcon; if ( !fRequest.isLocalRequest() ) { if( fRequest.GetViewMode() == VM_WORKSPACE ) { urlMaker.ConstructURL( url2, newBase.Text(), AC_EDITTEXTLOCAL, NULL, fRequest.GetUnicode() ); } else { fRequest.ConstructSafeURL( url2, depotFile->Text() + 2, AC_EDITTEXTLOCAL, NULL ); } urlMaker.ConstructIcon( textIcon, "/launcheditsmallIcon", 18, 25, "Edit workspace file in browser", 1 ); } else { if( fRequest.GetViewMode() == VM_WORKSPACE ) { urlMaker.ConstructURL( url2, newBase.Text(), AC_LAUNCHEDITOR, NULL, fRequest.GetUnicode() ); } else { fRequest.ConstructSafeURL( url2, depotFile->Text() + 2, AC_LAUNCHEDITOR, NULL ); } urlMaker.ConstructIcon( textIcon, "/launcheditsmallIcon", 18, 25, "Open workspace file in editor", 1 ); } htm.beginLink( url2.Text(), NULL, NULL, NULL, "View file text" ); htm << textIcon; htm.endLink(); } else if (fCurCli) htm.icon( clearIcon.Text(), "18", "25", "", 1 ); if (doDiff) { StrBuf diffIcon; if( fRequest.GetViewMode() == VM_WORKSPACE ) { urlMaker.ConstructURL( url2, newBase.Text(), AC_DIFFWVC, NULL, fRequest.GetUnicode() ); } else { urlMaker.ConstructURL( url2, depotFile->Text() + 2, AC_DIFFWVC, NULL, fRequest.GetUnicode() ); } urlMaker.ConstructIcon( diffIcon, "/rundiffsmallIcon", 18, 25, "Diff synced vs. workspace", 1 ); htm.beginLink( url2.Text() ); htm << diffIcon; htm.endLink(); } else if (fCurCli) htm.icon( clearIcon.Text(), "18", "25", "", 1 ); // // Output this file with a checkbox (unless it's a // read-only form) htm.beginLink( url.Text() ); htm.text( p4wStrBuf().EscapeHTML( *depotFile, Unicode() ).Text() ); htm.endLink(); htm << "#" << rev2 << " " << type << " " << action; if( !fReadOnly ) { DoCheckbox( 0, !fUnchecked, "Files", p4wStrBuf().EscapeHTML( *depotFile, Unicode() ).Text(), htm.Text() ); } else { fRequest << htm; } htm.Clear(); htm.linebreak(); fRequest << htm; } else if( !fPrintedError ) { // // List of changes. If list of files is empty, generate a Delete // changelist button only: otherwise output the changes in a // dropdown box for use with the Move button. // // If changelist is empty, only available option was to generate // Delete button. Since we already have done this, just return. if( fIsFirstFile ) return; // // Read only form doesn't have any buttons if( fReadOnly ) return; // // Generate the Move button with a dropdown list of // changelists StrPtr *owner = varList->GetVar("user"); const char * client = varList->GetVar("client")->Text(); StrPtr *changeNo = varList->GetVar("change"); const StrPtr *desc = varList->GetVar("desc"); const StrPtr *cmdArg = fRequest.GetCmdArg(); // // Ignore changes that are not on this user/client. int notOwner = 0; if( ( noCase && owner->CCompare( fRequest.GetUser() ) ) || ( !noCase && owner->XCompare( fRequest.GetUser() ) ) ) notOwner = 1; if( notOwner || strcmp(client, fRequest.GetClient().Text())) { return; } // // Output changelists in a dropdown menu StrBuf buf; if( !cmdArg ) { if( fIsFirstChange ) { htm.beginTRow(); htm.beginCol(); htm.endCol(); htm.beginCol( "top", NULL, "2" ); fRequest << htm; DoButton( "reopen", "Move to Changelist" ); BeginSelect( "changelistVal" ); fIsFirstChange = 0; } buf << changeNo->Text() << " - " << desc->Text(); DoOption( buf.Text() ); } else if( *changeNo != *cmdArg ) { buf << changeNo->Text() << " - " << desc->Text(); DoOption( buf.Text() ); } } } int p4wChangePendingEditPane::IgnoreField( const char * field ) { // // See if this is one of our fields to skip. if( strcmp( field, "Files" ) == 0 ) { return 1; } else { return 0; } } int p4wChangePendingEditPane::CustomField( const char * field, StrDict * varList, int maxLen, SpecElem *se ) { // // If this is read-only, text boxes are replaced with read-only text p4wHtml htm; StrBuf tag; tag << field << ":"; if( !strcmp( field, "Client" ) ) { StrPtr *client = varList->GetVar( StrRef( field ) ); fCurCli = !strcmp(client->Text(), fRequest.GetClient().Text()); if (!fCurCli) fReadOnly = 1; } if( fReadOnly ) { if( !strcmp( field, "Description" ) || !strcmp( field, "JobStatus" ) || !strcmp( field, "Jobs" ) ) { StrBuf val; if( !varList->GetVar( StrRef( field ) ) ) return 1; val.Set( varList->GetVar( StrRef( field ) ) ); if( !fIsOpen ) htm.beginTRow(); FormatFields( htm, tag.Text(), "top" ); htm.text( p4wStrBuf().EscapeHTML( StrRef(val), Unicode() ).Text() ); htm.endCol(); if( !fLeaveOpen ) htm.endTRow(); fRequest << htm; return 1; } } else { if( !strcmp( field, "Description" ) ) { StrPtr *value = varList->GetVar( StrRef( field ) ); if( !fIsOpen ) htm.beginTRow(); FormatFields( htm, tag.Text(), "top", NULL, "3" ); htm.beginTextbox( field, 6, fTextALen ); if( value ) htm.text( p4wStrBuf().EscapeHTML( *value, Unicode() ).Text() ); htm.endTextbox(); htm.endCol(); if( !fLeaveOpen ) htm.endTRow(); fRequest << htm; return 1; } else if( !strcmp( field, "Jobs" ) ) { const StrPtr * p; if( !fIsOpen ) htm.beginTRow(); FormatFields( htm, tag.Text(), "top", NULL, "3" ); htm.beginTextbox( field, 6, fTextALen ); const StrPtr *jb = fRequest.GetDynArg( "jb" ); if (jb && jb->Length()) htm.text( p4wStrBuf().EscapeHTML( *jb, Unicode() ).Text() ); if ( !jb || fRequest.GetDynArg( "arg" ) ) { for( int d = 0; ( p = varList->GetVar( StrRef ( field ), d ) ) != NULL; d++ ) { htm.text( p4wStrBuf().EscapeHTML( *p, Unicode() ).Text() ); } } htm.endTextbox(); htm.endCol(); if( !fLeaveOpen ) htm.endTRow(); fRequest << htm; return 1; } else if( !strcmp( field, "JobStatus" ) ) { StrPtr * val = varList->GetVar( se->tag.Text() ); FormatFields( htm, tag.Text() ); htm.beginSelect( field ); char *selectVal = strtok( se->values.Text(), "/" ); while( selectVal != NULL ) { if( ( val != NULL ) && ( strcmp( val->Text(), selectVal ) == 0 ) ) htm.selectOpt( 1 ); else htm.selectOpt( 0 ); htm.text( selectVal ); selectVal = strtok( NULL, "/" ); } htm.endSelect(); // // Finish up the Jobs by possibly adding the Add Job Fix button p4wURL urlMaker; StrBuf clearIcon; urlMaker.ConstructURL( clearIcon, "/clearpixelIcon", AC_ICON, NULL ); const StrPtr *jb = fRequest.GetDynArg( "jb" ); if (!jb) { htm.icon( clearIcon.Text(), "10", "60", "", 1 ); htm.button( "addjobfix", "Add Jobs" ); } // // Output a javascript method to allow users to clear // all the jobs in the Jobs field htm.icon( clearIcon.Text(), "10", "60", "", 1 ); htm << crlf; fRequest << htm; htm.Clear(); p4wJs js; js.beginJs( "1.2" ); js.clearField("Jobs", "Remove All Jobs"); js.endJs(); fRequest << js; if( !fLeaveOpen ) htm.endTRow(); fRequest << htm; return 1; } } return 0; } void p4wChangePendingEditPane::End() { // // Handle state transitions p4wHtml htm; if( FatalError() ) { htm.endTable(); htm.endCol(); htm.endTRow(); htm.endTable(); htm.endCol(); htm.endTRow(); htm.endForm(); htm.comment( "END CHANGEPENDINGEDIT PANE" ); fRequest << htm; return; } if( fState == gettingChange ) { // // Transition to displaying Files from opened fState = gettingFiles; return; } else if( fState == gettingFiles ) { // // End the row of Files & draw buttons ONLY if no error occurred if( !fPrintedError && !fReadOnly ) { if( !fIsFirstFile ) { htm.endCol(); htm.endTRow(); fRequest << htm; htm.Clear(); } DrawSubmitButton(); // // If there are no files, draw a Delete button. Otherwise, generate // a move changelist button with a dropdown of available changelists. const StrPtr *cmdArg = fRequest.GetCmdArg(); if( fIsFirstFile && cmdArg ) { htm.beginTRow(); htm.beginCol(); htm.endCol(); htm.beginCol( "top" ); fRequest << htm; htm.Clear(); DoButton( "delete", "Delete Changelist" ); DoHidden( 0, "changelistVal", cmdArg->Text() ); htm.endCol(); htm.endTRow(); fRequest << htm; } else if( cmdArg ) { htm.beginTRow(); htm.beginCol(); htm.endCol(); htm.beginCol( "top", NULL, "2" ); fRequest << htm; DoButton( "reopen", "Move to Changelist" ); BeginSelect( "changelistVal" ); DoOption( "default" ); fIsFirstChange = 0; } } fState = gettingChanges; } else { // // End the row of buttons if( !fPrintedError ) { if( !fIsFirstChange ) { EndSelect(); } // // Revert is the last button. Draw it if there are // files to revert. if( !fReadOnly && !fIsFirstFile ) { htm.beginTRow(); htm.beginCol(); htm.endCol(); htm.beginCol( "top", NULL, "2" ); fRequest << htm; htm.Clear(); DoButton( "revert", "Revert" ); DoHidden( 0, "formActions", "revert" ); htm.radio( "revertOpt", "unchanged", 1 ); htm.label( "only if unchanged", "unchanged" ); htm.radio( "revertOpt", "selected", 0 ); htm.label( "ALL selected files", "selected" ); htm.endCol(); htm.endTRow(); } } // // End the pane. htm.endTable(); htm.endCol(); htm.endTRow(); htm.endTable(); htm.endCol(); htm.endTRow(); htm.endForm(); htm.comment( "END CHANGEPENDINGEDIT PANE" ); fRequest << htm; } } void p4wChangePendingEditPane::DrawSubmitButton() { // // Submit buttons // // Check if submit -r is supported by this server int leaveOpen = 0; int handleUnchg = 0; const StrPtr *server = fRequest.GetProtocol( "server2" ); if( server && server->Atoi() > 12 ) { ++leaveOpen; if( server->Atoi() >= 21 ) // 2006.1 or later? handleUnchg = server->Atoi(); } p4wHtml htm; p4wURL urlMaker; StrBuf clearIcon; // // Output the Redisplay button just below the last file if( !fReadOnly && fRedisplayButton ) { htm.beginCol(); htm.endCol(); htm.beginCol( NULL, NULL, "3" ); htm << "<script language=javascript>" << crlf; htm << "document.write(\"<Input type=hidden name='checked' value='1'>\")" << crlf; htm << "document.write(\"<Input type=hidden name='unchecked' value='0'>\")" << crlf; htm << "</script>" << crlf; htm << "<noscript>" << crlf; htm.radio( "CheckOption", "checked", !fUnchecked, 0, "CheckOptionchecked" ); htm.label( "check all ", "CheckOptionchecked" ); htm.radio( "CheckOption", "unchecked", fUnchecked, 0, "CheckOptionunchecked" ); htm.label( "uncheck all ", "CheckOptionunchecked" ); htm << "</noscript>" << crlf; htm.radio( "ByPath", "unchecked", !fByPath, 0, "ByPathunchecked" ); htm.label( "show all files ", "ByPathunchecked" ); htm.radio( "ByPath", "checked", fByPath, 0, "ByPathchecked" ); htm.label( "show files in current path ", "ByPathchecked" ); fRequest << htm; htm.Clear(); DoButton( "redisplay", "Redisplay" ); htm.endCol(); htm.endTRow(); htm.beginTRow(); htm.beginCol( "top" ); htm.endCol(); } // // Some vertical whitespace urlMaker.ConstructURL( clearIcon, "/clearpixelIcon", AC_ICON, NULL ); htm.beginTRow(); htm.beginCol( NULL, NULL, NULL, NULL, NULL, "10" ); htm.icon( clearIcon.Text(), "10", "10", "", 1 ); htm.endCol(); htm.endTRow(); // // Don't display Submit button if there are no files to submit if( !fIsFirstFile ) { htm.beginTRow(); htm.beginCol(); htm.endCol(); htm.beginCol( "top", NULL, "2" ); fRequest << htm; htm.Clear(); DoButton( "submit", "Submit" ); if (handleUnchg < 22) { // is the server pre 2006.2? // // Submit -r option (server level > 12 only) if( leaveOpen ) { htm.checkbox( "openOpt", "y" ); htm.label( "leave files open", "openOpt" ); } // // Submit -R option (server level == 21 only) if( handleUnchg ) { htm.text( " - " ); htm.radio( "unchgOption", "submit", !fUnchecked, 0, "unchgOptionsubmit" ); htm.label( "Submit ", "unchgOptionsubmit" ); htm.radio( "unchgOption", "revert", fUnchecked, 0, "unchgOptionrevert" ); htm.label( "Revert", "unchgOptionrevert" ); htm.text( " unchanged files" ); } } else { // Note: p4wCmdView::SetPendingChgOpts() uses the following words // to parse which selection was chosen: // "client", "Submit ", "Revert ", "Leave ", and "reopen" htm.text( " <b>On Submit:</b>" ); htm.beginSelect( "submitOptions" ); htm.selectOpt( 1 ); htm.text( "Use client spec SubmitOptions value" ); htm.selectOpt( 0 ); htm.text( "Submit all selected files" ); htm.selectOpt( 0 ); htm.text( "Submit all selected files and reopen after submit" ); htm.selectOpt( 0 ); htm.text( "Revert unchanged files" ); htm.selectOpt( 0 ); htm.text( "Revert unchanged files and reopen submitted files" ); htm.selectOpt( 0 ); htm.text( "Leave unchanged files in default changelist" ); htm.selectOpt( 0 ); htm.text( "Leave unchanged files in default changelist and reopen submitted files" ); htm.endSelect(); } htm.endCol(); htm.endTRow(); } // // Create changelist button htm.beginTRow(); htm.beginCol(); fRequest << htm; htm.Clear(); // // Slip in those hiddent fields DoHidden( 0, "formActions", "change" ); DoHidden( 0, "formActions", "submit" ); DoHidden( 0, "formActions", "delete" ); DoHidden( 0, "formActions", "reopen" ); DoHidden( 0, "formActions", "redisplay" ); DoHidden( 0, "formActions", "addjobfix" ); htm.endCol(); htm.beginCol( "top" ); fRequest << htm; htm.Clear(); if( !fRequest.GetCmdArg() ) { DoButton( "change", "Create Changelist" ); } else { DoButton( "change", "Update Changelist" ); } htm.endCol(); htm.endTRow(); fRequest << htm; } // ------------------------------------- // Overrides for spec edit panes. // void p4wChangePendingEditPane::GetAction( StrBuf & actionURL ) { // // Constructs url used for the form ACTION value ConstructAction( AC_CHANGEORSUBMITCMD, NULL, 0, actionURL ); } void p4wChangePendingEditPane::RenderError( char *data, int escapeHTML ) { RenderErrorTbl( data, escapeHTML ); }
# | 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/Panes/p4wChangePendingEditPane.cpp | |||||
#1 | 8914 | Matt Attaway | Initial add of the P4Web source code |