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