diff org.eclipse.jface.databinding/src/org/eclipse/jface/internal/databinding/provisional/viewers/TreeNode.d @ 78:0a55d2d5a946

Added file for databinding
author Frank Benoit <benoit@tionex.de>
date Tue, 14 Apr 2009 11:35:29 +0200
parents
children 6be48cf9f95c
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/org.eclipse.jface.databinding/src/org/eclipse/jface/internal/databinding/provisional/viewers/TreeNode.d	Tue Apr 14 11:35:29 2009 +0200
@@ -0,0 +1,341 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *     Stefan Xenos, IBM - initial API and implementation
+ *******************************************************************************/
+module org.eclipse.jface.internal.databinding.provisional.viewers.TreeNode;
+
+import java.lang.all;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.eclipse.core.databinding.observable.IStaleListener;
+import org.eclipse.core.databinding.observable.Observables;
+import org.eclipse.core.databinding.observable.StaleEvent;
+import org.eclipse.core.databinding.observable.set.IObservableSet;
+import org.eclipse.core.databinding.observable.set.ISetChangeListener;
+import org.eclipse.core.databinding.observable.set.SetChangeEvent;
+import org.eclipse.core.databinding.observable.set.SetDiff;
+import org.eclipse.jface.databinding.viewers.ObservableListTreeContentProvider;
+import org.eclipse.jface.databinding.viewers.ObservableSetTreeContentProvider;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.swt.widgets.Control;
+
+/**
+ * 
+ * @since 1.0
+ * @deprecated Use {@link ObservableSetTreeContentProvider} or
+ * {@link ObservableListTreeContentProvider} instead.
+ */
+/* package */ class TreeNode : ISetChangeListener, IStaleListener {
+    private UnorderedTreeContentProvider contentProvider;
+    private Object element;
+    
+    // Stores the set of parents (null if there are less than 2)
+    private HashSet parents = null;
+    
+    // Stores one representative parent. If there is more than one parent,
+    // the complete set of parents can be found in the parents set.
+    Object parent;
+    
+    /**
+     * Set of child elements.
+     */
+    private IObservableSet children;
+    
+    private bool hasPendingNode = false;
+    private bool isStale;
+    private bool listeningToChildren = false;
+    private bool prefetchEnqueued = false;
+    
+    /**
+     * @param element
+     * @param cp
+     */
+    public this(Object element, UnorderedTreeContentProvider cp) {
+        this.element = element;
+        this.contentProvider = cp;
+        children = contentProvider.createChildSet(element);
+        if (children is null) {
+            children = Observables.emptyObservableSet();
+            listeningToChildren = true;
+        }
+        hasPendingNode = children.isStale();
+    }
+    
+    /**
+     * @param parent
+     */
+    public void addParent(Object parent) {
+        if (this.parent is null) {
+            this.parent = parent;
+        } else {
+            if (parent.equals(this.parent)) {
+                return;
+            }
+            if (parents is null) {
+                parents = new HashSet();
+                parents.add(this.parent);
+            }
+            parents.add(parent);
+        }
+    }
+    
+    /**
+     * @param parent
+     */
+    public void removeParent(Object parent) {
+        if (this.parents !is null) {
+            parents.remove(parent);
+        } 
+        
+        if (parent is this.parent) {
+            if (parents is null || parents.isEmpty()) {
+                this.parent = null;
+            } else {
+                this.parent = parents.iterator().next();
+            }
+        }
+        
+        if (this.parents !is null && this.parents.size() <= 1) {
+            this.parents = null;
+        }
+    }
+    
+    /**
+     * Returns the set of children for this node. If new children are discovered later, they
+     * will be added directly to the viewer.
+     *  
+     * @return TODO
+     */
+    public Set getChildren() {
+        if (!listeningToChildren) {
+            listeningToChildren = true;
+            children.addSetChangeListener(this);
+            hasPendingNode = children.isEmpty() && children.isStale();
+            children.addStaleListener(this);
+            updateStale();
+        }
+        
+        // If the child set is stale and empty, show the "pending" node
+        if (hasPendingNode) {
+            Object pendingNode = contentProvider.getPendingNode();
+            return Collections.singleton(pendingNode);
+        }
+        return children;
+    }
+    
+    /**
+     * @return TODO
+     */
+    public IObservableSet getChildrenSet() {
+        return children;
+    }
+    
+    private void updateStale() {
+        bool willBeStale = children.isStale();
+        if (willBeStale !is isStale) {
+            isStale = willBeStale;
+            
+            contentProvider.changeStale(isStale? 1 : -1);
+        }
+    }
+    
+    /**
+     * @return TODO
+     */
+    public bool isStale() {
+        return isStale;
+    }
+
+    /**
+     * Returns true if the viewer should show a plus sign for expanding this 
+     * node. 
+     * 
+     * @return TODO
+     */
+    public bool shouldShowPlus() {
+        if (children is null) {
+//            if (!hasPendingNode) {
+//                hasPendingNode = true;
+//                contentProvider.add(element, Collections.singleton(contentProvider.getPendingNode()));
+//            }
+            return true;
+        }
+        if (!listeningToChildren && !prefetchEnqueued) {
+            prefetchEnqueued = true;
+            contentProvider.enqueuePrefetch(this);
+        }
+        return !listeningToChildren || hasPendingNode || !children.isEmpty();
+    }
+    
+    /**
+     * Disposes this node and removes all remaining children.
+     */
+    public void dispose() {
+        if (children !is null) {
+            if (listeningToChildren) {
+                contentProvider.remove(element, children, true);
+                children.removeSetChangeListener(this);
+                children.removeStaleListener(this);
+            }
+            children.dispose();
+            children = null;
+            
+            if (listeningToChildren && isStale) {
+                contentProvider.changeStale(-1);
+            }
+        }
+    }
+    
+    /**
+     * @return TODO
+     */
+    public bool isDisposed() {
+        return children is null;
+    }
+    
+    /**
+     * Returns one representative parent, or null if this node is unparented. Use
+     * getParents() to get the complete set of known parents.
+     * 
+     * @return TODO
+     */
+    public Object getParent() {
+        return parent;
+    }
+    
+    /**
+     * 
+     * @return the set of all known parents for this node
+     */
+    public Set getParents() {
+        if (parents is null) {
+            if (parent is null) {
+                return Collections.EMPTY_SET;
+            }
+            return Collections.singleton(parent);
+        }
+        return parents;
+    }
+    
+    /**
+     * Called when the child set changes. Should not be called directly by the viewer.
+     */
+    public void handleSetChange(SetChangeEvent event) {
+        SetDiff diff = event.diff;
+        TreeViewer viewer = this.contentProvider.getViewer();
+        if (viewer !is null) {
+            Control control = viewer.getControl();
+            if (control !is null) {
+                if (control.isDisposed()) {
+                    // If the widgetry was disposed without notifying the content provider, then
+                    // dispose the content provider now and stop processing events.
+                    contentProvider.dispose();
+                    return;
+                }
+            }
+        }
+        
+        bool shouldHavePendingNode = children.isEmpty() && children.isStale();
+        
+        Set additions = diff.getAdditions();
+        // Check if we should add the pending node
+        if (shouldHavePendingNode && !hasPendingNode) {
+            HashSet newAdditions = new HashSet();
+            newAdditions.addAll(additions);
+            newAdditions.add(contentProvider.getPendingNode());
+            additions = newAdditions;
+            hasPendingNode = true;
+        }
+
+        Set removals = diff.getRemovals();
+        // Check if we should remove the pending node
+        if (!shouldHavePendingNode && hasPendingNode) {
+            HashSet newRemovals = new HashSet();
+            newRemovals.addAll(removals);
+            newRemovals.add(contentProvider.getPendingNode());
+            removals = newRemovals;
+            hasPendingNode = false;
+        }
+        if (!additions.isEmpty()) {
+            contentProvider.add(element, additions);
+        }
+        if (!removals.isEmpty()) {
+            contentProvider.remove(element, removals, children.isEmpty() && !hasPendingNode);
+        }
+        
+        updateStale();
+    }
+
+    public void handleStale(StaleEvent staleEvent) {
+        TreeViewer viewer = this.contentProvider.getViewer();
+        if (viewer !is null) {
+            Control control = viewer.getControl();
+            if (control !is null) {
+                if (control.isDisposed()) {
+                    // If the widgetry was disposed without notifying the content provider, then
+                    // dispose the content provider now and stop processing events.
+                    contentProvider.dispose();
+                    return;
+                }
+            }
+        }
+        
+        bool shouldHavePendingNode = children.isEmpty() && children.isStale();
+        
+        // Check if we should add the pending node
+        if (shouldHavePendingNode && !hasPendingNode) {
+            hasPendingNode = shouldHavePendingNode;
+            contentProvider.add(element, Collections.singleton(contentProvider.getPendingNode()));
+        }
+        
+        // Check if we should remove the pending node
+        if (!shouldHavePendingNode && hasPendingNode) {
+            hasPendingNode = shouldHavePendingNode;
+            contentProvider.remove(element, Collections.singleton(contentProvider.getPendingNode()), true);
+        }
+        
+        updateStale();
+    }
+
+    /**
+     * @return TODO
+     */
+    public Object getElement() {
+        return element;
+    }
+
+    /**
+     * 
+     */
+    public void prefetch() {
+        TreeViewer viewer = this.contentProvider.getViewer();
+        if (viewer !is null) {
+            Control control = viewer.getControl();
+            if (control !is null) {
+                if (control.isDisposed()) {
+                    // If the widgetry has been disposed, then avoid sending anything
+                    // to the viewer.
+                    return;
+                }
+            }
+        }
+        
+        Set children = getChildren();
+        if (!children.isEmpty()) {
+            contentProvider.add(element, children);
+        } else {
+            // We need to remove the + sign, and adding/removing elements won't do the trick
+            contentProvider.getViewer().refresh(element);
+        }
+    }
+}