001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.widgets; 003 004import static org.openstreetmap.josm.tools.I18n.tr; 005 006import java.util.ArrayList; 007import java.util.List; 008import java.util.StringTokenizer; 009 010import javax.swing.text.JTextComponent; 011 012import org.openstreetmap.josm.data.osm.OsmPrimitiveType; 013import org.openstreetmap.josm.data.osm.PrimitiveId; 014import org.openstreetmap.josm.data.osm.SimplePrimitiveId; 015import org.openstreetmap.josm.tools.Logging; 016import org.openstreetmap.josm.tools.Utils; 017 018/** 019 * A text field designed to enter one or several OSM primitive IDs. 020 * @author Matthias Julius 021 */ 022public class OsmIdTextField extends AbstractIdTextField<OsmIdTextField.OsmIdValidator> { 023 024 /** 025 * Constructs a new {@link OsmIdTextField} 026 */ 027 public OsmIdTextField() { 028 super(OsmIdValidator.class); 029 } 030 031 /** 032 * Sets the type of primitive object 033 * @param type The type of primitive object ( 034 * {@link OsmPrimitiveType#NODE NODE}, 035 * {@link OsmPrimitiveType#WAY WAY}, 036 * {@link OsmPrimitiveType#RELATION RELATION}) 037 */ 038 public void setType(OsmPrimitiveType type) { 039 validator.type = type; 040 } 041 042 /** 043 * Get entered ID list - supports "1,2,3" "1 2 ,3" or even "1 2 3 v2 6 v8" 044 * @return list of id's 045 */ 046 public final List<PrimitiveId> getIds() { 047 return new ArrayList<>(validator.ids); 048 } 049 050 /** 051 * Reads the OSM primitive id(s) 052 * @return true if valid OSM objects IDs have been read, false otherwise 053 * @see OsmIdValidator#readOsmIds 054 */ 055 @Override 056 public boolean readIds() { 057 return validator.readOsmIds(); 058 } 059 060 /** 061 * Validator for an OSM primitive ID entered in a {@link JTextComponent}. 062 */ 063 public static class OsmIdValidator extends AbstractTextComponentValidator { 064 065 private final List<PrimitiveId> ids = new ArrayList<>(); 066 private OsmPrimitiveType type; 067 068 /** 069 * Constructs a new {@link OsmIdValidator} 070 * @param tc The text component to validate 071 */ 072 public OsmIdValidator(JTextComponent tc) { 073 super(tc, false); 074 } 075 076 @Override 077 public boolean isValid() { 078 return readOsmIds(); 079 } 080 081 @Override 082 public void validate() { 083 if (!isValid()) { 084 feedbackInvalid(tr("The current value is not a valid OSM ID. Please enter an integer value > 0")); 085 } else { 086 feedbackValid(tr("Please enter an integer value > 0")); 087 } 088 } 089 090 /** 091 * Reads the OSM primitive id(s) 092 * @return true if valid OSM objects IDs have been read, false otherwise 093 */ 094 public boolean readOsmIds() { 095 String value = getComponent().getText(); 096 char c; 097 if (Utils.isBlank(value)) { 098 return false; 099 } 100 ids.clear(); 101 StringTokenizer st = new StringTokenizer(value, ",.+/ \t\n"); 102 String s; 103 while (st.hasMoreTokens()) { 104 s = st.nextToken(); 105 // convert tokens to int skipping v-words (version v2 etc) 106 c = s.charAt(0); 107 if (c != 'v') { 108 try { 109 ids.addAll(SimplePrimitiveId.multipleFromString(s)); 110 } catch (IllegalArgumentException ex) { 111 try { 112 Logging.trace(ex); 113 long id = Long.parseLong(s); 114 if (id <= 0) { 115 return false; 116 } else if (type == OsmPrimitiveType.NODE) { 117 ids.add(new SimplePrimitiveId(id, OsmPrimitiveType.NODE)); 118 } else if (type == OsmPrimitiveType.WAY || type == OsmPrimitiveType.CLOSEDWAY) { 119 ids.add(new SimplePrimitiveId(id, OsmPrimitiveType.WAY)); 120 } else if (type == OsmPrimitiveType.RELATION || type == OsmPrimitiveType.MULTIPOLYGON) { 121 ids.add(new SimplePrimitiveId(id, OsmPrimitiveType.RELATION)); 122 } else { 123 return false; 124 } 125 } catch (IllegalArgumentException ex2) { 126 Logging.trace(ex2); 127 return false; 128 } 129 } 130 } 131 } 132 return !ids.isEmpty(); 133 } 134 } 135}