blob: 2d21accdb7ad2610a92b9fe9a93af10b063911c1 [file] [log] [blame]
[email protected]90f39902009-10-03 04:25:371// Copyright (c) 2009 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"
18#include "chrome/browser/browser.h"
19#include "chrome/browser/browser_list.h"
[email protected]b08cadb92009-08-04 21:52:2920#include "chrome/browser/browser_process.h"
[email protected]ce560f82009-06-03 09:39:4421#include "chrome/browser/browser_window.h"
[email protected]9333f182008-12-09 17:34:1722#include "chrome/browser/history/query_parser.h"
[email protected]505323e22009-01-24 02:47:5823#include "chrome/browser/profile.h"
[email protected]f3ec7742009-01-15 00:59:1624#include "chrome/browser/tab_contents/page_navigator.h"
[email protected]1132436e2009-04-08 20:06:3325#include "chrome/browser/tab_contents/tab_contents.h"
[email protected]44b2c8852009-03-18 00:57:4926#include "chrome/common/notification_service.h"
27#include "chrome/common/pref_names.h"
28#include "chrome/common/pref_service.h"
[email protected]903e7a82009-07-28 00:45:3529#include "grit/app_strings.h"
[email protected]34ac8f32009-02-22 23:03:2730#include "grit/chromium_strings.h"
31#include "grit/generated_resources.h"
[email protected]fa5dfaf2009-06-02 22:12:0632#include "net/base/net_util.h"
[email protected]2362e4f2009-05-08 00:34:0533#include "views/event.h"
[email protected]7f856be2008-10-29 23:38:0634
[email protected]140aea052009-05-05 00:35:0935using base::Time;
36
[email protected]7f856be2008-10-29 23:38:0637namespace {
38
[email protected]7f856be2008-10-29 23:38:0639// A PageNavigator implementation that creates a new Browser. This is used when
40// opening a url and there is no Browser open. The Browser is created the first
41// time the PageNavigator method is invoked.
42class NewBrowserPageNavigator : public PageNavigator {
43 public:
44 explicit NewBrowserPageNavigator(Profile* profile)
45 : profile_(profile),
46 browser_(NULL) {}
47
48 virtual ~NewBrowserPageNavigator() {
49 if (browser_)
[email protected]15952e462008-11-14 00:29:0550 browser_->window()->Show();
[email protected]7f856be2008-10-29 23:38:0651 }
52
53 Browser* browser() const { return browser_; }
54
55 virtual void OpenURL(const GURL& url,
56 const GURL& referrer,
57 WindowOpenDisposition disposition,
58 PageTransition::Type transition) {
59 if (!browser_) {
60 Profile* profile = (disposition == OFF_THE_RECORD) ?
61 profile_->GetOffTheRecordProfile() : profile_;
[email protected]15952e462008-11-14 00:29:0562 browser_ = Browser::Create(profile);
[email protected]7f856be2008-10-29 23:38:0663 // Always open the first tab in the foreground.
64 disposition = NEW_FOREGROUND_TAB;
65 }
[email protected]e0c7c262009-04-23 23:09:4366 browser_->OpenURL(url, referrer, NEW_FOREGROUND_TAB, transition);
[email protected]7f856be2008-10-29 23:38:0667 }
68
69 private:
70 Profile* profile_;
71 Browser* browser_;
72
73 DISALLOW_COPY_AND_ASSIGN(NewBrowserPageNavigator);
74};
75
76void CloneDragDataImpl(BookmarkModel* model,
77 const BookmarkDragData::Element& element,
[email protected]b3c33d462009-06-26 22:29:2078 const BookmarkNode* parent,
[email protected]7f856be2008-10-29 23:38:0679 int index_to_add_at) {
80 if (element.is_url) {
81 model->AddURL(parent, index_to_add_at, element.title, element.url);
82 } else {
[email protected]b3c33d462009-06-26 22:29:2083 const BookmarkNode* new_folder = model->AddGroup(parent,
84 index_to_add_at,
85 element.title);
[email protected]7f856be2008-10-29 23:38:0686 for (int i = 0; i < static_cast<int>(element.children.size()); ++i)
87 CloneDragDataImpl(model, element.children[i], new_folder, i);
88 }
89}
90
91// Returns the number of descendants of node that are of type url.
[email protected]b3c33d462009-06-26 22:29:2092int DescendantURLCount(const BookmarkNode* node) {
[email protected]7f856be2008-10-29 23:38:0693 int result = 0;
94 for (int i = 0; i < node->GetChildCount(); ++i) {
[email protected]b3c33d462009-06-26 22:29:2095 const BookmarkNode* child = node->GetChild(i);
[email protected]7f856be2008-10-29 23:38:0696 if (child->is_url())
97 result++;
98 else
99 result += DescendantURLCount(child);
100 }
101 return result;
102}
103
104// Implementation of OpenAll. Opens all nodes of type URL and recurses for
105// groups. |navigator| is the PageNavigator used to open URLs. After the first
106// url is opened |opened_url| is set to true and |navigator| is set to the
107// PageNavigator of the last active tab. This is done to handle a window
108// disposition of new window, in which case we want subsequent tabs to open in
109// that window.
[email protected]b3c33d462009-06-26 22:29:20110void OpenAllImpl(const BookmarkNode* node,
[email protected]7f856be2008-10-29 23:38:06111 WindowOpenDisposition initial_disposition,
112 PageNavigator** navigator,
113 bool* opened_url) {
114 if (node->is_url()) {
115 WindowOpenDisposition disposition;
116 if (*opened_url)
117 disposition = NEW_BACKGROUND_TAB;
118 else
119 disposition = initial_disposition;
120 (*navigator)->OpenURL(node->GetURL(), GURL(), disposition,
121 PageTransition::AUTO_BOOKMARK);
122 if (!*opened_url) {
123 *opened_url = true;
124 // We opened the first URL which may have opened a new window or clobbered
125 // the current page, reset the navigator just to be sure.
126 Browser* new_browser = BrowserList::GetLastActive();
127 if (new_browser) {
128 TabContents* current_tab = new_browser->GetSelectedTabContents();
129 DCHECK(new_browser && current_tab);
130 if (new_browser && current_tab)
131 *navigator = current_tab;
132 } // else, new_browser == NULL, which happens during testing.
133 }
134 } else {
135 // Group, recurse through children.
136 for (int i = 0; i < node->GetChildCount(); ++i) {
137 OpenAllImpl(node->GetChild(i), initial_disposition, navigator,
138 opened_url);
139 }
140 }
141}
142
[email protected]d6d6d582009-10-12 19:22:26143bool ShouldOpenAll(gfx::NativeWindow parent,
[email protected]b3c33d462009-06-26 22:29:20144 const std::vector<const BookmarkNode*>& nodes) {
[email protected]7f856be2008-10-29 23:38:06145 int descendant_count = 0;
146 for (size_t i = 0; i < nodes.size(); ++i)
147 descendant_count += DescendantURLCount(nodes[i]);
[email protected]f785ad12008-11-19 23:01:28148 if (descendant_count < bookmark_utils::num_urls_before_prompting)
[email protected]7f856be2008-10-29 23:38:06149 return true;
150
151 std::wstring message =
152 l10n_util::GetStringF(IDS_BOOKMARK_BAR_SHOULD_OPEN_ALL,
153 IntToWString(descendant_count));
[email protected]a0368962009-02-24 21:47:16154#if defined(OS_WIN)
[email protected]7f856be2008-10-29 23:38:06155 return MessageBox(parent, message.c_str(),
156 l10n_util::GetString(IDS_PRODUCT_NAME).c_str(),
157 MB_YESNO | MB_ICONWARNING | MB_TOPMOST) == IDYES;
[email protected]a0368962009-02-24 21:47:16158#else
159 // TODO(port): Display a dialog prompt.
160 NOTIMPLEMENTED();
161 return true;
162#endif
[email protected]7f856be2008-10-29 23:38:06163}
164
[email protected]9333f182008-12-09 17:34:17165// Comparison function that compares based on date modified of the two nodes.
[email protected]b3c33d462009-06-26 22:29:20166bool MoreRecentlyModified(const BookmarkNode* n1, const BookmarkNode* n2) {
[email protected]9333f182008-12-09 17:34:17167 return n1->date_group_modified() > n2->date_group_modified();
168}
169
[email protected]cb362ccc2008-12-10 17:22:32170// Returns true if |text| contains each string in |words|. This is used when
171// searching for bookmarks.
172bool DoesBookmarkTextContainWords(const std::wstring& text,
173 const std::vector<std::wstring>& words) {
174 for (size_t i = 0; i < words.size(); ++i) {
175 if (text.find(words[i]) == std::wstring::npos)
176 return false;
177 }
178 return true;
179}
180
181// Returns true if |node|s title or url contains the strings in |words|.
[email protected]fa5dfaf2009-06-02 22:12:06182// |languages| argument is user's accept-language setting to decode IDN.
[email protected]b3c33d462009-06-26 22:29:20183bool DoesBookmarkContainWords(const BookmarkNode* node,
[email protected]fa5dfaf2009-06-02 22:12:06184 const std::vector<std::wstring>& words,
185 const std::wstring& languages) {
[email protected]cb362ccc2008-12-10 17:22:32186 return
187 DoesBookmarkTextContainWords(
188 l10n_util::ToLower(node->GetTitle()), words) ||
[email protected]1f31bb72009-12-16 03:18:25189 DoesBookmarkTextContainWords(
190 l10n_util::ToLower(UTF8ToWide(node->GetURL().spec())), words) ||
191 DoesBookmarkTextContainWords(l10n_util::ToLower(net::FormatUrl(
192 node->GetURL(), languages, false, true, NULL, NULL, NULL)), words);
[email protected]cb362ccc2008-12-10 17:22:32193}
194
[email protected]7f856be2008-10-29 23:38:06195} // namespace
196
197namespace bookmark_utils {
198
[email protected]f785ad12008-11-19 23:01:28199int num_urls_before_prompting = 15;
200
[email protected]f28cbb72008-11-04 19:29:08201int PreferredDropOperation(int source_operations, int operations) {
202 int common_ops = (source_operations & operations);
[email protected]7f856be2008-10-29 23:38:06203 if (!common_ops)
204 return 0;
205 if (DragDropTypes::DRAG_COPY & common_ops)
206 return DragDropTypes::DRAG_COPY;
207 if (DragDropTypes::DRAG_LINK & common_ops)
208 return DragDropTypes::DRAG_LINK;
209 if (DragDropTypes::DRAG_MOVE & common_ops)
210 return DragDropTypes::DRAG_MOVE;
211 return DragDropTypes::DRAG_NONE;
212}
213
[email protected]b3c33d462009-06-26 22:29:20214int BookmarkDragOperation(const BookmarkNode* node) {
[email protected]7aa4c002009-03-12 19:10:22215 if (node->is_url()) {
216 return DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_MOVE |
217 DragDropTypes::DRAG_LINK;
218 }
219 return DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_MOVE;
220}
221
222int BookmarkDropOperation(Profile* profile,
223 const views::DropTargetEvent& event,
224 const BookmarkDragData& data,
[email protected]b3c33d462009-06-26 22:29:20225 const BookmarkNode* parent,
[email protected]7aa4c002009-03-12 19:10:22226 int index) {
227 if (data.IsFromProfile(profile) && data.size() > 1)
228 // Currently only accept one dragged node at a time.
229 return DragDropTypes::DRAG_NONE;
230
231 if (!bookmark_utils::IsValidDropLocation(profile, data, parent, index))
232 return DragDropTypes::DRAG_NONE;
233
234 if (data.GetFirstNode(profile)) {
235 // User is dragging from this profile: move.
236 return DragDropTypes::DRAG_MOVE;
237 }
238 // User is dragging from another app, copy.
239 return PreferredDropOperation(event.GetSourceOperations(),
240 DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_LINK);
241}
242
243int PerformBookmarkDrop(Profile* profile,
244 const BookmarkDragData& data,
[email protected]b3c33d462009-06-26 22:29:20245 const BookmarkNode* parent_node,
[email protected]7aa4c002009-03-12 19:10:22246 int index) {
[email protected]b3c33d462009-06-26 22:29:20247 const BookmarkNode* dragged_node = data.GetFirstNode(profile);
[email protected]7aa4c002009-03-12 19:10:22248 BookmarkModel* model = profile->GetBookmarkModel();
249 if (dragged_node) {
250 // Drag from same profile, do a move.
251 model->Move(dragged_node, parent_node, index);
252 return DragDropTypes::DRAG_MOVE;
253 } else if (data.has_single_url()) {
254 // New URL, add it at the specified location.
[email protected]9c6a85d2010-01-21 22:53:46255 string16 title = data.elements[0].title;
[email protected]7aa4c002009-03-12 19:10:22256 if (title.empty()) {
257 // No title, use the host.
[email protected]9c6a85d2010-01-21 22:53:46258 title = UTF8ToUTF16(data.elements[0].url.host());
[email protected]7aa4c002009-03-12 19:10:22259 if (title.empty())
[email protected]9c6a85d2010-01-21 22:53:46260 title = l10n_util::GetStringUTF16(IDS_BOOMARK_BAR_UNKNOWN_DRAG_TITLE);
[email protected]7aa4c002009-03-12 19:10:22261 }
262 model->AddURL(parent_node, index, title, data.elements[0].url);
263 return DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_LINK;
264 } else {
265 // Dropping a group from different profile. Always accept.
266 bookmark_utils::CloneDragData(model, data.elements, parent_node, index);
267 return DragDropTypes::DRAG_COPY;
268 }
269}
270
[email protected]7f856be2008-10-29 23:38:06271bool IsValidDropLocation(Profile* profile,
272 const BookmarkDragData& data,
[email protected]b3c33d462009-06-26 22:29:20273 const BookmarkNode* drop_parent,
[email protected]7f856be2008-10-29 23:38:06274 int index) {
275 if (!drop_parent->is_folder()) {
276 NOTREACHED();
277 return false;
278 }
279
280 if (!data.is_valid())
281 return false;
282
283 if (data.IsFromProfile(profile)) {
[email protected]b3c33d462009-06-26 22:29:20284 std::vector<const BookmarkNode*> nodes = data.GetNodes(profile);
[email protected]7f856be2008-10-29 23:38:06285 for (size_t i = 0; i < nodes.size(); ++i) {
286 // Don't allow the drop if the user is attempting to drop on one of the
287 // nodes being dragged.
[email protected]b3c33d462009-06-26 22:29:20288 const BookmarkNode* node = nodes[i];
[email protected]7f856be2008-10-29 23:38:06289 int node_index = (drop_parent == node->GetParent()) ?
290 drop_parent->IndexOfChild(nodes[i]) : -1;
291 if (node_index != -1 && (index == node_index || index == node_index + 1))
292 return false;
293
294 // drop_parent can't accept a child that is an ancestor.
295 if (drop_parent->HasAncestor(node))
296 return false;
297 }
298 return true;
299 }
300 // From the same profile, always accept.
301 return true;
302}
303
304void CloneDragData(BookmarkModel* model,
305 const std::vector<BookmarkDragData::Element>& elements,
[email protected]b3c33d462009-06-26 22:29:20306 const BookmarkNode* parent,
[email protected]7f856be2008-10-29 23:38:06307 int index_to_add_at) {
308 if (!parent->is_folder() || !model) {
309 NOTREACHED();
310 return;
311 }
312 for (size_t i = 0; i < elements.size(); ++i)
313 CloneDragDataImpl(model, elements[i], parent, index_to_add_at + i);
314}
315
[email protected]d6d6d582009-10-12 19:22:26316void OpenAll(gfx::NativeWindow parent,
[email protected]7f856be2008-10-29 23:38:06317 Profile* profile,
318 PageNavigator* navigator,
[email protected]b3c33d462009-06-26 22:29:20319 const std::vector<const BookmarkNode*>& nodes,
[email protected]7f856be2008-10-29 23:38:06320 WindowOpenDisposition initial_disposition) {
321 if (!ShouldOpenAll(parent, nodes))
322 return;
323
324 NewBrowserPageNavigator navigator_impl(profile);
325 if (!navigator) {
[email protected]f0a51fb52009-03-05 12:46:38326 Browser* browser =
[email protected]299dabd2008-11-19 02:27:16327 BrowserList::FindBrowserWithType(profile, Browser::TYPE_NORMAL);
[email protected]b6f2b9132008-11-17 16:27:51328 if (!browser || !browser->GetSelectedTabContents()) {
[email protected]7f856be2008-10-29 23:38:06329 navigator = &navigator_impl;
[email protected]b6f2b9132008-11-17 16:27:51330 } else {
[email protected]c9938e6d2009-03-13 19:54:11331 if (initial_disposition != NEW_WINDOW &&
332 initial_disposition != OFF_THE_RECORD) {
333 browser->window()->Activate();
334 }
[email protected]7f856be2008-10-29 23:38:06335 navigator = browser->GetSelectedTabContents();
[email protected]b6f2b9132008-11-17 16:27:51336 }
[email protected]7f856be2008-10-29 23:38:06337 }
338
339 bool opened_url = false;
340 for (size_t i = 0; i < nodes.size(); ++i)
341 OpenAllImpl(nodes[i], initial_disposition, &navigator, &opened_url);
342}
343
[email protected]d6d6d582009-10-12 19:22:26344void OpenAll(gfx::NativeWindow parent,
[email protected]7f856be2008-10-29 23:38:06345 Profile* profile,
346 PageNavigator* navigator,
[email protected]b3c33d462009-06-26 22:29:20347 const BookmarkNode* node,
[email protected]7f856be2008-10-29 23:38:06348 WindowOpenDisposition initial_disposition) {
[email protected]b3c33d462009-06-26 22:29:20349 std::vector<const BookmarkNode*> nodes;
[email protected]7f856be2008-10-29 23:38:06350 nodes.push_back(node);
351 OpenAll(parent, profile, navigator, nodes, initial_disposition);
352}
353
[email protected]fafc8a422008-11-07 17:53:09354void CopyToClipboard(BookmarkModel* model,
[email protected]b3c33d462009-06-26 22:29:20355 const std::vector<const BookmarkNode*>& nodes,
[email protected]fafc8a422008-11-07 17:53:09356 bool remove_nodes) {
[email protected]b08cadb92009-08-04 21:52:29357#if defined(OS_WIN) || defined(OS_LINUX)
[email protected]fafc8a422008-11-07 17:53:09358 if (nodes.empty())
359 return;
360
[email protected]b08cadb92009-08-04 21:52:29361 BookmarkDragData(nodes).WriteToClipboard(NULL);
[email protected]fafc8a422008-11-07 17:53:09362
363 if (remove_nodes) {
364 for (size_t i = 0; i < nodes.size(); ++i) {
365 model->Remove(nodes[i]->GetParent(),
366 nodes[i]->GetParent()->IndexOfChild(nodes[i]));
367 }
368 }
[email protected]b08cadb92009-08-04 21:52:29369#else
370 // Not implemented on mac yet.
[email protected]7018c5f32009-07-31 23:37:57371#endif
[email protected]fafc8a422008-11-07 17:53:09372}
373
374void PasteFromClipboard(BookmarkModel* model,
[email protected]b3c33d462009-06-26 22:29:20375 const BookmarkNode* parent,
[email protected]fafc8a422008-11-07 17:53:09376 int index) {
[email protected]b08cadb92009-08-04 21:52:29377#if defined(OS_WIN) || defined(OS_LINUX)
[email protected]fafc8a422008-11-07 17:53:09378 if (!parent)
379 return;
380
[email protected]fafc8a422008-11-07 17:53:09381 BookmarkDragData bookmark_data;
[email protected]b08cadb92009-08-04 21:52:29382 if (!bookmark_data.ReadFromClipboard())
[email protected]fafc8a422008-11-07 17:53:09383 return;
384
385 if (index == -1)
386 index = parent->GetChildCount();
387 bookmark_utils::CloneDragData(model, bookmark_data.elements, parent, index);
[email protected]a0368962009-02-24 21:47:16388#else
[email protected]b08cadb92009-08-04 21:52:29389 // Not implemented on mac yet.
[email protected]a0368962009-02-24 21:47:16390#endif
[email protected]fafc8a422008-11-07 17:53:09391}
392
[email protected]b3c33d462009-06-26 22:29:20393bool CanPasteFromClipboard(const BookmarkNode* node) {
[email protected]fafc8a422008-11-07 17:53:09394 if (!node)
395 return false;
396
[email protected]eda57132009-10-01 14:55:28397#if defined(OS_MACOSX)
398 NOTIMPLEMENTED();
399 return false;
400#else
401 return g_browser_process->clipboard()->IsFormatAvailableByString(
[email protected]65a6150d2009-09-08 22:16:05402 BookmarkDragData::kClipboardFormatString, Clipboard::BUFFER_STANDARD);
[email protected]eda57132009-10-01 14:55:28403#endif
[email protected]fafc8a422008-11-07 17:53:09404}
405
[email protected]903e7a82009-07-28 00:45:35406std::string GetNameForURL(const GURL& url) {
407 if (url.is_valid()) {
408 return WideToUTF8(net::GetSuggestedFilename(
[email protected]630947c2009-11-04 18:37:31409 url, std::string(), std::string(), FilePath()).ToWStringHack());
[email protected]903e7a82009-07-28 00:45:35410 } else {
411 return l10n_util::GetStringUTF8(IDS_APP_UNTITLED_SHORTCUT_FILE_NAME);
412 }
413}
414
[email protected]b3c33d462009-06-26 22:29:20415std::vector<const BookmarkNode*> GetMostRecentlyModifiedGroups(
[email protected]9333f182008-12-09 17:34:17416 BookmarkModel* model,
417 size_t max_count) {
[email protected]b3c33d462009-06-26 22:29:20418 std::vector<const BookmarkNode*> nodes;
419 TreeNodeIterator<const BookmarkNode> iterator(model->root_node());
[email protected]9333f182008-12-09 17:34:17420 while (iterator.has_next()) {
[email protected]b3c33d462009-06-26 22:29:20421 const BookmarkNode* parent = iterator.Next();
[email protected]9333f182008-12-09 17:34:17422 if (parent->is_folder() && parent->date_group_modified() > base::Time()) {
423 if (max_count == 0) {
424 nodes.push_back(parent);
425 } else {
[email protected]b3c33d462009-06-26 22:29:20426 std::vector<const BookmarkNode*>::iterator i =
[email protected]9333f182008-12-09 17:34:17427 std::upper_bound(nodes.begin(), nodes.end(), parent,
428 &MoreRecentlyModified);
429 if (nodes.size() < max_count || i != nodes.end()) {
430 nodes.insert(i, parent);
431 while (nodes.size() > max_count)
432 nodes.pop_back();
433 }
434 }
435 } // else case, the root node, which we don't care about or imported nodes
436 // (which have a time of 0).
437 }
438
439 if (nodes.size() < max_count) {
440 // Add the bookmark bar and other nodes if there is space.
441 if (find(nodes.begin(), nodes.end(), model->GetBookmarkBarNode()) ==
442 nodes.end()) {
443 nodes.push_back(model->GetBookmarkBarNode());
444 }
445
446 if (nodes.size() < max_count &&
447 find(nodes.begin(), nodes.end(), model->other_node()) == nodes.end()) {
448 nodes.push_back(model->other_node());
449 }
450 }
451 return nodes;
452}
453
454void GetMostRecentlyAddedEntries(BookmarkModel* model,
455 size_t count,
[email protected]b3c33d462009-06-26 22:29:20456 std::vector<const BookmarkNode*>* nodes) {
457 TreeNodeIterator<const BookmarkNode> iterator(model->root_node());
[email protected]9333f182008-12-09 17:34:17458 while (iterator.has_next()) {
[email protected]b3c33d462009-06-26 22:29:20459 const BookmarkNode* node = iterator.Next();
[email protected]9333f182008-12-09 17:34:17460 if (node->is_url()) {
[email protected]b3c33d462009-06-26 22:29:20461 std::vector<const BookmarkNode*>::iterator insert_position =
[email protected]9333f182008-12-09 17:34:17462 std::upper_bound(nodes->begin(), nodes->end(), node,
463 &MoreRecentlyAdded);
464 if (nodes->size() < count || insert_position != nodes->end()) {
465 nodes->insert(insert_position, node);
466 while (nodes->size() > count)
467 nodes->pop_back();
468 }
469 }
470 }
471}
472
[email protected]b3c33d462009-06-26 22:29:20473bool MoreRecentlyAdded(const BookmarkNode* n1, const BookmarkNode* n2) {
[email protected]9333f182008-12-09 17:34:17474 return n1->date_added() > n2->date_added();
475}
476
[email protected]cb362ccc2008-12-10 17:22:32477void GetBookmarksContainingText(BookmarkModel* model,
478 const std::wstring& text,
479 size_t max_count,
[email protected]fa5dfaf2009-06-02 22:12:06480 const std::wstring& languages,
[email protected]b3c33d462009-06-26 22:29:20481 std::vector<const BookmarkNode*>* nodes) {
[email protected]cb362ccc2008-12-10 17:22:32482 std::vector<std::wstring> words;
483 QueryParser parser;
484 parser.ExtractQueryWords(l10n_util::ToLower(text), &words);
485 if (words.empty())
486 return;
487
[email protected]b3c33d462009-06-26 22:29:20488 TreeNodeIterator<const BookmarkNode> iterator(model->root_node());
[email protected]cb362ccc2008-12-10 17:22:32489 while (iterator.has_next()) {
[email protected]b3c33d462009-06-26 22:29:20490 const BookmarkNode* node = iterator.Next();
[email protected]fa5dfaf2009-06-02 22:12:06491 if (node->is_url() && DoesBookmarkContainWords(node, words, languages)) {
[email protected]cb362ccc2008-12-10 17:22:32492 nodes->push_back(node);
493 if (nodes->size() == max_count)
494 return;
495 }
496 }
497}
498
[email protected]b3c33d462009-06-26 22:29:20499bool DoesBookmarkContainText(const BookmarkNode* node,
[email protected]fa5dfaf2009-06-02 22:12:06500 const std::wstring& text,
501 const std::wstring& languages) {
[email protected]cb362ccc2008-12-10 17:22:32502 std::vector<std::wstring> words;
503 QueryParser parser;
504 parser.ExtractQueryWords(l10n_util::ToLower(text), &words);
505 if (words.empty())
506 return false;
507
[email protected]fa5dfaf2009-06-02 22:12:06508 return (node->is_url() && DoesBookmarkContainWords(node, words, languages));
[email protected]cb362ccc2008-12-10 17:22:32509}
510
[email protected]ec12ffe2009-10-16 22:28:44511static const BookmarkNode* CreateNewNode(BookmarkModel* model,
512 const BookmarkNode* parent, const BookmarkEditor::EditDetails& details,
[email protected]a8d71b02009-07-07 00:36:34513 const std::wstring& new_title, const GURL& new_url,
514 BookmarkEditor::Handler* handler) {
[email protected]ec12ffe2009-10-16 22:28:44515 const BookmarkNode* node;
516 if (details.type == BookmarkEditor::EditDetails::NEW_URL) {
517 node = model->AddURL(parent, parent->GetChildCount(), new_title, new_url);
518 } else if (details.type == BookmarkEditor::EditDetails::NEW_FOLDER) {
519 node = model->AddGroup(parent, parent->GetChildCount(), new_title);
520 for (size_t i = 0; i < details.urls.size(); ++i) {
521 model->AddURL(node, node->GetChildCount(), details.urls[i].second,
522 details.urls[i].first);
523 }
[email protected]eea8fd5532009-12-16 00:08:10524 model->SetDateGroupModified(parent, Time::Now());
[email protected]ec12ffe2009-10-16 22:28:44525 } else {
526 NOTREACHED();
527 return NULL;
[email protected]140aea052009-05-05 00:35:09528 }
529
[email protected]ec12ffe2009-10-16 22:28:44530 if (handler)
531 handler->NodeCreated(node);
532 return node;
533}
534
535const BookmarkNode* ApplyEditsWithNoGroupChange(BookmarkModel* model,
536 const BookmarkNode* parent, const BookmarkEditor::EditDetails& details,
537 const std::wstring& new_title, const GURL& new_url,
538 BookmarkEditor::Handler* handler) {
539 if (details.type == BookmarkEditor::EditDetails::NEW_URL ||
540 details.type == BookmarkEditor::EditDetails::NEW_FOLDER) {
541 return CreateNewNode(model, parent, details, new_title, new_url, handler);
542 }
543
544 const BookmarkNode* node = details.existing_node;
545 DCHECK(node);
546 const BookmarkNode* old_parent = node->GetParent();
547 int old_index = old_parent ? old_parent->IndexOfChild(node) : -1;
548
[email protected]140aea052009-05-05 00:35:09549 // If we're not showing the tree we only need to modify the node.
550 if (old_index == -1) {
551 NOTREACHED();
[email protected]a8d71b02009-07-07 00:36:34552 return node;
[email protected]140aea052009-05-05 00:35:09553 }
554
555 if (new_url != node->GetURL()) {
[email protected]ec12ffe2009-10-16 22:28:44556 // TODO(sky): need SetURL on the model.
[email protected]a8d71b02009-07-07 00:36:34557 const BookmarkNode* new_node = model->AddURLWithCreationTime(old_parent,
558 old_index, new_title, new_url, node->date_added());
[email protected]140aea052009-05-05 00:35:09559 model->Remove(old_parent, old_index + 1);
[email protected]a8d71b02009-07-07 00:36:34560 return new_node;
[email protected]140aea052009-05-05 00:35:09561 } else {
562 model->SetTitle(node, new_title);
563 }
[email protected]a8d71b02009-07-07 00:36:34564 return node;
[email protected]140aea052009-05-05 00:35:09565}
566
[email protected]a8d71b02009-07-07 00:36:34567const BookmarkNode* ApplyEditsWithPossibleGroupChange(BookmarkModel* model,
[email protected]ec12ffe2009-10-16 22:28:44568 const BookmarkNode* new_parent, const BookmarkEditor::EditDetails& details,
[email protected]a8d71b02009-07-07 00:36:34569 const std::wstring& new_title, const GURL& new_url,
570 BookmarkEditor::Handler* handler) {
[email protected]ec12ffe2009-10-16 22:28:44571 if (details.type == BookmarkEditor::EditDetails::NEW_URL ||
572 details.type == BookmarkEditor::EditDetails::NEW_FOLDER) {
573 return CreateNewNode(model, new_parent, details, new_title, new_url,
574 handler);
575 }
576
577 const BookmarkNode* node = details.existing_node;
578 DCHECK(node);
579 const BookmarkNode* old_parent = node->GetParent();
580 int old_index = old_parent->IndexOfChild(node);
[email protected]a8d71b02009-07-07 00:36:34581 const BookmarkNode* return_node = node;
[email protected]ec12ffe2009-10-16 22:28:44582
583 Time date_added = node->date_added();
584 if (new_parent == node->GetParent()) {
585 // The parent is the same.
586 if (node->is_url() && new_url != node->GetURL()) {
[email protected]140aea052009-05-05 00:35:09587 model->Remove(old_parent, old_index);
[email protected]ec12ffe2009-10-16 22:28:44588 return_node = model->AddURLWithCreationTime(old_parent, old_index,
589 new_title, new_url, date_added);
[email protected]140aea052009-05-05 00:35:09590 } else {
[email protected]140aea052009-05-05 00:35:09591 model->SetTitle(node, new_title);
592 }
[email protected]ec12ffe2009-10-16 22:28:44593 } else if (node->is_url() && new_url != node->GetURL()) {
594 // The parent and URL changed.
595 model->Remove(old_parent, old_index);
596 return_node = model->AddURLWithCreationTime(new_parent,
597 new_parent->GetChildCount(), new_title, new_url, date_added);
[email protected]140aea052009-05-05 00:35:09598 } else {
[email protected]ec12ffe2009-10-16 22:28:44599 // The parent and title changed. Move the node and change the title.
600 model->Move(node, new_parent, new_parent->GetChildCount());
601 model->SetTitle(node, new_title);
[email protected]140aea052009-05-05 00:35:09602 }
[email protected]a8d71b02009-07-07 00:36:34603 return return_node;
[email protected]140aea052009-05-05 00:35:09604}
605
[email protected]44b2c8852009-03-18 00:57:49606// Formerly in BookmarkBarView
607void ToggleWhenVisible(Profile* profile) {
608 PrefService* prefs = profile->GetPrefs();
609 const bool always_show = !prefs->GetBoolean(prefs::kShowBookmarkBar);
610
611 // The user changed when the bookmark bar is shown, update the preferences.
612 prefs->SetBoolean(prefs::kShowBookmarkBar, always_show);
[email protected]6faa0e0d2009-04-28 06:50:36613 prefs->ScheduleSavePersistentPrefs();
[email protected]44b2c8852009-03-18 00:57:49614
615 // And notify the notification service.
616 Source<Profile> source(profile);
617 NotificationService::current()->Notify(
618 NotificationType::BOOKMARK_BAR_VISIBILITY_PREF_CHANGED,
619 source,
620 NotificationService::NoDetails());
621}
622
[email protected]1e7bab72009-06-03 17:23:36623void RegisterPrefs(PrefService* prefs) {
624 prefs->RegisterDictionaryPref(prefs::kBookmarkManagerPlacement);
625 prefs->RegisterIntegerPref(prefs::kBookmarkManagerSplitLocation, -1);
626}
627
[email protected]44b2c8852009-03-18 00:57:49628void RegisterUserPrefs(PrefService* prefs) {
629 // Formerly in BookmarkBarView
630 prefs->RegisterBooleanPref(prefs::kShowBookmarkBar, false);
631
632 // Formerly in BookmarkTableView
633 prefs->RegisterIntegerPref(prefs::kBookmarkTableNameWidth1, -1);
634 prefs->RegisterIntegerPref(prefs::kBookmarkTableURLWidth1, -1);
635 prefs->RegisterIntegerPref(prefs::kBookmarkTableNameWidth2, -1);
636 prefs->RegisterIntegerPref(prefs::kBookmarkTableURLWidth2, -1);
637 prefs->RegisterIntegerPref(prefs::kBookmarkTablePathWidth, -1);
638}
639
[email protected]76624fde2009-10-09 18:13:23640void GetURLAndTitleToBookmark(TabContents* tab_contents,
[email protected]b3ac5c82009-10-08 20:56:54641 GURL* url,
642 std::wstring* title) {
[email protected]76624fde2009-10-09 18:13:23643 *url = tab_contents->GetURL();
644 *title = UTF16ToWideHack(tab_contents->GetTitle());
[email protected]b3ac5c82009-10-08 20:56:54645}
646
[email protected]ec12ffe2009-10-16 22:28:44647void GetURLsForOpenTabs(Browser* browser,
648 std::vector<std::pair<GURL, std::wstring> >* urls) {
[email protected]b3ac5c82009-10-08 20:56:54649 for (int i = 0; i < browser->tab_count(); ++i) {
[email protected]ec12ffe2009-10-16 22:28:44650 std::pair<GURL, std::wstring> entry;
651 GetURLAndTitleToBookmark(browser->GetTabContentsAt(i), &(entry.first),
652 &(entry.second));
653 urls->push_back(entry);
[email protected]b3ac5c82009-10-08 20:56:54654 }
[email protected]b3ac5c82009-10-08 20:56:54655}
656
[email protected]7f856be2008-10-29 23:38:06657} // namespace bookmark_utils