1 /* 2 * $Id$ 3 * 4 * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved. 5 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 * 7 * This code is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License version 2 only, as 9 * published by the Free Software Foundation. Oracle designates this 10 * particular file as subject to the "Classpath" exception as provided 11 * by Oracle in the LICENSE file that accompanied this code. 12 * 13 * This code is distributed in the hope that it will be useful, but WITHOUT 14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16 * version 2 for more details (a copy is included in the LICENSE file that 17 * accompanied this code). 18 * 19 * You should have received a copy of the GNU General Public License version 20 * 2 along with this work; if not, write to the Free Software Foundation, 21 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 22 * 23 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 24 * or visit www.oracle.com if you need additional information or have any 25 * questions. 26 */ 27 package com.sun.interview; 28 29 import java.util.Map; 30 import java.util.Vector; 31 32 /** 33 * A {@link Question question} to which the response is an array of strings. 34 */ 35 public abstract class StringListQuestion extends Question 36 { 37 /** 38 * Create a question with a nominated tag. 39 * @param interview The interview containing this question. 40 * @param tag A unique tag to identify this specific question. 41 */ 42 protected StringListQuestion(Interview interview, String tag) { 43 super(interview, tag); 44 clear(); 45 setDefaultValue(value); 46 } 47 48 /** 49 * Get the default response for this question. 50 * @return the default response for this question. 51 * 52 * @see #setDefaultValue 53 * @see #clear 54 */ 55 public String[] getDefaultValue() { 56 return defaultValue; 57 } 58 59 /** 60 * Set the default response for this question, 61 * used by the clear method. 62 * @param v the default response for this question. 63 * 64 * @see #getDefaultValue 65 * @see #clear 66 */ 67 public void setDefaultValue(String[] v) { 68 defaultValue = v; 69 } 70 71 /** 72 * Specify whether or not duplicates should be allowed in the list. 73 * By default, duplicates are allowed. 74 * @param b true if duplicates should be allowed, and false otherwise 75 * @see #isDuplicatesAllowed 76 */ 77 public void setDuplicatesAllowed(boolean b) { 78 duplicatesAllowed = b; 79 } 80 81 /** 82 * Check whether or not duplicates should be allowed in the list. 83 * @return true if duplicates should be allowed, and false otherwise 84 * @see #setDuplicatesAllowed 85 */ 86 public boolean isDuplicatesAllowed() { 87 return duplicatesAllowed; 88 } 89 90 /** 91 * Get the current (default or latest) response to this question. 92 * @return The current value. 93 * 94 * @see #setValue 95 */ 96 public String[] getValue() { 97 return value; 98 } 99 100 /** 101 * Verify this question is on the current path, and if it is, 102 * return the current value. 103 * @return the current value of this question 104 * @throws Interview.NotOnPathFault if this question is not on the 105 * current path 106 * @see #getValue 107 */ 108 public String[] getValueOnPath() 109 throws Interview.NotOnPathFault 110 { 111 interview.verifyPathContains(this); 112 return getValue(); 113 } 114 115 /** 116 * Get the response to this question as a string. 117 * @return a string representing the current response to this question, or null. 118 * @see #setValue(String) 119 */ 120 public String getStringValue() { 121 if (value == null) 122 return null; 123 124 StringBuffer sb = new StringBuffer(); 125 for (int i = 0; i < value.length; i++) { 126 if (sb.length() > 0) 127 sb.append('\n'); 128 if (value[i] != null) 129 sb.append(value[i]); 130 } 131 132 return sb.toString(); 133 } 134 135 public boolean isValueValid() { 136 return true; 137 } 138 139 public boolean isValueAlwaysValid() { 140 return false; 141 } 142 143 public void setValue(String s) { 144 setValue(s == null ? ((String[]) null) : split(s)); 145 } 146 147 /** 148 * Set the current value. 149 * @param newValue The value to be set. 150 * 151 * @see #getValue 152 */ 153 public void setValue(String[] newValue) { 154 if (newValue != null) { 155 for (int i = 0; i < newValue.length; i++) { 156 if (newValue[i] == null || (newValue[i].indexOf("\n") != -1)) 157 throw new IllegalArgumentException(); 158 } 159 } 160 161 if (!equal(newValue, value)) { 162 if (newValue == null) 163 value = null; 164 else { 165 value = new String[newValue.length]; 166 System.arraycopy(newValue, 0, value, 0, newValue.length); 167 } 168 interview.updatePath(this); 169 interview.setEdited(true); 170 } 171 } 172 173 /** 174 * Clear any response to this question, resetting the value 175 * back to its initial state. 176 */ 177 public void clear() { 178 setValue(defaultValue); 179 } 180 181 /** 182 * Load the value for this question from a dictionary, using 183 * the tag as the key. 184 * @param data The map from which to load the value for this question. 185 */ 186 protected void load(Map<String, String> data) { 187 String o = data.get(tag); 188 setValue(o); 189 } 190 191 /** 192 * Save the value for this question in a dictionary, using 193 * the tag as the key. 194 * @param data The map in which to save the value for this question. 195 */ 196 protected void save(Map<String, String> data) { 197 if (value != null) 198 data.put(tag, getStringValue()); 199 } 200 201 /** 202 * Compare two string arrays for equality. 203 * @param s1 the first array to be compared, or null 204 * @param s2 the other array to be compared, or null 205 * @return true if both parameters are null, or if both are non-null 206 * and are element-wise equal. 207 * @see #equal(String, String) 208 */ 209 protected static boolean equal(String[] s1, String[] s2) { 210 if (s1 == null || s2 == null) 211 return (s1 == s2); 212 213 if (s1.length != s2.length) 214 return false; 215 216 for (int i = 0; i < s1.length; i++) { 217 if (!equal(s1[i], s2[i])) 218 return false; 219 } 220 221 return true; 222 } 223 224 225 /** 226 * Compare two strings for equality. 227 * @param s1 the first string to be compared, or null 228 * @param s2 the other string to be compared, or null 229 * @return true if both parameters are null, or if both are non-null 230 * and equal. 231 */ 232 protected static boolean equal(String s1, String s2) { 233 return (s1 == null ? s2 == null : s1.equals(s2)); 234 } 235 236 /** 237 * Split a string into a set of newline-separated strings. 238 * @param s The string to be split, or null 239 * @return an array of strings containing the newline-separated substrings of 240 * the argument. 241 */ 242 protected static String[] split(String s) { 243 if (s == null) 244 return empty; 245 246 final char sep = '\n'; 247 248 Vector<String> v = new Vector<>(); 249 int start = -1; 250 for (int i = 0; i < s.length(); i++) { 251 if (s.charAt(i) == sep) { 252 if (start != -1) 253 v.addElement(s.substring(start, i)); 254 start = -1; 255 } else 256 if (start == -1) 257 start = i; 258 } 259 if (start != -1) 260 v.addElement(s.substring(start)); 261 if (v.size() == 0) 262 return empty; 263 String[] a = new String[v.size()]; 264 v.copyInto(a); 265 return a; 266 } 267 268 private static final String[] empty = { }; 269 270 /** 271 * The current response for this question. 272 */ 273 protected String[] value; 274 275 /** 276 * The default response for this question. 277 */ 278 private String[] defaultValue; 279 280 private boolean duplicatesAllowed = true; 281 }