Avi Drissman | 4a8573c | 2022-09-09 19:35:54 | [diff] [blame] | 1 | // Copyright 2012 The Chromium Authors |
[email protected] | 0a3ca08 | 2012-10-03 13:39:41 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "chrome/browser/ui/bookmarks/bookmark_utils.h" |
| 6 | |
avi | 655876a | 2015-12-25 07:18:15 | [diff] [blame] | 7 | #include <stddef.h> |
| 8 | |
Hans Wennborg | 1790e6b | 2020-04-24 19:10:33 | [diff] [blame] | 9 | #include "base/check.h" |
Caroline Rising | 5b1ac06 | 2021-03-26 15:56:35 | [diff] [blame] | 10 | #include "base/feature_list.h" |
Avi Drissman | 9269d4ed | 2023-01-07 01:38:06 | [diff] [blame] | 11 | #include "base/functional/bind.h" |
Ali Hijazi | e63cbaf6 | 2023-12-20 19:29:35 | [diff] [blame] | 12 | #include "base/memory/raw_ptr.h" |
Hans Wennborg | 1790e6b | 2020-04-24 19:10:33 | [diff] [blame] | 13 | #include "base/notreached.h" |
Katie D | e7c84a4 | 2020-04-13 16:12:44 | [diff] [blame] | 14 | #include "base/strings/utf_string_conversions.h" |
avi | 655876a | 2015-12-25 07:18:15 | [diff] [blame] | 15 | #include "build/build_config.h" |
Monica Basta | a5df492 | 2024-10-14 12:10:14 | [diff] [blame] | 16 | #include "chrome/browser/bookmarks/bookmark_merged_surface_service.h" |
| 17 | #include "chrome/browser/bookmarks/bookmark_merged_surface_service_factory.h" |
[email protected] | 345d7d3 | 2012-10-03 23:10:18 | [diff] [blame] | 18 | #include "chrome/browser/bookmarks/bookmark_model_factory.h" |
[email protected] | 345d7d3 | 2012-10-03 23:10:18 | [diff] [blame] | 19 | #include "chrome/browser/profiles/profile.h" |
[email protected] | 62d83ce | 2013-03-27 18:52:54 | [diff] [blame] | 20 | #include "chrome/browser/search/search.h" |
Pengchao Cai | 55da3ae0 | 2024-03-13 17:27:26 | [diff] [blame] | 21 | #include "chrome/browser/ui/ui_features.h" |
[email protected] | 03020ff | 2012-11-29 12:08:17 | [diff] [blame] | 22 | #include "chrome/common/pref_names.h" |
[email protected] | a46e9b5 | 2013-05-04 14:18:03 | [diff] [blame] | 23 | #include "chrome/common/url_constants.h" |
[email protected] | a90c8ca | 2014-05-20 17:16:04 | [diff] [blame] | 24 | #include "components/bookmarks/browser/bookmark_model.h" |
andresantoso | 72e58e1e | 2015-01-07 18:04:33 | [diff] [blame] | 25 | #include "components/bookmarks/browser/bookmark_node_data.h" |
brettw | e1f0af8b | 2015-10-09 21:30:46 | [diff] [blame] | 26 | #include "components/bookmarks/common/bookmark_pref_names.h" |
Monica Basta | b49e0af | 2024-09-27 17:13:46 | [diff] [blame] | 27 | #include "components/bookmarks/managed/managed_bookmark_service.h" |
Katie D | e7c84a4 | 2020-04-13 16:12:44 | [diff] [blame] | 28 | #include "components/dom_distiller/core/url_constants.h" |
| 29 | #include "components/dom_distiller/core/url_utils.h" |
brettw | b1fc1b8 | 2016-02-02 00:19:08 | [diff] [blame] | 30 | #include "components/prefs/pref_service.h" |
[email protected] | 720b1049 | 2014-07-23 08:48:40 | [diff] [blame] | 31 | #include "components/search/search.h" |
Side Yilmaz | 79ae7d7 | 2021-10-04 17:38:48 | [diff] [blame] | 32 | #include "components/strings/grit/components_strings.h" |
rsleevi | 24f64dc2 | 2015-08-07 21:39:21 | [diff] [blame] | 33 | #include "components/url_formatter/url_formatter.h" |
[email protected] | 75fee37 | 2013-03-06 00:42:44 | [diff] [blame] | 34 | #include "components/user_prefs/user_prefs.h" |
Elly Fong-Jones | 60969ec | 2017-10-05 19:28:11 | [diff] [blame] | 35 | #include "components/vector_icons/vector_icons.h" |
[email protected] | 0a3ca08 | 2012-10-03 13:39:41 | [diff] [blame] | 36 | #include "content/public/browser/web_contents.h" |
andresantoso | 72e58e1e | 2015-01-07 18:04:33 | [diff] [blame] | 37 | #include "ui/base/dragdrop/drag_drop_types.h" |
| 38 | #include "ui/base/dragdrop/drop_target_event.h" |
Henrique Ferreiro | af214ed5b | 2021-02-12 20:40:00 | [diff] [blame] | 39 | #include "ui/base/dragdrop/mojom/drag_drop_types.mojom.h" |
Side Yilmaz | 79ae7d7 | 2021-10-04 17:38:48 | [diff] [blame] | 40 | #include "ui/base/l10n/l10n_util.h" |
Peter Kasting | f81f0d5 | 2020-03-11 01:51:08 | [diff] [blame] | 41 | #include "ui/base/pointer/touch_ui_controller.h" |
Shibalik Mohapatra | 2fc38e1 | 2023-06-19 06:04:43 | [diff] [blame] | 42 | #include "ui/base/ui_base_features.h" |
Zoraiz Naeem | 496356e4 | 2025-02-11 02:50:12 | [diff] [blame] | 43 | #include "ui/color/color_variant.h" |
[email protected] | 0a3ca08 | 2012-10-03 13:39:41 | [diff] [blame] | 44 | |
jackhou | ce97cfa | 2015-09-04 02:34:46 | [diff] [blame] | 45 | #if defined(TOOLKIT_VIEWS) |
Peter Kasting | 2a4b9bfb | 2021-07-10 01:41:59 | [diff] [blame] | 46 | #include "chrome/grit/theme_resources.h" |
| 47 | #include "ui/base/resource/resource_bundle.h" |
Peter Kasting | 77b59a8 | 2022-03-18 00:06:27 | [diff] [blame] | 48 | #include "ui/base/themed_vector_icon.h" |
Peter Kasting | 618a92e | 2021-09-22 16:45:49 | [diff] [blame] | 49 | #include "ui/color/color_id.h" |
| 50 | #include "ui/color/color_provider.h" |
Peter Kasting | b20c6908 | 2019-06-27 05:17:18 | [diff] [blame] | 51 | #include "ui/gfx/canvas.h" |
estade | bd24203 | 2015-10-29 20:16:22 | [diff] [blame] | 52 | #include "ui/gfx/color_utils.h" |
David Sanders | 03ee601f | 2022-02-22 02:23:00 | [diff] [blame] | 53 | #include "ui/gfx/image/image_skia_rep.h" |
Peter Kasting | b20c6908 | 2019-06-27 05:17:18 | [diff] [blame] | 54 | #include "ui/gfx/image/image_skia_source.h" |
estade | 14415067 | 2015-09-01 20:58:38 | [diff] [blame] | 55 | #include "ui/gfx/paint_vector_icon.h" |
Peter Kasting | b20c6908 | 2019-06-27 05:17:18 | [diff] [blame] | 56 | #include "ui/gfx/scoped_canvas.h" |
Peter Kasting | 2460a8d6 | 2019-06-29 01:46:35 | [diff] [blame] | 57 | #include "ui/resources/grit/ui_resources.h" |
estade | 876515ed | 2015-09-08 18:38:39 | [diff] [blame] | 58 | #endif |
| 59 | |
[email protected] | ecb9a2a | 2012-10-10 14:11:47 | [diff] [blame] | 60 | namespace chrome { |
[email protected] | 0a3ca08 | 2012-10-03 13:39:41 | [diff] [blame] | 61 | namespace { |
| 62 | |
Henrique Ferreiro | af214ed5b | 2021-02-12 20:40:00 | [diff] [blame] | 63 | using ::bookmarks::BookmarkModel; |
| 64 | using ::bookmarks::BookmarkNode; |
| 65 | using ::ui::mojom::DragOperation; |
Monica Basta | a5df492 | 2024-10-14 12:10:14 | [diff] [blame] | 66 | using PermanentFolderType = BookmarkParentFolder::PermanentFolderType; |
Henrique Ferreiro | af214ed5b | 2021-02-12 20:40:00 | [diff] [blame] | 67 | |
Peter Kasting | b20c6908 | 2019-06-27 05:17:18 | [diff] [blame] | 68 | #if defined(TOOLKIT_VIEWS) |
| 69 | // Image source that flips the supplied source image in RTL. |
| 70 | class RTLFlipSource : public gfx::ImageSkiaSource { |
| 71 | public: |
| 72 | explicit RTLFlipSource(gfx::ImageSkia source) : source_(std::move(source)) {} |
| 73 | ~RTLFlipSource() override = default; |
| 74 | |
| 75 | // gfx::ImageSkiaSource: |
| 76 | gfx::ImageSkiaRep GetImageForScale(float scale) override { |
| 77 | gfx::Canvas canvas(source_.size(), scale, false); |
| 78 | gfx::ScopedCanvas scoped_canvas(&canvas); |
| 79 | scoped_canvas.FlipIfRTL(source_.width()); |
| 80 | canvas.DrawImageInt(source_, 0, 0); |
| 81 | return gfx::ImageSkiaRep(canvas.GetBitmap(), scale); |
| 82 | } |
| 83 | |
| 84 | private: |
| 85 | const gfx::ImageSkia source_; |
| 86 | }; |
Peter Kasting | b20c6908 | 2019-06-27 05:17:18 | [diff] [blame] | 87 | #endif // defined(TOOLKIT_VIEWS) |
estade | 14415067 | 2015-09-01 20:58:38 | [diff] [blame] | 88 | |
Monica Basta | a5df492 | 2024-10-14 12:10:14 | [diff] [blame] | 89 | // Returns true if the `dragged_node` can be dropped on `drop_parent` at |
| 90 | // `index`. A drop is not allowed on a managed node. A drop from a separate |
| 91 | // profile or a URL is allowed, where as a drop from the same profile is only |
| 92 | // allowed if: |
| 93 | // - The `dragged_node` is not an ancestor of `drop_parent` |
| 94 | // - The `dragged _node` isn't already a child of `drop_parent` at `index`. |
| 95 | bool IsValidBookmarkDropLocation( |
| 96 | const BookmarkMergedSurfaceService* bookmark_merged_service, |
| 97 | const bookmarks::BookmarkNode* dragged_node, |
| 98 | bool dragged_from_same_profile, |
| 99 | const BookmarkParentFolder& drop_parent, |
| 100 | size_t index) { |
| 101 | if (bookmark_merged_service->IsParentFolderManaged(drop_parent)) { |
| 102 | // Drop on a managed node is not allowed. |
| 103 | return false; |
| 104 | } |
| 105 | |
| 106 | if (!dragged_from_same_profile) { |
| 107 | // If the drop is not on a managed node, always accept if node from another |
| 108 | // profile or the user is dragging a URL. |
| 109 | // Note: It is expected if the user is dragging a URL |
| 110 | // `dragged_from_same_profile` is false as a URL is not associated with a |
| 111 | // profile. |
| 112 | return true; |
| 113 | } |
| 114 | |
| 115 | // `dragged_node` is null if the node is from another profile or the user is |
| 116 | // dragging a url. In both cases, `dragged_from_same_profile` is expected to |
| 117 | // be false. For dragging a node within the same profile, the `dragged_node` |
| 118 | // must be not null. |
| 119 | CHECK(dragged_node); |
| 120 | CHECK(!dragged_node->is_root()); |
| 121 | CHECK(!dragged_node->is_permanent_node()); |
| 122 | // Don't allow the drop if the user is attempting to drop on the node being |
| 123 | // dragged. |
| 124 | if (drop_parent.HasDirectChildNode(dragged_node)) { |
| 125 | // Reordering. |
| 126 | size_t node_index = bookmark_merged_service->GetIndexOf(dragged_node); |
| 127 | if (index == node_index || index == node_index + 1) { |
| 128 | return false; |
| 129 | } |
| 130 | } |
| 131 | |
| 132 | // drop_parent can't accept a child that is an ancestor. |
| 133 | if (drop_parent.HoldsNonPermanentFolder() && |
| 134 | drop_parent.as_non_permanent_folder()->HasAncestor(dragged_node)) { |
| 135 | return false; |
| 136 | } |
| 137 | |
| 138 | return true; |
| 139 | } |
| 140 | |
[email protected] | ecb9a2a | 2012-10-10 14:11:47 | [diff] [blame] | 141 | } // namespace |
[email protected] | 0a3ca08 | 2012-10-03 13:39:41 | [diff] [blame] | 142 | |
[email protected] | a46e9b5 | 2013-05-04 14:18:03 | [diff] [blame] | 143 | GURL GetURLToBookmark(content::WebContents* web_contents) { |
| 144 | DCHECK(web_contents); |
Peter Kasting | a486324 | 2024-12-23 00:19:43 | [diff] [blame] | 145 | if (search::IsInstantNTP(web_contents)) { |
Katie D | e7c84a4 | 2020-04-13 16:12:44 | [diff] [blame] | 146 | return GURL(kChromeUINewTabURL); |
Peter Kasting | a486324 | 2024-12-23 00:19:43 | [diff] [blame] | 147 | } |
Katie D | e7c84a4 | 2020-04-13 16:12:44 | [diff] [blame] | 148 | // Users cannot bookmark Reader Mode pages directly, so the bookmark |
| 149 | // interaction is as if it were with the original page. |
Sharon Yang | db87eea | 2021-12-23 21:53:18 | [diff] [blame] | 150 | if (dom_distiller::url_utils::IsDistilledPage( |
| 151 | web_contents->GetVisibleURL())) { |
Katie D | e7c84a4 | 2020-04-13 16:12:44 | [diff] [blame] | 152 | return dom_distiller::url_utils::GetOriginalUrlFromDistillerUrl( |
Sharon Yang | db87eea | 2021-12-23 21:53:18 | [diff] [blame] | 153 | web_contents->GetVisibleURL()); |
Katie D | e7c84a4 | 2020-04-13 16:12:44 | [diff] [blame] | 154 | } |
Sharon Yang | db87eea | 2021-12-23 21:53:18 | [diff] [blame] | 155 | return web_contents->GetVisibleURL(); |
[email protected] | a46e9b5 | 2013-05-04 14:18:03 | [diff] [blame] | 156 | } |
| 157 | |
Elly Fong-Jones | ba41c89 | 2021-04-23 23:17:27 | [diff] [blame] | 158 | bool GetURLAndTitleToBookmark(content::WebContents* web_contents, |
[email protected] | ecb9a2a | 2012-10-10 14:11:47 | [diff] [blame] | 159 | GURL* url, |
Jan Wilken Dörrie | 3f97e29 | 2021-03-11 18:07:14 | [diff] [blame] | 160 | std::u16string* title) { |
Elly Fong-Jones | ba41c89 | 2021-04-23 23:17:27 | [diff] [blame] | 161 | GURL u = GetURLToBookmark(web_contents); |
Peter Kasting | a486324 | 2024-12-23 00:19:43 | [diff] [blame] | 162 | if (!u.is_valid()) { |
Elly Fong-Jones | ba41c89 | 2021-04-23 23:17:27 | [diff] [blame] | 163 | return false; |
Peter Kasting | a486324 | 2024-12-23 00:19:43 | [diff] [blame] | 164 | } |
Elly Fong-Jones | ba41c89 | 2021-04-23 23:17:27 | [diff] [blame] | 165 | *url = u; |
Sharon Yang | db87eea | 2021-12-23 21:53:18 | [diff] [blame] | 166 | if (dom_distiller::url_utils::IsDistilledPage( |
| 167 | web_contents->GetVisibleURL())) { |
Katie D | e7c84a4 | 2020-04-13 16:12:44 | [diff] [blame] | 168 | // Users cannot bookmark Reader Mode pages directly. Instead, a bookmark |
| 169 | // is added for the original page and original title. |
| 170 | *title = |
| 171 | base::UTF8ToUTF16(dom_distiller::url_utils::GetTitleFromDistillerUrl( |
Sharon Yang | db87eea | 2021-12-23 21:53:18 | [diff] [blame] | 172 | web_contents->GetVisibleURL())); |
Katie D | e7c84a4 | 2020-04-13 16:12:44 | [diff] [blame] | 173 | } else { |
| 174 | *title = web_contents->GetTitle(); |
| 175 | } |
Side Yilmaz | 79ae7d7 | 2021-10-04 17:38:48 | [diff] [blame] | 176 | |
| 177 | // Use "New tab" as title if the current page is NTP even in incognito mode. |
Peter Kasting | a486324 | 2024-12-23 00:19:43 | [diff] [blame] | 178 | if (u == GURL(chrome::kChromeUINewTabURL)) { |
Side Yilmaz | 79ae7d7 | 2021-10-04 17:38:48 | [diff] [blame] | 179 | *title = l10n_util::GetStringUTF16(IDS_NEW_TAB_TITLE); |
Peter Kasting | a486324 | 2024-12-23 00:19:43 | [diff] [blame] | 180 | } |
Side Yilmaz | 79ae7d7 | 2021-10-04 17:38:48 | [diff] [blame] | 181 | |
Elly Fong-Jones | ba41c89 | 2021-04-23 23:17:27 | [diff] [blame] | 182 | return true; |
[email protected] | ecb9a2a | 2012-10-10 14:11:47 | [diff] [blame] | 183 | } |
| 184 | |
[email protected] | 03020ff | 2012-11-29 12:08:17 | [diff] [blame] | 185 | void ToggleBookmarkBarWhenVisible(content::BrowserContext* browser_context) { |
[email protected] | c7141feb | 2013-06-11 13:00:16 | [diff] [blame] | 186 | PrefService* prefs = user_prefs::UserPrefs::Get(browser_context); |
tfarina | 3bddbe11 | 2014-08-28 05:29:32 | [diff] [blame] | 187 | const bool always_show = |
| 188 | !prefs->GetBoolean(bookmarks::prefs::kShowBookmarkBar); |
[email protected] | 03020ff | 2012-11-29 12:08:17 | [diff] [blame] | 189 | |
| 190 | // The user changed when the bookmark bar is shown, update the preferences. |
tfarina | 3bddbe11 | 2014-08-28 05:29:32 | [diff] [blame] | 191 | prefs->SetBoolean(bookmarks::prefs::kShowBookmarkBar, always_show); |
[email protected] | 03020ff | 2012-11-29 12:08:17 | [diff] [blame] | 192 | } |
| 193 | |
Jan Wilken Dörrie | 3f97e29 | 2021-03-11 18:07:14 | [diff] [blame] | 194 | std::u16string FormatBookmarkURLForDisplay(const GURL& url) { |
[email protected] | 998615d9 | 2013-01-15 07:49:52 | [diff] [blame] | 195 | // Because this gets re-parsed by FixupURL(), it's safe to omit the scheme |
elawrence | fa34e54 | 2016-10-03 18:41:02 | [diff] [blame] | 196 | // and trailing slash, and unescape most characters. However, it's |
[email protected] | 998615d9 | 2013-01-15 07:49:52 | [diff] [blame] | 197 | // important not to drop any username/password, or unescape anything that |
| 198 | // changes the URL's meaning. |
elawrence | fa34e54 | 2016-10-03 18:41:02 | [diff] [blame] | 199 | url_formatter::FormatUrlTypes format_types = |
Christopher Grant | 91efeb3 | 2017-08-10 22:24:35 | [diff] [blame] | 200 | url_formatter::kFormatUrlOmitDefaults & |
elawrence | fa34e54 | 2016-10-03 18:41:02 | [diff] [blame] | 201 | ~url_formatter::kFormatUrlOmitUsernamePassword; |
| 202 | |
| 203 | // If username is present, we must not omit the scheme because FixupURL() will |
| 204 | // subsequently interpret the username as a scheme. crbug.com/639126 |
Peter Kasting | a486324 | 2024-12-23 00:19:43 | [diff] [blame] | 205 | if (url.has_username()) { |
elawrence | fa34e54 | 2016-10-03 18:41:02 | [diff] [blame] | 206 | format_types &= ~url_formatter::kFormatUrlOmitHTTP; |
Peter Kasting | a486324 | 2024-12-23 00:19:43 | [diff] [blame] | 207 | } |
elawrence | fa34e54 | 2016-10-03 18:41:02 | [diff] [blame] | 208 | |
Ryan Hamilton | 7f3bd3d | 2022-04-23 00:07:39 | [diff] [blame] | 209 | return url_formatter::FormatUrl(url, format_types, base::UnescapeRule::SPACES, |
elawrence | fa34e54 | 2016-10-03 18:41:02 | [diff] [blame] | 210 | nullptr, nullptr, nullptr); |
[email protected] | 998615d9 | 2013-01-15 07:49:52 | [diff] [blame] | 211 | } |
| 212 | |
scottmg | cf186a3 | 2016-02-17 05:26:55 | [diff] [blame] | 213 | bool IsAppsShortcutEnabled(Profile* profile) { |
Eric Willigers | 67edc444 | 2022-03-08 22:09:01 | [diff] [blame] | 214 | #if BUILDFLAG(IS_CHROMEOS) |
James Cook | f9d34d2 | 2017-10-04 16:39:35 | [diff] [blame] | 215 | // Chrome OS uses the app list / app launcher. |
scottmg | cf186a3 | 2016-02-17 05:26:55 | [diff] [blame] | 216 | return false; |
| 217 | #else |
sdefresne | 51bbec7b | 2015-08-03 14:18:13 | [diff] [blame] | 218 | return search::IsInstantExtendedAPIEnabled() && !profile->IsOffTheRecord(); |
scottmg | cf186a3 | 2016-02-17 05:26:55 | [diff] [blame] | 219 | #endif |
[email protected] | 4a0f050 | 2013-11-20 05:33:21 | [diff] [blame] | 220 | } |
| 221 | |
scottmg | cf186a3 | 2016-02-17 05:26:55 | [diff] [blame] | 222 | bool ShouldShowAppsShortcutInBookmarkBar(Profile* profile) { |
| 223 | return IsAppsShortcutEnabled(profile) && |
tfarina | 3bddbe11 | 2014-08-28 05:29:32 | [diff] [blame] | 224 | profile->GetPrefs()->GetBoolean( |
| 225 | bookmarks::prefs::kShowAppsShortcutInBookmarkBar); |
[email protected] | 62d83ce | 2013-03-27 18:52:54 | [diff] [blame] | 226 | } |
| 227 | |
Pengchao Cai | 55da3ae0 | 2024-03-13 17:27:26 | [diff] [blame] | 228 | bool ShouldShowTabGroupsInBookmarkBar(Profile* profile) { |
| 229 | return profile->GetPrefs()->GetBoolean( |
| 230 | bookmarks::prefs::kShowTabGroupsInBookmarkBar); |
| 231 | } |
| 232 | |
andresantoso | 72e58e1e | 2015-01-07 18:04:33 | [diff] [blame] | 233 | int GetBookmarkDragOperation(content::BrowserContext* browser_context, |
| 234 | const BookmarkNode* node) { |
| 235 | PrefService* prefs = user_prefs::UserPrefs::Get(browser_context); |
pke | 3e0d5c9 | 2016-08-08 09:07:30 | [diff] [blame] | 236 | BookmarkModel* model = |
| 237 | BookmarkModelFactory::GetForBrowserContext(browser_context); |
andresantoso | 72e58e1e | 2015-01-07 18:04:33 | [diff] [blame] | 238 | |
| 239 | int move = ui::DragDropTypes::DRAG_MOVE; |
| 240 | if (!prefs->GetBoolean(bookmarks::prefs::kEditBookmarksEnabled) || |
Mikel Astiz | c4d8065 | 2023-09-21 15:08:43 | [diff] [blame] | 241 | model->client()->IsNodeManaged(node)) { |
andresantoso | 72e58e1e | 2015-01-07 18:04:33 | [diff] [blame] | 242 | move = ui::DragDropTypes::DRAG_NONE; |
| 243 | } |
Peter Kasting | a486324 | 2024-12-23 00:19:43 | [diff] [blame] | 244 | if (node->is_url()) { |
andresantoso | 72e58e1e | 2015-01-07 18:04:33 | [diff] [blame] | 245 | return ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_LINK | move; |
Peter Kasting | a486324 | 2024-12-23 00:19:43 | [diff] [blame] | 246 | } |
andresantoso | 72e58e1e | 2015-01-07 18:04:33 | [diff] [blame] | 247 | return ui::DragDropTypes::DRAG_COPY | move; |
| 248 | } |
| 249 | |
Henrique Ferreiro | af214ed5b | 2021-02-12 20:40:00 | [diff] [blame] | 250 | DragOperation GetPreferredBookmarkDropOperation(int source_operations, |
| 251 | int operations) { |
andresantoso | 72e58e1e | 2015-01-07 18:04:33 | [diff] [blame] | 252 | int common_ops = (source_operations & operations); |
Peter Kasting | a486324 | 2024-12-23 00:19:43 | [diff] [blame] | 253 | if (!common_ops) { |
Henrique Ferreiro | af214ed5b | 2021-02-12 20:40:00 | [diff] [blame] | 254 | return DragOperation::kNone; |
Peter Kasting | a486324 | 2024-12-23 00:19:43 | [diff] [blame] | 255 | } |
| 256 | if (ui::DragDropTypes::DRAG_COPY & common_ops) { |
Henrique Ferreiro | af214ed5b | 2021-02-12 20:40:00 | [diff] [blame] | 257 | return DragOperation::kCopy; |
Peter Kasting | a486324 | 2024-12-23 00:19:43 | [diff] [blame] | 258 | } |
| 259 | if (ui::DragDropTypes::DRAG_LINK & common_ops) { |
Henrique Ferreiro | af214ed5b | 2021-02-12 20:40:00 | [diff] [blame] | 260 | return DragOperation::kLink; |
Peter Kasting | a486324 | 2024-12-23 00:19:43 | [diff] [blame] | 261 | } |
| 262 | if (ui::DragDropTypes::DRAG_MOVE & common_ops) { |
Henrique Ferreiro | af214ed5b | 2021-02-12 20:40:00 | [diff] [blame] | 263 | return DragOperation::kMove; |
Peter Kasting | a486324 | 2024-12-23 00:19:43 | [diff] [blame] | 264 | } |
Henrique Ferreiro | af214ed5b | 2021-02-12 20:40:00 | [diff] [blame] | 265 | return DragOperation::kNone; |
andresantoso | 72e58e1e | 2015-01-07 18:04:33 | [diff] [blame] | 266 | } |
| 267 | |
Henrique Ferreiro | af214ed5b | 2021-02-12 20:40:00 | [diff] [blame] | 268 | DragOperation GetBookmarkDropOperation(Profile* profile, |
| 269 | const ui::DropTargetEvent& event, |
| 270 | const bookmarks::BookmarkNodeData& data, |
Monica Basta | a5df492 | 2024-10-14 12:10:14 | [diff] [blame] | 271 | const BookmarkParentFolder& parent, |
Henrique Ferreiro | af214ed5b | 2021-02-12 20:40:00 | [diff] [blame] | 272 | size_t index) { |
Monica Basta | a5df492 | 2024-10-14 12:10:14 | [diff] [blame] | 273 | if (data.size() != 1) { |
| 274 | // Currently only accept one dragged element (bookmark node/url) at a time. |
Henrique Ferreiro | af214ed5b | 2021-02-12 20:40:00 | [diff] [blame] | 275 | return DragOperation::kNone; |
Mikel Astiz | c4d8065 | 2023-09-21 15:08:43 | [diff] [blame] | 276 | } |
andresantoso | 72e58e1e | 2015-01-07 18:04:33 | [diff] [blame] | 277 | |
Monica Basta | a5df492 | 2024-10-14 12:10:14 | [diff] [blame] | 278 | BookmarkMergedSurfaceService* const bookmark_merged_service = |
| 279 | BookmarkMergedSurfaceServiceFactory::GetForProfile(profile); |
| 280 | const BookmarkNode* const dragged_node = data.GetFirstNode( |
| 281 | bookmark_merged_service->bookmark_model(), profile->GetPath()); |
| 282 | if (!IsValidBookmarkDropLocation(bookmark_merged_service, dragged_node, |
| 283 | data.IsFromProfilePath(profile->GetPath()), |
| 284 | parent, index)) { |
| 285 | return DragOperation::kNone; |
| 286 | } |
| 287 | |
andresantoso | 72e58e1e | 2015-01-07 18:04:33 | [diff] [blame] | 288 | if (dragged_node) { |
| 289 | // User is dragging from this profile. |
Monica Basta | a5df492 | 2024-10-14 12:10:14 | [diff] [blame] | 290 | if (bookmark_merged_service->IsNodeManaged(dragged_node)) { |
andresantoso | 72e58e1e | 2015-01-07 18:04:33 | [diff] [blame] | 291 | // Do a copy instead of a move when dragging bookmarks that the user can't |
| 292 | // modify. |
Henrique Ferreiro | af214ed5b | 2021-02-12 20:40:00 | [diff] [blame] | 293 | return DragOperation::kCopy; |
andresantoso | 72e58e1e | 2015-01-07 18:04:33 | [diff] [blame] | 294 | } |
Henrique Ferreiro | af214ed5b | 2021-02-12 20:40:00 | [diff] [blame] | 295 | return DragOperation::kMove; |
andresantoso | 72e58e1e | 2015-01-07 18:04:33 | [diff] [blame] | 296 | } |
| 297 | |
| 298 | // User is dragging from another app, copy. |
Monica Basta | a5df492 | 2024-10-14 12:10:14 | [diff] [blame] | 299 | return GetPreferredBookmarkDropOperation( |
| 300 | event.source_operations(), |
andresantoso | 72e58e1e | 2015-01-07 18:04:33 | [diff] [blame] | 301 | ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_LINK); |
| 302 | } |
| 303 | |
Monica Basta | b49e0af | 2024-09-27 17:13:46 | [diff] [blame] | 304 | bool CanAllBeEditedByUser( |
| 305 | bookmarks::ManagedBookmarkService* managed_bookmark_service, |
| 306 | const std::vector< |
| 307 | raw_ptr<const bookmarks::BookmarkNode, VectorExperimental>>& nodes) { |
| 308 | if (!managed_bookmark_service) { |
| 309 | return true; |
| 310 | } |
| 311 | |
| 312 | for (const bookmarks::BookmarkNode* node : nodes) { |
| 313 | if (managed_bookmark_service->IsNodeManaged(node)) { |
| 314 | return false; |
| 315 | } |
| 316 | } |
| 317 | return true; |
| 318 | } |
| 319 | |
jackhou | ce97cfa | 2015-09-04 02:34:46 | [diff] [blame] | 320 | #if defined(TOOLKIT_VIEWS) |
Shibalik Mohapatra | bb09782 | 2023-06-26 18:10:17 | [diff] [blame] | 321 | |
| 322 | gfx::ImageSkia GetBookmarkFolderImageFromVectorIcon( |
| 323 | BookmarkFolderIconType icon_type, |
Zoraiz Naeem | 496356e4 | 2025-02-11 02:50:12 | [diff] [blame] | 324 | ui::ColorVariant color, |
Shibalik Mohapatra | bb09782 | 2023-06-26 18:10:17 | [diff] [blame] | 325 | const ui::ColorProvider* color_provider) { |
| 326 | const gfx::VectorIcon* id; |
| 327 | gfx::ImageSkia folder; |
| 328 | if (icon_type == BookmarkFolderIconType::kNormal) { |
Alison Gale | 4828f80e | 2024-05-16 17:24:42 | [diff] [blame] | 329 | id = &vector_icons::kFolderChromeRefreshIcon; |
Shibalik Mohapatra | bb09782 | 2023-06-26 18:10:17 | [diff] [blame] | 330 | } else { |
Alison Gale | 4828f80e | 2024-05-16 17:24:42 | [diff] [blame] | 331 | id = &vector_icons::kFolderManagedRefreshIcon; |
Shibalik Mohapatra | bb09782 | 2023-06-26 18:10:17 | [diff] [blame] | 332 | } |
Zoraiz Naeem | 496356e4 | 2025-02-11 02:50:12 | [diff] [blame] | 333 | |
Zoraiz Naeem | cd4d6a8 | 2025-03-19 18:28:18 | [diff] [blame] | 334 | const ui::ThemedVectorIcon icon(id, color); |
Shibalik Mohapatra | bb09782 | 2023-06-26 18:10:17 | [diff] [blame] | 335 | folder = icon.GetImageSkia(color_provider); |
| 336 | return folder; |
| 337 | } |
| 338 | |
Zoraiz Naeem | 496356e4 | 2025-02-11 02:50:12 | [diff] [blame] | 339 | ui::ImageModel GetBookmarkFolderIcon(BookmarkFolderIconType icon_type, |
| 340 | ui::ColorVariant color) { |
Peter Kasting | 2a4b9bfb | 2021-07-10 01:41:59 | [diff] [blame] | 341 | int default_id = IDR_FOLDER_CLOSED; |
Xiaohan Wang | e9439fd | 2022-01-18 21:00:31 | [diff] [blame] | 342 | #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) |
Peter Kasting | 2a4b9bfb | 2021-07-10 01:41:59 | [diff] [blame] | 343 | // This block must be #ifdefed because only these platforms actually have this |
| 344 | // resource ID. |
Monica Basta | a5df492 | 2024-10-14 12:10:14 | [diff] [blame] | 345 | if (icon_type == BookmarkFolderIconType::kManaged) { |
Peter Kasting | 2a4b9bfb | 2021-07-10 01:41:59 | [diff] [blame] | 346 | default_id = IDR_BOOKMARK_BAR_FOLDER_MANAGED; |
Monica Basta | a5df492 | 2024-10-14 12:10:14 | [diff] [blame] | 347 | } |
estade | 055a552 | 2016-08-05 21:45:24 | [diff] [blame] | 348 | #endif |
Peter Kasting | 2a4b9bfb | 2021-07-10 01:41:59 | [diff] [blame] | 349 | const auto generator = [](int default_id, BookmarkFolderIconType icon_type, |
Zoraiz Naeem | 496356e4 | 2025-02-11 02:50:12 | [diff] [blame] | 350 | ui::ColorVariant color, |
Peter Kasting | 618a92e | 2021-09-22 16:45:49 | [diff] [blame] | 351 | const ui::ColorProvider* color_provider) { |
Peter Kasting | 2a4b9bfb | 2021-07-10 01:41:59 | [diff] [blame] | 352 | gfx::ImageSkia folder; |
Alison Gale | 4828f80e | 2024-05-16 17:24:42 | [diff] [blame] | 353 | folder = |
| 354 | GetBookmarkFolderImageFromVectorIcon(icon_type, color, color_provider); |
Peter Kasting | 2a4b9bfb | 2021-07-10 01:41:59 | [diff] [blame] | 355 | return gfx::ImageSkia(std::make_unique<RTLFlipSource>(folder), |
| 356 | folder.size()); |
| 357 | }; |
| 358 | const gfx::Size size = |
| 359 | ui::ResourceBundle::GetSharedInstance().GetImageNamed(default_id).Size(); |
| 360 | return ui::ImageModel::FromImageGenerator( |
| 361 | base::BindRepeating(generator, default_id, icon_type, std::move(color)), |
| 362 | size); |
estade | 14415067 | 2015-09-01 20:58:38 | [diff] [blame] | 363 | } |
| 364 | #endif |
| 365 | |
[email protected] | 0a3ca08 | 2012-10-03 13:39:41 | [diff] [blame] | 366 | } // namespace chrome |