1 /* 2 ============================================================================== 3 4 This file is part of the JUCE library. 5 Copyright (c) 2020 - Raw Material Software Limited 6 7 JUCE is an open source library subject to commercial or open-source 8 licensing. 9 10 By using JUCE, you agree to the terms of both the JUCE 6 End-User License 11 Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020). 12 13 End User License Agreement: www.juce.com/juce-6-licence 14 Privacy Policy: www.juce.com/juce-privacy-policy 15 16 Or: You may also use this code under the terms of the GPL v3 (see 17 www.gnu.org/licenses). 18 19 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER 20 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE 21 DISCLAIMED. 22 23 ============================================================================== 24 */ 25 26 namespace juce 27 { 28 29 //============================================================================== 30 /** 31 One of these is used by a TableListBox as the data model for the table's contents. 32 33 The virtual methods that you override in this class take care of drawing the 34 table cells, and reacting to events. 35 36 @see TableListBox 37 38 @tags{GUI} 39 */ 40 class JUCE_API TableListBoxModel 41 { 42 public: 43 //============================================================================== 44 TableListBoxModel() = default; 45 46 /** Destructor. */ 47 virtual ~TableListBoxModel() = default; 48 49 //============================================================================== 50 /** This must return the number of rows currently in the table. 51 52 If the number of rows changes, you must call TableListBox::updateContent() to 53 cause it to refresh the list. 54 */ 55 virtual int getNumRows() = 0; 56 57 /** This must draw the background behind one of the rows in the table. 58 59 The graphics context has its origin at the row's top-left, and your method 60 should fill the area specified by the width and height parameters. 61 62 Note that the rowNumber value may be greater than the number of rows in your 63 list, so be careful that you don't assume it's less than getNumRows(). 64 */ 65 virtual void paintRowBackground (Graphics&, 66 int rowNumber, 67 int width, int height, 68 bool rowIsSelected) = 0; 69 70 /** This must draw one of the cells. 71 72 The graphics context's origin will already be set to the top-left of the cell, 73 whose size is specified by (width, height). 74 75 Note that the rowNumber value may be greater than the number of rows in your 76 list, so be careful that you don't assume it's less than getNumRows(). 77 */ 78 virtual void paintCell (Graphics&, 79 int rowNumber, 80 int columnId, 81 int width, int height, 82 bool rowIsSelected) = 0; 83 84 //============================================================================== 85 /** This is used to create or update a custom component to go in a cell. 86 87 Any cell may contain a custom component, or can just be drawn with the paintCell() method 88 and handle mouse clicks with cellClicked(). 89 90 This method will be called whenever a custom component might need to be updated - e.g. 91 when the table is changed, or TableListBox::updateContent() is called. 92 93 If you don't need a custom component for the specified cell, then return nullptr. 94 (Bear in mind that even if you're not creating a new component, you may still need to 95 delete existingComponentToUpdate if it's non-null). 96 97 If you do want a custom component, and the existingComponentToUpdate is null, then 98 this method must create a new component suitable for the cell, and return it. 99 100 If the existingComponentToUpdate is non-null, it will be a pointer to a component previously created 101 by this method. In this case, the method must either update it to make sure it's correctly representing 102 the given cell (which may be different from the one that the component was created for), or it can 103 delete this component and return a new one. 104 */ 105 virtual Component* refreshComponentForCell (int rowNumber, int columnId, bool isRowSelected, 106 Component* existingComponentToUpdate); 107 108 //============================================================================== 109 /** This callback is made when the user clicks on one of the cells in the table. 110 111 The mouse event's coordinates will be relative to the entire table row. 112 @see cellDoubleClicked, backgroundClicked 113 */ 114 virtual void cellClicked (int rowNumber, int columnId, const MouseEvent&); 115 116 /** This callback is made when the user clicks on one of the cells in the table. 117 118 The mouse event's coordinates will be relative to the entire table row. 119 @see cellClicked, backgroundClicked 120 */ 121 virtual void cellDoubleClicked (int rowNumber, int columnId, const MouseEvent&); 122 123 /** This can be overridden to react to the user double-clicking on a part of the list where 124 there are no rows. 125 126 @see cellClicked 127 */ 128 virtual void backgroundClicked (const MouseEvent&); 129 130 //============================================================================== 131 /** This callback is made when the table's sort order is changed. 132 133 This could be because the user has clicked a column header, or because the 134 TableHeaderComponent::setSortColumnId() method was called. 135 136 If you implement this, your method should re-sort the table using the given 137 column as the key. 138 */ 139 virtual void sortOrderChanged (int newSortColumnId, bool isForwards); 140 141 //============================================================================== 142 /** Returns the best width for one of the columns. 143 144 If you implement this method, you should measure the width of all the items 145 in this column, and return the best size. 146 147 Returning 0 means that the column shouldn't be changed. 148 149 This is used by TableListBox::autoSizeColumn() and TableListBox::autoSizeAllColumns(). 150 */ 151 virtual int getColumnAutoSizeWidth (int columnId); 152 153 /** Returns a tooltip for a particular cell in the table. */ 154 virtual String getCellTooltip (int rowNumber, int columnId); 155 156 //============================================================================== 157 /** Override this to be informed when rows are selected or deselected. 158 @see ListBox::selectedRowsChanged() 159 */ 160 virtual void selectedRowsChanged (int lastRowSelected); 161 162 /** Override this to be informed when the delete key is pressed. 163 @see ListBox::deleteKeyPressed() 164 */ 165 virtual void deleteKeyPressed (int lastRowSelected); 166 167 /** Override this to be informed when the return key is pressed. 168 @see ListBox::returnKeyPressed() 169 */ 170 virtual void returnKeyPressed (int lastRowSelected); 171 172 /** Override this to be informed when the list is scrolled. 173 174 This might be caused by the user moving the scrollbar, or by programmatic changes 175 to the list position. 176 */ 177 virtual void listWasScrolled(); 178 179 /** To allow rows from your table to be dragged-and-dropped, implement this method. 180 181 If this returns a non-null variant then when the user drags a row, the table will try to 182 find a DragAndDropContainer in its parent hierarchy, and will use it to trigger a 183 drag-and-drop operation, using this string as the source description, and the listbox 184 itself as the source component. 185 186 @see getDragSourceCustomData, DragAndDropContainer::startDragging 187 */ 188 virtual var getDragSourceDescription (const SparseSet<int>& currentlySelectedRows); 189 190 private: 191 #if JUCE_CATCH_DEPRECATED_CODE_MISUSE 192 // This method's signature has changed to take a MouseEvent parameter - please update your code! 193 JUCE_DEPRECATED_WITH_BODY (virtual int backgroundClicked(), { return 0; }) 194 #endif 195 }; 196 197 198 //============================================================================== 199 /** 200 A table of cells, using a TableHeaderComponent as its header. 201 202 This component makes it easy to create a table by providing a TableListBoxModel as 203 the data source. 204 205 206 @see TableListBoxModel, TableHeaderComponent 207 208 @tags{GUI} 209 */ 210 class JUCE_API TableListBox : public ListBox, 211 private ListBoxModel, 212 private TableHeaderComponent::Listener 213 { 214 public: 215 //============================================================================== 216 /** Creates a TableListBox. 217 218 The model pointer passed-in can be null, in which case you can set it later 219 with setModel(). The TableListBox does not take ownership of the model - it's 220 the caller's responsibility to manage its lifetime and make sure it 221 doesn't get deleted while still being used. 222 */ 223 TableListBox (const String& componentName = String(), 224 TableListBoxModel* model = nullptr); 225 226 /** Destructor. */ 227 ~TableListBox() override; 228 229 //============================================================================== 230 /** Changes the TableListBoxModel that is being used for this table. 231 The TableListBox does not take ownership of the model - it's the caller's responsibility 232 to manage its lifetime and make sure it doesn't get deleted while still being used. 233 */ 234 void setModel (TableListBoxModel* newModel); 235 236 /** Returns the model currently in use. */ getModel()237 TableListBoxModel* getModel() const noexcept { return model; } 238 239 //============================================================================== 240 /** Returns the header component being used in this table. */ getHeader()241 TableHeaderComponent& getHeader() const noexcept { return *header; } 242 243 /** Sets the header component to use for the table. 244 The table will take ownership of the component that you pass in, and will delete it 245 when it's no longer needed. 246 The pointer passed in may not be null. 247 */ 248 void setHeader (std::unique_ptr<TableHeaderComponent> newHeader); 249 250 /** Changes the height of the table header component. 251 @see getHeaderHeight 252 */ 253 void setHeaderHeight (int newHeight); 254 255 /** Returns the height of the table header. 256 @see setHeaderHeight 257 */ 258 int getHeaderHeight() const noexcept; 259 260 //============================================================================== 261 /** Resizes a column to fit its contents. 262 263 This uses TableListBoxModel::getColumnAutoSizeWidth() to find the best width, 264 and applies that to the column. 265 266 @see autoSizeAllColumns, TableHeaderComponent::setColumnWidth 267 */ 268 void autoSizeColumn (int columnId); 269 270 /** Calls autoSizeColumn() for all columns in the table. */ 271 void autoSizeAllColumns(); 272 273 /** Enables or disables the auto size options on the popup menu. 274 By default, these are enabled. 275 */ 276 void setAutoSizeMenuOptionShown (bool shouldBeShown) noexcept; 277 278 /** True if the auto-size options should be shown on the menu. 279 @see setAutoSizeMenuOptionShown 280 */ isAutoSizeMenuOptionShown()281 bool isAutoSizeMenuOptionShown() const noexcept { return autoSizeOptionsShown; } 282 283 /** Returns the position of one of the cells in the table. 284 285 If relativeToComponentTopLeft is true, the coordinates are relative to 286 the table component's top-left. The row number isn't checked to see if it's 287 in-range, but the column ID must exist or this will return an empty rectangle. 288 289 If relativeToComponentTopLeft is false, the coordinates are relative to the 290 top-left of the table's top-left cell. 291 */ 292 Rectangle<int> getCellPosition (int columnId, int rowNumber, 293 bool relativeToComponentTopLeft) const; 294 295 /** Returns the component that currently represents a given cell. 296 If the component for this cell is off-screen or if the position is out-of-range, 297 this may return nullptr. 298 @see getCellPosition 299 */ 300 Component* getCellComponent (int columnId, int rowNumber) const; 301 302 /** Scrolls horizontally if necessary to make sure that a particular column is visible. 303 304 @see ListBox::scrollToEnsureRowIsOnscreen 305 */ 306 void scrollToEnsureColumnIsOnscreen (int columnId); 307 308 //============================================================================== 309 /** @internal */ 310 int getNumRows() override; 311 /** @internal */ 312 void paintListBoxItem (int, Graphics&, int, int, bool) override; 313 /** @internal */ 314 Component* refreshComponentForRow (int rowNumber, bool isRowSelected, Component* existingComponentToUpdate) override; 315 /** @internal */ 316 void selectedRowsChanged (int row) override; 317 /** @internal */ 318 void deleteKeyPressed (int currentSelectedRow) override; 319 /** @internal */ 320 void returnKeyPressed (int currentSelectedRow) override; 321 /** @internal */ 322 void backgroundClicked (const MouseEvent&) override; 323 /** @internal */ 324 void listWasScrolled() override; 325 /** @internal */ 326 void tableColumnsChanged (TableHeaderComponent*) override; 327 /** @internal */ 328 void tableColumnsResized (TableHeaderComponent*) override; 329 /** @internal */ 330 void tableSortOrderChanged (TableHeaderComponent*) override; 331 /** @internal */ 332 void tableColumnDraggingChanged (TableHeaderComponent*, int) override; 333 /** @internal */ 334 void resized() override; 335 336 337 private: 338 //============================================================================== 339 class Header; 340 class RowComp; 341 342 TableHeaderComponent* header = nullptr; 343 TableListBoxModel* model; 344 int columnIdNowBeingDragged = 0; 345 bool autoSizeOptionsShown = true; 346 347 void updateColumnComponents() const; 348 349 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TableListBox) 350 }; 351 352 } // namespace juce 353