IncludeFilesDialog.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. /*
  2. ** Command & Conquer Renegade(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /***********************************************************************************************
  19. *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : LevelEdit *
  23. * *
  24. * $Archive:: /Commando/Code/Tools/LevelEdit/IncludeFilesDialog.cpp $Modtime:: $*
  25. * *
  26. * $Revision:: 3 $*
  27. * *
  28. *---------------------------------------------------------------------------------------------*
  29. * Functions: *
  30. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  31. #include "stdafx.h"
  32. #include "leveledit.h"
  33. #include "includefilesdialog.h"
  34. #include "filemgr.h"
  35. #include "icons.h"
  36. #include "utils.h"
  37. #ifdef _DEBUG
  38. #define new DEBUG_NEW
  39. #undef THIS_FILE
  40. static char THIS_FILE[] = __FILE__;
  41. #endif
  42. /////////////////////////////////////////////////////////////////////////////
  43. //
  44. // IncludeFilesDialogClass
  45. //
  46. IncludeFilesDialogClass::IncludeFilesDialogClass(CWnd* pParent /*=NULL*/)
  47. : m_hGlobalFolder (NULL),
  48. m_hLevelFolder (NULL),
  49. m_CurrentItem (NULL),
  50. CDialog(IncludeFilesDialogClass::IDD, pParent)
  51. {
  52. //{{AFX_DATA_INIT(IncludeFilesDialogClass)
  53. // NOTE: the ClassWizard will add member initialization here
  54. //}}AFX_DATA_INIT
  55. return ;
  56. }
  57. /////////////////////////////////////////////////////////////////////////////
  58. //
  59. // DoDataExchange
  60. //
  61. void
  62. IncludeFilesDialogClass::DoDataExchange (CDataExchange* pDX)
  63. {
  64. CDialog::DoDataExchange(pDX);
  65. //{{AFX_DATA_MAP(IncludeFilesDialogClass)
  66. DDX_Control(pDX, IDC_INCLUDE_TREE, m_IncludesTreeCtrl);
  67. //}}AFX_DATA_MAP
  68. return ;
  69. }
  70. BEGIN_MESSAGE_MAP(IncludeFilesDialogClass, CDialog)
  71. //{{AFX_MSG_MAP(IncludeFilesDialogClass)
  72. ON_NOTIFY(TVN_SELCHANGED, IDC_INCLUDE_TREE, OnSelchangedIncludeTree)
  73. ON_EN_CHANGE(IDC_SPEC_EDIT, OnChangeSpecEdit)
  74. ON_BN_CLICKED(IDC_ADD_REMOVE_BUTTON, OnAddRemoveButton)
  75. ON_WM_DESTROY()
  76. //}}AFX_MSG_MAP
  77. END_MESSAGE_MAP()
  78. /////////////////////////////////////////////////////////////////////////////
  79. //
  80. // OnInitDialog
  81. //
  82. BOOL
  83. IncludeFilesDialogClass::OnInitDialog (void)
  84. {
  85. // Allow the base class to process this message
  86. CDialog::OnInitDialog ();
  87. // Insert the 2 main folders into the tree control
  88. m_IncludesTreeCtrl.SetImageList (::Get_Global_Image_List (), TVSIL_NORMAL);
  89. m_hGlobalFolder = m_IncludesTreeCtrl.InsertItem ("Global", FOLDER_ICON, FOLDER_ICON);
  90. m_hLevelFolder = m_IncludesTreeCtrl.InsertItem ("Level Specific", FOLDER_ICON, FOLDER_ICON);
  91. // Ensure the file manager has the latest and greatest
  92. ::Get_File_Mgr ()->Build_Global_Include_List ();
  93. // Loop through all the global include files and add them to the tree control
  94. DynamicVectorClass<CString> &global_list = ::Get_File_Mgr ()->Get_Global_Include_File_List ();
  95. for (int index = 0; index < global_list.Count (); index ++) {
  96. int icon_index = (::strpbrk (global_list[index], "*?") != NULL) ? FILES_ICON : FILE_ICON;
  97. m_IncludesTreeCtrl.InsertItem (global_list[index], icon_index, icon_index, m_hGlobalFolder);
  98. }
  99. // Loop through all the level-specific include files and add them to the tree control
  100. DynamicVectorClass<CString> &level_list = ::Get_File_Mgr ()->Get_Include_File_List ();
  101. for (index = 0; index < level_list.Count (); index ++) {
  102. int icon_index = (::strpbrk (level_list[index], "*?") != NULL) ? FILES_ICON : FILE_ICON;
  103. m_IncludesTreeCtrl.InsertItem (level_list[index], icon_index, icon_index, m_hLevelFolder);
  104. }
  105. // Create the file picker control
  106. CRect rect;
  107. HWND hold_edit = ::GetDlgItem (m_hWnd, IDC_SPEC_EDIT);
  108. ::GetWindowRect (hold_edit, &rect);
  109. ScreenToClient (&rect);
  110. m_FilePicker.Create_Picker (WS_CHILD | WS_TABSTOP | WS_VISIBLE,
  111. rect,
  112. this,
  113. IDC_SPEC_EDIT);
  114. ::SetWindowPos (m_FilePicker, ::GetDlgItem (m_hWnd, IDC_SPEC_STATIC), 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOOWNERZORDER);
  115. ::DestroyWindow (hold_edit);
  116. // Ensure the file specs are sorted
  117. m_IncludesTreeCtrl.SortChildren (m_hGlobalFolder);
  118. m_IncludesTreeCtrl.SortChildren (m_hLevelFolder);
  119. m_IncludesTreeCtrl.SelectItem (m_hGlobalFolder);
  120. return TRUE;
  121. }
  122. /////////////////////////////////////////////////////////////////////////////
  123. //
  124. // OnOK
  125. //
  126. void
  127. IncludeFilesDialogClass::OnOK (void)
  128. {
  129. DynamicVectorClass<CString> &global_list = ::Get_File_Mgr ()->Get_Global_Include_File_List ();
  130. DynamicVectorClass<CString> &level_list = ::Get_File_Mgr ()->Get_Include_File_List ();
  131. global_list.Delete_All ();
  132. level_list.Delete_All ();
  133. // Loop through all the children of the global folder
  134. for (HTREEITEM hchild = m_IncludesTreeCtrl.GetChildItem (m_hGlobalFolder);
  135. hchild != NULL;
  136. hchild = m_IncludesTreeCtrl.GetNextSiblingItem (hchild)) {
  137. // Add this filespec to the global list
  138. CString child_text = m_IncludesTreeCtrl.GetItemText (hchild);
  139. global_list.Add (child_text);
  140. }
  141. // Loop through all the children of the level-specific folder
  142. for (hchild = m_IncludesTreeCtrl.GetChildItem (m_hLevelFolder);
  143. hchild != NULL;
  144. hchild = m_IncludesTreeCtrl.GetNextSiblingItem (hchild)) {
  145. // Add this filespec to the local list
  146. CString child_text = m_IncludesTreeCtrl.GetItemText (hchild);
  147. level_list.Add (child_text);
  148. }
  149. // Check the latest copy of the global include file list into the VSS
  150. ::Get_File_Mgr ()->Update_Global_Include_File_List ();
  151. // Allow the base class to process this message
  152. CDialog::OnOK ();
  153. return ;
  154. }
  155. /////////////////////////////////////////////////////////////////////////////
  156. //
  157. // OnSelchangedIncludeTree
  158. //
  159. void
  160. IncludeFilesDialogClass::OnSelchangedIncludeTree
  161. (
  162. NMHDR *pNMHDR,
  163. LRESULT *pResult
  164. )
  165. {
  166. NM_TREEVIEW *pNMTreeView = (NM_TREEVIEW *)pNMHDR;
  167. (*pResult) = 0;
  168. // Change the text in the edit control to reflect the new selection
  169. HTREEITEM hitem = m_IncludesTreeCtrl.GetSelectedItem ();
  170. if (m_IncludesTreeCtrl.GetParentItem (hitem) != NULL) {
  171. // Put the file spec into the edit control
  172. CString path = m_IncludesTreeCtrl.GetItemText (hitem);
  173. SetDlgItemText (IDC_SPEC_EDIT, path);
  174. SetDlgItemText (IDC_ADD_REMOVE_BUTTON, "&Remove");
  175. m_CurrentItem = hitem;
  176. // Let the file picker know the full path to the file
  177. path = ::Get_File_Mgr ()->Make_Full_Path (path);
  178. m_FilePicker.Set_Default_Filename (path);
  179. } else {
  180. //SetDlgItemText (IDC_SPEC_EDIT, "");
  181. SetDlgItemText (IDC_ADD_REMOVE_BUTTON, "&Add");
  182. m_CurrentItem = NULL;
  183. }
  184. // Ensure the 'add/remove' button is correctly enabled/disabled
  185. //::EnableWindow (::GetDlgItem (m_hWnd, IDC_ADD_REMOVE_BUTTON), enable_button);
  186. // Refresh the state of the 'add/remove' button
  187. //Update_Add_Remove_Button ();
  188. return ;
  189. }
  190. /////////////////////////////////////////////////////////////////////////////
  191. //
  192. // Update_Add_Remove_Button
  193. //
  194. void
  195. IncludeFilesDialogClass::Update_Add_Remove_Button (void)
  196. {
  197. CString filespec;
  198. GetDlgItemText (IDC_SPEC_EDIT, filespec);
  199. filespec = ::Get_File_Mgr ()->Make_Relative_Path (filespec);
  200. // Determine which item to use as a parent
  201. HTREEITEM hselected_item = m_IncludesTreeCtrl.GetSelectedItem ();
  202. HTREEITEM hroot = hselected_item;
  203. if (m_IncludesTreeCtrl.GetParentItem (hroot) != NULL) {
  204. hroot = m_IncludesTreeCtrl.GetParentItem (hroot);
  205. }
  206. // Change the button text if the entry was found or not
  207. m_CurrentItem = Find_Spec (filespec, hroot);
  208. if (m_CurrentItem != NULL) {
  209. SetDlgItemText (IDC_ADD_REMOVE_BUTTON, "&Remove");
  210. // Ensure this item is selected in the tree control as well
  211. if (hselected_item != m_CurrentItem) {
  212. m_IncludesTreeCtrl.SelectItem (m_CurrentItem);
  213. m_IncludesTreeCtrl.EnsureVisible (m_CurrentItem);
  214. }
  215. } else {
  216. SetDlgItemText (IDC_ADD_REMOVE_BUTTON, "&Add");
  217. }
  218. return ;
  219. }
  220. ////////////////////////////////////////////////////////////////////
  221. //
  222. // Find_Spec
  223. //
  224. HTREEITEM
  225. IncludeFilesDialogClass::Find_Spec
  226. (
  227. LPCTSTR filespec,
  228. HTREEITEM hroot
  229. )
  230. {
  231. HTREEITEM hitem = NULL;
  232. // Loop through all the children of the global folder
  233. for (HTREEITEM hchild = m_IncludesTreeCtrl.GetChildItem (hroot);
  234. (hchild != NULL) && (hitem == NULL);
  235. hchild = m_IncludesTreeCtrl.GetNextSiblingItem (hchild)) {
  236. // Is this the entry we are looking for?
  237. CString child_text = m_IncludesTreeCtrl.GetItemText (hchild);
  238. if (child_text.CompareNoCase (filespec) == 0) {
  239. hitem = hchild;
  240. }
  241. }
  242. // Return the tree item if we found the item
  243. return hitem;
  244. }
  245. ////////////////////////////////////////////////////////////////////
  246. //
  247. // OnChangeSpecEdit
  248. //
  249. void
  250. IncludeFilesDialogClass::OnChangeSpecEdit (void)
  251. {
  252. Update_Add_Remove_Button ();
  253. return ;
  254. }
  255. ////////////////////////////////////////////////////////////////////
  256. //
  257. // OnAddRemoveButton
  258. //
  259. void
  260. IncludeFilesDialogClass::OnAddRemoveButton (void)
  261. {
  262. // Are we adding or removing an entry from the tree control?
  263. if (m_CurrentItem != NULL) {
  264. HTREEITEM hnew_sel = m_IncludesTreeCtrl.GetPrevSiblingItem (m_CurrentItem);
  265. hnew_sel = (hnew_sel != NULL) ? hnew_sel : m_hGlobalFolder;
  266. m_IncludesTreeCtrl.DeleteItem (m_CurrentItem);
  267. m_IncludesTreeCtrl.SelectItem (hnew_sel);
  268. m_IncludesTreeCtrl.EnsureVisible (hnew_sel);
  269. } else {
  270. // Determine which item to use as a parent
  271. HTREEITEM hitem = m_IncludesTreeCtrl.GetSelectedItem ();
  272. if (m_IncludesTreeCtrl.GetParentItem (hitem) != NULL) {
  273. hitem = m_IncludesTreeCtrl.GetParentItem (hitem);
  274. }
  275. // Get the text the user entered
  276. CString filespec;
  277. GetDlgItemText (IDC_SPEC_EDIT, filespec);
  278. // Is the new path valid?
  279. bool rel_path = ::Is_Path_Relative (filespec);
  280. if ((rel_path == true) || ((rel_path == false) && ::Get_File_Mgr ()->Is_Path_Valid (filespec))) {
  281. // Add this entry to the tree control
  282. CString new_entry = ::Get_File_Mgr ()->Make_Relative_Path (filespec);
  283. int icon_index = (::strpbrk (new_entry, "*?") != NULL) ? FILES_ICON : FILE_ICON;
  284. HTREEITEM hnew_item = m_IncludesTreeCtrl.InsertItem (new_entry, icon_index, icon_index, hitem);
  285. // Now select this new item...
  286. m_IncludesTreeCtrl.SelectItem (hnew_item);
  287. m_IncludesTreeCtrl.EnsureVisible (hnew_item);
  288. } else {
  289. // Let the user know this path is invalid
  290. CString message;
  291. CString title;
  292. message.Format (IDS_INVALID_MODEL_PATH_MSG, (LPCTSTR)::Get_File_Mgr()->Get_Base_Path ());
  293. title.LoadString (IDS_INVALID_MODEL_PATH_TITLE);
  294. ::MessageBox (m_hWnd, message, title, MB_ICONERROR | MB_OK);
  295. }
  296. }
  297. // Ensure the file specs are sorted
  298. m_IncludesTreeCtrl.SortChildren (m_hGlobalFolder);
  299. m_IncludesTreeCtrl.SortChildren (m_hLevelFolder);
  300. return ;
  301. }
  302. ////////////////////////////////////////////////////////////////////
  303. //
  304. // OnDestroy
  305. //
  306. void
  307. IncludeFilesDialogClass::OnDestroy (void)
  308. {
  309. m_IncludesTreeCtrl.SetImageList (NULL, TVSIL_NORMAL);
  310. CDialog::OnDestroy();
  311. return ;
  312. }