// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/ui/bookmarks/bookmark_utils.h" #include #include "base/logging.h" #include "build/build_config.h" #include "chrome/browser/bookmarks/bookmark_model_factory.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/search/search.h" #include "chrome/common/pref_names.h" #include "chrome/common/url_constants.h" #include "components/bookmarks/browser/bookmark_model.h" #include "components/bookmarks/browser/bookmark_node_data.h" #include "components/bookmarks/common/bookmark_pref_names.h" #include "components/prefs/pref_service.h" #include "components/search/search.h" #include "components/url_formatter/url_formatter.h" #include "components/user_prefs/user_prefs.h" #include "content/public/browser/web_contents.h" #include "ui/base/dragdrop/drag_drop_types.h" #include "ui/base/dragdrop/drop_target_event.h" #if defined(ENABLE_EXTENSIONS) #include "chrome/browser/extensions/api/commands/command_service.h" #include "extensions/browser/extension_registry.h" #include "extensions/common/extension_set.h" #endif #if defined(TOOLKIT_VIEWS) #include "ui/gfx/color_utils.h" #include "ui/gfx/paint_vector_icon.h" #include "ui/gfx/vector_icons_public.h" #endif #if defined(OS_WIN) #include "chrome/grit/theme_resources.h" #include "ui/base/material_design/material_design_controller.h" #include "ui/base/resource/resource_bundle.h" #endif using bookmarks::BookmarkModel; using bookmarks::BookmarkNode; namespace chrome { namespace { // The ways in which extensions may customize the bookmark shortcut. enum BookmarkShortcutDisposition { BOOKMARK_SHORTCUT_DISPOSITION_UNCHANGED, BOOKMARK_SHORTCUT_DISPOSITION_REMOVED, BOOKMARK_SHORTCUT_DISPOSITION_OVERRIDE_REQUESTED }; // Indicates how the bookmark shortcut has been changed by extensions associated // with |profile|, if at all. BookmarkShortcutDisposition GetBookmarkShortcutDisposition(Profile* profile) { #if defined(ENABLE_EXTENSIONS) extensions::CommandService* command_service = extensions::CommandService::Get(profile); extensions::ExtensionRegistry* registry = extensions::ExtensionRegistry::Get(profile); if (!registry) return BOOKMARK_SHORTCUT_DISPOSITION_UNCHANGED; const extensions::ExtensionSet& extension_set = registry->enabled_extensions(); // This flag tracks whether any extension wants the disposition to be // removed. bool removed = false; for (extensions::ExtensionSet::const_iterator i = extension_set.begin(); i != extension_set.end(); ++i) { // Use the overridden disposition if any extension wants it. if (command_service->RequestsBookmarkShortcutOverride(i->get())) return BOOKMARK_SHORTCUT_DISPOSITION_OVERRIDE_REQUESTED; if (!removed && extensions::CommandService::RemovesBookmarkShortcut(i->get())) { removed = true; } } if (removed) return BOOKMARK_SHORTCUT_DISPOSITION_REMOVED; #endif return BOOKMARK_SHORTCUT_DISPOSITION_UNCHANGED; } #if defined(TOOLKIT_VIEWS) gfx::ImageSkia GetFolderIcon(gfx::VectorIconId id, SkColor text_color) { return gfx::CreateVectorIcon(id, 16, color_utils::DeriveDefaultIconColor(text_color)); } #endif } // namespace GURL GetURLToBookmark(content::WebContents* web_contents) { DCHECK(web_contents); return search::IsInstantNTP(web_contents) ? GURL(kChromeUINewTabURL) : web_contents->GetURL(); } void GetURLAndTitleToBookmark(content::WebContents* web_contents, GURL* url, base::string16* title) { *url = GetURLToBookmark(web_contents); *title = web_contents->GetTitle(); } void ToggleBookmarkBarWhenVisible(content::BrowserContext* browser_context) { PrefService* prefs = user_prefs::UserPrefs::Get(browser_context); const bool always_show = !prefs->GetBoolean(bookmarks::prefs::kShowBookmarkBar); // The user changed when the bookmark bar is shown, update the preferences. prefs->SetBoolean(bookmarks::prefs::kShowBookmarkBar, always_show); } base::string16 FormatBookmarkURLForDisplay(const GURL& url, const PrefService* prefs) { std::string languages; if (prefs) languages = prefs->GetString(prefs::kAcceptLanguages); // Because this gets re-parsed by FixupURL(), it's safe to omit the scheme // and trailing slash, and unescape most characters. However, it's // important not to drop any username/password, or unescape anything that // changes the URL's meaning. return url_formatter::FormatUrl( url, languages, url_formatter::kFormatUrlOmitAll & ~url_formatter::kFormatUrlOmitUsernamePassword, net::UnescapeRule::SPACES, nullptr, nullptr, nullptr); } bool IsAppsShortcutEnabled(Profile* profile) { // Legacy supervised users can not have apps installed currently so there's no // need to show the apps shortcut. if (profile->IsLegacySupervised()) return false; #if defined(USE_ASH) // Don't show the apps shortcut in ash since the app launcher is enabled. return false; #else return search::IsInstantExtendedAPIEnabled() && !profile->IsOffTheRecord(); #endif } bool ShouldShowAppsShortcutInBookmarkBar(Profile* profile) { return IsAppsShortcutEnabled(profile) && profile->GetPrefs()->GetBoolean( bookmarks::prefs::kShowAppsShortcutInBookmarkBar); } bool ShouldRemoveBookmarkThisPageUI(Profile* profile) { return GetBookmarkShortcutDisposition(profile) == BOOKMARK_SHORTCUT_DISPOSITION_REMOVED; } bool ShouldRemoveBookmarkOpenPagesUI(Profile* profile) { #if defined(ENABLE_EXTENSIONS) extensions::ExtensionRegistry* registry = extensions::ExtensionRegistry::Get(profile); if (!registry) return false; const extensions::ExtensionSet& extension_set = registry->enabled_extensions(); for (extensions::ExtensionSet::const_iterator i = extension_set.begin(); i != extension_set.end(); ++i) { if (extensions::CommandService::RemovesBookmarkOpenPagesShortcut(i->get())) return true; } #endif return false; } int GetBookmarkDragOperation(content::BrowserContext* browser_context, const BookmarkNode* node) { PrefService* prefs = user_prefs::UserPrefs::Get(browser_context); Profile* profile = Profile::FromBrowserContext(browser_context); BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile); int move = ui::DragDropTypes::DRAG_MOVE; if (!prefs->GetBoolean(bookmarks::prefs::kEditBookmarksEnabled) || !model->client()->CanBeEditedByUser(node)) { move = ui::DragDropTypes::DRAG_NONE; } if (node->is_url()) return ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_LINK | move; return ui::DragDropTypes::DRAG_COPY | move; } int GetPreferredBookmarkDropOperation(int source_operations, int operations) { int common_ops = (source_operations & operations); if (!common_ops) return ui::DragDropTypes::DRAG_NONE; if (ui::DragDropTypes::DRAG_COPY & common_ops) return ui::DragDropTypes::DRAG_COPY; if (ui::DragDropTypes::DRAG_LINK & common_ops) return ui::DragDropTypes::DRAG_LINK; if (ui::DragDropTypes::DRAG_MOVE & common_ops) return ui::DragDropTypes::DRAG_MOVE; return ui::DragDropTypes::DRAG_NONE; } int GetBookmarkDropOperation(Profile* profile, const ui::DropTargetEvent& event, const bookmarks::BookmarkNodeData& data, const BookmarkNode* parent, int index) { const base::FilePath& profile_path = profile->GetPath(); if (data.IsFromProfilePath(profile_path) && data.size() > 1) // Currently only accept one dragged node at a time. return ui::DragDropTypes::DRAG_NONE; if (!IsValidBookmarkDropLocation(profile, data, parent, index)) return ui::DragDropTypes::DRAG_NONE; BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile); if (!model->client()->CanBeEditedByUser(parent)) return ui::DragDropTypes::DRAG_NONE; const BookmarkNode* dragged_node = data.GetFirstNode(model, profile->GetPath()); if (dragged_node) { // User is dragging from this profile. if (!model->client()->CanBeEditedByUser(dragged_node)) { // Do a copy instead of a move when dragging bookmarks that the user can't // modify. return ui::DragDropTypes::DRAG_COPY; } return ui::DragDropTypes::DRAG_MOVE; } // User is dragging from another app, copy. return GetPreferredBookmarkDropOperation(event.source_operations(), ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_LINK); } bool IsValidBookmarkDropLocation(Profile* profile, const bookmarks::BookmarkNodeData& data, const BookmarkNode* drop_parent, int index) { if (!drop_parent->is_folder()) { NOTREACHED(); return false; } if (!data.is_valid()) return false; BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile); if (!model->client()->CanBeEditedByUser(drop_parent)) return false; const base::FilePath& profile_path = profile->GetPath(); if (data.IsFromProfilePath(profile_path)) { std::vector nodes = data.GetNodes(model, profile_path); for (size_t i = 0; i < nodes.size(); ++i) { // Don't allow the drop if the user is attempting to drop on one of the // nodes being dragged. const BookmarkNode* node = nodes[i]; int node_index = (drop_parent == node->parent()) ? drop_parent->GetIndexOf(nodes[i]) : -1; if (node_index != -1 && (index == node_index || index == node_index + 1)) return false; // drop_parent can't accept a child that is an ancestor. if (drop_parent->HasAncestor(node)) return false; } return true; } // From another profile, always accept. return true; } #if defined(TOOLKIT_VIEWS) gfx::ImageSkia GetBookmarkFolderIcon(SkColor text_color) { #if defined(OS_WIN) if (!ui::MaterialDesignController::IsModeMaterial()) { return *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed( IDR_BOOKMARK_BAR_FOLDER); } #endif return GetFolderIcon(gfx::VectorIconId::FOLDER, text_color); } gfx::ImageSkia GetBookmarkSupervisedFolderIcon(SkColor text_color) { #if defined(OS_WIN) if (!ui::MaterialDesignController::IsModeMaterial()) { return *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed( IDR_BOOKMARK_BAR_FOLDER_SUPERVISED); } #endif return GetFolderIcon(gfx::VectorIconId::FOLDER_SUPERVISED, text_color); } gfx::ImageSkia GetBookmarkManagedFolderIcon(SkColor text_color) { #if defined(OS_WIN) if (!ui::MaterialDesignController::IsModeMaterial()) { return *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed( IDR_BOOKMARK_BAR_FOLDER_MANAGED); } #endif return GetFolderIcon(gfx::VectorIconId::FOLDER_MANAGED, text_color); } #endif } // namespace chrome