aboutsummaryrefslogtreecommitdiff
path: root/mp/src/vgui2/vgui_controls/perforcefilelistframe.cpp
diff options
context:
space:
mode:
authorJoe Ludwig <[email protected]>2013-06-26 15:22:04 -0700
committerJoe Ludwig <[email protected]>2013-06-26 15:22:04 -0700
commit39ed87570bdb2f86969d4be821c94b722dc71179 (patch)
treeabc53757f75f40c80278e87650ea92808274aa59 /mp/src/vgui2/vgui_controls/perforcefilelistframe.cpp
downloadsource-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.tar.xz
source-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.zip
First version of the SOurce SDK 2013
Diffstat (limited to 'mp/src/vgui2/vgui_controls/perforcefilelistframe.cpp')
-rw-r--r--mp/src/vgui2/vgui_controls/perforcefilelistframe.cpp623
1 files changed, 623 insertions, 0 deletions
diff --git a/mp/src/vgui2/vgui_controls/perforcefilelistframe.cpp b/mp/src/vgui2/vgui_controls/perforcefilelistframe.cpp
new file mode 100644
index 00000000..1ba29d16
--- /dev/null
+++ b/mp/src/vgui2/vgui_controls/perforcefilelistframe.cpp
@@ -0,0 +1,623 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// List of perforce files and operations
+//
+//=============================================================================
+
+#include "vgui_controls/perforcefilelistframe.h"
+#include "tier1/KeyValues.h"
+#include "vgui_controls/Button.h"
+#include "vgui_controls/ListPanel.h"
+#include "vgui_controls/Splitter.h"
+#include "vgui_controls/TextEntry.h"
+#include "vgui_controls/MessageBox.h"
+#include "tier2/tier2.h"
+#include "p4lib/ip4.h"
+#include "filesystem.h"
+#include "vgui/IVGui.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+
+//-----------------------------------------------------------------------------
+// Sort by asset name
+//-----------------------------------------------------------------------------
+static int __cdecl OperationSortFunc( vgui::ListPanel *pPanel, const vgui::ListPanelItem &item1, const vgui::ListPanelItem &item2 )
+{
+ const char *string1 = item1.kv->GetString("operation");
+ const char *string2 = item2.kv->GetString("operation");
+ int nRetVal = Q_stricmp( string1, string2 );
+ if ( nRetVal != 0 )
+ return nRetVal;
+
+ string1 = item1.kv->GetString("filename");
+ string2 = item2.kv->GetString("filename");
+ return Q_stricmp( string1, string2 );
+}
+
+static int __cdecl FileBrowserSortFunc( vgui::ListPanel *pPanel, const vgui::ListPanelItem &item1, const vgui::ListPanelItem &item2 )
+{
+ const char *string1 = item1.kv->GetString("filename");
+ const char *string2 = item2.kv->GetString("filename");
+ return Q_stricmp( string1, string2 );
+}
+
+
+//-----------------------------------------------------------------------------
+// Constructor
+//-----------------------------------------------------------------------------
+COperationFileListFrame::COperationFileListFrame( vgui::Panel *pParent, const char *pTitle, const char *pColumnHeader, bool bShowDescription, bool bShowOkOnly, int nDialogID ) :
+ BaseClass( pParent, "PerforceFileList" )
+{
+ m_pText = NULL;
+ vgui::Panel *pBrowserParent = this;
+
+ m_pDescription = NULL;
+ m_pSplitter = NULL;
+ if ( bShowDescription )
+ {
+ m_pSplitter = new vgui::Splitter( this, "Splitter", vgui::SPLITTER_MODE_HORIZONTAL, 1 );
+
+ pBrowserParent = m_pSplitter->GetChild( 0 );
+ vgui::Panel *pDescParent = m_pSplitter->GetChild( 1 );
+
+ m_pDescription = new vgui::TextEntry( pDescParent, "Description" );
+ m_pDescription->SetMultiline( true );
+ m_pDescription->SetCatchEnterKey( true );
+ m_pDescription->SetText( "<enter description here>" );
+ }
+
+ // FIXME: Might be nice to have checkboxes per row
+ m_pFileBrowser = new vgui::ListPanel( pBrowserParent, "Browser" );
+ m_pFileBrowser->AddColumnHeader( 0, "operation", "Operation", 52, 0 );
+ m_pFileBrowser->AddColumnHeader( 1, "filename", pColumnHeader, 128, vgui::ListPanel::COLUMN_RESIZEWITHWINDOW );
+ m_pFileBrowser->SetSelectIndividualCells( false );
+ m_pFileBrowser->SetMultiselectEnabled( false );
+ m_pFileBrowser->SetEmptyListText( "No Perforce Operations" );
+ m_pFileBrowser->SetDragEnabled( true );
+ m_pFileBrowser->AddActionSignalTarget( this );
+ m_pFileBrowser->SetSortFunc( 0, OperationSortFunc );
+ m_pFileBrowser->SetSortFunc( 1, FileBrowserSortFunc );
+ m_pFileBrowser->SetSortColumn( 0 );
+
+ m_pYesButton = new vgui::Button( this, "YesButton", "Yes", this, "Yes" );
+ m_pNoButton = new vgui::Button( this, "NoButton", "No", this, "No" );
+
+ SetBlockDragChaining( true );
+ SetDeleteSelfOnClose( true );
+
+ if ( bShowDescription )
+ {
+ LoadControlSettingsAndUserConfig( "resource/perforcefilelistdescription.res", nDialogID );
+ }
+ else
+ {
+ LoadControlSettingsAndUserConfig( "resource/perforcefilelist.res", nDialogID );
+ }
+
+ if ( bShowOkOnly )
+ {
+ m_pYesButton->SetText( "#MessageBox_OK" );
+ m_pNoButton->SetVisible( false );
+ }
+
+ m_pContextKeyValues = NULL;
+
+ SetTitle( pTitle, false );
+}
+
+COperationFileListFrame::~COperationFileListFrame()
+{
+ SaveUserConfig();
+ CleanUpMessage();
+ if ( m_pText )
+ {
+ delete[] m_pText;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Deletes the message
+//-----------------------------------------------------------------------------
+void COperationFileListFrame::CleanUpMessage()
+{
+ if ( m_pContextKeyValues )
+ {
+ m_pContextKeyValues->deleteThis();
+ m_pContextKeyValues = NULL;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Performs layout
+//-----------------------------------------------------------------------------
+void COperationFileListFrame::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ if ( m_pSplitter )
+ {
+ int x, y, w, h;
+ GetClientArea( x, y, w, h );
+ y += 6;
+ h -= 36;
+ m_pSplitter->SetBounds( x, y, w, h );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Adds files to the frame
+//-----------------------------------------------------------------------------
+void COperationFileListFrame::ClearAllOperations()
+{
+ m_pFileBrowser->RemoveAll();
+}
+
+
+//-----------------------------------------------------------------------------
+// Adds the strings to the list panel
+//-----------------------------------------------------------------------------
+void COperationFileListFrame::AddOperation( const char *pOperation, const char *pFileName )
+{
+ KeyValues *kv = new KeyValues( "node", "filename", pFileName );
+ kv->SetString( "operation", pOperation );
+ m_pFileBrowser->AddItem( kv, 0, false, false );
+}
+
+void COperationFileListFrame::AddOperation( const char *pOperation, const char *pFileName, const Color& clr )
+{
+ KeyValues *kv = new KeyValues( "node", "filename", pFileName );
+ kv->SetString( "operation", pOperation );
+ kv->SetColor( "cellcolor", clr );
+ m_pFileBrowser->AddItem( kv, 0, false, false );
+}
+
+
+//-----------------------------------------------------------------------------
+// Resizes the operation column to fit the operation text
+//-----------------------------------------------------------------------------
+void COperationFileListFrame::ResizeOperationColumnToContents()
+{
+ m_pFileBrowser->ResizeColumnToContents( 0 );
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets the column header for the 'operation' column
+//-----------------------------------------------------------------------------
+void COperationFileListFrame::SetOperationColumnHeaderText( const char *pText )
+{
+ m_pFileBrowser->SetColumnHeaderText( 0, pText );
+}
+
+
+//-----------------------------------------------------------------------------
+// Adds the strings to the list panel
+//-----------------------------------------------------------------------------
+void COperationFileListFrame::DoModal( KeyValues *pContextKeyValues, const char *pMessage )
+{
+ m_MessageName = pMessage ? pMessage : "OperationConfirmed";
+ CleanUpMessage();
+ m_pContextKeyValues = pContextKeyValues;
+ m_pFileBrowser->SortList();
+ if ( m_pNoButton->IsVisible() )
+ {
+ m_pYesButton->SetEnabled( m_pFileBrowser->GetItemCount() != 0 );
+ }
+ BaseClass::DoModal();
+}
+
+
+//-----------------------------------------------------------------------------
+// Retrieves the number of files, the file names, and operations
+//-----------------------------------------------------------------------------
+int COperationFileListFrame::GetOperationCount()
+{
+ return m_pFileBrowser->GetItemCount();
+}
+
+const char *COperationFileListFrame::GetFileName( int i )
+{
+ int nItemId = m_pFileBrowser->GetItemIDFromRow( i );
+ KeyValues *pKeyValues = m_pFileBrowser->GetItem( nItemId );
+ return pKeyValues->GetString( "filename" );
+}
+
+const char *COperationFileListFrame::GetOperation( int i )
+{
+ int nItemId = m_pFileBrowser->GetItemIDFromRow( i );
+ KeyValues *pKeyValues = m_pFileBrowser->GetItem( nItemId );
+ return pKeyValues->GetString( "operation" );
+}
+
+
+//-----------------------------------------------------------------------------
+// Retreives the description (only if it was shown)
+//-----------------------------------------------------------------------------
+const char *COperationFileListFrame::GetDescription()
+{
+ return m_pText;
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the message name
+//-----------------------------------------------------------------------------
+const char *COperationFileListFrame::CompletionMessage()
+{
+ return m_MessageName;
+}
+
+
+//-----------------------------------------------------------------------------
+// On command
+//-----------------------------------------------------------------------------
+void COperationFileListFrame::OnCommand( const char *pCommand )
+{
+ if ( !Q_stricmp( pCommand, "Yes" ) )
+ {
+ if ( m_pDescription )
+ {
+ int nLen = m_pDescription->GetTextLength() + 1;
+ m_pText = new char[ nLen ];
+ m_pDescription->GetText( m_pText, nLen );
+ }
+
+ KeyValues *pActionKeys;
+ if ( PerformOperation() )
+ {
+ pActionKeys = new KeyValues( CompletionMessage(), "operationPerformed", 1 );
+ }
+ else
+ {
+ pActionKeys = new KeyValues( CompletionMessage(), "operationPerformed", 0 );
+ }
+
+ if ( m_pContextKeyValues )
+ {
+ pActionKeys->AddSubKey( m_pContextKeyValues );
+ m_pContextKeyValues = NULL;
+ }
+ CloseModal();
+ PostActionSignal( pActionKeys );
+ return;
+ }
+
+ if ( !Q_stricmp( pCommand, "No" ) )
+ {
+ KeyValues *pActionKeys = new KeyValues( CompletionMessage(), "operationPerformed", 0 );
+ if ( m_pContextKeyValues )
+ {
+ pActionKeys->AddSubKey( m_pContextKeyValues );
+ m_pContextKeyValues = NULL;
+ }
+ CloseModal();
+ PostActionSignal( pActionKeys );
+ return;
+ }
+
+ BaseClass::OnCommand( pCommand );
+}
+
+
+//-----------------------------------------------------------------------------
+//
+// Version that does the work of perforce actions
+//
+//-----------------------------------------------------------------------------
+CPerforceFileListFrame::CPerforceFileListFrame( vgui::Panel *pParent, const char *pTitle, const char *pColumnHeader, PerforceAction_t action ) :
+ BaseClass( pParent, pTitle, pColumnHeader, (action == PERFORCE_ACTION_FILE_SUBMIT), false, OPERATION_DIALOG_ID_PERFORCE )
+{
+ m_Action = action;
+}
+
+CPerforceFileListFrame::~CPerforceFileListFrame()
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Activates the modal dialog
+//-----------------------------------------------------------------------------
+void CPerforceFileListFrame::DoModal( KeyValues *pContextKeys, const char *pMessage )
+{
+ BaseClass::DoModal( pContextKeys, pMessage ? pMessage : "PerforceActionConfirmed" );
+}
+
+
+//-----------------------------------------------------------------------------
+// Adds a file for open
+//-----------------------------------------------------------------------------
+void CPerforceFileListFrame::AddFileForOpen( const char *pFullPath )
+{
+ bool bIsInPerforce = p4->IsFileInPerforce( pFullPath );
+ bool bIsOpened = ( p4->GetFileState( pFullPath ) != P4FILE_UNOPENED );
+ switch( m_Action )
+ {
+ case PERFORCE_ACTION_FILE_ADD:
+ if ( !bIsInPerforce && !bIsOpened )
+ {
+ AddOperation( "Add", pFullPath );
+ }
+ break;
+
+ case PERFORCE_ACTION_FILE_EDIT:
+ if ( bIsInPerforce && !bIsOpened )
+ {
+ AddOperation( "Edit", pFullPath );
+ }
+ break;
+
+ case PERFORCE_ACTION_FILE_DELETE:
+ if ( bIsInPerforce && !bIsOpened )
+ {
+ AddOperation( "Delete", pFullPath );
+ }
+ break;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Add files to dialog for submit/revert dialogs
+//-----------------------------------------------------------------------------
+void CPerforceFileListFrame::AddFileForSubmit( const char *pFullPath, P4FileState_t state )
+{
+ if ( state == P4FILE_UNOPENED )
+ return;
+
+ char pBuf[128];
+ const char *pPrefix = (m_Action == PERFORCE_ACTION_FILE_REVERT) ? "Revert" : "Submit";
+ switch( state )
+ {
+ case P4FILE_OPENED_FOR_ADD:
+ Q_snprintf( pBuf, sizeof(pBuf), "%s Add", pPrefix );
+ AddOperation( pBuf, pFullPath );
+ break;
+
+ case P4FILE_OPENED_FOR_EDIT:
+ Q_snprintf( pBuf, sizeof(pBuf), "%s Edit", pPrefix );
+ AddOperation( pBuf, pFullPath );
+ break;
+
+ case P4FILE_OPENED_FOR_DELETE:
+ Q_snprintf( pBuf, sizeof(pBuf), "%s Delete", pPrefix );
+ AddOperation( pBuf, pFullPath );
+ break;
+
+ case P4FILE_OPENED_FOR_INTEGRATE:
+ Q_snprintf( pBuf, sizeof(pBuf), "%s Integrate", pPrefix );
+ AddOperation( pBuf, pFullPath );
+ break;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Version of AddFile that accepts full paths
+//-----------------------------------------------------------------------------
+void CPerforceFileListFrame::AddFile( const char *pFullPath )
+{
+ if ( m_Action < PERFORCE_ACTION_FILE_REVERT )
+ {
+ // If the file wasn't found on the disk, then abort
+ if ( g_pFullFileSystem->FileExists( pFullPath, NULL ) )
+ {
+ AddFileForOpen( pFullPath );
+ }
+ return;
+ }
+
+ // Deal with submit, revert
+ bool bFileExists = g_pFullFileSystem->FileExists( pFullPath, NULL );
+ P4FileState_t state = p4->GetFileState( pFullPath );
+ if ( bFileExists || (state == P4FILE_OPENED_FOR_DELETE) )
+ {
+ AddFileForSubmit( pFullPath, state );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Version of AddFile that accepts relative paths + search path ids
+//-----------------------------------------------------------------------------
+void CPerforceFileListFrame::AddFile( const char *pRelativePath, const char *pPathId )
+{
+ // Deal with add, open, edit
+ if ( m_Action < PERFORCE_ACTION_FILE_REVERT )
+ {
+ // If the file wasn't found on the disk, then abort
+ if ( g_pFullFileSystem->FileExists( pRelativePath, pPathId ) )
+ {
+ char pFullPath[MAX_PATH];
+ g_pFullFileSystem->RelativePathToFullPath( pRelativePath, pPathId, pFullPath, sizeof( pFullPath ) );
+ AddFileForOpen( pFullPath );
+ }
+ return;
+ }
+
+ // Deal with submit, revert
+
+ // First, handle the case where the file exists on the drive
+ char pFullPath[MAX_PATH];
+ if ( g_pFullFileSystem->FileExists( pRelativePath, pPathId ) )
+ {
+ g_pFullFileSystem->RelativePathToFullPath( pRelativePath, pPathId, pFullPath, sizeof( pFullPath ) );
+ P4FileState_t state = p4->GetFileState( pFullPath );
+ AddFileForSubmit( pFullPath, state );
+ return;
+ }
+
+ // Get the list of opened files, cache it off so we aren't continually reasking
+ if ( Q_stricmp( pPathId, m_LastOpenedFilePathId ) )
+ {
+ p4->GetOpenedFileListInPath( pPathId, m_OpenedFiles );
+ m_LastOpenedFilePathId = pPathId;
+ }
+
+ // If the file doesn't exist, it was opened for delete.
+ // Using the client spec of the path, we need to piece together
+ // the full path; the full path unfortunately is usually ambiguous:
+ // you can never exactly know which mod it came from.
+ char pTemp[MAX_PATH];
+ char pSearchString[MAX_PATH];
+ Q_strncpy( pSearchString, pRelativePath, sizeof(pSearchString) );
+ Q_FixSlashes( pSearchString );
+
+ int k;
+ int nOpenedFileCount = m_OpenedFiles.Count();
+ for ( k = 0; k < nOpenedFileCount; ++k )
+ {
+ if ( m_OpenedFiles[k].m_eOpenState != P4FILE_OPENED_FOR_DELETE )
+ continue;
+
+ // Check to see if the end of the local file matches the file
+ const char *pLocalFile = p4->String( m_OpenedFiles[k].m_sLocalFile );
+
+ // This ensures the full path lies under the search path
+ if ( !g_pFullFileSystem->FullPathToRelativePathEx( pLocalFile, pPathId, pTemp, sizeof(pTemp) ) )
+ continue;
+
+ // The relative paths had better be the same
+ if ( Q_stricmp( pTemp, pSearchString ) )
+ continue;
+
+ AddFileForSubmit( pLocalFile, m_OpenedFiles[k].m_eOpenState );
+ break;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Does the perforce operation
+//-----------------------------------------------------------------------------
+bool CPerforceFileListFrame::PerformOperation( )
+{
+ int nFileCount = GetOperationCount();
+ const char **ppFileNames = (const char**)_alloca( nFileCount * sizeof(char*) );
+ for ( int i = 0; i < nFileCount; ++i )
+ {
+ ppFileNames[i] = GetFileName( i );
+ }
+
+ bool bSuccess = false;
+
+ switch ( m_Action )
+ {
+ case PERFORCE_ACTION_FILE_ADD:
+ bSuccess = p4->OpenFilesForAdd( nFileCount, ppFileNames );
+ break;
+
+ case PERFORCE_ACTION_FILE_EDIT:
+ bSuccess = p4->OpenFilesForEdit( nFileCount, ppFileNames );
+ break;
+
+ case PERFORCE_ACTION_FILE_DELETE:
+ bSuccess = p4->OpenFilesForDelete( nFileCount, ppFileNames );
+ break;
+
+ case PERFORCE_ACTION_FILE_REVERT:
+ bSuccess = p4->RevertFiles( nFileCount, ppFileNames );
+ break;
+
+ case PERFORCE_ACTION_FILE_SUBMIT:
+ {
+ // Ensure a description was added
+ const char *pDescription = GetDescription();
+ if ( !pDescription[0] || !Q_stricmp( pDescription, "<enter description here>" ) )
+ {
+ vgui::MessageBox *pError = new vgui::MessageBox( "Submission Error!", "Description required for submission.", GetParent() );
+ pError->SetSmallCaption( true );
+ pError->DoModal();
+ return false;
+ }
+ else
+ {
+ bSuccess = p4->SubmitFiles( nFileCount, ppFileNames, pDescription );
+ }
+ }
+ break;
+ }
+
+ const char *pErrorString = p4->GetLastError();
+ if ( !bSuccess )
+ {
+ vgui::MessageBox *pError = new vgui::MessageBox( "Perforce Error!", pErrorString, GetParent() );
+ pError->SetSmallCaption( true );
+ pError->DoModal();
+ }
+#if 0
+ if ( *pErrorString )
+ {
+ if ( V_strstr( pErrorString, "opened for add" ) )
+ return bSuccess;
+ if ( V_strstr( pErrorString, "opened for edit" ) )
+ return bSuccess;
+ // TODO - figure out the rest of these...
+
+ const char *pPrefix = "Perforce has generated the following message which may or may not be an error.\n"
+ "Please email joe with the text of the message, whether you think it was an error, and what perforce operation you where performing.\n"
+ "To copy the message, hit ~ to enter the console, where you will find the message reprinted.\n"
+ "Select the lines of text in the message, right click, select Copy, and then paste into an email message.\n\n";
+ static int nPrefixLen = V_strlen( pPrefix );
+ int nErrorStringLength = V_strlen( pErrorString );
+ char *pMsg = (char*)_alloca( nPrefixLen + nErrorStringLength + 1 );
+ V_strcpy( pMsg, pPrefix );
+ V_strcpy( pMsg + nPrefixLen, pErrorString );
+
+ vgui::MessageBox *pError = new vgui::MessageBox( "Dubious Perforce Message", pMsg, GetParent() );
+ pError->SetSmallCaption( true );
+ pError->DoModal();
+ }
+#endif
+ return bSuccess;
+}
+
+
+//-----------------------------------------------------------------------------
+// Show the perforce query dialog
+//-----------------------------------------------------------------------------
+void ShowPerforceQuery( vgui::Panel *pParent, const char *pFileName, vgui::Panel *pActionSignalTarget, KeyValues *pKeyValues, PerforceAction_t actionFilter )
+{
+ // Refresh the current perforce settings
+ p4->RefreshActiveClient();
+
+ PerforceAction_t action = PERFORCE_ACTION_NONE;
+ const char *pTitle = NULL;
+ if ( !p4->IsFileInPerforce( pFileName ) )
+ {
+ // If the file isn't in perforce, ask to add it
+ action = PERFORCE_ACTION_FILE_ADD;
+ pTitle = "Add File to Perforce?";
+ }
+ else if ( p4->GetFileState( pFileName ) == P4FILE_UNOPENED )
+ {
+ // If the file isn't checked out yet, ask to check it out
+ action = PERFORCE_ACTION_FILE_EDIT;
+ pTitle = "Check Out File from Perforce?";
+ }
+
+ if ( ( action == PERFORCE_ACTION_NONE ) || ( ( actionFilter != PERFORCE_ACTION_NONE ) && ( actionFilter != action ) ) )
+ {
+ // Spoof a completion event
+ KeyValues *pSpoofKeys = new KeyValues( "PerforceQueryCompleted", "operationPerformed", 1 );
+ if ( pKeyValues )
+ {
+ pSpoofKeys->AddSubKey( pKeyValues );
+ }
+ vgui::ivgui()->PostMessage( pActionSignalTarget->GetVPanel(), pSpoofKeys, 0 );
+ return;
+ }
+
+ CPerforceFileListFrame *pQuery = new CPerforceFileListFrame( pParent, pTitle, "File", action );
+ pQuery->AddFile( pFileName );
+ if ( pActionSignalTarget )
+ {
+ pQuery->AddActionSignalTarget( pActionSignalTarget );
+ }
+ pQuery->DoModal( pKeyValues, "PerforceQueryCompleted" );
+}