| Index: ui/views/controls/table/table_view.cc
|
| diff --git a/ui/views/controls/table/table_view.cc b/ui/views/controls/table/table_view.cc
|
| deleted file mode 100644
|
| index e5120d492956f504e9478377a1481869a655e73b..0000000000000000000000000000000000000000
|
| --- a/ui/views/controls/table/table_view.cc
|
| +++ /dev/null
|
| @@ -1,908 +0,0 @@
|
| -// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include "ui/views/controls/table/table_view.h"
|
| -
|
| -#include <map>
|
| -
|
| -#include "base/auto_reset.h"
|
| -#include "base/i18n/rtl.h"
|
| -#include "ui/events/event.h"
|
| -#include "ui/gfx/canvas.h"
|
| -#include "ui/gfx/image/image_skia.h"
|
| -#include "ui/gfx/rect_conversions.h"
|
| -#include "ui/gfx/skia_util.h"
|
| -#include "ui/gfx/text_utils.h"
|
| -#include "ui/native_theme/native_theme.h"
|
| -#include "ui/views/controls/scroll_view.h"
|
| -#include "ui/views/controls/table/table_grouper.h"
|
| -#include "ui/views/controls/table/table_header.h"
|
| -#include "ui/views/controls/table/table_utils.h"
|
| -#include "ui/views/controls/table/table_view_observer.h"
|
| -#include "ui/views/controls/table/table_view_row_background_painter.h"
|
| -
|
| -// Padding around the text (on each side).
|
| -static const int kTextVerticalPadding = 3;
|
| -static const int kTextHorizontalPadding = 6;
|
| -
|
| -// Size of images.
|
| -static const int kImageSize = 16;
|
| -
|
| -static const int kGroupingIndicatorSize = 6;
|
| -
|
| -namespace views {
|
| -
|
| -namespace {
|
| -
|
| -// Returns result, unless ascending is false in which case -result is returned.
|
| -int SwapCompareResult(int result, bool ascending) {
|
| - return ascending ? result : -result;
|
| -}
|
| -
|
| -// Populates |model_index_to_range_start| based on the |grouper|.
|
| -void GetModelIndexToRangeStart(TableGrouper* grouper,
|
| - int row_count,
|
| - std::map<int, int>* model_index_to_range_start) {
|
| - for (int model_index = 0; model_index < row_count;) {
|
| - GroupRange range;
|
| - grouper->GetGroupRange(model_index, &range);
|
| - DCHECK_GT(range.length, 0);
|
| - for (int range_counter = 0; range_counter < range.length; range_counter++)
|
| - (*model_index_to_range_start)[range_counter + model_index] = model_index;
|
| - model_index += range.length;
|
| - }
|
| -}
|
| -
|
| -// Returns the color id for the background of selected text. |has_focus|
|
| -// indicates if the table has focus.
|
| -ui::NativeTheme::ColorId text_background_color_id(bool has_focus) {
|
| - return has_focus ?
|
| - ui::NativeTheme::kColorId_TableSelectionBackgroundFocused :
|
| - ui::NativeTheme::kColorId_TableSelectionBackgroundUnfocused;
|
| -}
|
| -
|
| -// Returns the color id for text. |has_focus| indicates if the table has focus.
|
| -ui::NativeTheme::ColorId selected_text_color_id(bool has_focus) {
|
| - return has_focus ? ui::NativeTheme::kColorId_TableSelectedText :
|
| - ui::NativeTheme::kColorId_TableSelectedTextUnfocused;
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -// Used as the comparator to sort the contents of the table.
|
| -struct TableView::SortHelper {
|
| - explicit SortHelper(TableView* table) : table(table) {}
|
| -
|
| - bool operator()(int model_index1, int model_index2) {
|
| - return table->CompareRows(model_index1, model_index2) < 0;
|
| - }
|
| -
|
| - TableView* table;
|
| -};
|
| -
|
| -// Used as the comparator to sort the contents of the table when a TableGrouper
|
| -// is present. When groups are present we sort the groups based on the first row
|
| -// in the group and within the groups we keep the same order as the model.
|
| -struct TableView::GroupSortHelper {
|
| - explicit GroupSortHelper(TableView* table) : table(table) {}
|
| -
|
| - bool operator()(int model_index1, int model_index2) {
|
| - const int range1 = model_index_to_range_start[model_index1];
|
| - const int range2 = model_index_to_range_start[model_index2];
|
| - if (range1 == range2) {
|
| - // The two rows are in the same group, sort so that items in the same
|
| - // group always appear in the same order.
|
| - return model_index1 < model_index2;
|
| - }
|
| - return table->CompareRows(range1, range2) < 0;
|
| - }
|
| -
|
| - TableView* table;
|
| - std::map<int, int> model_index_to_range_start;
|
| -};
|
| -
|
| -TableView::VisibleColumn::VisibleColumn() : x(0), width(0) {}
|
| -
|
| -TableView::VisibleColumn::~VisibleColumn() {}
|
| -
|
| -TableView::PaintRegion::PaintRegion()
|
| - : min_row(0),
|
| - max_row(0),
|
| - min_column(0),
|
| - max_column(0) {
|
| -}
|
| -
|
| -TableView::PaintRegion::~PaintRegion() {}
|
| -
|
| -TableView::TableView(ui::TableModel* model,
|
| - const std::vector<ui::TableColumn>& columns,
|
| - TableTypes table_type,
|
| - bool single_selection)
|
| - : model_(NULL),
|
| - columns_(columns),
|
| - header_(NULL),
|
| - table_type_(table_type),
|
| - single_selection_(single_selection),
|
| - table_view_observer_(NULL),
|
| - row_height_(font_list_.GetHeight() + kTextVerticalPadding * 2),
|
| - last_parent_width_(0),
|
| - layout_width_(0),
|
| - grouper_(NULL),
|
| - in_set_visible_column_width_(false) {
|
| - for (size_t i = 0; i < columns.size(); ++i) {
|
| - VisibleColumn visible_column;
|
| - visible_column.column = columns[i];
|
| - visible_columns_.push_back(visible_column);
|
| - }
|
| - SetFocusable(true);
|
| - SetModel(model);
|
| -}
|
| -
|
| -TableView::~TableView() {
|
| - if (model_)
|
| - model_->SetObserver(NULL);
|
| -}
|
| -
|
| -// TODO: this doesn't support arbitrarily changing the model, rename this to
|
| -// ClearModel() or something.
|
| -void TableView::SetModel(ui::TableModel* model) {
|
| - if (model == model_)
|
| - return;
|
| -
|
| - if (model_)
|
| - model_->SetObserver(NULL);
|
| - model_ = model;
|
| - selection_model_.Clear();
|
| - if (model_)
|
| - model_->SetObserver(this);
|
| -}
|
| -
|
| -View* TableView::CreateParentIfNecessary() {
|
| - ScrollView* scroll_view = ScrollView::CreateScrollViewWithBorder();
|
| - scroll_view->SetContents(this);
|
| - CreateHeaderIfNecessary();
|
| - if (header_)
|
| - scroll_view->SetHeader(header_);
|
| - return scroll_view;
|
| -}
|
| -
|
| -void TableView::SetRowBackgroundPainter(
|
| - scoped_ptr<TableViewRowBackgroundPainter> painter) {
|
| - row_background_painter_ = painter.Pass();
|
| -}
|
| -
|
| -void TableView::SetGrouper(TableGrouper* grouper) {
|
| - grouper_ = grouper;
|
| - SortItemsAndUpdateMapping();
|
| -}
|
| -
|
| -int TableView::RowCount() const {
|
| - return model_ ? model_->RowCount() : 0;
|
| -}
|
| -
|
| -int TableView::SelectedRowCount() {
|
| - return static_cast<int>(selection_model_.size());
|
| -}
|
| -
|
| -void TableView::Select(int model_row) {
|
| - if (!model_)
|
| - return;
|
| -
|
| - SelectByViewIndex(model_row == -1 ? -1 : ModelToView(model_row));
|
| -}
|
| -
|
| -int TableView::FirstSelectedRow() {
|
| - return SelectedRowCount() == 0 ? -1 : selection_model_.selected_indices()[0];
|
| -}
|
| -
|
| -void TableView::SetColumnVisibility(int id, bool is_visible) {
|
| - if (is_visible == IsColumnVisible(id))
|
| - return;
|
| -
|
| - if (is_visible) {
|
| - VisibleColumn visible_column;
|
| - visible_column.column = FindColumnByID(id);
|
| - visible_columns_.push_back(visible_column);
|
| - } else {
|
| - for (size_t i = 0; i < visible_columns_.size(); ++i) {
|
| - if (visible_columns_[i].column.id == id) {
|
| - visible_columns_.erase(visible_columns_.begin() + i);
|
| - break;
|
| - }
|
| - }
|
| - }
|
| - UpdateVisibleColumnSizes();
|
| - PreferredSizeChanged();
|
| - SchedulePaint();
|
| - if (header_)
|
| - header_->SchedulePaint();
|
| -}
|
| -
|
| -void TableView::ToggleSortOrder(int visible_column_index) {
|
| - DCHECK(visible_column_index >= 0 &&
|
| - visible_column_index < static_cast<int>(visible_columns_.size()));
|
| - if (!visible_columns_[visible_column_index].column.sortable)
|
| - return;
|
| - const int column_id = visible_columns_[visible_column_index].column.id;
|
| - SortDescriptors sort(sort_descriptors_);
|
| - if (!sort.empty() && sort[0].column_id == column_id) {
|
| - sort[0].ascending = !sort[0].ascending;
|
| - } else {
|
| - SortDescriptor descriptor(column_id, true);
|
| - sort.insert(sort.begin(), descriptor);
|
| - // Only persist two sort descriptors.
|
| - if (sort.size() > 2)
|
| - sort.resize(2);
|
| - }
|
| - SetSortDescriptors(sort);
|
| -}
|
| -
|
| -bool TableView::IsColumnVisible(int id) const {
|
| - for (size_t i = 0; i < visible_columns_.size(); ++i) {
|
| - if (visible_columns_[i].column.id == id)
|
| - return true;
|
| - }
|
| - return false;
|
| -}
|
| -
|
| -void TableView::AddColumn(const ui::TableColumn& col) {
|
| - DCHECK(!HasColumn(col.id));
|
| - columns_.push_back(col);
|
| -}
|
| -
|
| -bool TableView::HasColumn(int id) const {
|
| - for (size_t i = 0; i < columns_.size(); ++i) {
|
| - if (columns_[i].id == id)
|
| - return true;
|
| - }
|
| - return false;
|
| -}
|
| -
|
| -void TableView::SetVisibleColumnWidth(int index, int width) {
|
| - DCHECK(index >= 0 && index < static_cast<int>(visible_columns_.size()));
|
| - if (visible_columns_[index].width == width)
|
| - return;
|
| - base::AutoReset<bool> reseter(&in_set_visible_column_width_, true);
|
| - visible_columns_[index].width = width;
|
| - for (size_t i = index + 1; i < visible_columns_.size(); ++i) {
|
| - visible_columns_[i].x =
|
| - visible_columns_[i - 1].x + visible_columns_[i - 1].width;
|
| - }
|
| - PreferredSizeChanged();
|
| - SchedulePaint();
|
| -}
|
| -
|
| -int TableView::ModelToView(int model_index) const {
|
| - if (!is_sorted())
|
| - return model_index;
|
| - DCHECK_GE(model_index, 0) << " negative model_index " << model_index;
|
| - DCHECK_LT(model_index, RowCount()) << " out of bounds model_index " <<
|
| - model_index;
|
| - return model_to_view_[model_index];
|
| -}
|
| -
|
| -int TableView::ViewToModel(int view_index) const {
|
| - if (!is_sorted())
|
| - return view_index;
|
| - DCHECK_GE(view_index, 0) << " negative view_index " << view_index;
|
| - DCHECK_LT(view_index, RowCount()) << " out of bounds view_index " <<
|
| - view_index;
|
| - return view_to_model_[view_index];
|
| -}
|
| -
|
| -void TableView::Layout() {
|
| - // parent()->parent() is the scrollview. When its width changes we force
|
| - // recalculating column sizes.
|
| - View* scroll_view = parent() ? parent()->parent() : NULL;
|
| - if (scroll_view) {
|
| - const int scroll_view_width = scroll_view->GetContentsBounds().width();
|
| - if (scroll_view_width != last_parent_width_) {
|
| - last_parent_width_ = scroll_view_width;
|
| - if (!in_set_visible_column_width_) {
|
| - // Layout to the parent (the Viewport), which differs from
|
| - // |scroll_view_width| when scrollbars are present.
|
| - layout_width_ = parent()->width();
|
| - UpdateVisibleColumnSizes();
|
| - }
|
| - }
|
| - }
|
| - // We have to override Layout like this since we're contained in a ScrollView.
|
| - gfx::Size pref = GetPreferredSize();
|
| - int width = pref.width();
|
| - int height = pref.height();
|
| - if (parent()) {
|
| - width = std::max(parent()->width(), width);
|
| - height = std::max(parent()->height(), height);
|
| - }
|
| - SetBounds(x(), y(), width, height);
|
| -}
|
| -
|
| -gfx::Size TableView::GetPreferredSize() const {
|
| - int width = 50;
|
| - if (header_ && !visible_columns_.empty())
|
| - width = visible_columns_.back().x + visible_columns_.back().width;
|
| - return gfx::Size(width, RowCount() * row_height_);
|
| -}
|
| -
|
| -bool TableView::OnKeyPressed(const ui::KeyEvent& event) {
|
| - if (!HasFocus())
|
| - return false;
|
| -
|
| - switch (event.key_code()) {
|
| - case ui::VKEY_A:
|
| - // control-a selects all.
|
| - if (event.IsControlDown() && !single_selection_ && RowCount()) {
|
| - ui::ListSelectionModel selection_model;
|
| - selection_model.SetSelectedIndex(selection_model_.active());
|
| - for (int i = 0; i < RowCount(); ++i)
|
| - selection_model.AddIndexToSelection(i);
|
| - SetSelectionModel(selection_model);
|
| - return true;
|
| - }
|
| - break;
|
| -
|
| - case ui::VKEY_HOME:
|
| - if (RowCount())
|
| - SelectByViewIndex(0);
|
| - return true;
|
| -
|
| - case ui::VKEY_END:
|
| - if (RowCount())
|
| - SelectByViewIndex(RowCount() - 1);
|
| - return true;
|
| -
|
| - case ui::VKEY_UP:
|
| - AdvanceSelection(ADVANCE_DECREMENT);
|
| - return true;
|
| -
|
| - case ui::VKEY_DOWN:
|
| - AdvanceSelection(ADVANCE_INCREMENT);
|
| - return true;
|
| -
|
| - default:
|
| - break;
|
| - }
|
| - if (table_view_observer_)
|
| - table_view_observer_->OnKeyDown(event.key_code());
|
| - return false;
|
| -}
|
| -
|
| -bool TableView::OnMousePressed(const ui::MouseEvent& event) {
|
| - RequestFocus();
|
| - if (!event.IsOnlyLeftMouseButton())
|
| - return true;
|
| -
|
| - const int row = event.y() / row_height_;
|
| - if (row < 0 || row >= RowCount())
|
| - return true;
|
| -
|
| - if (event.GetClickCount() == 2) {
|
| - SelectByViewIndex(row);
|
| - if (table_view_observer_)
|
| - table_view_observer_->OnDoubleClick();
|
| - } else if (event.GetClickCount() == 1) {
|
| - ui::ListSelectionModel new_model;
|
| - ConfigureSelectionModelForEvent(event, &new_model);
|
| - SetSelectionModel(new_model);
|
| - }
|
| -
|
| - return true;
|
| -}
|
| -
|
| -void TableView::OnGestureEvent(ui::GestureEvent* event) {
|
| - if (event->type() != ui::ET_GESTURE_TAP)
|
| - return;
|
| -
|
| - const int row = event->y() / row_height_;
|
| - if (row < 0 || row >= RowCount())
|
| - return;
|
| -
|
| - event->StopPropagation();
|
| - ui::ListSelectionModel new_model;
|
| - ConfigureSelectionModelForEvent(*event, &new_model);
|
| - SetSelectionModel(new_model);
|
| -}
|
| -
|
| -bool TableView::GetTooltipText(const gfx::Point& p,
|
| - base::string16* tooltip) const {
|
| - return GetTooltipImpl(p, tooltip, NULL);
|
| -}
|
| -
|
| -bool TableView::GetTooltipTextOrigin(const gfx::Point& p,
|
| - gfx::Point* loc) const {
|
| - return GetTooltipImpl(p, NULL, loc);
|
| -}
|
| -
|
| -void TableView::OnModelChanged() {
|
| - selection_model_.Clear();
|
| - NumRowsChanged();
|
| -}
|
| -
|
| -void TableView::OnItemsChanged(int start, int length) {
|
| - SortItemsAndUpdateMapping();
|
| -}
|
| -
|
| -void TableView::OnItemsAdded(int start, int length) {
|
| - for (int i = 0; i < length; ++i)
|
| - selection_model_.IncrementFrom(start);
|
| - NumRowsChanged();
|
| -}
|
| -
|
| -void TableView::OnItemsRemoved(int start, int length) {
|
| - // Determine the currently selected index in terms of the view. We inline the
|
| - // implementation here since ViewToModel() has DCHECKs that fail since the
|
| - // model has changed but |model_to_view_| has not been updated yet.
|
| - const int previously_selected_model_index = FirstSelectedRow();
|
| - int previously_selected_view_index = previously_selected_model_index;
|
| - if (previously_selected_model_index != -1 && is_sorted())
|
| - previously_selected_view_index =
|
| - model_to_view_[previously_selected_model_index];
|
| - for (int i = 0; i < length; ++i)
|
| - selection_model_.DecrementFrom(start);
|
| - NumRowsChanged();
|
| - // If the selection was empty and is no longer empty select the same visual
|
| - // index.
|
| - if (selection_model_.empty() && previously_selected_view_index != -1 &&
|
| - RowCount()) {
|
| - selection_model_.SetSelectedIndex(
|
| - ViewToModel(std::min(RowCount() - 1, previously_selected_view_index)));
|
| - }
|
| - if (table_view_observer_)
|
| - table_view_observer_->OnSelectionChanged();
|
| -}
|
| -
|
| -gfx::Point TableView::GetKeyboardContextMenuLocation() {
|
| - int first_selected = FirstSelectedRow();
|
| - gfx::Rect vis_bounds(GetVisibleBounds());
|
| - int y = vis_bounds.height() / 2;
|
| - if (first_selected != -1) {
|
| - gfx::Rect cell_bounds(GetRowBounds(first_selected));
|
| - if (cell_bounds.bottom() >= vis_bounds.y() &&
|
| - cell_bounds.bottom() < vis_bounds.bottom()) {
|
| - y = cell_bounds.bottom();
|
| - }
|
| - }
|
| - gfx::Point screen_loc(0, y);
|
| - if (base::i18n::IsRTL())
|
| - screen_loc.set_x(width());
|
| - ConvertPointToScreen(this, &screen_loc);
|
| - return screen_loc;
|
| -}
|
| -
|
| -void TableView::OnPaint(gfx::Canvas* canvas) {
|
| - // Don't invoke View::OnPaint so that we can render our own focus border.
|
| -
|
| - canvas->DrawColor(GetNativeTheme()->GetSystemColor(
|
| - ui::NativeTheme::kColorId_TableBackground));
|
| -
|
| - if (!RowCount() || visible_columns_.empty())
|
| - return;
|
| -
|
| - const PaintRegion region(GetPaintRegion(GetPaintBounds(canvas)));
|
| - if (region.min_column == -1)
|
| - return; // No need to paint anything.
|
| -
|
| - const SkColor selected_bg_color = GetNativeTheme()->GetSystemColor(
|
| - text_background_color_id(HasFocus()));
|
| - const SkColor fg_color = GetNativeTheme()->GetSystemColor(
|
| - ui::NativeTheme::kColorId_TableText);
|
| - const SkColor selected_fg_color = GetNativeTheme()->GetSystemColor(
|
| - selected_text_color_id(HasFocus()));
|
| - for (int i = region.min_row; i < region.max_row; ++i) {
|
| - const int model_index = ViewToModel(i);
|
| - const bool is_selected = selection_model_.IsSelected(model_index);
|
| - if (is_selected) {
|
| - canvas->FillRect(GetRowBounds(i), selected_bg_color);
|
| - } else if (row_background_painter_) {
|
| - row_background_painter_->PaintRowBackground(model_index,
|
| - GetRowBounds(i),
|
| - canvas);
|
| - }
|
| - if (selection_model_.active() == i && HasFocus())
|
| - canvas->DrawFocusRect(GetRowBounds(i));
|
| - for (int j = region.min_column; j < region.max_column; ++j) {
|
| - const gfx::Rect cell_bounds(GetCellBounds(i, j));
|
| - int text_x = kTextHorizontalPadding + cell_bounds.x();
|
| -
|
| - // Provide space for the grouping indicator, but draw it separately.
|
| - if (j == 0 && grouper_)
|
| - text_x += kGroupingIndicatorSize + kTextHorizontalPadding;
|
| -
|
| - // Always paint the icon in the first visible column.
|
| - if (j == 0 && table_type_ == ICON_AND_TEXT) {
|
| - gfx::ImageSkia image = model_->GetIcon(model_index);
|
| - if (!image.isNull()) {
|
| - int image_x = GetMirroredXWithWidthInView(text_x, kImageSize);
|
| - canvas->DrawImageInt(
|
| - image, 0, 0, image.width(), image.height(),
|
| - image_x,
|
| - cell_bounds.y() + (cell_bounds.height() - kImageSize) / 2,
|
| - kImageSize, kImageSize, true);
|
| - }
|
| - text_x += kImageSize + kTextHorizontalPadding;
|
| - }
|
| - if (text_x < cell_bounds.right() - kTextHorizontalPadding) {
|
| - canvas->DrawStringRectWithFlags(
|
| - model_->GetText(model_index, visible_columns_[j].column.id),
|
| - font_list_, is_selected ? selected_fg_color : fg_color,
|
| - gfx::Rect(GetMirroredXWithWidthInView(
|
| - text_x, cell_bounds.right() - text_x - kTextHorizontalPadding),
|
| - cell_bounds.y() + kTextVerticalPadding,
|
| - cell_bounds.right() - text_x,
|
| - cell_bounds.height() - kTextVerticalPadding * 2),
|
| - TableColumnAlignmentToCanvasAlignment(
|
| - visible_columns_[j].column.alignment));
|
| - }
|
| - }
|
| - }
|
| -
|
| - if (!grouper_ || region.min_column > 0)
|
| - return;
|
| -
|
| - const SkColor grouping_color = GetNativeTheme()->GetSystemColor(
|
| - ui::NativeTheme::kColorId_TableGroupingIndicatorColor);
|
| - SkPaint grouping_paint;
|
| - grouping_paint.setColor(grouping_color);
|
| - grouping_paint.setStyle(SkPaint::kFill_Style);
|
| - grouping_paint.setAntiAlias(true);
|
| - const int group_indicator_x = GetMirroredXInView(GetCellBounds(0, 0).x() +
|
| - kTextHorizontalPadding + kGroupingIndicatorSize / 2);
|
| - for (int i = region.min_row; i < region.max_row; ) {
|
| - const int model_index = ViewToModel(i);
|
| - GroupRange range;
|
| - grouper_->GetGroupRange(model_index, &range);
|
| - DCHECK_GT(range.length, 0);
|
| - // The order of rows in a group is consistent regardless of sort, so it's ok
|
| - // to do this calculation.
|
| - const int start = i - (model_index - range.start);
|
| - const int last = start + range.length - 1;
|
| - const gfx::Rect start_cell_bounds(GetCellBounds(start, 0));
|
| - if (start != last) {
|
| - const gfx::Rect last_cell_bounds(GetCellBounds(last, 0));
|
| - canvas->FillRect(gfx::Rect(
|
| - group_indicator_x - kGroupingIndicatorSize / 2,
|
| - start_cell_bounds.CenterPoint().y(),
|
| - kGroupingIndicatorSize,
|
| - last_cell_bounds.y() - start_cell_bounds.y()),
|
| - grouping_color);
|
| - canvas->DrawCircle(gfx::Point(group_indicator_x,
|
| - last_cell_bounds.CenterPoint().y()),
|
| - kGroupingIndicatorSize / 2, grouping_paint);
|
| - }
|
| - canvas->DrawCircle(gfx::Point(group_indicator_x,
|
| - start_cell_bounds.CenterPoint().y()),
|
| - kGroupingIndicatorSize / 2, grouping_paint);
|
| - i = last + 1;
|
| - }
|
| -}
|
| -
|
| -void TableView::OnFocus() {
|
| - SchedulePaintForSelection();
|
| -}
|
| -
|
| -void TableView::OnBlur() {
|
| - SchedulePaintForSelection();
|
| -}
|
| -
|
| -void TableView::NumRowsChanged() {
|
| - SortItemsAndUpdateMapping();
|
| - PreferredSizeChanged();
|
| - SchedulePaint();
|
| -}
|
| -
|
| -void TableView::SetSortDescriptors(const SortDescriptors& sort_descriptors) {
|
| - sort_descriptors_ = sort_descriptors;
|
| - SortItemsAndUpdateMapping();
|
| - if (header_)
|
| - header_->SchedulePaint();
|
| -}
|
| -
|
| -void TableView::SortItemsAndUpdateMapping() {
|
| - if (!is_sorted()) {
|
| - view_to_model_.clear();
|
| - model_to_view_.clear();
|
| - } else {
|
| - const int row_count = RowCount();
|
| - view_to_model_.resize(row_count);
|
| - model_to_view_.resize(row_count);
|
| - for (int i = 0; i < row_count; ++i)
|
| - view_to_model_[i] = i;
|
| - if (grouper_) {
|
| - GroupSortHelper sort_helper(this);
|
| - GetModelIndexToRangeStart(grouper_, RowCount(),
|
| - &sort_helper.model_index_to_range_start);
|
| - std::sort(view_to_model_.begin(), view_to_model_.end(), sort_helper);
|
| - } else {
|
| - std::sort(view_to_model_.begin(), view_to_model_.end(), SortHelper(this));
|
| - }
|
| - for (int i = 0; i < row_count; ++i)
|
| - model_to_view_[view_to_model_[i]] = i;
|
| - model_->ClearCollator();
|
| - }
|
| - SchedulePaint();
|
| -}
|
| -
|
| -int TableView::CompareRows(int model_row1, int model_row2) {
|
| - const int sort_result = model_->CompareValues(
|
| - model_row1, model_row2, sort_descriptors_[0].column_id);
|
| - if (sort_result == 0 && sort_descriptors_.size() > 1) {
|
| - // Try the secondary sort.
|
| - return SwapCompareResult(
|
| - model_->CompareValues(model_row1, model_row2,
|
| - sort_descriptors_[1].column_id),
|
| - sort_descriptors_[1].ascending);
|
| - }
|
| - return SwapCompareResult(sort_result, sort_descriptors_[0].ascending);
|
| -}
|
| -
|
| -gfx::Rect TableView::GetRowBounds(int row) const {
|
| - return gfx::Rect(0, row * row_height_, width(), row_height_);
|
| -}
|
| -
|
| -gfx::Rect TableView::GetCellBounds(int row, int visible_column_index) const {
|
| - if (!header_)
|
| - return GetRowBounds(row);
|
| - const VisibleColumn& vis_col(visible_columns_[visible_column_index]);
|
| - return gfx::Rect(vis_col.x, row * row_height_, vis_col.width, row_height_);
|
| -}
|
| -
|
| -void TableView::AdjustCellBoundsForText(int visible_column_index,
|
| - gfx::Rect* bounds) const {
|
| - int text_x = kTextHorizontalPadding + bounds->x();
|
| - if (visible_column_index == 0) {
|
| - if (grouper_)
|
| - text_x += kGroupingIndicatorSize + kTextHorizontalPadding;
|
| - if (table_type_ == ICON_AND_TEXT)
|
| - text_x += kImageSize + kTextHorizontalPadding;
|
| - }
|
| - bounds->set_x(text_x);
|
| - bounds->set_width(
|
| - std::max(0, bounds->right() - kTextHorizontalPadding - text_x));
|
| -}
|
| -
|
| -void TableView::CreateHeaderIfNecessary() {
|
| - // Only create a header if there is more than one column or the title of the
|
| - // only column is not empty.
|
| - if (header_ || (columns_.size() == 1 && columns_[0].title.empty()))
|
| - return;
|
| -
|
| - header_ = new TableHeader(this);
|
| -}
|
| -
|
| -void TableView::UpdateVisibleColumnSizes() {
|
| - if (!header_)
|
| - return;
|
| -
|
| - std::vector<ui::TableColumn> columns;
|
| - for (size_t i = 0; i < visible_columns_.size(); ++i)
|
| - columns.push_back(visible_columns_[i].column);
|
| -
|
| - int first_column_padding = 0;
|
| - if (table_type_ == ICON_AND_TEXT && header_)
|
| - first_column_padding += kImageSize + kTextHorizontalPadding;
|
| - if (grouper_)
|
| - first_column_padding += kGroupingIndicatorSize + kTextHorizontalPadding;
|
| -
|
| - std::vector<int> sizes = views::CalculateTableColumnSizes(
|
| - layout_width_, first_column_padding, header_->font_list(), font_list_,
|
| - std::max(kTextHorizontalPadding, TableHeader::kHorizontalPadding) * 2,
|
| - TableHeader::kSortIndicatorWidth, columns, model_);
|
| - DCHECK_EQ(visible_columns_.size(), sizes.size());
|
| - int x = 0;
|
| - for (size_t i = 0; i < visible_columns_.size(); ++i) {
|
| - visible_columns_[i].x = x;
|
| - visible_columns_[i].width = sizes[i];
|
| - x += sizes[i];
|
| - }
|
| -}
|
| -
|
| -TableView::PaintRegion TableView::GetPaintRegion(
|
| - const gfx::Rect& bounds) const {
|
| - DCHECK(!visible_columns_.empty());
|
| - DCHECK(RowCount());
|
| -
|
| - PaintRegion region;
|
| - region.min_row = std::min(RowCount() - 1,
|
| - std::max(0, bounds.y() / row_height_));
|
| - region.max_row = bounds.bottom() / row_height_;
|
| - if (bounds.bottom() % row_height_ != 0)
|
| - region.max_row++;
|
| - region.max_row = std::min(region.max_row, RowCount());
|
| -
|
| - if (!header_) {
|
| - region.max_column = 1;
|
| - return region;
|
| - }
|
| -
|
| - const int paint_x = GetMirroredXForRect(bounds);
|
| - const int paint_max_x = paint_x + bounds.width();
|
| - region.min_column = -1;
|
| - region.max_column = visible_columns_.size();
|
| - for (size_t i = 0; i < visible_columns_.size(); ++i) {
|
| - int max_x = visible_columns_[i].x + visible_columns_[i].width;
|
| - if (region.min_column == -1 && max_x >= paint_x)
|
| - region.min_column = static_cast<int>(i);
|
| - if (region.min_column != -1 && visible_columns_[i].x >= paint_max_x) {
|
| - region.max_column = i;
|
| - break;
|
| - }
|
| - }
|
| - return region;
|
| -}
|
| -
|
| -gfx::Rect TableView::GetPaintBounds(gfx::Canvas* canvas) const {
|
| - SkRect sk_clip_rect;
|
| - if (canvas->sk_canvas()->getClipBounds(&sk_clip_rect))
|
| - return gfx::ToEnclosingRect(gfx::SkRectToRectF(sk_clip_rect));
|
| - return GetVisibleBounds();
|
| -}
|
| -
|
| -void TableView::SchedulePaintForSelection() {
|
| - if (selection_model_.size() == 1) {
|
| - const int first_model_row = FirstSelectedRow();
|
| - SchedulePaintInRect(GetRowBounds(ModelToView(first_model_row)));
|
| - if (first_model_row != selection_model_.active())
|
| - SchedulePaintInRect(GetRowBounds(ModelToView(selection_model_.active())));
|
| - } else if (selection_model_.size() > 1) {
|
| - SchedulePaint();
|
| - }
|
| -}
|
| -
|
| -ui::TableColumn TableView::FindColumnByID(int id) const {
|
| - for (size_t i = 0; i < columns_.size(); ++i) {
|
| - if (columns_[i].id == id)
|
| - return columns_[i];
|
| - }
|
| - NOTREACHED();
|
| - return ui::TableColumn();
|
| -}
|
| -
|
| -void TableView::SelectByViewIndex(int view_index) {
|
| - ui::ListSelectionModel new_selection;
|
| - if (view_index != -1) {
|
| - SelectRowsInRangeFrom(view_index, true, &new_selection);
|
| - new_selection.set_anchor(ViewToModel(view_index));
|
| - new_selection.set_active(ViewToModel(view_index));
|
| - }
|
| -
|
| - SetSelectionModel(new_selection);
|
| -}
|
| -
|
| -void TableView::SetSelectionModel(const ui::ListSelectionModel& new_selection) {
|
| - if (new_selection.Equals(selection_model_))
|
| - return;
|
| -
|
| - SchedulePaintForSelection();
|
| - selection_model_.Copy(new_selection);
|
| - SchedulePaintForSelection();
|
| -
|
| - // Scroll the group for the active item to visible.
|
| - if (selection_model_.active() != -1) {
|
| - gfx::Rect vis_rect(GetVisibleBounds());
|
| - const GroupRange range(GetGroupRange(selection_model_.active()));
|
| - const int start_y = GetRowBounds(ModelToView(range.start)).y();
|
| - const int end_y =
|
| - GetRowBounds(ModelToView(range.start + range.length - 1)).bottom();
|
| - vis_rect.set_y(start_y);
|
| - vis_rect.set_height(end_y - start_y);
|
| - ScrollRectToVisible(vis_rect);
|
| - }
|
| -
|
| - if (table_view_observer_)
|
| - table_view_observer_->OnSelectionChanged();
|
| -}
|
| -
|
| -void TableView::AdvanceSelection(AdvanceDirection direction) {
|
| - if (selection_model_.active() == -1) {
|
| - SelectByViewIndex(0);
|
| - return;
|
| - }
|
| - int view_index = ModelToView(selection_model_.active());
|
| - if (direction == ADVANCE_DECREMENT)
|
| - view_index = std::max(0, view_index - 1);
|
| - else
|
| - view_index = std::min(RowCount() - 1, view_index + 1);
|
| - SelectByViewIndex(view_index);
|
| -}
|
| -
|
| -void TableView::ConfigureSelectionModelForEvent(
|
| - const ui::LocatedEvent& event,
|
| - ui::ListSelectionModel* model) const {
|
| - const int view_index = event.y() / row_height_;
|
| - DCHECK(view_index >= 0 && view_index < RowCount());
|
| -
|
| - if (selection_model_.anchor() == -1 ||
|
| - single_selection_ ||
|
| - (!event.IsControlDown() && !event.IsShiftDown())) {
|
| - SelectRowsInRangeFrom(view_index, true, model);
|
| - model->set_anchor(ViewToModel(view_index));
|
| - model->set_active(ViewToModel(view_index));
|
| - return;
|
| - }
|
| - if ((event.IsControlDown() && event.IsShiftDown()) || event.IsShiftDown()) {
|
| - // control-shift: copy existing model and make sure rows between anchor and
|
| - // |view_index| are selected.
|
| - // shift: reset selection so that only rows between anchor and |view_index|
|
| - // are selected.
|
| - if (event.IsControlDown() && event.IsShiftDown())
|
| - model->Copy(selection_model_);
|
| - else
|
| - model->set_anchor(selection_model_.anchor());
|
| - for (int i = std::min(view_index, ModelToView(model->anchor())),
|
| - end = std::max(view_index, ModelToView(model->anchor()));
|
| - i <= end; ++i) {
|
| - SelectRowsInRangeFrom(i, true, model);
|
| - }
|
| - model->set_active(ViewToModel(view_index));
|
| - } else {
|
| - DCHECK(event.IsControlDown());
|
| - // Toggle the selection state of |view_index| and set the anchor/active to
|
| - // it and don't change the state of any other rows.
|
| - model->Copy(selection_model_);
|
| - model->set_anchor(ViewToModel(view_index));
|
| - model->set_active(ViewToModel(view_index));
|
| - SelectRowsInRangeFrom(view_index,
|
| - !model->IsSelected(ViewToModel(view_index)),
|
| - model);
|
| - }
|
| -}
|
| -
|
| -void TableView::SelectRowsInRangeFrom(int view_index,
|
| - bool select,
|
| - ui::ListSelectionModel* model) const {
|
| - const GroupRange range(GetGroupRange(ViewToModel(view_index)));
|
| - for (int i = 0; i < range.length; ++i) {
|
| - if (select)
|
| - model->AddIndexToSelection(range.start + i);
|
| - else
|
| - model->RemoveIndexFromSelection(range.start + i);
|
| - }
|
| -}
|
| -
|
| -GroupRange TableView::GetGroupRange(int model_index) const {
|
| - GroupRange range;
|
| - if (grouper_) {
|
| - grouper_->GetGroupRange(model_index, &range);
|
| - } else {
|
| - range.start = model_index;
|
| - range.length = 1;
|
| - }
|
| - return range;
|
| -}
|
| -
|
| -bool TableView::GetTooltipImpl(const gfx::Point& location,
|
| - base::string16* tooltip,
|
| - gfx::Point* tooltip_origin) const {
|
| - const int row = location.y() / row_height_;
|
| - if (row < 0 || row >= RowCount() || visible_columns_.empty())
|
| - return false;
|
| -
|
| - const int x = GetMirroredXInView(location.x());
|
| - const int column = GetClosestVisibleColumnIndex(this, x);
|
| - if (x < visible_columns_[column].x ||
|
| - x > (visible_columns_[column].x + visible_columns_[column].width))
|
| - return false;
|
| -
|
| - const base::string16 text(model_->GetText(ViewToModel(row),
|
| - visible_columns_[column].column.id));
|
| - if (text.empty())
|
| - return false;
|
| -
|
| - gfx::Rect cell_bounds(GetCellBounds(row, column));
|
| - AdjustCellBoundsForText(column, &cell_bounds);
|
| - const int right = std::min(GetVisibleBounds().right(), cell_bounds.right());
|
| - if (right > cell_bounds.x() &&
|
| - gfx::GetStringWidth(text, font_list_) <= (right - cell_bounds.x()))
|
| - return false;
|
| -
|
| - if (tooltip)
|
| - *tooltip = text;
|
| - if (tooltip_origin) {
|
| - tooltip_origin->SetPoint(cell_bounds.x(),
|
| - cell_bounds.y() + kTextVerticalPadding);
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -} // namespace views
|
|
|