1 package org.simantics.browsing.ui.nattable;
3 import java.util.ArrayList;
4 import java.util.Collection;
5 import java.util.HashSet;
10 import org.eclipse.core.runtime.IAdaptable;
11 import org.eclipse.jface.resource.ColorDescriptor;
12 import org.eclipse.jface.resource.FontDescriptor;
13 import org.eclipse.jface.resource.ImageDescriptor;
14 import org.eclipse.nebula.widgets.nattable.style.CellStyleAttributes;
15 import org.eclipse.nebula.widgets.nattable.style.Style;
16 import org.eclipse.swt.graphics.Color;
17 import org.eclipse.swt.graphics.Font;
18 import org.eclipse.swt.graphics.Image;
19 import org.simantics.browsing.ui.BuiltinKeys;
20 import org.simantics.browsing.ui.NodeContext;
21 import org.simantics.browsing.ui.common.internal.GENodeQueryManager;
22 import org.simantics.browsing.ui.content.ImageDecorator;
23 import org.simantics.browsing.ui.content.Imager;
24 import org.simantics.browsing.ui.content.LabelDecorator;
25 import org.simantics.browsing.ui.content.Labeler;
26 import org.simantics.browsing.ui.nattable.NatTableGraphExplorer.GECache2;
27 import org.simantics.browsing.ui.nattable.NatTableGraphExplorer.GeViewerContext;
28 import org.simantics.browsing.ui.swt.ViewerRowReference;
29 import org.simantics.utils.datastructures.BijectionMap;
31 public class TreeNode implements IAdaptable {
32 private static boolean DEBUG = false;
34 private NodeContext context;
35 GENodeQueryManager manager;
36 GeViewerContext explorerContext;
39 List<TreeNode> children = new ArrayList<TreeNode>();
41 boolean autoExpanded = false;
43 public TreeNode(NodeContext context, GeViewerContext explorerContext) {
44 this.context = context;
45 this.explorerContext = explorerContext;
46 this.expanded = false;
47 manager = new GENodeQueryManager(explorerContext, null, null, ViewerRowReference.create(this));
48 explorerContext.getContextToNodeMap().add(context, this);
51 public int getDepth() {
54 return parent.getDepth() + 1;
59 public int getListIndex() {
63 public void setListIndex(int listIndex) {
64 this.listIndex = listIndex;
67 List<TreeNode> getChildren() {
71 public TreeNode getParent() {
75 public void setExpanded(boolean expanded) {
76 this.expanded = expanded;
79 public boolean isExpanded() {
83 public boolean isHidden() {
93 public TreeNode getCollapsedAncestor() {
94 TreeNode collapsed = null;
104 public NodeContext getContext() {
108 private Labeler labeler;
109 private Imager imager;
110 Collection<LabelDecorator> labelDecorators;
111 Collection<ImageDecorator> imageDecorators;
113 Map<String, String> labels;
114 Map<String, String> runtimeLabels;
116 public String getValueString(int column) {
119 if (labeler != null) {
120 String key = explorerContext.getGe().getColumns()[column].getKey();
122 if (runtimeLabels != null)
123 s = runtimeLabels.get(key);
126 if (labelDecorators != null && !labelDecorators.isEmpty()) {
128 for (LabelDecorator ld : labelDecorators) {
129 String ds = ld.decorateLabel(s, key, index);
139 public Image getImage(int column) {
140 String key = explorerContext.getGe().getColumns()[column].getKey();
141 if (imager != null) {
142 Object descOrImage = null;
143 boolean hasUncachedImages = false;
145 ImageDescriptor desc = imager.getImage(key);
148 // Attempt to decorate the label
149 if (!imageDecorators.isEmpty()) {
150 for (ImageDecorator id : imageDecorators) {
151 ImageDescriptor ds = id.decorateImage(desc, key, index);
157 // Try resolving only cached images here and now
158 Object img = explorerContext.getGe().localResourceManager.find(desc);
160 img = explorerContext.getGe().resourceManager.find(desc);
162 descOrImage = img != null ? img : desc;
163 hasUncachedImages |= img == null;
166 if (!hasUncachedImages) {
167 return (Image) descOrImage;
169 // Schedule loading to another thread to refrain from
171 // the UI with database operations.
172 explorerContext.getGe().queueImageTask(this, new ImageTask(this, descOrImage));
180 public void getStyle(int column, Style style) {
181 String key = explorerContext.getGe().getColumns()[column].getKey();
182 FontDescriptor font = explorerContext.getGe().originalFont;
183 ColorDescriptor bg = explorerContext.getGe().originalBackground;
184 ColorDescriptor fg = explorerContext.getGe().originalForeground;
186 // Attempt to decorate the label
187 if (labelDecorators != null && !labelDecorators.isEmpty()) {
189 for (LabelDecorator ld : labelDecorators) {
191 FontDescriptor dfont = ld.decorateFont(font, key, index);
195 ColorDescriptor dbg = ld.decorateBackground(bg, key, index);
199 ColorDescriptor dfg = ld.decorateForeground(fg, key, index);
205 if (font != explorerContext.getGe().originalFont) {
206 // System.out.println("set font: " + index + ": " +
208 style.setAttributeValue(CellStyleAttributes.FONT,(Font) explorerContext.getGe().localResourceManager.get(font));
210 style.setAttributeValue(CellStyleAttributes.FONT,(Font) (explorerContext.getGe().originalFont != null ? explorerContext.getGe().localResourceManager.get(explorerContext.getGe().originalFont) : null));
212 if (bg != explorerContext.getGe().originalBackground)
213 style.setAttributeValue(CellStyleAttributes.BACKGROUND_COLOR,(Color) explorerContext.getGe().localResourceManager.get(bg));
215 style.setAttributeValue(CellStyleAttributes.BACKGROUND_COLOR,(Color) (explorerContext.getGe().originalBackground != null ? explorerContext.getGe().localResourceManager.get(explorerContext.getGe().originalBackground) : null));
216 if (fg != explorerContext.getGe().originalForeground)
217 style.setAttributeValue(CellStyleAttributes.FOREGROUND_COLOR,(Color) explorerContext.getGe().localResourceManager.get(fg));
219 style.setAttributeValue(CellStyleAttributes.FOREGROUND_COLOR,(Color) (explorerContext.getGe().originalForeground != null ? explorerContext.getGe().localResourceManager.get(explorerContext.getGe().originalForeground) : null));
223 public void initData() {
224 labeler = manager.query(context, BuiltinKeys.SELECTED_LABELER);
225 imager = manager.query(context, BuiltinKeys.SELECTED_IMAGER);
226 labelDecorators = manager.query(context, BuiltinKeys.LABEL_DECORATORS);
227 imageDecorators = manager.query(context, BuiltinKeys.IMAGE_DECORATORS);
229 if (labeler != null) {
230 labels = labeler.getLabels();
231 runtimeLabels = labeler.getRuntimeLabels();
234 runtimeLabels = null;
238 public TreeNode addChild(NodeContext context, GeViewerContext explorerContext) {
239 TreeNode child = new TreeNode(context, explorerContext);
242 if (DEBUG) System.out.println("Add " + this + " -> " + child);
246 public TreeNode addChild(int index, NodeContext context,GeViewerContext explorerContext) {
248 TreeNode child = new TreeNode(context, explorerContext);
250 children.add(index,child);
251 if (DEBUG) System.out.println("Add " + this + " -> " + child + " at " + index);
255 public TreeNode setChild(int index, NodeContext context, GeViewerContext explorerContext) {
257 TreeNode child = new TreeNode(context, explorerContext);
259 children.set(index,child);
260 if (DEBUG) System.out.println("Set " + this + " -> " + child + " at " + index);
264 public void dispose() {
266 parent.children.remove(this);
270 public void dispose2() {
271 if (DEBUG) System.out.println("dispose " + this);
273 for (TreeNode n : children) {
278 explorerContext.getContextToNodeMap().remove(context, this);
280 explorerContext = null;
285 private void clearCache() {
286 if (explorerContext != null) {
287 GECache2 cache = explorerContext.cache;
290 cache.dispose(context);
295 public boolean updateChildren() {
297 throw new IllegalStateException("Node is disposed.");
299 NodeContext[] childContexts = manager.query(context, BuiltinKeys.FINAL_CHILDREN);
301 if (DEBUG) System.out.println("updateChildren " + childContexts.length + " " + this);
304 boolean modified = false;
305 synchronized (children) {
307 int oldCount = children.size();
308 BijectionMap<Integer, Integer> indexes = new BijectionMap<Integer, Integer>();
309 Set<Integer> mapped = new HashSet<Integer>();
310 boolean reorder = false;
311 // locate matching pairs form old and new children
312 for (int i = 0; i < oldCount; i++) {
313 NodeContext oldCtx = children.get(i).context;
314 for (int j = 0; j <childContexts.length; j++) {
315 if (mapped.contains(j))
317 if (oldCtx.equals(childContexts[j])) {
326 // update children if required
327 if (childContexts.length != oldCount || reorder || childContexts.length != indexes.size()) {
329 List<TreeNode> oldChildren = new ArrayList<TreeNode>(oldCount);
330 oldChildren.addAll(children);
331 if (childContexts.length >= oldCount) {
332 for (int i = 0; i < oldCount; i++) {
333 Integer oldIndex = indexes.getLeft(i);
334 if (oldIndex == null) {
335 setChild(i, childContexts[i], explorerContext);
337 TreeNode n = oldChildren.get(oldIndex);
342 for (int i = oldCount; i < childContexts.length; i++) {
343 Integer oldIndex = indexes.getLeft(i);
344 if (oldIndex == null) {
345 addChild(childContexts[i], explorerContext);
347 TreeNode n = oldChildren.get(oldIndex);
352 for (int i = 0; i < childContexts.length; i++) {
353 Integer oldIndex = indexes.getLeft(i);
354 if (oldIndex == null) {
355 setChild(i, childContexts[i], explorerContext);
357 TreeNode n = oldChildren.get(oldIndex);
361 for (int i = oldCount -1; i >= childContexts.length; i--) {
365 for (int i = 0; i < oldChildren.size(); i++) {
366 if (!indexes.containsLeft(i)) {
367 oldChildren.get(i).dispose2();
377 public boolean isDisposed() {
378 return context == null;
381 public GENodeQueryManager getManager() {
385 @SuppressWarnings("rawtypes")
387 public Object getAdapter(Class adapter) {
388 if (adapter == NodeContext.class)
391 return context.getAdapter(adapter);
395 public String toString() {
396 return "TreeNode: " + listIndex + " " + (expanded ? "(+)" : "(-)") + " " + context ;