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 "chrome/browser/bookmarks/bookmark_model.h"
      8 #include "chrome/browser/bookmarks/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 
     13 namespace {
     14 
     15 // Max number of most recently used folders.
     16 const size_t kMaxMRUFolders = 5;
     17 
     18 }  // namespace
     19 
     20 struct RecentlyUsedFoldersComboModel::Item {
     21   enum Type {
     22     TYPE_NODE,
     23     TYPE_SEPARATOR,
     24     TYPE_CHOOSE_ANOTHER_FOLDER
     25   };
     26 
     27   Item(const BookmarkNode* node, Type type);
     28   ~Item();
     29 
     30   bool operator==(const Item& item) const;
     31 
     32   const BookmarkNode* node;
     33   Type type;
     34 };
     35 
     36 RecentlyUsedFoldersComboModel::Item::Item(const BookmarkNode* node,
     37                                           Type type)
     38     : node(node),
     39       type(type) {
     40 }
     41 
     42 RecentlyUsedFoldersComboModel::Item::~Item() {}
     43 
     44 bool RecentlyUsedFoldersComboModel::Item::operator==(const Item& item) const {
     45   return item.node == node && item.type == type;
     46 }
     47 
     48 RecentlyUsedFoldersComboModel::RecentlyUsedFoldersComboModel(
     49     BookmarkModel* model,
     50     const BookmarkNode* node)
     51     : bookmark_model_(model),
     52       node_parent_index_(0) {
     53   // Use + 2 to account for bookmark bar and other node.
     54   std::vector<const BookmarkNode*> nodes =
     55       bookmark_utils::GetMostRecentlyModifiedFolders(model, kMaxMRUFolders + 2);
     56 
     57   for (size_t i = 0; i < nodes.size(); ++i)
     58     items_.push_back(Item(nodes[i], Item::TYPE_NODE));
     59 
     60   // We special case the placement of these, so remove them from the list, then
     61   // fix up the order.
     62   RemoveNode(model->bookmark_bar_node());
     63   RemoveNode(model->mobile_node());
     64   RemoveNode(model->other_node());
     65   RemoveNode(node->parent());
     66 
     67   // Make the parent the first item, unless it's a permanent node, which is
     68   // added below.
     69   if (!model->is_permanent_node(node->parent()))
     70     items_.insert(items_.begin(), Item(node->parent(), Item::TYPE_NODE));
     71 
     72   // Make sure we only have kMaxMRUFolders in the first chunk.
     73   if (items_.size() > kMaxMRUFolders)
     74     items_.erase(items_.begin() + kMaxMRUFolders, items_.end());
     75 
     76   // And put the bookmark bar and other nodes at the end of the list.
     77   items_.push_back(Item(model->bookmark_bar_node(), Item::TYPE_NODE));
     78   items_.push_back(Item(model->other_node(), Item::TYPE_NODE));
     79   if (model->mobile_node()->IsVisible())
     80     items_.push_back(Item(model->mobile_node(), Item::TYPE_NODE));
     81 #if defined(USE_AURA) || defined(TOOLKIT_GTK)
     82   items_.push_back(Item(NULL, Item::TYPE_SEPARATOR));
     83 #endif
     84   items_.push_back(Item(NULL, Item::TYPE_CHOOSE_ANOTHER_FOLDER));
     85 
     86   std::vector<Item>::iterator it = std::find(items_.begin(),
     87                                              items_.end(),
     88                                              Item(node->parent(),
     89                                                   Item::TYPE_NODE));
     90   node_parent_index_ = static_cast<int>(it - items_.begin());
     91 }
     92 
     93 RecentlyUsedFoldersComboModel::~RecentlyUsedFoldersComboModel() {}
     94 
     95 int RecentlyUsedFoldersComboModel::GetItemCount() const {
     96   return static_cast<int>(items_.size());
     97 }
     98 
     99 string16 RecentlyUsedFoldersComboModel::GetItemAt(int index) {
    100   switch (items_[index].type) {
    101     case Item::TYPE_NODE:
    102       return items_[index].node->GetTitle();
    103     case Item::TYPE_SEPARATOR:
    104       // This function should not be called for separators.
    105       NOTREACHED();
    106       return string16();
    107     case Item::TYPE_CHOOSE_ANOTHER_FOLDER:
    108       return l10n_util::GetStringUTF16(
    109           IDS_BOOKMARK_BUBBLE_CHOOSER_ANOTHER_FOLDER);
    110   }
    111   NOTREACHED();
    112   return string16();
    113 }
    114 
    115 bool RecentlyUsedFoldersComboModel::IsItemSeparatorAt(int index) {
    116   return items_[index].type == Item::TYPE_SEPARATOR;
    117 }
    118 
    119 int RecentlyUsedFoldersComboModel::GetDefaultIndex() const {
    120   return node_parent_index_;
    121 }
    122 
    123 void RecentlyUsedFoldersComboModel::MaybeChangeParent(
    124     const BookmarkNode* node,
    125     int selected_index) {
    126   if (items_[selected_index].type != Item::TYPE_NODE)
    127     return;
    128 
    129   const BookmarkNode* new_parent = GetNodeAt(selected_index);
    130   if (new_parent != node->parent()) {
    131     content::RecordAction(
    132         content::UserMetricsAction("BookmarkBubble_ChangeParent"));
    133     bookmark_model_->Move(node, new_parent, new_parent->child_count());
    134   }
    135 }
    136 
    137 const BookmarkNode* RecentlyUsedFoldersComboModel::GetNodeAt(int index) {
    138   if (index < 0 || index >= static_cast<int>(items_.size()))
    139     return NULL;
    140   return items_[index].node;
    141 }
    142 
    143 void RecentlyUsedFoldersComboModel::RemoveNode(const BookmarkNode* node) {
    144   std::vector<Item>::iterator it = std::find(items_.begin(),
    145                                              items_.end(),
    146                                              Item(node, Item::TYPE_NODE));
    147   if (it != items_.end())
    148     items_.erase(it);
    149 }
    150