How to preserve selections in a JFace TableViewer when refreshing? - java

In my project I have a TableViewer which has a model, a content provider and a label provider.
Once I update my model I call tableviewer.refresh(true) and according to the documentation here:
TableViewer Methods
I'm expecting my selections to be preserved.
Unfortunately this doesn't happen. Does anybody know a solution for that?
Is it something that I miss in here or is it a bug?
EDIT:
This is my model class(counter is for testing purposes to be sure that I have the same list returned after the first refresh):
public class ItemWorkgroup {
List<Item> currentItems = new ArrayList<Item>();
static int counter = 0;
public ItemWorkgroup()
{
}
public void add(Item item)
{
currentItems.add(item);
}
public Object[] getItems()
{
return currentItems.toArray();
}
public void addList(List<Item> newItemsList)
{
System.out.println("Current items first 1: "+currentItems);
if(counter == 0)
{
currentItems = newItemsList;
counter++;
}
System.out.println("Current items first 2: "+currentItems);
}
public List<Item> getItemList()
{
return currentItems;
}
}
This is the content provider class:
public class ContentProvider implements IStructuredContentProvider{
private Mediator mediator;
private ItemWorkgroup model;
public ContentProvider(Mediator mediator, ItemWorkgroup model) {
// TODO Auto-generated constructor stub
this.mediator = mediator;
this.model = model;
}
#Override
public void dispose() {
// TODO Auto-generated method stub
}
#Override
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
// TODO Auto-generated method stub
System.out.println("Input changed");
}
#Override
public Object[] getElements(Object inputElement) {
// TODO Auto-generated method stub
System.out.println("Getting elements");
if(inputElement instanceof ItemWorkgroup)
{
return ((ItemWorkgroup) inputElement).getItems();
}
else
return new Object[0];
}
public ItemWorkgroup getItems()
{
//Items is a list of items that I'm getting from somewhere
model.addList(items);
return model;
}

The viewer tries to maintain the selection but if your content provider returns different objects for the elements that were selected after the refresh then the tree viewer will not be able to restore the selection.
Your content provider must return the same object for things which have not changed for the selection to be preserved. (Or you can return an object where the equals and hashCode methods make it appear the same).

Related

How to use abstract method TreeModel in zk framework?

My question just very short."How to use abstract method or example used in this method?"
This method is from org.zkoss.zul.TreeModel
tmtAtasan = new TreeModel<Map<String,Object>>() {
#Override
public void addTreeDataListener(TreeDataListener arg0) {
// TODO Auto-generated method stub
}
#Override
public Map<String, Object> getChild(int[] arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public Map<String, Object> getChild(Map<String, Object> arg0,
int arg1) {
// TODO Auto-generated method stub
return null;
}
#Override
public int getChildCount(Map<String, Object> arg0) {
// TODO Auto-generated method stub
return 0;
}
#Override
public int getIndexOfChild(Map<String, Object> arg0,
Map<String, Object> arg1) {
// TODO Auto-generated method stub
return 0;
}
#Override
public int[] getPath(Map<String, Object> arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public Map<String, Object> getRoot() {
// TODO Auto-generated method stub
return null;
}
#Override
public boolean isLeaf(Map<String, Object> arg0) {
// TODO Auto-generated method stub
return false;
}
#Override
public void removeTreeDataListener(TreeDataListener arg0) {
// TODO Auto-generated method stub
}
};
I am badly stuck into this. Any help would be really appreciateable.
Thanks in advance!
Ok so from what I understand you just want to use a generic TreeModel without needing to redefine specific behaviors.
So let's imagine your model is a list of Employee beans like :
public class Employee {
private String name;
private List<Employee> listSubordinates = new ArrayList<Employee>();
public Employee(String pName) {
name = pName;
}
public void setName(String pName) {
this.name = pName;
}
public String getName() {
return name;
}
public List<Employee> getListSubordinates() {
return listSubordinates;
}
public void setListSubordinates(List<Employee> pListSubordinates) {
this.listSubordinates = pListSubordinates;
}
}
For this example, we'll imagine you have retrieved a list of employee that are sorted by hierarchy already (to simplify the example).
Employee boss1 = new Employee("Boss1");
Employee sub1 = new Employee("Sub1");
boss1.getListSubordinates().add(sub1);
Employee sub2 = new Employee("Sub2");
boss1.getListSubordinates().add(sub2);
Employee boss2 = new Employee("Boss2");
Employee sub3 = new Employee("Sub3");
boss2.getListSubordinates().add(sub3);
List<Employee> listBosses = Arrays.asList(boss1, boss2);
Again this is a simple example with just one level of hierarchy, if you had a variable level of hierarchy the following code would have to be recursive.
// Build the list of the nodes sorted by hierarchy
List<DefaultTreeNode<Employee>> firstLevelNodes = new ArrayList<DefaultTreeNode<Employee>>();
// For each employee of the highest level
for (Employee boss : listBosses) {
// Build the list of its sub employee
List<DefaultTreeNode<Employee>> listSubordinates = new ArrayList<DefaultTreeNode<Employee>>();
for (Employee subordinate : boss.getListSubordinates()) {
listSubordinates.add(new DefaultTreeNode<Employee>(subordinate));
}
// Then build the boss node with its data and its children nodes
DefaultTreeNode<Employee> bossNode = new DefaultTreeNode<Employee>(boss, listSubordinates);
// And add it to the list of first level nodes
firstLevelNodes.add(bossNode);
}
// Build the ROOT, a 'technical' node containing the nodes of the tree.
DefaultTreeNode<Employee> root = new DefaultTreeNode<Employee>(null, firstLevelNodes);
// Create the TreeModel
TreeModel treeModel = new DefaultTreeModel<Employee>(root);
And now you just have to set the TreeModel to your Tree component.
Hope this helps.

Binary Search Tree Instantiaition

I have Created Binary Search Tree by Using a Tree Interface and Recursion (I am aware that using a Node Class I can Implement the same ) providing methods for Adding and Checking if an element is in the Binary Search Tree or not.
The Problem I am facing is in instantiating & displaying the elements of the BST.
Here is my code
Tree Interface:
package bst;
public interface Tree<D extends Comparable>{
public boolean isempty();
public int cardinality();
public boolean member(D elt);
public NonEmptyBst<D> add(D elt);
}
EmptyBst Class:
package bst;
public class EmptyBst<D extends Comparable> implements Tree<D>{
public EmptyBst(){
D data=null;
}
#Override
public boolean isempty() {
// TODO Auto-generated method stub
return true;
}
#Override
public int cardinality() {
// TODO Auto-generated method stub
return 0;
}
#Override
public boolean member(D elt) {
// TODO Auto-generated method stub
return false;
}
#Override
public NonEmptyBst<D>add(D elt) {
// TODO Auto-generated method stub
return new NonEmptyBst<D>(elt);
}
}
NonEmptyBst Class
package bst;
public class NonEmptyBst<D extends Comparable> implements Tree<D> {
D data;
D root;
Tree<D> left;
Tree <D>right;
public NonEmptyBst(D elt){
data=elt;
root=elt;
left=new EmptyBst<D>();
right=new EmptyBst<D>();
}
NonEmptyBst(){
D dataThis=this.data;
}
public NonEmptyBst(D elt,Tree<D>leftTree,Tree<D>rightTree){
data=elt;
left=leftTree;
right=rightTree;
}
#Override
public boolean isempty() {
// TODO Auto-generated method stub
return false;
}
#Override
public int cardinality() {
// TODO Auto-generated method stub
return 1+left.cardinality()+right.cardinality();
}
public boolean member(D elt) {
if (data == elt) {
return true;
} else {
if (elt.compareTo(data) < 0) {
return left.member(elt);
} else {
return right.member(elt);
}
}
}
public NonEmptyBst<D> add(D elt) {
if (data == elt) {
return this;
} else {
if (elt.compareTo(data) < 0) {
return new NonEmptyBst(data, left.add(elt), right);
} else {
return new NonEmptyBst(data, left, right.add(elt));
}
}
}
}
BinarySearchTree Class
package bst;
import bst.Tree;
import bst.EmptyBst;
import bst.NonEmptyBst;
public class BinarySearchTree {
public static void main(String[] args) {
// TODO Auto-generated method stub
NonEmptyBst abcd=new NonEmptyBst( "abc");
NonEmptyBst ab=new NonEmptyBst(67);
abcd.add("cry me a river");
abcd.add("geeehfvmfvf");
abcd.add("I'm Sexy and i know it");
abcd.add("zzzzsd");
abcd.add("zzzzsd");
abcd.add("zzzfdsf");
abcd.add("zzfedfrsd");
abcd.add("tgrgdzsd");
abcd.add("gtrgrtgtrgtrzzzzsd");
abcd.add("zzzzsd");
abcd.add("zdddzzzsd");
abcd.add("zzzzsd");
abcd.add("zzzzsd");
}
}
**
How Can I access the data at all nodes and then Print Them out?The Particular Problem I am facing is In Getting an exception namely ClassCastException when I access the "leaf Nodes" and even if I Initalize new NonEmptyBst<D>in My NonEmptyBst<D>(D elt) constructor I end Up having a null pointer Exception
Exception in thread "main" java.lang.NullPointerException
at java.lang.String.compareTo(Unknown Source)
at java.lang.String.compareTo(Unknown Source)
at bst.NonEmptyBst.add(NonEmptyBst.java:51)
at bst.NonEmptyBst.add(NonEmptyBst.java:54)
at bst.BinarySearchTree.main(BinarySearchTree.java:11)
I'm not really sure I see the need for EmptyBst unless you are trying to follow the design-pattern for a Null Object.
Specifically, an "empty" tree can easily be checked if data == null && left == null && right == null. Also, no need for data here, since it is a local variable and never referenced.
public EmptyBst(){
D data=null;
}
And is there a difference between D data and D root?
I think you need to adjust your add method to capture the result of the recursion.
public NonEmptyBst<D> add(D elt) {
if (data == elt) {
return this;
} else {
if (elt.compareTo(data) < 0) {
this.left = this.left.add(elt);
} else {
this.right = this.right.add(elt);
}
}
return this;
}
You need to access it recursively. As I don't have your node implementation I'll write a general example:
// Return a list with all the nodes
public List<Node> preOrder() {
List<Node> l = new ArrayList<Node>();
l.add(this.value); // Add the data of the root
if(this.left != null) // Add elements to the left
l.addAll(this.left.preOrder());
if(this.right != null) // Add elements to the right
l.addAll(this.right.preOrder());
return l;
}
Then you would simply call it:
List<Node> nodes = myTree.preOrder();
And then loop through the list to do whatever you want.

Restoring original state of member variables set by a method when coming out of it

I have a class, of which one of the members is a boolean flag.
class Node
{
String name;
boolean flag;
public Node(String name) {
// TODO Auto-generated constructor stub
this.name = name;
flag = false;
}
}
I have created an array of these Nodes
ArrayList<Node> myArrayList = new ArrayList<>();
I have a method called funhello which sets the flag of the first Node in this ArrayList to true.
public void funhello()
{
myArrayList.get(0).flag = true;
}
I have another method called funworld which sets the flag of the second Node in this ArrayList to true.
public void funworld()
{
myArrayList.get(1).flag = true;
}
However, assume that these are independent functions, and I want funworld() to see the myArrayList in the same state as it was prior to calling funhello(). How can I ensure that the changes made inside a method do not have an effect on the members of the class, after I've left the method (without explicitly running a for loop and setting them all to false, of course). Is there a way in Java to do this making use of the language?
Entire code below
import java.util.ArrayList;
public class postsodontdisturbmembers {
public static void main(String[] args) {
MyDataStructure myDataStructure = new MyDataStructure();
myDataStructure.addMembers("A");
myDataStructure.addMembers("B");
myDataStructure.addMembers("C");
myDataStructure.addMembers("D");
myDataStructure.addMembers("E");
System.out.println("calling funhello...");myDataStructure.funhello();myDataStructure.print();System.out.println("");
System.out.println("calling funworld...");myDataStructure.funworld();myDataStructure.print();System.out.println("");
}
}
class MyDataStructure
{
ArrayList<Node> myArrayList = new ArrayList<>();
public void addMembers(String name)
{
myArrayList.add(new Node(name));
}
public void setflag(String name)
{
for(int i = 0;i<myArrayList.size();i++)
{
if(myArrayList.get(i).name.equals(name))
myArrayList.get(i).flag = true;
}
}
public void funhello()
{
myArrayList.get(0).flag = true;
}
public void funworld()
{
myArrayList.get(1).flag = true;
}
public void print()
{
for(int i = 0;i<myArrayList.size();i++)
System.out.println(myArrayList.get(i).name + " : " + myArrayList.get(i).flag);
}
}
class Node
{
String name;
boolean flag;
public Node(String name) {
// TODO Auto-generated constructor stub
this.name = name;
flag = false;
}
}

Threadsafety in SwingWorker - Updating JTable in a Threadsafe way

I have a list of travel offers that I read and parsed from a XML file and added them to my GUI using JTable. I also have some update functionalities (at interval and instantly on click) that updates the GUI as soon as new offers are added to the XML. My aim is to add the offers in the GUI in thread safe way.
This is the class (UpdateData.java) where i perform doInBackground() using Swingworker and more concern about safety. (Other classes are also shown below if anyone is interested to take a deeper look) Can SwingUtilities.invokeLater() be used to make it thread-safe? Does overriding Swingworkers done(), execute() and process() will help in some way to achieve safety? In that case how? (newbie at thread prog) (Other classes are given below if anyone is interested to get a deeper look). Some Help / Feedback will be highly appreciated.
Class: UpdateData.java
public class UpdateData extends SwingWorker<Integer, Integer> {
private ArrayList<RawTravelData> listOfOffer;
private TravelData offerData;
private XMLReader parseData;
//the controller
private ControlUpdate updtController;
//constructor
public UpdateData(TravelData o, ControlUpdate offerController) {
updtController = offerController;
parseData = new XMLReader();
offerData = o;
}
#Override
protected Integer doInBackground() throws Exception {
listOfOffer = parseData.fetchData();
offerData.setData(listOfOffer);
updtController.setOfferArray(listOfOffer);
return null;
}
}
Class: RawTravelData.java
public class RawTravelData {
private String destination = "";
private String travelDate = "";
private int currPrice;
//empty constructor
public RawTravelData() {
}
//setters ad getters for destination, travel date and currprise
}
Class: TravelData.java
public class TravelData extends AbstractTableModel {
//the table header strings
private String[] colNames = { "Destination", "Date", "Price", "Details" };
private static final long serialVersionUID = 1L;
//arraylist of the offer data
private ArrayList<RawTravelData> offerList;
//constructor
public TravelData(ArrayList<RawTravelData> rtd) {
offerList = rtd;
}
//second constructor to create empty list
public TravelData() {
offerList = new ArrayList<RawTravelData>();
}
//add the list
public void setData(ArrayList<RawTravelData> o) {
offerList = o;
this.fireTableDataChanged();
}
//get the offer list
public ArrayList<RawTravelData> getOfferList() {
return offerList;
}
#Override
public Class<?> getColumnClass(int columnIndex) {
switch (columnIndex) {
case 0:
return String.class;
case 1:
return Integer.class;
case 2:
return String.class;
case 3:
return String.class;
default:
break;
}
return String.class;
}
#Override
public int getColumnCount() {
return colNames.length;
}
#Override
public int getRowCount() {
return offerList.size();
}
#Override
public Object getValueAt(int arg0, int arg1) {
switch (arg1) {
case 0:
return offerList.get(arg0).getDestination();
case 1:
return offerList.get(arg0).getPrice();
case 2:
return offerList.get(arg0).getTravelDate();
case 3:
return "Details";
default:
break;
}
return "null";
}
#Override
public String getColumnName(int col) {
return colNames[col];
}
}
Class: XMLReader.java
public class XMLReader {
//Method to fetch and read all the data from the XML file
public ArrayList<RawTravelData> fetchData() {
//parse data and return as arraylist of offers
return arrayOfOffer;
}
}
Class: ControlUpdate.java
//This class is responsible for controlling the updating of the offer data in the background
public class ControlUpdate {
private TablePanel tablePane;
private ArrayList<RawTravelData> offerArray;
//..
//Constructor
public ControlUpdate(TablePanel tablePane) {
settingsVal = new SaveSettings();
this.tablePane = tablePane;
tablePane.getOfferTable().addMouseListener(
new TableSortListener(tablePane.getOfferTable(), this));
runUpdateTask();
setUpdateInterval(settingsVal.readSettings());
}
//run the updates
private void runUpdateTask() {
//used Timer and ScheduledThreadPool
}
//get the table panel
public TablePanel getTablePanel() {
return tablePane;
}
//setting the list to a new offer list for the updater
public void setOfferArray(ArrayList<RawTravelData> rtd) {
offerArray = rtd;
}
}
All modifications of Components and their models need to be performed in the AWT event dispatch thread, not in a background thread. The second and third lines of your doInBackground method should be moved to the done method, which is guaranteed to be executed in the AWT event thread.
It is also customary to have the SwingWorker's value type be the data you're obtaining in the background.
public class UpdateData
extends SwingWorker<List<RawTravelData>, Integer> {
// ...
#Override
protected List<RawTravelData> doInBackground() throws Exception {
return parseData.fetchData();
}
#Override
protected void done() {
try {
List<RawTravelData> listOfOffer = get();
offerData.setData(listOfOffer);
updtController.setOfferArray(listOfOffer);
} catch (ExecutionException e) {
throw new RuntimeException(e);
} catch (InterruptedException e) {
// Someone wants us to exit cleanly.
e.printStackTrace();
}
}
}

How to implement getParent method of a ContentProvider

I have a ContentProvider for a TreeSelectionDialog. I need to implement the getParent method in order to select the root of a tree if one of its nodes is checked. This is the code:
#SuppressWarnings("unchecked")
protected Node<T> getAdapter(Object element) {
if(element instanceof Tree)
return ((Tree<T>)element).getRootElement();
else
return (Node<T>)element;
}
#Override
public void dispose() {
// TODO Auto-generated method stub
}
#Override
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
// TODO Auto-generated method stub
}
#Override
public Object[] getElements(Object inputElement) {
return getChildren(inputElement);
}
#Override
public Object[] getChildren(Object parentElement) {
if(parentElement instanceof org.db.normalization.Table) {
if(((org.db.normalization.Table)parentElement).getStatus() == Status.DELETED)
return new Object[0];
List<org.db.normalization.Attribute> atts = new ArrayList<org.db.normalization.Attribute>();
for(Attribute a:((org.db.normalization.Table)parentElement).getAttributes().getAttributes())
if(a.getStatus() != Status.UNMODIFIED)
atts.add(a);
for(Attribute a:((org.db.normalization.Table)parentElement).getPrimaryKey().getAttributes())
if(a.getStatus() != Status.UNMODIFIED)
atts.add(a);
return atts.toArray();
} else if (parentElement instanceof org.db.normalization.Attribute) {
return new Object[0];
} else {
#SuppressWarnings("unchecked")
List<org.db.normalization.Table> n = (ArrayList<org.db.normalization.Table>)parentElement;
if (n.size() > 0) {
return n.toArray() ;
}
}
return new Object[0];
}
#Override
public Object getParent(Object element) {
// TODO Auto-generated method stub
return null;
}
#Override
public boolean hasChildren(Object element) {
// TODO Auto-generated method stub
return getChildren(element).length > 0;
}
I really have no idea of what to write in the getParent method, since I have no other information than the element received as a parameter, and this element alone, doesn't know its parent.
Thanks!
Most instances of a tree implementation, you do know your parent, so parents are either set by a setter method or on the constructor. You have no idea who the parent is, so you are presenting the worse case, where you basically have to get all node, and check rather the children of each node contain you.

Categories