Changeset 3262 in josm


Ignore:
Timestamp:
May 18, 2010 11:43:52 PM (3 years ago)
Author:
bastiK
Message:

extended command list dialog; added inspection panel

Location:
trunk
Files:
4 added
31 edited

Legend:

Unmodified
Added
Removed
  • trunk/data_nodist/README

    r3261 r3262  
    88Exif.GPSInfo.GPSImgDirection                 Rational    1  4650/100 
    99... 
    10 exif-direction-example.jpg 
    11 -------------------------- 
    12  
    13 Image that contains direction information in EXIF: 
    14  
    15 ... 
    16 Exif.GPSInfo.GPSImgDirectionRef              Ascii       2  Magnetic direction 
    17 Exif.GPSInfo.GPSImgDirection                 Rational    1  4650/100 
    18 ... 
  • 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.