Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

497 lines
14 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // This is a helper class designed to help with the chains of modal dialogs
  4. // encountered when trying to open or save a particular file
  5. //
  6. //=============================================================================
  7. #include "vgui_controls/FileOpenStateMachine.h"
  8. #include "tier1/KeyValues.h"
  9. #include "vgui_controls/FileOpenDialog.h"
  10. #include "vgui_controls/MessageBox.h"
  11. #include "vgui_controls/perforcefilelistframe.h"
  12. #include "vgui_controls/savedocumentquery.h"
  13. #include "filesystem.h"
  14. #include "p4lib/ip4.h"
  15. #include "tier2/tier2.h"
  16. #include "tier0/icommandline.h"
  17. // memdbgon must be the last include file in a .cpp file!!!
  18. #include "tier0/memdbgon.h"
  19. using namespace vgui;
  20. //-----------------------------------------------------------------------------
  21. // Constructor
  22. //-----------------------------------------------------------------------------
  23. FileOpenStateMachine::FileOpenStateMachine( vgui::Panel *pParent, IFileOpenStateMachineClient *pClient ) : BaseClass( pParent, "FileOpenStateMachine" )
  24. {
  25. m_pClient = pClient;
  26. m_CompletionState = SUCCESSFUL;
  27. m_CurrentState = STATE_NONE;
  28. m_pContextKeyValues = NULL;
  29. SetVisible( false );
  30. }
  31. FileOpenStateMachine::~FileOpenStateMachine()
  32. {
  33. CleanUpContextKeyValues();
  34. }
  35. //-----------------------------------------------------------------------------
  36. // Cleans up keyvalues
  37. //-----------------------------------------------------------------------------
  38. void FileOpenStateMachine::CleanUpContextKeyValues()
  39. {
  40. if ( m_pContextKeyValues )
  41. {
  42. m_pContextKeyValues->deleteThis();
  43. m_pContextKeyValues = NULL;
  44. }
  45. }
  46. //-----------------------------------------------------------------------------
  47. // Returns the state machine completion state
  48. //-----------------------------------------------------------------------------
  49. FileOpenStateMachine::CompletionState_t FileOpenStateMachine::GetCompletionState()
  50. {
  51. return m_CompletionState;
  52. }
  53. //-----------------------------------------------------------------------------
  54. // Utility to set the completion state
  55. //-----------------------------------------------------------------------------
  56. void FileOpenStateMachine::SetCompletionState( FileOpenStateMachine::CompletionState_t state )
  57. {
  58. m_CompletionState = state;
  59. if ( m_CompletionState == IN_PROGRESS )
  60. return;
  61. m_CurrentState = STATE_NONE;
  62. KeyValues *kv = new KeyValues( "FileStateMachineFinished" );
  63. kv->SetInt( "completionState", m_CompletionState );
  64. kv->SetInt( "wroteFile", m_bWroteFile );
  65. kv->SetString( "fullPath", m_FileName.Get() );
  66. kv->SetString( "fileType", m_bIsOpeningFile ? m_OpenFileType.Get() : m_SaveFileType.Get() );
  67. if ( m_pContextKeyValues )
  68. {
  69. kv->AddSubKey( m_pContextKeyValues );
  70. m_pContextKeyValues = NULL;
  71. }
  72. PostActionSignal( kv );
  73. }
  74. //-----------------------------------------------------------------------------
  75. // Called by the message box in OverwriteFileDialog
  76. //-----------------------------------------------------------------------------
  77. void FileOpenStateMachine::OnOverwriteFile( )
  78. {
  79. CheckOutDialog( );
  80. }
  81. void FileOpenStateMachine::OnCancelOverwriteFile( )
  82. {
  83. SetCompletionState( FILE_NOT_OVERWRITTEN );
  84. }
  85. //-----------------------------------------------------------------------------
  86. // Shows the overwrite existing file dialog
  87. //-----------------------------------------------------------------------------
  88. void FileOpenStateMachine::OverwriteFileDialog( )
  89. {
  90. if ( !g_pFullFileSystem->FileExists( m_FileName ) )
  91. {
  92. CheckOutDialog( );
  93. return;
  94. }
  95. m_CurrentState = STATE_SHOWING_OVERWRITE_DIALOG;
  96. char pBuf[1024];
  97. Q_snprintf( pBuf, sizeof(pBuf), "File already exists. Overwrite it?\n\n\"%s\"\n", m_FileName.Get() );
  98. vgui::MessageBox *pMessageBox = new vgui::MessageBox( "Overwrite Existing File?", pBuf, GetParent() );
  99. pMessageBox->AddActionSignalTarget( this );
  100. pMessageBox->SetOKButtonVisible( true );
  101. pMessageBox->SetOKButtonText( "Yes" );
  102. pMessageBox->SetCancelButtonVisible( true );
  103. pMessageBox->SetCancelButtonText( "No" );
  104. pMessageBox->SetCloseButtonVisible( false );
  105. pMessageBox->SetCommand( new KeyValues( "OverwriteFile" ) );
  106. pMessageBox->SetCancelCommand( new KeyValues( "CancelOverwriteFile" ) );
  107. pMessageBox->DoModal();
  108. }
  109. //-----------------------------------------------------------------------------
  110. // Used to open a particular file in perforce, and deal with all the lovely dialogs
  111. //-----------------------------------------------------------------------------
  112. void FileOpenStateMachine::OnFileSelectionCancelled()
  113. {
  114. if ( m_CurrentState == STATE_SHOWING_SAVE_DIALOG )
  115. {
  116. SetCompletionState( FILE_SAVE_NAME_NOT_SPECIFIED );
  117. return;
  118. }
  119. if ( m_CurrentState == STATE_SHOWING_OPEN_DIALOG )
  120. {
  121. SetCompletionState( FILE_OPEN_NAME_NOT_SPECIFIED );
  122. return;
  123. }
  124. Assert(0);
  125. }
  126. //-----------------------------------------------------------------------------
  127. // Used to open a particular file in perforce, and deal with all the lovely dialogs
  128. //-----------------------------------------------------------------------------
  129. void FileOpenStateMachine::OnFileSelected( KeyValues *pKeyValues )
  130. {
  131. if ( m_CurrentState == STATE_SHOWING_SAVE_DIALOG )
  132. {
  133. m_FileName = pKeyValues->GetString( "fullpath" );
  134. const char *pFilterInfo = pKeyValues->GetString( "filterinfo" );
  135. if ( pFilterInfo )
  136. {
  137. m_SaveFileType = pFilterInfo;
  138. }
  139. OverwriteFileDialog();
  140. return;
  141. }
  142. if ( m_CurrentState == STATE_SHOWING_OPEN_DIALOG )
  143. {
  144. m_FileName = pKeyValues->GetString( "fullpath" );
  145. const char *pFilterInfo = pKeyValues->GetString( "filterinfo" );
  146. if ( pFilterInfo )
  147. {
  148. m_OpenFileType = pFilterInfo;
  149. }
  150. ReadFile( );
  151. return;
  152. }
  153. Assert(0);
  154. }
  155. //-----------------------------------------------------------------------------
  156. // Writes the file out
  157. //-----------------------------------------------------------------------------
  158. void FileOpenStateMachine::WriteFile()
  159. {
  160. m_CurrentState = STATE_WRITING_FILE;
  161. if ( !m_pClient->OnWriteFileToDisk( m_FileName, m_SaveFileType, m_pContextKeyValues ) )
  162. {
  163. SetCompletionState( ERROR_WRITING_FILE );
  164. return;
  165. }
  166. m_bWroteFile = true;
  167. if ( m_bShowPerforceDialogs )
  168. {
  169. m_CurrentState = STATE_SHOWING_PERFORCE_ADD_DIALOG;
  170. ShowPerforceQuery( GetParent(), m_FileName, this, NULL, PERFORCE_ACTION_FILE_ADD );
  171. return;
  172. }
  173. if ( !m_bIsOpeningFile )
  174. {
  175. SetCompletionState( SUCCESSFUL );
  176. return;
  177. }
  178. OpenFileDialog();
  179. }
  180. //-----------------------------------------------------------------------------
  181. // Called by the message box in MakeFileWriteableDialog
  182. //-----------------------------------------------------------------------------
  183. void FileOpenStateMachine::OnMakeFileWriteable( )
  184. {
  185. if ( !g_pFullFileSystem->SetFileWritable( m_FileName, true ) )
  186. {
  187. SetCompletionState( ERROR_MAKING_FILE_WRITEABLE );
  188. return;
  189. }
  190. WriteFile();
  191. }
  192. void FileOpenStateMachine::OnCancelMakeFileWriteable( )
  193. {
  194. SetCompletionState( FILE_NOT_MADE_WRITEABLE );
  195. }
  196. //-----------------------------------------------------------------------------
  197. // Shows the make file writeable dialog
  198. //-----------------------------------------------------------------------------
  199. void FileOpenStateMachine::MakeFileWriteableDialog( )
  200. {
  201. // If the file is writeable, write it!
  202. if ( !g_pFullFileSystem->FileExists( m_FileName ) || g_pFullFileSystem->IsFileWritable( m_FileName ) )
  203. {
  204. WriteFile();
  205. return;
  206. }
  207. // If it's in perforce, and not checked out, then we must abort.
  208. bool bIsInPerforce = p4->IsFileInPerforce( m_FileName );
  209. bool bIsOpened = ( p4->GetFileState( m_FileName ) != P4FILE_UNOPENED );
  210. if ( bIsInPerforce && !bIsOpened )
  211. {
  212. SetCompletionState( FILE_NOT_CHECKED_OUT );
  213. return;
  214. }
  215. m_CurrentState = STATE_SHOWING_MAKE_FILE_WRITEABLE_DIALOG;
  216. char pBuf[1024];
  217. Q_snprintf( pBuf, sizeof(pBuf), "Encountered read-only file. Should it be made writeable?\n\n\"%s\"\n", m_FileName.Get() );
  218. vgui::MessageBox *pMessageBox = new vgui::MessageBox( "Make File Writeable?", pBuf, GetParent() );
  219. pMessageBox->AddActionSignalTarget( this );
  220. pMessageBox->SetOKButtonVisible( true );
  221. pMessageBox->SetOKButtonText( "Yes" );
  222. pMessageBox->SetCancelButtonVisible( true );
  223. pMessageBox->SetCancelButtonText( "No" );
  224. pMessageBox->SetCloseButtonVisible( false );
  225. pMessageBox->SetCommand( new KeyValues( "MakeFileWriteable" ) );
  226. pMessageBox->SetCancelCommand( new KeyValues( "CancelMakeFileWriteable" ) );
  227. pMessageBox->DoModal();
  228. }
  229. //-----------------------------------------------------------------------------
  230. // Called when ShowPerforceQuery completes
  231. //-----------------------------------------------------------------------------
  232. void FileOpenStateMachine::OnPerforceQueryCompleted( KeyValues *pKeyValues )
  233. {
  234. if ( m_CurrentState == STATE_SHOWING_CHECK_OUT_DIALOG )
  235. {
  236. if ( pKeyValues->GetInt( "operationPerformed" ) == 0 )
  237. {
  238. SetCompletionState( FILE_NOT_CHECKED_OUT );
  239. return;
  240. }
  241. MakeFileWriteableDialog();
  242. return;
  243. }
  244. if ( m_CurrentState == STATE_SHOWING_PERFORCE_ADD_DIALOG )
  245. {
  246. if ( !m_bIsOpeningFile )
  247. {
  248. SetCompletionState( SUCCESSFUL );
  249. return;
  250. }
  251. OpenFileDialog();
  252. return;
  253. }
  254. Assert(0);
  255. }
  256. //-----------------------------------------------------------------------------
  257. // Used to open a particular file in perforce, and deal with all the lovely dialogs
  258. //-----------------------------------------------------------------------------
  259. void FileOpenStateMachine::CheckOutDialog( )
  260. {
  261. if ( m_bShowPerforceDialogs )
  262. {
  263. m_CurrentState = STATE_SHOWING_CHECK_OUT_DIALOG;
  264. ShowPerforceQuery( GetParent(), m_FileName, this, NULL, PERFORCE_ACTION_FILE_EDIT );
  265. return;
  266. }
  267. WriteFile();
  268. }
  269. //-----------------------------------------------------------------------------
  270. // These 3 messages come from the savedocumentquery dialog
  271. //-----------------------------------------------------------------------------
  272. void FileOpenStateMachine::OnSaveFile()
  273. {
  274. if ( !m_FileName[0] || !Q_IsAbsolutePath( m_FileName ) )
  275. {
  276. m_CurrentState = STATE_SHOWING_SAVE_DIALOG;
  277. FileOpenDialog *pDialog = new FileOpenDialog( GetParent(), "Save As", false );
  278. m_pClient->SetupFileOpenDialog( pDialog, false, m_SaveFileType, m_pContextKeyValues );
  279. pDialog->SetDeleteSelfOnClose( true );
  280. pDialog->AddActionSignalTarget( this );
  281. pDialog->DoModal( );
  282. return;
  283. }
  284. CheckOutDialog( );
  285. }
  286. void FileOpenStateMachine::OnMarkNotDirty()
  287. {
  288. if ( !m_bIsOpeningFile )
  289. {
  290. SetCompletionState( SUCCESSFUL );
  291. return;
  292. }
  293. // Jump right to opening the file
  294. OpenFileDialog( );
  295. }
  296. void FileOpenStateMachine::OnCancelSaveDocument()
  297. {
  298. SetCompletionState( FILE_SAVE_CANCELLED );
  299. }
  300. //-----------------------------------------------------------------------------
  301. // Show the save document query dialog
  302. //-----------------------------------------------------------------------------
  303. void FileOpenStateMachine::ShowSaveQuery( )
  304. {
  305. m_CurrentState = STATE_SHOWING_SAVE_DIRTY_FILE_DIALOG;
  306. ShowSaveDocumentQuery( GetParent(), m_FileName, m_SaveFileType, 0, this, NULL );
  307. }
  308. //-----------------------------------------------------------------------------
  309. // Used to save a specified file, and deal with all the lovely dialogs
  310. //-----------------------------------------------------------------------------
  311. void FileOpenStateMachine::SaveFile( KeyValues *pContextKeyValues, const char *pFileName, const char *pFileType, int nFlags )
  312. {
  313. CleanUpContextKeyValues();
  314. SetCompletionState( IN_PROGRESS );
  315. m_pContextKeyValues = pContextKeyValues;
  316. m_FileName = pFileName;
  317. m_SaveFileType = pFileType;
  318. m_OpenFileType = NULL;
  319. m_OpenFileName = NULL;
  320. // Clear the P4 dialog flag for SDK users and licensees without Perforce
  321. if ( CommandLine()->FindParm( "-nop4" ) )
  322. {
  323. nFlags &= ~FOSM_SHOW_PERFORCE_DIALOGS;
  324. }
  325. m_bShowPerforceDialogs = ( nFlags & FOSM_SHOW_PERFORCE_DIALOGS ) != 0;
  326. m_bShowSaveQuery = ( nFlags & FOSM_SHOW_SAVE_QUERY ) != 0;
  327. m_bIsOpeningFile = false;
  328. m_bWroteFile = false;
  329. if ( m_bShowSaveQuery )
  330. {
  331. ShowSaveQuery();
  332. return;
  333. }
  334. OnSaveFile();
  335. }
  336. //-----------------------------------------------------------------------------
  337. // Reads the file in
  338. //-----------------------------------------------------------------------------
  339. void FileOpenStateMachine::ReadFile()
  340. {
  341. m_CurrentState = STATE_READING_FILE;
  342. if ( !m_pClient->OnReadFileFromDisk( m_FileName, m_OpenFileType, m_pContextKeyValues ) )
  343. {
  344. SetCompletionState( ERROR_READING_FILE );
  345. return;
  346. }
  347. SetCompletionState( SUCCESSFUL );
  348. }
  349. //-----------------------------------------------------------------------------
  350. // Shows the open file dialog
  351. //-----------------------------------------------------------------------------
  352. void FileOpenStateMachine::OpenFileDialog( )
  353. {
  354. m_CurrentState = STATE_SHOWING_OPEN_DIALOG;
  355. if ( m_OpenFileName.IsEmpty() )
  356. {
  357. FileOpenDialog *pDialog = new FileOpenDialog( GetParent(), "Open", true );
  358. m_pClient->SetupFileOpenDialog( pDialog, true, m_OpenFileType, m_pContextKeyValues );
  359. pDialog->SetDeleteSelfOnClose( true );
  360. pDialog->AddActionSignalTarget( this );
  361. pDialog->DoModal( );
  362. }
  363. else
  364. {
  365. m_FileName = m_OpenFileName;
  366. ReadFile();
  367. }
  368. }
  369. //-----------------------------------------------------------------------------
  370. // Opens a file, saves an existing one if necessary
  371. //-----------------------------------------------------------------------------
  372. void FileOpenStateMachine::OpenFile( const char *pOpenFileType, KeyValues *pContextKeyValues, const char *pSaveFileName, const char *pSaveFileType, int nFlags )
  373. {
  374. CleanUpContextKeyValues();
  375. SetCompletionState( IN_PROGRESS );
  376. m_pContextKeyValues = pContextKeyValues;
  377. m_FileName = pSaveFileName;
  378. m_SaveFileType = pSaveFileType;
  379. m_OpenFileType = pOpenFileType;
  380. m_OpenFileName = NULL;
  381. m_bShowPerforceDialogs = ( nFlags & FOSM_SHOW_PERFORCE_DIALOGS ) != 0;
  382. m_bShowSaveQuery = ( nFlags & FOSM_SHOW_SAVE_QUERY ) != 0;
  383. m_bIsOpeningFile = true;
  384. m_bWroteFile = false;
  385. if ( m_bShowSaveQuery )
  386. {
  387. ShowSaveQuery();
  388. return;
  389. }
  390. OpenFileDialog();
  391. }
  392. //-----------------------------------------------------------------------------
  393. // Version of OpenFile that skips browsing for a particular file to open
  394. //-----------------------------------------------------------------------------
  395. void FileOpenStateMachine::OpenFile( const char *pOpenFileName, const char *pOpenFileType, KeyValues *pContextKeyValues, const char *pSaveFileName, const char *pSaveFileType, int nFlags )
  396. {
  397. CleanUpContextKeyValues();
  398. SetCompletionState( IN_PROGRESS );
  399. m_pContextKeyValues = pContextKeyValues;
  400. m_FileName = pSaveFileName;
  401. m_SaveFileType = pSaveFileType;
  402. m_OpenFileType = pOpenFileType;
  403. m_bShowPerforceDialogs = ( nFlags & FOSM_SHOW_PERFORCE_DIALOGS ) != 0;
  404. m_bShowSaveQuery = ( nFlags & FOSM_SHOW_SAVE_QUERY ) != 0;
  405. m_bIsOpeningFile = true;
  406. m_bWroteFile = false;
  407. m_OpenFileName = pOpenFileName;
  408. if ( m_bShowSaveQuery )
  409. {
  410. ShowSaveQuery();
  411. return;
  412. }
  413. OpenFileDialog();
  414. }