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 }