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