1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef UI_VIEWS_CONTROLS_TABLE_TABLE_VIEW_VIEWS_H_
6#define UI_VIEWS_CONTROLS_TABLE_TABLE_VIEW_VIEWS_H_
7
8#include <vector>
9
10#include "base/memory/scoped_ptr.h"
11#include "ui/base/models/list_selection_model.h"
12#include "ui/base/models/table_model.h"
13#include "ui/base/models/table_model_observer.h"
14#include "ui/gfx/font_list.h"
15#include "ui/views/view.h"
16#include "ui/views/views_export.h"
17
18// A TableView is a view that displays multiple rows with any number of columns.
19// TableView is driven by a TableModel. The model returns the contents
20// to display. TableModel also has an Observer which is used to notify
21// TableView of changes to the model so that the display may be updated
22// appropriately.
23//
24// TableView itself has an observer that is notified when the selection
25// changes.
26//
27// When a table is sorted the model coordinates do not necessarily match the
28// view coordinates. All table methods are in terms of the model. If you need to
29// convert to view coordinates use ModelToView().
30//
31// Sorting is done by a locale sensitive string sort. You can customize the
32// sort by way of overriding TableModel::CompareValues().
33namespace views {
34
35struct GroupRange;
36class TableGrouper;
37class TableHeader;
38class TableViewObserver;
39class TableViewRowBackgroundPainter;
40class TableViewTestHelper;
41
42// The cells in the first column of a table can contain:
43// - only text
44// - a small icon (16x16) and some text
45// - a check box and some text
46enum TableTypes {
47  TEXT_ONLY = 0,
48  ICON_AND_TEXT,
49};
50
51class VIEWS_EXPORT TableView
52    : public views::View,
53      public ui::TableModelObserver {
54 public:
55  // Used to track a visible column. Useful only for the header.
56  struct VIEWS_EXPORT VisibleColumn {
57    VisibleColumn();
58    ~VisibleColumn();
59
60    // The column.
61    ui::TableColumn column;
62
63    // Starting x-coordinate of the column.
64    int x;
65
66    // Width of the column.
67    int width;
68  };
69
70  // Describes a sorted column.
71  struct VIEWS_EXPORT SortDescriptor {
72    SortDescriptor() : column_id(-1), ascending(true) {}
73    SortDescriptor(int column_id, bool ascending)
74        : column_id(column_id),
75          ascending(ascending) {}
76
77    // ID of the sorted column.
78    int column_id;
79
80    // Is the sort ascending?
81    bool ascending;
82  };
83
84  typedef std::vector<SortDescriptor> SortDescriptors;
85
86  // Creates a new table using the model and columns specified.
87  // The table type applies to the content of the first column (text, icon and
88  // text, checkbox and text).
89  TableView(ui::TableModel* model,
90            const std::vector<ui::TableColumn>& columns,
91            TableTypes table_type,
92            bool single_selection);
93  virtual ~TableView();
94
95  // Assigns a new model to the table view, detaching the old one if present.
96  // If |model| is NULL, the table view cannot be used after this call. This
97  // should be called in the containing view's destructor to avoid destruction
98  // issues when the model needs to be deleted before the table.
99  void SetModel(ui::TableModel* model);
100  ui::TableModel* model() const { return model_; }
101
102  // Returns a new ScrollView that contains the receiver.
103  View* CreateParentIfNecessary();
104
105  void SetRowBackgroundPainter(
106      scoped_ptr<TableViewRowBackgroundPainter> painter);
107
108  // Sets the TableGrouper. TableView does not own |grouper| (common use case is
109  // to have TableModel implement TableGrouper).
110  void SetGrouper(TableGrouper* grouper);
111
112  // Returns the number of rows in the TableView.
113  int RowCount() const;
114
115  // Returns the number of selected rows.
116  // TODO(sky): remove this and force callers to use selection_model().
117  int SelectedRowCount();
118
119  // Selects the specified item, making sure it's visible.
120  void Select(int model_row);
121
122  // Returns the first selected row in terms of the model.
123  int FirstSelectedRow();
124
125  const ui::ListSelectionModel& selection_model() const {
126    return selection_model_;
127  }
128
129  // Changes the visibility of the specified column (by id).
130  void SetColumnVisibility(int id, bool is_visible);
131  bool IsColumnVisible(int id) const;
132
133  // Adds the specified column. |col| is not made visible.
134  void AddColumn(const ui::TableColumn& col);
135
136  // Returns true if the column with the specified id is known (either visible
137  // or not).
138  bool HasColumn(int id) const;
139
140  // TODO(sky): rename to set_observer().
141  void SetObserver(TableViewObserver* observer) {
142    table_view_observer_ = observer;
143  }
144  TableViewObserver* observer() const { return table_view_observer_; }
145
146  const std::vector<VisibleColumn>& visible_columns() const {
147    return visible_columns_;
148  }
149
150  // Sets the width of the column. |index| is in terms of |visible_columns_|.
151  void SetVisibleColumnWidth(int index, int width);
152
153  // Toggles the sort order of the specified visible column index.
154  void ToggleSortOrder(int visible_column_index);
155
156  const SortDescriptors& sort_descriptors() const { return sort_descriptors_; }
157  bool is_sorted() const { return !sort_descriptors_.empty(); }
158
159  // Maps from the index in terms of the model to that of the view.
160  int ModelToView(int model_index) const;
161
162  // Maps from the index in terms of the view to that of the model.
163  int ViewToModel(int view_index) const;
164
165  int row_height() const { return row_height_; }
166
167  // View overrides:
168  virtual void Layout() OVERRIDE;
169  virtual gfx::Size GetPreferredSize() const OVERRIDE;
170  virtual bool OnKeyPressed(const ui::KeyEvent& event) OVERRIDE;
171  virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE;
172  virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
173  virtual bool GetTooltipText(const gfx::Point& p,
174                              base::string16* tooltip) const OVERRIDE;
175  virtual bool GetTooltipTextOrigin(const gfx::Point& p,
176                                    gfx::Point* loc) const OVERRIDE;
177
178  // ui::TableModelObserver overrides:
179  virtual void OnModelChanged() OVERRIDE;
180  virtual void OnItemsChanged(int start, int length) OVERRIDE;
181  virtual void OnItemsAdded(int start, int length) OVERRIDE;
182  virtual void OnItemsRemoved(int start, int length) OVERRIDE;
183
184 protected:
185  // View overrides:
186  virtual gfx::Point GetKeyboardContextMenuLocation() OVERRIDE;
187  virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
188  virtual void OnFocus() OVERRIDE;
189  virtual void OnBlur() OVERRIDE;
190
191 private:
192  friend class TableViewTestHelper;
193  struct GroupSortHelper;
194  struct SortHelper;
195
196  // Used during painting to determine the range of cells that need to be
197  // painted.
198  // NOTE: the row indices returned by this are in terms of the view and column
199  // indices in terms of |visible_columns_|.
200  struct VIEWS_EXPORT PaintRegion {
201    PaintRegion();
202    ~PaintRegion();
203
204    int min_row;
205    int max_row;
206    int min_column;
207    int max_column;
208  };
209
210  // Used by AdvanceSelection() to determine the direction to change the
211  // selection.
212  enum AdvanceDirection {
213    ADVANCE_DECREMENT,
214    ADVANCE_INCREMENT,
215  };
216
217  // Invoked when the number of rows changes in some way.
218  void NumRowsChanged();
219
220  // Resets the sort descriptions.
221  void SetSortDescriptors(const SortDescriptors& sort_descriptors);
222
223  // Does the actual sort and updates the mappings (|view_to_model_| and
224  // |model_to_view_|) appropriately.
225  void SortItemsAndUpdateMapping();
226
227  // Used to sort the two rows. Returns a value < 0, == 0 or > 0 indicating
228  // whether the row2 comes before row1, row2 is the same as row1 or row1 comes
229  // after row2. This invokes CompareValues on the model with the sorted column.
230  int CompareRows(int model_row1, int model_row2);
231
232  // Returns the bounds of the specified row.
233  gfx::Rect GetRowBounds(int row) const;
234
235  // Returns the bounds of the specified cell. |visible_column_index| indexes
236  // into |visible_columns_|.
237  gfx::Rect GetCellBounds(int row, int visible_column_index) const;
238
239  // Adjusts |bounds| based on where the text should be painted. |bounds| comes
240  // from GetCellBounds() and |visible_column_index| is the corresponding column
241  // (in terms of |visible_columns_|).
242  void AdjustCellBoundsForText(int visible_column_index,
243                               gfx::Rect* bounds) const;
244
245  // Creates |header_| if necessary.
246  void CreateHeaderIfNecessary();
247
248  // Updates the |x| and |width| of each of the columns in |visible_columns_|.
249  void UpdateVisibleColumnSizes();
250
251  // Returns the cells that need to be painted for the specified region.
252  // |bounds| is in terms of |this|.
253  PaintRegion GetPaintRegion(const gfx::Rect& bounds) const;
254
255  // Returns the bounds that need to be painted based on the clip set on
256  // |canvas|.
257  gfx::Rect GetPaintBounds(gfx::Canvas* canvas) const;
258
259  // Invokes SchedulePaint() for the selected rows.
260  void SchedulePaintForSelection();
261
262  // Returns the TableColumn matching the specified id.
263  ui::TableColumn FindColumnByID(int id) const;
264
265  // Sets the selection to the specified index (in terms of the view).
266  void SelectByViewIndex(int view_index);
267
268  // Sets the selection model to |new_selection|.
269  void SetSelectionModel(const ui::ListSelectionModel& new_selection);
270
271  // Advances the selection (from the active index) in the specified direction.
272  void AdvanceSelection(AdvanceDirection direction);
273
274  // Sets |model| appropriately based on a event.
275  void ConfigureSelectionModelForEvent(const ui::LocatedEvent& event,
276                                       ui::ListSelectionModel* model) const;
277
278  // Set the selection state of row at |view_index| to |select|, additionally
279  // any other rows in the GroupRange containing |view_index| are updated as
280  // well. This does not change the anchor or active index of |model|.
281  void SelectRowsInRangeFrom(int view_index,
282                             bool select,
283                             ui::ListSelectionModel* model) const;
284
285  // Returns the range of the specified model index. If a TableGrouper has not
286  // been set this returns a group with a start of |model_index| and length of
287  // 1.
288  GroupRange GetGroupRange(int model_index) const;
289
290  // Used by both GetTooltipText methods. Returns true if there is a tooltip and
291  // sets |tooltip| and/or |tooltip_origin| as appropriate, each of which may be
292  // NULL.
293  bool GetTooltipImpl(const gfx::Point& location,
294                      base::string16* tooltip,
295                      gfx::Point* tooltip_origin) const;
296
297  ui::TableModel* model_;
298
299  std::vector<ui::TableColumn> columns_;
300
301  // The set of visible columns. The values of these point to |columns_|. This
302  // may contain a subset of |columns_|.
303  std::vector<VisibleColumn> visible_columns_;
304
305  // The header. This is only created if more than one column is specified or
306  // the first column has a non-empty title.
307  TableHeader* header_;
308
309  const TableTypes table_type_;
310
311  const bool single_selection_;
312
313  // TODO(sky): rename to observer_.
314  TableViewObserver* table_view_observer_;
315
316  // The selection, in terms of the model.
317  ui::ListSelectionModel selection_model_;
318
319  gfx::FontList font_list_;
320
321  int row_height_;
322
323  // Width of the ScrollView last time Layout() was invoked. Used to determine
324  // when we should invoke UpdateVisibleColumnSizes().
325  int last_parent_width_;
326
327  // The width we layout to. This may differ from |last_parent_width_|.
328  int layout_width_;
329
330  // Current sort.
331  SortDescriptors sort_descriptors_;
332
333  // Mappings used when sorted.
334  std::vector<int> view_to_model_;
335  std::vector<int> model_to_view_;
336
337  scoped_ptr<TableViewRowBackgroundPainter> row_background_painter_;
338
339  TableGrouper* grouper_;
340
341  // True if in SetVisibleColumnWidth().
342  bool in_set_visible_column_width_;
343
344  DISALLOW_COPY_AND_ASSIGN(TableView);
345};
346
347}  // namespace views
348
349#endif  // UI_VIEWS_CONTROLS_TABLE_TABLE_VIEW_VIEWS_H_
350