Write common code for both SWT tree and table - java

The SWT control classes Tree and Table have several methods with the same signature and that work in the same way.
For example:
getItems
getSelection
But these methods are defined directly on Tree and Table, there is no common super class or interface where the methods are declared. Because of this it is hard to write code that works for both Tree and Table.
Is there a solution to this that makes it possible to write common code for both of the classes?

One possible solution is to create a class with the common methods, with subclasses that wraps a Tree or a Table and that delegate these methods to their wrapped control.
Using such classes generic code can look like this:
CollectionControl c = CollectionControl.create(treeOrTable);
int nrItems = c.getSelectionCount();
The following is an example of such classes:
/**
* Wrapps a {#link Tree} or {#link Table} to make it possible to work with them
* in a generic way.
*
* This class could be an interface in Java 8, which allows static methods on interfaces.
*/
public abstract class CollectionControl {
public abstract CollectionItem[] getItems();
public abstract CollectionItem[] getSelection();
public abstract int getSelectionCount();
public abstract Control getControl();
public abstract int getColumnCount();
interface CollectionItem {
String getText(int columnIx);
}
/**
* #param control Either a {#link Tree} or {#link Table}..
* #return A collection which wraps the argument an delegate method calls to it.
* #throws IllegalArgumentException if the argument is not a Tree or a Table.
*/
public static CollectionControl create(Control control) {
if (control instanceof Tree) {
return new TreeControl((Tree) control);
} else if (control instanceof Table) {
return new TableControl((Table) control);
}
throw new IllegalArgumentException();
}
private static class TreeControl extends CollectionControl {
private Tree tree;
public TreeControl(Tree tree) {
this.tree = tree;
}
#Override
public CollectionItem[] getSelection() {
CollectionItem[] items = new CollectionItem[tree.getSelectionCount()];
int ix = 0;
for (TreeItem item : tree.getSelection()) {
items[ix++] = new TreeCollectionItem(item);
}
return items;
}
#Override
public int getSelectionCount() {
return tree.getSelectionCount();
}
#Override
public Tree getControl() {
return tree;
}
#Override
public CollectionItem[] getItems() {
CollectionItem[] items = new CollectionItem[tree.getItemCount()];
int ix = 0;
for (TreeItem item : tree.getItems()) {
items[ix++] = new TreeCollectionItem(item);
}
return items;
}
#Override
public int getColumnCount() {
return tree.getColumnCount();
}
private static class TreeCollectionItem implements CollectionItem {
private TreeItem item;
public TreeCollectionItem(TreeItem item) {
this.item = item;
}
#Override
public String getText(int columnIx) {
return item.getText(columnIx);
}
}
}
private static class TableControl extends CollectionControl {
private Table table;
public TableControl(Table table) {
this.table = table;
}
#Override
public CollectionItem[] getSelection() {
CollectionItem[] items = new CollectionItem[table.getSelectionCount()];
int ix = 0;
for (TableItem item : table.getSelection()) {
items[ix++] = new TableCollectionItem(item);
}
return items;
}
#Override
public int getSelectionCount() {
return table.getSelectionCount();
}
#Override
public Table getControl() {
return table;
}
#Override
public CollectionItem[] getItems() {
CollectionItem[] items = new CollectionItem[table.getItemCount()];
int ix = 0;
for (TableItem item : table.getItems()) {
items[ix++] = new TableCollectionItem(item);
}
return items;
}
#Override
public int getColumnCount() {
return table.getColumnCount();
}
private static class TableCollectionItem implements CollectionItem {
private TableItem item;
public TableCollectionItem(TableItem item) {
this.item = item;
}
#Override
public String getText(int columnIx) {
return item.getText(columnIx);
}
}
}
}

Related

Visitor returns first Item of an List as null

I want to implement a Visitor for My class MyList. The List itself holds Elements of the type MyEntry. Those Entrys hold a generic Value and a reference to the next Entry in the List.
public class MyEntry<E> implements Visitable {
MyEntry<E> next;
E o;
MyEntry() {
this(null, null);
}
MyEntry(E o) {
this(o, null);
}
MyEntry(E o, MyEntry<E> e) {
this.o = o;
this.next = e;
}
public void accept(Visitor visitor) {
}
}
The List class
public class MyList<E> implements Visitable {
private MyEntry<E> begin;
private MyEntry<E> pos;
public MyList() {
pos = begin = new MyEntry<E>();
}
public void add(E x) {
MyEntry<E> newone = new MyEntry<E>(x, pos.next);
pos.next = newone;
}
public void advance() {
if (endpos()) {
throw new NoSuchElementException("Already at the end of this List");
}
pos = pos.next;
}
public void delete() {
if (endpos()) {
throw new NoSuchElementException("Already at the end of this List");
}
pos.next = pos.next.next;
}
public E elem() {
if (endpos()) {
throw new NoSuchElementException("Already at the end of this List");
}
return pos.next.o;
}
public boolean empty() {
return begin.next == null;
}
public boolean endpos() {
return pos.next == null;
}
public void reset() {
pos = begin;
}
#Override
public void accept(Visitor visitor) {
begin = pos;
while(pos.next != null && visitor.visit(pos.o)) {
//Move one Item forward
pos = pos.next;
}
}
I have implemented the Visitor interface to my ListVisitor class
public class ListVisitor implements Visitor {
public ListVisitor() {
}
#Override
public boolean visit(Object o) {
return false;
}
}
The Interface Visitor that will be implemented in every new Visitor that i want to create, for now i only have the ListVisitor
public interface Visitor<E> {
boolean visit(Object o);
}
And the Interface Visitable, that is implemented in every class i want to visit, in this case the MyList class and the MyEntry class.
public interface Visitable {
public void accept(Visitor visitor);
}
To test the implementation of the Visitor pattern I made a Testclass that creates a new Mylist and puts some Strings in it. Next it creates a new Visitor that visits the List.
import org.junit.Test;
public class MyListTest {
#Test
public void MyListTest() {
MyList s = new MyList();
s.add("Hello");
s.add("World");
s.add("!");
Visitor v = new Visitor() {
#Override
public boolean visit(Object o) {
System.out.println(o);
return true;
}
};
s.accept(v);
}
}
Now when I run MyListTest the output is:
null
!
World
My Question now is why the first Element that the Visitor visits has a null reference in it. When i add more items to my List before creating a Visitor the output always extends, except for the first item that has been inserted into the List, it will always be null.
Visitor pattern will not change the current code structure. It is used to add the new functionality in existing code. Classes which holds the new behaviors are commonly known as Visitors.
The classes and objects participating in this pattern are:
Visitor: It declares a Visit operation for each class of ConcreteElement in the object structure. The operation's name and
signature identify the class.
ConcreteVisitor: It implements each operation declared by the Visitor.
Element: It defines an Accept operation that takes a visitor as an argument.
ConcreteElement: It implements an Accept operation that takes a visitor as an argument.
ObjectStructure: It holds all the elements of the data structure as a collection, list of something which can be enumerated and used by
the visitors.
public abstract class Food {
public final string Name {
get {}
set {}
}
public final Decimal Price {
get {}
set {}
}
public final int Count {
get {}
set {}
}
public Food(string name, Decimal price, int count) {
this.Name = name;
this.Price = price;
this.Count = count;
}
public abstract void Accept(Visitor visitor);
}
public class Pizza extends Food {
public Pizza(string name, Decimal price, int count) {
super(name, price, count);
}
public override void Accept(Visitor visitor) {
visitor.Visit(this);
}
}
public class Pasta extends Food {
public Pasta(string name, Decimal price, int count) {
super(name, price, count);
}
public override void Accept(Visitor visitor) {
visitor.Visit(this);
}
}
public abstract class Visitor {
public abstract void Visit(Pasta pasta);
public abstract void Visit(Pizza pizza);
}
public class DiscountVisitor extends Visitor {
public override void Visit(Pasta pasta) {
var totalPrice = (pasta.Price * pasta.Count);
byte discount = 10;
pasta.Price = (totalPrice - (totalPrice * (discount / 100)));
}
public override void Visit(Pizza pizza) {
byte discount = 0;
if ((pizza.Count < 5)) {
discount = 10;
}
else if (((pizza.Count >= 5) && (pizza.Count < 20))) {
discount = 20;
}
else {
discount = 30;
}
var totalPrice = (pizza.Price * pizza.Count);
pizza.Price = (totalPrice - (totalPrice * (discount / 100)));
}
}
public class OrderList extends List<Food> {
public final void Attach(Food element) {
Add(element);
}
public final void Dettach(Food element) {
Remove(element);
}
public final void Accept(Visitor visitor) {
this.ForEach(() => { }, x.Accept(visitor));
}
public final void PrintBill() {
this.ForEach(() => { }, this.Print(x));
}
private final void Print(Food food) {
Console.WriteLine(string.Format("FoodName: {0}, Price:{1}, Count:{2}", food.Name, food.Price, food.Count));
}
}
}
OrderList orders = new OrderList();
orders.Add(new Pizza("pizza", 45000, 2));
orders.Add(new Pasta("pasta", 30000, 1));
DiscountVisitor visitor = new DiscountVisitor();
orders.Accept(visitor);
orders.PrintBill();

How to use an interface with methods that has in input or return type the reference of the interface?

I have an interface like that:
public interface IntTree {
public int getValue();
public int childrenNumber();
public int nodes ();
public int height ();
public boolean equals (IntTree t);
public void addChild (IntTree child);
public IntTree followPath(int[] path);
public void visit ();
public void printIntTree ();
}
And I don't know how to implement MyTree because there are a lot of references on the interface: for example:
public void addChild (IntTree child);
public IntTree followPath(int[] path);
public boolean equals (IntTree t);
So I don't understand how to use IntTree reference. I did all my methods with a cast for example:
public class MyTree implements IntTree {
private int data;
private LinkedList<MyTree> children; //I have to declare it IntTree or MyTree?
public MyTree(int data) {
this.data = data;
this.children = new LinkedList<>();
}
public void addChild(IntTree child){
this.children.addFirst((MyTree) child);
}
public LinkedList<MyTree> getChildren() {
return this.children;
}
}
But my teacher said that is wrong to do that, how can I get access for example to my children list etc if I can't cast it to MyTree object? how can I do a method public IntTree followPath(int[] path); if MyTree object = this and it's != from IntTree? Please explain me, I am getting mad:
And for the other methods that have nothing in input and not return a reference of the Interface I can implement it with the constructor of MyTree?
private LinkedList children; //I have to declare it IntTree or MyTree?
You should use IntTree here as then you'll add elements that implements IntTree interface so it could be a different class object then MyTree. What you're doing is not type safe, take this as example:
public class SomeTree implements IntTree {
//some code
}
And then lets use SomeTree with our MyTree.
MyTree myTree = new MyTree();
SomeTree child = new SomeTree();
myTree.addChild(child); //Here we get ClassCastException
If you need to implement IntTree interface without changing it then you should leave it as it is without casting. Your code should always be type safe if it is possible.
If you're allowed to modify the interface declaration then you can change it as following:
public interface IntTree<T extends IntTree<T>> {
public int getValue();
public int childrenNumber();
public int nodes ();
public int height ();
public boolean equals (T t);
public void addChild (T child);
public T followPath(int[] path);
public void visit ();
public void printIntTree ();
}
Then you should declare your class as:
public class MyTree implements IntTree<MyTree>
Now your methods will look like:
public void addChild (MyTree child);
public MyTree followPath(int[] path);
public boolean equals (MyTree t);
So you'll be able to work with them in the way you want.
The equals method is unnecesary, it's already defined in Object. You should override it.
For addChildren, you could store a IntTree list:
public class MyTree implements IntTree {
private int data;
private LinkedList<IntTree> children; //I have to declare it IntTree or MyTree?
public MyTree(int data) {
this.data = data;
this.children = new LinkedList<>();
}
public void addChild(IntTree child) {
children.addFirst(child);
}
public LinkedList<IntTree> getChildren() {
return children;
}
public IntTree followPath(int[] path) throws NoSuchTreeException {
for (int i = 0; i < path.length; i++) {
path[i] = path[i] - 1;
}
IntTree oggetto = this;
for (int i = 0; i < path.length; i++) {
int index = path[i];
if (index >= oggetto.getChildren().size() || oggetto.getChildren().isEmpty()) {
throw new NoSuchTreeException();
}
oggetto = oggetto.getChildren().get(i);
}
return oggetto;
}
In "followpath" i changed the type of oggeto asswell.
The key is hold the most general reference while avoiding the casts.
When you define an inteface it means that you are defining all methods that you will use in the class implementation.
In your interface you have the following methods:
public interface IntTree {
public int getValue();
public int childrenNumber();
public int nodes ();
public int height ();
public boolean equals (IntTree t);
public void addChild (IntTree child);
public IntTree followPath(int[] path) throws NoSuchTreeException;
public void visit ();
public void printIntTree ();
}
These methods must be overwritten in MyTree class, for example:
public class MyTree implements IntTree {
private int data;
private LinkedList<MyTree> children; //I have to declare it IntTree or MyTree?
public MyTree(int data) {
this.data = data;
this.children = new LinkedList<>();
}
public IntTree followPath(int[] path) throws NoSuchTreeException {
for (int i = 0; i < path.length; i++) {
path[i] = path[i] - 1;
}
MyTree oggetto = this;
for (int i = 0; i < path.length; i++) {
int index = path[i];
if (index >= oggetto.getChildren().size() || oggetto.getChildren().isEmpty()) {
throw new NoSuchTreeException();
}
oggetto = oggetto.getChildren().get(i);
}
return oggetto;
}
#Override
public int getValue() {
return 0; //Implement the logic for this method
}
#Override
public int childrenNumber() {
return 0; //Implement the logic for this method
}
#Override
public int nodes() {
return 0; //Implement the logic for this method
}
#Override
public int height() {
return 0; //Implement the logic for this method
}
#Override
public boolean equals(IntTree t) {
return false; //Implement the logic for this method
}
public void addChild(IntTree child) {
this.children.addFirst((MyTree) child);
}
public LinkedList<MyTree> getChildren() {
return this.children;
}
#Override
public void visit() {
//Implement the logic for this method
}
#Override
public void printIntTree() {
//Implement the logic for this method
}
}

Java type parameter is not within its bound

I have a class Zeitpunkt which implements a date with time and in addition a class Suchbaum which represents a binary search tree.
I want to use a Comparator-Object in Suchbaum to sort a tree by the day of Zeitpunkt, but when I want to create a Suchbaum object, it prints the named error.
Zeipunkt
public class Zeitpunkt<T> implements Comparable<T>
{
private int jahr;
private int monat;
private int tag;
private int stunden;
private int minuten;
private double sekunden;
public int vergleich(Zeitpunkt a) { ... }
#Override
public int compareTo(T o) {
if(o instanceof Zeitpunkt)
return vergleich((Zeitpunkt)o);
return 0;
}
...
}
Suchbaum
public class Suchbaum<T extends Comparable<T>> {
private class Element {
private T daten;
private Element links;
private Element rechts;
public Element(T t) {
daten = t;
links = null;
rechts = null;
}
}
private Element wurzel;
private Comparator<T> comp;
...
}
Testclass
public class BaumTest {
public static void main(String[] args) {
// error in the following line (IntelliJ underlines the first
// "Zeitpunkt"). Suchbaum<Zeitpunkt<?>> = ... doesn't work either..
// *Completely confused*
Suchbaum<Zeitpunkt> sb = new Suchbaum<>((Zeitpunkt z1, Zeitpunkt z2) -> {
if(z1.getTag() > z2.getTag())
return 1;
else if(z1.getTag() == z2.getTag())
return 0;
else
return -1;
});
}
}
Any ideas? (the other threads with this topic didn't help me out)
Seems that you don't want to make your Zeitpunkt class parametrized, you just want it to implement Comparable interface. So change it like this:
public class Zeitpunkt implements Comparable<Zeitpunkt> {
private int jahr;
private int monat;
private int tag;
private int stunden;
private int minuten;
private double sekunden;
public int vergleich(Zeitpunkt a) {
return 0;
}
#Override
public int compareTo(Zeitpunkt o) {
return vergleich(o);
}
}
Also you need to define a constructor in your Suchbaum class:
public Suchbaum(Comparator<T> comp) {
this.comp = comp;
}

Initialising a Subclass that extends an Abstract class

I have a TableModel class that extends the AbstrctTableModel class in java swing but when I try to initialise the subclass which is not abstract, the Netbeans 8.0 IDE complains that I am initialising an abstract class.
the code snippets are provide below.
public class TableModel extends AbstractTableModel {
private List<List<Object>> dataList = new ArrayList<>();
private String[] header = { "ID","SUBJECT","LETTTER FROM","LETTER DATE","DATE RECEIVED",
"REMARKS","DATE DISPATCHED","DESTINATION OFFICE"};
private int minRowCount = 5;
public TableModel()
{ }
public List<List<Object>> getDataList() {
return dataList;
}
public void setDataList(List<List<Object>> dataList) {
this.dataList = dataList;
fireTableDataChanged();
fireTableStructureChanged();
}
public void setHeader(String[] header) {
this.header = header;
}
public String[] getHeader() {
return header;
}
#Override
public int getRowCount() {
return Math.max(minRowCount, dataList.size());
}
#Override
public int getColumnCount() {
return header.length;
}
#Override
public String getColumnName(int col) {
return header[col];
}
#Override
public Object getValueAt(int row, int col) {
Object value = null;
if(row < dataList.size())
{value = dataList.get(row).get(col);}
return value;
}
#Override
public Class<?> getColumnClass(int column)
{
for (int row = 0; row < getRowCount(); row++)
{
Object o = getValueAt(row, column);
if (o != null)
{
return o.getClass();
}
}
return Object.class;
}
}
this is the code that initialises the Table Model class.
private TableColumnAdjuster tca;
/**
* Creates new form MyJFrame
*/
private TableModel tableModel ;
public MyJFrame() throws CorruptIndexException, LockObtainFailedException, IOException,
ParseException, java.text.ParseException, SQLException
{
tableModel = new TableModel(); // the Netbeans IDEcomplains about this code
initComponents();
}
You don't provide any info to specify the exact nature of the complaint, but I'm betting that the AbstractTableModel has an abstract method that your TableModel has failed to override. It would be a compilation error in that case.
If that's true, provide a concrete implementation for that method and you'll be able to take the next step.

Specify data in two columns of a table with TreeViewer/ViewContentProvider

I'm trying to create an eclipse plugin that creates a view with a Tree table that has two columns. I'm currently working off of the sample view template eclipse provides, but I cannot figure out how to specify different data for different columns to be displayed. Here is the code:
public class Variables extends ViewPart {
/**
* The ID of the view as specified by the extension.
*/
public static final String ID = "com.amazon.funce.views.Variables";
private TreeViewer viewer;
private DrillDownAdapter drillDownAdapter;
private Action action1;
private Action action2;
private Action doubleClickAction;
/*
* The content provider class is responsible for
* providing objects to the view. It can wrap
* existing objects in adapters or simply return
* objects as-is. These objects may be sensitive
* to the current input of the view, or ignore
* it and always show the same content
* (like Task List, for example).
*/
class TreeObject implements IAdaptable {
private String name;
private TreeParent parent;
public TreeObject(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setParent(TreeParent parent) {
this.parent = parent;
}
public TreeParent getParent() {
return parent;
}
public String toString() {
return getName();
}
public Object getAdapter(Class key) {
return null;
}
}
class TreeParent extends TreeObject {
private ArrayList children;
public TreeParent(String name) {
super(name);
children = new ArrayList();
}
public void addChild(TreeObject child) {
children.add(child);
child.setParent(this);
}
public void removeChild(TreeObject child) {
children.remove(child);
child.setParent(null);
}
public TreeObject [] getChildren() {
return (TreeObject [])children.toArray(new TreeObject[children.size()]);
}
public boolean hasChildren() {
return children.size()>0;
}
}
class ViewContentProvider implements IStructuredContentProvider,
ITreeContentProvider {
private TreeParent invisibleRoot;
public void inputChanged(Viewer v, Object oldInput, Object newInput) {
}
public void dispose() {
}
public Object[] getElements(Object parent) {
if (parent.equals(getViewSite())) {
if (invisibleRoot==null) initialize();
return getChildren(invisibleRoot);
}
return getChildren(parent);
}
public Object getParent(Object child) {
if (child instanceof TreeObject) {
return ((TreeObject)child).getParent();
}
return null;
}
public Object [] getChildren(Object parent) {
if (parent instanceof TreeParent) {
return ((TreeParent)parent).getChildren();
}
return new Object[0];
}
public boolean hasChildren(Object parent) {
if (parent instanceof TreeParent)
return ((TreeParent)parent).hasChildren();
return false;
}
/*
* We will set up a dummy model to initialize tree heararchy.
* In a real code, you will connect to a real model and
* expose its hierarchy.
*/
private void initialize() {
TreeObject to1 = new TreeObject("Leaf 1");
TreeObject to2 = new TreeObject("Leaf 2");
TreeObject to3 = new TreeObject("Leaf 3");
TreeParent p1 = new TreeParent("Parent 1");
p1.addChild(to1);
p1.addChild(to2);
p1.addChild(to3);
TreeObject to4 = new TreeObject("Leaf 4");
TreeParent p2 = new TreeParent("Parent 2");
p2.addChild(to4);
TreeParent root = new TreeParent("Root");
root.addChild(p1);
root.addChild(p2);
invisibleRoot = new TreeParent("");
invisibleRoot.addChild(root);
}
}
class ViewLabelProvider extends LabelProvider {
public String getText(Object obj) {
return obj.toString();
}
public Image getImage(Object obj) {
String imageKey = ISharedImages.IMG_OBJ_ELEMENT;
if (obj instanceof TreeParent)
imageKey = ISharedImages.IMG_OBJ_FOLDER;
return PlatformUI.getWorkbench().getSharedImages().getImage(imageKey);
}
}
class NameSorter extends ViewerSorter {
}
/**
* The constructor.
*/
public Variables() {
}
/**
* This is a callback that will allow us
* to create the viewer and initialize it.
*/
public void createPartControl(Composite parent) {
viewer = new TreeViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
//new
Tree tree = viewer.getTree();
tree.setHeaderVisible(true);
tree.setLinesVisible(true);
TreeColumn column1 = new TreeColumn(tree, SWT.LEFT);
column1.setText("Name");
column1.setWidth(400);
TreeColumn column2 = new TreeColumn(tree, SWT.LEFT);
column2.setText("Value");
column2.setWidth(200);
//end new
drillDownAdapter = new DrillDownAdapter(viewer);
viewer.setContentProvider(new ViewContentProvider());
viewer.setLabelProvider(new ViewLabelProvider());
viewer.setSorter(new NameSorter());
viewer.setInput(getViewSite());
// Create the help context id for the viewer's control
PlatformUI.getWorkbench().getHelpSystem().setHelp(viewer.getControl(), "com.Amazon.FuncE.viewer");
}
Right now what I have is two columns, but both show the same thing. How can I specify what kind of data goes into one column or the other?
Thanks
The issue is with your label provider. You are implementing an interface that doesn't give you ability to provide different text for different columns. You should implement ITableLabelProvider instead.

Categories