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

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

HIGHLIGTS:

  • complete events implementation
  • add CLI in Java Framsticks server
  • add automatic registration for events in GUI
  • improve objects fetching (object are never overwritten with new instances)
  • properly react for ListChange? events
  • add ListPanel? with table view
    • columns to be shown may be statically specified in configuration
    • currently modyfying data through tables is not available
  • improve maven configuration
    • configuration file may be specified without touching pom.xml

CHANGELOG:
Extract constants from Flags into ParamFlags? and SetStateFlags?.

Extract flags I/O to FlagsUtils? class.

Configured maven to exec given resource configuration.

For example:
mvn exec:exec -Dframsticks.config=/configs/managed-console.xml

Cleanup pom.xml

Rename ObjectTree? to LocalTree? (also make LocalTree? and RemoteTree? final).

Minor change.

Add maximum number of columns in ListPanelProvider?.

Improve ColumnsConfig? interpretation.

Automatically fill FramsClass?.name if trying to construct empty.

Improve identitifer case mangling in XmlLoader?.

Introduce configurable ColumnsConfig?.

Draft working version of ListPanel?.

Table is being shown (although empty).

More improvements to table building.

Move some functionality from Frame to TreeModel?.

Move tree classes in gui to separate package.

Remove old table related classes.

Add draft implementation of TableModel?.

Redirect ParamBuilder?.forAccess to AccessInterface?.

Optimize ParamBuilder?.forAccess()

Do not clear list when loading.

Do not load fetched values directly.

Implement different AccessInterface? copying policy.

Optimize fetching values routine.

Remove Mode enum (work out get semantics).

Some improvements to ListChange? handling.

Improve UniqueListAccess?.

Add reaction for ListChanges? in the TreeNode?.

EventListeners? are being added in the TreeNode?.

Listeners for ListParams? are now very naive (they download
whole list).

Automatially register on events in GUI.

Events are working in RemoteTree? and Server.

Move listeners to the ClientSideManagedConnection?.

Remove old classes responsible for event subscriptions.

Improve event reading.

Improve events handling at server side.

Add register attribute in FramsClassAnnotation?
to automatically also register other classes.

Registering events works.

Setup for remote listeners registration.

More improvements.

Minor changes.

Add rootTree to the ClientAtServer?.

Moving CLI to the ClientAtServer?.

Fix bug: use Void.TYPE instead of Void.class

More development around CLI.

  • Improve Path resolving.

Add synthetic root to ObjectTree?.

It is needed to allow sybling for the original root
that would containg CLI.

Some work with registering events in RemoteTree?.

Draft implementation of listener registering in RemoteTree?.

Support events registration in the ObjectTree?.

Add events support to ReflectionAccess?.

EventParam? is recognized by ParamCandidate?.

Prepare interface for Events across project.

Add EventListener? and API for listeners in Tree.

File size: 10.6 KB
Line 
1package com.framsticks.gui.tree;
2
3import java.lang.ref.WeakReference;
4import java.util.Iterator;
5import java.util.LinkedList;
6import java.util.List;
7import java.util.concurrent.atomic.AtomicInteger;
8
9import javax.swing.ImageIcon;
10import javax.swing.tree.TreePath;
11
12import org.apache.log4j.Logger;
13
14import com.framsticks.core.ListChange;
15import com.framsticks.core.Node;
16import com.framsticks.core.Path;
17import com.framsticks.core.Tree;
18import com.framsticks.gui.Frame;
19import com.framsticks.gui.ImageProvider;
20import com.framsticks.gui.TreeAtFrame;
21import com.framsticks.params.AccessInterface;
22import com.framsticks.params.CompositeParam;
23import com.framsticks.params.EventListener;
24import com.framsticks.params.FramsClass;
25import com.framsticks.params.PrimitiveParam;
26import com.framsticks.params.ValueParam;
27import com.framsticks.params.types.EventParam;
28import com.framsticks.params.types.ObjectParam;
29import com.framsticks.params.types.StringParam;
30import com.framsticks.util.FramsticksException;
31import com.framsticks.util.dispatching.FutureHandler;
32import com.framsticks.util.lang.Casting;
33import com.framsticks.util.lang.Containers;
34import com.framsticks.util.lang.Pair;
35import com.framsticks.util.swing.TooltipConstructor;
36import static com.framsticks.core.TreeOperations.*;
37
38public class TreeNode extends AbstractNode {
39        private static final Logger log = Logger.getLogger(TreeNode.class);
40
41
42        protected static final AtomicInteger counter = new AtomicInteger();
43
44        protected final WeakReference<Object> reference;
45        protected final CompositeParam param;
46        protected final TreeAtFrame treeAtFrame;
47        protected final List<Pair<WeakReference<Object>, WeakReference<TreeNode>>> children = new LinkedList<>();
48        protected final int number;
49        protected final String textualPath;
50        protected final ImageIcon imageIcon;
51        protected final TreeModel treeModel;
52
53        protected final List<EventListener<?>> listeners = new LinkedList<>();
54
55        public TreeNode(TreeAtFrame treeAtFrame, Path path) {
56                path.assureResolved();
57                this.textualPath = path.getTextual();
58                this.param = path.getTop().getParam();
59                this.treeAtFrame = treeAtFrame;
60                this.treeModel = treeAtFrame.getFrame().getTreeModel();
61                this.imageIcon = ImageProvider.loadImage(TreeCellRenderer.findIconName(param));
62
63                reference = new WeakReference<Object>(path.getTop().getObject());
64                number = counter.getAndIncrement();
65
66                /** Iterate over all EventParams and for matching ValueParams register listeners. */
67                if (param instanceof ObjectParam) {
68                        AccessInterface access = bindAccess(path);
69                        FramsClass framsClass = access.getFramsClass();
70                        for (EventParam eventParam : Containers.filterInstanceof(framsClass.getParamEntries(), EventParam.class)) {
71                                if (!eventParam.getId().endsWith("_changed")) {
72                                        continue;
73                                }
74                                String valueId = eventParam.getId().substring(0, eventParam.getId().length() - 8);
75                                final ValueParam valueParam = Casting.tryCast(ValueParam.class, framsClass.getParam(valueId));
76                                if (valueParam == null) {
77                                        continue;
78                                }
79                                registerForEventParam(path, eventParam, valueParam);
80                        }
81                }
82        }
83
84        protected <A> void tryAddListener(final Path path, final EventParam eventParam, Class<A> argumentType, final EventListener<A> listener) {
85                treeAtFrame.getTree().addListener(path, eventParam, listener, argumentType, new FutureHandler<Void>(treeAtFrame.getFrame()) {
86                        @Override
87                        protected void result(Void result) {
88                                assert treeAtFrame.getFrame().isActive();
89                                log.debug("registered gui listener for " + eventParam + " at " + path);
90                                listeners.add(listener);
91                        }
92                });
93        }
94
95        protected void registerForEventParam(Path path, EventParam eventParam, ValueParam valueParam) {
96                /** TODO make this listener not bind hold the reference to this TreeNode, maybe hold WeakReference internally */
97                if (valueParam instanceof PrimitiveParam) {
98
99                        tryAddListener(path, eventParam, Object.class, new EventListener<Object>() {
100                                @Override
101                                public void action(Object argument) {
102                                        treeModel.loadPath(assurePath(), true);
103                                }
104                        });
105
106                } else if (valueParam instanceof CompositeParam) {
107
108                        final CompositeParam compositeParam = (CompositeParam) valueParam;
109
110                        tryAddListener(path, eventParam, ListChange.class, new EventListener<ListChange>() {
111                                @Override
112                                public void action(ListChange listChange) {
113                                        assert treeAtFrame.getTree().isActive();
114
115                                        final Path listPath = assurePath().appendParam(compositeParam).tryFindResolution().assureResolved();
116                                        log.debug("reacting to change " + listChange + " in " + listPath);
117
118                                        if ((listChange.getAction().equals(ListChange.Action.Modify)) && (listChange.getPosition() == -1)) {
119                                                // get(listPath, future);
120                                                return;
121                                        }
122                                        final String id = listChange.getBestIdentifier();
123
124                                        AccessInterface access = bindAccess(listPath);
125                                        switch (listChange.getAction()) {
126                                                case Add: {
127                                                        tryGet(listPath.getTree(), Path.appendString(listPath.getTextual(), id), new FutureHandler<Path>(treeAtFrame.getFrame()) {
128                                                                @Override
129                                                                protected void result(Path result) {
130                                                                        final Frame frame = treeAtFrame.getFrame();
131                                                                        assert frame.isActive();
132                                                                        final TreePath treePath = frame.getTreeModel().convertToTreePath(listPath);
133                                                                        treeModel.nodeStructureChanged(treePath);
134                                                                        frame.updatePanelIfIsLeadSelection(treePath, listPath);
135                                                                        log.debug("added " + id + "(" + result + ") updated " + treePath);
136                                                                }
137                                                        });
138                                                        break;
139                                                }
140                                                case Remove: {
141                                                        access.set(id, null);
142                                                        Frame frame = treeAtFrame.getFrame();
143                                                        treeModel.nodeStructureChanged(frame.getTreeModel().convertToTreePath(listPath));
144                                                        break;
145                                                }
146                                                case Modify: {
147                                                        tryGet(listPath.getTree(), Path.appendString(listPath.getTextual(), id), new FutureHandler<Path>(treeAtFrame.getFrame()) {
148                                                                @Override
149                                                                protected void result(Path result) {
150                                                                        final Frame frame = treeAtFrame.getFrame();
151                                                                        assert frame.isActive();
152                                                                        final TreePath treePath = frame.getTreeModel().convertToTreePath(result);
153                                                                        treeModel.nodeStructureChanged(treePath);
154                                                                        frame.updatePanelIfIsLeadSelection(treePath, listPath);
155                                                                }
156                                                        });
157                                                        break;
158                                                }
159                                        }
160                                }
161                        });
162                }
163
164        }
165
166        protected Path assurePath() {
167                return Path.to(treeAtFrame.getTree(), textualPath).assureResolved();
168        }
169
170        public Node tryCreateNode() {
171                Object child = lock();
172                if (child == null) {
173                        return null;
174                }
175                return Path.to(treeAtFrame.getTree(), textualPath).assureResolved().getTop();
176        }
177
178        @Override
179        public int getChildCount() {
180                Object referent = lock();
181                if (referent == null) {
182                        return 0;
183                }
184                AccessInterface access = bindAccessFor(referent);
185                final int count = access.getCompositeParamCount();
186                return count;
187        }
188
189        public TreeNode getTreeNodeForChild(Object child) {
190                Iterator<Pair<WeakReference<Object>, WeakReference<TreeNode>>> i = children.iterator();
191                while (i.hasNext()) {
192                        Pair<WeakReference<Object>, WeakReference<TreeNode>> p = i.next();
193                        Object object = p.first.get();
194                        if (object == null) {
195                                i.remove();
196                                continue;
197                        }
198                        TreeNode treeNode = p.second.get();
199                        if (treeNode == null) {
200                                i.remove();
201                                continue;
202                        }
203                        if (object == child) {
204                                return treeNode;
205                        }
206                }
207                return null;
208
209                // WeakReference<GuiTreeNode> resultReference = children.get(child);
210                // if (resultReference == null) {
211                //      return null;
212                // }
213                // return resultReference.get();
214        }
215
216        @Override
217        public AbstractNode getChild(int number) {
218                Object referent = lock();
219                if (referent == null) {
220                        throw new FramsticksException().msg("invalid state - missing referent");
221                }
222                AccessInterface access = bindAccessFor(referent);
223
224                final int count = access.getCompositeParamCount();
225                if (number >= count) {
226                        throw new FramsticksException().msg("invalid state - no child");
227                }
228
229                CompositeParam childParam = access.getCompositeParam(number);
230                Object child = access.get(childParam, Object.class);
231                if (child == null) {
232                        log.debug("returning dummy node for " + childParam + " in " + referent);
233                        return new EmptyNode(childParam);
234                }
235
236                TreeNode result = getTreeNodeForChild(child);
237                if (result != null) {
238                        return result;
239                }
240                Path path = Path.to(treeAtFrame.getTree(), Path.appendString(textualPath, childParam.getId())).assureResolved();
241                result = new TreeNode(treeAtFrame, path);
242
243                children.add(Pair.make(new WeakReference<Object>(child), new WeakReference<TreeNode>(result)));
244
245                return result;
246
247        }
248
249        public Object lock() {
250                return reference.get();
251        }
252
253        @Override
254        public int getIndexOfChild(AbstractNode child) {
255                final TreeNode treeChild = Casting.tryCast(TreeNode.class, child);
256                if (treeChild == null) {
257                        return -1;
258                }
259                final Object childObject = treeChild.lock();
260                final Object parentObject = lock();
261                if (childObject == null || parentObject == null) {
262                        return -1;
263                }
264                final AccessInterface access = bindAccessFor(parentObject);
265
266                final int count = access.getCompositeParamCount();
267                for (int i = 0; i < count; ++i) {
268                        Object c = access.get(access.getCompositeParam(i), Object.class);
269                        if (c == childObject) {
270                                return i;
271                        }
272                }
273                log.debug(child + " not found in " + this);
274                return -1;
275        }
276
277        /**
278         * @return the param
279         */
280        public CompositeParam getParam() {
281                return param;
282        }
283
284        /**
285         * @return the tree
286         */
287        public Tree getTree() {
288                return treeAtFrame.getTree();
289        }
290
291
292        @Override
293        public String toString() {
294                return param.toString();
295        }
296
297        public static Node tryGetNode(TreePath treePath) {
298                return Casting.throwCast(TreeNode.class, treePath.getLastPathComponent()).tryCreateNode();
299        }
300
301        @Override
302        public boolean isLeaf() {
303                Object referent = lock();
304                if (referent == null) {
305                        return true;
306                }
307                return bindAccessFor(referent).getCompositeParamCount() == 0;
308        }
309
310        protected AccessInterface bindAccessFor(Object child) {
311                return treeAtFrame.getTree().prepareAccess(param).select(child);
312        }
313
314        @Override
315        public void render(TreeCellRenderer renderer) {
316                String name = param.getId();
317
318                Object child = lock();
319                if (child != null) {
320                        AccessInterface access = bindAccessFor(child);
321
322                        StringParam nameParam = Casting.tryCast(StringParam.class, access.getParam("name"));
323
324                        if (nameParam != null) {
325                                name = access.get(nameParam, String.class);
326                        }
327
328                        renderer.setToolTipText(new TooltipConstructor()
329                                .append("frams", access.getId())
330                                .append("java", child.getClass().getCanonicalName())
331                                .append("access", access.getClass().getSimpleName())
332                                .append("name", name)
333                                .append("id", param.getId())
334                                .append("object", Integer.toHexString(System.identityHashCode(child)))
335                                .append("number", number)
336                                .append("textual path", textualPath)
337                                .build());
338                } else {
339                        renderer.setToolTipText(new TooltipConstructor()
340                                .append("param", param)
341                                .append("textual path", textualPath)
342                                .build());
343                }
344                renderer.setText(name);
345                renderer.setIcon(imageIcon);
346
347        }
348
349}
Note: See TracBrowser for help on using the repository browser.