Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » JFace » StructuredViewer useHashlookup(useHashlookup and inplace edited model elements)
StructuredViewer useHashlookup [message #643829] Wed, 08 December 2010 12:56 Go to next message
Jens Kreidler is currently offline Jens KreidlerFriend
Messages: 17
Registered: July 2009
Junior Member
Hello,

I 've got a question about setting the jface's StructuredViewer's useHashlookup = true and editing in respect to refresh( Object element ).

Setting a List<Person> as the viewer's input and having a Person an implemented hashCode() and equals() that mentioned refresh( Object element ) doesn't work if a Person instance within the input model is edited (by reference).

Internally the Structured viewer can't lookup the appropiate widget and thus cannot update/refresh that single swt item. (I do not want to call refresh() as it does "too much")

- How can I enable in-place editing, using hashLookup = true?
- What is the best-practice for that?

I'm looking forward to any discussion! Greetings
Re: StructuredViewer useHashlookup [message #643869 is a reply to message #643829] Wed, 08 December 2010 14:27 Go to previous messageGo to next message
Daniel Krügler is currently offline Daniel KrüglerFriend
Messages: 853
Registered: July 2009
Senior Member
On 12/8/2010 13:56, Jens Kreidler wrote:
> Hello,
>
> I 've got a question about setting the jface's StructuredViewer's
> useHashlookup = true and editing in respect to refresh( Object element ).
>
> Setting a List<Person> as the viewer's input and having a Person an
> implemented hashCode() and equals() that mentioned refresh( Object
> element ) doesn't work if a Person instance within the input model is
> edited (by reference).
>
> Internally the Structured viewer can't lookup the appropiate widget and
> thus cannot update/refresh that single swt item. (I do not want to call
> refresh() as it does "too much")
>
> - How can I enable in-place editing, using hashLookup = true?
> - What is the best-practice for that?

You need to implement the IElementComparer for your type and set it via
the setComparer of your viewer.

HTH & Greetings from Bremen,

Daniel Krügler
Re: StructuredViewer useHashlookup [message #646323 is a reply to message #643869] Thu, 23 December 2010 10:51 Go to previous messageGo to next message
Jens Kreidler is currently offline Jens KreidlerFriend
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 Go to previous messageGo to next message
Carsten Habicht is currently offline Carsten HabichtFriend
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


Sylphen - Ihr Systemhaus in Mittelhessen - http://www.sylphen.com/
Re: StructuredViewer useHashlookup [message #650219 is a reply to message #650142] Sun, 23 January 2011 10:31 Go to previous message
Thomas Schindl is currently offline Thomas SchindlFriend
Messages: 5487
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
>
Previous Topic:[Databinding] TableViewer (rows vs columns)
Next Topic:Input Dialog - Textarea
Goto Forum:
  


Current Time: Thu Dec 18 23:14:55 GMT 2014

Powered by FUDForum. Page generated in 0.09077 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software