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 = L"*.*"; 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 (s.Back() == WCHAR_PATH_SEPARATOR) 472 s.DeleteBack(); 473 if (s.IsEmpty()) 474 return false; 475 if (s.Back() == WCHAR_PATH_SEPARATOR) 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 == 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(us2fs(pathPrefix + L'*')); 555 for (;;) 556 { 557 bool found; 558 CFileInfo fi; 559 if (!enumerator.Next(fi, found)) 560 return GetNormalizedError(); 561 if (!found) 562 break; 563 if (!fi.IsDir()) 564 { 565 if (FolderMode) 566 continue; 567 if (!ShowAllFiles) 568 { 569 unsigned i; 570 for (i = 0; i < Filters.Size(); i++) 571 if (DoesWildcardMatchName(Filters[i], fs2us(fi.Name))) 572 break; 573 if (i == Filters.Size()) 574 continue; 575 } 576 } 577 files.Add(fi); 578 } 579 } 580 581 DirPrefix = pathPrefix; 582 583 _files = files; 584 585 SetItemText(IDT_BROWSE_FOLDER, DirPrefix); 586 587 _list.SetRedraw(false); 588 _list.DeleteAllItems(); 589 590 LVITEMW item; 591 592 int index = 0; 593 int cursorIndex = -1; 594 595 #ifndef _SFX 596 if (_showDots && _topDirPrefix != DirPrefix) 597 { 598 item.iItem = index; 599 const UString itemName = L".."; 600 if (selectedName.IsEmpty()) 601 cursorIndex = index; 602 item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE; 603 int subItem = 0; 604 item.iSubItem = subItem++; 605 item.lParam = kParentIndex; 606 item.pszText = (wchar_t *)(const wchar_t *)itemName; 607 item.iImage = _extToIconMap.GetIconIndex(FILE_ATTRIBUTE_DIRECTORY, DirPrefix); 608 if (item.iImage < 0) 609 item.iImage = 0; 610 _list.InsertItem(&item); 611 _list.SetSubItem(index, subItem++, L""); 612 _list.SetSubItem(index, subItem++, L""); 613 index++; 614 } 615 #endif 616 617 for (unsigned i = 0; i < _files.Size(); i++, index++) 618 { 619 item.iItem = index; 620 const CFileInfo &fi = _files[i]; 621 const UString name = fs2us(fi.Name); 622 if (!selectedName.IsEmpty() && CompareFileNames(name, selectedName) == 0) 623 cursorIndex = index; 624 item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE; 625 int subItem = 0; 626 item.iSubItem = subItem++; 627 item.lParam = i; 628 item.pszText = (wchar_t *)(const wchar_t *)name; 629 630 const UString fullPath = DirPrefix + name; 631 #ifndef UNDER_CE 632 if (isDrive) 633 { 634 if (GetRealIconIndex(fi.Name + FCHAR_PATH_SEPARATOR, FILE_ATTRIBUTE_DIRECTORY, item.iImage) == 0) 635 item.iImage = 0; 636 } 637 else 638 #endif 639 item.iImage = _extToIconMap.GetIconIndex(fi.Attrib, fullPath); 640 if (item.iImage < 0) 641 item.iImage = 0; 642 _list.InsertItem(&item); 643 wchar_t s[32]; 644 { 645 FILETIME ft; 646 s[0] = 0; 647 if (FileTimeToLocalFileTime(&fi.MTime, &ft)) 648 ConvertFileTimeToString(ft, s, 649 #ifndef UNDER_CE 650 true 651 #else 652 false 653 #endif 654 , false); 655 _list.SetSubItem(index, subItem++, s); 656 } 657 { 658 s[0] = 0; 659 if (!fi.IsDir()) 660 ConvertSizeToString(fi.Size, s); 661 _list.SetSubItem(index, subItem++, s); 662 } 663 } 664 665 if (_list.GetItemCount() > 0 && cursorIndex >= 0) 666 _list.SetItemState_FocusedSelected(cursorIndex); 667 _list.SortItems(CompareItems2, (LPARAM)this); 668 if (_list.GetItemCount() > 0 && cursorIndex < 0) 669 _list.SetItemState(0, LVIS_FOCUSED, LVIS_FOCUSED); 670 _list.EnsureVisible(_list.GetFocusedItem(), false); 671 _list.SetRedraw(true); 672 _list.InvalidateRect(NULL, true); 673 return S_OK; 674 } 675 676 HRESULT CBrowseDialog::Reload() 677 { 678 UString selected; 679 int index = _list.GetNextSelectedItem(-1); 680 if (index >= 0) 681 { 682 int fileIndex = GetRealItemIndex(index); 683 if (fileIndex != kParentIndex) 684 selected = fs2us(_files[fileIndex].Name); 685 } 686 UString dirPathTemp = DirPrefix; 687 return Reload(dirPathTemp, selected); 688 } 689 690 void CBrowseDialog::OpenParentFolder() 691 { 692 UString parent, selected; 693 if (GetParentPath(DirPrefix, parent, selected)) 694 { 695 Reload(parent, selected); 696 SetPathEditText(); 697 } 698 } 699 700 void CBrowseDialog::SetPathEditText() 701 { 702 int index = _list.GetNextSelectedItem(-1); 703 if (index < 0) 704 { 705 if (FolderMode) 706 _pathEdit.SetText(DirPrefix); 707 return; 708 } 709 int fileIndex = GetRealItemIndex(index); 710 if (fileIndex == kParentIndex) 711 { 712 if (FolderMode) 713 _pathEdit.SetText(L".." WSTRING_PATH_SEPARATOR); 714 return; 715 } 716 const CFileInfo &file = _files[fileIndex]; 717 if (file.IsDir()) 718 { 719 if (!FolderMode) 720 return; 721 _pathEdit.SetText(fs2us(file.Name) + WCHAR_PATH_SEPARATOR); 722 } 723 else 724 _pathEdit.SetText(fs2us(file.Name)); 725 } 726 727 void CBrowseDialog::OnCreateDir() 728 { 729 UString name; 730 { 731 UString enteredName; 732 Dlg_CreateFolder((HWND)*this, enteredName); 733 if (enteredName.IsEmpty()) 734 return; 735 if (!CorrectFsPath(DirPrefix, enteredName, name)) 736 { 737 MessageBox_HResError((HWND)*this, ERROR_INVALID_NAME, name); 738 return; 739 } 740 } 741 if (name.IsEmpty()) 742 return; 743 744 FString destPath; 745 if (GetFullPath(us2fs(DirPrefix), us2fs(name), destPath)) 746 { 747 if (!NDir::CreateComplexDir(destPath)) 748 { 749 MessageBox_HResError((HWND)*this, GetNormalizedError(), fs2us(destPath)); 750 } 751 else 752 { 753 UString tempPath = DirPrefix; 754 Reload(tempPath, name); 755 SetPathEditText(); 756 } 757 _list.SetFocus(); 758 } 759 } 760 761 void CBrowseDialog::OnItemEnter() 762 { 763 int index = _list.GetNextSelectedItem(-1); 764 if (index < 0) 765 return; 766 int fileIndex = GetRealItemIndex(index); 767 if (fileIndex == kParentIndex) 768 OpenParentFolder(); 769 else 770 { 771 const CFileInfo &file = _files[fileIndex]; 772 if (!file.IsDir()) 773 { 774 if (!FolderMode) 775 FinishOnOK(); 776 /* 777 MessageBox_Error_Global(*this, FolderMode ? 778 L"You must select some folder": 779 L"You must select some file"); 780 */ 781 return; 782 } 783 UString s = DirPrefix + fs2us(file.Name) + WCHAR_PATH_SEPARATOR; 784 HRESULT res = Reload(s, L""); 785 if (res != S_OK) 786 MessageBox_HResError(*this, res, s); 787 SetPathEditText(); 788 } 789 } 790 791 void CBrowseDialog::FinishOnOK() 792 { 793 UString s; 794 _pathEdit.GetText(s); 795 FString destPath; 796 if (!GetFullPath(us2fs(DirPrefix), us2fs(s), destPath)) 797 { 798 MessageBox_HResError((HWND)*this, ERROR_INVALID_NAME, s); 799 return; 800 } 801 FilePath = fs2us(destPath); 802 if (FolderMode) 803 NormalizeDirPathPrefix(FilePath); 804 End(IDOK); 805 } 806 807 #endif 808 809 bool MyBrowseForFolder(HWND owner, LPCWSTR title, LPCWSTR path, UString &resultPath) 810 { 811 resultPath.Empty(); 812 813 #ifndef UNDER_CE 814 815 #ifdef USE_MY_BROWSE_DIALOG 816 if (!IsSuperOrDevicePath(path)) 817 #endif 818 return NShell::BrowseForFolder(owner, title, path, resultPath); 819 820 #endif 821 822 #ifdef USE_MY_BROWSE_DIALOG 823 824 CBrowseDialog dialog; 825 dialog.FolderMode = true; 826 if (title) 827 dialog.Title = title; 828 if (path) 829 dialog.FilePath = path; 830 if (dialog.Create(owner) != IDOK) 831 return false; 832 resultPath = dialog.FilePath; 833 #endif 834 835 return true; 836 } 837 838 bool MyBrowseForFile(HWND owner, LPCWSTR title, LPCWSTR path, 839 LPCWSTR filterDescription, LPCWSTR filter, UString &resultPath) 840 { 841 resultPath.Empty(); 842 843 #ifndef UNDER_CE 844 845 #ifdef USE_MY_BROWSE_DIALOG 846 if (!IsSuperOrDevicePath(path)) 847 #endif 848 { 849 if (MyGetOpenFileName(owner, title, NULL, path, filterDescription, filter, resultPath)) 850 return true; 851 #ifdef UNDER_CE 852 return false; 853 #else 854 // maybe we must use GetLastError in WinCE. 855 DWORD errorCode = CommDlgExtendedError(); 856 const wchar_t *errorMessage = NULL; 857 switch (errorCode) 858 { 859 case 0: return false; // cancel or close obn dialog 860 case FNERR_INVALIDFILENAME: errorMessage = L"Invalid File Name"; break; 861 default: errorMessage = L"Open Dialog Error"; 862 } 863 if (!errorMessage) 864 return false; 865 { 866 UString s = errorMessage; 867 s.Add_LF(); 868 s += path; 869 MessageBox_Error_Global(owner, s); 870 } 871 #endif 872 } 873 874 #endif 875 876 #ifdef USE_MY_BROWSE_DIALOG 877 CBrowseDialog dialog; 878 if (title) 879 dialog.Title = title; 880 if (path) 881 dialog.FilePath = path; 882 dialog.FolderMode = false; 883 if (filter) 884 dialog.SetFilter(filter); 885 if (filterDescription) 886 dialog.FilterDescription = filterDescription; 887 if (dialog.Create(owner) != IDOK) 888 return false; 889 resultPath = dialog.FilePath; 890 #endif 891 892 return true; 893 } 894 895 896 #ifdef _WIN32 897 898 static void RemoveDotsAndSpaces(UString &path) 899 { 900 while (!path.IsEmpty()) 901 { 902 wchar_t c = path.Back(); 903 if (c != ' ' && c != '.') 904 return; 905 path.DeleteBack(); 906 } 907 } 908 909 910 bool CorrectFsPath(const UString &relBase, const UString &path2, UString &result) 911 { 912 result.Empty(); 913 914 UString path = path2; 915 path.Replace(L'/', WCHAR_PATH_SEPARATOR); 916 unsigned start = 0; 917 UString base; 918 919 if (IsAbsolutePath(path)) 920 { 921 #if defined(_WIN32) && !defined(UNDER_CE) 922 if (IsSuperOrDevicePath(path)) 923 { 924 result = path; 925 return true; 926 } 927 #endif 928 int pos = GetRootPrefixSize(path); 929 if (pos > 0) 930 start = pos; 931 } 932 else 933 { 934 #if defined(_WIN32) && !defined(UNDER_CE) 935 if (IsSuperOrDevicePath(relBase)) 936 { 937 result = path; 938 return true; 939 } 940 #endif 941 base = relBase; 942 } 943 944 /* We can't use backward, since we must change only disk paths */ 945 /* 946 for (;;) 947 { 948 if (path.Len() <= start) 949 break; 950 if (DoesFileOrDirExist(us2fs(path))) 951 break; 952 if (path.Back() == WCHAR_PATH_SEPARATOR) 953 { 954 path.DeleteBack(); 955 result.Insert(0, WCHAR_PATH_SEPARATOR);; 956 } 957 int pos = path.ReverseFind(WCHAR_PATH_SEPARATOR) + 1; 958 UString cur = path.Ptr(pos); 959 RemoveDotsAndSpaces(cur); 960 result.Insert(0, cur); 961 path.DeleteFrom(pos); 962 } 963 result.Insert(0, path); 964 return true; 965 */ 966 967 result += path.Left(start); 968 bool checkExist = true; 969 UString cur; 970 971 for (;;) 972 { 973 if (start == path.Len()) 974 break; 975 int slashPos = path.Find(WCHAR_PATH_SEPARATOR, start); 976 cur.SetFrom(path.Ptr(start), (slashPos < 0 ? path.Len() : slashPos) - start); 977 if (checkExist) 978 { 979 CFileInfo fi; 980 if (fi.Find(us2fs(base + result + cur))) 981 { 982 if (!fi.IsDir()) 983 { 984 result = path; 985 break; 986 } 987 } 988 else 989 checkExist = false; 990 } 991 if (!checkExist) 992 RemoveDotsAndSpaces(cur); 993 result += cur; 994 if (slashPos < 0) 995 break; 996 result.Add_PathSepar(); 997 start = slashPos + 1; 998 } 999 1000 return true; 1001 } 1002 1003 #else 1004 1005 bool CorrectFsPath(const UString & /* relBase */, const UString &path, UString &result) 1006 { 1007 result = path; 1008 return true; 1009 } 1010 1011 #endif 1012 1013 bool Dlg_CreateFolder(HWND wnd, UString &destName) 1014 { 1015 destName.Empty(); 1016 CComboDialog dlg; 1017 LangString(IDS_CREATE_FOLDER, dlg.Title); 1018 LangString(IDS_CREATE_FOLDER_NAME, dlg.Static); 1019 LangString(IDS_CREATE_FOLDER_DEFAULT_NAME, dlg.Value); 1020 if (dlg.Create(wnd) != IDOK) 1021 return false; 1022 destName = dlg.Value; 1023 return true; 1024 } 1025