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 // Get the file paths of desktop files and folders |
295 // filtered by predicate |p|. | |
Alexei Svitkine (slow)
2016/01/05 19:55:22
Nit: Wrapping is off for this comment.
| |
296 template <class Filter> | |
Alexei Svitkine (slow)
2016/01/05 19:55:22
Templates are not commonly used in Chromium (outsi
| |
297 std::set<base::FilePath> ListUserDesktopContents(const Filter& p) { | |
298 std::set<base::FilePath> res; | |
299 | |
300 base::FilePath user_shortcuts_directory; | |
301 if (!GetDesktopShortcutsDirectories(&user_shortcuts_directory, nullptr)) | |
302 return res; | |
303 | |
304 base::FileEnumerator enumerator( | |
305 user_shortcuts_directory, false, | |
306 base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES); | |
307 for (base::FilePath path = enumerator.Next(); !path.empty(); | |
308 path = enumerator.Next()) { | |
309 if (p(path)) | |
Alexei Svitkine (slow)
2016/01/05 19:55:22
p(path) doesn't sound very readable. Name the para
| |
310 res.insert(path); | |
311 } | |
312 return res; | |
313 } | |
314 | |
315 // Checks if |path| is the Chrome desktop shortcut (|chrome_exe|) that have | |
293 // the specified |command_line|. If |include_empty_command_lines| is true, | 316 // the specified |command_line|. If |include_empty_command_lines| is true, |
294 // Chrome desktop shortcuts with empty command lines will also be included. | 317 // Chrome desktop shortcuts with empty command lines will also be included. |
295 void ListDesktopShortcutsWithCommandLine(const base::FilePath& chrome_exe, | 318 struct ChromeCommandLineFilter { |
296 const base::string16& command_line, | 319 const base::FilePath& chrome_exe; |
297 bool include_empty_command_lines, | 320 const base::string16& command_line; |
298 std::vector<base::FilePath>* paths) { | 321 bool include_empty_command_lines; |
299 base::FilePath user_shortcuts_directory; | |
300 if (!GetDesktopShortcutsDirectories(&user_shortcuts_directory, NULL)) | |
301 return; | |
302 | 322 |
303 base::FileEnumerator enumerator(user_shortcuts_directory, false, | 323 ChromeCommandLineFilter(const base::FilePath& chrome_exe, |
304 base::FileEnumerator::FILES); | 324 const base::string16& command_line, |
305 for (base::FilePath path = enumerator.Next(); !path.empty(); | 325 bool include_empty_command_lines) |
306 path = enumerator.Next()) { | 326 : chrome_exe(chrome_exe), |
327 command_line(command_line), | |
328 include_empty_command_lines(include_empty_command_lines) {} | |
329 | |
330 bool operator()(const base::FilePath& path) const { | |
307 base::string16 shortcut_command_line; | 331 base::string16 shortcut_command_line; |
308 if (!IsChromeShortcut(path, chrome_exe, &shortcut_command_line)) | 332 if (!IsChromeShortcut(path, chrome_exe, &shortcut_command_line)) |
309 continue; | 333 return false; |
310 | 334 |
311 // TODO(asvitkine): Change this to build a CommandLine object and ensure all | 335 // 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 | 336 // args from |command_line| are present in the shortcut's CommandLine. This |
313 // will be more robust when |command_line| contains multiple args. | 337 // will be more robust when |command_line| contains multiple args. |
314 if ((shortcut_command_line.empty() && include_empty_command_lines) || | 338 if ((shortcut_command_line.empty() && include_empty_command_lines) || |
315 (shortcut_command_line.find(command_line) != base::string16::npos)) { | 339 (shortcut_command_line.find(command_line) != base::string16::npos)) { |
316 paths->push_back(path); | 340 return true; |
317 } | 341 } |
342 return false; | |
318 } | 343 } |
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. |
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 auto new_shortcut_filename = | |
383 profiles::internal::GetShortcutUniqueFilenameForProfile( | |
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 auto desktop_contents = ListUserDesktopContents([](...) { return true; }); | |
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 std::copy_if(desktop_contents.begin(), desktop_contents.end(), | |
508 std::inserter(shortcuts, shortcuts.begin()), filter); | |
Alexei Svitkine (slow)
2016/01/05 19:55:22
Why copy_if here instead of passing the filter dir
| |
509 | |
431 if (params.old_profile_name != params.profile_name) { | 510 if (params.old_profile_name != params.profile_name) { |
432 const base::string16 old_shortcut_filename = | 511 RenameChromeDesktopShortcutForProfile(params.old_profile_name, |
433 profiles::internal::GetShortcutFilenameForProfile( | 512 params.profile_name, &shortcuts, |
434 params.old_profile_name, | 513 &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 } | 514 } |
442 | 515 |
443 ShellUtil::ShortcutProperties properties(ShellUtil::CURRENT_USER); | 516 ShellUtil::ShortcutProperties properties(ShellUtil::CURRENT_USER); |
444 installer::Product product(distribution); | 517 installer::Product product(distribution); |
445 product.AddDefaultShortcutProperties(chrome_exe, &properties); | 518 product.AddDefaultShortcutProperties(chrome_exe, &properties); |
446 | 519 |
447 const base::string16 command_line = | |
448 profiles::internal::CreateProfileShortcutFlags(params.profile_path); | |
449 | 520 |
450 // Only set the profile-specific properties when |profile_name| is non empty. | 521 // 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, | 522 // If it is empty, it means the shortcut being created should be a regular, |
452 // non-profile Chrome shortcut. | 523 // non-profile Chrome shortcut. |
453 if (!params.profile_name.empty()) { | 524 if (!params.profile_name.empty()) { |
454 properties.set_arguments(command_line); | 525 properties.set_arguments(command_line); |
455 properties.set_icon(shortcut_icon, 0); | 526 properties.set_icon(shortcut_icon, 0); |
456 } else { | 527 } else { |
457 // Set the arguments explicitly to the empty string to ensure that | 528 // Set the arguments explicitly to the empty string to ensure that |
458 // |ShellUtil::CreateOrUpdateShortcut| updates that part of the shortcut. | 529 // |ShellUtil::CreateOrUpdateShortcut| updates that part of the shortcut. |
459 properties.set_arguments(base::string16()); | 530 properties.set_arguments(base::string16()); |
460 } | 531 } |
461 | 532 |
462 properties.set_app_id( | 533 properties.set_app_id( |
463 ShellIntegration::GetChromiumModelIdForProfile(params.profile_path)); | 534 ShellIntegration::GetChromiumModelIdForProfile(params.profile_path)); |
464 | 535 |
465 ShellUtil::ShortcutOperation operation = | 536 ShellUtil::ShortcutOperation operation = |
466 ShellUtil::SHELL_SHORTCUT_REPLACE_EXISTING; | 537 ShellUtil::SHELL_SHORTCUT_REPLACE_EXISTING; |
467 | 538 |
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 && | 539 if (params.create_mode == ProfileShortcutManagerWin::CREATE_WHEN_NONE_FOUND && |
473 shortcuts.empty()) { | 540 shortcuts.empty()) { |
474 const base::string16 shortcut_name = | 541 const base::string16 shortcut_name = |
475 profiles::internal::GetShortcutFilenameForProfile(params.profile_name, | 542 profiles::internal::GetShortcutUniqueFilenameForProfile( |
476 distribution); | 543 params.profile_name, distribution, desktop_contents); |
477 shortcuts.push_back(base::FilePath(shortcut_name)); | 544 shortcuts.insert(base::FilePath(shortcut_name)); |
478 operation = ShellUtil::SHELL_SHORTCUT_CREATE_IF_NO_SYSTEM_LEVEL; | 545 operation = ShellUtil::SHELL_SHORTCUT_CREATE_IF_NO_SYSTEM_LEVEL; |
479 } | 546 } |
480 | 547 |
481 for (size_t i = 0; i < shortcuts.size(); ++i) { | 548 for (const auto& shortcut : shortcuts) { |
482 const base::FilePath shortcut_name = | 549 const base::FilePath shortcut_name = shortcut.BaseName().RemoveExtension(); |
483 shortcuts[i].BaseName().RemoveExtension(); | |
484 properties.set_shortcut_name(shortcut_name.value()); | 550 properties.set_shortcut_name(shortcut_name.value()); |
485 ShellUtil::CreateOrUpdateShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP, | 551 ShellUtil::CreateOrUpdateShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP, |
486 distribution, properties, operation); | 552 distribution, properties, operation); |
487 } | 553 } |
488 } | 554 } |
489 | 555 |
490 // Returns true if any desktop shortcuts exist with target |chrome_exe|, | 556 // Returns true if any desktop shortcuts exist with target |chrome_exe|, |
491 // regardless of their command line arguments. | 557 // regardless of their command line arguments. |
492 bool ChromeDesktopShortcutsExist(const base::FilePath& chrome_exe) { | 558 bool ChromeDesktopShortcutsExist(const base::FilePath& chrome_exe) { |
493 base::FilePath user_shortcuts_directory; | 559 base::FilePath user_shortcuts_directory; |
(...skipping 20 matching lines...) Expand all Loading... | |
514 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 580 DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
515 | 581 |
516 base::FilePath chrome_exe; | 582 base::FilePath chrome_exe; |
517 if (!PathService::Get(base::FILE_EXE, &chrome_exe)) { | 583 if (!PathService::Get(base::FILE_EXE, &chrome_exe)) { |
518 NOTREACHED(); | 584 NOTREACHED(); |
519 return; | 585 return; |
520 } | 586 } |
521 | 587 |
522 const base::string16 command_line = | 588 const base::string16 command_line = |
523 profiles::internal::CreateProfileShortcutFlags(profile_path); | 589 profiles::internal::CreateProfileShortcutFlags(profile_path); |
524 std::vector<base::FilePath> shortcuts; | 590 ChromeCommandLineFilter filter(chrome_exe, command_line, false); |
525 ListDesktopShortcutsWithCommandLine(chrome_exe, command_line, false, | 591 const auto shortcuts = ListUserDesktopContents(filter); |
anthonyvd
2016/01/04 16:30:18
nit: Can you write the actual return type when cal
| |
526 &shortcuts); | |
527 | 592 |
528 for (size_t i = 0; i < shortcuts.size(); ++i) { | 593 for (const auto& shortcut : shortcuts) { |
529 // Use base::DeleteFile() instead of ShellUtil::RemoveShortcuts(), as the | 594 // Use base::DeleteFile() instead of ShellUtil::RemoveShortcuts(), as the |
530 // latter causes non-profile taskbar shortcuts to be removed since it | 595 // latter causes non-profile taskbar shortcuts to be removed since it |
531 // doesn't consider the command-line of the shortcuts it deletes. | 596 // doesn't consider the command-line of the shortcuts it deletes. |
532 // TODO(huangs): Refactor with ShellUtil::RemoveShortcuts(). | 597 // TODO(huangs): Refactor with ShellUtil::RemoveShortcuts(). |
533 base::win::UnpinShortcutFromTaskbar(shortcuts[i]); | 598 base::win::UnpinShortcutFromTaskbar(shortcut); |
534 base::DeleteFile(shortcuts[i], false); | 599 base::DeleteFile(shortcut, false); |
535 // Notify the shell that the shortcut was deleted to ensure desktop refresh. | 600 // Notify the shell that the shortcut was deleted to ensure desktop refresh. |
536 SHChangeNotify(SHCNE_DELETE, SHCNF_PATH, shortcuts[i].value().c_str(), | 601 SHChangeNotify(SHCNE_DELETE, SHCNF_PATH, shortcut.value().c_str(), nullptr); |
537 NULL); | |
538 } | 602 } |
539 | 603 |
540 // If |ensure_shortcuts_remain| is true and deleting this profile caused the | 604 // 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. | 605 // last shortcuts to be removed, re-create a regular non-profile shortcut. |
542 const bool had_shortcuts = !shortcuts.empty(); | 606 const bool had_shortcuts = !shortcuts.empty(); |
543 if (ensure_shortcuts_remain && had_shortcuts && | 607 if (ensure_shortcuts_remain && had_shortcuts && |
544 !ChromeDesktopShortcutsExist(chrome_exe)) { | 608 !ChromeDesktopShortcutsExist(chrome_exe)) { |
545 BrowserDistribution* distribution = BrowserDistribution::GetDistribution(); | 609 BrowserDistribution* distribution = BrowserDistribution::GetDistribution(); |
546 // Ensure that the distribution supports creating shortcuts. If it doesn't, | 610 // Ensure that the distribution supports creating shortcuts. If it doesn't, |
547 // the following code may result in NOTREACHED() being hit. | 611 // the following code may result in NOTREACHED() being hit. |
(...skipping 17 matching lines...) Expand all Loading... | |
565 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 629 DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
566 | 630 |
567 base::FilePath chrome_exe; | 631 base::FilePath chrome_exe; |
568 if (!PathService::Get(base::FILE_EXE, &chrome_exe)) { | 632 if (!PathService::Get(base::FILE_EXE, &chrome_exe)) { |
569 NOTREACHED(); | 633 NOTREACHED(); |
570 return false; | 634 return false; |
571 } | 635 } |
572 | 636 |
573 const base::string16 command_line = | 637 const base::string16 command_line = |
574 profiles::internal::CreateProfileShortcutFlags(profile_path); | 638 profiles::internal::CreateProfileShortcutFlags(profile_path); |
575 std::vector<base::FilePath> shortcuts; | 639 ChromeCommandLineFilter filter(chrome_exe, command_line, false); |
576 ListDesktopShortcutsWithCommandLine(chrome_exe, command_line, false, | 640 const auto shortcuts = ListUserDesktopContents(filter); |
577 &shortcuts); | |
578 return !shortcuts.empty(); | 641 return !shortcuts.empty(); |
579 } | 642 } |
580 | 643 |
581 // Replaces any reserved characters with spaces, and trims the resulting string | 644 // Replaces any reserved characters with spaces, and trims the resulting string |
582 // to prevent any leading and trailing spaces. Also makes sure that the | 645 // to prevent any leading and trailing spaces. Also makes sure that the |
583 // resulting filename doesn't exceed |kMaxProfileShortcutFileNameLength|. | 646 // resulting filename doesn't exceed |kMaxProfileShortcutFileNameLength|. |
584 // TODO(macourteau): find a way to limit the total path's length to MAX_PATH | 647 // 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| | 648 // instead of limiting the profile's name to |kMaxProfileShortcutFileNameLength| |
586 // characters. | 649 // characters. |
587 base::string16 SanitizeShortcutProfileNameString( | 650 base::string16 SanitizeShortcutProfileNameString( |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
636 shortcut_name.append(SanitizeShortcutProfileNameString(profile_name)); | 699 shortcut_name.append(SanitizeShortcutProfileNameString(profile_name)); |
637 shortcut_name.append(L" - "); | 700 shortcut_name.append(L" - "); |
638 shortcut_name.append(l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME)); | 701 shortcut_name.append(l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME)); |
639 } else { | 702 } else { |
640 shortcut_name.append( | 703 shortcut_name.append( |
641 distribution->GetShortcutName(BrowserDistribution::SHORTCUT_CHROME)); | 704 distribution->GetShortcutName(BrowserDistribution::SHORTCUT_CHROME)); |
642 } | 705 } |
643 return shortcut_name + installer::kLnkExt; | 706 return shortcut_name + installer::kLnkExt; |
644 } | 707 } |
645 | 708 |
709 base::string16 GetShortcutUniqueFilenameForProfile( | |
710 const base::string16& profile_name, | |
711 BrowserDistribution* distribution, | |
712 const std::set<base::FilePath>& excludes) { | |
713 std::set<base::string16> excludes_names; | |
714 std::transform(excludes.begin(), excludes.end(), | |
715 std::inserter(excludes_names, excludes_names.begin()), | |
716 [](const base::FilePath& e) { return e.BaseName().value(); }); | |
717 | |
718 const auto base_name = | |
719 GetShortcutFilenameForProfile(profile_name, distribution); | |
720 auto name = base_name; | |
721 for (int uniquifier = 2; excludes_names.count(name) > 0; ++uniquifier) | |
anthonyvd
2016/01/04 16:30:18
Little bikeshedding: I think this should start at
| |
722 name = base::FilePath(base_name) | |
723 .InsertBeforeExtensionASCII(base::StringPrintf(" (%d)", uniquifier)) | |
724 .value(); | |
725 return name; | |
726 } | |
727 | |
728 // Corresponds to GetShortcutUniqueFilenameForProfile. | |
729 ShortcutFilenameMatcher::ShortcutFilenameMatcher( | |
730 const base::string16& profile_name, | |
731 BrowserDistribution* distribution) | |
732 : profile_shortcut_filename_( | |
733 GetShortcutFilenameForProfile(profile_name, distribution)), | |
734 lnk_ext_(installer::kLnkExt), | |
735 profile_shortcut_name_(profile_shortcut_filename_) { | |
736 DCHECK(profile_shortcut_name_.ends_with(lnk_ext_)); | |
737 profile_shortcut_name_.remove_suffix(lnk_ext_.size()); | |
738 } | |
739 | |
740 bool ShortcutFilenameMatcher::IsCanonical( | |
741 const base::string16& filename) const { | |
742 if (filename == profile_shortcut_filename_) | |
743 return true; | |
744 | |
745 base::StringPiece16 shortcut_suffix(filename); | |
746 if (!shortcut_suffix.starts_with(profile_shortcut_name_)) | |
747 return false; | |
748 shortcut_suffix.remove_prefix(profile_shortcut_name_.size()); | |
749 | |
750 if (!shortcut_suffix.ends_with(lnk_ext_)) | |
751 return false; | |
752 shortcut_suffix.remove_suffix(lnk_ext_.size()); | |
753 | |
754 if (shortcut_suffix.size() < 4 || !shortcut_suffix.starts_with(L" (") || | |
755 !shortcut_suffix.ends_with(L")")) | |
Alexei Svitkine (slow)
2016/01/05 19:55:22
Nit: {}'s
| |
756 return false; | |
757 return std::all_of(shortcut_suffix.begin() + 2, shortcut_suffix.end() - 1, | |
758 [](wchar_t c) { return c >= L'0' && c <= L'9'; }); | |
Alexei Svitkine (slow)
2016/01/05 19:55:22
Can this be isdigit?
| |
759 } | |
760 | |
646 base::string16 CreateProfileShortcutFlags(const base::FilePath& profile_path) { | 761 base::string16 CreateProfileShortcutFlags(const base::FilePath& profile_path) { |
647 return base::StringPrintf(L"--%ls=\"%ls\"", | 762 return base::StringPrintf(L"--%ls=\"%ls\"", |
648 base::ASCIIToUTF16( | 763 base::ASCIIToUTF16( |
649 switches::kProfileDirectory).c_str(), | 764 switches::kProfileDirectory).c_str(), |
650 profile_path.BaseName().value().c_str()); | 765 profile_path.BaseName().value().c_str()); |
651 } | 766 } |
652 | 767 |
653 } // namespace internal | 768 } // namespace internal |
654 } // namespace profiles | 769 } // namespace profiles |
655 | 770 |
(...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
877 // Ensure the profile's icon file has been created. | 992 // Ensure the profile's icon file has been created. |
878 CreateOrUpdateProfileIcon(profile->GetPath()); | 993 CreateOrUpdateProfileIcon(profile->GetPath()); |
879 } | 994 } |
880 break; | 995 break; |
881 } | 996 } |
882 default: | 997 default: |
883 NOTREACHED(); | 998 NOTREACHED(); |
884 break; | 999 break; |
885 } | 1000 } |
886 } | 1001 } |
OLD | NEW |