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

Side by Side Diff: ui/shell_dialogs/select_file_dialog_win.cc

Issue 487453002: Experimentally isolate GetSaveFileName in a utility process. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Small cleanups. Created 6 years, 4 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 "ui/shell_dialogs/select_file_dialog_win.h" 5 #include "ui/shell_dialogs/select_file_dialog_win.h"
6 6
7 #include <shlobj.h> 7 #include <shlobj.h>
8 8
9 #include <algorithm> 9 #include <algorithm>
10 #include <set> 10 #include <set>
11 11
12 #include "base/bind.h" 12 #include "base/bind.h"
13 #include "base/file_util.h" 13 #include "base/file_util.h"
14 #include "base/files/file_path.h" 14 #include "base/files/file_path.h"
15 #include "base/i18n/case_conversion.h" 15 #include "base/i18n/case_conversion.h"
16 #include "base/message_loop/message_loop.h" 16 #include "base/message_loop/message_loop.h"
17 #include "base/message_loop/message_loop_proxy.h" 17 #include "base/message_loop/message_loop_proxy.h"
18 #include "base/strings/string_split.h"
19 #include "base/strings/utf_string_conversions.h" 18 #include "base/strings/utf_string_conversions.h"
20 #include "base/threading/thread.h" 19 #include "base/threading/thread.h"
21 #include "base/win/metro.h" 20 #include "base/tuple.h"
22 #include "base/win/registry.h" 21 #include "base/win/registry.h"
23 #include "base/win/scoped_comptr.h" 22 #include "base/win/scoped_comptr.h"
24 #include "base/win/shortcut.h" 23 #include "base/win/shortcut.h"
25 #include "base/win/windows_version.h"
26 #include "grit/ui_strings.h" 24 #include "grit/ui_strings.h"
27 #include "ui/aura/window.h" 25 #include "ui/aura/window.h"
28 #include "ui/aura/window_event_dispatcher.h" 26 #include "ui/aura/window_event_dispatcher.h"
29 #include "ui/aura/window_tree_host.h" 27 #include "ui/aura/window_tree_host.h"
30 #include "ui/base/l10n/l10n_util.h" 28 #include "ui/base/l10n/l10n_util.h"
31 #include "ui/base/win/open_file_name_win.h" 29 #include "ui/base/win/open_file_name_win.h"
32 #include "ui/gfx/native_widget_types.h" 30 #include "ui/gfx/native_widget_types.h"
33 #include "ui/shell_dialogs/base_shell_dialog_win.h" 31 #include "ui/shell_dialogs/base_shell_dialog_win.h"
34 #include "ui/shell_dialogs/shell_dialogs_delegate.h" 32 #include "ui/shell_dialogs/shell_dialogs_delegate.h"
35 #include "win8/viewer/metro_viewer_process_host.h" 33 #include "win8/viewer/metro_viewer_process_host.h"
36 34
37 namespace { 35 namespace {
38 36
39 bool CallBuiltinGetOpenFileName(OPENFILENAME* ofn) { 37 bool CallBuiltinGetOpenFileName(OPENFILENAME* ofn) {
40 return ::GetOpenFileName(ofn) == TRUE; 38 return ::GetOpenFileName(ofn) == TRUE;
41 } 39 }
42 40
41 bool CallBuiltinGetSaveFileName(OPENFILENAME* ofn) {
42 return ::GetSaveFileName(ofn) == TRUE;
43 }
44
43 // Given |extension|, if it's not empty, then remove the leading dot. 45 // Given |extension|, if it's not empty, then remove the leading dot.
44 std::wstring GetExtensionWithoutLeadingDot(const std::wstring& extension) { 46 std::wstring GetExtensionWithoutLeadingDot(const std::wstring& extension) {
45 DCHECK(extension.empty() || extension[0] == L'.'); 47 DCHECK(extension.empty() || extension[0] == L'.');
46 return extension.empty() ? extension : extension.substr(1); 48 return extension.empty() ? extension : extension.substr(1);
47 } 49 }
48 50
49 // Diverts to a metro-specific implementation as appropriate.
50 bool CallGetSaveFileName(OPENFILENAME* ofn) {
51 HMODULE metro_module = base::win::GetMetroModule();
52 if (metro_module != NULL) {
53 typedef BOOL (*MetroGetSaveFileName)(OPENFILENAME*);
54 MetroGetSaveFileName metro_get_save_file_name =
55 reinterpret_cast<MetroGetSaveFileName>(
56 ::GetProcAddress(metro_module, "MetroGetSaveFileName"));
57 if (metro_get_save_file_name == NULL) {
58 NOTREACHED();
59 return false;
60 }
61
62 return metro_get_save_file_name(ofn) == TRUE;
63 } else {
64 return GetSaveFileName(ofn) == TRUE;
65 }
66 }
67
68 // Distinguish directories from regular files. 51 // Distinguish directories from regular files.
69 bool IsDirectory(const base::FilePath& path) { 52 bool IsDirectory(const base::FilePath& path) {
70 base::File::Info file_info; 53 base::File::Info file_info;
71 return base::GetFileInfo(path, &file_info) ? 54 return base::GetFileInfo(path, &file_info) ?
72 file_info.is_directory : path.EndsWithSeparator(); 55 file_info.is_directory : path.EndsWithSeparator();
73 } 56 }
74 57
75 // Get the file type description from the registry. This will be "Text Document" 58 // Get the file type description from the registry. This will be "Text Document"
76 // for .txt files, "JPEG Image" for .jpg files, etc. If the registry doesn't 59 // for .txt files, "JPEG Image" for .jpg files, etc. If the registry doesn't
77 // have an entry for the file type, we return false, true if the description was 60 // have an entry for the file type, we return false, true if the description was
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
166 149
167 if (include_all_files) { 150 if (include_all_files) {
168 result.append(all_desc.c_str(), all_desc.size() + 1); 151 result.append(all_desc.c_str(), all_desc.size() + 1);
169 result.append(all_ext.c_str(), all_ext.size() + 1); 152 result.append(all_ext.c_str(), all_ext.size() + 1);
170 } 153 }
171 154
172 result.append(1, '\0'); // Double NULL required. 155 result.append(1, '\0'); // Double NULL required.
173 return result; 156 return result;
174 } 157 }
175 158
176 // Enforce visible dialog box.
177 UINT_PTR CALLBACK SaveAsDialogHook(HWND dialog, UINT message,
178 WPARAM wparam, LPARAM lparam) {
179 static const UINT kPrivateMessage = 0x2F3F;
180 switch (message) {
181 case WM_INITDIALOG: {
182 // Do nothing here. Just post a message to defer actual processing.
183 PostMessage(dialog, kPrivateMessage, 0, 0);
184 return TRUE;
185 }
186 case kPrivateMessage: {
187 // The dialog box is the parent of the current handle.
188 HWND real_dialog = GetParent(dialog);
189
190 // Retrieve the final size.
191 RECT dialog_rect;
192 GetWindowRect(real_dialog, &dialog_rect);
193
194 // Verify that the upper left corner is visible.
195 POINT point = { dialog_rect.left, dialog_rect.top };
196 HMONITOR monitor1 = MonitorFromPoint(point, MONITOR_DEFAULTTONULL);
197 point.x = dialog_rect.right;
198 point.y = dialog_rect.bottom;
199
200 // Verify that the lower right corner is visible.
201 HMONITOR monitor2 = MonitorFromPoint(point, MONITOR_DEFAULTTONULL);
202 if (monitor1 && monitor2)
203 return 0;
204
205 // Some part of the dialog box is not visible, fix it by moving is to the
206 // client rect position of the browser window.
207 HWND parent_window = GetParent(real_dialog);
208 if (!parent_window)
209 return 0;
210 WINDOWINFO parent_info;
211 parent_info.cbSize = sizeof(WINDOWINFO);
212 GetWindowInfo(parent_window, &parent_info);
213 SetWindowPos(real_dialog, NULL,
214 parent_info.rcClient.left,
215 parent_info.rcClient.top,
216 0, 0, // Size.
217 SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSIZE |
218 SWP_NOZORDER);
219
220 return 0;
221 }
222 }
223 return 0;
224 }
225
226 // Prompt the user for location to save a file.
227 // Callers should provide the filter string, and also a filter index.
228 // The parameter |index| indicates the initial index of filter description
229 // and filter pattern for the dialog box. If |index| is zero or greater than
230 // the number of total filter types, the system uses the first filter in the
231 // |filter| buffer. |index| is used to specify the initial selected extension,
232 // and when done contains the extension the user chose. The parameter
233 // |final_name| returns the file name which contains the drive designator,
234 // path, file name, and extension of the user selected file name. |def_ext| is
235 // the default extension to give to the file if the user did not enter an
236 // extension. If |ignore_suggested_ext| is true, any file extension contained in
237 // |suggested_name| will not be used to generate the file name. This is useful
238 // in the case of saving web pages, where we know the extension type already and
239 // where |suggested_name| may contain a '.' character as a valid part of the
240 // name, thus confusing our extension detection code.
241 bool SaveFileAsWithFilter(HWND owner,
242 const std::wstring& suggested_name,
243 const std::wstring& filter,
244 const std::wstring& def_ext,
245 bool ignore_suggested_ext,
246 unsigned* index,
247 std::wstring* final_name) {
248 DCHECK(final_name);
249 // Having an empty filter makes for a bad user experience. We should always
250 // specify a filter when saving.
251 DCHECK(!filter.empty());
252 const base::FilePath suggested_path(suggested_name);
253 std::wstring file_part = suggested_path.BaseName().value();
254 // If the suggested_name is a root directory, file_part will be '\', and the
255 // call to GetSaveFileName below will fail.
256 if (file_part.size() == 1 && file_part[0] == L'\\')
257 file_part.clear();
258
259 // The size of the in/out buffer in number of characters we pass to win32
260 // GetSaveFileName. From MSDN "The buffer must be large enough to store the
261 // path and file name string or strings, including the terminating NULL
262 // character. ... The buffer should be at least 256 characters long.".
263 // _IsValidPathComDlg does a copy expecting at most MAX_PATH, otherwise will
264 // result in an error of FNERR_INVALIDFILENAME. So we should only pass the
265 // API a buffer of at most MAX_PATH.
266 wchar_t file_name[MAX_PATH];
267 base::wcslcpy(file_name, file_part.c_str(), arraysize(file_name));
268
269 OPENFILENAME save_as;
270 // We must do this otherwise the ofn's FlagsEx may be initialized to random
271 // junk in release builds which can cause the Places Bar not to show up!
272 ZeroMemory(&save_as, sizeof(save_as));
273 save_as.lStructSize = sizeof(OPENFILENAME);
274 save_as.hwndOwner = owner;
275 save_as.hInstance = NULL;
276
277 save_as.lpstrFilter = filter.empty() ? NULL : filter.c_str();
278
279 save_as.lpstrCustomFilter = NULL;
280 save_as.nMaxCustFilter = 0;
281 save_as.nFilterIndex = *index;
282 save_as.lpstrFile = file_name;
283 save_as.nMaxFile = arraysize(file_name);
284 save_as.lpstrFileTitle = NULL;
285 save_as.nMaxFileTitle = 0;
286
287 // Set up the initial directory for the dialog.
288 std::wstring directory;
289 if (!suggested_name.empty()) {
290 if (IsDirectory(suggested_path)) {
291 directory = suggested_path.value();
292 file_part.clear();
293 } else {
294 directory = suggested_path.DirName().value();
295 }
296 }
297
298 save_as.lpstrInitialDir = directory.c_str();
299 save_as.lpstrTitle = NULL;
300 save_as.Flags = OFN_OVERWRITEPROMPT | OFN_EXPLORER | OFN_ENABLESIZING |
301 OFN_NOCHANGEDIR | OFN_PATHMUSTEXIST;
302 save_as.lpstrDefExt = &def_ext[0];
303 save_as.lCustData = NULL;
304
305 if (base::win::GetVersion() < base::win::VERSION_VISTA) {
306 // The save as on Windows XP remembers its last position,
307 // and if the screen resolution changed, it will be off screen.
308 save_as.Flags |= OFN_ENABLEHOOK;
309 save_as.lpfnHook = &SaveAsDialogHook;
310 }
311
312 // Must be NULL or 0.
313 save_as.pvReserved = NULL;
314 save_as.dwReserved = 0;
315
316 if (!CallGetSaveFileName(&save_as)) {
317 // Zero means the dialog was closed, otherwise we had an error.
318 DWORD error_code = CommDlgExtendedError();
319 if (error_code != 0) {
320 NOTREACHED() << "GetSaveFileName failed with code: " << error_code;
321 }
322 return false;
323 }
324
325 // Return the user's choice.
326 final_name->assign(save_as.lpstrFile);
327 *index = save_as.nFilterIndex;
328
329 // Figure out what filter got selected from the vector with embedded nulls.
330 // NOTE: The filter contains a string with embedded nulls, such as:
331 // JPG Image\0*.jpg\0All files\0*.*\0\0
332 // The filter index is 1-based index for which pair got selected. So, using
333 // the example above, if the first index was selected we need to skip 1
334 // instance of null to get to "*.jpg".
335 std::vector<std::wstring> filters;
336 if (!filter.empty() && save_as.nFilterIndex > 0)
337 base::SplitString(filter, '\0', &filters);
338 std::wstring filter_selected;
339 if (!filters.empty())
340 filter_selected = filters[(2 * (save_as.nFilterIndex - 1)) + 1];
341
342 // Get the extension that was suggested to the user (when the Save As dialog
343 // was opened). For saving web pages, we skip this step since there may be
344 // 'extension characters' in the title of the web page.
345 std::wstring suggested_ext;
346 if (!ignore_suggested_ext)
347 suggested_ext = GetExtensionWithoutLeadingDot(suggested_path.Extension());
348
349 // If we can't get the extension from the suggested_name, we use the default
350 // extension passed in. This is to cover cases like when saving a web page,
351 // where we get passed in a name without an extension and a default extension
352 // along with it.
353 if (suggested_ext.empty())
354 suggested_ext = def_ext;
355
356 *final_name =
357 ui::AppendExtensionIfNeeded(*final_name, filter_selected, suggested_ext);
358 return true;
359 }
360
361 // Implementation of SelectFileDialog that shows a Windows common dialog for 159 // Implementation of SelectFileDialog that shows a Windows common dialog for
362 // choosing a file or folder. 160 // choosing a file or folder.
363 class SelectFileDialogImpl : public ui::SelectFileDialog, 161 class SelectFileDialogImpl : public ui::SelectFileDialog,
364 public ui::BaseShellDialogImpl { 162 public ui::BaseShellDialogImpl {
365 public: 163 public:
366 SelectFileDialogImpl( 164 SelectFileDialogImpl(
367 Listener* listener, 165 Listener* listener,
368 ui::SelectFilePolicy* policy, 166 ui::SelectFilePolicy* policy,
369 const base::Callback<bool(OPENFILENAME*)>& get_open_file_name_impl); 167 const base::Callback<bool(OPENFILENAME*)>& get_open_file_name_impl,
168 const base::Callback<bool(OPENFILENAME*)>& get_save_file_name_impl);
370 169
371 // BaseShellDialog implementation: 170 // BaseShellDialog implementation:
372 virtual bool IsRunning(gfx::NativeWindow owning_window) const OVERRIDE; 171 virtual bool IsRunning(gfx::NativeWindow owning_window) const OVERRIDE;
373 virtual void ListenerDestroyed() OVERRIDE; 172 virtual void ListenerDestroyed() OVERRIDE;
374 173
375 protected: 174 protected:
376 // SelectFileDialog implementation: 175 // SelectFileDialog implementation:
377 virtual void SelectFileImpl( 176 virtual void SelectFileImpl(
378 Type type, 177 Type type,
379 const base::string16& title, 178 const base::string16& title,
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
419 RunState run_state; 218 RunState run_state;
420 scoped_refptr<base::MessageLoopProxy> ui_proxy; 219 scoped_refptr<base::MessageLoopProxy> ui_proxy;
421 HWND owner; 220 HWND owner;
422 void* params; 221 void* params;
423 }; 222 };
424 223
425 // Shows the file selection dialog modal to |owner| and calls the result 224 // Shows the file selection dialog modal to |owner| and calls the result
426 // back on the ui thread. Run on the dialog thread. 225 // back on the ui thread. Run on the dialog thread.
427 void ExecuteSelectFile(const ExecuteSelectParams& params); 226 void ExecuteSelectFile(const ExecuteSelectParams& params);
428 227
228 // Prompt the user for location to save a file.
229 // Callers should provide the filter string, and also a filter index.
230 // The parameter |index| indicates the initial index of filter description
231 // and filter pattern for the dialog box. If |index| is zero or greater than
232 // the number of total filter types, the system uses the first filter in the
233 // |filter| buffer. |index| is used to specify the initial selected extension,
234 // and when done contains the extension the user chose. The parameter
235 // |final_name| returns the file name which contains the drive designator,
236 // path, file name, and extension of the user selected file name. |def_ext| is
237 // the default extension to give to the file if the user did not enter an
238 // extension. If |ignore_suggested_ext| is true, any file extension contained
239 // in |suggested_name| will not be used to generate the file name. This is
240 // useful in the case of saving web pages, where we know the extension type
241 // already and where |suggested_name| may contain a '.' character as a valid
242 // part of the name, thus confusing our extension detection code.
243 bool SaveFileAsWithFilter(HWND owner,
244 const std::wstring& suggested_name,
245 const std::wstring& filter,
246 const std::wstring& def_ext,
247 bool ignore_suggested_ext,
248 unsigned* index,
249 std::wstring* final_name);
250
429 // Notifies the listener that a folder was chosen. Run on the ui thread. 251 // Notifies the listener that a folder was chosen. Run on the ui thread.
430 void FileSelected(const base::FilePath& path, int index, 252 void FileSelected(const base::FilePath& path, int index,
431 void* params, RunState run_state); 253 void* params, RunState run_state);
432 254
433 // Notifies listener that multiple files were chosen. Run on the ui thread. 255 // Notifies listener that multiple files were chosen. Run on the ui thread.
434 void MultiFilesSelected(const std::vector<base::FilePath>& paths, 256 void MultiFilesSelected(const std::vector<base::FilePath>& paths,
435 void* params, 257 void* params,
436 RunState run_state); 258 RunState run_state);
437 259
438 // Notifies the listener that no file was chosen (the action was canceled). 260 // Notifies the listener that no file was chosen (the action was canceled).
(...skipping 30 matching lines...) Expand all
469 291
470 virtual bool HasMultipleFileTypeChoicesImpl() OVERRIDE; 292 virtual bool HasMultipleFileTypeChoicesImpl() OVERRIDE;
471 293
472 // Returns the filter to be used while displaying the open/save file dialog. 294 // Returns the filter to be used while displaying the open/save file dialog.
473 // This is computed from the extensions for the file types being opened. 295 // This is computed from the extensions for the file types being opened.
474 // |file_types| can be NULL in which case the returned filter will be empty. 296 // |file_types| can be NULL in which case the returned filter will be empty.
475 base::string16 GetFilterForFileTypes(const FileTypeInfo* file_types); 297 base::string16 GetFilterForFileTypes(const FileTypeInfo* file_types);
476 298
477 bool has_multiple_file_type_choices_; 299 bool has_multiple_file_type_choices_;
478 base::Callback<bool(OPENFILENAME*)> get_open_file_name_impl_; 300 base::Callback<bool(OPENFILENAME*)> get_open_file_name_impl_;
301 base::Callback<bool(OPENFILENAME*)> get_save_file_name_impl_;
479 302
480 DISALLOW_COPY_AND_ASSIGN(SelectFileDialogImpl); 303 DISALLOW_COPY_AND_ASSIGN(SelectFileDialogImpl);
481 }; 304 };
482 305
483 SelectFileDialogImpl::SelectFileDialogImpl( 306 SelectFileDialogImpl::SelectFileDialogImpl(
484 Listener* listener, 307 Listener* listener,
485 ui::SelectFilePolicy* policy, 308 ui::SelectFilePolicy* policy,
486 const base::Callback<bool(OPENFILENAME*)>& get_open_file_name_impl) 309 const base::Callback<bool(OPENFILENAME*)>& get_open_file_name_impl,
310 const base::Callback<bool(OPENFILENAME*)>& get_save_file_name_impl)
487 : SelectFileDialog(listener, policy), 311 : SelectFileDialog(listener, policy),
488 BaseShellDialogImpl(), 312 BaseShellDialogImpl(),
489 has_multiple_file_type_choices_(false), 313 has_multiple_file_type_choices_(false),
490 get_open_file_name_impl_(get_open_file_name_impl) { 314 get_open_file_name_impl_(get_open_file_name_impl),
315 get_save_file_name_impl_(get_save_file_name_impl) {
491 } 316 }
492 317
493 SelectFileDialogImpl::~SelectFileDialogImpl() { 318 SelectFileDialogImpl::~SelectFileDialogImpl() {
494 } 319 }
495 320
496 void SelectFileDialogImpl::SelectFileImpl( 321 void SelectFileDialogImpl::SelectFileImpl(
497 Type type, 322 Type type,
498 const base::string16& title, 323 const base::string16& title,
499 const base::FilePath& default_path, 324 const base::FilePath& default_path,
500 const FileTypeInfo* file_types, 325 const FileTypeInfo* file_types,
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after
633 base::Bind(&SelectFileDialogImpl::FileSelected, this, path, 458 base::Bind(&SelectFileDialogImpl::FileSelected, this, path,
634 filter_index, params.params, params.run_state)); 459 filter_index, params.params, params.run_state));
635 } else { 460 } else {
636 params.ui_proxy->PostTask( 461 params.ui_proxy->PostTask(
637 FROM_HERE, 462 FROM_HERE,
638 base::Bind(&SelectFileDialogImpl::FileNotSelected, this, params.params, 463 base::Bind(&SelectFileDialogImpl::FileNotSelected, this, params.params,
639 params.run_state)); 464 params.run_state));
640 } 465 }
641 } 466 }
642 467
468 bool SelectFileDialogImpl::SaveFileAsWithFilter(
469 HWND owner,
470 const std::wstring& suggested_name,
471 const std::wstring& filter,
472 const std::wstring& def_ext,
473 bool ignore_suggested_ext,
474 unsigned* index,
475 std::wstring* final_name) {
476 DCHECK(final_name);
477 // Having an empty filter makes for a bad user experience. We should always
478 // specify a filter when saving.
479 DCHECK(!filter.empty());
480
481 ui::win::OpenFileName save_as(owner,
482 OFN_OVERWRITEPROMPT | OFN_EXPLORER |
483 OFN_ENABLESIZING | OFN_NOCHANGEDIR |
484 OFN_PATHMUSTEXIST);
485
486 const base::FilePath suggested_path = base::FilePath(suggested_name);
487 if (!suggested_name.empty()) {
488 base::FilePath suggested_file_name;
489 base::FilePath suggested_directory;
490 if (IsDirectory(suggested_path)) {
491 suggested_directory = suggested_path;
492 } else {
493 suggested_directory = suggested_path.DirName();
494 suggested_file_name = suggested_path.BaseName();
495 // If the suggested_name is a root directory, file_part will be '\', and
496 // the call to GetSaveFileName below will fail.
497 if (suggested_file_name.value() == L"\\")
498 suggested_file_name.clear();
499 }
500 save_as.SetInitialSelection(suggested_directory, suggested_file_name);
501 }
502
503 save_as.GetOPENFILENAME()->lpstrFilter =
504 filter.empty() ? NULL : filter.c_str();
505 save_as.GetOPENFILENAME()->nFilterIndex = *index;
506 save_as.GetOPENFILENAME()->lpstrDefExt = &def_ext[0];
507 save_as.MaybeInstallWindowPositionHookForSaveAsOnXP();
508
509 if (!get_save_file_name_impl_.Run(save_as.GetOPENFILENAME()))
510 return false;
511
512 // Return the user's choice.
513 final_name->assign(save_as.GetOPENFILENAME()->lpstrFile);
514 *index = save_as.GetOPENFILENAME()->nFilterIndex;
515
516 // Figure out what filter got selected. The filter index is 1-based.
517 std::wstring filter_selected;
518 if (*index > 0) {
519 std::vector<Tuple2<base::string16, base::string16> > filters =
520 ui::win::OpenFileName::GetFilters(save_as.GetOPENFILENAME());
521 if (*index > filters.size())
522 NOTREACHED() << "Invalid filter index.";
523 else
524 filter_selected = filters[*index - 1].b;
525 }
526
527 // Get the extension that was suggested to the user (when the Save As dialog
528 // was opened). For saving web pages, we skip this step since there may be
529 // 'extension characters' in the title of the web page.
530 std::wstring suggested_ext;
531 if (!ignore_suggested_ext)
532 suggested_ext = GetExtensionWithoutLeadingDot(suggested_path.Extension());
533
534 // If we can't get the extension from the suggested_name, we use the default
535 // extension passed in. This is to cover cases like when saving a web page,
536 // where we get passed in a name without an extension and a default extension
537 // along with it.
538 if (suggested_ext.empty())
539 suggested_ext = def_ext;
540
541 *final_name =
542 ui::AppendExtensionIfNeeded(*final_name, filter_selected, suggested_ext);
543 return true;
544 }
545
643 void SelectFileDialogImpl::FileSelected(const base::FilePath& selected_folder, 546 void SelectFileDialogImpl::FileSelected(const base::FilePath& selected_folder,
644 int index, 547 int index,
645 void* params, 548 void* params,
646 RunState run_state) { 549 RunState run_state) {
647 if (listener_) 550 if (listener_)
648 listener_->FileSelected(selected_folder, index, params); 551 listener_->FileSelected(selected_folder, index, params);
649 EndRun(run_state); 552 EndRun(run_state);
650 } 553 }
651 554
652 void SelectFileDialogImpl::MultiFilesSelected( 555 void SelectFileDialogImpl::MultiFilesSelected(
(...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after
849 size_t index = return_value.find_last_not_of(L'.'); 752 size_t index = return_value.find_last_not_of(L'.');
850 if (index < return_value.size() - 1) 753 if (index < return_value.size() - 1)
851 return_value.resize(index + 1); 754 return_value.resize(index + 1);
852 755
853 return return_value; 756 return return_value;
854 } 757 }
855 758
856 SelectFileDialog* CreateWinSelectFileDialog( 759 SelectFileDialog* CreateWinSelectFileDialog(
857 SelectFileDialog::Listener* listener, 760 SelectFileDialog::Listener* listener,
858 SelectFilePolicy* policy, 761 SelectFilePolicy* policy,
859 const base::Callback<bool(OPENFILENAME* ofn)>& get_open_file_name_impl) { 762 const base::Callback<bool(OPENFILENAME* ofn)>& get_open_file_name_impl,
860 return new SelectFileDialogImpl(listener, policy, get_open_file_name_impl); 763 const base::Callback<bool(OPENFILENAME* ofn)>& get_save_file_name_impl) {
764 return new SelectFileDialogImpl(
765 listener, policy, get_open_file_name_impl, get_save_file_name_impl);
861 } 766 }
862 767
863 SelectFileDialog* CreateDefaultWinSelectFileDialog( 768 SelectFileDialog* CreateDefaultWinSelectFileDialog(
864 SelectFileDialog::Listener* listener, 769 SelectFileDialog::Listener* listener,
865 SelectFilePolicy* policy) { 770 SelectFilePolicy* policy) {
866 return CreateWinSelectFileDialog( 771 return CreateWinSelectFileDialog(listener,
867 listener, policy, base::Bind(&CallBuiltinGetOpenFileName)); 772 policy,
773 base::Bind(&CallBuiltinGetOpenFileName),
774 base::Bind(&CallBuiltinGetSaveFileName));
868 } 775 }
869 776
870 } // namespace ui 777 } // namespace ui
OLDNEW
« ui/base/win/open_file_name_win.cc ('K') | « ui/shell_dialogs/select_file_dialog_win.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698