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.

638 lines
18 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Singleton dialog that generates and presents the entity report.
  4. //
  5. //===========================================================================//
  6. #include "EntityReportPanel.h"
  7. #include "tier1/KeyValues.h"
  8. #include "tier1/utlbuffer.h"
  9. #include "iregistry.h"
  10. #include "vgui/ivgui.h"
  11. #include "vgui_controls/listpanel.h"
  12. #include "vgui_controls/textentry.h"
  13. #include "vgui_controls/checkbutton.h"
  14. #include "vgui_controls/combobox.h"
  15. #include "vgui_controls/radiobutton.h"
  16. #include "vgui_controls/messagebox.h"
  17. #include "dmevmfentity.h"
  18. #include "foundrydoc.h"
  19. #include "foundrytool.h"
  20. // memdbgon must be the last include file in a .cpp file!!!
  21. #include <tier0/memdbgon.h>
  22. using namespace vgui;
  23. //-----------------------------------------------------------------------------
  24. // Sort by target name
  25. //-----------------------------------------------------------------------------
  26. static int __cdecl TargetNameSortFunc( vgui::ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2 )
  27. {
  28. const char *string1 = item1.kv->GetString("targetname");
  29. const char *string2 = item2.kv->GetString("targetname");
  30. int nRetVal = Q_stricmp( string1, string2 );
  31. if ( nRetVal != 0 )
  32. return nRetVal;
  33. string1 = item1.kv->GetString("classname");
  34. string2 = item2.kv->GetString("classname");
  35. return Q_stricmp( string1, string2 );
  36. }
  37. //-----------------------------------------------------------------------------
  38. // Sort by class name
  39. //-----------------------------------------------------------------------------
  40. static int __cdecl ClassNameSortFunc( vgui::ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2 )
  41. {
  42. const char *string1 = item1.kv->GetString("classname");
  43. const char *string2 = item2.kv->GetString("classname");
  44. int nRetVal = Q_stricmp( string1, string2 );
  45. if ( nRetVal != 0 )
  46. return nRetVal;
  47. string1 = item1.kv->GetString("targetname");
  48. string2 = item2.kv->GetString("targetname");
  49. return Q_stricmp( string1, string2 );
  50. }
  51. //-----------------------------------------------------------------------------
  52. // Constructor
  53. //-----------------------------------------------------------------------------
  54. CEntityReportPanel::CEntityReportPanel( CFoundryDoc *pDoc, vgui::Panel* pParent, const char *pName )
  55. : BaseClass( pParent, pName ), m_pDoc( pDoc )
  56. {
  57. m_bSuppressEntityListUpdate = false;
  58. m_iFilterByType = FILTER_SHOW_EVERYTHING;
  59. m_bFilterByKeyvalue = false;
  60. m_bFilterByClass = false;
  61. m_bFilterByHidden = false;
  62. m_bFilterByKeyvalue = false;
  63. m_bExact = false;
  64. m_bFilterTextChanged = false;
  65. SetPaintBackgroundEnabled( true );
  66. m_pEntities = new vgui::ListPanel( this, "Entities" );
  67. m_pEntities->AddColumnHeader( 0, "targetname", "Name", 52, ListPanel::COLUMN_RESIZEWITHWINDOW );
  68. m_pEntities->AddColumnHeader( 1, "classname", "Class Name", 52, ListPanel::COLUMN_RESIZEWITHWINDOW );
  69. m_pEntities->SetColumnSortable( 0, true );
  70. m_pEntities->SetColumnSortable( 1, true );
  71. m_pEntities->SetEmptyListText( "No Entities" );
  72. // m_pEntities->SetDragEnabled( true );
  73. m_pEntities->AddActionSignalTarget( this );
  74. m_pEntities->SetSortFunc( 0, TargetNameSortFunc );
  75. m_pEntities->SetSortFunc( 1, ClassNameSortFunc );
  76. m_pEntities->SetSortColumn( 0 );
  77. // Filtering checkboxes
  78. m_pFilterByClass = new vgui::CheckButton( this, "ClassnameCheck", "" );
  79. m_pFilterByClass->AddActionSignalTarget( this );
  80. m_pFilterByKeyvalue = new vgui::CheckButton( this, "KeyvalueCheck", "" );
  81. m_pFilterByKeyvalue->AddActionSignalTarget( this );
  82. m_pFilterByHidden = new vgui::CheckButton( this, "HiddenCheck", "" );
  83. m_pFilterByHidden->AddActionSignalTarget( this );
  84. m_pExact = new vgui::CheckButton( this, "ExactCheck", "" );
  85. m_pExact->AddActionSignalTarget( this );
  86. // Filtering text entries
  87. m_pFilterKey = new vgui::TextEntry( this, "KeyTextEntry" );
  88. m_pFilterValue = new vgui::TextEntry( this, "ValueTextEntry" );
  89. // Classname combobox
  90. m_pFilterClass = new vgui::ComboBox( this, "ClassNameComboBox", 16, true );
  91. // Filter by type radio buttons
  92. m_pFilterEverything = new vgui::RadioButton( this, "EverythingRadio", "" );
  93. m_pFilterPointEntities = new vgui::RadioButton( this, "PointRadio", "" );
  94. m_pFilterBrushModels = new vgui::RadioButton( this, "BrushRadio", "" );
  95. LoadControlSettings( "resource/entityreportpanel.res" );
  96. ReadSettingsFromRegistry();
  97. // Used for updating filter while changing text
  98. ivgui()->AddTickSignal( GetVPanel(), 300 );
  99. }
  100. //-----------------------------------------------------------------------------
  101. // Reads settings from registry
  102. //-----------------------------------------------------------------------------
  103. void CEntityReportPanel::ReadSettingsFromRegistry()
  104. {
  105. m_bSuppressEntityListUpdate = true;
  106. const char *pKeyBase = g_pFoundryTool->GetRegistryName();
  107. m_pFilterByKeyvalue->SetSelected( registry->ReadInt(pKeyBase, "FilterByKeyvalue", 0) );
  108. m_pFilterByClass->SetSelected( registry->ReadInt(pKeyBase, "FilterByClass", 0) );
  109. m_pFilterByHidden->SetSelected( registry->ReadInt(pKeyBase, "FilterByHidden", 1) );
  110. m_pExact->SetSelected( registry->ReadInt(pKeyBase, "Exact", 0) );
  111. m_iFilterByType = (FilterType_t)registry->ReadInt(pKeyBase, "FilterByType", FILTER_SHOW_EVERYTHING);
  112. m_pFilterEverything->SetSelected( m_iFilterByType == FILTER_SHOW_EVERYTHING );
  113. m_pFilterPointEntities->SetSelected( m_iFilterByType == FILTER_SHOW_POINT_ENTITIES );
  114. m_pFilterBrushModels->SetSelected( m_iFilterByType == FILTER_SHOW_BRUSH_ENTITIES );
  115. // Gotta call change functions manually since SetText doesn't post an action signal
  116. const char *pValue = registry->ReadString( pKeyBase, "FilterClass", "" );
  117. m_pFilterClass->SetText( pValue );
  118. OnChangeFilterclass( pValue );
  119. pValue = registry->ReadString( pKeyBase, "FilterKey", "" );
  120. m_pFilterKey->SetText( pValue );
  121. OnChangeFilterkey( pValue );
  122. pValue = registry->ReadString( pKeyBase, "FilterValue", "" );
  123. m_pFilterValue->SetText( pValue );
  124. OnChangeFiltervalue( pValue );
  125. m_bSuppressEntityListUpdate = false;
  126. UpdateEntityList();
  127. }
  128. //-----------------------------------------------------------------------------
  129. // Writes settings to registry
  130. //-----------------------------------------------------------------------------
  131. void CEntityReportPanel::SaveSettingsToRegistry()
  132. {
  133. const char *pKeyBase = g_pFoundryTool->GetRegistryName();
  134. registry->WriteInt(pKeyBase, "FilterByKeyvalue", m_bFilterByKeyvalue);
  135. registry->WriteInt(pKeyBase, "FilterByClass", m_bFilterByClass);
  136. registry->WriteInt(pKeyBase, "FilterByHidden", m_bFilterByHidden);
  137. registry->WriteInt(pKeyBase, "FilterByType", m_iFilterByType);
  138. registry->WriteInt(pKeyBase, "Exact", m_bExact);
  139. registry->WriteString(pKeyBase, "FilterClass", m_szFilterClass);
  140. registry->WriteString(pKeyBase, "FilterKey", m_szFilterKey);
  141. registry->WriteString(pKeyBase, "FilterValue", m_szFilterValue);
  142. }
  143. //-----------------------------------------------------------------------------
  144. // Purpose: Shows the most recent selected object in properties window
  145. //-----------------------------------------------------------------------------
  146. void CEntityReportPanel::OnProperties(void)
  147. {
  148. int iSel = m_pEntities->GetSelectedItem( 0 );
  149. KeyValues *kv = m_pEntities->GetItem( iSel );
  150. CDmeVMFEntity *pEntity = (CDmeVMFEntity *)kv->GetPtr( "entity" );
  151. g_pFoundryTool->ShowEntityInEntityProperties( pEntity );
  152. }
  153. //-----------------------------------------------------------------------------
  154. // Purpose: Deletes the marked objects.
  155. //-----------------------------------------------------------------------------
  156. void CEntityReportPanel::OnDeleteEntities(void)
  157. {
  158. // This is undoable
  159. CAppUndoScopeGuard guard( NOTIFY_SETDIRTYFLAG, "Delete Entities", "Delete Entities" );
  160. int iSel = m_pEntities->GetSelectedItem( 0 );
  161. //
  162. // Build a list of objects to delete.
  163. //
  164. int nCount = m_pEntities->GetSelectedItemsCount();
  165. for (int i = 0; i < nCount; i++)
  166. {
  167. int nItemID = m_pEntities->GetSelectedItem(i);
  168. KeyValues *kv = m_pEntities->GetItem( nItemID );
  169. CDmeVMFEntity *pEntity = (CDmeVMFEntity *)kv->GetPtr( "entity" );
  170. if ( pEntity )
  171. {
  172. m_pDoc->DeleteEntity( pEntity );
  173. }
  174. }
  175. guard.Release();
  176. UpdateEntityList();
  177. // Update the list box selection.
  178. if (iSel >= m_pEntities->GetItemCount())
  179. {
  180. iSel = m_pEntities->GetItemCount() - 1;
  181. }
  182. m_pEntities->SetSingleSelectedItem( iSel );
  183. }
  184. //-----------------------------------------------------------------------------
  185. // Called when buttons are clicked
  186. //-----------------------------------------------------------------------------
  187. void CEntityReportPanel::OnCommand( const char *pCommand )
  188. {
  189. if ( !Q_stricmp( pCommand, "delete" ) )
  190. {
  191. // Confirm we want to do it
  192. MessageBox *pConfirm = new MessageBox( "#FoundryDeleteObjects", "#FoundryDeleteObjectsMsg", g_pFoundryTool->GetRootPanel() );
  193. pConfirm->AddActionSignalTarget( this );
  194. pConfirm->SetOKButtonText( "Yes" );
  195. pConfirm->SetCommand( new KeyValues( "DeleteEntities" ) );
  196. pConfirm->SetCancelButtonVisible( true );
  197. pConfirm->SetCancelButtonText( "No" );
  198. pConfirm->DoModal();
  199. return;
  200. }
  201. if ( !Q_stricmp( pCommand, "ShowProperties" ) )
  202. {
  203. OnProperties();
  204. return;
  205. }
  206. }
  207. //-----------------------------------------------------------------------------
  208. // Call this when our settings are dirty
  209. //-----------------------------------------------------------------------------
  210. void CEntityReportPanel::MarkDirty( bool bFilterDirty )
  211. {
  212. float flTime = Plat_FloatTime();
  213. m_bRegistrySettingsChanged = true;
  214. m_flRegistryTime = flTime;
  215. if ( bFilterDirty && !m_bFilterTextChanged )
  216. {
  217. m_bFilterTextChanged = true;
  218. m_flFilterTime = flTime;
  219. }
  220. }
  221. //-----------------------------------------------------------------------------
  222. // Methods related to filtering
  223. //-----------------------------------------------------------------------------
  224. void CEntityReportPanel::OnFilterByHidden( bool bState )
  225. {
  226. m_bFilterByHidden = bState;
  227. UpdateEntityList();
  228. MarkDirty( false );
  229. }
  230. void CEntityReportPanel::OnFilterByKeyvalue( bool bState )
  231. {
  232. m_bFilterByKeyvalue = bState;
  233. UpdateEntityList();
  234. MarkDirty( false );
  235. m_pFilterKey->SetEnabled( bState );
  236. m_pFilterValue->SetEnabled( bState );
  237. m_pExact->SetEnabled( bState );
  238. }
  239. void CEntityReportPanel::OnFilterKeyValueExact( bool bState )
  240. {
  241. m_bExact = bState;
  242. UpdateEntityList();
  243. MarkDirty( false );
  244. }
  245. void CEntityReportPanel::OnFilterByType( FilterType_t type )
  246. {
  247. m_iFilterByType = type;
  248. UpdateEntityList();
  249. MarkDirty( false );
  250. }
  251. void CEntityReportPanel::OnFilterByClass( bool bState )
  252. {
  253. m_bFilterByClass = bState;
  254. UpdateEntityList();
  255. MarkDirty( false );
  256. m_pFilterClass->SetEnabled( bState );
  257. }
  258. void CEntityReportPanel::OnChangeFilterkey( const char *pText )
  259. {
  260. m_szFilterKey = pText;
  261. MarkDirty( true );
  262. }
  263. void CEntityReportPanel::OnChangeFiltervalue( const char *pText )
  264. {
  265. m_szFilterValue = pText;
  266. MarkDirty( true );
  267. }
  268. void CEntityReportPanel::OnChangeFilterclass( const char *pText )
  269. {
  270. m_szFilterClass = pText;
  271. MarkDirty( true );
  272. }
  273. //-----------------------------------------------------------------------------
  274. // Deals with all check buttons
  275. //-----------------------------------------------------------------------------
  276. void CEntityReportPanel::OnTextChanged( KeyValues *kv )
  277. {
  278. TextEntry *pPanel = (TextEntry*)kv->GetPtr( "panel", NULL );
  279. int nLength = pPanel->GetTextLength();
  280. char *pBuf = (char*)_alloca( nLength + 1 );
  281. pPanel->GetText( pBuf, nLength+1 );
  282. if ( pPanel == m_pFilterClass )
  283. {
  284. OnChangeFilterclass( pBuf );
  285. return;
  286. }
  287. if ( pPanel == m_pFilterKey )
  288. {
  289. OnChangeFilterkey( pBuf );
  290. return;
  291. }
  292. if ( pPanel == m_pFilterValue )
  293. {
  294. OnChangeFiltervalue( pBuf );
  295. return;
  296. }
  297. }
  298. //-----------------------------------------------------------------------------
  299. // Deals with all check buttons
  300. //-----------------------------------------------------------------------------
  301. void CEntityReportPanel::OnButtonToggled( KeyValues *kv )
  302. {
  303. Panel *pPanel = (Panel*)kv->GetPtr( "panel", NULL );
  304. bool bState = kv->GetInt( "state", 0 ) != 0;
  305. if ( pPanel == m_pFilterByClass )
  306. {
  307. OnFilterByClass( bState );
  308. return;
  309. }
  310. if ( pPanel == m_pFilterByKeyvalue )
  311. {
  312. OnFilterByKeyvalue( bState );
  313. return;
  314. }
  315. if ( pPanel == m_pFilterByHidden )
  316. {
  317. OnFilterByHidden( bState );
  318. return;
  319. }
  320. if ( pPanel == m_pExact )
  321. {
  322. OnFilterKeyValueExact( bState );
  323. return;
  324. }
  325. if ( pPanel == m_pFilterEverything )
  326. {
  327. OnFilterByType( FILTER_SHOW_EVERYTHING );
  328. return;
  329. }
  330. if ( pPanel == m_pFilterPointEntities )
  331. {
  332. OnFilterByType( FILTER_SHOW_POINT_ENTITIES );
  333. return;
  334. }
  335. if ( pPanel == m_pFilterBrushModels )
  336. {
  337. OnFilterByType( FILTER_SHOW_BRUSH_ENTITIES );
  338. return;
  339. }
  340. }
  341. //-----------------------------------------------------------------------------
  342. // FIXME: Necessary because SetSelected doesn't cause a ButtonToggled message to trigger
  343. //-----------------------------------------------------------------------------
  344. void CEntityReportPanel::OnCheckButtonChecked( KeyValues *kv )
  345. {
  346. OnButtonToggled( kv );
  347. }
  348. void CEntityReportPanel::OnRadioButtonChecked( KeyValues *kv )
  349. {
  350. OnButtonToggled( kv );
  351. }
  352. #if 0
  353. //-----------------------------------------------------------------------------
  354. // Purpose: Centers the 2D and 3D views on the selected entities.
  355. //-----------------------------------------------------------------------------
  356. void CEntityReportPanel::OnGoto()
  357. {
  358. MarkSelectedEntities();
  359. m_pDoc->CenterViewsOnSelection();
  360. }
  361. //-----------------------------------------------------------------------------
  362. // Purpose:
  363. //-----------------------------------------------------------------------------
  364. void CEntityReportPanel::MarkSelectedEntities()
  365. {
  366. m_pDoc->SelectObject(NULL, CMapDoc::scClear);
  367. for(int i = 0; i < m_cEntities.GetCount(); i++)
  368. {
  369. if(!m_cEntities.GetSel(i))
  370. continue;
  371. CMapEntity *pEntity = (CMapEntity*) m_cEntities.GetItemDataPtr(i);
  372. m_pDoc->SelectObject(pEntity, CMapDoc::scSelect);
  373. }
  374. m_pDoc->SelectObject(NULL, CMapDoc::scUpdateDisplay);
  375. }
  376. #endif
  377. void CEntityReportPanel::OnTick( )
  378. {
  379. BaseClass::OnTick();
  380. // check filters
  381. float flTime = Plat_FloatTime();
  382. if ( m_bFilterTextChanged )
  383. {
  384. if ( (flTime - m_flFilterTime) > 1e-3 )
  385. {
  386. m_bFilterTextChanged = false;
  387. m_flFilterTime = flTime;
  388. UpdateEntityList();
  389. }
  390. }
  391. if ( m_bRegistrySettingsChanged )
  392. {
  393. if ( (flTime - m_flRegistryTime) > 1e-3 )
  394. {
  395. m_bRegistrySettingsChanged = false;
  396. m_flRegistryTime = flTime;
  397. SaveSettingsToRegistry();
  398. }
  399. }
  400. }
  401. bool CEntityReportPanel::ShouldAddEntityToList( CDmeVMFEntity *pEntity )
  402. {
  403. // nope.
  404. if ( !m_bFilterByHidden && !pEntity->IsVisible() )
  405. return false;
  406. /*
  407. if (!pDlg->m_pDoc->selection.IsEmpty() && !pEntity->IsSelected())
  408. return true;
  409. */
  410. if ( m_iFilterByType == FILTER_SHOW_POINT_ENTITIES && pEntity->IsPlaceholder() )
  411. return false;
  412. if ( m_iFilterByType == FILTER_SHOW_BRUSH_ENTITIES && !pEntity->IsPlaceholder() )
  413. return false;
  414. const char* pClassName = pEntity->GetClassName();
  415. if ( m_bFilterByClass )
  416. {
  417. if ( !m_szFilterClass.IsEmpty() )
  418. {
  419. if ( !Q_stristr( pClassName, m_szFilterClass ) )
  420. return false;
  421. }
  422. }
  423. if ( !m_bFilterByKeyvalue || m_szFilterValue.IsEmpty() )
  424. return true;
  425. CUtlBuffer buf( 256, 0, CUtlBuffer::TEXT_BUFFER );
  426. for ( CDmAttribute *pKey = pEntity->FirstEntityKey(); pKey; pKey = pEntity->NextEntityKey( pKey ) )
  427. {
  428. // first, check key
  429. if ( m_szFilterKey.IsEmpty() || !Q_stricmp( m_szFilterKey, pKey->GetName() ) )
  430. {
  431. // now, check value (as a string)
  432. buf.Clear();
  433. pKey->Serialize( buf );
  434. const char *pValue = (const char*)buf.Base();
  435. if ( (!m_bExact && Q_stristr( pValue, m_szFilterValue ) ) || !Q_stricmp( pValue, m_szFilterValue ) )
  436. return true;
  437. }
  438. }
  439. return false;
  440. }
  441. //-----------------------------------------------------------------------------
  442. // Purpose:
  443. //-----------------------------------------------------------------------------
  444. void CEntityReportPanel::UpdateEntityList(void)
  445. {
  446. if ( m_bSuppressEntityListUpdate )
  447. return;
  448. m_bFilterTextChanged = false;
  449. m_pEntities->RemoveAll();
  450. const CDmrElementArray<CDmElement> entityList( m_pDoc->GetEntityList() );
  451. int nCount = entityList.Count();
  452. for ( int i = 0; i < nCount; ++i )
  453. {
  454. CDmeVMFEntity *pEntity = CastElement<CDmeVMFEntity>( entityList[i] );
  455. if ( ShouldAddEntityToList( pEntity ) )
  456. {
  457. const char *pClassName = pEntity->GetClassName( );
  458. const char *pTargetName = pEntity->GetTargetName( );
  459. if ( !pTargetName || !pTargetName[0] )
  460. {
  461. pTargetName = "<no name>";
  462. }
  463. if ( !pClassName || !pClassName[0] )
  464. {
  465. pClassName = "<no class>";
  466. }
  467. KeyValues *kv = new KeyValues( "node", "targetname", pTargetName );
  468. kv->SetString( "classname", pClassName );
  469. kv->SetPtr( "entity", pEntity );
  470. m_pEntities->AddItem( kv, 0, false, false );
  471. }
  472. }
  473. m_pEntities->SortList();
  474. }
  475. #if 0
  476. //-----------------------------------------------------------------------------
  477. // Purpose:
  478. //-----------------------------------------------------------------------------
  479. void CEntityReportPanel::GenerateReport()
  480. {
  481. POSITION p = pGD->Classes.GetHeadPosition();
  482. CString str;
  483. while(p)
  484. {
  485. GDclass *pc = pGD->Classes.GetNext(p);
  486. if(!pc->IsBaseClass())
  487. {
  488. str = pc->GetName();
  489. if(str != "worldspawn")
  490. m_cFilterClass.AddString(str);
  491. }
  492. }
  493. SetTimer(1, 500, NULL);
  494. OnFilterbykeyvalue();
  495. OnFilterbytype();
  496. OnFilterbyclass();
  497. }
  498. //-----------------------------------------------------------------------------
  499. // Purpose:
  500. //-----------------------------------------------------------------------------
  501. void CEntityReportPanel::OnSelChangeEntityList()
  502. {
  503. MarkSelectedEntities();
  504. }
  505. //-----------------------------------------------------------------------------
  506. // Purpose:
  507. //-----------------------------------------------------------------------------
  508. void CEntityReportPanel::OnDblClkEntityList()
  509. {
  510. m_pDoc->CenterViewsOnSelection();
  511. }
  512. //-----------------------------------------------------------------------------
  513. // Purpose:
  514. //-----------------------------------------------------------------------------
  515. void CEntityReportPanel::OnOK()
  516. {
  517. DestroyWindow();
  518. }
  519. //-----------------------------------------------------------------------------
  520. // Purpose:
  521. //-----------------------------------------------------------------------------
  522. void CEntityReportPanel::OnClose()
  523. {
  524. DestroyWindow();
  525. }
  526. //-----------------------------------------------------------------------------
  527. // Purpose: Called when our window is being destroyed.
  528. //-----------------------------------------------------------------------------
  529. void CEntityReportPanel::OnDestroy()
  530. {
  531. SaveToIni();
  532. s_pDlg = NULL;
  533. delete this;
  534. }
  535. #endif