Ignore:
Timestamp:
2010-09-15T18:56:19+02:00 (14 years ago)
Author:
stoecker
Message:

remove tabs

Location:
applications/editors/josm/plugins/addrinterpolation/src/org/openstreetmap/josm/plugins/AddrInterpolation
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • applications/editors/josm/plugins/addrinterpolation/src/org/openstreetmap/josm/plugins/AddrInterpolation/AddrInterpolationAction.java

    r17762 r23191  
    2222SelectionChangedListener {
    2323
    24         public AddrInterpolationAction(){
    25                 super(tr("Address Interpolation"), "AddrInterpolation", tr("Handy Address Interpolation Functions"),
    26                                 Shortcut.registerShortcut("tools:AddressInterpolation", tr("Tool: {0}", tr("Address Interpolation")),
    27                                                 KeyEvent.VK_A, Shortcut.GROUP_MENU,
    28                                                 InputEvent.ALT_DOWN_MASK | InputEvent.CTRL_DOWN_MASK), false);
    29                 setEnabled(false);
    30                 DataSet.selListeners.add(this);
    31         }
     24    public AddrInterpolationAction(){
     25        super(tr("Address Interpolation"), "AddrInterpolation", tr("Handy Address Interpolation Functions"),
     26                Shortcut.registerShortcut("tools:AddressInterpolation", tr("Tool: {0}", tr("Address Interpolation")),
     27                        KeyEvent.VK_A, Shortcut.GROUP_MENU,
     28                        InputEvent.ALT_DOWN_MASK | InputEvent.CTRL_DOWN_MASK), false);
     29        setEnabled(false);
     30        DataSet.selListeners.add(this);
     31    }
    3232
    33         public void actionPerformed(ActionEvent e) {
    34                 AddrInterpolationDialog addrDialog = new AddrInterpolationDialog(tr("Define Address Interpolation"));
     33    public void actionPerformed(ActionEvent e) {
     34        AddrInterpolationDialog addrDialog = new AddrInterpolationDialog(tr("Define Address Interpolation"));
    3535
    3636
    37         }
     37    }
    3838
    39         public void selectionChanged(
    40                         Collection<? extends OsmPrimitive> newSelection) {
     39    public void selectionChanged(
     40            Collection<? extends OsmPrimitive> newSelection) {
    4141
    42                 for (OsmPrimitive osm : newSelection) {
    43                         if (osm instanceof Way) {
    44                                 setEnabled(true);
    45                                 return;
    46                         }
    47                 }
    48                 setEnabled(false);
     42        for (OsmPrimitive osm : newSelection) {
     43            if (osm instanceof Way) {
     44                setEnabled(true);
     45                return;
     46            }
     47        }
     48        setEnabled(false);
    4949
    50         }
     50    }
    5151
    5252}
  • applications/editors/josm/plugins/addrinterpolation/src/org/openstreetmap/josm/plugins/AddrInterpolation/AddrInterpolationDialog.java

    r23102 r23191  
    6969public class AddrInterpolationDialog extends JDialog implements ActionListener  {
    7070
    71         private Way selectedStreet = null;
    72         private Way addrInterpolationWay = null;
    73         private Relation associatedStreetRelation = null;
    74         private ArrayList<Node> houseNumberNodes = null;  // Additional nodes with addr:housenumber
    75 
    76         private static String lastIncrement = "";
    77         private static int lastAccuracyIndex = 0;
    78         private static String lastCity = "";
    79         private static String lastState = "";
    80         private static String lastPostCode = "";
    81         private static String lastCountry = "";
    82         private static String lastFullAddress = "";
    83         private static boolean lastConvertToHousenumber = false;
    84 
    85         // Edit controls
    86         private EscapeDialog dialog=null;
    87         private JRadioButton streetNameButton = null;
    88         private JRadioButton streetRelationButton  = null;
    89         private JTextField startTextField = null;
    90         private JTextField endTextField = null;
    91         private JTextField incrementTextField = null;
    92         private JTextField cityTextField = null;
    93         private JTextField stateTextField = null;
    94         private JTextField postCodeTextField = null;
    95         private JTextField countryTextField = null;
    96         private JTextField fullTextField = null;
    97         private Checkbox cbConvertToHouseNumbers = null;
    98 
    99         private boolean relationChanged = false; // Whether to re-trigger data changed for relation
    100         // Track whether interpolation method is known so that auto detect doesn't override a previous choice.
    101         private boolean interpolationMethodSet = false;
    102 
    103 
    104         // NOTE: The following 2 arrays must match in number of elements and position
    105         // Tag values for map (Except that 'Numeric' is replaced by actual # on map)
    106         String[] addrInterpolationTags = { "odd", "even", "all", "alphabetic", "Numeric" };
    107         String[] addrInterpolationStrings = { tr("Odd"), tr("Even"), tr("All"), tr("Alphabetic"), tr("Numeric") }; // Translatable names for display
    108         private final int NumericIndex = 4;
    109         private JComboBox addrInterpolationList = null;
    110 
    111         // NOTE: The following 2 arrays must match in number of elements and position
    112         String[] addrInclusionTags = { "actual", "estimate", "potential" }; // Tag values for map
    113         String[] addrInclusionStrings = { tr("Actual"), tr("Estimate"), tr("Potential") }; // Translatable names for display
    114         private JComboBox addrInclusionList = null;
    115 
    116 
    117 
    118         // For tracking edit changes as group for undo
    119         private Collection<Command> commandGroup = null;
    120         private Relation editedRelation = null;
    121 
    122         public AddrInterpolationDialog(String name) {
    123 
    124                 if (!FindAndSaveSelections()) {
    125                         return;
    126                 }
    127 
    128                 JPanel editControlsPane = CreateEditControls();
    129 
    130                 ShowDialog(editControlsPane, name);
    131 
    132         }
    133 
    134 
    135 
    136         private void ShowDialog(JPanel editControlsPane, String name) {
    137                 dialog = new EscapeDialog((Frame) Main.parent, name, true);
    138 
    139                 dialog.add(editControlsPane);
    140                 dialog.setSize(new Dimension(300,500));
    141                 dialog.setLocation(new Point(100,300));
    142 
    143                 // Listen for windowOpened event to set focus
    144                 dialog.addWindowListener( new WindowAdapter()
    145                 {
    146                         @Override
    147                         public void windowOpened( WindowEvent e )
    148                         {
    149                                 if (addrInterpolationWay != null) {
    150                                         startTextField.requestFocus();
    151                                 }
    152                                 else {
    153                                         cityTextField.requestFocus();
    154                                 }
    155                         }
    156                 });
    157 
    158                 dialog.setVisible(true);
    159 
    160                 lastIncrement = incrementTextField.getText();
    161                 lastCity = cityTextField.getText();
    162                 lastState = stateTextField.getText();
    163                 lastPostCode = postCodeTextField.getText();
    164                 lastCountry = countryTextField.getText();
    165                 lastFullAddress = fullTextField.getText();
    166                 lastConvertToHousenumber = cbConvertToHouseNumbers.getState();
    167 
    168         }
    169 
    170 
    171 
    172         // Create edit control items and return JPanel on which they reside
    173         private JPanel CreateEditControls() {
    174 
    175                 JPanel editControlsPane = new JPanel();
    176                 GridBagLayout gridbag = new GridBagLayout();
    177                 GridBagConstraints c = new GridBagConstraints();
    178 
    179                 editControlsPane.setLayout(gridbag);
    180 
    181                 editControlsPane.setBorder(BorderFactory.createEmptyBorder(15,15,15,15));
    182 
    183 
    184                 String streetName = selectedStreet.get("name");
    185                 String streetRelation = FindRelation();
    186                 if (streetRelation.equals("")) {
    187                         streetRelation = " (Create new)";
    188                 }
    189                 streetNameButton = new JRadioButton(tr("Name: {0}", streetName));
    190                 streetRelationButton = new JRadioButton(tr("Relation: {0}", streetRelation));
    191                 if (associatedStreetRelation == null) {
    192                         streetNameButton.setSelected(true);
    193                 }else {
    194                         streetRelationButton.setSelected(true);
    195                 }
    196 
    197                 // Create edit controls for street / relation radio buttons
    198                 ButtonGroup group = new ButtonGroup();
    199                 group.add(streetNameButton);
    200                 group.add(streetRelationButton);
    201                 JPanel radioButtonPanel = new JPanel(new BorderLayout());
    202                 radioButtonPanel.setBorder(BorderFactory.createTitledBorder(tr("Associate with street using:")));
    203                 radioButtonPanel.add(streetNameButton, BorderLayout.NORTH);
    204                 radioButtonPanel.add(streetRelationButton, BorderLayout.SOUTH);
    205 
    206                 // Add to edit panel
    207                 c.gridx = 0;
    208                 c.gridwidth = 2; // # of columns to span
    209                 c.fill = GridBagConstraints.HORIZONTAL;      // Full width
    210                 c.gridwidth = GridBagConstraints.REMAINDER;     //end row
    211                 editControlsPane.add(radioButtonPanel, c);
    212 
    213                 JLabel numberingLabel = new JLabel(tr("Numbering Scheme:"));
    214                 addrInterpolationList = new JComboBox(addrInterpolationStrings);
    215 
    216                 JLabel incrementLabel = new JLabel(tr("Increment:"));
    217                 incrementTextField = new JTextField(lastIncrement, 100);
    218                 incrementTextField.setEnabled(false);
    219 
    220                 JLabel startLabel = new JLabel(tr("Starting #:"));
    221                 JLabel endLabel = new JLabel(tr("Ending #:"));
    222 
    223                 startTextField = new JTextField(10);
    224                 endTextField = new JTextField(10);
    225 
    226                 JLabel inclusionLabel = new JLabel(tr("Accuracy:"));
    227                 addrInclusionList = new JComboBox(addrInclusionStrings);
    228                 addrInclusionList.setSelectedIndex(lastAccuracyIndex);
    229 
    230                 // Preload any values already set in map
    231                 GetExistingMapKeys();
    232 
    233 
    234                 JLabel[] textLabels = {startLabel, endLabel, numberingLabel, incrementLabel, inclusionLabel};
    235                 Component[] editFields = {startTextField, endTextField, addrInterpolationList, incrementTextField, addrInclusionList};
    236                 AddEditControlRows(textLabels, editFields,      editControlsPane);
    237 
    238                 cbConvertToHouseNumbers = new Checkbox(tr("Convert way to individual house numbers."), null, lastConvertToHousenumber);
    239                 // cbConvertToHouseNumbers.setSelected(lastConvertToHousenumber);
    240 
    241                 // Address interpolation fields not valid if Way not selected
    242                 if (addrInterpolationWay == null) {
    243                         addrInterpolationList.setEnabled(false);
    244                         startTextField.setEnabled(false);
    245                         endTextField.setEnabled(false);
    246                         cbConvertToHouseNumbers.setEnabled(false);
    247                 }
    248 
    249 
    250 
    251                 JPanel optionPanel = CreateOptionalFields();
    252                 c.gridx = 0;
    253                 c.gridwidth = 2; // # of columns to span
    254                 c.fill = GridBagConstraints.BOTH;      // Full width
    255                 c.gridwidth = GridBagConstraints.REMAINDER;     //end row
    256 
    257                 editControlsPane.add(optionPanel, c);
    258 
    259 
    260                 KeyAdapter enterProcessor = new KeyAdapter() {
    261                         @Override
    262                         public void keyPressed(KeyEvent e) {
    263                                 if (e.getKeyCode() == KeyEvent.VK_ENTER) {
    264                                         if (ValidateAndSave()) {
    265                                                 dialog.dispose();
    266                                         }
    267 
    268                                 }
    269                         }
    270                 };
    271 
    272                 // Make Enter == OK click on fields using this adapter
    273                 endTextField.addKeyListener(enterProcessor);
    274                 cityTextField.addKeyListener(enterProcessor);
    275                 addrInterpolationList.addKeyListener(enterProcessor);
    276                 incrementTextField.addKeyListener(enterProcessor);
    277 
    278 
    279                 // Watch when Interpolation Method combo box is selected so that
    280                 // it can auto-detect method based on entered numbers.
    281                 addrInterpolationList.addFocusListener(new FocusAdapter() {
    282                         @Override
    283                         public void focusGained(FocusEvent fe){
    284                                 if (!interpolationMethodSet) {
    285                                         if (AutoDetectInterpolationMethod()) {
    286                                                 interpolationMethodSet = true;  // Don't auto detect over a previous choice
    287                                         }
    288                                 }
    289                         }
    290                 });
    291 
    292 
    293                 // Watch when Interpolation Method combo box is changed so that
    294                 // Numeric increment box can be enabled or disabled.
    295                 addrInterpolationList.addActionListener(new ActionListener() {
    296                         public void actionPerformed(ActionEvent e){
    297                                 int selectedIndex = addrInterpolationList.getSelectedIndex();
    298                                 incrementTextField.setEnabled(selectedIndex == NumericIndex); // Enable or disable numeric field
    299                         }
    300                 });
    301 
    302 
    303                 editControlsPane.add(cbConvertToHouseNumbers, c);
    304 
    305 
    306 
    307                 if (houseNumberNodes.size() > 0) {
    308                         JLabel houseNumberNodeNote = new JLabel(tr("Will associate {0} additional house number nodes",
    309                                         houseNumberNodes.size() ));
    310                         editControlsPane.add(houseNumberNodeNote, c);
    311                 }
    312 
    313                 editControlsPane.add(new UrlLabel("http://wiki.openstreetmap.org/wiki/JOSM/Plugins/AddrInterpolation",
    314                                 tr("More information about this feature")), c);
    315 
    316 
    317                 c.gridx = 0;
    318                 c.gridwidth = 1; //next-to-last
    319                 c.fill = GridBagConstraints.NONE;      //reset to default
    320                 c.weightx = 0.0;
    321                 c.insets = new Insets(15, 0, 0, 0);
    322                 c.anchor = GridBagConstraints.LINE_END;
    323                 JButton okButton = new JButton(tr("OK"), ImageProvider.get("ok"));
    324                 editControlsPane.add(okButton, c);
    325 
    326                 c.gridx = 1;
    327                 c.gridwidth = GridBagConstraints.REMAINDER;     //end row
    328                 c.weightx = 1.0;
    329                 c.anchor = GridBagConstraints.LINE_START;
    330 
    331                 JButton cancelButton = new JButton(tr("Cancel"), ImageProvider.get("cancel"));
    332                 editControlsPane.add(cancelButton, c);
    333 
    334                 okButton.setActionCommand("ok");
    335                 okButton.addActionListener(this);
    336                 cancelButton.setActionCommand("cancel");
    337                 cancelButton.addActionListener(this);
    338 
    339                 return editControlsPane;
    340         }
    341 
    342 
    343 
    344         // Call after both starting and ending housenumbers have been entered - usually when
    345         // combo box gets focus.
    346         // Return true if a method was detected
    347         private boolean AutoDetectInterpolationMethod() {
    348 
    349                 String startValueString = ReadTextField(startTextField);
    350                 String endValueString = ReadTextField(endTextField);
    351                 if ( (startValueString == null) || (endValueString== null) ) {
    352                         // Not all values entered yet
    353                         return false;
    354                 }
    355 
    356                 // String[] addrInterpolationTags = { "odd", "even", "all", "alphabetic", ### };  // Tag values for map
    357 
    358                 if (isLong(startValueString) && isLong(endValueString)) {
    359                         // Have 2 numeric values
    360                         long startValue = Long.parseLong( startValueString );
    361                         long endValue = Long.parseLong( endValueString );
    362 
    363                         if (isEven(startValue)) {
    364                                 if (isEven(endValue)) {
    365                                         SelectInterpolationMethod("even");
    366                                 }
    367                                 else {
    368                                         SelectInterpolationMethod("all");
    369                                 }
    370                         } else {
    371                                 if (!isEven(endValue)) {
    372                                         SelectInterpolationMethod("odd");
    373                                 }
    374                                 else {
    375                                         SelectInterpolationMethod("all");
    376                                 }
    377                         }
    378 
    379 
    380                 } else {
    381                         // Test for possible alpha
    382                         char startingChar = startValueString.charAt(startValueString.length()-1);
    383                         char endingChar = endValueString.charAt(endValueString.length()-1);
    384 
    385                         if ( (!IsNumeric("" + startingChar)) &&  (!IsNumeric("" + endingChar)) ) {
    386                                 // Both end with alpha
    387                                 SelectInterpolationMethod("alphabetic");
    388                                 return true;
    389                         }
    390 
    391                         if ( (IsNumeric("" + startingChar)) &&  (!IsNumeric("" + endingChar)) ) {
    392                                 endingChar = Character.toUpperCase(endingChar);
    393                                 if ( (endingChar >= 'A') && (endingChar <= 'Z') ) {
    394                                         // First is a number, last is Latin alpha
    395                                         SelectInterpolationMethod("alphabetic");
    396                                         return true;
    397                                 }
    398                         }
    399                        
    400                         // Did not detect alpha
    401                         return false;
    402 
    403                 }
    404                
    405                 return true;
    406 
    407         }
    408 
    409 
    410 
    411         // Set Interpolation Method combo box to method specified by 'currentMethod' (an OSM key value)
    412         private void SelectInterpolationMethod(String currentMethod) {
    413                 int currentIndex = 0;
    414                 if (isLong(currentMethod)) {
    415                         // Valid number: Numeric increment method
    416                         currentIndex = addrInterpolationTags.length-1;
    417                         incrementTextField.setText(currentMethod);
    418                         incrementTextField.setEnabled(true);
    419                 }
    420                 else {
    421                         // Must scan OSM key values because combo box is already loaded with translated strings
    422                         for (int i=0; i<addrInterpolationTags.length; i++) {
    423                                 if (addrInterpolationTags[i].equals(currentMethod)) {
    424                                         currentIndex = i;
    425                                         break;
    426                                 }
    427                         }
    428                 }
    429                 addrInterpolationList.setSelectedIndex(currentIndex);
    430 
    431         }
    432 
    433 
    434         // Set Inclusion Method combo box to method specified by 'currentMethod' (an OSM key value)
    435         private void SelectInclusion(String currentMethod) {
    436                 int currentIndex = 0;
    437                 // Must scan OSM key values because combo box is already loaded with translated strings
    438                 for (int i=0; i<addrInclusionTags.length; i++) {
    439                         if (addrInclusionTags[i].equals(currentMethod)) {
    440                                 currentIndex = i;
    441                                 break;
    442                         }
    443                 }
    444                 addrInclusionList.setSelectedIndex(currentIndex);
    445 
    446         }
    447 
    448 
    449 
    450         // Create optional control fields in a group box
    451         private JPanel CreateOptionalFields() {
    452 
    453                 JPanel editControlsPane = new JPanel();
    454                 GridBagLayout gridbag = new GridBagLayout();
    455 
    456                 editControlsPane.setLayout(gridbag);
    457 
    458                 editControlsPane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
    459 
    460                 JLabel[] optionalTextLabels = {new JLabel(tr("City:")),
    461                                 new JLabel(tr("State:")),
    462                                 new JLabel(tr("Post Code:")),
    463                                 new JLabel(tr("Country:")),
    464                                 new JLabel(tr("Full Address:"))};
    465                 cityTextField = new JTextField(lastCity, 100);
    466                 stateTextField = new JTextField(lastState, 100);
    467                 postCodeTextField = new JTextField(lastPostCode, 20);
    468                 countryTextField = new JTextField(lastCountry, 2);
    469                 fullTextField = new JTextField(lastFullAddress, 300);
    470 
    471                 // Special processing for addr:country code, max length and uppercase
    472                 countryTextField.addKeyListener(new KeyAdapter() {
    473                         @Override
    474                         public void keyTyped(KeyEvent e) {
    475                                 JTextField jtextfield = (JTextField)e.getSource();
    476                                 String text = jtextfield.getText();
    477                                 int length = text.length();
    478                                 if (length == jtextfield.getColumns()) {
    479                                         e.consume();
    480                                 } else if (length > jtextfield.getColumns()) {
    481                                         // show error message ??
    482                                         e.consume();
    483                                 } else {
    484                                         // Accept key; convert to upper case
    485                                         if (!e.isActionKey()) {
    486                                                 e.setKeyChar(Character.toUpperCase(e.getKeyChar()) );
    487                                         }
    488                                 }
    489                         }
    490                 });
    491 
    492                 Component[] optionalEditFields = {cityTextField, stateTextField, postCodeTextField, countryTextField, fullTextField};
    493                 AddEditControlRows(optionalTextLabels, optionalEditFields,      editControlsPane);
    494 
    495 
    496 
    497                 JPanel optionPanel = new JPanel(new BorderLayout());
    498                 Border groupBox = BorderFactory.createEtchedBorder();
    499                 TitledBorder titleBorder = BorderFactory.createTitledBorder(groupBox, tr("Optional Information:"),
    500                                 TitledBorder.LEFT, TitledBorder.TOP);
    501 
    502                 optionPanel.setBorder(titleBorder);
    503                 optionPanel.add(editControlsPane, BorderLayout.CENTER);
    504 
    505                 return optionPanel;
    506         }
    507 
    508 
    509 
    510         // Populate dialog for any possible existing settings if editing an existing Address interpolation way
    511         private void GetExistingMapKeys() {
    512 
    513 
    514                 // Check all nodes for optional addressing data
    515                 //    Address interpolation nodes will overwrite these value if they contain optional data
    516                 for (Node node : houseNumberNodes) {
    517                         CheckNodeForAddressTags(node);
    518                 }
    519 
    520                 if (addrInterpolationWay != null) {
    521                         String currentMethod = addrInterpolationWay.get("addr:interpolation");
    522                         if (currentMethod != null) {
    523 
    524                                 SelectInterpolationMethod(currentMethod);
    525                                 interpolationMethodSet = true;  // Don't auto detect over a previous choice
    526                         }
    527 
    528                         String currentInclusion = addrInterpolationWay.get("addr:inclusion");
    529                         if (currentInclusion != null) {
    530                                 SelectInclusion(currentInclusion);
    531                         }
    532 
    533                         Node firstNode = addrInterpolationWay.getNode(0);
    534                         Node lastNode = addrInterpolationWay.getNode(addrInterpolationWay.getNodesCount()-1);
    535 
    536                         // Get any existing start / end # values
    537                         String value = firstNode.get("addr:housenumber");
    538                         if (value != null) {
    539                                 startTextField.setText(value);
    540                         }
    541 
    542                         value = lastNode.get("addr:housenumber");
    543                         if (value != null) {
    544                                 endTextField.setText(value);
    545                         }
    546                         CheckNodeForAddressTags(firstNode);
    547                         CheckNodeForAddressTags(lastNode);
    548 
    549                 }
    550 
    551 
    552 
    553         }
    554 
    555 
    556         // Check for any existing address data.   If found,
    557         // overwrite any previous data
    558         private void CheckNodeForAddressTags(Node checkNode) {
    559 
    560                 // Interrogate possible existing optional values
    561                 String value = checkNode.get("addr:city");
    562                 if (value != null) {
    563                         lastCity = value;
    564                 }
    565                 value = checkNode.get("addr:state");
    566                 if (value != null) {
    567                         lastState = value;
    568                 }
    569                 value = checkNode.get("addr:postcode");
    570                 if (value != null) {
    571                         lastPostCode = value;
    572                 }
    573                 value = checkNode.get("addr:country");
    574                 if (value != null) {
    575                         lastCountry = value;
    576                 }
    577                 value = checkNode.get("addr:full");
    578                 if (value != null) {
    579                         lastFullAddress = value;
    580                 }
    581 
    582         }
    583 
    584 
    585 
    586         // Look for a possible 'associatedStreet' type of relation for selected street
    587         // Returns relation description, or an empty string
    588         private String FindRelation() {
    589                 String relationDescription = null;
    590                 DataSet currentDataSet = Main.main.getCurrentDataSet();
    591                 if (currentDataSet != null) {
    592                         for (Relation relation : currentDataSet.getRelations()) {
    593 
    594                                 String relationType = relation.get("type");
    595                                 if (relationType != null) {
    596                                         if (relationType.equals("associatedStreet")) {
    597                                                 for (RelationMember relationMember : relation.getMembers()) {
    598                                                         if (relationMember.isWay()){
    599                                                                 Way way = (Way) relationMember.getMember();
    600                                                                 // System.out.println("Name: " + way.get("name") );
    601                                                                 if (way == selectedStreet) {
    602                                                                         associatedStreetRelation = relation;
    603                                                                         relationDescription = Long.toString(way.getId());
    604 
    605                                                                         String streetName = "";
    606                                                                         if (relation.getKeys().containsKey("name")) {
    607                                                                                 streetName =  relation.get("name");
    608                                                                         } else {
    609                                                                                 // Relation is unnamed - use street name
    610                                                                                 streetName =  selectedStreet.get("name");
    611                                                                         }
    612                                                                         relationDescription += " (" + streetName + ")";
    613                                                                         return relationDescription;
    614                                                                 }
    615                                                         }
    616 
    617                                                 }
    618                                         }
    619 
    620                                 }
    621                         }
    622 
    623                 }
    624 
    625                 return "";
    626         }
    627 
    628 
    629         // We can proceed only if there is both a named way (the 'street') and
    630         // one un-named way (the address interpolation way ) selected.
    631         //    The plugin menu item is enabled after a single way is selected to display a more meaningful
    632         //    message (a new user may not realize that they need to select both the street and
    633         //    address interpolation way first).
    634         // Also, selected street and working address interpolation ways are saved.
    635         private boolean FindAndSaveSelections() {
    636 
    637                 boolean isValid = false;
    638 
    639                 int namedWayCount = 0;
    640                 int unNamedWayCount = 0;
    641                 DataSet currentDataSet = Main.main.getCurrentDataSet();
    642                 if (currentDataSet != null) {
    643                         for (OsmPrimitive osm : currentDataSet.getSelectedWays()) {
    644                                 Way way = (Way) osm;
    645                                 if (way.getKeys().containsKey("name")) {
    646                                         namedWayCount++;
    647                                         this.selectedStreet = way;
    648                                 }
    649                                 else {
    650                                         unNamedWayCount++;
    651                                         this.addrInterpolationWay = way;
    652                                 }
    653                         }
    654 
    655                         // Get additional nodes with addr:housenumber tags:
    656                         //   Either selected or in the middle of the Address Interpolation way
    657                         //     Do not include end points of Address Interpolation way in this set yet.
    658                         houseNumberNodes  = new ArrayList<Node>();
    659                         // Check selected nodes
    660                         for (OsmPrimitive osm : currentDataSet.getSelectedNodes()) {
    661                                 Node node = (Node) osm;
    662                                 if (node.getKeys().containsKey("addr:housenumber")) {
    663                                         houseNumberNodes.add(node);
    664                                 }
    665                         }
    666 
    667                         if (addrInterpolationWay != null) {
    668                                 // Check nodes in middle of address interpolation way
    669                                 if (addrInterpolationWay.getNodesCount() > 2) {
    670                                         for (int i=1; i<(addrInterpolationWay.getNodesCount()-2); i++) {
    671                                                 Node testNode = addrInterpolationWay.getNode(i);
    672                                                 if (testNode.getKeys().containsKey("addr:housenumber")) {
    673                                                         houseNumberNodes.add(testNode);
    674                                                 }
    675                                         }
    676                                 }
    677                         }
    678 
    679                 }
    680 
    681                 if (namedWayCount != 1) {
    682                         JOptionPane.showMessageDialog(
    683                                         Main.parent,
    684                                         tr("Please select a street to associate with address interpolation way"),
    685                                         tr("Error"),
    686                                         JOptionPane.ERROR_MESSAGE
    687                         );
    688                 } else {
    689                         // Avoid 2 error dialogs if both conditions don't match
    690                         if (unNamedWayCount != 1) {
    691                                 // Allow for street + house number nodes only to be selected (no address interpolation way).
    692                                 if (houseNumberNodes.size() > 0) {
    693                                         isValid = true;
    694                                 } else {
    695                                         JOptionPane.showMessageDialog(
    696                                                         Main.parent,
    697                                                         tr("Please select address interpolation way for this street"),
    698                                                         tr("Error"),
    699                                                         JOptionPane.ERROR_MESSAGE
    700                                         );
    701                                 }
    702                         } else {
    703                                 isValid = true;
    704                         }
    705                 }
    706 
    707 
    708                 return isValid;
    709         }
    710 
    711 
    712         /**
    713         * Add rows of edit controls - with labels in the left column, and controls in the right
    714         * column on the gridbag of the specified container.
    715         */
    716         private void AddEditControlRows(JLabel[] labels,
    717                         Component[] editFields,
    718                         Container container) {
    719                 GridBagConstraints c = new GridBagConstraints();
    720                 c.anchor = GridBagConstraints.EAST;
    721                 int numLabels = labels.length;
    722 
    723                 for (int i = 0; i < numLabels; i++) {
    724                         c.gridx = 0;
    725                         c.gridwidth = 1; //next-to-last
    726                         c.fill = GridBagConstraints.NONE;      //reset to default
    727                         c.weightx = 0.0;                       //reset to default
    728                         container.add(labels[i], c);
    729 
    730                         c.gridx = 1;
    731                         c.gridwidth = GridBagConstraints.REMAINDER;     //end row
    732                         c.fill = GridBagConstraints.HORIZONTAL;
    733                         c.weightx = 1.0;
    734                         container.add(editFields[i], c);
    735                 }
    736         }
    737 
    738 
    739 
    740         public void actionPerformed(ActionEvent e) {
    741                 if ("ok".equals(e.getActionCommand())) {
    742                         if (ValidateAndSave()) {
    743                                 dialog.dispose();
    744                         }
    745 
    746                 } else  if ("cancel".equals(e.getActionCommand())) {
    747                         dialog.dispose();
    748 
    749                 }
    750         }
    751 
    752 
    753 
    754         // For Alpha interpolation, return base string
    755         //   For example: "22A" -> "22"
    756         //   For example: "A" -> ""
    757         //    Input string must not be empty
    758         private String BaseAlpha(String strValue) {
    759                 if (strValue.length() > 0) {
    760                         return strValue.substring(0, strValue.length()-1);
    761                 }
    762                 else {
    763                         return "";
    764                 }
    765         }
    766 
    767 
    768         private char LastChar(String strValue) {
    769                 if (strValue.length() > 0) {
    770                         return strValue.charAt(strValue.length()-1);
    771                 }
    772                 else {
    773                         return 0;
    774                 }
    775         }
    776 
    777 
    778         // Test for valid positive long int
    779         private boolean isLong( String input )
    780         {
    781                 try
    782                 {
    783                         Long val = Long.parseLong( input );
    784                         return (val > 0);
    785                 }
    786                 catch( Exception e)
    787                 {
    788                         return false;
    789                 }
    790         }
    791 
    792         private boolean isEven( Long input )
    793         {
    794                 return ((input %2) == 0);
    795         }
    796 
    797         private static Pattern p = Pattern.compile("^[0-9]+$");
    798         private static boolean IsNumeric(String s) {
    799                 return p.matcher(s).matches();
    800         }
    801 
    802 
    803         private void InterpolateAlphaSection(int startNodeIndex, int endNodeIndex, String endValueString,
    804                         char startingChar, char endingChar) {
    805 
    806 
    807                 String baseAlpha = BaseAlpha(endValueString);
    808                 int nSegments  =endNodeIndex - startNodeIndex;
    809 
    810                 double[] segmentLengths = new double[nSegments];
    811                 // Total length of address interpolation way section
    812                 double totalLength= CalculateSegmentLengths(startNodeIndex, endNodeIndex, segmentLengths);
    813 
    814 
    815                 int nHouses = endingChar - startingChar-1;  // # of house number nodes to create
    816                 if (nHouses > 0) {
    817 
    818                         double houseSpacing = totalLength / (nHouses+1);
    819 
    820                         Node lastHouseNode = addrInterpolationWay.getNode(startNodeIndex);
    821                         int currentSegment = 0; // Segment being used to place new house # node
    822                         char currentChar= startingChar;
    823                         while (nHouses > 0) {
    824                                 double distanceNeeded = houseSpacing;
    825 
    826                                 // Move along segments until we can place the new house number
    827                                 while (distanceNeeded > segmentLengths[currentSegment]) {
    828                                         distanceNeeded -= segmentLengths[currentSegment];
    829                                         currentSegment++;
    830                                         lastHouseNode = addrInterpolationWay.getNode(startNodeIndex + currentSegment);
    831                                 }
    832 
    833                                 // House number is to be positioned in current segment.
    834                                 double proportion = distanceNeeded / segmentLengths[currentSegment];
    835                                 Node toNode = addrInterpolationWay.getNode(startNodeIndex + 1 + currentSegment);
    836                                 LatLon newHouseNumberPosition = lastHouseNode.getCoor().interpolate(toNode.getCoor(), proportion);
    837 
    838 
    839 
    840                                 Node newHouseNumberNode = new Node(newHouseNumberPosition);
    841                                 currentChar++;
    842                                 if ( (currentChar >'Z') && (currentChar <'a')) {
    843                                         // Wraparound past uppercase Z: go directly to lower case a
    844                                         currentChar = 'a';
    845 
    846                                 }
    847                                 String newHouseNumber = baseAlpha + currentChar;
    848                                 newHouseNumberNode.put("addr:housenumber", newHouseNumber);
    849 
    850                                 commandGroup.add(new AddCommand(newHouseNumberNode));
    851                                 houseNumberNodes.add(newHouseNumberNode);   // Street, etc information to be added later
    852 
    853                                 lastHouseNode = newHouseNumberNode;
    854 
    855 
    856                                 segmentLengths[currentSegment] -= distanceNeeded; // Track amount used
    857                                 nHouses -- ;
    858                         }
    859                 }
    860 
    861 
    862         }
    863 
    864 
    865         private void CreateAlphaInterpolation(String startValueString, String endValueString) {
    866                 char startingChar = LastChar(startValueString);
    867                 char endingChar = LastChar(endValueString);
    868 
    869                 if (isLong(startValueString)) {
    870                         // Special case of numeric first value, followed by 'A'
    871                         startingChar = 'A'-1;
    872                 }
    873 
    874                 // Search for possible anchors from the 2nd node to 2nd from last, interpolating between each anchor
    875                 int startIndex = 0; // Index into first interpolation zone of address interpolation way
    876                 for (int i=1; i<addrInterpolationWay.getNodesCount()-1; i++) {
    877                         Node testNode = addrInterpolationWay.getNode(i);
    878                         String endNodeNumber = testNode.get("addr:housenumber");
    879                         if (endNodeNumber != null) {
    880                                 // This is a potential anchor node
    881                                 if (endNodeNumber != "") {
    882                                         char anchorChar = LastChar(endNodeNumber);
    883                                         if ( (anchorChar >startingChar) && (anchorChar < endingChar) ) {
    884                                                 // Lies within the expected range
    885                                                 InterpolateAlphaSection(startIndex, i, endNodeNumber, startingChar, anchorChar);
    886 
    887                                                 // For next interpolation section
    888                                                 startingChar = anchorChar;
    889                                                 startValueString = endNodeNumber;
    890                                                 startIndex = i;
    891                                         }
    892                                 }
    893 
    894                         }
    895                 }
    896 
    897                 // End nodes do not actually contain housenumber value yet (command has not executed), so use user-entered value
    898                 InterpolateAlphaSection(startIndex, addrInterpolationWay.getNodesCount()-1, endValueString, startingChar, endingChar);
    899 
    900         }
    901 
    902 
    903         private double CalculateSegmentLengths(int startNodeIndex, int endNodeIndex, double segmentLengths[]) {
    904                 Node fromNode = addrInterpolationWay.getNode(startNodeIndex);
    905                 double totalLength = 0.0;
    906                 int nSegments = segmentLengths.length;
    907                 for (int segment = 0; segment < nSegments; segment++) {
    908                         Node toNode = addrInterpolationWay.getNode(startNodeIndex + 1 + segment);
    909                         segmentLengths[segment]= fromNode.getCoor().greatCircleDistance(toNode.getCoor());
    910                         totalLength += segmentLengths[segment];
    911 
    912                         fromNode = toNode;
    913                 }
    914                 return totalLength;
    915 
    916         }
    917 
    918 
    919         private void InterpolateNumericSection(int startNodeIndex, int endNodeIndex,
    920                         long startingAddr, long endingAddr,
    921                         long increment) {
    922 
    923 
    924                 int nSegments  =endNodeIndex - startNodeIndex;
    925 
    926                 double[] segmentLengths = new double[nSegments];
    927 
    928                 // Total length of address interpolation way section
    929                 double totalLength= CalculateSegmentLengths(startNodeIndex, endNodeIndex, segmentLengths);
    930 
    931 
    932                 int nHouses = (int)((endingAddr - startingAddr) / increment) -1;
    933                 if (nHouses > 0) {
    934 
    935                         double houseSpacing = totalLength / (nHouses+1);
    936 
    937                         Node lastHouseNode = addrInterpolationWay.getNode(startNodeIndex);
    938                         int currentSegment = 0; // Segment being used to place new house # node
    939                         long currentHouseNumber = startingAddr;
    940                         while (nHouses > 0) {
    941                                 double distanceNeeded = houseSpacing;
    942 
    943                                 // Move along segments until we can place the new house number
    944                                 while (distanceNeeded > segmentLengths[currentSegment]) {
    945                                         distanceNeeded -= segmentLengths[currentSegment];
    946                                         currentSegment++;
    947                                         lastHouseNode = addrInterpolationWay.getNode(startNodeIndex + currentSegment);
    948                                 }
    949 
    950                                 // House number is to be positioned in current segment.
    951                                 double proportion = distanceNeeded / segmentLengths[currentSegment];
    952                                 Node toNode = addrInterpolationWay.getNode(startNodeIndex + 1 + currentSegment);
    953                                 LatLon newHouseNumberPosition = lastHouseNode.getCoor().interpolate(toNode.getCoor(), proportion);
    954 
    955 
    956                                 Node newHouseNumberNode = new Node(newHouseNumberPosition);
    957                                 currentHouseNumber += increment;
    958                                 String newHouseNumber = Long.toString(currentHouseNumber);
    959                                 newHouseNumberNode.put("addr:housenumber", newHouseNumber);
    960 
    961                                 commandGroup.add(new AddCommand(newHouseNumberNode));
    962                                 houseNumberNodes.add(newHouseNumberNode);   // Street, etc information to be added later
    963 
    964                                 lastHouseNode = newHouseNumberNode;
    965 
    966 
    967                                 segmentLengths[currentSegment] -= distanceNeeded; // Track amount used
    968                                 nHouses -- ;
    969                         }
    970                 }
    971 
    972 
    973         }
    974 
    975 
    976         private void CreateNumericInterpolation(String startValueString, String endValueString, long increment) {
    977 
    978                 long startingAddr = Long.parseLong( startValueString );
    979                 long endingAddr = Long.parseLong( endValueString );
    980 
    981 
    982                 // Search for possible anchors from the 2nd node to 2nd from last, interpolating between each anchor
    983                 int startIndex = 0; // Index into first interpolation zone of address interpolation way
    984                 for (int i=1; i<addrInterpolationWay.getNodesCount()-1; i++) {
    985                         Node testNode = addrInterpolationWay.getNode(i);
    986                         String strEndNodeNumber = testNode.get("addr:housenumber");
    987                         if (strEndNodeNumber != null) {
    988                                 // This is a potential anchor node
    989                                 if (isLong(strEndNodeNumber)) {
    990 
    991                                         long anchorAddrNumber = Long.parseLong( strEndNodeNumber );
    992                                         if ( (anchorAddrNumber >startingAddr) && (anchorAddrNumber < endingAddr) ) {
    993                                                 // Lies within the expected range
    994                                                 InterpolateNumericSection(startIndex, i, startingAddr, anchorAddrNumber, increment);
    995 
    996                                                 // For next interpolation section
    997                                                 startingAddr = anchorAddrNumber;
    998                                                 startValueString = strEndNodeNumber;
    999                                                 startIndex = i;
    1000                                         }
    1001                                 }
    1002 
    1003                         }
    1004                 }
    1005 
    1006                 // End nodes do not actually contain housenumber value yet (command has not executed), so use user-entered value
    1007                 InterpolateNumericSection(startIndex, addrInterpolationWay.getNodesCount()-1, startingAddr, endingAddr, increment);
    1008         }
    1009 
    1010 
    1011         // Called if user has checked "Convert to House Numbers" checkbox.
    1012         private void ConvertWayToHousenumbers(String selectedMethod, String startValueString, String endValueString,
    1013                         String incrementString) {
    1014                 // - Use nodes labeled with 'same type' as interim anchors in the middle of the way to identify unequal spacing.
    1015                 // - Ignore nodes of different type; for example '25b' is ignored in sequence 5..15
    1016 
    1017                 // Calculate required number of house numbers to create
    1018                 if (selectedMethod.equals("alphabetic")) {
    1019 
    1020                         CreateAlphaInterpolation(startValueString, endValueString);
    1021 
    1022 
    1023                 } else {
    1024                         long increment = 1;
    1025                         if (selectedMethod.equals("odd") || selectedMethod.equals("even")) {
    1026                                 increment = 2;
    1027                         } else if (selectedMethod.equals("Numeric")) {
    1028                                 increment = Long.parseLong(incrementString);
    1029                         }
    1030                         CreateNumericInterpolation(startValueString, endValueString, increment);
    1031 
    1032                 }
    1033 
    1034 
    1035                 RemoveAddressInterpolationWay();
    1036 
    1037         }
    1038 
    1039 
    1040         private void RemoveAddressInterpolationWay() {
    1041 
    1042                 // Remove untagged nodes
    1043                 for (int i=1; i<addrInterpolationWay.getNodesCount()-1; i++) {
    1044                         Node testNode = addrInterpolationWay.getNode(i);
    1045                         if (!testNode.hasKeys()) {
    1046                                 commandGroup.add(new DeleteCommand(testNode));
    1047                         }
    1048                 }
    1049 
    1050                 // Remove way
    1051                 commandGroup.add(new DeleteCommand(addrInterpolationWay));
    1052                 addrInterpolationWay = null;
    1053 
    1054         }
    1055 
    1056 
    1057 
    1058         private boolean ValidateAndSave() {
    1059 
    1060                 String startValueString = ReadTextField(startTextField);
    1061                 String endValueString = ReadTextField(endTextField);
    1062                 String incrementString = ReadTextField(incrementTextField);
    1063                 String city = ReadTextField(cityTextField);
    1064                 String state = ReadTextField(stateTextField);
    1065                 String postCode = ReadTextField(postCodeTextField);
    1066                 String country = ReadTextField(countryTextField);
    1067                 String fullAddress = ReadTextField(fullTextField);
    1068 
    1069                 String selectedMethod = GetInterpolationMethod();
    1070                 if (addrInterpolationWay != null) {
    1071                         Long startAddr=0L, endAddr=0L;
    1072                         if (!selectedMethod.equals("alphabetic")) {
    1073                                 Long[] addrArray = {startAddr, endAddr};
    1074                                 if (!ValidAddressNumbers(startValueString, endValueString, addrArray )) {
    1075                                         return false;
    1076                                 }
    1077                                 startAddr = addrArray[0];
    1078                                 endAddr = addrArray[1];
    1079                         }
    1080 
    1081                         String errorMessage = "";
    1082                         if (selectedMethod.equals("odd")) {
    1083                                 if (isEven(startAddr) || isEven(endAddr)) {
    1084                                         errorMessage = tr("Expected odd numbers for addresses");
    1085                                 }
    1086 
    1087                         } else if (selectedMethod.equals("even")) {
    1088                                 if (!isEven(startAddr) || !isEven(endAddr)) {
    1089                                         errorMessage = tr("Expected even numbers for addresses");
    1090                                 }
    1091                         } else if (selectedMethod.equals("all")) {
    1092 
    1093                         }else if (selectedMethod.equals("alphabetic")) {
    1094                                 errorMessage = ValidateAlphaAddress(startValueString, endValueString);
    1095 
    1096                         }else if (selectedMethod.equals("Numeric")) {
    1097 
    1098                                 if (!ValidNumericIncrementString(incrementString, startAddr, endAddr)) {
    1099                                         errorMessage = tr("Expected valid number for address increment");
    1100                                 }
    1101 
    1102                         }
    1103                         if (!errorMessage.equals("")) {
    1104                                 JOptionPane.showMessageDialog(Main.parent, errorMessage, tr("Error"),   JOptionPane.ERROR_MESSAGE);
    1105                                 return false;
    1106                         }
    1107                 }
    1108 
    1109                 if (country != null) {
    1110                         if (country.length() != 2) {
    1111                                 JOptionPane.showMessageDialog(Main.parent,
    1112                                                 tr("Country code must be 2 letters"), tr("Error"),      JOptionPane.ERROR_MESSAGE);
    1113                                 return false;
    1114                         }
    1115                 }
    1116 
    1117                 // Entries are valid ... save in map
    1118 
    1119                 commandGroup = new LinkedList<Command>();
    1120 
    1121                 String streetName = selectedStreet.get("name");
    1122 
    1123                 if (addrInterpolationWay != null) {
    1124 
    1125                         Node firstNode = addrInterpolationWay.getNode(0);
    1126                         Node lastNode = addrInterpolationWay.getNode(addrInterpolationWay.getNodesCount()-1);
    1127 
    1128                         // De-select address interpolation way; leave street selected
    1129                         DataSet currentDataSet = Main.main.getCurrentDataSet();
    1130                         if (currentDataSet != null) {
    1131                                 currentDataSet.clearSelection(addrInterpolationWay);
    1132                                 currentDataSet.clearSelection(lastNode);  // Workaround for JOSM Bug #3838
    1133                         }
    1134 
    1135 
    1136                         String interpolationTagValue = selectedMethod;
    1137                         if (selectedMethod.equals("Numeric")) {
    1138                                 // The interpolation method is the number for 'Numeric' case
    1139                                 interpolationTagValue = incrementString;
    1140                         }
    1141 
    1142                         if (cbConvertToHouseNumbers.getState()) {
    1143                                 // Convert way to house numbers is checked.
    1144                                 //  Create individual nodes and delete interpolation way
    1145                                 ConvertWayToHousenumbers(selectedMethod, startValueString, endValueString, incrementString);
    1146                         } else {
    1147                                 // Address interpolation way will remain
    1148                                 commandGroup.add(new ChangePropertyCommand(addrInterpolationWay, "addr:interpolation", interpolationTagValue));
    1149                                 commandGroup.add(new ChangePropertyCommand(addrInterpolationWay, "addr:inclusion", GetInclusionMethod()));
    1150                         }
    1151 
    1152                         commandGroup.add(new ChangePropertyCommand(firstNode, "addr:housenumber", startValueString));
    1153                         commandGroup.add(new ChangePropertyCommand(lastNode, "addr:housenumber", endValueString));
    1154                         // Add address interpolation house number nodes to main house number node list for common processing
    1155                         houseNumberNodes.add(firstNode);
    1156                         houseNumberNodes.add(lastNode);
    1157 
    1158                 }
    1159 
    1160 
    1161 
    1162                 if (streetRelationButton.isSelected()) {
    1163 
    1164                         // Relation button was selected
    1165                         if (associatedStreetRelation == null) {
    1166                                 CreateRelation(streetName);
    1167                                 // relationChanged = true;   (not changed since it was created)
    1168                         }
    1169                         // Make any additional changes only to the copy
    1170                         editedRelation = new Relation(associatedStreetRelation);
    1171 
    1172                         if (addrInterpolationWay != null) {
    1173                                 AddToRelation(associatedStreetRelation, addrInterpolationWay, "house");
    1174                         }
    1175                 }
    1176 
    1177 
    1178                 // For all nodes, add to relation and
    1179                 //   Add optional text fields to all nodes if specified
    1180                 for (Node node : houseNumberNodes) {
    1181 
    1182                         if (streetRelationButton.isSelected()) {
    1183                                 AddToRelation(associatedStreetRelation, node, "house");
    1184                         }
    1185                         if ((city != null) || (streetNameButton.isSelected()) ) {
    1186                                 // Include street unconditionally if adding nodes only or city name specified
    1187                                 commandGroup.add(new ChangePropertyCommand(node, "addr:street", streetName));
    1188                         }
    1189                         // Set or remove remaining optional fields
    1190                         commandGroup.add(new ChangePropertyCommand(node, "addr:city", city));
    1191                         commandGroup.add(new ChangePropertyCommand(node, "addr:state", state));
    1192                         commandGroup.add(new ChangePropertyCommand(node, "addr:postcode", postCode));
    1193                         commandGroup.add(new ChangePropertyCommand(node, "addr:country", country));
    1194                         commandGroup.add(new ChangePropertyCommand(node, "addr:full", fullAddress));
    1195                 }
    1196 
    1197                 if (relationChanged) {
    1198                         commandGroup.add(new ChangeCommand(associatedStreetRelation, editedRelation));
    1199                 }
    1200 
    1201 
    1202                 Main.main.undoRedo.add(new SequenceCommand(tr("Address Interpolation"), commandGroup));
    1203                 Main.map.repaint();
    1204 
    1205                 return true;
    1206         }
    1207 
    1208 
    1209         private boolean ValidNumericIncrementString(String incrementString, long startingAddr, long endingAddr) {
    1210 
    1211                 if (!isLong(incrementString)) {
    1212                         return false;
    1213                 }
    1214                 long testIncrement = Long.parseLong(incrementString);
    1215                 if ( (testIncrement <=0) || (testIncrement > endingAddr ) ) {
    1216                         return false;
    1217                 }
    1218 
    1219                 if ( ((endingAddr - startingAddr) % testIncrement) != 0) {
    1220                         return false;
    1221                 }
    1222                 return true;
    1223         }
    1224 
    1225 
    1226 
    1227         // Create Associated Street relation, add street, and add to list of commands to perform
    1228         private void CreateRelation(String streetName) {
    1229                 associatedStreetRelation = new Relation();
    1230                 associatedStreetRelation.put("name", streetName);
    1231                 associatedStreetRelation.put("type", "associatedStreet");
    1232                 RelationMember newStreetMember = new RelationMember("street", selectedStreet);
    1233                 associatedStreetRelation.addMember(newStreetMember);
    1234                 commandGroup.add(new AddCommand(associatedStreetRelation));
    1235         }
    1236 
    1237 
    1238 
    1239         // Read from dialog text box, removing leading and trailing spaces
    1240         // Return the string, or null for a zero length string
    1241         private String ReadTextField(JTextField field) {
    1242                 String value = field.getText();
    1243                 if (value != null) {
    1244                         value = value.trim();
    1245                         if (value.equals("")) {
    1246                                 value = null;
    1247                         }
    1248                 }
    1249                 return value;
    1250         }
    1251 
    1252 
    1253         // Test if relation contains specified member
    1254         //   If not already present, it is added
    1255         private void AddToRelation(Relation relation,   OsmPrimitive testMember, String role) {
    1256                 boolean isFound = false;
    1257                 for (RelationMember relationMember : relation.getMembers()) {
    1258 
    1259                         if (testMember == relationMember.getMember()) {
    1260                                 isFound = true;
    1261                                 break;
    1262                         }
    1263                 }
    1264 
    1265                 if (!isFound) {
    1266                         RelationMember newMember = new RelationMember(role, testMember);
    1267                         editedRelation.addMember(newMember);
    1268 
    1269                         relationChanged = true;
    1270                 }
    1271         }
    1272 
    1273 
    1274 
    1275         // Check alphabetic style address
    1276         //   Last character of both must be alpha
    1277         //   Last character of ending must be greater than starting
    1278         //   Return empty error message if OK
    1279         private String ValidateAlphaAddress(String startValueString,
    1280                         String endValueString) {
    1281                 String errorMessage="";
    1282 
    1283                 if (startValueString.equals("") || endValueString.equals("")) {
    1284                         errorMessage = tr("Please enter valid number for starting and ending address");
    1285                 } else {
    1286                         char startingChar = LastChar(startValueString);
    1287                         char endingChar = LastChar(endValueString);
    1288 
    1289 
    1290                         boolean isOk = false;
    1291                         if ( (IsNumeric("" + startingChar)) &&  (!IsNumeric("" + endingChar)) ) {
    1292                                 endingChar = Character.toUpperCase(endingChar);
    1293                                 if ( (endingChar >= 'A') && (endingChar <= 'Z') ) {
    1294                                         // First is a number, last is Latin alpha
    1295                                         isOk = true;
    1296                                 }
    1297                         } else if ( (!IsNumeric("" + startingChar)) && (!IsNumeric("" + endingChar)) ) {
    1298                                 // Both are alpha
    1299                                 isOk = true;
    1300                         }
    1301                         if (!isOk) {
    1302                                 errorMessage = tr("Alphabetic address must end with a letter");
    1303                         }
    1304 
    1305 
    1306                         // if a number is included, validate that it is the same number
    1307                         if (endValueString.length() > 1) {
    1308 
    1309                                 // Get number portion of first item: may or may not have letter suffix
    1310                                 String numStart = BaseAlpha(startValueString);
    1311                                 if (IsNumeric(startValueString)) {
    1312                                         numStart = startValueString;
    1313                                 }
    1314 
    1315                                 String numEnd = BaseAlpha(endValueString);
    1316                                 if (!numStart.equals(numEnd)) {
    1317                                         errorMessage = tr("Starting and ending numbers must be the same for alphabetic addresses");
    1318                                 }
    1319                         }
    1320 
    1321                         // ?? Character collation in all languages ??
    1322                         if (startingChar >= endingChar) {
    1323                                 errorMessage = tr("Starting address letter must be less than ending address letter");
    1324                         }
    1325 
    1326                 }
    1327 
    1328                 return errorMessage;
    1329         }
    1330 
    1331 
    1332 
    1333         // Convert string addresses to numeric, with error check
    1334         private boolean ValidAddressNumbers(String startValueString,
    1335                         String endValueString, Long[] addrArray) {
    1336                 String errorMessage = "";
    1337 
    1338                 if (!isLong(startValueString)) {
    1339                         errorMessage = tr("Please enter valid number for starting address");
    1340                 }
    1341                 if (!isLong(endValueString)) {
    1342                         errorMessage = tr("Please enter valid number for ending address");
    1343                 }
    1344                 if (errorMessage.equals("")) {
    1345                         addrArray[0] = Long.parseLong( startValueString );
    1346                         addrArray[1] = Long.parseLong( endValueString );
    1347 
    1348                         if (addrArray[1] <= addrArray[0]) {
    1349                                 errorMessage = tr("Starting address number must be less than ending address number");
    1350                         }
    1351                 }
    1352 
    1353                 if (errorMessage.equals("")) {
    1354                         return true;
    1355 
    1356                 } else {
    1357                         JOptionPane.showMessageDialog(Main.parent, errorMessage, tr("Error"),   JOptionPane.ERROR_MESSAGE);
    1358                         return false;
    1359                 }
    1360         }
    1361 
    1362 
    1363 
    1364         private String GetInterpolationMethod() {
    1365                 int selectedIndex = addrInterpolationList.getSelectedIndex();
    1366                 return addrInterpolationTags[selectedIndex];
    1367         }
    1368 
    1369 
    1370         private String GetInclusionMethod() {
    1371                 int selectedIndex = addrInclusionList.getSelectedIndex();
    1372                 lastAccuracyIndex = selectedIndex;
    1373                 return addrInclusionTags[selectedIndex];
    1374         }
     71    private Way selectedStreet = null;
     72    private Way addrInterpolationWay = null;
     73    private Relation associatedStreetRelation = null;
     74    private ArrayList<Node> houseNumberNodes = null;  // Additional nodes with addr:housenumber
     75
     76    private static String lastIncrement = "";
     77    private static int lastAccuracyIndex = 0;
     78    private static String lastCity = "";
     79    private static String lastState = "";
     80    private static String lastPostCode = "";
     81    private static String lastCountry = "";
     82    private static String lastFullAddress = "";
     83    private static boolean lastConvertToHousenumber = false;
     84
     85    // Edit controls
     86    private EscapeDialog dialog=null;
     87    private JRadioButton streetNameButton = null;
     88    private JRadioButton streetRelationButton  = null;
     89    private JTextField startTextField = null;
     90    private JTextField endTextField = null;
     91    private JTextField incrementTextField = null;
     92    private JTextField cityTextField = null;
     93    private JTextField stateTextField = null;
     94    private JTextField postCodeTextField = null;
     95    private JTextField countryTextField = null;
     96    private JTextField fullTextField = null;
     97    private Checkbox cbConvertToHouseNumbers = null;
     98
     99    private boolean relationChanged = false; // Whether to re-trigger data changed for relation
     100    // Track whether interpolation method is known so that auto detect doesn't override a previous choice.
     101    private boolean interpolationMethodSet = false;
     102
     103
     104    // NOTE: The following 2 arrays must match in number of elements and position
     105    // Tag values for map (Except that 'Numeric' is replaced by actual # on map)
     106    String[] addrInterpolationTags = { "odd", "even", "all", "alphabetic", "Numeric" };
     107    String[] addrInterpolationStrings = { tr("Odd"), tr("Even"), tr("All"), tr("Alphabetic"), tr("Numeric") }; // Translatable names for display
     108    private final int NumericIndex = 4;
     109    private JComboBox addrInterpolationList = null;
     110
     111    // NOTE: The following 2 arrays must match in number of elements and position
     112    String[] addrInclusionTags = { "actual", "estimate", "potential" }; // Tag values for map
     113    String[] addrInclusionStrings = { tr("Actual"), tr("Estimate"), tr("Potential") }; // Translatable names for display
     114    private JComboBox addrInclusionList = null;
     115
     116
     117
     118    // For tracking edit changes as group for undo
     119    private Collection<Command> commandGroup = null;
     120    private Relation editedRelation = null;
     121
     122    public AddrInterpolationDialog(String name) {
     123
     124        if (!FindAndSaveSelections()) {
     125            return;
     126        }
     127
     128        JPanel editControlsPane = CreateEditControls();
     129
     130        ShowDialog(editControlsPane, name);
     131
     132    }
     133
     134
     135
     136    private void ShowDialog(JPanel editControlsPane, String name) {
     137        dialog = new EscapeDialog((Frame) Main.parent, name, true);
     138
     139        dialog.add(editControlsPane);
     140        dialog.setSize(new Dimension(300,500));
     141        dialog.setLocation(new Point(100,300));
     142
     143        // Listen for windowOpened event to set focus
     144        dialog.addWindowListener( new WindowAdapter()
     145        {
     146            @Override
     147            public void windowOpened( WindowEvent e )
     148            {
     149                if (addrInterpolationWay != null) {
     150                    startTextField.requestFocus();
     151                }
     152                else {
     153                    cityTextField.requestFocus();
     154                }
     155            }
     156        });
     157
     158        dialog.setVisible(true);
     159
     160        lastIncrement = incrementTextField.getText();
     161        lastCity = cityTextField.getText();
     162        lastState = stateTextField.getText();
     163        lastPostCode = postCodeTextField.getText();
     164        lastCountry = countryTextField.getText();
     165        lastFullAddress = fullTextField.getText();
     166        lastConvertToHousenumber = cbConvertToHouseNumbers.getState();
     167
     168    }
     169
     170
     171
     172    // Create edit control items and return JPanel on which they reside
     173    private JPanel CreateEditControls() {
     174
     175        JPanel editControlsPane = new JPanel();
     176        GridBagLayout gridbag = new GridBagLayout();
     177        GridBagConstraints c = new GridBagConstraints();
     178
     179        editControlsPane.setLayout(gridbag);
     180
     181        editControlsPane.setBorder(BorderFactory.createEmptyBorder(15,15,15,15));
     182
     183
     184        String streetName = selectedStreet.get("name");
     185        String streetRelation = FindRelation();
     186        if (streetRelation.equals("")) {
     187            streetRelation = " (Create new)";
     188        }
     189        streetNameButton = new JRadioButton(tr("Name: {0}", streetName));
     190        streetRelationButton = new JRadioButton(tr("Relation: {0}", streetRelation));
     191        if (associatedStreetRelation == null) {
     192            streetNameButton.setSelected(true);
     193        }else {
     194            streetRelationButton.setSelected(true);
     195        }
     196
     197        // Create edit controls for street / relation radio buttons
     198        ButtonGroup group = new ButtonGroup();
     199        group.add(streetNameButton);
     200        group.add(streetRelationButton);
     201        JPanel radioButtonPanel = new JPanel(new BorderLayout());
     202        radioButtonPanel.setBorder(BorderFactory.createTitledBorder(tr("Associate with street using:")));
     203        radioButtonPanel.add(streetNameButton, BorderLayout.NORTH);
     204        radioButtonPanel.add(streetRelationButton, BorderLayout.SOUTH);
     205
     206        // Add to edit panel
     207        c.gridx = 0;
     208        c.gridwidth = 2; // # of columns to span
     209        c.fill = GridBagConstraints.HORIZONTAL;      // Full width
     210        c.gridwidth = GridBagConstraints.REMAINDER;     //end row
     211        editControlsPane.add(radioButtonPanel, c);
     212
     213        JLabel numberingLabel = new JLabel(tr("Numbering Scheme:"));
     214        addrInterpolationList = new JComboBox(addrInterpolationStrings);
     215
     216        JLabel incrementLabel = new JLabel(tr("Increment:"));
     217        incrementTextField = new JTextField(lastIncrement, 100);
     218        incrementTextField.setEnabled(false);
     219
     220        JLabel startLabel = new JLabel(tr("Starting #:"));
     221        JLabel endLabel = new JLabel(tr("Ending #:"));
     222
     223        startTextField = new JTextField(10);
     224        endTextField = new JTextField(10);
     225
     226        JLabel inclusionLabel = new JLabel(tr("Accuracy:"));
     227        addrInclusionList = new JComboBox(addrInclusionStrings);
     228        addrInclusionList.setSelectedIndex(lastAccuracyIndex);
     229
     230        // Preload any values already set in map
     231        GetExistingMapKeys();
     232
     233
     234        JLabel[] textLabels = {startLabel, endLabel, numberingLabel, incrementLabel, inclusionLabel};
     235        Component[] editFields = {startTextField, endTextField, addrInterpolationList, incrementTextField, addrInclusionList};
     236        AddEditControlRows(textLabels, editFields,  editControlsPane);
     237
     238        cbConvertToHouseNumbers = new Checkbox(tr("Convert way to individual house numbers."), null, lastConvertToHousenumber);
     239        // cbConvertToHouseNumbers.setSelected(lastConvertToHousenumber);
     240
     241        // Address interpolation fields not valid if Way not selected
     242        if (addrInterpolationWay == null) {
     243            addrInterpolationList.setEnabled(false);
     244            startTextField.setEnabled(false);
     245            endTextField.setEnabled(false);
     246            cbConvertToHouseNumbers.setEnabled(false);
     247        }
     248
     249
     250
     251        JPanel optionPanel = CreateOptionalFields();
     252        c.gridx = 0;
     253        c.gridwidth = 2; // # of columns to span
     254        c.fill = GridBagConstraints.BOTH;      // Full width
     255        c.gridwidth = GridBagConstraints.REMAINDER;     //end row
     256
     257        editControlsPane.add(optionPanel, c);
     258
     259
     260        KeyAdapter enterProcessor = new KeyAdapter() {
     261            @Override
     262            public void keyPressed(KeyEvent e) {
     263                if (e.getKeyCode() == KeyEvent.VK_ENTER) {
     264                    if (ValidateAndSave()) {
     265                        dialog.dispose();
     266                    }
     267
     268                }
     269            }
     270        };
     271
     272        // Make Enter == OK click on fields using this adapter
     273        endTextField.addKeyListener(enterProcessor);
     274        cityTextField.addKeyListener(enterProcessor);
     275        addrInterpolationList.addKeyListener(enterProcessor);
     276        incrementTextField.addKeyListener(enterProcessor);
     277
     278
     279        // Watch when Interpolation Method combo box is selected so that
     280        // it can auto-detect method based on entered numbers.
     281        addrInterpolationList.addFocusListener(new FocusAdapter() {
     282            @Override
     283            public void focusGained(FocusEvent fe){
     284                if (!interpolationMethodSet) {
     285                    if (AutoDetectInterpolationMethod()) {
     286                        interpolationMethodSet = true;  // Don't auto detect over a previous choice
     287                    }
     288                }
     289            }
     290        });
     291
     292
     293        // Watch when Interpolation Method combo box is changed so that
     294        // Numeric increment box can be enabled or disabled.
     295        addrInterpolationList.addActionListener(new ActionListener() {
     296            public void actionPerformed(ActionEvent e){
     297                int selectedIndex = addrInterpolationList.getSelectedIndex();
     298                incrementTextField.setEnabled(selectedIndex == NumericIndex); // Enable or disable numeric field
     299            }
     300        });
     301
     302
     303        editControlsPane.add(cbConvertToHouseNumbers, c);
     304
     305
     306
     307        if (houseNumberNodes.size() > 0) {
     308            JLabel houseNumberNodeNote = new JLabel(tr("Will associate {0} additional house number nodes",
     309                    houseNumberNodes.size() ));
     310            editControlsPane.add(houseNumberNodeNote, c);
     311        }
     312
     313        editControlsPane.add(new UrlLabel("http://wiki.openstreetmap.org/wiki/JOSM/Plugins/AddrInterpolation",
     314                tr("More information about this feature")), c);
     315
     316
     317        c.gridx = 0;
     318        c.gridwidth = 1; //next-to-last
     319        c.fill = GridBagConstraints.NONE;      //reset to default
     320        c.weightx = 0.0;
     321        c.insets = new Insets(15, 0, 0, 0);
     322        c.anchor = GridBagConstraints.LINE_END;
     323        JButton okButton = new JButton(tr("OK"), ImageProvider.get("ok"));
     324        editControlsPane.add(okButton, c);
     325
     326        c.gridx = 1;
     327        c.gridwidth = GridBagConstraints.REMAINDER;     //end row
     328        c.weightx = 1.0;
     329        c.anchor = GridBagConstraints.LINE_START;
     330
     331        JButton cancelButton = new JButton(tr("Cancel"), ImageProvider.get("cancel"));
     332        editControlsPane.add(cancelButton, c);
     333
     334        okButton.setActionCommand("ok");
     335        okButton.addActionListener(this);
     336        cancelButton.setActionCommand("cancel");
     337        cancelButton.addActionListener(this);
     338
     339        return editControlsPane;
     340    }
     341
     342
     343
     344    // Call after both starting and ending housenumbers have been entered - usually when
     345    // combo box gets focus.
     346    // Return true if a method was detected
     347    private boolean AutoDetectInterpolationMethod() {
     348
     349        String startValueString = ReadTextField(startTextField);
     350        String endValueString = ReadTextField(endTextField);
     351        if ( (startValueString == null) || (endValueString== null) ) {
     352            // Not all values entered yet
     353            return false;
     354        }
     355
     356        // String[] addrInterpolationTags = { "odd", "even", "all", "alphabetic", ### };  // Tag values for map
     357
     358        if (isLong(startValueString) && isLong(endValueString)) {
     359            // Have 2 numeric values
     360            long startValue = Long.parseLong( startValueString );
     361            long endValue = Long.parseLong( endValueString );
     362
     363            if (isEven(startValue)) {
     364                if (isEven(endValue)) {
     365                    SelectInterpolationMethod("even");
     366                }
     367                else {
     368                    SelectInterpolationMethod("all");
     369                }
     370            } else {
     371                if (!isEven(endValue)) {
     372                    SelectInterpolationMethod("odd");
     373                }
     374                else {
     375                    SelectInterpolationMethod("all");
     376                }
     377            }
     378
     379
     380        } else {
     381            // Test for possible alpha
     382            char startingChar = startValueString.charAt(startValueString.length()-1);
     383            char endingChar = endValueString.charAt(endValueString.length()-1);
     384
     385            if ( (!IsNumeric("" + startingChar)) &&  (!IsNumeric("" + endingChar)) ) {
     386                // Both end with alpha
     387                SelectInterpolationMethod("alphabetic");
     388                return true;
     389            }
     390
     391            if ( (IsNumeric("" + startingChar)) &&  (!IsNumeric("" + endingChar)) ) {
     392                endingChar = Character.toUpperCase(endingChar);
     393                if ( (endingChar >= 'A') && (endingChar <= 'Z') ) {
     394                    // First is a number, last is Latin alpha
     395                    SelectInterpolationMethod("alphabetic");
     396                    return true;
     397                }
     398            }
     399           
     400            // Did not detect alpha
     401            return false;
     402
     403        }
     404       
     405        return true;
     406
     407    }
     408
     409
     410
     411    // Set Interpolation Method combo box to method specified by 'currentMethod' (an OSM key value)
     412    private void SelectInterpolationMethod(String currentMethod) {
     413        int currentIndex = 0;
     414        if (isLong(currentMethod)) {
     415            // Valid number: Numeric increment method
     416            currentIndex = addrInterpolationTags.length-1;
     417            incrementTextField.setText(currentMethod);
     418            incrementTextField.setEnabled(true);
     419        }
     420        else {
     421            // Must scan OSM key values because combo box is already loaded with translated strings
     422            for (int i=0; i<addrInterpolationTags.length; i++) {
     423                if (addrInterpolationTags[i].equals(currentMethod)) {
     424                    currentIndex = i;
     425                    break;
     426                }
     427            }
     428        }
     429        addrInterpolationList.setSelectedIndex(currentIndex);
     430
     431    }
     432
     433
     434    // Set Inclusion Method combo box to method specified by 'currentMethod' (an OSM key value)
     435    private void SelectInclusion(String currentMethod) {
     436        int currentIndex = 0;
     437        // Must scan OSM key values because combo box is already loaded with translated strings
     438        for (int i=0; i<addrInclusionTags.length; i++) {
     439            if (addrInclusionTags[i].equals(currentMethod)) {
     440                currentIndex = i;
     441                break;
     442            }
     443        }
     444        addrInclusionList.setSelectedIndex(currentIndex);
     445
     446    }
     447
     448
     449
     450    // Create optional control fields in a group box
     451    private JPanel CreateOptionalFields() {
     452
     453        JPanel editControlsPane = new JPanel();
     454        GridBagLayout gridbag = new GridBagLayout();
     455
     456        editControlsPane.setLayout(gridbag);
     457
     458        editControlsPane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
     459
     460        JLabel[] optionalTextLabels = {new JLabel(tr("City:")),
     461                new JLabel(tr("State:")),
     462                new JLabel(tr("Post Code:")),
     463                new JLabel(tr("Country:")),
     464                new JLabel(tr("Full Address:"))};
     465        cityTextField = new JTextField(lastCity, 100);
     466        stateTextField = new JTextField(lastState, 100);
     467        postCodeTextField = new JTextField(lastPostCode, 20);
     468        countryTextField = new JTextField(lastCountry, 2);
     469        fullTextField = new JTextField(lastFullAddress, 300);
     470
     471        // Special processing for addr:country code, max length and uppercase
     472        countryTextField.addKeyListener(new KeyAdapter() {
     473            @Override
     474            public void keyTyped(KeyEvent e) {
     475                JTextField jtextfield = (JTextField)e.getSource();
     476                String text = jtextfield.getText();
     477                int length = text.length();
     478                if (length == jtextfield.getColumns()) {
     479                    e.consume();
     480                } else if (length > jtextfield.getColumns()) {
     481                    // show error message ??
     482                    e.consume();
     483                } else {
     484                    // Accept key; convert to upper case
     485                    if (!e.isActionKey()) {
     486                        e.setKeyChar(Character.toUpperCase(e.getKeyChar()) );
     487                    }
     488                }
     489            }
     490        });
     491
     492        Component[] optionalEditFields = {cityTextField, stateTextField, postCodeTextField, countryTextField, fullTextField};
     493        AddEditControlRows(optionalTextLabels, optionalEditFields,  editControlsPane);
     494
     495
     496
     497        JPanel optionPanel = new JPanel(new BorderLayout());
     498        Border groupBox = BorderFactory.createEtchedBorder();
     499        TitledBorder titleBorder = BorderFactory.createTitledBorder(groupBox, tr("Optional Information:"),
     500                TitledBorder.LEFT, TitledBorder.TOP);
     501
     502        optionPanel.setBorder(titleBorder);
     503        optionPanel.add(editControlsPane, BorderLayout.CENTER);
     504
     505        return optionPanel;
     506    }
     507
     508
     509
     510    // Populate dialog for any possible existing settings if editing an existing Address interpolation way
     511    private void GetExistingMapKeys() {
     512
     513
     514        // Check all nodes for optional addressing data
     515        //    Address interpolation nodes will overwrite these value if they contain optional data
     516        for (Node node : houseNumberNodes) {
     517            CheckNodeForAddressTags(node);
     518        }
     519
     520        if (addrInterpolationWay != null) {
     521            String currentMethod = addrInterpolationWay.get("addr:interpolation");
     522            if (currentMethod != null) {
     523
     524                SelectInterpolationMethod(currentMethod);
     525                interpolationMethodSet = true;  // Don't auto detect over a previous choice
     526            }
     527
     528            String currentInclusion = addrInterpolationWay.get("addr:inclusion");
     529            if (currentInclusion != null) {
     530                SelectInclusion(currentInclusion);
     531            }
     532
     533            Node firstNode = addrInterpolationWay.getNode(0);
     534            Node lastNode = addrInterpolationWay.getNode(addrInterpolationWay.getNodesCount()-1);
     535
     536            // Get any existing start / end # values
     537            String value = firstNode.get("addr:housenumber");
     538            if (value != null) {
     539                startTextField.setText(value);
     540            }
     541
     542            value = lastNode.get("addr:housenumber");
     543            if (value != null) {
     544                endTextField.setText(value);
     545            }
     546            CheckNodeForAddressTags(firstNode);
     547            CheckNodeForAddressTags(lastNode);
     548
     549        }
     550
     551
     552
     553    }
     554
     555
     556    // Check for any existing address data.   If found,
     557    // overwrite any previous data
     558    private void CheckNodeForAddressTags(Node checkNode) {
     559
     560        // Interrogate possible existing optional values
     561        String value = checkNode.get("addr:city");
     562        if (value != null) {
     563            lastCity = value;
     564        }
     565        value = checkNode.get("addr:state");
     566        if (value != null) {
     567            lastState = value;
     568        }
     569        value = checkNode.get("addr:postcode");
     570        if (value != null) {
     571            lastPostCode = value;
     572        }
     573        value = checkNode.get("addr:country");
     574        if (value != null) {
     575            lastCountry = value;
     576        }
     577        value = checkNode.get("addr:full");
     578        if (value != null) {
     579            lastFullAddress = value;
     580        }
     581
     582    }
     583
     584
     585
     586    // Look for a possible 'associatedStreet' type of relation for selected street
     587    // Returns relation description, or an empty string
     588    private String FindRelation() {
     589        String relationDescription = null;
     590        DataSet currentDataSet = Main.main.getCurrentDataSet();
     591        if (currentDataSet != null) {
     592            for (Relation relation : currentDataSet.getRelations()) {
     593
     594                String relationType = relation.get("type");
     595                if (relationType != null) {
     596                    if (relationType.equals("associatedStreet")) {
     597                        for (RelationMember relationMember : relation.getMembers()) {
     598                            if (relationMember.isWay()){
     599                                Way way = (Way) relationMember.getMember();
     600                                // System.out.println("Name: " + way.get("name") );
     601                                if (way == selectedStreet) {
     602                                    associatedStreetRelation = relation;
     603                                    relationDescription = Long.toString(way.getId());
     604
     605                                    String streetName = "";
     606                                    if (relation.getKeys().containsKey("name")) {
     607                                        streetName =  relation.get("name");
     608                                    } else {
     609                                        // Relation is unnamed - use street name
     610                                        streetName =  selectedStreet.get("name");
     611                                    }
     612                                    relationDescription += " (" + streetName + ")";
     613                                    return relationDescription;
     614                                }
     615                            }
     616
     617                        }
     618                    }
     619
     620                }
     621            }
     622
     623        }
     624
     625        return "";
     626    }
     627
     628
     629    // We can proceed only if there is both a named way (the 'street') and
     630    // one un-named way (the address interpolation way ) selected.
     631    //    The plugin menu item is enabled after a single way is selected to display a more meaningful
     632    //    message (a new user may not realize that they need to select both the street and
     633    //    address interpolation way first).
     634    // Also, selected street and working address interpolation ways are saved.
     635    private boolean FindAndSaveSelections() {
     636
     637        boolean isValid = false;
     638
     639        int namedWayCount = 0;
     640        int unNamedWayCount = 0;
     641        DataSet currentDataSet = Main.main.getCurrentDataSet();
     642        if (currentDataSet != null) {
     643            for (OsmPrimitive osm : currentDataSet.getSelectedWays()) {
     644                Way way = (Way) osm;
     645                if (way.getKeys().containsKey("name")) {
     646                    namedWayCount++;
     647                    this.selectedStreet = way;
     648                }
     649                else {
     650                    unNamedWayCount++;
     651                    this.addrInterpolationWay = way;
     652                }
     653            }
     654
     655            // Get additional nodes with addr:housenumber tags:
     656            //   Either selected or in the middle of the Address Interpolation way
     657            //     Do not include end points of Address Interpolation way in this set yet.
     658            houseNumberNodes  = new ArrayList<Node>();
     659            // Check selected nodes
     660            for (OsmPrimitive osm : currentDataSet.getSelectedNodes()) {
     661                Node node = (Node) osm;
     662                if (node.getKeys().containsKey("addr:housenumber")) {
     663                    houseNumberNodes.add(node);
     664                }
     665            }
     666
     667            if (addrInterpolationWay != null) {
     668                // Check nodes in middle of address interpolation way
     669                if (addrInterpolationWay.getNodesCount() > 2) {
     670                    for (int i=1; i<(addrInterpolationWay.getNodesCount()-2); i++) {
     671                        Node testNode = addrInterpolationWay.getNode(i);
     672                        if (testNode.getKeys().containsKey("addr:housenumber")) {
     673                            houseNumberNodes.add(testNode);
     674                        }
     675                    }
     676                }
     677            }
     678
     679        }
     680
     681        if (namedWayCount != 1) {
     682            JOptionPane.showMessageDialog(
     683                    Main.parent,
     684                    tr("Please select a street to associate with address interpolation way"),
     685                    tr("Error"),
     686                    JOptionPane.ERROR_MESSAGE
     687            );
     688        } else {
     689            // Avoid 2 error dialogs if both conditions don't match
     690            if (unNamedWayCount != 1) {
     691                // Allow for street + house number nodes only to be selected (no address interpolation way).
     692                if (houseNumberNodes.size() > 0) {
     693                    isValid = true;
     694                } else {
     695                    JOptionPane.showMessageDialog(
     696                            Main.parent,
     697                            tr("Please select address interpolation way for this street"),
     698                            tr("Error"),
     699                            JOptionPane.ERROR_MESSAGE
     700                    );
     701                }
     702            } else {
     703                isValid = true;
     704            }
     705        }
     706
     707
     708        return isValid;
     709    }
     710
     711
     712    /**
     713    * Add rows of edit controls - with labels in the left column, and controls in the right
     714    * column on the gridbag of the specified container.
     715    */
     716    private void AddEditControlRows(JLabel[] labels,
     717            Component[] editFields,
     718            Container container) {
     719        GridBagConstraints c = new GridBagConstraints();
     720        c.anchor = GridBagConstraints.EAST;
     721        int numLabels = labels.length;
     722
     723        for (int i = 0; i < numLabels; i++) {
     724            c.gridx = 0;
     725            c.gridwidth = 1; //next-to-last
     726            c.fill = GridBagConstraints.NONE;      //reset to default
     727            c.weightx = 0.0;                       //reset to default
     728            container.add(labels[i], c);
     729
     730            c.gridx = 1;
     731            c.gridwidth = GridBagConstraints.REMAINDER;     //end row
     732            c.fill = GridBagConstraints.HORIZONTAL;
     733            c.weightx = 1.0;
     734            container.add(editFields[i], c);
     735        }
     736    }
     737
     738
     739
     740    public void actionPerformed(ActionEvent e) {
     741        if ("ok".equals(e.getActionCommand())) {
     742            if (ValidateAndSave()) {
     743                dialog.dispose();
     744            }
     745
     746        } else  if ("cancel".equals(e.getActionCommand())) {
     747            dialog.dispose();
     748
     749        }
     750    }
     751
     752
     753
     754    // For Alpha interpolation, return base string
     755    //   For example: "22A" -> "22"
     756    //   For example: "A" -> ""
     757    //    Input string must not be empty
     758    private String BaseAlpha(String strValue) {
     759        if (strValue.length() > 0) {
     760            return strValue.substring(0, strValue.length()-1);
     761        }
     762        else {
     763            return "";
     764        }
     765    }
     766
     767
     768    private char LastChar(String strValue) {
     769        if (strValue.length() > 0) {
     770            return strValue.charAt(strValue.length()-1);
     771        }
     772        else {
     773            return 0;
     774        }
     775    }
     776
     777
     778    // Test for valid positive long int
     779    private boolean isLong( String input )
     780    {
     781        try
     782        {
     783            Long val = Long.parseLong( input );
     784            return (val > 0);
     785        }
     786        catch( Exception e)
     787        {
     788            return false;
     789        }
     790    }
     791
     792    private boolean isEven( Long input )
     793    {
     794        return ((input %2) == 0);
     795    }
     796
     797    private static Pattern p = Pattern.compile("^[0-9]+$");
     798    private static boolean IsNumeric(String s) {
     799        return p.matcher(s).matches();
     800    }
     801
     802
     803    private void InterpolateAlphaSection(int startNodeIndex, int endNodeIndex, String endValueString,
     804            char startingChar, char endingChar) {
     805
     806
     807        String baseAlpha = BaseAlpha(endValueString);
     808        int nSegments  =endNodeIndex - startNodeIndex;
     809
     810        double[] segmentLengths = new double[nSegments];
     811        // Total length of address interpolation way section
     812        double totalLength= CalculateSegmentLengths(startNodeIndex, endNodeIndex, segmentLengths);
     813
     814
     815        int nHouses = endingChar - startingChar-1;  // # of house number nodes to create
     816        if (nHouses > 0) {
     817
     818            double houseSpacing = totalLength / (nHouses+1);
     819
     820            Node lastHouseNode = addrInterpolationWay.getNode(startNodeIndex);
     821            int currentSegment = 0; // Segment being used to place new house # node
     822            char currentChar= startingChar;
     823            while (nHouses > 0) {
     824                double distanceNeeded = houseSpacing;
     825
     826                // Move along segments until we can place the new house number
     827                while (distanceNeeded > segmentLengths[currentSegment]) {
     828                    distanceNeeded -= segmentLengths[currentSegment];
     829                    currentSegment++;
     830                    lastHouseNode = addrInterpolationWay.getNode(startNodeIndex + currentSegment);
     831                }
     832
     833                // House number is to be positioned in current segment.
     834                double proportion = distanceNeeded / segmentLengths[currentSegment];
     835                Node toNode = addrInterpolationWay.getNode(startNodeIndex + 1 + currentSegment);
     836                LatLon newHouseNumberPosition = lastHouseNode.getCoor().interpolate(toNode.getCoor(), proportion);
     837
     838
     839
     840                Node newHouseNumberNode = new Node(newHouseNumberPosition);
     841                currentChar++;
     842                if ( (currentChar >'Z') && (currentChar <'a')) {
     843                    // Wraparound past uppercase Z: go directly to lower case a
     844                    currentChar = 'a';
     845
     846                }
     847                String newHouseNumber = baseAlpha + currentChar;
     848                newHouseNumberNode.put("addr:housenumber", newHouseNumber);
     849
     850                commandGroup.add(new AddCommand(newHouseNumberNode));
     851                houseNumberNodes.add(newHouseNumberNode);   // Street, etc information to be added later
     852
     853                lastHouseNode = newHouseNumberNode;
     854
     855
     856                segmentLengths[currentSegment] -= distanceNeeded; // Track amount used
     857                nHouses -- ;
     858            }
     859        }
     860
     861
     862    }
     863
     864
     865    private void CreateAlphaInterpolation(String startValueString, String endValueString) {
     866        char startingChar = LastChar(startValueString);
     867        char endingChar = LastChar(endValueString);
     868
     869        if (isLong(startValueString)) {
     870            // Special case of numeric first value, followed by 'A'
     871            startingChar = 'A'-1;
     872        }
     873
     874        // Search for possible anchors from the 2nd node to 2nd from last, interpolating between each anchor
     875        int startIndex = 0; // Index into first interpolation zone of address interpolation way
     876        for (int i=1; i<addrInterpolationWay.getNodesCount()-1; i++) {
     877            Node testNode = addrInterpolationWay.getNode(i);
     878            String endNodeNumber = testNode.get("addr:housenumber");
     879            if (endNodeNumber != null) {
     880                // This is a potential anchor node
     881                if (endNodeNumber != "") {
     882                    char anchorChar = LastChar(endNodeNumber);
     883                    if ( (anchorChar >startingChar) && (anchorChar < endingChar) ) {
     884                        // Lies within the expected range
     885                        InterpolateAlphaSection(startIndex, i, endNodeNumber, startingChar, anchorChar);
     886
     887                        // For next interpolation section
     888                        startingChar = anchorChar;
     889                        startValueString = endNodeNumber;
     890                        startIndex = i;
     891                    }
     892                }
     893
     894            }
     895        }
     896
     897        // End nodes do not actually contain housenumber value yet (command has not executed), so use user-entered value
     898        InterpolateAlphaSection(startIndex, addrInterpolationWay.getNodesCount()-1, endValueString, startingChar, endingChar);
     899
     900    }
     901
     902
     903    private double CalculateSegmentLengths(int startNodeIndex, int endNodeIndex, double segmentLengths[]) {
     904        Node fromNode = addrInterpolationWay.getNode(startNodeIndex);
     905        double totalLength = 0.0;
     906        int nSegments = segmentLengths.length;
     907        for (int segment = 0; segment < nSegments; segment++) {
     908            Node toNode = addrInterpolationWay.getNode(startNodeIndex + 1 + segment);
     909            segmentLengths[segment]= fromNode.getCoor().greatCircleDistance(toNode.getCoor());
     910            totalLength += segmentLengths[segment];
     911
     912            fromNode = toNode;
     913        }
     914        return totalLength;
     915
     916    }
     917
     918
     919    private void InterpolateNumericSection(int startNodeIndex, int endNodeIndex,
     920            long startingAddr, long endingAddr,
     921            long increment) {
     922
     923
     924        int nSegments  =endNodeIndex - startNodeIndex;
     925
     926        double[] segmentLengths = new double[nSegments];
     927
     928        // Total length of address interpolation way section
     929        double totalLength= CalculateSegmentLengths(startNodeIndex, endNodeIndex, segmentLengths);
     930
     931
     932        int nHouses = (int)((endingAddr - startingAddr) / increment) -1;
     933        if (nHouses > 0) {
     934
     935            double houseSpacing = totalLength / (nHouses+1);
     936
     937            Node lastHouseNode = addrInterpolationWay.getNode(startNodeIndex);
     938            int currentSegment = 0; // Segment being used to place new house # node
     939            long currentHouseNumber = startingAddr;
     940            while (nHouses > 0) {
     941                double distanceNeeded = houseSpacing;
     942
     943                // Move along segments until we can place the new house number
     944                while (distanceNeeded > segmentLengths[currentSegment]) {
     945                    distanceNeeded -= segmentLengths[currentSegment];
     946                    currentSegment++;
     947                    lastHouseNode = addrInterpolationWay.getNode(startNodeIndex + currentSegment);
     948                }
     949
     950                // House number is to be positioned in current segment.
     951                double proportion = distanceNeeded / segmentLengths[currentSegment];
     952                Node toNode = addrInterpolationWay.getNode(startNodeIndex + 1 + currentSegment);
     953                LatLon newHouseNumberPosition = lastHouseNode.getCoor().interpolate(toNode.getCoor(), proportion);
     954
     955
     956                Node newHouseNumberNode = new Node(newHouseNumberPosition);
     957                currentHouseNumber += increment;
     958                String newHouseNumber = Long.toString(currentHouseNumber);
     959                newHouseNumberNode.put("addr:housenumber", newHouseNumber);
     960
     961                commandGroup.add(new AddCommand(newHouseNumberNode));
     962                houseNumberNodes.add(newHouseNumberNode);   // Street, etc information to be added later
     963
     964                lastHouseNode = newHouseNumberNode;
     965
     966
     967                segmentLengths[currentSegment] -= distanceNeeded; // Track amount used
     968                nHouses -- ;
     969            }
     970        }
     971
     972
     973    }
     974
     975
     976    private void CreateNumericInterpolation(String startValueString, String endValueString, long increment) {
     977
     978        long startingAddr = Long.parseLong( startValueString );
     979        long endingAddr = Long.parseLong( endValueString );
     980
     981
     982        // Search for possible anchors from the 2nd node to 2nd from last, interpolating between each anchor
     983        int startIndex = 0; // Index into first interpolation zone of address interpolation way
     984        for (int i=1; i<addrInterpolationWay.getNodesCount()-1; i++) {
     985            Node testNode = addrInterpolationWay.getNode(i);
     986            String strEndNodeNumber = testNode.get("addr:housenumber");
     987            if (strEndNodeNumber != null) {
     988                // This is a potential anchor node
     989                if (isLong(strEndNodeNumber)) {
     990
     991                    long anchorAddrNumber = Long.parseLong( strEndNodeNumber );
     992                    if ( (anchorAddrNumber >startingAddr) && (anchorAddrNumber < endingAddr) ) {
     993                        // Lies within the expected range
     994                        InterpolateNumericSection(startIndex, i, startingAddr, anchorAddrNumber, increment);
     995
     996                        // For next interpolation section
     997                        startingAddr = anchorAddrNumber;
     998                        startValueString = strEndNodeNumber;
     999                        startIndex = i;
     1000                    }
     1001                }
     1002
     1003            }
     1004        }
     1005
     1006        // End nodes do not actually contain housenumber value yet (command has not executed), so use user-entered value
     1007        InterpolateNumericSection(startIndex, addrInterpolationWay.getNodesCount()-1, startingAddr, endingAddr, increment);
     1008    }
     1009
     1010
     1011    // Called if user has checked "Convert to House Numbers" checkbox.
     1012    private void ConvertWayToHousenumbers(String selectedMethod, String startValueString, String endValueString,
     1013            String incrementString) {
     1014        // - Use nodes labeled with 'same type' as interim anchors in the middle of the way to identify unequal spacing.
     1015        // - Ignore nodes of different type; for example '25b' is ignored in sequence 5..15
     1016
     1017        // Calculate required number of house numbers to create
     1018        if (selectedMethod.equals("alphabetic")) {
     1019
     1020            CreateAlphaInterpolation(startValueString, endValueString);
     1021
     1022
     1023        } else {
     1024            long increment = 1;
     1025            if (selectedMethod.equals("odd") || selectedMethod.equals("even")) {
     1026                increment = 2;
     1027            } else if (selectedMethod.equals("Numeric")) {
     1028                increment = Long.parseLong(incrementString);
     1029            }
     1030            CreateNumericInterpolation(startValueString, endValueString, increment);
     1031
     1032        }
     1033
     1034
     1035        RemoveAddressInterpolationWay();
     1036
     1037    }
     1038
     1039
     1040    private void RemoveAddressInterpolationWay() {
     1041
     1042        // Remove untagged nodes
     1043        for (int i=1; i<addrInterpolationWay.getNodesCount()-1; i++) {
     1044            Node testNode = addrInterpolationWay.getNode(i);
     1045            if (!testNode.hasKeys()) {
     1046                commandGroup.add(new DeleteCommand(testNode));
     1047            }
     1048        }
     1049
     1050        // Remove way
     1051        commandGroup.add(new DeleteCommand(addrInterpolationWay));
     1052        addrInterpolationWay = null;
     1053
     1054    }
     1055
     1056
     1057
     1058    private boolean ValidateAndSave() {
     1059
     1060        String startValueString = ReadTextField(startTextField);
     1061        String endValueString = ReadTextField(endTextField);
     1062        String incrementString = ReadTextField(incrementTextField);
     1063        String city = ReadTextField(cityTextField);
     1064        String state = ReadTextField(stateTextField);
     1065        String postCode = ReadTextField(postCodeTextField);
     1066        String country = ReadTextField(countryTextField);
     1067        String fullAddress = ReadTextField(fullTextField);
     1068
     1069        String selectedMethod = GetInterpolationMethod();
     1070        if (addrInterpolationWay != null) {
     1071            Long startAddr=0L, endAddr=0L;
     1072            if (!selectedMethod.equals("alphabetic")) {
     1073                Long[] addrArray = {startAddr, endAddr};
     1074                if (!ValidAddressNumbers(startValueString, endValueString, addrArray )) {
     1075                    return false;
     1076                }
     1077                startAddr = addrArray[0];
     1078                endAddr = addrArray[1];
     1079            }
     1080
     1081            String errorMessage = "";
     1082            if (selectedMethod.equals("odd")) {
     1083                if (isEven(startAddr) || isEven(endAddr)) {
     1084                    errorMessage = tr("Expected odd numbers for addresses");
     1085                }
     1086
     1087            } else if (selectedMethod.equals("even")) {
     1088                if (!isEven(startAddr) || !isEven(endAddr)) {
     1089                    errorMessage = tr("Expected even numbers for addresses");
     1090                }
     1091            } else if (selectedMethod.equals("all")) {
     1092
     1093            }else if (selectedMethod.equals("alphabetic")) {
     1094                errorMessage = ValidateAlphaAddress(startValueString, endValueString);
     1095
     1096            }else if (selectedMethod.equals("Numeric")) {
     1097
     1098                if (!ValidNumericIncrementString(incrementString, startAddr, endAddr)) {
     1099                    errorMessage = tr("Expected valid number for address increment");
     1100                }
     1101
     1102            }
     1103            if (!errorMessage.equals("")) {
     1104                JOptionPane.showMessageDialog(Main.parent, errorMessage, tr("Error"),   JOptionPane.ERROR_MESSAGE);
     1105                return false;
     1106            }
     1107        }
     1108
     1109        if (country != null) {
     1110            if (country.length() != 2) {
     1111                JOptionPane.showMessageDialog(Main.parent,
     1112                        tr("Country code must be 2 letters"), tr("Error"),  JOptionPane.ERROR_MESSAGE);
     1113                return false;
     1114            }
     1115        }
     1116
     1117        // Entries are valid ... save in map
     1118
     1119        commandGroup = new LinkedList<Command>();
     1120
     1121        String streetName = selectedStreet.get("name");
     1122
     1123        if (addrInterpolationWay != null) {
     1124
     1125            Node firstNode = addrInterpolationWay.getNode(0);
     1126            Node lastNode = addrInterpolationWay.getNode(addrInterpolationWay.getNodesCount()-1);
     1127
     1128            // De-select address interpolation way; leave street selected
     1129            DataSet currentDataSet = Main.main.getCurrentDataSet();
     1130            if (currentDataSet != null) {
     1131                currentDataSet.clearSelection(addrInterpolationWay);
     1132                currentDataSet.clearSelection(lastNode);  // Workaround for JOSM Bug #3838
     1133            }
     1134
     1135
     1136            String interpolationTagValue = selectedMethod;
     1137            if (selectedMethod.equals("Numeric")) {
     1138                // The interpolation method is the number for 'Numeric' case
     1139                interpolationTagValue = incrementString;
     1140            }
     1141
     1142            if (cbConvertToHouseNumbers.getState()) {
     1143                // Convert way to house numbers is checked.
     1144                //  Create individual nodes and delete interpolation way
     1145                ConvertWayToHousenumbers(selectedMethod, startValueString, endValueString, incrementString);
     1146            } else {
     1147                // Address interpolation way will remain
     1148                commandGroup.add(new ChangePropertyCommand(addrInterpolationWay, "addr:interpolation", interpolationTagValue));
     1149                commandGroup.add(new ChangePropertyCommand(addrInterpolationWay, "addr:inclusion", GetInclusionMethod()));
     1150            }
     1151
     1152            commandGroup.add(new ChangePropertyCommand(firstNode, "addr:housenumber", startValueString));
     1153            commandGroup.add(new ChangePropertyCommand(lastNode, "addr:housenumber", endValueString));
     1154            // Add address interpolation house number nodes to main house number node list for common processing
     1155            houseNumberNodes.add(firstNode);
     1156            houseNumberNodes.add(lastNode);
     1157
     1158        }
     1159
     1160
     1161
     1162        if (streetRelationButton.isSelected()) {
     1163
     1164            // Relation button was selected
     1165            if (associatedStreetRelation == null) {
     1166                CreateRelation(streetName);
     1167                // relationChanged = true;   (not changed since it was created)
     1168            }
     1169            // Make any additional changes only to the copy
     1170            editedRelation = new Relation(associatedStreetRelation);
     1171
     1172            if (addrInterpolationWay != null) {
     1173                AddToRelation(associatedStreetRelation, addrInterpolationWay, "house");
     1174            }
     1175        }
     1176
     1177
     1178        // For all nodes, add to relation and
     1179        //   Add optional text fields to all nodes if specified
     1180        for (Node node : houseNumberNodes) {
     1181
     1182            if (streetRelationButton.isSelected()) {
     1183                AddToRelation(associatedStreetRelation, node, "house");
     1184            }
     1185            if ((city != null) || (streetNameButton.isSelected()) ) {
     1186                // Include street unconditionally if adding nodes only or city name specified
     1187                commandGroup.add(new ChangePropertyCommand(node, "addr:street", streetName));
     1188            }
     1189            // Set or remove remaining optional fields
     1190            commandGroup.add(new ChangePropertyCommand(node, "addr:city", city));
     1191            commandGroup.add(new ChangePropertyCommand(node, "addr:state", state));
     1192            commandGroup.add(new ChangePropertyCommand(node, "addr:postcode", postCode));
     1193            commandGroup.add(new ChangePropertyCommand(node, "addr:country", country));
     1194            commandGroup.add(new ChangePropertyCommand(node, "addr:full", fullAddress));
     1195        }
     1196
     1197        if (relationChanged) {
     1198            commandGroup.add(new ChangeCommand(associatedStreetRelation, editedRelation));
     1199        }
     1200
     1201
     1202        Main.main.undoRedo.add(new SequenceCommand(tr("Address Interpolation"), commandGroup));
     1203        Main.map.repaint();
     1204
     1205        return true;
     1206    }
     1207
     1208
     1209    private boolean ValidNumericIncrementString(String incrementString, long startingAddr, long endingAddr) {
     1210
     1211        if (!isLong(incrementString)) {
     1212            return false;
     1213        }
     1214        long testIncrement = Long.parseLong(incrementString);
     1215        if ( (testIncrement <=0) || (testIncrement > endingAddr ) ) {
     1216            return false;
     1217        }
     1218
     1219        if ( ((endingAddr - startingAddr) % testIncrement) != 0) {
     1220            return false;
     1221        }
     1222        return true;
     1223    }
     1224
     1225
     1226
     1227    // Create Associated Street relation, add street, and add to list of commands to perform
     1228    private void CreateRelation(String streetName) {
     1229        associatedStreetRelation = new Relation();
     1230        associatedStreetRelation.put("name", streetName);
     1231        associatedStreetRelation.put("type", "associatedStreet");
     1232        RelationMember newStreetMember = new RelationMember("street", selectedStreet);
     1233        associatedStreetRelation.addMember(newStreetMember);
     1234        commandGroup.add(new AddCommand(associatedStreetRelation));
     1235    }
     1236
     1237
     1238
     1239    // Read from dialog text box, removing leading and trailing spaces
     1240    // Return the string, or null for a zero length string
     1241    private String ReadTextField(JTextField field) {
     1242        String value = field.getText();
     1243        if (value != null) {
     1244            value = value.trim();
     1245            if (value.equals("")) {
     1246                value = null;
     1247            }
     1248        }
     1249        return value;
     1250    }
     1251
     1252
     1253    // Test if relation contains specified member
     1254    //   If not already present, it is added
     1255    private void AddToRelation(Relation relation,   OsmPrimitive testMember, String role) {
     1256        boolean isFound = false;
     1257        for (RelationMember relationMember : relation.getMembers()) {
     1258
     1259            if (testMember == relationMember.getMember()) {
     1260                isFound = true;
     1261                break;
     1262            }
     1263        }
     1264
     1265        if (!isFound) {
     1266            RelationMember newMember = new RelationMember(role, testMember);
     1267            editedRelation.addMember(newMember);
     1268
     1269            relationChanged = true;
     1270        }
     1271    }
     1272
     1273
     1274
     1275    // Check alphabetic style address
     1276    //   Last character of both must be alpha
     1277    //   Last character of ending must be greater than starting
     1278    //   Return empty error message if OK
     1279    private String ValidateAlphaAddress(String startValueString,
     1280            String endValueString) {
     1281        String errorMessage="";
     1282
     1283        if (startValueString.equals("") || endValueString.equals("")) {
     1284            errorMessage = tr("Please enter valid number for starting and ending address");
     1285        } else {
     1286            char startingChar = LastChar(startValueString);
     1287            char endingChar = LastChar(endValueString);
     1288
     1289
     1290            boolean isOk = false;
     1291            if ( (IsNumeric("" + startingChar)) &&  (!IsNumeric("" + endingChar)) ) {
     1292                endingChar = Character.toUpperCase(endingChar);
     1293                if ( (endingChar >= 'A') && (endingChar <= 'Z') ) {
     1294                    // First is a number, last is Latin alpha
     1295                    isOk = true;
     1296                }
     1297            } else if ( (!IsNumeric("" + startingChar)) && (!IsNumeric("" + endingChar)) ) {
     1298                // Both are alpha
     1299                isOk = true;
     1300            }
     1301            if (!isOk) {
     1302                errorMessage = tr("Alphabetic address must end with a letter");
     1303            }
     1304
     1305
     1306            // if a number is included, validate that it is the same number
     1307            if (endValueString.length() > 1) {
     1308
     1309                // Get number portion of first item: may or may not have letter suffix
     1310                String numStart = BaseAlpha(startValueString);
     1311                if (IsNumeric(startValueString)) {
     1312                    numStart = startValueString;
     1313                }
     1314
     1315                String numEnd = BaseAlpha(endValueString);
     1316                if (!numStart.equals(numEnd)) {
     1317                    errorMessage = tr("Starting and ending numbers must be the same for alphabetic addresses");
     1318                }
     1319            }
     1320
     1321            // ?? Character collation in all languages ??
     1322            if (startingChar >= endingChar) {
     1323                errorMessage = tr("Starting address letter must be less than ending address letter");
     1324            }
     1325
     1326        }
     1327
     1328        return errorMessage;
     1329    }
     1330
     1331
     1332
     1333    // Convert string addresses to numeric, with error check
     1334    private boolean ValidAddressNumbers(String startValueString,
     1335            String endValueString, Long[] addrArray) {
     1336        String errorMessage = "";
     1337
     1338        if (!isLong(startValueString)) {
     1339            errorMessage = tr("Please enter valid number for starting address");
     1340        }
     1341        if (!isLong(endValueString)) {
     1342            errorMessage = tr("Please enter valid number for ending address");
     1343        }
     1344        if (errorMessage.equals("")) {
     1345            addrArray[0] = Long.parseLong( startValueString );
     1346            addrArray[1] = Long.parseLong( endValueString );
     1347
     1348            if (addrArray[1] <= addrArray[0]) {
     1349                errorMessage = tr("Starting address number must be less than ending address number");
     1350            }
     1351        }
     1352
     1353        if (errorMessage.equals("")) {
     1354            return true;
     1355
     1356        } else {
     1357            JOptionPane.showMessageDialog(Main.parent, errorMessage, tr("Error"),   JOptionPane.ERROR_MESSAGE);
     1358            return false;
     1359        }
     1360    }
     1361
     1362
     1363
     1364    private String GetInterpolationMethod() {
     1365        int selectedIndex = addrInterpolationList.getSelectedIndex();
     1366        return addrInterpolationTags[selectedIndex];
     1367    }
     1368
     1369
     1370    private String GetInclusionMethod() {
     1371        int selectedIndex = addrInclusionList.getSelectedIndex();
     1372        lastAccuracyIndex = selectedIndex;
     1373        return addrInclusionTags[selectedIndex];
     1374    }
    13751375
    13761376
  • applications/editors/josm/plugins/addrinterpolation/src/org/openstreetmap/josm/plugins/AddrInterpolation/AddrInterpolationPlugin.java

    r19422 r23191  
    99public class AddrInterpolationPlugin extends Plugin {
    1010
    11         AddrInterpolationAction action = null;
     11    AddrInterpolationAction action = null;
    1212
    13         /**
    14         * constructor
    15         */
    16         public AddrInterpolationPlugin(PluginInformation info) {
    17                 super(info);
    18                 action = new AddrInterpolationAction();
    19                 Main.main.menu.toolsMenu.add(action);
    20         }
     13    /**
     14    * constructor
     15    */
     16    public AddrInterpolationPlugin(PluginInformation info) {
     17        super(info);
     18        action = new AddrInterpolationAction();
     19        Main.main.menu.toolsMenu.add(action);
     20    }
    2121}
  • applications/editors/josm/plugins/addrinterpolation/src/org/openstreetmap/josm/plugins/AddrInterpolation/EscapeDialog.java

    r17721 r23191  
    1515
    1616public class EscapeDialog extends JDialog {
    17         public EscapeDialog() {
    18                 this((Frame)null, false);
    19         }
    20         public EscapeDialog(Frame owner) {
    21                 this(owner, false);
    22         }
    23         public EscapeDialog(Frame owner, boolean modal) {
    24                 this(owner, null, modal);
    25         }
    26         public EscapeDialog(Frame owner, String title) {
    27                 this(owner, title, false);
    28         }
    29         public EscapeDialog(Frame owner, String title, boolean modal) {
    30                 super(owner, title, modal);
    31         }
    32         public EscapeDialog(Dialog owner) {
    33                 this(owner, false);
    34         }
    35         public EscapeDialog(Dialog owner, boolean modal) {
    36                 this(owner, null, modal);
    37         }
    38         public EscapeDialog(Dialog owner, String title) {
    39                 this(owner, title, false);
    40         }
    41         public EscapeDialog(Dialog owner, String title, boolean modal) {
    42                 super(owner, title, modal);
    43         }
     17    public EscapeDialog() {
     18        this((Frame)null, false);
     19    }
     20    public EscapeDialog(Frame owner) {
     21        this(owner, false);
     22    }
     23    public EscapeDialog(Frame owner, boolean modal) {
     24        this(owner, null, modal);
     25    }
     26    public EscapeDialog(Frame owner, String title) {
     27        this(owner, title, false);
     28    }
     29    public EscapeDialog(Frame owner, String title, boolean modal) {
     30        super(owner, title, modal);
     31    }
     32    public EscapeDialog(Dialog owner) {
     33        this(owner, false);
     34    }
     35    public EscapeDialog(Dialog owner, boolean modal) {
     36        this(owner, null, modal);
     37    }
     38    public EscapeDialog(Dialog owner, String title) {
     39        this(owner, title, false);
     40    }
     41    public EscapeDialog(Dialog owner, String title, boolean modal) {
     42        super(owner, title, modal);
     43    }
    4444
    4545
    46         @Override
    47         protected JRootPane createRootPane() {
    48                 ActionListener escapeActionListener = new ActionListener() {
    49                         public void actionPerformed(ActionEvent actionEvent) {
    50                                 dispose();
    51                                 // setVisible(false);
    52                         }
    53                 };
    54                 JRootPane rootPane = new JRootPane();
    55                 KeyStroke stroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0);
    56                 rootPane.registerKeyboardAction(escapeActionListener, stroke, JComponent.WHEN_IN_FOCUSED_WINDOW);
     46    @Override
     47    protected JRootPane createRootPane() {
     48        ActionListener escapeActionListener = new ActionListener() {
     49            public void actionPerformed(ActionEvent actionEvent) {
     50                dispose();
     51                // setVisible(false);
     52            }
     53        };
     54        JRootPane rootPane = new JRootPane();
     55        KeyStroke stroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0);
     56        rootPane.registerKeyboardAction(escapeActionListener, stroke, JComponent.WHEN_IN_FOCUSED_WINDOW);
    5757
    58                 return rootPane;
    59         }
     58        return rootPane;
     59    }
    6060}
    6161
Note: See TracChangeset for help on using the changeset viewer.