blob: 88df062d3e345767d7e2282dc55111860fc52111 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/bookmarks/recently_used_folders_combo_model.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/bookmarks/bookmark_utils.h"
#include "content/public/browser/user_metrics.h"
#include "grit/generated_resources.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/models/combobox_model_observer.h"
namespace {
// Max number of most recently used folders.
const size_t kMaxMRUFolders = 5;
} // namespace
struct RecentlyUsedFoldersComboModel::Item {
enum Type {
TYPE_NODE,
TYPE_SEPARATOR,
TYPE_CHOOSE_ANOTHER_FOLDER
};
Item(const BookmarkNode* node, Type type);
~Item();
bool operator==(const Item& item) const;
const BookmarkNode* node;
Type type;
};
RecentlyUsedFoldersComboModel::Item::Item(const BookmarkNode* node,
Type type)
: node(node),
type(type) {
}
RecentlyUsedFoldersComboModel::Item::~Item() {}
bool RecentlyUsedFoldersComboModel::Item::operator==(const Item& item) const {
return item.node == node && item.type == type;
}
RecentlyUsedFoldersComboModel::RecentlyUsedFoldersComboModel(
BookmarkModel* model,
const BookmarkNode* node)
: bookmark_model_(model),
node_parent_index_(0) {
bookmark_model_->AddObserver(this);
// Use + 2 to account for bookmark bar and other node.
std::vector<const BookmarkNode*> nodes =
bookmark_utils::GetMostRecentlyModifiedFolders(model, kMaxMRUFolders + 2);
for (size_t i = 0; i < nodes.size(); ++i)
items_.push_back(Item(nodes[i], Item::TYPE_NODE));
// We special case the placement of these, so remove them from the list, then
// fix up the order.
RemoveNode(model->bookmark_bar_node());
RemoveNode(model->mobile_node());
RemoveNode(model->other_node());
RemoveNode(node->parent());
// Make the parent the first item, unless it's a permanent node, which is
// added below.
if (!model->is_permanent_node(node->parent()))
items_.insert(items_.begin(), Item(node->parent(), Item::TYPE_NODE));
// Make sure we only have kMaxMRUFolders in the first chunk.
if (items_.size() > kMaxMRUFolders)
items_.erase(items_.begin() + kMaxMRUFolders, items_.end());
// And put the bookmark bar and other nodes at the end of the list.
items_.push_back(Item(model->bookmark_bar_node(), Item::TYPE_NODE));
items_.push_back(Item(model->other_node(), Item::TYPE_NODE));
if (model->mobile_node()->IsVisible())
items_.push_back(Item(model->mobile_node(), Item::TYPE_NODE));
#if defined(USE_AURA) || defined(TOOLKIT_GTK)
items_.push_back(Item(NULL, Item::TYPE_SEPARATOR));
#endif
items_.push_back(Item(NULL, Item::TYPE_CHOOSE_ANOTHER_FOLDER));
std::vector<Item>::iterator it = std::find(items_.begin(),
items_.end(),
Item(node->parent(),
Item::TYPE_NODE));
node_parent_index_ = static_cast<int>(it - items_.begin());
}
RecentlyUsedFoldersComboModel::~RecentlyUsedFoldersComboModel() {
bookmark_model_->RemoveObserver(this);
}
int RecentlyUsedFoldersComboModel::GetItemCount() const {
return static_cast<int>(items_.size());
}
string16 RecentlyUsedFoldersComboModel::GetItemAt(int index) {
switch (items_[index].type) {
case Item::TYPE_NODE:
return items_[index].node->GetTitle();
case Item::TYPE_SEPARATOR:
// This function should not be called for separators.
NOTREACHED();
return string16();
case Item::TYPE_CHOOSE_ANOTHER_FOLDER:
return l10n_util::GetStringUTF16(
IDS_BOOKMARK_BUBBLE_CHOOSER_ANOTHER_FOLDER);
}
NOTREACHED();
return string16();
}
bool RecentlyUsedFoldersComboModel::IsItemSeparatorAt(int index) {
return items_[index].type == Item::TYPE_SEPARATOR;
}
int RecentlyUsedFoldersComboModel::GetDefaultIndex() const {
return node_parent_index_;
}
void RecentlyUsedFoldersComboModel::AddObserver(
ui::ComboboxModelObserver* observer) {
observers_.AddObserver(observer);
}
void RecentlyUsedFoldersComboModel::RemoveObserver(
ui::ComboboxModelObserver* observer) {
observers_.RemoveObserver(observer);
}
void RecentlyUsedFoldersComboModel::Loaded(BookmarkModel* model,
bool ids_reassigned) {
}
void RecentlyUsedFoldersComboModel::BookmarkModelBeingDeleted(
BookmarkModel* model) {
}
void RecentlyUsedFoldersComboModel::BookmarkNodeMoved(
BookmarkModel* model,
const BookmarkNode* old_parent,
int old_index,
const BookmarkNode* new_parent,
int new_index) {
}
void RecentlyUsedFoldersComboModel::BookmarkNodeAdded(
BookmarkModel* model,
const BookmarkNode* parent,
int index) {
}
void RecentlyUsedFoldersComboModel::OnWillRemoveBookmarks(
BookmarkModel* model,
const BookmarkNode* parent,
int old_index,
const BookmarkNode* node) {
// Changing is rare enough that we don't attempt to readjust the contents.
// Update |items_| so we aren't left pointing to a deleted node.
bool changed = false;
for (std::vector<Item>::iterator i = items_.begin();
i != items_.end();) {
if (i->type == Item::TYPE_NODE && i->node->HasAncestor(node)) {
i = items_.erase(i);
changed = true;
} else {
++i;
}
}
if (changed)
FOR_EACH_OBSERVER(ui::ComboboxModelObserver, observers_, OnModelChanged());
}
void RecentlyUsedFoldersComboModel::BookmarkNodeRemoved(
BookmarkModel* model,
const BookmarkNode* parent,
int old_index,
const BookmarkNode* node) {
}
void RecentlyUsedFoldersComboModel::BookmarkNodeChanged(
BookmarkModel* model,
const BookmarkNode* node) {
}
void RecentlyUsedFoldersComboModel::BookmarkNodeFaviconChanged(
BookmarkModel* model,
const BookmarkNode* node) {
}
void RecentlyUsedFoldersComboModel::BookmarkNodeChildrenReordered(
BookmarkModel* model,
const BookmarkNode* node) {
}
void RecentlyUsedFoldersComboModel::BookmarkAllNodesRemoved(
BookmarkModel* model) {
// Changing is rare enough that we don't attempt to readjust the contents.
// Update |items_| so we aren't left pointing to a deleted node.
bool changed = false;
for (std::vector<Item>::iterator i = items_.begin();
i != items_.end();) {
if (i->type == Item::TYPE_NODE &&
!bookmark_model_->is_permanent_node(i->node)) {
i = items_.erase(i);
changed = true;
} else {
++i;
}
}
if (changed)
FOR_EACH_OBSERVER(ui::ComboboxModelObserver, observers_, OnModelChanged());
}
void RecentlyUsedFoldersComboModel::MaybeChangeParent(
const BookmarkNode* node,
int selected_index) {
if (items_[selected_index].type != Item::TYPE_NODE)
return;
const BookmarkNode* new_parent = GetNodeAt(selected_index);
if (new_parent != node->parent()) {
content::RecordAction(
content::UserMetricsAction("BookmarkBubble_ChangeParent"));
bookmark_model_->Move(node, new_parent, new_parent->child_count());
}
}
const BookmarkNode* RecentlyUsedFoldersComboModel::GetNodeAt(int index) {
if (index < 0 || index >= static_cast<int>(items_.size()))
return NULL;
return items_[index].node;
}
void RecentlyUsedFoldersComboModel::RemoveNode(const BookmarkNode* node) {
std::vector<Item>::iterator it = std::find(items_.begin(),
items_.end(),
Item(node, Item::TYPE_NODE));
if (it != items_.end())
items_.erase(it);
}