- add sources.
[platform/framework/web/crosswalk.git] / src / ui / views / controls / tree / tree_view.cc
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 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