blob: 201b063f6e73778769faabcf0182afde2fc6dc34 [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]a0368962009-02-24 21:47:1615#include "base/basictypes.h"
[email protected]cb362ccc2008-12-10 17:22:3216#include "base/string_util.h"
[email protected]9333f182008-12-09 17:34:1717#include "base/time.h"
[email protected]7f856be2008-10-29 23:38:0618#include "chrome/browser/bookmarks/bookmark_drag_data.h"
19#include "chrome/browser/bookmarks/bookmark_model.h"
20#include "chrome/browser/browser.h"
21#include "chrome/browser/browser_list.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]6f329092009-03-17 04:56:5529#include "chrome/views/controls/tree/tree_node_iterator.h"
[email protected]7f856be2008-10-29 23:38:0630#include "chrome/views/event.h"
[email protected]34ac8f32009-02-22 23:03:2731#include "grit/chromium_strings.h"
32#include "grit/generated_resources.h"
[email protected]7f856be2008-10-29 23:38:0633
[email protected]140aea052009-05-05 00:35:0934using base::Time;
35
[email protected]7f856be2008-10-29 23:38:0636namespace {
37
[email protected]7f856be2008-10-29 23:38:0638// A PageNavigator implementation that creates a new Browser. This is used when
39// opening a url and there is no Browser open. The Browser is created the first
40// time the PageNavigator method is invoked.
41class NewBrowserPageNavigator : public PageNavigator {
42 public:
43 explicit NewBrowserPageNavigator(Profile* profile)
44 : profile_(profile),
45 browser_(NULL) {}
46
47 virtual ~NewBrowserPageNavigator() {
48 if (browser_)
[email protected]15952e462008-11-14 00:29:0549 browser_->window()->Show();
[email protected]7f856be2008-10-29 23:38:0650 }
51
52 Browser* browser() const { return browser_; }
53
54 virtual void OpenURL(const GURL& url,
55 const GURL& referrer,
56 WindowOpenDisposition disposition,
57 PageTransition::Type transition) {
58 if (!browser_) {
59 Profile* profile = (disposition == OFF_THE_RECORD) ?
60 profile_->GetOffTheRecordProfile() : profile_;
[email protected]15952e462008-11-14 00:29:0561 browser_ = Browser::Create(profile);
[email protected]7f856be2008-10-29 23:38:0662 // Always open the first tab in the foreground.
63 disposition = NEW_FOREGROUND_TAB;
64 }
[email protected]e0c7c262009-04-23 23:09:4365 browser_->OpenURL(url, referrer, NEW_FOREGROUND_TAB, transition);
[email protected]7f856be2008-10-29 23:38:0666 }
67
68 private:
69 Profile* profile_;
70 Browser* browser_;
71
72 DISALLOW_COPY_AND_ASSIGN(NewBrowserPageNavigator);
73};
74
75void CloneDragDataImpl(BookmarkModel* model,
76 const BookmarkDragData::Element& element,
77 BookmarkNode* parent,
78 int index_to_add_at) {
79 if (element.is_url) {
80 model->AddURL(parent, index_to_add_at, element.title, element.url);
81 } else {
82 BookmarkNode* new_folder = model->AddGroup(parent, index_to_add_at,
83 element.title);
84 for (int i = 0; i < static_cast<int>(element.children.size()); ++i)
85 CloneDragDataImpl(model, element.children[i], new_folder, i);
86 }
87}
88
89// Returns the number of descendants of node that are of type url.
90int DescendantURLCount(BookmarkNode* node) {
91 int result = 0;
92 for (int i = 0; i < node->GetChildCount(); ++i) {
93 BookmarkNode* child = node->GetChild(i);
94 if (child->is_url())
95 result++;
96 else
97 result += DescendantURLCount(child);
98 }
99 return result;
100}
101
102// Implementation of OpenAll. Opens all nodes of type URL and recurses for
103// groups. |navigator| is the PageNavigator used to open URLs. After the first
104// url is opened |opened_url| is set to true and |navigator| is set to the
105// PageNavigator of the last active tab. This is done to handle a window
106// disposition of new window, in which case we want subsequent tabs to open in
107// that window.
108void OpenAllImpl(BookmarkNode* node,
109 WindowOpenDisposition initial_disposition,
110 PageNavigator** navigator,
111 bool* opened_url) {
112 if (node->is_url()) {
113 WindowOpenDisposition disposition;
114 if (*opened_url)
115 disposition = NEW_BACKGROUND_TAB;
116 else
117 disposition = initial_disposition;
118 (*navigator)->OpenURL(node->GetURL(), GURL(), disposition,
119 PageTransition::AUTO_BOOKMARK);
120 if (!*opened_url) {
121 *opened_url = true;
122 // We opened the first URL which may have opened a new window or clobbered
123 // the current page, reset the navigator just to be sure.
124 Browser* new_browser = BrowserList::GetLastActive();
125 if (new_browser) {
126 TabContents* current_tab = new_browser->GetSelectedTabContents();
127 DCHECK(new_browser && current_tab);
128 if (new_browser && current_tab)
129 *navigator = current_tab;
130 } // else, new_browser == NULL, which happens during testing.
131 }
132 } else {
133 // Group, recurse through children.
134 for (int i = 0; i < node->GetChildCount(); ++i) {
135 OpenAllImpl(node->GetChild(i), initial_disposition, navigator,
136 opened_url);
137 }
138 }
139}
140
[email protected]d3216442009-03-05 21:07:27141bool ShouldOpenAll(gfx::NativeWindow parent,
142 const std::vector<BookmarkNode*>& nodes) {
[email protected]7f856be2008-10-29 23:38:06143 int descendant_count = 0;
144 for (size_t i = 0; i < nodes.size(); ++i)
145 descendant_count += DescendantURLCount(nodes[i]);
[email protected]f785ad12008-11-19 23:01:28146 if (descendant_count < bookmark_utils::num_urls_before_prompting)
[email protected]7f856be2008-10-29 23:38:06147 return true;
148
149 std::wstring message =
150 l10n_util::GetStringF(IDS_BOOKMARK_BAR_SHOULD_OPEN_ALL,
151 IntToWString(descendant_count));
[email protected]a0368962009-02-24 21:47:16152#if defined(OS_WIN)
[email protected]7f856be2008-10-29 23:38:06153 return MessageBox(parent, message.c_str(),
154 l10n_util::GetString(IDS_PRODUCT_NAME).c_str(),
155 MB_YESNO | MB_ICONWARNING | MB_TOPMOST) == IDYES;
[email protected]a0368962009-02-24 21:47:16156#else
157 // TODO(port): Display a dialog prompt.
158 NOTIMPLEMENTED();
159 return true;
160#endif
[email protected]7f856be2008-10-29 23:38:06161}
162
[email protected]9333f182008-12-09 17:34:17163// Comparison function that compares based on date modified of the two nodes.
164bool MoreRecentlyModified(BookmarkNode* n1, BookmarkNode* n2) {
165 return n1->date_group_modified() > n2->date_group_modified();
166}
167
[email protected]cb362ccc2008-12-10 17:22:32168// Returns true if |text| contains each string in |words|. This is used when
169// searching for bookmarks.
170bool DoesBookmarkTextContainWords(const std::wstring& text,
171 const std::vector<std::wstring>& words) {
172 for (size_t i = 0; i < words.size(); ++i) {
173 if (text.find(words[i]) == std::wstring::npos)
174 return false;
175 }
176 return true;
177}
178
179// Returns true if |node|s title or url contains the strings in |words|.
180bool DoesBookmarkContainWords(BookmarkNode* node,
181 const std::vector<std::wstring>& words) {
182 return
183 DoesBookmarkTextContainWords(
184 l10n_util::ToLower(node->GetTitle()), words) ||
185 DoesBookmarkTextContainWords(UTF8ToWide(node->GetURL().spec()), words);
186}
187
[email protected]7f856be2008-10-29 23:38:06188} // namespace
189
190namespace bookmark_utils {
191
[email protected]f785ad12008-11-19 23:01:28192int num_urls_before_prompting = 15;
193
[email protected]f28cbb72008-11-04 19:29:08194int PreferredDropOperation(int source_operations, int operations) {
195 int common_ops = (source_operations & operations);
[email protected]7f856be2008-10-29 23:38:06196 if (!common_ops)
197 return 0;
198 if (DragDropTypes::DRAG_COPY & common_ops)
199 return DragDropTypes::DRAG_COPY;
200 if (DragDropTypes::DRAG_LINK & common_ops)
201 return DragDropTypes::DRAG_LINK;
202 if (DragDropTypes::DRAG_MOVE & common_ops)
203 return DragDropTypes::DRAG_MOVE;
204 return DragDropTypes::DRAG_NONE;
205}
206
[email protected]7aa4c002009-03-12 19:10:22207int BookmarkDragOperation(BookmarkNode* node) {
208 if (node->is_url()) {
209 return DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_MOVE |
210 DragDropTypes::DRAG_LINK;
211 }
212 return DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_MOVE;
213}
214
215int BookmarkDropOperation(Profile* profile,
216 const views::DropTargetEvent& event,
217 const BookmarkDragData& data,
218 BookmarkNode* parent,
219 int index) {
220 if (data.IsFromProfile(profile) && data.size() > 1)
221 // Currently only accept one dragged node at a time.
222 return DragDropTypes::DRAG_NONE;
223
224 if (!bookmark_utils::IsValidDropLocation(profile, data, parent, index))
225 return DragDropTypes::DRAG_NONE;
226
227 if (data.GetFirstNode(profile)) {
228 // User is dragging from this profile: move.
229 return DragDropTypes::DRAG_MOVE;
230 }
231 // User is dragging from another app, copy.
232 return PreferredDropOperation(event.GetSourceOperations(),
233 DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_LINK);
234}
235
236int PerformBookmarkDrop(Profile* profile,
237 const BookmarkDragData& data,
238 BookmarkNode* parent_node,
239 int index) {
240 BookmarkNode* dragged_node = data.GetFirstNode(profile);
241 BookmarkModel* model = profile->GetBookmarkModel();
242 if (dragged_node) {
243 // Drag from same profile, do a move.
244 model->Move(dragged_node, parent_node, index);
245 return DragDropTypes::DRAG_MOVE;
246 } else if (data.has_single_url()) {
247 // New URL, add it at the specified location.
248 std::wstring title = data.elements[0].title;
249 if (title.empty()) {
250 // No title, use the host.
251 title = UTF8ToWide(data.elements[0].url.host());
252 if (title.empty())
253 title = l10n_util::GetString(IDS_BOOMARK_BAR_UNKNOWN_DRAG_TITLE);
254 }
255 model->AddURL(parent_node, index, title, data.elements[0].url);
256 return DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_LINK;
257 } else {
258 // Dropping a group from different profile. Always accept.
259 bookmark_utils::CloneDragData(model, data.elements, parent_node, index);
260 return DragDropTypes::DRAG_COPY;
261 }
262}
263
[email protected]7f856be2008-10-29 23:38:06264bool IsValidDropLocation(Profile* profile,
265 const BookmarkDragData& data,
266 BookmarkNode* drop_parent,
267 int index) {
268 if (!drop_parent->is_folder()) {
269 NOTREACHED();
270 return false;
271 }
272
273 if (!data.is_valid())
274 return false;
275
276 if (data.IsFromProfile(profile)) {
277 std::vector<BookmarkNode*> nodes = data.GetNodes(profile);
278 for (size_t i = 0; i < nodes.size(); ++i) {
279 // Don't allow the drop if the user is attempting to drop on one of the
280 // nodes being dragged.
281 BookmarkNode* node = nodes[i];
282 int node_index = (drop_parent == node->GetParent()) ?
283 drop_parent->IndexOfChild(nodes[i]) : -1;
284 if (node_index != -1 && (index == node_index || index == node_index + 1))
285 return false;
286
287 // drop_parent can't accept a child that is an ancestor.
288 if (drop_parent->HasAncestor(node))
289 return false;
290 }
291 return true;
292 }
293 // From the same profile, always accept.
294 return true;
295}
296
297void CloneDragData(BookmarkModel* model,
298 const std::vector<BookmarkDragData::Element>& elements,
299 BookmarkNode* parent,
300 int index_to_add_at) {
301 if (!parent->is_folder() || !model) {
302 NOTREACHED();
303 return;
304 }
305 for (size_t i = 0; i < elements.size(); ++i)
306 CloneDragDataImpl(model, elements[i], parent, index_to_add_at + i);
307}
308
[email protected]a0368962009-02-24 21:47:16309void OpenAll(gfx::NativeWindow parent,
[email protected]7f856be2008-10-29 23:38:06310 Profile* profile,
311 PageNavigator* navigator,
312 const std::vector<BookmarkNode*>& nodes,
313 WindowOpenDisposition initial_disposition) {
314 if (!ShouldOpenAll(parent, nodes))
315 return;
316
317 NewBrowserPageNavigator navigator_impl(profile);
318 if (!navigator) {
[email protected]f0a51fb52009-03-05 12:46:38319 Browser* browser =
[email protected]299dabd2008-11-19 02:27:16320 BrowserList::FindBrowserWithType(profile, Browser::TYPE_NORMAL);
[email protected]b6f2b9132008-11-17 16:27:51321 if (!browser || !browser->GetSelectedTabContents()) {
[email protected]7f856be2008-10-29 23:38:06322 navigator = &navigator_impl;
[email protected]b6f2b9132008-11-17 16:27:51323 } else {
[email protected]c9938e6d2009-03-13 19:54:11324 if (initial_disposition != NEW_WINDOW &&
325 initial_disposition != OFF_THE_RECORD) {
326 browser->window()->Activate();
327 }
[email protected]7f856be2008-10-29 23:38:06328 navigator = browser->GetSelectedTabContents();
[email protected]b6f2b9132008-11-17 16:27:51329 }
[email protected]7f856be2008-10-29 23:38:06330 }
331
332 bool opened_url = false;
333 for (size_t i = 0; i < nodes.size(); ++i)
334 OpenAllImpl(nodes[i], initial_disposition, &navigator, &opened_url);
335}
336
[email protected]a0368962009-02-24 21:47:16337void OpenAll(gfx::NativeWindow parent,
[email protected]7f856be2008-10-29 23:38:06338 Profile* profile,
339 PageNavigator* navigator,
340 BookmarkNode* node,
341 WindowOpenDisposition initial_disposition) {
342 std::vector<BookmarkNode*> nodes;
343 nodes.push_back(node);
344 OpenAll(parent, profile, navigator, nodes, initial_disposition);
345}
346
[email protected]fafc8a422008-11-07 17:53:09347void CopyToClipboard(BookmarkModel* model,
348 const std::vector<BookmarkNode*>& nodes,
349 bool remove_nodes) {
350 if (nodes.empty())
351 return;
352
[email protected]a0368962009-02-24 21:47:16353#if defined(OS_WIN)
[email protected]fafc8a422008-11-07 17:53:09354 OSExchangeData* data = new OSExchangeData();
355 BookmarkDragData(nodes).Write(NULL, data);
356 OleSetClipboard(data);
357 // OLE takes ownership of OSExchangeData.
[email protected]a0368962009-02-24 21:47:16358#else
359 // TODO(port): Clipboard integration. Don't we have clipboard
360 // implemented somewhere else?
361 NOTIMPLEMENTED();
362#endif
[email protected]fafc8a422008-11-07 17:53:09363
364 if (remove_nodes) {
365 for (size_t i = 0; i < nodes.size(); ++i) {
366 model->Remove(nodes[i]->GetParent(),
367 nodes[i]->GetParent()->IndexOfChild(nodes[i]));
368 }
369 }
370}
371
372void PasteFromClipboard(BookmarkModel* model,
373 BookmarkNode* parent,
374 int index) {
375 if (!parent)
376 return;
377
[email protected]a0368962009-02-24 21:47:16378#if defined(OS_WIN)
[email protected]fafc8a422008-11-07 17:53:09379 IDataObject* data;
380 if (OleGetClipboard(&data) != S_OK)
381 return;
382
383 OSExchangeData data_wrapper(data);
384 BookmarkDragData bookmark_data;
385 if (!bookmark_data.Read(data_wrapper))
386 return;
387
388 if (index == -1)
389 index = parent->GetChildCount();
390 bookmark_utils::CloneDragData(model, bookmark_data.elements, parent, index);
[email protected]a0368962009-02-24 21:47:16391#else
392 // TODO(port): Clipboard integration.
393 NOTIMPLEMENTED();
394#endif
[email protected]fafc8a422008-11-07 17:53:09395}
396
397bool CanPasteFromClipboard(BookmarkNode* node) {
398 if (!node)
399 return false;
400
[email protected]a0368962009-02-24 21:47:16401#if defined(OS_WIN)
[email protected]fafc8a422008-11-07 17:53:09402 IDataObject* data;
403 if (OleGetClipboard(&data) != S_OK)
404 return false;
405
406 OSExchangeData data_wrapper(data);
407 BookmarkDragData bookmark_data;
408 return bookmark_data.Read(data_wrapper);
[email protected]a0368962009-02-24 21:47:16409#else
410 // TODO(port): Clipboard integration.
411 NOTIMPLEMENTED();
412 return false;
413#endif
[email protected]fafc8a422008-11-07 17:53:09414}
415
[email protected]9333f182008-12-09 17:34:17416std::vector<BookmarkNode*> GetMostRecentlyModifiedGroups(
417 BookmarkModel* model,
418 size_t max_count) {
419 std::vector<BookmarkNode*> nodes;
420 views::TreeNodeIterator<BookmarkNode> iterator(model->root_node());
421 while (iterator.has_next()) {
422 BookmarkNode* parent = iterator.Next();
423 if (parent->is_folder() && parent->date_group_modified() > base::Time()) {
424 if (max_count == 0) {
425 nodes.push_back(parent);
426 } else {
427 std::vector<BookmarkNode*>::iterator i =
428 std::upper_bound(nodes.begin(), nodes.end(), parent,
429 &MoreRecentlyModified);
430 if (nodes.size() < max_count || i != nodes.end()) {
431 nodes.insert(i, parent);
432 while (nodes.size() > max_count)
433 nodes.pop_back();
434 }
435 }
436 } // else case, the root node, which we don't care about or imported nodes
437 // (which have a time of 0).
438 }
439
440 if (nodes.size() < max_count) {
441 // Add the bookmark bar and other nodes if there is space.
442 if (find(nodes.begin(), nodes.end(), model->GetBookmarkBarNode()) ==
443 nodes.end()) {
444 nodes.push_back(model->GetBookmarkBarNode());
445 }
446
447 if (nodes.size() < max_count &&
448 find(nodes.begin(), nodes.end(), model->other_node()) == nodes.end()) {
449 nodes.push_back(model->other_node());
450 }
451 }
452 return nodes;
453}
454
455void GetMostRecentlyAddedEntries(BookmarkModel* model,
456 size_t count,
457 std::vector<BookmarkNode*>* nodes) {
458 views::TreeNodeIterator<BookmarkNode> iterator(model->root_node());
459 while (iterator.has_next()) {
460 BookmarkNode* node = iterator.Next();
461 if (node->is_url()) {
462 std::vector<BookmarkNode*>::iterator insert_position =
463 std::upper_bound(nodes->begin(), nodes->end(), node,
464 &MoreRecentlyAdded);
465 if (nodes->size() < count || insert_position != nodes->end()) {
466 nodes->insert(insert_position, node);
467 while (nodes->size() > count)
468 nodes->pop_back();
469 }
470 }
471 }
472}
473
474void GetBookmarksMatchingText(BookmarkModel* model,
475 const std::wstring& text,
476 size_t max_count,
477 std::vector<TitleMatch>* matches) {
478 QueryParser parser;
479 ScopedVector<QueryNode> query_nodes;
480 parser.ParseQuery(text, &query_nodes.get());
481 if (query_nodes.empty())
482 return;
483
484 views::TreeNodeIterator<BookmarkNode> iterator(model->root_node());
485 Snippet::MatchPositions match_position;
486 while (iterator.has_next()) {
487 BookmarkNode* node = iterator.Next();
[email protected]9333f182008-12-09 17:34:17488 if (node->is_url() &&
489 parser.DoesQueryMatch(node->GetTitle(), query_nodes.get(),
490 &match_position)) {
491 matches->push_back(TitleMatch());
492 matches->back().node = node;
493 matches->back().match_positions.swap(match_position);
494 if (matches->size() == max_count)
495 break;
496 }
497 }
498}
499
[email protected]9333f182008-12-09 17:34:17500bool MoreRecentlyAdded(BookmarkNode* n1, BookmarkNode* n2) {
501 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,
507 std::vector<BookmarkNode*>* nodes) {
508 std::vector<std::wstring> words;
509 QueryParser parser;
510 parser.ExtractQueryWords(l10n_util::ToLower(text), &words);
511 if (words.empty())
512 return;
513
514 views::TreeNodeIterator<BookmarkNode> iterator(model->root_node());
515 while (iterator.has_next()) {
516 BookmarkNode* node = iterator.Next();
517 if (node->is_url() && DoesBookmarkContainWords(node, words)) {
518 nodes->push_back(node);
519 if (nodes->size() == max_count)
520 return;
521 }
522 }
523}
524
525bool DoesBookmarkContainText(BookmarkNode* node, const std::wstring& text) {
526 std::vector<std::wstring> words;
527 QueryParser parser;
528 parser.ExtractQueryWords(l10n_util::ToLower(text), &words);
529 if (words.empty())
530 return false;
531
532 return (node->is_url() && DoesBookmarkContainWords(node, words));
533}
534
[email protected]140aea052009-05-05 00:35:09535void ApplyEditsWithNoGroupChange(BookmarkModel* model,
536 BookmarkNode* parent,
537 BookmarkNode* node,
538 const std::wstring& new_title,
539 const GURL& new_url,
540 BookmarkEditor::Handler* handler) {
541 BookmarkNode* old_parent = node ? node->GetParent() : NULL;
542 const int old_index = old_parent ? old_parent->IndexOfChild(node) : -1;
543
544 if (!node) {
545 node =
546 model->AddURL(parent, parent->GetChildCount(), new_title, new_url);
547
548 if (handler)
549 handler->NodeCreated(node);
550 return;
551 }
552
553 // If we're not showing the tree we only need to modify the node.
554 if (old_index == -1) {
555 NOTREACHED();
556 return;
557 }
558
559 if (new_url != node->GetURL()) {
560 model->AddURLWithCreationTime(old_parent, old_index, new_title,
561 new_url, node->date_added());
562 model->Remove(old_parent, old_index + 1);
563 } else {
564 model->SetTitle(node, new_title);
565 }
566}
567
568void ApplyEditsWithPossibleGroupChange(BookmarkModel* model,
569 BookmarkNode* new_parent,
570 BookmarkNode* node,
571 const std::wstring& new_title,
572 const GURL& new_url,
573 BookmarkEditor::Handler* handler) {
574 BookmarkNode* old_parent = node ? node->GetParent() : NULL;
575 const int old_index = old_parent ? old_parent->IndexOfChild(node) : -1;
576
577 if (node) {
578 Time date_added = node->date_added();
579 if (new_parent == node->GetParent()) {
580 // The parent is the same.
581 if (new_url != node->GetURL()) {
582 model->Remove(old_parent, old_index);
583 BookmarkNode* new_node =
584 model->AddURL(old_parent, old_index, new_title, new_url);
585 new_node->set_date_added(date_added);
586 } else {
587 model->SetTitle(node, new_title);
588 }
589 } else if (new_url != node->GetURL()) {
590 // The parent and URL changed.
591 model->Remove(old_parent, old_index);
592 BookmarkNode* new_node =
593 model->AddURL(new_parent, new_parent->GetChildCount(), new_title,
594 new_url);
595 new_node->set_date_added(date_added);
596 } else {
597 // The parent and title changed. Move the node and change the title.
598 model->Move(node, new_parent, new_parent->GetChildCount());
599 model->SetTitle(node, new_title);
600 }
601 } else {
602 // We're adding a new URL.
603 node =
604 model->AddURL(new_parent, new_parent->GetChildCount(), new_title,
605 new_url);
606 if (handler)
607 handler->NodeCreated(node);
608 }
609}
610
[email protected]44b2c8852009-03-18 00:57:49611// Formerly in BookmarkBarView
612void ToggleWhenVisible(Profile* profile) {
613 PrefService* prefs = profile->GetPrefs();
614 const bool always_show = !prefs->GetBoolean(prefs::kShowBookmarkBar);
615
616 // The user changed when the bookmark bar is shown, update the preferences.
617 prefs->SetBoolean(prefs::kShowBookmarkBar, always_show);
[email protected]6faa0e0d2009-04-28 06:50:36618 prefs->ScheduleSavePersistentPrefs();
[email protected]44b2c8852009-03-18 00:57:49619
620 // And notify the notification service.
621 Source<Profile> source(profile);
622 NotificationService::current()->Notify(
623 NotificationType::BOOKMARK_BAR_VISIBILITY_PREF_CHANGED,
624 source,
625 NotificationService::NoDetails());
626}
627
628void 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]7f856be2008-10-29 23:38:06640} // namespace bookmark_utils