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.
5 #include "ui/views/controls/tree/tree_view.h"
9 #include "base/strings/string_util.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "ui/base/models/tree_node_model.h"
12 #include "ui/views/controls/prefix_selector.h"
13 #include "ui/views/controls/textfield/textfield.h"
14 #include "ui/views/test/views_test_base.h"
17 using ui::TreeModelNode
;
20 using base::ASCIIToUTF16
;
24 class TestNode
: public TreeNode
<TestNode
> {
27 ~TestNode() override
{}
30 DISALLOW_COPY_AND_ASSIGN(TestNode
);
33 // Creates the following structure:
39 class TreeViewTest
: public ViewsTestBase
{
41 TreeViewTest() : model_(new TestNode
) {
42 static_cast<TestNode
*>(model_
.GetRoot())->SetTitle(ASCIIToUTF16("root"));
43 Add(model_
.GetRoot(), 0, "a");
44 Add(Add(model_
.GetRoot(), 1, "b"), 0, "b1");
45 Add(model_
.GetRoot(), 2, "c");
49 TestNode
* Add(TestNode
* parent
,
51 const std::string
& title
);
53 std::string
TreeViewContentsAsString();
55 std::string
GetSelectedNodeTitle();
57 std::string
GetEditingNodeTitle();
59 TestNode
* GetNodeByTitle(const std::string
& title
);
61 void IncrementSelection(bool next
);
62 void CollapseOrSelectParent();
63 void ExpandOrSelectChild();
65 PrefixSelector
* selector() { return tree_
.GetPrefixSelector(); }
67 ui::TreeNodeModel
<TestNode
> model_
;
71 std::string
InternalNodeAsString(TreeView::InternalNode
* node
);
73 TestNode
* GetNodeByTitleImpl(TestNode
* node
, const base::string16
& title
);
75 DISALLOW_COPY_AND_ASSIGN(TreeViewTest
);
78 TestNode
* TreeViewTest::Add(TestNode
* parent
,
80 const std::string
& title
) {
81 TestNode
* new_node
= new TestNode
;
82 new_node
->SetTitle(ASCIIToUTF16(title
));
83 model_
.Add(parent
, new_node
, index
);
87 std::string
TreeViewTest::TreeViewContentsAsString() {
88 return InternalNodeAsString(&tree_
.root_
);
91 std::string
TreeViewTest::GetSelectedNodeTitle() {
92 TreeModelNode
* model_node
= tree_
.GetSelectedNode();
93 return model_node
? base::UTF16ToASCII(model_node
->GetTitle())
97 std::string
TreeViewTest::GetEditingNodeTitle() {
98 TreeModelNode
* model_node
= tree_
.GetEditingNode();
99 return model_node
? base::UTF16ToASCII(model_node
->GetTitle())
103 TestNode
* TreeViewTest::GetNodeByTitle(const std::string
& title
) {
104 return GetNodeByTitleImpl(model_
.GetRoot(), ASCIIToUTF16(title
));
107 void TreeViewTest::IncrementSelection(bool next
) {
108 tree_
.IncrementSelection(next
? TreeView::INCREMENT_NEXT
:
109 TreeView::INCREMENT_PREVIOUS
);
112 void TreeViewTest::CollapseOrSelectParent() {
113 tree_
.CollapseOrSelectParent();
116 void TreeViewTest::ExpandOrSelectChild() {
117 tree_
.ExpandOrSelectChild();
120 int TreeViewTest::GetRowCount() {
121 return tree_
.GetRowCount();
124 TestNode
* TreeViewTest::GetNodeByTitleImpl(TestNode
* node
,
125 const base::string16
& title
) {
126 if (node
->GetTitle() == title
)
128 for (int i
= 0; i
< node
->child_count(); ++i
) {
129 TestNode
* child
= GetNodeByTitleImpl(node
->GetChild(i
), title
);
136 std::string
TreeViewTest::InternalNodeAsString(
137 TreeView::InternalNode
* node
) {
138 std::string result
= base::UTF16ToASCII(node
->model_node()->GetTitle());
139 if (node
->is_expanded() && node
->child_count()) {
141 for (int i
= 0; i
< node
->child_count(); ++i
) {
144 result
+= InternalNodeAsString(node
->GetChild(i
));
151 // Verifies setting model correctly updates internal state.
152 TEST_F(TreeViewTest
, SetModel
) {
153 tree_
.SetModel(&model_
);
154 EXPECT_EQ("root [a b c]", TreeViewContentsAsString());
155 EXPECT_EQ("root", GetSelectedNodeTitle());
156 EXPECT_EQ(4, GetRowCount());
159 // Verifies SetSelectedNode works.
160 TEST_F(TreeViewTest
, SetSelectedNode
) {
161 tree_
.SetModel(&model_
);
162 EXPECT_EQ("root", GetSelectedNodeTitle());
164 // NULL should clear the selection.
165 tree_
.SetSelectedNode(NULL
);
166 EXPECT_EQ(std::string(), GetSelectedNodeTitle());
169 tree_
.SetSelectedNode(GetNodeByTitle("c"));
170 EXPECT_EQ("c", GetSelectedNodeTitle());
172 // Select 'b1', which should expand 'b'.
173 tree_
.SetSelectedNode(GetNodeByTitle("b1"));
174 EXPECT_EQ("root [a b [b1] c]", TreeViewContentsAsString());
175 EXPECT_EQ("b1", GetSelectedNodeTitle());
178 // Makes sure SetRootShown doesn't blow up.
179 TEST_F(TreeViewTest
, HideRoot
) {
180 tree_
.SetModel(&model_
);
181 tree_
.SetRootShown(false);
182 EXPECT_EQ("root [a b c]", TreeViewContentsAsString());
183 EXPECT_EQ("a", GetSelectedNodeTitle());
184 EXPECT_EQ(3, GetRowCount());
187 // Expands a node and verifies the children are loaded correctly.
188 TEST_F(TreeViewTest
, Expand
) {
189 tree_
.SetModel(&model_
);
190 tree_
.Expand(GetNodeByTitle("b1"));
191 EXPECT_EQ("root [a b [b1] c]", TreeViewContentsAsString());
192 EXPECT_EQ("root",GetSelectedNodeTitle());
193 EXPECT_EQ(5, GetRowCount());
196 // Collapes a node and verifies state.
197 TEST_F(TreeViewTest
, Collapse
) {
198 tree_
.SetModel(&model_
);
199 tree_
.Expand(GetNodeByTitle("b1"));
200 EXPECT_EQ("root [a b [b1] c]", TreeViewContentsAsString());
201 EXPECT_EQ(5, GetRowCount());
202 tree_
.SetSelectedNode(GetNodeByTitle("b1"));
203 EXPECT_EQ("b1", GetSelectedNodeTitle());
204 tree_
.Collapse(GetNodeByTitle("b"));
205 EXPECT_EQ("root [a b c]", TreeViewContentsAsString());
206 // Selected node should have moved to 'b'
207 EXPECT_EQ("b", GetSelectedNodeTitle());
208 EXPECT_EQ(4, GetRowCount());
211 // Verifies adding nodes works.
212 TEST_F(TreeViewTest
, TreeNodesAdded
) {
213 tree_
.SetModel(&model_
);
214 EXPECT_EQ("root [a b c]", TreeViewContentsAsString());
215 // Add a node between b and c.
216 Add(model_
.GetRoot(), 2, "B");
217 EXPECT_EQ("root [a b B c]", TreeViewContentsAsString());
218 EXPECT_EQ("root", GetSelectedNodeTitle());
219 EXPECT_EQ(5, GetRowCount());
221 // Add a child of b1, which hasn't been loaded and shouldn't do anything.
222 Add(GetNodeByTitle("b1"), 0, "b11");
223 EXPECT_EQ("root [a b B c]", TreeViewContentsAsString());
224 EXPECT_EQ("root", GetSelectedNodeTitle());
225 EXPECT_EQ(5, GetRowCount());
227 // Add a child of b, which isn't expanded yet, so it shouldn't effect
229 Add(GetNodeByTitle("b"), 1, "b2");
230 EXPECT_EQ("root [a b B c]", TreeViewContentsAsString());
231 EXPECT_EQ("root", GetSelectedNodeTitle());
232 EXPECT_EQ(5, GetRowCount());
234 // Expand b and make sure b2 is there.
235 tree_
.Expand(GetNodeByTitle("b"));
236 EXPECT_EQ("root [a b [b1 b2] B c]", TreeViewContentsAsString());
237 EXPECT_EQ("root",GetSelectedNodeTitle());
238 EXPECT_EQ(7, GetRowCount());
241 // Verifies removing nodes works.
242 TEST_F(TreeViewTest
, TreeNodesRemoved
) {
243 // Add c1 as a child of c and c11 as a child of c1.
244 Add(Add(GetNodeByTitle("c"), 0, "c1"), 0, "c11");
245 tree_
.SetModel(&model_
);
247 // Remove c11, which shouldn't have any effect on the tree.
248 EXPECT_EQ("root [a b c]", TreeViewContentsAsString());
249 EXPECT_EQ("root", GetSelectedNodeTitle());
250 EXPECT_EQ(4, GetRowCount());
252 // Expand b1, then collapse it and remove its only child, b1. This shouldn't
254 tree_
.Expand(GetNodeByTitle("b"));
255 tree_
.Collapse(GetNodeByTitle("b"));
256 delete model_
.Remove(GetNodeByTitle("b1")->parent(), GetNodeByTitle("b1"));
257 EXPECT_EQ("root [a b c]", TreeViewContentsAsString());
258 EXPECT_EQ("root", GetSelectedNodeTitle());
259 EXPECT_EQ(4, GetRowCount());
262 delete model_
.Remove(GetNodeByTitle("b")->parent(), GetNodeByTitle("b"));
263 EXPECT_EQ("root [a c]", TreeViewContentsAsString());
264 EXPECT_EQ("root", GetSelectedNodeTitle());
265 EXPECT_EQ(3, GetRowCount());
267 // Remove 'c11', shouldn't visually change anything.
268 delete model_
.Remove(GetNodeByTitle("c11")->parent(), GetNodeByTitle("c11"));
269 EXPECT_EQ("root [a c]", TreeViewContentsAsString());
270 EXPECT_EQ("root", GetSelectedNodeTitle());
271 EXPECT_EQ(3, GetRowCount());
273 // Select 'c1', remove 'c' and make sure selection changes.
274 tree_
.SetSelectedNode(GetNodeByTitle("c1"));
275 EXPECT_EQ("c1", GetSelectedNodeTitle());
276 delete model_
.Remove(GetNodeByTitle("c")->parent(), GetNodeByTitle("c"));
277 EXPECT_EQ("root [a]", TreeViewContentsAsString());
278 EXPECT_EQ("root", GetSelectedNodeTitle());
279 EXPECT_EQ(2, GetRowCount());
281 tree_
.SetRootShown(false);
282 // Add 'b' select it and remove it. Because we're not showing the root
283 // selection should change to 'a'.
284 Add(GetNodeByTitle("root"), 1, "b");
285 tree_
.SetSelectedNode(GetNodeByTitle("b"));
286 delete model_
.Remove(GetNodeByTitle("b")->parent(), GetNodeByTitle("b"));
287 EXPECT_EQ("root [a]", TreeViewContentsAsString());
288 EXPECT_EQ("a", GetSelectedNodeTitle());
289 EXPECT_EQ(1, GetRowCount());
292 // Verifies changing a node title works.
293 TEST_F(TreeViewTest
, TreeNodeChanged
) {
294 // Add c1 as a child of c and c11 as a child of c1.
295 Add(Add(GetNodeByTitle("c"), 0, "c1"), 0, "c11");
296 tree_
.SetModel(&model_
);
298 // Change c11, shouldn't do anything.
299 model_
.SetTitle(GetNodeByTitle("c11"), ASCIIToUTF16("c11.new"));
300 EXPECT_EQ("root [a b c]", TreeViewContentsAsString());
301 EXPECT_EQ("root", GetSelectedNodeTitle());
302 EXPECT_EQ(4, GetRowCount());
304 // Change 'b1', shouldn't do anything.
305 model_
.SetTitle(GetNodeByTitle("b1"), ASCIIToUTF16("b1.new"));
306 EXPECT_EQ("root [a b c]", TreeViewContentsAsString());
307 EXPECT_EQ("root", GetSelectedNodeTitle());
308 EXPECT_EQ(4, GetRowCount());
311 model_
.SetTitle(GetNodeByTitle("b"), ASCIIToUTF16("b.new"));
312 EXPECT_EQ("root [a b.new c]", TreeViewContentsAsString());
313 EXPECT_EQ("root", GetSelectedNodeTitle());
314 EXPECT_EQ(4, GetRowCount());
317 // Verifies IncrementSelection() works.
318 TEST_F(TreeViewTest
, IncrementSelection
) {
319 tree_
.SetModel(&model_
);
321 IncrementSelection(true);
322 EXPECT_EQ("a", GetSelectedNodeTitle());
323 IncrementSelection(true);
324 EXPECT_EQ("b", GetSelectedNodeTitle());
325 IncrementSelection(true);
326 tree_
.Expand(GetNodeByTitle("b"));
327 IncrementSelection(false);
328 EXPECT_EQ("b1", GetSelectedNodeTitle());
329 IncrementSelection(true);
330 EXPECT_EQ("c", GetSelectedNodeTitle());
331 IncrementSelection(true);
332 EXPECT_EQ("c", GetSelectedNodeTitle());
334 tree_
.SetRootShown(false);
335 tree_
.SetSelectedNode(GetNodeByTitle("a"));
336 EXPECT_EQ("a", GetSelectedNodeTitle());
337 IncrementSelection(false);
338 EXPECT_EQ("a", GetSelectedNodeTitle());
341 // Verifies CollapseOrSelectParent works.
342 TEST_F(TreeViewTest
, CollapseOrSelectParent
) {
343 tree_
.SetModel(&model_
);
345 tree_
.SetSelectedNode(GetNodeByTitle("root"));
346 CollapseOrSelectParent();
347 EXPECT_EQ("root", TreeViewContentsAsString());
348 EXPECT_EQ("root", GetSelectedNodeTitle());
350 // Hide the root, which should implicitly expand the root.
351 tree_
.SetRootShown(false);
352 EXPECT_EQ("root [a b c]", TreeViewContentsAsString());
353 EXPECT_EQ("a", GetSelectedNodeTitle());
355 tree_
.SetSelectedNode(GetNodeByTitle("b1"));
356 EXPECT_EQ("root [a b [b1] c]", TreeViewContentsAsString());
357 EXPECT_EQ("b1", GetSelectedNodeTitle());
358 CollapseOrSelectParent();
359 EXPECT_EQ("root [a b [b1] c]", TreeViewContentsAsString());
360 EXPECT_EQ("b", GetSelectedNodeTitle());
361 CollapseOrSelectParent();
362 EXPECT_EQ("root [a b c]", TreeViewContentsAsString());
363 EXPECT_EQ("b", GetSelectedNodeTitle());
366 // Verifies ExpandOrSelectChild works.
367 TEST_F(TreeViewTest
, ExpandOrSelectChild
) {
368 tree_
.SetModel(&model_
);
370 tree_
.SetSelectedNode(GetNodeByTitle("root"));
371 ExpandOrSelectChild();
372 EXPECT_EQ("root [a b c]", TreeViewContentsAsString());
373 EXPECT_EQ("a", GetSelectedNodeTitle());
375 ExpandOrSelectChild();
376 EXPECT_EQ("root [a b c]", TreeViewContentsAsString());
377 EXPECT_EQ("a", GetSelectedNodeTitle());
379 tree_
.SetSelectedNode(GetNodeByTitle("b"));
380 ExpandOrSelectChild();
381 EXPECT_EQ("root [a b [b1] c]", TreeViewContentsAsString());
382 EXPECT_EQ("b", GetSelectedNodeTitle());
383 ExpandOrSelectChild();
384 EXPECT_EQ("root [a b [b1] c]", TreeViewContentsAsString());
385 EXPECT_EQ("b1", GetSelectedNodeTitle());
386 ExpandOrSelectChild();
387 EXPECT_EQ("root [a b [b1] c]", TreeViewContentsAsString());
388 EXPECT_EQ("b1", GetSelectedNodeTitle());
391 // Verify selection is properly updated on each keystroke.
392 TEST_F(TreeViewTest
, SelectOnKeyStroke
) {
393 tree_
.SetModel(&model_
);
394 tree_
.ExpandAll(model_
.GetRoot());
395 selector()->InsertText(ASCIIToUTF16("b"));
396 EXPECT_EQ("b", GetSelectedNodeTitle());
397 selector()->InsertText(ASCIIToUTF16("1"));
398 EXPECT_EQ("b1", GetSelectedNodeTitle());
400 // Invoke OnViewBlur() to reset time.
401 selector()->OnViewBlur();
402 selector()->InsertText(ASCIIToUTF16("z"));
403 EXPECT_EQ("b1", GetSelectedNodeTitle());
405 selector()->OnViewBlur();
406 selector()->InsertText(ASCIIToUTF16("a"));
407 EXPECT_EQ("a", GetSelectedNodeTitle());
410 // Verifies edits are committed when focus is lost.
411 TEST_F(TreeViewTest
, CommitOnFocusLost
) {
412 tree_
.SetModel(&model_
);
414 tree_
.SetSelectedNode(GetNodeByTitle("root"));
415 ExpandOrSelectChild();
416 tree_
.SetEditable(true);
417 tree_
.StartEditing(GetNodeByTitle("a"));
418 tree_
.editor()->SetText(ASCIIToUTF16("a changed"));
419 tree_
.OnDidChangeFocus(NULL
, NULL
);
420 EXPECT_TRUE(GetNodeByTitle("a changed") != NULL
);