blob: e43c89dc2464a765101caa330bcc4f5d491cf697 [file] [log] [blame]
[email protected]bbbc1ef2010-02-12 18:03:411// Copyright (c) 2010 The Chromium Authors. All rights reserved.
[email protected]7f856be2008-10-29 23:38:062// 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/bookmarks/bookmark_utils.h"
6
[email protected]90f39902009-10-03 04:25:377#include "app/clipboard/clipboard.h"
[email protected]37126212009-05-06 02:23:318#include "app/drag_drop_types.h"
[email protected]a92b8642009-05-05 23:38:569#include "app/l10n_util.h"
[email protected]992c6252009-05-13 18:54:2010#include "app/tree_node_iterator.h"
[email protected]a0368962009-02-24 21:47:1611#include "base/basictypes.h"
[email protected]630947c2009-11-04 18:37:3112#include "base/file_path.h"
[email protected]cb362ccc2008-12-10 17:22:3213#include "base/string_util.h"
[email protected]9c6a85d2010-01-21 22:53:4614#include "base/string16.h"
[email protected]9333f182008-12-09 17:34:1715#include "base/time.h"
[email protected]7f856be2008-10-29 23:38:0616#include "chrome/browser/bookmarks/bookmark_drag_data.h"
17#include "chrome/browser/bookmarks/bookmark_model.h"
[email protected]eda74d62010-03-07 03:43:5118#if defined(OS_MACOSX)
19#include "chrome/browser/bookmarks/bookmark_pasteboard_helper_mac.h"
20#endif
[email protected]7f856be2008-10-29 23:38:0621#include "chrome/browser/browser.h"
22#include "chrome/browser/browser_list.h"
[email protected]b08cadb92009-08-04 21:52:2923#include "chrome/browser/browser_process.h"
[email protected]ce560f82009-06-03 09:39:4424#include "chrome/browser/browser_window.h"
[email protected]9333f182008-12-09 17:34:1725#include "chrome/browser/history/query_parser.h"
[email protected]052313b2010-02-19 09:43:0826#include "chrome/browser/pref_service.h"
[email protected]505323e22009-01-24 02:47:5827#include "chrome/browser/profile.h"
[email protected]f3ec7742009-01-15 00:59:1628#include "chrome/browser/tab_contents/page_navigator.h"
[email protected]1132436e2009-04-08 20:06:3329#include "chrome/browser/tab_contents/tab_contents.h"
[email protected]44b2c8852009-03-18 00:57:4930#include "chrome/common/notification_service.h"
31#include "chrome/common/pref_names.h"
[email protected]903e7a82009-07-28 00:45:3532#include "grit/app_strings.h"
[email protected]34ac8f32009-02-22 23:03:2733#include "grit/chromium_strings.h"
34#include "grit/generated_resources.h"
[email protected]fa5dfaf2009-06-02 22:12:0635#include "net/base/net_util.h"
[email protected]2362e4f2009-05-08 00:34:0536#include "views/event.h"
[email protected]7f856be2008-10-29 23:38:0637
[email protected]ced90ae12010-02-20 02:06:1638#if defined(TOOLKIT_VIEWS)
39#include "app/os_exchange_data.h"
40#include "views/drag_utils.h"
41#include "views/widget/root_view.h"
42#include "views/widget/widget.h"
43#endif
44
[email protected]140aea052009-05-05 00:35:0945using base::Time;
46
[email protected]7f856be2008-10-29 23:38:0647namespace {
48
[email protected]7f856be2008-10-29 23:38:0649// A PageNavigator implementation that creates a new Browser. This is used when
50// opening a url and there is no Browser open. The Browser is created the first
51// time the PageNavigator method is invoked.
52class NewBrowserPageNavigator : public PageNavigator {
53 public:
54 explicit NewBrowserPageNavigator(Profile* profile)
55 : profile_(profile),
56 browser_(NULL) {}
57
58 virtual ~NewBrowserPageNavigator() {
59 if (browser_)
[email protected]15952e462008-11-14 00:29:0560 browser_->window()->Show();
[email protected]7f856be2008-10-29 23:38:0661 }
62
63 Browser* browser() const { return browser_; }
64
65 virtual void OpenURL(const GURL& url,
66 const GURL& referrer,
67 WindowOpenDisposition disposition,
68 PageTransition::Type transition) {
69 if (!browser_) {
70 Profile* profile = (disposition == OFF_THE_RECORD) ?
71 profile_->GetOffTheRecordProfile() : profile_;
[email protected]15952e462008-11-14 00:29:0572 browser_ = Browser::Create(profile);
[email protected]7f856be2008-10-29 23:38:0673 // Always open the first tab in the foreground.
74 disposition = NEW_FOREGROUND_TAB;
75 }
[email protected]e0c7c262009-04-23 23:09:4376 browser_->OpenURL(url, referrer, NEW_FOREGROUND_TAB, transition);
[email protected]7f856be2008-10-29 23:38:0677 }
78
79 private:
80 Profile* profile_;
81 Browser* browser_;
82
83 DISALLOW_COPY_AND_ASSIGN(NewBrowserPageNavigator);
84};
85
86void CloneDragDataImpl(BookmarkModel* model,
87 const BookmarkDragData::Element& element,
[email protected]b3c33d462009-06-26 22:29:2088 const BookmarkNode* parent,
[email protected]7f856be2008-10-29 23:38:0689 int index_to_add_at) {
90 if (element.is_url) {
91 model->AddURL(parent, index_to_add_at, element.title, element.url);
92 } else {
[email protected]b3c33d462009-06-26 22:29:2093 const BookmarkNode* new_folder = model->AddGroup(parent,
94 index_to_add_at,
95 element.title);
[email protected]7f856be2008-10-29 23:38:0696 for (int i = 0; i < static_cast<int>(element.children.size()); ++i)
97 CloneDragDataImpl(model, element.children[i], new_folder, i);
98 }
99}
100
101// Returns the number of descendants of node that are of type url.
[email protected]b3c33d462009-06-26 22:29:20102int DescendantURLCount(const BookmarkNode* node) {
[email protected]7f856be2008-10-29 23:38:06103 int result = 0;
104 for (int i = 0; i < node->GetChildCount(); ++i) {
[email protected]b3c33d462009-06-26 22:29:20105 const BookmarkNode* child = node->GetChild(i);
[email protected]7f856be2008-10-29 23:38:06106 if (child->is_url())
107 result++;
108 else
109 result += DescendantURLCount(child);
110 }
111 return result;
112}
113
114// Implementation of OpenAll. Opens all nodes of type URL and recurses for
115// groups. |navigator| is the PageNavigator used to open URLs. After the first
116// url is opened |opened_url| is set to true and |navigator| is set to the
117// PageNavigator of the last active tab. This is done to handle a window
118// disposition of new window, in which case we want subsequent tabs to open in
119// that window.
[email protected]b3c33d462009-06-26 22:29:20120void OpenAllImpl(const BookmarkNode* node,
[email protected]7f856be2008-10-29 23:38:06121 WindowOpenDisposition initial_disposition,
122 PageNavigator** navigator,
123 bool* opened_url) {
124 if (node->is_url()) {
125 WindowOpenDisposition disposition;
126 if (*opened_url)
127 disposition = NEW_BACKGROUND_TAB;
128 else
129 disposition = initial_disposition;
130 (*navigator)->OpenURL(node->GetURL(), GURL(), disposition,
131 PageTransition::AUTO_BOOKMARK);
132 if (!*opened_url) {
133 *opened_url = true;
134 // We opened the first URL which may have opened a new window or clobbered
135 // the current page, reset the navigator just to be sure.
136 Browser* new_browser = BrowserList::GetLastActive();
137 if (new_browser) {
138 TabContents* current_tab = new_browser->GetSelectedTabContents();
139 DCHECK(new_browser && current_tab);
140 if (new_browser && current_tab)
141 *navigator = current_tab;
142 } // else, new_browser == NULL, which happens during testing.
143 }
144 } else {
145 // Group, recurse through children.
146 for (int i = 0; i < node->GetChildCount(); ++i) {
147 OpenAllImpl(node->GetChild(i), initial_disposition, navigator,
148 opened_url);
149 }
150 }
151}
152
[email protected]d6d6d582009-10-12 19:22:26153bool ShouldOpenAll(gfx::NativeWindow parent,
[email protected]b3c33d462009-06-26 22:29:20154 const std::vector<const BookmarkNode*>& nodes) {
[email protected]7f856be2008-10-29 23:38:06155 int descendant_count = 0;
156 for (size_t i = 0; i < nodes.size(); ++i)
157 descendant_count += DescendantURLCount(nodes[i]);
[email protected]f785ad12008-11-19 23:01:28158 if (descendant_count < bookmark_utils::num_urls_before_prompting)
[email protected]7f856be2008-10-29 23:38:06159 return true;
160
161 std::wstring message =
162 l10n_util::GetStringF(IDS_BOOKMARK_BAR_SHOULD_OPEN_ALL,
163 IntToWString(descendant_count));
[email protected]a0368962009-02-24 21:47:16164#if defined(OS_WIN)
[email protected]7f856be2008-10-29 23:38:06165 return MessageBox(parent, message.c_str(),
166 l10n_util::GetString(IDS_PRODUCT_NAME).c_str(),
167 MB_YESNO | MB_ICONWARNING | MB_TOPMOST) == IDYES;
[email protected]a0368962009-02-24 21:47:16168#else
169 // TODO(port): Display a dialog prompt.
[email protected]2083180a2010-02-03 20:11:30170 // http://crbug.com/34481
[email protected]a0368962009-02-24 21:47:16171 NOTIMPLEMENTED();
172 return true;
173#endif
[email protected]7f856be2008-10-29 23:38:06174}
175
[email protected]9333f182008-12-09 17:34:17176// Comparison function that compares based on date modified of the two nodes.
[email protected]b3c33d462009-06-26 22:29:20177bool MoreRecentlyModified(const BookmarkNode* n1, const BookmarkNode* n2) {
[email protected]9333f182008-12-09 17:34:17178 return n1->date_group_modified() > n2->date_group_modified();
179}
180
[email protected]cb362ccc2008-12-10 17:22:32181// Returns true if |text| contains each string in |words|. This is used when
182// searching for bookmarks.
183bool DoesBookmarkTextContainWords(const std::wstring& text,
184 const std::vector<std::wstring>& words) {
185 for (size_t i = 0; i < words.size(); ++i) {
186 if (text.find(words[i]) == std::wstring::npos)
187 return false;
188 }
189 return true;
190}
191
192// Returns true if |node|s title or url contains the strings in |words|.
[email protected]fa5dfaf2009-06-02 22:12:06193// |languages| argument is user's accept-language setting to decode IDN.
[email protected]b3c33d462009-06-26 22:29:20194bool DoesBookmarkContainWords(const BookmarkNode* node,
[email protected]fa5dfaf2009-06-02 22:12:06195 const std::vector<std::wstring>& words,
196 const std::wstring& languages) {
[email protected]cb362ccc2008-12-10 17:22:32197 return
198 DoesBookmarkTextContainWords(
199 l10n_util::ToLower(node->GetTitle()), words) ||
[email protected]1f31bb72009-12-16 03:18:25200 DoesBookmarkTextContainWords(
201 l10n_util::ToLower(UTF8ToWide(node->GetURL().spec())), words) ||
202 DoesBookmarkTextContainWords(l10n_util::ToLower(net::FormatUrl(
203 node->GetURL(), languages, false, true, NULL, NULL, NULL)), words);
[email protected]cb362ccc2008-12-10 17:22:32204}
205
[email protected]7f856be2008-10-29 23:38:06206} // namespace
207
208namespace bookmark_utils {
209
[email protected]f785ad12008-11-19 23:01:28210int num_urls_before_prompting = 15;
211
[email protected]f28cbb72008-11-04 19:29:08212int PreferredDropOperation(int source_operations, int operations) {
213 int common_ops = (source_operations & operations);
[email protected]7f856be2008-10-29 23:38:06214 if (!common_ops)
215 return 0;
216 if (DragDropTypes::DRAG_COPY & common_ops)
217 return DragDropTypes::DRAG_COPY;
218 if (DragDropTypes::DRAG_LINK & common_ops)
219 return DragDropTypes::DRAG_LINK;
220 if (DragDropTypes::DRAG_MOVE & common_ops)
221 return DragDropTypes::DRAG_MOVE;
222 return DragDropTypes::DRAG_NONE;
223}
224
[email protected]b3c33d462009-06-26 22:29:20225int BookmarkDragOperation(const BookmarkNode* node) {
[email protected]7aa4c002009-03-12 19:10:22226 if (node->is_url()) {
227 return DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_MOVE |
228 DragDropTypes::DRAG_LINK;
229 }
230 return DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_MOVE;
231}
232
233int BookmarkDropOperation(Profile* profile,
234 const views::DropTargetEvent& event,
235 const BookmarkDragData& data,
[email protected]b3c33d462009-06-26 22:29:20236 const BookmarkNode* parent,
[email protected]7aa4c002009-03-12 19:10:22237 int index) {
238 if (data.IsFromProfile(profile) && data.size() > 1)
239 // Currently only accept one dragged node at a time.
240 return DragDropTypes::DRAG_NONE;
241
242 if (!bookmark_utils::IsValidDropLocation(profile, data, parent, index))
243 return DragDropTypes::DRAG_NONE;
244
245 if (data.GetFirstNode(profile)) {
246 // User is dragging from this profile: move.
247 return DragDropTypes::DRAG_MOVE;
248 }
249 // User is dragging from another app, copy.
250 return PreferredDropOperation(event.GetSourceOperations(),
251 DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_LINK);
252}
253
254int PerformBookmarkDrop(Profile* profile,
255 const BookmarkDragData& data,
[email protected]b3c33d462009-06-26 22:29:20256 const BookmarkNode* parent_node,
[email protected]7aa4c002009-03-12 19:10:22257 int index) {
[email protected]7aa4c002009-03-12 19:10:22258 BookmarkModel* model = profile->GetBookmarkModel();
[email protected]eda74d62010-03-07 03:43:51259 if (data.IsFromProfile(profile)) {
260 const std::vector<const BookmarkNode*> dragged_nodes =
261 data.GetNodes(profile);
262 if (!dragged_nodes.empty()) {
263 // Drag from same profile. Move nodes.
264 for (size_t i = 0; i < dragged_nodes.size(); ++i) {
265 model->Move(dragged_nodes[i], parent_node, index);
266 index = parent_node->IndexOfChild(dragged_nodes[i]) + 1;
267 }
268 return DragDropTypes::DRAG_MOVE;
[email protected]ced90ae12010-02-20 02:06:16269 }
[email protected]eda74d62010-03-07 03:43:51270 return DragDropTypes::DRAG_NONE;
[email protected]7aa4c002009-03-12 19:10:22271 }
[email protected]eda74d62010-03-07 03:43:51272 // Dropping a group from different profile. Always accept.
273 bookmark_utils::CloneDragData(model, data.elements, parent_node, index);
274 return DragDropTypes::DRAG_COPY;
[email protected]7aa4c002009-03-12 19:10:22275}
276
[email protected]7f856be2008-10-29 23:38:06277bool IsValidDropLocation(Profile* profile,
278 const BookmarkDragData& data,
[email protected]b3c33d462009-06-26 22:29:20279 const BookmarkNode* drop_parent,
[email protected]7f856be2008-10-29 23:38:06280 int index) {
281 if (!drop_parent->is_folder()) {
282 NOTREACHED();
283 return false;
284 }
285
286 if (!data.is_valid())
287 return false;
288
289 if (data.IsFromProfile(profile)) {
[email protected]b3c33d462009-06-26 22:29:20290 std::vector<const BookmarkNode*> nodes = data.GetNodes(profile);
[email protected]7f856be2008-10-29 23:38:06291 for (size_t i = 0; i < nodes.size(); ++i) {
292 // Don't allow the drop if the user is attempting to drop on one of the
293 // nodes being dragged.
[email protected]b3c33d462009-06-26 22:29:20294 const BookmarkNode* node = nodes[i];
[email protected]7f856be2008-10-29 23:38:06295 int node_index = (drop_parent == node->GetParent()) ?
296 drop_parent->IndexOfChild(nodes[i]) : -1;
297 if (node_index != -1 && (index == node_index || index == node_index + 1))
298 return false;
299
300 // drop_parent can't accept a child that is an ancestor.
301 if (drop_parent->HasAncestor(node))
302 return false;
303 }
304 return true;
305 }
306 // From the same profile, always accept.
307 return true;
308}
309
310void CloneDragData(BookmarkModel* model,
311 const std::vector<BookmarkDragData::Element>& elements,
[email protected]b3c33d462009-06-26 22:29:20312 const BookmarkNode* parent,
[email protected]7f856be2008-10-29 23:38:06313 int index_to_add_at) {
314 if (!parent->is_folder() || !model) {
315 NOTREACHED();
316 return;
317 }
318 for (size_t i = 0; i < elements.size(); ++i)
319 CloneDragDataImpl(model, elements[i], parent, index_to_add_at + i);
320}
321
[email protected]ced90ae12010-02-20 02:06:16322
323// Bookmark dragging
324void DragBookmarks(Profile* profile,
325 const std::vector<const BookmarkNode*>& nodes,
326 gfx::NativeView view) {
327 DCHECK(!nodes.empty());
328
329#if defined(TOOLKIT_VIEWS)
330 // Set up our OLE machinery
331 OSExchangeData data;
332 BookmarkDragData drag_data(nodes);
333 drag_data.Write(profile, &data);
334
335 views::RootView* root_view = views::Widget::GetWidgetFromNativeView(view)->GetRootView();
336
337 // Allow nested message loop so we get DnD events as we drag this around.
338 bool was_nested = MessageLoop::current()->IsNested();
339 MessageLoop::current()->SetNestableTasksAllowed(true);
340
341 root_view->StartDragForViewFromMouseEvent(NULL, data,
342 DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_MOVE |
343 DragDropTypes::DRAG_LINK);
344
345 MessageLoop::current()->SetNestableTasksAllowed(was_nested);
[email protected]eda74d62010-03-07 03:43:51346#elif defined(OS_MACOSX)
347 // Allow nested message loop so we get DnD events as we drag this around.
348 bool was_nested = MessageLoop::current()->IsNested();
349 MessageLoop::current()->SetNestableTasksAllowed(true);
350 bookmark_pasteboard_helper_mac::StartDrag(profile, nodes, view);
351 MessageLoop::current()->SetNestableTasksAllowed(was_nested);
[email protected]ced90ae12010-02-20 02:06:16352#else
[email protected]eda74d62010-03-07 03:43:51353 // TODO(arv): Implement for GTK.
[email protected]ced90ae12010-02-20 02:06:16354 NOTIMPLEMENTED();
355#endif
356}
357
[email protected]d6d6d582009-10-12 19:22:26358void OpenAll(gfx::NativeWindow parent,
[email protected]7f856be2008-10-29 23:38:06359 Profile* profile,
360 PageNavigator* navigator,
[email protected]b3c33d462009-06-26 22:29:20361 const std::vector<const BookmarkNode*>& nodes,
[email protected]7f856be2008-10-29 23:38:06362 WindowOpenDisposition initial_disposition) {
363 if (!ShouldOpenAll(parent, nodes))
364 return;
365
366 NewBrowserPageNavigator navigator_impl(profile);
367 if (!navigator) {
[email protected]f0a51fb52009-03-05 12:46:38368 Browser* browser =
[email protected]299dabd2008-11-19 02:27:16369 BrowserList::FindBrowserWithType(profile, Browser::TYPE_NORMAL);
[email protected]b6f2b9132008-11-17 16:27:51370 if (!browser || !browser->GetSelectedTabContents()) {
[email protected]7f856be2008-10-29 23:38:06371 navigator = &navigator_impl;
[email protected]b6f2b9132008-11-17 16:27:51372 } else {
[email protected]c9938e6d2009-03-13 19:54:11373 if (initial_disposition != NEW_WINDOW &&
374 initial_disposition != OFF_THE_RECORD) {
375 browser->window()->Activate();
376 }
[email protected]7f856be2008-10-29 23:38:06377 navigator = browser->GetSelectedTabContents();
[email protected]b6f2b9132008-11-17 16:27:51378 }
[email protected]7f856be2008-10-29 23:38:06379 }
380
381 bool opened_url = false;
382 for (size_t i = 0; i < nodes.size(); ++i)
383 OpenAllImpl(nodes[i], initial_disposition, &navigator, &opened_url);
384}
385
[email protected]d6d6d582009-10-12 19:22:26386void OpenAll(gfx::NativeWindow parent,
[email protected]7f856be2008-10-29 23:38:06387 Profile* profile,
388 PageNavigator* navigator,
[email protected]b3c33d462009-06-26 22:29:20389 const BookmarkNode* node,
[email protected]7f856be2008-10-29 23:38:06390 WindowOpenDisposition initial_disposition) {
[email protected]b3c33d462009-06-26 22:29:20391 std::vector<const BookmarkNode*> nodes;
[email protected]7f856be2008-10-29 23:38:06392 nodes.push_back(node);
393 OpenAll(parent, profile, navigator, nodes, initial_disposition);
394}
395
[email protected]fafc8a422008-11-07 17:53:09396void CopyToClipboard(BookmarkModel* model,
[email protected]b3c33d462009-06-26 22:29:20397 const std::vector<const BookmarkNode*>& nodes,
[email protected]fafc8a422008-11-07 17:53:09398 bool remove_nodes) {
[email protected]fafc8a422008-11-07 17:53:09399 if (nodes.empty())
400 return;
401
[email protected]b08cadb92009-08-04 21:52:29402 BookmarkDragData(nodes).WriteToClipboard(NULL);
[email protected]fafc8a422008-11-07 17:53:09403
404 if (remove_nodes) {
405 for (size_t i = 0; i < nodes.size(); ++i) {
406 model->Remove(nodes[i]->GetParent(),
407 nodes[i]->GetParent()->IndexOfChild(nodes[i]));
408 }
409 }
[email protected]fafc8a422008-11-07 17:53:09410}
411
412void PasteFromClipboard(BookmarkModel* model,
[email protected]b3c33d462009-06-26 22:29:20413 const BookmarkNode* parent,
[email protected]fafc8a422008-11-07 17:53:09414 int index) {
[email protected]fafc8a422008-11-07 17:53:09415 if (!parent)
416 return;
417
[email protected]fafc8a422008-11-07 17:53:09418 BookmarkDragData bookmark_data;
[email protected]b08cadb92009-08-04 21:52:29419 if (!bookmark_data.ReadFromClipboard())
[email protected]fafc8a422008-11-07 17:53:09420 return;
421
422 if (index == -1)
423 index = parent->GetChildCount();
424 bookmark_utils::CloneDragData(model, bookmark_data.elements, parent, index);
[email protected]fafc8a422008-11-07 17:53:09425}
426
[email protected]b3c33d462009-06-26 22:29:20427bool CanPasteFromClipboard(const BookmarkNode* node) {
[email protected]fafc8a422008-11-07 17:53:09428 if (!node)
429 return false;
[email protected]0fe52a02010-02-06 00:39:25430 return BookmarkDragData::ClipboardContainsBookmarks();
[email protected]fafc8a422008-11-07 17:53:09431}
432
[email protected]903e7a82009-07-28 00:45:35433std::string GetNameForURL(const GURL& url) {
434 if (url.is_valid()) {
435 return WideToUTF8(net::GetSuggestedFilename(
[email protected]630947c2009-11-04 18:37:31436 url, std::string(), std::string(), FilePath()).ToWStringHack());
[email protected]903e7a82009-07-28 00:45:35437 } else {
438 return l10n_util::GetStringUTF8(IDS_APP_UNTITLED_SHORTCUT_FILE_NAME);
439 }
440}
441
[email protected]b3c33d462009-06-26 22:29:20442std::vector<const BookmarkNode*> GetMostRecentlyModifiedGroups(
[email protected]9333f182008-12-09 17:34:17443 BookmarkModel* model,
444 size_t max_count) {
[email protected]b3c33d462009-06-26 22:29:20445 std::vector<const BookmarkNode*> nodes;
446 TreeNodeIterator<const BookmarkNode> iterator(model->root_node());
[email protected]9333f182008-12-09 17:34:17447 while (iterator.has_next()) {
[email protected]b3c33d462009-06-26 22:29:20448 const BookmarkNode* parent = iterator.Next();
[email protected]9333f182008-12-09 17:34:17449 if (parent->is_folder() && parent->date_group_modified() > base::Time()) {
450 if (max_count == 0) {
451 nodes.push_back(parent);
452 } else {
[email protected]b3c33d462009-06-26 22:29:20453 std::vector<const BookmarkNode*>::iterator i =
[email protected]9333f182008-12-09 17:34:17454 std::upper_bound(nodes.begin(), nodes.end(), parent,
455 &MoreRecentlyModified);
456 if (nodes.size() < max_count || i != nodes.end()) {
457 nodes.insert(i, parent);
458 while (nodes.size() > max_count)
459 nodes.pop_back();
460 }
461 }
462 } // else case, the root node, which we don't care about or imported nodes
463 // (which have a time of 0).
464 }
465
466 if (nodes.size() < max_count) {
467 // Add the bookmark bar and other nodes if there is space.
468 if (find(nodes.begin(), nodes.end(), model->GetBookmarkBarNode()) ==
469 nodes.end()) {
470 nodes.push_back(model->GetBookmarkBarNode());
471 }
472
473 if (nodes.size() < max_count &&
474 find(nodes.begin(), nodes.end(), model->other_node()) == nodes.end()) {
475 nodes.push_back(model->other_node());
476 }
477 }
478 return nodes;
479}
480
481void GetMostRecentlyAddedEntries(BookmarkModel* model,
482 size_t count,
[email protected]b3c33d462009-06-26 22:29:20483 std::vector<const BookmarkNode*>* nodes) {
484 TreeNodeIterator<const BookmarkNode> iterator(model->root_node());
[email protected]9333f182008-12-09 17:34:17485 while (iterator.has_next()) {
[email protected]b3c33d462009-06-26 22:29:20486 const BookmarkNode* node = iterator.Next();
[email protected]9333f182008-12-09 17:34:17487 if (node->is_url()) {
[email protected]b3c33d462009-06-26 22:29:20488 std::vector<const BookmarkNode*>::iterator insert_position =
[email protected]9333f182008-12-09 17:34:17489 std::upper_bound(nodes->begin(), nodes->end(), node,
490 &MoreRecentlyAdded);
491 if (nodes->size() < count || insert_position != nodes->end()) {
492 nodes->insert(insert_position, node);
493 while (nodes->size() > count)
494 nodes->pop_back();
495 }
496 }
497 }
498}
499
[email protected]b3c33d462009-06-26 22:29:20500bool MoreRecentlyAdded(const BookmarkNode* n1, const BookmarkNode* n2) {
[email protected]9333f182008-12-09 17:34:17501 return n1->date_added() > n2->date_added();
502}
503
[email protected]cb362ccc2008-12-10 17:22:32504void GetBookmarksContainingText(BookmarkModel* model,
505 const std::wstring& text,
506 size_t max_count,
[email protected]fa5dfaf2009-06-02 22:12:06507 const std::wstring& languages,
[email protected]b3c33d462009-06-26 22:29:20508 std::vector<const BookmarkNode*>* nodes) {
[email protected]cb362ccc2008-12-10 17:22:32509 std::vector<std::wstring> words;
510 QueryParser parser;
511 parser.ExtractQueryWords(l10n_util::ToLower(text), &words);
512 if (words.empty())
513 return;
514
[email protected]b3c33d462009-06-26 22:29:20515 TreeNodeIterator<const BookmarkNode> iterator(model->root_node());
[email protected]cb362ccc2008-12-10 17:22:32516 while (iterator.has_next()) {
[email protected]b3c33d462009-06-26 22:29:20517 const BookmarkNode* node = iterator.Next();
[email protected]fa5dfaf2009-06-02 22:12:06518 if (node->is_url() && DoesBookmarkContainWords(node, words, languages)) {
[email protected]cb362ccc2008-12-10 17:22:32519 nodes->push_back(node);
520 if (nodes->size() == max_count)
521 return;
522 }
523 }
524}
525
[email protected]b3c33d462009-06-26 22:29:20526bool DoesBookmarkContainText(const BookmarkNode* node,
[email protected]fa5dfaf2009-06-02 22:12:06527 const std::wstring& text,
528 const std::wstring& languages) {
[email protected]cb362ccc2008-12-10 17:22:32529 std::vector<std::wstring> words;
530 QueryParser parser;
531 parser.ExtractQueryWords(l10n_util::ToLower(text), &words);
532 if (words.empty())
533 return false;
534
[email protected]fa5dfaf2009-06-02 22:12:06535 return (node->is_url() && DoesBookmarkContainWords(node, words, languages));
[email protected]cb362ccc2008-12-10 17:22:32536}
537
[email protected]ec12ffe2009-10-16 22:28:44538static const BookmarkNode* CreateNewNode(BookmarkModel* model,
539 const BookmarkNode* parent, const BookmarkEditor::EditDetails& details,
[email protected]a8d71b02009-07-07 00:36:34540 const std::wstring& new_title, const GURL& new_url,
541 BookmarkEditor::Handler* handler) {
[email protected]ec12ffe2009-10-16 22:28:44542 const BookmarkNode* node;
543 if (details.type == BookmarkEditor::EditDetails::NEW_URL) {
544 node = model->AddURL(parent, parent->GetChildCount(), new_title, new_url);
545 } else if (details.type == BookmarkEditor::EditDetails::NEW_FOLDER) {
546 node = model->AddGroup(parent, parent->GetChildCount(), new_title);
547 for (size_t i = 0; i < details.urls.size(); ++i) {
548 model->AddURL(node, node->GetChildCount(), details.urls[i].second,
549 details.urls[i].first);
550 }
[email protected]eea8fd5532009-12-16 00:08:10551 model->SetDateGroupModified(parent, Time::Now());
[email protected]ec12ffe2009-10-16 22:28:44552 } else {
553 NOTREACHED();
554 return NULL;
[email protected]140aea052009-05-05 00:35:09555 }
556
[email protected]ec12ffe2009-10-16 22:28:44557 if (handler)
558 handler->NodeCreated(node);
559 return node;
560}
561
562const BookmarkNode* ApplyEditsWithNoGroupChange(BookmarkModel* model,
563 const BookmarkNode* parent, const BookmarkEditor::EditDetails& details,
564 const std::wstring& new_title, const GURL& new_url,
565 BookmarkEditor::Handler* handler) {
566 if (details.type == BookmarkEditor::EditDetails::NEW_URL ||
567 details.type == BookmarkEditor::EditDetails::NEW_FOLDER) {
568 return CreateNewNode(model, parent, details, new_title, new_url, handler);
569 }
570
571 const BookmarkNode* node = details.existing_node;
572 DCHECK(node);
[email protected]ec12ffe2009-10-16 22:28:44573
[email protected]e5486602010-02-09 21:27:55574 if (node->is_url())
575 model->SetURL(node, new_url);
576 model->SetTitle(node, new_title);
[email protected]140aea052009-05-05 00:35:09577
[email protected]a8d71b02009-07-07 00:36:34578 return node;
[email protected]140aea052009-05-05 00:35:09579}
580
[email protected]a8d71b02009-07-07 00:36:34581const BookmarkNode* ApplyEditsWithPossibleGroupChange(BookmarkModel* model,
[email protected]ec12ffe2009-10-16 22:28:44582 const BookmarkNode* new_parent, const BookmarkEditor::EditDetails& details,
[email protected]a8d71b02009-07-07 00:36:34583 const std::wstring& new_title, const GURL& new_url,
584 BookmarkEditor::Handler* handler) {
[email protected]ec12ffe2009-10-16 22:28:44585 if (details.type == BookmarkEditor::EditDetails::NEW_URL ||
586 details.type == BookmarkEditor::EditDetails::NEW_FOLDER) {
587 return CreateNewNode(model, new_parent, details, new_title, new_url,
588 handler);
589 }
590
591 const BookmarkNode* node = details.existing_node;
592 DCHECK(node);
[email protected]ec12ffe2009-10-16 22:28:44593
[email protected]e5486602010-02-09 21:27:55594 if (new_parent != node->GetParent())
[email protected]ec12ffe2009-10-16 22:28:44595 model->Move(node, new_parent, new_parent->GetChildCount());
[email protected]e5486602010-02-09 21:27:55596 if (node->is_url())
597 model->SetURL(node, new_url);
598 model->SetTitle(node, new_title);
599
600 return node;
[email protected]140aea052009-05-05 00:35:09601}
602
[email protected]44b2c8852009-03-18 00:57:49603// Formerly in BookmarkBarView
604void ToggleWhenVisible(Profile* profile) {
605 PrefService* prefs = profile->GetPrefs();
606 const bool always_show = !prefs->GetBoolean(prefs::kShowBookmarkBar);
607
608 // The user changed when the bookmark bar is shown, update the preferences.
609 prefs->SetBoolean(prefs::kShowBookmarkBar, always_show);
[email protected]6faa0e0d2009-04-28 06:50:36610 prefs->ScheduleSavePersistentPrefs();
[email protected]44b2c8852009-03-18 00:57:49611
612 // And notify the notification service.
613 Source<Profile> source(profile);
614 NotificationService::current()->Notify(
615 NotificationType::BOOKMARK_BAR_VISIBILITY_PREF_CHANGED,
616 source,
617 NotificationService::NoDetails());
618}
619
[email protected]1e7bab72009-06-03 17:23:36620void RegisterPrefs(PrefService* prefs) {
621 prefs->RegisterDictionaryPref(prefs::kBookmarkManagerPlacement);
622 prefs->RegisterIntegerPref(prefs::kBookmarkManagerSplitLocation, -1);
623}
624
[email protected]44b2c8852009-03-18 00:57:49625void RegisterUserPrefs(PrefService* prefs) {
626 // Formerly in BookmarkBarView
627 prefs->RegisterBooleanPref(prefs::kShowBookmarkBar, false);
628
629 // Formerly in BookmarkTableView
630 prefs->RegisterIntegerPref(prefs::kBookmarkTableNameWidth1, -1);
631 prefs->RegisterIntegerPref(prefs::kBookmarkTableURLWidth1, -1);
632 prefs->RegisterIntegerPref(prefs::kBookmarkTableNameWidth2, -1);
633 prefs->RegisterIntegerPref(prefs::kBookmarkTableURLWidth2, -1);
634 prefs->RegisterIntegerPref(prefs::kBookmarkTablePathWidth, -1);
635}
636
[email protected]76624fde2009-10-09 18:13:23637void GetURLAndTitleToBookmark(TabContents* tab_contents,
[email protected]b3ac5c82009-10-08 20:56:54638 GURL* url,
639 std::wstring* title) {
[email protected]76624fde2009-10-09 18:13:23640 *url = tab_contents->GetURL();
641 *title = UTF16ToWideHack(tab_contents->GetTitle());
[email protected]b3ac5c82009-10-08 20:56:54642}
643
[email protected]ec12ffe2009-10-16 22:28:44644void GetURLsForOpenTabs(Browser* browser,
645 std::vector<std::pair<GURL, std::wstring> >* urls) {
[email protected]b3ac5c82009-10-08 20:56:54646 for (int i = 0; i < browser->tab_count(); ++i) {
[email protected]ec12ffe2009-10-16 22:28:44647 std::pair<GURL, std::wstring> entry;
648 GetURLAndTitleToBookmark(browser->GetTabContentsAt(i), &(entry.first),
649 &(entry.second));
650 urls->push_back(entry);
[email protected]b3ac5c82009-10-08 20:56:54651 }
[email protected]b3ac5c82009-10-08 20:56:54652}
653
[email protected]7f856be2008-10-29 23:38:06654} // namespace bookmark_utils