JFace Tree Knoten verzögert nachladen

Thomas Darimont

Erfahrenes Mitglied
Hallo,

hier mal ein kleines Beispiel wie man in einem JFace Tree einzelne Knoten verzögert nachladen könnte. Ein Anwendungsbeispiel wäre Beispielsweise das verzögerte Nachladen komplexerer Hierarchien aus der Datenbank ohne den Baum zu blockieren. Während des Ladens wird ein temporärer Knoten angezeigt der dann durch die "richtigen" Knoten ersetzt wird, sobald diese verfügbar sind.

Java:
/**
 *
 */
package de.tutorials;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

import org.eclipse.jface.viewers.IContentProvider;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.window.ApplicationWindow;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;

/**
 * @author Thomas.Darimont
 */
public class JFaceDeferredTreeInitializationExample extends ApplicationWindow {

	/**
	 * 
	 */
	ExecutorService deferredNodeInitializerService;

	/**
	 * 
	 */
	TreeViewer treeViewer;

	/**
	 * @param shell
	 */
	public JFaceDeferredTreeInitializationExample(Shell shell) {
		super(shell);
		setBlockOnOpen(true);
		deferredNodeInitializerService = Executors.newCachedThreadPool();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.jface.window.ApplicationWindow#configureShell(org.eclipse.swt.widgets.Shell)
	 */
	protected void configureShell(Shell shell) {
		super.configureShell(shell);
		shell.setText("JFaceDeferredTreeInitializationExample");
		shell.setSize(640, 480);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.jface.window.Window#handleShellCloseEvent()
	 */
	@Override
	protected void handleShellCloseEvent() {
		super.handleShellCloseEvent();
		deferredNodeInitializerService.shutdownNow();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.jface.window.Window#createContents(org.eclipse.swt.widgets.Composite)
	 */
	protected Control createContents(Composite composite) {
		treeViewer = new TreeViewer(composite);
		treeViewer.setContentProvider(createTreeContentProvider());
		treeViewer.setInput(createTreeModel());
		return composite;
	}

	/**
	 * @return
	 */
	private Object createTreeModel() {
		TreeNode<String> root = new TreeNode<String>("root", "0");
		TreeNode<String> nodeA = root.addChild(new TreeNode<String>("A", "1"));
		TreeNode<String> nodeAA = nodeA.addChild(new TreeNode<String>("AAX",
				"2"));
		TreeNode<String> nodeAB = nodeA
				.addChild(new TreeNode<String>("AB", "3"));
		TreeNode<String> nodeABA = nodeAB.addChild(new TreeNode<String>("ABAX",
				"4"));

		TreeNode<String> nodeB = root.addChild(new TreeNode<String>("B", "5"));
		TreeNode<String> nodeBA = nodeB
				.addChild(new TreeNode<String>("BA", "6"));
		TreeNode<String> nodeBB = nodeB.addChild(new TreeNode<String>("BBX",
				"7"));
		return root;
	}

	/**
	 * @return
	 */
	@SuppressWarnings("unchecked")
	private IContentProvider createTreeContentProvider() {
		return new ITreeContentProvider() {
			public Object[] getChildren(final Object parentElement) {
				System.out.println("getChildren");
				final TreeNode parentNode = (TreeNode) parentElement;
				if (!parentNode.isInitialized()) {
					final TreeNode temporaryNode = createTemporaryNode(parentNode);
					Future<Object[]> future = deferredNodeInitializerService
							.submit(new Callable<Object[]>() {
								public Object[] call() throws Exception {
									TreeNode[] children = computeChildrenFor(parentElement);
									exchangeChildren(parentNode, temporaryNode,
											children);
									parentNode.setInitialized(true);
									return null;
								}
							});
					return new Object[] { temporaryNode };
				} else {
					return parentNode.getChildren();
				}
			}

			public Object getParent(Object element) {
				return ((TreeNode) element).getParent();
			}

			public boolean hasChildren(Object element) {
				return ((TreeNode) element).hasChildren();
			}

			public Object[] getElements(Object inputElement) {
				return getChildren(inputElement);
			}

			public void dispose() {
				// noop
			}

			public void inputChanged(Viewer viewer, Object oldInput,
					Object newInput) {
				// noop
			}
		};
	}

	/**
	 * @param parentNode
	 * @return
	 */
	@SuppressWarnings("unchecked")
	private TreeNode createTemporaryNode(TreeNode parentNode) {
		final TreeNode temporaryNode = new TreeNode("loading...");
		temporaryNode.setData("");
		return temporaryNode;
	}

	/**
	 * @param parentElement
	 * @return
	 * @throws InterruptedException
	 */
	private TreeNode<?>[] computeChildrenFor(final Object parentElement)
			throws InterruptedException {
		TimeUnit.SECONDS.sleep((long) (Math.random() * 10));
		TreeNode<?>[] children = ((TreeNode<?>) parentElement).getChildren();
		return children;
	}

	/**
	 * @param <TTargetType>
	 * @param parentNode
	 * @param temporaryTreeNode
	 * @param childrenToBeReplaced
	 */
	private <TTargetType> void exchangeChildren(
			final TreeNode<TTargetType> parentNode,
			TreeNode<TTargetType> temporaryTreeNode,
			TreeNode<TTargetType>[] childrenToBeReplaced) {
		parentNode.clearChildren();
		parentNode.addChildren(childrenToBeReplaced);
		temporaryTreeNode.setParent(null);
		Display.getDefault().asyncExec(new Runnable() {
			public void run() {
				treeViewer.refresh();
				System.out.println("refresh " + parentNode.id);
			}
		});
	}

	/**
	 * @author Tom
	 * @param <TTargetType>
	 */
	class TreeNode<TTargetType> {
		String id;
		TTargetType data;
		List<TreeNode<TTargetType>> children;
		TreeNode<TTargetType> parent;
		boolean initialized;

		public TreeNode(String id) {
			this.id = id;
			this.children = new ArrayList<TreeNode<TTargetType>>();
		}

		public void clearChildren() {
			this.children.clear();
		}

		public TreeNode(String id, TTargetType data) {
			this(id);
			this.data = data;
		}

		public TreeNode<TTargetType> addChild(TreeNode<TTargetType> node) {
			this.children.add(node);
			node.parent = this;
			return node;
		}

		public void addChildren(TreeNode<TTargetType>[] nodes) {
			for (TreeNode<TTargetType> node : nodes) {
				addChild(node);
			}
		}

		@SuppressWarnings("unchecked")
		public TreeNode<TTargetType>[] getChildren() {
			return this.children.toArray(new TreeNode[this.children.size()]);
		}

		/**
		 * @param children
		 *            the children to set
		 */
		public void setChildren(List<TreeNode<TTargetType>> children) {
			this.children = children;
		}

		boolean hasChildren() {
			return !this.children.isEmpty();
		}

		public TreeNode<TTargetType> getParent() {
			return this.parent;
		}

		/**
		 * @param parent
		 *            the parent to set
		 */
		public void setParent(TreeNode<TTargetType> parent) {
			this.parent = parent;
		}

		/**
		 * @return the id
		 */
		public String getId() {
			return this.id;
		}

		/**
		 * @param id
		 *            the id to set
		 */
		public void setId(String id) {
			this.id = id;
		}

		public String toString() {
			return this.id + ": " + this.data;
		}

		/**
		 * @return the initialized
		 */
		public boolean isInitialized() {
			return initialized;
		}

		/**
		 * @param initialized
		 *            the initialized to set
		 */
		public void setInitialized(boolean initialized) {
			this.initialized = initialized;
		}

		/**
		 * @return the data
		 */
		public TTargetType getData() {
			return data;
		}

		/**
		 * @param data
		 *            the data to set
		 */
		public void setData(TTargetType data) {
			this.data = data;
		}

	}

	/**
	 * @param args
	 */
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		JFaceDeferredTreeInitializationExample deferredTreeInitializationExample = new JFaceDeferredTreeInitializationExample(
				new Shell());
		deferredTreeInitializationExample.open();
	}
}

Gruß Tom
 
Zurück