001 package ezvcard.types; 002 003 import java.util.ArrayList; 004 import java.util.Arrays; 005 import java.util.List; 006 007 import ezvcard.VCardSubTypes; 008 import ezvcard.VCardVersion; 009 import ezvcard.io.CompatibilityMode; 010 import ezvcard.util.HCardElement; 011 import ezvcard.util.VCardStringUtils; 012 import ezvcard.util.XCardElement; 013 014 /* 015 Copyright (c) 2012, Michael Angstadt 016 All rights reserved. 017 018 Redistribution and use in source and binary forms, with or without 019 modification, are permitted provided that the following conditions are met: 020 021 1. Redistributions of source code must retain the above copyright notice, this 022 list of conditions and the following disclaimer. 023 2. Redistributions in binary form must reproduce the above copyright notice, 024 this list of conditions and the following disclaimer in the documentation 025 and/or other materials provided with the distribution. 026 027 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 028 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 029 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 030 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 031 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 032 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 033 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 034 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 035 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 036 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 037 038 The views and conclusions contained in the software and documentation are those 039 of the authors and should not be interpreted as representing official policies, 040 either expressed or implied, of the FreeBSD Project. 041 */ 042 043 /** 044 * <p> 045 * Contains the separated components of the person's name. 046 * </p> 047 * 048 * <p> 049 * Multiple instances of this type can be added ONLY if each instance has an 050 * ALTID parameter and the value of the ALTID parameter is the same across all 051 * instances. However, this is a border-case; under most circumstances, you will 052 * only need to add one instance. 053 * </p> 054 * 055 * <pre> 056 * VCard vcard = new VCard(); 057 * StructuredNameType n = new StructuredNameType(); 058 * n.setFamily("House"); 059 * n.setGiven("Gregory"); 060 * n.addPrefix("Dr"); 061 * n.addSuffix("MD"); 062 * vcard.setStructuredName(n); 063 * </pre> 064 * 065 * <p> 066 * vCard property name: N 067 * </p> 068 * <p> 069 * vCard versions: 2.1, 3.0, 4.0 070 * </p> 071 * @author Michael Angstadt 072 */ 073 public class StructuredNameType extends VCardType { 074 public static final String NAME = "N"; 075 076 private String family; 077 private String given; 078 private List<String> additional = new ArrayList<String>(); 079 private List<String> prefixes = new ArrayList<String>(); 080 private List<String> suffixes = new ArrayList<String>(); 081 082 public StructuredNameType() { 083 super(NAME); 084 } 085 086 /** 087 * Gets the family name (aka "last name"). 088 * @return the family name or null if not set 089 */ 090 public String getFamily() { 091 return family; 092 } 093 094 /** 095 * Sets the family name (aka "last name"). 096 * @param family the family name or null to remove 097 */ 098 public void setFamily(String family) { 099 this.family = family; 100 } 101 102 /** 103 * Gets the given name (aka "first name"). 104 * @return the given name or null if not set 105 */ 106 public String getGiven() { 107 return given; 108 } 109 110 /** 111 * Sets the given name (aka "first name"). 112 * @param given the given name or null to remove 113 */ 114 public void setGiven(String given) { 115 this.given = given; 116 } 117 118 /** 119 * Gets any additional names the person goes by. 120 * @return the additional names or empty list if there are none 121 */ 122 public List<String> getAdditional() { 123 return additional; 124 } 125 126 /** 127 * Adds an additional name the person goes by. 128 * @param additional the additional name to add 129 */ 130 public void addAdditional(String additional) { 131 this.additional.add(additional); 132 } 133 134 /** 135 * Gets the prefixes. 136 * @return the prefixes (e.g. "Mr.") or empty list if there are none 137 */ 138 public List<String> getPrefixes() { 139 return prefixes; 140 } 141 142 /** 143 * Adds a prefix. 144 * @param prefix the prefix to add (e.g. "Mr.") 145 */ 146 public void addPrefix(String prefix) { 147 this.prefixes.add(prefix); 148 } 149 150 /** 151 * Gets the suffixes. 152 * @return the suffixes (e.g. "Jr.") or empty list if there are none 153 */ 154 public List<String> getSuffixes() { 155 return suffixes; 156 } 157 158 /** 159 * Adds a suffix. 160 * @param suffix the suffix to add (e.g. "Jr.") 161 */ 162 public void addSuffix(String suffix) { 163 this.suffixes.add(suffix); 164 } 165 166 /** 167 * Gets the string(s) that define how to sort the vCard. 168 * <p> 169 * 2.1 and 3.0 vCards should use the {@link SortStringType SORT-STRING} 170 * property instead. 171 * </p> 172 * <p> 173 * vCard versions: 4.0 174 * </p> 175 * @return the sort string(s) (e.g. ["Aboville", "Christine"] if the family 176 * name is "d'Aboville" and the given name is "Christine") or empty list if 177 * there are none 178 * @see VCardSubTypes#getSortAs 179 */ 180 public List<String> getSortAs() { 181 return subTypes.getSortAs(); 182 } 183 184 /** 185 * Sets the string that defines how to sort the vCard. 186 * <p> 187 * 2.1 and 3.0 vCards should use the {@link SortStringType SORT-STRING} 188 * property instead. 189 * </p> 190 * <p> 191 * vCard versions: 4.0 192 * </p> 193 * @param family the sorttable family name (e.g. "Adboville" if the family 194 * name is "d'Aboville") or null to remove 195 */ 196 public void setSortAs(String family) { 197 if (family == null) { 198 subTypes.setSortAs(); 199 } else { 200 subTypes.setSortAs(family); 201 } 202 } 203 204 /** 205 * Sets the strings that define how to sort the vCard. 206 * <p> 207 * 2.1 and 3.0 vCards should use the {@link SortStringType SORT-STRING} 208 * property instead. 209 * </p> 210 * <p> 211 * vCard versions: 4.0 212 * </p> 213 * @param family the sortable family name (e.g. "Adboville" if the family 214 * name is "d'Aboville") 215 * @param given the sortable given name 216 */ 217 public void setSortAs(String family, String given) { 218 subTypes.setSortAs(family, given); 219 } 220 221 /** 222 * Gets the language the name is written in. 223 * @return the language or null if not set 224 * @see VCardSubTypes#getLanguage 225 */ 226 public String getLanguage() { 227 return subTypes.getLanguage(); 228 } 229 230 /** 231 * Sets the language the name is written in. 232 * @param language the language or null to remove 233 * @see VCardSubTypes#setLanguage 234 */ 235 public void setLanguage(String language) { 236 subTypes.setLanguage(language); 237 } 238 239 /** 240 * Gets the ALTID. 241 * <p> 242 * vCard versions: 4.0 243 * </p> 244 * @return the ALTID or null if it doesn't exist 245 * @see VCardSubTypes#getAltId 246 */ 247 public String getAltId() { 248 return subTypes.getAltId(); 249 } 250 251 /** 252 * Sets the ALTID. 253 * <p> 254 * vCard versions: 4.0 255 * </p> 256 * @param altId the ALTID or null to remove 257 * @see VCardSubTypes#setAltId 258 */ 259 public void setAltId(String altId) { 260 subTypes.setAltId(altId); 261 } 262 263 @Override 264 protected void doMarshalText(StringBuilder value, VCardVersion version, List<String> warnings, CompatibilityMode compatibilityMode) { 265 if (family != null) { 266 value.append(VCardStringUtils.escape(family)); 267 } 268 269 value.append(';'); 270 if (given != null) { 271 value.append(VCardStringUtils.escape(given)); 272 } 273 274 value.append(';'); 275 if (!additional.isEmpty()) { 276 for (String s : additional) { 277 value.append(VCardStringUtils.escape(s)).append(','); 278 } 279 value.deleteCharAt(value.length() - 1); 280 } 281 282 value.append(';'); 283 if (!prefixes.isEmpty()) { 284 for (String s : prefixes) { 285 value.append(VCardStringUtils.escape(s)).append(','); 286 } 287 value.deleteCharAt(value.length() - 1); 288 } 289 290 value.append(';'); 291 if (!suffixes.isEmpty()) { 292 for (String s : suffixes) { 293 value.append(VCardStringUtils.escape(s)).append(','); 294 } 295 value.deleteCharAt(value.length() - 1); 296 } 297 } 298 299 @Override 300 protected void doUnmarshalText(String value, VCardVersion version, List<String> warnings, CompatibilityMode compatibilityMode) { 301 //preserve empty items and don't unescape escaped characters(e.g. "additional" might have escaped commas) 302 String split[] = VCardStringUtils.splitBy(value, ';', false, false); 303 304 int i = 0; 305 306 family = (split.length > i && split[i].length() > 0) ? VCardStringUtils.unescape(split[i]) : null; 307 i++; 308 309 given = (split.length > i && split[i].length() > 0) ? VCardStringUtils.unescape(split[i]) : null; 310 i++; 311 312 if (split.length > i && split[i].length() > 0) { 313 additional = new ArrayList<String>(Arrays.asList(VCardStringUtils.splitBy(split[i], ',', true, true))); 314 } else { 315 additional = new ArrayList<String>(); 316 } 317 i++; 318 319 if (split.length > i && split[i].length() > 0) { 320 prefixes = new ArrayList<String>(Arrays.asList(VCardStringUtils.splitBy(split[i], ',', true, true))); 321 } else { 322 prefixes = new ArrayList<String>(); 323 } 324 i++; 325 326 if (split.length > i && split[i].length() > 0) { 327 suffixes = new ArrayList<String>(Arrays.asList(VCardStringUtils.splitBy(split[i], ',', true, true))); 328 } else { 329 suffixes = new ArrayList<String>(); 330 } 331 i++; 332 } 333 334 @Override 335 protected void doMarshalXml(XCardElement parent, List<String> warnings, CompatibilityMode compatibilityMode) { 336 if (family != null) { 337 parent.append("surname", family); 338 } 339 if (given != null) { 340 parent.append("given", given); 341 } 342 parent.append("additional", additional); 343 parent.append("prefix", prefixes); 344 parent.append("suffix", suffixes); 345 } 346 347 @Override 348 protected void doUnmarshalXml(XCardElement element, List<String> warnings, CompatibilityMode compatibilityMode) { 349 family = element.get("surname"); 350 given = element.get("given"); 351 352 additional.clear(); 353 additional.addAll(element.getAll("additional")); 354 355 prefixes.clear(); 356 prefixes.addAll(element.getAll("prefix")); 357 358 suffixes.clear(); 359 suffixes.addAll(element.getAll("suffix")); 360 } 361 362 @Override 363 protected void doUnmarshalHtml(HCardElement element, List<String> warnings) { 364 family = element.firstValue("family-name"); 365 given = element.firstValue("given-name"); 366 367 additional.clear(); 368 additional.addAll(element.allValues("additional-name")); 369 370 prefixes.clear(); 371 prefixes.addAll(element.allValues("honorific-prefix")); 372 373 suffixes.clear(); 374 suffixes.addAll(element.allValues("honorific-suffix")); 375 } 376 }