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