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
42 public TreeNode(NodeContext context, GeViewerContext explorerContext) {
\r
43 this.context = context;
\r
44 this.explorerContext = explorerContext;
\r
45 this.expanded = false;
\r
46 manager = new GENodeQueryManager(explorerContext, null, null, ViewerRowReference.create(this));
\r
47 explorerContext.getContextToNodeMap().add(context, this);
\r
53 return parent.getDepth() + 1;
\r
58 public int getListIndex() {
\r
62 public void setListIndex(int listIndex) {
\r
63 this.listIndex = listIndex;
\r
66 List<TreeNode> getChildren() {
\r
70 public TreeNode getParent() {
\r
74 public void setExpanded(boolean expanded) {
\r
75 this.expanded = expanded;
\r
78 public boolean isExpanded() {
\r
82 public NodeContext getContext() {
\r
86 private Labeler labeler;
\r
87 private Imager imager;
\r
88 Collection<LabelDecorator> labelDecorators;
\r
89 Collection<ImageDecorator> imageDecorators;
\r
91 Map<String, String> labels;
\r
92 Map<String, String> runtimeLabels;
\r
94 public String getValueString(int column) {
\r
98 if (labeler != null) {
\r
99 String key = explorerContext.getGe().getColumns()[column].getKey();
\r
101 if (runtimeLabels != null)
\r
102 s = runtimeLabels.get(key);
\r
104 s = labels.get(key);
\r
105 if (labelDecorators != null && !labelDecorators.isEmpty()) {
\r
107 for (LabelDecorator ld : labelDecorators) {
\r
108 String ds = ld.decorateLabel(s, key, index);
\r
118 public Image getImage(int column) {
\r
119 String key = explorerContext.getGe().getColumns()[column].getKey();
\r
120 if (imager != null) {
\r
121 Object descOrImage = null;
\r
122 boolean hasUncachedImages = false;
\r
124 ImageDescriptor desc = imager.getImage(key);
\r
125 if (desc != null) {
\r
127 // Attempt to decorate the label
\r
128 if (!imageDecorators.isEmpty()) {
\r
129 for (ImageDecorator id : imageDecorators) {
\r
130 ImageDescriptor ds = id.decorateImage(desc, key, index);
\r
136 // Try resolving only cached images here and now
\r
137 Object img = explorerContext.getGe().localResourceManager.find(desc);
\r
139 img = explorerContext.getGe().resourceManager.find(desc);
\r
141 descOrImage = img != null ? img : desc;
\r
142 hasUncachedImages |= img == null;
\r
145 if (!hasUncachedImages) {
\r
146 return (Image) descOrImage;
\r
148 // Schedule loading to another thread to refrain from
\r
150 // the UI with database operations.
\r
151 explorerContext.getGe().queueImageTask(this, new ImageTask(this, descOrImage));
\r
159 public void getStyle(int column, Style style) {
\r
160 String key = explorerContext.getGe().getColumns()[column].getKey();
\r
161 FontDescriptor font = explorerContext.getGe().originalFont;
\r
162 ColorDescriptor bg = explorerContext.getGe().originalBackground;
\r
163 ColorDescriptor fg = explorerContext.getGe().originalForeground;
\r
165 // Attempt to decorate the label
\r
166 if (labelDecorators != null && !labelDecorators.isEmpty()) {
\r
168 for (LabelDecorator ld : labelDecorators) {
\r
170 FontDescriptor dfont = ld.decorateFont(font, key, index);
\r
174 ColorDescriptor dbg = ld.decorateBackground(bg, key, index);
\r
178 ColorDescriptor dfg = ld.decorateForeground(fg, key, index);
\r
184 if (font != explorerContext.getGe().originalFont) {
\r
185 // System.out.println("set font: " + index + ": " +
\r
187 style.setAttributeValue(CellStyleAttributes.FONT,(Font) explorerContext.getGe().localResourceManager.get(font));
\r
189 style.setAttributeValue(CellStyleAttributes.FONT,(Font) (explorerContext.getGe().originalFont != null ? explorerContext.getGe().localResourceManager.get(explorerContext.getGe().originalFont) : null));
\r
191 if (bg != explorerContext.getGe().originalBackground)
\r
192 style.setAttributeValue(CellStyleAttributes.BACKGROUND_COLOR,(Color) explorerContext.getGe().localResourceManager.get(bg));
\r
194 style.setAttributeValue(CellStyleAttributes.BACKGROUND_COLOR,(Color) (explorerContext.getGe().originalBackground != null ? explorerContext.getGe().localResourceManager.get(explorerContext.getGe().originalBackground) : null));
\r
195 if (fg != explorerContext.getGe().originalForeground)
\r
196 style.setAttributeValue(CellStyleAttributes.FOREGROUND_COLOR,(Color) explorerContext.getGe().localResourceManager.get(fg));
\r
198 style.setAttributeValue(CellStyleAttributes.FOREGROUND_COLOR,(Color) (explorerContext.getGe().originalForeground != null ? explorerContext.getGe().localResourceManager.get(explorerContext.getGe().originalForeground) : null));
\r
202 private void initData() {
\r
203 labeler = manager.query(context, BuiltinKeys.SELECTED_LABELER);
\r
204 imager = manager.query(context, BuiltinKeys.SELECTED_IMAGER);
\r
205 labelDecorators = manager.query(context, BuiltinKeys.LABEL_DECORATORS);
\r
206 imageDecorators = manager.query(context, BuiltinKeys.IMAGE_DECORATORS);
\r
208 if (labeler != null) {
\r
209 labels = labeler.getLabels();
\r
210 runtimeLabels = labeler.getRuntimeLabels();
\r
213 runtimeLabels = null;
\r
217 public TreeNode addChild(NodeContext context, GeViewerContext explorerContext) {
\r
218 TreeNode child = new TreeNode(context, explorerContext);
\r
219 child.parent = this;
\r
220 children.add(child);
\r
221 if (DEBUG) System.out.println("Add " + this + " -> " + child);
\r
225 public TreeNode addChild(int index, NodeContext context,GeViewerContext explorerContext) {
\r
227 TreeNode child = new TreeNode(context, explorerContext);
\r
228 child.parent = this;
\r
229 children.add(index,child);
\r
230 if (DEBUG) System.out.println("Add " + this + " -> " + child + " at " + index);
\r
234 public TreeNode setChild(int index, NodeContext context, GeViewerContext explorerContext) {
\r
236 TreeNode child = new TreeNode(context, explorerContext);
\r
237 child.parent = this;
\r
238 children.set(index,child);
\r
239 if (DEBUG) System.out.println("Set " + this + " -> " + child + " at " + index);
\r
243 public void dispose() {
\r
244 if (parent != null)
\r
245 parent.children.remove(this);
\r
249 public void dispose2() {
\r
250 if (DEBUG) System.out.println("dispose " + this);
\r
252 for (TreeNode n : children) {
\r
257 explorerContext.getContextToNodeMap().remove(context, this);
\r
259 explorerContext = null;
\r
264 private void clearCache() {
\r
265 if (explorerContext != null) {
\r
266 GECache2 cache = explorerContext.cache;
\r
268 if (cache != null) {
\r
269 cache.dispose(context);
\r
274 public boolean updateChildren() {
\r
275 if (context == null)
\r
276 throw new IllegalStateException("Node is disposed.");
\r
278 NodeContext[] childContexts = manager.query(context, BuiltinKeys.FINAL_CHILDREN);
\r
280 if (DEBUG) System.out.println("updateChildren " + childContexts.length + " " + this);
\r
283 boolean modified = false;
\r
284 synchronized (children) {
\r
286 int oldCount = children.size();
\r
287 BijectionMap<Integer, Integer> indexes = new BijectionMap<Integer, Integer>();
\r
288 Set<Integer> mapped = new HashSet<Integer>();
\r
289 boolean reorder = false;
\r
290 // locate matching pairs form old and new children
\r
291 for (int i = 0; i < oldCount; i++) {
\r
292 NodeContext oldCtx = children.get(i).context;
\r
293 for (int j = 0; j <childContexts.length; j++) {
\r
294 if (mapped.contains(j))
\r
296 if (oldCtx.equals(childContexts[j])) {
\r
305 // update children if required
\r
306 if (childContexts.length != oldCount || reorder || childContexts.length != indexes.size()) {
\r
308 List<TreeNode> oldChildren = new ArrayList<TreeNode>(oldCount);
\r
309 oldChildren.addAll(children);
\r
310 if (childContexts.length >= oldCount) {
\r
311 for (int i = 0; i < oldCount; i++) {
\r
312 Integer oldIndex = indexes.getLeft(i);
\r
313 if (oldIndex == null) {
\r
314 setChild(i, childContexts[i], explorerContext);
\r
316 TreeNode n = oldChildren.get(oldIndex);
\r
317 children.set(i, n);
\r
321 for (int i = oldCount; i < childContexts.length; i++) {
\r
322 addChild(childContexts[i], explorerContext);
\r
325 for (int i = 0; i < childContexts.length; i++) {
\r
326 Integer oldIndex = indexes.getLeft(i);
\r
327 if (oldIndex == null) {
\r
328 setChild(i, childContexts[i], explorerContext);
\r
330 TreeNode n = oldChildren.get(oldIndex);
\r
331 children.set(i, n);
\r
334 for (int i = oldCount -1; i >= childContexts.length; i--) {
\r
335 children.remove(i);
\r
338 for (int i = 0; i < oldChildren.size(); i++) {
\r
339 if (!indexes.containsLeft(i)) {
\r
340 oldChildren.get(i).dispose2();
\r
350 public boolean isDisposed() {
\r
351 return context == null;
\r
354 public GENodeQueryManager getManager() {
\r
358 @SuppressWarnings("rawtypes")
\r
360 public Object getAdapter(Class adapter) {
\r
361 if (adapter == NodeContext.class)
\r
364 return context.getAdapter(adapter);
\r