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