Chromium Code Reviews| OLD | NEW |
|---|---|
| 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/profiles/profile_shortcut_manager_win.h" | 5 #include "chrome/browser/profiles/profile_shortcut_manager_win.h" |
| 6 | 6 |
| 7 #include <shlobj.h> // For SHChangeNotify(). | 7 #include <shlobj.h> // For SHChangeNotify(). |
| 8 | 8 |
| 9 #include <algorithm> | |
| 10 #include <set> | |
| 9 #include <string> | 11 #include <string> |
| 10 #include <vector> | 12 #include <vector> |
| 11 | 13 |
| 12 #include "base/bind.h" | 14 #include "base/bind.h" |
| 13 #include "base/command_line.h" | 15 #include "base/command_line.h" |
| 14 #include "base/files/file_enumerator.h" | 16 #include "base/files/file_enumerator.h" |
| 15 #include "base/files/file_util.h" | 17 #include "base/files/file_util.h" |
| 16 #include "base/path_service.h" | 18 #include "base/path_service.h" |
| 17 #include "base/prefs/pref_service.h" | 19 #include "base/prefs/pref_service.h" |
| 18 #include "base/strings/string16.h" | 20 #include "base/strings/string16.h" |
| (...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 282 return false; | 284 return false; |
| 283 | 285 |
| 284 base::FilePath target_path; | 286 base::FilePath target_path; |
| 285 if (!base::win::ResolveShortcut(path, &target_path, command_line)) | 287 if (!base::win::ResolveShortcut(path, &target_path, command_line)) |
| 286 return false; | 288 return false; |
| 287 // One of the paths may be in short (elided) form. Compare long paths to | 289 // One of the paths may be in short (elided) form. Compare long paths to |
| 288 // ensure these are still properly matched. | 290 // ensure these are still properly matched. |
| 289 return ConvertToLongPath(target_path) == ConvertToLongPath(chrome_exe); | 291 return ConvertToLongPath(target_path) == ConvertToLongPath(chrome_exe); |
| 290 } | 292 } |
| 291 | 293 |
| 292 // Populates |paths| with the file paths of Chrome desktop shortcuts that have | 294 // Checks if |path| is the Chrome desktop shortcut (|chrome_exe|) that have |
| 293 // the specified |command_line|. If |include_empty_command_lines| is true, | 295 // the specified |command_line|. If |include_empty_command_lines| is true, |
| 294 // Chrome desktop shortcuts with empty command lines will also be included. | 296 // Chrome desktop shortcuts with empty command lines will also be included. |
|
Alexei Svitkine (slow)
2016/01/15 18:01:38
This comment doesn't seem to be applicable to the
Michael K. (Yandex Team)
2016/01/18 09:37:54
I've looked through the code and it seems that com
| |
| 295 void ListDesktopShortcutsWithCommandLine(const base::FilePath& chrome_exe, | 297 struct ChromeCommandLineFilter { |
| 296 const base::string16& command_line, | 298 const base::FilePath& chrome_exe; |
| 297 bool include_empty_command_lines, | 299 const base::string16& command_line; |
| 298 std::vector<base::FilePath>* paths) { | 300 bool include_empty_command_lines; |
| 299 base::FilePath user_shortcuts_directory; | |
| 300 if (!GetDesktopShortcutsDirectories(&user_shortcuts_directory, NULL)) | |
| 301 return; | |
| 302 | 301 |
| 303 base::FileEnumerator enumerator(user_shortcuts_directory, false, | 302 ChromeCommandLineFilter(const base::FilePath& chrome_exe, |
| 304 base::FileEnumerator::FILES); | 303 const base::string16& command_line, |
| 305 for (base::FilePath path = enumerator.Next(); !path.empty(); | 304 bool include_empty_command_lines) |
| 306 path = enumerator.Next()) { | 305 : chrome_exe(chrome_exe), |
| 306 command_line(command_line), | |
| 307 include_empty_command_lines(include_empty_command_lines) {} | |
| 308 | |
| 309 bool operator()(const base::FilePath& path) const { | |
| 307 base::string16 shortcut_command_line; | 310 base::string16 shortcut_command_line; |
| 308 if (!IsChromeShortcut(path, chrome_exe, &shortcut_command_line)) | 311 if (!IsChromeShortcut(path, chrome_exe, &shortcut_command_line)) |
| 309 continue; | 312 return false; |
| 310 | 313 |
| 311 // TODO(asvitkine): Change this to build a CommandLine object and ensure all | 314 // TODO(asvitkine): Change this to build a CommandLine object and ensure all |
| 312 // args from |command_line| are present in the shortcut's CommandLine. This | 315 // args from |command_line| are present in the shortcut's CommandLine. This |
| 313 // will be more robust when |command_line| contains multiple args. | 316 // will be more robust when |command_line| contains multiple args. |
| 314 if ((shortcut_command_line.empty() && include_empty_command_lines) || | 317 if ((shortcut_command_line.empty() && include_empty_command_lines) || |
| 315 (shortcut_command_line.find(command_line) != base::string16::npos)) { | 318 (shortcut_command_line.find(command_line) != base::string16::npos)) { |
| 316 paths->push_back(path); | 319 return true; |
| 317 } | 320 } |
| 321 return false; | |
| 318 } | 322 } |
| 323 }; | |
| 324 | |
| 325 // Get the file paths of desktop files and folders optionally filtered | |
| 326 // by |filter|. | |
| 327 std::set<base::FilePath> ListUserDesktopContents( | |
| 328 const ChromeCommandLineFilter* filter) { | |
| 329 std::set<base::FilePath> res; | |
|
Alexei Svitkine (slow)
2016/01/15 18:01:38
Nit: result
Michael K. (Yandex Team)
2016/01/18 09:37:54
Done.
| |
| 330 | |
| 331 base::FilePath user_shortcuts_directory; | |
| 332 if (!GetDesktopShortcutsDirectories(&user_shortcuts_directory, nullptr)) | |
| 333 return res; | |
| 334 | |
| 335 base::FileEnumerator enumerator( | |
| 336 user_shortcuts_directory, false, | |
| 337 base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES); | |
| 338 for (base::FilePath path = enumerator.Next(); !path.empty(); | |
| 339 path = enumerator.Next()) { | |
| 340 if (!filter || (*filter)(path)) | |
| 341 res.insert(path); | |
| 342 } | |
| 343 return res; | |
| 319 } | 344 } |
| 320 | 345 |
| 321 // Renames the given desktop shortcut and informs the shell of this change. | 346 // Renames the given desktop shortcut and informs the shell of this change. |
| 322 bool RenameDesktopShortcut(const base::FilePath& old_shortcut_path, | 347 bool RenameDesktopShortcut(const base::FilePath& old_shortcut_path, |
| 323 const base::FilePath& new_shortcut_path) { | 348 const base::FilePath& new_shortcut_path) { |
| 324 if (!base::Move(old_shortcut_path, new_shortcut_path)) | 349 if (!base::Move(old_shortcut_path, new_shortcut_path)) |
| 325 return false; | 350 return false; |
| 326 | 351 |
| 327 // Notify the shell of the rename, which allows the icon to keep its position | 352 // Notify the shell of the rename, which allows the icon to keep its position |
| 328 // on the desktop when renamed. Note: This only works if either SHCNF_FLUSH or | 353 // on the desktop when renamed. Note: This only works if either SHCNF_FLUSH or |
| 329 // SHCNF_FLUSHNOWAIT is specified as a flag. | 354 // SHCNF_FLUSHNOWAIT is specified as a flag. |
| 330 SHChangeNotify(SHCNE_RENAMEITEM, SHCNF_PATH | SHCNF_FLUSHNOWAIT, | 355 SHChangeNotify(SHCNE_RENAMEITEM, SHCNF_PATH | SHCNF_FLUSHNOWAIT, |
| 331 old_shortcut_path.value().c_str(), | 356 old_shortcut_path.value().c_str(), |
| 332 new_shortcut_path.value().c_str()); | 357 new_shortcut_path.value().c_str()); |
| 333 return true; | 358 return true; |
| 334 } | 359 } |
| 335 | 360 |
| 336 // Renames an existing Chrome desktop profile shortcut. Must be called on the | 361 // Renames an existing Chrome desktop profile shortcut. Must be called on the |
| 337 // FILE thread. | 362 // FILE thread. |
|
Alexei Svitkine (slow)
2016/01/15 18:01:38
Document the new params.
Michael K. (Yandex Team)
2016/01/18 09:37:54
Done.
| |
| 338 void RenameChromeDesktopShortcutForProfile( | 363 void RenameChromeDesktopShortcutForProfile( |
| 339 const base::string16& old_shortcut_filename, | 364 const base::string16& old_profile_name, |
| 340 const base::string16& new_shortcut_filename) { | 365 const base::string16& new_profile_name, |
| 366 std::set<base::FilePath>* profile_shortcuts, | |
| 367 std::set<base::FilePath>* desktop_contents) { | |
| 368 DCHECK(profile_shortcuts); | |
| 369 DCHECK(desktop_contents); | |
| 341 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 370 DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
| 342 | 371 |
| 343 base::FilePath user_shortcuts_directory; | 372 base::FilePath user_shortcuts_directory; |
| 344 base::FilePath system_shortcuts_directory; | 373 base::FilePath system_shortcuts_directory; |
| 345 if (!GetDesktopShortcutsDirectories(&user_shortcuts_directory, | 374 if (!GetDesktopShortcutsDirectories(&user_shortcuts_directory, |
| 346 &system_shortcuts_directory)) { | 375 &system_shortcuts_directory)) { |
| 347 return; | 376 return; |
| 348 } | 377 } |
| 349 | 378 |
| 350 const base::FilePath old_shortcut_path = | 379 BrowserDistribution* distribution = BrowserDistribution::GetDistribution(); |
| 351 user_shortcuts_directory.Append(old_shortcut_filename); | 380 |
| 381 // Get a new unique shortcut name. | |
| 382 const base::string16 new_shortcut_filename = | |
| 383 profiles::internal::GetUniqueShortcutFilenameForProfile( | |
| 384 new_profile_name, distribution, *desktop_contents); | |
| 352 const base::FilePath new_shortcut_path = | 385 const base::FilePath new_shortcut_path = |
| 353 user_shortcuts_directory.Append(new_shortcut_filename); | 386 user_shortcuts_directory.Append(new_shortcut_filename); |
| 354 | 387 |
| 355 if (base::PathExists(old_shortcut_path)) { | 388 if (!profile_shortcuts->empty()) { |
| 389 // From all profile_shortcuts choose only with known (canonical) name. | |
| 390 profiles::internal::ShortcutFilenameMatcher matcher(old_profile_name, | |
| 391 distribution); | |
| 392 auto it = std::find_if(profile_shortcuts->begin(), profile_shortcuts->end(), | |
| 393 [&matcher](const base::FilePath& p) { | |
| 394 return matcher.IsCanonical(p.BaseName().value()); | |
| 395 }); | |
| 396 // If all profile_shortcuts were renamed by user, respect it and do not | |
| 397 // rename. | |
| 398 if (it == profile_shortcuts->end()) | |
| 399 return; | |
| 400 const base::FilePath old_shortcut_path = *it; | |
| 401 | |
| 356 // Rename the old shortcut unless a system-level shortcut exists at the | 402 // Rename the old shortcut unless a system-level shortcut exists at the |
| 357 // destination, in which case the old shortcut is simply deleted. | 403 // destination, in which case the old shortcut is simply deleted. |
| 358 const base::FilePath possible_new_system_shortcut = | 404 const base::FilePath possible_new_system_shortcut = |
| 359 system_shortcuts_directory.Append(new_shortcut_filename); | 405 system_shortcuts_directory.Append(new_shortcut_filename); |
| 360 if (base::PathExists(possible_new_system_shortcut)) | 406 if (base::PathExists(possible_new_system_shortcut)) { |
| 361 base::DeleteFile(old_shortcut_path, false); | 407 if (base::DeleteFile(old_shortcut_path, false)) { |
| 362 else if (!RenameDesktopShortcut(old_shortcut_path, new_shortcut_path)) | 408 profile_shortcuts->erase(old_shortcut_path); |
| 363 DLOG(ERROR) << "Could not rename Windows profile desktop shortcut."; | 409 desktop_contents->erase(old_shortcut_path); |
| 410 } else { | |
| 411 DLOG(ERROR) << "Could not delete Windows profile desktop shortcut."; | |
| 412 } | |
| 413 } else { | |
| 414 if (RenameDesktopShortcut(old_shortcut_path, new_shortcut_path)) { | |
| 415 profile_shortcuts->erase(old_shortcut_path); | |
| 416 desktop_contents->erase(old_shortcut_path); | |
| 417 profile_shortcuts->insert(new_shortcut_path); | |
| 418 desktop_contents->insert(new_shortcut_path); | |
| 419 } else { | |
| 420 DLOG(ERROR) << "Could not rename Windows profile desktop shortcut."; | |
| 421 } | |
| 422 } | |
| 364 } else { | 423 } else { |
| 365 // If the shortcut does not exist, it may have been renamed by the user. In | 424 // If the shortcut does not exist, it may have been deleted by the user. |
| 366 // that case, its name should not be changed. | |
| 367 // It's also possible that a system-level shortcut exists instead - this | 425 // It's also possible that a system-level shortcut exists instead - this |
| 368 // should only be the case for the original Chrome shortcut from an | 426 // should only be the case for the original Chrome shortcut from an |
| 369 // installation. If that's the case, copy that one over - it will get its | 427 // installation. If that's the case, copy that one over - it will get its |
| 370 // properties updated by | 428 // properties updated by |
| 371 // |CreateOrUpdateDesktopShortcutsAndIconForProfile()|. | 429 // |CreateOrUpdateDesktopShortcutsAndIconForProfile()|. |
| 430 const auto old_shortcut_filename = | |
| 431 profiles::internal::GetShortcutFilenameForProfile(old_profile_name, | |
| 432 distribution); | |
| 372 const base::FilePath possible_old_system_shortcut = | 433 const base::FilePath possible_old_system_shortcut = |
| 373 system_shortcuts_directory.Append(old_shortcut_filename); | 434 system_shortcuts_directory.Append(old_shortcut_filename); |
| 374 if (base::PathExists(possible_old_system_shortcut)) | 435 if (base::PathExists(possible_old_system_shortcut)) { |
| 375 base::CopyFile(possible_old_system_shortcut, new_shortcut_path); | 436 if (base::CopyFile(possible_old_system_shortcut, new_shortcut_path)) { |
| 437 profile_shortcuts->insert(new_shortcut_path); | |
| 438 desktop_contents->insert(new_shortcut_path); | |
| 439 } else { | |
| 440 DLOG(ERROR) << "Could not copy Windows profile desktop shortcut."; | |
| 441 } | |
| 442 } | |
| 376 } | 443 } |
| 377 } | 444 } |
| 378 | 445 |
| 379 struct CreateOrUpdateShortcutsParams { | 446 struct CreateOrUpdateShortcutsParams { |
| 380 CreateOrUpdateShortcutsParams( | 447 CreateOrUpdateShortcutsParams( |
| 381 base::FilePath profile_path, | 448 base::FilePath profile_path, |
| 382 ProfileShortcutManagerWin::CreateOrUpdateMode create_mode, | 449 ProfileShortcutManagerWin::CreateOrUpdateMode create_mode, |
| 383 ProfileShortcutManagerWin::NonProfileShortcutAction action) | 450 ProfileShortcutManagerWin::NonProfileShortcutAction action) |
| 384 : create_mode(create_mode), action(action), profile_path(profile_path) {} | 451 : create_mode(create_mode), action(action), profile_path(profile_path) {} |
| 385 ~CreateOrUpdateShortcutsParams() {} | 452 ~CreateOrUpdateShortcutsParams() {} |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 421 if (!PathService::Get(base::FILE_EXE, &chrome_exe)) { | 488 if (!PathService::Get(base::FILE_EXE, &chrome_exe)) { |
| 422 NOTREACHED(); | 489 NOTREACHED(); |
| 423 return; | 490 return; |
| 424 } | 491 } |
| 425 | 492 |
| 426 BrowserDistribution* distribution = BrowserDistribution::GetDistribution(); | 493 BrowserDistribution* distribution = BrowserDistribution::GetDistribution(); |
| 427 // Ensure that the distribution supports creating shortcuts. If it doesn't, | 494 // Ensure that the distribution supports creating shortcuts. If it doesn't, |
| 428 // the following code may result in NOTREACHED() being hit. | 495 // the following code may result in NOTREACHED() being hit. |
| 429 DCHECK(distribution->CanCreateDesktopShortcuts()); | 496 DCHECK(distribution->CanCreateDesktopShortcuts()); |
| 430 | 497 |
| 498 std::set<base::FilePath> desktop_contents = ListUserDesktopContents(nullptr); | |
| 499 | |
| 500 const base::string16 command_line = | |
| 501 profiles::internal::CreateProfileShortcutFlags(params.profile_path); | |
| 502 ChromeCommandLineFilter filter( | |
| 503 chrome_exe, command_line, | |
| 504 params.action == ProfileShortcutManagerWin::UPDATE_NON_PROFILE_SHORTCUTS); | |
| 505 | |
| 506 std::set<base::FilePath> shortcuts; | |
| 507 // Do not call ListUserDesktopContents again (but with filter) to avoid | |
| 508 // excess work inside it. Just reuse non-filtered desktop_contents. | |
| 509 // We need both of them (desktop_contents and shortcuts) later. | |
| 510 std::copy_if(desktop_contents.begin(), desktop_contents.end(), | |
| 511 std::inserter(shortcuts, shortcuts.begin()), filter); | |
| 512 | |
| 431 if (params.old_profile_name != params.profile_name) { | 513 if (params.old_profile_name != params.profile_name) { |
| 432 const base::string16 old_shortcut_filename = | 514 RenameChromeDesktopShortcutForProfile(params.old_profile_name, |
| 433 profiles::internal::GetShortcutFilenameForProfile( | 515 params.profile_name, &shortcuts, |
| 434 params.old_profile_name, | 516 &desktop_contents); |
| 435 distribution); | |
| 436 const base::string16 new_shortcut_filename = | |
| 437 profiles::internal::GetShortcutFilenameForProfile(params.profile_name, | |
| 438 distribution); | |
| 439 RenameChromeDesktopShortcutForProfile(old_shortcut_filename, | |
| 440 new_shortcut_filename); | |
| 441 } | 517 } |
| 442 | 518 |
| 443 ShellUtil::ShortcutProperties properties(ShellUtil::CURRENT_USER); | 519 ShellUtil::ShortcutProperties properties(ShellUtil::CURRENT_USER); |
| 444 installer::Product product(distribution); | 520 installer::Product product(distribution); |
| 445 product.AddDefaultShortcutProperties(chrome_exe, &properties); | 521 product.AddDefaultShortcutProperties(chrome_exe, &properties); |
| 446 | 522 |
| 447 const base::string16 command_line = | |
| 448 profiles::internal::CreateProfileShortcutFlags(params.profile_path); | |
| 449 | 523 |
| 450 // Only set the profile-specific properties when |profile_name| is non empty. | 524 // Only set the profile-specific properties when |profile_name| is non empty. |
| 451 // If it is empty, it means the shortcut being created should be a regular, | 525 // If it is empty, it means the shortcut being created should be a regular, |
| 452 // non-profile Chrome shortcut. | 526 // non-profile Chrome shortcut. |
| 453 if (!params.profile_name.empty()) { | 527 if (!params.profile_name.empty()) { |
| 454 properties.set_arguments(command_line); | 528 properties.set_arguments(command_line); |
| 455 properties.set_icon(shortcut_icon, 0); | 529 properties.set_icon(shortcut_icon, 0); |
| 456 } else { | 530 } else { |
| 457 // Set the arguments explicitly to the empty string to ensure that | 531 // Set the arguments explicitly to the empty string to ensure that |
| 458 // |ShellUtil::CreateOrUpdateShortcut| updates that part of the shortcut. | 532 // |ShellUtil::CreateOrUpdateShortcut| updates that part of the shortcut. |
| 459 properties.set_arguments(base::string16()); | 533 properties.set_arguments(base::string16()); |
| 460 } | 534 } |
| 461 | 535 |
| 462 properties.set_app_id( | 536 properties.set_app_id( |
| 463 ShellIntegration::GetChromiumModelIdForProfile(params.profile_path)); | 537 ShellIntegration::GetChromiumModelIdForProfile(params.profile_path)); |
| 464 | 538 |
| 465 ShellUtil::ShortcutOperation operation = | 539 ShellUtil::ShortcutOperation operation = |
| 466 ShellUtil::SHELL_SHORTCUT_REPLACE_EXISTING; | 540 ShellUtil::SHELL_SHORTCUT_REPLACE_EXISTING; |
| 467 | 541 |
| 468 std::vector<base::FilePath> shortcuts; | |
| 469 ListDesktopShortcutsWithCommandLine(chrome_exe, command_line, | |
| 470 params.action == ProfileShortcutManagerWin::UPDATE_NON_PROFILE_SHORTCUTS, | |
| 471 &shortcuts); | |
| 472 if (params.create_mode == ProfileShortcutManagerWin::CREATE_WHEN_NONE_FOUND && | 542 if (params.create_mode == ProfileShortcutManagerWin::CREATE_WHEN_NONE_FOUND && |
| 473 shortcuts.empty()) { | 543 shortcuts.empty()) { |
| 474 const base::string16 shortcut_name = | 544 const base::string16 shortcut_name = |
| 475 profiles::internal::GetShortcutFilenameForProfile(params.profile_name, | 545 profiles::internal::GetUniqueShortcutFilenameForProfile( |
| 476 distribution); | 546 params.profile_name, distribution, desktop_contents); |
| 477 shortcuts.push_back(base::FilePath(shortcut_name)); | 547 shortcuts.insert(base::FilePath(shortcut_name)); |
| 478 operation = ShellUtil::SHELL_SHORTCUT_CREATE_IF_NO_SYSTEM_LEVEL; | 548 operation = ShellUtil::SHELL_SHORTCUT_CREATE_IF_NO_SYSTEM_LEVEL; |
| 479 } | 549 } |
| 480 | 550 |
| 481 for (size_t i = 0; i < shortcuts.size(); ++i) { | 551 for (const auto& shortcut : shortcuts) { |
| 482 const base::FilePath shortcut_name = | 552 const base::FilePath shortcut_name = shortcut.BaseName().RemoveExtension(); |
| 483 shortcuts[i].BaseName().RemoveExtension(); | |
| 484 properties.set_shortcut_name(shortcut_name.value()); | 553 properties.set_shortcut_name(shortcut_name.value()); |
| 485 ShellUtil::CreateOrUpdateShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP, | 554 ShellUtil::CreateOrUpdateShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP, |
| 486 distribution, properties, operation); | 555 distribution, properties, operation); |
| 487 } | 556 } |
| 488 } | 557 } |
| 489 | 558 |
| 490 // Returns true if any desktop shortcuts exist with target |chrome_exe|, | 559 // Returns true if any desktop shortcuts exist with target |chrome_exe|, |
| 491 // regardless of their command line arguments. | 560 // regardless of their command line arguments. |
| 492 bool ChromeDesktopShortcutsExist(const base::FilePath& chrome_exe) { | 561 bool ChromeDesktopShortcutsExist(const base::FilePath& chrome_exe) { |
| 493 base::FilePath user_shortcuts_directory; | 562 base::FilePath user_shortcuts_directory; |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 514 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 583 DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
| 515 | 584 |
| 516 base::FilePath chrome_exe; | 585 base::FilePath chrome_exe; |
| 517 if (!PathService::Get(base::FILE_EXE, &chrome_exe)) { | 586 if (!PathService::Get(base::FILE_EXE, &chrome_exe)) { |
| 518 NOTREACHED(); | 587 NOTREACHED(); |
| 519 return; | 588 return; |
| 520 } | 589 } |
| 521 | 590 |
| 522 const base::string16 command_line = | 591 const base::string16 command_line = |
| 523 profiles::internal::CreateProfileShortcutFlags(profile_path); | 592 profiles::internal::CreateProfileShortcutFlags(profile_path); |
| 524 std::vector<base::FilePath> shortcuts; | 593 ChromeCommandLineFilter filter(chrome_exe, command_line, false); |
| 525 ListDesktopShortcutsWithCommandLine(chrome_exe, command_line, false, | 594 const std::set<base::FilePath> shortcuts = ListUserDesktopContents(&filter); |
| 526 &shortcuts); | |
| 527 | 595 |
| 528 for (size_t i = 0; i < shortcuts.size(); ++i) { | 596 for (const auto& shortcut : shortcuts) { |
| 529 // Use base::DeleteFile() instead of ShellUtil::RemoveShortcuts(), as the | 597 // Use base::DeleteFile() instead of ShellUtil::RemoveShortcuts(), as the |
| 530 // latter causes non-profile taskbar shortcuts to be removed since it | 598 // latter causes non-profile taskbar shortcuts to be removed since it |
| 531 // doesn't consider the command-line of the shortcuts it deletes. | 599 // doesn't consider the command-line of the shortcuts it deletes. |
| 532 // TODO(huangs): Refactor with ShellUtil::RemoveShortcuts(). | 600 // TODO(huangs): Refactor with ShellUtil::RemoveShortcuts(). |
| 533 base::win::UnpinShortcutFromTaskbar(shortcuts[i]); | 601 base::win::UnpinShortcutFromTaskbar(shortcut); |
| 534 base::DeleteFile(shortcuts[i], false); | 602 base::DeleteFile(shortcut, false); |
| 535 // Notify the shell that the shortcut was deleted to ensure desktop refresh. | 603 // Notify the shell that the shortcut was deleted to ensure desktop refresh. |
| 536 SHChangeNotify(SHCNE_DELETE, SHCNF_PATH, shortcuts[i].value().c_str(), | 604 SHChangeNotify(SHCNE_DELETE, SHCNF_PATH, shortcut.value().c_str(), nullptr); |
| 537 NULL); | |
| 538 } | 605 } |
| 539 | 606 |
| 540 // If |ensure_shortcuts_remain| is true and deleting this profile caused the | 607 // If |ensure_shortcuts_remain| is true and deleting this profile caused the |
| 541 // last shortcuts to be removed, re-create a regular non-profile shortcut. | 608 // last shortcuts to be removed, re-create a regular non-profile shortcut. |
| 542 const bool had_shortcuts = !shortcuts.empty(); | 609 const bool had_shortcuts = !shortcuts.empty(); |
| 543 if (ensure_shortcuts_remain && had_shortcuts && | 610 if (ensure_shortcuts_remain && had_shortcuts && |
| 544 !ChromeDesktopShortcutsExist(chrome_exe)) { | 611 !ChromeDesktopShortcutsExist(chrome_exe)) { |
| 545 BrowserDistribution* distribution = BrowserDistribution::GetDistribution(); | 612 BrowserDistribution* distribution = BrowserDistribution::GetDistribution(); |
| 546 // Ensure that the distribution supports creating shortcuts. If it doesn't, | 613 // Ensure that the distribution supports creating shortcuts. If it doesn't, |
| 547 // the following code may result in NOTREACHED() being hit. | 614 // the following code may result in NOTREACHED() being hit. |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 565 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 632 DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
| 566 | 633 |
| 567 base::FilePath chrome_exe; | 634 base::FilePath chrome_exe; |
| 568 if (!PathService::Get(base::FILE_EXE, &chrome_exe)) { | 635 if (!PathService::Get(base::FILE_EXE, &chrome_exe)) { |
| 569 NOTREACHED(); | 636 NOTREACHED(); |
| 570 return false; | 637 return false; |
| 571 } | 638 } |
| 572 | 639 |
| 573 const base::string16 command_line = | 640 const base::string16 command_line = |
| 574 profiles::internal::CreateProfileShortcutFlags(profile_path); | 641 profiles::internal::CreateProfileShortcutFlags(profile_path); |
| 575 std::vector<base::FilePath> shortcuts; | 642 ChromeCommandLineFilter filter(chrome_exe, command_line, false); |
| 576 ListDesktopShortcutsWithCommandLine(chrome_exe, command_line, false, | 643 const std::set<base::FilePath> shortcuts = ListUserDesktopContents(&filter); |
| 577 &shortcuts); | |
| 578 return !shortcuts.empty(); | 644 return !shortcuts.empty(); |
| 579 } | 645 } |
| 580 | 646 |
| 581 // Replaces any reserved characters with spaces, and trims the resulting string | 647 // Replaces any reserved characters with spaces, and trims the resulting string |
| 582 // to prevent any leading and trailing spaces. Also makes sure that the | 648 // to prevent any leading and trailing spaces. Also makes sure that the |
| 583 // resulting filename doesn't exceed |kMaxProfileShortcutFileNameLength|. | 649 // resulting filename doesn't exceed |kMaxProfileShortcutFileNameLength|. |
| 584 // TODO(macourteau): find a way to limit the total path's length to MAX_PATH | 650 // TODO(macourteau): find a way to limit the total path's length to MAX_PATH |
| 585 // instead of limiting the profile's name to |kMaxProfileShortcutFileNameLength| | 651 // instead of limiting the profile's name to |kMaxProfileShortcutFileNameLength| |
| 586 // characters. | 652 // characters. |
| 587 base::string16 SanitizeShortcutProfileNameString( | 653 base::string16 SanitizeShortcutProfileNameString( |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 636 shortcut_name.append(SanitizeShortcutProfileNameString(profile_name)); | 702 shortcut_name.append(SanitizeShortcutProfileNameString(profile_name)); |
| 637 shortcut_name.append(L" - "); | 703 shortcut_name.append(L" - "); |
| 638 shortcut_name.append(l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME)); | 704 shortcut_name.append(l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME)); |
| 639 } else { | 705 } else { |
| 640 shortcut_name.append( | 706 shortcut_name.append( |
| 641 distribution->GetShortcutName(BrowserDistribution::SHORTCUT_CHROME)); | 707 distribution->GetShortcutName(BrowserDistribution::SHORTCUT_CHROME)); |
| 642 } | 708 } |
| 643 return shortcut_name + installer::kLnkExt; | 709 return shortcut_name + installer::kLnkExt; |
| 644 } | 710 } |
| 645 | 711 |
| 712 base::string16 GetUniqueShortcutFilenameForProfile( | |
| 713 const base::string16& profile_name, | |
| 714 BrowserDistribution* distribution, | |
| 715 const std::set<base::FilePath>& excludes) { | |
| 716 std::set<base::string16> excludes_names; | |
| 717 std::transform(excludes.begin(), excludes.end(), | |
| 718 std::inserter(excludes_names, excludes_names.begin()), | |
| 719 [](const base::FilePath& e) { return e.BaseName().value(); }); | |
| 720 | |
| 721 const auto base_name = | |
| 722 GetShortcutFilenameForProfile(profile_name, distribution); | |
| 723 auto name = base_name; | |
| 724 for (int uniquifier = 1; excludes_names.count(name) > 0; ++uniquifier) | |
|
Alexei Svitkine (slow)
2016/01/15 18:01:38
Nit: {}'s
Michael K. (Yandex Team)
2016/01/18 09:37:54
Done.
| |
| 725 name = base::FilePath(base_name) | |
|
Alexei Svitkine (slow)
2016/01/15 18:01:38
Move the FilePath outside the loop.
Michael K. (Yandex Team)
2016/01/18 09:37:54
Acknowledged.
| |
| 726 .InsertBeforeExtensionASCII(base::StringPrintf(" (%d)", uniquifier)) | |
| 727 .value(); | |
| 728 return name; | |
| 729 } | |
| 730 | |
| 731 // Corresponds to GetUniqueShortcutFilenameForProfile. | |
| 732 ShortcutFilenameMatcher::ShortcutFilenameMatcher( | |
| 733 const base::string16& profile_name, | |
| 734 BrowserDistribution* distribution) | |
| 735 : profile_shortcut_filename_( | |
| 736 GetShortcutFilenameForProfile(profile_name, distribution)), | |
| 737 lnk_ext_(installer::kLnkExt), | |
| 738 profile_shortcut_name_(profile_shortcut_filename_) { | |
| 739 DCHECK(profile_shortcut_name_.ends_with(lnk_ext_)); | |
| 740 profile_shortcut_name_.remove_suffix(lnk_ext_.size()); | |
| 741 } | |
| 742 | |
| 743 bool ShortcutFilenameMatcher::IsCanonical( | |
| 744 const base::string16& filename) const { | |
| 745 if (filename == profile_shortcut_filename_) | |
| 746 return true; | |
| 747 | |
| 748 base::StringPiece16 shortcut_suffix(filename); | |
| 749 if (!shortcut_suffix.starts_with(profile_shortcut_name_)) | |
| 750 return false; | |
| 751 shortcut_suffix.remove_prefix(profile_shortcut_name_.size()); | |
| 752 | |
| 753 if (!shortcut_suffix.ends_with(lnk_ext_)) | |
| 754 return false; | |
| 755 shortcut_suffix.remove_suffix(lnk_ext_.size()); | |
| 756 | |
| 757 if (shortcut_suffix.size() < 4 || !shortcut_suffix.starts_with(L" (") || | |
| 758 !shortcut_suffix.ends_with(L")")) { | |
| 759 return false; | |
| 760 } | |
| 761 return std::all_of(shortcut_suffix.begin() + 2, shortcut_suffix.end() - 1, | |
| 762 iswdigit); | |
| 763 } | |
| 764 | |
| 646 base::string16 CreateProfileShortcutFlags(const base::FilePath& profile_path) { | 765 base::string16 CreateProfileShortcutFlags(const base::FilePath& profile_path) { |
| 647 return base::StringPrintf(L"--%ls=\"%ls\"", | 766 return base::StringPrintf(L"--%ls=\"%ls\"", |
| 648 base::ASCIIToUTF16( | 767 base::ASCIIToUTF16( |
| 649 switches::kProfileDirectory).c_str(), | 768 switches::kProfileDirectory).c_str(), |
| 650 profile_path.BaseName().value().c_str()); | 769 profile_path.BaseName().value().c_str()); |
| 651 } | 770 } |
| 652 | 771 |
| 653 } // namespace internal | 772 } // namespace internal |
| 654 } // namespace profiles | 773 } // namespace profiles |
| 655 | 774 |
| (...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 877 // Ensure the profile's icon file has been created. | 996 // Ensure the profile's icon file has been created. |
| 878 CreateOrUpdateProfileIcon(profile->GetPath()); | 997 CreateOrUpdateProfileIcon(profile->GetPath()); |
| 879 } | 998 } |
| 880 break; | 999 break; |
| 881 } | 1000 } |
| 882 default: | 1001 default: |
| 883 NOTREACHED(); | 1002 NOTREACHED(); |
| 884 break; | 1003 break; |
| 885 } | 1004 } |
| 886 } | 1005 } |
| OLD | NEW |