12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file. 42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/views/controls/table/table_view.h" 62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <map> 82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/auto_reset.h" 102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/i18n/rtl.h" 112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/base/events/event.h" 122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/gfx/canvas.h" 132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/gfx/image/image_skia.h" 142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/gfx/rect_conversions.h" 152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/gfx/skia_util.h" 162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/native_theme/native_theme.h" 172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/views/controls/scroll_view.h" 182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/views/controls/table/table_grouper.h" 192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/views/controls/table/table_header.h" 202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/views/controls/table/table_utils.h" 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/views/controls/table/table_view_observer.h" 222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/views/controls/table/table_view_row_background_painter.h" 232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Padding around the text (on each side). 252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static const int kTextVerticalPadding = 3; 262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static const int kTextHorizontalPadding = 6; 272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Size of images. 292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static const int kImageSize = 16; 302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static const int kGroupingIndicatorSize = 6; 322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace views { 342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace { 362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Returns result, unless ascending is false in which case -result is returned. 382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int SwapCompareResult(int result, bool ascending) { 392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return ascending ? result : -result; 402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Populates |model_index_to_range_start| based on the |grouper|. 432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void GetModelIndexToRangeStart(TableGrouper* grouper, 442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int row_count, 452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::map<int, int>* model_index_to_range_start) { 462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (int model_index = 0; model_index < row_count;) { 472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) GroupRange range; 482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) grouper->GetGroupRange(model_index, &range); 492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK_GT(range.length, 0); 502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (int range_counter = 0; range_counter < range.length; range_counter++) 512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) (*model_index_to_range_start)[range_counter + model_index] = model_index; 522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) model_index += range.length; 532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Returns the color id for the background of selected text. |has_focus| 572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// indicates if the table has focus. 582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ui::NativeTheme::ColorId text_background_color_id(bool has_focus) { 592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return has_focus ? 602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ui::NativeTheme::kColorId_TableSelectionBackgroundFocused : 612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ui::NativeTheme::kColorId_TableSelectionBackgroundUnfocused; 622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Returns the color id for text. |has_focus| indicates if the table has focus. 652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ui::NativeTheme::ColorId selected_text_color_id(bool has_focus) { 662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return has_focus ? ui::NativeTheme::kColorId_TableSelectedText : 672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ui::NativeTheme::kColorId_TableSelectedTextUnfocused; 682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace 712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Used as the comparator to sort the contents of the table. 732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)struct TableView::SortHelper { 742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) explicit SortHelper(TableView* table) : table(table) {} 752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool operator()(int model_index1, int model_index2) { 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return table->CompareRows(model_index1, model_index2) < 0; 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) TableView* table; 812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}; 822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Used as the comparator to sort the contents of the table when a TableGrouper 842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// is present. When groups are present we sort the groups based on the first row 852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// in the group and within the groups we keep the same order as the model. 862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)struct TableView::GroupSortHelper { 872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) explicit GroupSortHelper(TableView* table) : table(table) {} 882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool operator()(int model_index1, int model_index2) { 902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const int range1 = model_index_to_range_start[model_index1]; 912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const int range2 = model_index_to_range_start[model_index2]; 922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (range1 == range2) { 932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The two rows are in the same group, sort so that items in the same 942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // group always appear in the same order. 952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return model_index1 < model_index2; 962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return table->CompareRows(range1, range2) < 0; 982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) TableView* table; 1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::map<int, int> model_index_to_range_start; 1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}; 1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TableView::VisibleColumn::VisibleColumn() : x(0), width(0) {} 1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TableView::VisibleColumn::~VisibleColumn() {} 1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TableView::PaintRegion::PaintRegion() 1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : min_row(0), 1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) max_row(0), 1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) min_column(0), 1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) max_column(0) { 1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TableView::PaintRegion::~PaintRegion() {} 1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TableView::TableView(ui::TableModel* model, 1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::vector<ui::TableColumn>& columns, 1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) TableTypes table_type, 120c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) bool single_selection) 1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : model_(NULL), 1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) columns_(columns), 1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) header_(NULL), 1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) table_type_(table_type), 1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) single_selection_(single_selection), 1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) table_view_observer_(NULL), 1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) row_height_(font_.GetHeight() + kTextVerticalPadding * 2), 1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) last_parent_width_(0), 1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) layout_width_(0), 1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) grouper_(NULL), 1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) in_set_visible_column_width_(false) { 1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (size_t i = 0; i < columns.size(); ++i) { 1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) VisibleColumn visible_column; 1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) visible_column.column = columns[i]; 1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) visible_columns_.push_back(visible_column); 1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) set_focusable(true); 1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SetModel(model); 1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TableView::~TableView() { 1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (model_) 1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) model_->SetObserver(NULL); 1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// TODO: this doesn't support arbitrarily changing the model, rename this to 1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// ClearModel() or something. 1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TableView::SetModel(ui::TableModel* model) { 1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (model == model_) 1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (model_) 1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) model_->SetObserver(NULL); 1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) model_ = model; 1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) selection_model_.Clear(); 1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (model_) 1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) model_->SetObserver(this); 1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)View* TableView::CreateParentIfNecessary() { 1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ScrollView* scroll_view = ScrollView::CreateScrollViewWithBorder(); 1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scroll_view->SetContents(this); 1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CreateHeaderIfNecessary(); 1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (header_) 1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scroll_view->SetHeader(header_); 1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return scroll_view; 1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TableView::SetRowBackgroundPainter( 1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_ptr<TableViewRowBackgroundPainter> painter) { 1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) row_background_painter_ = painter.Pass(); 1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TableView::SetGrouper(TableGrouper* grouper) { 1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) grouper_ = grouper; 1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SortItemsAndUpdateMapping(); 1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int TableView::RowCount() const { 1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return model_ ? model_->RowCount() : 0; 1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int TableView::SelectedRowCount() { 1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return static_cast<int>(selection_model_.size()); 1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TableView::Select(int model_row) { 1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!model_) 1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SelectByViewIndex(model_row == -1 ? -1 : ModelToView(model_row)); 1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int TableView::FirstSelectedRow() { 1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return SelectedRowCount() == 0 ? -1 : selection_model_.selected_indices()[0]; 1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TableView::SetColumnVisibility(int id, bool is_visible) { 1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (is_visible == IsColumnVisible(id)) 2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (is_visible) { 2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) VisibleColumn visible_column; 2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) visible_column.column = FindColumnByID(id); 2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) visible_columns_.push_back(visible_column); 2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (size_t i = 0; i < visible_columns_.size(); ++i) { 2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (visible_columns_[i].column.id == id) { 2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) visible_columns_.erase(visible_columns_.begin() + i); 2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) UpdateVisibleColumnSizes(); 2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) PreferredSizeChanged(); 2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SchedulePaint(); 2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (header_) 2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) header_->SchedulePaint(); 2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TableView::ToggleSortOrder(int visible_column_index) { 2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(visible_column_index >= 0 && 2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) visible_column_index < static_cast<int>(visible_columns_.size())); 2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!visible_columns_[visible_column_index].column.sortable) 2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const int column_id = visible_columns_[visible_column_index].column.id; 2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SortDescriptors sort(sort_descriptors_); 2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!sort.empty() && sort[0].column_id == column_id) { 2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) sort[0].ascending = !sort[0].ascending; 2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SortDescriptor descriptor(column_id, true); 2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) sort.insert(sort.begin(), descriptor); 2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Only persist two sort descriptors. 2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (sort.size() > 2) 2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) sort.resize(2); 2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SetSortDescriptors(sort); 2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool TableView::IsColumnVisible(int id) const { 2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (size_t i = 0; i < visible_columns_.size(); ++i) { 2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (visible_columns_[i].column.id == id) 2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TableView::AddColumn(const ui::TableColumn& col) { 2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(!HasColumn(col.id)); 2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) columns_.push_back(col); 2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool TableView::HasColumn(int id) const { 2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (size_t i = 0; i < columns_.size(); ++i) { 2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (columns_[i].id == id) 2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TableView::SetVisibleColumnWidth(int index, int width) { 2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(index >= 0 && index < static_cast<int>(visible_columns_.size())); 2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (visible_columns_[index].width == width) 2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::AutoReset<bool> reseter(&in_set_visible_column_width_, true); 2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) visible_columns_[index].width = width; 2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (size_t i = index + 1; i < visible_columns_.size(); ++i) { 2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) visible_columns_[i].x = 2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) visible_columns_[i - 1].x + visible_columns_[i - 1].width; 2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) PreferredSizeChanged(); 2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SchedulePaint(); 2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int TableView::ModelToView(int model_index) const { 2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!is_sorted()) 2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return model_index; 2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK_GE(model_index, 0) << " negative model_index " << model_index; 2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK_LT(model_index, RowCount()) << " out of bounds model_index " << 2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) model_index; 2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return model_to_view_[model_index]; 2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int TableView::ViewToModel(int view_index) const { 2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!is_sorted()) 2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return view_index; 2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK_GE(view_index, 0) << " negative view_index " << view_index; 2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK_LT(view_index, RowCount()) << " out of bounds view_index " << 2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) view_index; 2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return view_to_model_[view_index]; 2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TableView::Layout() { 2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // parent()->parent() is the scrollview. When its width changes we force 2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // recalculating column sizes. 2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) View* scroll_view = parent() ? parent()->parent() : NULL; 2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (scroll_view) { 2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const int scroll_view_width = scroll_view->GetContentsBounds().width(); 2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (scroll_view_width != last_parent_width_) { 3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) last_parent_width_ = scroll_view_width; 3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!in_set_visible_column_width_) { 3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Layout to the parent (the Viewport), which differs from 3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // |scroll_view_width| when scrollbars are present. 3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) layout_width_ = parent()->width(); 3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) UpdateVisibleColumnSizes(); 3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // We have to override Layout like this since we're contained in a ScrollView. 3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gfx::Size pref = GetPreferredSize(); 3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int width = pref.width(); 3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int height = pref.height(); 3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (parent()) { 3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) width = std::max(parent()->width(), width); 3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) height = std::max(parent()->height(), height); 3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SetBounds(x(), y(), width, height); 3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)gfx::Size TableView::GetPreferredSize() { 3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int width = 50; 3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (header_ && !visible_columns_.empty()) 3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) width = visible_columns_.back().x + visible_columns_.back().width; 3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return gfx::Size(width, RowCount() * row_height_); 3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool TableView::OnKeyPressed(const ui::KeyEvent& event) { 3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!HasFocus()) 3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) switch (event.key_code()) { 332c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) case ui::VKEY_A: 333c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // control-a selects all. 334c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (event.IsControlDown() && !single_selection_ && RowCount()) { 335c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ui::ListSelectionModel selection_model; 336c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) selection_model.SetSelectedIndex(selection_model_.active()); 337c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for (int i = 0; i < RowCount(); ++i) 338c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) selection_model.AddIndexToSelection(i); 339c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) SetSelectionModel(selection_model); 340c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return true; 341c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 342c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) break; 343c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case ui::VKEY_HOME: 3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (RowCount()) 3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SelectByViewIndex(0); 3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case ui::VKEY_END: 3502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (RowCount()) 3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SelectByViewIndex(RowCount() - 1); 3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case ui::VKEY_UP: 3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AdvanceSelection(ADVANCE_DECREMENT); 3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case ui::VKEY_DOWN: 3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AdvanceSelection(ADVANCE_INCREMENT); 3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) default: 3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 3642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (table_view_observer_) 3662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) table_view_observer_->OnKeyDown(event.key_code()); 3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool TableView::OnMousePressed(const ui::MouseEvent& event) { 3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) RequestFocus(); 3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!event.IsOnlyLeftMouseButton()) 3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 3742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const int row = event.y() / row_height_; 3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (row < 0 || row >= RowCount()) 3772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (event.GetClickCount() == 2) { 3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SelectByViewIndex(row); 3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (table_view_observer_) 3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) table_view_observer_->OnDoubleClick(); 3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else if (event.GetClickCount() == 1) { 3842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ui::ListSelectionModel new_model; 3852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ConfigureSelectionModelForEvent(event, &new_model); 3862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SetSelectionModel(new_model); 3872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 3902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool TableView::GetTooltipText(const gfx::Point& p, 3932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) string16* tooltip) const { 3942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return GetTooltipImpl(p, tooltip, NULL); 3952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool TableView::GetTooltipTextOrigin(const gfx::Point& p, 3982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gfx::Point* loc) const { 3992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return GetTooltipImpl(p, NULL, loc); 4002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 4012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TableView::OnModelChanged() { 4032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) selection_model_.Clear(); 4042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NumRowsChanged(); 4052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 4062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TableView::OnItemsChanged(int start, int length) { 4082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SortItemsAndUpdateMapping(); 4092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 4102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TableView::OnItemsAdded(int start, int length) { 4122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (int i = 0; i < length; ++i) 4132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) selection_model_.IncrementFrom(start); 4142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NumRowsChanged(); 4152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 4162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TableView::OnItemsRemoved(int start, int length) { 4182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Determine the currently selected index in terms of the view. We inline the 4192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // implementation here since ViewToModel() has DCHECKs that fail since the 4202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // model has changed but |model_to_view_| has not been updated yet. 4212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const int previously_selected_model_index = FirstSelectedRow(); 4222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int previously_selected_view_index = previously_selected_model_index; 4232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (previously_selected_model_index != -1 && is_sorted()) 4242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) previously_selected_view_index = 4252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) model_to_view_[previously_selected_model_index]; 4262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (int i = 0; i < length; ++i) 4272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) selection_model_.DecrementFrom(start); 4282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NumRowsChanged(); 4292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // If the selection was empty and is no longer empty select the same visual 4302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // index. 4312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (selection_model_.empty() && previously_selected_view_index != -1 && 4322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) RowCount()) { 4332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) selection_model_.SetSelectedIndex( 4342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ViewToModel(std::min(RowCount() - 1, previously_selected_view_index))); 4352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (table_view_observer_) 4372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) table_view_observer_->OnSelectionChanged(); 4382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 4392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)gfx::Point TableView::GetKeyboardContextMenuLocation() { 4412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int first_selected = FirstSelectedRow(); 4422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gfx::Rect vis_bounds(GetVisibleBounds()); 4432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int y = vis_bounds.height() / 2; 4442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (first_selected != -1) { 4452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gfx::Rect cell_bounds(GetRowBounds(first_selected)); 4462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (cell_bounds.bottom() >= vis_bounds.y() && 4472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) cell_bounds.bottom() < vis_bounds.bottom()) { 4482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) y = cell_bounds.bottom(); 4492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gfx::Point screen_loc(0, y); 4522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (base::i18n::IsRTL()) 4532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) screen_loc.set_x(width()); 4542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ConvertPointToScreen(this, &screen_loc); 4552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return screen_loc; 4562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 4572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TableView::OnPaint(gfx::Canvas* canvas) { 4592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Don't invoke View::OnPaint so that we can render our own focus border. 4602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) canvas->DrawColor(GetNativeTheme()->GetSystemColor( 4622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ui::NativeTheme::kColorId_TableBackground)); 4632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!RowCount() || visible_columns_.empty()) 4652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 4662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const PaintRegion region(GetPaintRegion(GetPaintBounds(canvas))); 4682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (region.min_column == -1) 4692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; // No need to paint anything. 4702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const SkColor selected_bg_color = GetNativeTheme()->GetSystemColor( 4722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) text_background_color_id(HasFocus())); 4732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const SkColor fg_color = GetNativeTheme()->GetSystemColor( 4742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ui::NativeTheme::kColorId_TableText); 4752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const SkColor selected_fg_color = GetNativeTheme()->GetSystemColor( 4762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) selected_text_color_id(HasFocus())); 4772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (int i = region.min_row; i < region.max_row; ++i) { 4782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const int model_index = ViewToModel(i); 4792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const bool is_selected = selection_model_.IsSelected(model_index); 4802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (is_selected) { 481c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) canvas->FillRect(GetRowBounds(i), selected_bg_color); 4822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else if (row_background_painter_) { 4832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) row_background_painter_->PaintRowBackground(model_index, 4842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) GetRowBounds(i), 4852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) canvas); 4862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 487c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (selection_model_.active() == i && HasFocus()) 488c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) canvas->DrawFocusRect(GetRowBounds(i)); 4892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (int j = region.min_column; j < region.max_column; ++j) { 4902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const gfx::Rect cell_bounds(GetCellBounds(i, j)); 4912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int text_x = kTextHorizontalPadding + cell_bounds.x(); 4922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Provide space for the grouping indicator, but draw it separately. 4942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (j == 0 && grouper_) 4952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) text_x += kGroupingIndicatorSize + kTextHorizontalPadding; 4962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Always paint the icon in the first visible column. 4982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (j == 0 && table_type_ == ICON_AND_TEXT) { 4992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gfx::ImageSkia image = model_->GetIcon(model_index); 5002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!image.isNull()) { 5012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int image_x = GetMirroredXWithWidthInView(text_x, kImageSize); 5022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) canvas->DrawImageInt( 5032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) image, 0, 0, image.width(), image.height(), 5042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) image_x, 5052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) cell_bounds.y() + (cell_bounds.height() - kImageSize) / 2, 5062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) kImageSize, kImageSize, true); 5072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 5082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) text_x += kImageSize + kTextHorizontalPadding; 5092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 5102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (text_x < cell_bounds.right() - kTextHorizontalPadding) { 5112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) canvas->DrawStringInt( 5122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) model_->GetText(model_index, visible_columns_[j].column.id), font_, 5132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) is_selected ? selected_fg_color : fg_color, 5142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) GetMirroredXWithWidthInView(text_x, cell_bounds.right() - text_x - 5152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) kTextHorizontalPadding), 5162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) cell_bounds.y() + kTextVerticalPadding, 5172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) cell_bounds.right() - text_x, 5182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) cell_bounds.height() - kTextVerticalPadding * 2, 5192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) TableColumnAlignmentToCanvasAlignment( 5202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) visible_columns_[j].column.alignment)); 5212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 5222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 5232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 5242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!grouper_ || region.min_column > 0) 5262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 5272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const SkColor grouping_color = GetNativeTheme()->GetSystemColor( 5292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ui::NativeTheme::kColorId_TableGroupingIndicatorColor); 5302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SkPaint grouping_paint; 5312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) grouping_paint.setColor(grouping_color); 5322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) grouping_paint.setStyle(SkPaint::kFill_Style); 5332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) grouping_paint.setAntiAlias(true); 5342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const int group_indicator_x = GetMirroredXInView(GetCellBounds(0, 0).x() + 5352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) kTextHorizontalPadding + kGroupingIndicatorSize / 2); 5362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (int i = region.min_row; i < region.max_row; ) { 5372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const int model_index = ViewToModel(i); 5382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) GroupRange range; 5392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) grouper_->GetGroupRange(model_index, &range); 5402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK_GT(range.length, 0); 5412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The order of rows in a group is consistent regardless of sort, so it's ok 5422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // to do this calculation. 5432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const int start = i - (model_index - range.start); 5442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const int last = start + range.length - 1; 5452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const gfx::Rect start_cell_bounds(GetCellBounds(start, 0)); 5462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (start != last) { 5472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const gfx::Rect last_cell_bounds(GetCellBounds(last, 0)); 5482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) canvas->FillRect(gfx::Rect( 5492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) group_indicator_x - kGroupingIndicatorSize / 2, 5502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) start_cell_bounds.CenterPoint().y(), 5512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) kGroupingIndicatorSize, 5522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) last_cell_bounds.y() - start_cell_bounds.y()), 5532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) grouping_color); 5542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) canvas->DrawCircle(gfx::Point(group_indicator_x, 5552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) last_cell_bounds.CenterPoint().y()), 5562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) kGroupingIndicatorSize / 2, grouping_paint); 5572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 5582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) canvas->DrawCircle(gfx::Point(group_indicator_x, 5592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) start_cell_bounds.CenterPoint().y()), 5602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) kGroupingIndicatorSize / 2, grouping_paint); 5612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) i = last + 1; 5622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 5632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 5642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TableView::OnFocus() { 5662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SchedulePaintForSelection(); 5672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 5682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TableView::OnBlur() { 5702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SchedulePaintForSelection(); 5712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 5722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TableView::NumRowsChanged() { 5742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SortItemsAndUpdateMapping(); 5752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) PreferredSizeChanged(); 5762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SchedulePaint(); 5772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 5782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TableView::SetSortDescriptors(const SortDescriptors& sort_descriptors) { 5802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) sort_descriptors_ = sort_descriptors; 5812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SortItemsAndUpdateMapping(); 5822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (header_) 5832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) header_->SchedulePaint(); 5842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 5852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TableView::SortItemsAndUpdateMapping() { 5872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!is_sorted()) { 5882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) view_to_model_.clear(); 5892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) model_to_view_.clear(); 5902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 5912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const int row_count = RowCount(); 5922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) view_to_model_.resize(row_count); 5932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) model_to_view_.resize(row_count); 5942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (int i = 0; i < row_count; ++i) 5952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) view_to_model_[i] = i; 5962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (grouper_) { 5972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) GroupSortHelper sort_helper(this); 5982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) GetModelIndexToRangeStart(grouper_, RowCount(), 5992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) &sort_helper.model_index_to_range_start); 6002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::sort(view_to_model_.begin(), view_to_model_.end(), sort_helper); 6012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 6022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::sort(view_to_model_.begin(), view_to_model_.end(), SortHelper(this)); 6032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 6042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (int i = 0; i < row_count; ++i) 6052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) model_to_view_[view_to_model_[i]] = i; 6062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) model_->ClearCollator(); 6072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 6082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SchedulePaint(); 6092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 6102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 6112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int TableView::CompareRows(int model_row1, int model_row2) { 6122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const int sort_result = model_->CompareValues( 6132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) model_row1, model_row2, sort_descriptors_[0].column_id); 6142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (sort_result == 0 && sort_descriptors_.size() > 1) { 6152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Try the secondary sort. 6162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return SwapCompareResult( 6172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) model_->CompareValues(model_row1, model_row2, 6182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) sort_descriptors_[1].column_id), 6192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) sort_descriptors_[1].ascending); 6202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 6212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return SwapCompareResult(sort_result, sort_descriptors_[0].ascending); 6222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 6232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 6242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)gfx::Rect TableView::GetRowBounds(int row) const { 6252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return gfx::Rect(0, row * row_height_, width(), row_height_); 6262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 6272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 6282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)gfx::Rect TableView::GetCellBounds(int row, int visible_column_index) const { 6292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!header_) 6302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return GetRowBounds(row); 6312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const VisibleColumn& vis_col(visible_columns_[visible_column_index]); 6322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return gfx::Rect(vis_col.x, row * row_height_, vis_col.width, row_height_); 6332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 6342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 6352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TableView::AdjustCellBoundsForText(int visible_column_index, 6362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gfx::Rect* bounds) const { 6372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int text_x = kTextHorizontalPadding + bounds->x(); 6382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (visible_column_index == 0) { 6392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (grouper_) 6402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) text_x += kGroupingIndicatorSize + kTextHorizontalPadding; 6412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (table_type_ == ICON_AND_TEXT) 6422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) text_x += kImageSize + kTextHorizontalPadding; 6432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 6442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bounds->set_x(text_x); 6452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bounds->set_width( 6462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::max(0, bounds->right() - kTextHorizontalPadding - text_x)); 6472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 6482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 6492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TableView::CreateHeaderIfNecessary() { 6502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Only create a header if there is more than one column or the title of the 6512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // only column is not empty. 6522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (header_ || (columns_.size() == 1 && columns_[0].title.empty())) 6532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 6542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 6552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) header_ = new TableHeader(this); 6562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 6572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 6582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TableView::UpdateVisibleColumnSizes() { 6592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!header_) 6602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 6612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 6622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::vector<ui::TableColumn> columns; 6632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (size_t i = 0; i < visible_columns_.size(); ++i) 6642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) columns.push_back(visible_columns_[i].column); 6652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 6662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int first_column_padding = 0; 6672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (table_type_ == ICON_AND_TEXT && header_) 6682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) first_column_padding += kImageSize + kTextHorizontalPadding; 6692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (grouper_) 6702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) first_column_padding += kGroupingIndicatorSize + kTextHorizontalPadding; 6712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 6722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::vector<int> sizes = views::CalculateTableColumnSizes( 6732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) layout_width_, first_column_padding, header_->font(), font_, 6742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::max(kTextHorizontalPadding, TableHeader::kHorizontalPadding) * 2, 6752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) TableHeader::kSortIndicatorWidth, columns, model_); 6762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK_EQ(visible_columns_.size(), sizes.size()); 6772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int x = 0; 6782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (size_t i = 0; i < visible_columns_.size(); ++i) { 6792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) visible_columns_[i].x = x; 6802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) visible_columns_[i].width = sizes[i]; 6812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) x += sizes[i]; 6822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 6832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 6842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 6852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TableView::PaintRegion TableView::GetPaintRegion( 6862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const gfx::Rect& bounds) const { 6872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(!visible_columns_.empty()); 6882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(RowCount()); 6892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 6902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) PaintRegion region; 6912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) region.min_row = std::min(RowCount() - 1, 6922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::max(0, bounds.y() / row_height_)); 6932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) region.max_row = bounds.bottom() / row_height_; 6942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (bounds.bottom() % row_height_ != 0) 6952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) region.max_row++; 6962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) region.max_row = std::min(region.max_row, RowCount()); 6972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 6982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!header_) { 6992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) region.max_column = 1; 7002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return region; 7012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 7022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 7032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const int paint_x = GetMirroredXForRect(bounds); 7042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const int paint_max_x = paint_x + bounds.width(); 7052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) region.min_column = -1; 7062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) region.max_column = visible_columns_.size(); 7072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (size_t i = 0; i < visible_columns_.size(); ++i) { 7082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int max_x = visible_columns_[i].x + visible_columns_[i].width; 7092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (region.min_column == -1 && max_x >= paint_x) 7102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) region.min_column = static_cast<int>(i); 7112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (region.min_column != -1 && visible_columns_[i].x >= paint_max_x) { 7122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) region.max_column = i; 7132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 7142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 7152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 7162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return region; 7172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 7182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 7192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)gfx::Rect TableView::GetPaintBounds(gfx::Canvas* canvas) const { 7202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SkRect sk_clip_rect; 7212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (canvas->sk_canvas()->getClipBounds(&sk_clip_rect)) 7222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return gfx::ToEnclosingRect(gfx::SkRectToRectF(sk_clip_rect)); 7232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return GetVisibleBounds(); 7242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 7252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 7262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TableView::SchedulePaintForSelection() { 727c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (selection_model_.size() == 1) { 728c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const int first_model_row = FirstSelectedRow(); 729c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) SchedulePaintInRect(GetRowBounds(ModelToView(first_model_row))); 730c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (first_model_row != selection_model_.active()) 731c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) SchedulePaintInRect(GetRowBounds(ModelToView(selection_model_.active()))); 732c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } else if (selection_model_.size() > 1) { 7332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SchedulePaint(); 734c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 7352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 7362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 7372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ui::TableColumn TableView::FindColumnByID(int id) const { 7382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (size_t i = 0; i < columns_.size(); ++i) { 7392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (columns_[i].id == id) 7402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return columns_[i]; 7412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 7422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NOTREACHED(); 7432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return ui::TableColumn(); 7442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 7452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 7462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TableView::SelectByViewIndex(int view_index) { 7472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ui::ListSelectionModel new_selection; 7482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (view_index != -1) { 7492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SelectRowsInRangeFrom(view_index, true, &new_selection); 750c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) new_selection.set_anchor(ViewToModel(view_index)); 751c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) new_selection.set_active(ViewToModel(view_index)); 7522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 7532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 7542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SetSelectionModel(new_selection); 7552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 7562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 7572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TableView::SetSelectionModel(const ui::ListSelectionModel& new_selection) { 7582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (new_selection.Equals(selection_model_)) 7592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 7602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 7612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SchedulePaintForSelection(); 7622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) selection_model_.Copy(new_selection); 7632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SchedulePaintForSelection(); 7642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 7652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Scroll the group for the active item to visible. 7662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (selection_model_.active() != -1) { 7672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gfx::Rect vis_rect(GetVisibleBounds()); 7682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const GroupRange range(GetGroupRange(selection_model_.active())); 7692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const int start_y = GetRowBounds(ModelToView(range.start)).y(); 7702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const int end_y = 7712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) GetRowBounds(ModelToView(range.start + range.length - 1)).bottom(); 7722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) vis_rect.set_y(start_y); 7732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) vis_rect.set_height(end_y - start_y); 7742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ScrollRectToVisible(vis_rect); 7752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 7762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 7772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (table_view_observer_) 7782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) table_view_observer_->OnSelectionChanged(); 7792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 7802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 7812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TableView::AdvanceSelection(AdvanceDirection direction) { 7822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (selection_model_.active() == -1) { 7832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SelectByViewIndex(0); 7842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 7852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 7862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int view_index = ModelToView(selection_model_.active()); 787c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (direction == ADVANCE_DECREMENT) 788c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) view_index = std::max(0, view_index - 1); 789c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) else 790c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) view_index = std::min(RowCount() - 1, view_index + 1); 7912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SelectByViewIndex(view_index); 7922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 7932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 7942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TableView::ConfigureSelectionModelForEvent( 7952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const ui::MouseEvent& event, 7962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ui::ListSelectionModel* model) const { 797c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const int view_index = event.y() / row_height_; 7982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(view_index >= 0 && view_index < RowCount()); 7992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 8002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (selection_model_.anchor() == -1 || 8012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) single_selection_ || 8022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) (!event.IsControlDown() && !event.IsShiftDown())) { 8032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SelectRowsInRangeFrom(view_index, true, model); 804c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) model->set_anchor(ViewToModel(view_index)); 805c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) model->set_active(ViewToModel(view_index)); 8062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 8072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 8082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if ((event.IsControlDown() && event.IsShiftDown()) || event.IsShiftDown()) { 8092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // control-shift: copy existing model and make sure rows between anchor and 8102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // |view_index| are selected. 8112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // shift: reset selection so that only rows between anchor and |view_index| 8122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // are selected. 8132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (event.IsControlDown() && event.IsShiftDown()) 8142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) model->Copy(selection_model_); 8152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) else 8162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) model->set_anchor(selection_model_.anchor()); 8172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (int i = std::min(view_index, ModelToView(model->anchor())), 8182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) end = std::max(view_index, ModelToView(model->anchor())); 8192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) i <= end; ++i) { 8202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SelectRowsInRangeFrom(i, true, model); 8212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 8222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) model->set_active(ViewToModel(view_index)); 8232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 8242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(event.IsControlDown()); 8252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Toggle the selection state of |view_index| and set the anchor/active to 8262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // it and don't change the state of any other rows. 8272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) model->Copy(selection_model_); 8282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) model->set_anchor(ViewToModel(view_index)); 8292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) model->set_active(ViewToModel(view_index)); 8302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SelectRowsInRangeFrom(view_index, 8312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) !model->IsSelected(ViewToModel(view_index)), 8322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) model); 8332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 8342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 8352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 8362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TableView::SelectRowsInRangeFrom(int view_index, 8372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool select, 8382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ui::ListSelectionModel* model) const { 8392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const GroupRange range(GetGroupRange(ViewToModel(view_index))); 8402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (int i = 0; i < range.length; ++i) { 8412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (select) 8422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) model->AddIndexToSelection(range.start + i); 8432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) else 8442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) model->RemoveIndexFromSelection(range.start + i); 8452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 8462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 8472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 8482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)GroupRange TableView::GetGroupRange(int model_index) const { 8492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) GroupRange range; 8502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (grouper_) { 8512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) grouper_->GetGroupRange(model_index, &range); 8522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 8532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) range.start = model_index; 8542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) range.length = 1; 8552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 8562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return range; 8572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 8582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 8592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool TableView::GetTooltipImpl(const gfx::Point& location, 8602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) string16* tooltip, 8612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gfx::Point* tooltip_origin) const { 8622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const int row = location.y() / row_height_; 8632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (row < 0 || row >= RowCount() || visible_columns_.empty()) 8642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 8652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 8662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const int x = GetMirroredXInView(location.x()); 8672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const int column = GetClosestVisibleColumnIndex(this, x); 8682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (x < visible_columns_[column].x || 8692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) x > (visible_columns_[column].x + visible_columns_[column].width)) 8702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 8712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 8722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const string16 text(model_->GetText(ViewToModel(row), 8732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) visible_columns_[column].column.id)); 8742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (text.empty()) 8752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 8762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 8772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gfx::Rect cell_bounds(GetCellBounds(row, column)); 8782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AdjustCellBoundsForText(column, &cell_bounds); 8792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const int right = std::min(GetVisibleBounds().right(), cell_bounds.right()); 8802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (right > cell_bounds.x() && 8812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) font_.GetStringWidth(text) <= (right - cell_bounds.x())) 8822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 8832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 8842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (tooltip) 8852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *tooltip = text; 8862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (tooltip_origin) { 8872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) tooltip_origin->SetPoint(cell_bounds.x(), 8882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) cell_bounds.y() + kTextVerticalPadding); 8892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 8902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 8912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 8922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 8932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace views 894