Changeset 3262 in josm for trunk/src/org


Ignore:
Timestamp:
2010-05-18T23:43:52+02:00 (14 years ago)
Author:
bastiK
Message:

extended command list dialog; added inspection panel

Location:
trunk/src/org/openstreetmap/josm
Files:
3 added
30 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/actions/MoveAction.java

    r2323 r3262  
    9494        ? Main.main.undoRedo.commands.getLast() : null;
    9595
    96         if (c instanceof MoveCommand && affectedNodes.equals(((MoveCommand)c).getMovedNodes())) {
     96        if (c instanceof MoveCommand && affectedNodes.equals(((MoveCommand)c).getParticipatingPrimitives())) {
    9797            ((MoveCommand)c).moveAgain(distx, disty);
    9898        } else {
  • trunk/src/org/openstreetmap/josm/actions/mapmode/ExtrudeAction.java

    r3184 r3262  
    190190                // Better way of testing list equality non-order-sensitively?
    191191                if (c instanceof MoveCommand
    192                         && ((MoveCommand)c).getMovedNodes().contains(n1)
    193                         && ((MoveCommand)c).getMovedNodes().contains(n2)
    194                         && ((MoveCommand)c).getMovedNodes().size() == 2) {
     192                        && ((MoveCommand)c).getParticipatingPrimitives().contains(n1)
     193                        && ((MoveCommand)c).getParticipatingPrimitives().contains(n2)
     194                        && ((MoveCommand)c).getParticipatingPrimitives().size() == 2) {
    195195                    // MoveCommand doesn't let us know how much it has already moved the selection
    196196                    // so we have to do some ugly record-keeping.
  • trunk/src/org/openstreetmap/josm/actions/mapmode/SelectAction.java

    r3201 r3262  
    233233
    234234            if (mode == Mode.move) {
    235                 if (c instanceof MoveCommand && affectedNodes.equals(((MoveCommand)c).getMovedNodes())) {
     235                if (c instanceof MoveCommand && affectedNodes.equals(((MoveCommand)c).getParticipatingPrimitives())) {
    236236                    ((MoveCommand)c).moveAgain(dx,dy);
    237237                } else {
  • trunk/src/org/openstreetmap/josm/command/AddCommand.java

    r1990 r3262  
    66
    77import java.util.Collection;
     8import java.util.Collections;
    89
    910import javax.swing.JLabel;
    10 import javax.swing.tree.DefaultMutableTreeNode;
    11 import javax.swing.tree.MutableTreeNode;
    1211
    1312import org.openstreetmap.josm.data.osm.OsmPrimitive;
     
    6160    }
    6261
    63     @Override public MutableTreeNode description() {
     62    @Override public JLabel getDescription() {
    6463        String msg;
    6564        switch(OsmPrimitiveType.from(osm)) {
     
    7069        }
    7170
    72         return new DefaultMutableTreeNode(
    73                 new JLabel(
    74                         tr(msg,
    75                                 osm.getDisplayName(DefaultNameFormatter.getInstance())
    76                         ),
    77                         ImageProvider.get(OsmPrimitiveType.from(osm)),
    78                         JLabel.HORIZONTAL
    79                 )
    80         );
     71        return new JLabel(
     72                tr(msg, osm.getDisplayName(DefaultNameFormatter.getInstance())),
     73                ImageProvider.get(OsmPrimitiveType.from(osm)),
     74                JLabel.HORIZONTAL);
     75    }
     76
     77    @Override
     78    public Collection<OsmPrimitive> getParticipatingPrimitives() {
     79        return Collections.singleton(osm);
    8180    }
    8281}
  • trunk/src/org/openstreetmap/josm/command/AddPrimitivesCommand.java

    r3257 r3262  
    66import java.util.ArrayList;
    77import java.util.Collection;
     8import java.util.HashSet;
    89import java.util.List;
    910
    1011import javax.swing.JLabel;
    11 import javax.swing.tree.DefaultMutableTreeNode;
    12 import javax.swing.tree.MutableTreeNode;
    1312
    1413import org.openstreetmap.josm.data.osm.Node;
     
    5655    }
    5756
    58     @Override
    59     public MutableTreeNode description() {
    60         return new DefaultMutableTreeNode(
    61                 new JLabel(trn("Added {0} object", "Added {0} objects", data.size(), data.size()), null,
    62                         JLabel.HORIZONTAL
    63                 )
     57    @Override public JLabel getDescription() {
     58        return new JLabel(trn("Added {0} object", "Added {0} objects", data.size(), data.size()), null,
     59                            JLabel.HORIZONTAL
    6460        );
    6561    }
     
    7167    }
    7268
     69    @Override
     70    public Collection<? extends OsmPrimitive> getParticipatingPrimitives() {
     71        Collection<OsmPrimitive> prims = new HashSet<OsmPrimitive>();
     72        for (PrimitiveData d : data) {
     73            OsmPrimitive osm = getLayer().data.getPrimitiveById(d);
     74            if (osm == null)
     75                throw new RuntimeException();
     76            prims.add(osm);
     77        }
     78        return prims;
     79    }
    7380}
  • trunk/src/org/openstreetmap/josm/command/ChangeCommand.java

    r3152 r3262  
    88
    99import javax.swing.JLabel;
    10 import javax.swing.tree.DefaultMutableTreeNode;
    11 import javax.swing.tree.MutableTreeNode;
    1210
    1311import org.openstreetmap.josm.data.osm.OsmPrimitive;
     
    5250    }
    5351
    54     @Override public MutableTreeNode description() {
     52    @Override public JLabel getDescription() {
    5553        String msg = "";
    5654        switch(OsmPrimitiveType.from(osm)) {
     
    5957        case RELATION: msg = marktr("Change relation {0}"); break;
    6058        }
    61         return new DefaultMutableTreeNode(
    62                 new JLabel(tr(msg,
    63                         osm.getDisplayName(DefaultNameFormatter.getInstance()),
    64                         ImageProvider.get(OsmPrimitiveType.from(osm)),
    65                         JLabel.HORIZONTAL)));
     59        return new JLabel(tr(msg,
     60                    osm.getDisplayName(DefaultNameFormatter.getInstance())),
     61                    ImageProvider.get(OsmPrimitiveType.from(osm)),
     62                    JLabel.HORIZONTAL);
    6663    }
    6764}
  • trunk/src/org/openstreetmap/josm/command/ChangeNodesCommand.java

    r3142 r3262  
    88
    99import javax.swing.JLabel;
    10 import javax.swing.tree.DefaultMutableTreeNode;
    11 import javax.swing.tree.MutableTreeNode;
    1210
    1311import org.openstreetmap.josm.data.osm.Node;
     
    4846    }
    4947
    50     @Override public MutableTreeNode description() {
     48    @Override public JLabel getDescription() {
    5149        String msg = tr("Changed nodes of {0}", way.getDisplayName(DefaultNameFormatter.getInstance()));
    52         return new DefaultMutableTreeNode(
    53                 new JLabel(msg,
     50        return new JLabel(msg,
    5451                        ImageProvider.get(OsmPrimitiveType.WAY),
    55                         JLabel.HORIZONTAL));
     52                        JLabel.HORIZONTAL);
    5653    }
    5754}
  • trunk/src/org/openstreetmap/josm/command/ChangePropertyCommand.java

    r2990 r3262  
    55import static org.openstreetmap.josm.tools.I18n.tr;
    66
     7import java.util.ArrayList;
    78import java.util.Collection;
     9import java.util.Collections;
    810import java.util.LinkedList;
    911import java.util.List;
    1012
    1113import javax.swing.JLabel;
    12 import javax.swing.tree.DefaultMutableTreeNode;
    13 import javax.swing.tree.MutableTreeNode;
    1414
    1515import org.openstreetmap.josm.data.osm.OsmPrimitive;
     
    9292    }
    9393
    94     @Override public MutableTreeNode description() {
     94    @Override public JLabel getDescription() {
    9595        String text;
    9696        if (objects.size() == 1) {
     
    117117                    : tr("Set {0}={1} for {2} objects", key, value, objects.size());
    118118        }
    119         DefaultMutableTreeNode root = new DefaultMutableTreeNode(new JLabel(text, ImageProvider.get("data", "key"), JLabel.HORIZONTAL));
     119        return new JLabel(text, ImageProvider.get("data", "key"), JLabel.HORIZONTAL);
     120    }
     121
     122    @Override public Collection<PseudoCommand> getChildren() {
    120123        if (objects.size() == 1)
    121             return root;
    122         for (OsmPrimitive osm : objects) {
    123             root.add(new DefaultMutableTreeNode(
    124                     new JLabel(
    125                             osm.getDisplayName(DefaultNameFormatter.getInstance()),
    126                             ImageProvider.get(OsmPrimitiveType.from(osm)),
    127                             JLabel.HORIZONTAL)
    128             )
    129             );
     124            return null;
     125        List<PseudoCommand> children = new ArrayList<PseudoCommand>();
     126        for (final OsmPrimitive osm : objects) {
     127            children.add(new PseudoCommand() {
     128                @Override public JLabel getDescription() {
     129                    return new JLabel(
     130                                osm.getDisplayName(DefaultNameFormatter.getInstance()),
     131                                ImageProvider.get(OsmPrimitiveType.from(osm)),
     132                                JLabel.HORIZONTAL);
     133
     134                }
     135                @Override public Collection<? extends OsmPrimitive> getParticipatingPrimitives() {
     136                    return Collections.singleton(osm);
     137                }
     138
     139            });
    130140        }
    131         return root;
     141        return children;
    132142    }
    133143}
  • trunk/src/org/openstreetmap/josm/command/ChangeRelationMemberRoleCommand.java

    r3083 r3262  
    77
    88import javax.swing.JLabel;
    9 import javax.swing.tree.DefaultMutableTreeNode;
    10 import javax.swing.tree.MutableTreeNode;
    119
    1210import org.openstreetmap.josm.Main;
     
    6765    }
    6866
    69     @Override public MutableTreeNode description() {
    70         return new DefaultMutableTreeNode(
    71                 new JLabel(
     67    @Override public JLabel getDescription() {
     68        return new JLabel(
    7269                        tr("Change relation member role for {0} {1}",
    7370                                OsmPrimitiveType.from(relation),
     
    7572                        ),
    7673                        ImageProvider.get(OsmPrimitiveType.from(relation)),
    77                         JLabel.HORIZONTAL)
     74                        JLabel.HORIZONTAL
    7875        );
    7976    }
  • trunk/src/org/openstreetmap/josm/command/Command.java

    r3034 r3262  
    99import java.util.Map.Entry;
    1010
     11import javax.swing.tree.DefaultMutableTreeNode;
    1112import javax.swing.tree.MutableTreeNode;
    1213
     
    3031 * @author imi
    3132 */
    32 abstract public class Command {
     33abstract public class Command extends PseudoCommand {
    3334
    3435    private static final class CloneVisitor extends AbstractVisitor {
     
    132133     * Replies the layer this command is (or was) applied to.
    133134     *
    134      * @return
    135135     */
    136136    protected  OsmDataLayer getLayer() {
     
    150150            Collection<OsmPrimitive> added);
    151151
    152     abstract public MutableTreeNode description();
     152    /**
     153     * Return the primitives that take part in this command.
     154     */
     155    @Override public Collection<? extends OsmPrimitive> getParticipatingPrimitives() {
     156        return cloneMap.keySet();
     157    }
     158
     159    /**
     160     * Provide a description that can be presented in a list or tree view.
     161     * This override will be removed when
     162     * <code>description()</code> is removed.
     163     */
     164    @Override public Object getDescription() {
     165        return ((DefaultMutableTreeNode) description()).getUserObject();
     166    }
     167
     168    /**
     169     * @deprecated use getDescription() and getChildren() instead
     170     */
     171    @Deprecated
     172    public MutableTreeNode description() {
     173        return null;
     174    }
    153175
    154176}
  • trunk/src/org/openstreetmap/josm/command/ConflictAddCommand.java

    r3083 r3262  
    88import javax.swing.JLabel;
    99import javax.swing.JOptionPane;
    10 import javax.swing.tree.DefaultMutableTreeNode;
    11 import javax.swing.tree.MutableTreeNode;
    1210
    1311import org.openstreetmap.josm.Main;
     
    6563    }
    6664
    67     @Override public MutableTreeNode description() {
    68         return new DefaultMutableTreeNode(
    69                 new JLabel(
     65    @Override public JLabel getDescription() {
     66        return new JLabel(
    7067                        tr("Add conflict for ''{0}''",
    7168                                conflict.getMy().getDisplayName(DefaultNameFormatter.getInstance())
     
    7370                        ImageProvider.get(OsmPrimitiveType.from(conflict.getMy())),
    7471                        JLabel.HORIZONTAL
    75                 )
    7672        );
    7773    }
  • trunk/src/org/openstreetmap/josm/command/CoordinateConflictResolveCommand.java

    r3083 r3262  
    77
    88import javax.swing.JLabel;
    9 import javax.swing.tree.DefaultMutableTreeNode;
    10 import javax.swing.tree.MutableTreeNode;
    119
    1210import org.openstreetmap.josm.data.conflict.Conflict;
     
    4038    }
    4139
    42     @Override
    43     public MutableTreeNode description() {
    44         return new DefaultMutableTreeNode(
    45                 new JLabel(
     40    @Override public JLabel getDescription() {
     41        return new JLabel(
    4642                        tr("Resolve conflicts in coordinates in {0}",conflict.getMy().getId()),
    4743                        ImageProvider.get("data", "object"),
    4844                        JLabel.HORIZONTAL
    49                 )
    5045        );
    5146    }
  • trunk/src/org/openstreetmap/josm/command/DeleteCommand.java

    r3152 r3262  
    148148    public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted,
    149149            Collection<OsmPrimitive> added) {
    150         deleted.addAll(toDelete);
    151     }
    152 
    153     @Override
    154     public MutableTreeNode description() {
     150    }
     151
     152    @Override public JLabel getDescription() {
    155153        if (toDelete.size() == 1) {
    156154            OsmPrimitive primitive = toDelete.iterator().next();
     
    162160            }
    163161
    164             return new DefaultMutableTreeNode(new JLabel(tr(msg, primitive.getDisplayName(DefaultNameFormatter.getInstance())),
    165                     ImageProvider.get(OsmPrimitiveType.from(primitive)), JLabel.HORIZONTAL));
    166         }
    167 
    168         Set<OsmPrimitiveType> typesToDelete = new HashSet<OsmPrimitiveType>();
    169         for (OsmPrimitive osm : toDelete) {
    170             typesToDelete.add(OsmPrimitiveType.from(osm));
    171         }
    172         String msg = "";
    173         String apiname = "object";
    174         if (typesToDelete.size() > 1) {
    175             msg = trn("Delete {0} object", "Delete {0} objects", toDelete.size(), toDelete.size());
     162            return new JLabel(tr(msg, primitive.getDisplayName(DefaultNameFormatter.getInstance())),
     163                    ImageProvider.get(OsmPrimitiveType.from(primitive)), JLabel.HORIZONTAL);
    176164        } else {
    177             OsmPrimitiveType t = typesToDelete.iterator().next();
    178             apiname = t.getAPIName();
    179             switch(t) {
    180             case NODE: msg = trn("Delete {0} node", "Delete {0} nodes", toDelete.size(), toDelete.size()); break;
    181             case WAY: msg = trn("Delete {0} way", "Delete {0} ways", toDelete.size(), toDelete.size()); break;
    182             case RELATION: msg = trn("Delete {0} relation", "Delete {0} relations", toDelete.size(), toDelete.size()); break;
    183             }
    184         }
    185         DefaultMutableTreeNode root = new DefaultMutableTreeNode(
    186                 new JLabel(msg, ImageProvider.get("data", apiname), JLabel.HORIZONTAL)
    187         );
    188         for (OsmPrimitive osm : toDelete) {
    189             root.add(new DefaultMutableTreeNode(new JLabel(
    190                     osm.getDisplayName(DefaultNameFormatter.getInstance()),
    191                     ImageProvider.get(OsmPrimitiveType.from(osm)), JLabel.HORIZONTAL)));
    192         }
    193         return root;
     165            Set<OsmPrimitiveType> typesToDelete = new HashSet<OsmPrimitiveType>();
     166            for (OsmPrimitive osm : toDelete) {
     167                typesToDelete.add(OsmPrimitiveType.from(osm));
     168            }
     169            String msg = "";
     170            String apiname = "object";
     171            if (typesToDelete.size() > 1) {
     172                msg = trn("Delete {0} object", "Delete {0} objects", toDelete.size(), toDelete.size());
     173            } else {
     174                OsmPrimitiveType t = typesToDelete.iterator().next();
     175                apiname = t.getAPIName();
     176                switch(t) {
     177                case NODE: msg = trn("Delete {0} node", "Delete {0} nodes", toDelete.size(), toDelete.size()); break;
     178                case WAY: msg = trn("Delete {0} way", "Delete {0} ways", toDelete.size(), toDelete.size()); break;
     179                case RELATION: msg = trn("Delete {0} relation", "Delete {0} relations", toDelete.size(), toDelete.size()); break;
     180                }
     181            }
     182            return  new JLabel(msg, ImageProvider.get("data", apiname), JLabel.HORIZONTAL);
     183        }
     184    }
     185
     186    @Override public Collection<PseudoCommand> getChildren() {
     187        if (toDelete.size() == 1) {
     188            return null;
     189        } else {
     190            List<PseudoCommand> children = new ArrayList<PseudoCommand>();
     191            for (final OsmPrimitive osm : toDelete) {
     192                children.add(new PseudoCommand() {
     193                    @Override public JLabel getDescription() {
     194                        return new JLabel(
     195                            tr("Deleted ''{0}''",
     196                                osm.getDisplayName(DefaultNameFormatter.getInstance())),
     197                            ImageProvider.get(OsmPrimitiveType.from(osm)), JLabel.HORIZONTAL);
     198                        }
     199                    @Override public Collection<? extends OsmPrimitive> getParticipatingPrimitives() {
     200                        return Collections.singleton(osm);
     201                    }
     202
     203                });
     204            }
     205            return children;
     206
     207        }
     208    }
     209
     210    @Override public Collection<? extends OsmPrimitive> getParticipatingPrimitives() {
     211        return toDelete;
    194212    }
    195213
  • trunk/src/org/openstreetmap/josm/command/DeletedStateConflictResolveCommand.java

    r3083 r3262  
    77
    88import javax.swing.JLabel;
    9 import javax.swing.tree.DefaultMutableTreeNode;
    10 import javax.swing.tree.MutableTreeNode;
    119
    1210import org.openstreetmap.josm.data.conflict.Conflict;
     
    4038    }
    4139
    42     @Override
    43     public MutableTreeNode description() {
    44         return new DefaultMutableTreeNode(
    45                 new JLabel(
     40    @Override public JLabel getDescription() {
     41        return new JLabel(
    4642                        tr("Resolve conflicts in deleted state in {0}",conflict.getMy().getId()),
    4743                        ImageProvider.get("data", "object"),
    4844                        JLabel.HORIZONTAL
    49                 )
    5045        );
    5146    }
  • trunk/src/org/openstreetmap/josm/command/ModifiedConflictResolveCommand.java

    r3083 r3262  
    88
    99import javax.swing.JLabel;
    10 import javax.swing.tree.DefaultMutableTreeNode;
    11 import javax.swing.tree.MutableTreeNode;
    1210
    1311import org.openstreetmap.josm.data.conflict.Conflict;
     
    3533    }
    3634
    37     @Override
    38     public MutableTreeNode description() {
     35    @Override public JLabel getDescription() {
    3936        String msg = "";
    4037        switch(OsmPrimitiveType.from(conflict.getMy())) {
     
    4340        case RELATION: msg = marktr("Set the ''modified'' flag for relation {0}"); break;
    4441        }
    45         return new DefaultMutableTreeNode(
    46                 new JLabel(
     42        return new JLabel(
    4743                        tr(msg,conflict.getMy().getId()),
    4844                        ImageProvider.get("data", "object"),
    4945                        JLabel.HORIZONTAL
    50                 )
    5146        );
    5247    }
  • trunk/src/org/openstreetmap/josm/command/MoveCommand.java

    r3253 r3262  
    1111
    1212import javax.swing.JLabel;
    13 import javax.swing.tree.DefaultMutableTreeNode;
    14 import javax.swing.tree.MutableTreeNode;
    1513
    1614import org.openstreetmap.josm.data.coor.LatLon;
     
    118116    }
    119117
    120     @Override public MutableTreeNode description() {
    121         return new DefaultMutableTreeNode(new JLabel(trn("Move {0} node", "Move {0} nodes", nodes.size(), nodes.size()), ImageProvider.get("data", "node"), JLabel.HORIZONTAL));
     118    @Override public JLabel getDescription() {
     119        return new JLabel(trn("Move {0} node", "Move {0} nodes", nodes.size(), nodes.size()), ImageProvider.get("data", "node"), JLabel.HORIZONTAL);
    122120    }
    123121
     122    /**
     123     * @Deprecated use getParticipatingPrimitives() instead
     124     */
     125    @Deprecated
    124126    public Collection<Node> getMovedNodes() {
    125127        return nodes;
    126128    }
     129
     130    @Override
     131    public Collection<Node> getParticipatingPrimitives() {
     132        return nodes;
     133    }
    127134}
  • trunk/src/org/openstreetmap/josm/command/PurgePrimitivesCommand.java

    r3089 r3262  
    55import static org.openstreetmap.josm.tools.I18n.trn;
    66
     7import java.util.ArrayList;
    78import java.util.Collection;
    89import java.util.Collections;
    910import java.util.HashSet;
     11import java.util.List;
    1012import java.util.Set;
    1113import java.util.logging.Logger;
    1214
    1315import javax.swing.JLabel;
    14 import javax.swing.tree.DefaultMutableTreeNode;
    15 import javax.swing.tree.MutableTreeNode;
    1616
    1717import org.openstreetmap.josm.Main;
     
    9696    }
    9797
    98     protected MutableTreeNode getDescription(OsmPrimitive primitive) {
    99         return new DefaultMutableTreeNode(
    100                 new JLabel(
    101                         tr("Purged object ''{0}''", primitive.getDisplayName(DefaultNameFormatter.getInstance())),
     98    @Override public JLabel getDescription() {
     99        if (purgedPrimitives.size() == 1) {
     100            return new JLabel(
     101                tr("Purged object ''{0}''",
     102                        purgedPrimitives.iterator().next().getDisplayName(DefaultNameFormatter.getInstance())),
     103                ImageProvider.get("data", "object"),
     104                JLabel.HORIZONTAL
     105            );
     106        } else {
     107            return new JLabel(trn("Purged {0} object", "Purged {0} objects", purgedPrimitives.size(), purgedPrimitives.size()));
     108        }
     109    }
     110
     111    @Override public Collection<PseudoCommand> getChildren() {
     112        if (purgedPrimitives.size() == 1)
     113            return null;
     114        List<PseudoCommand> children = new ArrayList<PseudoCommand>();
     115        for (final OsmPrimitive osm : purgedPrimitives) {
     116            children.add(new PseudoCommand() {
     117                @Override public JLabel getDescription() {
     118                    return new JLabel(
     119                        tr("Purged object ''{0}''",
     120                                osm.getDisplayName(DefaultNameFormatter.getInstance())),
    102121                        ImageProvider.get("data", "object"),
    103122                        JLabel.HORIZONTAL
    104                 )
    105         );
    106     }
    107 
    108     protected MutableTreeNode getDescription(Collection<OsmPrimitive> primitives) {
    109 
    110         DefaultMutableTreeNode root = new DefaultMutableTreeNode(
    111                 trn("Purged {0} object", "Purged {0} objects", primitives.size(), primitives.size())
    112         );
    113         for (OsmPrimitive p : primitives) {
    114             root.add(getDescription(p));
    115         }
    116         return root;
    117     }
    118 
    119     @Override
    120     public MutableTreeNode description() {
    121         if (purgedPrimitives.size() == 1)
    122             return getDescription(purgedPrimitives.iterator().next());
    123         else
    124             return getDescription(purgedPrimitives);
     123                    );
     124                }
     125                @Override public Collection<? extends OsmPrimitive> getParticipatingPrimitives() {
     126                    return Collections.singleton(osm);
     127                }
     128
     129            });
     130        }
     131        return children;
    125132    }
    126133
  • trunk/src/org/openstreetmap/josm/command/RelationMemberConflictResolverCommand.java

    r3083 r3262  
    99
    1010import javax.swing.JLabel;
    11 import javax.swing.tree.DefaultMutableTreeNode;
    12 import javax.swing.tree.MutableTreeNode;
    1311
    1412import org.openstreetmap.josm.Main;
     
    5149    }
    5250
    53     @Override
    54     public MutableTreeNode description() {
    55         return new DefaultMutableTreeNode(
    56                 new JLabel(
     51    @Override public JLabel getDescription() {
     52        return new JLabel(
    5753                        tr("Resolve conflicts in member list of relation {0}", my.getId()),
    5854                        ImageProvider.get("data", "object"),
    5955                        JLabel.HORIZONTAL
    60                 )
    6156        );
    6257    }
  • trunk/src/org/openstreetmap/josm/command/RotateCommand.java

    r2070 r3262  
    99
    1010import javax.swing.JLabel;
    11 import javax.swing.tree.DefaultMutableTreeNode;
    12 import javax.swing.tree.MutableTreeNode;
    1311
    1412import org.openstreetmap.josm.data.coor.EastNorth;
     
    138136    }
    139137
    140     @Override public MutableTreeNode description() {
    141         return new DefaultMutableTreeNode(new JLabel(trn("Rotate {0} node", "Rotate {0} nodes", nodes.size(), nodes.size()), ImageProvider.get("data", "node"), JLabel.HORIZONTAL));
     138    @Override public JLabel getDescription() {
     139        return new JLabel(trn("Rotate {0} node", "Rotate {0} nodes", nodes.size(), nodes.size()), ImageProvider.get("data", "node"), JLabel.HORIZONTAL);
    142140    }
    143141
  • trunk/src/org/openstreetmap/josm/command/SequenceCommand.java

    r1750 r3262  
    66import java.util.Arrays;
    77import java.util.Collection;
     8import java.util.HashSet;
     9import java.util.List;
    810
    9 import javax.swing.tree.DefaultMutableTreeNode;
    10 import javax.swing.tree.MutableTreeNode;
     11import javax.swing.JLabel;
    1112
    1213import org.openstreetmap.josm.Main;
    1314import org.openstreetmap.josm.data.osm.OsmPrimitive;
     15import org.openstreetmap.josm.tools.ImageProvider;
    1416
    1517/**
     
    8890    }
    8991
    90     @Override public MutableTreeNode description() {
    91         DefaultMutableTreeNode root = new DefaultMutableTreeNode(tr("Sequence")+": "+name);
     92    @Override public JLabel getDescription() {
     93        return new JLabel(tr("Sequence")+": "+name, ImageProvider.get("data", "sequence"), JLabel.HORIZONTAL);
     94    }
     95
     96    @Override
     97    public Collection<PseudoCommand> getChildren() {
     98        return (List) Arrays.asList(sequence);
     99    }
     100
     101    @Override
     102    public Collection<? extends OsmPrimitive> getParticipatingPrimitives() {
     103        Collection<OsmPrimitive> prims = new HashSet<OsmPrimitive>();
    92104        for (Command c : sequence) {
    93             root.add(c.description());
     105            prims.addAll(c.getParticipatingPrimitives());
    94106        }
    95         return root;
     107        return prims;
    96108    }
    97109}
  • trunk/src/org/openstreetmap/josm/command/TagConflictResolveCommand.java

    r3083 r3262  
    1010
    1111import javax.swing.JLabel;
    12 import javax.swing.tree.DefaultMutableTreeNode;
    13 import javax.swing.tree.MutableTreeNode;
    1412
    1513import org.openstreetmap.josm.data.conflict.Conflict;
     
    6159    }
    6260
    63     @Override
    64     public MutableTreeNode description() {
     61    @Override public JLabel getDescription() {
    6562        String msg = "";
    6663        switch(OsmPrimitiveType.from(conflict.getMy())) {
     
    6966        case RELATION: msg = marktr("Resolve {0} tag conflicts in relation {1}"); break;
    7067        }
    71         return new DefaultMutableTreeNode(
    72                 new JLabel(
     68        return new JLabel(
    7369                        tr(msg,getNumDecidedConflicts(), conflict.getMy().getId()),
    7470                        ImageProvider.get("data", "object"),
    7571                        JLabel.HORIZONTAL
    76                 )
    7772        );
    7873    }
  • trunk/src/org/openstreetmap/josm/command/UndeletePrimitivesCommand.java

    r3083 r3262  
    1111
    1212import javax.swing.JLabel;
    13 import javax.swing.tree.DefaultMutableTreeNode;
    14 import javax.swing.tree.MutableTreeNode;
    1513
    1614import org.openstreetmap.josm.data.osm.DataSet;
     
    6260    }
    6361
    64     @Override
    65     public MutableTreeNode description() {
    66         return new DefaultMutableTreeNode(
    67                 new JLabel(
     62    @Override public JLabel getDescription() {
     63        return new JLabel(
    6864                        trn("Undelete {0} primitive", "Undelete {0} primitives", toUndelete.size(), toUndelete.size()),
    6965                        ImageProvider.get("data", "object"),
    7066                        JLabel.HORIZONTAL
    71                 )
    7267        );
    7368    }
  • trunk/src/org/openstreetmap/josm/command/VersionConflictResolveCommand.java

    r3083 r3262  
    88
    99import javax.swing.JLabel;
    10 import javax.swing.tree.DefaultMutableTreeNode;
    11 import javax.swing.tree.MutableTreeNode;
    1210
    1311import org.openstreetmap.josm.data.conflict.Conflict;
     
    3533    }
    3634
    37     @Override
    38     public MutableTreeNode description() {
     35    @Override public JLabel getDescription() {
    3936        String msg = "";
    4037        switch(OsmPrimitiveType.from(conflict.getMy())) {
     
    4340        case RELATION: msg = marktr("Resolve version conflict for relation {0}"); break;
    4441        }
    45         return new DefaultMutableTreeNode(
    46                 new JLabel(
     42        return new JLabel(
    4743                        tr(msg,conflict.getMy().getId()),
    4844                        ImageProvider.get("data", "object"),
    4945                        JLabel.HORIZONTAL
    50                 )
    5146        );
    5247    }
  • trunk/src/org/openstreetmap/josm/command/WayNodesConflictResolverCommand.java

    r3083 r3262  
    99
    1010import javax.swing.JLabel;
    11 import javax.swing.tree.DefaultMutableTreeNode;
    12 import javax.swing.tree.MutableTreeNode;
    1311
    1412import org.openstreetmap.josm.data.conflict.Conflict;
     
    4745    }
    4846
    49     @Override
    50     public MutableTreeNode description() {
    51         return new DefaultMutableTreeNode(
    52                 new JLabel(
     47    @Override public JLabel getDescription() {
     48        return new JLabel(
    5349                        tr("Resolve conflicts in node list of way {0}", conflict.getMy().getId()),
    5450                        ImageProvider.get("data", "object"),
    5551                        JLabel.HORIZONTAL
    56                 )
    5752        );
    5853    }
  • trunk/src/org/openstreetmap/josm/data/UndoRedoHandler.java

    r3225 r3262  
    2323     * The stack for redoing commands
    2424     */
    25     private final Stack<Command> redoCommands = new Stack<Command>();
     25    public final LinkedList<Command> redoCommands = new LinkedList<Command>();
    2626
    2727    public final LinkedList<CommandQueueListener> listenerCommands = new LinkedList<CommandQueueListener>();
     
    6464     * Undoes the last added command.
    6565     */
    66     synchronized public void undo() {
     66    public void undo() {
     67        undo(1);
     68    }
     69
     70    /**
     71     * Undoes multiple commands.
     72     */
     73    synchronized public void undo(int num) {
    6774        if (commands.isEmpty())
    6875            return;
    6976        Collection<? extends OsmPrimitive> oldSelection = Main.main.getCurrentDataSet().getSelected();
    70         final Command c = commands.removeLast();
    71         c.undoCommand();
    72         redoCommands.push(c);
     77        for (int i=1; i<=num; ++i) {
     78            final Command c = commands.removeLast();
     79            c.undoCommand();
     80            redoCommands.addFirst(c);
     81            if (commands.isEmpty())
     82                break;
     83        }
    7384        fireCommandsChanged();
    7485        Collection<? extends OsmPrimitive> newSelection = Main.main.getCurrentDataSet().getSelected();
     
    8091    /**
    8192     * Redoes the last undoed command.
    82      * TODO: This has to be moved to a central place in order to support multiple layers.
    8393     */
    8494    public void redo() {
     95        redo(1);
     96    }
     97
     98    /**
     99     * Redoes multiple commands.
     100     */
     101    public void redo(int num) {
    85102        if (redoCommands.isEmpty())
    86103            return;
    87104        Collection<? extends OsmPrimitive> oldSelection = Main.main.getCurrentDataSet().getSelected();
    88         final Command c = redoCommands.pop();
    89         c.executeCommand();
    90         commands.add(c);
     105        for (int i=0; i<num; ++i) {
     106            final Command c = redoCommands.pop();
     107            c.executeCommand();
     108            commands.add(c);
     109            if (redoCommands.isEmpty())
     110                break;
     111        }
    91112        fireCommandsChanged();
    92113        Collection<? extends OsmPrimitive> newSelection = Main.main.getCurrentDataSet().getSelected();
  • trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java

    r3207 r3262  
    383383
    384384    /**
    385      * Replies <code>true</code>, if the object is usable.
    386      *
    387      * @return <code>true</code>, if the object is unusable.
     385     * Replies <code>true</code>, if the object is usable (i.e. complete
     386     * and not deleted).
     387     *
     388     * @return <code>true</code>, if the object is usable.
    388389     * @see #delete(boolean)
    389390     */
  • trunk/src/org/openstreetmap/josm/data/osm/Relation.java

    r3155 r3262  
    5353
    5454    /**
    55      *
    56      * @since 1926
     55     * @return number of members
    5756     */
    5857    public int getMembersCount() {
     
    6059    }
    6160
    62     /**
    63      *
    64      * @param index
    65      * @return
    66      * @since 1926
    67      */
    6861    public RelationMember getMember(int index) {
    6962        return members.get(index);
    7063    }
    7164
    72     /**
    73      *
    74      * @param member
    75      * @since 1951
    76      */
    7765    public void addMember(RelationMember member) {
    7866        members.add(member);
     
    8169    }
    8270
    83     /**
    84      *
    85      * @param index
    86      * @param member
    87      * @since 1951
    88      */
    8971    public void addMember(int index, RelationMember member) {
    9072        members.add(index, member);
     
    9880     * @param member
    9981     * @return Member that was at the position
    100      * @since 1951
    10182     */
    10283    public RelationMember setMember(int index, RelationMember member) {
     
    11495     * @param index
    11596     * @return Member that was at the position
    116      * @since 1951
    11797     */
    11898    public RelationMember removeMember(int index) {
  • trunk/src/org/openstreetmap/josm/data/osm/User.java

    r3034 r3262  
    190190        return true;
    191191    }
     192
     193    @Override
     194    public String toString() {
     195        StringBuffer s = new StringBuffer();
     196        s.append("id:"+uid);
     197        if (names.size() == 1) {
     198            s.append(" name:"+getName());
     199        }
     200        else if (names.size() > 1) {
     201            s.append(String.format(" %d names:%s", names.size(), getName()));
     202        }
     203        return s.toString();
     204    }
    192205}
  • trunk/src/org/openstreetmap/josm/gui/dialogs/CommandStackDialog.java

    r2224 r3262  
    66import java.awt.BorderLayout;
    77import java.awt.Component;
     8import java.awt.Dimension;
     9import java.awt.GridBagLayout;
     10import java.awt.Point;
     11import java.awt.event.ActionEvent;
    812import java.awt.event.KeyEvent;
    9 import java.util.Collection;
    10 
     13import java.awt.event.MouseEvent;
     14
     15import java.util.ArrayList;
     16import java.util.LinkedHashSet;
     17import java.util.List;
     18import java.util.Set;
     19
     20import javax.swing.AbstractAction;
     21import javax.swing.Box;
    1122import javax.swing.JLabel;
     23import javax.swing.JPanel;
     24import javax.swing.JPopupMenu;
    1225import javax.swing.JScrollPane;
     26import javax.swing.JSeparator;
    1327import javax.swing.JTree;
     28import javax.swing.event.TreeModelEvent;
     29import javax.swing.event.TreeModelListener;
     30import javax.swing.event.TreeSelectionEvent;
     31import javax.swing.event.TreeSelectionListener;
    1432import javax.swing.tree.DefaultMutableTreeNode;
    1533import javax.swing.tree.DefaultTreeCellRenderer;
    1634import javax.swing.tree.DefaultTreeModel;
     35import javax.swing.tree.TreePath;
     36import javax.swing.tree.TreeSelectionModel;
    1737
    1838import org.openstreetmap.josm.Main;
    1939import org.openstreetmap.josm.command.Command;
     40import org.openstreetmap.josm.command.PseudoCommand;
     41import org.openstreetmap.josm.data.osm.DatasetCollection;
     42import org.openstreetmap.josm.data.osm.OsmPrimitive;
    2043import org.openstreetmap.josm.gui.MapFrame;
     44import org.openstreetmap.josm.gui.SideButton;
     45import org.openstreetmap.josm.gui.layer.OsmDataLayer;
    2146import org.openstreetmap.josm.gui.layer.OsmDataLayer.CommandQueueListener;
     47import org.openstreetmap.josm.gui.widgets.PopupMenuLauncher;
     48import org.openstreetmap.josm.tools.GBC;
     49import org.openstreetmap.josm.tools.ImageProvider;
     50import org.openstreetmap.josm.tools.Predicate;
    2251import org.openstreetmap.josm.tools.Shortcut;
    2352
    2453public class CommandStackDialog extends ToggleDialog implements CommandQueueListener {
    2554
    26     private DefaultTreeModel treeModel = new DefaultTreeModel(new DefaultMutableTreeNode());
    27     private JTree tree = new JTree(treeModel);
     55    private DefaultTreeModel undoTreeModel = new DefaultTreeModel(new DefaultMutableTreeNode());
     56    private DefaultTreeModel redoTreeModel = new DefaultTreeModel(new DefaultMutableTreeNode());
     57
     58    private JTree undoTree = new JTree(undoTreeModel);
     59    private JTree redoTree = new JTree(redoTreeModel);
     60
     61    private UndoRedoSelectionListener undoSelectionListener;
     62    private UndoRedoSelectionListener redoSelectionListener;
     63
     64    private JScrollPane scrollPane;
     65    private JSeparator separator = new JSeparator();
     66    // only visible, if separator is the top most component
     67    private Component spacer = Box.createRigidArea(new Dimension(0, 3));
     68
     69    // last operation is remembered to select the next undo/redo entry in the list
     70    // after undo/redo command
     71    private UndoRedoType lastOperation = UndoRedoType.UNDO;
    2872
    2973    public CommandStackDialog(final MapFrame mapFrame) {
     
    3276        Main.main.undoRedo.listenerCommands.add(this);
    3377
    34         tree.setRootVisible(false);
    35         tree.setShowsRootHandles(true);
    36         tree.expandRow(0);
    37         tree.setCellRenderer(new DefaultTreeCellRenderer(){
    38             @Override public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) {
    39                 super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
    40                 DefaultMutableTreeNode v = (DefaultMutableTreeNode)value;
    41                 if (v.getUserObject() instanceof JLabel) {
    42                     JLabel l = (JLabel)v.getUserObject();
    43                     setIcon(l.getIcon());
    44                     setText(l.getText());
    45                 }
    46                 return this;
     78        undoTree.addMouseListener(new PopupMenuHandler());
     79        undoTree.setRootVisible(false);
     80        undoTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
     81        undoTree.setShowsRootHandles(true);
     82        undoTree.expandRow(0);
     83        undoTree.setCellRenderer(new CommandCellRenderer());
     84        undoSelectionListener = new UndoRedoSelectionListener(undoTree);
     85        undoTree.getSelectionModel().addTreeSelectionListener(undoSelectionListener);
     86
     87        redoTree.addMouseListener(new PopupMenuHandler());
     88        redoTree.setRootVisible(false);
     89        redoTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
     90        redoTree.setShowsRootHandles(true);
     91        redoTree.expandRow(0);
     92        redoTree.setCellRenderer(new CommandCellRenderer());
     93        redoSelectionListener = new UndoRedoSelectionListener(redoTree);
     94        redoTree.getSelectionModel().addTreeSelectionListener(redoSelectionListener);
     95
     96        JPanel treesPanel = new JPanel(new GridBagLayout());
     97
     98        treesPanel.add(spacer, GBC.eol());
     99        spacer.setVisible(false);
     100        treesPanel.add(undoTree, GBC.eol().fill(GBC.HORIZONTAL));
     101        separator.setVisible(false);
     102        treesPanel.add(separator, GBC.eol().fill(GBC.HORIZONTAL));
     103        treesPanel.add(redoTree, GBC.eol().fill(GBC.HORIZONTAL));
     104        treesPanel.add(Box.createRigidArea(new Dimension(0, 0)), GBC.std().weight(0, 1));
     105        treesPanel.setBackground(redoTree.getBackground());
     106
     107        scrollPane = new JScrollPane(treesPanel);
     108        add(scrollPane, BorderLayout.CENTER);
     109        add(createButtonPanel(), BorderLayout.SOUTH);
     110    }
     111
     112    private static class CommandCellRenderer extends DefaultTreeCellRenderer {
     113        @Override public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) {
     114            super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
     115            DefaultMutableTreeNode v = (DefaultMutableTreeNode)value;
     116            if (v.getUserObject() instanceof JLabel) {
     117                JLabel l = (JLabel)v.getUserObject();
     118                setIcon(l.getIcon());
     119                setText(l.getText());
     120            }
     121            return this;
     122        }
     123    }
     124
     125    /**
     126     * Selection listener for undo and redo area.
     127     * If one is clicked, takes away the selection from the other, so
     128     * it behaves as if it was one component.
     129     */
     130    private class UndoRedoSelectionListener implements TreeSelectionListener {
     131        private JTree source;
     132
     133        public UndoRedoSelectionListener(JTree source) {
     134            this.source = source;
     135        }
     136
     137        @Override
     138        public void valueChanged(TreeSelectionEvent e) {
     139            if (source == undoTree) {
     140                redoTree.getSelectionModel().removeTreeSelectionListener(redoSelectionListener);
     141                redoTree.clearSelection();
     142                redoTree.getSelectionModel().addTreeSelectionListener(redoSelectionListener);
     143            }
     144            if (source == redoTree) {
     145                undoTree.getSelectionModel().removeTreeSelectionListener(undoSelectionListener);
     146                undoTree.clearSelection();
     147                undoTree.getSelectionModel().addTreeSelectionListener(undoSelectionListener);
     148            }
     149        }
     150    }
     151
     152    protected JPanel createButtonPanel() {
     153        JPanel buttonPanel = getButtonPanel(3);
     154
     155        SelectAction selectAction = new SelectAction();
     156        wireUpdateEnabledStateUpdater(selectAction, undoTree);
     157        wireUpdateEnabledStateUpdater(selectAction, redoTree);
     158        buttonPanel.add(new SideButton(selectAction));
     159
     160        UndoRedoAction undoAction = new UndoRedoAction(UndoRedoType.UNDO);
     161        wireUpdateEnabledStateUpdater(undoAction, undoTree);
     162        buttonPanel.add(new SideButton(undoAction));
     163
     164        UndoRedoAction redoAction = new UndoRedoAction(UndoRedoType.REDO);
     165        wireUpdateEnabledStateUpdater(redoAction, redoTree);
     166        buttonPanel.add(new SideButton(redoAction));
     167
     168        return buttonPanel;
     169    }
     170
     171    /**
     172     * Interface to provide a callback for enabled state update.
     173     */
     174    protected interface IEnabledStateUpdating {
     175        void updateEnabledState();
     176    }
     177
     178    /**
     179     * Wires updater for enabled state to the events.
     180     */
     181    protected void wireUpdateEnabledStateUpdater(final IEnabledStateUpdating updater, JTree tree) {
     182        addShowNotifyListener(updater);
     183
     184        tree.addTreeSelectionListener(new TreeSelectionListener() {
     185            @Override
     186            public void valueChanged(TreeSelectionEvent e) {
     187                updater.updateEnabledState();
    47188            }
    48189        });
    49         tree.setVisibleRowCount(8);
    50         add(new JScrollPane(tree), BorderLayout.CENTER);
    51     }
    52 
    53     @Override public void setVisible(boolean v) {
    54         if (v) {
    55             buildList();
    56         } else if (tree != null) {
    57             treeModel.setRoot(new DefaultMutableTreeNode());
    58         }
    59         super.setVisible(v);
    60     }
    61 
    62     private void buildList() {
    63         if(Main.main.undoRedo.commands.size() != 0) {
    64             setTitle(tr("Command Stack: {0}", Main.main.undoRedo.commands.size()));
    65         } else {
    66             setTitle(tr("Command Stack"));
    67         }
     190
     191        tree.getModel().addTreeModelListener(new TreeModelListener() {
     192            @Override
     193            public void treeNodesChanged(TreeModelEvent e) {
     194                updater.updateEnabledState();
     195            }
     196
     197            @Override
     198            public void treeNodesInserted(TreeModelEvent e) {
     199                updater.updateEnabledState();
     200            }
     201
     202            @Override
     203            public void treeNodesRemoved(TreeModelEvent e) {
     204                updater.updateEnabledState();
     205            }
     206
     207            @Override
     208            public void treeStructureChanged(TreeModelEvent e) {
     209                updater.updateEnabledState();
     210            }
     211        });
     212    }
     213
     214    @Override
     215    public void showNotify() {
     216        buildTrees();
     217        for (IEnabledStateUpdating listener : showNotifyListener) {
     218            listener.updateEnabledState();
     219        }
     220    }
     221
     222    /**
     223     * Simple listener setup to update the button enabled state when the side dialog shows.
     224     */
     225    Set<IEnabledStateUpdating> showNotifyListener = new LinkedHashSet<IEnabledStateUpdating>();
     226
     227    private void addShowNotifyListener(IEnabledStateUpdating listener) {
     228        showNotifyListener.add(listener);
     229    }
     230
     231    @Override
     232    public void hideNotify() {
     233        undoTreeModel.setRoot(new DefaultMutableTreeNode());
     234        redoTreeModel.setRoot(new DefaultMutableTreeNode());
     235    }
     236
     237    /**
     238     * Build the trees of undo and redo commands (initially or when
     239     * they have changed).
     240     */
     241    private void buildTrees() {
     242        setTitle(tr("Command Stack"));
    68243        if (Main.map == null || Main.map.mapView == null || Main.map.mapView.getEditLayer() == null)
    69244            return;
    70         Collection<Command> commands = Main.main.undoRedo.commands;
    71         DefaultMutableTreeNode root = new DefaultMutableTreeNode();
    72         for (Command c : commands) {
    73             root.add(c.description());
    74         }
    75         treeModel.setRoot(root);
    76         tree.scrollRowToVisible(treeModel.getChildCount(root)-1);
    77     }
    78 
     245
     246        List<Command> undoCommands = Main.main.undoRedo.commands;
     247        DefaultMutableTreeNode undoRoot = new DefaultMutableTreeNode();
     248        for (int i=0; i<undoCommands.size(); ++i) {
     249            undoRoot.add(getNodeForCommand(undoCommands.get(i), i));
     250        }
     251        undoTreeModel.setRoot(undoRoot);
     252        undoTree.scrollRowToVisible(undoTreeModel.getChildCount(undoRoot)-1);
     253        scrollPane.getHorizontalScrollBar().setValue(0);
     254
     255        List<Command> redoCommands = Main.main.undoRedo.redoCommands;
     256        DefaultMutableTreeNode redoRoot = new DefaultMutableTreeNode();
     257        for (int i=0; i<redoCommands.size(); ++i) {
     258            redoRoot.add(getNodeForCommand(redoCommands.get(i), i));
     259        }
     260        redoTreeModel.setRoot(redoRoot);
     261        if (redoTreeModel.getChildCount(redoRoot) > 0) {
     262            redoTree.scrollRowToVisible(0);
     263            scrollPane.getHorizontalScrollBar().setValue(0);
     264        }
     265
     266        separator.setVisible(!undoCommands.isEmpty() || !redoCommands.isEmpty());
     267        spacer.setVisible(undoCommands.isEmpty() && !redoCommands.isEmpty());
     268
     269        // if one tree is empty, move selection to the other
     270        switch (lastOperation) {
     271            case UNDO:
     272                if (undoCommands.isEmpty()) {
     273                    lastOperation = UndoRedoType.REDO;
     274                }
     275                break;
     276            case REDO:
     277                if (redoCommands.isEmpty()) {
     278                    lastOperation = UndoRedoType.UNDO;
     279                }
     280                break;
     281        }
     282
     283        // select the next command to undo/redo
     284        switch (lastOperation) {
     285            case UNDO:
     286                undoTree.setSelectionRow(undoTree.getRowCount()-1);
     287                break;
     288            case REDO:
     289                redoTree.setSelectionRow(0);
     290                break;
     291        }
     292    }
     293
     294    /**
     295     * Wraps a command in a CommandListMutableTreeNode.
     296     * Recursively adds child commands.
     297     */
     298    protected CommandListMutableTreeNode getNodeForCommand(PseudoCommand c, int idx) {
     299        CommandListMutableTreeNode node = new CommandListMutableTreeNode(c, idx);
     300        if (c.getChildren() != null) {
     301            List<PseudoCommand> children = new ArrayList<PseudoCommand>(c.getChildren());
     302            for (int i=0; i<children.size(); ++i) {
     303                node.add(getNodeForCommand(children.get(i), i));
     304            }
     305        }
     306        return node;
     307    }
     308
     309    @Override
    79310    public void commandChanged(int queueSize, int redoSize) {
    80311        if (!isVisible())
    81312            return;
    82         treeModel.setRoot(new DefaultMutableTreeNode());
    83         buildList();
     313        buildTrees();
     314    }
     315
     316    public class SelectAction extends AbstractAction implements IEnabledStateUpdating {
     317
     318        public SelectAction() {
     319            super();
     320            putValue(NAME,tr("Select"));
     321            putValue(SHORT_DESCRIPTION, tr("Selects the objects that take part in this command (unless currently deleted)"));
     322            putValue(SMALL_ICON, ImageProvider.get("dialogs","select"));
     323
     324        }
     325
     326        @Override
     327        public void actionPerformed(ActionEvent e) {
     328            TreePath path;
     329            undoTree.getSelectionPath();
     330            if (!undoTree.isSelectionEmpty()) {
     331                path = undoTree.getSelectionPath();
     332            } else if (!redoTree.isSelectionEmpty()) {
     333                path = redoTree.getSelectionPath();
     334            } else
     335                throw new IllegalStateException();
     336
     337            if (Main.map == null || Main.map.mapView == null || Main.map.mapView.getEditLayer() == null) return;
     338            PseudoCommand c = ((CommandListMutableTreeNode) path.getLastPathComponent()).getCommand();
     339
     340            final OsmDataLayer currentLayer = Main.map.mapView.getEditLayer();
     341
     342            DatasetCollection<OsmPrimitive> prims = new DatasetCollection<OsmPrimitive>(
     343                    c.getParticipatingPrimitives(),
     344                    new Predicate<OsmPrimitive>(){
     345                        @Override
     346                        public boolean evaluate(OsmPrimitive o) {
     347                            OsmPrimitive p = currentLayer.data.getPrimitiveById(o);
     348                            return p != null && p.isUsable();
     349                        }
     350                    }
     351            );
     352            Main.map.mapView.getEditLayer().data.setSelected(prims);
     353        }
     354
     355        @Override
     356        public void updateEnabledState() {
     357            setEnabled(!undoTree.isSelectionEmpty() || !redoTree.isSelectionEmpty());
     358        }
     359
     360    }
     361
     362    /**
     363     * undo / redo switch to reduce duplicate code
     364     */
     365    protected enum UndoRedoType {UNDO, REDO};
     366
     367    /**
     368     * Action to undo or redo all commands up to (and including) the seleced item.
     369     */
     370    protected class UndoRedoAction extends AbstractAction implements IEnabledStateUpdating {
     371        private UndoRedoType type;
     372        private JTree tree;
     373
     374        /**
     375         * constructor
     376         * @param type decide whether it is an undo action or a redo action
     377         */
     378        public UndoRedoAction(UndoRedoType type) {
     379            super();
     380            this.type = type;
     381            switch (type) {
     382                case UNDO:
     383                    tree = undoTree;
     384                    putValue(NAME,tr("Undo"));
     385                    putValue(SHORT_DESCRIPTION, tr("Undo the selected and all later commands"));
     386                    putValue(SMALL_ICON, ImageProvider.get("undo"));
     387                    break;
     388                case REDO:
     389                    tree = redoTree;
     390                    putValue(NAME,tr("Redo"));
     391                    putValue(SHORT_DESCRIPTION, tr("Redo the selected and all earlier commands"));
     392                    putValue(SMALL_ICON, ImageProvider.get("redo"));
     393                    break;
     394            }
     395        }
     396
     397        @Override
     398        public void actionPerformed(ActionEvent e) {
     399            lastOperation = type;
     400            TreePath path = tree.getSelectionPath();
     401
     402            // we can only undo top level commands
     403            if (path.getPathCount() != 2)
     404                throw new IllegalStateException();
     405
     406            int idx = ((CommandListMutableTreeNode) path.getLastPathComponent()).getIndex();
     407
     408            // calculate the number of commands to undo/redo; then do it
     409            switch (type) {
     410                case UNDO:
     411                    int numUndo = ((DefaultMutableTreeNode) undoTreeModel.getRoot()).getChildCount() - idx;
     412                    Main.main.undoRedo.undo(numUndo);
     413                    break;
     414                case REDO:
     415                    int numRedo = idx+1;
     416                    Main.main.undoRedo.redo(numRedo);
     417                    break;
     418            }
     419            Main.map.repaint();
     420        }
     421
     422        @Override
     423        public void updateEnabledState() {
     424            // do not allow execution if nothing is selected or a sub command was selected
     425            setEnabled(!tree.isSelectionEmpty() && tree.getSelectionPath().getPathCount()==2);
     426        }
     427    }
     428
     429    class PopupMenuHandler extends PopupMenuLauncher {
     430        @Override
     431        public void launch(MouseEvent evt) {
     432            Point p = evt.getPoint();
     433            JTree tree = (JTree) evt.getSource();
     434            int row = tree.getRowForLocation(p.x, p.y);
     435            if (row != -1) {
     436                TreePath path = tree.getPathForLocation(p.x, p.y);
     437                // right click on unselected element -> select it first
     438                if (!tree.isPathSelected(path)) {
     439                    tree.setSelectionPath(path);
     440                }
     441                TreePath[] selPaths = tree.getSelectionPaths();
     442
     443                CommandStackPopup menu = new CommandStackPopup(selPaths);
     444                menu.show(tree, p.x, p.y-3);
     445            }
     446        }
     447    }
     448
     449    private class CommandStackPopup extends JPopupMenu {
     450        private TreePath[] sel;
     451        public CommandStackPopup(TreePath[] sel){
     452            this.sel = sel;
     453            add(new SelectAction());
     454        }
    84455    }
    85456}
  • trunk/src/org/openstreetmap/josm/gui/dialogs/SelectionListDialog.java

    r3176 r3262  
    9494    private ZoomToListSelection actZoomToListSelection;
    9595    private DownloadSelectedIncompleteMembersAction actDownloadSelectedIncompleteMembers;
     96    private InspectAction actInspect;
    9697
    9798    /**
     
    176177        lstPrimitives.getSelectionModel().addListSelectionListener(actDownloadSelectedIncompleteMembers);
    177178
     179        actInspect = new InspectAction();
     180        lstPrimitives.getSelectionModel().addListSelectionListener(actInspect);
     181
    178182        lstPrimitives.addMouseListener(new SelectionPopupMenuLauncher());
    179183        lstPrimitives.addMouseListener(new DblClickHandler());
     
    248252            addSeparator();
    249253            add(actDownloadSelectedIncompleteMembers);
     254            addSeparator();
     255            add(actInspect);
    250256        }
    251257    }
     
    741747     *
    742748     */
    743     class DownloadSelectedIncompleteMembersAction extends AbstractAction implements ListSelectionListener{
     749    class DownloadSelectedIncompleteMembersAction extends AbstractAction implements ListSelectionListener {
    744750        public DownloadSelectedIncompleteMembersAction() {
    745751            putValue(SHORT_DESCRIPTION, tr("Download incomplete members of selected relations"));
     
    771777        protected void updateEnabledState() {
    772778            setEnabled(!model.getSelectedRelationsWithIncompleteMembers().isEmpty());
     779        }
     780
     781        public void valueChanged(ListSelectionEvent e) {
     782            updateEnabledState();
     783        }
     784    }
     785
     786    class InspectAction extends AbstractAction implements ListSelectionListener {
     787        public InspectAction() {
     788            putValue(SHORT_DESCRIPTION, tr("Get detailed information on the internal state of the objects."));
     789            putValue(NAME, tr("Inspect"));
     790            updateEnabledState();
     791        }
     792
     793        public void actionPerformed(ActionEvent e) {
     794            Collection<OsmPrimitive> sel = model.getSelected();
     795            if (sel.isEmpty()) return;
     796            InspectPrimitiveDialog inspectDialog = new InspectPrimitiveDialog(sel);
     797            inspectDialog.showDialog();
     798        }
     799
     800        public void updateEnabledState() {
     801            setEnabled(!model.getSelected().isEmpty());
    773802        }
    774803
Note: See TracChangeset for help on using the changeset viewer.