Home » Eclipse Projects » JFace » StructuredViewer useHashlookup(useHashlookup and inplace edited model elements)
| |
Re: StructuredViewer useHashlookup [message #646323 is a reply to message #643869] |
Thu, 23 December 2010 10:51 |
Jens Kreidler Messages: 17 Registered: July 2009 |
Junior Member |
|
|
Thanks Daniel for your reply.
I just had time for looking deeper into this -
ok, using an IElementComparer is a provided way for setting up the internal elementMap of a StructuredViewer - but unfortunately this does not solve an in-place editing for instance.
Assume you have set the TreeViewer's input with a list of a type with ITreeNode's. Each node has a field "element", the payload of the tree node, so treeViewer.setInput( treeNodeList );
A model instance holds that list. A user opens an edit dialog and manipulates - lets say - the element of the ITreeNode index 0.
After editing, you call treeViewer.update( treeNode, null );
This way works fine and fits great in an Model-View-Controller pattern when the treeViewer is configured with useHashlookup = false. But it fails when this is set to false: after the update( node, null ) - call just the hashCode is compared and the appropiate widget cannot be found in via the tree StructuredViewer. No wonder, because the element has been edited in-place and next hashCode is calculated on the edited instance.
So, what can be done? Considering the ITreeNode's elements are DTOs with a technical key, you must implement an IElementComparer that just looks into this technical key? Or is there an other usage possibility? Does any one have an idea, s.th. to discuss?
Thanks in advance
|
|
|
Re: StructuredViewer useHashlookup [message #650142 is a reply to message #646323] |
Fri, 21 January 2011 22:28 |
Carsten Habicht Messages: 14 Registered: January 2011 |
Junior Member |
|
|
Hi Jens,
maybe I just don't understand your scenario very well, but isnt that a problem with the hashCode and equals methods of your viewer's element class?
Here's a test class I bungled together in Helios (as a plugin project with a "RCP application with a view" template). Because you talk about ITreeNodes in your second post (didn't find that interface in the Eclipse APIs), it builds a tree of Node objects that have an id, a text-caption and a list of children. The root node of that tree is thrown into a TreeViewer that has set useHashLookup to true. IMO it should make no difference if you alter a string or any complex type the node references, so there is a button that simply changes the caption of a certain node and then refreshes it in the viewer.
package treeviewertest;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.TreeViewerColumn;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeColumn;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.ViewPart;
public class View extends ViewPart {
public View() {
}
public static final String ID = "TreeViewerTest.view";
private TreeViewer viewer;
class Node {
final List<View.Node> children = new ArrayList<View.Node>();
final int id;
String text;
public Node(int id, String text) {
this.id = id;
this.text = text;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public List<View.Node> getChildren() {
return children;
}
public int getId() {
return id;
}
@Override
public int hashCode() {
return id;
}
@Override
public boolean equals(Object obj) {
return id == ((Node) obj).id;
}
}
class ViewContentProvider implements ITreeContentProvider {
Node root = null;
public void inputChanged(Viewer v, Object oldInput, Object newInput) {
root = (Node) newInput;
}
public void dispose() {
}
public Object[] getElements(Object parent) {
if (parent instanceof Node) {
return ((Node) parent).getChildren().toArray();
}
return new Object[0];
}
@Override
public Object[] getChildren(Object parentElement) {
return ((Node) parentElement).getChildren().toArray();
}
@Override
public Object getParent(Object element) {
return null;
}
@Override
public boolean hasChildren(Object element) {
return ((Node) element).getChildren().size() > 0;
}
}
class ViewLabelProvider extends LabelProvider implements ITableLabelProvider {
public String getColumnText(Object obj, int index) {
switch (index) {
case 0:
return "" + ((Node) obj).getId();
case 1:
return ((Node) obj).getText();
default:
return getText(obj);
}
}
public Image getColumnImage(Object obj, int index) {
return null;
}
public Image getImage(Object obj) {
return PlatformUI.getWorkbench().getSharedImages()
.getImage(ISharedImages.IMG_OBJ_ELEMENT);
}
}
/**
* This is a callback that will allow us to create the viewer and initialize
* it.
*/
public void createPartControl(Composite parent) {
Composite composite = new Composite(parent, SWT.NONE);
composite.setLayout(new GridLayout(1, false));
Button btnEditElement = new Button(composite, SWT.NONE);
btnEditElement.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
edit();
}
});
btnEditElement.setText("Edit Element 23");
viewer = new TreeViewer(composite, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL
| SWT.FULL_SELECTION);
viewer.setUseHashlookup(true);
Tree tree = viewer.getTree();
tree.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
tree.setHeaderVisible(true);
TreeViewerColumn treeViewerColumn = new TreeViewerColumn(viewer, SWT.NONE);
TreeColumn idCol = treeViewerColumn.getColumn();
idCol.setWidth(100);
idCol.setText("ID");
TreeViewerColumn treeViewerColumn_1 = new TreeViewerColumn(viewer, SWT.NONE);
TreeColumn textCol = treeViewerColumn_1.getColumn();
textCol.setWidth(100);
textCol.setText("Text");
viewer.setContentProvider(new ViewContentProvider());
viewer.setLabelProvider(new ViewLabelProvider());
Node root = new Node(-1, "root");
createTree(root, 1);
viewer.setInput(root);
}
private int i = 0;
Random r = new Random(1235l);
Node el;
private void createTree(Node parent, int depth) {
for (int j = 0; j < 6 / depth; j++) {
if (i > 40) {
return;
}
Node child = new Node(i, "Node " + i);
if (i == 23) {
el = child;
}
i++;
parent.getChildren().add(child);
if (r.nextInt(11) < 6) {
createTree(child, depth + 1);
}
}
}
public void setFocus() {
viewer.getControl().setFocus();
}
private void edit() {
if (el != null) {
el.setText("Hallo. Wurde gerade editiert! " + (i++));
viewer.refresh(el);
}
}
}
Is that at least remotely the right direction?
Cheers
Carsten
|
|
|
Re: StructuredViewer useHashlookup [message #650219 is a reply to message #650142] |
Sun, 23 January 2011 10:31 |
Thomas Schindl Messages: 6651 Registered: July 2009 |
Senior Member |
|
|
Hi,
I think Carsten is right this looks very much like a problem in your
hashCode implementation which has to stable during the lifetime of your
instance (it has to use immutable values!) to be used in HashSet/Map!
The only other option is that your IElementComparer uses
System.identityHashCode().
Tom
Am 21.01.11 23:28, schrieb Carsten Habicht:
> Hi Jens,
>
> maybe I just don't understand your scenario very well, but isnt that a
> problem with the hashCode and equals methods of your viewer's element
> class?
>
> Here's a test class I bungled together in Helios (as a plugin project
> with a "RCP application with a view" template). Because you talk about
> ITreeNodes in your second post (didn't find that interface in the
> Eclipse APIs), it builds a tree of Node objects that have an id, a
> text-caption and a list of children. The root node of that tree is
> thrown into a TreeViewer that has set useHashLookup to true. IMO it
> should make no difference if you alter a string or any complex type the
> node references, so there is a button that simply changes the caption of
> a certain node and then refreshes it in the viewer.
>
> package treeviewertest;
>
> import java.util.ArrayList;
> import java.util.List;
> import java.util.Random;
>
> import org.eclipse.jface.viewers.ITableLabelProvider;
> import org.eclipse.jface.viewers.ITreeContentProvider;
> import org.eclipse.jface.viewers.LabelProvider;
> import org.eclipse.jface.viewers.TreeViewer;
> import org.eclipse.jface.viewers.TreeViewerColumn;
> import org.eclipse.jface.viewers.Viewer;
> import org.eclipse.swt.SWT;
> import org.eclipse.swt.events.SelectionAdapter;
> import org.eclipse.swt.events.SelectionEvent;
> import org.eclipse.swt.graphics.Image;
> import org.eclipse.swt.layout.GridData;
> import org.eclipse.swt.layout.GridLayout;
> import org.eclipse.swt.widgets.Button;
> import org.eclipse.swt.widgets.Composite;
> import org.eclipse.swt.widgets.Tree;
> import org.eclipse.swt.widgets.TreeColumn;
> import org.eclipse.ui.ISharedImages;
> import org.eclipse.ui.PlatformUI;
> import org.eclipse.ui.part.ViewPart;
>
> public class View extends ViewPart {
> public View() {
> }
>
> public static final String ID = "TreeViewerTest.view";
>
> private TreeViewer viewer;
>
> class Node {
> final List<View.Node> children = new ArrayList<View.Node>();
> final int id;
> String text;
>
> public Node(int id, String text) {
> this.id = id;
> this.text = text;
> }
>
> public String getText() {
> return text;
> }
>
> public void setText(String text) {
> this.text = text;
> }
>
> public List<View.Node> getChildren() {
> return children;
> }
>
> public int getId() {
> return id;
> }
>
> @Override
> public int hashCode() {
> return id;
> }
>
> @Override
> public boolean equals(Object obj) {
> return id == ((Node) obj).id;
> }
> }
>
> class ViewContentProvider implements ITreeContentProvider {
> Node root = null;
>
> public void inputChanged(Viewer v, Object oldInput, Object newInput) {
> root = (Node) newInput;
> }
>
> public void dispose() {
> }
>
> public Object[] getElements(Object parent) {
> if (parent instanceof Node) {
> return ((Node) parent).getChildren().toArray();
> }
> return new Object[0];
> }
>
> @Override
> public Object[] getChildren(Object parentElement) {
> return ((Node) parentElement).getChildren().toArray();
> }
>
> @Override
> public Object getParent(Object element) {
> return null;
> }
>
> @Override
> public boolean hasChildren(Object element) {
> return ((Node) element).getChildren().size() > 0;
> }
> }
>
> class ViewLabelProvider extends LabelProvider implements
> ITableLabelProvider {
> public String getColumnText(Object obj, int index) {
> switch (index) {
> case 0:
> return "" + ((Node) obj).getId();
> case 1:
> return ((Node) obj).getText();
> default:
> return getText(obj);
> }
> }
>
> public Image getColumnImage(Object obj, int index) {
> return null;
> }
>
> public Image getImage(Object obj) {
> return PlatformUI.getWorkbench().getSharedImages()
> .getImage(ISharedImages.IMG_OBJ_ELEMENT);
> }
> }
>
> /**
> * This is a callback that will allow us to create the viewer and
> initialize
> * it.
> */
> public void createPartControl(Composite parent) {
> Composite composite = new Composite(parent, SWT.NONE);
> composite.setLayout(new GridLayout(1, false));
>
> Button btnEditElement = new Button(composite, SWT.NONE);
> btnEditElement.addSelectionListener(new SelectionAdapter() {
> @Override
> public void widgetSelected(SelectionEvent e) {
> edit();
> }
> });
> btnEditElement.setText("Edit Element 23");
> viewer = new TreeViewer(composite, SWT.MULTI | SWT.H_SCROLL |
> SWT.V_SCROLL
> | SWT.FULL_SELECTION);
> viewer.setUseHashlookup(true);
> Tree tree = viewer.getTree();
> tree.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
> tree.setHeaderVisible(true);
>
> TreeViewerColumn treeViewerColumn = new TreeViewerColumn(viewer,
> SWT.NONE);
> TreeColumn idCol = treeViewerColumn.getColumn();
> idCol.setWidth(100);
> idCol.setText("ID");
>
> TreeViewerColumn treeViewerColumn_1 = new TreeViewerColumn(viewer,
> SWT.NONE);
> TreeColumn textCol = treeViewerColumn_1.getColumn();
> textCol.setWidth(100);
> textCol.setText("Text");
> viewer.setContentProvider(new ViewContentProvider());
> viewer.setLabelProvider(new ViewLabelProvider());
>
> Node root = new Node(-1, "root");
> createTree(root, 1);
> viewer.setInput(root);
> }
>
> private int i = 0;
> Random r = new Random(1235l);
> Node el;
>
> private void createTree(Node parent, int depth) {
> for (int j = 0; j < 6 / depth; j++) {
> if (i > 40) {
> return;
> }
> Node child = new Node(i, "Node " + i);
> if (i == 23) {
> el = child;
> }
> i++;
> parent.getChildren().add(child);
> if (r.nextInt(11) < 6) {
> createTree(child, depth + 1);
> }
> }
> }
>
> public void setFocus() {
> viewer.getControl().setFocus();
> }
>
> private void edit() {
> if (el != null) {
> el.setText("Hallo. Wurde gerade editiert! " + (i++));
> viewer.refresh(el);
> }
> }
> }
> Is that at least remotely the right direction?
>
> Cheers
> Carsten
>
|
|
|
Goto Forum:
Current Time: Thu Sep 26 21:14:23 GMT 2024
Powered by FUDForum. Page generated in 0.05791 seconds
|