Home | History | Annotate | Download | only in bookmarks
      1 // Copyright (c) 2012 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/ui/bookmarks/recently_used_folders_combo_model.h"
      6 
      7 #include "components/bookmarks/browser/bookmark_model.h"
      8 #include "components/bookmarks/browser/bookmark_utils.h"
      9 #include "content/public/browser/user_metrics.h"
     10 #include "grit/generated_resources.h"
     11 #include "ui/base/l10n/l10n_util.h"
     12 #include "ui/base/models/combobox_model_observer.h"
     13 
     14 namespace {
     15 
     16 // Max number of most recently used folders.
     17 const size_t kMaxMRUFolders = 5;
     18 
     19 }  // namespace
     20 
     21 struct RecentlyUsedFoldersComboModel::Item {
     22   enum Type {
     23     TYPE_NODE,
     24     TYPE_SEPARATOR,
     25     TYPE_CHOOSE_ANOTHER_FOLDER
     26   };
     27 
     28   Item(const BookmarkNode* node, Type type);
     29   ~Item();
     30 
     31   bool operator==(const Item& item) const;
     32 
     33   const BookmarkNode* node;
     34   Type type;
     35 };
     36 
     37 RecentlyUsedFoldersComboModel::Item::Item(const BookmarkNode* node,
     38                                           Type type)
     39     : node(node),
     40       type(type) {
     41 }
     42 
     43 RecentlyUsedFoldersComboModel::Item::~Item() {}
     44 
     45 bool RecentlyUsedFoldersComboModel::Item::operator==(const Item& item) const {
     46   return item.node == node && item.type == type;
     47 }
     48 
     49 RecentlyUsedFoldersComboModel::RecentlyUsedFoldersComboModel(
     50     BookmarkModel* model,
     51     const BookmarkNode* node)
     52     : bookmark_model_(model),
     53       node_parent_index_(0) {
     54   bookmark_model_->AddObserver(this);
     55   // Use + 2 to account for bookmark bar and other node.
     56   std::vector<const BookmarkNode*> nodes =
     57       bookmark_utils::GetMostRecentlyModifiedUserFolders(model,
     58                                                          kMaxMRUFolders + 2);
     59 
     60   for (size_t i = 0; i < nodes.size(); ++i)
     61     items_.push_back(Item(nodes[i], Item::TYPE_NODE));
     62 
     63   // We special case the placement of these, so remove them from the list, then
     64   // fix up the order.
     65   RemoveNode(model->bookmark_bar_node());
     66   RemoveNode(model->mobile_node());
     67   RemoveNode(model->other_node());
     68   RemoveNode(node->parent());
     69 
     70   // Make the parent the first item, unless it's a permanent node, which is
     71   // added below.
     72   if (!model->is_permanent_node(node->parent()))
     73     items_.insert(items_.begin(), Item(node->parent(), Item::TYPE_NODE));
     74 
     75   // Make sure we only have kMaxMRUFolders in the first chunk.
     76   if (items_.size() > kMaxMRUFolders)
     77     items_.erase(items_.begin() + kMaxMRUFolders, items_.end());
     78 
     79   // And put the bookmark bar and other nodes at the end of the list.
     80   items_.push_back(Item(model->bookmark_bar_node(), Item::TYPE_NODE));
     81   items_.push_back(Item(model->other_node(), Item::TYPE_NODE));
     82   if (model->mobile_node()->IsVisible())
     83     items_.push_back(Item(model->mobile_node(), Item::TYPE_NODE));
     84   items_.push_back(Item(NULL, Item::TYPE_SEPARATOR));
     85   items_.push_back(Item(NULL, Item::TYPE_CHOOSE_ANOTHER_FOLDER));
     86 
     87   std::vector<Item>::iterator it = std::find(items_.begin(),
     88                                              items_.end(),
     89                                              Item(node->parent(),
     90                                                   Item::TYPE_NODE));
     91   node_parent_index_ = static_cast<int>(it - items_.begin());
     92 }
     93 
     94 RecentlyUsedFoldersComboModel::~RecentlyUsedFoldersComboModel() {
     95   bookmark_model_->RemoveObserver(this);
     96 }
     97 
     98 int RecentlyUsedFoldersComboModel::GetItemCount() const {
     99   return static_cast<int>(items_.size());
    100 }
    101 
    102 base::string16 RecentlyUsedFoldersComboModel::GetItemAt(int index) {
    103   switch (items_[index].type) {
    104     case Item::TYPE_NODE:
    105       return items_[index].node->GetTitle();
    106     case Item::TYPE_SEPARATOR:
    107       // This function should not be called for separators.
    108       NOTREACHED();
    109       return base::string16();
    110     case Item::TYPE_CHOOSE_ANOTHER_FOLDER:
    111       return l10n_util::GetStringUTF16(
    112           IDS_BOOKMARK_BUBBLE_CHOOSER_ANOTHER_FOLDER);
    113   }
    114   NOTREACHED();
    115   return base::string16();
    116 }
    117 
    118 bool RecentlyUsedFoldersComboModel::IsItemSeparatorAt(int index) {
    119   return items_[index].type == Item::TYPE_SEPARATOR;
    120 }
    121 
    122 int RecentlyUsedFoldersComboModel::GetDefaultIndex() const {
    123   return node_parent_index_;
    124 }
    125 
    126 void RecentlyUsedFoldersComboModel::AddObserver(
    127     ui::ComboboxModelObserver* observer) {
    128   observers_.AddObserver(observer);
    129 }
    130 
    131 void RecentlyUsedFoldersComboModel::RemoveObserver(
    132     ui::ComboboxModelObserver* observer) {
    133   observers_.RemoveObserver(observer);
    134 }
    135 
    136 void RecentlyUsedFoldersComboModel::BookmarkModelLoaded(BookmarkModel* model,
    137                                                         bool ids_reassigned) {}
    138 
    139 void RecentlyUsedFoldersComboModel::BookmarkModelBeingDeleted(
    140     BookmarkModel* model) {
    141 }
    142 
    143 void RecentlyUsedFoldersComboModel::BookmarkNodeMoved(
    144     BookmarkModel* model,
    145     const BookmarkNode* old_parent,
    146     int old_index,
    147     const BookmarkNode* new_parent,
    148     int new_index) {
    149 }
    150 
    151 void RecentlyUsedFoldersComboModel::BookmarkNodeAdded(
    152     BookmarkModel* model,
    153     const BookmarkNode* parent,
    154     int index) {
    155 }
    156 
    157 void RecentlyUsedFoldersComboModel::OnWillRemoveBookmarks(
    158     BookmarkModel* model,
    159     const BookmarkNode* parent,
    160     int old_index,
    161     const BookmarkNode* node) {
    162   // Changing is rare enough that we don't attempt to readjust the contents.
    163   // Update |items_| so we aren't left pointing to a deleted node.
    164   bool changed = false;
    165   for (std::vector<Item>::iterator i = items_.begin();
    166        i != items_.end();) {
    167     if (i->type == Item::TYPE_NODE && i->node->HasAncestor(node)) {
    168       i = items_.erase(i);
    169       changed = true;
    170     } else {
    171       ++i;
    172     }
    173   }
    174   if (changed) {
    175     FOR_EACH_OBSERVER(ui::ComboboxModelObserver, observers_,
    176                       OnComboboxModelChanged(this));
    177   }
    178 }
    179 
    180 void RecentlyUsedFoldersComboModel::BookmarkNodeRemoved(
    181     BookmarkModel* model,
    182     const BookmarkNode* parent,
    183     int old_index,
    184     const BookmarkNode* node,
    185     const std::set<GURL>& removed_urls) {}
    186 
    187 void RecentlyUsedFoldersComboModel::BookmarkNodeChanged(
    188     BookmarkModel* model,
    189     const BookmarkNode* node) {
    190 }
    191 
    192 void RecentlyUsedFoldersComboModel::BookmarkNodeFaviconChanged(
    193     BookmarkModel* model,
    194     const BookmarkNode* node) {
    195 }
    196 
    197 void RecentlyUsedFoldersComboModel::BookmarkNodeChildrenReordered(
    198       BookmarkModel* model,
    199       const BookmarkNode* node) {
    200 }
    201 
    202 void RecentlyUsedFoldersComboModel::BookmarkAllUserNodesRemoved(
    203     BookmarkModel* model,
    204     const std::set<GURL>& removed_urls) {
    205   // Changing is rare enough that we don't attempt to readjust the contents.
    206   // Update |items_| so we aren't left pointing to a deleted node.
    207   bool changed = false;
    208   for (std::vector<Item>::iterator i = items_.begin();
    209        i != items_.end();) {
    210     if (i->type == Item::TYPE_NODE &&
    211         !bookmark_model_->is_permanent_node(i->node)) {
    212       i = items_.erase(i);
    213       changed = true;
    214     } else {
    215       ++i;
    216     }
    217   }
    218   if (changed) {
    219     FOR_EACH_OBSERVER(ui::ComboboxModelObserver, observers_,
    220                       OnComboboxModelChanged(this));
    221   }
    222 }
    223 
    224 void RecentlyUsedFoldersComboModel::MaybeChangeParent(
    225     const BookmarkNode* node,
    226     int selected_index) {
    227   if (items_[selected_index].type != Item::TYPE_NODE)
    228     return;
    229 
    230   const BookmarkNode* new_parent = GetNodeAt(selected_index);
    231   if (new_parent != node->parent()) {
    232     content::RecordAction(
    233         base::UserMetricsAction("BookmarkBubble_ChangeParent"));
    234     bookmark_model_->Move(node, new_parent, new_parent->child_count());
    235   }
    236 }
    237 
    238 const BookmarkNode* RecentlyUsedFoldersComboModel::GetNodeAt(int index) {
    239   if (index < 0 || index >= static_cast<int>(items_.size()))
    240     return NULL;
    241   return items_[index].node;
    242 }
    243 
    244 void RecentlyUsedFoldersComboModel::RemoveNode(const BookmarkNode* node) {
    245   std::vector<Item>::iterator it = std::find(items_.begin(),
    246                                              items_.end(),
    247                                              Item(node, Item::TYPE_NODE));
    248   if (it != items_.end())
    249     items_.erase(it);
    250 }
    251