This is how I update my TableViewer that displays a list:
public void view(MyListClass list) {
ViewerSupport.bind(
this,
new WritableList(list, controller.theClass()),
BeanProperties.values(controller.theClass(), controller.strings())
);
}
controller is an instance of a class that encapsulates my glue code (it is a different class for the two listings; as is controller.theClass()). strings() is an array of property names. MyListClass descends from ArrayList<MyListEntryObject>. That works fine. But, I want to display a matrix of data. MyMatrixClass is a HashMap<Point, MyMatrixEntryObject>. This is what I've tried:
private void view(MyMatrixClass matrix) {
columns(matrix.columns());
List<WritableList> lists = new ArrayList<WritableList>(matrix.rows());
for (MyEntityClass list : matrix.children())
if (list instanceof MyListClass)
lists.add(new WritableList((MyListClass) list, controller.theClass()));
WritableList[] alists = lists.toArray(new WritableList[0]);
MultiList mlist = new MultiList(alists);
ViewerSupport.bind(
this,
mlist,
BeanProperties.value(controller.theClass(), "value")
);
}
This doesn't work. I get null argument popup errors. (Every data model class implements MyEntityClass. Class names have been altered due to this being a proprietary program I'm being employed to develop.)
Long story short, how do I use ViewerSupport and BeanProperties to display a matrix of data in a TableViewer?
As the JFace table viewer is line-based, you have to provide your matrix in a line-based way. You have to create a collection of the lines of the matrix, and then set this list as the input of the viewer. After that, you could create BeanProperties, that display the columns of the selected rows.
Related
In NatTable I am adding a row in filtered table. After removing the filter, the newly added row moves to last position in the table.
But I want to it to stay in the same position, that is next to the row which I added when the table is filtered.
I am currently using the RowInsertCommand. I don't want to add row via model or list which used to populated the table. I want to achieve only via NatTable commands. Is it possible?
It is always hard to follow the explanations and the issue without example code. But I assume you simply copied code from the NatTable examples, so I will explain your issue based on that.
First, the RowInsertCommand has several constructors. If you are using a constructor without a rowIndex or rowPositionparameter, the new object will ALWAYS be added at the end of the list.
When using the filter functionality in NatTable with GlazedLists, the list that is wrapped in the body DataLayer is the FilterList. If you are operating on the FilterList for calculating the rowIndex where the new object should be added and have the FilterList as base list in the RowInsertCommandHandler, the place where the new object is added is transformed between the FilterList and the base EventList, which might not be the desired result.
To solve this you need to create the RowInsertCommandHandler by using the base EventList.
EventList<T> eventList = GlazedLists.eventList(values);
TransformedList<T, T> rowObjectsGlazedList = GlazedLists.threadSafeList(eventList);
SortedList<T> sortedList = new SortedList<>(rowObjectsGlazedList, null);
this.filterList = new FilterList<>(sortedList);
this.baseList = eventList;
bodyDataLayer.registerCommandHandler(new RowInsertCommandHandler<>(this.baseList));
The action that performs the add operation then of course needs to calculate the index based on the base EventList. The following code is part of the SelectionAdapter of an IMenuItemProvider:
int rowPosition = MenuItemProviders.getNatEventData(event).getRowPosition();
int rowIndex = natTable.getRowIndexByPosition(rowPosition);
Object relative = bodyLayerStack.filterList.get(rowIndex);
int baseIndex = bodyLayerStack.baseList.indexOf(relative);
Object newObject = new ...;
natTable.doCommand(new RowInsertCommand<>(baseIndex + 1, newObject));
So I'm trying to make a simple program that takes in some basic information about a loan, and turns it into an amortization table.
I am using WindowBuilder for this, and thus I have a Tableviewer that is supposed to have a column for Month, interest, payment, ect.
Unfortunately, I can't figure out how to get the table to actually display information. I have a Loan object that generates an ArrayList of month objects (each month being one row of the table), but from what I've read online, it's not as simple as telling the Tableviewer to populate each column with a variable from that arraylist.
I have set my Content Provider to be a Loan object, which contains an Arraylist of Month Objects, and each Month object has a getter for each column.
How do I go about displaying the text in each column?
Thanks.
EDIT:
So, here is the snippet of code from the example given to me below:
colFirstName.setLabelProvider(new ColumnLabelProvider() {
#Override
public String getText(Object element) {
Person p = (Person) element;
return p.getFirstName();
}});
I don't quite understand what is going on here. It's overriding the getText method, and casting the element to the type of element that has their data?
balanceCol.setLabelProvider(new ColumnLabelProvider(){
#Override
public String getText(Object element) {
Loan m = (Loan) element;
return m.getMonthObj().get(0).getMonth();
}
});
When I run this, it almost sorta works. It fills in about half the months, and then I get this error:
java.lang.ClassCastException: model.Month cannot be cast to model.Loan
I have an observable list of chart data which is created automatically. Is there any way to automatically combine the data which has the same category name in to one category?
The reason I need this is since the observable list of data is created directly form a table in a SQL database, I can not know if the user actually wants to show a combined view or each category and value separately in the chart.
Say I have the following data:
Instead of Bordeau-1 appearing this many times, I want all the values combined in to one pie called Bordeau-1, the same goes for Boredeau-2 and 3.
This is the code I use to automatically create data from the ObservableList which represents a table:
ObservableList<PieChart.Data> pieChartData
=
FXCollections.observableArrayList(EasyBind.map(observableListData, rowData -> {
String name = (String) rowData.get(0);
Double value = Double.parseDouble(rowData.get(1));
return new PieChart.Data(name, value);
}));
When you load the data, store it in a Map<String, Double>, and use the Map.merge(...) method to add or combine new values.
So in the code where you are loading the data from the database, you do this:
public Map<String, Double> loadDataFromDatabase() {
Map<String, Double> data = new HashMap<>();
// for each row in database:
// get name and value from row
data.merge(name, value, Double::sum);
// end for...
return data ;
}
Once you have loaded all the data into the map, you need to convert it to an ObservableList<PieChart.Data>. I don't think there's a cute way to do this in EasyBind, and if you're loading all the data at the start anyway, then you don't need the bound list. You can do something like:
ObservableList<PieChart.Data> pieChartData =
data.entrySet().stream()
.map(entry -> new PieChart.Data(entry.getKey(), entry.getValue()))
.collect(Collectors.toCollection(() -> FXCollections.observableArrayList()));
If the original map may get modified after the pie chart is created, you will need to make it an ObservableMap, register a listener with it, and update the pie chart data accordingly if the map changes. If you need this, it might be worth requesting the appropriate functionality in the EasyBind framework. Something like a method
public static <K, V, T> ObservableList<T> mapToList(ObservableMap<K, V> map, Function<Map.Entry<K, V>, T> mapping);
I'm using the ListDataProvider example here as a guide. The columns are sorting fine as expectd based on the provided comparators. I'm trying to programatically apply a sort as alluded to on this line from the example:
// We know that the data is sorted alphabetically by default.
table.getColumnSortList().push(nameColumn);
What this does, is it makes the cell column appear to be sorted with the carrot sort indicator. However, the underlying data isn't sorted. Is there a way to get the table to actually apply the sort progarmatically. I suppose I could use this in conjunction with actually sorting the data via Collections.sort(), but I'd like to avoid that and do it in one place.
You can apply sorting on a column programatically with little exta code. The following code snippet does that -
When ever u set data to the cellTable you have to initialize the ListHandler as below code does -
cellTable.addColumnSortHandler( createColumnSortHandler() );
private ListHandler<T> createColumnSortHandler()
{
final ListHandler<T> listHandler = new ListHandler<T>(listDataProvider.getList());
listHandler.setComparator( sortColumn, comparator );
return listHandler;
}
And when u want to fire the SortEvent execute the following code snippet -
ColumnSortInfo columnSortInfo = new ColumnSortInfo( sortColumn, sortDirection );
cellTable.getColumnSortList().push( columnSortInfo );
ColumnSortEvent.fire( cellTable, cellTable.getColumnSortList());
you have to call setData on grid again.....
I am trying to display a CheckBoxTable in an Eclipse page which enables the user to select any one of a number of items - the items that are available come from an EMF model and are enums.
I've got the content provider and the label provider set up correctly (I think) but I can't figure what to use to set the input in order to display the full list of enums.
So say my model has an enum called MyEnum which has values of ONE, TWO and THREE - I want to be able to display all three of those enums to the user as check boxes.
I need to call setInput(...) on the viewer but what do I pass into it to get those enums?
Although I've never done it for a CheckboxTableViewer, I have set an EEnum as the source of values for other StructuredViewer classes like ComboViewer. What I did was create a custom IStructuredContentProvider that is a subclass of ArrayList and takes the EEnum as a constructor argument (call this class EEnumContentProvider). In the constructor, I iterate over the EEnum's getELiterals() and call add() on each of their getInstance() values. Like this:
public EEnumContentProvider(EEnum source) {
List<EEnumLiteral> literals = source.getELiterals();
for (EEnumLiteral aLiteral : literals) {
add(aLiteral.getInstance());
}
}
You can easily implement IStructuredContentProvider.getElements(Object) by using returning the result of toArray() and you don't care about IContentProvider.setInput() because the contents aren't based on the input, they're static.
Then you can set an instance of EEnumContentProvider as the content provider for the viewer.
Simply you need to get the literals and add them to the control as follows:
/* Populate the Combo Box with the Literals */
EEnum cFEnum = Package.Literals.LITERAL_ENUMERATION;
/*
* Add an EMPTY item value so that the user can disable the specific
* feature
*/
this.cmbNames.add( EMPTY_STRING );
/*
* Add the Enumeration Literals to the
* appropriate SWT Combo widget.
*/
for (int i=0; i<cFEnum.getELiterals().size(); i++){
this.cmbNames.add( cFEnum.getEEnumLiteral( i ).toString() );
}
cFEnum = null;
String[] sortedTypes = this.cmbNames.getItems();
Arrays.sort( sortedTypes );
this.cmbNames.setItems( sortedTypes );