Chromium Code Reviews| 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 |