/* Copyright (c) 2002-2012 Croteam Ltd. This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as published by the Free Software Foundation This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ // Browser.cpp : implementation file // #include "stdafx.h" #include "Browser.h" #ifdef _DEBUG #undef new #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif //////////////////////////////////////////////////////////////////// // CBrowser Construction/Destruction CBrowser::CBrowser(void) { // set default number of subdirectories (none) for( INDEX i=0; iMoveWindow( NewTreePos); m_boxBrowseWnd = PIXaabbox2D( PIX2D(NewBrowserPos.TopLeft().x, NewBrowserPos.TopLeft().y), PIX2D(NewBrowserPos.BottomRight().x, NewBrowserPos.BottomRight().y) ); m_BrowseWindow.m_BrowseWndWidth = NewBrowserPos.Width(); m_BrowseWindow.m_BrowseWndHeight = NewBrowserPos.Height(); m_boxTreeWnd = PIXaabbox2D( PIX2D(NewTreePos.TopLeft().x, NewTreePos.TopLeft().y), PIX2D(NewTreePos.BottomRight().x, NewTreePos.BottomRight().y) ); return csResult; } BEGIN_MESSAGE_MAP(CBrowser, CDialogBar) //{{AFX_MSG_MAP(CBrowser) ON_COMMAND(ID_CREATE_DIRECTORY, OnCreateDirectory) ON_COMMAND(ID_DELETE_DIRECTORY, OnDeleteDirectory) ON_COMMAND(ID_SAVE_VIRTUAL_TREE, OnSaveVirtualTree) ON_COMMAND(ID_LOAD_VIRTUAL_TREE, OnLoadVirtualTree) ON_COMMAND(ID_RENAME_DIRECTORY, OnRenameDirectory) ON_WM_CONTEXTMENU() ON_COMMAND(ID_SAVE_AS_VIRTUAL_TREE, OnSaveAsVirtualTree) ON_COMMAND(ID_IMPORT_VIRTUAL_TREE, OnImportVirtualTree) ON_COMMAND(ID_EXPORT_VIRTUAL_TREE, OnExportVirtualTree) ON_UPDATE_COMMAND_UI(ID_IMPORT_VIRTUAL_TREE, OnUpdateImportVirtualTree) ON_UPDATE_COMMAND_UI(ID_EXPORT_VIRTUAL_TREE, OnUpdateExportVirtualTree) ON_COMMAND(ID_DUMP_VT, OnDumpVt) //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////// // CBrowser message handlers ///////////////////////////////////////////////////////////////////// void CBrowser::AddDirectoryRecursiv(CVirtualTreeNode *pOneDirectory, HTREEITEM hParent) { // Insert one entry into virtual directory tree HTREEITEM InsertedDir; InsertedDir = m_TreeCtrl.InsertItem( 0, L"", 0, 0, TVIS_SELECTED, TVIF_STATE, 0, hParent, TVI_SORT ); pOneDirectory->vtn_Handle = (ULONG) InsertedDir; m_TreeCtrl.SetItemData( InsertedDir, (ULONG)(pOneDirectory)); m_TreeCtrl.SetItemText( InsertedDir, CString(pOneDirectory->vtn_strName)); m_TreeCtrl.SetItemImage( InsertedDir, pOneDirectory->vtn_itIconType, pOneDirectory->vtn_itIconType + NO_OF_ICONS); // Now add this directory's subdirectories recursively FOREACHINLIST( CVirtualTreeNode, vtn_lnInDirectory, pOneDirectory->vtn_lhChildren, it) { CVirtualTreeNode &vtn=*it; if( vtn.vtn_bIsDirectory) { AddDirectoryRecursiv( &vtn, InsertedDir); } } } void CBrowser::OnCreateDirectory() { CDlgCreateVirtualDirectory dlg; if( dlg.DoModal() == IDOK) { CloseSelectedDirectory(); CVirtualTreeNode *pvtnCurrent; // Is this root directory ? if( m_TreeCtrl.GetCount() == 0) { // Set data in instanciated CVirtualTreeNode because it is Root m_VirtualTree.vtn_bIsDirectory = TRUE; m_VirtualTree.vtn_itIconType = dlg.m_iSelectedIconType; m_VirtualTree.vtn_strName = CTString( CStringA(dlg.m_strDirectoryName)); // Root's parent is NULL m_VirtualTree.vnt_pvtnParent = NULL; pvtnCurrent = &m_VirtualTree; } else { // Allocate new CVirtualTreeNode to carry new directory data CVirtualTreeNode *pvtnNewDir = new CVirtualTreeNode(); pvtnCurrent = pvtnNewDir; pvtnNewDir->vtn_bIsDirectory = TRUE; pvtnNewDir->vtn_itIconType = dlg.m_iSelectedIconType; pvtnNewDir->vtn_strName = CTString( CStringA(dlg.m_strDirectoryName)); // Get ptr to parent CVirtualTreeNode HTREEITEM pSelectedItem = m_TreeCtrl.GetSelectedItem(); if( pSelectedItem == NULL) return; pvtnNewDir->vnt_pvtnParent = (CVirtualTreeNode *)m_TreeCtrl.GetItemData( pSelectedItem); // And add this new directory into its list pvtnNewDir->vnt_pvtnParent->vtn_lhChildren.AddTail( pvtnNewDir->vtn_lnInDirectory); } m_bVirtualTreeChanged = TRUE; m_TreeCtrl.DeleteAllItems(); AddDirectoryRecursiv( &m_VirtualTree, TVI_ROOT); // Fill CTreeCtrl using recursion m_TreeCtrl.SortChildren( NULL); // Now select it m_TreeCtrl.SelectItem( (HTREEITEM) pvtnCurrent->vtn_Handle); OpenSelectedDirectory(); } m_TreeCtrl.SetFocus(); } void CBrowser::OnUpdateVirtualTreeControl(void) { m_bVirtualTreeChanged = TRUE; m_TreeCtrl.DeleteAllItems(); AddDirectoryRecursiv( &m_VirtualTree, TVI_ROOT); m_TreeCtrl.SortChildren( NULL); // Now select it m_TreeCtrl.SelectItem( (HTREEITEM) m_VirtualTree.vtn_Handle); OpenSelectedDirectory(); m_TreeCtrl.SetFocus(); } void CBrowser::OnDeleteDirectory() { if( m_TreeCtrl.GetCount() == 0) return; if( ::MessageBoxA( this->m_hWnd, "Do You really want to delete directory and all its subdirectories?", "Warning !", MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON1 | MB_TASKMODAL | MB_TOPMOST) != IDYES) { m_TreeCtrl.SetFocus(); return; } CloseSelectedDirectory(); DeleteDirectory(); OpenSelectedDirectory(); } void CBrowser::DeleteDirectory(void) { if( m_TreeCtrl.GetCount() == 0) return; CVirtualTreeNode *pvtnParent = NULL; HTREEITEM pSelectedItem = m_TreeCtrl.GetSelectedItem(); if( pSelectedItem == NULL) return; CVirtualTreeNode *pVTN = (CVirtualTreeNode *)m_TreeCtrl.GetItemData( pSelectedItem); // Delete all subdirectories FORDELETELIST( CVirtualTreeNode, vtn_lnInDirectory, pVTN->vtn_lhChildren, litDel) { delete &litDel.Current(); } // If this is not root directory, remove it from list and delete it if( pVTN->vnt_pvtnParent != NULL) { pvtnParent = pVTN->vnt_pvtnParent; pVTN->vtn_lnInDirectory.Remove(); delete pVTN; } m_TreeCtrl.DeleteAllItems(); // If it wasn't root directory, fill TreeCtrl with data if( pvtnParent != NULL) { AddDirectoryRecursiv( &m_VirtualTree, TVI_ROOT); // Fill CTreeCtrl using recursion m_TreeCtrl.SortChildren( NULL); HTREEITEM NewActiveDir = (HTREEITEM) pvtnParent->vtn_Handle; if( m_TreeCtrl.ItemHasChildren(NewActiveDir) ) { NewActiveDir = m_TreeCtrl.GetChildItem( NewActiveDir); } m_TreeCtrl.SelectItem( NewActiveDir); } m_bVirtualTreeChanged = TRUE; m_TreeCtrl.SetFocus(); } CVirtualTreeNode *CBrowser::FindItemDirectory(CVirtualTreeNode *pvtnCurrentDirectory, CTFileName fnItemFileName) { // Now search this directory recursivly FOREACHINLIST( CVirtualTreeNode, vtn_lnInDirectory, pvtnCurrentDirectory->vtn_lhChildren, it) { if( it->vtn_bIsDirectory) { CVirtualTreeNode *pvtnResult = FindItemDirectory( &it.Current(), fnItemFileName); if( pvtnResult != NULL) return pvtnResult; } else { if( it->vtn_fnItem == fnItemFileName) { // deselect all items in directory FOREACHINLIST( CVirtualTreeNode, vtn_lnInDirectory, pvtnCurrentDirectory->vtn_lhChildren, it2) { it2->vtn_bSelected = FALSE; } // selected requested item it->vtn_bSelected = TRUE; return pvtnCurrentDirectory; } } } return NULL; } void CBrowser::SelectItemDirectory( CTFileName fnItemFileName) { CVirtualTreeNode *pvtnItemDirectory = FindItemDirectory( &m_VirtualTree, fnItemFileName); if( pvtnItemDirectory != NULL) { CloseSelectedDirectory(); // Now select it m_TreeCtrl.SelectItem( (HTREEITEM) pvtnItemDirectory->vtn_Handle); OpenSelectedDirectory(); } } /* * Separate subdirectory names along current path */ INDEX CBrowser::GetSelectedDirectory( CTString strArray[]) { INDEX iSubDirsCt = 0; HTREEITEM pItem = m_TreeCtrl.GetSelectedItem(); if( pItem == NULL) return -1; FOREVER { CTString strItemName = CTString( CStringA(m_TreeCtrl.GetItemText(pItem))); strArray[ iSubDirsCt] = strItemName; iSubDirsCt ++; if( m_TreeCtrl.GetParentItem(pItem) == NULL) break; pItem = m_TreeCtrl.GetParentItem(pItem); } return iSubDirsCt; } HTREEITEM CBrowser::GetVirtualDirectoryItem( CTString strArray[], INDEX iSubDirsCt) { INDEX j; // pick up root item ptr if path finding fails, it will be selected HTREEITEM pRootItem = m_TreeCtrl.GetRootItem(); HTREEITEM pItem = pRootItem; // loop all directories starting from root and search for selected subdirectory name for( j=iSubDirsCt-1; j>=0; j--) { BOOL bSucess; HTREEITEM pStartItem = pItem; FOREVER { if( pItem == NULL) { bSucess = FALSE; break; } // get current directory's (starting from root) first subdirectory CTString strItemName = CTString( CStringA(m_TreeCtrl.GetItemText(pItem))); // is this subdirectory's name same as one in list of selected along given path if( strArray[ j] == strItemName) { // subdirectory found, if it has children or selected subdirectories counter reached 0 if( m_TreeCtrl.ItemHasChildren( pItem) || (j==0) ) { // mark that we found current subdirectory bSucess = TRUE; // if counter didn't reached 0 if( j!=0) { // it becomes current and we will try to find his selected subdirectory pItem = m_TreeCtrl.GetChildItem( pItem); } break; } // we have no more children and counter is not 0 which means else { // that we didn't succeeded bSucess = FALSE; break; } } // this directory's name is not one we are searching for else { // so skip to next item in current directory pItem = m_TreeCtrl.GetNextItem( pItem, TVGN_NEXT); // if we have wrapped back to start of items list, we didn't find any dir with // selected name if( pStartItem == pItem) { // so we weren't successful bSucess = FALSE; break; } } } // directory search finished, if selected subdirectory wasn't found if( !bSucess) { // select root item pItem = pRootItem; // stop searching break; } } return pItem; } /* * Selects subdirectory using given path */ void CBrowser::SelectVirtualDirectory( CTString strArray[], INDEX iSubDirsCt) { // get virtual directory item HTREEITEM pItem = GetVirtualDirectoryItem( strArray, iSubDirsCt); // select last found directory m_TreeCtrl.SelectItem( pItem); // make it visible m_TreeCtrl.EnsureVisible( pItem); } CTFileName CBrowser::GetIOFileName(CTString strTitle, BOOL bSave) { // You can't save with no directories if( bSave && m_TreeCtrl.GetCount()==0) return CTString(""); CWorldEditorApp *pApp = (CWorldEditorApp *)AfxGetApp(); CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd()); char chrChoosedFileName[ 256]; OPENFILENAMEA ofnSaveVirtualTree; const char *pFilters = "Virtual tree files (*.vrt)\0*.vrt\0\0"; strcpy( chrChoosedFileName, pMainFrame->m_fnLastVirtualTree.FileName()); strcat( chrChoosedFileName, pMainFrame->m_fnLastVirtualTree.FileExt()); memset( &ofnSaveVirtualTree, 0, sizeof( OPENFILENAME)); ofnSaveVirtualTree.lStructSize = sizeof(OPENFILENAME); ofnSaveVirtualTree.lpstrFilter = pFilters; ofnSaveVirtualTree.lpstrFile = chrChoosedFileName; ofnSaveVirtualTree.nMaxFile = 256; char strInitDir[ 256]; strcpy( strInitDir, _fnmApplicationPath + pMainFrame->m_fnLastVirtualTree.FileDir()); ofnSaveVirtualTree.lpstrInitialDir = strInitDir; ofnSaveVirtualTree.lpstrTitle = strTitle; ofnSaveVirtualTree.Flags = OFN_EXPLORER | OFN_ENABLEHOOK; ofnSaveVirtualTree.lpstrDefExt = "vrt"; ofnSaveVirtualTree.hwndOwner = pMainFrame->m_hWnd; BOOL bResult=FALSE; if( bSave) { bResult=GetSaveFileNameA( &ofnSaveVirtualTree); } else { bResult=GetOpenFileNameA( &ofnSaveVirtualTree); } if( !bResult) { m_TreeCtrl.SetFocus(); return CTString(""); } CTFileName fnTree = CTString(chrChoosedFileName); try { fnTree.RemoveApplicationPath_t(); } catch( char *str_err) { AfxMessageBox( CString(str_err)); return CTString(""); } return fnTree; } void CBrowser::SaveVirtualTree(CTFileName fnSave, CVirtualTreeNode *pvtn) { ASSERT(pvtn!=NULL); if(pvtn==NULL) return; CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd()); CTFileStream File; try { File.Create_t( fnSave, CTStream::CM_BINARY); File.WriteID_t( CChunkID("VRTT")); File.WriteID_t( CChunkID(VIRTUAL_TREE_VERSION)); pvtn->Write_t( &File); // This will recursivly save tree beneath given tree node // Now we will try to save selected item's path File.WriteID_t( CChunkID("SELC")); // write ID of virtual tree buffer File.WriteID_t( CChunkID("VTBF")); // obtain selected directpry's path CTString strArray[ 32]; INDEX iSubDirsCt = GetSelectedDirectory( strArray); // write count of sub-directories File << iSubDirsCt; // write names of all subdirectories along path into file INDEX i=0; for( ; im_fnLastVirtualTree, &m_VirtualTree); } void CBrowser::OnSaveAsVirtualTree() { CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd()); CTFileName fnSave=GetIOFileName("Save virtual tree to file", TRUE); if( fnSave!="") { // remember choosed file name as last used pMainFrame->m_fnLastVirtualTree = fnSave; // save virtual tree SaveVirtualTree(fnSave, &m_VirtualTree); } } void CBrowser::OnLoadVirtualTree() { CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd()); if( m_bVirtualTreeChanged) { if( ::MessageBoxA( this->m_hWnd, "Current virtual directory not saved. Do You want to continue anyway?", "Warning !", MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON1 | MB_TASKMODAL | MB_TOPMOST) != IDYES) { m_TreeCtrl.SetFocus(); return; } } CTFileName fnOpen=GetIOFileName("Load virtual tree", FALSE); if( fnOpen!="") { // remember choosed file name as last used pMainFrame->m_fnLastVirtualTree = fnOpen; // open virtual tree branch OnLoadVirtualTreeInternal(fnOpen, NULL); } } void CBrowser::OnImportVirtualTree() { CTFileName fnImport=GetIOFileName("Import virtual tree", FALSE); if( fnImport!="") { HTREEITEM pSelectedItem = m_TreeCtrl.GetSelectedItem(); if( pSelectedItem == NULL) return; CVirtualTreeNode *pVTN = (CVirtualTreeNode *)m_TreeCtrl.GetItemData( pSelectedItem); // open virtual tree branch OnLoadVirtualTreeInternal(fnImport, pVTN); } } void CBrowser::OnExportVirtualTree() { HTREEITEM pSelectedItem = m_TreeCtrl.GetSelectedItem(); if( pSelectedItem == NULL) return; CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd()); CTFileName fnExport=GetIOFileName("Export virtual tree", TRUE); if( fnExport!="") { CVirtualTreeNode *pVTN = (CVirtualTreeNode *)m_TreeCtrl.GetItemData( pSelectedItem); // save virtual tree branch SaveVirtualTree(fnExport, pVTN); } } void CBrowser::OnUpdateImportVirtualTree(CCmdUI* pCmdUI) { HTREEITEM pSelectedItem = m_TreeCtrl.GetSelectedItem(); pCmdUI->Enable( pSelectedItem != NULL); } void CBrowser::OnUpdateExportVirtualTree(CCmdUI* pCmdUI) { HTREEITEM pSelectedItem = m_TreeCtrl.GetSelectedItem(); pCmdUI->Enable( pSelectedItem != NULL); } void CBrowser::OnLoadVirtualTreeInternal(CTFileName fnVirtulTree, CVirtualTreeNode *pvtnRoot) { CloseSelectedDirectory(); try { LoadVirtualTree_t( fnVirtulTree, pvtnRoot); } catch( char *strError) { AfxMessageBox( CString(strError)); FORDELETELIST( CVirtualTreeNode, vtn_lnInDirectory, m_VirtualTree.vtn_lhChildren, litDel) { delete &litDel.Current(); } return; } m_TreeCtrl.SetFocus(); m_bVirtualTreeChanged = FALSE; OpenSelectedDirectory(); } void CBrowser::LoadVirtualTree_t( CTFileName fnVirtulTree, CVirtualTreeNode *pvtnRoot) { if( pvtnRoot==NULL) { // If current tree is not empty, delete it if( m_TreeCtrl.GetCount() != 0) { FORDELETELIST( CVirtualTreeNode, vtn_lnInDirectory, m_VirtualTree.vtn_lhChildren, litDel) { delete &litDel.Current(); } m_TreeCtrl.SelectItem( m_TreeCtrl.GetRootItem()); DeleteDirectory(); } } CTFileStream File; File.Open_t( fnVirtulTree, CTStream::OM_READ); if( !(CChunkID("VRTT") == File.GetID_t())) { throw( "This is not valid virtual tree file"); } if( !(CChunkID(VIRTUAL_TREE_VERSION) == File.GetID_t())) { throw( "Invalid version of virtual tree file."); } if( pvtnRoot==NULL) { m_VirtualTree.Read_t( &File, NULL); } else { CVirtualTreeNode *pVTNNew = new CVirtualTreeNode; pVTNNew->Read_t( &File, pvtnRoot); } // delete all items m_TreeCtrl.DeleteAllItems(); AddDirectoryRecursiv( &m_VirtualTree, TVI_ROOT); // Fill CTreeCtrl using recursion if( pvtnRoot!=NULL) { // don't read rest of data File.Close(); return; } // Now we will try to load selected directory definition File.ExpectID_t( CChunkID("SELC")); // expect ID for virtual tree buffer File.ExpectID_t( CChunkID("VTBF")); INDEX iSubDirsCt; // read count of sub-directories File >> iSubDirsCt; // limited number of sub directories ASSERT( iSubDirsCt <= 32); // we will load selected directories from root up to finaly selected CTString strArray[ 32]; // load as many subdirectory names as count says INDEX i=0; for( ; i> strArray[ i]; } // try to select directory SelectVirtualDirectory( strArray, iSubDirsCt); // now read all four virtual tree buffers for( i=0; i> iSubDirsCt; // store it in array of counters m_aiSubDirectoriesCt[ i] = iSubDirsCt; // limited number of sub directories ASSERT( iSubDirsCt <= 32); // load as many subdirectory names as count says for( INDEX j=0; j> m_astrVTreeBuffer[i][j]; } } File.ExpectID_t( CChunkID("END_")); File.Close(); } void CBrowser::OnRenameDirectory() { if( m_TreeCtrl.GetCount() != 0) { HTREEITEM pSelectedItem = m_TreeCtrl.GetSelectedItem(); if( pSelectedItem == NULL) return; CVirtualTreeNode *pVTN = (CVirtualTreeNode *)m_TreeCtrl.GetItemData( pSelectedItem); CDlgCreateVirtualDirectory dlg( pVTN->vtn_strName, CTString("Rename virtual directory") ); if( dlg.DoModal() == IDOK) { pVTN->vtn_itIconType = dlg.m_iSelectedIconType; pVTN->vtn_strName = CTString( CStringA(dlg.m_strDirectoryName)); m_TreeCtrl.SetItemImage( pSelectedItem, pVTN->vtn_itIconType, pVTN->vtn_itIconType + NO_OF_ICONS); m_TreeCtrl.SetItemText( pSelectedItem, CString(pVTN->vtn_strName)); m_bVirtualTreeChanged = TRUE; } m_TreeCtrl.SetFocus(); } } void CBrowser::OnContextMenu(CWnd* pWnd, CPoint point) { CRect rectBrowser; GetWindowRect( &rectBrowser); CPoint ptInBrowser = CPoint( point.x - rectBrowser.TopLeft().x, point.y - rectBrowser.TopLeft().y); PIXaabbox2D boxPoint = PIXaabbox2D( PIX2D(ptInBrowser.x, ptInBrowser.y) ); if( (m_boxBrowseWnd & boxPoint) == boxPoint) { m_BrowseWindow.OnContextMenu( point); } else if( (m_boxTreeWnd & boxPoint) == boxPoint) { m_TreeCtrl.OnContextMenu( point); } } CVirtualTreeNode *CBrowser::GetSelectedDirectory(void) { if( m_TreeCtrl.GetCount() != 0) { HTREEITEM pSelectedItem = m_TreeCtrl.GetSelectedItem(); if( pSelectedItem!=NULL) { return (CVirtualTreeNode *)m_TreeCtrl.GetItemData( pSelectedItem); } } return NULL; } void CBrowser::OpenSelectedDirectory(void) { CVirtualTreeNode *pVTN = GetSelectedDirectory(); if( pVTN != NULL) { m_BrowseWindow.OpenDirectory( pVTN); } } void CBrowser::CloseSelectedDirectory(void) { CVirtualTreeNode *pVTN = GetSelectedDirectory(); if( pVTN != NULL) { m_BrowseWindow.CloseDirectory( pVTN); } } void CBrowser::OnDumpVt() { CTFileName fnName = _EngineGUI.FileRequester( "Dump virtual tree as ...", "Text file\0*.txt\0" FILTER_ALL FILTER_END, "Dump virtual tree directory", "VirtualTrees\\"); if( fnName == "") return; CTFileStream FileDump; try { FileDump.Create_t( fnName, CTStream::CM_TEXT); m_VirtualTree.Dump(&FileDump); FileDump.Close(); } catch( char *str_err) { AfxMessageBox( CString(str_err)); } }