summaryrefslogtreecommitdiff
path: root/hammer/SearchReplaceDlg.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /hammer/SearchReplaceDlg.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'hammer/SearchReplaceDlg.cpp')
-rw-r--r--hammer/SearchReplaceDlg.cpp599
1 files changed, 599 insertions, 0 deletions
diff --git a/hammer/SearchReplaceDlg.cpp b/hammer/SearchReplaceDlg.cpp
new file mode 100644
index 0000000..628bdc8
--- /dev/null
+++ b/hammer/SearchReplaceDlg.cpp
@@ -0,0 +1,599 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "stdafx.h"
+#include "History.h"
+#include "GlobalFunctions.h"
+#include "MapDoc.h"
+#include "MapWorld.h"
+#include "SearchReplaceDlg.h"
+#include "hammer.h"
+#include "Selection.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+
+//
+// Context data for a FindFirstObject/FindNextObject session.
+//
+struct FindObject_t
+{
+ //
+ // Where to look: in the world or in the selection set.
+ //
+ FindReplaceIn_t eFindIn;
+
+ CMapWorld *pWorld;
+ EnumChildrenPos_t WorldPos; // A position in the world tree for world searches.
+
+ CUtlVector<CMapClass *> SelectionList; // A copy of the selection list for selection only searches.
+ int nSelectionIndex; // The index into the selection list for iterating the selection list.
+
+ //
+ // What to look for.
+ //
+ CString strFindText;
+ bool bVisiblesOnly;
+ bool bCaseSensitive;
+ bool bWholeWord;
+};
+
+
+CMapClass *FindNextObject(FindObject_t &FindObject);
+bool FindCheck(CMapClass *pObject, FindObject_t &FindObject);
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns true if the string matches the search criteria, false if not.
+// Input : pszString - String to check.
+// FindObject - Search criteria, including string to search for.
+//-----------------------------------------------------------------------------
+bool MatchString(const char *pszString, FindObject_t &FindObject)
+{
+ if (FindObject.bWholeWord)
+ {
+ if (FindObject.bCaseSensitive)
+ {
+ return (!strcmp(pszString, FindObject.strFindText));
+ }
+
+ return (!stricmp(pszString, FindObject.strFindText));
+ }
+
+ if (FindObject.bCaseSensitive)
+ {
+ return (strstr(pszString, FindObject.strFindText) != NULL);
+ }
+
+ return (Q_stristr(pszString, FindObject.strFindText) != NULL);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns true if the string matches the search criteria, false if not.
+// Input : pszIn -
+// pszOut - String to check.
+// FindObject - Search criteria, including string to search for.
+//-----------------------------------------------------------------------------
+bool ReplaceString(char *pszOut, const char *pszIn, FindObject_t &FindObject, const char *pszReplace)
+{
+ //
+ // Whole matches are simple, just strcpy the replacement string into the out buffer.
+ //
+ if (FindObject.bWholeWord)
+ {
+ if (FindObject.bCaseSensitive && (!strcmp(pszIn, FindObject.strFindText)))
+ {
+ strcpy(pszOut, pszReplace);
+ return true;
+ }
+
+ if (!stricmp(pszIn, FindObject.strFindText))
+ {
+ strcpy(pszOut, pszReplace);
+ return true;
+ }
+ }
+
+ //
+ // Partial matches are a little tougher.
+ //
+ const char *pszStart = NULL;
+ if (FindObject.bCaseSensitive)
+ {
+ pszStart = strstr(pszIn, FindObject.strFindText);
+ }
+ else
+ {
+ pszStart = Q_stristr(pszIn, FindObject.strFindText);
+ }
+
+ if (pszStart != NULL)
+ {
+ int nOffset = pszStart - pszIn;
+
+ strncpy(pszOut, pszIn, nOffset);
+ pszOut += nOffset;
+ pszIn += nOffset + strlen(FindObject.strFindText);
+
+ strcpy(pszOut, pszReplace);
+ pszOut += strlen(pszReplace);
+
+ strcpy(pszOut, pszIn);
+
+ return true;
+ }
+
+ return false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Begins a Find or Find/Replace operation.
+//-----------------------------------------------------------------------------
+CMapClass *FindFirstObject(FindObject_t &FindObject)
+{
+ CMapClass *pObject = NULL;
+
+ if (FindObject.eFindIn == FindInWorld)
+ {
+ // Search the entire world.
+ pObject = FindObject.pWorld->GetFirstDescendent(FindObject.WorldPos);
+ }
+ else
+ {
+ // Search the selection only.
+ if (FindObject.SelectionList.Count())
+ {
+ pObject = FindObject.SelectionList.Element(0);
+ FindObject.nSelectionIndex = 1;
+ }
+ }
+
+ if (!pObject)
+ {
+ return NULL;
+ }
+
+ if (FindCheck(pObject, FindObject))
+ {
+ return pObject;
+ }
+
+ return FindNextObject(FindObject);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : pObject -
+//-----------------------------------------------------------------------------
+CMapClass *FindNextObject(FindObject_t &FindObject)
+{
+ while (true)
+ {
+ CMapClass *pObject = NULL;
+ if (FindObject.eFindIn == FindInWorld)
+ {
+ // Search the entire world.
+ pObject = FindObject.pWorld->GetNextDescendent(FindObject.WorldPos);
+ }
+ else
+ {
+ // Search the selection only.
+ if (FindObject.nSelectionIndex < FindObject.SelectionList.Count())
+ {
+ pObject = FindObject.SelectionList.Element(FindObject.nSelectionIndex);
+ FindObject.nSelectionIndex++;
+ }
+ }
+
+ if ((!pObject) || FindCheck(pObject, FindObject))
+ {
+ return pObject;
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : pObject -
+// FindObject -
+// Output : Returns true if the object matches the search criteria, false if not.
+//-----------------------------------------------------------------------------
+bool FindCheck(CMapClass *pObject, FindObject_t &FindObject)
+{
+ CMapEntity *pEntity = dynamic_cast <CMapEntity *>(pObject);
+ if (!pEntity)
+ {
+ return false;
+ }
+
+ if (FindObject.bVisiblesOnly && !pObject->IsVisible())
+ {
+ return false;
+ }
+
+ //
+ // Search keyvalues.
+ //
+ for ( int i=pEntity->GetFirstKeyValue(); i != pEntity->GetInvalidKeyValue(); i=pEntity->GetNextKeyValue( i ) )
+ {
+ const char *pszValue = pEntity->GetKeyValue(i);
+ if (pszValue && MatchString(pszValue, FindObject))
+ {
+ return true;
+ }
+ }
+
+ //
+ // Search connections.
+ //
+ int nConnCount = pEntity->Connections_GetCount();
+ for (int i = 0; i < nConnCount; i++)
+ {
+ CEntityConnection *pConn = pEntity->Connections_Get(i);
+ if (pConn)
+ {
+ if (MatchString(pConn->GetTargetName(), FindObject) ||
+ MatchString(pConn->GetParam(), FindObject))
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : pLastFound -
+// FindObject -
+// pszReplaceText -
+// Output : Returns the number of occurrences of the find text that were replaced.
+//-----------------------------------------------------------------------------
+int FindReplace(CMapEntity *pEntity, FindObject_t &FindObject, const char *pszReplace)
+{
+ int nReplacedCount = 0;
+
+ //
+ // Replace keyvalues.
+ //
+ for ( int i=pEntity->GetFirstKeyValue(); i != pEntity->GetInvalidKeyValue(); i=pEntity->GetNextKeyValue( i ) )
+ {
+ const char *pszValue = pEntity->GetKeyValue(i);
+ char szNewValue[MAX_PATH];
+ if (pszValue && ReplaceString(szNewValue, pszValue, FindObject, pszReplace))
+ {
+ const char *pszKey = pEntity->GetKey(i);
+ if (pszKey)
+ {
+ pEntity->SetKeyValue(pszKey, szNewValue);
+ nReplacedCount++;
+ }
+ }
+ }
+
+ //
+ // Replace connections.
+ //
+ int nConnCount = pEntity->Connections_GetCount();
+ for (int i = 0; i < nConnCount; i++)
+ {
+ CEntityConnection *pConn = pEntity->Connections_Get(i);
+ if (pConn)
+ {
+ char szNewValue[MAX_PATH];
+
+ if (ReplaceString(szNewValue, pConn->GetTargetName(), FindObject, pszReplace))
+ {
+ pConn->SetTargetName(szNewValue);
+ nReplacedCount++;
+ }
+
+ if (ReplaceString(szNewValue, pConn->GetParam(), FindObject, pszReplace))
+ {
+ pConn->SetParam(szNewValue);
+ nReplacedCount++;
+ }
+ }
+ }
+
+ return nReplacedCount;
+}
+
+
+BEGIN_MESSAGE_MAP(CSearchReplaceDlg, CDialog)
+ //{{AFX_MSG_MAP(CSearchReplaceDlg)
+ ON_WM_SHOWWINDOW()
+ ON_COMMAND_EX(IDC_FIND_NEXT, OnFindReplace)
+ ON_COMMAND_EX(IDC_REPLACE, OnFindReplace)
+ ON_COMMAND_EX(IDC_REPLACE_ALL, OnFindReplace)
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : pParent -
+//-----------------------------------------------------------------------------
+CSearchReplaceDlg::CSearchReplaceDlg(CWnd *pParent)
+ : CDialog(CSearchReplaceDlg::IDD, pParent)
+{
+ m_bNewSearch = true;
+
+ //{{AFX_DATA_INIT(CSearchReplaceDlg)
+ m_bVisiblesOnly = FALSE;
+ m_nFindIn = FindInWorld;
+ m_bWholeWord = FALSE;
+ m_bCaseSensitive = FALSE;
+ //}}AFX_DATA_INIT
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : Returns TRUE on success, FALSE on failure.
+//-----------------------------------------------------------------------------
+BOOL CSearchReplaceDlg::Create(CWnd *pwndParent)
+{
+ return CDialog::Create(CSearchReplaceDlg::IDD, pwndParent);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : pDX -
+//-----------------------------------------------------------------------------
+void CSearchReplaceDlg::DoDataExchange(CDataExchange* pDX)
+{
+ CDialog::DoDataExchange(pDX);
+
+ //{{AFX_DATA_MAP(CSearchReplaceDlg)
+ DDX_Check(pDX, IDC_VISIBLES_ONLY, m_bVisiblesOnly);
+ DDX_Check(pDX, IDC_WHOLE_WORD, m_bWholeWord);
+ DDX_Check(pDX, IDC_CASE_SENSITIVE, m_bCaseSensitive);
+ DDX_Text(pDX, IDC_FIND_TEXT, m_strFindText);
+ DDX_Text(pDX, IDC_REPLACE_TEXT, m_strReplaceText);
+ DDX_Radio(pDX, IDC_SELECTION, m_nFindIn);
+ //}}AFX_DATA_MAP
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CSearchReplaceDlg::OnCancel(void)
+{
+ ShowWindow(SW_HIDE);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Fill out the find criteria from the dialog controls.
+// Input : FindObject -
+//-----------------------------------------------------------------------------
+void CSearchReplaceDlg::GetFindCriteria(FindObject_t &FindObject, CMapDoc *pDoc)
+{
+ FindObject.pWorld = pDoc->GetMapWorld();
+
+ if (m_nFindIn == FindInSelection)
+ {
+ FindObject.eFindIn = FindInSelection;
+
+ FindObject.SelectionList.RemoveAll();
+
+ const CMapObjectList *pSelection = pDoc->GetSelection()->GetList();
+ for (int i = 0; i < pSelection->Count(); i++)
+ {
+ CMapClass *pObject = pSelection->Element(i);
+ if ( pObject->IsGroup() )
+ {
+ // If it's a group, get all the entities in the group.
+ const CMapObjectList *pChildren = pObject->GetChildren();
+ FOR_EACH_OBJ( *pChildren, pos )
+ {
+ FindObject.SelectionList.AddToTail( pChildren->Element(pos) );
+ }
+ }
+ else
+ {
+ FindObject.SelectionList.AddToTail(pObject);
+ }
+ }
+ }
+ else
+ {
+ FindObject.eFindIn = FindInWorld;
+ }
+
+ FindObject.strFindText = m_strFindText;
+ FindObject.bVisiblesOnly = (m_bVisiblesOnly == TRUE);
+ FindObject.bWholeWord = (m_bWholeWord == TRUE);
+ FindObject.bCaseSensitive = (m_bCaseSensitive == TRUE);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Called when they hit the Find, the Replace, or the Replace All button.
+// Input : uCmd - The ID of the button the user hit, IDC_FIND_NEXT or IDC_REPLACE.
+// Output : Returns TRUE to indicate that the message was handled.
+//-----------------------------------------------------------------------------
+BOOL CSearchReplaceDlg::OnFindReplace(UINT uCmd)
+{
+ CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
+ if (!pDoc)
+ {
+ return TRUE;
+ }
+
+ static FindObject_t FindObject;
+ static CMapClass *pLastFound = NULL;
+ static int nReplaceCount = 0;
+ FindObject_t TempFindObject;
+
+ bool bDone = false;
+
+ UpdateData();
+ GetFindCriteria(TempFindObject, pDoc);
+
+ if ( strcmp(TempFindObject.strFindText, FindObject.strFindText) != 0 )
+ {
+ m_bNewSearch = true;
+ }
+
+ do
+ {
+ CMapClass *pObject = NULL;
+
+ if (m_bNewSearch)
+ {
+ //
+ // New search. Fetch the data from the controls.
+ //
+ UpdateData();
+ GetFindCriteria(FindObject, pDoc);
+
+ //
+ // We have to keep track of the last object in the iteration for replacement,
+ // because replacement is done when me advance to the next object.
+ //
+ pLastFound = NULL;
+ nReplaceCount = 0;
+
+ pObject = FindFirstObject(FindObject);
+ }
+ else
+ {
+ pObject = FindNextObject(FindObject);
+ }
+
+ //
+ // Replace All is undone as single operation. Mark the undo position the first time
+ // we find a match during a Replace All.
+ //
+ if (m_bNewSearch && (uCmd == IDC_REPLACE_ALL) && pObject)
+ {
+ GetHistory()->MarkUndoPosition(pDoc->GetSelection()->GetList(), "Replace Text");
+ }
+
+ //
+ // If we have an object to do the replace on, do the replace.
+ //
+ if (pLastFound && ((uCmd == IDC_REPLACE) || (uCmd == IDC_REPLACE_ALL)))
+ {
+ if (uCmd == IDC_REPLACE)
+ {
+ // Allow for undo each time we do a Replace.
+ GetHistory()->MarkUndoPosition(NULL, "Replace Text");
+ }
+
+ //
+ // Do the replace on the last matching object we found. This lets the user see what
+ // object will be modified before it is done.
+ //
+ GetHistory()->Keep(pLastFound);
+ nReplaceCount += FindReplace((CMapEntity *)pLastFound, FindObject, m_strReplaceText);
+
+ GetDlgItem(IDCANCEL)->SetWindowText("Close");
+ }
+
+ if (pObject)
+ {
+ //
+ // We found an object that satisfies our search.
+ //
+ if ((uCmd == IDC_FIND_NEXT) || (uCmd == IDC_REPLACE))
+ {
+ //
+ // Highlight the match.
+ //
+ pDoc->SelectObject(pObject, scClear | scSelect);
+ pDoc->CenterViewsOnSelection();
+ }
+
+ //
+ // Stop after one match unless we are doing a Replace All.
+ //
+ if (uCmd != IDC_REPLACE_ALL)
+ {
+ bDone = true;
+ }
+
+ m_bNewSearch = false;
+ pLastFound = pObject;
+ }
+ else
+ {
+ //
+ // No more objects in the search set match our criteria.
+ //
+ if ((m_bNewSearch) || (uCmd != IDC_REPLACE_ALL))
+ {
+ CString str;
+ str.Format("Finished searching for '%s'.", m_strFindText.GetBuffer());
+ MessageBox(str, "Find/Replace Text", MB_OK);
+
+ // TODO: put the old selection back
+ }
+ else if (uCmd == IDC_REPLACE_ALL)
+ {
+ CString str;
+ str.Format("Replaced %d occurrences of the string '%s' with '%s'.", nReplaceCount, m_strFindText.GetBuffer(), m_strReplaceText.GetBuffer());
+ MessageBox(str, "Find/Replace Text", MB_OK);
+ }
+
+ m_bNewSearch = true;
+ bDone = true;
+ }
+
+ } while (!bDone);
+
+ return TRUE;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CSearchReplaceDlg::OnOK()
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Called any time we are hidden or shown.
+// Input : bShow -
+// nStatus -
+//-----------------------------------------------------------------------------
+void CSearchReplaceDlg::OnShowWindow(BOOL bShow, UINT nStatus)
+{
+ if (bShow)
+ {
+ m_bNewSearch = true;
+ GetDlgItem(IDCANCEL)->SetWindowText("Cancel");
+
+ m_nFindIn = FindInWorld;
+ CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
+ if (pDoc)
+ {
+ if ( !pDoc->GetSelection()->IsEmpty() )
+ {
+ m_nFindIn = FindInSelection;
+ }
+ }
+
+ // Populate the controls with the current data.
+ UpdateData(FALSE);
+ }
+
+ CDialog::OnShowWindow(bShow, nStatus);
+}