| OLD | NEW |
| (Empty) |
| 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 <string> | |
| 8 | |
| 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" | |
| 15 | |
| 16 using ui::TreeModel; | |
| 17 using ui::TreeModelNode; | |
| 18 using ui::TreeNode; | |
| 19 | |
| 20 using base::ASCIIToUTF16; | |
| 21 | |
| 22 namespace views { | |
| 23 | |
| 24 class TestNode : public TreeNode<TestNode> { | |
| 25 public: | |
| 26 TestNode() {} | |
| 27 virtual ~TestNode() {} | |
| 28 | |
| 29 private: | |
| 30 DISALLOW_COPY_AND_ASSIGN(TestNode); | |
| 31 }; | |
| 32 | |
| 33 // Creates the following structure: | |
| 34 // 'root' | |
| 35 // 'a' | |
| 36 // 'b' | |
| 37 // 'b1' | |
| 38 // 'c' | |
| 39 class TreeViewTest : public ViewsTestBase { | |
| 40 public: | |
| 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"); | |
| 46 } | |
| 47 | |
| 48 protected: | |
| 49 TestNode* Add(TestNode* parent, | |
| 50 int index, | |
| 51 const std::string& title); | |
| 52 | |
| 53 std::string TreeViewContentsAsString(); | |
| 54 | |
| 55 std::string GetSelectedNodeTitle(); | |
| 56 | |
| 57 std::string GetEditingNodeTitle(); | |
| 58 | |
| 59 TestNode* GetNodeByTitle(const std::string& title); | |
| 60 | |
| 61 void IncrementSelection(bool next); | |
| 62 void CollapseOrSelectParent(); | |
| 63 void ExpandOrSelectChild(); | |
| 64 int GetRowCount(); | |
| 65 PrefixSelector* selector() { return tree_.selector_.get(); } | |
| 66 | |
| 67 ui::TreeNodeModel<TestNode > model_; | |
| 68 TreeView tree_; | |
| 69 | |
| 70 private: | |
| 71 std::string InternalNodeAsString(TreeView::InternalNode* node); | |
| 72 | |
| 73 TestNode* GetNodeByTitleImpl(TestNode* node, const base::string16& title); | |
| 74 | |
| 75 DISALLOW_COPY_AND_ASSIGN(TreeViewTest); | |
| 76 }; | |
| 77 | |
| 78 TestNode* TreeViewTest::Add(TestNode* parent, | |
| 79 int index, | |
| 80 const std::string& title) { | |
| 81 TestNode* new_node = new TestNode; | |
| 82 new_node->SetTitle(ASCIIToUTF16(title)); | |
| 83 model_.Add(parent, new_node, index); | |
| 84 return new_node; | |
| 85 } | |
| 86 | |
| 87 std::string TreeViewTest::TreeViewContentsAsString() { | |
| 88 return InternalNodeAsString(&tree_.root_); | |
| 89 } | |
| 90 | |
| 91 std::string TreeViewTest::GetSelectedNodeTitle() { | |
| 92 TreeModelNode* model_node = tree_.GetSelectedNode(); | |
| 93 return model_node ? base::UTF16ToASCII(model_node->GetTitle()) | |
| 94 : std::string(); | |
| 95 } | |
| 96 | |
| 97 std::string TreeViewTest::GetEditingNodeTitle() { | |
| 98 TreeModelNode* model_node = tree_.GetEditingNode(); | |
| 99 return model_node ? base::UTF16ToASCII(model_node->GetTitle()) | |
| 100 : std::string(); | |
| 101 } | |
| 102 | |
| 103 TestNode* TreeViewTest::GetNodeByTitle(const std::string& title) { | |
| 104 return GetNodeByTitleImpl(model_.GetRoot(), ASCIIToUTF16(title)); | |
| 105 } | |
| 106 | |
| 107 void TreeViewTest::IncrementSelection(bool next) { | |
| 108 tree_.IncrementSelection(next ? TreeView::INCREMENT_NEXT : | |
| 109 TreeView::INCREMENT_PREVIOUS); | |
| 110 } | |
| 111 | |
| 112 void TreeViewTest::CollapseOrSelectParent() { | |
| 113 tree_.CollapseOrSelectParent(); | |
| 114 } | |
| 115 | |
| 116 void TreeViewTest::ExpandOrSelectChild() { | |
| 117 tree_.ExpandOrSelectChild(); | |
| 118 } | |
| 119 | |
| 120 int TreeViewTest::GetRowCount() { | |
| 121 return tree_.GetRowCount(); | |
| 122 } | |
| 123 | |
| 124 TestNode* TreeViewTest::GetNodeByTitleImpl(TestNode* node, | |
| 125 const base::string16& title) { | |
| 126 if (node->GetTitle() == title) | |
| 127 return node; | |
| 128 for (int i = 0; i < node->child_count(); ++i) { | |
| 129 TestNode* child = GetNodeByTitleImpl(node->GetChild(i), title); | |
| 130 if (child) | |
| 131 return child; | |
| 132 } | |
| 133 return NULL; | |
| 134 } | |
| 135 | |
| 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()) { | |
| 140 result += " ["; | |
| 141 for (int i = 0; i < node->child_count(); ++i) { | |
| 142 if (i > 0) | |
| 143 result += " "; | |
| 144 result += InternalNodeAsString(node->GetChild(i)); | |
| 145 } | |
| 146 result += "]"; | |
| 147 } | |
| 148 return result; | |
| 149 } | |
| 150 | |
| 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()); | |
| 157 } | |
| 158 | |
| 159 // Verifies SetSelectedNode works. | |
| 160 TEST_F(TreeViewTest, SetSelectedNode) { | |
| 161 tree_.SetModel(&model_); | |
| 162 EXPECT_EQ("root", GetSelectedNodeTitle()); | |
| 163 | |
| 164 // NULL should clear the selection. | |
| 165 tree_.SetSelectedNode(NULL); | |
| 166 EXPECT_EQ(std::string(), GetSelectedNodeTitle()); | |
| 167 | |
| 168 // Select 'c'. | |
| 169 tree_.SetSelectedNode(GetNodeByTitle("c")); | |
| 170 EXPECT_EQ("c", GetSelectedNodeTitle()); | |
| 171 | |
| 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()); | |
| 176 } | |
| 177 | |
| 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()); | |
| 185 } | |
| 186 | |
| 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()); | |
| 194 } | |
| 195 | |
| 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()); | |
| 209 } | |
| 210 | |
| 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()); | |
| 220 | |
| 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()); | |
| 226 | |
| 227 // Add a child of b, which isn't expanded yet, so it shouldn't effect | |
| 228 // anything. | |
| 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()); | |
| 233 | |
| 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()); | |
| 239 } | |
| 240 | |
| 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_); | |
| 246 | |
| 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()); | |
| 251 | |
| 252 // Expand b1, then collapse it and remove its only child, b1. This shouldn't | |
| 253 // effect the tree. | |
| 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()); | |
| 260 | |
| 261 // Remove 'b'. | |
| 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()); | |
| 266 | |
| 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()); | |
| 272 | |
| 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()); | |
| 280 | |
| 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()); | |
| 290 } | |
| 291 | |
| 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_); | |
| 297 | |
| 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()); | |
| 303 | |
| 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()); | |
| 309 | |
| 310 // Change 'b'. | |
| 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()); | |
| 315 } | |
| 316 | |
| 317 // Verifies IncrementSelection() works. | |
| 318 TEST_F(TreeViewTest, IncrementSelection) { | |
| 319 tree_.SetModel(&model_); | |
| 320 | |
| 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()); | |
| 333 | |
| 334 tree_.SetRootShown(false); | |
| 335 tree_.SetSelectedNode(GetNodeByTitle("a")); | |
| 336 EXPECT_EQ("a", GetSelectedNodeTitle()); | |
| 337 IncrementSelection(false); | |
| 338 EXPECT_EQ("a", GetSelectedNodeTitle()); | |
| 339 } | |
| 340 | |
| 341 // Verifies CollapseOrSelectParent works. | |
| 342 TEST_F(TreeViewTest, CollapseOrSelectParent) { | |
| 343 tree_.SetModel(&model_); | |
| 344 | |
| 345 tree_.SetSelectedNode(GetNodeByTitle("root")); | |
| 346 CollapseOrSelectParent(); | |
| 347 EXPECT_EQ("root", TreeViewContentsAsString()); | |
| 348 EXPECT_EQ("root", GetSelectedNodeTitle()); | |
| 349 | |
| 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()); | |
| 354 | |
| 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()); | |
| 364 } | |
| 365 | |
| 366 // Verifies ExpandOrSelectChild works. | |
| 367 TEST_F(TreeViewTest, ExpandOrSelectChild) { | |
| 368 tree_.SetModel(&model_); | |
| 369 | |
| 370 tree_.SetSelectedNode(GetNodeByTitle("root")); | |
| 371 ExpandOrSelectChild(); | |
| 372 EXPECT_EQ("root [a b c]", TreeViewContentsAsString()); | |
| 373 EXPECT_EQ("a", GetSelectedNodeTitle()); | |
| 374 | |
| 375 ExpandOrSelectChild(); | |
| 376 EXPECT_EQ("root [a b c]", TreeViewContentsAsString()); | |
| 377 EXPECT_EQ("a", GetSelectedNodeTitle()); | |
| 378 | |
| 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()); | |
| 389 } | |
| 390 | |
| 391 // Verify selection is properly updated on each keystroke. | |
| 392 TEST_F(TreeViewTest, SelectOnKeyStroke) { | |
| 393 tree_.SetModel(&model_); | |
| 394 tree_.ExpandAll(model_.GetRoot()); | |
| 395 tree_.GetTextInputClient(); | |
| 396 selector()->InsertText(ASCIIToUTF16("b")); | |
| 397 EXPECT_EQ("b", GetSelectedNodeTitle()); | |
| 398 selector()->InsertText(ASCIIToUTF16("1")); | |
| 399 EXPECT_EQ("b1", GetSelectedNodeTitle()); | |
| 400 | |
| 401 // Invoke OnViewBlur() to reset time. | |
| 402 selector()->OnViewBlur(); | |
| 403 selector()->InsertText(ASCIIToUTF16("z")); | |
| 404 EXPECT_EQ("b1", GetSelectedNodeTitle()); | |
| 405 | |
| 406 selector()->OnViewBlur(); | |
| 407 selector()->InsertText(ASCIIToUTF16("a")); | |
| 408 EXPECT_EQ("a", GetSelectedNodeTitle()); | |
| 409 } | |
| 410 | |
| 411 // Verifies edits are committed when focus is lost. | |
| 412 TEST_F(TreeViewTest, CommitOnFocusLost) { | |
| 413 tree_.SetModel(&model_); | |
| 414 | |
| 415 tree_.SetSelectedNode(GetNodeByTitle("root")); | |
| 416 ExpandOrSelectChild(); | |
| 417 tree_.SetEditable(true); | |
| 418 tree_.StartEditing(GetNodeByTitle("a")); | |
| 419 tree_.editor()->SetText(ASCIIToUTF16("a changed")); | |
| 420 tree_.OnDidChangeFocus(NULL, NULL); | |
| 421 EXPECT_TRUE(GetNodeByTitle("a changed") != NULL); | |
| 422 } | |
| 423 | |
| 424 } // namespace views | |
| OLD | NEW |