I'm looking for a way to create a treeTable view in Nattable. I already have a NatTable implemented with filter, sorting, ...
But now I'm looking into a TreeTable like the TreeGridWithCheckBoxFieldsExample from the Nattable examples. The only requirement is that I do not change my datamodel for the tree.
I have two different objects Company and role. Every company does has all the roles. So in this situation I need a tree with all the companies as root object and all the roles beneath all the companies.
From the example it looks like I need to create a format class that implements the TreeList.Format but they are using the model to link the parent (I will not do this because it's a violation of the MVC principle.
Can someone get me on track to create a treetable view in NatTable?
After checking some example of Natable I got a working treeTable. But have only one problem left. The parent items are not correctly shown.
The treeFormat looks like:
public class TreeFormat implements TreeList.Format<PermissionViewModel> {
public TreeFormat() {
}
#Override
public Comparator getComparator(int depth) {
return new Comparator<PermissionViewModel>() {
#Override
public int compare(PermissionViewModel object1, PermissionViewModel object2) {
return object1.getModuleName().compareTo(object2.getModuleName());
}
};
}
#Override
public void getPath(List<PermissionViewModel> path, PermissionViewModel element) {
path.add(element);
PermissionViewModel parent = element.getParent();
while (parent != null) {
path.add(parent);
parent = parent.getParent();
}
Collections.reverse(path);
}
#Override
public boolean allowsChildren(PermissionViewModel element) {
return true;
}
The model that I use is a viewModel and is a one to one map to the normal model
public class PermissionViewModel implements Comparable {
private PermissionViewModel parent;
private ArrayList<PermissionViewModel> children = new ArrayList();
private Integer permissionId;
private String moduleName;
private String permissionName;
private boolean active;
private boolean on;
public PermissionViewModel(PermissionViewModel parent, Permission permission) {
this.parent = parent;
if (parent != null) {
parent.addChild(this);
}
if(parent == null && permission != null)
{
this.permissionId = 0;
this.moduleName = "";
this.permissionName = permission.getModuleName();
this.active = false;
}
else
{
this.permissionId = permission.getPermissionId();
this.moduleName = permission.getModuleName();
this.permissionName = permission.getPermissionName();
this.active = permission.isActive();
}
}
public PermissionViewModel getParent() {
return this.parent;
}
public void addChild(PermissionViewModel child) {
this.children.add(child);
}
public List getChildren() {
return this.children;
}
public PermissionViewModel getSelf() {
return this;
}
public boolean isOn() {
if (this.children.size() == 0) {
return this.on;
} else {
return getCheckBoxState() == CheckBoxStateEnum.CHECKED;
}
}
public void setOn(boolean on) {
if (this.children.size() == 0) {
this.on = on;
} else {
for (PermissionViewModel child : this.children) {
child.setOn(on);
}
}
}
public CheckBoxStateEnum getCheckBoxState() {
if (this.children.size() == 0) {
return this.on ? CheckBoxStateEnum.CHECKED
: CheckBoxStateEnum.UNCHECKED;
} else {
boolean atLeastOneChildChecked = false;
boolean atLeastOneChildUnchecked = false;
for (PermissionViewModel child : this.children) {
CheckBoxStateEnum childCheckBoxState = child.getCheckBoxState();
switch (childCheckBoxState) {
case CHECKED:
atLeastOneChildChecked = true;
break;
case SEMICHECKED:
return CheckBoxStateEnum.SEMICHECKED;
case UNCHECKED:
atLeastOneChildUnchecked = true;
break;
}
}
if (atLeastOneChildChecked) {
if (atLeastOneChildUnchecked) {
return CheckBoxStateEnum.SEMICHECKED;
} else {
return CheckBoxStateEnum.CHECKED;
}
} else {
return CheckBoxStateEnum.UNCHECKED;
}
}
}
#Override
public int compareTo(Object o) {
return 0;
}
public Integer getPermissionId() {
return permissionId;
}
public String getModuleName() {
return moduleName;
}
public String getPermissionName() {
return permissionName;
}
public boolean isActive() {
return active;
}
}
Putting data in the tree table will be done with following source:
ArrayList<PermissionViewModel> permissionViewModelsList = new ArrayList<>();
String previousModule = "";
PermissionViewModel currentParent = null;
for (Permission element : repo.getAllData()) {
if(!previousModule.equals(element.getModuleName()))
{
previousModule = element.getModuleName();
currentParent = new PermissionViewModel(null, element);
permissionViewModelsList.add(currentParent);
permissionViewModelsList.add(new PermissionViewModel(currentParent, element));
}
else
{
permissionViewModelsList.add(new PermissionViewModel(currentParent, element));
}
}
Collections.reverse(permissionViewModelsList);
permissionTable.setItems(permissionViewModelsList);
permissionTable.refresh(true);
But when I look at the table the root elements are viewed but the childeren of the root elements are wrong. I viewed the list of elements and there I can't find any issues. Can someone find the issue that I have?
I changed to order of the columns. I placed the "Module Name" before the "Name" column. And the parent module name has been placed in the module name column. This fixed my problem.
The issue in this case was that the comperator that I used is not working on mixed data in the same fields. Tnx to Dirk Fauth I found it.
Related
I have the following problem. I have the following classes
public class Main {
public static void main(String[] args) {
// Expected: true
// Results in: true
List<String> strLst = new ArrayList<>();
strLst.add(new String("A"));
System.out.println(strLst.contains(new String("A")));
// Expected: true
// Results in: true
List<Number> numLst = new ArrayList<>();
numLst.add(new Number(1));
System.out.println(numLst.contains(new Number(1)));
// Expected: true
// Results in: false
Container<String> integers = new Container<>();
integers.add(new String("A"));
System.out.println(integers.contains(new String("A")));
// Expected: true
// Results in: false
Container<Number> numbers = new Container<>();
numbers.add(new Number(1));
System.out.println(numbers.contains(new Number(1)));
}
}
class Container<T> {
ArrayList<Node<T>> internal = new ArrayList<>();
public void add(T elem) {
internal.add(new Node<>(elem));
}
public boolean contains(T label) {
for (Node<T> e : internal) {
if (e.getLabel().equals(e)) {
return true;
}
}
return false;
}
}
class Node<T> {
T label;
public Node(T label) {
this.label = label;
}
public T getLabel() {
return label;
}
}
class Number {
private int val;
public Number(int val) {
this.val = val;
}
public boolean equals(Object o) {
if (o instanceof Number) {
return this.val == ((Number) o).val;
}
return false;
}
}
I am not sure what went wrong here. I would expect similar behavior with my Container as with ArrayList. But it does not, because in my opinion ArrayList (see https://github.com/openjdk-mirror/jdk7u-jdk/blob/master/src/share/classes/java/util/ArrayList.java#L251) implements contains in a similar way.
What does ArrayList do different than I do? And if it is not possible to implement such behavior the way I hope to, how would I do this alternatively?
The line
if (e.getLabel().equals(e)) {
in contains should be
if (e.getLabel().equals(label)) {
Solution:
public boolean contains(T label) {
for (Node<T> e : internal) {
if (e.getLabel().equals(label)) {
return true;
}
}
return false;
}
I am trying to create my own binary search tree. But I can't think of any way to implement a working iterator that has hasNext(), next().
I got the idea the only way to traverse a Binary search tree was through recursion. But how could I possibly save a recursion call if I am trying to use next, so it resumes when next gets called again and returns the value?
Is there any other way
import java.util.Iterator;
public class TreeWordSet implements WordSetInterface {
private BST root = null;
private class BST {
Word value;
BST left = null;
BST right = null;
BST(Word word) {
value = word;
}
void add(Word newWord) {
if (newWord.compareTo(value) < 0) {
if(left == null) {
left = new BST(newWord);
} else {
left.add(newWord);
}
} else if (newWord.compareTo(value) > 0) {
if (right == null) {
right = new BST(newWord);
} else {
right.add(newWord);
}
}
}
}
#Override
public void add(Word word) {
if (root == null) {
root = new BST(word);
} else {
root.add(word);
}
}
#Override
public boolean contains(Word word) {
return false;
}
#Override
public int size() {
return 0;
}
private class TreeWordSetIterator implements Iterator<Word> {
#Override
public boolean hasNext() {
return false;
}
#Override
public Word next() {
return null;
}
}
#Override
public Iterator<Word> iterator() {
return new TreeWordSetIterator();
}
}
If this is an exercise for the purpose of learning, maybe the best way is to just go look how TreeSet does it. If this is an exercise for production use, stop it right here right now and extend TreeSet if you really need to.
I solved it this way, it's not glamourous. Until someone can provide a better solution
private class TreeWordSetIterator implements Iterator<Word> {
Word arr[] = new Word[size()];
int i = 0;
TreeWordSetIterator(){
traverse(root);
i = 0;
}
private void traverse(BST currentNode) {
if (currentNode == null) {
return;
}
traverse(currentNode.left);
arr[i] = currentNode.value;
i++;
traverse(currentNode.right);
}
#Override
public boolean hasNext() {
if (i < size()) {
return true;
} else {
return false;
}
}
#Override
public Word next() {
Word current = arr[i];
i++;
return current;
}
}
I have a test for testing that adding the same Edge (Arista) but with the same vertices (but flipped order) is the same (this is not a directed graph).
And this is strange because the two first assertions passes OK (adding Edge1 and Edge2 will result in edges.sizes = 1 because they are the same, theoretically).
But then when testing that edges.contains(Edge2) returns false.
Why could it have worked when testing addition (to not add it duplicated) but does not work when testing contains()?
This is the code:
#Test
public final void testAristaWithSameVerticesIsNotAddedTwice() throws Exception {
Grafo grafo = new Grafo();
Vertice vertice1 = new Vertice("Vertice 1");
Vertice vertice2 = new Vertice("Vertice 2");
grafo.agregarVertice(vertice1);
grafo.agregarVertice(vertice2);
Arista arista = new Arista(vertice1, vertice2, 10);
Arista arista2 = new Arista(vertice2, vertice1, 10);
grafo.agregarArista(arista);
grafo.agregarArista(arista);
assertEquals(1, grafo.getAristasQuantity());
assertTrue(grafo.hasArista(arista));
assertTrue(grafo.hasArista(arista2)); // fails here
}
Grafo class:
private HashSet<Arista> aristas;
public boolean hasArista(Arista arista) {
return this.aristas.contains(arista);
}
Arista class
package entities;
public class Arista {
protected Vertice vertice1;
protected Vertice vertice2;
protected int peso;
public Arista(Vertice vertice1, Vertice vertice2, int peso) {
this.vertice1 = vertice1;
this.vertice2 = vertice2;
this.peso = peso;
}
public Vertice getVertice1() {
return vertice1;
}
public Vertice getVertice2() {
return vertice2;
}
public int getPeso() {
return peso;
}
public void setPeso(int peso ) {
this.peso = peso;
}
public int hashCode() {
return vertice1.hashCode() + vertice2.hashCode();
}
public boolean equals(Arista arista) {
if (arista == this) {
return true;
}
if ((arista.getVertice1() == this.vertice1 && arista.getVertice2() == this.vertice2)
|| (arista.getVertice2() == this.vertice1 && arista.getVertice1() == this.vertice2)) {
return true;
}
return false;
}
}
I found out that the equals() wasn't overriding the parent definition because it was not well defined. So it wasn't being called.
Correct way is:
#Override
public boolean equals(Object object) {
if (object instanceof Arista) {
Arista arista = (Arista) object;
if (arista == this) {
return true;
}
if ((arista.getVertice1() == this.vertice1 && arista.getVertice2() == this.vertice2)
|| (arista.getVertice2() == this.vertice1 && arista.getVertice1() == this.vertice2)) {
return true;
}
}
return false;
}
I search solution of my problem, my algorithm code delete element from Binary Search tree doesn't work properly. I don't know, where is error in this code and how it should be to work
public void usun(int wartosc) {
korzen = usunrekord(korzen, wartosc);
}
private Wezel usunrekord(Wezel korzen, int wartosc1) {
if (korzen == null)
return korzen;
if (wartosc1 < korzen.getWartosc()) {
korzen.setLewy(usunrekord(korzen.getLewy(), wartosc1));
if (wartosc1 > korzen.getWartosc())
korzen.setPrawy(usunrekord(korzen.getPrawy(), wartosc1));
else {
if (korzen.getLewy() == null)
return korzen.getPrawy();
else if (korzen.getPrawy() == null)
return korzen.getLewy();
korzen.setWartosc(znajdzMin());
korzen.setPrawy(usunrekord(korzen.getPrawy(), korzen.getWartosc()));
}
return korzen;
}
return korzen;
}
Class Node, create tree binary search based on it
public class Wezel {
private int wartosc;
private Wezel lewy;
private Wezel prawy;
public Wezel(int wartosc) {
this.wartosc = wartosc;
}
public int getWartosc() {
return wartosc;
}
public void setWartosc(int wartosc) {
this.wartosc = wartosc;
}
public Wezel getLewy() {
return lewy;
}
public void setLewy(Wezel lewy) {
this.lewy = lewy;
}
public Wezel getPrawy() {
return prawy;
}
public void setPrawy(Wezel prawy) {
this.prawy = prawy;
}
}
I am using a tree table model in my app which extends AbstractTreeTableModel in order to create a JXTreeTable. Below is my model.
import org.jdesktop.swingx.treetable.AbstractTreeTableModel;
import org.jdesktop.swingx.treetable.DefaultTreeTableModel;
import org.jdesktop.swingx.treetable.TreeTableModel;
import javax.swing.tree.TreeModel;
public class MyDataModel extends AbstractTreeTableModel{
static protected String[] columnNames = { "Field", "Value" };
static protected Class<?>[] columnTypes = { Object.class, Object.class};
public MyDataModel(MyDataNode rootNode) {
super(rootNode);
root = rootNode;
}
#Override
public Object getChild(Object parent, int index) {
return ((MyDataNode) parent).getChildren().get(index);
}
#Override
public int getChildCount(Object parent) {
return ((MyDataNode) parent).getChildren().size();
}
#Override
public int getIndexOfChild(Object parent, Object child) {
return 0;
}
#Override
public int getColumnCount() {
return columnNames.length;
}
#Override
public String getColumnName(int column) {
return columnNames[column];
}
#Override
public Class<?> getColumnClass(int column) {
return columnTypes[column];
}
#Override
public Object getValueAt(Object node, int column) {
MyDataNode mNode=(MyDataNode)node;
Object obj =mNode.getNodeDataObject();
if(column==0){
return mNode.getName();
}
else if (column==1){
if(obj instanceof Field){
Field field=(Field)mNode.getNodeDataObject();
if(field.getFieldDef().getListValue().size()>0){
return field.getFieldDef().getListValue();
}
else
return mNode.getDefaultValue();
}
else
return mNode.getDefaultValue();
}
return null;
}
#Override
public boolean isCellEditable(Object node, int column) {
//only allow Field values to be editable
if(((MyDataNode)node).getNodeDataObject() instanceof Field && column==1)
return true;
else
return false;
}
#Override
public boolean isLeaf(Object node) {
MyDataNode mNode=(MyDataNode)node;
Object obj=mNode.getNodeDataObject();
if(obj instanceof Field){
Field field=(Field)obj;
if(field.getFieldDef().getDataType().equalsIgnoreCase("MULTIPLE_MESSAGE")){
return false;
}
else
return true;
}
return false;
}
#Override
public void setValueAt(Object aValue, Object node, int column) {
MyDataNode mNode=(MyDataNode)node;
if (mNode.getNodeDataObject() instanceof Field && column == 1) {
Field field = (Field) mNode.getNodeDataObject();
field.setDefaultValue(aValue);
field.setSelectedValue(aValue);
}
}
}
This is how I use the JXTreeTable in my app
MyDataModel treeTableModel = new MyDataModel(createDataStructure(message));
jTreeTable = new JXTreeTable(treeTableModel);
private static MyDataNode createDataStructure(Message message) {
//setting fields as children of the root
nodeList = new ArrayList<>();
for (int index=0;index<message.getListFields().size() ; index++) {
if(message.getListFields().get(index).getFieldDef()
.getDataType().equalsIgnoreCase("MULTIPLE_MESSAGE")){
nodeList.add(new MyDataNode(message.getListFields()
.get(index).getFieldDef().getfName(), "", childMessagesRoot,
message.getListFields().get(index)));
}
else{
nodeList.add(new MyDataNode(message.getListFields()
.get(index).getFieldDef().getfName(), (String)(message.getListFields().
get(index).getDefaultValue()),
null,message.getListFields().get(index)));
}
}
//setting the Message to the root of the tree
root = new MyDataNode(message.getMsgName(), "", nodeList,message);
return root;
}
when I need to add a new node to the JXTreeTable, I try to get its model and use insertNodeInto() function call but the model doesn't support the insertNodeInto() function.
Someone please let me know where I am going wrong in the code. This is the first time I am using tree tables so there could be something missing.
insertNodeInto is a method of DefaultTreeTableModel, but not one of AbstractTreeTableModel.
Let MyDataModel extend DefaultTreeTableModel rather than AbstractTreeTableModel to be able to use insertNodeInto.
When accessing the TreeTableModel through JXTreeTable#getTreeTableModel, remember to cast the returned object of type TreeTableModel to DefaultTreeTableModel before calling insertNodeInto.
I found where I had gone wrong. I extended MyDataModel class with DefaultTreeTableModel and made my node class(I am using a custom node class) extend DefaultMutableTreeTableNode this gave the solution to use insertNodeInto method to get the current selected node of the tree table.