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