Ignore:
Timestamp:
07/12/13 23:41:06 (11 years ago)
Author:
psniegowski
Message:

HIGHLIGHTS:

  • add <include/> to configuration
  • add side notes to tree
    • used to store arbitrary information alongside the tree structure
  • migrate to log4j2
    • supports lazy string evaluation of passed arguments
  • improve GUI tree
    • it stays in synchronization with actual state (even in high load test scenario)
  • improve panel management in GUI
  • make loading objects in GUI more lazy
  • offload parsing to connection receiver thread
    • info parsing
    • first step of objects parsing
  • fix connection parsing bug (eof in long values)
  • support zero-arguments procedure in table view

CHANGELOG:
Implement procedure calls from table view.

Refactorization around procedures in tables.

Add table editor for buttons.

Render buttons in the the list view.

Further improve Columns.

Add Column class for TableModel?.

Accept also non-arguments ProcedureParams? in tableView.

Increase maximal TextAreaControl? size.

Add tooltip to ProcedureControl?.

Fix bug of interpreting eofs in long values by connection reader.

Further rework connection parsing.

Simplify client connection processing.

Test ListChange? modification.

Test ListChange? events with java server.

Add TestChild?.

Fix bug with fast deregistering when connecting to running server.

Another minor refactorization in TreeOperations?.

Fix bug in SimpleAbstractAccess? loading routine.

Another minor improvement.

Minor change.

Make reading of List objects two-phase.

Another minor change.

Dispatch parsing into receiver thread.

Another step.

Enclose passing value in ObjectParam? case in closure.

Minor step.

Minor change on way to offload parsing.

Temporarily comment out single ValueParam? get.

It will be generalized to multi ValueParam?.

Process info in receiver thread.

Add DispatchingExceptionHandler?.

Make waits in browser test longer.

Use FETCHED_MARK.

It is honored in GUI, where it used to decide whether to get values

after user action.

It is set in standard algorithm for processing fetched values.

Add remove operation to side notes.

Make loading more lazy.

Improve loading policy.

On node choose load itself, on node expansion, load children.

Minor improvement.

Fix bug with panel interleaving.

Minor improvements.

Improve panel management.

More cleaning around panels.

Reorganize panels.

Further improve tree.

Fix bug in TreeModel?.

Remove children from TreeNode?.

Implement TreeNode? hashCode and equals.

Make TreeNode? delegate equals and hashcode to internal reference.

Move listeners from TreeNode? to side notes.

Store path.textual as a side note.

Side note params instead of accesses for objects.

More refactorizations.

In TreeNode? bindAccess based on side notes.

Minor step.

Hide createAccess.

Rename AccessInterface? to Access.

Minor changes.

Several improvements in high load scenarios.

Change semantics of ArrayListAccess?.set(index, null);

It now removes the element, making list shorter
(it was set to null before).

Add path remove handler.

Handle exceptions in Connection.

Update .gitignore

Configure logging to file.

Move registration to TreeModel?.

Further refactorization.

Minor refactorization.

Minor improvements.

Use specialized event also for Modify action of ListChange?.

Use remove events.

Use the insertion events for tree.

Further improve tree refreshing.

Further improve reacting on events in GUI.

Fix problem with not adding objects on addition list change.

Migrate to log4j lazy String construction interface.

Migrate imports to log4j2.

Drop dependency on adapter to version 1.2.

Switch log4j implementation to log4j2.

Add dirty mark to the NodeAtFrame?.

Make selecting in AccessInterfaces? type safe.

Ignore containers size settings in Model and Genotype.

Use tree side notes to remember local changes and panels.

Add sideNotes to tree.

They will be used to store various accompanying information
right in the tree.

Use ReferenceIdentityMap? from apache in TreeNode?.

It suits the need perfectly (weak semantics on both key and value).

Make ArrayListParam? do not react size changes.

Guard in TableModel? before not yet loaded objects.

Add <include/> clause and AutoInjector?.

Extract common columns configuration to separate xml,
that can be included by other configurations.

Location:
java/main/src/main/java/com/framsticks/gui/tree
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • java/main/src/main/java/com/framsticks/gui/tree/AbstractNode.java

    r99 r100  
    11package com.framsticks.gui.tree;
     2
     3import com.framsticks.gui.AbstractPanel;
    24
    35
     
    911
    1012        public abstract int getChildCount();
    11         public abstract AbstractNode getChild(int number);
    12         public abstract int getIndexOfChild(AbstractNode child);
     13        public abstract Object getChild(int number);
     14        public abstract int getIndexOfChild(Object child);
    1315
    1416        public abstract boolean isLeaf();
    1517        public abstract void render(TreeCellRenderer renderer);
    1618
     19        public abstract AbstractPanel getPanel();
     20
    1721}
  • java/main/src/main/java/com/framsticks/gui/tree/EmptyNode.java

    r99 r100  
    22
    33
     4import com.framsticks.gui.AbstractPanel;
     5import com.framsticks.gui.Frame;
    46import com.framsticks.gui.ImageProvider;
    57import com.framsticks.params.CompositeParam;
     
    810
    911        protected final CompositeParam param;
     12        protected final Frame frame;
    1013
    1114        /**
    1215         * @param param
    1316         */
    14         public EmptyNode(CompositeParam param) {
     17        public EmptyNode(Frame frame, CompositeParam param) {
    1518                this.param = param;
     19                this.frame = frame;
    1620        }
    1721
     
    2226
    2327        @Override
    24         public AbstractNode getChild(int number) {
     28        public Object getChild(int number) {
    2529                return null;
    2630        }
    2731
    2832        @Override
    29         public int getIndexOfChild(AbstractNode child) {
     33        public int getIndexOfChild(Object child) {
    3034                return -1;
    3135        }
     
    3337        @Override
    3438        public boolean isLeaf() {
    35                 return true;
     39                return false;
    3640        }
    3741
    3842        @Override
    3943        public void render(TreeCellRenderer renderer) {
    40                 renderer.setIcon(ImageProvider.loadImage(TreeCellRenderer.findIconName(param)));
     44                // TODO Auto-generated method stub
     45
     46                renderer.setToolTipText("?");
    4147                renderer.setText(param.getId());
    42                 renderer.setToolTipText("?");
     48                renderer.setIcon(ImageProvider.loadImage(ImageProvider.FOLDER_CLOSED));
     49        }
     50
     51        /**
     52         * @return the param
     53         */
     54        public CompositeParam getParam() {
     55                return param;
    4356        }
    4457
    4558        @Override
    46         public String toString() {
    47                 return param.toString();
     59        public AbstractPanel getPanel() {
     60                return frame.getEmptyPanel();
    4861        }
    4962
  • java/main/src/main/java/com/framsticks/gui/tree/MetaNode.java

    r99 r100  
    55
    66
     7import com.framsticks.gui.AbstractPanel;
     8import com.framsticks.gui.Frame;
    79import com.framsticks.gui.ImageProvider;
    810
    911public class MetaNode extends AbstractNode {
    1012
    11         protected List<AbstractNode> children = new LinkedList<>();
     13        protected final Frame frame;
     14        protected final List<Object> children = new LinkedList<>();
    1215        protected String name = "meta node";
     16
     17        /**
     18         * @param frame
     19         */
     20        public MetaNode(Frame frame) {
     21                this.frame = frame;
     22        }
    1323
    1424        /**
    1525         * @return the children
    1626         */
    17         public List<AbstractNode> getChildren() {
     27        public List<Object> getChildren() {
    1828                return children;
    1929        }
     
    3949
    4050        @Override
    41         public AbstractNode getChild(int number) {
     51        public Object getChild(int number) {
    4252                return children.get(number);
    4353        }
    4454
    4555        @Override
    46         public int getIndexOfChild(AbstractNode child) {
     56        public int getIndexOfChild(Object child) {
    4757                return children.indexOf(child);
    4858        }
     
    6575        }
    6676
     77        @Override
     78        public AbstractPanel getPanel() {
     79                return frame.getEmptyPanel();
     80        }
     81
    6782}
  • java/main/src/main/java/com/framsticks/gui/tree/TreeCellRenderer.java

    r99 r100  
    1515public class TreeCellRenderer extends DefaultTreeCellRenderer {
    1616
    17         public TreeCellRenderer() {
     17        protected final TreeModel treeModel;
    1818
    19                 // setOpenIcon(ImageProvider.loadImage(ImageProvider.FOLDER_OPEN));
    20                 // setClosedIcon(ImageProvider.loadImage(ImageProvider.FOLDER_CLOSED));
    21                 // setLeafIcon(ImageProvider.loadImage(ImageProvider.NODE));
     19
     20        /**
     21         * @param treeModel
     22         */
     23        public TreeCellRenderer(TreeModel treeModel) {
     24                this.treeModel = treeModel;
    2225        }
    2326
     
    3538
    3639                if (!(value instanceof AbstractNode)) {
    37                         setIcon(ImageProvider.loadImage(ImageProvider.SERVER));
    38                         setText("framsticks");
     40                        setText("?");
     41                        // treeModel.renderTreeObject(Casting.throwCast(TreeNode.class, value), this);
    3942                        return this;
    4043                }
     
    9295
    9396
    94 
    9597}
  • java/main/src/main/java/com/framsticks/gui/tree/TreeModel.java

    r99 r100  
    11package com.framsticks.gui.tree;
    22
    3 // import java.util.Enumeration;
     3import java.util.Enumeration;
    44import java.util.Iterator;
    55import java.util.LinkedList;
    66import java.util.List;
    77
     8import javax.annotation.Nullable;
    89import javax.swing.event.TreeModelEvent;
    910import javax.swing.event.TreeModelListener;
    1011import javax.swing.tree.TreePath;
    1112
    12 import org.apache.log4j.Logger;
    13 
    14 
     13import org.apache.logging.log4j.Logger;
     14import org.apache.logging.log4j.LogManager;
     15
     16import com.framsticks.core.ListChange;
    1517import com.framsticks.core.Node;
    1618import com.framsticks.core.Path;
    17 import com.framsticks.core.Tree;
    1819import com.framsticks.core.TreeOperations;
    1920import com.framsticks.gui.Frame;
    20 import com.framsticks.params.AccessInterface;
     21import com.framsticks.params.Access;
     22import com.framsticks.params.CompositeParam;
     23import com.framsticks.params.EventListener;
     24import com.framsticks.params.ListAccess;
     25import com.framsticks.params.PrimitiveParam;
     26import com.framsticks.params.Util;
     27import com.framsticks.params.ValueParam;
     28import com.framsticks.params.types.EventParam;
    2129import com.framsticks.util.FramsticksException;
     30import com.framsticks.util.Misc;
    2231import com.framsticks.util.UnsupportedOperationException;
    2332import com.framsticks.util.dispatching.FutureHandler;
    2433import com.framsticks.util.lang.Casting;
    2534
     35import static com.framsticks.core.TreeOperations.*;
     36
    2637public class TreeModel implements javax.swing.tree.TreeModel {
    27         private static final Logger log = Logger.getLogger(TreeModel.class);
     38        private static final Logger log = LogManager.getLogger(TreeModel.class);
    2839
    2940
    3041        protected List<TreeModelListener> listeners = new LinkedList<>();
     42
    3143
    3244        protected final Frame frame;
     
    4557
    4658        @Override
    47         public AbstractNode getChild(Object parent, int number) {
    48                 return Casting.assertCast(AbstractNode.class, parent).getChild(number);
     59        public Object getChild(Object parent, int number) {
     60                return Casting.throwCast(AbstractNode.class, parent).getChild(number);
    4961        }
    5062
    5163        @Override
    5264        public int getChildCount(Object parent) {
    53                 return Casting.assertCast(AbstractNode.class, parent).getChildCount();
     65                return Casting.throwCast(AbstractNode.class, parent).getChildCount();
    5466        }
    5567
     
    5971                        return -1;
    6072                }
    61                 return Casting.assertCast(AbstractNode.class, parent).getIndexOfChild(Casting.assertCast(AbstractNode.class, child));
     73                return Casting.throwCast(AbstractNode.class, parent).getIndexOfChild(child);
    6274        }
    6375
     
    6981        @Override
    7082        public boolean isLeaf(Object node) {
    71                 return Casting.assertCast(AbstractNode.class, node).isLeaf();
     83                return Casting.throwCast(AbstractNode.class, node).isLeaf();
    7284        }
    7385
     
    8597        protected boolean changing = false;
    8698
    87         public void nodeStructureChanged(TreePath treePath) {
     99        public void treeNodesInserted(TreeModelEvent event) {
     100                assert frame.isActive();
     101                try {
     102                        for (TreeModelListener listener : listeners) {
     103                                listener.treeNodesInserted(event);
     104                        }
     105                } catch (ArrayIndexOutOfBoundsException e) {
     106                }
     107        }
     108
     109        public void treeNodesRemoved(TreeModelEvent event) {
     110                assert frame.isActive();
     111                try {
     112                        for (TreeModelListener listener : listeners) {
     113                                listener.treeNodesRemoved(event);
     114                        }
     115                } catch (ArrayIndexOutOfBoundsException e) {
     116                }
     117        }
     118
     119        public void treeNodesChanged(TreeModelEvent event) {
     120                try {
     121                        for (TreeModelListener listener : listeners) {
     122                                listener.treeNodesChanged(event);
     123                        }
     124                } catch (ArrayIndexOutOfBoundsException e) {
     125                }
     126        }
     127
     128        public TreeModelEvent prepareModelEvent(TreePath treePath, int number, TreeNode node) {
     129                return new TreeModelEvent(this, treePath, new int[] {number}, new Object[] { node });
     130        }
     131
     132
     133        public TreeModelEvent prepareModelEventRegarding(Access access, String id, TreePath treeListPath) {
     134
     135                int number = Util.getNumberOfCompositeParamChild(access, access.get(id, Object.class));
     136                if (number == -1) {
     137                        log.debug("encountered minor tree inconsistency in {}", treeListPath);
     138                        return null;
     139                }
     140                TreeNode node = Casting.throwCast(TreeNode.class, Casting.throwCast(TreeNode.class, treeListPath.getLastPathComponent()).getChild(number));
     141                return prepareModelEvent(treeListPath, number, node);
     142        }
     143
     144        public void treeStructureChanged(TreePath treePath) {
     145
    88146                if (treePath == null) {
    89147                        return;
     
    92150
    93151                changing = true;
    94                 log.debug("changing: " + treePath);
    95                 // Enumeration<TreePath> expanded = frame.jtree.getExpandedDescendants(treePath);
     152                log.debug("changing structure: {}", treePath);
     153                Enumeration<TreePath> expanded = frame.getJtree().getExpandedDescendants(treePath);
    96154                TreePath selection = frame.getJtree().getSelectionPath();
    97155
    98                 for (TreeModelListener listener : listeners) {
    99                         listener.treeStructureChanged(new TreeModelEvent(this, treePath));
    100                 }
    101                 // if (expanded != null) {
    102                 //      while (expanded.hasMoreElements()) {
    103                 //              TreePath expansion = expanded.nextElement();
    104                 //              // log.info("reexpanding: " + expansion);
    105                 //              frame.jtree.expandPath(expansion);
    106                 //      }
    107                 // }
     156                try {
     157                        for (TreeModelListener listener : listeners) {
     158                                listener.treeStructureChanged(new TreeModelEvent(this, treePath));
     159                        }
     160                } catch (ArrayIndexOutOfBoundsException e) {
     161                }
     162
     163
     164                if (expanded != null) {
     165                        while (expanded.hasMoreElements()) {
     166                                TreePath expansion = expanded.nextElement();
     167                                // log.info("reexpanding: {}", expansion);
     168                                frame.getJtree().expandPath(expansion);
     169                        }
     170                }
     171
    108172                if (selection != null) {
    109173                        frame.getJtree().setSelectionPath(selection);
     
    112176        }
    113177
    114         public Path convertToPath(TreePath treePath) {
     178        /**
     179         *
     180         * This method may return null on conversion failure, which may happen in highload situations.
     181         */
     182        public @Nullable Path convertToPath(TreePath treePath) {
    115183                final Object[] components = treePath.getPath();
    116184                assert components[0] == frame.getRootNode();
     
    128196                        Node node = treeNode.tryCreateNode();
    129197                        if (node == null) {
    130                                 throw new FramsticksException().msg("failed to recreate path").arg("treePath", treePath);
     198                                return null;
     199                                // throw new FramsticksException().msg("failed to recreate path").arg("treePath", treePath);
    131200                        }
    132201                        nodes.add(node);
     
    137206        }
    138207
    139         public TreePath convertToTreePath(Path path) {
     208        public TreePath convertToTreePath(Path path, boolean forceComplete) {
    140209                assert frame.isActive();
    141210
     
    143212                accumulator.add(getRoot());
    144213
    145                 for (AbstractNode r : getRoot().getChildren()) {
     214                for (Object r : getRoot().getChildren()) {
    146215                        if (r instanceof TreeNode) {
    147216                                TreeNode root = (TreeNode) r;
    148217                                if (root.getTree() == path.getTree()) {
     218                                        Iterator<Node> n = path.getNodes().iterator();
     219                                        TreeNode treeNode = root;
    149220                                        accumulator.add(root);
    150 
    151                                         Iterator<Node> i = path.getNodes().iterator();
    152                                         i.next();
    153                                         TreeNode treeNode = root;
    154 
    155                                         while (i.hasNext()) {
    156                                                 Node node = i.next();
    157                                                 treeNode = treeNode.getTreeNodeForChild(node.getObject());
     221                                        n.next();
     222                                        while (n.hasNext()) {
     223                                                Node node = n.next();
     224                                                treeNode = treeNode.prepareTreeNodeForChild(Path.build().tree(path.getTree()).buildUpTo(path.getNodes(), node).finish());
    158225                                                if (treeNode == null) {
    159226                                                        break;
     
    161228                                                accumulator.add(treeNode);
    162229                                        }
    163 
    164230                                        break;
    165231                                }
     
    167233                }
    168234                return new TreePath(accumulator.toArray());
     235        }
     236
     237        /**
     238         * @return the listeners
     239         */
     240        public List<TreeModelListener> getListeners() {
     241                return listeners;
    169242        }
    170243
     
    180253                        return;
    181254                }
    182                 AccessInterface access = TreeOperations.bindAccess(path);
     255                Access access = TreeOperations.bindAccess(path);
    183256
    184257                int count = access.getCompositeParamCount();
     
    193266                        return;
    194267                }
    195                 if (path.isResolved() && !reload) {
     268                if (!reload && path.isResolved() && isMarked(path.getTree(), path.getTopObject(), FETCHED_MARK, false)) {
    196269                        return;
    197270                }
     
    199272                        @Override
    200273                        protected void result(Path result) {
    201                                 final TreePath treePath = convertToTreePath(result);
    202 
    203                                 nodeStructureChanged(treePath);
    204                                 frame.updatePanelIfIsLeadSelection(treePath, result);
     274                                final TreePath treePath = convertToTreePath(result, true);
     275
     276
     277                                if (treePath != null) {
     278                                        treeStructureChanged(treePath);
     279                                        frame.updatePanelIfIsLeadSelection(result);
     280                                }
    205281                        }
    206282                });
    207283        }
    208284
    209         public void chooseTreeNode(final TreePath treePath) {
     285        public void expandTreeNode(TreePath treePath) {
    210286                assert frame.isActive();
    211287                if (treePath == null) {
     
    215291                        return;
    216292                }
    217 
    218293                Path path = convertToPath(treePath);
    219294                if (path == null) {
    220295                        return;
    221296                }
     297                loadChildren(path.assureResolved(), false);
     298        }
     299
     300        public void chooseTreeNode(final TreePath treePath) {
     301                assert frame.isActive();
     302                if (treePath == null) {
     303                        return;
     304                }
     305                if (isChanging()) {
     306                        return;
     307                }
     308
     309                Path path = convertToPath(treePath);
     310                if (path == null) {
     311                        return;
     312                }
    222313                path = path.assureResolved();
    223                 final Tree tree = path.getTree();
    224 
    225                 frame.getTreeAtFrames().get(tree).useOrCreatePanel(treePath);
    226                 loadChildren(path, false);
    227 
    228         }
     314
     315                log.debug("choosing {}", path);
     316                frame.showPanelForTreePath(treePath);
     317                loadPath(path, false);
     318
     319        }
     320
     321
     322        protected void registerForEventParam(final TreeNode treeNode, Path path, final EventParam eventParam, ValueParam valueParam) {
     323                /** TODO make this listener not bind hold the reference to this TreeNode, maybe hold WeakReference internally */
     324                if (valueParam instanceof PrimitiveParam) {
     325
     326                        treeNode.tryAddListener(path, eventParam, Object.class, new EventListener<Object>() {
     327                                @Override
     328                                public void action(Object argument) {
     329                                        loadPath(treeNode.assurePath(), true);
     330                                }
     331                        });
     332
     333                } else if (valueParam instanceof CompositeParam) {
     334
     335                        final CompositeParam compositeParam = (CompositeParam) valueParam;
     336
     337                        treeNode.tryAddListener(path, eventParam, ListChange.class, new EventListener<ListChange>() {
     338                                @Override
     339                                public void action(ListChange listChange) {
     340                                        assert treeNode.getTree().isActive();
     341
     342                                        Path parentPath = treeNode.assurePath();
     343                                        final Path listPath = parentPath.appendParam(compositeParam).tryFindResolution();
     344                                        if (!listPath.isResolved()) {
     345                                                /** that situation is quietly ignored - it may happen if first event comes before the container was resolved */
     346                                                return;
     347                                        }
     348
     349                                        log.debug("reacting to change {} in {}", listChange, listPath);
     350                                        final TreePath treeListPath = convertToTreePath(listPath, true);
     351                                        if (treeListPath == null) {
     352                                                throw new FramsticksException().msg("path was not fully converted").arg("path", listPath);
     353                                        }
     354
     355                                        if ((listChange.getAction().equals(ListChange.Action.Modify)) && (listChange.getPosition() == -1)) {
     356                                                // get(listPath, future);
     357                                                // treeModel.nodeStructureChanged(treePath);
     358                                                // frame.updatePanelIfIsLeadSelection(treePath, result);
     359                                                return;
     360                                        }
     361                                        final String id = listChange.getBestIdentifier();
     362
     363                                        final ListAccess access = (ListAccess) bindAccess(listPath);
     364                                        switch (listChange.getAction()) {
     365                                                case Add: {
     366                                                        Path childPath = listPath.appendParam(access.prepareParamFor(id)).tryFindResolution();
     367                                                        if (!childPath.isResolved()) {
     368                                                                childPath = create(childPath);
     369
     370                                                                TreeModelEvent event = prepareModelEventRegarding(access, id, treeListPath);
     371                                                                if (event != null) {
     372                                                                        treeNodesInserted(event);
     373                                                                } else {
     374                                                                        treeStructureChanged(treeListPath);
     375                                                                }
     376                                                                frame.updatePanelIfIsLeadSelection(listPath);
     377                                                        }
     378
     379                                                        listPath.getTree().get(childPath, new FutureHandler<Path>(frame) {
     380                                                                @Override
     381                                                                protected void result(Path result) {
     382                                                                        if (!result.isResolved()) {
     383                                                                                log.warn("inconsistency after addition list change: {}", result);
     384                                                                        }
     385                                                                        assert frame.isActive();
     386                                                                        final TreePath treePath = Misc.throwIfNull(frame.getTreeModel().convertToTreePath(result, true));
     387
     388                                                                        // treeModel.nodeStructureChanged(treePath);
     389                                                                        frame.updatePanelIfIsLeadSelection(result);
     390
     391                                                                        log.debug("added {}({}) updated {}", id, result, treePath);
     392                                                                }
     393                                                        });
     394                                                        break;
     395                                                }
     396                                                case Remove: {
     397
     398                                                        TreeModelEvent event = prepareModelEventRegarding(access, id, treeListPath);
     399                                                        access.set(id, null);
     400                                                        if (event != null) {
     401                                                                treeNodesRemoved(event);
     402                                                        } else {
     403                                                                treeStructureChanged(treeListPath);
     404                                                        }
     405
     406                                                        frame.updatePanelIfIsLeadSelection(listPath);
     407
     408                                                        break;
     409                                                }
     410                                                case Modify: {
     411                                                        Path childPath = listPath.appendParam(access.prepareParamFor(id)).tryResolveIfNeeded();
     412                                                        listPath.getTree().get(childPath, new FutureHandler<Path>(frame) {
     413                                                                @Override
     414                                                                protected void result(Path result) {
     415                                                                        assert frame.isActive();
     416                                                                        // final TreePath treePath = frame.getTreeModel().convertToTreePath(result, true);
     417
     418                                                                        TreeModelEvent event = prepareModelEventRegarding(access, id, treeListPath);
     419                                                                        if (event != null) {
     420                                                                                treeNodesChanged(event);
     421                                                                        } else {
     422                                                                                treeStructureChanged(treeListPath);
     423                                                                        }
     424
     425                                                                        frame.updatePanelIfIsLeadSelection(listPath);
     426                                                                        frame.updatePanelIfIsLeadSelection(result);
     427                                                                }
     428                                                        });
     429                                                        break;
     430                                                }
     431                                        }
     432                                }
     433                        });
     434                }
     435
     436        }
     437
     438
     439
     440        protected final Object createdTag = new Object();
     441
     442
     443
    229444}
  • java/main/src/main/java/com/framsticks/gui/tree/TreeNode.java

    r99 r100  
    55import java.util.LinkedList;
    66import java.util.List;
    7 import java.util.concurrent.atomic.AtomicInteger;
    8 
    9 import javax.swing.ImageIcon;
    10 import javax.swing.tree.TreePath;
    11 
    12 import org.apache.log4j.Logger;
    13 
    14 import com.framsticks.core.ListChange;
     7
     8import org.apache.logging.log4j.LogManager;
     9import org.apache.logging.log4j.Logger;
     10
    1511import com.framsticks.core.Node;
    1612import com.framsticks.core.Path;
     
    1915import com.framsticks.gui.ImageProvider;
    2016import com.framsticks.gui.TreeAtFrame;
    21 import com.framsticks.params.AccessInterface;
     17import com.framsticks.gui.TreePanel;
     18import com.framsticks.params.Access;
    2219import com.framsticks.params.CompositeParam;
    2320import com.framsticks.params.EventListener;
    2421import com.framsticks.params.FramsClass;
    25 import com.framsticks.params.PrimitiveParam;
    2622import com.framsticks.params.ValueParam;
    2723import com.framsticks.params.types.EventParam;
     
    3228import com.framsticks.util.lang.Casting;
    3329import com.framsticks.util.lang.Containers;
    34 import com.framsticks.util.lang.Pair;
    3530import com.framsticks.util.swing.TooltipConstructor;
     31
    3632import static com.framsticks.core.TreeOperations.*;
    3733
    3834public class TreeNode extends AbstractNode {
    39         private static final Logger log = Logger.getLogger(TreeNode.class);
    40 
    41 
    42         protected static final AtomicInteger counter = new AtomicInteger();
     35
     36        private static final Logger log = LogManager.getLogger(TreeNode.class);
    4337
    4438        protected final WeakReference<Object> reference;
     39        protected final int hashCode;
     40        protected final TreeAtFrame treeAtFrame;
     41        protected final String textual;
    4542        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 
     43        protected TreePanel panel;
     44
     45        public TreeModel getTreeModel() {
     46                return treeAtFrame.getFrame().getTreeModel();
     47        }
     48
     49        /**
     50         * @param reference
     51         */
    5552        public TreeNode(TreeAtFrame treeAtFrame, Path path) {
    5653                path.assureResolved();
    57                 this.textualPath = path.getTextual();
     54
     55                this.reference = new WeakReference<Object>(path.getTopObject());
     56                this.textual = path.getTextual();
     57                this.treeAtFrame = treeAtFrame;
    5858                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();
     59                hashCode = System.identityHashCode(path.getTopObject());
     60
     61                if (getTree().getSideNote(path.getTopObject(), getTreeModel().createdTag, Object.class) == getTreeModel().createdTag) {
     62                        return;
     63                }
     64
     65                // path.getTree().putSideNote(path.getTopObject(), Textual.class, path.getTextual());
     66                path.getTree().putSideNote(path.getTopObject(), getTreeModel().createdTag, getTreeModel().createdTag);
    6567
    6668                /** Iterate over all EventParams and for matching ValueParams register listeners. */
    67                 if (param instanceof ObjectParam) {
    68                         AccessInterface access = bindAccess(path);
     69                if (path.getTop().getParam() instanceof ObjectParam) {
     70                        Access access = bindAccess(path);
    6971                        FramsClass framsClass = access.getFramsClass();
    7072                        for (EventParam eventParam : Containers.filterInstanceof(framsClass.getParamEntries(), EventParam.class)) {
     
    7779                                        continue;
    7880                                }
    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();
     81                                getTreeModel().registerForEventParam(this, path, eventParam, valueParam);
     82                        }
     83                }
     84        }
     85
     86        @Override
     87        public int hashCode() {
     88                return hashCode;
     89        }
     90
     91        @Override
     92        public boolean equals(Object obj) {
     93                if (obj instanceof TreeNode) {
     94                        return lock() == ((TreeNode) obj).lock();
     95                }
     96                return false;
    21497        }
    21598
     
    220103                        throw new FramsticksException().msg("invalid state - missing referent");
    221104                }
    222                 AccessInterface access = bindAccessFor(referent);
     105                Tree tree = getTree();
     106                Access access = bindAccessForTreeObject(referent);
    223107
    224108                final int count = access.getCompositeParamCount();
     
    227111                }
    228112
     113                /** textual path may be not valid anymore*/
    229114                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 
     115
     116                try {
     117                        Path path = Path.to(tree, getTextual()).appendParam(childParam).tryFindResolution();
     118                        if (!path.isResolved()) {
     119                                path = create(path);
     120                        }
     121                        return prepareTreeNodeForChild(path);
     122                } catch (FramsticksException e) {
     123                }
     124                return new EmptyNode(getFrame(), childParam);
     125
     126        }
     127
     128        public TreeNode prepareTreeNodeForChild(Path path) {
     129                assert path.getTree() == getTree();
     130                Object parent = lock();
     131                Iterator<Node> n = path.getNodes().iterator();
     132                while (n.hasNext()) {
     133                        if (n.next().getObject() == parent) {
     134                                break;
     135                        }
     136                }
     137                if (!n.hasNext()) {
     138                        return null;
     139                        // throw new FramsticksException().msg("tree node is not on path (or is last)").arg("path", path).arg("node", this);
     140                }
     141                return new TreeNode(treeAtFrame, path);
    247142        }
    248143
     
    252147
    253148        @Override
    254         public int getIndexOfChild(AbstractNode child) {
     149        public int getIndexOfChild(Object child) {
    255150                final TreeNode treeChild = Casting.tryCast(TreeNode.class, child);
    256151                if (treeChild == null) {
     
    262157                        return -1;
    263158                }
    264                 final AccessInterface access = bindAccessFor(parentObject);
     159                final Access access = bindAccessForTreeObject(parentObject);
    265160
    266161                final int count = access.getCompositeParamCount();
     
    271166                        }
    272167                }
    273                 log.debug(child + " not found in " + this);
     168                log.debug("{} not found in {}", child, this);
    274169                return -1;
    275170        }
    276171
    277         /**
    278          * @return the param
    279          */
    280         public CompositeParam getParam() {
    281                 return param;
    282         }
    283 
    284         /**
    285          * @return the tree
    286          */
     172        public Frame getFrame() {
     173                return getTreeAtFrame().getFrame();
     174        }
     175
     176        public TreeAtFrame getTreeAtFrame() {
     177                return treeAtFrame;
     178        }
     179
    287180        public Tree getTree() {
    288                 return treeAtFrame.getTree();
    289         }
    290 
     181                return getTreeAtFrame().getTree();
     182        }
     183
     184        protected Path assurePath() {
     185                return Path.to(getTree(), getTextual()).assureResolved();
     186        }
    291187
    292188        @Override
    293189        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();
     190                return getTextual();
     191        }
     192
     193        public Node tryCreateNode() {
     194                Object child = lock();
     195                if (child == null) {
     196                        return null;
     197                }
     198                String textual = getTextual();
     199                Path path = Path.tryTo(getTree(), textual);
     200                if (path.isResolved(textual)) {
     201                        return path.getTop();
     202                }
     203                return null;
     204        }
     205
     206        @Override
     207        public int getChildCount() {
     208                Object referent = lock();
     209                if (referent == null) {
     210                        return 0;
     211                }
     212                Access access = bindAccessForTreeObject(referent);
     213                final int count = access.getCompositeParamCount();
     214                return count;
    299215        }
    300216
     
    305221                        return true;
    306222                }
    307                 return bindAccessFor(referent).getCompositeParamCount() == 0;
    308         }
    309 
    310         protected AccessInterface bindAccessFor(Object child) {
    311                 return treeAtFrame.getTree().prepareAccess(param).select(child);
     223                return bindAccessForTreeObject(referent).getCompositeParamCount() == 0;
     224        }
     225
     226        protected Access bindAccessForTreeObject(Object child) {
     227                return bindAccessFromSideNote(getTree(), child);
    312228        }
    313229
    314230        @Override
    315231        public void render(TreeCellRenderer renderer) {
     232
     233                Object child = lock();
     234                if (child == null) {
     235                        renderer.setToolTipText("?");
     236                        renderer.setText("?");
     237                        renderer.setIcon(ImageProvider.loadImage(ImageProvider.FOLDER_CLOSED));
     238                        return;
     239                }
     240                Access access = bindAccessForTreeObject(child);
     241                CompositeParam param = getTree().getSideNote(child, CompositeParam.class, CompositeParam.class);
    316242                String name = param.getId();
    317243
    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()
     244                StringParam nameParam = Casting.tryCast(StringParam.class, access.getParam("name"));
     245
     246                if (nameParam != null) {
     247                        name = access.get(nameParam, String.class);
     248                }
     249
     250                renderer.setToolTipText(new TooltipConstructor()
    329251                                .append("frams", access.getId())
    330252                                .append("java", child.getClass().getCanonicalName())
     
    333255                                .append("id", param.getId())
    334256                                .append("object", Integer.toHexString(System.identityHashCode(child)))
    335                                 .append("number", number)
    336                                 .append("textual path", textualPath)
     257                                .append("size", access.getCompositeParamCount())
    337258                                .build());
    338                 } else {
    339                         renderer.setToolTipText(new TooltipConstructor()
    340                                 .append("param", param)
    341                                 .append("textual path", textualPath)
    342                                 .build());
    343                 }
     259
     260                renderer.setIcon(ImageProvider.loadImage(TreeCellRenderer.findIconName(param)));
    344261                renderer.setText(name);
    345                 renderer.setIcon(imageIcon);
    346 
     262        }
     263
     264        // public static class Textual {
     265        // }
     266
     267        public String getTextual() {
     268                return textual;
     269                // return getTree().getSideNote(lock(), Textual.class, String.class);
     270        }
     271
     272        protected final Object listenersTag = new Object();
     273
     274        public List<EventListener<?>> getListeners() {
     275                @SuppressWarnings("unchecked")
     276                List<EventListener<?>> result = getTree().getSideNote(lock(), listenersTag, List.class);
     277                if (result == null) {
     278                        result = new LinkedList<>();
     279                        getTree().putSideNote(lock(), listenersTag, result);
     280                }
     281
     282                return result;
     283        }
     284
     285        protected <A> void tryAddListener(final Path path, final EventParam eventParam, Class<A> argumentType, final EventListener<A> listener) {
     286                getTree().addListener(path, eventParam, listener, argumentType, new FutureHandler<Void>(getFrame()) {
     287                        @Override
     288                        protected void result(Void result) {
     289                                assert getFrame().isActive();
     290                                log.debug("registered gui listener for {} at {}", eventParam, path);
     291                                getListeners().add(listener);
     292                        }
     293                });
     294        }
     295
     296        @Override
     297        public TreePanel getPanel() {
     298                if (panel != null) {
     299                        return panel;
     300                }
     301                panel = getTreeAtFrame().preparePanel(param);
     302                return panel;
    347303        }
    348304
Note: See TracChangeset for help on using the changeset viewer.