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.

573 lines
14 KiB

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