Home | History | Annotate | Download | only in tree
      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 "ui/views/controls/tree/tree_view.h"
      6 
      7 #include <algorithm>
      8 
      9 #include "base/i18n/rtl.h"
     10 #include "base/message_loop/message_loop.h"
     11 #include "grit/ui_resources.h"
     12 #include "ui/base/accessibility/accessible_view_state.h"
     13 #include "ui/base/events/event.h"
     14 #include "ui/base/keycodes/keyboard_codes.h"
     15 #include "ui/base/resource/resource_bundle.h"
     16 #include "ui/gfx/canvas.h"
     17 #include "ui/gfx/image/image.h"
     18 #include "ui/gfx/rect_conversions.h"
     19 #include "ui/gfx/skia_util.h"
     20 #include "ui/native_theme/native_theme.h"
     21 #include "ui/views/controls/prefix_selector.h"
     22 #include "ui/views/controls/scroll_view.h"
     23 #include "ui/views/controls/textfield/textfield.h"
     24 #include "ui/views/controls/tree/tree_view_controller.h"
     25 #include "ui/views/ime/input_method.h"
     26 
     27 using ui::TreeModel;
     28 using ui::TreeModelNode;
     29 
     30 namespace views {
     31 
     32 // Insets around the view.
     33 static const int kHorizontalInset = 2;
     34 static const int kVerticalInset = 2;
     35 // Padding before/after the image.
     36 static const int kImagePadding = 4;
     37 // Size of the arrow region.
     38 static const int kArrowRegionSize = 12;
     39 // Padding around the text (on each side).
     40 static const int kTextVerticalPadding = 3;
     41 static const int kTextHorizontalPadding = 2;
     42 // How much children are indented from their parent.
     43 static const int kIndent = 20;
     44 
     45 namespace {
     46 
     47 // Returns the color id for the background of selected text. |has_focus|
     48 // indicates if the tree has focus.
     49 ui::NativeTheme::ColorId text_background_color_id(bool has_focus) {
     50   return has_focus ?
     51       ui::NativeTheme::kColorId_TreeSelectionBackgroundFocused :
     52       ui::NativeTheme::kColorId_TreeSelectionBackgroundUnfocused;
     53 }
     54 
     55 // Returns the color id for text. |has_focus| indicates if the tree has focus
     56 // and |is_selected| is true if the item is selected.
     57 ui::NativeTheme::ColorId text_color_id(bool has_focus, bool is_selected) {
     58   if (is_selected) {
     59     if (has_focus)
     60       return ui::NativeTheme::kColorId_TreeSelectedText;
     61     return ui::NativeTheme::kColorId_TreeSelectedTextUnfocused;
     62   }
     63   return ui::NativeTheme::kColorId_TreeText;
     64 }
     65 
     66 }  // namespace
     67 
     68 TreeView::TreeView()
     69     : model_(NULL),
     70       selected_node_(NULL),
     71       editing_(false),
     72       editor_(NULL),
     73       focus_manager_(NULL),
     74       auto_expand_children_(false),
     75       editable_(true),
     76       controller_(NULL),
     77       root_shown_(true),
     78       has_custom_icons_(false),
     79       row_height_(font_.GetHeight() + kTextVerticalPadding * 2) {
     80   set_focusable(true);
     81   closed_icon_ = *ui::ResourceBundle::GetSharedInstance().GetImageNamed(
     82       (base::i18n::IsRTL() ? IDR_FOLDER_CLOSED_RTL
     83                            : IDR_FOLDER_CLOSED)).ToImageSkia();
     84   open_icon_ = *ui::ResourceBundle::GetSharedInstance().GetImageNamed(
     85       (base::i18n::IsRTL() ? IDR_FOLDER_OPEN_RTL
     86                            : IDR_FOLDER_OPEN)).ToImageSkia();
     87   text_offset_ = closed_icon_.width() + kImagePadding + kImagePadding +
     88       kArrowRegionSize;
     89 }
     90 
     91 TreeView::~TreeView() {
     92   if (model_)
     93     model_->RemoveObserver(this);
     94   if (focus_manager_) {
     95     focus_manager_->RemoveFocusChangeListener(this);
     96     focus_manager_ = NULL;
     97   }
     98 }
     99 
    100 View* TreeView::CreateParentIfNecessary() {
    101   ScrollView* scroll_view = ScrollView::CreateScrollViewWithBorder();
    102   scroll_view->SetContents(this);
    103   return scroll_view;
    104 }
    105 
    106 void TreeView::SetModel(TreeModel* model) {
    107   if (model == model_)
    108     return;
    109   if (model_)
    110     model_->RemoveObserver(this);
    111 
    112   CancelEdit();
    113 
    114   model_ = model;
    115   selected_node_ = NULL;
    116   icons_.clear();
    117   if (model_) {
    118     model_->AddObserver(this);
    119     model_->GetIcons(&icons_);
    120 
    121     root_.RemoveAll();
    122     ConfigureInternalNode(model_->GetRoot(), &root_);
    123     LoadChildren(&root_);
    124     root_.set_is_expanded(true);
    125     if (root_shown_)
    126       selected_node_ = &root_;
    127     else if (root_.child_count())
    128       selected_node_ = root_.GetChild(0);
    129   }
    130   DrawnNodesChanged();
    131 }
    132 
    133 void TreeView::SetEditable(bool editable) {
    134   if (editable == editable_)
    135     return;
    136   editable_ = editable;
    137   CancelEdit();
    138 }
    139 
    140 void TreeView::StartEditing(TreeModelNode* node) {
    141   DCHECK(node);
    142   // Cancel the current edit.
    143   CancelEdit();
    144   // Make sure all ancestors are expanded.
    145   if (model_->GetParent(node))
    146     Expand(model_->GetParent(node));
    147   // Select the node, else if the user commits the edit the selection reverts.
    148   SetSelectedNode(node);
    149   if (GetSelectedNode() != node)
    150     return;  // Selection failed for some reason, don't start editing.
    151   DCHECK(!editing_);
    152   editing_ = true;
    153   if (!editor_) {
    154     editor_ = new Textfield;
    155     // Add the editor immediately as GetPreferredSize returns the wrong thing if
    156     // not parented.
    157     AddChildView(editor_);
    158     editor_->SetFont(font_);
    159     empty_editor_size_ = editor_->GetPreferredSize();
    160     editor_->SetController(this);
    161   }
    162   editor_->SetText(selected_node_->model_node()->GetTitle());
    163   LayoutEditor();
    164   editor_->SetVisible(true);
    165   SchedulePaintForNode(selected_node_);
    166   editor_->RequestFocus();
    167   editor_->SelectAll(false);
    168 
    169   // Listen for focus changes so that we can cancel editing.
    170   focus_manager_ = GetFocusManager();
    171   if (focus_manager_)
    172     focus_manager_->AddFocusChangeListener(this);
    173 
    174   // Accelerators to commit/cancel edit.
    175   AddAccelerator(ui::Accelerator(ui::VKEY_RETURN, ui::EF_NONE));
    176   AddAccelerator(ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE));
    177 }
    178 
    179 void TreeView::CancelEdit() {
    180   if (!editing_)
    181     return;
    182 
    183   // WARNING: don't touch |selected_node_|, it may be bogus.
    184 
    185   editing_ = false;
    186   if (focus_manager_) {
    187     focus_manager_->RemoveFocusChangeListener(this);
    188     focus_manager_ = NULL;
    189   }
    190   editor_->SetVisible(false);
    191   SchedulePaint();
    192 
    193   RemoveAccelerator(ui::Accelerator(ui::VKEY_RETURN, ui::EF_NONE));
    194   RemoveAccelerator(ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE));
    195 }
    196 
    197 void TreeView::CommitEdit() {
    198   if (!editing_)
    199     return;
    200 
    201   DCHECK(selected_node_);
    202   const bool editor_has_focus = editor_->HasFocus();
    203   model_->SetTitle(GetSelectedNode(), editor_->text());
    204   CancelEdit();
    205   if (editor_has_focus)
    206     RequestFocus();
    207 }
    208 
    209 TreeModelNode* TreeView::GetEditingNode() {
    210   return editing_ ? selected_node_->model_node() : NULL;
    211 }
    212 
    213 void TreeView::SetSelectedNode(TreeModelNode* model_node) {
    214   if (editing_ || model_node != selected_node_)
    215     CancelEdit();
    216   if (model_node && model_->GetParent(model_node))
    217     Expand(model_->GetParent(model_node));
    218   if (model_node && model_node == root_.model_node() && !root_shown_)
    219     return;  // Ignore requests to select the root when not shown.
    220   InternalNode* node = model_node ? GetInternalNodeForModelNode(
    221       model_node, CREATE_IF_NOT_LOADED) : NULL;
    222   bool was_empty_selection = (selected_node_ == NULL);
    223   bool changed = (selected_node_ != node);
    224   if (changed) {
    225     SchedulePaintForNode(selected_node_);
    226     selected_node_ = node;
    227     if (selected_node_ == &root_ && !root_shown_)
    228       selected_node_ = NULL;
    229     if (selected_node_ && selected_node_ != &root_)
    230       Expand(model_->GetParent(selected_node_->model_node()));
    231     SchedulePaintForNode(selected_node_);
    232   }
    233 
    234   if (selected_node_)
    235     ScrollRectToVisible(GetBoundsForNode(selected_node_));
    236 
    237   // Notify controller if the old selection was empty to handle the case of
    238   // remove explicitly resetting selected_node_ before invoking this.
    239   if (controller_ && (changed || was_empty_selection))
    240     controller_->OnTreeViewSelectionChanged(this);
    241 }
    242 
    243 TreeModelNode* TreeView::GetSelectedNode() {
    244   return selected_node_ ? selected_node_->model_node() : NULL;
    245 }
    246 
    247 void TreeView::Collapse(ui::TreeModelNode* model_node) {
    248   // Don't collapse the root if the root isn't shown, otherwise nothing is
    249   // displayed.
    250   if (model_node == root_.model_node() && !root_shown_)
    251     return;
    252   InternalNode* node =
    253       GetInternalNodeForModelNode(model_node, DONT_CREATE_IF_NOT_LOADED);
    254   if (!node)
    255     return;
    256   bool was_expanded = IsExpanded(model_node);
    257   if (node->is_expanded()) {
    258     if (selected_node_ && selected_node_->HasAncestor(node))
    259       SetSelectedNode(model_node);
    260     node->set_is_expanded(false);
    261   }
    262   if (was_expanded)
    263     DrawnNodesChanged();
    264 }
    265 
    266 void TreeView::Expand(TreeModelNode* node) {
    267   if (ExpandImpl(node))
    268     DrawnNodesChanged();
    269   // TODO: need to support auto_expand_children_.
    270 }
    271 
    272 void TreeView::ExpandAll(TreeModelNode* node) {
    273   DCHECK(node);
    274   // Expand the node.
    275   bool expanded_at_least_one = ExpandImpl(node);
    276   // And recursively expand all the children.
    277   for (int i = model_->GetChildCount(node) - 1; i >= 0; --i) {
    278     TreeModelNode* child = model_->GetChild(node, i);
    279     if (ExpandImpl(child))
    280       expanded_at_least_one = true;
    281   }
    282   if (expanded_at_least_one)
    283     DrawnNodesChanged();
    284 }
    285 
    286 bool TreeView::IsExpanded(TreeModelNode* model_node) {
    287   if (!model_node) {
    288     // NULL check primarily for convenience for uses in this class so don't have
    289     // to add NULL checks every where we look up the parent.
    290     return true;
    291   }
    292   InternalNode* node = GetInternalNodeForModelNode(
    293       model_node, DONT_CREATE_IF_NOT_LOADED);
    294   if (!node)
    295     return false;
    296 
    297   while (node) {
    298     if (!node->is_expanded())
    299       return false;
    300     node = node->parent();
    301   }
    302   return true;
    303 }
    304 
    305 void TreeView::SetRootShown(bool root_shown) {
    306   if (root_shown_ == root_shown)
    307     return;
    308   root_shown_ = root_shown;
    309   if (!root_shown_ && selected_node_ == &root_) {
    310     if (model_->GetChildCount(root_.model_node()))
    311       SetSelectedNode(model_->GetChild(root_.model_node(), 0));
    312     else
    313       SetSelectedNode(NULL);
    314   }
    315   DrawnNodesChanged();
    316 }
    317 
    318 ui::TreeModelNode* TreeView::GetNodeForRow(int row) {
    319   int depth = 0;
    320   InternalNode* node = GetNodeByRow(row, &depth);
    321   return node ? node->model_node() : NULL;
    322 }
    323 
    324 int TreeView::GetRowForNode(ui::TreeModelNode* node) {
    325   InternalNode* internal_node =
    326       GetInternalNodeForModelNode(node, DONT_CREATE_IF_NOT_LOADED);
    327   if (!internal_node)
    328     return -1;
    329   int depth = 0;
    330   return GetRowForInternalNode(internal_node, &depth);
    331 }
    332 
    333 void TreeView::Layout() {
    334   int width = preferred_size_.width();
    335   int height = preferred_size_.height();
    336   if (parent()) {
    337     width = std::max(parent()->width(), width);
    338     height = std::max(parent()->height(), height);
    339   }
    340   SetBounds(x(), y(), width, height);
    341   LayoutEditor();
    342 }
    343 
    344 gfx::Size TreeView::GetPreferredSize() {
    345   return preferred_size_;
    346 }
    347 
    348 bool TreeView::AcceleratorPressed(const ui::Accelerator& accelerator) {
    349   if (accelerator.key_code() == ui::VKEY_RETURN) {
    350     CommitEdit();
    351   } else {
    352     DCHECK_EQ(ui::VKEY_ESCAPE, accelerator.key_code());
    353     CancelEdit();
    354     RequestFocus();
    355   }
    356   return true;
    357 }
    358 
    359 bool TreeView::OnMousePressed(const ui::MouseEvent& event) {
    360   return OnClickOrTap(event);
    361 }
    362 
    363 ui::TextInputClient* TreeView::GetTextInputClient() {
    364   if (!selector_)
    365     selector_.reset(new PrefixSelector(this));
    366   return selector_.get();
    367 }
    368 
    369 void TreeView::OnGestureEvent(ui::GestureEvent* event) {
    370   if (event->type() == ui::ET_GESTURE_TAP) {
    371     if (OnClickOrTap(*event))
    372       event->SetHandled();
    373   }
    374 }
    375 
    376 void TreeView::ShowContextMenu(const gfx::Point& p,
    377                                ui::MenuSourceType source_type) {
    378   if (!model_)
    379     return;
    380   if (source_type == ui::MENU_SOURCE_MOUSE) {
    381     // Only invoke View's implementation (which notifies the
    382     // ContextMenuController) if over a node.
    383     gfx::Point local_point(p);
    384     ConvertPointToTarget(NULL, this, &local_point);
    385     int row = (local_point.y() - kVerticalInset) / row_height_;
    386     int depth = 0;
    387     InternalNode* node = GetNodeByRow(row, &depth);
    388     if (!node)
    389       return;
    390     gfx::Rect bounds(GetBoundsForNodeImpl(node, row, depth));
    391     if (!bounds.Contains(local_point))
    392       return;
    393   }
    394   View::ShowContextMenu(p, source_type);
    395 }
    396 
    397 void TreeView::GetAccessibleState(ui::AccessibleViewState* state) {
    398   state->role = ui::AccessibilityTypes::ROLE_OUTLINE;
    399   state->state = ui::AccessibilityTypes::STATE_READONLY;
    400 }
    401 
    402 void TreeView::TreeNodesAdded(TreeModel* model,
    403                               TreeModelNode* parent,
    404                               int start,
    405                               int count) {
    406   InternalNode* parent_node =
    407       GetInternalNodeForModelNode(parent, DONT_CREATE_IF_NOT_LOADED);
    408   if (!parent_node || !parent_node->loaded_children())
    409     return;
    410   for (int i = 0; i < count; ++i) {
    411     InternalNode* child = new InternalNode;
    412     ConfigureInternalNode(model_->GetChild(parent, start + i), child);
    413     parent_node->Add(child, start + i);
    414   }
    415   if (IsExpanded(parent))
    416     DrawnNodesChanged();
    417 }
    418 
    419 void TreeView::TreeNodesRemoved(TreeModel* model,
    420                                 TreeModelNode* parent,
    421                                 int start,
    422                                 int count) {
    423   InternalNode* parent_node =
    424       GetInternalNodeForModelNode(parent, DONT_CREATE_IF_NOT_LOADED);
    425   if (!parent_node || !parent_node->loaded_children())
    426     return;
    427   bool reset_selection = false;
    428   for (int i = 0; i < count; ++i) {
    429     InternalNode* child_removing = parent_node->GetChild(start);
    430     if (selected_node_ && selected_node_->HasAncestor(child_removing))
    431       reset_selection = true;
    432     delete parent_node->Remove(child_removing);
    433   }
    434   if (reset_selection) {
    435     // selected_node_ is no longer valid (at the time we enter this function
    436     // its model_node() is likely deleted). Explicitly NULL out the field
    437     // rather than invoking SetSelectedNode() otherwise, we'll try and use a
    438     // deleted value.
    439     selected_node_ = NULL;
    440     TreeModelNode* to_select = parent;
    441     if (parent == root_.model_node() && !root_shown_) {
    442       to_select = model_->GetChildCount(parent) > 0 ?
    443           model_->GetChild(parent, 0) : NULL;
    444     }
    445     SetSelectedNode(to_select);
    446   }
    447   if (IsExpanded(parent))
    448     DrawnNodesChanged();
    449 }
    450 
    451 void TreeView::TreeNodeChanged(TreeModel* model, TreeModelNode* model_node) {
    452   InternalNode* node =
    453       GetInternalNodeForModelNode(model_node, DONT_CREATE_IF_NOT_LOADED);
    454   if (!node)
    455     return;
    456   int old_width = node->text_width();
    457   UpdateNodeTextWidth(node);
    458   if (old_width != node->text_width() &&
    459       ((node == &root_ && root_shown_) ||
    460        (node != &root_ && IsExpanded(node->parent()->model_node())))) {
    461     DrawnNodesChanged();
    462   }
    463 }
    464 
    465 void TreeView::ContentsChanged(Textfield* sender,
    466                                const string16& new_contents) {
    467 }
    468 
    469 bool TreeView::HandleKeyEvent(Textfield* sender,
    470                               const ui::KeyEvent& key_event) {
    471   switch (key_event.key_code()) {
    472     case ui::VKEY_RETURN:
    473       CommitEdit();
    474       return true;
    475 
    476     case ui::VKEY_ESCAPE:
    477       CancelEdit();
    478       RequestFocus();
    479       return true;
    480 
    481     default:
    482       return false;
    483   }
    484 }
    485 
    486 void TreeView::OnWillChangeFocus(View* focused_before, View* focused_now) {
    487 }
    488 
    489 void TreeView::OnDidChangeFocus(View* focused_before, View* focused_now) {
    490   CommitEdit();
    491 }
    492 
    493 int TreeView::GetRowCount() {
    494   int row_count = root_.NumExpandedNodes();
    495   if (!root_shown_)
    496     row_count--;
    497   return row_count;
    498 }
    499 
    500 int TreeView::GetSelectedRow() {
    501   ui::TreeModelNode* model_node = GetSelectedNode();
    502   return model_node ? GetRowForNode(model_node) : -1;
    503 }
    504 
    505 void TreeView::SetSelectedRow(int row) {
    506   SetSelectedNode(GetNodeForRow(row));
    507 }
    508 
    509 string16 TreeView::GetTextForRow(int row) {
    510   return GetNodeForRow(row)->GetTitle();
    511 }
    512 
    513 gfx::Point TreeView::GetKeyboardContextMenuLocation() {
    514   int y = height() / 2;
    515   if (selected_node_) {
    516     gfx::Rect node_bounds(GetBoundsForNode(selected_node_));
    517     gfx::Rect vis_bounds(GetVisibleBounds());
    518     if (node_bounds.y() >= vis_bounds.y() &&
    519         node_bounds.y() < vis_bounds.bottom()) {
    520       y = node_bounds.y();
    521     }
    522   }
    523   gfx::Point screen_loc(0, y);
    524   if (base::i18n::IsRTL())
    525     screen_loc.set_x(width());
    526   ConvertPointToScreen(this, &screen_loc);
    527   return screen_loc;
    528 }
    529 
    530 bool TreeView::OnKeyPressed(const ui::KeyEvent& event) {
    531   if (!HasFocus())
    532     return false;
    533 
    534   switch (event.key_code()) {
    535     case ui::VKEY_F2:
    536       if (!editing_) {
    537         TreeModelNode* selected_node = GetSelectedNode();
    538         if (selected_node && (!controller_ ||
    539                               controller_->CanEdit(this, selected_node))) {
    540           StartEditing(selected_node);
    541         }
    542       }
    543       return true;
    544 
    545     case ui::VKEY_UP:
    546     case ui::VKEY_DOWN:
    547       IncrementSelection(event.key_code() == ui::VKEY_UP ?
    548                          INCREMENT_PREVIOUS : INCREMENT_NEXT);
    549       return true;
    550 
    551     case ui::VKEY_LEFT:
    552       if (base::i18n::IsRTL())
    553         ExpandOrSelectChild();
    554       else
    555         CollapseOrSelectParent();
    556       return true;
    557 
    558     case ui::VKEY_RIGHT:
    559       if (base::i18n::IsRTL())
    560         CollapseOrSelectParent();
    561       else
    562         ExpandOrSelectChild();
    563       return true;
    564 
    565     default:
    566       break;
    567   }
    568   return false;
    569 }
    570 
    571 void TreeView::OnPaint(gfx::Canvas* canvas) {
    572   // Don't invoke View::OnPaint so that we can render our own focus border.
    573   canvas->DrawColor(GetNativeTheme()->GetSystemColor(
    574                         ui::NativeTheme::kColorId_TreeBackground));
    575 
    576   int min_y, max_y;
    577   {
    578     SkRect sk_clip_rect;
    579     if (canvas->sk_canvas()->getClipBounds(&sk_clip_rect)) {
    580       // Pixels partially inside the clip rect should be included.
    581       gfx::Rect clip_rect = gfx::ToEnclosingRect(
    582           gfx::SkRectToRectF(sk_clip_rect));
    583       min_y = clip_rect.y();
    584       max_y = clip_rect.bottom();
    585     } else {
    586       gfx::Rect vis_bounds = GetVisibleBounds();
    587       min_y = vis_bounds.y();
    588       max_y = vis_bounds.bottom();
    589     }
    590   }
    591 
    592   int min_row = std::max(0, (min_y - kVerticalInset) / row_height_);
    593   int max_row = (max_y - kVerticalInset) / row_height_;
    594   if ((max_y - kVerticalInset) % row_height_ != 0)
    595     max_row++;
    596   int current_row = root_row();
    597   PaintRows(canvas, min_row, max_row, &root_, root_depth(), &current_row);
    598 }
    599 
    600 void TreeView::OnFocus() {
    601   GetInputMethod()->OnFocus();
    602   View::OnFocus();
    603   SchedulePaintForNode(selected_node_);
    604 
    605   // Notify the InputMethod so that it knows to query the TextInputClient.
    606   if (GetInputMethod())
    607     GetInputMethod()->OnCaretBoundsChanged(this);
    608 }
    609 
    610 void TreeView::OnBlur() {
    611   GetInputMethod()->OnBlur();
    612   SchedulePaintForNode(selected_node_);
    613   if (selector_)
    614     selector_->OnViewBlur();
    615 }
    616 
    617 bool TreeView::OnClickOrTap(const ui::LocatedEvent& event) {
    618   CommitEdit();
    619   RequestFocus();
    620 
    621   int row = (event.y() - kVerticalInset) / row_height_;
    622   int depth = 0;
    623   InternalNode* node = GetNodeByRow(row, &depth);
    624   if (node) {
    625     gfx::Rect bounds(GetBoundsForNodeImpl(node, row, depth));
    626     if (bounds.Contains(event.location())) {
    627       int relative_x = event.x() - bounds.x();
    628       if (base::i18n::IsRTL())
    629         relative_x = bounds.width() - relative_x;
    630       if (relative_x < kArrowRegionSize &&
    631           model_->GetChildCount(node->model_node())) {
    632         if (node->is_expanded())
    633           Collapse(node->model_node());
    634         else
    635           Expand(node->model_node());
    636       } else if (relative_x > kArrowRegionSize) {
    637         SetSelectedNode(node->model_node());
    638         bool should_toggle = false;
    639         if (event.type() == ui::ET_GESTURE_TAP) {
    640           const ui::GestureEvent& gesture =
    641               static_cast<const ui::GestureEvent&>(event);
    642           should_toggle = gesture.details().tap_count() == 2;
    643         } else {
    644           should_toggle = (event.flags() & ui::EF_IS_DOUBLE_CLICK) != 0;
    645         }
    646         if (should_toggle) {
    647           if (node->is_expanded())
    648             Collapse(node->model_node());
    649           else
    650             Expand(node->model_node());
    651         }
    652       }
    653     }
    654   }
    655   return true;
    656 }
    657 
    658 void TreeView::LoadChildren(InternalNode* node) {
    659   DCHECK_EQ(0, node->child_count());
    660   DCHECK(!node->loaded_children());
    661   node->set_loaded_children(true);
    662   for (int i = 0, child_count = model_->GetChildCount(node->model_node());
    663        i < child_count; ++i) {
    664     InternalNode* child = new InternalNode;
    665     ConfigureInternalNode(model_->GetChild(node->model_node(), i), child);
    666     node->Add(child, node->child_count());
    667   }
    668 }
    669 
    670 void TreeView::ConfigureInternalNode(TreeModelNode* model_node,
    671                                      InternalNode* node) {
    672   node->Reset(model_node);
    673   UpdateNodeTextWidth(node);
    674 }
    675 
    676 void TreeView::UpdateNodeTextWidth(InternalNode* node) {
    677   int width = 0, height = 0;
    678   gfx::Canvas::SizeStringInt(node->model_node()->GetTitle(), font_,
    679                              &width, &height, 0, gfx::Canvas::NO_ELLIPSIS);
    680   node->set_text_width(width);
    681 }
    682 
    683 void TreeView::DrawnNodesChanged() {
    684   UpdatePreferredSize();
    685   PreferredSizeChanged();
    686   SchedulePaint();
    687 }
    688 
    689 void TreeView::UpdatePreferredSize() {
    690   preferred_size_ = gfx::Size();
    691   if (!model_)
    692     return;
    693 
    694   preferred_size_.SetSize(
    695       root_.GetMaxWidth(text_offset_, root_shown_ ? 1 : 0) +
    696       kTextHorizontalPadding * 2,
    697       row_height_ * GetRowCount() + kVerticalInset * 2);
    698 }
    699 
    700 void TreeView::LayoutEditor() {
    701   if (!editing_)
    702     return;
    703 
    704   DCHECK(selected_node_);
    705   // Position the editor so that its text aligns with the text we drew.
    706   gfx::Rect row_bounds = GetBoundsForNode(selected_node_);
    707   row_bounds.set_x(
    708       GetMirroredXWithWidthInView(row_bounds.x(), row_bounds.width()));
    709   row_bounds.set_x(row_bounds.x() + text_offset_);
    710   row_bounds.set_width(row_bounds.width() - text_offset_);
    711   row_bounds.Inset(kTextHorizontalPadding, kTextVerticalPadding);
    712   row_bounds.Inset(-empty_editor_size_.width() / 2,
    713                    -(empty_editor_size_.height() - font_.GetHeight()) / 2);
    714   // Give a little extra space for editing.
    715   row_bounds.set_width(row_bounds.width() + 50);
    716   editor_->SetBoundsRect(row_bounds);
    717   editor_->Layout();
    718 }
    719 
    720 void TreeView::SchedulePaintForNode(InternalNode* node) {
    721   if (!node)
    722     return;  // Explicitly allow NULL to be passed in.
    723   SchedulePaintInRect(GetBoundsForNode(node));
    724 }
    725 
    726 void TreeView::PaintRows(gfx::Canvas* canvas,
    727                          int min_row,
    728                          int max_row,
    729                          InternalNode* node,
    730                          int depth,
    731                          int* row) {
    732   if (*row >= max_row)
    733     return;
    734 
    735   if (*row >= min_row && *row < max_row)
    736     PaintRow(canvas, node, *row, depth);
    737   (*row)++;
    738   if (!node->is_expanded())
    739     return;
    740   depth++;
    741   for (int i = 0; i < node->child_count() && *row < max_row; ++i)
    742     PaintRows(canvas, min_row, max_row, node->GetChild(i), depth, row);
    743 }
    744 
    745 void TreeView::PaintRow(gfx::Canvas* canvas,
    746                         InternalNode* node,
    747                         int row,
    748                         int depth) {
    749   gfx::Rect bounds(GetBoundsForNodeImpl(node, row, depth));
    750 
    751   if (model_->GetChildCount(node->model_node()))
    752     PaintExpandControl(canvas, bounds, node->is_expanded());
    753 
    754   // Paint the icon.
    755   gfx::ImageSkia icon;
    756   int icon_index = model_->GetIconIndex(node->model_node());
    757   if (icon_index != -1)
    758     icon = icons_[icon_index];
    759   else if (node == selected_node_)
    760     icon = open_icon_;
    761   else
    762     icon = closed_icon_;
    763   int icon_x = kArrowRegionSize + kImagePadding +
    764                (open_icon_.width() - icon.width()) / 2;
    765   if (base::i18n::IsRTL())
    766     icon_x = bounds.right() - icon_x - open_icon_.width();
    767   else
    768     icon_x += bounds.x();
    769   canvas->DrawImageInt(
    770       icon, icon_x,
    771       bounds.y() + (bounds.height() - icon.height()) / 2);
    772 
    773   if (!editing_ || node != selected_node_) {
    774     gfx::Rect text_bounds(bounds.x() + text_offset_, bounds.y(),
    775                           bounds.width() - text_offset_, bounds.height());
    776     if (base::i18n::IsRTL())
    777       text_bounds.set_x(bounds.x());
    778     if (node == selected_node_) {
    779       const SkColor bg_color = GetNativeTheme()->GetSystemColor(
    780           text_background_color_id(HasFocus()));
    781       canvas->FillRect(text_bounds, bg_color);
    782       if (HasFocus())
    783         canvas->DrawFocusRect(text_bounds);
    784     }
    785     const ui::NativeTheme::ColorId color_id =
    786         text_color_id(HasFocus(), node == selected_node_);
    787     canvas->DrawStringInt(node->model_node()->GetTitle(), font_,
    788                           GetNativeTheme()->GetSystemColor(color_id),
    789                           text_bounds.x() + kTextHorizontalPadding,
    790                           text_bounds.y() + kTextVerticalPadding,
    791                           text_bounds.width() - kTextHorizontalPadding * 2,
    792                           text_bounds.height() - kTextVerticalPadding * 2);
    793   }
    794 }
    795 
    796 void TreeView::PaintExpandControl(gfx::Canvas* canvas,
    797                                   const gfx::Rect& node_bounds,
    798                                   bool expanded) {
    799   int center_x;
    800   if (base::i18n::IsRTL()) {
    801     center_x = node_bounds.right() - kArrowRegionSize +
    802                (kArrowRegionSize - 4) / 2;
    803   } else {
    804     center_x = node_bounds.x() + (kArrowRegionSize - 4) / 2;
    805   }
    806   int center_y = node_bounds.y() + node_bounds.height() / 2;
    807   const SkColor arrow_color = GetNativeTheme()->GetSystemColor(
    808       ui::NativeTheme::kColorId_TreeArrow);
    809   // TODO: this should come from an image.
    810   if (!expanded) {
    811     int delta = base::i18n::IsRTL() ? 1 : -1;
    812     for (int i = 0; i < 4; ++i) {
    813       canvas->FillRect(gfx::Rect(center_x + delta * (2 - i),
    814                                  center_y - (3 - i), 1, (3 - i) * 2 + 1),
    815                        arrow_color);
    816     }
    817   } else {
    818     center_y -= 2;
    819     for (int i = 0; i < 4; ++i) {
    820       canvas->FillRect(gfx::Rect(center_x - (3 - i), center_y + i,
    821                                  (3 - i) * 2 + 1, 1), arrow_color);
    822     }
    823   }
    824 }
    825 
    826 TreeView::InternalNode* TreeView::GetInternalNodeForModelNode(
    827     ui::TreeModelNode* model_node,
    828     GetInternalNodeCreateType create_type) {
    829   if (model_node == root_.model_node())
    830     return &root_;
    831   InternalNode* parent_internal_node =
    832       GetInternalNodeForModelNode(model_->GetParent(model_node), create_type);
    833   if (!parent_internal_node)
    834     return NULL;
    835   if (!parent_internal_node->loaded_children()) {
    836     if (create_type == DONT_CREATE_IF_NOT_LOADED)
    837       return NULL;
    838     LoadChildren(parent_internal_node);
    839   }
    840   return parent_internal_node->GetChild(
    841       model_->GetIndexOf(parent_internal_node->model_node(), model_node));
    842 }
    843 
    844 gfx::Rect TreeView::GetBoundsForNode(InternalNode* node) {
    845   int row, depth;
    846   row = GetRowForInternalNode(node, &depth);
    847   return GetBoundsForNodeImpl(node, row, depth);
    848 }
    849 
    850 gfx::Rect TreeView::GetBoundsForNodeImpl(InternalNode* node,
    851                                          int row,
    852                                          int depth) {
    853   gfx::Rect rect(depth * kIndent + kHorizontalInset,
    854                  row * row_height_ + kVerticalInset,
    855                  text_offset_ + node->text_width() +
    856                  kTextHorizontalPadding * 2,
    857                  row_height_);
    858   rect.set_x(GetMirroredXWithWidthInView(rect.x(), rect.width()));
    859   return rect;
    860 }
    861 
    862 int TreeView::GetRowForInternalNode(InternalNode* node, int* depth) {
    863   DCHECK(!node->parent() || IsExpanded(node->parent()->model_node()));
    864   *depth = -1;
    865   int row = -1;
    866   InternalNode* tmp_node = node;
    867   while (tmp_node->parent()) {
    868     int index_in_parent = tmp_node->parent()->GetIndexOf(tmp_node);
    869     (*depth)++;
    870     row++;  // For node.
    871     for (int i = 0; i < index_in_parent; ++i)
    872       row += tmp_node->parent()->GetChild(i)->NumExpandedNodes();
    873     tmp_node = tmp_node->parent();
    874   }
    875   if (root_shown_) {
    876     (*depth)++;
    877     row++;
    878   }
    879   return row;
    880 }
    881 
    882 TreeView::InternalNode* TreeView::GetNodeByRow(int row, int* depth) {
    883   int current_row = root_row();
    884   *depth = 0;
    885   return GetNodeByRowImpl(&root_, row, root_depth(), &current_row, depth);
    886 }
    887 
    888 TreeView::InternalNode* TreeView::GetNodeByRowImpl(InternalNode* node,
    889                                                    int target_row,
    890                                                    int current_depth,
    891                                                    int* current_row,
    892                                                    int* node_depth) {
    893   if (*current_row == target_row) {
    894     *node_depth = current_depth;
    895     return node;
    896   }
    897   (*current_row)++;
    898   if (node->is_expanded()) {
    899     current_depth++;
    900     for (int i = 0; i < node->child_count(); ++i) {
    901       InternalNode* result = GetNodeByRowImpl(
    902           node->GetChild(i), target_row, current_depth, current_row,
    903           node_depth);
    904       if (result)
    905         return result;
    906     }
    907   }
    908   return NULL;
    909 }
    910 
    911 void TreeView::IncrementSelection(IncrementType type) {
    912   if (!model_)
    913     return;
    914 
    915   if (!GetSelectedNode()) {
    916     // If nothing is selected select the first or last node.
    917     if (!root_.child_count())
    918       return;
    919     if (type == INCREMENT_PREVIOUS) {
    920       int row_count = GetRowCount();
    921       int depth = 0;
    922       DCHECK(row_count);
    923       InternalNode* node = GetNodeByRow(row_count - 1, &depth);
    924       SetSelectedNode(node->model_node());
    925     } else if (root_shown_) {
    926       SetSelectedNode(root_.model_node());
    927     } else {
    928       SetSelectedNode(root_.GetChild(0)->model_node());
    929     }
    930     return;
    931   }
    932 
    933   int depth = 0;
    934   int delta = type == INCREMENT_PREVIOUS ? -1 : 1;
    935   int row = GetRowForInternalNode(selected_node_, &depth);
    936   int new_row = std::min(GetRowCount() - 1, std::max(0, row + delta));
    937   if (new_row == row)
    938     return;  // At the end/beginning.
    939   SetSelectedNode(GetNodeByRow(new_row, &depth)->model_node());
    940 }
    941 
    942 void TreeView::CollapseOrSelectParent() {
    943   if (selected_node_) {
    944     if (selected_node_->is_expanded())
    945       Collapse(selected_node_->model_node());
    946     else if (selected_node_->parent())
    947       SetSelectedNode(selected_node_->parent()->model_node());
    948   }
    949 }
    950 
    951 void TreeView::ExpandOrSelectChild() {
    952   if (selected_node_) {
    953     if (!selected_node_->is_expanded())
    954       Expand(selected_node_->model_node());
    955     else if (selected_node_->child_count())
    956       SetSelectedNode(selected_node_->GetChild(0)->model_node());
    957   }
    958 }
    959 
    960 bool TreeView::ExpandImpl(TreeModelNode* model_node) {
    961   TreeModelNode* parent = model_->GetParent(model_node);
    962   if (!parent) {
    963     // Node should be the root.
    964     DCHECK_EQ(root_.model_node(), model_node);
    965     bool was_expanded = root_.is_expanded();
    966     root_.set_is_expanded(true);
    967     return !was_expanded;
    968   }
    969 
    970   // Expand all the parents.
    971   bool return_value = ExpandImpl(parent);
    972   InternalNode* internal_node =
    973       GetInternalNodeForModelNode(model_node, CREATE_IF_NOT_LOADED);
    974   DCHECK(internal_node);
    975   if (!internal_node->is_expanded()) {
    976     if (!internal_node->loaded_children())
    977       LoadChildren(internal_node);
    978     internal_node->set_is_expanded(true);
    979     return_value = true;
    980   }
    981   return return_value;
    982 }
    983 
    984 // InternalNode ----------------------------------------------------------------
    985 
    986 TreeView::InternalNode::InternalNode()
    987     : model_node_(NULL),
    988       loaded_children_(false),
    989       is_expanded_(false),
    990       text_width_(0) {
    991 }
    992 
    993 TreeView::InternalNode::~InternalNode() {
    994 }
    995 
    996 void TreeView::InternalNode::Reset(ui::TreeModelNode* node) {
    997   model_node_ = node;
    998   loaded_children_ = false;
    999   is_expanded_ = false;
   1000   text_width_ = 0;
   1001 }
   1002 
   1003 int TreeView::InternalNode::NumExpandedNodes() const {
   1004   int result = 1;  // For this.
   1005   if (!is_expanded_)
   1006     return result;
   1007   for (int i = 0; i < child_count(); ++i)
   1008     result += GetChild(i)->NumExpandedNodes();
   1009   return result;
   1010 }
   1011 
   1012 int TreeView::InternalNode::GetMaxWidth(int indent, int depth) {
   1013   int max_width = text_width_ + indent * depth;
   1014   if (!is_expanded_)
   1015     return max_width;
   1016   for (int i = 0; i < child_count(); ++i) {
   1017     max_width = std::max(max_width,
   1018                          GetChild(i)->GetMaxWidth(indent, depth + 1));
   1019   }
   1020   return max_width;
   1021 }
   1022 
   1023 }  // namespace views
   1024