blob: 964df018138a73588f5c15cc232f1b8355a3abfc [file] [log] [blame]
[email protected]7f856be2008-10-29 23:38:061// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
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/bookmarks/bookmark_utils.h"
6
[email protected]37126212009-05-06 02:23:317#include "app/drag_drop_types.h"
[email protected]a92b8642009-05-05 23:38:568#include "app/l10n_util.h"
[email protected]37126212009-05-06 02:23:319// TODO(port): Port these files.
10#if defined(OS_WIN)
11#include "app/os_exchange_data.h"
12#else
13#include "chrome/common/temp_scaffolding_stubs.h"
14#endif
[email protected]992c6252009-05-13 18:54:2015#include "app/tree_node_iterator.h"
[email protected]a0368962009-02-24 21:47:1616#include "base/basictypes.h"
[email protected]cb362ccc2008-12-10 17:22:3217#include "base/string_util.h"
[email protected]9333f182008-12-09 17:34:1718#include "base/time.h"
[email protected]7f856be2008-10-29 23:38:0619#include "chrome/browser/bookmarks/bookmark_drag_data.h"
20#include "chrome/browser/bookmarks/bookmark_model.h"
21#include "chrome/browser/browser.h"
22#include "chrome/browser/browser_list.h"
[email protected]9333f182008-12-09 17:34:1723#include "chrome/browser/history/query_parser.h"
[email protected]505323e22009-01-24 02:47:5824#include "chrome/browser/profile.h"
[email protected]f3ec7742009-01-15 00:59:1625#include "chrome/browser/tab_contents/page_navigator.h"
[email protected]1132436e2009-04-08 20:06:3326#include "chrome/browser/tab_contents/tab_contents.h"
[email protected]44b2c8852009-03-18 00:57:4927#include "chrome/common/notification_service.h"
28#include "chrome/common/pref_names.h"
29#include "chrome/common/pref_service.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,
78 BookmarkNode* parent,
79 int index_to_add_at) {
80 if (element.is_url) {
81 model->AddURL(parent, index_to_add_at, element.title, element.url);
82 } else {
83 BookmarkNode* new_folder = model->AddGroup(parent, index_to_add_at,
84 element.title);
85 for (int i = 0; i < static_cast<int>(element.children.size()); ++i)
86 CloneDragDataImpl(model, element.children[i], new_folder, i);
87 }
88}
89
90// Returns the number of descendants of node that are of type url.
91int DescendantURLCount(BookmarkNode* node) {
92 int result = 0;
93 for (int i = 0; i < node->GetChildCount(); ++i) {
94 BookmarkNode* child = node->GetChild(i);
95 if (child->is_url())
96 result++;
97 else
98 result += DescendantURLCount(child);
99 }
100 return result;
101}
102
103// Implementation of OpenAll. Opens all nodes of type URL and recurses for
104// groups. |navigator| is the PageNavigator used to open URLs. After the first
105// url is opened |opened_url| is set to true and |navigator| is set to the
106// PageNavigator of the last active tab. This is done to handle a window
107// disposition of new window, in which case we want subsequent tabs to open in
108// that window.
109void OpenAllImpl(BookmarkNode* node,
110 WindowOpenDisposition initial_disposition,
111 PageNavigator** navigator,
112 bool* opened_url) {
113 if (node->is_url()) {
114 WindowOpenDisposition disposition;
115 if (*opened_url)
116 disposition = NEW_BACKGROUND_TAB;
117 else
118 disposition = initial_disposition;
119 (*navigator)->OpenURL(node->GetURL(), GURL(), disposition,
120 PageTransition::AUTO_BOOKMARK);
121 if (!*opened_url) {
122 *opened_url = true;
123 // We opened the first URL which may have opened a new window or clobbered
124 // the current page, reset the navigator just to be sure.
125 Browser* new_browser = BrowserList::GetLastActive();
126 if (new_browser) {
127 TabContents* current_tab = new_browser->GetSelectedTabContents();
128 DCHECK(new_browser && current_tab);
129 if (new_browser && current_tab)
130 *navigator = current_tab;
131 } // else, new_browser == NULL, which happens during testing.
132 }
133 } else {
134 // Group, recurse through children.
135 for (int i = 0; i < node->GetChildCount(); ++i) {
136 OpenAllImpl(node->GetChild(i), initial_disposition, navigator,
137 opened_url);
138 }
139 }
140}
141
[email protected]6128eae2009-05-27 22:00:39142bool ShouldOpenAll(gfx::NativeView parent,
[email protected]d3216442009-03-05 21:07:27143 const std::vector<BookmarkNode*>& nodes) {
[email protected]7f856be2008-10-29 23:38:06144 int descendant_count = 0;
145 for (size_t i = 0; i < nodes.size(); ++i)
146 descendant_count += DescendantURLCount(nodes[i]);
[email protected]f785ad12008-11-19 23:01:28147 if (descendant_count < bookmark_utils::num_urls_before_prompting)
[email protected]7f856be2008-10-29 23:38:06148 return true;
149
150 std::wstring message =
151 l10n_util::GetStringF(IDS_BOOKMARK_BAR_SHOULD_OPEN_ALL,
152 IntToWString(descendant_count));
[email protected]a0368962009-02-24 21:47:16153#if defined(OS_WIN)
[email protected]7f856be2008-10-29 23:38:06154 return MessageBox(parent, message.c_str(),
155 l10n_util::GetString(IDS_PRODUCT_NAME).c_str(),
156 MB_YESNO | MB_ICONWARNING | MB_TOPMOST) == IDYES;
[email protected]a0368962009-02-24 21:47:16157#else
158 // TODO(port): Display a dialog prompt.
159 NOTIMPLEMENTED();
160 return true;
161#endif
[email protected]7f856be2008-10-29 23:38:06162}
163
[email protected]9333f182008-12-09 17:34:17164// Comparison function that compares based on date modified of the two nodes.
165bool MoreRecentlyModified(BookmarkNode* n1, BookmarkNode* n2) {
166 return n1->date_group_modified() > n2->date_group_modified();
167}
168
[email protected]cb362ccc2008-12-10 17:22:32169// Returns true if |text| contains each string in |words|. This is used when
170// searching for bookmarks.
171bool DoesBookmarkTextContainWords(const std::wstring& text,
172 const std::vector<std::wstring>& words) {
173 for (size_t i = 0; i < words.size(); ++i) {
174 if (text.find(words[i]) == std::wstring::npos)
175 return false;
176 }
177 return true;
178}
179
180// Returns true if |node|s title or url contains the strings in |words|.
[email protected]fa5dfaf2009-06-02 22:12:06181// |languages| argument is user's accept-language setting to decode IDN.
[email protected]cb362ccc2008-12-10 17:22:32182bool DoesBookmarkContainWords(BookmarkNode* node,
[email protected]fa5dfaf2009-06-02 22:12:06183 const std::vector<std::wstring>& words,
184 const std::wstring& languages) {
[email protected]cb362ccc2008-12-10 17:22:32185 return
186 DoesBookmarkTextContainWords(
187 l10n_util::ToLower(node->GetTitle()), words) ||
[email protected]fa5dfaf2009-06-02 22:12:06188 DoesBookmarkTextContainWords(UTF8ToWide(node->GetURL().spec()), words) ||
189 DoesBookmarkTextContainWords(net::FormatUrl(
190 node->GetURL(), languages, false, true, NULL, NULL), words);
[email protected]cb362ccc2008-12-10 17:22:32191}
192
[email protected]7f856be2008-10-29 23:38:06193} // namespace
194
195namespace bookmark_utils {
196
[email protected]f785ad12008-11-19 23:01:28197int num_urls_before_prompting = 15;
198
[email protected]f28cbb72008-11-04 19:29:08199int PreferredDropOperation(int source_operations, int operations) {
200 int common_ops = (source_operations & operations);
[email protected]7f856be2008-10-29 23:38:06201 if (!common_ops)
202 return 0;
203 if (DragDropTypes::DRAG_COPY & common_ops)
204 return DragDropTypes::DRAG_COPY;
205 if (DragDropTypes::DRAG_LINK & common_ops)
206 return DragDropTypes::DRAG_LINK;
207 if (DragDropTypes::DRAG_MOVE & common_ops)
208 return DragDropTypes::DRAG_MOVE;
209 return DragDropTypes::DRAG_NONE;
210}
211
[email protected]7aa4c002009-03-12 19:10:22212int BookmarkDragOperation(BookmarkNode* node) {
213 if (node->is_url()) {
214 return DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_MOVE |
215 DragDropTypes::DRAG_LINK;
216 }
217 return DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_MOVE;
218}
219
220int BookmarkDropOperation(Profile* profile,
221 const views::DropTargetEvent& event,
222 const BookmarkDragData& data,
223 BookmarkNode* parent,
224 int index) {
225 if (data.IsFromProfile(profile) && data.size() > 1)
226 // Currently only accept one dragged node at a time.
227 return DragDropTypes::DRAG_NONE;
228
229 if (!bookmark_utils::IsValidDropLocation(profile, data, parent, index))
230 return DragDropTypes::DRAG_NONE;
231
232 if (data.GetFirstNode(profile)) {
233 // User is dragging from this profile: move.
234 return DragDropTypes::DRAG_MOVE;
235 }
236 // User is dragging from another app, copy.
237 return PreferredDropOperation(event.GetSourceOperations(),
238 DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_LINK);
239}
240
241int PerformBookmarkDrop(Profile* profile,
242 const BookmarkDragData& data,
243 BookmarkNode* parent_node,
244 int index) {
245 BookmarkNode* dragged_node = data.GetFirstNode(profile);
246 BookmarkModel* model = profile->GetBookmarkModel();
247 if (dragged_node) {
248 // Drag from same profile, do a move.
249 model->Move(dragged_node, parent_node, index);
250 return DragDropTypes::DRAG_MOVE;
251 } else if (data.has_single_url()) {
252 // New URL, add it at the specified location.
253 std::wstring title = data.elements[0].title;
254 if (title.empty()) {
255 // No title, use the host.
256 title = UTF8ToWide(data.elements[0].url.host());
257 if (title.empty())
258 title = l10n_util::GetString(IDS_BOOMARK_BAR_UNKNOWN_DRAG_TITLE);
259 }
260 model->AddURL(parent_node, index, title, data.elements[0].url);
261 return DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_LINK;
262 } else {
263 // Dropping a group from different profile. Always accept.
264 bookmark_utils::CloneDragData(model, data.elements, parent_node, index);
265 return DragDropTypes::DRAG_COPY;
266 }
267}
268
[email protected]7f856be2008-10-29 23:38:06269bool IsValidDropLocation(Profile* profile,
270 const BookmarkDragData& data,
271 BookmarkNode* drop_parent,
272 int index) {
273 if (!drop_parent->is_folder()) {
274 NOTREACHED();
275 return false;
276 }
277
278 if (!data.is_valid())
279 return false;
280
281 if (data.IsFromProfile(profile)) {
282 std::vector<BookmarkNode*> nodes = data.GetNodes(profile);
283 for (size_t i = 0; i < nodes.size(); ++i) {
284 // Don't allow the drop if the user is attempting to drop on one of the
285 // nodes being dragged.
286 BookmarkNode* node = nodes[i];
287 int node_index = (drop_parent == node->GetParent()) ?
288 drop_parent->IndexOfChild(nodes[i]) : -1;
289 if (node_index != -1 && (index == node_index || index == node_index + 1))
290 return false;
291
292 // drop_parent can't accept a child that is an ancestor.
293 if (drop_parent->HasAncestor(node))
294 return false;
295 }
296 return true;
297 }
298 // From the same profile, always accept.
299 return true;
300}
301
302void CloneDragData(BookmarkModel* model,
303 const std::vector<BookmarkDragData::Element>& elements,
304 BookmarkNode* parent,
305 int index_to_add_at) {
306 if (!parent->is_folder() || !model) {
307 NOTREACHED();
308 return;
309 }
310 for (size_t i = 0; i < elements.size(); ++i)
311 CloneDragDataImpl(model, elements[i], parent, index_to_add_at + i);
312}
313
[email protected]6128eae2009-05-27 22:00:39314void OpenAll(gfx::NativeView parent,
[email protected]7f856be2008-10-29 23:38:06315 Profile* profile,
316 PageNavigator* navigator,
317 const std::vector<BookmarkNode*>& nodes,
318 WindowOpenDisposition initial_disposition) {
319 if (!ShouldOpenAll(parent, nodes))
320 return;
321
322 NewBrowserPageNavigator navigator_impl(profile);
323 if (!navigator) {
[email protected]f0a51fb52009-03-05 12:46:38324 Browser* browser =
[email protected]299dabd2008-11-19 02:27:16325 BrowserList::FindBrowserWithType(profile, Browser::TYPE_NORMAL);
[email protected]b6f2b9132008-11-17 16:27:51326 if (!browser || !browser->GetSelectedTabContents()) {
[email protected]7f856be2008-10-29 23:38:06327 navigator = &navigator_impl;
[email protected]b6f2b9132008-11-17 16:27:51328 } else {
[email protected]c9938e6d2009-03-13 19:54:11329 if (initial_disposition != NEW_WINDOW &&
330 initial_disposition != OFF_THE_RECORD) {
331 browser->window()->Activate();
332 }
[email protected]7f856be2008-10-29 23:38:06333 navigator = browser->GetSelectedTabContents();
[email protected]b6f2b9132008-11-17 16:27:51334 }
[email protected]7f856be2008-10-29 23:38:06335 }
336
337 bool opened_url = false;
338 for (size_t i = 0; i < nodes.size(); ++i)
339 OpenAllImpl(nodes[i], initial_disposition, &navigator, &opened_url);
340}
341
[email protected]6128eae2009-05-27 22:00:39342void OpenAll(gfx::NativeView parent,
[email protected]7f856be2008-10-29 23:38:06343 Profile* profile,
344 PageNavigator* navigator,
345 BookmarkNode* node,
346 WindowOpenDisposition initial_disposition) {
347 std::vector<BookmarkNode*> nodes;
348 nodes.push_back(node);
349 OpenAll(parent, profile, navigator, nodes, initial_disposition);
350}
351
[email protected]fafc8a422008-11-07 17:53:09352void CopyToClipboard(BookmarkModel* model,
353 const std::vector<BookmarkNode*>& nodes,
354 bool remove_nodes) {
355 if (nodes.empty())
356 return;
357
[email protected]a0368962009-02-24 21:47:16358#if defined(OS_WIN)
[email protected]fafc8a422008-11-07 17:53:09359 OSExchangeData* data = new OSExchangeData();
360 BookmarkDragData(nodes).Write(NULL, data);
361 OleSetClipboard(data);
362 // OLE takes ownership of OSExchangeData.
[email protected]a0368962009-02-24 21:47:16363#else
364 // TODO(port): Clipboard integration. Don't we have clipboard
365 // implemented somewhere else?
366 NOTIMPLEMENTED();
367#endif
[email protected]fafc8a422008-11-07 17:53:09368
369 if (remove_nodes) {
370 for (size_t i = 0; i < nodes.size(); ++i) {
371 model->Remove(nodes[i]->GetParent(),
372 nodes[i]->GetParent()->IndexOfChild(nodes[i]));
373 }
374 }
375}
376
377void PasteFromClipboard(BookmarkModel* model,
378 BookmarkNode* parent,
379 int index) {
380 if (!parent)
381 return;
382
[email protected]a0368962009-02-24 21:47:16383#if defined(OS_WIN)
[email protected]fafc8a422008-11-07 17:53:09384 IDataObject* data;
385 if (OleGetClipboard(&data) != S_OK)
386 return;
387
388 OSExchangeData data_wrapper(data);
389 BookmarkDragData bookmark_data;
390 if (!bookmark_data.Read(data_wrapper))
391 return;
392
393 if (index == -1)
394 index = parent->GetChildCount();
395 bookmark_utils::CloneDragData(model, bookmark_data.elements, parent, index);
[email protected]a0368962009-02-24 21:47:16396#else
397 // TODO(port): Clipboard integration.
398 NOTIMPLEMENTED();
399#endif
[email protected]fafc8a422008-11-07 17:53:09400}
401
402bool CanPasteFromClipboard(BookmarkNode* node) {
403 if (!node)
404 return false;
405
[email protected]a0368962009-02-24 21:47:16406#if defined(OS_WIN)
[email protected]fafc8a422008-11-07 17:53:09407 IDataObject* data;
408 if (OleGetClipboard(&data) != S_OK)
409 return false;
410
411 OSExchangeData data_wrapper(data);
412 BookmarkDragData bookmark_data;
413 return bookmark_data.Read(data_wrapper);
[email protected]a0368962009-02-24 21:47:16414#else
415 // TODO(port): Clipboard integration.
416 NOTIMPLEMENTED();
417 return false;
418#endif
[email protected]fafc8a422008-11-07 17:53:09419}
420
[email protected]9333f182008-12-09 17:34:17421std::vector<BookmarkNode*> GetMostRecentlyModifiedGroups(
422 BookmarkModel* model,
423 size_t max_count) {
424 std::vector<BookmarkNode*> nodes;
[email protected]992c6252009-05-13 18:54:20425 TreeNodeIterator<BookmarkNode> iterator(model->root_node());
[email protected]9333f182008-12-09 17:34:17426 while (iterator.has_next()) {
427 BookmarkNode* parent = iterator.Next();
428 if (parent->is_folder() && parent->date_group_modified() > base::Time()) {
429 if (max_count == 0) {
430 nodes.push_back(parent);
431 } else {
432 std::vector<BookmarkNode*>::iterator i =
433 std::upper_bound(nodes.begin(), nodes.end(), parent,
434 &MoreRecentlyModified);
435 if (nodes.size() < max_count || i != nodes.end()) {
436 nodes.insert(i, parent);
437 while (nodes.size() > max_count)
438 nodes.pop_back();
439 }
440 }
441 } // else case, the root node, which we don't care about or imported nodes
442 // (which have a time of 0).
443 }
444
445 if (nodes.size() < max_count) {
446 // Add the bookmark bar and other nodes if there is space.
447 if (find(nodes.begin(), nodes.end(), model->GetBookmarkBarNode()) ==
448 nodes.end()) {
449 nodes.push_back(model->GetBookmarkBarNode());
450 }
451
452 if (nodes.size() < max_count &&
453 find(nodes.begin(), nodes.end(), model->other_node()) == nodes.end()) {
454 nodes.push_back(model->other_node());
455 }
456 }
457 return nodes;
458}
459
460void GetMostRecentlyAddedEntries(BookmarkModel* model,
461 size_t count,
462 std::vector<BookmarkNode*>* nodes) {
[email protected]992c6252009-05-13 18:54:20463 TreeNodeIterator<BookmarkNode> iterator(model->root_node());
[email protected]9333f182008-12-09 17:34:17464 while (iterator.has_next()) {
465 BookmarkNode* node = iterator.Next();
466 if (node->is_url()) {
467 std::vector<BookmarkNode*>::iterator insert_position =
468 std::upper_bound(nodes->begin(), nodes->end(), node,
469 &MoreRecentlyAdded);
470 if (nodes->size() < count || insert_position != nodes->end()) {
471 nodes->insert(insert_position, node);
472 while (nodes->size() > count)
473 nodes->pop_back();
474 }
475 }
476 }
477}
478
[email protected]9333f182008-12-09 17:34:17479bool MoreRecentlyAdded(BookmarkNode* n1, BookmarkNode* n2) {
480 return n1->date_added() > n2->date_added();
481}
482
[email protected]cb362ccc2008-12-10 17:22:32483void GetBookmarksContainingText(BookmarkModel* model,
484 const std::wstring& text,
485 size_t max_count,
[email protected]fa5dfaf2009-06-02 22:12:06486 const std::wstring& languages,
[email protected]cb362ccc2008-12-10 17:22:32487 std::vector<BookmarkNode*>* nodes) {
488 std::vector<std::wstring> words;
489 QueryParser parser;
490 parser.ExtractQueryWords(l10n_util::ToLower(text), &words);
491 if (words.empty())
492 return;
493
[email protected]992c6252009-05-13 18:54:20494 TreeNodeIterator<BookmarkNode> iterator(model->root_node());
[email protected]cb362ccc2008-12-10 17:22:32495 while (iterator.has_next()) {
496 BookmarkNode* node = iterator.Next();
[email protected]fa5dfaf2009-06-02 22:12:06497 if (node->is_url() && DoesBookmarkContainWords(node, words, languages)) {
[email protected]cb362ccc2008-12-10 17:22:32498 nodes->push_back(node);
499 if (nodes->size() == max_count)
500 return;
501 }
502 }
503}
504
[email protected]fa5dfaf2009-06-02 22:12:06505bool DoesBookmarkContainText(BookmarkNode* node,
506 const std::wstring& text,
507 const std::wstring& languages) {
[email protected]cb362ccc2008-12-10 17:22:32508 std::vector<std::wstring> words;
509 QueryParser parser;
510 parser.ExtractQueryWords(l10n_util::ToLower(text), &words);
511 if (words.empty())
512 return false;
513
[email protected]fa5dfaf2009-06-02 22:12:06514 return (node->is_url() && DoesBookmarkContainWords(node, words, languages));
[email protected]cb362ccc2008-12-10 17:22:32515}
516
[email protected]140aea052009-05-05 00:35:09517void ApplyEditsWithNoGroupChange(BookmarkModel* model,
518 BookmarkNode* parent,
519 BookmarkNode* node,
520 const std::wstring& new_title,
521 const GURL& new_url,
522 BookmarkEditor::Handler* handler) {
523 BookmarkNode* old_parent = node ? node->GetParent() : NULL;
524 const int old_index = old_parent ? old_parent->IndexOfChild(node) : -1;
525
526 if (!node) {
527 node =
528 model->AddURL(parent, parent->GetChildCount(), new_title, new_url);
529
530 if (handler)
531 handler->NodeCreated(node);
532 return;
533 }
534
535 // If we're not showing the tree we only need to modify the node.
536 if (old_index == -1) {
537 NOTREACHED();
538 return;
539 }
540
541 if (new_url != node->GetURL()) {
542 model->AddURLWithCreationTime(old_parent, old_index, new_title,
543 new_url, node->date_added());
544 model->Remove(old_parent, old_index + 1);
545 } else {
546 model->SetTitle(node, new_title);
547 }
548}
549
550void ApplyEditsWithPossibleGroupChange(BookmarkModel* model,
551 BookmarkNode* new_parent,
552 BookmarkNode* node,
553 const std::wstring& new_title,
554 const GURL& new_url,
555 BookmarkEditor::Handler* handler) {
556 BookmarkNode* old_parent = node ? node->GetParent() : NULL;
557 const int old_index = old_parent ? old_parent->IndexOfChild(node) : -1;
558
559 if (node) {
560 Time date_added = node->date_added();
561 if (new_parent == node->GetParent()) {
562 // The parent is the same.
563 if (new_url != node->GetURL()) {
564 model->Remove(old_parent, old_index);
565 BookmarkNode* new_node =
566 model->AddURL(old_parent, old_index, new_title, new_url);
567 new_node->set_date_added(date_added);
568 } else {
569 model->SetTitle(node, new_title);
570 }
571 } else if (new_url != node->GetURL()) {
572 // The parent and URL changed.
573 model->Remove(old_parent, old_index);
574 BookmarkNode* new_node =
575 model->AddURL(new_parent, new_parent->GetChildCount(), new_title,
576 new_url);
577 new_node->set_date_added(date_added);
578 } else {
579 // The parent and title changed. Move the node and change the title.
580 model->Move(node, new_parent, new_parent->GetChildCount());
581 model->SetTitle(node, new_title);
582 }
583 } else {
584 // We're adding a new URL.
585 node =
586 model->AddURL(new_parent, new_parent->GetChildCount(), new_title,
587 new_url);
588 if (handler)
589 handler->NodeCreated(node);
590 }
591}
592
[email protected]44b2c8852009-03-18 00:57:49593// Formerly in BookmarkBarView
594void ToggleWhenVisible(Profile* profile) {
595 PrefService* prefs = profile->GetPrefs();
596 const bool always_show = !prefs->GetBoolean(prefs::kShowBookmarkBar);
597
598 // The user changed when the bookmark bar is shown, update the preferences.
599 prefs->SetBoolean(prefs::kShowBookmarkBar, always_show);
[email protected]6faa0e0d2009-04-28 06:50:36600 prefs->ScheduleSavePersistentPrefs();
[email protected]44b2c8852009-03-18 00:57:49601
602 // And notify the notification service.
603 Source<Profile> source(profile);
604 NotificationService::current()->Notify(
605 NotificationType::BOOKMARK_BAR_VISIBILITY_PREF_CHANGED,
606 source,
607 NotificationService::NoDetails());
608}
609
610void RegisterUserPrefs(PrefService* prefs) {
611 // Formerly in BookmarkBarView
612 prefs->RegisterBooleanPref(prefs::kShowBookmarkBar, false);
613
614 // Formerly in BookmarkTableView
615 prefs->RegisterIntegerPref(prefs::kBookmarkTableNameWidth1, -1);
616 prefs->RegisterIntegerPref(prefs::kBookmarkTableURLWidth1, -1);
617 prefs->RegisterIntegerPref(prefs::kBookmarkTableNameWidth2, -1);
618 prefs->RegisterIntegerPref(prefs::kBookmarkTableURLWidth2, -1);
619 prefs->RegisterIntegerPref(prefs::kBookmarkTablePathWidth, -1);
620}
621
[email protected]7f856be2008-10-29 23:38:06622} // namespace bookmark_utils