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

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

Add f0 parsing and f0->Model transformation.

File size: 17.6 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                if (access == null) {
127                        return;
128                }
129        final List<Path> childrenPaths = new LinkedList<Path>();
130        /**Prepare path for each child.*/
131        for (Param param : access.getParams()) {
132            if (!(param instanceof CompositeParam)) {
133                continue;
134            }
135            Path childPath = p.appendParam((CompositeParam)param);
136            childrenPaths.add(childPath);
137        }
138        /**If some child were found, update in frame context.*/
139        if (childrenPaths.size() > 0) {
140            frame.invokeLater(new Runnable() {
141                @Override
142                public void run() {
143                    TreePath treePath = frame.startChange();
144                    updatePath(p);
145                    Map<String, TreeNode> current = new HashMap<String, TreeNode>();
146                    for (int c = 0; c < TreeNode.this.getChildCount(); ++c) {
147                        TreeNode n = (TreeNode)TreeNode.this.getChildAt(c);
148                        current.put(n.path.getLastElement(), n);
149                    }
150                    for (final Path childPath : childrenPaths) {
151                        String e = childPath.getLastElement();
152                        if (current.containsKey(e)) {
153                            /*
154                            final TreeNode n = current.get(e);
155                            childPath.getInstance().invokeLater(new Runnable() {
156                                @Override
157                                public void run() {
158                                    n.updateChildren(childPath);
159                                }
160                            });
161                            */
162                            current.remove(e);
163                            continue;
164                        }
165                        TreeNode childNode = new TreeNode(frame, endpoint, childPath);
166                        TreeNode.this.add(childNode);
167                    }
168                    for (TreeNode n : current.values()) {
169                        TreeNode.this.remove(n);
170                    }
171                    frame.markNodeChanged(TreeNode.this, treePath);
172                    frame.repaintTree();
173                    LOGGER.debug("updated children of " + TreeNode.this);
174                }
175            });
176        } else {
177            LOGGER.debug("no children in " + TreeNode.this);
178        }
179    }
180
181    public void select() {
182        final Path p = path;
183
184        p.getInstance().invokeLater(new Runnable() {
185            @Override
186            public void run() {
187                final Path updated = (p.isResolved()) ? p : p.findResolution();
188                if (updated.isResolved()) {
189                    Logging.log(LOGGER, "update", updated, null);
190                    fetch(updated);
191                    postUpdatePath(updated);
192                    return;
193                }
194                p.getInstance().resolve(updated, new Future<Path>() {
195                    @Override
196                    public void result(final Path result, Exception e) {
197                        if (Logging.log(LOGGER, "resolve and select", TreeNode.this, e)) {
198                            return;
199                        }
200
201                        fetch(result);
202                        postUpdatePath(result);
203                    }
204                });
205            }
206        });
207
208    }
209
210    @Override
211    public String toString() {
212        return path.toString();
213    }
214
215        public final Panel getPanel() {
216        assert frame.isActive();
217                return panel;
218        }
219
220    protected void updateDescriptions(final Path p) {
221        assert p.getInstance().isActive();
222        if (!p.isResolved()) {
223            return;
224        }
225        AccessInterface access = p.getInstance().bindAccess(p);
226                if (access == null) {
227                        return;
228                }
229        StringBuilder t = new StringBuilder();
230        /** html formatting is used here, since tooltips in swing do not support simple \n line breaks */
231        t.append("<html>");
232        t.append("frams: ").append(access.getId()).append("<br/>");
233        t.append("java: ").append(p.getTopObject().getClass().getCanonicalName()).append("<br/>");
234        t.append("access: ").append(access.getClass().getSimpleName());
235        t.append("</html>");
236        final String tooltip = t.toString();
237
238        StringParam nameParam = Casting.tryCast(StringParam.class, access.getParam("name"));
239        final String name = (nameParam != null ? access.get(nameParam, String.class) : path.getTop().getParam().getId());
240
241        frame.invokeLater(new Runnable() {
242            @Override
243            public void run() {
244
245                TreeNode.this.tooltip = tooltip;
246                TreeNode.this.name = name;
247            }
248        });
249    }
250
251/*
252        public void updateData() {
253        assert browser.isActive();
254                final Node node = getNode();
255        browser.manager.invokeLater(new Runnable() {
256            @Override
257            public void run() {
258                node.fetchValues(new StateFunctor() {
259                    @Override
260                    public void call(Exception e) {
261                        if (e != null) {
262                            return;
263                        }
264                        browser.invokeLater(new Runnable() {
265                            @Override
266                            public void run() {
267                                assert browser.isActive();
268                                if (panel.getCurrentTreeNode() == TreeNode.this) {
269                                    panel.refreshComponents();
270                                }
271
272                                browser.tree.repaint();
273                                panel.refreshComponents();
274                            }
275                        });
276                    }
277                });
278            }
279        });
280        }
281*/
282
283    public void showPanel() {
284        assert frame.isActive();
285        assert panel != null;
286        frame.showPanel(panel);
287    }
288
289    public void fillPanelWithValues() {
290        assert frame.isActive();
291        final Path p = path;
292        assert p.isResolved();
293        assert panel != null;
294        panel.setCurrentTreeNode(this);
295        p.getInstance().invokeLater(new Runnable() {
296            @Override
297            public void run() {
298                AccessInterface access = p.getInstance().bindAccess(p);
299                panel.refreshComponents(access);
300
301                frame.invokeLater(new Runnable() {
302                    @Override
303                    public void run() {
304                        showPanel();
305                    }
306                });
307            }
308        });
309
310    }
311
312        public void useOrCreatePanel() {
313        assert frame.isActive();
314                if (panel != null) {
315            LOGGER.trace("panel is already attached: " + path);
316            fillPanelWithValues();
317                        return;
318                }
319        if (!path.isResolved()) {
320            LOGGER.trace("path is not resolved: " + path);
321            return;
322        }
323
324        CompositeParam param = path.getTop().getParam();
325        panel = endpoint.findPanel(param.computeAccessId());
326        if (panel != null) {
327            LOGGER.debug("found prepared panel for: " + path);
328            fillPanelWithValues();
329            return;
330        }
331        final Path p = path;
332        LOGGER.debug("preparing panel: " + p);
333        p.getInstance().invokeLater(new Runnable() {
334            @Override
335            public void run() {
336                assert p.getInstance().isActive();
337                final CompositeParam param = p.getTop().getParam();
338                if (param instanceof ObjectParam) {
339                    AccessInterface access = p.getInstance().prepareAccess(param);
340                    final List<Param> params = new LinkedList<Param>();
341                    for (Param p : access.getParams()) {
342                        if (p instanceof CompositeParam) {
343                            continue;
344                        }
345                        params.add(p);
346                    }
347                    frame.invokeLater(new Runnable() {
348                        @Override
349                        public void run() {
350                            panel = new ObjectPanel(endpoint, param.getContainedTypeName(), params);
351                            fillPanelWithValues();
352                        }
353                    });
354                    return;
355                }
356                if (param instanceof ListParam) {
357                                        frame.invokeLater(new Runnable() {
358                                                @Override
359                                                public void run() {
360                                                        panel = new ListPanel(endpoint);
361                                                        fillPanelWithValues();
362                                                }
363                                        });
364                                        return;
365                    //return panel = new ListPanel(browser, access);
366                }
367                assert false;
368            }
369        });
370        }
371
372    public String getTooltip() {
373        assert frame.isActive();
374        return tooltip;
375    }
376
377
378
379
380    /*public void subscribe(final EventParam eventParam) {
381        assert browser.isActive();
382        if (hasSubscribed(eventParam)) {
383            LOGGER.error(eventParam + " is already subscribed for " + this);
384            return;
385        }
386        Node node = getNode();
387        node.getConnection().subscribe(node.getPath() + "/" + eventParam.getId(), new SubscriptionCallback() {
388            @Override
389            public EventCallback subscribed(final Subscription subscription) {
390                if (subscription == null) {
391                    LOGGER.error("subscription failed");
392                    return null;
393                }
394                if (hasSubscribed(eventParam)) {
395                    //abort subscription
396                    return null;
397                }
398                userSubscriptions.put(eventParam, subscription);
399                LOGGER.debug("subscription succeeded: " + subscription);
400                subscription.setDispatcher(browser);
401                return new EventCallback() {
402                    @Override
403                    public void call(SourceInterface content) {
404                        assert browser.isActive();
405                        LOGGER.info("event " + subscription + " occurred");
406                    }
407                };
408            }
409        });
410
411    }*/
412
413    public boolean hasSubscribed(EventParam param) {
414        assert frame.isActive();
415        return userSubscriptions.containsKey(param);
416    }
417
418    public void unsubscribe(EventParam eventParam) {
419        assert frame.isActive();
420        if (!hasSubscribed(eventParam)) {
421            LOGGER.error("could not unsubscribe from " + eventParam);
422            return;
423        }
424        userSubscriptions.get(eventParam).unsubscribe(new LoggingStateCallback(LOGGER, "unsubscribed " + eventParam));
425        userSubscriptions.remove(eventParam);
426    }
427
428/*
429
430    @Override
431    public void onChildChange(final Child child, ListChange.Action action) {
432        assert browser.manager.isActive();
433
434        switch (action) {
435            case Remove: {
436                Dispatching.invokeDispatch(browser, browser.manager, new Runnable() {
437                    @Override
438                    public void run() {
439                        assert browser.manager.isActive();
440                        final TreeNode treeNode = (TreeNode) child.getUserObject();
441                        if (treeNode == null) {
442                            LOGGER.error("child " + child + " had no tree node attached");
443                            return;
444                        }
445                        browser.invokeLater(new Runnable() {
446                            @Override
447                            public void run() {
448                                assert browser.isActive();
449                                TreePath path = browser.startChange();
450                                //assert treeNode.getParent() == TreeNode.this;
451                                if (treeNode.getParent() != null) {
452                                    browser.treeModel.removeNodeFromParent(treeNode);
453                                }
454                                //remove(treeNode);
455                                browser.markNodeChanged(TreeNode.this, path);
456                            }
457                        });
458                    }
459                });
460                break;
461            }
462        }
463
464    }
465*/
466
467    public String getName() {
468        return name;
469    }
470
471    public String getIconName() {
472        return iconName;
473    }
474
475    @Override
476    public void onUpgrade(Path path) {
477    }
478
479    @Override
480    public void onChange(Path path) {
481    }
482
483    @Override
484    public void onChildChange(Path path, ListChange.Action action) {
485    }
486
487    public final Frame getFrame() {
488        return frame;
489    }
490
491        public boolean changeValue(ValueControl component, Object newValue) {
492                LOGGER.debug("changing value of " + component + " to '" + newValue + "'");
493
494                if (changedValues == null) {
495                        changedValues = new HashMap<ValueControl, Object>();
496                }
497                changedValues.put(component, newValue);
498
499                return true;
500        }
501
502        public Path getInstancePath() {
503                assert frame.isActive();
504                return path;
505        }
506
507        public void applyChanges() {
508                assert frame.isActive();
509                if (changedValues == null) {
510                        return;
511                }
512                final Map<ValueControl, Object> changes = changedValues;
513                changedValues = null;
514                endpoint.getEndpoint().invokeLater(new Runnable() {
515                        @Override
516                        public void run() {
517                                for (Map.Entry<ValueControl, Object> e : changes.entrySet()) {
518                                        final ValueControl key = e.getKey();
519                                        final Path p = path;
520                                        endpoint.getEndpoint().getInstance().storeValue(p, e.getKey().getParam(), e.getValue(), new StateFunctor() {
521                                                @Override
522                                                public void call(Exception e) {
523                                                        changes.remove(key);
524                                                        if (!changes.isEmpty()) {
525                                                                return;
526                                                        }
527                                                        LOGGER.debug("applied changes for: " + p);
528                                                        frame.invokeLater(new Runnable() {
529                                                                @Override
530                                                                public void run() {
531                                                                        fillPanelWithValues();
532                                                                }
533                                                        });
534                                                }
535                                        });
536                                }
537                        }
538                });
539        }
540
541}
Note: See TracBrowser for help on using the repository browser.