/* * Copyright 2004 Perforce Software. All rights reserved. * * Developed by Data Shades Ltd. */ #include "PluginOperations.h" #include "FileOpDialog.h" #include "FullSubmitDialog.h" #include "OpenFilesDialog.h" #include "TabbedOptionsDialog.h" #include "AboutDialog.h" #include "OpenDepotDialog.h" #include "HistoryDialog.h" #include "StatusDialog.h" #include "OldVersionDialog.h" #include "ExternalRefDialog.h" #include "ResultsDialog.h" #include "ResolveDialog.h" #include "CheckInAddDialog.h" #include "PluginHost.h" #include "PluginMessages.h" #include "htmlhelp.h" #include "debug.h" #include <commctrl.h> PluginOperations::PluginOperations( PluginHost *host ) { this->host = host; login = false; gotInfo = false; options = new PerforceOptions( host->GetName() ); online = (BOOL)options->GetOptionValue( SERVER_ONLINE ); DBG2_open(); // Load windows common controls. INITCOMMONCONTROLSEX icex; icex.dwSize = sizeof( INITCOMMONCONTROLSEX ); icex.dwICC = ICC_BAR_CLASSES | ICC_LISTVIEW_CLASSES | ICC_TREEVIEW_CLASSES | ICC_USEREX_CLASSES; InitCommonControlsEx( &icex ); } PluginOperations::~PluginOperations() { delete options; DBG2_close(); } void PluginOperations::ToggleOnline() { online = online ? 0: 1; options->SetOptionValue( SERVER_ONLINE, online ); } MenuState *PluginOperations::GetMenuState() { if ( !online || host->GetNumDocs() == 0 ) { return new MenuState( online, NULL, false ); } else { UniStrBuf path; bool fileExists = host->GetCurrDocPath( path ); if ( fileExists ) { // Use our own results as we do not // want the menu stat to appear in results of // last command PerforceResults statResults; fileExists = Stat( path.Text(), &stat, &statResults ); } return new MenuState( online, &stat, fileExists ); } } void PluginOperations::FileOpenEvent() { UniStrBuf filename; if (!online || !host->GetCurrDocPath( filename ) ) { return; } // Use our own results as we do not // want the internal stat to appear in results of // last command PerforceResults statResults; // Is file under Perforce if ( Stat( filename.Text(), &stat, &statResults ) ) { // If file is checked in if (!stat.IsOpen()) { // If file is not the latest version if (!stat.IsLatestVersion()) { OldVersionDialog dialog( this, stat.HaveRevision(), stat.HeadRevision() ); if ( dialog.Show( host->GetInstance(), host->GetWin()) ) { if (dialog.ExitCode() == IDSYNC) { Sync( filename.Text() ); host->ReloadCurrDoc(); } else { Edit(); } } } else { bool doEdit = false; bool doPrompt = false; if ( !host->IsReloading() ) { switch ( options->GetOptionValue( CHECK_OUT_ON_OPEN_OPTION ) ) { case PROMPT_OPTION: doPrompt = true; break; case ALWAYS_OPTION: doEdit = true; break; } } // Reload after a revert else { switch ( options->GetOptionValue( CHECK_OUT_ON_REOPEN_OPTION ) ) { case PROMPT_OPTION: doPrompt = true; break; case ALWAYS_OPTION: doEdit = true; break; } } if ( doPrompt ) { if ( MessageBox( host->GetWin(), P4_OPEN_DOCUMENT_MSG, P4_OPEN_DOCUMENT_TITLE, MB_ICONQUESTION | MB_OKCANCEL ) == IDOK ) { doEdit = true; } } if ( doEdit ) { Edit(); } } } } } void PluginOperations::FileCloseEvent() { UniStrBuf filename; if (!online || !host->GetCurrDocPath( filename ) ) { return; } // Use our own results as we do not // want the internal stat to appear in results of // last command PerforceResults statResults; bool fileExists = Stat( filename.Text(), &stat, &statResults ); if ( fileExists && stat.IsOpen() ) { bool doPrompt = false; bool doSubmit = false; switch ( options->GetOptionValue( CHECK_IN_ON_CLOSE_OPTION ) ) { case PROMPT_OPTION: doPrompt = true; break; case ALWAYS_OPTION: doSubmit = true; break; } if ( doPrompt ) { if ( MessageBox( host->GetWin(), P4_CLOSE_DOCUMENT_MSG, P4_CLOSE_DOCUMENT_TITLE, MB_ICONQUESTION | MB_YESNO ) == IDYES ) { doSubmit = true; } } if ( doSubmit ) { Submit(); } } } void PluginOperations::SetFileDir() { oldDir[0] = '\0'; if ( currFile.Length() == 0 ) { return; } // Change current directory to where the file is so that P4CONFIG works TCHAR *filename = currFile.Text(); TCHAR *end = filename + _tcslen( filename ) - 1; for ( ; *end != '\\' && *end != '/' && end != filename; end-- ) { ; } if ( end != filename ) { TCHAR dir[MAX_PATH]; _tcsncpy_s( dir, filename, end - filename ); dir[end - filename] = '\0'; GetCurrentDirectory( MAX_PATH, oldDir ); SetCurrentDirectory( dir ); } } void PluginOperations::RestoreOldDir() { if ( _tcslen( oldDir ) > 0 ) { SetCurrentDirectory( oldDir ); } } bool PluginOperations::Stat( TCHAR *filename, PerforceFileStat *stat, PerforceResults *results ) { // Store the current file currFile.Clear(); currFile.Set( filename ); if ( results == NULL ) { results = &this->results; } try { CONNECTION( this ); PerforceCommand cmd( _T("fstat"), filename ); con.Exec( &cmd, results ); if ( results->Count() == 1 ) { UniStrDict* dict = (UniStrDict *)results->Get( 0 ); if ( dict->GetVar( "depotFile" ) != NULL ) { stat->Set( dict ); return true; } } } catch (std::exception e) { DisplayError( e ); } return false; } void PluginOperations::DisplayError( std::exception &err ) { UniStrBuf buff; Translate::ToWinChar( err.what(), &buff ); MessageBox( host->GetWin(), buff.Text(), P4_ERROR_TITLE, MB_ICONERROR | MB_OK ); // If server connect error then go to offline operation if ( _tcsstr( buff.Text(), _T("check $P4PORT") ) != NULL ) { ToggleOnline(); } } void PluginOperations::ShowOpenFiles() { try { CONNECTION( this ); PerforceCommand cmd( _T("opened"), _T("-c"), _T("default") ); con.Exec( &cmd, &results ); OpenFilesDialog dialog( this, &results ); dialog.Show( host->GetInstance(), host->GetWin() ); } catch (std::exception e) { DisplayError( e ); } } void PluginOperations::ShowOptions() { TabbedOptionsDialog dialog( this, options, host->HasRefs() ); dialog.Show( host->GetInstance(), host->GetWin() ); } void PluginOperations::ShowOpenDepot( StrBufArray *filetypes ) { try { OpenDepotDialog dialog( this, options, filetypes ); if ( dialog.Show( host->GetInstance(), host->GetWin() ) == TRUE ) { StrPtr *clientFile = dialog.SelectedFile(); if ( clientFile != NULL ) { // If host cannot display multiple documents then we need to // lose the current document if ( !host->HasMultiDocs() && host->IsCurrDocDirty() ) { if ( MessageBox( host->GetWin(), P4_OPEN_SAVE_CURR_MSG, P4_OPEN_SAVE_CURR_TITLE, MB_ICONQUESTION | MB_YESNO ) == IDYES ) { host->SaveCurrDoc(); } } host->LoadDoc( clientFile ); } } } catch ( std::exception e ) { DisplayError( e ); } } void PluginOperations::ShowAbout() { AboutDialog dialog( this, host->GetDesc(), host->GetVersion(), host->GetHostVersion() ); dialog.Show( host->GetInstance(), host->GetWin() ); } void PluginOperations::ShowHelp() { HKEY helpKey; bool foundHelp = false; // Generate full registry path; UniStrBuf regKeyName; regKeyName.Set( SOFTWARE_KEY ); regKeyName.Append( _T("\\") ); regKeyName.Append( PERFORCE_KEY ); regKeyName.Append( _T("\\") ); regKeyName.Append( _T("P4GT") ); if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE, regKeyName.Text(), 0, KEY_QUERY_VALUE, &helpKey ) == ERROR_SUCCESS ) { DWORD type; TCHAR path[MAX_PATH]; DWORD size = MAX_PATH; long ret = RegQueryValueEx( helpKey, _T("HelpFilePath"), NULL, &type, ( LPBYTE )path, &size ); RegCloseKey( helpKey ); if ( ret == ERROR_SUCCESS ) { // Check help file exists DWORD attr = GetFileAttributes( path ); if ( attr != 0xFFFFFFFF ) { foundHelp = true; HtmlHelp( host->GetWin(), path, HH_DISPLAY_TOPIC, NULL); } } } if ( !foundHelp ) { MessageBox( host->GetWin(), P4_NO_HELP_MSG, P4_NO_HELP_TITLE, MB_ICONERROR | MB_OK ); } } void PluginOperations::ShowInfo() { try { CONNECTION( this ); PerforceCommand cmd( _T("info") ); con.Exec( &cmd, &results ); ResultsDialog dialog( this, _T("info"), &results, &con.GetCwd() ); dialog.Show( host->GetInstance(), host->GetWin() ); } catch ( std::exception e ) { DisplayError( e ); } } void PluginOperations::ShowStatus() { UniStrBuf filename; if ( host->GetCurrDocPath( filename ) ) { // We need to do another stat after the menu stat to // so we can store the results. Stat( filename.Text(), &stat ); FileOpDialog dialog( this, _T("fstat"), filename.Text(), &results, options ); //StatusDialog dialog( &stat ); dialog.Show( host->GetInstance(), host->GetWin() ); } } void PluginOperations::NeedSaveDialog() { MessageBox( host->GetWin(), P4_NEED_SAVE_MSG, P4_NEED_SAVE_TITLE, MB_ICONEXCLAMATION | MB_OK); } void PluginOperations::ShowHistory() { UniStrBuf filename; if ( host->GetCurrDocPath( filename ) ) { try { CONNECTION( this ); PerforceCommand cmd( _T("filelog"), _T("-l") , filename.Text() ); con.Exec( &cmd, &results ); HistoryDialog dialog( this, &results ); if ( dialog.Show( host->GetInstance(), host->GetWin() ) ) { // If host cannot display multiple documents then we need to // lose the current document if ( !host->HasMultiDocs() && host->IsCurrDocDirty() ) { if ( MessageBox( host->GetWin(), P4_PREV_SAVE_CURR_MSG, P4_PREV_SAVE_CURR_TITLE, MB_ICONQUESTION | MB_YESNO ) == IDYES ) { host->SaveCurrDoc(); } } host->LoadDoc( dialog.TempFile() ); }; } catch ( std::exception e ) { DisplayError( e ); } } } void PluginOperations::SyncReferences( StrBufArray *files ) { int syncOption = options->GetOptionValue( SYNC_FILE_REF_OPTION ); if ( syncOption == NEVER_OPTION ) { return; } CONNECTION( this ); PerforceCommand cmd( _T("fstat") ); for ( int i=0; i<files->Count(); i++ ) { cmd.Append( (TCHAR *)files->Get( i ) ); } PerforceResults statResults; con.Exec( &cmd, &statResults ); // Check if we have any old files bool gotOld = false; PerforceFileStat refStat; for ( int i=0; i<statResults.Count(); i++ ) { UniStrDict* dict = (UniStrDict *)statResults.Get( i ); if ( dict->GetVar( "depotFile" ) != NULL ) { refStat.Set( dict ); if ( !refStat.IsLatestVersion() ) { gotOld = true; } } } if ( gotOld ) { bool doSync = true; ExternalRefDialog dialog( this, &statResults ); if ( syncOption == PROMPT_OPTION ) { if ( dialog.Show( host->GetInstance(), host->GetWin() ) == TRUE ) { // Files storage is owned by dialog files = dialog.GetSyncFiles(); } else { doSync = false; } } if ( doSync ) { PerforceCommand cmd( _T("sync") ); for ( int i=0; i<files->Count(); i++ ) { cmd.Append( files->Get( i ) ); } con.Exec( &cmd, &results ); } } } void PluginOperations::Sync( TCHAR *filename, bool show ) { DoFileOp( _T("sync"), filename, show ); } void PluginOperations::Add() { UniStrBuf filename; if ( host->GetCurrDocPath( filename ) ) { bool showDialog = options->GetOptionValue( SHOW_CONFIRMATION_OPTION ) ? true : false; if ( DoFileOp( _T("add"), filename.Text(), showDialog ) ) { switch ( options->GetOptionValue( CHECK_IN_ON_ADD_OPTION ) ) { case ALWAYS_OPTION: Submit(); break; case PROMPT_OPTION: CheckInAddDialog dialog( this, options ); if ( dialog.Show( host->GetInstance(), host->GetWin() ) == TRUE ) { Submit(); } break; } } } else { NeedSaveDialog(); } } void PluginOperations::Edit() { UniStrBuf filename; if ( host->GetCurrDocPath( filename ) ) { bool doEdit = true; bool doLock = true; if ( stat.IsOtherLocked() && options->GetOptionValue( LOCK_ON_CHECK_OUT_OPTION ) ) { UniStrBuf msg; msg.Set( _T("This document is checked-in to Perforce.\r\n\r\n") ); msg.Append( _T("The document has already been locked by someone else: ") ); msg.Append( stat.GetOtherLockedUserClient() ); msg.Append( _T(".\r\n\r\n") ); msg.Append( _T("Automatic locking after Check Out is not possible.\r\n") ); msg.Append( _T("Do you still want to Check Out without locking it?") ); if ( MessageBox( host->GetWin(), msg.Text(), _T("P4GT - Check Out Document"), MB_ICONQUESTION | MB_YESNO ) == IDYES ) { doEdit = true; doLock = false; } else { doEdit = false; doLock = false; } } if ( doEdit ) { bool showDialog = options->GetOptionValue( SHOW_CONFIRMATION_OPTION ) ? true : false; DoFileOp( _T("edit"), filename.Text(), showDialog ); if ( doLock ) { switch ( options->GetOptionValue( LOCK_ON_CHECK_OUT_OPTION ) ) { case PROMPT_OPTION: if ( MessageBox( host->GetWin(), _T("This document has been Checked Out. Do you now want to lock the document?"), _T("P4GT - Check Out Document"), MB_ICONQUESTION | MB_YESNO ) == IDYES ) { DoFileOp( _T("lock"), filename.Text(), false ); } break; case ALWAYS_OPTION: DoFileOp( _T("lock"), filename.Text(), false ); break; } } } } } void PluginOperations::Revert() { UniStrBuf filename; if ( host->GetCurrDocPath( filename ) ) { bool doRevert = false; if ( stat.IsOpenForAdd() ) { doRevert = true; } else if (MessageBox( host->GetWin(), P4_REVERT_MSG, P4_REVERT_TITLE, MB_ICONQUESTION | MB_YESNO ) == IDYES ) { doRevert = true; } if ( doRevert ) { DoFileOp( _T("revert"), filename.Text() ); host->SetReloading( true ); host->ReloadCurrDoc(); host->SetReloading( false ); } } } void PluginOperations::ToggleLock() { UniStrBuf filename; if ( host->GetCurrDocPath( filename ) ) { if ( stat.IsOurLocked() ) { DoFileOp( _T("unlock"), filename.Text() ); } else { DoFileOp( _T("lock"), filename.Text() ); } } } void PluginOperations::Submit() { UniStrBuf filename; if ( host->GetCurrDocPath( filename ) ) { // Need to make sure we stat the file. // This is because it would not happen if it is a new file // that is being automatically submitted after an add PerforceResults statResults; Stat( filename.Text(), &stat, &statResults ); // Check if file needs to be saved before submit if ( host->IsCurrDocDirty() ) { if ( MessageBox( host->GetWin(), P4_SUBMIT_SAVE_CURR_MSG, P4_SUBMIT_SAVE_CURR_TITLE, MB_ICONQUESTION | MB_YESNO ) == IDYES ) { host->SaveCurrDoc(); } } bool doSubmit = true; CONNECTION( this ); // Check if need to resolve. if ( !stat.IsLatestVersion() ) { ResolveDialog dialog( this ); if ( dialog.Show( host->GetInstance(), host->GetWin() ) == TRUE ) { int option = dialog.GetOption(); if ( option == IDC_UNDO_RADIO ) { Revert(); doSubmit = false; } else if ( option == IDC_CHECK_IN_RADIO ) { try { Sync( (TCHAR *)stat.DepotPath()->Text(), false ); PerforceCommand cmd( _T("resolve"), _T("-ay"), (TCHAR *)stat.DepotPath()->Text() ); con.Exec( &cmd, &results ); } catch ( std::exception e ) { DisplayError( e ); doSubmit = false; } } else { doSubmit = false; } } else { doSubmit = false; } } if ( !doSubmit ) { return; } try { PerforceCommand cmd( _T("change"), _T("-o") ); con.Exec( &cmd, &results ); FullSubmitDialog dialog( this, &con, &results, stat.DepotPath(), options->GetOptionValue( OTHER_DOCUMENTS_OPTION ) ); if ( dialog.Show( host->GetInstance(), host->GetWin() ) == TRUE ) { UniStrBuf desc; dialog.GetDescription( desc ); StrPtr *files = dialog.GetSubmitFiles(); StrPtr *jobs = dialog.GetSubmitJobs(); PerforceCommand cmd( _T("submit") ); if ( dialog.GetKeepOut() ) { cmd.Append( _T("-r") ); } if ( dialog.GetJobStatus() ) { cmd.Append( _T("-s") ); } cmd.Append( _T("-i") ); cmd.SetInputVar( "Change", _T("new") ); cmd.SetInputVar( "Description", desc.Text() ); cmd.SetInputVar( "Files", (TCHAR *)files->Text() ); if ( jobs->Length() > 0 ) { cmd.SetInputVar( "Jobs", (TCHAR *)jobs->Text() ); } con.Exec( &cmd, &results ); ResultsDialog resultsDialog( this, _T("submit"), &results ); resultsDialog.Show( host->GetInstance(), host->GetWin() ); try { // Relock document if keeping checked out if ( dialog.GetKeepOut() && options->GetOptionValue( LOCK_ON_CHECK_OUT_OPTION ) ) { DoFileOp( _T("lock"), filename.Text(), false ); } } catch ( std::exception e ) { // Ignore any errors from attempting lock } } } catch ( std::exception e ) { DisplayError( e ); } } } void PluginOperations::ShowLastResults() { ResultsDialog dialog( this, _T("last"), &results ); dialog.Show( host->GetInstance(), host->GetWin() ); } bool PluginOperations::GetDepotPath( PerforceConnection& con, TCHAR* filename, StrBuf& buff ) { PerforceCommand cmd( _T("opened"), filename ); con.Exec( &cmd, &results ); if ( results.Count() == 1 ) { StrDict* dict = ( StrDict * )results.Get( 0 ); StrPtr* depotFile = dict->GetVar( "depotFile" ); if ( depotFile != NULL ) { buff.Set( depotFile ); return true; } } return false; } TCHAR *PluginOperations::AddOutsideRoot( TCHAR *op, PerforceResults &results ) { if ( _tcscmp( op, _T("add") ) == 0 && results.Count() > 0 ) { StrDict *dict = (StrDict *)results.Get( 0 ); StrPtr *msg = dict->GetVar( "msg" ); if ( msg != NULL ) { TCHAR *root = _tcsstr( (TCHAR *)msg->Text(), _T("is not under client's root") ); if ( root != NULL ) { return root + 27; } } } return NULL; } bool PluginOperations::DoFileOp( TCHAR *op, TCHAR *filename, bool show ) { try { CONNECTION( this ); PerforceCommand cmd(op, filename); con.Exec(&cmd, &results); // Check for adding files not under the client root TCHAR *root = AddOutsideRoot( op, results ); if ( root != NULL ) { UniStrBuf msg; msg.Set( _T("This file cannot be added to Perforce as it is outside the client root ") ); msg.Append( root ); MessageBox( host->GetWin(), msg.Text(), P4_NEED_SAVE_TITLE, MB_ICONERROR | MB_OK ); return false; } else if ( show ) { FileOpDialog dialog( this, op, filename, &results, options ); dialog.Show( host->GetInstance(), host->GetWin() ); } return true; } catch ( std::exception e ) { DisplayError( e ); return false; } } void PluginOperations::SetPassword( TCHAR *password ) { this->password.Set( password ); }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#1 | 10843 | Robert Cowham |
Initial version of P4OFC source code. See README.txt (and LICENSE.txt and doc\P4OFC-Design.docx) |