Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(244)

Side by Side Diff: ui/base/dialogs/select_file_dialog_win.cc

Issue 10698168: Part 3 of Move SelectFileDialog implementation to ui/base/dialogs/ (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: More namespace to force rebuild. Created 8 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/ui/select_file_dialog.h" 5 #include "ui/base/dialogs/select_file_dialog_win.h"
6 6
7 #include <windows.h> 7 #include <windows.h>
8 #include <commdlg.h> 8 #include <commdlg.h>
9 #include <shlobj.h> 9 #include <shlobj.h>
10 10
11 #include <algorithm> 11 #include <algorithm>
12 #include <set> 12 #include <set>
13 13
14 #include "base/bind.h" 14 #include "base/bind.h"
15 #include "base/file_path.h" 15 #include "base/file_path.h"
16 #include "base/file_util.h" 16 #include "base/file_util.h"
17 #include "base/i18n/case_conversion.h" 17 #include "base/i18n/case_conversion.h"
18 #include "base/message_loop.h" 18 #include "base/message_loop.h"
19 #include "base/string_split.h" 19 #include "base/string_split.h"
20 #include "base/threading/thread.h" 20 #include "base/threading/thread.h"
21 #include "base/utf_string_conversions.h" 21 #include "base/utf_string_conversions.h"
22 #include "base/win/metro.h" 22 #include "base/win/metro.h"
23 #include "base/win/registry.h" 23 #include "base/win/registry.h"
24 #include "base/win/scoped_comptr.h" 24 #include "base/win/scoped_comptr.h"
25 #include "base/win/windows_version.h" 25 #include "base/win/windows_version.h"
26 #include "chrome/browser/ui/views/base_shell_dialog_win.h"
27 #include "content/public/browser/browser_thread.h"
28 #include "grit/generated_resources.h"
29 #include "grit/ui_strings.h" 26 #include "grit/ui_strings.h"
27 #include "ui/base/dialogs/base_shell_dialog_win.h"
30 #include "ui/base/l10n/l10n_util.h" 28 #include "ui/base/l10n/l10n_util.h"
31 29 #include "ui/gfx/native_widget_types.h"
32 using content::BrowserThread;
33 30
34 namespace { 31 namespace {
35 32
36 // Given |extension|, if it's not empty, then remove the leading dot. 33 // Given |extension|, if it's not empty, then remove the leading dot.
37 std::wstring GetExtensionWithoutLeadingDot(const std::wstring& extension) { 34 std::wstring GetExtensionWithoutLeadingDot(const std::wstring& extension) {
38 DCHECK(extension.empty() || extension[0] == L'.'); 35 DCHECK(extension.empty() || extension[0] == L'.');
39 return extension.empty() ? extension : extension.substr(1); 36 return extension.empty() ? extension : extension.substr(1);
40 } 37 }
41 38
42 // Diverts to a metro-specific implementation as appropriate. 39 // Diverts to a metro-specific implementation as appropriate.
(...skipping 27 matching lines...) Expand all
70 NOTREACHED(); 67 NOTREACHED();
71 return false; 68 return false;
72 } 69 }
73 70
74 return metro_get_save_file_name(ofn) == TRUE; 71 return metro_get_save_file_name(ofn) == TRUE;
75 } else { 72 } else {
76 return GetSaveFileName(ofn) == TRUE; 73 return GetSaveFileName(ofn) == TRUE;
77 } 74 }
78 } 75 }
79 76
80 } // namespace
81
82 // This function takes the output of a SaveAs dialog: a filename, a filter and
83 // the extension originally suggested to the user (shown in the dialog box) and
84 // returns back the filename with the appropriate extension tacked on. If the
85 // user requests an unknown extension and is not using the 'All files' filter,
86 // the suggested extension will be appended, otherwise we will leave the
87 // filename unmodified. |filename| should contain the filename selected in the
88 // SaveAs dialog box and may include the path, |filter_selected| should be
89 // '*.something', for example '*.*' or it can be blank (which is treated as
90 // *.*). |suggested_ext| should contain the extension without the dot (.) in
91 // front, for example 'jpg'.
92 std::wstring AppendExtensionIfNeeded(const std::wstring& filename,
93 const std::wstring& filter_selected,
94 const std::wstring& suggested_ext) {
95 DCHECK(!filename.empty());
96 std::wstring return_value = filename;
97
98 // If we wanted a specific extension, but the user's filename deleted it or
99 // changed it to something that the system doesn't understand, re-append.
100 // Careful: Checking net::GetMimeTypeFromExtension() will only find
101 // extensions with a known MIME type, which many "known" extensions on Windows
102 // don't have. So we check directly for the "known extension" registry key.
103 std::wstring file_extension(
104 GetExtensionWithoutLeadingDot(FilePath(filename).Extension()));
105 std::wstring key(L"." + file_extension);
106 if (!(filter_selected.empty() || filter_selected == L"*.*") &&
107 !base::win::RegKey(HKEY_CLASSES_ROOT, key.c_str(), KEY_READ).Valid() &&
108 file_extension != suggested_ext) {
109 if (return_value[return_value.length() - 1] != L'.')
110 return_value.append(L".");
111 return_value.append(suggested_ext);
112 }
113
114 // Strip any trailing dots, which Windows doesn't allow.
115 size_t index = return_value.find_last_not_of(L'.');
116 if (index < return_value.size() - 1)
117 return_value.resize(index + 1);
118
119 return return_value;
120 }
121
122 namespace {
123
124 // Get the file type description from the registry. This will be "Text Document" 77 // Get the file type description from the registry. This will be "Text Document"
125 // for .txt files, "JPEG Image" for .jpg files, etc. If the registry doesn't 78 // for .txt files, "JPEG Image" for .jpg files, etc. If the registry doesn't
126 // have an entry for the file type, we return false, true if the description was 79 // have an entry for the file type, we return false, true if the description was
127 // found. 'file_ext' must be in form ".txt". 80 // found. 'file_ext' must be in form ".txt".
128 static bool GetRegistryDescriptionFromExtension(const std::wstring& file_ext, 81 static bool GetRegistryDescriptionFromExtension(const std::wstring& file_ext,
129 std::wstring* reg_description) { 82 std::wstring* reg_description) {
130 DCHECK(reg_description); 83 DCHECK(reg_description);
131 base::win::RegKey reg_ext(HKEY_CLASSES_ROOT, file_ext.c_str(), KEY_READ); 84 base::win::RegKey reg_ext(HKEY_CLASSES_ROOT, file_ext.c_str(), KEY_READ);
132 std::wstring reg_app; 85 std::wstring reg_app;
133 if (reg_ext.ReadValue(NULL, &reg_app) == ERROR_SUCCESS && !reg_app.empty()) { 86 if (reg_ext.ReadValue(NULL, &reg_app) == ERROR_SUCCESS && !reg_app.empty()) {
(...skipping 253 matching lines...) Expand 10 before | Expand all | Expand 10 after
387 suggested_ext = GetExtensionWithoutLeadingDot(suggested_path.Extension()); 340 suggested_ext = GetExtensionWithoutLeadingDot(suggested_path.Extension());
388 341
389 // If we can't get the extension from the suggested_name, we use the default 342 // If we can't get the extension from the suggested_name, we use the default
390 // extension passed in. This is to cover cases like when saving a web page, 343 // extension passed in. This is to cover cases like when saving a web page,
391 // where we get passed in a name without an extension and a default extension 344 // where we get passed in a name without an extension and a default extension
392 // along with it. 345 // along with it.
393 if (suggested_ext.empty()) 346 if (suggested_ext.empty())
394 suggested_ext = def_ext; 347 suggested_ext = def_ext;
395 348
396 *final_name = 349 *final_name =
397 AppendExtensionIfNeeded(*final_name, filter_selected, suggested_ext); 350 ui::AppendExtensionIfNeeded(*final_name, filter_selected, suggested_ext);
398 return true; 351 return true;
399 } 352 }
400 353
401 // Prompt the user for location to save a file. 'suggested_name' is a full path 354 // Prompt the user for location to save a file. 'suggested_name' is a full path
402 // that gives the dialog box a hint as to how to initialize itself. 355 // that gives the dialog box a hint as to how to initialize itself.
403 // For example, a 'suggested_name' of: 356 // For example, a 'suggested_name' of:
404 // "C:\Documents and Settings\jojo\My Documents\picture.png" 357 // "C:\Documents and Settings\jojo\My Documents\picture.png"
405 // will start the dialog in the "C:\Documents and Settings\jojo\My Documents\" 358 // will start the dialog in the "C:\Documents and Settings\jojo\My Documents\"
406 // directory, and filter for .png file types. 359 // directory, and filter for .png file types.
407 // 'owner' is the window to which the dialog box is modal, NULL for a modeless 360 // 'owner' is the window to which the dialog box is modal, NULL for a modeless
(...skipping 12 matching lines...) Expand all
420 unsigned index = 1; 373 unsigned index = 1;
421 return SaveFileAsWithFilter(owner, 374 return SaveFileAsWithFilter(owner,
422 suggested_name, 375 suggested_name,
423 filter, 376 filter,
424 L"", 377 L"",
425 false, 378 false,
426 &index, 379 &index,
427 final_name); 380 final_name);
428 } 381 }
429 382
430 } // namespace
431
432 // Implementation of SelectFileDialog that shows a Windows common dialog for 383 // Implementation of SelectFileDialog that shows a Windows common dialog for
433 // choosing a file or folder. 384 // choosing a file or folder.
434 class SelectFileDialogImpl : public SelectFileDialog, 385 class SelectFileDialogImpl : public ui::SelectFileDialog,
435 public BaseShellDialogImpl { 386 public ui::BaseShellDialogImpl {
436 public: 387 public:
437 explicit SelectFileDialogImpl(Listener* listener, 388 explicit SelectFileDialogImpl(Listener* listener,
438 ui::SelectFilePolicy* policy); 389 ui::SelectFilePolicy* policy);
439 390
440 // BaseShellDialog implementation: 391 // BaseShellDialog implementation:
441 virtual bool IsRunning(HWND owning_hwnd) const OVERRIDE; 392 virtual bool IsRunning(HWND owning_hwnd) const OVERRIDE;
442 virtual void ListenerDestroyed() OVERRIDE; 393 virtual void ListenerDestroyed() OVERRIDE;
443 394
444 protected: 395 protected:
445 // SelectFileDialog implementation: 396 // SelectFileDialog implementation:
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after
623 if (success) 574 if (success)
624 path = FilePath(path_as_wstring); 575 path = FilePath(path_as_wstring);
625 DisableOwner(params.run_state.owner); 576 DisableOwner(params.run_state.owner);
626 } else if (params.type == SELECT_OPEN_FILE) { 577 } else if (params.type == SELECT_OPEN_FILE) {
627 success = RunOpenFileDialog(params.title, filter, 578 success = RunOpenFileDialog(params.title, filter,
628 params.run_state.owner, &path); 579 params.run_state.owner, &path);
629 } else if (params.type == SELECT_OPEN_MULTI_FILE) { 580 } else if (params.type == SELECT_OPEN_MULTI_FILE) {
630 std::vector<FilePath> paths; 581 std::vector<FilePath> paths;
631 if (RunOpenMultiFileDialog(params.title, filter, 582 if (RunOpenMultiFileDialog(params.title, filter,
632 params.run_state.owner, &paths)) { 583 params.run_state.owner, &paths)) {
633 BrowserThread::PostTask( 584 params.run_state.dialog_thread->message_loop()->PostTask(
634 BrowserThread::UI,
635 FROM_HERE, 585 FROM_HERE,
636 base::Bind(&SelectFileDialogImpl::MultiFilesSelected, this, paths, 586 base::Bind(&SelectFileDialogImpl::MultiFilesSelected, this, paths,
637 params.params, params.run_state)); 587 params.params, params.run_state));
638 return; 588 return;
639 } 589 }
640 } 590 }
641 591
642 if (success) { 592 if (success) {
643 BrowserThread::PostTask( 593 params.run_state.dialog_thread->message_loop()->PostTask(
644 BrowserThread::UI,
645 FROM_HERE, 594 FROM_HERE,
646 base::Bind(&SelectFileDialogImpl::FileSelected, this, path, 595 base::Bind(&SelectFileDialogImpl::FileSelected, this, path,
647 filter_index, params.params, params.run_state)); 596 filter_index, params.params, params.run_state));
648 } else { 597 } else {
649 BrowserThread::PostTask( 598 params.run_state.dialog_thread->message_loop()->PostTask(
650 BrowserThread::UI,
651 FROM_HERE, 599 FROM_HERE,
652 base::Bind(&SelectFileDialogImpl::FileNotSelected, this, params.params, 600 base::Bind(&SelectFileDialogImpl::FileNotSelected, this, params.params,
653 params.run_state)); 601 params.run_state));
654 } 602 }
655 } 603 }
656 604
657 void SelectFileDialogImpl::FileSelected(const FilePath& selected_folder, 605 void SelectFileDialogImpl::FileSelected(const FilePath& selected_folder,
658 int index, 606 int index,
659 void* params, 607 void* params,
660 RunState run_state) { 608 RunState run_state) {
(...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after
844 std::vector<FilePath>::iterator path = files.begin(); 792 std::vector<FilePath>::iterator path = files.begin();
845 for (std::vector<FilePath>::iterator file = path + 1; 793 for (std::vector<FilePath>::iterator file = path + 1;
846 file != files.end(); ++file) { 794 file != files.end(); ++file) {
847 paths->push_back(path->Append(*file)); 795 paths->push_back(path->Append(*file));
848 } 796 }
849 } 797 }
850 } 798 }
851 return success; 799 return success;
852 } 800 }
853 801
854 // static 802 } // namespace
855 SelectFileDialog* SelectFileDialog::Create(Listener* listener, 803
856 ui::SelectFilePolicy* policy) { 804 namespace ui {
805
806 // This function takes the output of a SaveAs dialog: a filename, a filter and
807 // the extension originally suggested to the user (shown in the dialog box) and
808 // returns back the filename with the appropriate extension tacked on. If the
809 // user requests an unknown extension and is not using the 'All files' filter,
810 // the suggested extension will be appended, otherwise we will leave the
811 // filename unmodified. |filename| should contain the filename selected in the
812 // SaveAs dialog box and may include the path, |filter_selected| should be
813 // '*.something', for example '*.*' or it can be blank (which is treated as
814 // *.*). |suggested_ext| should contain the extension without the dot (.) in
815 // front, for example 'jpg'.
816 std::wstring AppendExtensionIfNeeded(
817 const std::wstring& filename,
818 const std::wstring& filter_selected,
819 const std::wstring& suggested_ext) {
820 DCHECK(!filename.empty());
821 std::wstring return_value = filename;
822
823 // If we wanted a specific extension, but the user's filename deleted it or
824 // changed it to something that the system doesn't understand, re-append.
825 // Careful: Checking net::GetMimeTypeFromExtension() will only find
826 // extensions with a known MIME type, which many "known" extensions on Windows
827 // don't have. So we check directly for the "known extension" registry key.
828 std::wstring file_extension(
829 GetExtensionWithoutLeadingDot(FilePath(filename).Extension()));
830 std::wstring key(L"." + file_extension);
831 if (!(filter_selected.empty() || filter_selected == L"*.*") &&
832 !base::win::RegKey(HKEY_CLASSES_ROOT, key.c_str(), KEY_READ).Valid() &&
833 file_extension != suggested_ext) {
834 if (return_value[return_value.length() - 1] != L'.')
835 return_value.append(L".");
836 return_value.append(suggested_ext);
837 }
838
839 // Strip any trailing dots, which Windows doesn't allow.
840 size_t index = return_value.find_last_not_of(L'.');
841 if (index < return_value.size() - 1)
842 return_value.resize(index + 1);
843
844 return return_value;
845 }
846
847 SelectFileDialog* CreateWinSelectFileDialog(
848 SelectFileDialog::Listener* listener,
849 SelectFilePolicy* policy) {
857 return new SelectFileDialogImpl(listener, policy); 850 return new SelectFileDialogImpl(listener, policy);
858 } 851 }
852
853 } // namespace ui
OLDNEW
« no previous file with comments | « ui/base/dialogs/select_file_dialog_win.h ('k') | ui/base/dialogs/select_file_dialog_win_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698