PageRenderTime 93ms CodeModel.GetById 20ms app.highlight 67ms RepoModel.GetById 1ms app.codeStats 1ms

/SgaReader2/frmFileStoreViewer.cpp

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