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