Ticket #5729: JOSM-terracer.patch

File JOSM-terracer.patch, 53.6 KB (added by robome, 13 years ago)
  • 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);
     
    159172            loLabel.setToolTipText(tr("Lowest housenumber of the terraced house"));
    160173            hiLabel = new JLabel();
    161174            hiLabel.setText(tr("Highest Number"));
     175            numbersLabel = new JLabel();
     176            numbersLabel.setText(tr("List of Numbers"));
     177            loLabel.setPreferredSize(new Dimension(111, 16));
    162178            final String txt = relationExists ? tr("add to existing associatedStreet relation") : tr("create an associatedStreet relation");
    163179
    164180            handleRelationCheckBox = new JCheckBox(txt, Main.pref.getBoolean(HANDLE_RELATION, true));
     
    174190            inputPanel.add(getLo(), GBC.eol().fill(GBC.HORIZONTAL).insets(5,3,0,0));
    175191            inputPanel.add(hiLabel, GBC.std().insets(3,3,0,0));
    176192            inputPanel.add(getHi(), GBC.eol().fill(GBC.HORIZONTAL).insets(5,3,0,0));
     193            inputPanel.add(numbersLabel, GBC.std().insets(3,3,0,0));
     194            inputPanel.add(getNumbers(), GBC.eol().fill(GBC.HORIZONTAL).insets(5,3,0,0));
    177195            inputPanel.add(interpolationLabel, GBC.std().insets(3,3,0,0));
    178196            inputPanel.add(getInterpolation(), GBC.eol().insets(5,3,0,0));
    179197            inputPanel.add(segmentsLabel, GBC.std().insets(3,3,0,0));
    180198            inputPanel.add(getSegments(), GBC.eol().fill(GBC.HORIZONTAL).insets(5,3,0,0));
    181             if (street == null) {
     199            if (streetName == null) {
    182200                inputPanel.add(streetLabel, GBC.std().insets(3,3,0,0));
    183201                inputPanel.add(getStreet(), GBC.eol().insets(5,3,0,0));
    184202            } else {
    185                 inputPanel.add(new JLabel(tr("Street name: ")+"\""+street.get("name")+"\""), GBC.eol().insets(3,3,0,0));
     203                inputPanel.add(new JLabel(tr("Street name: ")+"\""+streetName+"\""), GBC.eol().insets(3,3,0,0));
    186204            }
    187205            inputPanel.add(handleRelationCheckBox, GBC.eol().insets(3,3,0,0));
    188206            inputPanel.add(deleteOutlineCheckBox, GBC.eol().insets(3,3,0,0));
     207           
     208            if (numbers.isVisible())
     209            {
     210                loLabel.setVisible(false);
     211                lo.setVisible(false);
     212                lo.setEnabled(false);
     213                hiLabel.setVisible(false);
     214                hi.setVisible(false);
     215                hi.setEnabled(false);
     216                interpolationLabel.setVisible(false);
     217                interpolation.setVisible(false);
     218                interpolation.setEnabled(false);
     219                segments.setText(String.valueOf(housenumbers.size()));
     220                segments.setEditable(false);
     221            }
    189222        }
    190223        return inputPanel;
    191224    }
     
    223256        }
    224257        return hi;
    225258    }
     259   
     260    /**
     261     * This method initializes numbers
     262     *
     263     * @return javax.swing.JTextField
     264     */
     265    private JTextField getNumbers() {
     266        if (numbers == null) {
     267            numbers = new JTextField();
     268           
     269            Iterator<Node> it = housenumbers.iterator();
     270            StringBuilder s = new StringBuilder(256);
     271            if (it.hasNext()) {
     272                s.append(it.next().get("addr:housenumber"));
     273                while (it.hasNext())
     274                    s.append(';').append(it.next().get("addr:housenumber"));
     275            }
     276            else {
     277                numbersLabel.setVisible(false);
     278                numbers.setVisible(false);
     279            }
     280           
     281            numbers.setText(s.toString());
     282            numbers.setEditable(false);
     283        }
     284        return numbers;
     285    }
    226286
    227287    /**
    228288     * This method initializes street
  • src/terracer/TerracerAction.java

     
    1515import java.util.ArrayList;
    1616import java.util.Collection;
    1717import java.util.Collections;
     18import java.util.Comparator;
    1819import java.util.Iterator;
    1920import java.util.LinkedList;
    2021import 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;
    2127
    2228import javax.swing.JOptionPane;
    2329
     
    3036import org.openstreetmap.josm.command.DeleteCommand;
    3137import org.openstreetmap.josm.command.SequenceCommand;
    3238import org.openstreetmap.josm.data.coor.LatLon;
     39import org.openstreetmap.josm.data.osm.DataSet;
    3340import org.openstreetmap.josm.data.osm.Node;
    3441import org.openstreetmap.josm.data.osm.OsmPrimitive;
    3542import org.openstreetmap.josm.data.osm.Relation;
     
    4047import org.openstreetmap.josm.tools.Shortcut;
    4148
    4249/**
    43  * Terraces a quadrilateral, closed way into a series of quadrilateral,
    44  * closed ways. If two ways are selected and one of them can be identified as
    45  * a street (highway=*, name=*) then the given street will be added
    46  * to the 'associatedStreet' relation.
    47  *
    48  *
    49  * At present it only works on quadrilaterals, but there is no reason
    50  * why it couldn't be extended to work with other shapes too. The
    51  * algorithm employed is naive, but it works in the simple case.
    52  *
     50 * Terraces a quadrilateral, closed way into a series of quadrilateral, closed
     51 * ways. If two ways are selected and one of them can be identified as a street
     52 * (highway=*, name=*) then the given street will be added to the
     53 * 'associatedStreet' relation.
     54 * 
     55 * 
     56 * At present it only works on quadrilaterals, but there is no reason why it
     57 * couldn't be extended to work with other shapes too. The algorithm employed is
     58 * naive, but it works in the simple case.
     59 * 
    5360 * @author zere
    5461 */
    5562public final class TerracerAction extends JosmAction {
     
    7784                .getSelected();
    7885        Way outline = null;
    7986        Way street = null;
     87        String streetname = null;
     88        ArrayList<Node> housenumbers = new ArrayList<Node>();
    8089
    8190        class InvalidUserInputException extends Exception {
    8291            InvalidUserInputException(String message) {
    8392                super(message);
    8493            }
     94
    8595            InvalidUserInputException() {
    8696                super();
    8797            }
    8898        }
    8999
    90100        try {
    91             if (sel.size() == 2) {
    92                 Iterator<OsmPrimitive> it = sel.iterator();
    93                 OsmPrimitive prim1 = it.next();
    94                 OsmPrimitive prim2 = it.next();
    95                 if (!(prim1 instanceof Way && prim2 instanceof Way))
    96                     throw new InvalidUserInputException();
    97                 Way way1 = (Way) prim1;
    98                 Way way2 = (Way) prim2;
    99                 if (way2.get("highway") != null) {
    100                     street = way2;
    101                     outline = way1;
    102                 } else if (way1.get("highway") != null) {
    103                     street = way1;
    104                     outline = way2;
    105                 } else
    106                     throw new InvalidUserInputException();
    107                 if (street.get("name") == null)
    108                     throw new InvalidUserInputException();
    109 
    110             } else if (sel.size() == 1) {
     101            if (sel.size() == 1) {
    111102                OsmPrimitive prim = sel.iterator().next();
    112103
    113104                if (!(prim instanceof Way))
    114105                    throw new InvalidUserInputException();
    115106
    116                 outline = (Way)prim;
     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                    String type = way.get("building");
     114                    if (type != null) {
     115                        if (outline == null)
     116                            outline = way;
     117                        else
     118                            // already have a building
     119                            throw new InvalidUserInputException();
     120                    } else if ((type = way.get("highway")) != null) {
     121                        if (street == null)
     122                            street = way;
     123                        else
     124                            // already have a street
     125                            throw new InvalidUserInputException();
     126
     127                        if ((streetname = street.get("name")) == null)
     128                            throw new InvalidUserInputException();
     129                    } else
     130                        throw new InvalidUserInputException();
     131                }
     132
     133                if (outline == null)
     134                    throw new InvalidUserInputException();
     135
     136                List<Node> nodes = OsmPrimitive
     137                        .getFilteredList(sel, Node.class);
     138                Iterator<Node> nit = nodes.iterator();
     139                // Actually this should test if the selected address nodes lies
     140                // within
     141                // within the selected outline. Any ideas how to do this?
     142                while (nit.hasNext()) {
     143                    Node node = nit.next();
     144                    if (node.get("addr:housenumber") != null) {
     145                        String nodesstreetname = node.get("addr:street");
     146                        // if a node has a street name if must be equal
     147                        // to the one of the other address nodes
     148                        if (nodesstreetname != null) {
     149                            if (streetname == null)
     150                                streetname = nodesstreetname;
     151                            else if (!nodesstreetname.equals(streetname))
     152                                throw new InvalidUserInputException();
     153                        }
     154                        // if a node has a street name it must be
     155                        // equal to the one of the street line
     156                        if (nodesstreetname != null && street != null
     157                                && !nodesstreetname.equals(street.get("name")))
     158                            throw new InvalidUserInputException();
     159
     160                        housenumbers.add(node);
     161                    } else {
     162                        // A given node might not be an address node but then
     163                        // it should be part of the building or the street line.
     164                        if (!outline.containsNode(node)
     165                                && !(street != null && street
     166                                        .containsNode(node)))
     167                            throw new InvalidUserInputException();
     168                    }
     169                }
     170
     171                Collections.sort(housenumbers, new HousenumberNodeComparator());
    117172            } else
    118173                throw new InvalidUserInputException();
    119174
     
    128183            return;
    129184        }
    130185
    131         // If we have a street, try to find a associatedStreet relation that could be reused.
     186        // If we have a street, try to find an associatedStreet relation that
     187        // could be reused.
    132188        Relation associatedStreet = null;
    133189        if (street != null) {
    134             outer:for (OsmPrimitive osm : Main.main.getCurrentDataSet().allNonDeletedPrimitives()) {
    135                 if (!(osm instanceof Relation)) continue;
     190            outer: for (OsmPrimitive osm : Main.main.getCurrentDataSet()
     191                    .allNonDeletedPrimitives()) {
     192                if (!(osm instanceof Relation))
     193                    continue;
    136194                Relation rel = (Relation) osm;
    137                 if ("associatedStreet".equals(rel.get("type")) && street.get("name").equals(rel.get("name"))) {
     195                if ("associatedStreet".equals(rel.get("type"))
     196                        && street.get("name").equals(rel.get("name"))) {
    138197                    List<RelationMember> members = rel.getMembers();
    139198                    for (RelationMember m : members) {
    140                         if ("street".equals(m.getRole()) && m.isWay() && m.getMember().equals(street)) {
     199                        if ("street".equals(m.getRole()) && m.isWay()
     200                                && m.getMember().equals(street)) {
    141201                            associatedStreet = rel;
    142202                            break outer;
    143203                        }
     
    146206            }
    147207        }
    148208
    149         String title = trn("Change {0} object", "Change {0} objects", sel.size(), sel.size());
    150         // show input dialog.
    151         new HouseNumberInputHandler(this, outline, street, associatedStreet, title);
     209        if (housenumbers.size() == 1) {
     210            // Special case of one outline and one address node.
     211            // Don't open the dialogue, just copy the node keys
     212            // to the outline, set building just in case it isn't there
     213            // and remove the node.
     214            Collection<Command> commands = new LinkedList<Command>();
     215            Way newOutline = new Way(outline);
     216            for (Entry<String, String> entry : housenumbers.get(0).getKeys()
     217                    .entrySet()) {
     218                newOutline.put(entry.getKey(), entry.getValue());
     219            }
     220            newOutline.put("building", "yes");
     221            commands.add(new ChangeCommand(outline, newOutline));
     222            commands.add(DeleteCommand.delete(Main.main.getEditLayer(),
     223                    housenumbers, true, true));
     224            Main.main.undoRedo
     225                    .add(new SequenceCommand(tr("Terrace"), commands));
     226            Main.main.getCurrentDataSet().setSelected(newOutline);
     227        } else {
     228            String title = trn("Change {0} object", "Change {0} objects", sel
     229                    .size(), sel.size());
     230            // show input dialog.
     231            new HouseNumberInputHandler(this, outline, street, streetname,
     232                    associatedStreet, housenumbers, title);
     233        }
    152234    }
    153235
    154236    public Integer getNumber(String number) {
     
    160242    }
    161243
    162244    /**
     245     * Sorts the house number nodes according their numbers only
     246     *
     247     * @param house
     248     *            number nodes
     249     */
     250    class HousenumberNodeComparator implements Comparator<Node> {
     251        private final Pattern pat = Pattern.compile("^([0-9]+)");
     252
     253        /*
     254         * (non-Javadoc)
     255         *
     256         * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
     257         */
     258        @Override
     259        public int compare(Node node1, Node node2) {
     260            // It's necessary to strip off trailing non-numbers so we can
     261            // compare the numbers itself numerically since string comparison
     262            // doesn't work for numbers with different number of digits,
     263            // e.g. 9 is higher than 11
     264            String node1String = node1.get("addr:housenumber");
     265            String node2String = node2.get("addr:housenumber");
     266            Matcher mat = pat.matcher(node1String);
     267            if (mat.find()) {
     268                Integer node1Int = Integer.valueOf(mat.group(1));
     269                mat = pat.matcher(node2String);
     270                if (mat.find()) {
     271                    Integer node2Int = Integer.valueOf(mat.group(1));
     272
     273                    return node1Int.compareTo(node2Int);
     274                }
     275            }
     276
     277            return node1String.compareTo(node2String);
     278        }
     279    }
     280
     281    /**
    163282     * Terraces a single, closed, quadrilateral way.
    164      *
     283     * 
    165284     * Any node must be adjacent to both a short and long edge, we naively
    166285     * choose the longest edge and its opposite and interpolate along them
    167286     * linearly to produce new nodes. Those nodes are then assembled into
    168287     * closed, quadrilateral ways and left in the selection.
    169      *
    170      * @param outline The closed, quadrilateral way to terrace.
    171      * @param street The street, the buildings belong to (may be null)
     288     *
     289     * @param outline
     290     *            The closed, quadrilateral way to terrace.
     291     * @param street
     292     *            The street, the buildings belong to (may be null)
    172293     * @param associatedStreet
    173294     * @param From
    174295     * @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
     296     * @param streetName
     297     *            the name of a street (may be null). Used if not null and
     298     *            street is null.
     299     * @param handleRelations
     300     *            If the user likes to add a relation or extend an existing
     301     *            relation
     302     * @param streetName
     303     *            the name of the street, derived from the street line or the
     304     *            house numbers (may be null)
     305     * @param housenumbers
     306     * @param deleteOutline
     307     *            If the outline way should be deleted, when done
    178308     */
    179     public void terraceBuilding(Way outline,
    180                 Way street,
    181                 Relation associatedStreet,
    182                 Integer segments,
    183                 String From,
    184                 String To,
    185                 int step,
    186                 String streetName,
    187                 boolean handleRelations,
    188                 boolean deleteOutline) {
     309    public void terraceBuilding(Way outline, Way street,
     310            Relation associatedStreet, Integer segments, String From,
     311            String To, int step, ArrayList<Node> housenumbers,
     312            String streetName, boolean handleRelations, boolean deleteOutline) {
    189313        final int nb;
    190 
    191         Integer to, from;
    192         to = getNumber(To);
    193         from = getNumber(From);
    194         if (to != null && from != null) {
    195             nb = 1 + (to.intValue() - from.intValue()) / step;
    196         } else if (segments != null) {
    197             nb = segments.intValue();
     314        Integer to = null, from = null;
     315        if (housenumbers.isEmpty()) {
     316            to = getNumber(To);
     317            from = getNumber(From);
     318            if (to != null && from != null) {
     319                nb = 1 + (to.intValue() - from.intValue()) / step;
     320            } else if (segments != null) {
     321                nb = segments.intValue();
     322            } else {
     323                // if we get here, there is is a bug in the input validation.
     324                throw new TerracerRuntimeException(
     325                        "Could not determine segments from parameters, this is a bug. "
     326                                + "Parameters were: segments " + segments
     327                                + " from " + from + " to " + to + " step "
     328                                + step);
     329            }
    198330        } else {
    199             // if we get here, there is is a bug in the input validation.
    200             throw new TerracerRuntimeException(
    201                     "Could not determine segments from parameters, this is a bug. "
    202                             + "Parameters were: segments " + segments
    203                             + " from " + from + " to " + to + " step " + step);
     331            nb = housenumbers.size();
    204332        }
    205333
     334        // now find which is the longest side connecting the first node
     335        Pair<Way, Way> interp = findFrontAndBack(outline);
     336
     337        final double frontLength = wayLength(interp.a);
     338        final double backLength = wayLength(interp.b);
     339
    206340        // new nodes array to hold all intermediate nodes
    207341        Node[][] new_nodes = new Node[2][nb + 1];
    208342
    209343        this.commands = new LinkedList<Command>();
    210344        Collection<Way> ways = new LinkedList<Way>();
    211345
    212         // Should this building be terraced (i.e. is there more then one section?)
    213346        if (nb > 1) {
    214347            // create intermediate nodes by interpolating.
    215 
    216             // now find which is the longest side connecting the first node
    217             Pair<Way, Way> interp = findFrontAndBack(outline);
    218 
    219             final double frontLength = wayLength(interp.a);
    220             final double backLength = wayLength(interp.b);
    221 
    222348            for (int i = 0; i <= nb; ++i) {
    223                 new_nodes[0][i] = interpolateAlong(interp.a, frontLength * i / nb);
    224                 new_nodes[1][i] = interpolateAlong(interp.b, backLength * i / nb);
     349                new_nodes[0][i] = interpolateAlong(interp.a, frontLength * i
     350                        / nb);
     351                new_nodes[1][i] = interpolateAlong(interp.b, backLength * i
     352                        / nb);
    225353                this.commands.add(new AddCommand(new_nodes[0][i]));
    226354                this.commands.add(new AddCommand(new_nodes[1][i]));
    227355            }
     
    229357            // assemble new quadrilateral, closed ways
    230358            for (int i = 0; i < nb; ++i) {
    231359                Way terr = new Way();
    232                 // Using Way.nodes.add rather than Way.addNode because the latter
    233                 // doesn't
    234                 // exist in older versions of JOSM.
    235360                terr.addNode(new_nodes[0][i]);
    236361                terr.addNode(new_nodes[0][i + 1]);
    237362                terr.addNode(new_nodes[1][i + 1]);
     
    242367                TagCollection.from(outline).applyTo(terr);
    243368
    244369                String number = null;
    245                 if (from != null) {
    246                     number = Integer.toString(from + i * step);
     370                Set<Entry<String, String>> additionalKeys = null;
     371                if (housenumbers.isEmpty()) {
     372                    if (from != null) {
     373                        // only, if the user has specified house numbers
     374                        number = Integer.toString(from + i * step);
     375                    }
     376                } else {
     377                    number = housenumbers.get(i).get("addr:housenumber");
     378                    additionalKeys = housenumbers.get(i).getKeys().entrySet();
    247379                }
    248                 terr = addressBuilding(terr, street, streetName, number);
    249380
     381                terr = addressBuilding(terr, street, streetName, number,
     382                        additionalKeys);
     383
    250384                ways.add(terr);
    251385                this.commands.add(new AddCommand(terr));
    252386            }
    253387
    254388            if (deleteOutline) {
    255                 this.commands.add(DeleteCommand.delete(Main.main.getEditLayer(), Collections.singleton(outline), true, true));
     389                this.commands.add(DeleteCommand.delete(
     390                        Main.main.getEditLayer(), Collections
     391                                .singleton(outline), true, true));
    256392            }
    257393        } else {
    258             // Single section, just add the address details
     394            // Single building, just add the address details
    259395            Way newOutline;
    260             newOutline = addressBuilding(outline, street, streetName, From);
     396            newOutline = addressBuilding(outline, street, streetName, From,
     397                    null);
    261398            ways.add(newOutline);
    262399            this.commands.add(new ChangeCommand(outline, newOutline));
    263400        }
    264401
    265402        if (handleRelations) { // create a new relation or merge with existing
    266             if (associatedStreet == null) {  // create a new relation
     403            if (associatedStreet == null) { // create a new relation
    267404                associatedStreet = new Relation();
    268405                associatedStreet.put("type", "associatedStreet");
    269406                if (street != null) { // a street was part of the selection
    270407                    associatedStreet.put("name", street.get("name"));
    271                     associatedStreet.addMember(new RelationMember("street", street));
     408                    associatedStreet.addMember(new RelationMember("street",
     409                            street));
    272410                } else {
    273411                    associatedStreet.put("name", streetName);
    274412                }
     
    276414                    associatedStreet.addMember(new RelationMember("house", w));
    277415                }
    278416                this.commands.add(new AddCommand(associatedStreet));
    279             }
    280             else { // relation exists already - add new members
     417            } else { // relation exists already - add new members
    281418                Relation newAssociatedStreet = new Relation(associatedStreet);
    282419                for (Way w : ways) {
    283                     newAssociatedStreet.addMember(new RelationMember("house", w));
     420                    newAssociatedStreet
     421                            .addMember(new RelationMember("house", w));
    284422                }
    285                 this.commands.add(new ChangeCommand(associatedStreet, newAssociatedStreet));
     423                this.commands.add(new ChangeCommand(associatedStreet,
     424                        newAssociatedStreet));
    286425            }
    287426        }
     427
     428        // Remove the address node since their tags have been incorporated into
     429        // the terraces.
     430        // Or should removing them also be an option?
     431        if (!housenumbers.isEmpty())
     432            commands.add(DeleteCommand.delete(Main.main.getEditLayer(),
     433                    housenumbers, true, true));
     434
    288435        Main.main.undoRedo.add(new SequenceCommand(tr("Terrace"), commands));
    289436        if (nb > 1) {
    290437            // Select the new building outlines (for quick reversing)
    291438            Main.main.getCurrentDataSet().setSelected(ways);
    292439        } else if (street != null) {
    293             // Select the way (for quick selection of a new house (with the same way))
     440            // Select the way (for quick selection of a new house (with the same
     441            // way))
    294442            Main.main.getCurrentDataSet().setSelected(street);
    295443        }
    296444    }
    297445
    298446    /**
    299447     * Adds address details to a single building
    300      *
    301      * @param outline The closed, quadrilateral way to add the address to.
    302      * @param street The street, the buildings belong to (may be null)
    303      * @param streetName the name of a street (may be null). Used if not null and street is null.
    304      * @param number The house number
     448     *
     449     * @param outline
     450     *            The closed, quadrilateral way to add the address to.
     451     * @param street
     452     *            The street, the buildings belong to (may be null)
     453     * @param streetName
     454     *            the name of a street (may be null). Used if not null and
     455     *            street is null.
     456     * @param number
     457     *            The house number
     458     * @param additionalKeys
     459     *            More keys to be copied onto the new outline
    305460     * @return the way with added address details
    306461     */
    307     private Way addressBuilding(Way outline, Way street, String streetName, String number) {
     462    private Way addressBuilding(Way outline, Way street, String streetName,
     463            String number, Set<Entry<String, String>> additionalKeys) {
    308464        Way changedOutline = outline;
    309465        if (number != null) {
    310466            // only, if the user has specified house numbers
    311             this.commands.add(new ChangePropertyCommand(changedOutline, "addr:housenumber", number));
     467            this.commands.add(new ChangePropertyCommand(changedOutline,
     468                    "addr:housenumber", number));
    312469        }
     470        if (additionalKeys != null) {
     471            for (Entry<String, String> entry : additionalKeys) {
     472                this.commands.add(new ChangePropertyCommand(changedOutline,
     473                        entry.getKey(), entry.getValue()));
     474            }
     475        }
    313476        changedOutline.put("building", "yes");
    314477        if (street != null) {
    315             this.commands.add(new ChangePropertyCommand(changedOutline, "addr:street", street.get("name")));
     478            this.commands.add(new ChangePropertyCommand(changedOutline,
     479                    "addr:street", street.get("name")));
    316480        } else if (streetName != null) {
    317             this.commands.add(new ChangePropertyCommand(changedOutline, "addr:street", streetName));
     481            this.commands.add(new ChangePropertyCommand(changedOutline,
     482                    "addr:street", streetName));
    318483        }
    319484        return changedOutline;
    320485    }
     
    322487    /**
    323488     * Creates a node at a certain distance along a way, as calculated by the
    324489     * great circle distance.
    325      *
     490     * 
    326491     * Note that this really isn't an efficient way to do this and leads to
    327      * O(N^2) running time for the main algorithm, but its simple and easy
    328      * to understand, and probably won't matter for reasonable-sized ways.
    329      *
    330      * @param w The way to interpolate.
    331      * @param l The length at which to place the node.
     492     * O(N^2) running time for the main algorithm, but its simple and easy to
     493     * understand, and probably won't matter for reasonable-sized ways.
     494     *
     495     * @param w
     496     *            The way to interpolate.
     497     * @param l
     498     *            The length at which to place the node.
    332499     * @return A node at a distance l along w from the first point.
    333500     */
    334501    private Node interpolateAlong(Way w, double l) {
    335         List<Pair<Node,Node>> pairs = w.getNodePairs(false);
     502        List<Pair<Node, Node>> pairs = w.getNodePairs(false);
    336503        for (int i = 0; i < pairs.size(); ++i) {
    337             Pair<Node,Node> p = pairs.get(i);
    338             final double seg_length = p.a.getCoor().greatCircleDistance(p.b.getCoor());
    339             if (l <= seg_length ||
    340                     i == pairs.size() - 1) {    // be generous on the last segment (numerical roudoff can lead to a small overshoot)
     504            Pair<Node, Node> p = pairs.get(i);
     505            final double seg_length = p.a.getCoor().greatCircleDistance(
     506                    p.b.getCoor());
     507            if (l <= seg_length || i == pairs.size() - 1) { // be generous on
     508                                                            // the last segment
     509                                                            // (numerical
     510                                                            // roudoff can lead
     511                                                            // to a small
     512                                                            // overshoot)
    341513                return interpolateNode(p.a, p.b, l / seg_length);
    342514            } else {
    343515                l -= seg_length;
     
    350522    /**
    351523     * Calculates the great circle length of a way by summing the great circle
    352524     * distance of each pair of nodes.
    353      *
    354      * @param w The way to calculate length of.
     525     *
     526     * @param w
     527     *            The way to calculate length of.
    355528     * @return The length of the way.
    356529     */
    357530    private double wayLength(Way w) {
     
    366539     * Given a way, try and find a definite front and back by looking at the
    367540     * segments to find the "sides". Sides are assumed to be single segments
    368541     * which cannot be contiguous.
    369      *
    370      * @param w The way to analyse.
     542     *
     543     * @param w
     544     *            The way to analyse.
    371545     * @return A pair of ways (front, back) pointing in the same directions.
    372546     */
    373547    private Pair<Way, Way> findFrontAndBack(Way w) {
     
    428602     * returns the distance of two segments of a closed polygon
    429603     */
    430604    private int indexDistance(int i1, int i2, int n) {
    431         return Math.min(positiveModulus(i1 - i2, n), positiveModulus(i2 - i1, n));
     605        return Math.min(positiveModulus(i1 - i2, n),
     606                positiveModulus(i2 - i1, n));
    432607    }
    433608
    434609    /**
    435610     * return the modulus in the range [0, n)
    436611     */
    437612    private int positiveModulus(int a, int n) {
    438         if (n <=0)
     613        if (n <= 0)
    439614            throw new IllegalArgumentException();
    440615        int res = a % n;
    441616        if (res < 0) {
     
    445620    }
    446621
    447622    /**
    448      * Calculate the length of a side (from node i to i+1) in a way. This assumes that
    449      * the way is closed, but I only ever call it for buildings.
     623     * Calculate the length of a side (from node i to i+1) in a way. This
     624     * assumes that the way is closed, but I only ever call it for buildings.
    450625     */
    451626    private double sideLength(Way w, int i) {
    452627        Node a = w.getNode(i);
     
    456631
    457632    /**
    458633     * Given an array of doubles (but this could made generic very easily) sort
    459      * into order and return the array of indexes such that, for a returned array
    460      * x, a[x[i]] is sorted for ascending index i.
    461      *
    462      * This isn't efficient at all, but should be fine for the small arrays we're
    463      * expecting. If this gets slow - replace it with some more efficient algorithm.
    464      *
    465      * @param a The array to sort.
    466      * @return An array of indexes, the same size as the input, such that a[x[i]]
    467      * is in sorted order.
     634     * into order and return the array of indexes such that, for a returned
     635     * array x, a[x[i]] is sorted for ascending index i.
     636     *
     637     * This isn't efficient at all, but should be fine for the small arrays
     638     * we're expecting. If this gets slow - replace it with some more efficient
     639     * algorithm.
     640     *
     641     * @param a
     642     *            The array to sort.
     643     * @return An array of indexes, the same size as the input, such that
     644     *         a[x[i]] is in sorted order.
    468645     */
    469646    private int[] sortedIndexes(final double[] a) {
    470647        class SortWithIndex implements Comparable<SortWithIndex> {
     
    517694
    518695    /**
    519696     * Calculate sideness of a single segment given the nodes which make up that
    520      * segment and its previous and next segments in order. Sideness is calculated
    521      * for the segment b-c.
     697     * segment and its previous and next segments in order. Sideness is
     698     * calculated for the segment b-c.
    522699     */
    523700    private double calculateSideness(Node a, Node b, Node c, Node d) {
    524701        final double ndx = b.getCoor().getX() - a.getCoor().getX();
     
    533710    /**
    534711     * Creates a new node at the interpolated position between the argument
    535712     * nodes. Interpolates linearly in projected coordinates.
    536      *
    537      * @param a First node, at which f=0.
    538      * @param b Last node, at which f=1.
    539      * @param f Fractional position between first and last nodes.
     713     *
     714     * @param a
     715     *            First node, at which f=0.
     716     * @param b
     717     *            Last node, at which f=1.
     718     * @param f
     719     *            Fractional position between first and last nodes.
    540720     * @return A new node at the interpolated position.
    541721     */
    542722    private Node interpolateNode(Node a, Node b, double f) {
  • 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;
    3032
    3133/**
    32  * The Class HouseNumberInputHandler contains all the logic
    33  * behind the house number input dialog.
    34  *
    35  * From a refactoring viewpoint, this class is indeed more interested in the fields
    36  * of the HouseNumberInputDialog. This is desired design, as the HouseNumberInputDialog
    37  * is already cluttered with auto-generated layout code.
    38  *
     34 * The Class HouseNumberInputHandler contains all the logic behind the house
     35 * number input dialog.
     36 * 
     37 * From a refactoring viewpoint, this class is indeed more interested in the
     38 * fields of the HouseNumberInputDialog. This is desired design, as the
     39 * HouseNumberInputDialog is already cluttered with auto-generated layout code.
     40 * 
    3941 * @author casualwalker
    4042 */
    41  public class HouseNumberInputHandler extends JosmAction implements ActionListener, FocusListener, ItemListener {
     43public class HouseNumberInputHandler extends JosmAction implements
     44        ActionListener, FocusListener, ItemListener {
    4245    private TerracerAction terracerAction;
    43     private Way outline, street;
     46    private Way outline;
     47    private Way street;
     48    private String streetName;
    4449    private Relation associatedStreet;
     50    private ArrayList<Node> housenumbers;
    4551    public HouseNumberInputDialog dialog;
    4652
    4753    /**
    4854     * Instantiates a new house number input handler.
    49      *
    50      * @param terracerAction the terracer action
    51      * @param outline the closed, quadrilateral way to terrace.
    52      * @param street the street, the buildings belong to (may be null)
    53      * @param associatedStreet a relation where we can add the houses (may be null)
    54      * @param title the title
     55     *
     56     * @param terracerAction
     57     *            the terracer action
     58     * @param outline
     59     *            the closed, quadrilateral way to terrace.
     60     * @param street
     61     *            the street, the buildings belong to (may be null)
     62     * @param streetName
     63     *            the name of the street, derived from either the street line or
     64     *            the house numbers which are guaranteed to have the same name
     65     *            attached (may be null)
     66     * @param associatedStreet
     67     *            a relation where we can add the houses (may be null)
     68     * @param housenumbers
     69     *            a list of house number nodes in this outline (may be empty)
     70     * @param title
     71     *            the title
    5572     */
    5673    public HouseNumberInputHandler(final TerracerAction terracerAction,
    57             final Way outline, final Way street, final Relation associatedStreet,
    58             final String title) {
     74            final Way outline, final Way street, final String streetName,
     75            final Relation associatedStreet,
     76            final ArrayList<Node> housenumbers, final String title) {
    5977        this.terracerAction = terracerAction;
    6078        this.outline = outline;
    6179        this.street = street;
     80        this.streetName = streetName;
    6281        this.associatedStreet = associatedStreet;
     82        this.housenumbers = housenumbers;
    6383
    6484        // This dialog is started modal
    65         this.dialog = new HouseNumberInputDialog(this, street, associatedStreet != null);
     85        this.dialog = new HouseNumberInputDialog(this, street, streetName,
     86                associatedStreet != null, housenumbers);
    6687
    6788        // We're done
    6889    }
    6990
    7091    /**
    71      * Find a button with a certain caption.
    72      * Loops recursively through all objects to find all buttons.
    73      * Function returns on the first match.
    74      *
    75      * @param root A container object that is recursively searched for other containers or buttons
    76      * @param caption The caption of the button that is being searched
    77      *
     92     * Find a button with a certain caption. Loops recursively through all
     93     * objects to find all buttons. Function returns on the first match.
     94     *
     95     * @param root
     96     *            A container object that is recursively searched for other
     97     *            containers or buttons
     98     * @param caption
     99     *            The caption of the button that is being searched
     100     *
    78101     * @return The first button that matches the caption or null if not found
    79102     */
    80103    private static JButton getButton(Container root, String caption) {
    81104        Component children[] = root.getComponents();
    82          for (Component child : children) {
     105        for (Component child : children) {
    83106            JButton b;
    84107            if (child instanceof JButton) {
    85108                b = (JButton) child;
    86                 if (caption.equals(b.getText())) return b;
     109                if (caption.equals(b.getText()))
     110                    return b;
    87111            } else if (child instanceof Container) {
    88                   b = getButton((Container)child, caption);
    89                   if (b != null) return b;
    90              }
    91          }
     112                b = getButton((Container) child, caption);
     113                if (b != null)
     114                    return b;
     115            }
     116        }
    92117        return null;
    93118    }
    94119
    95120    /**
    96      * Validate the current input fields.
    97      * When the validation fails, a red message is
    98      * displayed and the OK button is disabled.
    99      *
     121     * Validate the current input fields. When the validation fails, a red
     122     * message is displayed and the OK button is disabled.
     123     *
    100124     * Should be triggered each time the input changes.
    101125     */
    102126    private boolean validateInput() {
     
    107131        isOk = isOk && checkSegmentsFromHousenumber(message);
    108132        isOk = isOk && checkSegments(message);
    109133
    110         // Allow non numeric characters for the low number as long as there is no high number of the segmentcount is 1
     134        // Allow non numeric characters for the low number as long as there is
     135        // no high number of the segmentcount is 1
    111136        if (dialog.hi.getText().length() > 0 | segments() > 1) {
    112137            isOk = isOk
    113138                    && checkNumberStringField(dialog.lo, tr("Lowest number"),
     
    127152
    128153            // For some reason the messageLabel doesn't want to show up
    129154            dialog.messageLabel.setForeground(Color.black);
    130             dialog.messageLabel.setText(tr(HouseNumberInputDialog.DEFAULT_MESSAGE));
     155            dialog.messageLabel
     156                    .setText(tr(HouseNumberInputDialog.DEFAULT_MESSAGE));
    131157            return true;
    132158        } else {
    133159            JButton okButton = getButton(dialog, "OK");
    134160            if (okButton != null)
    135161                okButton.setEnabled(false);
    136162
    137             // For some reason the messageLabel doesn't want to show up, so a MessageDialog is shown instead. Someone more knowledgeable might fix this.
     163            // For some reason the messageLabel doesn't want to show up, so a
     164            // MessageDialog is shown instead. Someone more knowledgeable might
     165            // fix this.
    138166            dialog.messageLabel.setForeground(Color.red);
    139167            dialog.messageLabel.setText(message.toString());
    140             //JOptionPane.showMessageDialog(null, message.toString(), tr("Error"), JOptionPane.ERROR_MESSAGE);
     168            // JOptionPane.showMessageDialog(null, message.toString(),
     169            // tr("Error"), JOptionPane.ERROR_MESSAGE);
    141170
    142171            return false;
    143172        }
    144173    }
    145174
    146175    /**
    147      * Checks, if the lowest house number is indeed lower than the
    148      * highest house number.
    149      * This check applies only, if the house number fields are used at all.
    150      *
    151      * @param message the message
    152      *
     176     * Checks, if the lowest house number is indeed lower than the highest house
     177     * number. This check applies only, if the house number fields are used at
     178     * all.
     179     *
     180     * @param message
     181     *            the message
     182     *
    153183     * @return true, if successful
    154184     */
    155185    private boolean checkNumberOrder(final StringBuffer message) {
    156186        if (numberFrom() != null && numberTo() != null) {
    157187            if (numberFrom().intValue() > numberTo().intValue()) {
    158188                appendMessageNewLine(message);
    159                 message.append(tr("Lowest housenumber cannot be higher than highest housenumber"));
     189                message
     190                        .append(tr("Lowest housenumber cannot be higher than highest housenumber"));
    160191                return false;
    161192            }
    162193        }
     
    164195    }
    165196
    166197    /**
    167      * Obtain the number segments from the house number fields and check,
    168      * if they are valid.
    169      *
    170      * Also disables the segments field, if the house numbers contain
    171      * valid information.
    172      *
    173      * @param message the message
    174      *
     198     * Obtain the number segments from the house number fields and check, if
     199     * they are valid.
     200     *
     201     * Also disables the segments field, if the house numbers contain valid
     202     * information.
     203     *
     204     * @param message
     205     *            the message
     206     *
    175207     * @return true, if successful
    176208     */
    177209    private boolean checkSegmentsFromHousenumber(final StringBuffer message) {
    178         dialog.segments.setEditable(true);
     210        if (!dialog.numbers.isVisible()) {
     211            dialog.segments.setEditable(true);
    179212
    180         if (numberFrom() != null && numberTo() != null) {
     213            if (numberFrom() != null && numberTo() != null) {
    181214
    182             int segments = numberTo().intValue() - numberFrom().intValue();
     215                int segments = numberTo().intValue() - numberFrom().intValue();
    183216
    184             if (segments % stepSize() != 0) {
    185                 appendMessageNewLine(message);
    186                 message.append(tr("Housenumbers do not match odd/even setting"));
    187                 return false;
    188             }
     217                if (segments % stepSize() != 0) {
     218                    appendMessageNewLine(message);
     219                    message
     220                            .append(tr("Housenumbers do not match odd/even setting"));
     221                    return false;
     222                }
    189223
    190             int steps = segments / stepSize();
    191             steps++; // difference 0 means 1 building, see
    192             // TerracerActon.terraceBuilding
    193             dialog.segments.setText(String.valueOf(steps));
    194             dialog.segments.setEditable(false);
     224                int steps = segments / stepSize();
     225                steps++; // difference 0 means 1 building, see
     226                // TerracerActon.terraceBuilding
     227                dialog.segments.setText(String.valueOf(steps));
     228                dialog.segments.setEditable(false);
    195229
     230            }
    196231        }
    197232        return true;
    198233    }
    199234
    200235    /**
    201      * Check the number of segments.
    202      * It must be a number and greater than 1.
    203      *
    204      * @param message the message
    205      *
     236     * Check the number of segments. It must be a number and greater than 1.
     237     *
     238     * @param message
     239     *           the message
     240     * 
    206241     * @return true, if successful
    207242     */
    208243    private boolean checkSegments(final StringBuffer message) {
     
    217252
    218253    /**
    219254     * Check, if a string field contains a positive integer.
    220      *
    221      * @param field the field
    222      * @param label the label
    223      * @param message the message
    224      *
     255     *
     256     * @param field
     257     *            the field
     258     * @param label
     259     *            the label
     260     * @param message
     261     *            the message
     262     *
    225263     * @return true, if successful
    226264     */
    227265    private boolean checkNumberStringField(final JTextField field,
     
    247285
    248286    /**
    249287     * Append a new line to the message, if the message is not empty.
    250      *
    251      * @param message the message
     288     *
     289     * @param message
     290     *            the message
    252291     */
    253292    private void appendMessageNewLine(final StringBuffer message) {
    254293        if (message.length() > 0) {
     
    256295        }
    257296    }
    258297
    259     /* (non-Javadoc)
    260      * @see java.awt.event.ItemListener#itemStateChanged(java.awt.event.ItemEvent)
     298    /*
     299     * (non-Javadoc)
     300     *
     301     * @see
     302     * java.awt.event.ItemListener#itemStateChanged(java.awt.event.ItemEvent)
    261303     * Called when the user selects from a pulldown selection
    262304     */
    263305    public void itemStateChanged(ItemEvent e) {
    264306        validateInput();
    265307    }
    266308
    267     /* (non-Javadoc)
    268      * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
     309    /*
     310     * (non-Javadoc)
     311     *
     312     * @see
     313     * java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
    269314     */
    270315    public void actionPerformed(final ActionEvent e) {
    271316        // OK or Cancel button-actions
     
    274319            if ("OK".equals(button.getActionCommand()) & button.isEnabled()) {
    275320                if (validateInput()) {
    276321                    saveValues();
    277 
     322                           
    278323                    terracerAction.terraceBuilding(
    279                         outline,
     324                            outline,
    280325                        street,
    281326                        associatedStreet,
    282327                        segments(),
    283328                        dialog.lo.getText(),
    284329                        dialog.hi.getText(),
    285330                        stepSize(),
     331                        housenumbers,
    286332                        streetName(),
    287333                        doHandleRelation(),
    288334                        doDeleteOutline());
    289 
     335                               
    290336                    this.dialog.dispose();
    291                 }
     337                    }
    292338            } else if ("Cancel".equals(button.getActionCommand())) {
    293339                this.dialog.dispose();
    294340            }
     
    299345    }
    300346
    301347    /**
    302      * Calculate the step size between two house numbers,
    303      * based on the interpolation setting.
    304      *
     348     * Calculate the step size between two house numbers, based on the
     349     * interpolation setting.
     350     * 
    305351     * @return the stepSize (1 for all, 2 for odd /even)
    306352     */
    307353    public Integer stepSize() {
     
    311357
    312358    /**
    313359     * Gets the number of segments, if set.
    314      *
     360     * 
    315361     * @return the number of segments or null, if not set / invalid.
    316362     */
    317363    public Integer segments() {
     
    324370
    325371    /**
    326372     * Gets the lowest house number.
    327      *
     373     * 
    328374     * @return the number of lowest house number or null, if not set / invalid.
    329375     */
    330376    public Integer numberFrom() {
     
    337383
    338384    /**
    339385     * Gets the highest house number.
    340      *
     386     * 
    341387     * @return the number of highest house number or null, if not set / invalid.
    342388     */
    343389    public Integer numberTo() {
     
    350396
    351397    /**
    352398     * Gets the street name.
    353      *
    354      * @return the  street name or null, if not set / invalid.
     399     * 
     400     * @return the street name or null, if not set / invalid.
    355401     */
    356402    public String streetName() {
    357         if (street != null)
    358             return null;
     403        if (streetName != null)
     404            return streetName;
    359405
    360406        Object selected = dialog.streetComboBox.getSelectedItem();
    361407        if (selected == null) {
     
    371417    }
    372418
    373419    /**
    374      * Whether the user likes to create a relation or add to
    375      * an existing one.
     420     * Whether the user likes to create a relation or add to an existing one.
    376421     */
    377422    public boolean doHandleRelation() {
    378423        if (this.dialog == null) {
    379             JOptionPane.showMessageDialog(null, "dialog", "alert", JOptionPane.ERROR_MESSAGE);
     424            JOptionPane.showMessageDialog(null, "dialog", "alert",
     425                    JOptionPane.ERROR_MESSAGE);
    380426        }
    381427        if (this.dialog.handleRelationCheckBox == null) {
    382             JOptionPane.showMessageDialog(null, "checkbox", "alert", JOptionPane.ERROR_MESSAGE);
     428            JOptionPane.showMessageDialog(null, "checkbox", "alert",
     429                    JOptionPane.ERROR_MESSAGE);
    383430            return true;
    384         }  else {
     431        } else {
    385432            return this.dialog.handleRelationCheckBox.isSelected();
    386433        }
    387434    }
    388435
    389 
    390436    /**
    391437     * Whether the user likes to delete the outline way.
    392438     */
     
    394440        return dialog.deleteOutlineCheckBox.isSelected();
    395441    }
    396442
    397     /* (non-Javadoc)
     443    /*
     444     * (non-Javadoc)
     445     *
    398446     * @see java.awt.event.FocusListener#focusGained(java.awt.event.FocusEvent)
    399447     */
    400448    public void focusGained(FocusEvent e) {
    401449        // Empty, but placeholder is required
    402450    }
    403451
    404     /* (non-Javadoc)
     452    /*
     453     * (non-Javadoc)
     454     *
    405455     * @see java.awt.event.FocusListener#focusLost(java.awt.event.FocusEvent)
    406456     */
    407457    public void focusLost(FocusEvent e) {
     
    415465     * Saves settings.
    416466     */
    417467    public void saveValues() {
    418         Main.pref.put(HouseNumberInputDialog.HANDLE_RELATION, doHandleRelation());
     468        Main.pref.put(HouseNumberInputDialog.HANDLE_RELATION,
     469                doHandleRelation());
    419470        Main.pref.put(HouseNumberInputDialog.DELETE_OUTLINE, doDeleteOutline());
    420         Main.pref.put(HouseNumberInputDialog.INTERPOLATION, stepSize().toString());
     471        Main.pref.put(HouseNumberInputDialog.INTERPOLATION, stepSize()
     472                .toString());
    421473    }
    422474}