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.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(). 33 namespace views { 34 35 struct GroupRange; 36 class TableGrouper; 37 class TableHeader; 38 class TableViewObserver; 39 class TableViewRowBackgroundPainter; 40 class 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 46 enum TableTypes { 47 TEXT_ONLY = 0, 48 ICON_AND_TEXT, 49 }; 50 51 class 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() OVERRIDE; 170 virtual bool OnKeyPressed(const ui::KeyEvent& event) OVERRIDE; 171 virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE; 172 virtual bool GetTooltipText(const gfx::Point& p, 173 string16* tooltip) const OVERRIDE; 174 virtual bool GetTooltipTextOrigin(const gfx::Point& p, 175 gfx::Point* loc) const OVERRIDE; 176 177 // ui::TableModelObserver overrides: 178 virtual void OnModelChanged() OVERRIDE; 179 virtual void OnItemsChanged(int start, int length) OVERRIDE; 180 virtual void OnItemsAdded(int start, int length) OVERRIDE; 181 virtual void OnItemsRemoved(int start, int length) OVERRIDE; 182 183 protected: 184 // View overrides: 185 virtual gfx::Point GetKeyboardContextMenuLocation() OVERRIDE; 186 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE; 187 virtual void OnFocus() OVERRIDE; 188 virtual void OnBlur() OVERRIDE; 189 190 private: 191 friend class TableViewTestHelper; 192 struct GroupSortHelper; 193 struct SortHelper; 194 195 // Used during painting to determine the range of cells that need to be 196 // painted. 197 // NOTE: the row indices returned by this are in terms of the view and column 198 // indices in terms of |visible_columns_|. 199 struct VIEWS_EXPORT PaintRegion { 200 PaintRegion(); 201 ~PaintRegion(); 202 203 int min_row; 204 int max_row; 205 int min_column; 206 int max_column; 207 }; 208 209 // Used by AdvanceSelection() to determine the direction to change the 210 // selection. 211 enum AdvanceDirection { 212 ADVANCE_DECREMENT, 213 ADVANCE_INCREMENT, 214 }; 215 216 // Invoked when the number of rows changes in some way. 217 void NumRowsChanged(); 218 219 // Resets the sort descriptions. 220 void SetSortDescriptors(const SortDescriptors& sort_descriptors); 221 222 // Does the actual sort and updates the mappings (|view_to_model_| and 223 // |model_to_view_|) appropriately. 224 void SortItemsAndUpdateMapping(); 225 226 // Used to sort the two rows. Returns a value < 0, == 0 or > 0 indicating 227 // whether the row2 comes before row1, row2 is the same as row1 or row1 comes 228 // after row2. This invokes CompareValues on the model with the sorted column. 229 int CompareRows(int model_row1, int model_row2); 230 231 // Returns the bounds of the specified row. 232 gfx::Rect GetRowBounds(int row) const; 233 234 // Returns the bounds of the specified cell. |visible_column_index| indexes 235 // into |visible_columns_|. 236 gfx::Rect GetCellBounds(int row, int visible_column_index) const; 237 238 // Adjusts |bounds| based on where the text should be painted. |bounds| comes 239 // from GetCellBounds() and |visible_column_index| is the corresponding column 240 // (in terms of |visible_columns_|). 241 void AdjustCellBoundsForText(int visible_column_index, 242 gfx::Rect* bounds) const; 243 244 // Creates |header_| if necessary. 245 void CreateHeaderIfNecessary(); 246 247 // Updates the |x| and |width| of each of the columns in |visible_columns_|. 248 void UpdateVisibleColumnSizes(); 249 250 // Returns the cells that need to be painted for the specified region. 251 // |bounds| is in terms of |this|. 252 PaintRegion GetPaintRegion(const gfx::Rect& bounds) const; 253 254 // Returns the bounds that need to be painted based on the clip set on 255 // |canvas|. 256 gfx::Rect GetPaintBounds(gfx::Canvas* canvas) const; 257 258 // Invokes SchedulePaint() for the selected rows. 259 void SchedulePaintForSelection(); 260 261 // Returns the TableColumn matching the specified id. 262 ui::TableColumn FindColumnByID(int id) const; 263 264 // Sets the selection to the specified index (in terms of the view). 265 void SelectByViewIndex(int view_index); 266 267 // Sets the selection model to |new_selection|. 268 void SetSelectionModel(const ui::ListSelectionModel& new_selection); 269 270 // Advances the selection (from the active index) in the specified direction. 271 void AdvanceSelection(AdvanceDirection direction); 272 273 // Sets |model| appropriately based on a mouse event. 274 void ConfigureSelectionModelForEvent(const ui::MouseEvent& event, 275 ui::ListSelectionModel* model) const; 276 277 // Set the selection state of row at |view_index| to |select|, additionally 278 // any other rows in the GroupRange containing |view_index| are updated as 279 // well. This does not change the anchor or active index of |model|. 280 void SelectRowsInRangeFrom(int view_index, 281 bool select, 282 ui::ListSelectionModel* model) const; 283 284 // Returns the range of the specified model index. If a TableGrouper has not 285 // been set this returns a group with a start of |model_index| and length of 286 // 1. 287 GroupRange GetGroupRange(int model_index) const; 288 289 // Used by both GetTooltipText methods. Returns true if there is a tooltip and 290 // sets |tooltip| and/or |tooltip_origin| as appropriate, each of which may be 291 // NULL. 292 bool GetTooltipImpl(const gfx::Point& location, 293 string16* tooltip, 294 gfx::Point* tooltip_origin) const; 295 296 ui::TableModel* model_; 297 298 std::vector<ui::TableColumn> columns_; 299 300 // The set of visible columns. The values of these point to |columns_|. This 301 // may contain a subset of |columns_|. 302 std::vector<VisibleColumn> visible_columns_; 303 304 // The header. This is only created if more than one column is specified or 305 // the first column has a non-empty title. 306 TableHeader* header_; 307 308 const TableTypes table_type_; 309 310 const bool single_selection_; 311 312 // TODO(sky): rename to observer_. 313 TableViewObserver* table_view_observer_; 314 315 // The selection, in terms of the model. 316 ui::ListSelectionModel selection_model_; 317 318 gfx::Font font_; 319 320 int row_height_; 321 322 // Width of the ScrollView last time Layout() was invoked. Used to determine 323 // when we should invoke UpdateVisibleColumnSizes(). 324 int last_parent_width_; 325 326 // The width we layout to. This may differ from |last_parent_width_|. 327 int layout_width_; 328 329 // Current sort. 330 SortDescriptors sort_descriptors_; 331 332 // Mappings used when sorted. 333 std::vector<int> view_to_model_; 334 std::vector<int> model_to_view_; 335 336 scoped_ptr<TableViewRowBackgroundPainter> row_background_painter_; 337 338 TableGrouper* grouper_; 339 340 // True if in SetVisibleColumnWidth(). 341 bool in_set_visible_column_width_; 342 343 DISALLOW_COPY_AND_ASSIGN(TableView); 344 }; 345 346 } // namespace views 347 348 #endif // UI_VIEWS_CONTROLS_TABLE_TABLE_VIEW_VIEWS_H_ 349