1 16 package org.apache.cocoon.forms.formmodel; 17 18 import java.util.ArrayList ; 19 import java.util.Iterator ; 20 import java.util.List ; 21 import java.util.Locale ; 22 23 import org.apache.cocoon.forms.FormsConstants; 24 import org.apache.cocoon.forms.FormContext; 25 import org.apache.cocoon.forms.util.I18nMessage; 26 import org.apache.cocoon.forms.event.WidgetEvent; 27 import org.apache.cocoon.forms.validation.ValidationError; 28 import org.apache.cocoon.forms.validation.ValidationErrorAware; 29 import org.apache.cocoon.xml.AttributesImpl; 30 import org.apache.cocoon.xml.XMLUtils; 31 import org.xml.sax.ContentHandler ; 32 import org.xml.sax.SAXException ; 33 34 47 public class Repeater extends AbstractWidget 48 implements ValidationErrorAware { 49 50 private static final String REPEATER_EL = "repeater"; 51 private static final String HEADINGS_EL = "headings"; 52 private static final String HEADING_EL = "heading"; 53 private static final String LABEL_EL = "label"; 54 private static final String REPEATER_SIZE_EL = "repeater-size"; 55 56 private final RepeaterDefinition definition; 57 private final List rows = new ArrayList (); 58 protected ValidationError validationError; 59 60 61 public Repeater(RepeaterDefinition repeaterDefinition) { 62 super(repeaterDefinition); 63 this.definition = repeaterDefinition; 64 for (int i = 0; i < this.definition.getInitialSize(); i++) { 67 rows.add(new RepeaterRow(definition)); 68 } 69 } 70 71 public WidgetDefinition getDefinition() { 72 return definition; 73 } 74 75 public void initialize() { 76 for (int i = 0; i < this.rows.size(); i++) { 77 ((RepeaterRow)rows.get(i)).initialize(); 78 } 79 super.initialize(); 80 } 81 82 public int getSize() { 83 return rows.size(); 84 } 85 86 public int getMinSize() { 87 return this.definition.getMinSize(); 88 } 89 90 public int getMaxSize() { 91 return this.definition.getMaxSize(); 92 } 93 94 public RepeaterRow addRow() { 95 RepeaterRow repeaterRow = new RepeaterRow(definition); 96 rows.add(repeaterRow); 97 repeaterRow.initialize(); 98 getForm().addWidgetUpdate(this); 99 return repeaterRow; 100 } 101 102 public RepeaterRow addRow(int index) { 103 RepeaterRow repeaterRow = new RepeaterRow(definition); 104 if (index >= this.rows.size()) { 105 rows.add(repeaterRow); 106 } else { 107 rows.add(index, repeaterRow); 108 } 109 repeaterRow.initialize(); 110 getForm().addWidgetUpdate(this); 111 return repeaterRow; 112 } 113 114 public RepeaterRow getRow(int index) { 115 return (RepeaterRow)rows.get(index); 116 } 117 118 125 public Widget getChild(String id) { 126 int rowIndex; 127 try { 128 rowIndex = Integer.parseInt(id); 129 } catch (NumberFormatException nfe) { 130 return null; 132 } 133 134 if (rowIndex < 0 || rowIndex >= getSize()) { 135 return null; 136 } 137 138 return getRow(rowIndex); 139 } 140 141 147 public static RepeaterRow getParentRow(Widget widget) { 148 Widget result = widget; 149 while(result != null && ! (result instanceof Repeater.RepeaterRow)) { 150 result = result.getParent(); 151 } 152 153 if (result == null) { 154 throw new RuntimeException ("Could not find a parent row for widget " + widget); 155 156 } 157 return (Repeater.RepeaterRow)result; 158 } 159 160 165 public int indexOf(RepeaterRow row) { 166 return this.rows.indexOf(row); 167 } 168 169 172 public void removeRow(int index) { 173 rows.remove(index); 174 getForm().addWidgetUpdate(this); 175 } 176 177 182 public void moveRow(int from, int to) { 183 int size = this.rows.size(); 184 185 if (from < 0 || from >= size || to < 0 || to > size) { 186 throw new IllegalArgumentException ("Cannot move from " + from + " to " + to + 187 " on repeater with " + size + " rows"); 188 } 189 190 if (from == to) { 191 return; 192 } 193 194 Object fromRow = this.rows.remove(from); 195 if (to == size) { 196 this.rows.add(fromRow); 198 199 } else if (to > from) { 200 this.rows.add(to - 1, fromRow); 202 203 } else { 204 this.rows.add(to, fromRow); 205 } 206 207 getForm().addWidgetUpdate(this); 208 } 209 210 public void moveRowLeft(int index) { 211 if (index == 0 || index >= this.rows.size()) { 212 } else { 214 Object temp = this.rows.get(index-1); 215 this.rows.set(index-1, this.rows.get(index)); 216 this.rows.set(index, temp); 217 } 218 getForm().addWidgetUpdate(this); 219 } 220 221 public void moveRowRight(int index) { 222 if (index < 0 || index >= this.rows.size() - 1) { 223 } else { 225 Object temp = this.rows.get(index+1); 226 this.rows.set(index+1, this.rows.get(index)); 227 this.rows.set(index, temp); 228 } 229 getForm().addWidgetUpdate(this); 230 } 231 232 236 public void removeRows() { 237 clear(); 238 getForm().addWidgetUpdate(this); 239 } 240 241 244 public void clear() { 245 rows.clear(); 246 247 for (int i = 0; i < this.definition.getInitialSize(); i++) { 249 addRow(); 250 } 251 getForm().addWidgetUpdate(this); 252 } 253 254 260 public Widget getWidget(int rowIndex, String id) { 261 RepeaterRow row = (RepeaterRow)rows.get(rowIndex); 262 return row.getChild(id); 263 } 264 265 public void readFromRequest(FormContext formContext) { 266 if (!getCombinedState().isAcceptingInputs()) 267 return; 268 269 String sizeParameter = formContext.getRequest().getParameter(getRequestParameterName() + ".size"); 271 if (sizeParameter != null) { 272 int size = 0; 273 try { 274 size = Integer.parseInt(sizeParameter); 275 } catch (NumberFormatException exc) { 276 } 278 279 if (size > 500) 282 throw new RuntimeException ("Client is not allowed to specify a repeater size larger than 500."); 283 284 int currentSize = getSize(); 285 if (currentSize < size) { 286 for (int i = currentSize; i < size; i++) { 287 addRow(); 288 } 289 } else if (currentSize > size) { 290 for (int i = currentSize - 1; i >= size; i--) { 291 removeRow(i); 292 } 293 } 294 } 295 296 Iterator rowIt = rows.iterator(); 298 while (rowIt.hasNext()) { 299 RepeaterRow row = (RepeaterRow)rowIt.next(); 300 row.readFromRequest(formContext); 301 } 302 } 303 304 307 public boolean validate() { 308 if (!getCombinedState().isValidatingValues()) { 309 this.wasValid = true; 310 return true; 311 } 312 313 boolean valid = true; 314 Iterator rowIt = rows.iterator(); 315 while (rowIt.hasNext()) { 316 RepeaterRow row = (RepeaterRow)rowIt.next(); 317 valid = valid & row.validate(); 318 } 319 320 if (rows.size() > getMaxSize() || rows.size() < getMinSize()) { 321 String [] boundaries = new String [2]; 322 boundaries[0] = String.valueOf(getMinSize()); 323 boundaries[1] = String.valueOf(getMaxSize()); 324 this.validationError = new ValidationError(new I18nMessage("repeater.cardinality", boundaries, FormsConstants.I18N_CATALOGUE)); 325 valid=false; 326 } 327 328 329 if (valid) { 330 valid = super.validate(); 331 } 332 333 this.wasValid = valid && this.validationError == null; 334 return this.wasValid; 335 } 336 337 338 339 342 public String getXMLElementName() { 343 return REPEATER_EL; 344 } 345 346 347 348 351 public AttributesImpl getXMLElementAttributes() { 352 AttributesImpl attrs = super.getXMLElementAttributes(); 353 attrs.addCDATAAttribute("size", String.valueOf(getSize())); 354 int size = getMinSize(); 356 if (size > 0) { 357 attrs.addCDATAAttribute("min-size", String.valueOf(size)); 358 } 359 size = getMaxSize(); 360 if (size != Integer.MAX_VALUE) { 361 attrs.addCDATAAttribute("max-size", String.valueOf(size)); 362 } 363 return attrs; 364 } 365 366 367 public void generateDisplayData(ContentHandler contentHandler) 368 throws SAXException { 369 contentHandler.startElement(FormsConstants.INSTANCE_NS, LABEL_EL, FormsConstants.INSTANCE_PREFIX_COLON + LABEL_EL, XMLUtils.EMPTY_ATTRIBUTES); 371 generateLabel(contentHandler); 372 contentHandler.endElement(FormsConstants.INSTANCE_NS, LABEL_EL, FormsConstants.INSTANCE_PREFIX_COLON + LABEL_EL); 373 374 contentHandler.startElement(FormsConstants.INSTANCE_NS, HEADINGS_EL, FormsConstants.INSTANCE_PREFIX_COLON + HEADINGS_EL, XMLUtils.EMPTY_ATTRIBUTES); 376 Iterator widgetDefinitionIt = definition.getWidgetDefinitions().iterator(); 377 while (widgetDefinitionIt.hasNext()) { 378 WidgetDefinition widgetDefinition = (WidgetDefinition)widgetDefinitionIt.next(); 379 contentHandler.startElement(FormsConstants.INSTANCE_NS, HEADING_EL, FormsConstants.INSTANCE_PREFIX_COLON + HEADING_EL, XMLUtils.EMPTY_ATTRIBUTES); 380 widgetDefinition.generateLabel(contentHandler); 381 contentHandler.endElement(FormsConstants.INSTANCE_NS, HEADING_EL, FormsConstants.INSTANCE_PREFIX_COLON + HEADING_EL); 382 } 383 contentHandler.endElement(FormsConstants.INSTANCE_NS, HEADINGS_EL, FormsConstants.INSTANCE_PREFIX_COLON + HEADINGS_EL); 384 } 385 386 387 public void generateItemSaxFragment(ContentHandler contentHandler, Locale locale) throws SAXException { 388 Iterator rowIt = rows.iterator(); 390 while (rowIt.hasNext()) { 391 RepeaterRow row = (RepeaterRow)rowIt.next(); 392 row.generateSaxFragment(contentHandler, locale); 393 } 394 } 395 396 399 public void generateWidgetLabel(String widgetId, ContentHandler contentHandler) throws SAXException { 400 WidgetDefinition widgetDefinition = definition.getWidgetDefinition(widgetId); 401 if (widgetDefinition == null) 402 throw new SAXException ("Repeater \"" + getRequestParameterName() + "\" at " + this.getLocation() 403 + " contains no widget with id \"" + widgetId + "\"."); 404 widgetDefinition.generateLabel(contentHandler); 405 } 406 407 410 public void generateSize(ContentHandler contentHandler) throws SAXException { 411 AttributesImpl attrs = getXMLElementAttributes(); 412 contentHandler.startElement(FormsConstants.INSTANCE_NS, REPEATER_SIZE_EL, FormsConstants.INSTANCE_PREFIX_COLON + REPEATER_SIZE_EL, attrs); 413 contentHandler.endElement(FormsConstants.INSTANCE_NS, REPEATER_SIZE_EL, FormsConstants.INSTANCE_PREFIX_COLON + REPEATER_SIZE_EL); 414 } 415 416 422 public ValidationError getValidationError() { 423 return this.validationError; 424 } 425 426 429 public void setValidationError(ValidationError error) { 430 this.validationError = error; 431 } 432 433 public class RepeaterRow extends AbstractContainerWidget { 434 435 private static final String ROW_EL = "repeater-row"; 436 437 public RepeaterRow(RepeaterDefinition definition) { 438 super(definition); 439 setParent(Repeater.this); 440 definition.createWidgets(this); 441 } 442 443 public WidgetDefinition getDefinition() { 444 return Repeater.this.definition; 445 } 446 447 private int cachedPosition = -100; 448 private String cachedId = "--undefined--"; 449 450 public String getId() { 451 int pos = rows.indexOf(this); 452 if (pos == -1) { 453 throw new IllegalStateException ("Row has currently no position"); 454 } 455 if (pos != this.cachedPosition) { 456 this.cachedPosition = pos; 457 this.cachedId = String.valueOf(pos); 459 widgetNameChanged(); 460 } 461 return this.cachedId; 462 } 463 464 public String getRequestParameterName() { 465 getId(); 467 468 return super.getRequestParameterName(); 469 } 470 471 public Form getForm() { 472 return Repeater.this.getForm(); 473 } 474 475 public void initialize() { 476 Iterator it = this.getChildren(); 480 while(it.hasNext()) { 481 ((Widget)it.next()).initialize(); 482 } 483 } 484 485 public boolean validate() { 486 return widgets.validate(); 488 } 489 490 493 public String getXMLElementName() { 494 return ROW_EL; 495 } 496 497 public void generateLabel(ContentHandler contentHandler) throws SAXException { 498 } 500 501 public void generateDisplayData(ContentHandler contentHandler) 502 throws SAXException { 503 } 505 506 public void broadcastEvent(WidgetEvent event) { 507 throw new UnsupportedOperationException ("Widget " + this.getRequestParameterName() + " doesn't handle events."); 508 } 509 } 510 511 } 512 | Popular Tags |