tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

BrowseDialog.cpp (24417B)


      1 // BrowseDialog.cpp
      2 
      3 #include "StdAfx.h"
      4 
      5 #include "../../../Common/MyWindows.h"
      6 
      7 #include <commctrl.h>
      8 
      9 #ifndef UNDER_CE
     10 #include "../../../Windows/CommonDialog.h"
     11 #include "../../../Windows/Shell.h"
     12 #endif
     13 
     14 #include "../../../Windows/FileName.h"
     15 #include "../../../Windows/FileFind.h"
     16 
     17 #ifdef UNDER_CE
     18 #include <commdlg.h>
     19 #endif
     20 
     21 #include "BrowseDialog.h"
     22 
     23 #define USE_MY_BROWSE_DIALOG
     24 
     25 #ifdef USE_MY_BROWSE_DIALOG
     26 
     27 #include "../../../Common/Defs.h"
     28 #include "../../../Common/IntToString.h"
     29 #include "../../../Common/Wildcard.h"
     30 
     31 #include "../../../Windows/FileDir.h"
     32 #include "../../../Windows/PropVariantConv.h"
     33 
     34 #include "../../../Windows/Control/ComboBox.h"
     35 #include "../../../Windows/Control/Dialog.h"
     36 #include "../../../Windows/Control/Edit.h"
     37 #include "../../../Windows/Control/ListView.h"
     38 
     39 #include "BrowseDialogRes.h"
     40 #include "PropertyNameRes.h"
     41 #include "SysIconUtils.h"
     42 
     43 #ifndef _SFX
     44 #include "RegistryUtils.h"
     45 #endif
     46 
     47 #endif
     48 
     49 #include "ComboDialog.h"
     50 #include "LangUtils.h"
     51 
     52 #include "resource.h"
     53 
     54 using namespace NWindows;
     55 using namespace NFile;
     56 using namespace NName;
     57 using namespace NFind;
     58 
     59 #ifdef USE_MY_BROWSE_DIALOG
     60 
     61 extern bool g_LVN_ITEMACTIVATE_Support;
     62 
     63 static const int kParentIndex = -1;
     64 static const UINT k_Message_RefreshPathEdit = WM_APP + 1;
     65 
     66 static HRESULT GetNormalizedError()
     67 {
     68  DWORD errorCode = GetLastError();
     69  return errorCode == 0 ? E_FAIL : errorCode;
     70 }
     71 
     72 extern UString HResultToMessage(HRESULT errorCode);
     73 
     74 static void MessageBox_Error_Global(HWND wnd, const wchar_t *message)
     75 {
     76  ::MessageBoxW(wnd, message, L"7-Zip", MB_ICONERROR);
     77 }
     78 
     79 static void MessageBox_HResError(HWND wnd, HRESULT errorCode, const wchar_t *name)
     80 {
     81  UString s = HResultToMessage(errorCode);
     82  if (name)
     83  {
     84    s.Add_LF();
     85    s += name;
     86  }
     87  MessageBox_Error_Global(wnd, s);
     88 }
     89 
     90 class CBrowseDialog: public NControl::CModalDialog
     91 {
     92  NControl::CListView _list;
     93  NControl::CEdit _pathEdit;
     94  NControl::CComboBox _filterCombo;
     95 
     96  CObjectVector<CFileInfo> _files;
     97 
     98  CExtToIconMap _extToIconMap;
     99  int _sortIndex;
    100  bool _ascending;
    101  bool _showDots;
    102  UString _topDirPrefix; // we don't open parent of that folder
    103  UString DirPrefix;
    104 
    105  virtual bool OnInit();
    106  virtual bool OnSize(WPARAM wParam, int xSize, int ySize);
    107  virtual bool OnMessage(UINT message, WPARAM wParam, LPARAM lParam);
    108  virtual bool OnNotify(UINT controlID, LPNMHDR header);
    109  virtual bool OnKeyDown(LPNMLVKEYDOWN keyDownInfo);
    110  virtual bool OnButtonClicked(int buttonID, HWND buttonHWND);
    111  virtual void OnOK();
    112 
    113  void Post_RefreshPathEdit() { PostMsg(k_Message_RefreshPathEdit); }
    114 
    115  bool GetParentPath(const UString &path, UString &parentPrefix, UString &name);
    116  // Reload changes DirPrefix. Don't send DirPrefix in pathPrefix parameter
    117  HRESULT Reload(const UString &pathPrefix, const UString &selectedName);
    118  HRESULT Reload();
    119  
    120  void OpenParentFolder();
    121  void SetPathEditText();
    122  void OnCreateDir();
    123  void OnItemEnter();
    124  void FinishOnOK();
    125 
    126  int GetRealItemIndex(int indexInListView) const
    127  {
    128    LPARAM param;
    129    if (!_list.GetItemParam(indexInListView, param))
    130      return (int)-1;
    131    return (int)param;
    132  }
    133 
    134 public:
    135  bool FolderMode;
    136  UString Title;
    137  UString FilePath;  // input/ result path
    138  bool ShowAllFiles;
    139  UStringVector Filters;
    140  UString FilterDescription;
    141 
    142  CBrowseDialog(): FolderMode(false), _showDots(false), ShowAllFiles(true) {}
    143  void SetFilter(const UString &s);
    144  INT_PTR Create(HWND parent = 0) { return CModalDialog::Create(IDD_BROWSE, parent); }
    145  int CompareItems(LPARAM lParam1, LPARAM lParam2);
    146 };
    147 
    148 void CBrowseDialog::SetFilter(const UString &s)
    149 {
    150  Filters.Clear();
    151  UString mask;
    152  unsigned i;
    153  for (i = 0; i < s.Len(); i++)
    154  {
    155    wchar_t c = s[i];
    156    if (c == ';')
    157    {
    158      if (!mask.IsEmpty())
    159        Filters.Add(mask);
    160      mask.Empty();
    161    }
    162    else
    163      mask += c;
    164  }
    165  if (!mask.IsEmpty())
    166    Filters.Add(mask);
    167  ShowAllFiles = Filters.IsEmpty();
    168  for (i = 0; i < Filters.Size(); i++)
    169  {
    170    const UString &f = Filters[i];
    171    if (f == L"*.*" || f == L"*")
    172    {
    173      ShowAllFiles = true;
    174      break;
    175    }
    176  }
    177 }
    178 
    179 bool CBrowseDialog::OnInit()
    180 {
    181  #ifdef LANG
    182  LangSetDlgItems(*this, NULL, 0);
    183  #endif
    184  if (!Title.IsEmpty())
    185    SetText(Title);
    186  _list.Attach(GetItem(IDL_BROWSE));
    187  _filterCombo.Attach(GetItem(IDC_BROWSE_FILTER));
    188  _pathEdit.Attach(GetItem(IDE_BROWSE_PATH));
    189 
    190  if (FolderMode)
    191    HideItem(IDC_BROWSE_FILTER);
    192  else
    193    EnableItem(IDC_BROWSE_FILTER, false);
    194 
    195  #ifndef UNDER_CE
    196  _list.SetUnicodeFormat();
    197  #endif
    198 
    199  #ifndef _SFX
    200  CFmSettings st;
    201  st.Load();
    202  if (st.SingleClick)
    203    _list.SetExtendedListViewStyle(LVS_EX_ONECLICKACTIVATE | LVS_EX_TRACKSELECT);
    204  _showDots = st.ShowDots;
    205  #endif
    206 
    207  {
    208    UString s;
    209    if (!FilterDescription.IsEmpty())
    210      s = FilterDescription;
    211    else if (ShowAllFiles)
    212      s = "*.*";
    213    else
    214    {
    215      FOR_VECTOR (i, Filters)
    216      {
    217        if (i != 0)
    218          s.Add_Space();
    219        s += Filters[i];
    220      }
    221    }
    222    _filterCombo.AddString(s);
    223    _filterCombo.SetCurSel(0);
    224  }
    225 
    226  _list.SetImageList(GetSysImageList(true), LVSIL_SMALL);
    227  _list.SetImageList(GetSysImageList(false), LVSIL_NORMAL);
    228 
    229  _list.InsertColumn(0, LangString(IDS_PROP_NAME), 100);
    230  _list.InsertColumn(1, LangString(IDS_PROP_MTIME), 100);
    231  {
    232    LV_COLUMNW column;
    233    column.iSubItem = 2;
    234    column.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
    235    column.fmt = LVCFMT_RIGHT;
    236    column.cx = 100;
    237    const UString s = LangString(IDS_PROP_SIZE);
    238    column.pszText = (wchar_t *)(const wchar_t *)s;
    239    _list.InsertColumn(2, &column);
    240  }
    241 
    242  _list.InsertItem(0, L"12345678901234567"
    243      #ifndef UNDER_CE
    244      L"1234567890"
    245      #endif
    246      );
    247  _list.SetSubItem(0, 1, L"2009-09-09"
    248      #ifndef UNDER_CE
    249      L" 09:09"
    250      #endif
    251      );
    252  _list.SetSubItem(0, 2, L"9999 MB");
    253  for (int i = 0; i < 3; i++)
    254    _list.SetColumnWidthAuto(i);
    255  _list.DeleteAllItems();
    256 
    257  _ascending = true;
    258  _sortIndex = 0;
    259 
    260  NormalizeSize();
    261 
    262  _topDirPrefix.Empty();
    263  {
    264    int rootSize = GetRootPrefixSize(FilePath);
    265    #if defined(_WIN32) && !defined(UNDER_CE)
    266    // We can go up from root folder to drives list
    267    if (IsDrivePath(FilePath))
    268      rootSize = 0;
    269    else if (IsSuperPath(FilePath))
    270    {
    271      if (IsDrivePath(FilePath.Ptr(kSuperPathPrefixSize)))
    272        rootSize = kSuperPathPrefixSize;
    273    }
    274    #endif
    275    _topDirPrefix.SetFrom(FilePath, rootSize);
    276  }
    277 
    278  UString name;
    279  if (!GetParentPath(FilePath, DirPrefix, name))
    280    DirPrefix = _topDirPrefix;
    281 
    282  for (;;)
    283  {
    284    UString baseFolder = DirPrefix;
    285    if (Reload(baseFolder, name) == S_OK)
    286      break;
    287    name.Empty();
    288    if (DirPrefix.IsEmpty())
    289      break;
    290    UString parent, name2;
    291    GetParentPath(DirPrefix, parent, name2);
    292    DirPrefix = parent;
    293  }
    294 
    295  if (name.IsEmpty())
    296    name = FilePath;
    297  if (FolderMode)
    298    NormalizeDirPathPrefix(name);
    299  _pathEdit.SetText(name);
    300 
    301  #ifndef UNDER_CE
    302  /* If we clear UISF_HIDEFOCUS, the focus rectangle in ListView will be visible,
    303     even if we use mouse for pressing the button to open this dialog. */
    304  PostMsg(MY__WM_UPDATEUISTATE, MAKEWPARAM(MY__UIS_CLEAR, MY__UISF_HIDEFOCUS));
    305  #endif
    306 
    307  return CModalDialog::OnInit();
    308 }
    309 
    310 bool CBrowseDialog::OnSize(WPARAM /* wParam */, int xSize, int ySize)
    311 {
    312  int mx, my;
    313  {
    314    RECT r;
    315    GetClientRectOfItem(IDB_BROWSE_PARENT, r);
    316    mx = r.left;
    317    my = r.top;
    318  }
    319  InvalidateRect(NULL);
    320 
    321  int xLim = xSize - mx;
    322  {
    323    RECT r;
    324    GetClientRectOfItem(IDT_BROWSE_FOLDER, r);
    325    MoveItem(IDT_BROWSE_FOLDER, r.left, r.top, xLim - r.left, RECT_SIZE_Y(r));
    326  }
    327 
    328  int bx1, bx2, by;
    329  GetItemSizes(IDCANCEL, bx1, by);
    330  GetItemSizes(IDOK, bx2, by);
    331  int y = ySize - my - by;
    332  int x = xLim - bx1;
    333  MoveItem(IDCANCEL, x, y, bx1, by);
    334  MoveItem(IDOK, x - mx - bx2, y, bx2, by);
    335 
    336  // Y_Size of ComboBox is tricky. So we use Y_Size of _pathEdit instead
    337 
    338  int yPathSize;
    339  {
    340    RECT r;
    341    GetClientRectOfItem(IDE_BROWSE_PATH, r);
    342    yPathSize = RECT_SIZE_Y(r);
    343    _pathEdit.Move(r.left, y - my - yPathSize - my - yPathSize, xLim - r.left, yPathSize);
    344  }
    345 
    346  {
    347    RECT r;
    348    GetClientRectOfItem(IDC_BROWSE_FILTER, r);
    349    _filterCombo.Move(r.left, y - my - yPathSize, xLim - r.left, RECT_SIZE_Y(r));
    350  }
    351 
    352  {
    353    RECT r;
    354    GetClientRectOfItem(IDL_BROWSE, r);
    355    _list.Move(r.left, r.top, xLim - r.left, y - my - yPathSize - my - yPathSize - my - r.top);
    356  }
    357 
    358  return false;
    359 }
    360 
    361 bool CBrowseDialog::OnMessage(UINT message, WPARAM wParam, LPARAM lParam)
    362 {
    363  if (message == k_Message_RefreshPathEdit)
    364  {
    365    SetPathEditText();
    366    return true;
    367  }
    368  return CModalDialog::OnMessage(message, wParam, lParam);
    369 }
    370 
    371 bool CBrowseDialog::OnNotify(UINT /* controlID */, LPNMHDR header)
    372 {
    373  if (header->hwndFrom != _list)
    374    return false;
    375  switch (header->code)
    376  {
    377    case LVN_ITEMACTIVATE:
    378      if (g_LVN_ITEMACTIVATE_Support)
    379        OnItemEnter();
    380      break;
    381    case NM_DBLCLK:
    382    case NM_RETURN: // probabably it's unused
    383      if (!g_LVN_ITEMACTIVATE_Support)
    384        OnItemEnter();
    385      break;
    386    case LVN_COLUMNCLICK:
    387    {
    388      int index = LPNMLISTVIEW(header)->iSubItem;
    389      if (index == _sortIndex)
    390        _ascending = !_ascending;
    391      else
    392      {
    393        _ascending = (index == 0);
    394        _sortIndex = index;
    395      }
    396      Reload();
    397      return false;
    398    }
    399    case LVN_KEYDOWN:
    400    {
    401      bool boolResult = OnKeyDown(LPNMLVKEYDOWN(header));
    402      Post_RefreshPathEdit();
    403      return boolResult;
    404    }
    405    case NM_RCLICK:
    406    case NM_CLICK:
    407    case LVN_BEGINDRAG:
    408      Post_RefreshPathEdit();
    409      break;
    410  }
    411  return false;
    412 }
    413 
    414 bool CBrowseDialog::OnKeyDown(LPNMLVKEYDOWN keyDownInfo)
    415 {
    416  bool ctrl = IsKeyDown(VK_CONTROL);
    417 
    418  switch (keyDownInfo->wVKey)
    419  {
    420    case VK_BACK:
    421      OpenParentFolder();
    422      return true;
    423    case 'R':
    424      if (ctrl)
    425      {
    426        Reload();
    427        return true;
    428      }
    429      return false;
    430    case VK_F7:
    431      OnCreateDir();
    432      return true;
    433  }
    434  return false;
    435 }
    436 
    437 bool CBrowseDialog::OnButtonClicked(int buttonID, HWND buttonHWND)
    438 {
    439  switch (buttonID)
    440  {
    441    case IDB_BROWSE_PARENT: OpenParentFolder(); break;
    442    case IDB_BROWSE_CREATE_DIR: OnCreateDir(); break;
    443    default: return CModalDialog::OnButtonClicked(buttonID, buttonHWND);
    444  }
    445  _list.SetFocus();
    446  return true;
    447 }
    448 
    449 void CBrowseDialog::OnOK()
    450 {
    451  /* When we press "Enter" in listview, Windows sends message to first Button.
    452     We check that message was from ListView; */
    453  if (GetFocus() == _list)
    454  {
    455    OnItemEnter();
    456    return;
    457  }
    458  FinishOnOK();
    459 }
    460 
    461 
    462 bool CBrowseDialog::GetParentPath(const UString &path, UString &parentPrefix, UString &name)
    463 {
    464  parentPrefix.Empty();
    465  name.Empty();
    466  if (path.IsEmpty())
    467    return false;
    468  if (_topDirPrefix == path)
    469    return false;
    470  UString s = path;
    471  if (IS_PATH_SEPAR(s.Back()))
    472    s.DeleteBack();
    473  if (s.IsEmpty())
    474    return false;
    475  if (IS_PATH_SEPAR(s.Back()))
    476    return false;
    477  int pos = s.ReverseFind_PathSepar();
    478  parentPrefix.SetFrom(s, pos + 1);
    479  name = s.Ptr(pos + 1);
    480  return true;
    481 }
    482 
    483 int CBrowseDialog::CompareItems(LPARAM lParam1, LPARAM lParam2)
    484 {
    485  if (lParam1 == kParentIndex) return -1;
    486  if (lParam2 == kParentIndex) return 1;
    487  const CFileInfo &f1 = _files[(int)lParam1];
    488  const CFileInfo &f2 = _files[(int)lParam2];
    489 
    490  bool isDir1 = f1.IsDir();
    491  bool isDir2 = f2.IsDir();
    492  if (isDir1 && !isDir2) return -1;
    493  if (isDir2 && !isDir1) return 1;
    494  
    495  int res = 0;
    496  switch (_sortIndex)
    497  {
    498    case 0: res = CompareFileNames(fs2us(f1.Name), fs2us(f2.Name)); break;
    499    case 1: res = CompareFileTime(&f1.MTime, &f2.MTime); break;
    500    case 2: res = MyCompare(f1.Size, f2.Size); break;
    501  }
    502  return _ascending ? res: -res;
    503 }
    504 
    505 static int CALLBACK CompareItems2(LPARAM lParam1, LPARAM lParam2, LPARAM lpData)
    506 {
    507  return ((CBrowseDialog *)lpData)->CompareItems(lParam1, lParam2);
    508 }
    509 
    510 static void ConvertSizeToString(UInt64 v, wchar_t *s)
    511 {
    512  Byte c = 0;
    513       if (v >= ((UInt64)10000 << 20)) { v >>= 30; c = 'G'; }
    514  else if (v >= ((UInt64)10000 << 10)) { v >>= 20; c = 'M'; }
    515  else if (v >= ((UInt64)10000 <<  0)) { v >>= 10; c = 'K'; }
    516  ConvertUInt64ToString(v, s);
    517  if (c != 0)
    518  {
    519    s += MyStringLen(s);
    520    *s++ = ' ';
    521    *s++ = c;
    522    *s++ = 0;
    523  }
    524 }
    525 
    526 // Reload changes DirPrefix. Don't send DirPrefix in pathPrefix parameter
    527 
    528 HRESULT CBrowseDialog::Reload(const UString &pathPrefix, const UString &selectedName)
    529 {
    530  CObjectVector<CFileInfo> files;
    531  
    532  #ifndef UNDER_CE
    533  bool isDrive = false;
    534  if (pathPrefix.IsEmpty() || pathPrefix.IsEqualTo(kSuperPathPrefix))
    535  {
    536    isDrive = true;
    537    FStringVector drives;
    538    if (!MyGetLogicalDriveStrings(drives))
    539      return GetNormalizedError();
    540    FOR_VECTOR (i, drives)
    541    {
    542      FString d = drives[i];
    543      if (d.Len() < 3 || d.Back() != '\\')
    544        return E_FAIL;
    545      d.DeleteBack();
    546      CFileInfo &fi = files.AddNew();
    547      fi.SetAsDir();
    548      fi.Name = d;
    549    }
    550  }
    551  else
    552  #endif
    553  {
    554    CEnumerator enumerator;
    555    enumerator.SetDirPrefix(us2fs(pathPrefix));
    556    for (;;)
    557    {
    558      bool found;
    559      CFileInfo fi;
    560      if (!enumerator.Next(fi, found))
    561        return GetNormalizedError();
    562      if (!found)
    563        break;
    564      if (!fi.IsDir())
    565      {
    566        if (FolderMode)
    567          continue;
    568        if (!ShowAllFiles)
    569        {
    570          unsigned i;
    571          for (i = 0; i < Filters.Size(); i++)
    572            if (DoesWildcardMatchName(Filters[i], fs2us(fi.Name)))
    573              break;
    574          if (i == Filters.Size())
    575            continue;
    576        }
    577      }
    578      files.Add(fi);
    579    }
    580  }
    581 
    582  DirPrefix = pathPrefix;
    583 
    584  _files = files;
    585 
    586  SetItemText(IDT_BROWSE_FOLDER, DirPrefix);
    587 
    588  _list.SetRedraw(false);
    589  _list.DeleteAllItems();
    590 
    591  LVITEMW item;
    592 
    593  int index = 0;
    594  int cursorIndex = -1;
    595 
    596  #ifndef _SFX
    597  if (_showDots && _topDirPrefix != DirPrefix)
    598  {
    599    item.iItem = index;
    600    const UString itemName ("..");
    601    if (selectedName.IsEmpty())
    602      cursorIndex = index;
    603    item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
    604    int subItem = 0;
    605    item.iSubItem = subItem++;
    606    item.lParam = kParentIndex;
    607    item.pszText = (wchar_t *)(const wchar_t *)itemName;
    608    item.iImage = _extToIconMap.GetIconIndex(FILE_ATTRIBUTE_DIRECTORY, DirPrefix);
    609    if (item.iImage < 0)
    610      item.iImage = 0;
    611    _list.InsertItem(&item);
    612    _list.SetSubItem(index, subItem++, L"");
    613    _list.SetSubItem(index, subItem++, L"");
    614    index++;
    615  }
    616  #endif
    617 
    618  for (unsigned i = 0; i < _files.Size(); i++, index++)
    619  {
    620    item.iItem = index;
    621    const CFileInfo &fi = _files[i];
    622    const UString name = fs2us(fi.Name);
    623    if (!selectedName.IsEmpty() && CompareFileNames(name, selectedName) == 0)
    624      cursorIndex = index;
    625    item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
    626    int subItem = 0;
    627    item.iSubItem = subItem++;
    628    item.lParam = i;
    629    item.pszText = (wchar_t *)(const wchar_t *)name;
    630 
    631    const UString fullPath = DirPrefix + name;
    632    #ifndef UNDER_CE
    633    if (isDrive)
    634    {
    635      if (GetRealIconIndex(fi.Name + FCHAR_PATH_SEPARATOR, FILE_ATTRIBUTE_DIRECTORY, item.iImage) == 0)
    636        item.iImage = 0;
    637    }
    638    else
    639    #endif
    640      item.iImage = _extToIconMap.GetIconIndex(fi.Attrib, fullPath);
    641    if (item.iImage < 0)
    642      item.iImage = 0;
    643    _list.InsertItem(&item);
    644    wchar_t s[32];
    645    {
    646      s[0] = 0;
    647      ConvertUtcFileTimeToString(fi.MTime, s,
    648            #ifndef UNDER_CE
    649              kTimestampPrintLevel_MIN
    650            #else
    651              kTimestampPrintLevel_DAY
    652            #endif
    653              );
    654      _list.SetSubItem(index, subItem++, s);
    655    }
    656    {
    657      s[0] = 0;
    658      if (!fi.IsDir())
    659        ConvertSizeToString(fi.Size, s);
    660      _list.SetSubItem(index, subItem++, s);
    661    }
    662  }
    663 
    664  if (_list.GetItemCount() > 0 && cursorIndex >= 0)
    665    _list.SetItemState_FocusedSelected(cursorIndex);
    666  _list.SortItems(CompareItems2, (LPARAM)this);
    667  if (_list.GetItemCount() > 0 && cursorIndex < 0)
    668    _list.SetItemState(0, LVIS_FOCUSED, LVIS_FOCUSED);
    669  _list.EnsureVisible(_list.GetFocusedItem(), false);
    670  _list.SetRedraw(true);
    671  _list.InvalidateRect(NULL, true);
    672  return S_OK;
    673 }
    674 
    675 HRESULT CBrowseDialog::Reload()
    676 {
    677  UString selected;
    678  int index = _list.GetNextSelectedItem(-1);
    679  if (index >= 0)
    680  {
    681    int fileIndex = GetRealItemIndex(index);
    682    if (fileIndex != kParentIndex)
    683      selected = fs2us(_files[fileIndex].Name);
    684  }
    685  UString dirPathTemp = DirPrefix;
    686  return Reload(dirPathTemp, selected);
    687 }
    688 
    689 void CBrowseDialog::OpenParentFolder()
    690 {
    691  UString parent, selected;
    692  if (GetParentPath(DirPrefix, parent, selected))
    693  {
    694    Reload(parent, selected);
    695    SetPathEditText();
    696  }
    697 }
    698 
    699 void CBrowseDialog::SetPathEditText()
    700 {
    701  int index = _list.GetNextSelectedItem(-1);
    702  if (index < 0)
    703  {
    704    if (FolderMode)
    705      _pathEdit.SetText(DirPrefix);
    706    return;
    707  }
    708  int fileIndex = GetRealItemIndex(index);
    709  if (fileIndex == kParentIndex)
    710  {
    711    if (FolderMode)
    712      _pathEdit.SetText(L".." WSTRING_PATH_SEPARATOR);
    713    return;
    714  }
    715  const CFileInfo &file = _files[fileIndex];
    716  if (file.IsDir())
    717  {
    718    if (!FolderMode)
    719      return;
    720    _pathEdit.SetText(fs2us(file.Name) + WCHAR_PATH_SEPARATOR);
    721  }
    722  else
    723    _pathEdit.SetText(fs2us(file.Name));
    724 }
    725 
    726 void CBrowseDialog::OnCreateDir()
    727 {
    728  UString name;
    729  {
    730    UString enteredName;
    731    Dlg_CreateFolder((HWND)*this, enteredName);
    732    if (enteredName.IsEmpty())
    733      return;
    734    if (!CorrectFsPath(DirPrefix, enteredName, name))
    735    {
    736      MessageBox_HResError((HWND)*this, ERROR_INVALID_NAME, name);
    737      return;
    738    }
    739  }
    740  if (name.IsEmpty())
    741    return;
    742 
    743  FString destPath;
    744  if (GetFullPath(us2fs(DirPrefix), us2fs(name), destPath))
    745  {
    746    if (!NDir::CreateComplexDir(destPath))
    747    {
    748      MessageBox_HResError((HWND)*this, GetNormalizedError(), fs2us(destPath));
    749    }
    750    else
    751    {
    752      UString tempPath = DirPrefix;
    753      Reload(tempPath, name);
    754      SetPathEditText();
    755    }
    756    _list.SetFocus();
    757  }
    758 }
    759 
    760 void CBrowseDialog::OnItemEnter()
    761 {
    762  int index = _list.GetNextSelectedItem(-1);
    763  if (index < 0)
    764    return;
    765  int fileIndex = GetRealItemIndex(index);
    766  if (fileIndex == kParentIndex)
    767    OpenParentFolder();
    768  else
    769  {
    770    const CFileInfo &file = _files[fileIndex];
    771    if (!file.IsDir())
    772    {
    773      if (!FolderMode)
    774        FinishOnOK();
    775      /*
    776      MessageBox_Error_Global(*this, FolderMode ?
    777            L"You must select some folder":
    778            L"You must select some file");
    779      */
    780      return;
    781    }
    782    UString s = DirPrefix;
    783    s += fs2us(file.Name);
    784    s.Add_PathSepar();
    785    HRESULT res = Reload(s, UString());
    786    if (res != S_OK)
    787      MessageBox_HResError(*this, res, s);
    788    SetPathEditText();
    789  }
    790 }
    791 
    792 void CBrowseDialog::FinishOnOK()
    793 {
    794  UString s;
    795  _pathEdit.GetText(s);
    796  FString destPath;
    797  if (!GetFullPath(us2fs(DirPrefix), us2fs(s), destPath))
    798  {
    799    MessageBox_HResError((HWND)*this, ERROR_INVALID_NAME, s);
    800    return;
    801  }
    802  FilePath = fs2us(destPath);
    803  if (FolderMode)
    804    NormalizeDirPathPrefix(FilePath);
    805  End(IDOK);
    806 }
    807 
    808 #endif
    809 
    810 bool MyBrowseForFolder(HWND owner, LPCWSTR title, LPCWSTR path, UString &resultPath)
    811 {
    812  resultPath.Empty();
    813 
    814  #ifndef UNDER_CE
    815 
    816  #ifdef USE_MY_BROWSE_DIALOG
    817  if (!IsSuperOrDevicePath(path))
    818  #endif
    819    return NShell::BrowseForFolder(owner, title, path, resultPath);
    820 
    821  #endif
    822 
    823  #ifdef USE_MY_BROWSE_DIALOG
    824 
    825  CBrowseDialog dialog;
    826  dialog.FolderMode = true;
    827  if (title)
    828    dialog.Title = title;
    829  if (path)
    830    dialog.FilePath = path;
    831  if (dialog.Create(owner) != IDOK)
    832    return false;
    833  resultPath = dialog.FilePath;
    834  #endif
    835 
    836  return true;
    837 }
    838 
    839 bool MyBrowseForFile(HWND owner, LPCWSTR title, LPCWSTR path,
    840    LPCWSTR filterDescription, LPCWSTR filter, UString &resultPath)
    841 {
    842  resultPath.Empty();
    843 
    844  #ifndef UNDER_CE
    845 
    846  #ifdef USE_MY_BROWSE_DIALOG
    847  if (!IsSuperOrDevicePath(path))
    848  #endif
    849  {
    850    if (MyGetOpenFileName(owner, title, NULL, path, filterDescription, filter, resultPath))
    851      return true;
    852    #ifdef UNDER_CE
    853    return false;
    854    #else
    855    // maybe we must use GetLastError in WinCE.
    856    DWORD errorCode = CommDlgExtendedError();
    857    const char *errorMessage = NULL;
    858    switch (errorCode)
    859    {
    860      case 0: return false; // cancel or close obn dialog
    861      case FNERR_INVALIDFILENAME: errorMessage = "Invalid File Name"; break;
    862      default: errorMessage = "Open Dialog Error";
    863    }
    864    if (!errorMessage)
    865      return false;
    866    {
    867      UString s (errorMessage);
    868      s.Add_LF();
    869      s += path;
    870      MessageBox_Error_Global(owner, s);
    871    }
    872    #endif
    873  }
    874 
    875  #endif
    876  
    877  #ifdef USE_MY_BROWSE_DIALOG
    878  CBrowseDialog dialog;
    879  if (title)
    880    dialog.Title = title;
    881  if (path)
    882    dialog.FilePath = path;
    883  dialog.FolderMode = false;
    884  if (filter)
    885    dialog.SetFilter(filter);
    886  if (filterDescription)
    887    dialog.FilterDescription = filterDescription;
    888  if (dialog.Create(owner) != IDOK)
    889    return false;
    890  resultPath = dialog.FilePath;
    891  #endif
    892 
    893  return true;
    894 }
    895 
    896 
    897 #ifdef _WIN32
    898 
    899 static void RemoveDotsAndSpaces(UString &path)
    900 {
    901  while (!path.IsEmpty())
    902  {
    903    wchar_t c = path.Back();
    904    if (c != ' ' && c != '.')
    905      return;
    906    path.DeleteBack();
    907  }
    908 }
    909 
    910 
    911 bool CorrectFsPath(const UString &relBase, const UString &path2, UString &result)
    912 {
    913  result.Empty();
    914 
    915  UString path = path2;
    916  path.Replace(L'/', WCHAR_PATH_SEPARATOR);
    917  unsigned start = 0;
    918  UString base;
    919  
    920  if (IsAbsolutePath(path))
    921  {
    922    #if defined(_WIN32) && !defined(UNDER_CE)
    923    if (IsSuperOrDevicePath(path))
    924    {
    925      result = path;
    926      return true;
    927    }
    928    #endif
    929    int pos = GetRootPrefixSize(path);
    930    if (pos > 0)
    931      start = pos;
    932  }
    933  else
    934  {
    935    #if defined(_WIN32) && !defined(UNDER_CE)
    936    if (IsSuperOrDevicePath(relBase))
    937    {
    938      result = path;
    939      return true;
    940    }
    941    #endif
    942    base = relBase;
    943  }
    944 
    945  /* We can't use backward, since we must change only disk paths */
    946  /*
    947  for (;;)
    948  {
    949    if (path.Len() <= start)
    950      break;
    951    if (DoesFileOrDirExist(us2fs(path)))
    952      break;
    953    if (path.Back() == WCHAR_PATH_SEPARATOR)
    954    {
    955      path.DeleteBack();
    956      result.Insert(0, WCHAR_PATH_SEPARATOR);;
    957    }
    958    int pos = path.ReverseFind(WCHAR_PATH_SEPARATOR) + 1;
    959    UString cur = path.Ptr(pos);
    960    RemoveDotsAndSpaces(cur);
    961    result.Insert(0, cur);
    962    path.DeleteFrom(pos);
    963  }
    964  result.Insert(0, path);
    965  return true;
    966  */
    967 
    968  result += path.Left(start);
    969  bool checkExist = true;
    970  UString cur;
    971 
    972  for (;;)
    973  {
    974    if (start == path.Len())
    975      break;
    976    int slashPos = path.Find(WCHAR_PATH_SEPARATOR, start);
    977    cur.SetFrom(path.Ptr(start), (slashPos < 0 ? path.Len() : slashPos) - start);
    978    if (checkExist)
    979    {
    980      CFileInfo fi;
    981      if (fi.Find(us2fs(base + result + cur)))
    982      {
    983        if (!fi.IsDir())
    984        {
    985          result = path;
    986          break;
    987        }
    988      }
    989      else
    990        checkExist = false;
    991    }
    992    if (!checkExist)
    993      RemoveDotsAndSpaces(cur);
    994    result += cur;
    995    if (slashPos < 0)
    996      break;
    997    result.Add_PathSepar();
    998    start = slashPos + 1;
    999  }
   1000  
   1001  return true;
   1002 }
   1003 
   1004 #else
   1005 
   1006 bool CorrectFsPath(const UString & /* relBase */, const UString &path, UString &result)
   1007 {
   1008  result = path;
   1009  return true;
   1010 }
   1011 
   1012 #endif
   1013 
   1014 bool Dlg_CreateFolder(HWND wnd, UString &destName)
   1015 {
   1016  destName.Empty();
   1017  CComboDialog dlg;
   1018  LangString(IDS_CREATE_FOLDER, dlg.Title);
   1019  LangString(IDS_CREATE_FOLDER_NAME, dlg.Static);
   1020  LangString(IDS_CREATE_FOLDER_DEFAULT_NAME, dlg.Value);
   1021  if (dlg.Create(wnd) != IDOK)
   1022    return false;
   1023  destName = dlg.Value;
   1024  return true;
   1025 }