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.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • 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.