Ticket #5729: JOSM-terracer.2.patch

File JOSM-terracer.2.patch, 33.6 KB (added by robome, 11 years ago)

new version against rev 24697

  • src/terracer/HouseNumberInputDialog.java

     
    1515import java.awt.Dimension;
    1616import java.awt.GridBagConstraints;
    1717import java.awt.GridBagLayout;
     18import java.util.ArrayList;
     19import java.util.Iterator;
    1820import java.awt.event.ActionEvent;
    1921import java.util.TreeSet;
    2022
     
    2628import javax.swing.JTextField;
    2729
    2830import org.openstreetmap.josm.Main;
     31import org.openstreetmap.josm.data.osm.Node;
    2932import org.openstreetmap.josm.data.osm.OsmPrimitive;
    3033import org.openstreetmap.josm.data.osm.Way;
    3134import org.openstreetmap.josm.gui.ExtendedDialog;
     
    5457    final static String INTERPOLATION = "plugins.terracer.interpolation";
    5558
    5659    final private Way street;
     60    final private String streetName;
    5761    final private boolean relationExists;
     62    final ArrayList<Node> housenumbers;
    5863
    5964    protected static final String DEFAULT_MESSAGE = tr("Enter housenumbers or amount of segments");
    6065    private static final long serialVersionUID = 1L;
     
    6469    JTextField lo;
    6570    private JLabel hiLabel;
    6671    JTextField hi;
     72    private JLabel numbersLabel;
     73    JTextField numbers;
    6774    private JLabel streetLabel;
    6875    AutoCompletingComboBox streetComboBox;
    6976    private JLabel segmentsLabel;
     
    7986    /**
    8087     * @param street If street is not null, we assume, the name of the street to be fixed
    8188     * and just show a label. If street is null, we show a ComboBox/InputField.
     89     * @param streetName the name of the street, derived from either the
     90     *        street line or the house numbers which are guaranteed to have the
     91     *        same name attached (may be null)
    8292     * @param relationExists If the buildings can be added to an existing relation or not.
     93     * @param housenumbers a list of house numbers in this outline (may be empty)
    8394     */
    84     public HouseNumberInputDialog(HouseNumberInputHandler handler, Way street, boolean relationExists) {
     95    public HouseNumberInputDialog(HouseNumberInputHandler handler, Way street, String streetName, boolean relationExists, ArrayList<Node> housenumbers) {
    8596        super(Main.parent,
    8697                tr("Terrace a house"),
    8798                new String[] { tr("OK"), tr("Cancel")},
     
    89100        );
    90101        this.inputHandler = handler;
    91102        this.street = street;
     103        this.streetName = streetName;
    92104        this.relationExists = relationExists;
     105        this.housenumbers = housenumbers;
    93106        handler.dialog = this;
    94107        JPanel content = getInputPanel();
    95108        setContent(content);
     
    161174            loLabel.setToolTipText(tr("Lowest housenumber of the terraced house"));
    162175            hiLabel = new JLabel();
    163176            hiLabel.setText(tr("Highest Number"));
     177            numbersLabel = new JLabel();
     178            numbersLabel.setText(tr("List of Numbers"));
     179            loLabel.setPreferredSize(new Dimension(111, 16));
    164180            final String txt = relationExists ? tr("add to existing associatedStreet relation") : tr("create an associatedStreet relation");
    165181
    166182            handleRelationCheckBox = new JCheckBox(txt, Main.pref.getBoolean(HANDLE_RELATION, true));
     
    176192            inputPanel.add(getLo(), GBC.eol().fill(GBC.HORIZONTAL).insets(5,3,0,0));
    177193            inputPanel.add(hiLabel, GBC.std().insets(3,3,0,0));
    178194            inputPanel.add(getHi(), GBC.eol().fill(GBC.HORIZONTAL).insets(5,3,0,0));
     195            inputPanel.add(numbersLabel, GBC.std().insets(3,3,0,0));
     196            inputPanel.add(getNumbers(), GBC.eol().fill(GBC.HORIZONTAL).insets(5,3,0,0));
    179197            inputPanel.add(interpolationLabel, GBC.std().insets(3,3,0,0));
    180198            inputPanel.add(getInterpolation(), GBC.eol().insets(5,3,0,0));
    181199            inputPanel.add(segmentsLabel, GBC.std().insets(3,3,0,0));
    182200            inputPanel.add(getSegments(), GBC.eol().fill(GBC.HORIZONTAL).insets(5,3,0,0));
    183             if (street == null) {
     201            if (streetName == null) {
    184202                inputPanel.add(streetLabel, GBC.std().insets(3,3,0,0));
    185203                inputPanel.add(getStreet(), GBC.eol().insets(5,3,0,0));
    186204            } else {
    187                 inputPanel.add(new JLabel(tr("Street name: ")+"\""+street.get("name")+"\""), GBC.eol().insets(3,3,0,0));
     205                inputPanel.add(new JLabel(tr("Street name: ")+"\""+streetName+"\""), GBC.eol().insets(3,3,0,0));
    188206            }
    189207            inputPanel.add(handleRelationCheckBox, GBC.eol().insets(3,3,0,0));
    190208            inputPanel.add(deleteOutlineCheckBox, GBC.eol().insets(3,3,0,0));
     209           
     210            if (numbers.isVisible())
     211            {
     212                loLabel.setVisible(false);
     213                lo.setVisible(false);
     214                lo.setEnabled(false);
     215                hiLabel.setVisible(false);
     216                hi.setVisible(false);
     217                hi.setEnabled(false);
     218                interpolationLabel.setVisible(false);
     219                interpolation.setVisible(false);
     220                interpolation.setEnabled(false);
     221                segments.setText(String.valueOf(housenumbers.size()));
     222                segments.setEditable(false);
     223            }
    191224        }
    192225        return inputPanel;
    193226    }
     
    225258        }
    226259        return hi;
    227260    }
     261   
     262    /**
     263     * This method initializes numbers
     264     *
     265     * @return javax.swing.JTextField
     266     */
     267    private JTextField getNumbers() {
     268        if (numbers == null) {
     269            numbers = new JTextField();
     270           
     271            Iterator<Node> it = housenumbers.iterator();
     272            StringBuilder s = new StringBuilder(256);
     273            if (it.hasNext()) {
     274                s.append(it.next().get("addr:housenumber"));
     275                while (it.hasNext())
     276                    s.append(';').append(it.next().get("addr:housenumber"));
     277            }
     278            else {
     279                numbersLabel.setVisible(false);
     280                numbers.setVisible(false);
     281            }
     282           
     283            numbers.setText(s.toString());
     284            numbers.setEditable(false);
     285        }
     286        return numbers;
     287    }
    228288
    229289    /**
    230290     * This method initializes street
  • src/terracer/TerracerAction.java

     
    1515import java.util.ArrayList;
    1616import java.util.Collection;
    1717import java.util.Collections;
     18import java.util.Comparator;
     19import java.util.Iterator;
    1820import java.util.LinkedList;
    1921import java.util.List;
     22import java.util.Map;
     23import java.util.Set;
     24import java.util.Map.Entry;
     25import java.util.regex.Matcher;
     26import java.util.regex.Pattern;
    2027
    2128import javax.swing.JOptionPane;
    2229
     
    2835import org.openstreetmap.josm.command.Command;
    2936import org.openstreetmap.josm.command.DeleteCommand;
    3037import org.openstreetmap.josm.command.SequenceCommand;
     38import org.openstreetmap.josm.data.osm.DataSet;
    3139import org.openstreetmap.josm.data.osm.Node;
    3240import org.openstreetmap.josm.data.osm.OsmPrimitive;
    3341import org.openstreetmap.josm.data.osm.Relation;
     
    7583        Collection<OsmPrimitive> sel = getCurrentDataSet().getSelected();
    7684        Way outline = null;
    7785        Way street = null;
     86        String streetname = null;
     87        ArrayList<Node> housenumbers = new ArrayList<Node>();
    7888        Node init = null;
    7989
    8090        class InvalidUserInputException extends Exception {
    8191            InvalidUserInputException(String message) {
    8292                super(message);
    8393            }
     94
    8495            InvalidUserInputException() {
    8596                super();
    8697            }
    8798        }
    8899
    89100        try {
    90             for (OsmPrimitive osm : sel) {
    91                 if (osm instanceof Node) {
    92                     if (init != null)
    93                         throw new InvalidUserInputException();
    94                     init = (Node) osm;
    95                 } else if (osm instanceof Way) {
    96                     if (osm.hasKey("highway")) {
     101            if (sel.size() == 1) {
     102                OsmPrimitive prim = sel.iterator().next();
     103
     104                if (!(prim instanceof Way))
     105                    throw new InvalidUserInputException();
     106
     107                outline = (Way) prim;
     108            } else if (sel.size() > 1) {
     109                List<Way> ways = OsmPrimitive.getFilteredList(sel, Way.class);
     110                Iterator<Way> wit = ways.iterator();
     111                while (wit.hasNext()) {
     112                    Way way = wit.next();
     113                    if (way.hasKey("building")) {
     114                        if (outline != null)
     115                            // already have a building
     116                            throw new InvalidUserInputException();
     117                        outline = way;
     118                    } else if (way.hasKey("highway")) {
    97119                        if (street != null)
     120                            // already have a street
    98121                            throw new InvalidUserInputException();
    99                         street = (Way) osm;
    100                         if (!street.hasKey("name"))
     122                        street = way;
     123
     124                        if ((streetname = street.get("name")) == null)
    101125                            throw new InvalidUserInputException();
     126                    } else
     127                        throw new InvalidUserInputException();
     128                }
     129
     130                if (outline == null)
     131                    throw new InvalidUserInputException();
     132
     133                List<Node> nodes = OsmPrimitive.getFilteredList(sel, Node.class);
     134                Iterator<Node> nit = nodes.iterator();
     135                // Actually this should test if the selected address nodes lie
     136                // within the selected outline. Any ideas how to do this?
     137                while (nit.hasNext()) {
     138                    Node node = nit.next();
     139                    if (node.hasKey("addr:housenumber")) {
     140                        String nodesstreetname = node.get("addr:street");
     141                        // if a node has a street name if must be equal
     142                        // to the one of the other address nodes
     143                        if (nodesstreetname != null) {
     144                            if (streetname == null)
     145                                streetname = nodesstreetname;
     146                            else if (!nodesstreetname.equals(streetname))
     147                                throw new InvalidUserInputException();
     148                        }
     149
     150                        housenumbers.add(node);
    102151                    } else {
    103                         if (outline != null)
     152                        // A given node might not be an address node but then
     153                        // it has to be part of the building to help getting
     154                        // the number direction right.
     155                        if (!outline.containsNode(node) || init != null)
    104156                            throw new InvalidUserInputException();
    105                         outline = (Way) osm;
     157                        init = node;
    106158                    }
    107159                }
     160
     161                Collections.sort(housenumbers, new HousenumberNodeComparator());
    108162            }
    109             if (outline == null)
    110                 throw new InvalidUserInputException();
    111            
    112             if (init != null && !init.getReferrers().contains(outline))
    113                 throw new InvalidUserInputException();
    114163
    115             if (outline.getNodesCount() < 5)
     164            if (outline == null || !outline.isClosed() || outline.getNodesCount() < 5)
    116165                throw new InvalidUserInputException();
    117 
    118             if (!outline.isClosed())
    119                 throw new InvalidUserInputException();
    120166        } catch (InvalidUserInputException ex) {
    121167            new ExtendedDialog(Main.parent, tr("Invalid selection"), new String[] {"OK"})
    122168                .setButtonIcons(new String[] {"ok"}).setIcon(JOptionPane.INFORMATION_MESSAGE)
     
    127173            return;
    128174        }
    129175
    130         // If we have a street, try to find a associatedStreet relation that could be reused.
     176        // If we have a street, try to find an associatedStreet relation that could be reused.
    131177        Relation associatedStreet = null;
    132178        if (street != null) {
    133179            outer:for (OsmPrimitive osm : Main.main.getCurrentDataSet().allNonDeletedPrimitives()) {
     
    145191            }
    146192        }
    147193
    148         String title = trn("Change {0} object", "Change {0} objects", sel.size(), sel.size());
    149         // show input dialog.
    150         new HouseNumberInputHandler(this, outline, init, street, associatedStreet, title);
     194        if (housenumbers.size() == 1) {
     195            // Special case of one outline and one address node.
     196            // Don't open the dialogue, just copy the node keys
     197            // to the outline, set building just in case it isn't there
     198            // and remove the node.
     199            Collection<Command> commands = new LinkedList<Command>();
     200            Way newOutline = new Way(outline);
     201            for (Entry<String, String> entry : housenumbers.get(0).getKeys()
     202                    .entrySet()) {
     203                newOutline.put(entry.getKey(), entry.getValue());
     204            }
     205            newOutline.put("building", "yes");
     206            commands.add(new ChangeCommand(outline, newOutline));
     207            commands.add(DeleteCommand.delete(Main.main.getEditLayer(),
     208                    housenumbers, true, true));
     209            Main.main.undoRedo
     210                    .add(new SequenceCommand(tr("Terrace"), commands));
     211            Main.main.getCurrentDataSet().setSelected(newOutline);
     212        } else {
     213            String title = trn("Change {0} object", "Change {0} objects", sel
     214                    .size(), sel.size());
     215            // show input dialog.
     216            new HouseNumberInputHandler(this, outline, init, street, streetname,
     217                    associatedStreet, housenumbers, title);
     218        }
    151219    }
    152220
    153221    public Integer getNumber(String number) {
     
    159227    }
    160228
    161229    /**
     230     * Sorts the house number nodes according their numbers only
     231     *
     232     * @param house
     233     *            number nodes
     234     */
     235    class HousenumberNodeComparator implements Comparator<Node> {
     236        private final Pattern pat = Pattern.compile("^([0-9]+)");
     237
     238        /*
     239         * (non-Javadoc)
     240         *
     241         * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
     242         */
     243        @Override
     244        public int compare(Node node1, Node node2) {
     245            // It's necessary to strip off trailing non-numbers so we can
     246            // compare the numbers itself numerically since string comparison
     247            // doesn't work for numbers with different number of digits,
     248            // e.g. 9 is higher than 11
     249            String node1String = node1.get("addr:housenumber");
     250            String node2String = node2.get("addr:housenumber");
     251            Matcher mat = pat.matcher(node1String);
     252            if (mat.find()) {
     253                Integer node1Int = Integer.valueOf(mat.group(1));
     254                mat = pat.matcher(node2String);
     255                if (mat.find()) {
     256                    Integer node2Int = Integer.valueOf(mat.group(1));
     257
     258                    return node1Int.compareTo(node2Int);
     259                }
     260            }
     261
     262            return node1String.compareTo(node2String);
     263        }
     264    }
     265
     266    /**
    162267     * Terraces a single, closed, quadrilateral way.
    163268     *
    164269     * Any node must be adjacent to both a short and long edge, we naively
     
    170275     * @param init The node that hints at which side to start the numbering
    171276     * @param street The street, the buildings belong to (may be null)
    172277     * @param associatedStreet
    173      * @param From
    174      * @param To
    175      * @param streetName the name of a street (may be null). Used if not null and street is null.
    176      * @param handleRelations If the user likes to add a relation or extend an existing relation
    177      * @param deleteOutline If the outline way should be deleted, when done
     278     * @param segments The number of segments to generate
     279     * @param From Starting housenumber
     280     * @param To Ending housenumber
     281     * @param step The step width to use
     282     * @param housenumbers List of housenumbers to use. From and To are ignored
     283     *        if this is set.
     284     * @param streetName the name of the street, derived from the street line
     285     *        or the house numbers (may be null)
     286     * @param handleRelations If the user likes to add a relation or extend an
     287     *        existing relation
     288     * @param deleteOutline If the outline way should be deleted when done
    178289     */
    179290    public void terraceBuilding(Way outline,
    180291                Node init,
     
    184295                String From,
    185296                String To,
    186297                int step,
     298                ArrayList<Node> housenumbers,
    187299                String streetName,
    188300                boolean handleRelations,
    189301                boolean deleteOutline) {
    190302        final int nb;
    191 
    192         Integer to, from;
    193         to = getNumber(To);
    194         from = getNumber(From);
    195         if (to != null && from != null) {
    196             nb = 1 + (to.intValue() - from.intValue()) / step;
    197         } else if (segments != null) {
    198             nb = segments.intValue();
     303        Integer to = null, from = null;
     304        if (housenumbers.isEmpty()) {
     305            to = getNumber(To);
     306            from = getNumber(From);
     307            if (to != null && from != null) {
     308                nb = 1 + (to.intValue() - from.intValue()) / step;
     309            } else if (segments != null) {
     310                nb = segments.intValue();
     311            } else {
     312                // if we get here, there is is a bug in the input validation.
     313                throw new TerracerRuntimeException(
     314                        "Could not determine segments from parameters, this is a bug. "
     315                                + "Parameters were: segments " + segments
     316                                + " from " + from + " to " + to + " step "
     317                                + step);
     318            }
    199319        } else {
    200             // if we get here, there is is a bug in the input validation.
    201             throw new TerracerRuntimeException(
    202                     "Could not determine segments from parameters, this is a bug. "
    203                             + "Parameters were: segments " + segments
    204                             + " from " + from + " to " + to + " step " + step);
     320            nb = housenumbers.size();
    205321        }
    206322
     323        // now find which is the longest side connecting the first node
     324        Pair<Way, Way> interp = findFrontAndBack(outline);
     325
     326        boolean swap = false;
     327        if (init != null) {
     328            if (interp.a.lastNode().equals(init) || interp.b.lastNode().equals(init)) {
     329                swap = true;
     330            }
     331        }
     332
     333        final double frontLength = wayLength(interp.a);
     334        final double backLength = wayLength(interp.b);
     335
    207336        // new nodes array to hold all intermediate nodes
    208337        Node[][] new_nodes = new Node[2][nb + 1];
    209338
    210339        this.commands = new LinkedList<Command>();
    211340        Collection<Way> ways = new LinkedList<Way>();
    212341
    213         // Should this building be terraced (i.e. is there more then one section?)
    214342        if (nb > 1) {
    215             // create intermediate nodes by interpolating.
    216 
    217             // now find which is the longest side connecting the first node
    218             Pair<Way, Way> interp = findFrontAndBack(outline);
    219 
    220             boolean swap = false;
    221             if (init != null) {
    222                 if (interp.a.lastNode().equals(init) || interp.b.lastNode().equals(init)) {
    223                     swap = true;
    224                 }
    225             }
    226 
    227             final double frontLength = wayLength(interp.a);
    228             final double backLength = wayLength(interp.b);
    229 
    230343            for (int i = 0; i <= nb; ++i) {
    231344                int i_dir = swap ? nb - i : i;
    232345                new_nodes[0][i] = interpolateAlong(interp.a, frontLength * i_dir / nb);
     
    248361                TagCollection.from(outline).applyTo(terr);
    249362
    250363                String number = null;
    251                 if (from != null) {
    252                     number = Integer.toString(from + i * step);
     364                Set<Entry<String, String>> additionalKeys = null;
     365                if (housenumbers.isEmpty()) {
     366                    if (from != null) {
     367                        // only, if the user has specified house numbers
     368                        number = Integer.toString(from + i * step);
     369                    }
     370                } else {
     371                    number = housenumbers.get(i).get("addr:housenumber");
     372                    additionalKeys = housenumbers.get(i).getKeys().entrySet();
    253373                }
    254                 terr = addressBuilding(terr, street, streetName, number);
    255374
     375                terr = addressBuilding(terr, street, streetName, number,
     376                        additionalKeys);
     377
    256378                ways.add(terr);
    257379                this.commands.add(new AddCommand(terr));
    258380            }
     
    261383                this.commands.add(DeleteCommand.delete(Main.main.getEditLayer(), Collections.singleton(outline), true, true));
    262384            }
    263385        } else {
    264             // Single section, just add the address details
     386            // Single building, just add the address details
    265387            Way newOutline;
    266             newOutline = addressBuilding(outline, street, streetName, From);
     388            newOutline = addressBuilding(outline, street, streetName, From, null);
    267389            ways.add(newOutline);
    268390            this.commands.add(new ChangeCommand(outline, newOutline));
    269391        }
     
    282404                    associatedStreet.addMember(new RelationMember("house", w));
    283405                }
    284406                this.commands.add(new AddCommand(associatedStreet));
    285             }
    286             else { // relation exists already - add new members
     407            } else { // relation exists already - add new members
    287408                Relation newAssociatedStreet = new Relation(associatedStreet);
    288409                for (Way w : ways) {
    289410                    newAssociatedStreet.addMember(new RelationMember("house", w));
     
    291412                this.commands.add(new ChangeCommand(associatedStreet, newAssociatedStreet));
    292413            }
    293414        }
     415
     416        // Remove the address node since their tags have been incorporated into
     417        // the terraces.
     418        // Or should removing them also be an option?
     419        if (!housenumbers.isEmpty())
     420            commands.add(DeleteCommand.delete(Main.main.getEditLayer(),
     421                    housenumbers, true, true));
     422
    294423        Main.main.undoRedo.add(new SequenceCommand(tr("Terrace"), commands));
    295424        if (nb > 1) {
    296425            // Select the new building outlines (for quick reversing)
     
    308437     * @param street The street, the buildings belong to (may be null)
    309438     * @param streetName the name of a street (may be null). Used if not null and street is null.
    310439     * @param number The house number
     440     * @param additionalKeys More keys to be copied onto the new outline
    311441     * @return the way with added address details
    312442     */
    313     private Way addressBuilding(Way outline, Way street, String streetName, String number) {
     443    private Way addressBuilding(Way outline, Way street, String streetName,
     444            String number, Set<Entry<String, String>> additionalKeys) {
    314445        Way changedOutline = outline;
    315446        if (number != null) {
    316447            // only, if the user has specified house numbers
    317448            this.commands.add(new ChangePropertyCommand(changedOutline, "addr:housenumber", number));
    318449        }
     450        if (additionalKeys != null) {
     451            for (Entry<String, String> entry : additionalKeys) {
     452                this.commands.add(new ChangePropertyCommand(changedOutline,
     453                        entry.getKey(), entry.getValue()));
     454            }
     455        }
    319456        changedOutline.put("building", "yes");
    320457        if (street != null) {
    321458            this.commands.add(new ChangePropertyCommand(changedOutline, "addr:street", street.get("name")));
     
    342479        for (int i = 0; i < pairs.size(); ++i) {
    343480            Pair<Node,Node> p = pairs.get(i);
    344481            final double seg_length = p.a.getCoor().greatCircleDistance(p.b.getCoor());
    345             if (l <= seg_length ||
    346                     i == pairs.size() - 1) {    // be generous on the last segment (numerical roudoff can lead to a small overshoot)
     482            if (l <= seg_length || i == pairs.size() - 1) {
     483                // be generous on the last segment (numerical roudoff can lead to a small overshoot)
    347484                return interpolateNode(p.a, p.b, l / seg_length);
    348485            } else {
    349486                l -= seg_length;
     
    441578     * return the modulus in the range [0, n)
    442579     */
    443580    private int positiveModulus(int a, int n) {
    444         if (n <=0)
     581        if (n <= 0)
    445582            throw new IllegalArgumentException();
    446583        int res = a % n;
    447584        if (res < 0) {
  • src/terracer/HouseNumberInputHandler.java

     
    1818import java.awt.event.FocusListener;
    1919import java.awt.event.ItemEvent;
    2020import java.awt.event.ItemListener;
     21import java.util.ArrayList;
    2122
    2223import javax.swing.JButton;
    2324import javax.swing.JTextField;
    2425import javax.swing.JOptionPane;
    2526
    2627import org.openstreetmap.josm.Main;
     28import org.openstreetmap.josm.data.osm.Node;
    2729import org.openstreetmap.josm.data.osm.Way;
    2830import org.openstreetmap.josm.data.osm.Relation;
    2931import org.openstreetmap.josm.actions.JosmAction;
     
    3941 *
    4042 * @author casualwalker
    4143 */
    42  public class HouseNumberInputHandler extends JosmAction implements ActionListener, FocusListener, ItemListener {
     44public class HouseNumberInputHandler extends JosmAction implements ActionListener, FocusListener, ItemListener {
    4345    private TerracerAction terracerAction;
    4446    private Way outline, street;
     47    private String streetName;
    4548    private Node init;
    4649    private Relation associatedStreet;
     50    private ArrayList<Node> housenumbers;
    4751    public HouseNumberInputDialog dialog;
    4852
    4953    /**
     
    5357     * @param outline the closed, quadrilateral way to terrace.
    5458     * @param init The node that hints at which side to start the numbering
    5559     * @param street the street, the buildings belong to (may be null)
     60     * @param streetName the name of the street, derived from either the street line or
     61     *            the house numbers which are guaranteed to have the same name
     62     *            attached (may be null)
    5663     * @param associatedStreet a relation where we can add the houses (may be null)
     64     * @param housenumbers a list of house number nodes in this outline (may be empty)
    5765     * @param title the title
    5866     */
    5967    public HouseNumberInputHandler(final TerracerAction terracerAction,
    60             final Way outline, final Node init, final Way street, final Relation associatedStreet,
    61             final String title) {
     68            final Way outline, final Node init, final Way street, final String streetName,
     69            final Relation associatedStreet,
     70            final ArrayList<Node> housenumbers, final String title) {
    6271        this.terracerAction = terracerAction;
    6372        this.outline = outline;
    6473        this.init = init;
    6574        this.street = street;
     75        this.streetName = streetName;
    6676        this.associatedStreet = associatedStreet;
     77        this.housenumbers = housenumbers;
    6778
    6879        // This dialog is started modal
    69         this.dialog = new HouseNumberInputDialog(this, street, associatedStreet != null);
     80        this.dialog = new HouseNumberInputDialog(this, street, streetName,
     81                associatedStreet != null, housenumbers);
    7082
    7183        // We're done
    7284    }
     
    8395     */
    8496    private static JButton getButton(Container root, String caption) {
    8597        Component children[] = root.getComponents();
    86          for (Component child : children) {
     98        for (Component child : children) {
    8799            JButton b;
    88100            if (child instanceof JButton) {
    89101                b = (JButton) child;
    90102                if (caption.equals(b.getText())) return b;
    91103            } else if (child instanceof Container) {
    92                   b = getButton((Container)child, caption);
    93                   if (b != null) return b;
    94              }
    95          }
     104                b = getButton((Container) child, caption);
     105                if (b != null) return b;
     106            }
     107        }
    96108        return null;
    97109    }
    98110
     
    111123        isOk = isOk && checkSegmentsFromHousenumber(message);
    112124        isOk = isOk && checkSegments(message);
    113125
    114         // Allow non numeric characters for the low number as long as there is no high number of the segmentcount is 1
     126        // Allow non numeric characters for the low number as long as there is
     127        // no high number of the segmentcount is 1
    115128        if (dialog.hi.getText().length() > 0 | segments() > 1) {
    116129            isOk = isOk
    117130                    && checkNumberStringField(dialog.lo, tr("Lowest number"),
     
    138151            if (okButton != null)
    139152                okButton.setEnabled(false);
    140153
    141             // For some reason the messageLabel doesn't want to show up, so a MessageDialog is shown instead. Someone more knowledgeable might fix this.
     154            // For some reason the messageLabel doesn't want to show up, so a
     155            // MessageDialog is shown instead. Someone more knowledgeable might fix this.
    142156            dialog.messageLabel.setForeground(Color.red);
    143157            dialog.messageLabel.setText(message.toString());
    144             //JOptionPane.showMessageDialog(null, message.toString(), tr("Error"), JOptionPane.ERROR_MESSAGE);
     158            // JOptionPane.showMessageDialog(null, message.toString(),
     159            // tr("Error"), JOptionPane.ERROR_MESSAGE);
    145160
    146161            return false;
    147162        }
     
    179194     * @return true, if successful
    180195     */
    181196    private boolean checkSegmentsFromHousenumber(final StringBuffer message) {
    182         dialog.segments.setEditable(true);
     197        if (!dialog.numbers.isVisible()) {
     198            dialog.segments.setEditable(true);
    183199
    184         if (numberFrom() != null && numberTo() != null) {
     200            if (numberFrom() != null && numberTo() != null) {
     201                int segments = numberTo().intValue() - numberFrom().intValue();
    185202
    186             int segments = numberTo().intValue() - numberFrom().intValue();
     203                if (segments % stepSize() != 0) {
     204                    appendMessageNewLine(message);
     205                    message
     206                            .append(tr("Housenumbers do not match odd/even setting"));
     207                    return false;
     208                }
    187209
    188             if (segments % stepSize() != 0) {
    189                 appendMessageNewLine(message);
    190                 message.append(tr("Housenumbers do not match odd/even setting"));
    191                 return false;
     210                int steps = segments / stepSize();
     211                steps++; // difference 0 means 1 building, see
     212                // TerracerActon.terraceBuilding
     213                dialog.segments.setText(String.valueOf(steps));
     214                dialog.segments.setEditable(false);
     215
    192216            }
    193 
    194             int steps = segments / stepSize();
    195             steps++; // difference 0 means 1 building, see
    196             // TerracerActon.terraceBuilding
    197             dialog.segments.setText(String.valueOf(steps));
    198             dialog.segments.setEditable(false);
    199 
    200217        }
    201218        return true;
    202219    }
     
    260277        }
    261278    }
    262279
    263     /* (non-Javadoc)
     280    /*
     281     * (non-Javadoc)
     282     *
    264283     * @see java.awt.event.ItemListener#itemStateChanged(java.awt.event.ItemEvent)
    265284     * Called when the user selects from a pulldown selection
    266285     */
     
    268287        validateInput();
    269288    }
    270289
    271     /* (non-Javadoc)
     290    /*
     291     * (non-Javadoc)
     292     *
    272293     * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
    273294     */
    274295    public void actionPerformed(final ActionEvent e) {
     
    288309                        dialog.lo.getText(),
    289310                        dialog.hi.getText(),
    290311                        stepSize(),
     312                        housenumbers,
    291313                        streetName(),
    292314                        doHandleRelation(),
    293315                        doDeleteOutline());
     
    356378    /**
    357379     * Gets the street name.
    358380     *
    359      * @return the  street name or null, if not set / invalid.
     381     * @return the street name or null, if not set / invalid.
    360382     */
    361383    public String streetName() {
    362         if (street != null)
    363             return null;
     384        if (streetName != null)
     385            return streetName;
    364386
    365387        Object selected = dialog.streetComboBox.getSelectedItem();
    366388        if (selected == null) {
     
    386408        if (this.dialog.handleRelationCheckBox == null) {
    387409            JOptionPane.showMessageDialog(null, "checkbox", "alert", JOptionPane.ERROR_MESSAGE);
    388410            return true;
    389         }  else {
     411        } else {
    390412            return this.dialog.handleRelationCheckBox.isSelected();
    391413        }
    392414    }
    393415
    394 
    395416    /**
    396417     * Whether the user likes to delete the outline way.
    397418     */
     
    399420        return dialog.deleteOutlineCheckBox.isSelected();
    400421    }
    401422
    402     /* (non-Javadoc)
     423    /*
     424     * (non-Javadoc)
     425     *
    403426     * @see java.awt.event.FocusListener#focusGained(java.awt.event.FocusEvent)
    404427     */
    405428    public void focusGained(FocusEvent e) {
    406429        // Empty, but placeholder is required
    407430    }
    408431
    409     /* (non-Javadoc)
     432    /*
     433     * (non-Javadoc)
     434     *
    410435     * @see java.awt.event.FocusListener#focusLost(java.awt.event.FocusEvent)
    411436     */
    412437    public void focusLost(FocusEvent e) {