001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.tagging.presets.items; 003 004import static org.openstreetmap.josm.tools.I18n.tr; 005 006import java.awt.GridBagLayout; 007import java.util.Collection; 008import java.util.LinkedList; 009import java.util.List; 010import java.util.Set; 011 012import javax.swing.JLabel; 013import javax.swing.JPanel; 014 015import org.openstreetmap.josm.data.osm.OsmPrimitive; 016import org.openstreetmap.josm.data.osm.Tag; 017import org.openstreetmap.josm.data.osm.search.SearchCompiler; 018import org.openstreetmap.josm.data.osm.search.SearchParseError; 019import org.openstreetmap.josm.data.osm.search.SearchSetting; 020import org.openstreetmap.josm.gui.tagging.presets.TaggingPresetItem; 021import org.openstreetmap.josm.gui.tagging.presets.TaggingPresetType; 022import org.openstreetmap.josm.tools.GBC; 023import org.openstreetmap.josm.tools.ImageProvider; 024import org.xml.sax.SAXException; 025 026/** 027 * The <code>roles</code> element in tagging presets definition. 028 * <p> 029 * A list of {@link Role} elements. Describes the roles that are expected for 030 * the members of a relation. 031 * <p> 032 * Used for data validation, auto completion, among others. 033 */ 034public class Roles extends TaggingPresetItem { 035 036 /** 037 * The <code>role</code> element in tagging preset definition. 038 * 039 * Information on a certain role, which is expected for the relation members. 040 */ 041 public static class Role { 042 public Set<TaggingPresetType> types; // NOSONAR 043 /** Role name used in a relation */ 044 public String key; // NOSONAR 045 /** Is the role name a regular expression */ 046 public boolean regexp; // NOSONAR 047 /** The text to display */ 048 public String text; // NOSONAR 049 /** The context used for translating {@link #text} */ 050 public String text_context; // NOSONAR 051 /** The localized version of {@link #text}. */ 052 public String locale_text; // NOSONAR 053 /** An expression (cf. search dialog) for objects of this role */ 054 public SearchCompiler.Match memberExpression; // NOSONAR 055 /** Is this role required at least once in the relation? */ 056 public boolean required; // NOSONAR 057 /** How often must the element appear */ 058 private long count; 059 060 public void setType(String types) throws SAXException { 061 this.types = getType(types); 062 } 063 064 public void setRequisite(String str) throws SAXException { 065 if ("required".equals(str)) { 066 required = true; 067 } else if (!"optional".equals(str)) 068 throw new SAXException(tr("Unknown requisite: {0}", str)); 069 } 070 071 public void setRegexp(String str) throws SAXException { 072 if ("true".equals(str)) { 073 regexp = true; 074 } else if (!"false".equals(str)) 075 throw new SAXException(tr("Unknown regexp value: {0}", str)); 076 } 077 078 public void setMember_expression(String memberExpression) throws SAXException { 079 try { 080 final SearchSetting searchSetting = new SearchSetting(); 081 searchSetting.text = memberExpression; 082 searchSetting.caseSensitive = true; 083 searchSetting.regexSearch = true; 084 this.memberExpression = SearchCompiler.compile(searchSetting); 085 } catch (SearchParseError ex) { 086 throw new SAXException(tr("Illegal member expression: {0}", ex.getMessage()), ex); 087 } 088 } 089 090 public void setCount(String count) { 091 this.count = Long.parseLong(count); 092 } 093 094 /** 095 * Return either argument, the highest possible value or the lowest allowed value 096 * @param c count 097 * @return the highest possible value or the lowest allowed value 098 * @see #required 099 */ 100 public long getValidCount(long c) { 101 if (count > 0 && !required) 102 return c != 0 ? count : 0; 103 else if (count > 0) 104 return count; 105 else if (!required) 106 return c != 0 ? c : 0; 107 else 108 return c != 0 ? c : 1; 109 } 110 111 /** 112 * Check if the given role matches this class (required to check regexp role types) 113 * @param role role to check 114 * @return <code>true</code> if role matches 115 * @since 11989 116 */ 117 public boolean isRole(String role) { 118 if (regexp && role != null) { // pass null through, it will anyway fail 119 return role.matches(this.key); 120 } 121 return this.key.equals(role); 122 } 123 124 public boolean addToPanel(JPanel p) { 125 String cstring; 126 if (count > 0 && !required) { 127 cstring = "0,"+count; 128 } else if (count > 0) { 129 cstring = String.valueOf(count); 130 } else if (!required) { 131 cstring = "0-..."; 132 } else { 133 cstring = "1-..."; 134 } 135 if (locale_text == null) { 136 locale_text = getLocaleText(text, text_context, null); 137 } 138 p.add(new JLabel(locale_text+':'), GBC.std().insets(0, 0, 10, 0)); 139 p.add(new JLabel(key), GBC.std().insets(0, 0, 10, 0)); 140 p.add(new JLabel(cstring), types == null ? GBC.eol() : GBC.std().insets(0, 0, 10, 0)); 141 if (types != null) { 142 JPanel pp = new JPanel(); 143 for (TaggingPresetType t : types) { 144 pp.add(new JLabel(ImageProvider.get(t.getIconName()))); 145 } 146 p.add(pp, GBC.eol()); 147 } 148 return true; 149 } 150 151 @Override 152 public String toString() { 153 return "Role [key=" + key + ", text=" + text + ']'; 154 } 155 } 156 157 /** 158 * List of {@link Role} elements. 159 */ 160 public final List<Role> roles = new LinkedList<>(); 161 162 @Override 163 public boolean addToPanel(JPanel p, Collection<OsmPrimitive> sel, boolean presetInitiallyMatches) { 164 p.add(new JLabel(" "), GBC.eol()); // space 165 if (!roles.isEmpty()) { 166 JPanel proles = new JPanel(new GridBagLayout()); 167 proles.add(new JLabel(tr("Available roles")), GBC.std().insets(0, 0, 10, 0)); 168 proles.add(new JLabel(tr("role")), GBC.std().insets(0, 0, 10, 0)); 169 proles.add(new JLabel(tr("count")), GBC.std().insets(0, 0, 10, 0)); 170 proles.add(new JLabel(tr("elements")), GBC.eol()); 171 for (Role i : roles) { 172 i.addToPanel(proles); 173 } 174 p.add(proles, GBC.eol()); 175 } 176 return false; 177 } 178 179 @Override 180 public void addCommands(List<Tag> changedTags) { 181 // Do nothing 182 } 183 184 @Override 185 public String toString() { 186 return "Roles [roles=" + roles + ']'; 187 } 188}