Vaadin - adding columns to grid from map - java

I want to show data in vaadin's grid, but I want to create columns dynamically for each value from customAttributes list. My data model more or less look like this
Item
name: String
localization: Localization
visible: Boolean
customAttributes: List<CustomAttribute>
CustomAttribute
name: String
value: String
Each Item has the same set of attribute types, only the values are different. User can manually defined new attribute types.
How can I create this grid?
Currently I do it in this way:
grid.setColumns("name", "visible");
grid.addColumn(v -> v.getLocalization().getName()).setHeader("Localization");
But I have no idea for dynamic creating columns for each custom attribute.

Like it was already written in the comments, you can loop over the attribute names assuming your have a list (or set) of them. One small gotcha is that you need to do that in a way that ensures values inside the callback are effectively final.
attributeNames.forEach(name -> {
grid.addColumn(item -> item.getCustomAttributes().get(name))
.setHeader(name);
});
If you don't directly know the attribute names but you're loading all items into memory instead of lazy loading them, then you can find the unique names by iterating over all items:
items.stream().flatMap(item -> item.getCustomAttributes().keySet().stream())
.distinct().forEach(<same loop as in the previous example>);

Related

Filter in RecyclerView

I have RecyclerView witch initialized with data like this:
data class ObjectData(
var name: String,
var pass: Boolean
) : Serializable
I am Initialing the Adapter with ArrayList. In my Activity I have filter (All, Passed, No Passed). When I click one of the filters I wish that RecyclerView refresh with new data regarding the "pass" value. Example: On "Passed" filter button it will show only ObjectData with pass=true.
Question: What is the best approach to this? I can hold 3 list views, one with all data, one with passed objects and one with unpassed, and update adapter with the needed list when filter is changed. But this will cause data duplication. I can on filter copy all data to new filtered list, but it will trigger copy on every button filter click, and the user may change filters rapidly.
What can you suggest.
I would simply create copies lazily and cache them for example like this:
data class ObjectData(
var name: String,
var pass: Boolean
) : Serializable
val allData: List<ObjectData> = emptyList()
val filteredData: Map<Boolean, List<ObjectData>> by lazy {
allData.groupBy { it.pass }
}
This way you'll create both filtered lists in one go and only when you need them.
Honestly if data set is not big i wouldn't really optimise prematurely unless i see performance is bad. Nowadays Android has much better memory handling.

Programmatically check if a field in a domino document is a Text or a TextList - is it possible?

I am trying to implement a method that replaces all values inside a Hashmap with all the values inside a document.
The idea behind that is that I loop through all items that I get from Document.getItems() and simply use the Item.getType() method so I can decide what type I use for which field.
Something like that:
private void replace(SomeClass model, Document document) {
Map<String, Object> objectsMap = model.getObjectsMap();
Vector<Item> items = document.getItems();
for(Item item : items) {
if(item.getType() == Item.TEXT) {
model.add(item.getName(), item.getValueString()); // model.add(...) is basically a Map.put(String key, Object value);
} else if(item.getType() == Item.AUTHORS) {
// ...
} else if(/*...*/) {
// ...
}
}
}
Now my problem is that I cannot distinguish between a Text and a TextList because getType() returns 1280 for both.
Has anyone tried something like that already or maybe can give me a hint of what approach might be a workaround?
EDIT
Regarding the idea from one of the comments, to use a TextList when item.getValues().size() > 1 and Text otherwise:
As mentioned in the comment the problem is, that I want to be able to use the field later as well.
For example:
If I have a TextList field with one item in the document, and I would use the approach described above, I would put a String inside the Map for this field.
If I want to add more Items to this field (which should be a Vector since originally it was a TextList) I wouldn't be able to - at least not in a straight forward way.
NotesItems always return A Vector for values. There is no distinction between text and textList. However what you could do: get the form object and check the field properties. If allow multi value is ticked, then you can presume it was intended as textList rather than text.
That should sort your conversion decision. You also could flag items with more than one value that don’t have allow multi value set in the field - code would have done that
You could check the size of item.getValues() - which returns a Vector . If the size of the vector is > 0 it is a textilst.

Bind two input elements to a single model attribute

I have a simple form with two radios and two dropdowns populated with values from the same ENUM class for each radio respectively. At the same time I have to use a model which has only one attribute for the dropdown.
The problem is this model is used by a service, which I cannot change and it expects only this concrete model attribute. I need to decouple and temporarily save the values of the two dropdowns separately in the model. And then based on the selection from the radios, get the temporary value and assign it to the model attribute which then is used by this service.
Do you have a good idea, recommendation how best to achieve something like this?
Currently I have only a getter + setter for this attribute. But if I introduce another two temporary attributes with their gettrers and setters, how do I then assign their values to the 'global' attribute I want to send further?
public class TimeoutSetting implements Serializable {
public TimeoutEnum timeoutEnum;
public void setTimeoutEnum(TimeoutEnum timeoutEnum) {
this.timeoutEnum = timeoutEnum;
}
public TimeoutEnum getTimeoutEnum() {
return timeoutEnum;
}
}
So the timeoutEnum needs to be sort of mapped to two additional attributes. Let's say firstTimeout and secondTimeout, where I store the values from the first and second dropdowns. But then I send to the service only the value in the timeoutEnum. I need something similar, such that in the UI the two dropdowns are decoupled from one another, i.e. if I change the value of firstDropdown, the second one stays unchanged and so on (remember they are part of radio buttons, so only ONE is active at a time).

Exclude columns from clearing in realm database

Can i exclude two columns from clearing in Realm Database?
when i use realm.clear(City.class).
For example i don't want to clear data on name and location columns
When using clear method
I want to save it from clearing
No, you cannot do that. First, Realm.clear() is renamed to Realm.delete().
Basically the purpose of this API is to delete all the elements which are the type of given class. It is NOT set the default values to all the fields of those elements.
For your use case, you need to iterate and call set all values manually. Something like:
RealmResults<City> results = realm.where(City.class).findAll();
for (City city : results) {
city.setName(null);
city.setZipCode(0);
}

creating dataset in weka if values are lists/arrays

if the elements are just nominal or string values we can use Instance object to represent that particular instance. Also for the Instances dataset we can get attributes by pre-defining them. But i have question. what is the approach if we want to use collections as values to the attribute elements?
for ex:
weka.core.Attribute attribute1 = new weka.core.Attribute("list1");
weka.core.Attribute attribute2 = new weka.core.Attribute("list2");
weka.core.Attribute classAttribute = new weka.core.Attribute("Function");
FastVector fvWekaAttributes = new FastVector(3);
fvWekaAttributes.addElement(attribute1);
fvWekaAttributes.addElement(attribute2);
fvWekaAttributes.addElement(classAttribute);
is the way we create the attributes if two are nominal values and one is string(class). and the way we add elements in to any dataset(ex:trainInstances), we create Instance object and add like this:
Instance iExample = new Instance(3);
iExample.setValue((weka.core.Attribute)fvWekaAttributes.elementAt(0), 10);
iExample.setValue((weka.core.Attribute)fvWekaAttributes.elementAt(0), 15);
iExample.setValue((weka.core.Attribute)fvWekaAttributes.elementAt(2), "F1");
trainInstances.add(iExample);
this is ok, but what should i use to store Lists/collections instead of single nominal values. I want to do like this:
int[] list1={10,20,30,40};
int[] list2={90,80,70,60};
iExample.setValue((weka.core.Attribute)fvWekaAttributes.elementAt(0), **list1**);
iExample.setValue((weka.core.Attribute)fvWekaAttributes.elementAt(0), **list2**);
iExample.setValue((weka.core.Attribute)fvWekaAttributes.elementAt(2), "F1");
trainInstances.add(iExample);
to be more specific, these lists might change their sizes sometimes. i..e, in this example we see each list of length 4 in size but should support lists of different sizes in other Instance objects.
Is that possible using WEKA or any learning API. If so, please provide me the resources. It is mandatory to my master thesis..
In order to keep their Instances (dataset) objects as compact as possible, weka uses an index-value method to represent each value of a string or nominal Attribute. Each weka Instance (row in a dataset) only stores the index associated with the value for the attribute.
You are probably going to have to decide if the list element (as a whole) is more important that the individual elements of the list. If so, you will need to enumerate each of the possible lists that can occur as a value for that Attribute, and this list will need to be provided to the Attribute when it is created. If this is reasonable, you may decide to convert the lists to strings (i.e. list1="10,20,30,40").
If the individual elements of the list have value, it may be easier to create separate Attributes to identify if elements occur in the list or not.
If there is a fixed limit to the number of elements that occur in a list (and especially if the order of the list is important), you may consider having a separate Attribute for each list element. (i.e. Attibute("first_element_of_list"), Attribute("second_element_of_list"), ... etc)
If there is a fixed number of values that may occur on those lists and/or if the order is not important, you may consider having boolean Attribute to indicate if a specified element occurs in the list. (i.e. Attribute("10_in_list"), Attribute("20_in_list"), ... etc)

Categories