OLD | NEW |
1 // Copyright (c) 2011 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 "chrome/browser/ui/select_file_dialog.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> |
(...skipping 10 matching lines...) Expand all Loading... |
22 #include "base/win/registry.h" | 22 #include "base/win/registry.h" |
23 #include "base/win/scoped_comptr.h" | 23 #include "base/win/scoped_comptr.h" |
24 #include "base/win/windows_version.h" | 24 #include "base/win/windows_version.h" |
25 #include "content/public/browser/browser_thread.h" | 25 #include "content/public/browser/browser_thread.h" |
26 #include "grit/generated_resources.h" | 26 #include "grit/generated_resources.h" |
27 #include "grit/ui_strings.h" | 27 #include "grit/ui_strings.h" |
28 #include "ui/base/l10n/l10n_util.h" | 28 #include "ui/base/l10n/l10n_util.h" |
29 | 29 |
30 using content::BrowserThread; | 30 using content::BrowserThread; |
31 | 31 |
| 32 namespace { |
| 33 |
| 34 // Given |extension|, if it's not empty, then remove the leading dot. |
| 35 std::wstring GetExtensionWithoutLeadingDot(const std::wstring& extension) { |
| 36 DCHECK(extension.empty() || extension[0] == L'.'); |
| 37 return extension.empty() ? extension : extension.substr(1); |
| 38 } |
| 39 |
| 40 } // namespace |
| 41 |
32 // This function takes the output of a SaveAs dialog: a filename, a filter and | 42 // This function takes the output of a SaveAs dialog: a filename, a filter and |
33 // the extension originally suggested to the user (shown in the dialog box) and | 43 // the extension originally suggested to the user (shown in the dialog box) and |
34 // returns back the filename with the appropriate extension tacked on. If the | 44 // returns back the filename with the appropriate extension tacked on. If the |
35 // user requests an unknown extension and is not using the 'All files' filter, | 45 // user requests an unknown extension and is not using the 'All files' filter, |
36 // the suggested extension will be appended, otherwise we will leave the | 46 // the suggested extension will be appended, otherwise we will leave the |
37 // filename unmodified. |filename| should contain the filename selected in the | 47 // filename unmodified. |filename| should contain the filename selected in the |
38 // SaveAs dialog box and may include the path, |filter_selected| should be | 48 // SaveAs dialog box and may include the path, |filter_selected| should be |
39 // '*.something', for example '*.*' or it can be blank (which is treated as | 49 // '*.something', for example '*.*' or it can be blank (which is treated as |
40 // *.*). |suggested_ext| should contain the extension without the dot (.) in | 50 // *.*). |suggested_ext| should contain the extension without the dot (.) in |
41 // front, for example 'jpg'. | 51 // front, for example 'jpg'. |
42 std::wstring AppendExtensionIfNeeded(const std::wstring& filename, | 52 std::wstring AppendExtensionIfNeeded(const std::wstring& filename, |
43 const std::wstring& filter_selected, | 53 const std::wstring& filter_selected, |
44 const std::wstring& suggested_ext) { | 54 const std::wstring& suggested_ext) { |
45 DCHECK(!filename.empty()); | 55 DCHECK(!filename.empty()); |
46 std::wstring return_value = filename; | 56 std::wstring return_value = filename; |
47 | 57 |
48 // If we wanted a specific extension, but the user's filename deleted it or | 58 // If we wanted a specific extension, but the user's filename deleted it or |
49 // changed it to something that the system doesn't understand, re-append. | 59 // changed it to something that the system doesn't understand, re-append. |
50 // Careful: Checking net::GetMimeTypeFromExtension() will only find | 60 // Careful: Checking net::GetMimeTypeFromExtension() will only find |
51 // extensions with a known MIME type, which many "known" extensions on Windows | 61 // extensions with a known MIME type, which many "known" extensions on Windows |
52 // don't have. So we check directly for the "known extension" registry key. | 62 // don't have. So we check directly for the "known extension" registry key. |
53 std::wstring file_extension(file_util::GetFileExtensionFromPath(filename)); | 63 std::wstring file_extension( |
| 64 GetExtensionWithoutLeadingDot(FilePath(filename).Extension())); |
54 std::wstring key(L"." + file_extension); | 65 std::wstring key(L"." + file_extension); |
55 if (!(filter_selected.empty() || filter_selected == L"*.*") && | 66 if (!(filter_selected.empty() || filter_selected == L"*.*") && |
56 !base::win::RegKey(HKEY_CLASSES_ROOT, key.c_str(), KEY_READ).Valid() && | 67 !base::win::RegKey(HKEY_CLASSES_ROOT, key.c_str(), KEY_READ).Valid() && |
57 file_extension != suggested_ext) { | 68 file_extension != suggested_ext) { |
58 if (return_value[return_value.length() - 1] != L'.') | 69 if (return_value[return_value.length() - 1] != L'.') |
59 return_value.append(L"."); | 70 return_value.append(L"."); |
60 return_value.append(suggested_ext); | 71 return_value.append(suggested_ext); |
61 } | 72 } |
62 | 73 |
63 // Strip any trailing dots, which Windows doesn't allow. | 74 // Strip any trailing dots, which Windows doesn't allow. |
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
237 const std::wstring& suggested_name, | 248 const std::wstring& suggested_name, |
238 const std::wstring& filter, | 249 const std::wstring& filter, |
239 const std::wstring& def_ext, | 250 const std::wstring& def_ext, |
240 bool ignore_suggested_ext, | 251 bool ignore_suggested_ext, |
241 unsigned* index, | 252 unsigned* index, |
242 std::wstring* final_name) { | 253 std::wstring* final_name) { |
243 DCHECK(final_name); | 254 DCHECK(final_name); |
244 // Having an empty filter makes for a bad user experience. We should always | 255 // Having an empty filter makes for a bad user experience. We should always |
245 // specify a filter when saving. | 256 // specify a filter when saving. |
246 DCHECK(!filter.empty()); | 257 DCHECK(!filter.empty()); |
247 std::wstring file_part = FilePath(suggested_name).BaseName().value(); | 258 const FilePath suggested_path(suggested_name); |
| 259 std::wstring file_part = suggested_path.BaseName().value(); |
248 // If the suggested_name is a root directory, file_part will be '\', and the | 260 // If the suggested_name is a root directory, file_part will be '\', and the |
249 // call to GetSaveFileName below will fail. | 261 // call to GetSaveFileName below will fail. |
250 if (file_part.size() == 1 && file_part[0] == L'\\') | 262 if (file_part.size() == 1 && file_part[0] == L'\\') |
251 file_part.clear(); | 263 file_part.clear(); |
252 | 264 |
253 // The size of the in/out buffer in number of characters we pass to win32 | 265 // The size of the in/out buffer in number of characters we pass to win32 |
254 // GetSaveFileName. From MSDN "The buffer must be large enough to store the | 266 // GetSaveFileName. From MSDN "The buffer must be large enough to store the |
255 // path and file name string or strings, including the terminating NULL | 267 // path and file name string or strings, including the terminating NULL |
256 // character. ... The buffer should be at least 256 characters long.". | 268 // character. ... The buffer should be at least 256 characters long.". |
257 // _IsValidPathComDlg does a copy expecting at most MAX_PATH, otherwise will | 269 // _IsValidPathComDlg does a copy expecting at most MAX_PATH, otherwise will |
(...skipping 16 matching lines...) Expand all Loading... |
274 save_as.nMaxCustFilter = 0; | 286 save_as.nMaxCustFilter = 0; |
275 save_as.nFilterIndex = *index; | 287 save_as.nFilterIndex = *index; |
276 save_as.lpstrFile = file_name; | 288 save_as.lpstrFile = file_name; |
277 save_as.nMaxFile = arraysize(file_name); | 289 save_as.nMaxFile = arraysize(file_name); |
278 save_as.lpstrFileTitle = NULL; | 290 save_as.lpstrFileTitle = NULL; |
279 save_as.nMaxFileTitle = 0; | 291 save_as.nMaxFileTitle = 0; |
280 | 292 |
281 // Set up the initial directory for the dialog. | 293 // Set up the initial directory for the dialog. |
282 std::wstring directory; | 294 std::wstring directory; |
283 if (!suggested_name.empty()) | 295 if (!suggested_name.empty()) |
284 directory = FilePath(suggested_name).DirName().value(); | 296 directory = suggested_path.DirName().value(); |
285 | 297 |
286 save_as.lpstrInitialDir = directory.c_str(); | 298 save_as.lpstrInitialDir = directory.c_str(); |
287 save_as.lpstrTitle = NULL; | 299 save_as.lpstrTitle = NULL; |
288 save_as.Flags = OFN_OVERWRITEPROMPT | OFN_EXPLORER | OFN_ENABLESIZING | | 300 save_as.Flags = OFN_OVERWRITEPROMPT | OFN_EXPLORER | OFN_ENABLESIZING | |
289 OFN_NOCHANGEDIR | OFN_PATHMUSTEXIST; | 301 OFN_NOCHANGEDIR | OFN_PATHMUSTEXIST; |
290 save_as.lpstrDefExt = &def_ext[0]; | 302 save_as.lpstrDefExt = &def_ext[0]; |
291 save_as.lCustData = NULL; | 303 save_as.lCustData = NULL; |
292 | 304 |
293 if (base::win::GetVersion() < base::win::VERSION_VISTA) { | 305 if (base::win::GetVersion() < base::win::VERSION_VISTA) { |
294 // The save as on Windows XP remembers its last position, | 306 // The save as on Windows XP remembers its last position, |
(...skipping 30 matching lines...) Expand all Loading... |
325 base::SplitString(filter, '\0', &filters); | 337 base::SplitString(filter, '\0', &filters); |
326 std::wstring filter_selected; | 338 std::wstring filter_selected; |
327 if (!filters.empty()) | 339 if (!filters.empty()) |
328 filter_selected = filters[(2 * (save_as.nFilterIndex - 1)) + 1]; | 340 filter_selected = filters[(2 * (save_as.nFilterIndex - 1)) + 1]; |
329 | 341 |
330 // Get the extension that was suggested to the user (when the Save As dialog | 342 // Get the extension that was suggested to the user (when the Save As dialog |
331 // was opened). For saving web pages, we skip this step since there may be | 343 // was opened). For saving web pages, we skip this step since there may be |
332 // 'extension characters' in the title of the web page. | 344 // 'extension characters' in the title of the web page. |
333 std::wstring suggested_ext; | 345 std::wstring suggested_ext; |
334 if (!ignore_suggested_ext) | 346 if (!ignore_suggested_ext) |
335 suggested_ext = file_util::GetFileExtensionFromPath(suggested_name); | 347 suggested_ext = GetExtensionWithoutLeadingDot(suggested_path.Extension()); |
336 | 348 |
337 // If we can't get the extension from the suggested_name, we use the default | 349 // If we can't get the extension from the suggested_name, we use the default |
338 // extension passed in. This is to cover cases like when saving a web page, | 350 // extension passed in. This is to cover cases like when saving a web page, |
339 // where we get passed in a name without an extension and a default extension | 351 // where we get passed in a name without an extension and a default extension |
340 // along with it. | 352 // along with it. |
341 if (suggested_ext.empty()) | 353 if (suggested_ext.empty()) |
342 suggested_ext = def_ext; | 354 suggested_ext = def_ext; |
343 | 355 |
344 *final_name = | 356 *final_name = |
345 AppendExtensionIfNeeded(*final_name, filter_selected, suggested_ext); | 357 AppendExtensionIfNeeded(*final_name, filter_selected, suggested_ext); |
(...skipping 610 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
956 } | 968 } |
957 } | 969 } |
958 } | 970 } |
959 return success; | 971 return success; |
960 } | 972 } |
961 | 973 |
962 // static | 974 // static |
963 SelectFileDialog* SelectFileDialog::Create(Listener* listener) { | 975 SelectFileDialog* SelectFileDialog::Create(Listener* listener) { |
964 return new SelectFileDialogImpl(listener); | 976 return new SelectFileDialogImpl(listener); |
965 } | 977 } |
OLD | NEW |