910e62b5创建于 1月15日历史提交
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef UI_VIEWS_CONTROLS_TABLE_TABLE_VIEW_H_
#define UI_VIEWS_CONTROLS_TABLE_TABLE_VIEW_H_

#include <memory>
#include <vector>

#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "ui/base/models/list_selection_model.h"
#include "ui/base/models/table_model.h"
#include "ui/base/models/table_model_observer.h"
#include "ui/color/color_id.h"
#include "ui/compositor/layer.h"
#include "ui/gfx/font_list.h"
#include "ui/gfx/render_text.h"
#include "ui/views/controls/table/table_grouper.h"
#include "ui/views/layout/layout_provider.h"
#include "ui/views/metadata/view_factory.h"
#include "ui/views/style/platform_style.h"
#include "ui/views/style/typography.h"
#include "ui/views/view.h"
#include "ui/views/views_export.h"

namespace ui {

struct AXActionData;

}  // namespace ui

namespace task_manager {

// Forward declaring TaskManagerView to use as a PassKey because it has
// permission to disable alternating row colors on macOS.
class TaskManagerView;

}  // namespace task_manager

// A TableView is a view that displays multiple rows with any number of columns.
// TableView is driven by a TableModel. The model returns the contents
// to display. TableModel also has an Observer which is used to notify
// TableView of changes to the model so that the display may be updated
// appropriately.
//
// TableView itself has an observer that is notified when the selection
// changes.
//
// When a table is sorted the model coordinates do not necessarily match the
// view coordinates. All table methods are in terms of the model. If you need to
// convert to view coordinates use ModelToView().
//
// Sorting is done by a locale sensitive string sort. You can customize the
// sort by way of overriding TableModel::CompareValues().
namespace views {

class AXVirtualView;
struct GroupRange;
class ScrollView;
class TableGrouper;
class TableHeader;
class TableViewObserver;
class TableViewTestHelper;

struct VIEWS_EXPORT TableHeaderStyle {
  TableHeaderStyle(int cell_vertical_padding,
                   int cell_horizontal_padding,
                   int resize_bar_vertical_padding,
                   int separator_horizontal_padding,
                   gfx::Font::Weight font_weight,
                   ui::ColorId separator_horizontal_color_id,
                   ui::ColorId separator_vertical_color_id,
                   ui::ColorId background_color_id,
                   float focus_ring_upper_corner_radius,
                   bool header_sort_state);
  TableHeaderStyle();
  ~TableHeaderStyle();

  std::optional<int> cell_vertical_padding;
  std::optional<int> cell_horizontal_padding;
  std::optional<int> resize_bar_vertical_padding;
  std::optional<int> separator_horizontal_padding;
  std::optional<gfx::Font::Weight> font_weight;
  std::optional<ui::ColorId> separator_horizontal_color_id;
  std::optional<ui::ColorId> separator_vertical_color_id;
  std::optional<ui::ColorId> background_color_id;

  // Applied to the top left corner of the first column, and top right corner
  // of the last column. Applied to both if there is only one column.
  std::optional<float> focus_ring_upper_corner_radius;

  // Add sort state to column header.
  std::optional<bool> header_sort_state;
};

struct TableBackgroundStyle {
  ui::ColorId background = ui::kColorTableBackground;
  ui::ColorId alternate = ui::kColorTableBackgroundAlternate;
  ui::ColorId selected_focused = ui::kColorTableBackgroundSelectedFocused;
  ui::ColorId selected_unfocused = ui::kColorTableBackgroundSelectedUnfocused;
};

struct TableStyle {
  TableBackgroundStyle background_tokens;

  // Icons will be drawn with a rounded rect background if this is set to true.
  bool icons_have_background = false;

  // Focus Ring is drawn inside the cell, instead of outside the cell.
  bool inset_focus_ring = false;
};

// The cell's in the first column of a table can contain:
// - only text
// - a small icon (16x16) and some text
// - a check box and some text
enum class TableType : bool { kTextOnly, kIconAndText };

class VIEWS_EXPORT TableView : public View, public ui::TableModelObserver {
  METADATA_HEADER(TableView, View)

 public:
  // Used by AdvanceActiveVisibleColumn(), AdvanceSelection() and
  // ResizeColumnViaKeyboard() to determine the direction to change the
  // selection.
  enum class AdvanceDirection : bool {
    kDecrement,
    kIncrement,
  };

  // Used to track a visible column. Useful only for the header.
  struct VIEWS_EXPORT VisibleColumn {
    VisibleColumn();
    ~VisibleColumn();

    // The column.
    ui::TableColumn column;

    // Starting x-coordinate of the column.
    int x = 0;

    // Width of the column.
    int width = 0;
  };

  // Describes a sorted column.
  struct VIEWS_EXPORT SortDescriptor {
    SortDescriptor() = default;
    SortDescriptor(int column_id, bool ascending)
        : column_id(column_id), ascending(ascending) {}

    // ID of the sorted column.
    int column_id = -1;

    // Is the sort ascending?
    bool ascending = true;
  };

  using SortDescriptors = std::vector<SortDescriptor>;

  static constexpr int kTextContext = style::CONTEXT_TABLE_ROW;
  static constexpr int kTextStyle = style::STYLE_BODY_4;

  // Creates a new table using the model and columns specified.
  // The table type applies to the content of the first column (text, icon and
  // text, checkbox and text).
  TableView();
  TableView(ui::TableModel* model,
            const std::vector<ui::TableColumn>& columns,
            TableType table_type,
            bool single_selection);

  TableView(const TableView&) = delete;
  TableView& operator=(const TableView&) = delete;

  ~TableView() override;

  // Returns a new ScrollView that contains the given |table|.
  static std::unique_ptr<ScrollView> CreateScrollViewWithTable(
      std::unique_ptr<TableView> table,
      bool has_border = true);

  // Returns a new Builder<ScrollView> that contains the |table| constructed
  // from the given Builder<TableView>.
  static Builder<ScrollView> CreateScrollViewBuilderWithTable(
      Builder<TableView>&& table);

  // Initialize the table with the appropriate data.
  void Init(ui::TableModel* model,
            const std::vector<ui::TableColumn>& columns,
            TableType table_type,
            bool single_selection);

  // Assigns a new model to the table view, detaching the old one if present.
  // If |model| is NULL, the table view cannot be used after this call. This
  // should be called in the containing view's destructor to avoid destruction
  // issues when the model needs to be deleted before the table.
  void SetModel(ui::TableModel* model);
  ui::TableModel* model() const { return model_; }

  void SetColumns(const std::vector<ui::TableColumn>& columns);

  void SetTableType(TableType table_type);
  TableType GetTableType() const;

  void SetSingleSelection(bool single_selection);
  bool GetSingleSelection() const;

  // Sets the TableGrouper. TableView does not own |grouper| (common use case is
  // to have TableModel implement TableGrouper).
  void SetGrouper(TableGrouper* grouper);

  // Determines whether to draw the TableGrouper on the left side of the table.
  void SetGrouperVisibility(bool visible);

  // Returns the number of rows in the TableView.
  size_t GetRowCount() const;

  // Selects the specified item, making sure it's visible.
  void Select(std::optional<size_t> model_row);

  // Selects all items.
  void SetSelectionAll(bool select);

  // Returns the first selected row in terms of the model.
  std::optional<size_t> GetFirstSelectedRow() const;

  const ui::ListSelectionModel& selection_model() const {
    return selection_model_;
  }

  // Changes the visibility of the specified column (by id).
  void SetColumnVisibility(int id, bool is_visible);
  bool IsColumnVisible(int id) const;

  // Returns true if the column with the specified id is known (either visible
  // or not).
  bool HasColumn(int id) const;

  // Returns whether an active row and column have been set.
  bool GetHasFocusIndicator() const;

  // These functions are deprecated. Favor calling the equivalent functions
  // below.
  void set_observer(TableViewObserver* observer) { observer_ = observer; }
  TableViewObserver* observer() const { return observer_; }

  // The following are equivalent to the above, but are named for compatibility
  // with metadata properties and view builder.
  void SetObserver(TableViewObserver* observer);
  TableViewObserver* GetObserver() const;

  std::optional<size_t> GetActiveVisibleColumnIndex() const;

  void SetActiveVisibleColumnIndex(std::optional<size_t> index);

  const std::vector<VisibleColumn>& visible_columns() const {
    return visible_columns_;
  }

  const VisibleColumn& GetVisibleColumn(size_t index);

  // Get the column ids for visible columns.
  std::vector<int> GetVisibleColumnIds() const;

  // Sets the width of the column. |index| is in terms of |visible_columns_|.
  void SetVisibleColumnWidth(size_t index, int width);

  // Modify the table sort order, depending on a clicked column and the previous
  // table sort order. Does nothing if this column is not sortable.
  //
  // When called repeatedly on the same sortable column, the sort order will
  // cycle through three states in order: sorted -> reverse-sorted -> unsorted.
  // When switching from one sort column to another, the previous sort column
  // will be remembered and used as a secondary sort key.
  void ToggleSortOrder(size_t visible_column_index);

  const SortDescriptors& sort_descriptors() const { return sort_descriptors_; }
  void SetSortDescriptors(const SortDescriptors& descriptors);
  bool GetIsSorted() const { return !sort_descriptors_.empty(); }

  // Maps from the index in terms of the model to that of the view.
  size_t ModelToView(size_t model_index) const;

  // Maps from the index in terms of the view to that of the model.
  size_t ViewToModel(size_t view_index) const;

  void SetRowPadding(views::DistanceMetric distance_metric);
  int GetRowHeight() const { return row_height_; }

  bool GetSelectOnRemove() const;
  void SetSelectOnRemove(bool select_on_remove);

  // WARNING: this function forces a sort on every paint, and is therefore
  // expensive! It assumes you are calling SchedulePaint() at intervals for
  // the whole table. If your model is properly notifying the table, this is
  // not needed. This is only used in th extremely rare case, where between the
  // time the SchedulePaint() is called and the paint is processed, the
  // underlying data may change. Also, this only works if the number of rows
  // remains the same.
  bool GetSortOnPaint() const;
  void SetSortOnPaint(bool sort_on_paint);

  // TODO(crbug.com/406294165): Experimental, do not use in prod until bug is
  // fixed. If enabled, hovering over a row causes the row's background color to
  // change.
  void SetMouseHoveringEnabled(bool enabled);

  // Returns true if it was manually enabled via SetMouseHoveringEnabled().
  bool IsHoverEffectEnabled() const;

  // Updates whether table rows will render with alternating colors. Enabling
  // only works on macOS, other platforms results in a no-op.
  void SetAlternatingRowColorsEnabled(
      base::PassKey<task_manager::TaskManagerView> key,
      bool enabled);
  void SetAlternatingRowColorsEnabledForTesting(bool enabled);

  // Returns the proper ax sort direction.
  ax::mojom::SortDirection GetFirstSortDescriptorDirection() const;

  // Updates the relative bounds of the virtual accessibility children created
  // in RebuildVirtualAccessibilityChildren(). This function is public so that
  // the table's |header_| can trigger an update when its visible bounds are
  // changed, because its accessibility information is also contained in the
  // table's virtual accessibility children.
  void UpdateVirtualAccessibilityChildrenBounds();

  // Returns the virtual accessibility view corresponding to the specified cell.
  // |row| should be a view index, not a model index.
  // |visible_column_index| indexes into |visible_columns_|.
  AXVirtualView* GetVirtualAccessibilityCell(size_t row,
                                             size_t visible_column_index) const;

  bool header_row_is_active() const { return header_row_is_active_; }

  void SetHeaderStyle(const TableHeaderStyle& style);
  const TableHeaderStyle& header_style() const { return header_style_; }

  void SetTableStyle(const TableStyle& style);
  const TableStyle& table_style() const { return table_style_; }

  ui::ColorId BackgroundColorId() const;
  ui::ColorId BackgroundAlternateColorId() const;
  ui::ColorId BackgroundSelectedFocusedColorId() const;
  ui::ColorId BackgroundSelectedUnfocusedColorId() const;

  // View overrides:
  void Layout(PassKey) override;
  gfx::Size CalculatePreferredSize(
      const SizeBounds& /*available_size*/) const override;
  bool GetNeedsNotificationWhenVisibleBoundsChange() const override;
  void OnVisibleBoundsChanged() override;
  bool OnKeyPressed(const ui::KeyEvent& event) override;
  bool OnMousePressed(const ui::MouseEvent& event) override;
  void OnMouseEntered(const ui::MouseEvent& event) override;
  void OnMouseMoved(const ui::MouseEvent& event) override;
  void OnMouseExited(const ui::MouseEvent& event) override;
  void OnGestureEvent(ui::GestureEvent* event) override;
  std::u16string GetRenderedTooltipText(const gfx::Point& p) const override;
  bool HandleAccessibleAction(const ui::AXActionData& action_data) override;
  void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
  void OnThemeChanged() override;

  // ui::TableModelObserver overrides:
  void OnModelChanged() override;
  void OnItemsChanged(size_t start, size_t length) override;
  void OnItemsAdded(size_t start, size_t length) override;
  void OnItemsRemoved(size_t start, size_t length) override;
  void OnItemsMoved(size_t old_start, size_t length, size_t new_start) override;

 protected:
  // View overrides:
  gfx::Point GetKeyboardContextMenuLocation() override;
  void OnFocus() override;
  void OnBlur() override;
  void OnPaint(gfx::Canvas* canvas) override;

 private:
  friend class TableViewTestHelper;
  friend class TaskManagerView;

  class HighlightPathGenerator;
  struct GroupSortHelper;
  struct SortHelper;

  // Used during painting to determine the range of cell's that need to be
  // painted.
  // NOTE: the row indices returned by this are in terms of the view and column
  // indices in terms of |visible_columns_|.
  struct VIEWS_EXPORT PaintRegion {
    PaintRegion();
    ~PaintRegion();

    size_t min_row = 0;
    size_t max_row = 0;
    size_t min_column = 0;
    size_t max_column = 0;
  };

  void OnPaintImpl(gfx::Canvas* canvas);

  // Draws a string with the desired parameters in an efficient way by reusing
  // RenderTexts for each cell.
  void DrawString(gfx::Canvas* canvas,
                  const std::u16string& text,
                  SkColor color,
                  const gfx::Rect& text_bounds,
                  int flags,
                  size_t row,
                  size_t col);

  // Updates |render_text| from the specified parameters.
  void UpdateRenderText(const gfx::Rect& rect,
                        const std::u16string& text,
                        int flags,
                        SkColor color,
                        gfx::RenderText* render_text);

  // Returns the horizontal margin between the bounds of a cell and its
  // contents.
  int GetCellMargin() const;

  // Returns the horizontal spacing between elements (grouper, icon, and text)
  // in a cell.
  int GetCellElementSpacing() const;

  // Does the actual sort and updates the mappings (|view_to_model_| and
  // |model_to_view_|) appropriately. If |schedule_paint| is true,
  // schedules a paint. This should be true, unless called from
  // OnPaint.
  void SortItemsAndUpdateMapping(bool schedule_paint);

  // Used to sort the two rows. Returns a value < 0, == 0 or > 0 indicating
  // whether the row2 comes before row1, row2 is the same as row1 or row1 comes
  // after row2. This invokes CompareValues on the model with the sorted column.
  int CompareRows(size_t model_row1, size_t model_row2);

  // Returns the bounds of the specified row.
  gfx::Rect GetRowBounds(size_t row) const;

  // Returns the bounds of the specified cell. |visible_column_index| indexes
  // into |visible_columns_|.
  gfx::Rect GetCellBounds(size_t row, size_t visible_column_index) const;

  // Returns the bounds of the active cell.
  gfx::Rect GetActiveCellBounds() const;

  // Adjusts |bounds| based on where the text should be painted. |bounds| comes
  // from GetCellBounds() and |visible_column_index| is the corresponding column
  // (in terms of |visible_columns_|).
  void AdjustCellBoundsForText(size_t visible_column_index,
                               gfx::Rect* bounds) const;

  // Creates |header_| if necessary.
  void CreateHeaderIfNecessary(ScrollView* scroll_view);

  // Updates the |x| and |width| of each of the columns in |visible_columns_|.
  void UpdateVisibleColumnSizes();

  // Returns to the src icon bounds. If it exceeds the drawn boundary.It needs
  // to be clipped, and this method has done so for the caller.
  gfx::Rect GetPaintIconSrcBounds(const gfx::Size& image_size,
                                  int image_dest_width) const;

  // Returns the paint icon bounds in the cell.
  gfx::Rect GetPaintIconDestBounds(const gfx::Rect& cell_bounds,
                                   int text_bounds_x) const;

  // Returns the cell's that need to be painted for the specified region.
  // |bounds| is in terms of |this|.
  PaintRegion GetPaintRegion(const gfx::Rect& bounds) const;

  // Returns the bounds that need to be painted based on the clip set on
  // |canvas|.
  gfx::Rect GetPaintBounds(gfx::Canvas* canvas) const;

  // Invokes SchedulePaint() for the selected rows.
  void SchedulePaintForSelection();

  // Invokes SchedulePaintForRect() on the old and new hovered rows.
  // If either parameter is nullopt, paint is not scheduled for that parameter.
  void OnHoverChanged(std::optional<size_t> new_hovered_row);

  // Returns the TableColumn matching the specified id.
  ui::TableColumn FindColumnByID(int id) const;

  // Advances the active visible column (from the active visible column index)
  // in the specified direction.
  void AdvanceActiveVisibleColumn(AdvanceDirection direction);

  // Sets the selection to the specified index (in terms of the view).
  void SelectByViewIndex(std::optional<size_t> view_index);

  // Sets the selection model to |new_selection|.
  void SetSelectionModel(ui::ListSelectionModel new_selection);

  // Advances the selection (from the active index) in the specified direction.
  void AdvanceSelection(AdvanceDirection direction);

  // Sets |model| appropriately based on a event.
  void ConfigureSelectionModelForEvent(const ui::LocatedEvent& event,
                                       ui::ListSelectionModel* model) const;

  // Set the selection state of row at |view_index| to |select|, additionally
  // any other rows in the GroupRange containing |view_index| are updated as
  // well. This does not change the anchor or active index of |model|.
  void SelectRowsInRangeFrom(size_t view_index,
                             bool select,
                             ui::ListSelectionModel* model) const;

  // Returns the range of the specified model index. If a TableGrouper has not
  // been set this returns a group with a start of |model_index| and length of
  // 1.
  GroupRange GetGroupRange(size_t model_index) const;

  // Updates the accessible name for the table's views from `start_view_index`
  // up to `start_view_index` + `length`.
  void UpdateAccessibleNameForIndex(size_t start_view_index, size_t length);

  // Updates a set of accessibility views that expose the visible table contents
  // to assistive software.
  void RebuildVirtualAccessibilityChildren();

  // Clears the set of accessibility views set up in
  // RebuildVirtualAccessibilityChildren(). Useful when the model is in the
  // process of changing but the virtual accessibility children haven't been
  // updated yet, e.g. showing or hiding a column via SetColumnVisibility().
  void ClearVirtualAccessibilityChildren();

  void UpdateVirtualAccessibilityChildrenVisibilityState();

  void SetAccessibleSelectionForIndex(size_t view_index, bool selected) const;
  void SetAccessibleSelectionForRange(size_t start_view_index,
                                      size_t end_view_index,
                                      bool selected) const;
  void ClearAccessibleSelection() const;
  void UpdateAccessibleSelectionForColumnIndex(
      size_t visible_column_index) const;

  // Helper functions used in UpdateVirtualAccessibilityChildrenBounds() for
  // calculating the accessibility bounds for the header and table rows and
  // cell's.
  gfx::Rect CalculateHeaderRowAccessibilityBounds() const;
  gfx::Rect CalculateHeaderCellAccessibilityBounds(
      const size_t visible_column_index) const;
  gfx::Rect CalculateTableRowAccessibilityBounds(const size_t row_index) const;
  gfx::Rect CalculateTableCellAccessibilityBounds(
      const size_t row_index,
      const size_t visible_column_index) const;

  // Schedule a future call UpdateAccessibilityFocus if not already pending.
  void ScheduleUpdateAccessibilityFocusIfNeeded();

  // A PassKey so that no other code can call UpdateAccessibilityFocus
  // directly, only ScheduleUpdateAccessibilityFocusIfNeeded.
  class UpdateAccessibilityFocusPassKey {
   public:
    ~UpdateAccessibilityFocusPassKey() = default;

   private:
    friend void TableView::ScheduleUpdateAccessibilityFocusIfNeeded();

    // Avoid =default to disallow creation by uniform initialization.
    UpdateAccessibilityFocusPassKey() {}  // NOLINT
  };

  // Updates the internal accessibility state and fires the required
  // accessibility events to indicate to assistive software which row is active
  // and which cell is focused, if any. Don't call this directly; call
  // ScheduleUpdateAccessibilityFocusIfNeeded to ensure that only one call
  // is made and that it happens after all changes have been made.
  void UpdateAccessibilityFocus(UpdateAccessibilityFocusPassKey pass_key);

  // Returns the virtual accessibility view corresponding to the specified row.
  // |row| should be a view index into the TableView's body elements, not a
  // model index.
  AXVirtualView* GetVirtualAccessibilityBodyRow(size_t row) const;

  // Returns the virtual accessibility view corresponding to the header row, if
  // it exists.
  AXVirtualView* GetVirtualAccessibilityHeaderRow();

  // Returns the virtual accessibility view corresponding to the cell in the
  // given row at the specified column index.
  // `ax_row` should be the virtual view of either a header or body row.
  // `visible_column_index` indexes into `visible_columns_`.
  AXVirtualView* GetVirtualAccessibilityCellImpl(
      AXVirtualView* ax_row,
      size_t visible_column_index) const;

  // Creates a virtual accessibility view that is used to expose information
  // about the row at |view_index| to assistive software.
  std::unique_ptr<AXVirtualView> CreateRowAccessibilityView(size_t view_index);

  // Creates a virtual accessibility view that is used to expose information
  // about the cell at the provided coordinates |row_index| and |column_index|
  // to assistive software.
  std::unique_ptr<AXVirtualView> CreateCellAccessibilityView(
      size_t row_index,
      size_t column_index);

  // Creates a virtual accessibility view that is used to expose information
  // about this header to assistive software.
  std::unique_ptr<AXVirtualView> CreateHeaderAccessibilityView();

  // Updates the accessibility data for |ax_row| to match the data in the view
  // at |view_index| in the table. Returns false if row data not changed.
  bool UpdateVirtualAccessibilityRowData(AXVirtualView* ax_row,
                                         int view_index,
                                         int model_index);

  // Installs a focus ring on the TableView.
  void InstallFocusRing();

  // Updates the focus rings of the TableView and the TableHeader if necessary.
  void UpdateFocusRings();

  // Update the accessibility name of the table header when column sorting
  // changes.
  void UpdateHeaderAXName();

  // Handles key events for keyboard navigation by cell. Returns true if the
  // event was handled.
  bool HandleKeyPressedForKeyboardNavigationByCell(const ui::KeyEvent& event);

  // Updates `scroll_offset_` and redraws the hover layer based on the rows
  // underneath the cursor.
  void SyncHoverToScroll();

  // As long as IsHoveringPossible(), guarantees that the hover layer is redrawn
  // at the current mouse location and `scroll_offset_`.
  void ForceHoverUpdate();

  // Computes the row (or all grouped rows) at the specified coordinates, and
  // updates the hover layer if necessary.
  void SetHover(gfx::Point view_coordinates);

  // Clears `hovered_rows_`, and hides the hover layer.
  void ClearHover();

  // Updates the transform of `hover_layer_` using `hovered_rows_`.
  void UpdateHoverLayer();

  // TODO(327473315): Only one of raw_ptr in this class is dangling. Find which
  // one.
  raw_ptr<ui::TableModel, LeakedDanglingUntriaged> model_ = nullptr;

  std::vector<ui::TableColumn> columns_;

  // The set of visible columns. The values of these point to |columns_|. This
  // may contain a subset of |columns_|.
  std::vector<VisibleColumn> visible_columns_;

  // The active visible column. Used for keyboard access to functionality such
  // as sorting and resizing. nullopt if no visible column is active.
  std::optional<size_t> active_visible_column_index_ = std::nullopt;

  // The header. This is only created if more than one column is specified or
  // the first column has a non-empty title.
  // TODO(327473315): Only one of raw_ptr in this class is dangling. Find which
  // one.
  raw_ptr<TableHeader, LeakedDanglingUntriaged> header_ = nullptr;

  // TableView allows using the keyboard to activate a cell or row, including
  // optionally the header row. This bool keeps track of whether the active row
  // is the header row, since the selection model doesn't support that.
  bool header_row_is_active_ = false;

  // The model index rows beneath the cursor, if the table is focused.
  std::optional<GroupRange> hovered_rows_ = std::nullopt;

  // The view index of the row underneath the cursor. Note: A single row.
  std::optional<size_t> view_index_of_row_under_cursor_ = std::nullopt;

  // If enabled, rows will alternate between kColorTableBackground and
  // kColorTableBackgroundAlternate.
  bool alternating_row_colors_ =
      PlatformStyle::kTableViewSupportsAlternatingRowColors;

  TableType table_type_ = TableType::kTextOnly;

  bool single_selection_ = true;

  // If |select_on_remove_| is true: when a selected item is removed, if the
  // removed item is not the last item, select its next one; otherwise select
  // its previous one if there is an item.
  // If |select_on_remove_| is false: when a selected item is removed, no item
  // is selected then.
  bool select_on_remove_ = true;

  // TODO(327473315): Only one of raw_ptr in this class is dangling. Find which
  // one.
  raw_ptr<TableViewObserver, LeakedDanglingUntriaged> observer_ = nullptr;
  // If |sort_on_paint_| is true, table will sort before painting.
  bool sort_on_paint_ = false;

  // The selection, in terms of the model.
  ui::ListSelectionModel selection_model_;

  gfx::FontList font_list_;

  int row_height_;

  // Width of the ScrollView at last layout. Used to determine when we should
  // invoke UpdateVisibleColumnSizes().
  int last_parent_width_ = 0;

  // The width we layout to. This may differ from |last_parent_width_|.
  int layout_width_ = 0;

  // Current sort.
  SortDescriptors sort_descriptors_;

  // Mappings used when sorted.
  std::vector<size_t> view_to_model_;
  std::vector<size_t> model_to_view_;

  // TODO(327473315): Only one of raw_ptr in this class is dangling. Find which
  // one.
  raw_ptr<TableGrouper, LeakedDanglingUntriaged> grouper_ = nullptr;

  // True if in SetVisibleColumnWidth().
  bool in_set_visible_column_width_ = false;

  // Keeps track whether a call to UpdateAccessibilityFocus is already
  // pending or not.
  bool update_accessibility_focus_pending_ = false;

  // Draws the Grouper if one is present, and set to true.
  bool grouper_visible_ = true;

  // Customization for the header. Includes options such as padding.
  TableHeaderStyle header_style_;

  // Customization for the table.
  TableStyle table_style_;

  // TODO(crbug.com/388086397): Enable by mouse hovering by default when color
  // tokens are refined on all platforms.
  bool hovering_enabled_ = false;

  // Hover Layer used to highlight a row based on mouse cursor position.
  ui::Layer hover_layer_{ui::LAYER_SOLID_COLOR};

  // RenderText cache from row,col.
  std::vector<std::vector<std::unique_ptr<gfx::RenderText>>> render_text_cache_;

  // Callback subscriptions.
  base::CallbackListSubscription on_scroll_view_scrolled_;

  // Last received offset from the on_scroll_view_scrolled_ callback
  gfx::Point scroll_offset_{0, 0};

  // Weak pointer factory, enables using PostTask safely.
  base::WeakPtrFactory<TableView> weak_factory_;
};

BEGIN_VIEW_BUILDER(VIEWS_EXPORT, TableView, View)
VIEW_BUILDER_PROPERTY(std::optional<size_t>, ActiveVisibleColumnIndex)
VIEW_BUILDER_PROPERTY(const std::vector<ui::TableColumn>&,
                      Columns,
                      std::vector<ui::TableColumn>)
VIEW_BUILDER_PROPERTY(ui::TableModel*, Model)
VIEW_BUILDER_PROPERTY(TableType, TableType)
VIEW_BUILDER_PROPERTY(bool, SingleSelection)
VIEW_BUILDER_PROPERTY(TableGrouper*, Grouper)
VIEW_BUILDER_PROPERTY(TableViewObserver*, Observer)
VIEW_BUILDER_PROPERTY(bool, SelectOnRemove)
VIEW_BUILDER_PROPERTY(bool, SortOnPaint)
VIEW_BUILDER_METHOD(SetColumnVisibility, int, bool)
VIEW_BUILDER_METHOD(SetVisibleColumnWidth, int, int)
END_VIEW_BUILDER

}  // namespace views

DEFINE_VIEW_BUILDER(VIEWS_EXPORT, views::TableView)

namespace base {

// Allow use of ScopedObservation with TableView, which requires use of
// SetObserver and only supports a single TableViewObserver at a time.
template <>
struct ScopedObservationTraits<views::TableView, views::TableViewObserver> {
  static void AddObserver(views::TableView* source,
                          views::TableViewObserver* observer) {
    CHECK(!source->GetObserver())
        << "TableView does not support multiple observers";
    source->SetObserver(observer);
  }
  static void RemoveObserver(views::TableView* source,
                             views::TableViewObserver* observer) {
    CHECK_EQ(source->GetObserver(), observer)
        << "TableView does not support multiple observers";
    source->SetObserver(nullptr);
  }
};

}  // namespace base

#endif  // UI_VIEWS_CONTROLS_TABLE_TABLE_VIEW_H_