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.

472 lines
9.8 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "workspace.h"
  8. #include <KeyValues.h>
  9. #include "project.h"
  10. #include "vstdlib/random.h"
  11. #include "cmdlib.h"
  12. #include "FileSystem_Tools.h"
  13. #include "utlbuffer.h"
  14. #include "workspacemanager.h"
  15. #include "workspacebrowser.h"
  16. #include "soundbrowser.h"
  17. #include "wavebrowser.h"
  18. CWorkspace::CWorkspace( char const *filename )
  19. {
  20. m_szVSSUserName[ 0 ] = 0;
  21. m_szVSSProject[ 0 ] = 0;
  22. Q_strncpy( m_szFile, filename, sizeof( m_szFile ) );
  23. // By default, name is the same as the filename
  24. Q_FileBase( m_szFile, m_szName, sizeof( m_szName ) );
  25. m_bDirty = false;
  26. LoadFromFile();
  27. }
  28. CWorkspace::~CWorkspace()
  29. {
  30. while ( m_Projects.Count() > 0 )
  31. {
  32. CProject *p = m_Projects[ 0 ];
  33. m_Projects.Remove( 0 );
  34. delete p;
  35. }
  36. }
  37. char const *CWorkspace::GetName() const
  38. {
  39. return m_szName;
  40. }
  41. bool CWorkspace::IsDirty( void ) const
  42. {
  43. int c = GetProjectCount();
  44. for ( int i = 0; i < c; i++ )
  45. {
  46. CProject *p = GetProject( i );
  47. Assert( p );
  48. if ( p->IsDirty() )
  49. return true;
  50. }
  51. return m_bDirty;
  52. }
  53. void CWorkspace::SetDirty( bool dirty )
  54. {
  55. m_bDirty = dirty;
  56. }
  57. int CWorkspace::GetProjectCount() const
  58. {
  59. return m_Projects.Count();
  60. }
  61. CProject *CWorkspace::GetProject( int index ) const
  62. {
  63. if ( index < 0 || index >= m_Projects.Count() )
  64. return NULL;
  65. return m_Projects[ index ];
  66. }
  67. void CWorkspace::RemoveProject( CProject *project )
  68. {
  69. if ( m_Projects.Find( project ) == m_Projects.InvalidIndex() )
  70. return;
  71. m_Projects.FindAndRemove( project );
  72. SetDirty( true );
  73. }
  74. void CWorkspace::AddProject( CProject *project )
  75. {
  76. SetDirty( true );
  77. Assert( m_Projects.Find( project ) == m_Projects.InvalidIndex() );
  78. m_Projects.AddToTail( project );
  79. }
  80. CProject *CWorkspace::FindProjectFile( char const *filename ) const
  81. {
  82. int c = GetProjectCount();
  83. for ( int i = 0 ; i < c; i++ )
  84. {
  85. CProject *p = GetProject( i );
  86. Assert( p );
  87. if ( !Q_stricmp( p->GetFileName(), filename ) )
  88. return p;
  89. }
  90. return NULL;
  91. }
  92. void CWorkspace::LoadFromFile()
  93. {
  94. KeyValues *kv = new KeyValues( m_szName );
  95. if ( kv->LoadFromFile( filesystem, m_szFile ) )
  96. {
  97. for ( KeyValues *proj = kv->GetFirstSubKey(); proj; proj = proj->GetNextKey() )
  98. {
  99. // Add named projects
  100. if ( !Q_stricmp( proj->GetName(), "project" ) )
  101. {
  102. bool expanded = false;
  103. char filename[ 256 ];
  104. filename[0] = 0;
  105. for ( KeyValues *sub = proj->GetFirstSubKey(); sub; sub = sub->GetNextKey() )
  106. {
  107. if ( !Q_stricmp( sub->GetName(), "file" ) )
  108. {
  109. Q_strcpy( filename, sub->GetString() );
  110. continue;
  111. }
  112. else if ( !Q_stricmp( sub->GetName(), "expanded" ) )
  113. {
  114. expanded = sub->GetInt() ? true : false;
  115. continue;
  116. }
  117. else
  118. {
  119. Assert( 0 );
  120. }
  121. }
  122. CProject *p = new CProject( this, filename );
  123. p->SetExpanded( expanded );
  124. p->SetDirty( false );
  125. m_Projects.AddToTail( p );
  126. continue;
  127. }
  128. else if ( !Q_stricmp( proj->GetName(), "vss_username" ) )
  129. {
  130. SetVSSUserName( proj->GetString() );
  131. Con_Printf( "VSS User: '%s'\n", GetVSSUserName() );
  132. continue;
  133. }
  134. else if ( !Q_stricmp( proj->GetName(), "vss_project" ) )
  135. {
  136. SetVSSProject( proj->GetString() );
  137. Con_Printf( "VSS Project: '%s'\n", GetVSSProject() );
  138. continue;
  139. }
  140. else if ( !Q_stricmp( proj->GetName(), "window" ) )
  141. {
  142. SetDirty( true );
  143. char const *windowname = proj->GetString( "windowname", "" );
  144. if ( !Q_stricmp( windowname, "workspace" ) )
  145. {
  146. SceneManager_LoadWindowPositions( proj, GetWorkspaceManager()->GetBrowser() );
  147. continue;
  148. }
  149. else if ( !Q_stricmp( windowname, "soundbrowser" ) )
  150. {
  151. SceneManager_LoadWindowPositions( proj, GetWorkspaceManager()->GetSoundBrowser() );
  152. continue;
  153. }
  154. else if ( !Q_stricmp( windowname, "wavebrowser" ) )
  155. {
  156. SceneManager_LoadWindowPositions( proj, GetWorkspaceManager()->GetWaveBrowser() );
  157. continue;
  158. }
  159. else if ( !Q_stricmp( windowname, "main" ) )
  160. {
  161. SceneManager_LoadWindowPositions( proj, GetWorkspaceManager() );
  162. continue;
  163. }
  164. else
  165. {
  166. Assert( 0 );
  167. }
  168. }
  169. Assert( 0 );
  170. }
  171. }
  172. kv->deleteThis();
  173. }
  174. static void SaveWindowPositions( CUtlBuffer& buf, char const *windowname, mxWindow *wnd )
  175. {
  176. buf.Printf( "\t\"window\"\n" );
  177. buf.Printf( "\t{\n" );
  178. buf.Printf( "\t\twindowname\t\"%s\"\n", windowname );
  179. SceneManager_SaveWindowPositions( buf, 2, wnd );
  180. buf.Printf( "\t}\n" );
  181. }
  182. void CWorkspace::SaveToFile()
  183. {
  184. SetDirty( false );
  185. CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
  186. buf.Printf( "%s\n{\n", GetName() );
  187. // walk projects
  188. int c = GetProjectCount();
  189. for ( int i = 0; i < c; i++ )
  190. {
  191. CProject *p = GetProject( i );
  192. Assert( p );
  193. buf.Printf( "\t\"project\"\n" );
  194. buf.Printf( "\t{\n" );
  195. buf.Printf( "\t\t\"expanded\"\t\"%i\"\n", p->IsExpanded() );
  196. buf.Printf( "\t\t\"file\"\t\"%s\"\n", p->GetFileName() );
  197. buf.Printf( "\t}\n" );
  198. p->SaveChanges();
  199. }
  200. buf.Printf( "\t\"vss_username\"\t\"%s\"\n", GetVSSUserName() );
  201. buf.Printf( "\t\"vss_project\"\t\"%s\"\n", GetVSSProject() );
  202. // Save window positions
  203. SaveWindowPositions( buf, "main", GetWorkspaceManager() );
  204. SaveWindowPositions( buf, "workspace", GetWorkspaceManager()->GetBrowser() );
  205. SaveWindowPositions( buf, "soundbrowser", GetWorkspaceManager()->GetSoundBrowser() );
  206. SaveWindowPositions( buf, "wavebrowser", GetWorkspaceManager()->GetWaveBrowser() );
  207. buf.Printf( "}\n" );
  208. if ( filesystem->FileExists( m_szFile ) && !filesystem->IsFileWritable( m_szFile ) )
  209. {
  210. int retval = mxMessageBox( NULL, va( "Check out '%s'?", m_szFile ), g_appTitle, MX_MB_YESNOCANCEL );
  211. if ( retval != 0 )
  212. return;
  213. VSS_Checkout( m_szFile );
  214. if ( !filesystem->IsFileWritable( m_szFile ) )
  215. {
  216. mxMessageBox( NULL, va( "Unable to check out'%s'!!!", m_szFile ), g_appTitle, MX_MB_OK );
  217. return;
  218. }
  219. }
  220. // Write it out baby
  221. FileHandle_t fh = filesystem->Open( m_szFile, "wt" );
  222. if (fh)
  223. {
  224. filesystem->Write( buf.Base(), buf.TellPut(), fh );
  225. filesystem->Close(fh);
  226. }
  227. else
  228. {
  229. Con_Printf( "CWorkspace::SaveToFile: Unable to write file %s!!!\n", m_szFile );
  230. }
  231. }
  232. void CWorkspace::SaveChanges()
  233. {
  234. if ( !IsDirty() )
  235. return;
  236. SaveToFile();
  237. }
  238. void CWorkspace::ValidateTree( mxTreeView *tree, mxTreeViewItem *parent )
  239. {
  240. CUtlVector< mxTreeViewItem * > m_KnownItems;
  241. int c = GetProjectCount();
  242. CProject *proj;
  243. for ( int i = 0; i < c; i++ )
  244. {
  245. proj = GetProject( i );
  246. if ( !proj )
  247. continue;
  248. char sz[ 256 ];
  249. if ( proj->GetComments() && proj->GetComments()[0] )
  250. {
  251. Q_snprintf( sz, sizeof( sz ), "%s : %s", proj->GetName(), proj->GetComments() );
  252. }
  253. else
  254. {
  255. Q_strncpy( sz, proj->GetName(), sizeof( sz ) );
  256. }
  257. mxTreeViewItem *spot = proj->FindItem( tree, parent );
  258. if ( !spot )
  259. {
  260. spot = tree->add( parent, sz );
  261. }
  262. m_KnownItems.AddToTail( spot );
  263. proj->SetOrdinal ( i );
  264. tree->setLabel( spot, sz );
  265. tree->setImages( spot, proj->GetIconIndex(), proj->GetIconIndex() );
  266. tree->setUserData( spot, proj );
  267. //tree->setOpen( spot, proj->IsExpanded() );
  268. proj->ValidateTree( tree, spot );
  269. }
  270. // Now check for dangling items
  271. mxTreeViewItem *start = tree->getFirstChild( parent );
  272. while ( start )
  273. {
  274. mxTreeViewItem *next = tree->getNextChild( start );
  275. if ( m_KnownItems.Find( start ) == m_KnownItems.InvalidIndex() )
  276. {
  277. tree->remove( start );
  278. }
  279. start = next;
  280. }
  281. tree->sortTree( parent, true, CWorkspaceBrowser::CompareFunc, 0 );
  282. }
  283. bool CWorkspace::CanClose( void )
  284. {
  285. if ( !IsDirty() )
  286. return true;
  287. int retval = mxMessageBox( NULL, va( "Save changes to workspace '%s'?", GetName() ), g_appTitle, MX_MB_YESNOCANCEL );
  288. if ( retval == 2 )
  289. return false;
  290. if ( retval == 0 )
  291. {
  292. SaveChanges();
  293. }
  294. return true;
  295. }
  296. char const *CWorkspace::GetVSSUserName() const
  297. {
  298. return m_szVSSUserName;
  299. }
  300. char const *CWorkspace::GetVSSProject() const
  301. {
  302. return m_szVSSProject;
  303. }
  304. void CWorkspace::SetVSSUserName( char const *username )
  305. {
  306. Q_strncpy( m_szVSSUserName, username, sizeof( m_szVSSUserName ) );
  307. }
  308. void CWorkspace::SetVSSProject( char const *projectname )
  309. {
  310. Q_strncpy( m_szVSSProject, projectname, sizeof( m_szVSSProject ) );
  311. while ( Q_strlen( m_szVSSProject ) > 0 )
  312. {
  313. if ( m_szVSSProject[ Q_strlen( m_szVSSProject ) - 1 ] == '/' ||
  314. m_szVSSProject[ Q_strlen( m_szVSSProject ) - 1 ] == '\\' )
  315. {
  316. m_szVSSProject[ Q_strlen( m_szVSSProject ) - 1 ] = 0;
  317. }
  318. else
  319. {
  320. break;
  321. }
  322. }
  323. }
  324. void CWorkspace::Checkout( bool updatestateicons /*= true*/ )
  325. {
  326. VSS_Checkout( GetFileName(), updatestateicons );
  327. }
  328. void CWorkspace::Checkin(bool updatestateicons /*= true*/)
  329. {
  330. VSS_Checkin( GetFileName(), updatestateicons );
  331. }
  332. bool CWorkspace::IsCheckedOut() const
  333. {
  334. return filesystem->IsFileWritable( GetFileName() );
  335. }
  336. int CWorkspace::GetIconIndex() const
  337. {
  338. if ( IsCheckedOut() )
  339. {
  340. return IMAGE_WORKSPACE_CHECKEDOUT;
  341. }
  342. else
  343. {
  344. return IMAGE_WORKSPACE;
  345. }
  346. }
  347. void CWorkspace::MoveChildUp( ITreeItem *child )
  348. {
  349. int c = GetProjectCount();
  350. for ( int i = 1; i < c; i++ )
  351. {
  352. CProject *p = GetProject( i );
  353. if ( p != child )
  354. continue;
  355. CProject *prev = GetProject( i - 1 );
  356. // Swap
  357. m_Projects[ i - 1 ] = p;
  358. m_Projects[ i ] = prev;
  359. return;
  360. }
  361. }
  362. void CWorkspace::MoveChildDown( ITreeItem *child )
  363. {
  364. int c = GetProjectCount();
  365. for ( int i = 0; i < c - 1; i++ )
  366. {
  367. CProject *p = GetProject( i );
  368. if ( p != child )
  369. continue;
  370. CProject *next = GetProject( i + 1 );
  371. // Swap
  372. m_Projects[ i ] = next;
  373. m_Projects[ i + 1 ] = p;
  374. return;
  375. }
  376. }
  377. bool CWorkspace::IsChildFirst( ITreeItem *child )
  378. {
  379. int idx = m_Projects.Find( (CProject *)child );
  380. if ( idx == m_Projects.InvalidIndex() )
  381. return false;
  382. if ( idx != 0 )
  383. return false;
  384. return true;
  385. }
  386. bool CWorkspace::IsChildLast( ITreeItem *child )
  387. {
  388. int idx = m_Projects.Find( (CProject *)child );
  389. if ( idx == m_Projects.InvalidIndex() )
  390. return false;
  391. if ( idx != m_Projects.Count() - 1 )
  392. return false;
  393. return true;
  394. }