Demonstrate the basic functionality of the File System
[chromium-blink-merge.git] / ui / views / controls / table / table_view_unittest.cc
blob1d59358d31eebe28d93c64579ccf6176e3a20e20
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/table/table_view.h"
7 #include "base/strings/string_number_conversions.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "testing/gtest/include/gtest/gtest.h"
10 #include "ui/views/controls/table/table_grouper.h"
11 #include "ui/views/controls/table/table_header.h"
12 #include "ui/views/controls/table/table_view_observer.h"
14 // Put the tests in the views namespace to make it easier to declare them as
15 // friend classes.
16 namespace views {
18 class TableViewTestHelper {
19 public:
20 explicit TableViewTestHelper(TableView* table) : table_(table) {}
22 std::string GetPaintRegion(const gfx::Rect& bounds) {
23 TableView::PaintRegion region(table_->GetPaintRegion(bounds));
24 return "rows=" + base::IntToString(region.min_row) + " " +
25 base::IntToString(region.max_row) + " cols=" +
26 base::IntToString(region.min_column) + " " +
27 base::IntToString(region.max_column);
30 size_t visible_col_count() {
31 return table_->visible_columns().size();
34 TableHeader* header() { return table_->header_; }
36 private:
37 TableView* table_;
39 DISALLOW_COPY_AND_ASSIGN(TableViewTestHelper);
42 namespace {
44 // TestTableModel2 -------------------------------------------------------------
46 // Trivial TableModel implementation that is backed by a vector of vectors.
47 // Provides methods for adding/removing/changing the contents that notify the
48 // observer appropriately.
50 // Initial contents are:
51 // 0, 1
52 // 1, 1
53 // 2, 2
54 // 3, 0
55 class TestTableModel2 : public ui::TableModel {
56 public:
57 TestTableModel2();
59 // Adds a new row at index |row| with values |c1_value| and |c2_value|.
60 void AddRow(int row, int c1_value, int c2_value);
62 // Removes the row at index |row|.
63 void RemoveRow(int row);
65 // Changes the values of the row at |row|.
66 void ChangeRow(int row, int c1_value, int c2_value);
68 // ui::TableModel:
69 virtual int RowCount() OVERRIDE;
70 virtual base::string16 GetText(int row, int column_id) OVERRIDE;
71 virtual void SetObserver(ui::TableModelObserver* observer) OVERRIDE;
72 virtual int CompareValues(int row1, int row2, int column_id) OVERRIDE;
74 private:
75 ui::TableModelObserver* observer_;
77 // The data.
78 std::vector<std::vector<int> > rows_;
80 DISALLOW_COPY_AND_ASSIGN(TestTableModel2);
83 TestTableModel2::TestTableModel2() : observer_(NULL) {
84 AddRow(0, 0, 1);
85 AddRow(1, 1, 1);
86 AddRow(2, 2, 2);
87 AddRow(3, 3, 0);
90 void TestTableModel2::AddRow(int row, int c1_value, int c2_value) {
91 DCHECK(row >= 0 && row <= static_cast<int>(rows_.size()));
92 std::vector<int> new_row;
93 new_row.push_back(c1_value);
94 new_row.push_back(c2_value);
95 rows_.insert(rows_.begin() + row, new_row);
96 if (observer_)
97 observer_->OnItemsAdded(row, 1);
99 void TestTableModel2::RemoveRow(int row) {
100 DCHECK(row >= 0 && row <= static_cast<int>(rows_.size()));
101 rows_.erase(rows_.begin() + row);
102 if (observer_)
103 observer_->OnItemsRemoved(row, 1);
106 void TestTableModel2::ChangeRow(int row, int c1_value, int c2_value) {
107 DCHECK(row >= 0 && row < static_cast<int>(rows_.size()));
108 rows_[row][0] = c1_value;
109 rows_[row][1] = c2_value;
110 if (observer_)
111 observer_->OnItemsChanged(row, 1);
114 int TestTableModel2::RowCount() {
115 return static_cast<int>(rows_.size());
118 base::string16 TestTableModel2::GetText(int row, int column_id) {
119 return base::IntToString16(rows_[row][column_id]);
122 void TestTableModel2::SetObserver(ui::TableModelObserver* observer) {
123 observer_ = observer;
126 int TestTableModel2::CompareValues(int row1, int row2, int column_id) {
127 return rows_[row1][column_id] - rows_[row2][column_id];
130 // Returns the view to model mapping as a string.
131 std::string GetViewToModelAsString(TableView* table) {
132 std::string result;
133 for (int i = 0; i < table->RowCount(); ++i) {
134 if (i != 0)
135 result += " ";
136 result += base::IntToString(table->ViewToModel(i));
138 return result;
141 // Returns the model to view mapping as a string.
142 std::string GetModelToViewAsString(TableView* table) {
143 std::string result;
144 for (int i = 0; i < table->RowCount(); ++i) {
145 if (i != 0)
146 result += " ";
147 result += base::IntToString(table->ModelToView(i));
149 return result;
152 class TestTableView : public TableView {
153 public:
154 TestTableView(ui::TableModel* model,
155 const std::vector<ui::TableColumn>& columns)
156 : TableView(model, columns, TEXT_ONLY, false) {
159 // View overrides:
160 virtual bool HasFocus() const OVERRIDE {
161 // Overriden so key processing works.
162 return true;
165 private:
166 DISALLOW_COPY_AND_ASSIGN(TestTableView);
169 } // namespace
171 class TableViewTest : public testing::Test {
172 public:
173 TableViewTest() : table_(NULL) {}
175 virtual void SetUp() OVERRIDE {
176 model_.reset(new TestTableModel2);
177 std::vector<ui::TableColumn> columns(2);
178 columns[0].title = base::ASCIIToUTF16("Title Column 0");
179 columns[0].sortable = true;
180 columns[1].title = base::ASCIIToUTF16("Title Column 1");
181 columns[1].id = 1;
182 columns[1].sortable = true;
183 table_ = new TestTableView(model_.get(), columns);
184 parent_.reset(table_->CreateParentIfNecessary());
185 parent_->SetBounds(0, 0, 10000, 10000);
186 parent_->Layout();
187 helper_.reset(new TableViewTestHelper(table_));
190 void ClickOnRow(int row, int flags) {
191 const int y = row * table_->row_height();
192 const ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED, gfx::Point(0, y),
193 gfx::Point(0, y),
194 ui::EF_LEFT_MOUSE_BUTTON | flags,
195 ui::EF_LEFT_MOUSE_BUTTON);
196 table_->OnMousePressed(pressed);
199 void TapOnRow(int row) {
200 const int y = row * table_->row_height();
201 const ui::GestureEventDetails event_details(ui::ET_GESTURE_TAP,
202 .0f, .0f);
203 ui::GestureEvent tap(ui::ET_GESTURE_TAP, 0, y, 0, base::TimeDelta(),
204 event_details, 1);
205 table_->OnGestureEvent(&tap);
208 // Returns the state of the selection model as a string. The format is:
209 // 'active=X anchor=X selection=X X X...'.
210 std::string SelectionStateAsString() const {
211 const ui::ListSelectionModel& model(table_->selection_model());
212 std::string result = "active=" + base::IntToString(model.active()) +
213 " anchor=" + base::IntToString(model.anchor()) +
214 " selection=";
215 const ui::ListSelectionModel::SelectedIndices& selection(
216 model.selected_indices());
217 for (size_t i = 0; i < selection.size(); ++i) {
218 if (i != 0)
219 result += " ";
220 result += base::IntToString(selection[i]);
222 return result;
225 void PressKey(ui::KeyboardCode code) {
226 ui::KeyEvent event(ui::ET_KEY_PRESSED, code, 0, false);
227 table_->OnKeyPressed(event);
230 protected:
231 scoped_ptr<TestTableModel2> model_;
233 // Owned by |parent_|.
234 TableView* table_;
236 scoped_ptr<TableViewTestHelper> helper_;
238 private:
239 scoped_ptr<View> parent_;
241 DISALLOW_COPY_AND_ASSIGN(TableViewTest);
244 // Verifies GetPaintRegion.
245 TEST_F(TableViewTest, GetPaintRegion) {
246 // Two columns should be visible.
247 EXPECT_EQ(2u, helper_->visible_col_count());
249 EXPECT_EQ("rows=0 4 cols=0 2", helper_->GetPaintRegion(table_->bounds()));
250 EXPECT_EQ("rows=0 4 cols=0 1",
251 helper_->GetPaintRegion(gfx::Rect(0, 0, 1, table_->height())));
254 // Verifies SetColumnVisibility().
255 TEST_F(TableViewTest, ColumnVisibility) {
256 // Two columns should be visible.
257 EXPECT_EQ(2u, helper_->visible_col_count());
259 // Should do nothing (column already visible).
260 table_->SetColumnVisibility(0, true);
261 EXPECT_EQ(2u, helper_->visible_col_count());
263 // Hide the first column.
264 table_->SetColumnVisibility(0, false);
265 ASSERT_EQ(1u, helper_->visible_col_count());
266 EXPECT_EQ(1, table_->visible_columns()[0].column.id);
267 EXPECT_EQ("rows=0 4 cols=0 1", helper_->GetPaintRegion(table_->bounds()));
269 // Hide the second column.
270 table_->SetColumnVisibility(1, false);
271 EXPECT_EQ(0u, helper_->visible_col_count());
273 // Show the second column.
274 table_->SetColumnVisibility(1, true);
275 ASSERT_EQ(1u, helper_->visible_col_count());
276 EXPECT_EQ(1, table_->visible_columns()[0].column.id);
277 EXPECT_EQ("rows=0 4 cols=0 1", helper_->GetPaintRegion(table_->bounds()));
279 // Show the first column.
280 table_->SetColumnVisibility(0, true);
281 ASSERT_EQ(2u, helper_->visible_col_count());
282 EXPECT_EQ(1, table_->visible_columns()[0].column.id);
283 EXPECT_EQ(0, table_->visible_columns()[1].column.id);
284 EXPECT_EQ("rows=0 4 cols=0 2", helper_->GetPaintRegion(table_->bounds()));
287 // Verifies resizing a column works.
288 TEST_F(TableViewTest, Resize) {
289 const int x = table_->visible_columns()[0].width;
290 EXPECT_NE(0, x);
291 // Drag the mouse 1 pixel to the left.
292 const ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED, gfx::Point(x, 0),
293 gfx::Point(x, 0), ui::EF_LEFT_MOUSE_BUTTON,
294 ui::EF_LEFT_MOUSE_BUTTON);
295 helper_->header()->OnMousePressed(pressed);
296 const ui::MouseEvent dragged(ui::ET_MOUSE_DRAGGED, gfx::Point(x - 1, 0),
297 gfx::Point(x - 1, 0), ui::EF_LEFT_MOUSE_BUTTON,
299 helper_->header()->OnMouseDragged(dragged);
301 // This should shrink the first column and pull the second column in.
302 EXPECT_EQ(x - 1, table_->visible_columns()[0].width);
303 EXPECT_EQ(x - 1, table_->visible_columns()[1].x);
306 // Verifies resizing a column works with a gesture.
307 TEST_F(TableViewTest, ResizeViaGesture) {
308 const int x = table_->visible_columns()[0].width;
309 EXPECT_NE(0, x);
310 // Drag the mouse 1 pixel to the left.
311 const ui::GestureEventDetails event_details(ui::ET_GESTURE_SCROLL_BEGIN,
312 .0f, .0f);
313 ui::GestureEvent scroll_begin(ui::ET_GESTURE_SCROLL_BEGIN, x, 0, 0,
314 base::TimeDelta(), event_details, 1);
315 helper_->header()->OnGestureEvent(&scroll_begin);
316 ui::GestureEvent scroll_update(ui::ET_GESTURE_SCROLL_UPDATE, x - 1, 0,
317 0, base::TimeDelta(), event_details, 1);
318 helper_->header()->OnGestureEvent(&scroll_update);
320 // This should shrink the first column and pull the second column in.
321 EXPECT_EQ(x - 1, table_->visible_columns()[0].width);
322 EXPECT_EQ(x - 1, table_->visible_columns()[1].x);
325 // Assertions for table sorting.
326 TEST_F(TableViewTest, Sort) {
327 // Toggle the sort order of the first column, shouldn't change anything.
328 table_->ToggleSortOrder(0);
329 ASSERT_EQ(1u, table_->sort_descriptors().size());
330 EXPECT_EQ(0, table_->sort_descriptors()[0].column_id);
331 EXPECT_TRUE(table_->sort_descriptors()[0].ascending);
332 EXPECT_EQ("0 1 2 3", GetViewToModelAsString(table_));
333 EXPECT_EQ("0 1 2 3", GetModelToViewAsString(table_));
335 // Invert the sort (first column descending).
336 table_->ToggleSortOrder(0);
337 ASSERT_EQ(1u, table_->sort_descriptors().size());
338 EXPECT_EQ(0, table_->sort_descriptors()[0].column_id);
339 EXPECT_FALSE(table_->sort_descriptors()[0].ascending);
340 EXPECT_EQ("3 2 1 0", GetViewToModelAsString(table_));
341 EXPECT_EQ("3 2 1 0", GetModelToViewAsString(table_));
343 // Change cell 0x3 to -1, meaning we have 0, 1, 2, -1 (in the first column).
344 model_->ChangeRow(3, -1, 0);
345 ASSERT_EQ(1u, table_->sort_descriptors().size());
346 EXPECT_EQ(0, table_->sort_descriptors()[0].column_id);
347 EXPECT_FALSE(table_->sort_descriptors()[0].ascending);
348 EXPECT_EQ("2 1 0 3", GetViewToModelAsString(table_));
349 EXPECT_EQ("2 1 0 3", GetModelToViewAsString(table_));
351 // Invert sort again (first column ascending).
352 table_->ToggleSortOrder(0);
353 ASSERT_EQ(1u, table_->sort_descriptors().size());
354 EXPECT_EQ(0, table_->sort_descriptors()[0].column_id);
355 EXPECT_TRUE(table_->sort_descriptors()[0].ascending);
356 EXPECT_EQ("3 0 1 2", GetViewToModelAsString(table_));
357 EXPECT_EQ("1 2 3 0", GetModelToViewAsString(table_));
359 // Add a row so that model has 0, 3, 1, 2, -1.
360 model_->AddRow(1, 3, 4);
361 ASSERT_EQ(1u, table_->sort_descriptors().size());
362 EXPECT_EQ(0, table_->sort_descriptors()[0].column_id);
363 EXPECT_TRUE(table_->sort_descriptors()[0].ascending);
364 EXPECT_EQ("4 0 2 3 1", GetViewToModelAsString(table_));
365 EXPECT_EQ("1 4 2 3 0", GetModelToViewAsString(table_));
367 // Delete the first row, ending up with 3, 1, 2, -1.
368 model_->RemoveRow(0);
369 ASSERT_EQ(1u, table_->sort_descriptors().size());
370 EXPECT_EQ(0, table_->sort_descriptors()[0].column_id);
371 EXPECT_TRUE(table_->sort_descriptors()[0].ascending);
372 EXPECT_EQ("3 1 2 0", GetViewToModelAsString(table_));
373 EXPECT_EQ("3 1 2 0", GetModelToViewAsString(table_));
376 // Verfies clicking on the header sorts.
377 TEST_F(TableViewTest, SortOnMouse) {
378 EXPECT_TRUE(table_->sort_descriptors().empty());
380 const int x = table_->visible_columns()[0].width / 2;
381 EXPECT_NE(0, x);
382 // Press and release the mouse.
383 const ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED, gfx::Point(x, 0),
384 gfx::Point(x, 0), ui::EF_LEFT_MOUSE_BUTTON,
385 ui::EF_LEFT_MOUSE_BUTTON);
386 // The header must return true, else it won't normally get the release.
387 EXPECT_TRUE(helper_->header()->OnMousePressed(pressed));
388 const ui::MouseEvent release(ui::ET_MOUSE_RELEASED, gfx::Point(x, 0),
389 gfx::Point(x, 0), ui::EF_LEFT_MOUSE_BUTTON,
390 ui::EF_LEFT_MOUSE_BUTTON);
391 helper_->header()->OnMouseReleased(release);
393 ASSERT_EQ(1u, table_->sort_descriptors().size());
394 EXPECT_EQ(0, table_->sort_descriptors()[0].column_id);
395 EXPECT_TRUE(table_->sort_descriptors()[0].ascending);
398 namespace {
400 class TableGrouperImpl : public TableGrouper {
401 public:
402 TableGrouperImpl() {}
404 void SetRanges(const std::vector<int>& ranges) {
405 ranges_ = ranges;
408 // TableGrouper overrides:
409 virtual void GetGroupRange(int model_index, GroupRange* range) OVERRIDE {
410 int offset = 0;
411 size_t range_index = 0;
412 for (; range_index < ranges_.size() && offset < model_index; ++range_index)
413 offset += ranges_[range_index];
415 if (offset == model_index) {
416 range->start = model_index;
417 range->length = ranges_[range_index];
418 } else {
419 range->start = offset - ranges_[range_index - 1];
420 range->length = ranges_[range_index - 1];
424 private:
425 std::vector<int> ranges_;
427 DISALLOW_COPY_AND_ASSIGN(TableGrouperImpl);
430 } // namespace
432 // Assertions around grouping.
433 TEST_F(TableViewTest, Grouping) {
434 // Configure the grouper so that there are two groups:
435 // A 0
436 // 1
437 // B 2
438 // 3
439 TableGrouperImpl grouper;
440 std::vector<int> ranges;
441 ranges.push_back(2);
442 ranges.push_back(2);
443 grouper.SetRanges(ranges);
444 table_->SetGrouper(&grouper);
446 // Toggle the sort order of the first column, shouldn't change anything.
447 table_->ToggleSortOrder(0);
448 ASSERT_EQ(1u, table_->sort_descriptors().size());
449 EXPECT_EQ(0, table_->sort_descriptors()[0].column_id);
450 EXPECT_TRUE(table_->sort_descriptors()[0].ascending);
451 EXPECT_EQ("0 1 2 3", GetViewToModelAsString(table_));
452 EXPECT_EQ("0 1 2 3", GetModelToViewAsString(table_));
454 // Sort descending, resulting:
455 // B 2
456 // 3
457 // A 0
458 // 1
459 table_->ToggleSortOrder(0);
460 ASSERT_EQ(1u, table_->sort_descriptors().size());
461 EXPECT_EQ(0, table_->sort_descriptors()[0].column_id);
462 EXPECT_FALSE(table_->sort_descriptors()[0].ascending);
463 EXPECT_EQ("2 3 0 1", GetViewToModelAsString(table_));
464 EXPECT_EQ("2 3 0 1", GetModelToViewAsString(table_));
466 // Change the entry in the 4th row to -1. The model now becomes:
467 // A 0
468 // 1
469 // B 2
470 // -1
471 // Since the first entry in the range didn't change the sort isn't impacted.
472 model_->ChangeRow(3, -1, 0);
473 ASSERT_EQ(1u, table_->sort_descriptors().size());
474 EXPECT_EQ(0, table_->sort_descriptors()[0].column_id);
475 EXPECT_FALSE(table_->sort_descriptors()[0].ascending);
476 EXPECT_EQ("2 3 0 1", GetViewToModelAsString(table_));
477 EXPECT_EQ("2 3 0 1", GetModelToViewAsString(table_));
479 // Change the entry in the 3rd row to -1. The model now becomes:
480 // A 0
481 // 1
482 // B -1
483 // -1
484 model_->ChangeRow(2, -1, 0);
485 ASSERT_EQ(1u, table_->sort_descriptors().size());
486 EXPECT_EQ(0, table_->sort_descriptors()[0].column_id);
487 EXPECT_FALSE(table_->sort_descriptors()[0].ascending);
488 EXPECT_EQ("0 1 2 3", GetViewToModelAsString(table_));
489 EXPECT_EQ("0 1 2 3", GetModelToViewAsString(table_));
491 // Toggle to ascending sort.
492 table_->ToggleSortOrder(0);
493 ASSERT_EQ(1u, table_->sort_descriptors().size());
494 EXPECT_EQ(0, table_->sort_descriptors()[0].column_id);
495 EXPECT_TRUE(table_->sort_descriptors()[0].ascending);
496 EXPECT_EQ("2 3 0 1", GetViewToModelAsString(table_));
497 EXPECT_EQ("2 3 0 1", GetModelToViewAsString(table_));
500 namespace {
502 class TableViewObserverImpl : public TableViewObserver {
503 public:
504 TableViewObserverImpl() : selection_changed_count_(0) {}
506 int GetChangedCountAndClear() {
507 const int count = selection_changed_count_;
508 selection_changed_count_ = 0;
509 return count;
512 // TableViewObserver overrides:
513 virtual void OnSelectionChanged() OVERRIDE {
514 selection_changed_count_++;
517 private:
518 int selection_changed_count_;
520 DISALLOW_COPY_AND_ASSIGN(TableViewObserverImpl);
523 } // namespace
525 // Assertions around changing the selection.
526 TEST_F(TableViewTest, Selection) {
527 TableViewObserverImpl observer;
528 table_->SetObserver(&observer);
530 // Initially no selection.
531 EXPECT_EQ("active=-1 anchor=-1 selection=", SelectionStateAsString());
533 // Select the last row.
534 table_->Select(3);
535 EXPECT_EQ(1, observer.GetChangedCountAndClear());
536 EXPECT_EQ("active=3 anchor=3 selection=3", SelectionStateAsString());
538 // Change sort, shouldn't notify of change (toggle twice so that order
539 // actually changes).
540 table_->ToggleSortOrder(0);
541 table_->ToggleSortOrder(0);
542 EXPECT_EQ(0, observer.GetChangedCountAndClear());
543 EXPECT_EQ("active=3 anchor=3 selection=3", SelectionStateAsString());
545 // Remove the selected row, this should notify of a change and update the
546 // selection.
547 model_->RemoveRow(3);
548 EXPECT_EQ(1, observer.GetChangedCountAndClear());
549 EXPECT_EQ("active=2 anchor=2 selection=2", SelectionStateAsString());
551 // Insert a row, since the selection in terms of the original model hasn't
552 // changed the observer is not notified.
553 model_->AddRow(0, 1, 2);
554 EXPECT_EQ(0, observer.GetChangedCountAndClear());
555 EXPECT_EQ("active=3 anchor=3 selection=3", SelectionStateAsString());
557 table_->SetObserver(NULL);
560 // Verifies selection works by way of a gesture.
561 TEST_F(TableViewTest, SelectOnTap) {
562 // Initially no selection.
563 EXPECT_EQ("active=-1 anchor=-1 selection=", SelectionStateAsString());
565 TableViewObserverImpl observer;
566 table_->SetObserver(&observer);
568 // Click on the first row, should select it.
569 TapOnRow(0);
570 EXPECT_EQ(1, observer.GetChangedCountAndClear());
571 EXPECT_EQ("active=0 anchor=0 selection=0", SelectionStateAsString());
573 table_->SetObserver(NULL);
576 // Verifies up/down correctly navigates through groups.
577 TEST_F(TableViewTest, KeyUpDown) {
578 // Configure the grouper so that there are three groups:
579 // A 0
580 // 1
581 // B 5
582 // C 2
583 // 3
584 model_->AddRow(2, 5, 0);
585 TableGrouperImpl grouper;
586 std::vector<int> ranges;
587 ranges.push_back(2);
588 ranges.push_back(1);
589 ranges.push_back(2);
590 grouper.SetRanges(ranges);
591 table_->SetGrouper(&grouper);
593 TableViewObserverImpl observer;
594 table_->SetObserver(&observer);
596 // Initially no selection.
597 EXPECT_EQ("active=-1 anchor=-1 selection=", SelectionStateAsString());
599 PressKey(ui::VKEY_DOWN);
600 EXPECT_EQ(1, observer.GetChangedCountAndClear());
601 EXPECT_EQ("active=0 anchor=0 selection=0 1", SelectionStateAsString());
603 PressKey(ui::VKEY_DOWN);
604 EXPECT_EQ(1, observer.GetChangedCountAndClear());
605 EXPECT_EQ("active=1 anchor=1 selection=0 1", SelectionStateAsString());
607 PressKey(ui::VKEY_DOWN);
608 EXPECT_EQ(1, observer.GetChangedCountAndClear());
609 EXPECT_EQ("active=2 anchor=2 selection=2", SelectionStateAsString());
611 PressKey(ui::VKEY_DOWN);
612 EXPECT_EQ(1, observer.GetChangedCountAndClear());
613 EXPECT_EQ("active=3 anchor=3 selection=3 4", SelectionStateAsString());
615 PressKey(ui::VKEY_DOWN);
616 EXPECT_EQ(1, observer.GetChangedCountAndClear());
617 EXPECT_EQ("active=4 anchor=4 selection=3 4", SelectionStateAsString());
619 PressKey(ui::VKEY_DOWN);
620 EXPECT_EQ(0, observer.GetChangedCountAndClear());
621 EXPECT_EQ("active=4 anchor=4 selection=3 4", SelectionStateAsString());
623 PressKey(ui::VKEY_UP);
624 EXPECT_EQ(1, observer.GetChangedCountAndClear());
625 EXPECT_EQ("active=3 anchor=3 selection=3 4", SelectionStateAsString());
627 PressKey(ui::VKEY_UP);
628 EXPECT_EQ(1, observer.GetChangedCountAndClear());
629 EXPECT_EQ("active=2 anchor=2 selection=2", SelectionStateAsString());
631 PressKey(ui::VKEY_UP);
632 EXPECT_EQ(1, observer.GetChangedCountAndClear());
633 EXPECT_EQ("active=1 anchor=1 selection=0 1", SelectionStateAsString());
635 PressKey(ui::VKEY_UP);
636 EXPECT_EQ(1, observer.GetChangedCountAndClear());
637 EXPECT_EQ("active=0 anchor=0 selection=0 1", SelectionStateAsString());
639 PressKey(ui::VKEY_UP);
640 EXPECT_EQ(0, observer.GetChangedCountAndClear());
641 EXPECT_EQ("active=0 anchor=0 selection=0 1", SelectionStateAsString());
643 // Sort the table descending by column 1, view now looks like:
644 // B 5 model: 2
645 // C 2 3
646 // 3 4
647 // A 0 0
648 // 1 1
649 table_->ToggleSortOrder(0);
650 table_->ToggleSortOrder(0);
652 EXPECT_EQ("2 3 4 0 1", GetViewToModelAsString(table_));
654 table_->Select(-1);
655 EXPECT_EQ("active=-1 anchor=-1 selection=", SelectionStateAsString());
657 observer.GetChangedCountAndClear();
658 // Up with nothing selected selects the first row.
659 PressKey(ui::VKEY_UP);
660 EXPECT_EQ(1, observer.GetChangedCountAndClear());
661 EXPECT_EQ("active=2 anchor=2 selection=2", SelectionStateAsString());
663 PressKey(ui::VKEY_DOWN);
664 EXPECT_EQ(1, observer.GetChangedCountAndClear());
665 EXPECT_EQ("active=3 anchor=3 selection=3 4", SelectionStateAsString());
667 PressKey(ui::VKEY_DOWN);
668 EXPECT_EQ(1, observer.GetChangedCountAndClear());
669 EXPECT_EQ("active=4 anchor=4 selection=3 4", SelectionStateAsString());
671 PressKey(ui::VKEY_DOWN);
672 EXPECT_EQ(1, observer.GetChangedCountAndClear());
673 EXPECT_EQ("active=0 anchor=0 selection=0 1", SelectionStateAsString());
675 PressKey(ui::VKEY_DOWN);
676 EXPECT_EQ(1, observer.GetChangedCountAndClear());
677 EXPECT_EQ("active=1 anchor=1 selection=0 1", SelectionStateAsString());
679 PressKey(ui::VKEY_DOWN);
680 EXPECT_EQ(0, observer.GetChangedCountAndClear());
681 EXPECT_EQ("active=1 anchor=1 selection=0 1", SelectionStateAsString());
683 PressKey(ui::VKEY_UP);
684 EXPECT_EQ(1, observer.GetChangedCountAndClear());
685 EXPECT_EQ("active=0 anchor=0 selection=0 1", SelectionStateAsString());
687 PressKey(ui::VKEY_UP);
688 EXPECT_EQ(1, observer.GetChangedCountAndClear());
689 EXPECT_EQ("active=4 anchor=4 selection=3 4", SelectionStateAsString());
691 PressKey(ui::VKEY_UP);
692 EXPECT_EQ(1, observer.GetChangedCountAndClear());
693 EXPECT_EQ("active=3 anchor=3 selection=3 4", SelectionStateAsString());
695 PressKey(ui::VKEY_UP);
696 EXPECT_EQ(1, observer.GetChangedCountAndClear());
697 EXPECT_EQ("active=2 anchor=2 selection=2", SelectionStateAsString());
699 PressKey(ui::VKEY_UP);
700 EXPECT_EQ(0, observer.GetChangedCountAndClear());
701 EXPECT_EQ("active=2 anchor=2 selection=2", SelectionStateAsString());
703 table_->SetObserver(NULL);
706 // Verifies home/end do the right thing.
707 TEST_F(TableViewTest, HomeEnd) {
708 // Configure the grouper so that there are three groups:
709 // A 0
710 // 1
711 // B 5
712 // C 2
713 // 3
714 model_->AddRow(2, 5, 0);
715 TableGrouperImpl grouper;
716 std::vector<int> ranges;
717 ranges.push_back(2);
718 ranges.push_back(1);
719 ranges.push_back(2);
720 grouper.SetRanges(ranges);
721 table_->SetGrouper(&grouper);
723 TableViewObserverImpl observer;
724 table_->SetObserver(&observer);
726 // Initially no selection.
727 EXPECT_EQ("active=-1 anchor=-1 selection=", SelectionStateAsString());
729 PressKey(ui::VKEY_HOME);
730 EXPECT_EQ(1, observer.GetChangedCountAndClear());
731 EXPECT_EQ("active=0 anchor=0 selection=0 1", SelectionStateAsString());
733 PressKey(ui::VKEY_END);
734 EXPECT_EQ(1, observer.GetChangedCountAndClear());
735 EXPECT_EQ("active=4 anchor=4 selection=3 4", SelectionStateAsString());
737 table_->SetObserver(NULL);
740 // Verifies multiple selection gestures work (control-click, shift-click ...).
741 TEST_F(TableViewTest, Multiselection) {
742 // Configure the grouper so that there are three groups:
743 // A 0
744 // 1
745 // B 5
746 // C 2
747 // 3
748 model_->AddRow(2, 5, 0);
749 TableGrouperImpl grouper;
750 std::vector<int> ranges;
751 ranges.push_back(2);
752 ranges.push_back(1);
753 ranges.push_back(2);
754 grouper.SetRanges(ranges);
755 table_->SetGrouper(&grouper);
757 // Initially no selection.
758 EXPECT_EQ("active=-1 anchor=-1 selection=", SelectionStateAsString());
760 TableViewObserverImpl observer;
761 table_->SetObserver(&observer);
763 // Click on the first row, should select it and the second row.
764 ClickOnRow(0, 0);
765 EXPECT_EQ(1, observer.GetChangedCountAndClear());
766 EXPECT_EQ("active=0 anchor=0 selection=0 1", SelectionStateAsString());
768 // Click on the last row, should select it and the row before it.
769 ClickOnRow(4, 0);
770 EXPECT_EQ(1, observer.GetChangedCountAndClear());
771 EXPECT_EQ("active=4 anchor=4 selection=3 4", SelectionStateAsString());
773 // Shift click on the third row, should extend selection to it.
774 ClickOnRow(2, ui::EF_SHIFT_DOWN);
775 EXPECT_EQ(1, observer.GetChangedCountAndClear());
776 EXPECT_EQ("active=2 anchor=4 selection=2 3 4", SelectionStateAsString());
778 // Control click on third row, should toggle it.
779 ClickOnRow(2, ui::EF_CONTROL_DOWN);
780 EXPECT_EQ(1, observer.GetChangedCountAndClear());
781 EXPECT_EQ("active=2 anchor=2 selection=3 4", SelectionStateAsString());
783 // Control-shift click on second row, should extend selection to it.
784 ClickOnRow(1, ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN);
785 EXPECT_EQ(1, observer.GetChangedCountAndClear());
786 EXPECT_EQ("active=1 anchor=2 selection=0 1 2 3 4", SelectionStateAsString());
788 // Click on last row again.
789 ClickOnRow(4, 0);
790 EXPECT_EQ(1, observer.GetChangedCountAndClear());
791 EXPECT_EQ("active=4 anchor=4 selection=3 4", SelectionStateAsString());
793 table_->SetObserver(NULL);
796 // Verifies multiple selection gestures work when sorted.
797 TEST_F(TableViewTest, MultiselectionWithSort) {
798 // Configure the grouper so that there are three groups:
799 // A 0
800 // 1
801 // B 5
802 // C 2
803 // 3
804 model_->AddRow(2, 5, 0);
805 TableGrouperImpl grouper;
806 std::vector<int> ranges;
807 ranges.push_back(2);
808 ranges.push_back(1);
809 ranges.push_back(2);
810 grouper.SetRanges(ranges);
811 table_->SetGrouper(&grouper);
813 // Sort the table descending by column 1, view now looks like:
814 // B 5 model: 2
815 // C 2 3
816 // 3 4
817 // A 0 0
818 // 1 1
819 table_->ToggleSortOrder(0);
820 table_->ToggleSortOrder(0);
822 // Initially no selection.
823 EXPECT_EQ("active=-1 anchor=-1 selection=", SelectionStateAsString());
825 TableViewObserverImpl observer;
826 table_->SetObserver(&observer);
828 // Click on the third row, should select it and the second row.
829 ClickOnRow(2, 0);
830 EXPECT_EQ(1, observer.GetChangedCountAndClear());
831 EXPECT_EQ("active=4 anchor=4 selection=3 4", SelectionStateAsString());
833 // Extend selection to first row.
834 ClickOnRow(0, ui::EF_SHIFT_DOWN);
835 EXPECT_EQ(1, observer.GetChangedCountAndClear());
836 EXPECT_EQ("active=2 anchor=4 selection=2 3 4", SelectionStateAsString());
838 table_->SetObserver(NULL);
841 } // namespace views