| // BrowseDialog.cpp |
| |
| #include "StdAfx.h" |
| |
| #include "../../../Common/MyWindows.h" |
| |
| #include "../../../Common/IntToString.h" |
| |
| #ifndef UNDER_CE |
| #include "../../../Windows/CommonDialog.h" |
| #include "../../../Windows/Shell.h" |
| #endif |
| |
| #include "../../../Windows/FileName.h" |
| #include "../../../Windows/FileFind.h" |
| |
| #ifdef UNDER_CE |
| #include <commdlg.h> |
| #endif |
| |
| #include "BrowseDialog.h" |
| |
| #define USE_MY_BROWSE_DIALOG |
| |
| #ifdef USE_MY_BROWSE_DIALOG |
| |
| #include "../../../Common/Defs.h" |
| #include "../../../Common/Wildcard.h" |
| |
| #include "../../../Windows/FileDir.h" |
| #include "../../../Windows/PropVariantConv.h" |
| |
| #include "../../../Windows/Control/ComboBox.h" |
| #include "../../../Windows/Control/Dialog.h" |
| #include "../../../Windows/Control/Edit.h" |
| #include "../../../Windows/Control/ListView.h" |
| |
| #include "BrowseDialogRes.h" |
| #include "PropertyNameRes.h" |
| #include "SysIconUtils.h" |
| |
| #ifndef Z7_SFX |
| #include "RegistryUtils.h" |
| #endif |
| |
| #endif // USE_MY_BROWSE_DIALOG |
| |
| #include "ComboDialog.h" |
| #include "LangUtils.h" |
| |
| #include "resource.h" |
| |
| using namespace NWindows; |
| using namespace NFile; |
| using namespace NName; |
| using namespace NFind; |
| |
| static void MessageBox_Error_Global(HWND wnd, const wchar_t *message) |
| { |
| ::MessageBoxW(wnd, message, L"7-Zip", MB_ICONERROR); |
| } |
| |
| #ifdef USE_MY_BROWSE_DIALOG |
| |
| extern bool g_LVN_ITEMACTIVATE_Support; |
| |
| static const int kParentIndex = -1; |
| static const UINT k_Message_RefreshPathEdit = WM_APP + 1; |
| |
| extern UString HResultToMessage(HRESULT errorCode); |
| |
| static void MessageBox_HResError(HWND wnd, HRESULT errorCode, const wchar_t *name) |
| { |
| UString s = HResultToMessage(errorCode); |
| if (name) |
| { |
| s.Add_LF(); |
| s += name; |
| } |
| MessageBox_Error_Global(wnd, s); |
| } |
| |
| class CBrowseDialog: public NControl::CModalDialog |
| { |
| NControl::CListView _list; |
| NControl::CEdit _pathEdit; |
| NControl::CComboBox _filterCombo; |
| |
| CObjectVector<CFileInfo> _files; |
| |
| CExtToIconMap _extToIconMap; |
| int _sortIndex; |
| bool _ascending; |
| #ifndef Z7_SFX |
| bool _showDots; |
| #endif |
| UString _topDirPrefix; // we don't open parent of that folder |
| UString DirPrefix; |
| |
| virtual bool OnInit() Z7_override; |
| virtual bool OnSize(WPARAM wParam, int xSize, int ySize) Z7_override; |
| virtual bool OnMessage(UINT message, WPARAM wParam, LPARAM lParam) Z7_override; |
| virtual bool OnNotify(UINT controlID, LPNMHDR header) Z7_override; |
| virtual bool OnCommand(unsigned code, unsigned itemID, LPARAM lParam) Z7_override; |
| virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override; |
| virtual void OnOK() Z7_override; |
| |
| bool OnKeyDown(LPNMLVKEYDOWN keyDownInfo); |
| |
| void Post_RefreshPathEdit() { PostMsg(k_Message_RefreshPathEdit); } |
| |
| bool GetParentPath(const UString &path, UString &parentPrefix, UString &name); |
| // Reload changes DirPrefix. Don't send DirPrefix in pathPrefix parameter |
| HRESULT Reload(const UString &pathPrefix, const UString &selectedName); |
| HRESULT Reload(); |
| |
| void OpenParentFolder(); |
| void SetPathEditText(); |
| void OnCreateDir(); |
| void OnItemEnter(); |
| void FinishOnOK(); |
| |
| int GetRealItemIndex(int indexInListView) const |
| { |
| LPARAM param; |
| if (!_list.GetItemParam((unsigned)indexInListView, param)) |
| return (int)-1; |
| return (int)param; |
| } |
| |
| public: |
| |
| bool SaveMode; |
| bool FolderMode; |
| int FilterIndex; // [in / out] |
| CObjectVector<CBrowseFilterInfo> Filters; |
| |
| UString FilePath; // [in / out] |
| UString Title; |
| |
| CBrowseDialog(): |
| #ifndef Z7_SFX |
| _showDots(false), |
| #endif |
| SaveMode(false) |
| , FolderMode(false) |
| , FilterIndex(-1) |
| {} |
| INT_PTR Create(HWND parent = NULL) { return CModalDialog::Create(IDD_BROWSE, parent); } |
| int CompareItems(LPARAM lParam1, LPARAM lParam2) const; |
| }; |
| |
| |
| bool CBrowseDialog::OnInit() |
| { |
| #ifdef Z7_LANG |
| LangSetDlgItems(*this, NULL, 0); |
| #endif |
| if (!Title.IsEmpty()) |
| SetText(Title); |
| _list.Attach(GetItem(IDL_BROWSE)); |
| _filterCombo.Attach(GetItem(IDC_BROWSE_FILTER)); |
| _pathEdit.Attach(GetItem(IDE_BROWSE_PATH)); |
| |
| #ifndef UNDER_CE |
| _list.SetUnicodeFormat(); |
| #endif |
| |
| #ifndef Z7_SFX |
| CFmSettings st; |
| st.Load(); |
| if (st.SingleClick) |
| _list.SetExtendedListViewStyle(LVS_EX_ONECLICKACTIVATE | LVS_EX_TRACKSELECT); |
| _showDots = st.ShowDots; |
| #endif |
| |
| { |
| /* |
| Filters.Clear(); // for debug |
| if (Filters.IsEmpty() && !FolderMode) |
| { |
| CBrowseFilterInfo &f = Filters.AddNew(); |
| const UString mask("*.*"); |
| f.Masks.Add(mask); |
| // f.Description = "("; |
| f.Description += mask; |
| // f.Description += ")"; |
| } |
| */ |
| |
| FOR_VECTOR (i, Filters) |
| { |
| _filterCombo.AddString(Filters[i].Description); |
| } |
| |
| if (Filters.Size() <= 1) |
| { |
| if (FolderMode) |
| HideItem(IDC_BROWSE_FILTER); |
| else |
| EnableItem(IDC_BROWSE_FILTER, false); |
| } |
| |
| if (/* FilterIndex >= 0 && */ (unsigned)FilterIndex < Filters.Size()) |
| _filterCombo.SetCurSel(FilterIndex); |
| } |
| |
| _list.SetImageList(GetSysImageList(true), LVSIL_SMALL); |
| _list.SetImageList(GetSysImageList(false), LVSIL_NORMAL); |
| |
| _list.InsertColumn(0, LangString(IDS_PROP_NAME), 100); |
| _list.InsertColumn(1, LangString(IDS_PROP_MTIME), 100); |
| { |
| LV_COLUMNW column; |
| column.iSubItem = 2; |
| column.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; |
| column.fmt = LVCFMT_RIGHT; |
| column.cx = 100; |
| const UString s = LangString(IDS_PROP_SIZE); |
| column.pszText = s.Ptr_non_const(); |
| _list.InsertColumn(2, &column); |
| } |
| |
| _list.InsertItem(0, L"12345678901234567" |
| #ifndef UNDER_CE |
| L"1234567890" |
| #endif |
| ); |
| _list.SetSubItem(0, 1, L"2009-09-09" |
| #ifndef UNDER_CE |
| L" 09:09" |
| #endif |
| ); |
| _list.SetSubItem(0, 2, L"9999 MB"); |
| for (int i = 0; i < 3; i++) |
| _list.SetColumnWidthAuto(i); |
| _list.DeleteAllItems(); |
| |
| _ascending = true; |
| _sortIndex = 0; |
| |
| NormalizeSize(); |
| |
| _topDirPrefix.Empty(); |
| { |
| unsigned rootSize = GetRootPrefixSize(FilePath); |
| #if defined(_WIN32) && !defined(UNDER_CE) |
| // We can go up from root folder to drives list |
| if (IsDrivePath(FilePath)) |
| rootSize = 0; |
| else if (IsSuperPath(FilePath)) |
| { |
| if (IsDrivePath(FilePath.Ptr(kSuperPathPrefixSize))) |
| rootSize = kSuperPathPrefixSize; |
| } |
| #endif |
| _topDirPrefix.SetFrom(FilePath, rootSize); |
| } |
| |
| UString name; |
| if (!GetParentPath(FilePath, DirPrefix, name)) |
| DirPrefix = _topDirPrefix; |
| |
| for (;;) |
| { |
| UString baseFolder = DirPrefix; |
| if (Reload(baseFolder, name) == S_OK) |
| break; |
| name.Empty(); |
| if (DirPrefix.IsEmpty()) |
| break; |
| UString parent, name2; |
| GetParentPath(DirPrefix, parent, name2); |
| DirPrefix = parent; |
| } |
| |
| if (name.IsEmpty()) |
| name = FilePath; |
| if (FolderMode) |
| NormalizeDirPathPrefix(name); |
| _pathEdit.SetText(name); |
| |
| #ifndef UNDER_CE |
| /* If we clear UISF_HIDEFOCUS, the focus rectangle in ListView will be visible, |
| even if we use mouse for pressing the button to open this dialog. */ |
| PostMsg(Z7_WIN_WM_UPDATEUISTATE, MAKEWPARAM(Z7_WIN_UIS_CLEAR, Z7_WIN_UISF_HIDEFOCUS)); |
| #endif |
| |
| return CModalDialog::OnInit(); |
| } |
| |
| bool CBrowseDialog::OnSize(WPARAM /* wParam */, int xSize, int ySize) |
| { |
| int mx, my; |
| { |
| RECT r; |
| GetClientRectOfItem(IDB_BROWSE_PARENT, r); |
| mx = r.left; |
| my = r.top; |
| } |
| InvalidateRect(NULL); |
| |
| int xLim = xSize - mx; |
| { |
| RECT r; |
| GetClientRectOfItem(IDT_BROWSE_FOLDER, r); |
| MoveItem(IDT_BROWSE_FOLDER, r.left, r.top, xLim - r.left, RECT_SIZE_Y(r)); |
| } |
| |
| int bx1, bx2, by; |
| GetItemSizes(IDCANCEL, bx1, by); |
| GetItemSizes(IDOK, bx2, by); |
| int y = ySize - my - by; |
| int x = xLim - bx1; |
| MoveItem(IDCANCEL, x, y, bx1, by); |
| MoveItem(IDOK, x - mx - bx2, y, bx2, by); |
| |
| // Y_Size of ComboBox is tricky. So we use Y_Size of _pathEdit instead |
| |
| int yPathSize; |
| { |
| RECT r; |
| GetClientRectOfItem(IDE_BROWSE_PATH, r); |
| yPathSize = RECT_SIZE_Y(r); |
| _pathEdit.Move(r.left, y - my - yPathSize - my - yPathSize, xLim - r.left, yPathSize); |
| } |
| |
| { |
| RECT r; |
| GetClientRectOfItem(IDC_BROWSE_FILTER, r); |
| _filterCombo.Move(r.left, y - my - yPathSize, xLim - r.left, RECT_SIZE_Y(r)); |
| } |
| |
| { |
| RECT r; |
| GetClientRectOfItem(IDL_BROWSE, r); |
| _list.Move(r.left, r.top, xLim - r.left, y - my - yPathSize - my - yPathSize - my - r.top); |
| } |
| |
| return false; |
| } |
| |
| bool CBrowseDialog::OnMessage(UINT message, WPARAM wParam, LPARAM lParam) |
| { |
| if (message == k_Message_RefreshPathEdit) |
| { |
| SetPathEditText(); |
| return true; |
| } |
| return CModalDialog::OnMessage(message, wParam, lParam); |
| } |
| |
| |
| bool CBrowseDialog::OnCommand(unsigned code, unsigned itemID, LPARAM lParam) |
| { |
| if (code == CBN_SELCHANGE) |
| { |
| switch (itemID) |
| { |
| case IDC_BROWSE_FILTER: |
| { |
| Reload(); |
| return true; |
| } |
| } |
| } |
| return CModalDialog::OnCommand(code, itemID, lParam); |
| } |
| |
| |
| bool CBrowseDialog::OnNotify(UINT /* controlID */, LPNMHDR header) |
| { |
| if (header->hwndFrom != _list) |
| return false; |
| switch (header->code) |
| { |
| case LVN_ITEMACTIVATE: |
| if (g_LVN_ITEMACTIVATE_Support) |
| OnItemEnter(); |
| break; |
| case NM_DBLCLK: |
| case NM_RETURN: // probabably it's unused |
| if (!g_LVN_ITEMACTIVATE_Support) |
| OnItemEnter(); |
| break; |
| case LVN_COLUMNCLICK: |
| { |
| const int index = LPNMLISTVIEW(header)->iSubItem; |
| if (index == _sortIndex) |
| _ascending = !_ascending; |
| else |
| { |
| _ascending = (index == 0); |
| _sortIndex = index; |
| } |
| Reload(); |
| return false; |
| } |
| case LVN_KEYDOWN: |
| { |
| bool boolResult = OnKeyDown(LPNMLVKEYDOWN(header)); |
| Post_RefreshPathEdit(); |
| return boolResult; |
| } |
| case NM_RCLICK: |
| case NM_CLICK: |
| case LVN_BEGINDRAG: |
| Post_RefreshPathEdit(); |
| break; |
| } |
| return false; |
| } |
| |
| bool CBrowseDialog::OnKeyDown(LPNMLVKEYDOWN keyDownInfo) |
| { |
| const bool ctrl = IsKeyDown(VK_CONTROL); |
| |
| switch (keyDownInfo->wVKey) |
| { |
| case VK_BACK: |
| OpenParentFolder(); |
| return true; |
| case 'R': |
| if (ctrl) |
| { |
| Reload(); |
| return true; |
| } |
| return false; |
| case VK_F7: |
| OnCreateDir(); |
| return true; |
| } |
| return false; |
| } |
| |
| |
| bool CBrowseDialog::OnButtonClicked(unsigned buttonID, HWND buttonHWND) |
| { |
| switch (buttonID) |
| { |
| case IDB_BROWSE_PARENT: OpenParentFolder(); break; |
| case IDB_BROWSE_CREATE_DIR: OnCreateDir(); break; |
| default: return CModalDialog::OnButtonClicked(buttonID, buttonHWND); |
| } |
| _list.SetFocus(); |
| return true; |
| } |
| |
| void CBrowseDialog::OnOK() |
| { |
| /* When we press "Enter" in listview, Windows sends message to first Button. |
| We check that message was from ListView; */ |
| if (GetFocus() == _list) |
| { |
| OnItemEnter(); |
| return; |
| } |
| FinishOnOK(); |
| } |
| |
| |
| bool CBrowseDialog::GetParentPath(const UString &path, UString &parentPrefix, UString &name) |
| { |
| parentPrefix.Empty(); |
| name.Empty(); |
| if (path.IsEmpty()) |
| return false; |
| if (_topDirPrefix == path) |
| return false; |
| UString s = path; |
| if (IS_PATH_SEPAR(s.Back())) |
| s.DeleteBack(); |
| if (s.IsEmpty()) |
| return false; |
| if (IS_PATH_SEPAR(s.Back())) |
| return false; |
| const unsigned pos1 = (unsigned)(s.ReverseFind_PathSepar() + 1); |
| parentPrefix.SetFrom(s, pos1); |
| name = s.Ptr(pos1); |
| return true; |
| } |
| |
| int CBrowseDialog::CompareItems(LPARAM lParam1, LPARAM lParam2) const |
| { |
| if (lParam1 == kParentIndex) return -1; |
| if (lParam2 == kParentIndex) return 1; |
| const CFileInfo &f1 = _files[(int)lParam1]; |
| const CFileInfo &f2 = _files[(int)lParam2]; |
| |
| const bool isDir1 = f1.IsDir(); |
| const bool isDir2 = f2.IsDir(); |
| if (isDir1 && !isDir2) return -1; |
| if (isDir2 && !isDir1) return 1; |
| |
| int res = 0; |
| switch (_sortIndex) |
| { |
| case 0: res = CompareFileNames(fs2us(f1.Name), fs2us(f2.Name)); break; |
| case 1: res = CompareFileTime(&f1.MTime, &f2.MTime); break; |
| case 2: res = MyCompare(f1.Size, f2.Size); break; |
| } |
| return _ascending ? res: -res; |
| } |
| |
| static int CALLBACK CompareItems2(LPARAM lParam1, LPARAM lParam2, LPARAM lpData) |
| { |
| return ((CBrowseDialog *)lpData)->CompareItems(lParam1, lParam2); |
| } |
| |
| static void ConvertSizeToString(UInt64 v, wchar_t *s) |
| { |
| char c = 0; |
| if (v >= ((UInt64)10000 << 20)) { v >>= 30; c = 'G'; } |
| else if (v >= ((UInt64)10000 << 10)) { v >>= 20; c = 'M'; } |
| else if (v >= ((UInt64)10000 << 0)) { v >>= 10; c = 'K'; } |
| s = ConvertUInt64ToString(v, s); |
| if (c != 0) |
| { |
| *s++ = ' '; |
| *s++ = (wchar_t)c; |
| *s++ = 'B'; |
| *s++ = 0; |
| } |
| } |
| |
| // Reload changes DirPrefix. Don't send DirPrefix in pathPrefix parameter |
| |
| HRESULT CBrowseDialog::Reload(const UString &pathPrefix, const UString &selectedName) |
| { |
| CObjectVector<CFileInfo> files; |
| |
| #ifndef UNDER_CE |
| bool isDrive = false; |
| if (pathPrefix.IsEmpty() || pathPrefix.IsEqualTo(kSuperPathPrefix)) |
| { |
| isDrive = true; |
| FStringVector drives; |
| if (!MyGetLogicalDriveStrings(drives)) |
| return GetLastError_noZero_HRESULT(); |
| FOR_VECTOR (i, drives) |
| { |
| const FString &d = drives[i]; |
| if (d.Len() < 2 || d.Back() != '\\') |
| return E_FAIL; |
| CFileInfo &fi = files.AddNew(); |
| fi.SetAsDir(); |
| fi.Name = d; |
| fi.Name.DeleteBack(); |
| } |
| } |
| else |
| #endif |
| { |
| const UStringVector *masks = NULL; |
| if (!Filters.IsEmpty() && _filterCombo.GetCount() > 0) |
| { |
| const int selected = _filterCombo.GetCurSel(); |
| // GetItemData_of_CurSel(); // we don't use data field |
| if (/* selected >= 0 && */ (unsigned)selected < Filters.Size()) |
| { |
| const UStringVector &m = Filters[selected].Masks; |
| if (m.Size() > 1 || (m.Size() == 1 |
| && !m[0].IsEqualTo("*.*") |
| && !m[0].IsEqualTo("*"))) |
| masks = &m; |
| } |
| } |
| CEnumerator enumerator; |
| enumerator.SetDirPrefix(us2fs(pathPrefix)); |
| CFileInfo fi; |
| for (;;) |
| { |
| bool found; |
| if (!enumerator.Next(fi, found)) |
| return GetLastError_noZero_HRESULT(); |
| if (!found) |
| break; |
| if (!fi.IsDir()) |
| { |
| if (FolderMode) |
| continue; |
| if (masks) |
| { |
| unsigned i; |
| const unsigned numMasks = masks->Size(); |
| for (i = 0; i < numMasks; i++) |
| if (DoesWildcardMatchName((*masks)[i], fs2us(fi.Name))) |
| break; |
| if (i == numMasks) |
| continue; |
| } |
| } |
| files.Add(fi); |
| } |
| } |
| |
| DirPrefix = pathPrefix; |
| |
| _files = files; |
| |
| SetItemText(IDT_BROWSE_FOLDER, DirPrefix); |
| |
| _list.SetRedraw(false); |
| _list.DeleteAllItems(); |
| |
| LVITEMW item; |
| |
| unsigned index = 0; |
| int cursorIndex = -1; |
| |
| #ifndef Z7_SFX |
| if (_showDots && _topDirPrefix != DirPrefix) |
| { |
| item.iItem = (int)index; |
| const UString itemName (".."); |
| if (selectedName.IsEmpty()) |
| cursorIndex = (int)index; |
| item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE; |
| unsigned subItem = 0; |
| item.iSubItem = (int)(subItem++); |
| item.lParam = kParentIndex; |
| item.pszText = itemName.Ptr_non_const(); |
| item.iImage = _extToIconMap.GetIconIndex(FILE_ATTRIBUTE_DIRECTORY, DirPrefix); |
| if (item.iImage < 0) |
| item.iImage = 0; |
| _list.InsertItem(&item); |
| _list.SetSubItem(index, subItem++, L""); |
| _list.SetSubItem(index, subItem++, L""); |
| index++; |
| } |
| #endif |
| |
| for (unsigned i = 0; i < _files.Size(); i++, index++) |
| { |
| item.iItem = (int)index; |
| const CFileInfo &fi = _files[i]; |
| const UString name = fs2us(fi.Name); |
| if (!selectedName.IsEmpty() && CompareFileNames(name, selectedName) == 0) |
| cursorIndex = (int)index; |
| item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE; |
| unsigned subItem = 0; |
| item.iSubItem = (int)(subItem++); |
| item.lParam = (LPARAM)i; |
| item.pszText = name.Ptr_non_const(); |
| |
| const UString fullPath = DirPrefix + name; |
| #ifndef UNDER_CE |
| if (isDrive) |
| { |
| if (GetRealIconIndex(fi.Name + FCHAR_PATH_SEPARATOR, FILE_ATTRIBUTE_DIRECTORY, item.iImage) == 0) |
| item.iImage = 0; |
| } |
| else |
| #endif |
| item.iImage = _extToIconMap.GetIconIndex(fi.Attrib, fullPath); |
| if (item.iImage < 0) |
| item.iImage = 0; |
| _list.InsertItem(&item); |
| wchar_t s[32]; |
| { |
| s[0] = 0; |
| ConvertUtcFileTimeToString(fi.MTime, s, |
| #ifndef UNDER_CE |
| kTimestampPrintLevel_MIN |
| #else |
| kTimestampPrintLevel_DAY |
| #endif |
| ); |
| _list.SetSubItem(index, subItem++, s); |
| } |
| { |
| s[0] = 0; |
| if (!fi.IsDir()) |
| ConvertSizeToString(fi.Size, s); |
| _list.SetSubItem(index, subItem++, s); |
| } |
| } |
| |
| if (_list.GetItemCount() > 0 && cursorIndex >= 0) |
| _list.SetItemState_FocusedSelected(cursorIndex); |
| _list.SortItems(CompareItems2, (LPARAM)this); |
| if (_list.GetItemCount() > 0 && cursorIndex < 0) |
| _list.SetItemState(0, LVIS_FOCUSED, LVIS_FOCUSED); |
| _list.EnsureVisible(_list.GetFocusedItem(), false); |
| _list.SetRedraw(true); |
| _list.InvalidateRect(NULL, true); |
| return S_OK; |
| } |
| |
| HRESULT CBrowseDialog::Reload() |
| { |
| UString selected; |
| const int index = _list.GetNextSelectedItem(-1); |
| if (index >= 0) |
| { |
| const int fileIndex = GetRealItemIndex(index); |
| if (fileIndex != kParentIndex) |
| selected = fs2us(_files[fileIndex].Name); |
| } |
| const UString dirPathTemp = DirPrefix; |
| return Reload(dirPathTemp, selected); |
| } |
| |
| void CBrowseDialog::OpenParentFolder() |
| { |
| UString parent, selected; |
| if (GetParentPath(DirPrefix, parent, selected)) |
| { |
| Reload(parent, selected); |
| SetPathEditText(); |
| } |
| } |
| |
| void CBrowseDialog::SetPathEditText() |
| { |
| const int index = _list.GetNextSelectedItem(-1); |
| if (index < 0) |
| { |
| if (FolderMode) |
| _pathEdit.SetText(DirPrefix); |
| return; |
| } |
| const int fileIndex = GetRealItemIndex(index); |
| if (fileIndex == kParentIndex) |
| { |
| if (FolderMode) |
| _pathEdit.SetText(L".." WSTRING_PATH_SEPARATOR); |
| return; |
| } |
| const CFileInfo &file = _files[fileIndex]; |
| if (file.IsDir()) |
| { |
| if (!FolderMode) |
| return; |
| _pathEdit.SetText(fs2us(file.Name) + WCHAR_PATH_SEPARATOR); |
| } |
| else |
| _pathEdit.SetText(fs2us(file.Name)); |
| } |
| |
| void CBrowseDialog::OnCreateDir() |
| { |
| UString name; |
| { |
| UString enteredName; |
| Dlg_CreateFolder((HWND)*this, enteredName); |
| if (enteredName.IsEmpty()) |
| return; |
| if (!CorrectFsPath(DirPrefix, enteredName, name)) |
| { |
| MessageBox_HResError((HWND)*this, ERROR_INVALID_NAME, name); |
| return; |
| } |
| } |
| if (name.IsEmpty()) |
| return; |
| |
| FString destPath; |
| if (GetFullPath(us2fs(DirPrefix), us2fs(name), destPath)) |
| { |
| if (!NDir::CreateComplexDir(destPath)) |
| { |
| MessageBox_HResError((HWND)*this, GetLastError_noZero_HRESULT(), fs2us(destPath)); |
| } |
| else |
| { |
| UString tempPath = DirPrefix; |
| Reload(tempPath, name); |
| SetPathEditText(); |
| } |
| _list.SetFocus(); |
| } |
| } |
| |
| void CBrowseDialog::OnItemEnter() |
| { |
| const int index = _list.GetNextSelectedItem(-1); |
| if (index < 0) |
| return; |
| const int fileIndex = GetRealItemIndex(index); |
| if (fileIndex == kParentIndex) |
| OpenParentFolder(); |
| else |
| { |
| const CFileInfo &file = _files[fileIndex]; |
| if (!file.IsDir()) |
| { |
| if (!FolderMode) |
| FinishOnOK(); |
| /* |
| MessageBox_Error_Global(*this, FolderMode ? |
| L"You must select some folder": |
| L"You must select some file"); |
| */ |
| return; |
| } |
| UString s = DirPrefix; |
| s += fs2us(file.Name); |
| s.Add_PathSepar(); |
| const HRESULT res = Reload(s, UString()); |
| if (res != S_OK) |
| MessageBox_HResError(*this, res, s); |
| SetPathEditText(); |
| } |
| } |
| |
| void CBrowseDialog::FinishOnOK() |
| { |
| UString s; |
| _pathEdit.GetText(s); |
| FString destPath; |
| if (!GetFullPath(us2fs(DirPrefix), us2fs(s), destPath)) |
| { |
| MessageBox_HResError((HWND)*this, ERROR_INVALID_NAME, s); |
| return; |
| } |
| FilePath = fs2us(destPath); |
| if (FolderMode) |
| NormalizeDirPathPrefix(FilePath); |
| FilterIndex = _filterCombo.GetCurSel(); |
| End(IDOK); |
| } |
| |
| #endif // USE_MY_BROWSE_DIALOG |
| |
| |
| |
| bool MyBrowseForFolder(HWND owner, LPCWSTR title, LPCWSTR path, UString &resultPath) |
| { |
| resultPath.Empty(); |
| |
| #ifndef UNDER_CE |
| |
| #ifdef USE_MY_BROWSE_DIALOG |
| if (!IsSuperOrDevicePath(path)) |
| if (MyStringLen(path) < MAX_PATH) |
| #endif |
| return NShell::BrowseForFolder(owner, title, path, resultPath); |
| |
| #endif // UNDER_CE |
| |
| #ifdef USE_MY_BROWSE_DIALOG |
| |
| CBrowseDialog dialog; |
| dialog.FolderMode = true; |
| if (title) |
| dialog.Title = title; |
| if (path) |
| dialog.FilePath = path; |
| if (dialog.Create(owner) != IDOK) |
| return false; |
| resultPath = dialog.FilePath; |
| return true; |
| |
| #endif |
| } |
| |
| |
| // LPCWSTR filterDescription, LPCWSTR filter, |
| |
| bool CBrowseInfo::BrowseForFile(const CObjectVector<CBrowseFilterInfo> &filters) |
| { |
| #ifndef UNDER_CE |
| #ifdef USE_MY_BROWSE_DIALOG |
| /* win10: |
| GetOpenFileName() for FilePath doesn't support super prefix "\\\\?\\" |
| GetOpenFileName() for FilePath doesn't support long path |
| */ |
| if (!IsSuperOrDevicePath(FilePath)) |
| // if (filters.Size() > 100) // for debug |
| #endif |
| { |
| const UString filePath_Store = FilePath; |
| UString dirPrefix; |
| { |
| FString prefix, name; |
| if (NDir::GetFullPathAndSplit(us2fs(FilePath), prefix, name)) |
| { |
| dirPrefix = fs2us(prefix); |
| FilePath = fs2us(name); |
| } |
| } |
| UStringVector filters2; |
| FOR_VECTOR (i, filters) |
| { |
| const CBrowseFilterInfo &fi = filters[i]; |
| filters2.Add(fi.Description); |
| UString s; |
| FOR_VECTOR (k, fi.Masks) |
| { |
| if (k != 0) |
| s += ";"; |
| s += fi.Masks[k]; |
| } |
| filters2.Add(s); |
| } |
| if (CommonDlg_BrowseForFile(!dirPrefix.IsEmpty() ? dirPrefix.Ptr(): NULL, filters2)) |
| return true; |
| FilePath = filePath_Store; |
| |
| #ifdef UNDER_CE |
| return false; |
| #else |
| // maybe we must use GetLastError in WinCE. |
| const DWORD errorCode = CommDlgExtendedError(); |
| #ifdef USE_MY_BROWSE_DIALOG |
| // FNERR_INVALIDFILENAME is expected error, if long path was used |
| if (errorCode != FNERR_INVALIDFILENAME |
| || FilePath.Len() < MAX_PATH) |
| #endif |
| { |
| if (errorCode == 0) // cancel or close on dialog |
| return false; |
| const char *message = NULL; |
| if (errorCode == FNERR_INVALIDFILENAME) |
| message = "Invalid file name"; |
| UString s ("Open Dialog Error:"); |
| s.Add_LF(); |
| if (message) |
| s += message; |
| else |
| { |
| char temp[16]; |
| ConvertUInt32ToHex8Digits(errorCode, temp); |
| s += "Error #"; |
| s += temp; |
| } |
| s.Add_LF(); |
| s += FilePath; |
| MessageBox_Error_Global(hwndOwner, s); |
| } |
| #endif // UNDER_CE |
| } |
| |
| #endif // UNDER_CE |
| |
| #ifdef USE_MY_BROWSE_DIALOG |
| |
| CBrowseDialog dialog; |
| |
| dialog.FolderMode = false; |
| dialog.SaveMode = SaveMode; |
| dialog.FilterIndex = FilterIndex; |
| dialog.Filters = filters; |
| |
| if (lpstrTitle) |
| dialog.Title = lpstrTitle; |
| dialog.FilePath = FilePath; |
| if (dialog.Create(hwndOwner) != IDOK) |
| return false; |
| FilePath = dialog.FilePath; |
| FilterIndex = dialog.FilterIndex; |
| #endif |
| |
| return true; |
| } |
| |
| |
| #ifdef _WIN32 |
| |
| static void RemoveDotsAndSpaces(UString &path) |
| { |
| while (!path.IsEmpty()) |
| { |
| wchar_t c = path.Back(); |
| if (c != ' ' && c != '.') |
| return; |
| path.DeleteBack(); |
| } |
| } |
| |
| |
| bool CorrectFsPath(const UString &relBase, const UString &path2, UString &result) |
| { |
| result.Empty(); |
| |
| UString path = path2; |
| #ifdef _WIN32 |
| path.Replace(L'/', WCHAR_PATH_SEPARATOR); |
| #endif |
| unsigned start = 0; |
| UString base; |
| |
| if (IsAbsolutePath(path)) |
| { |
| #if defined(_WIN32) && !defined(UNDER_CE) |
| if (IsSuperOrDevicePath(path)) |
| { |
| result = path; |
| return true; |
| } |
| #endif |
| start = GetRootPrefixSize(path); |
| } |
| else |
| { |
| #if defined(_WIN32) && !defined(UNDER_CE) |
| if (IsSuperOrDevicePath(relBase)) |
| { |
| result = path; |
| return true; |
| } |
| #endif |
| base = relBase; |
| } |
| |
| /* We can't use backward, since we must change only disk paths */ |
| /* |
| for (;;) |
| { |
| if (path.Len() <= start) |
| break; |
| if (DoesFileOrDirExist(us2fs(path))) |
| break; |
| if (path.Back() == WCHAR_PATH_SEPARATOR) |
| { |
| path.DeleteBack(); |
| result.Insert(0, WCHAR_PATH_SEPARATOR); |
| } |
| int pos = path.ReverseFind(WCHAR_PATH_SEPARATOR) + 1; |
| UString cur = path.Ptr(pos); |
| RemoveDotsAndSpaces(cur); |
| result.Insert(0, cur); |
| path.DeleteFrom(pos); |
| } |
| result.Insert(0, path); |
| return true; |
| */ |
| |
| result += path.Left(start); |
| bool checkExist = true; |
| UString cur; |
| |
| for (;;) |
| { |
| if (start == path.Len()) |
| break; |
| const int slashPos = path.Find(WCHAR_PATH_SEPARATOR, start); |
| cur.SetFrom(path.Ptr(start), (slashPos < 0 ? path.Len() : (unsigned)slashPos) - start); |
| if (checkExist) |
| { |
| CFileInfo fi; |
| if (fi.Find(us2fs(base + result + cur))) |
| { |
| if (!fi.IsDir()) |
| { |
| result = path; |
| break; |
| } |
| } |
| else |
| checkExist = false; |
| } |
| if (!checkExist) |
| RemoveDotsAndSpaces(cur); |
| result += cur; |
| if (slashPos < 0) |
| break; |
| start = (unsigned)(slashPos + 1); |
| result.Add_PathSepar(); |
| } |
| |
| return true; |
| } |
| |
| #else |
| |
| bool CorrectFsPath(const UString & /* relBase */, const UString &path, UString &result) |
| { |
| result = path; |
| return true; |
| } |
| |
| #endif |
| |
| bool Dlg_CreateFolder(HWND wnd, UString &destName) |
| { |
| destName.Empty(); |
| CComboDialog dlg; |
| LangString(IDS_CREATE_FOLDER, dlg.Title); |
| LangString(IDS_CREATE_FOLDER_NAME, dlg.Static); |
| LangString(IDS_CREATE_FOLDER_DEFAULT_NAME, dlg.Value); |
| if (dlg.Create(wnd) != IDOK) |
| return false; |
| destName = dlg.Value; |
| return true; |
| } |