source: java/main/src/main/java/com/framsticks/gui/TreeNode.java @ 77

Last change on this file since 77 was 77, checked in by psniegowski, 11 years ago

Add new java codebase.

File size: 17.4 KB
Line 
1package com.framsticks.gui;
2
3import com.framsticks.communication.Subscription;
4import com.framsticks.communication.util.LoggingStateCallback;
5import com.framsticks.core.ListChange;
6import com.framsticks.core.Path;
7import com.framsticks.gui.components.ValueControl;
8import com.framsticks.gui.view.TreeCellRenderer;
9import com.framsticks.params.AccessInterface;
10import com.framsticks.params.Param;
11import com.framsticks.params.types.*;
12import com.framsticks.remote.*;
13import com.framsticks.util.Casting;
14import com.framsticks.util.Future;
15import com.framsticks.util.Logging;
16import com.framsticks.util.StateFunctor;
17import org.apache.log4j.Logger;
18
19import javax.swing.tree.DefaultMutableTreeNode;
20import javax.swing.tree.TreePath;
21import java.util.HashMap;
22import java.util.LinkedList;
23import java.util.List;
24import java.util.Map;
25
26/**
27 * @author Piotr Sniegowski
28 */
29public class TreeNode extends DefaultMutableTreeNode implements NodeListener {
30
31        private static final Logger LOGGER = Logger.getLogger(TreeNode.class.getName());
32
33        Panel panel;
34
35        final protected Frame frame;
36    final protected EndpointAtFrame endpoint;
37
38    final protected Map<EventParam, Subscription> userSubscriptions = new HashMap<EventParam, Subscription>();
39        protected Map<ValueControl, Object> changedValues = null;
40    protected String tooltip;
41    protected String name;
42    protected String iconName;
43    protected Path path;
44
45
46    public TreeNode(Frame frame, EndpointAtFrame endpoint, final Path path) {
47        assert frame.isActive();
48        this.frame = frame;
49                LOGGER.debug("creating treenode for: " + path);
50        this.path = path;
51        this.endpoint = endpoint;
52
53        name = path.getTop().getParam().getId();
54        iconName = TreeCellRenderer.findIconName(name, path.getTextual());
55        tooltip = "?";
56        path.getInstance().invokeLater(new Runnable() {
57            @Override
58            public void run() {
59                updateDescriptions(path);
60            }
61        });
62        }
63
64    public void fetch(final Path p) {
65        assert p.getInstance().isActive();
66        LOGGER.debug("fetching: " + p);
67        p.getInstance().fetchValues(p, new StateFunctor() {
68            @Override
69            public void call(Exception e) {
70                assert p.getInstance().isActive();
71                if (Logging.log(LOGGER, "fetch", TreeNode.this, e)) {
72                    frame.invokeLater(new Runnable() {
73                        @Override
74                        public void run() {
75                            LOGGER.debug("removing node from tree: " + p);
76                            TreeNode.this.removeFromParent();
77                            frame.repaintTree();
78                        }
79                    });
80                    return;
81                }
82                updateChildren(p);
83                frame.invokeLater(new Runnable() {
84                    @Override
85                    public void run() {
86                        //TODO maybe this should be called from some better place
87                        useOrCreatePanel();
88                    }
89                });
90
91            }
92        });
93    }
94
95    protected void postUpdatePath(final Path newPath) {
96        assert !frame.isActive();
97        /** TODO those two actions could be merged into single closure */
98        frame.invokeLater(new Runnable() {
99            @Override
100            public void run() {
101                updatePath(newPath);
102            }
103        });
104        updateDescriptions(newPath);
105    }
106
107    protected void updatePath(Path newPath) {
108        assert frame.isActive();
109        if (!path.isResolved()) {
110            path = newPath;
111                        LOGGER.debug("updated treenode's path: " + path);
112            return;
113        }
114        if (path.matches(newPath)) {
115            return;
116        }
117        this.removeAllChildren();
118    }
119
120    /** Update children, by removing non existing and adding new ones.
121     */
122    protected void updateChildren(final Path p) {
123        assert p.getInstance().isActive();
124        LOGGER.debug("updating children of " + this);
125        AccessInterface access = p.getInstance().bindAccess(p.getTop());
126        final List<Path> childrenPaths = new LinkedList<Path>();
127        /**Prepare path for each child.*/
128        for (Param param : access.getParams()) {
129            if (!(param instanceof CompositeParam)) {
130                continue;
131            }
132            Path childPath = p.appendParam((CompositeParam)param);
133            childrenPaths.add(childPath);
134        }
135        /**If some child were found, update in frame context.*/
136        if (childrenPaths.size() > 0) {
137            frame.invokeLater(new Runnable() {
138                @Override
139                public void run() {
140                    TreePath treePath = frame.startChange();
141                    updatePath(p);
142                    Map<String, TreeNode> current = new HashMap<String, TreeNode>();
143                    for (int c = 0; c < TreeNode.this.getChildCount(); ++c) {
144                        TreeNode n = (TreeNode)TreeNode.this.getChildAt(c);
145                        current.put(n.path.getLastElement(), n);
146                    }
147                    for (final Path childPath : childrenPaths) {
148                        String e = childPath.getLastElement();
149                        if (current.containsKey(e)) {
150                            /*
151                            final TreeNode n = current.get(e);
152                            childPath.getInstance().invokeLater(new Runnable() {
153                                @Override
154                                public void run() {
155                                    n.updateChildren(childPath);
156                                }
157                            });
158                            */
159                            current.remove(e);
160                            continue;
161                        }
162                        TreeNode childNode = new TreeNode(frame, endpoint, childPath);
163                        TreeNode.this.add(childNode);
164                    }
165                    for (TreeNode n : current.values()) {
166                        TreeNode.this.remove(n);
167                    }
168                    frame.markNodeChanged(TreeNode.this, treePath);
169                    frame.repaintTree();
170                    LOGGER.debug("updated children of " + TreeNode.this);
171                }
172            });
173        } else {
174            LOGGER.debug("no children in " + TreeNode.this);
175        }
176    }
177
178    public void select() {
179        final Path p = path;
180
181        p.getInstance().invokeLater(new Runnable() {
182            @Override
183            public void run() {
184                final Path updated = (p.isResolved()) ? p : p.findResolution();
185                if (updated.isResolved()) {
186                    Logging.log(LOGGER, "update", updated, null);
187                    fetch(updated);
188                    postUpdatePath(updated);
189                    return;
190                }
191                p.getInstance().resolve(updated, new Future<Path>() {
192                    @Override
193                    public void result(final Path result, Exception e) {
194                        if (Logging.log(LOGGER, "resolve and select", TreeNode.this, e)) {
195                            return;
196                        }
197
198                        fetch(result);
199                        postUpdatePath(result);
200                    }
201                });
202            }
203        });
204
205    }
206
207    @Override
208    public String toString() {
209        return path.toString();
210    }
211
212
213        public final Panel getPanel() {
214        assert frame.isActive();
215                return panel;
216        }
217
218    protected void updateDescriptions(final Path p) {
219        assert p.getInstance().isActive();
220        if (!p.isResolved()) {
221            return;
222        }
223        AccessInterface access = p.getInstance().bindAccess(p);
224        assert access != null;
225        StringBuilder t = new StringBuilder();
226        /** html formatting is used here, since tooltips in swing do not support simple \n line breaks */
227        t.append("<html>");
228        t.append("frams: ").append(access.getId()).append("<br/>");
229        t.append("java: ").append(p.getTopObject().getClass().getCanonicalName()).append("<br/>");
230        t.append("access: ").append(access.getClass().getSimpleName());
231        t.append("</html>");
232        final String tooltip = t.toString();
233
234        StringParam nameParam = Casting.tryCast(StringParam.class, access.getParam("name"));
235        final String name = (nameParam != null ? access.get(nameParam, String.class) : path.getTop().getParam().getId());
236
237        frame.invokeLater(new Runnable() {
238            @Override
239            public void run() {
240
241                TreeNode.this.tooltip = tooltip;
242                TreeNode.this.name = name;
243            }
244        });
245    }
246
247/*
248        public void updateData() {
249        assert browser.isActive();
250                final Node node = getNode();
251        browser.manager.invokeLater(new Runnable() {
252            @Override
253            public void run() {
254                node.fetchValues(new StateFunctor() {
255                    @Override
256                    public void call(Exception e) {
257                        if (e != null) {
258                            return;
259                        }
260                        browser.invokeLater(new Runnable() {
261                            @Override
262                            public void run() {
263                                assert browser.isActive();
264                                if (panel.getCurrentTreeNode() == TreeNode.this) {
265                                    panel.refreshComponents();
266                                }
267
268                                browser.tree.repaint();
269                                panel.refreshComponents();
270                            }
271                        });
272                    }
273                });
274            }
275        });
276        }
277*/
278
279    public void showPanel() {
280        assert frame.isActive();
281        assert panel != null;
282        frame.showPanel(panel);
283    }
284
285    public void fillPanelWithValues() {
286        assert frame.isActive();
287        final Path p = path;
288        assert p.isResolved();
289        assert panel != null;
290        panel.setCurrentTreeNode(this);
291        p.getInstance().invokeLater(new Runnable() {
292            @Override
293            public void run() {
294                AccessInterface access = p.getInstance().bindAccess(p);
295                panel.refreshComponents(access);
296
297                frame.invokeLater(new Runnable() {
298                    @Override
299                    public void run() {
300                        showPanel();
301                    }
302                });
303            }
304        });
305
306    }
307
308        public void useOrCreatePanel() {
309        assert frame.isActive();
310                if (panel != null) {
311            LOGGER.trace("panel is already attached: " + path);
312            fillPanelWithValues();
313                        return;
314                }
315        if (!path.isResolved()) {
316            LOGGER.trace("path is not resolved: " + path);
317            return;
318        }
319
320        CompositeParam param = path.getTop().getParam();
321        panel = endpoint.findPanel(param.computeAccessId());
322        if (panel != null) {
323            LOGGER.debug("found prepared panel for: " + path);
324            fillPanelWithValues();
325            return;
326        }
327        final Path p = path;
328        LOGGER.debug("preparing panel: " + p);
329        p.getInstance().invokeLater(new Runnable() {
330            @Override
331            public void run() {
332                assert p.getInstance().isActive();
333                final CompositeParam param = p.getTop().getParam();
334                if (param instanceof ObjectParam) {
335                    AccessInterface access = p.getInstance().prepareAccess(param);
336                    final List<Param> params = new LinkedList<Param>();
337                    for (Param p : access.getParams()) {
338                        if (p instanceof CompositeParam) {
339                            continue;
340                        }
341                        params.add(p);
342                    }
343                    frame.invokeLater(new Runnable() {
344                        @Override
345                        public void run() {
346                            panel = new ObjectPanel(endpoint, param.getContainedTypeName(), params);
347                            fillPanelWithValues();
348                        }
349                    });
350                    return;
351                }
352                if (param instanceof ListParam) {
353                                        frame.invokeLater(new Runnable() {
354                                                @Override
355                                                public void run() {
356                                                        panel = new ListPanel(endpoint);
357                                                        fillPanelWithValues();
358                                                }
359                                        });
360                                        return;
361                    //return panel = new ListPanel(browser, access);
362                }
363                assert false;
364            }
365        });
366        }
367
368    public String getTooltip() {
369        assert frame.isActive();
370        return tooltip;
371    }
372
373
374
375
376    /*public void subscribe(final EventParam eventParam) {
377        assert browser.isActive();
378        if (hasSubscribed(eventParam)) {
379            LOGGER.error(eventParam + " is already subscribed for " + this);
380            return;
381        }
382        Node node = getNode();
383        node.getConnection().subscribe(node.getPath() + "/" + eventParam.getId(), new SubscriptionCallback() {
384            @Override
385            public EventCallback subscribed(final Subscription subscription) {
386                if (subscription == null) {
387                    LOGGER.error("subscription failed");
388                    return null;
389                }
390                if (hasSubscribed(eventParam)) {
391                    //abort subscription
392                    return null;
393                }
394                userSubscriptions.put(eventParam, subscription);
395                LOGGER.debug("subscription succeeded: " + subscription);
396                subscription.setDispatcher(browser);
397                return new EventCallback() {
398                    @Override
399                    public void call(SourceInterface content) {
400                        assert browser.isActive();
401                        LOGGER.info("event " + subscription + " occurred");
402                    }
403                };
404            }
405        });
406
407    }*/
408
409    public boolean hasSubscribed(EventParam param) {
410        assert frame.isActive();
411        return userSubscriptions.containsKey(param);
412    }
413
414    public void unsubscribe(EventParam eventParam) {
415        assert frame.isActive();
416        if (!hasSubscribed(eventParam)) {
417            LOGGER.error("could not unsubscribe from " + eventParam);
418            return;
419        }
420        userSubscriptions.get(eventParam).unsubscribe(new LoggingStateCallback(LOGGER, "unsubscribed " + eventParam));
421        userSubscriptions.remove(eventParam);
422    }
423
424/*
425
426    @Override
427    public void onChildChange(final Child child, ListChange.Action action) {
428        assert browser.manager.isActive();
429
430        switch (action) {
431            case Remove: {
432                Dispatching.invokeDispatch(browser, browser.manager, new Runnable() {
433                    @Override
434                    public void run() {
435                        assert browser.manager.isActive();
436                        final TreeNode treeNode = (TreeNode) child.getUserObject();
437                        if (treeNode == null) {
438                            LOGGER.error("child " + child + " had no tree node attached");
439                            return;
440                        }
441                        browser.invokeLater(new Runnable() {
442                            @Override
443                            public void run() {
444                                assert browser.isActive();
445                                TreePath path = browser.startChange();
446                                //assert treeNode.getParent() == TreeNode.this;
447                                if (treeNode.getParent() != null) {
448                                    browser.treeModel.removeNodeFromParent(treeNode);
449                                }
450                                //remove(treeNode);
451                                browser.markNodeChanged(TreeNode.this, path);
452                            }
453                        });
454                    }
455                });
456                break;
457            }
458        }
459
460    }
461*/
462
463    public String getName() {
464        return name;
465    }
466
467    public String getIconName() {
468        return iconName;
469    }
470
471    @Override
472    public void onUpgrade(Path path) {
473    }
474
475    @Override
476    public void onChange(Path path) {
477    }
478
479    @Override
480    public void onChildChange(Path path, ListChange.Action action) {
481    }
482
483    public final Frame getFrame() {
484        return frame;
485    }
486
487        public boolean changeValue(ValueControl component, Object newValue) {
488                LOGGER.debug("changing value of " + component + " to '" + newValue + "'");
489
490                if (changedValues == null) {
491                        changedValues = new HashMap<ValueControl, Object>();
492                }
493                changedValues.put(component, newValue);
494
495                return true;
496        }
497
498        public void applyChanges() {
499                assert frame.isActive();
500                if (changedValues == null) {
501                        return;
502                }
503                final Map<ValueControl, Object> changes = changedValues;
504                changedValues = null;
505                endpoint.getEndpoint().invokeLater(new Runnable() {
506                        @Override
507                        public void run() {
508                                for (Map.Entry<ValueControl, Object> e : changes.entrySet()) {
509                                        final ValueControl key = e.getKey();
510                                        final Path p = path;
511                                        endpoint.getEndpoint().getInstance().storeValue(p, e.getKey().getParam(), e.getValue(), new StateFunctor() {
512                                                @Override
513                                                public void call(Exception e) {
514                                                        changes.remove(key);
515                                                        if (!changes.isEmpty()) {
516                                                                return;
517                                                        }
518                                                        LOGGER.debug("applied changes for: " + p);
519                                                        frame.invokeLater(new Runnable() {
520                                                                @Override
521                                                                public void run() {
522                                                                        fillPanelWithValues();
523                                                                }
524                                                        });
525                                                }
526                                        });
527                                }
528                        }
529                });
530        }
531
532}
Note: See TracBrowser for help on using the repository browser.