| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2011 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 VIEWS_CONTROLS_TABLE_TABLE_VIEW_H_ | |
| 6 #define VIEWS_CONTROLS_TABLE_TABLE_VIEW_H_ | |
| 7 #pragma once | |
| 8 | |
| 9 #include <map> | |
| 10 #include <vector> | |
| 11 | |
| 12 #include "base/gtest_prod_util.h" | |
| 13 #include "base/string16.h" | |
| 14 #include "build/build_config.h" | |
| 15 #include "third_party/skia/include/core/SkColor.h" | |
| 16 #include "ui/base/keycodes/keyboard_codes.h" | |
| 17 #include "ui/base/models/table_model_observer.h" | |
| 18 #include "views/views_export.h" | |
| 19 | |
| 20 #if defined(OS_WIN) | |
| 21 #include <windows.h> | |
| 22 | |
| 23 // TODO(port): remove the ifdef when native_control.h is ported. | |
| 24 #include "views/controls/native_control.h" | |
| 25 | |
| 26 typedef struct tagNMLVCUSTOMDRAW NMLVCUSTOMDRAW; | |
| 27 #endif // defined(OS_WIN) | |
| 28 | |
| 29 namespace gfx { | |
| 30 class Font; | |
| 31 } | |
| 32 | |
| 33 namespace ui { | |
| 34 struct TableColumn; | |
| 35 class TableModel; | |
| 36 } | |
| 37 | |
| 38 // A TableView is a view that displays multiple rows with any number of columns. | |
| 39 // TableView is driven by a TableModel. The model returns the contents | |
| 40 // to display. TableModel also has an Observer which is used to notify | |
| 41 // TableView of changes to the model so that the display may be updated | |
| 42 // appropriately. | |
| 43 // | |
| 44 // TableView itself has an observer that is notified when the selection | |
| 45 // changes. | |
| 46 // | |
| 47 // Tables may be sorted either by directly invoking SetSortDescriptors or by | |
| 48 // marking the column as sortable and the user doing a gesture to sort the | |
| 49 // contents. TableView itself maintains the sort so that the underlying model | |
| 50 // isn't effected. | |
| 51 // | |
| 52 // When a table is sorted the model coordinates do not necessarily match the | |
| 53 // view coordinates. All table methods are in terms of the model. If you need to | |
| 54 // convert to view coordinates use model_to_view. | |
| 55 // | |
| 56 // Sorting is done by a locale sensitive string sort. You can customize the | |
| 57 // sort by way of overriding CompareValues. | |
| 58 // | |
| 59 // TableView is a wrapper around the window type ListView in report mode. | |
| 60 namespace views { | |
| 61 | |
| 62 class ListView; | |
| 63 class ListViewParent; | |
| 64 class TableView; | |
| 65 class TableViewObserver; | |
| 66 | |
| 67 // The cells in the first column of a table can contain: | |
| 68 // - only text | |
| 69 // - a small icon (16x16) and some text | |
| 70 // - a check box and some text | |
| 71 enum TableTypes { | |
| 72 TEXT_ONLY = 0, | |
| 73 ICON_AND_TEXT, | |
| 74 CHECK_BOX_AND_TEXT | |
| 75 }; | |
| 76 | |
| 77 // Returned from SelectionBegin/SelectionEnd | |
| 78 class VIEWS_EXPORT TableSelectionIterator { | |
| 79 public: | |
| 80 TableSelectionIterator(TableView* view, int view_index); | |
| 81 TableSelectionIterator& operator=(const TableSelectionIterator& other); | |
| 82 bool operator==(const TableSelectionIterator& other); | |
| 83 bool operator!=(const TableSelectionIterator& other); | |
| 84 TableSelectionIterator& operator++(); | |
| 85 int operator*(); | |
| 86 | |
| 87 private: | |
| 88 void UpdateModelIndexFromViewIndex(); | |
| 89 | |
| 90 TableView* table_view_; | |
| 91 int view_index_; | |
| 92 | |
| 93 // The index in terms of the model. This is returned from the * operator. This | |
| 94 // is cached to avoid dependencies on the view_to_model mapping. | |
| 95 int model_index_; | |
| 96 }; | |
| 97 | |
| 98 #if defined(OS_WIN) | |
| 99 // TODO(port): Port TableView. | |
| 100 class VIEWS_EXPORT TableView : public NativeControl, | |
| 101 public ui::TableModelObserver { | |
| 102 public: | |
| 103 typedef TableSelectionIterator iterator; | |
| 104 | |
| 105 // A helper struct for GetCellColors. Set |color_is_set| to true if color is | |
| 106 // set. See OnCustomDraw for more details on why we need this. | |
| 107 struct ItemColor { | |
| 108 bool color_is_set; | |
| 109 SkColor color; | |
| 110 }; | |
| 111 | |
| 112 // Describes a sorted column. | |
| 113 struct SortDescriptor { | |
| 114 SortDescriptor() : column_id(-1), ascending(true) {} | |
| 115 SortDescriptor(int column_id, bool ascending) | |
| 116 : column_id(column_id), | |
| 117 ascending(ascending) { } | |
| 118 | |
| 119 // ID of the sorted column. | |
| 120 int column_id; | |
| 121 | |
| 122 // Is the sort ascending? | |
| 123 bool ascending; | |
| 124 }; | |
| 125 | |
| 126 typedef std::vector<SortDescriptor> SortDescriptors; | |
| 127 | |
| 128 // Creates a new table using the model and columns specified. | |
| 129 // The table type applies to the content of the first column (text, icon and | |
| 130 // text, checkbox and text). | |
| 131 // When autosize_columns is true, columns always fill the available width. If | |
| 132 // false, columns are not resized when the table is resized. An extra empty | |
| 133 // column at the right fills the remaining space. | |
| 134 // When resizable_columns is true, users can resize columns by dragging the | |
| 135 // separator on the column header. NOTE: Right now this is always true. The | |
| 136 // code to set it false is still in place to be a base for future, better | |
| 137 // resizing behavior (see http://b/issue?id=874646 ), but no one uses or | |
| 138 // tests the case where this flag is false. | |
| 139 // Note that setting both resizable_columns and autosize_columns to false is | |
| 140 // probably not a good idea, as there is no way for the user to increase a | |
| 141 // column's size in that case. | |
| 142 TableView(ui::TableModel* model, const std::vector<ui::TableColumn>& columns, | |
| 143 TableTypes table_type, bool single_selection, | |
| 144 bool resizable_columns, bool autosize_columns); | |
| 145 virtual ~TableView(); | |
| 146 | |
| 147 // Assigns a new model to the table view, detaching the old one if present. | |
| 148 // If |model| is NULL, the table view cannot be used after this call. This | |
| 149 // should be called in the containing view's destructor to avoid destruction | |
| 150 // issues when the model needs to be deleted before the table. | |
| 151 void SetModel(ui::TableModel* model); | |
| 152 ui::TableModel* model() const { return model_; } | |
| 153 | |
| 154 // Resorts the contents. | |
| 155 void SetSortDescriptors(const SortDescriptors& sort_descriptors); | |
| 156 | |
| 157 // Current sort. | |
| 158 const SortDescriptors& sort_descriptors() const { return sort_descriptors_; } | |
| 159 | |
| 160 // Returns the number of rows in the TableView. | |
| 161 int RowCount() const; | |
| 162 | |
| 163 // Returns the number of selected rows. | |
| 164 int SelectedRowCount(); | |
| 165 | |
| 166 // Selects the specified item, making sure it's visible. | |
| 167 void Select(int model_row); | |
| 168 | |
| 169 // Sets the selected state of an item (without sending any selection | |
| 170 // notifications). Note that this routine does NOT set the focus to the | |
| 171 // item at the given index. | |
| 172 void SetSelectedState(int model_row, bool state); | |
| 173 | |
| 174 // Sets the focus to the item at the given index. | |
| 175 void SetFocusOnItem(int model_row); | |
| 176 | |
| 177 // Returns the first selected row in terms of the model. | |
| 178 int FirstSelectedRow(); | |
| 179 | |
| 180 // Returns true if the item at the specified index is selected. | |
| 181 bool IsItemSelected(int model_row); | |
| 182 | |
| 183 // Returns true if the item at the specified index has the focus. | |
| 184 bool ItemHasTheFocus(int model_row); | |
| 185 | |
| 186 // Returns an iterator over the selection. The iterator proceeds from the | |
| 187 // last index to the first. | |
| 188 // | |
| 189 // NOTE: the iterator iterates over the visual order (but returns coordinates | |
| 190 // in terms of the model). | |
| 191 iterator SelectionBegin(); | |
| 192 iterator SelectionEnd(); | |
| 193 | |
| 194 // ui::TableModelObserver methods. | |
| 195 virtual void OnModelChanged(); | |
| 196 virtual void OnItemsChanged(int start, int length); | |
| 197 virtual void OnItemsAdded(int start, int length); | |
| 198 virtual void OnItemsRemoved(int start, int length); | |
| 199 | |
| 200 void SetObserver(TableViewObserver* observer) { | |
| 201 table_view_observer_ = observer; | |
| 202 } | |
| 203 TableViewObserver* observer() const { return table_view_observer_; } | |
| 204 | |
| 205 // Replaces the set of known columns without changing the current visible | |
| 206 // columns. | |
| 207 void SetColumns(const std::vector<ui::TableColumn>& columns); | |
| 208 void AddColumn(const ui::TableColumn& col); | |
| 209 bool HasColumn(int id); | |
| 210 | |
| 211 // Sets which columns (by id) are displayed. All transient size and position | |
| 212 // information is lost. | |
| 213 void SetVisibleColumns(const std::vector<int>& columns); | |
| 214 void SetColumnVisibility(int id, bool is_visible); | |
| 215 bool IsColumnVisible(int id) const; | |
| 216 | |
| 217 // Resets the size of the columns based on the sizes passed to the | |
| 218 // constructor. Your normally needn't invoked this, it's done for you the | |
| 219 // first time the TableView is given a valid size. | |
| 220 void ResetColumnSizes(); | |
| 221 | |
| 222 // Sometimes we may want to size the TableView to a specific width and | |
| 223 // height. | |
| 224 virtual gfx::Size GetPreferredSize(); | |
| 225 void SetPreferredSize(const gfx::Size& size); | |
| 226 | |
| 227 // Is the table sorted? | |
| 228 bool is_sorted() const { return !sort_descriptors_.empty(); } | |
| 229 | |
| 230 // Maps from the index in terms of the model to that of the view. | |
| 231 int ModelToView(int model_index) const; | |
| 232 | |
| 233 // Maps from the index in terms of the view to that of the model. | |
| 234 int ViewToModel(int view_index) const; | |
| 235 | |
| 236 // Sets the text to display on top of the table. This is useful if the table | |
| 237 // is empty and you want to inform the user why. | |
| 238 void SetAltText(const string16& alt_text); | |
| 239 | |
| 240 protected: | |
| 241 // Overriden to return the position of the first selected row. | |
| 242 virtual gfx::Point GetKeyboardContextMenuLocation() OVERRIDE; | |
| 243 | |
| 244 // Subclasses that want to customize the colors of a particular row/column, | |
| 245 // must invoke this passing in true. The default value is false, such that | |
| 246 // GetCellColors is never invoked. | |
| 247 void SetCustomColorsEnabled(bool custom_colors_enabled); | |
| 248 | |
| 249 // Notification from the ListView that the selected state of an item has | |
| 250 // changed. | |
| 251 virtual void OnSelectedStateChanged(); | |
| 252 | |
| 253 // Notification from the ListView that the used double clicked the table. | |
| 254 virtual void OnDoubleClick(); | |
| 255 | |
| 256 // Notification from the ListView that the user middle clicked the table. | |
| 257 virtual void OnMiddleClick(); | |
| 258 | |
| 259 // Overridden from NativeControl. Notifies the observer. | |
| 260 virtual bool OnKeyDown(ui::KeyboardCode virtual_keycode) OVERRIDE; | |
| 261 | |
| 262 // View override. | |
| 263 virtual void OnBoundsChanged(const gfx::Rect& previous_bounds) OVERRIDE; | |
| 264 | |
| 265 // Invoked to customize the colors or font at a particular cell. If you | |
| 266 // change the colors or font, return true. This is only invoked if | |
| 267 // SetCustomColorsEnabled(true) has been invoked. | |
| 268 virtual bool GetCellColors(int model_row, | |
| 269 int column, | |
| 270 ItemColor* foreground, | |
| 271 ItemColor* background, | |
| 272 LOGFONT* logfont); | |
| 273 | |
| 274 // Subclasses that want to perform some custom painting (on top of the regular | |
| 275 // list view painting) should return true here and implement the PostPaint | |
| 276 // method. | |
| 277 virtual bool ImplementPostPaint() { return false; } | |
| 278 // Subclasses can implement in this method extra-painting for cells. | |
| 279 virtual void PostPaint(int model_row, int column, bool selected, | |
| 280 const gfx::Rect& bounds, HDC device_context) { } | |
| 281 virtual void PostPaint() {} | |
| 282 | |
| 283 virtual HWND CreateNativeControl(HWND parent_container); | |
| 284 | |
| 285 virtual LRESULT OnNotify(int w_param, LPNMHDR l_param); | |
| 286 | |
| 287 // Used to sort the two rows. Returns a value < 0, == 0 or > 0 indicating | |
| 288 // whether the row2 comes before row1, row2 is the same as row1 or row1 comes | |
| 289 // after row2. This invokes CompareValues on the model with the sorted column. | |
| 290 virtual int CompareRows(int model_row1, int model_row2); | |
| 291 | |
| 292 // Called before sorting. This does nothing and is intended for subclasses | |
| 293 // that need to cache state used during sorting. | |
| 294 virtual void PrepareForSort() {} | |
| 295 | |
| 296 // Returns the width of the specified column by id, or -1 if the column isn't | |
| 297 // visible. | |
| 298 int GetColumnWidth(int column_id); | |
| 299 | |
| 300 // Returns the offset from the top of the client area to the start of the | |
| 301 // content. | |
| 302 int content_offset() const { return content_offset_; } | |
| 303 | |
| 304 // Draws the alt_text_. Does nothing if there is no alt_text_. | |
| 305 void PaintAltText(); | |
| 306 | |
| 307 // Size (width and height) of images. | |
| 308 static const int kImageSize; | |
| 309 | |
| 310 private: | |
| 311 // Direction of a sort. | |
| 312 enum SortDirection { | |
| 313 ASCENDING_SORT, | |
| 314 DESCENDING_SORT, | |
| 315 NO_SORT | |
| 316 }; | |
| 317 | |
| 318 // We need this wrapper to pass the table view to the windows proc handler | |
| 319 // when subclassing the list view and list view header, as the reinterpret | |
| 320 // cast from GetWindowLongPtr would break the pointer if it is pointing to a | |
| 321 // subclass (in the OO sense of TableView). | |
| 322 struct TableViewWrapper { | |
| 323 explicit TableViewWrapper(TableView* view) : table_view(view) { } | |
| 324 TableView* table_view; | |
| 325 }; | |
| 326 | |
| 327 friend class ListViewParent; | |
| 328 friend class TableSelectionIterator; | |
| 329 friend class GroupModelTableViewTest; | |
| 330 FRIEND_TEST_ALL_PREFIXES(GroupModelTableViewTest, ShiftSelectAcrossGroups); | |
| 331 FRIEND_TEST_ALL_PREFIXES(GroupModelTableViewTest, ShiftSelectSameGroup); | |
| 332 | |
| 333 LRESULT OnCustomDraw(NMLVCUSTOMDRAW* draw_info); | |
| 334 | |
| 335 // Invoked when the user clicks on a column to toggle the sort order. If | |
| 336 // column_id is the primary sorted column the direction of the sort is | |
| 337 // toggled, otherwise column_id is made the primary sorted column. | |
| 338 void ToggleSortOrder(int column_id); | |
| 339 | |
| 340 // Updates the lparam of each of the list view items to be the model index. | |
| 341 // If length is > 0, all items with an index >= start get offset by length. | |
| 342 // This is used during sorting to determine how the items were sorted. | |
| 343 void UpdateItemsLParams(int start, int length); | |
| 344 | |
| 345 // Does the actual sort and updates the mappings (view_to_model and | |
| 346 // model_to_view) appropriately. | |
| 347 void SortItemsAndUpdateMapping(); | |
| 348 | |
| 349 // Selects multiple items from the current view row to the marked view row | |
| 350 // (implements shift-click behavior). |view_index| is the most recent row | |
| 351 // that the user clicked on, and so there is no guarantee that | |
| 352 // |view_index| > |mark_view_index| or vice-versa. Returns false if the | |
| 353 // selection attempt was rejected because it crossed group boundaries. | |
| 354 bool SelectMultiple(int view_index, int mark_view_index); | |
| 355 | |
| 356 // Method invoked by ListView to compare the two values. Invokes CompareRows. | |
| 357 static int CALLBACK SortFunc(LPARAM model_index_1_p, | |
| 358 LPARAM model_index_2_p, | |
| 359 LPARAM table_view_param); | |
| 360 | |
| 361 // Method invoked by ListView when sorting back to natural state. Returns | |
| 362 // model_index_1_p - model_index_2_p. | |
| 363 static int CALLBACK NaturalSortFunc(LPARAM model_index_1_p, | |
| 364 LPARAM model_index_2_p, | |
| 365 LPARAM table_view_param); | |
| 366 | |
| 367 // Resets the sort image displayed for the specified column. | |
| 368 void ResetColumnSortImage(int column_id, SortDirection direction); | |
| 369 | |
| 370 // Adds a new column. | |
| 371 void InsertColumn(const ui::TableColumn& tc, int index); | |
| 372 | |
| 373 // Update headers and internal state after columns have changed | |
| 374 void OnColumnsChanged(); | |
| 375 | |
| 376 // Updates the ListView with values from the model. See UpdateListViewCache0 | |
| 377 // for a complete description. | |
| 378 // This turns off redrawing, and invokes UpdateListViewCache0 to do the | |
| 379 // actual updating. | |
| 380 void UpdateListViewCache(int start, int length, bool add); | |
| 381 | |
| 382 // Updates ListView with values from the model. | |
| 383 // If add is true, this adds length items starting at index start. | |
| 384 // If add is not true, the items are not added, the but the values in the | |
| 385 // range start - [start + length] are updated from the model. | |
| 386 void UpdateListViewCache0(int start, int length, bool add); | |
| 387 | |
| 388 // Returns the index of the selected item before |view_index|, or -1 if | |
| 389 // |view_index| is the first selected item. | |
| 390 // | |
| 391 // WARNING: this returns coordinates in terms of the view, NOT the model. | |
| 392 int PreviousSelectedViewIndex(int view_index); | |
| 393 | |
| 394 // Returns the last selected view index in the table view, or -1 if the table | |
| 395 // is empty, or nothing is selected. | |
| 396 // | |
| 397 // WARNING: this returns coordinates in terms of the view, NOT the model. | |
| 398 int LastSelectedViewIndex(); | |
| 399 | |
| 400 // The TableColumn visible at position pos. | |
| 401 const ui::TableColumn& GetColumnAtPosition(int pos); | |
| 402 | |
| 403 // Window procedure of the list view class. We subclass the list view to | |
| 404 // ignore WM_ERASEBKGND, which gives smoother painting during resizing. | |
| 405 static LRESULT CALLBACK TableWndProc(HWND window, | |
| 406 UINT message, | |
| 407 WPARAM w_param, | |
| 408 LPARAM l_param); | |
| 409 | |
| 410 // Window procedure of the header class. We subclass the header of the table | |
| 411 // to disable resizing of columns. | |
| 412 static LRESULT CALLBACK TableHeaderWndProc(HWND window, UINT message, | |
| 413 WPARAM w_param, LPARAM l_param); | |
| 414 | |
| 415 // Updates content_offset_ from the position of the header. | |
| 416 void UpdateContentOffset(); | |
| 417 | |
| 418 // Reloads the groups from the model if there is one and it has groups. | |
| 419 void UpdateGroups(); | |
| 420 | |
| 421 // Returns the bounds of the alt text. | |
| 422 gfx::Rect GetAltTextBounds(); | |
| 423 | |
| 424 // Returns the font used for alt text. | |
| 425 gfx::Font GetAltTextFont(); | |
| 426 | |
| 427 // Overriden in order to update the column sizes, which can only be sized | |
| 428 // accurately when the native control is available. | |
| 429 virtual void VisibilityChanged(View* starting_from, bool is_visible); | |
| 430 | |
| 431 ui::TableModel* model_; | |
| 432 TableTypes table_type_; | |
| 433 TableViewObserver* table_view_observer_; | |
| 434 | |
| 435 // An ordered list of id's into |all_columns_| representing current visible | |
| 436 // columns. | |
| 437 std::vector<int> visible_columns_; | |
| 438 | |
| 439 // Mapping of an int id to a TableColumn representing all possible columns. | |
| 440 std::map<int, ui::TableColumn> all_columns_; | |
| 441 | |
| 442 // Cached value of columns_.size() | |
| 443 int column_count_; | |
| 444 | |
| 445 // Selection mode. | |
| 446 bool single_selection_; | |
| 447 | |
| 448 // If true, any events that would normally be propagated to the observer | |
| 449 // are ignored. For example, if this is true and the selection changes in | |
| 450 // the listview, the observer is not notified. | |
| 451 bool ignore_listview_change_; | |
| 452 | |
| 453 // Reflects the value passed to SetCustomColorsEnabled. | |
| 454 bool custom_colors_enabled_; | |
| 455 | |
| 456 // Whether or not columns should automatically be resized to fill the | |
| 457 // the available width when the list view is resized. | |
| 458 bool autosize_columns_; | |
| 459 | |
| 460 // Whether or not the user can resize columns. | |
| 461 bool resizable_columns_; | |
| 462 | |
| 463 // Whether the column sizes have been determined. | |
| 464 bool column_sizes_valid_; | |
| 465 | |
| 466 // NOTE: While this has the name View in it, it's not a view. Rather it's | |
| 467 // a wrapper around the List-View window. | |
| 468 HWND list_view_; | |
| 469 | |
| 470 // The list view's header original proc handler. It is required when | |
| 471 // subclassing. | |
| 472 WNDPROC header_original_handler_; | |
| 473 | |
| 474 // Window procedure of the listview before we subclassed it. | |
| 475 WNDPROC original_handler_; | |
| 476 | |
| 477 // A wrapper around 'this' used when "subclassing" the list view and header. | |
| 478 TableViewWrapper table_view_wrapper_; | |
| 479 | |
| 480 // A custom font we use when overriding the font type for a specific cell. | |
| 481 HFONT custom_cell_font_; | |
| 482 | |
| 483 // The preferred size of the table view. | |
| 484 gfx::Size preferred_size_; | |
| 485 | |
| 486 int content_offset_; | |
| 487 | |
| 488 // Current sort. | |
| 489 SortDescriptors sort_descriptors_; | |
| 490 | |
| 491 // Mappings used when sorted. | |
| 492 scoped_array<int> view_to_model_; | |
| 493 scoped_array<int> model_to_view_; | |
| 494 | |
| 495 string16 alt_text_; | |
| 496 | |
| 497 DISALLOW_COPY_AND_ASSIGN(TableView); | |
| 498 }; | |
| 499 #endif // defined(OS_WIN) | |
| 500 | |
| 501 } // namespace views | |
| 502 | |
| 503 #endif // VIEWS_CONTROLS_TABLE_TABLE_VIEW_H_ | |
| OLD | NEW |