/SgaReader2/frmFileStoreViewer.cpp

http://modstudio2.googlecode.com/ · C++ · 603 lines · 515 code · 61 blank · 27 comment · 68 complexity · 76b7f16f1517394ae6080f1e02b1e027 MD5 · raw file

  1. /*
  2. Copyright (c) 2009 Peter "Corsix" Cawley
  3. Permission is hereby granted, free of charge, to any person
  4. obtaining a copy of this software and associated documentation
  5. files (the "Software"), to deal in the Software without
  6. restriction, including without limitation the rights to use,
  7. copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. copies of the Software, and to permit persons to whom the
  9. Software is furnished to do so, subject to the following
  10. conditions:
  11. The above copyright notice and this permission notice shall be
  12. included in all copies or substantial portions of the Software.
  13. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  14. EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  15. OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  16. NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  17. HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  18. WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  20. OTHER DEALINGS IN THE SOFTWARE.
  21. */
  22. #include "application.h"
  23. #include "frmFileStoreViewer.h"
  24. #include "frmExtract.h"
  25. #include <wx/datetime.h>
  26. #include <wx/display.h>
  27. #include <wx/filedlg.h>
  28. #include <wx/filename.h>
  29. #include <wx/menu.h>
  30. #include <wx/mimetype.h>
  31. #include <wx/msgdlg.h>
  32. #include <wx/sizer.h>
  33. #include <wx/splitter.h>
  34. #include <memory>
  35. BEGIN_EVENT_TABLE(frmFileStoreViewer, wxFrame)
  36. EVT_CLOSE ( frmFileStoreViewer::onCloseSelf )
  37. EVT_LIST_ITEM_ACTIVATED(LST_DETAILS, frmFileStoreViewer::onFileDoAction )
  38. EVT_MENU (wxID_OPEN , frmFileStoreViewer::onOpen )
  39. EVT_MENU (MNU_OPEN_FS, frmFileStoreViewer::onOpenFileSystem)
  40. EVT_MENU (wxID_EXIT , frmFileStoreViewer::onExit )
  41. EVT_MENU (wxID_ABOUT , frmFileStoreViewer::onAbout )
  42. EVT_SIZE ( frmFileStoreViewer::onResize )
  43. EVT_TREE_ITEM_EXPANDING(TREE_FILES , frmFileStoreViewer::onTreeExpanding )
  44. EVT_TREE_SEL_CHANGED (TREE_FILES , frmFileStoreViewer::onTreeSelection )
  45. END_EVENT_TABLE()
  46. class SGATreeData : public wxTreeItemData
  47. {
  48. public:
  49. SGATreeData(const RainString& sPath, bool bLoaded = false)
  50. : m_sPath(sPath), m_bLoaded(bLoaded)
  51. {
  52. }
  53. const RainString& getPath() const {return m_sPath;}
  54. bool isLoaded() const {return m_bLoaded;}
  55. void setLoaded(bool bLoaded = true) {m_bLoaded = bLoaded;}
  56. protected:
  57. RainString m_sPath;
  58. bool m_bLoaded;
  59. };
  60. frmFileStoreViewer::frmFileStoreViewer(const wxString& sTitle)
  61. : wxFrame(NULL, wxID_ANY, sTitle)
  62. , m_pArchive(0)
  63. , m_pAttribPreviewWindow(0)
  64. , m_sBaseTitle(sTitle)
  65. {
  66. m_sDateFormat = TheConfig[L"Dates"][L"Format"].value();
  67. if(m_sDateFormat.IsEmpty())
  68. {
  69. m_sDateFormat = L"%d/%m/%Y %H:%M:%S";
  70. }
  71. {
  72. m_pIcons = new wxImageList(16, 16);
  73. wxBitmap oIcons(L"IDB_ICONS", wxBITMAP_TYPE_BMP_RESOURCE);
  74. for(int x = 0; x < oIcons.GetWidth(); x += 16)
  75. {
  76. m_pIcons->Add(oIcons.GetSubBitmap(wxRect(x, 0, 16, 16)), wxColour(255, 0, 255));
  77. }
  78. }
  79. wxSizer *pMainSizer = new wxBoxSizer(wxVERTICAL);
  80. CreateStatusBar()->SetStatusText(L"Ready");
  81. wxMenuBar *pMenuBar = new wxMenuBar;
  82. {
  83. wxMenu *pFileMenu = new wxMenu;
  84. pMenuBar->Append(pFileMenu, L"&File");
  85. pFileMenu->Append(wxID_OPEN, wxEmptyString, L"Opens an SGA archive for browsing");
  86. pFileMenu->Append(MNU_OPEN_FS, L"Open filesystem", L"Opens your computer\'s file-system for browsing");
  87. pFileMenu->AppendSeparator();
  88. IniFile::Section& oRecent = TheConfig[L"Recent"];
  89. if(!oRecent.empty())
  90. {
  91. int i = 1;
  92. for(IniFile::Section::iterator itr = oRecent.begin(), itrEnd = oRecent.end(); itr != itrEnd && i <= 5; ++itr, ++i)
  93. {
  94. pFileMenu->Append(wxID_FILE1 - 1 + i, RainString().printf(L"%i ", i) + itr->value(), RainString(L"Opens ") + itr->value());
  95. }
  96. pFileMenu->AppendSeparator();
  97. }
  98. pFileMenu->Append(wxID_EXIT, wxEmptyString, L"Closes the application");
  99. }
  100. {
  101. wxMenu *pHelpMenu = new wxMenu;
  102. pMenuBar->Append(pHelpMenu, L"&Help");
  103. pHelpMenu->Append(wxID_ABOUT, wxEmptyString, L"Shows details about the application");
  104. }
  105. SetMenuBar(pMenuBar);
  106. wxSplitterWindow *pSplitter = new wxSplitterWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSP_3D | wxSP_LIVE_UPDATE);
  107. wxPanel *pRightPanel = new wxPanel(pSplitter);
  108. m_pFilesTree = new wxTreeCtrl(pSplitter, TREE_FILES, wxDefaultPosition, wxDefaultSize, wxBORDER_SUNKEN | wxTR_HAS_BUTTONS | wxTR_HIDE_ROOT | wxTR_SINGLE | wxTR_LINES_AT_ROOT);
  109. m_pFilesTree->SetImageList(m_pIcons);
  110. m_pDetailsView = new wxListCtrl(pRightPanel, LST_DETAILS, wxDefaultPosition, wxDefaultSize, wxBORDER_SUNKEN | wxLC_REPORT | /*wxLC_VIRTUAL |*/ wxLC_SINGLE_SEL);
  111. m_pDetailsView->SetImageList(m_pIcons, wxIMAGE_LIST_SMALL);
  112. m_pDetailsView->InsertColumn(0, L"Name");
  113. m_pDetailsView->InsertColumn(1, L"Date modified");
  114. m_pDetailsView->InsertColumn(2, L"Type");
  115. m_pDetailsView->InsertColumn(3, L"Size");
  116. for(int i = 0; i < 4; ++i)
  117. {
  118. m_pDetailsView->SetColumnWidth(i, wxLIST_AUTOSIZE_USEHEADER);
  119. }
  120. m_pDetailsView->SetColumnWidth(0, m_pDetailsView->GetColumnWidth(0) * 5);
  121. m_pDetailsView->SetColumnWidth(1, m_pDetailsView->GetColumnWidth(1) * 3 / 2);
  122. m_pDetailsView->SetColumnWidth(2, m_pDetailsView->GetColumnWidth(2) * 3);
  123. m_pDetailsView->SetColumnWidth(3, m_pDetailsView->GetColumnWidth(3) * 3);
  124. wxString aActions[] = {
  125. L"Navigate",
  126. L"Extract",
  127. #ifdef RAINMAN2_USE_RBF
  128. L"Preview",
  129. #endif
  130. };
  131. wxSizer *pRightSizer = new wxBoxSizer(wxVERTICAL);
  132. wxSizer *pDefaultActionSizer = new wxBoxSizer(wxHORIZONTAL);
  133. pDefaultActionSizer->Add(new wxStaticText(pRightPanel, wxID_ANY, L"Default directory action:"), 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
  134. pDefaultActionSizer->Add(m_pDirectoryDefaultActionList = new wxChoice(pRightPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, 2, aActions), 0, wxALL | wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, 2);
  135. m_pDirectoryDefaultActionList->SetSelection(0);
  136. pDefaultActionSizer->AddStretchSpacer(1);
  137. pDefaultActionSizer->Add(new wxStaticText(pRightPanel, wxID_ANY, L"Default file action:"), 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
  138. pDefaultActionSizer->Add(m_pFileDefaultActionList = new wxChoice(pRightPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, sizeof(aActions) / sizeof(*aActions) - 1, aActions + 1), 0, wxALL | wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, 2);
  139. m_pFileDefaultActionList->SetSelection(0);
  140. pDefaultActionSizer->AddStretchSpacer(1);
  141. pRightSizer->Add(pDefaultActionSizer, 0, wxEXPAND);
  142. pRightSizer->Add(m_pDetailsView, 1, wxEXPAND);
  143. pRightSizer->SetSizeHints(pRightPanel);
  144. pRightPanel->SetSizer(pRightSizer);
  145. pSplitter->SplitVertically(m_pFilesTree, pRightPanel, 260);
  146. pMainSizer->Add(pSplitter, 1, wxALL | wxEXPAND, 0);
  147. pMainSizer->SetSizeHints(this);
  148. SetSizer(pMainSizer);
  149. {
  150. wxRect rcScreen = wxDisplay(wxDisplay::GetFromPoint(GetPosition())).GetClientArea();
  151. int iWidth = (rcScreen.width * 3) / 4;
  152. int iHeight = (rcScreen.height * 3) / 4;
  153. SetSize(rcScreen.x + (rcScreen.width - iWidth) / 2, rcScreen.y + (rcScreen.height - iHeight) / 2, iWidth, iHeight);
  154. }
  155. Layout();
  156. // Automated testing
  157. //_doLoadArchive(L"E:\\Valve\\Steam\\SteamApps\\common\\warhammer 40,000 dawn of war ii - beta\\GameAssets\\Archives\\gameattrib.sga", AT_SGA);
  158. //m_pFileDefaultActionList->SetSelection(1);
  159. }
  160. frmFileStoreViewer::~frmFileStoreViewer()
  161. {
  162. _closeCurrentArchive();
  163. delete m_pIcons;
  164. TheConfig["Dates"]["Format"] = m_sDateFormat;
  165. }
  166. void frmFileStoreViewer::onExit(wxCommandEvent &e)
  167. {
  168. Close();
  169. }
  170. void frmFileStoreViewer::onOpen(wxCommandEvent &e)
  171. {
  172. wxFileDialog oFileSelector(this, wxFileSelectorPromptStr, wxEmptyString, wxEmptyString, wxEmptyString, wxFD_OPEN | wxFD_FILE_MUST_EXIST | wxFD_CHANGE_DIR);
  173. oFileSelector.SetMessage(L"Choose an archive");
  174. oFileSelector.SetWildcard(
  175. L"Relic game archives (*.sga;*.spk)|*.sga;*.spk|"
  176. L"SGA archives (*.sga)|*.sga|"
  177. L"SPK archives (*.spk)|*.spk|"
  178. L"All files (*.*)|*.*"
  179. );
  180. oFileSelector.SetFilterIndex(0);
  181. if(oFileSelector.ShowModal() == wxID_CANCEL)
  182. return;
  183. else
  184. {
  185. switch(oFileSelector.GetFilterIndex())
  186. {
  187. case 0: // SGA / SPK
  188. if(oFileSelector.GetFilename().AfterLast('.').CompareTo(L"sga", wxString::ignoreCase) == 0)
  189. {
  190. case 1: // SGA
  191. _doLoadArchive(oFileSelector.GetPath(), AT_SGA);
  192. break;
  193. }
  194. else
  195. {
  196. case 2: // SPK
  197. _doLoadArchive(oFileSelector.GetPath(), AT_SPK);
  198. break;
  199. }
  200. case 3: // *
  201. {
  202. IFile *pFile = RainOpenFileNoThrow(oFileSelector.GetPath(), FM_Read);
  203. if(SpkArchive::doesFileResemble(pFile))
  204. {
  205. delete pFile; pFile = 0;
  206. _doLoadArchive(oFileSelector.GetPath(), AT_SPK);
  207. }
  208. else
  209. {
  210. delete pFile; pFile = 0;
  211. _doLoadArchive(oFileSelector.GetPath(), AT_SGA);
  212. }
  213. break;
  214. }
  215. }
  216. }
  217. }
  218. void frmFileStoreViewer::onFileDoAction(wxListEvent &e)
  219. {
  220. long iIndex = e.GetIndex();
  221. if(iIndex < 0 || iIndex >= m_pDetailsView->GetItemCount() || !m_oCurrentFolderId.IsOk())
  222. return;
  223. SGATreeData *pFolderData = reinterpret_cast<SGATreeData*>(m_pFilesTree->GetItemData(m_oCurrentFolderId));
  224. switch(m_pDetailsView->GetItemData(iIndex))
  225. {
  226. case 0: // up
  227. {
  228. wxTreeItemId oParent = m_pFilesTree->GetItemParent(m_oCurrentFolderId);
  229. if(oParent.IsOk())
  230. {
  231. m_pFilesTree->SelectItem(oParent);
  232. m_pFilesTree->SetFocus();
  233. }
  234. break;
  235. }
  236. case 1: // folder
  237. if(m_pDirectoryDefaultActionList->GetSelection() == 0)
  238. {
  239. if(!m_pFilesTree->IsExpanded(m_oCurrentFolderId))
  240. m_pFilesTree->Expand(m_oCurrentFolderId);
  241. wxTreeItemIdValue oCookie;
  242. wxTreeItemId oChild = m_pFilesTree->GetFirstChild(m_oCurrentFolderId, oCookie);
  243. wxString sLookingFor = m_pDetailsView->GetItemText(iIndex);
  244. while(oChild.IsOk())
  245. {
  246. if(m_pFilesTree->GetItemText(oChild) == sLookingFor)
  247. {
  248. m_pFilesTree->SelectItem(oChild);
  249. m_pFilesTree->SetFocus();
  250. break;
  251. }
  252. oChild = m_pFilesTree->GetNextChild(m_oCurrentFolderId, oCookie);
  253. }
  254. }
  255. else
  256. {
  257. frmExtract oExtractor(this, m_pArchive, m_sCurrentArchivePath, pFolderData->getPath() + L"\\" + RainString(m_pDetailsView->GetItemText(iIndex)), GetStatusBar());
  258. oExtractor.ShowModal();
  259. }
  260. break;
  261. case 2: // file
  262. if(m_pFileDefaultActionList->GetSelection() == 0)
  263. {
  264. frmExtract oExtractor(this, m_pArchive, m_sCurrentArchivePath, pFolderData->getPath() + L"\\" + RainString(m_pDetailsView->GetItemText(iIndex)), GetStatusBar());
  265. oExtractor.ShowModal();
  266. }
  267. #ifdef RAINMAN2_USE_RBF
  268. else
  269. {
  270. if(m_pAttribPreviewWindow == 0)
  271. {
  272. m_pAttribPreviewWindow = new frmAttribPreview;
  273. m_pAttribPreviewWindow->setFileStore(m_pArchive);
  274. m_pAttribPreviewWindow->Connect(wxID_ANY, wxEVT_CLOSE_WINDOW, wxCloseEventHandler(frmFileStoreViewer::onClosePreviewWindow), 0, this);
  275. m_pAttribPreviewWindow->Show();
  276. }
  277. try
  278. {
  279. m_pAttribPreviewWindow->loadFile(pFolderData->getPath() + L"\\" + RainString(m_pDetailsView->GetItemText(iIndex)));
  280. }
  281. CATCH_MESSAGE_BOX(L"Error loading file", {});
  282. m_pAttribPreviewWindow->SetFocus();
  283. }
  284. #endif
  285. break;
  286. }
  287. }
  288. void frmFileStoreViewer::onCloseSelf(wxCloseEvent &e)
  289. {
  290. if(m_pAttribPreviewWindow)
  291. m_pAttribPreviewWindow->Disconnect(wxID_ANY, wxEVT_CLOSE_WINDOW);
  292. Destroy();
  293. }
  294. void frmFileStoreViewer::onClosePreviewWindow(wxCloseEvent &e)
  295. {
  296. m_pAttribPreviewWindow->Destroy();
  297. m_pAttribPreviewWindow = 0;
  298. }
  299. void frmFileStoreViewer::_closeCurrentArchive()
  300. {
  301. if(m_pArchive)
  302. {
  303. GetStatusBar()->SetStatusText(L"Closing " + m_sCurrentShortName + L"...");
  304. delete m_pArchive;
  305. m_pArchive = 0;
  306. }
  307. m_oCurrentFolderId = wxTreeItemId();
  308. m_pFilesTree->DeleteAllItems();
  309. m_pDetailsView->DeleteAllItems();
  310. m_sCurrentShortName.clear();
  311. m_sCurrentArchivePath.clear();
  312. SetTitle(m_sBaseTitle);
  313. }
  314. void frmFileStoreViewer::onOpenFileSystem(wxCommandEvent &e)
  315. {
  316. _closeCurrentArchive();
  317. m_sCurrentShortName = L"file system";
  318. m_sCurrentArchivePath.clear();
  319. GetStatusBar()->SetStatusText(L"Loading " + m_sCurrentShortName + L"...");
  320. try
  321. {
  322. CHECK_ALLOCATION(m_pArchive = new (std::nothrow) FileSystemStore);
  323. }
  324. CATCH_MESSAGE_BOX_1(L"Unable to open %s", m_sCurrentShortName.c_str(), {
  325. _closeCurrentArchive();
  326. return;
  327. });
  328. _onLoadedArchive();
  329. GetStatusBar()->SetStatusText(L"Loaded " + m_sCurrentShortName + wxString::Format(L", %lu drives found", static_cast<unsigned long>(m_pArchive->getEntryPointCount())));
  330. }
  331. void frmFileStoreViewer::_doLoadArchive(wxString sPath, eArchiveTypes eArchiveType)
  332. {
  333. _closeCurrentArchive();
  334. wxFileName oFileName(sPath);
  335. m_sCurrentShortName = oFileName.GetFullName();
  336. m_sCurrentArchivePath = RainString(oFileName.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR));
  337. GetStatusBar()->SetStatusText(L"Loading " + m_sCurrentShortName + L"...");
  338. IArchiveFileStore *pArchive = 0;
  339. try
  340. {
  341. switch(eArchiveType)
  342. {
  343. case AT_SGA:
  344. CHECK_ALLOCATION(pArchive = new (std::nothrow) SgaArchive);
  345. break;
  346. case AT_SPK:
  347. CHECK_ALLOCATION(pArchive = new (std::nothrow) SpkArchive);
  348. break;
  349. default:
  350. THROW_SIMPLE(L"Unknown archive type");
  351. };
  352. m_pArchive = pArchive;
  353. pArchive->init(RainOpenFile(sPath, FM_Read));
  354. }
  355. CATCH_MESSAGE_BOX_1(L"Unable to open archive file \'%s\'", sPath.c_str(), {
  356. _closeCurrentArchive();
  357. return;
  358. });
  359. _onLoadedArchive();
  360. if(pArchive->getEntryPointCount() != 0 && pArchive->getFileCount() == 0)
  361. {
  362. ::wxMessageBox(L"Archive was loaded successfully, but it contains no files.", L"Open archive", wxICON_INFORMATION, this);
  363. }
  364. GetStatusBar()->SetStatusText(L"Loaded " + m_sCurrentShortName + wxString::Format(L", %u files in %u directories", pArchive->getFileCount(), pArchive->getDirectoryCount()));
  365. }
  366. void frmFileStoreViewer::_onLoadedArchive()
  367. {
  368. SetTitle(m_sBaseTitle + L" - " + m_sCurrentShortName);
  369. wxTreeItemId oRoot = m_pFilesTree->AddRoot(wxEmptyString);
  370. size_t iEntryCount = m_pArchive->getEntryPointCount();
  371. if(iEntryCount == 0)
  372. {
  373. ::wxMessageBox(L"Archive was loaded successfully, but it contains no files.", L"Open archive", wxICON_INFORMATION, this);
  374. return;
  375. }
  376. wxTreeItemId oEntry, oFirstEntry;
  377. for(size_t i = 0; i < iEntryCount; ++i)
  378. {
  379. const RainString& sName = m_pArchive->getEntryPointName(i);
  380. oEntry = m_pFilesTree->AppendItem(oRoot, sName, 1, -1, new SGATreeData(sName));
  381. if(i == 0)
  382. oFirstEntry = oEntry;
  383. m_pFilesTree->SetItemHasChildren(oEntry);
  384. if(iEntryCount == 1)
  385. m_pFilesTree->Expand(oEntry);
  386. }
  387. m_pFilesTree->SetFocus();
  388. m_pFilesTree->SelectItem(oFirstEntry);
  389. }
  390. void frmFileStoreViewer::onAbout(wxCommandEvent &e)
  391. {
  392. ::wxMessageBox(
  393. L"SGA Reader 2 by Corsix, part of the Mod Studio 2 suite\n"
  394. L"Available from http://code.google.com/p/modstudio2/\n"
  395. L"Uses wxWidgets, Rainman2 and famfamfam \'silk\' icons"
  396. , m_sBaseTitle, wxICON_INFORMATION, this);
  397. }
  398. void frmFileStoreViewer::onResize(wxSizeEvent &e)
  399. {
  400. Layout();
  401. }
  402. void frmFileStoreViewer::onTreeSelection(wxTreeEvent &e)
  403. {
  404. wxTreeItemId oItem = e.GetItem();
  405. if(!oItem.IsOk() || m_pArchive == NULL)
  406. return;
  407. m_pDetailsView->Freeze();
  408. m_pDetailsView->DeleteAllItems();
  409. m_oCurrentFolderId = oItem;
  410. SGATreeData *pData = reinterpret_cast<SGATreeData*>(m_pFilesTree->GetItemData(oItem));
  411. wxString sDirectory(L"Directory");
  412. std::auto_ptr<IDirectory> pDirectory;
  413. try
  414. {
  415. if(pData->getPath().indexOf('\\') != RainString::NOT_FOUND)
  416. {
  417. m_pDetailsView->InsertItem(0, L"Up one level");
  418. m_pDetailsView->SetItem(0, 1, wxEmptyString);
  419. m_pDetailsView->SetItem(0, 2, sDirectory);
  420. m_pDetailsView->SetItem(0, 3, wxEmptyString);
  421. m_pDetailsView->SetItemImage(0, 0);
  422. m_pDetailsView->SetItemData(0, 0);
  423. }
  424. pDirectory.reset(m_pArchive->openDirectory(pData->getPath()));
  425. for(IDirectory::iterator itr = pDirectory->begin(), itrEnd = pDirectory->end(); itr != itrEnd; ++itr)
  426. {
  427. long iIndex = m_pDetailsView->GetItemCount();
  428. m_pDetailsView->InsertItem(iIndex, itr->name());
  429. wxString sType;
  430. int iIcon;
  431. if(itr->isDirectory())
  432. {
  433. m_pDetailsView->SetItem(iIndex, 1, wxEmptyString);
  434. sType = sDirectory;
  435. m_pDetailsView->SetItem(iIndex, 3, wxEmptyString);
  436. m_pDetailsView->SetItemData(iIndex, 1);
  437. iIcon = 2;
  438. }
  439. else
  440. {
  441. m_pDetailsView->SetItemData(iIndex, 2);
  442. wxDateTime oTimestamp(itr->timestamp());
  443. m_pDetailsView->SetItem(iIndex, 1, oTimestamp.Format(m_sDateFormat));
  444. wxString sExt = itr->name().afterLast('.').toUpper();
  445. sType = sExt + L" file";
  446. iIcon = 3;
  447. bool bGotType = false;
  448. if(!bGotType)
  449. {
  450. const IniFile::Section& oSection = TheConfig[L"Types"];
  451. if(oSection.hasValue(sExt, false))
  452. {
  453. sType = oSection[sExt].value();
  454. bGotType = true;
  455. if(sType.Find(';') != wxNOT_FOUND)
  456. {
  457. wxString sIconIndex = sType.BeforeFirst(';');
  458. long iIconIndexLong;
  459. if(sIconIndex.ToLong(&iIconIndexLong))
  460. {
  461. iIcon = static_cast<int>(iIconIndexLong);
  462. sType = sType.AfterFirst(';');
  463. }
  464. }
  465. }
  466. }
  467. if(!bGotType)
  468. {
  469. wxFileType *pType = wxTheMimeTypesManager->GetFileTypeFromExtension(sExt);
  470. if(pType)
  471. {
  472. wxString sDesc;
  473. if(pType->GetDescription(&sDesc) && !sDesc.IsEmpty())
  474. {
  475. sType = sDesc;
  476. bGotType = true;
  477. }
  478. }
  479. delete pType;
  480. }
  481. const wchar_t* aSuffixs[] = {L"Bytes", L"KB", L"MB", L"GB", NULL};
  482. int iSuffix = 0;
  483. double fSize = static_cast<double>(itr->size().iLower) + static_cast<double>(itr->size().iUpper) * 4294967296.0;
  484. while(aSuffixs[iSuffix + 1] && fSize >= 1024.0)
  485. {
  486. ++iSuffix;
  487. fSize = fSize / 1024;
  488. }
  489. m_pDetailsView->SetItem(iIndex, 3, wxString::Format(L"%.1f %s", fSize, aSuffixs[iSuffix]));
  490. }
  491. m_pDetailsView->SetItem(iIndex, 2, sType);
  492. m_pDetailsView->SetItemImage(iIndex, iIcon);
  493. }
  494. }
  495. CATCH_MESSAGE_BOX(L"Unable to list directory contents", {});
  496. m_pDetailsView->Thaw();
  497. }
  498. void frmFileStoreViewer::onTreeExpanding(wxTreeEvent &e)
  499. {
  500. wxTreeItemId oItem = e.GetItem();
  501. SGATreeData *pData = reinterpret_cast<SGATreeData*>(m_pFilesTree->GetItemData(oItem));
  502. if(!pData->isLoaded())
  503. {
  504. std::auto_ptr<IDirectory> pDirectory;
  505. try
  506. {
  507. pDirectory.reset(m_pArchive->openDirectory(pData->getPath()));
  508. for(IDirectory::iterator itr = pDirectory->begin(), itrEnd = pDirectory->end(); itr != itrEnd; ++itr)
  509. {
  510. if(itr->isDirectory())
  511. {
  512. wxTreeItemData *pNewData = new SGATreeData(pData->getPath() + L"\\" + itr->name());
  513. wxTreeItemId oChild = m_pFilesTree->AppendItem(oItem, itr->name(), 2, -1, pNewData);
  514. IDirectory *pChild = 0;
  515. try
  516. {
  517. pChild = itr->open();
  518. for(IDirectory::iterator itr = pChild->begin(), itrEnd = pChild->end(); itr != itrEnd; ++itr)
  519. {
  520. if(itr->isDirectory())
  521. {
  522. m_pFilesTree->SetItemHasChildren(oChild);
  523. break;
  524. }
  525. }
  526. delete pChild;
  527. }
  528. catch(RainException *pE)
  529. {
  530. delete pE;
  531. m_pFilesTree->SetItemHasChildren(oChild); // best guess
  532. }
  533. }
  534. }
  535. pData->setLoaded();
  536. }
  537. CATCH_MESSAGE_BOX(L"Unable to determine directory children", {});
  538. }
  539. }