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/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}
Note: See TracChangeset for help on using the changeset viewer.