| Index: chrome/browser/importer/profile_writer.cc
|
| diff --git a/chrome/browser/importer/profile_writer.cc b/chrome/browser/importer/profile_writer.cc
|
| index 6f3d222e5f043c2a0509c9b557a45cf6a32e5982..da6397683ce8ef3c37c5c4d9e37892e019f254e5 100644
|
| --- a/chrome/browser/importer/profile_writer.cc
|
| +++ b/chrome/browser/importer/profile_writer.cc
|
| @@ -4,6 +4,9 @@
|
|
|
| #include "chrome/browser/importer/profile_writer.h"
|
|
|
| +#include <string>
|
| +
|
| +#include "base/string_number_conversions.h"
|
| #include "base/stringprintf.h"
|
| #include "base/threading/thread.h"
|
| #include "base/utf_string_conversions.h"
|
| @@ -16,6 +19,54 @@
|
| #include "chrome/common/pref_names.h"
|
| #include "content/common/notification_service.h"
|
|
|
| +namespace {
|
| +
|
| +// Generates a unique folder name. If |folder_name| is not unique, then this
|
| +// repeatedly tests for '|folder_name| + (i)' until a unique name is found.
|
| +string16 GenerateUniqueFolderName(BookmarkModel* model,
|
| + const string16& folder_name) {
|
| + // Build a set containing the bookmark bar folder names.
|
| + std::set<string16> existing_folder_names;
|
| + const BookmarkNode* bookmark_bar = model->GetBookmarkBarNode();
|
| + for (int i = 0; i < bookmark_bar->child_count(); ++i) {
|
| + const BookmarkNode* node = bookmark_bar->GetChild(i);
|
| + if (node->is_folder())
|
| + existing_folder_names.insert(node->GetTitle());
|
| + }
|
| +
|
| + // If the given name is unique, use it.
|
| + if (existing_folder_names.find(folder_name) == existing_folder_names.end())
|
| + return folder_name;
|
| +
|
| + // Otherwise iterate until we find a unique name.
|
| + for (size_t i = 1; i <= existing_folder_names.size(); ++i) {
|
| + string16 name = folder_name + ASCIIToUTF16(" (") + base::IntToString16(i) +
|
| + ASCIIToUTF16(")");
|
| + if (existing_folder_names.find(name) == existing_folder_names.end())
|
| + return name;
|
| + }
|
| +
|
| + NOTREACHED();
|
| + return folder_name;
|
| +}
|
| +
|
| +// Shows the bookmarks toolbar.
|
| +void ShowBookmarkBar(Profile* profile) {
|
| + PrefService* prefs = profile->GetPrefs();
|
| + // Check whether the bookmark bar is shown in current pref.
|
| + if (!prefs->GetBoolean(prefs::kShowBookmarkBar)) {
|
| + // Set the pref and notify the notification service.
|
| + prefs->SetBoolean(prefs::kShowBookmarkBar, true);
|
| + prefs->ScheduleSavePersistentPrefs();
|
| + Source<Profile> source(profile);
|
| + NotificationService::current()->Notify(
|
| + NotificationType::BOOKMARK_BAR_VISIBILITY_PREF_CHANGED, source,
|
| + NotificationService::NoDetails());
|
| + }
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| ProfileWriter::BookmarkEntry::BookmarkEntry()
|
| : in_toolbar(false),
|
| is_folder(false) {}
|
| @@ -61,72 +112,89 @@ void ProfileWriter::AddHomepage(const GURL& home_page) {
|
| }
|
|
|
| void ProfileWriter::AddBookmarks(const std::vector<BookmarkEntry>& bookmarks,
|
| - const string16& first_folder_name,
|
| - int options) {
|
| + const string16& top_level_folder_name) {
|
| if (bookmarks.empty())
|
| return;
|
|
|
| BookmarkModel* model = profile_->GetBookmarkModel();
|
| DCHECK(model->IsLoaded());
|
|
|
| - bool import_to_bookmark_bar = ((options & IMPORT_TO_BOOKMARK_BAR) != 0);
|
| - string16 real_first_folder = import_to_bookmark_bar ? first_folder_name :
|
| - GenerateUniqueFolderName(model, first_folder_name);
|
| + // If the bookmark bar is currently empty, we should import directly to it.
|
| + // Otherwise, we should import everything to a subfolder.
|
| + const BookmarkNode* bookmark_bar = model->GetBookmarkBarNode();
|
| + bool import_to_top_level = bookmark_bar->child_count() == 0;
|
|
|
| - bool show_bookmark_toolbar = false;
|
| - std::set<const BookmarkNode*> folders_added_to;
|
| + // If the user currently has no bookmarks in the bookmark bar, make sure that
|
| + // at least some of the imported bookmarks end up there. Otherwise, we'll end
|
| + // up with just a single folder containing the imported bookmarks, which makes
|
| + // for unnecessary nesting.
|
| + bool add_all_to_top_level = import_to_top_level;
|
| + for (std::vector<BookmarkEntry>::const_iterator it = bookmarks.begin();
|
| + it != bookmarks.end() && add_all_to_top_level; ++it) {
|
| + if (it->in_toolbar)
|
| + add_all_to_top_level = false;
|
| + }
|
|
|
| model->BeginImportMode();
|
|
|
| - for (std::vector<BookmarkEntry>::const_iterator it = bookmarks.begin();
|
| - it != bookmarks.end(); ++it) {
|
| - // Don't insert this url if it isn't valid.
|
| - if (!it->is_folder && !it->url.is_valid())
|
| + std::set<const BookmarkNode*> folders_added_to;
|
| + const BookmarkNode* top_level_folder = NULL;
|
| + for (std::vector<BookmarkEntry>::const_iterator bookmark = bookmarks.begin();
|
| + bookmark != bookmarks.end(); ++bookmark) {
|
| + // Disregard any bookmarks with invalid urls.
|
| + if (!bookmark->is_folder && !bookmark->url.is_valid())
|
| continue;
|
|
|
| - // We suppose that bookmarks are unique by Title, URL, and Folder. Since
|
| - // checking for uniqueness may not be always the user's intention we have
|
| - // this as an option.
|
| - if (options & ADD_IF_UNIQUE && DoesBookmarkExist(model, *it,
|
| - real_first_folder, import_to_bookmark_bar))
|
| - continue;
|
| + const BookmarkNode* parent = NULL;
|
| + if (import_to_top_level && (add_all_to_top_level || bookmark->in_toolbar)) {
|
| + // Add directly to the bookmarks bar.
|
| + parent = bookmark_bar;
|
| + } else {
|
| + // Add to a folder that will contain all the imported bookmarks not added
|
| + // to the bar. The first time we do so, create the folder.
|
| + if (!top_level_folder) {
|
| + string16 name = GenerateUniqueFolderName(model, top_level_folder_name);
|
| + top_level_folder = model->AddFolder(bookmark_bar,
|
| + bookmark_bar->child_count(),
|
| + name);
|
| + }
|
| + parent = top_level_folder;
|
| + }
|
|
|
| - // Set up folders in BookmarkModel in such a way that path[i] is
|
| - // the subfolder of path[i-1]. Finally they construct a path in the
|
| - // model:
|
| - // path[0] \ path[1] \ ... \ path[size() - 1]
|
| - const BookmarkNode* parent =
|
| - (it->in_toolbar ? model->GetBookmarkBarNode() : model->other_node());
|
| - for (std::vector<string16>::const_iterator i = it->path.begin();
|
| - i != it->path.end(); ++i) {
|
| - const BookmarkNode* child = NULL;
|
| - const string16& folder_name = (!import_to_bookmark_bar &&
|
| - !it->in_toolbar && (i == it->path.begin())) ? real_first_folder : *i;
|
| + // Ensure any enclosing folders are present in the model. The bookmark's
|
| + // enclosing folder structure should be
|
| + // path[0] > path[1] > ... > path[size() - 1]
|
| + for (std::vector<string16>::const_iterator folder_name =
|
| + bookmark->path.begin();
|
| + folder_name != bookmark->path.end(); ++folder_name) {
|
| + if (bookmark->in_toolbar && parent == bookmark_bar &&
|
| + folder_name == bookmark->path.begin()) {
|
| + // If we're importing directly to the bookmarks bar, skip over the
|
| + // folder named "Bookmarks Toolbar" (or any non-Firefox equivalent).
|
| + continue;
|
| + }
|
|
|
| + const BookmarkNode* child = NULL;
|
| for (int index = 0; index < parent->child_count(); ++index) {
|
| const BookmarkNode* node = parent->GetChild(index);
|
| - if (node->is_folder() && node->GetTitle() == folder_name) {
|
| + if (node->is_folder() && node->GetTitle() == *folder_name) {
|
| child = node;
|
| break;
|
| }
|
| }
|
| if (!child)
|
| - child = model->AddFolder(parent, parent->child_count(), folder_name);
|
| + child = model->AddFolder(parent, parent->child_count(), *folder_name);
|
| parent = child;
|
| }
|
|
|
| folders_added_to.insert(parent);
|
| - if (it->is_folder) {
|
| - model->AddFolder(parent, parent->child_count(), it->title);
|
| + if (bookmark->is_folder) {
|
| + model->AddFolder(parent, parent->child_count(), bookmark->title);
|
| } else {
|
| model->AddURLWithCreationTime(parent, parent->child_count(),
|
| - it->title, it->url, it->creation_time);
|
| + bookmark->title, bookmark->url,
|
| + bookmark->creation_time);
|
| }
|
| -
|
| - // If some items are put into toolbar, it looks like the user was using
|
| - // it in their last browser. We turn on the bookmarks toolbar.
|
| - if (it->in_toolbar)
|
| - show_bookmark_toolbar = true;
|
| }
|
|
|
| // In order to keep the imported-to folders from appearing in the 'recently
|
| @@ -139,8 +207,9 @@ void ProfileWriter::AddBookmarks(const std::vector<BookmarkEntry>& bookmarks,
|
|
|
| model->EndImportMode();
|
|
|
| - if (show_bookmark_toolbar && !(options & BOOKMARK_BAR_DISABLED))
|
| - ShowBookmarkBar();
|
| + // If the user was previously using a toolbar, we should show the bar.
|
| + if (import_to_top_level && !add_all_to_top_level)
|
| + ShowBookmarkBar(profile_);
|
| }
|
|
|
| void ProfileWriter::AddFavicons(
|
| @@ -265,94 +334,4 @@ void ProfileWriter::AddKeywords(const std::vector<TemplateURL*>& template_urls,
|
| }
|
| }
|
|
|
| -void ProfileWriter::ShowBookmarkBar() {
|
| - DCHECK(profile_);
|
| -
|
| - PrefService* prefs = profile_->GetPrefs();
|
| - // Check whether the bookmark bar is shown in current pref.
|
| - if (!prefs->GetBoolean(prefs::kShowBookmarkBar)) {
|
| - // Set the pref and notify the notification service.
|
| - prefs->SetBoolean(prefs::kShowBookmarkBar, true);
|
| - prefs->ScheduleSavePersistentPrefs();
|
| - Source<Profile> source(profile_);
|
| - NotificationService::current()->Notify(
|
| - NotificationType::BOOKMARK_BAR_VISIBILITY_PREF_CHANGED, source,
|
| - NotificationService::NoDetails());
|
| - }
|
| -}
|
| -
|
| ProfileWriter::~ProfileWriter() {}
|
| -
|
| -string16 ProfileWriter::GenerateUniqueFolderName(
|
| - BookmarkModel* model,
|
| - const string16& folder_name) {
|
| - // Build a set containing the folder names of the other folder.
|
| - std::set<string16> other_folder_names;
|
| - const BookmarkNode* other = model->other_node();
|
| -
|
| - for (int i = 0, child_count = other->child_count(); i < child_count; ++i) {
|
| - const BookmarkNode* node = other->GetChild(i);
|
| - if (node->is_folder())
|
| - other_folder_names.insert(node->GetTitle());
|
| - }
|
| -
|
| - if (other_folder_names.find(folder_name) == other_folder_names.end())
|
| - return folder_name; // Name is unique, use it.
|
| -
|
| - // Otherwise iterate until we find a unique name.
|
| - for (int i = 1; i < 100; ++i) {
|
| - string16 name = folder_name + UTF8ToUTF16(base::StringPrintf(" (%d)", i));
|
| - if (other_folder_names.find(name) == other_folder_names.end())
|
| - return name;
|
| - }
|
| -
|
| - return folder_name;
|
| -}
|
| -
|
| -bool ProfileWriter::DoesBookmarkExist(
|
| - BookmarkModel* model,
|
| - const BookmarkEntry& entry,
|
| - const string16& first_folder_name,
|
| - bool import_to_bookmark_bar) {
|
| - std::vector<const BookmarkNode*> nodes_with_same_url;
|
| - model->GetNodesByURL(entry.url, &nodes_with_same_url);
|
| - if (nodes_with_same_url.empty())
|
| - return false;
|
| -
|
| - for (size_t i = 0; i < nodes_with_same_url.size(); ++i) {
|
| - const BookmarkNode* node = nodes_with_same_url[i];
|
| - if (entry.title != node->GetTitle())
|
| - continue;
|
| -
|
| - // Does the path match?
|
| - bool found_match = true;
|
| - const BookmarkNode* parent = node->parent();
|
| - for (std::vector<string16>::const_reverse_iterator path_it =
|
| - entry.path.rbegin();
|
| - (path_it != entry.path.rend()) && found_match; ++path_it) {
|
| - const string16& folder_name =
|
| - (!import_to_bookmark_bar && path_it + 1 == entry.path.rend()) ?
|
| - first_folder_name : *path_it;
|
| - if (NULL == parent || *path_it != folder_name)
|
| - found_match = false;
|
| - else
|
| - parent = parent->parent();
|
| - }
|
| -
|
| - // We need a post test to differentiate checks such as
|
| - // /home/hello and /hello. The parent should either by the other folder
|
| - // node, or the bookmarks bar, depending upon import_to_bookmark_bar and
|
| - // entry.in_toolbar.
|
| - if (found_match &&
|
| - ((import_to_bookmark_bar && entry.in_toolbar && parent !=
|
| - model->GetBookmarkBarNode()) ||
|
| - ((!import_to_bookmark_bar || !entry.in_toolbar) &&
|
| - parent != model->other_node()))) {
|
| - found_match = false;
|
| - }
|
| -
|
| - if (found_match)
|
| - return true; // Found a match with the same url path and title.
|
| - }
|
| - return false;
|
| -}
|
|
|