2 ==============================================================================
4 This file is part of the JUCE library - "Jules' Utility Class Extensions"
5 Copyright 2004-9 by Raw Material Software Ltd.
7 ------------------------------------------------------------------------------
9 JUCE can be redistributed and/or modified under the terms of the GNU General
10 Public License (Version 2), as published by the Free Software Foundation.
11 A copy of the license is included in the JUCE distribution, or can be found
12 online at www.gnu.org/licenses.
14 JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 ------------------------------------------------------------------------------
20 To release a closed-source product which uses JUCE, commercial licenses are
21 available: visit www.rawmaterialsoftware.com/juce for more information.
23 ==============================================================================
26 #include "../jucedemo_headers.h"
29 //==============================================================================
31 This class shows how to implement a TableListBoxModel to show in a TableListBox.
33 class TableDemoComponent
: public Component
,
34 public TableListBoxModel
37 //==============================================================================
41 // Load some data from an embedded XML file..
44 // Create our table component and add it to this component..
45 addAndMakeVisible (&table
);
46 table
.setModel (this);
49 table
.setColour (ListBox::outlineColourId
, Colours::grey
);
50 table
.setOutlineThickness (1);
52 // Add some columns to the table header, based on the column list in our database..
53 forEachXmlChildElement (*columnList
, columnXml
)
55 table
.getHeader().addColumn (columnXml
->getStringAttribute ("name"),
56 columnXml
->getIntAttribute ("columnId"),
57 columnXml
->getIntAttribute ("width"),
59 TableHeaderComponent::defaultFlags
);
62 // we could now change some initial settings..
63 table
.getHeader().setSortColumnId (1, true); // sort forwards by the ID column
64 table
.getHeader().setColumnVisible (7, false); // hide the "length" column until the user shows it
66 // un-comment this line to have a go of stretch-to-fit mode
67 // table.getHeader().setStretchToFitActive (true);
69 table
.setMultipleSelectionEnabled (true);
76 //==============================================================================
77 // This is overloaded from TableListBoxModel, and must return the total number of rows in our table
83 // This is overloaded from TableListBoxModel, and should fill in the background of the whole row
84 void paintRowBackground (Graphics
& g
, int /*rowNumber*/, int /*width*/, int /*height*/, bool rowIsSelected
)
87 g
.fillAll (Colours::lightblue
);
90 // This is overloaded from TableListBoxModel, and must paint any cells that aren't using custom
92 void paintCell (Graphics
& g
,
95 int width
, int height
,
96 bool /*rowIsSelected*/)
98 g
.setColour (Colours::black
);
101 const XmlElement
* rowElement
= dataList
->getChildElement (rowNumber
);
105 const String
text (rowElement
->getStringAttribute (getAttributeNameForColumnId (columnId
)));
107 g
.drawText (text
, 2, 0, width
- 4, height
, Justification::centredLeft
, true);
110 g
.setColour (Colours::black
.withAlpha (0.2f
));
111 g
.fillRect (width
- 1, 0, 1, height
);
114 // This is overloaded from TableListBoxModel, and tells us that the user has clicked a table header
115 // to change the sort order.
116 void sortOrderChanged (int newSortColumnId
, bool isForwards
)
118 if (newSortColumnId
!= 0)
120 DemoDataSorter
sorter (getAttributeNameForColumnId (newSortColumnId
), isForwards
);
121 dataList
->sortChildElements (sorter
);
123 table
.updateContent();
127 // This is overloaded from TableListBoxModel, and must update any custom components that we're using
128 Component
* refreshComponentForCell (int rowNumber
, int columnId
, bool /*isRowSelected*/,
129 Component
* existingComponentToUpdate
)
131 if (columnId
== 5) // If it's the ratings column, we'll return our custom component..
133 RatingColumnCustomComponent
* ratingsBox
= (RatingColumnCustomComponent
*) existingComponentToUpdate
;
135 // If an existing component is being passed-in for updating, we'll re-use it, but
136 // if not, we'll have to create one.
138 ratingsBox
= new RatingColumnCustomComponent (*this);
140 ratingsBox
->setRowAndColumn (rowNumber
, columnId
);
146 // for any other column, just return 0, as we'll be painting these columns directly.
148 jassert (existingComponentToUpdate
== 0);
153 // This is overloaded from TableListBoxModel, and should choose the best width for the specified
155 int getColumnAutoSizeWidth (int columnId
)
158 return 100; // (this is the ratings column, containing a custom component)
162 // find the widest bit of text in this column..
163 for (int i
= getNumRows(); --i
>= 0;)
165 const XmlElement
* rowElement
= dataList
->getChildElement (i
);
169 const String
text (rowElement
->getStringAttribute (getAttributeNameForColumnId (columnId
)));
171 widest
= jmax (widest
, font
.getStringWidth (text
));
178 // A couple of quick methods to set and get the "rating" value when the user
179 // changes the combo box
180 int getRating (const int rowNumber
) const
182 return dataList
->getChildElement (rowNumber
)->getIntAttribute ("Rating");
185 void setRating (const int rowNumber
, const int newRating
)
187 dataList
->getChildElement (rowNumber
)->setAttribute ("Rating", newRating
);
190 //==============================================================================
193 // position our table with a gap around its edge
194 table
.setBoundsInset (BorderSize
<int> (8));
199 TableListBox table
; // the table component itself
202 ScopedPointer
<XmlElement
> demoData
; // This is the XML document loaded from the embedded file "demo table data.xml"
203 XmlElement
* columnList
; // A pointer to the sub-node of demoData that contains the list of columns
204 XmlElement
* dataList
; // A pointer to the sub-node of demoData that contains the list of data rows
205 int numRows
; // The number of rows of data we've got
207 //==============================================================================
208 // This is a custom component containing a combo box, which we're going to put inside
209 // our table's "rating" column.
210 class RatingColumnCustomComponent
: public Component
,
211 public ComboBoxListener
214 RatingColumnCustomComponent (TableDemoComponent
& owner_
)
217 // just put a combo box inside this component
218 addAndMakeVisible (&comboBox
);
219 comboBox
.addItem ("fab", 1);
220 comboBox
.addItem ("groovy", 2);
221 comboBox
.addItem ("hep", 3);
222 comboBox
.addItem ("neat", 4);
223 comboBox
.addItem ("wild", 5);
224 comboBox
.addItem ("swingin", 6);
225 comboBox
.addItem ("mad for it", 7);
227 // when the combo is changed, we'll get a callback.
228 comboBox
.addListener (this);
229 comboBox
.setWantsKeyboardFocus (false);
232 ~RatingColumnCustomComponent()
238 comboBox
.setBoundsInset (BorderSize
<int> (2));
241 // Our demo code will call this when we may need to update our contents
242 void setRowAndColumn (const int newRow
, const int newColumn
)
245 columnId
= newColumn
;
246 comboBox
.setSelectedId (owner
.getRating (row
), true);
249 void comboBoxChanged (ComboBox
* /*comboBoxThatHasChanged*/)
251 owner
.setRating (row
, comboBox
.getSelectedId());
255 TableDemoComponent
& owner
;
260 //==============================================================================
261 // A comparator used to sort our data when the user clicks a column header
265 DemoDataSorter (const String attributeToSort_
, bool forwards
)
266 : attributeToSort (attributeToSort_
),
267 direction (forwards
? 1 : -1)
271 int compareElements (XmlElement
* first
, XmlElement
* second
) const
273 int result
= first
->getStringAttribute (attributeToSort
)
274 .compareLexicographically (second
->getStringAttribute (attributeToSort
));
277 result
= first
->getStringAttribute ("ID")
278 .compareLexicographically (second
->getStringAttribute ("ID"));
280 return direction
* result
;
284 String attributeToSort
;
288 //==============================================================================
289 // this loads the embedded database XML file into memory
292 XmlDocument
dataDoc (String ((const char*) BinaryData::demo_table_data_xml
));
293 demoData
= dataDoc
.getDocumentElement();
295 dataList
= demoData
->getChildByName ("DATA");
296 columnList
= demoData
->getChildByName ("COLUMNS");
298 numRows
= dataList
->getNumChildElements();
301 // (a utility method to search our XML for the attribute that matches a column ID)
302 const String
getAttributeNameForColumnId (const int columnId
) const
304 forEachXmlChildElement (*columnList
, columnXml
)
306 if (columnXml
->getIntAttribute ("columnId") == columnId
)
307 return columnXml
->getStringAttribute ("name");
310 return String::empty
;
313 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TableDemoComponent
);
317 //==============================================================================
318 Component
* createTableDemo()
320 return new TableDemoComponent();