Counter Strike : Global Offensive Source Code
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.

605 lines
16 KiB

  1. //===================== Copyright (c) Valve Corporation. All Rights Reserved. ======================
  2. //
  3. // Singleton dialog that generates and presents the entity report.
  4. //
  5. //==================================================================================================
  6. #include "stdafx.h"
  7. #include "EntityReportDlg.h"
  8. #include "fgdlib/GameData.h"
  9. #include "GlobalFunctions.h"
  10. #include "History.h"
  11. #include "MainFrm.h"
  12. #include "MapEntity.h"
  13. #include "MapInstance.h"
  14. #include "MapView2D.h"
  15. #include "MapWorld.h"
  16. #include "ObjectProperties.h"
  17. #include "hammer.h"
  18. // memdbgon must be the last include file in a .cpp file!!!
  19. #include <tier0/memdbgon.h>
  20. static CEntityReportDlg *s_pDlg = NULL;
  21. static char *pszIniSection = "EntityReportDlg";
  22. //-----------------------------------------------------------------------------
  23. // Purpose: Static function
  24. //-----------------------------------------------------------------------------
  25. void CEntityReportDlg::ShowEntityReport( CMapDoc *pDoc, CWnd *pwndParent, EntityReportFilterParms_t *pParms )
  26. {
  27. if (!s_pDlg)
  28. {
  29. s_pDlg = new CEntityReportDlg(pDoc, pwndParent);
  30. s_pDlg->Create(IDD, pwndParent);
  31. }
  32. if ( pParms )
  33. {
  34. s_pDlg->m_bFilterByKeyvalue = pParms->m_bFilterByKeyvalue;
  35. s_pDlg->m_bFilterByClass = pParms->m_bFilterByClass;
  36. s_pDlg->m_bFilterByHidden = pParms->m_bFilterByHidden;
  37. s_pDlg->m_bExact = pParms->m_bExact;
  38. s_pDlg->m_iFilterByType = pParms->m_nFilterByType;
  39. s_pDlg->m_szFilterKey.SetString( pParms->m_filterKey.Get() );
  40. s_pDlg->m_szFilterValue.SetString( pParms->m_filterValue.Get() );
  41. s_pDlg->m_szFilterClass.SetString( pParms->m_filterClass.Get() );
  42. s_pDlg->m_bGotoFirstMatch = true;
  43. s_pDlg->UpdateData( FALSE );
  44. }
  45. else
  46. {
  47. s_pDlg->m_bGotoFirstMatch = false;
  48. }
  49. s_pDlg->ShowWindow( SW_SHOW );
  50. s_pDlg->GenerateReport();
  51. }
  52. //-----------------------------------------------------------------------------
  53. // Purpose: Private constructor.
  54. //-----------------------------------------------------------------------------
  55. CEntityReportDlg::CEntityReportDlg(CMapDoc *pDoc, CWnd* pParent /*=NULL*/)
  56. : CDialog(CEntityReportDlg::IDD, pParent)
  57. {
  58. m_pDoc = pDoc;
  59. CWinApp *pApp = AfxGetApp();
  60. m_bFilterByKeyvalue = pApp->GetProfileInt(pszIniSection, "FilterByKeyvalue", FALSE);
  61. m_bFilterByClass = pApp->GetProfileInt(pszIniSection, "FilterByClass", FALSE);
  62. m_bFilterByHidden = pApp->GetProfileInt(pszIniSection, "FilterByHidden", TRUE);
  63. m_iFilterByType = pApp->GetProfileInt(pszIniSection, "FilterByType", 0);
  64. m_bExact = pApp->GetProfileInt(pszIniSection, "Exact", FALSE);
  65. m_szFilterClass = pApp->GetProfileString(pszIniSection, "FilterClass", "");
  66. m_szFilterKey = pApp->GetProfileString(pszIniSection, "FilterKey", "");
  67. m_szFilterValue = pApp->GetProfileString(pszIniSection, "FilterValue", "");
  68. m_bFilterTextChanged = false;
  69. m_bGotoFirstMatch = false;
  70. //{{AFX_DATA_INIT(CEntityReportDlg)
  71. //}}AFX_DATA_INIT
  72. }
  73. void CEntityReportDlg::SaveToIni()
  74. {
  75. CWinApp *pApp = AfxGetApp();
  76. pApp->WriteProfileInt(pszIniSection, "FilterByKeyvalue", m_bFilterByKeyvalue);
  77. pApp->WriteProfileInt(pszIniSection, "FilterByClass", m_bFilterByClass);
  78. pApp->WriteProfileInt(pszIniSection, "FilterByHidden", m_bFilterByHidden);
  79. pApp->WriteProfileInt(pszIniSection, "FilterByType", m_iFilterByType);
  80. pApp->WriteProfileInt(pszIniSection, "Exact", m_bExact);
  81. pApp->WriteProfileString(pszIniSection, "FilterClass", m_szFilterClass);
  82. pApp->WriteProfileString(pszIniSection, "FilterKey", m_szFilterKey);
  83. pApp->WriteProfileString(pszIniSection, "FilterValue", m_szFilterValue);
  84. }
  85. void CEntityReportDlg::DoDataExchange(CDataExchange* pDX)
  86. {
  87. CDialog::DoDataExchange(pDX);
  88. //{{AFX_DATA_MAP(CEntityReportDlg)
  89. DDX_Control(pDX, IDC_EXACTVALUE, m_cExact);
  90. DDX_Control(pDX, IDC_FILTERCLASS, m_cFilterClass);
  91. DDX_Control(pDX, IDC_FILTERBYCLASS, m_cFilterByClass);
  92. DDX_Control(pDX, IDC_ENTITIES, m_cEntities);
  93. DDX_Control(pDX, IDC_FILTERVALUE, m_cFilterValue);
  94. DDX_Control(pDX, IDC_FILTERKEY, m_cFilterKey);
  95. DDX_Control(pDX, IDC_FILTERBYTYPE, m_cFilterByType);
  96. DDX_Control(pDX, IDC_FILTERBYKEYVALUE, m_cFilterByKeyvalue);
  97. DDX_Control(pDX, IDC_FILTERBYHIDDEN, m_cFilterByHidden);
  98. //}}AFX_DATA_MAP
  99. DDX_Check(pDX, IDC_EXACTVALUE, m_bExact);
  100. DDX_Check(pDX, IDC_FILTERBYCLASS, m_bFilterByClass);
  101. DDX_Radio(pDX, IDC_FILTERBYTYPE, m_iFilterByType);
  102. DDX_Text(pDX, IDC_FILTERCLASS, m_szFilterClass);
  103. DDX_Text(pDX, IDC_FILTERVALUE, m_szFilterValue);
  104. DDX_Text(pDX, IDC_FILTERKEY, m_szFilterKey);
  105. DDX_Check(pDX, IDC_FILTERBYKEYVALUE, m_bFilterByKeyvalue);
  106. DDX_Check(pDX, IDC_FILTERBYHIDDEN, m_bFilterByHidden);
  107. }
  108. BEGIN_MESSAGE_MAP(CEntityReportDlg, CDialog)
  109. //{{AFX_MSG_MAP(CEntityReportDlg)
  110. ON_BN_CLICKED(IDC_DELETE, OnDelete)
  111. ON_BN_CLICKED(IDC_FILTERBYHIDDEN, OnFilterbyhidden)
  112. ON_BN_CLICKED(IDC_FILTERBYKEYVALUE, OnFilterbykeyvalue)
  113. ON_BN_CLICKED(IDC_FILTERBYTYPE, OnFilterbytype)
  114. ON_EN_CHANGE(IDC_FILTERKEY, OnChangeFilterkey)
  115. ON_EN_CHANGE(IDC_FILTERVALUE, OnChangeFiltervalue)
  116. ON_BN_CLICKED(IDC_GOTO, OnGoto)
  117. ON_BN_CLICKED(IDC_PROPERTIES, OnProperties)
  118. ON_WM_TIMER()
  119. ON_CBN_EDITCHANGE(IDC_FILTERCLASS, OnEditchangeFilterclass)
  120. ON_BN_CLICKED(IDC_FILTERBYCLASS, OnFilterbyclass)
  121. ON_CBN_SELCHANGE(IDC_FILTERCLASS, OnSelchangeFilterclass)
  122. ON_BN_CLICKED(IDC_RADIO2, OnFilterbytype)
  123. ON_BN_CLICKED(IDC_RADIO3, OnFilterbytype)
  124. ON_BN_CLICKED(IDC_EXACTVALUE, OnExactvalue)
  125. ON_LBN_SELCHANGE(IDC_ENTITIES, OnSelChangeEntityList)
  126. ON_LBN_DBLCLK(IDC_ENTITIES, OnDblClkEntityList)
  127. ON_WM_DESTROY()
  128. ON_WM_CLOSE()
  129. //}}AFX_MSG_MAP
  130. END_MESSAGE_MAP()
  131. //-----------------------------------------------------------------------------
  132. // Purpose: Deletes the marked objects.
  133. //-----------------------------------------------------------------------------
  134. void CEntityReportDlg::OnDelete(void)
  135. {
  136. if (AfxMessageBox("Delete Objects?", MB_YESNO) == IDNO)
  137. {
  138. return;
  139. }
  140. GetHistory()->MarkUndoPosition(NULL, "Delete Objects");
  141. int iSel = m_cEntities.GetCurSel();
  142. //
  143. // Build a list of objects to delete.
  144. //
  145. CMapObjectList Objects;
  146. for (int i = 0; i < m_cEntities.GetCount(); i++)
  147. {
  148. if (!m_cEntities.GetSel(i))
  149. {
  150. continue;
  151. }
  152. CMapEntity *pEntity = (CMapEntity *)m_cEntities.GetItemDataPtr(i);
  153. Objects.AddToTail(pEntity);
  154. m_cEntities.DeleteString(i);
  155. --i;
  156. }
  157. m_pDoc->DeleteObjectList(Objects);
  158. //
  159. // Update the list box selection.
  160. //
  161. if (iSel >= m_cEntities.GetCount())
  162. {
  163. iSel = m_cEntities.GetCount() - 1;
  164. }
  165. m_cEntities.SetCurSel(iSel);
  166. }
  167. void CEntityReportDlg::OnFilterbyhidden()
  168. {
  169. m_bFilterByHidden = m_cFilterByHidden.GetCheck();
  170. UpdateEntityList();
  171. }
  172. void CEntityReportDlg::OnFilterbykeyvalue()
  173. {
  174. m_bFilterByKeyvalue = m_cFilterByKeyvalue.GetCheck();
  175. UpdateEntityList();
  176. m_cFilterKey.EnableWindow(m_bFilterByKeyvalue);
  177. m_cFilterValue.EnableWindow(m_bFilterByKeyvalue);
  178. m_cExact.EnableWindow(m_bFilterByKeyvalue);
  179. }
  180. void CEntityReportDlg::OnFilterbytype()
  181. {
  182. // walk all children in group
  183. int iButton = 0;
  184. HWND hWndCtrl = ::GetDlgItem(m_hWnd, IDC_FILTERBYTYPE);
  185. do {
  186. // control in group is a radio button
  187. if(::SendMessage(hWndCtrl, BM_GETCHECK, 0, 0L) != 0)
  188. break;
  189. iButton++;
  190. hWndCtrl = ::GetWindow(hWndCtrl, GW_HWNDNEXT);
  191. } while(hWndCtrl != NULL && !(GetWindowLong(hWndCtrl, GWL_STYLE) & WS_GROUP));
  192. m_iFilterByType = iButton;
  193. UpdateEntityList();
  194. }
  195. void CEntityReportDlg::OnChangeFilterkey()
  196. {
  197. m_cFilterKey.GetWindowText(m_szFilterKey);
  198. m_szFilterKey.MakeUpper();
  199. m_dwFilterTime = time(NULL);
  200. m_bFilterTextChanged = true;
  201. }
  202. void CEntityReportDlg::OnChangeFiltervalue()
  203. {
  204. m_cFilterValue.GetWindowText(m_szFilterValue);
  205. m_szFilterValue.MakeUpper();
  206. m_dwFilterTime = time(NULL);
  207. m_bFilterTextChanged = true;
  208. }
  209. //-----------------------------------------------------------------------------
  210. // Purpose: Centers the 2D and 3D views on the selected entities.
  211. //-----------------------------------------------------------------------------
  212. void CEntityReportDlg::OnGoto()
  213. {
  214. CMapDoc *pMapDoc = MarkSelectedEntities();
  215. if ( pMapDoc )
  216. {
  217. pMapDoc->ShowWindow( true );
  218. pMapDoc->CenterViewsOnSelection();
  219. }
  220. }
  221. //-----------------------------------------------------------------------------
  222. // Purpose:
  223. //-----------------------------------------------------------------------------
  224. CMapDoc *CEntityReportDlg::MarkSelectedEntities()
  225. {
  226. CUtlVector< CMapDoc * > FoundMaps;
  227. for(int i = 0; i < m_cEntities.GetCount(); i++)
  228. {
  229. if(!m_cEntities.GetSel(i))
  230. continue;
  231. CMapEntity *pEntity = (CMapEntity*) m_cEntities.GetItemDataPtr(i);
  232. CMapClass *pTopMapClass = pEntity;
  233. while( pTopMapClass->GetParent() )
  234. {
  235. pTopMapClass = pTopMapClass->GetParent();
  236. }
  237. CMapWorld *pMapWorld = dynamic_cast< CMapWorld * >( pTopMapClass );
  238. if ( pMapWorld )
  239. {
  240. CMapDoc *pMapDoc = pMapWorld->GetOwningDocument();
  241. if ( FoundMaps.Find( pMapDoc ) == -1 )
  242. {
  243. FoundMaps.AddToTail( pMapDoc );
  244. pMapDoc->SelectObject( NULL, scClear|scSaveChanges );
  245. }
  246. pMapDoc->SelectObject( pEntity, scSelect );
  247. }
  248. }
  249. if ( FoundMaps.Count() == 1 )
  250. {
  251. return FoundMaps[ 0 ];
  252. }
  253. return NULL;
  254. }
  255. void CEntityReportDlg::OnProperties()
  256. {
  257. CMapDoc *pMapDoc = MarkSelectedEntities();
  258. if ( pMapDoc )
  259. {
  260. pMapDoc->ShowWindow( true );
  261. GetMainWnd()->pObjectProperties->ShowWindow(SW_SHOW);
  262. }
  263. }
  264. void CEntityReportDlg::OnTimer(UINT nIDEvent)
  265. {
  266. CDialog::OnTimer(nIDEvent);
  267. // check filters
  268. if(!m_bFilterTextChanged)
  269. return;
  270. if((time(NULL) - m_dwFilterTime) > 1)
  271. {
  272. m_bFilterTextChanged = false;
  273. m_dwFilterTime = time(NULL);
  274. UpdateEntityList();
  275. }
  276. }
  277. BOOL AddEntityToList(CMapEntity *pEntity, CEntityReportDlg *pDlg)
  278. {
  279. char szString[256];
  280. // nope.
  281. if (!pDlg->m_bFilterByHidden && !pEntity->IsVisible())
  282. {
  283. return TRUE;
  284. }
  285. /*
  286. if (!pDlg->m_pDoc->selection.IsEmpty() && !pEntity->IsSelected())
  287. {
  288. return TRUE;
  289. }
  290. */
  291. if (pDlg->m_iFilterByType)
  292. {
  293. if (pDlg->m_iFilterByType == 1 && pEntity->IsPlaceholder())
  294. {
  295. return TRUE;
  296. }
  297. if (pDlg->m_iFilterByType == 2 && !pEntity->IsPlaceholder())
  298. {
  299. return TRUE;
  300. }
  301. }
  302. const char* pszClassName = pEntity->GetClassName();
  303. if ( pEntity && stricmp( pszClassName, "func_instance" ) == 0 )
  304. {
  305. CMapInstance *pMapInstance = pEntity->GetChildOfType( ( CMapInstance * )NULL );
  306. if ( pMapInstance )
  307. {
  308. CMapDoc *pMapDoc = pMapInstance->GetInstancedMap();
  309. if ( pMapDoc )
  310. {
  311. CMapWorld *pWorld = pMapDoc->GetMapWorld();
  312. pWorld->EnumChildren(ENUMMAPCHILDRENPROC(AddEntityToList), DWORD(pDlg), MAPCLASS_TYPE(CMapEntity));
  313. }
  314. }
  315. }
  316. if (pDlg->m_bFilterByClass)
  317. {
  318. if (pDlg->m_szFilterClass.IsEmpty())
  319. {
  320. if (pszClassName[0])
  321. {
  322. return(TRUE);
  323. }
  324. }
  325. else
  326. {
  327. strcpy(szString, pEntity->GetClassName());
  328. strupr(szString);
  329. if (!strstr(szString, pDlg->m_szFilterClass))
  330. {
  331. return(TRUE);
  332. }
  333. }
  334. }
  335. strcpy(szString, pszClassName);
  336. // Append targetname in brackets, if applicable
  337. if ( pEntity->GetKeyValue("targetname") && strcmp(pEntity->GetKeyValue("targetname"), "(null)") )
  338. {
  339. sprintf(szString + strlen(szString), " (%s)", pEntity->GetKeyValue("targetname") );
  340. }
  341. BOOL bAdd = TRUE;
  342. if (pDlg->m_bFilterByKeyvalue)
  343. bAdd = FALSE;
  344. MDkeyvalue tmpkv;
  345. for (int i = pEntity->GetFirstKeyValue(); i != pEntity->GetInvalidKeyValue(); i=pEntity->GetNextKeyValue( i ) )
  346. {
  347. // if filtering by keyvalue, check!
  348. if (pDlg->m_bFilterByKeyvalue && !bAdd && !pDlg->m_szFilterValue.IsEmpty())
  349. {
  350. // first, check key
  351. if (pDlg->m_szFilterKey.IsEmpty() || !strcmpi(pDlg->m_szFilterKey, pEntity->GetKey(i)))
  352. {
  353. // now, check value
  354. char szTmp1[128], szTmp2[128];
  355. strcpy(szTmp1, pEntity->GetKeyValue(i));
  356. strupr(szTmp1);
  357. strcpy(szTmp2, pDlg->m_szFilterValue);
  358. if ((!pDlg->m_bExact && strstr(szTmp1, szTmp2)) || !strcmpi(szTmp1, szTmp2))
  359. {
  360. bAdd = TRUE;
  361. }
  362. }
  363. }
  364. GDclass *pClass = pEntity->GetClass();
  365. if (pClass != NULL)
  366. {
  367. GDinputvariable *pVar = pClass->VarForName(pEntity->GetKey(i));
  368. if (!pVar || !pVar->IsReportable())
  369. continue;
  370. }
  371. sprintf(szString + strlen(szString), "\t%s", pEntity->GetKeyValue(i));
  372. if (pClass == NULL)
  373. {
  374. break; // just do first if no class
  375. }
  376. }
  377. if (bAdd)
  378. {
  379. int iIndex = pDlg->m_cEntities.AddString(szString);
  380. pDlg->m_cEntities.SetItemDataPtr(iIndex, PVOID(pEntity));
  381. }
  382. return TRUE;
  383. }
  384. //-----------------------------------------------------------------------------
  385. // Purpose:
  386. //-----------------------------------------------------------------------------
  387. void CEntityReportDlg::UpdateEntityList(void)
  388. {
  389. m_bFilterTextChanged = false;
  390. m_cEntities.SetRedraw(FALSE);
  391. m_cEntities.ResetContent();
  392. int x = 80;
  393. m_cEntities.SetTabStops(x);
  394. m_szFilterValue.MakeUpper();
  395. m_szFilterKey.MakeUpper();
  396. m_szFilterClass.MakeUpper();
  397. // add items to list
  398. CMapWorld *pWorld = m_pDoc->GetMapWorld();
  399. pWorld->EnumChildren(ENUMMAPCHILDRENPROC(AddEntityToList), DWORD(this), MAPCLASS_TYPE(CMapEntity));
  400. m_cEntities.SetRedraw(TRUE);
  401. m_cEntities.Invalidate();
  402. }
  403. //-----------------------------------------------------------------------------
  404. // Purpose:
  405. //-----------------------------------------------------------------------------
  406. void CEntityReportDlg::GenerateReport()
  407. {
  408. CString str;
  409. int nCount = pGD->GetClassCount();
  410. for (int i = 0; i < nCount; i++)
  411. {
  412. GDclass *pc = pGD->GetClass(i);
  413. if(!pc->IsBaseClass())
  414. {
  415. str = pc->GetName();
  416. if(str != "worldspawn")
  417. m_cFilterClass.AddString(str);
  418. }
  419. }
  420. SetTimer(1, 500, NULL);
  421. OnFilterbykeyvalue();
  422. OnFilterbytype();
  423. OnFilterbyclass();
  424. if ( m_bGotoFirstMatch && m_cEntities.GetCount() )
  425. {
  426. // Select and go to first matching entity
  427. m_cEntities.SetSel( 0 );
  428. MarkSelectedEntities();
  429. OnGoto();
  430. }
  431. }
  432. void CEntityReportDlg::OnEditchangeFilterclass()
  433. {
  434. m_cFilterClass.GetWindowText(m_szFilterClass);
  435. m_szFilterClass.MakeUpper();
  436. m_dwFilterTime = time(NULL);
  437. m_bFilterTextChanged = true;
  438. }
  439. void CEntityReportDlg::OnFilterbyclass()
  440. {
  441. m_bFilterByClass = m_cFilterByClass.GetCheck();
  442. UpdateEntityList();
  443. m_cFilterClass.EnableWindow(m_bFilterByClass);
  444. }
  445. void CEntityReportDlg::OnSelchangeFilterclass()
  446. {
  447. int iSel = m_cFilterClass.GetCurSel();
  448. m_cFilterClass.GetLBText(iSel, m_szFilterClass);
  449. m_szFilterClass.MakeUpper();
  450. UpdateEntityList();
  451. }
  452. //-----------------------------------------------------------------------------
  453. // Purpose:
  454. //-----------------------------------------------------------------------------
  455. void CEntityReportDlg::OnSelChangeEntityList()
  456. {
  457. MarkSelectedEntities();
  458. }
  459. //-----------------------------------------------------------------------------
  460. // Purpose:
  461. //-----------------------------------------------------------------------------
  462. void CEntityReportDlg::OnDblClkEntityList()
  463. {
  464. CMapDoc *pMapDoc = MarkSelectedEntities();
  465. if ( pMapDoc )
  466. {
  467. pMapDoc->ShowWindow( true );
  468. pMapDoc->CenterViewsOnSelection();
  469. }
  470. }
  471. //-----------------------------------------------------------------------------
  472. // Purpose:
  473. //-----------------------------------------------------------------------------
  474. void CEntityReportDlg::OnExactvalue()
  475. {
  476. m_bExact = m_cExact.GetCheck();
  477. UpdateEntityList();
  478. }
  479. //-----------------------------------------------------------------------------
  480. // Purpose:
  481. //-----------------------------------------------------------------------------
  482. void CEntityReportDlg::OnOK()
  483. {
  484. DestroyWindow();
  485. }
  486. //-----------------------------------------------------------------------------
  487. // Purpose:
  488. //-----------------------------------------------------------------------------
  489. void CEntityReportDlg::OnClose()
  490. {
  491. DestroyWindow();
  492. }
  493. //-----------------------------------------------------------------------------
  494. // Purpose: Called when our window is being destroyed.
  495. //-----------------------------------------------------------------------------
  496. void CEntityReportDlg::OnDestroy()
  497. {
  498. SaveToIni();
  499. s_pDlg = NULL;
  500. delete this;
  501. }