Skip to main content

JSR295 v.0.5 and JXTreeTable

110 replies [Last post]
mveksler
Offline
Joined: 2007-01-26
Points: 0

Has anyone tried creating binding to JXTreetable?
I am trying both JSR295 and Beans Properties approaches and both unsucceseful so far. The JSR 295 source has various helpter for different swing componenets (i.e. check JCheckBox, JTable, JTree, JText, etc.) However, there is no helper for JXTreeTable :-) I know that JXTreeTable extends JTable however, its data model manages TreeNodes. Do we have to use to different helpres to bind to JXTreeTable? One for JTable that binds to Table model of the JXTreeTable and another for JTree that bindins to TreeTableModel? If so, how can I manage TreeTableNodes insertion, deletion, updates to structure while maintaining objects in the list and inside TreeNodes insync?

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
mveksler
Offline
Joined: 2007-01-26
Points: 0

Thank you, I appreciate your work.
I think it would be better to just give only root and tree table componenet to the binder. This way, the Adapter will step though and create a tree for me.

mveksler
Offline
Joined: 2007-01-26
Points: 0

It is working now, however, I get extra child Person node which is empry and when I clikc on it I get index out of bouds,
Could you please let me know where you in the node you fixed this bug. I am trying to follow the TreeTableAdapterModel.

Shai Almog

I think that node is the dummy address book you added to the root, you
should probably create the address book and just extract its property
context but you shouldn't add it physically to the root.

--
Shai Almog
vPrise
http://www.vprise.com/

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

Shai Almog

This tree is great but your root is "RootBean" if I read your code
correctly and that can't be done with the current code. Your root must
be a Person too.

--
Shai Almog
vPrise
http://www.vprise.com/

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

mveksler
Offline
Joined: 2007-01-26
Points: 0

I have tried with PersonBean as a root node and I get exception;
"C:\Program Files\Java\jdk1.5.0_10\bin\java" -Didea.launcher.port=7533 "-Didea.launcher.bin.path=C:\Program Files\JetBrains\IntelliJ IDEA 6.0\bin" -Dfile.encoding=windows-1252 -classpath "C:\Program Files\Java\jdk1.5.0_10\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.5.0_10\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.5.0_10\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.5.0_10\jre\lib\jce.jar;C:\Program Files\Java\jdk1.5.0_10\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.5.0_10\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.5.0_10\jre\lib\rt.jar;C:\Program Files\Java\jdk1.5.0_10\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.5.0_10\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.5.0_10\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.5.0_10\jre\lib\ext\sunpkcs11.jar;C:\Documents and Settings\MikeV\IdeaProjects\SwingX\classes\test\SwingX;C:\Documents and Settings\MikeV\IdeaProjects\SwingX\classes\production\SwingX;C:\Documents and Settings\MikeV\Desktop\SwingLabs\swingx-2007_05_13-bin\swingx-2007_05_13-bin\swingx-2007_05_13.jar;C:\Documents and Settings\MikeV\Desktop\SwingLabs\beansbinding-0.5.jar;C:\Documents and Settings\MikeV\Desktop\SwingLabs\bean-properties\new-drop5-13\new-drop\full.jar;C:\Documents and Settings\MikeV\Desktop\SwingLabs\bean-properties\new-drop5-13\new-drop\SwingXBinding.jar;C:\Documents and Settings\MikeV\Desktop\SwingLabs\bean-properties\new-drop5-13\new-drop\props.jar;C:\Documents and Settings\MikeV\Desktop\SwingLabs\bean-properties\new-drop5-13\new-drop\SwingXBinding-src\src;C:\Program Files\JetBrains\IntelliJ IDEA 6.0\lib\idea_rt.jar" com.intellij.rt.execution.application.AppMain TrretableUI
Exception in thread "AWT-EventQueue-0" java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at java.util.ArrayList.RangeCheck(ArrayList.java:546)
at java.util.ArrayList.get(ArrayList.java:321)
at net.java.dev.properties.IndexedPropertyImpl.get(IndexedPropertyImpl.java:40)
at TrretableUI.bindTree(TrretableUI.java:85)
at TrretableUI.createUI(TrretableUI.java:73)
at TrretableUI$1.run(TrretableUI.java:29)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:461)
at java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:242)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:163)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:157)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:149)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:110)

Process finished with exit code 0

Here is the new code:

public class State {
private String name;
public State() {
}

public State(String name)
{
this.name = name;
}

public String toString() {
return name;
}
}

import net.java.dev.properties.Property;
import net.java.dev.properties.IndexedProperty;
import net.java.dev.properties.container.ObservableProperty;
import net.java.dev.properties.container.BeanContainer;
import net.java.dev.properties.container.ObservableIndexed;

import java.util.Date;

public class PersonBean {
public final Property name = new ObservableProperty("");
public final Property lastName = new ObservableProperty("");
public final Property firstName = new ObservableProperty("");
public final Property dob = new ObservableProperty(new Date());
public final IndexedProperty addressNodes = new ObservableIndexed();
public final IndexedProperty personNodes = new ObservableIndexed();

public PersonBean() {
BeanContainer.bind(this);
}

public PersonBean(String abbrev) {
this();
name.set(abbrev);
}

public String toString() {
return name.get();
}

public static PersonBean createTree()
{
PersonBean root = new PersonBean("root");
PersonBean person = new PersonBean("PERSON1");
person.lastName.set("LAST1");
person.firstName.set("FIRST1");
person.dob.set(new Date(System.currentTimeMillis()));
AddressBean address = new AddressBean("HOME");
address.address1.set("1234 Test Drv");
address.address2.set("PO BOX 123");
address.city.set("San Diego");
address.sate.set(new State("CA"));
person.addressNodes.add(address);
address = new AddressBean("WORK");
address.address1.set("4321 Test Drv");
address.address2.set("PO BOX 321");
address.city.set("New Yourk");
address.sate.set(new State("NY"));
person.addressNodes.add(address);
root.personNodes.add(person);
person = new PersonBean("PERSON2");
person.lastName.set("LAST2");
person.firstName.set("FIRST2");
person.dob.set(new Date(System.currentTimeMillis()));
address = new AddressBean("HOME");
address.address1.set("1234 Test Drv");
address.address2.set("PO BOX 123");
address.city.set("San Diego");
address.sate.set(new State("CA"));
person.addressNodes.add(address);
address = new AddressBean("WORK");
address.address1.set("4321 Test Drv");
address.address2.set("PO BOX 321");
address.city.set("New Yourk");
address.sate.set(new State("NY"));
person.addressNodes.add(address);
root.personNodes.add(person);
return root;
}
}

import net.java.dev.properties.Property;
import net.java.dev.properties.container.ObservableProperty;
import net.java.dev.properties.container.BeanContainer;

public class AddressBean {
public final Property name = new ObservableProperty("");
public final Property address1 = new ObservableProperty("");
public final Property address2 = new ObservableProperty("");
public final Property city = new ObservableProperty("");
public final Property sate = new ObservableProperty(new State(""));
public final Property zip = new ObservableProperty("");

public AddressBean()
{
BeanContainer.bind(this);
}

public AddressBean(String str)
{
this();
name.set(str);
}

public String toString()
{
return name.get();
}
}

import org.jdesktop.swingx.JXTreeTable;
import org.jdesktop.swingx.JXDatePicker;
import org.jdesktop.swingx.autocomplete.ComboBoxCellEditor;
import org.jdesktop.swingx.renderer.*;

import javax.swing.*;
import javax.swing.table.TableCellEditor;

import net.java.dev.properties.binding.swingx.adapters.SwingXBind;
import net.java.dev.properties.container.PropertyContext;

import java.awt.*;
import java.awt.event.KeyListener;
import java.awt.event.KeyEvent;
import java.util.Date;
import java.util.Vector;
import java.text.DateFormat;

public class TrretableUI {

public PersonBean t;
public static JComboBox combo;
public static Vector pos = new Vector();
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
TrretableUI bean = new TrretableUI();
public void run() {
bean.createUI();
}
});
}

public void createUI()
{
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
System.out.println(e);
}

pos.add(new State(""));
pos.add(new State("FAC1"));
pos.add(new State("FAC2"));
pos.add(new State("FAC3"));

combo = new JComboBox(new DefaultComboBoxModel(pos));

JFrame frm = new JFrame("Tree Test");
frm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JXTreeTable tree = new JXTreeTable();
tree.setRootVisible(true);
//tree.setShowGrid(true, true);
tree.setDefaultRenderer(Date.class, new DefaultTableRenderer(new DatePickerProvider()));
//tree.setDefaultRenderer(State.class, new DefaultTableRenderer(new ComboBoxProvider()));
tree.setDefaultEditor(Date.class, new DateCellEditor());
tree.setDefaultEditor(State.class, new ComboBoxCellEditor(combo));

tree.addKeyListener(new KeyListener() {
public void keyTyped(KeyEvent e) {
//To change body of implemented methods use File | Settings | File Templates.
}

public void keyPressed(KeyEvent e) {
//To change body of implemented methods use File | Settings | File Templates.
}

public void keyReleased(KeyEvent e) {
// System.out.println(t.addressNodes.get(0).dob.get());
// System.out.println(t.addressNodes.get(0).state.get());
}
});
bindTree(tree);
tree.packAll();
frm.add(new JScrollPane(tree), BorderLayout.CENTER);
frm.pack();
frm.setLocationByPlatform(true);
frm.setVisible(true);

}

private void bindTree(JXTreeTable tree) {
t = PersonBean.createTree();
SwingXBind.get().bindContent(t,
new PropertyContext[] {t.personNodes.getContext()},
new PropertyContext[]{t.personNodes.get(0).lastName.getContext(), t.personNodes.get(0).firstName.getContext(),
t.personNodes.get(0).dob.getContext(),t.addressNodes.get(0).address1.getContext(),
t.addressNodes.get(0).address2.getContext(), t.addressNodes.get(0).city.getContext(),
t.addressNodes.get(0).sate.getContext()},
tree);
}

public static class DatePickerProvider extends ComponentProvider
{

protected void format(CellContext cellContext) {
//To change body of implemented methods use File | Settings | File Templates.
}

protected void configureState(CellContext cellContext) {

}

protected JXDatePicker createRendererComponent() {
return new JXDatePicker(); //To change body of implemented methods use File | Settings | File Templates.
}
}

public static class ComboBoxProvider extends ComponentProvider
{
protected void format(CellContext cellContext) {
rendererComponent.setSelectedItem(cellContext.getValue());
rendererComponent.revalidate();
}

protected void configureState(CellContext cellContext) {

}

protected JComboBox createRendererComponent() {
return new JComboBox(new DefaultComboBoxModel(pos)); //To change body of implemented methods use File | Settings | File Templates.
}
}

public class DateCellEditor extends AbstractCellEditor implements TableCellEditor {
public DateCellEditor() {
datePicker = new JXDatePicker();
datePicker.setFormats(DateFormat.getDateInstance(DateFormat.SHORT));
}

public Object getCellEditorValue() {
return datePicker.getDate();
}

public Component getTableCellEditorComponent(
JTable table, Object value, boolean isSelected, int row, int column) {
if (value != null && value instanceof Date) {
datePicker.setDate((Date) value);
}
return datePicker;
}

private JXDatePicker datePicker;
}
}

mveksler
Offline
Joined: 2007-01-26
Points: 0

OK,
I got it to work with initializing the Addressbean indexed property in PatientBean.
This is because I dont have any address in root and it was blowing up with an exception.

However, I only get Person Nodes in the tree and dont see Address Nodes as children of person.

Shai Almog

I was just about to write about that ;-)
Do you see addresses in the columns?
Do you expect them to appear as nodes in the tree too?

How does this line look in your current code:

SwingXBind.get().bindContent(t,
new PropertyContext[] {t.personNodes.getContext()},
new PropertyContext[]{t.personNodes.get(0).lastName.getContext(),
t.personNodes.get(0).firstName.getContext(),
t.personNodes.get(0).dob.getContext(),t.addressNodes.get(0).address1.getContext(),
t.addressNodes.get(0).address2.getContext(),
t.addressNodes.get(0).city.getContext(),
t.addressNodes.get(0).sate.getContext()},
tree);

--
Shai Almog
vPrise
http://www.vprise.com/

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

mveksler
Offline
Joined: 2007-01-26
Points: 0

I see the problem with this line:

SwingXBind.get().bindContent(t,
new PropertyContext[] {t.personNodes.getContext()},
new PropertyContext[]{t.personNodes.get(0).lastName.getContext(), t.personNodes.get(0).firstName.getContext(),
t.personNodes.get(0).dob.getContext(),t.addressNodes.get(0).address1.getContext(),
t.addressNodes.get(0).address2.getContext(), t.addressNodes.get(0).city.getContext(),
t.addressNodes.get(0).sate.getContext()},
tree);

Here I have listed personNodes as children for this TreetableAdapterModel.
I guess it is TreeTableAdapterModel limitation at the moment?

I guess we could write different TreeTableAdapter which woould only take ROOT bean and then step through entire tree to create tree table and columns. I think it should not be hard to do as each bean exposes properties and indexed properties. The only thing I can see as trubling is when you have multiple indexed properties in the bean. However, it is easy to determin if the indexed property is the same type as perent and add elements of that type to the tree in the same level as parent node.?

Shai Almog

OK I saw the problem, there is a bug in my code (I'll try to release a
drop soon) but you also didn't "map" the addressNodes to anything so
even after the fix it won't work:
SwingXBind.get().bindContent(t,
new PropertyContext[] {t.personNodes.getContext(),
t.addressNodes.getContext()},

Notice that I mapped address node as a root element too. This will
throw an exception in the current code I will let you know when there
will be a code drop.

I don't think you will need a new tree table model so let me know
after you see the code drop.

--
Shai Almog
vPrise
http://www.vprise.com/

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

Shai Almog

Uploading a drop now, I need to go out for a couple of hours so unless
the process fails it should be there soon ;-)

--
Shai Almog
vPrise
http://www.vprise.com/

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

mveksler
Offline
Joined: 2007-01-26
Points: 0

I have another question.

Can I mix different beans when building the tree nodes?

Say I have parent or root node Patient which contaones properties like First name, Last Name, etc. Now, I want child nodes to be Address bean with address propertties.

Is this posible?

I am getting Exception in thread "AWT-EventQueue-0" net.java.dev.properties.container.BeanBindException: Trying to access a property of a bean on an instance of a bean of a different type field: childrenNodes on bean of: AddressBean

Shai Almog

All beans need to be of the same type with the current implementation. I
thought about mapping to different types but it would make the mapping
remarkably complicated both in implementation and usage.
However, its possible that you could do something like this using
inheritance. E.g. have something like HierarchyBean as the base class and
have AddressBean derive from it.
I haven't checked it but if you can't get it to work let me know keep in
mind a couple of things though:
1. HierarchyBean must be public non-abstract and have a default constructor
that invokes BeanContainer.bind(this). You must create an instance of it and
use it to map the tree.

2. Subclasses must still invoke BeanContainer.bind(this) despite deriving
from HierarchyBean.

--
Shai Almog
vPrise
http://www.vprise.com/
[att1.html]

kschaefe
Offline
Joined: 2006-06-08
Points: 0

I just thought that I'd comment with:

A lot of my use cases for the JXTreeTable utilize different node types at different depths, whose only common ancestor is Object. :)

I think that in the long run you will need to support variant types to truly support (what I see as) the most common cases.

Karl

Shai Almog

Karl,
I think you are discussing direct mapping to the model wherein this is about
binding.
You are using a common interface which is essentially the model, in binding
the model is transparent to you. However the binding implementation would
need some information in order to infer the hierarchy, for the underlying
model which is why a common base class is essentially the simplest route.
If you can come up with an API/datastructure that would still indicate the
hierarchy (which can be many levels deep/change in runtime) and be usable by
mere mortals without inheritance I would see what I can do.

--
Shai Almog
vPrise
http://www.vprise.com/
[att1.html]

kschaefe
Offline
Joined: 2006-06-08
Points: 0

I see what you're getting at.

Walking the entire tree to "map" it, is going to b*d complex, so far a large tree the time to map the tree is not worth the effort.

Can the binding structure peek at the model? Or are you completely sans model at that level? I don't think I understand bean-properties enough to answer your questions.

How do you bind a normal tree that contains variant nodes types?

Karl

Shai Almog

> Can the binding structure peek at the model? Or are you completely sans
> model at that level? I don't think I understand bean-properties enough to
> answer your questions.

This is really unrelated to bean properties but rather to a binding
framework in general, when I use the word property you can imagine it as a
get/set that might even return a collection.
Essentially the binding layer builds a TreeTableModel and installs it on the
JXTreeTable, this model implements calls to the appropriate properties to
return a value.
With a table model there is a requirement of mapping a particular column to
a property (e.g. a get/set method), with a tree model you get another
requirement of mapping to a hierarchy e.g.:
The model gets BeanX as root and needs some way to discover its children
(and some way to discover its column values).
Discovering column values is trivial, I just pass a reference to the
properties that represent each column e.g. (simplified code):
bind(table, new PropertyContext[] { column1Property, column2Property.... });

With a tree table I need to somehow add information about hierarchy, so I
need to have something like:
bind(treeTable, new PropertyContext[] { column1Property, column2Property....
}, new PropertyContext[]{ indexedProperty }, root);

indexedProperty is essentially a collection that would contain the children
for the bean, so when I go to root and want to extract its children I can do
this using indexed property.
To put it in terms that would be clear a node in the tree maps to the same
bean type as root, otherwise it can't be a part of the hierarchy.

However, at least the original version of the tree table allowed leaf nodes
to be of different types. If this doesn't work then I should take a look at
it but I'm a bit busy this weekend so I'm not sure if I will get it done
soon.

How do you bind a normal tree that contains variant nodes types?
>

Normal tree has the exact same issue, trees are notoriously hard to bind to
and that is why most binding frameworks avoid them altogether. AFAIK
JGoodies didn't support it, although I think this was added in a recent
version.

--
Shai Almog
vPrise
http://www.vprise.com/
[att1.html]

mveksler
Offline
Joined: 2007-01-26
Points: 0

Works greate.
I can add, remove, and insert nodes just fine.
Now I am onto more complicated task.
I want to be able to sort the tree and be able to use filters.

mveksler
Offline
Joined: 2007-01-26
Points: 0

Found another problem.
Here is what happaned.
I have added new action which adds new node to the selected node.
The node gets added just fine; however, when I try to delete newly added node then it is not removed from the tree?! When I try to delet it again I get Index Out Of Bound Exception. So looks like newly added node was deleted from ObservableIndexedProperty however the tree table was not updated?!

Here is the code:
import net.java.dev.properties.container.ObservableProperty;
import net.java.dev.properties.container.ObservableIndexed;
import net.java.dev.properties.container.BeanContainer;
import net.java.dev.properties.container.PropertyContext;
import net.java.dev.properties.Property;
import net.java.dev.properties.IndexedProperty;
import net.java.dev.properties.test.swingx.SimpleFileSystemModel;
import net.java.dev.properties.binding.swingx.adapters.SwingXBind;

import javax.swing.*;
import javax.swing.tree.TreePath;
import javax.swing.tree.DefaultMutableTreeNode;
import java.util.Date;
import java.util.Iterator;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;

import org.jdesktop.swingx.JXTreeTable;
import org.jdesktop.swingx.treetable.DefaultTreeTableModel;

public class TreeTableNode {
/**
* This observable property will be used in the toString which will be used by TreeTable Renderer to display in the table.
*/
public final Property data = new ObservableProperty("");

/**
* This indexed propery will track changes to the chield tree nodes
*/
public final IndexedProperty childrenNodes = new ObservableIndexed();

/**
* This property will map to a column
*/
public final Property dateColumn = new ObservableProperty();

/**
* This propery will map to another column
*/
public final Property stringColumn = new ObservableProperty();

public final Property isLeaf = new ObservableProperty();

/** Creates a new instance of TreeBinding */
public TreeTableNode() {
BeanContainer.bind(this);
}

public TreeTableNode(String data) {
this();
this.data.set(data);
}

public String toString() {
return data.get();
}

private static TreeTableNode createTree() {
TreeTableNode t = new TreeTableNode("Data Node");
TreeTableNode leaf = new TreeTableNode("First");
leaf.isLeaf.set(false);
t.childrenNodes.add(leaf);
leaf = new TreeTableNode("Second");
leaf.isLeaf.set(false);
t.childrenNodes.add(leaf);
leaf = new TreeTableNode("Third");
leaf.isLeaf.set(false);
t.childrenNodes.add(leaf);
leaf = new TreeTableNode("Forth");
leaf.isLeaf.set(false);
t.childrenNodes.add(leaf);
TreeTableNode t2 = new TreeTableNode("Has childrenNodes");
t2.stringColumn.set("Simple String");
t2.dateColumn.set(new Date());
t2.isLeaf.set(true);
leaf = new TreeTableNode("Inner Child 1");
leaf.isLeaf.set(false);
t2.childrenNodes.add(leaf);
leaf = new TreeTableNode("Inner Child 2");
leaf.isLeaf.set(false);
t2.childrenNodes.add(leaf);
t.childrenNodes.add(t2);
return t;
}

public static void main(String[] argv) throws Exception {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
JFrame frm = new JFrame("Tree Test");
frm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JXTreeTable tree = new JXTreeTable();
tree.setRootVisible(true);
tree.setShowGrid(true, true);
TreeTableNode t = createTree();
SwingXBind.get().bindContent(t,
new PropertyContext[] {t.childrenNodes.getContext()},
new PropertyContext[]{t.dateColumn.getContext(), t.stringColumn.getContext()},
tree);
tree.packAll();

AbstractAction actionDelete = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
System.out.println(e);
System.out.println("Selected Row: " + tree.getSelectedRow() + " Path: " + tree.getPathForRow(tree.getSelectedRow()));
TreePath selectedPath = tree.getTreeSelectionModel().getSelectionPath();
if (selectedPath == null) {
JOptionPane.showMessageDialog(tree,
"Must select a node in the tree before you can delete", "Error",
JOptionPane.ERROR_MESSAGE);
} else if (tree.getSelectedRow() >= 0 /*&& !((TreeTableNode) selectedPath.getLastPathComponent()).isLeaf.get()*/) {
TreeTableNode toBeDeletedNode = (TreeTableNode) selectedPath.getLastPathComponent();

TreePath parentNodePath = selectedPath.getParentPath();
TreeTableNode parentNode;
if(parentNodePath!=null)
{
parentNode = (TreeTableNode) selectedPath.getParentPath().getLastPathComponent();
parentNode.childrenNodes.remove(toBeDeletedNode);
}
else
{
parentNode = toBeDeletedNode;
System.out.println("I dont know what should I do with root node?");
}

System.out.println(parentNode.childrenNodes);

}
}
};

AbstractAction actionAdd = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
System.out.println(e);
System.out.println("Selected Row: " + tree.getSelectedRow() + " Path: " + tree.getPathForRow(tree.getSelectedRow()));
TreePath selectedPath = tree.getTreeSelectionModel().getSelectionPath();
if (selectedPath == null) {
JOptionPane.showMessageDialog(tree,
"Must select a node in the tree before you can add new node", "Error",
JOptionPane.ERROR_MESSAGE);
} else if (tree.getSelectedRow() >= 0) {
TreeTableNode newNode = new TreeTableNode("New Node");
TreeTableNode parentNode = (TreeTableNode) selectedPath.getLastPathComponent();
parentNode.childrenNodes.add(newNode);
System.out.println(parentNode.childrenNodes);
}
}
};

tree.registerKeyboardAction(actionDelete, "delete", KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), 0);

tree.registerKeyboardAction(actionAdd, "insert", KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, 0), 0);

frm.add(new JScrollPane(tree), BorderLayout.CENTER);
frm.pack();
frm.setLocationByPlatform(true);
frm.setVisible(true);

// Thread.sleep(10000);
// int index=0;
// for(Iterator treeNodeIter = t.childrenNodes.iterator();treeNodeIter.hasNext();)
// {
// TreeTableNode node = (TreeTableNode) treeNodeIter.next();
// node.data.set(String.valueOf(index++));
// System.out.println(node);
// }
}
}

vprise
Offline
Joined: 2003-11-07
Points: 0

> Found another problem.

Yes, fixed it already its a stupid bug of mine in the code that prevents duplicate events from being sent. It accidentally assumes that the remove/insert events are one and the same. Problem is that tree/treetable are remarkably sensitive in terms of their events. I'll try to package a drop a bit later the is already in the SwingXBinding CVS.

Thanks.

mveksler
Offline
Joined: 2007-01-26
Points: 0

Thanks you.
I will wait for the drop.

vprise
Offline
Joined: 2003-11-07
Points: 0

Its uploaded.

mveksler
Offline
Joined: 2007-01-26
Points: 0

Thank you.
Will give it a try.

vprise
Offline
Joined: 2003-11-07
Points: 0

> Ok, thanks a lot.
> I tried it, and it is now working.
> However, what should I do when I get to the root?
> Can I somehow delet root? Or it is imposible to
> delete root?
> I can only hide the root.

Great, as you both have said root in your case should probably be hidden (JXTable.setRootVisible(false) for those googling this discussion). You can also toggle this on the fly.
This is a requirement derived from JTree so it can't be fixed in the bindings.

mveksler
Offline
Joined: 2007-01-26
Points: 0

Not a problem. I should have looked through the Tree requirements first ;-)
I am still playing around. will post anything I find.
Thank you.

mveksler
Offline
Joined: 2007-01-26
Points: 0

Found another problem I think ;-)
I have added keyboard action to delete nodes.
I got parent node and removed selected child node however the table was not updated?
Does this binding implements nodeRemoved, nodeInserted, etc events?
This events are responsible to update tree table hierarchy.

Here is the example;
import net.java.dev.properties.container.ObservableProperty;
import net.java.dev.properties.container.ObservableIndexed;
import net.java.dev.properties.container.BeanContainer;
import net.java.dev.properties.container.PropertyContext;
import net.java.dev.properties.Property;
import net.java.dev.properties.IndexedProperty;
import net.java.dev.properties.test.swingx.SimpleFileSystemModel;
import net.java.dev.properties.binding.swingx.adapters.SwingXBind;

import javax.swing.*;
import javax.swing.tree.TreePath;
import javax.swing.tree.DefaultMutableTreeNode;
import java.util.Date;
import java.util.Iterator;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;

import org.jdesktop.swingx.JXTreeTable;
import org.jdesktop.swingx.treetable.DefaultTreeTableModel;

public class TreeTableNode {
/**
* This observable property will be used in the toString which will be used by TreeTable Renderer to display in the table.
*/
public final Property data = new ObservableProperty("");

/**
* This indexed propery will track changes to the chield tree nodes
*/
public final IndexedProperty childrenNodes = new ObservableIndexed();

/**
* This property will map to a column
*/
public final Property dateColumn = new ObservableProperty();

/**
* This propery will map to another column
*/
public final Property stringColumn = new ObservableProperty();

public final Property isLeaf = new ObservableProperty();

/** Creates a new instance of TreeBinding */
public TreeTableNode() {
BeanContainer.bind(this);
}

public TreeTableNode(String data) {
this();
this.data.set(data);
}

public String toString() {
return data.get();
}

private static TreeTableNode createTree() {
TreeTableNode t = new TreeTableNode("Data Node");
TreeTableNode leaf = new TreeTableNode("First");
leaf.isLeaf.set(false);
t.childrenNodes.add(leaf);
leaf = new TreeTableNode("Second");
leaf.isLeaf.set(false);
t.childrenNodes.add(leaf);
leaf = new TreeTableNode("Third");
leaf.isLeaf.set(false);
t.childrenNodes.add(leaf);
leaf = new TreeTableNode("Forth");
leaf.isLeaf.set(false);
t.childrenNodes.add(leaf);
TreeTableNode t2 = new TreeTableNode("Has childrenNodes");
t2.stringColumn.set("Simple String");
t2.dateColumn.set(new Date());
t2.childrenNodes.add(new TreeTableNode("Inner Child 1"));
t2.childrenNodes.add(new TreeTableNode("Inner Child 2"));
t.childrenNodes.add(t2);
return t;
}

public static void main(String[] argv) throws Exception {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
JFrame frm = new JFrame("Tree Test");
frm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JXTreeTable tree = new JXTreeTable();
tree.setRootVisible(true);
tree.setShowGrid(true, true);
TreeTableNode t = createTree();
SwingXBind.get().bindContent(t,
new PropertyContext[] {t.childrenNodes.getContext()},
new PropertyContext[]{t.dateColumn.getContext(), t.stringColumn.getContext()},
tree);
tree.packAll();

AbstractAction action = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
System.out.println(e);
System.out.println("Selected Row: " + tree.getSelectedRow() + " Path: " + tree.getPathForRow(tree.getSelectedRow()));
TreePath selectedPath = tree.getTreeSelectionModel().getSelectionPath();
if (selectedPath == null) {
JOptionPane.showMessageDialog(tree,
"Must select a node in the tree before you can delete", "Error",
JOptionPane.ERROR_MESSAGE);
} else if (tree.getSelectedRow() >= 0 && !((TreeTableNode) selectedPath.getLastPathComponent()).isLeaf.get()) {
TreeTableNode toBeDeletedNode = (TreeTableNode) selectedPath.getLastPathComponent();

TreeTableNode parentNode = (TreeTableNode) selectedPath.getParentPath().getLastPathComponent();

parentNode.childrenNodes.remove(toBeDeletedNode);

System.out.println(parentNode.childrenNodes);

}
}

};

tree.registerKeyboardAction(action, "delete", KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), 0);

frm.add(new JScrollPane(tree), BorderLayout.CENTER);
frm.pack();
frm.setLocationByPlatform(true);
frm.setVisible(true);

// Thread.sleep(10000);
// int index=0;
// for(Iterator treeNodeIter = t.childrenNodes.iterator();treeNodeIter.hasNext();)
// {
// TreeTableNode node = (TreeTableNode) treeNodeIter.next();
// node.data.set(String.valueOf(index++));
// System.out.println(node);
// }
}
}

mveksler
Offline
Joined: 2007-01-26
Points: 0

Maybe I am not doing it right?
Do I have to create SwingXTableAdapter?

vprise
Offline
Joined: 2003-11-07
Points: 0

The SwingXTableAdapter is created when you call bind, I will take a look at this and get back to you when I figure it out. This should generally work.

vprise
Offline
Joined: 2003-11-07
Points: 0

A tough one ;-)
OK, I fixed this in CVS (only modified the SwingXBinding code for the fix) the fixed exposed a couple of other bugs which were pretty hard to track...
Anyway, there is one minor fix that needs to go in your code where isLeaf must be initialized with a value in order to prevent a null pointer exception later on. I just passed false to the contructor argument.
I will try to refresh the code drop later today with the fix.

Thanks.

Shai Almog

The full code drop is now also updated with the fix.

--
Shai Almog
vPrise
http://www.vprise.com/
[att1.html]

mveksler
Offline
Joined: 2007-01-26
Points: 0

Ok, thanks a lot.
I tried it, and it is now working.
However, what should I do when I get to the root?
Can I somehow delet root? Or it is imposible to delete root?
I can only hide the root.

import net.java.dev.properties.container.ObservableProperty;
import net.java.dev.properties.container.ObservableIndexed;
import net.java.dev.properties.container.BeanContainer;
import net.java.dev.properties.container.PropertyContext;
import net.java.dev.properties.Property;
import net.java.dev.properties.IndexedProperty;
import net.java.dev.properties.test.swingx.SimpleFileSystemModel;
import net.java.dev.properties.binding.swingx.adapters.SwingXBind;

import javax.swing.*;
import javax.swing.tree.TreePath;
import javax.swing.tree.DefaultMutableTreeNode;
import java.util.Date;
import java.util.Iterator;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;

import org.jdesktop.swingx.JXTreeTable;
import org.jdesktop.swingx.treetable.DefaultTreeTableModel;

public class TreeTableNode {
/**
* This observable property will be used in the toString which will be used by TreeTable Renderer to display in the table.
*/
public final Property data = new ObservableProperty("");

/**
* This indexed propery will track changes to the chield tree nodes
*/
public final IndexedProperty childrenNodes = new ObservableIndexed();

/**
* This property will map to a column
*/
public final Property dateColumn = new ObservableProperty();

/**
* This propery will map to another column
*/
public final Property stringColumn = new ObservableProperty();

public final Property isLeaf = new ObservableProperty();

/** Creates a new instance of TreeBinding */
public TreeTableNode() {
BeanContainer.bind(this);
}

public TreeTableNode(String data) {
this();
this.data.set(data);
}

public String toString() {
return data.get();
}

private static TreeTableNode createTree() {
TreeTableNode t = new TreeTableNode("Data Node");
TreeTableNode leaf = new TreeTableNode("First");
leaf.isLeaf.set(false);
t.childrenNodes.add(leaf);
leaf = new TreeTableNode("Second");
leaf.isLeaf.set(false);
t.childrenNodes.add(leaf);
leaf = new TreeTableNode("Third");
leaf.isLeaf.set(false);
t.childrenNodes.add(leaf);
leaf = new TreeTableNode("Forth");
leaf.isLeaf.set(false);
t.childrenNodes.add(leaf);
TreeTableNode t2 = new TreeTableNode("Has childrenNodes");
t2.stringColumn.set("Simple String");
t2.dateColumn.set(new Date());
t2.isLeaf.set(true);
leaf = new TreeTableNode("Inner Child 1");
leaf.isLeaf.set(false);
t2.childrenNodes.add(leaf);
leaf = new TreeTableNode("Inner Child 2");
leaf.isLeaf.set(false);
t2.childrenNodes.add(leaf);
t.childrenNodes.add(t2);
return t;
}

public static void main(String[] argv) throws Exception {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
JFrame frm = new JFrame("Tree Test");
frm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JXTreeTable tree = new JXTreeTable();
tree.setRootVisible(true);
tree.setShowGrid(true, true);
TreeTableNode t = createTree();
SwingXBind.get().bindContent(t,
new PropertyContext[] {t.childrenNodes.getContext()},
new PropertyContext[]{t.dateColumn.getContext(), t.stringColumn.getContext()},
tree);
tree.packAll();

AbstractAction action = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
System.out.println(e);
System.out.println("Selected Row: " + tree.getSelectedRow() + " Path: " + tree.getPathForRow(tree.getSelectedRow()));
TreePath selectedPath = tree.getTreeSelectionModel().getSelectionPath();
if (selectedPath == null) {
JOptionPane.showMessageDialog(tree,
"Must select a node in the tree before you can delete", "Error",
JOptionPane.ERROR_MESSAGE);
} else if (tree.getSelectedRow() >= 0 /*&& !((TreeTableNode) selectedPath.getLastPathComponent()).isLeaf.get()*/) {
TreeTableNode toBeDeletedNode = (TreeTableNode) selectedPath.getLastPathComponent();

TreePath parentNodePath = selectedPath.getParentPath();
TreeTableNode parentNode;
if(parentNodePath!=null)
{
parentNode = (TreeTableNode) selectedPath.getParentPath().getLastPathComponent();
parentNode.childrenNodes.remove(toBeDeletedNode);
}
else
{
parentNode = toBeDeletedNode;
System.out.println("I dont know what should I do with root node?");
tree.setRootVisible(false);
}

System.out.println(parentNode.childrenNodes);

}
}

};

tree.registerKeyboardAction(action, "delete", KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), 0);

frm.add(new JScrollPane(tree), BorderLayout.CENTER);
frm.pack();
frm.setLocationByPlatform(true);
frm.setVisible(true);

// Thread.sleep(10000);
// int index=0;
// for(Iterator treeNodeIter = t.childrenNodes.iterator();treeNodeIter.hasNext();)
// {
// TreeTableNode node = (TreeTableNode) treeNodeIter.next();
// node.data.set(String.valueOf(index++));
// System.out.println(node);
// }
}
}

kschaefe
Offline
Joined: 2006-06-08
Points: 0

> Ok, thanks a lot.
> I tried it, and it is now working.
> However, what should I do when I get to the root?
> Can I somehow delet root? Or it is imposible to
> delete root?
> I can only hide the root.
The JXTreeTable is a tree and as such it needs to have a root. The tree table provides a mechanism for hiding the root. since it is often unnecessary for the tabular display. There is no way, however, to have the tree table without the root.

Karl

vprise
Offline
Joined: 2003-11-07
Points: 0

OK, the problem might be a bit tricky to solve... However, there is a simple workaround and I will solve it soon.
The issue seems to be, that while I do bind listeners to all the indexed properties I don't do the same for every property returned from the tree. This should be fixed and I will make sure to do so, its not trivial since it will incur some memory overhead but that should be in proportion to the size of the tree table and thus no big deal.
In the meantime you can change your loop code like this:
for(int iter = 0 ;iter < t.childrenNodes.size();iter++) {
TreeTableNode node = t.childrenNodes.get(iter);
node.data.set(String.valueOf(iter));
t.childrenNodes.set(iter, node);
System.out.println(node);
}

It will fix the effect you are seeing.

If this doesn't solve your problem you will have to checkout from CVS and compile, you currently need Java 6 to compile so this might be a problem. I will try to publish a new version over the weekend once I fix the bug and finish some other unrelated changes.

Thanks,
Shai.

mveksler
Offline
Joined: 2007-01-26
Points: 0

Do I have to build the project or CVS already has JARs that I can plug into the project?

vprise
Offline
Joined: 2003-11-07
Points: 0

FYI I just checked in to CVS and uploaded a code drop to the files section that solves the root cause of the problem. You can download the code drop from the Documents and Files section in the bean properties project as a single ZIP file containing everything you need.
Let me know if you have any problems/questions.

Thanks.

mveksler
Offline
Joined: 2007-01-26
Points: 0

Sweat,
Works like a charm ;-)
I will play with it more. I will post my findings if I see some odd behavior.
Thank you very much.

vprise
Offline
Joined: 2003-11-07
Points: 0

OK, I see the problem I will track it down and let you know ;-)

mveksler
Offline
Joined: 2007-01-26
Points: 0

Thanks a lot.

mveksler
Offline
Joined: 2007-01-26
Points: 0

Your code listed works just fine and displays local file system in hierarchical fashion.
Let me know if I can help you understand tree tables better.
They are very easy to use.

mveksler
Offline
Joined: 2007-01-26
Points: 0

I was able to create a tree of mixed nodes. I have PersonBean with properties of first, last name which contains child nodes like Address with properties like city, state, etc.

I run into problem when I try to bind columns to the child node properties.

I was hopping that bean-properties could do something like JSR 295 which runs retroscope of the entire bean to find properties.

In other words, the ROOT node in my case Person should be able to expose its childres properties.

Shai Almog

The columns in the tree table exist for all nodes children and parents.
So the binding could in potential check whether a property belongs to the
parent bean and if not return null which would mean that if you bind a
property from another bean you will get null from that column in other
beans.

Is that what you mean?

Or do you mean something more akin to a separate bean to manage the table?
If its the latter then this isn't really feasible in the constraints of the
tree table model.

--
Shai Almog
vPrise
http://www.vprise.com/
[att1.html]

mveksler
Offline
Joined: 2007-01-26
Points: 0

Here is what I mean:

import net.java.dev.properties.Property;
import net.java.dev.properties.container.ObservableProperty;
import net.java.dev.properties.container.BeanContainer;

public class AddressBean {
public final Property name = new ObservableProperty("");
public final Property address1 = new ObservableProperty("");
public final Property address2 = new ObservableProperty("");
public final Property city = new ObservableProperty("");
public final Property sate = new ObservableProperty("");
public final Property zip = new ObservableProperty("");

public AddressBean()
{
BeanContainer.bind(this);
}

public AddressBean(String str)
{
this();
name.set(str);
}

public String toString()
{
return name.get();
}
}

public class PersonBean {
public final Property name = new ObservableProperty("");
public final Property firstName = new ObservableProperty("");
public final Property lastName = new ObservableProperty("");
public final Property age = new ObservableProperty("");
public final IndexedProperty childrenNodes = new ObservableIndexed();
//public final Property address = new ObservableProperty(new AddressBean());

public PersonBean ()
{
BeanContainer.bind(this);
}

public PersonBean (String str)
{
this();
name.set(str);
}

public static PatientBean createTree()
{
PersonBean root = new PersonBean ("Patient Address");
AddressBean home = new AddressBean("Home Address");
home.address1.set("1234 test Drive");
home.address2.set("PO BOX 1234");
home.city.set("San Diego");
home.sate.set("CA");
home.zip.set("92130");
root.childrenNodes.add(home);
AddressBean work = new AddressBean("Work Address");
home.address1.set("1234 test Drive");
home.address2.set("PO BOX 1234");
home.city.set("San Diego");
home.sate.set("CA");
home.zip.set("92130");
root.childrenNodes.add(work);
return root;
}

public String toString()
{
return name.get();
}
}

import org.jdesktop.swingx.JXTreeTable;

import javax.swing.*;

import net.java.dev.properties.binding.swingx.adapters.SwingXBind;
import net.java.dev.properties.container.PropertyContext;

import java.awt.*;

public class MixedBeanProperties {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
MixedBeanProperties bean = new MixedBeanProperties();
public void run() {
bean.createUI();
}
});
}

public void createUI()
{
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
System.out.println(e);
}

JFrame frm = new JFrame("Tree Test");
frm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JXTreeTable tree = new JXTreeTable();
tree.setRootVisible(true);
tree.setShowGrid(true, true);
bindTree(tree);
tree.packAll();
frm.add(new JScrollPane(tree), BorderLayout.CENTER);
frm.pack();
frm.setLocationByPlatform(true);
frm.setVisible(true);

}

private void bindTree(JXTreeTable tree) {
PatientBean t = PatientBean.createTree();
SwingXBind.get().bindContent(t,
new PropertyContext[] {t.childrenNodes.getContext()},
new PropertyContext[]{t.childrenNodes.get(0).address1.getContext()}, //this is where my question stands. The the PersonBean does not have a way to expose children properties so that I can bind them to the columns.
tree);
}
}

Shai Almog

Its a bit hard for me to understand the code without running it and I'm
missing PatientBean in order to run the code, can you post that too?

--
Shai Almog
vPrise
http://www.vprise.com/
[att1.html]

mveksler
Offline
Joined: 2007-01-26
Points: 0

Sorry forgot to change that. The PatientbBan is actually the PersonBean.
I was messing with the code and forgot to replace that.
Just replace Patient with Person

Shai Almog

It seems that what you need is the former of the two I mentioned, I can do
this but right now this has a performance implication that isn't very
significant but exists even when you don't need this feature.
So whenever I access a property rather than just extract its value I have to
test whether its of the right bean type. This test isn't trivial in the
current code, I should probably make it trivial and efficient so its a good
idea in general.

I'll try to build a release for right after the weekend, the code you have
will work and if you need a temporary fix so you can go on working you can
just replace the following code as such:
/*SwingXBind.get().bindContent(t,
new PropertyContext[] {t.childrenNodes.getContext()},
new
PropertyContext[]{t.childrenNodes.get(0).address1.getContext()},
//this is where my question stands. The the PersonBean does not have a way
to expose children properties so that I can bind them to the columns.
tree);*/
tree.setTreeTableModel(new TreeTableAdapterModel(t,
new PropertyContext[] {t.childrenNodes.getContext()},
new
PropertyContext[]{t.childrenNodes.get(0).address1.getContext()},
//this is where my question stands. The the PersonBean does not have a way
to expose children properties so that I can bind them to the columns.
null) {
public boolean isCellEditable(Object node, int column) {
try {
return super.isCellEditable(node, column);
} catch(BeanBindException err) {
return false;
}
}

public Object getValueAt(Object node, int column) {
try {
return super.getValueAt(node, column);
} catch(BeanBindException err) {
return null;
}
}
});

--
Shai Almog
vPrise
http://www.vprise.com/
[att1.html]

Shai Almog

Just so we are clear the code above is from bindTree in MixedBeanProperties

--
Shai Almog
vPrise
http://www.vprise.com/
[att1.html]

mveksler
Offline
Joined: 2007-01-26
Points: 0

Thank you. I will wait for the new build.
What I whant is for the root bean to expose childrens properties.

I want to be able to acccss children properties like this:

PatientBean t = PatientBean.createTree();
t.address1 // this is a property of AddressBean
t.address2 // this is a property of AddressBean
t.city // this is a property of AddressBean

Shai Almog

If I understand correctly then address1 is a property of type address,
so this should work as long as you don't expect address to have child
nodes since this will make everything very complicated.
This should work with the patch I sent since its very local and you
can put it in your own code at one point only.

--
Shai Almog
vPrise
http://www.vprise.com/

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

mveksler
Offline
Joined: 2007-01-26
Points: 0

However, with this patch, it will only work for t.childeNodes.get(0) //this is a Home Address. What about t.childNodes.get(1) //?? this is my Work Address.
In the binding, we only bind columns to the first child?!

Shai Almog

I didn't get that example?
As long as a childNodes doesn't have children within it this should work.

--
Shai Almog
vPrise
http://www.vprise.com/

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

mveksler
Offline
Joined: 2007-01-26
Points: 0

It is a little akward to do something like this: t.childNodes.get(0).address1.

All we doing here is using properties to build column factory?
That is why I think it would be better if parent bena could inherit childne nodes properties?!