package org.nocket.gen.page.visitor.bind.builder.components;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.collections.CollectionUtils;
import org.apache.wicket.Component;
import org.apache.wicket.behavior.Behavior;
import org.apache.wicket.markup.ComponentTag;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.markup.repeater.RepeatingView;
import org.apache.wicket.model.IModel;
import org.nocket.gen.page.element.RepeatingPanelElement;
import org.nocket.page.DMDPanelFactory;
@SuppressWarnings("serial")
public class GeneratedRepeatingPanel extends RepeatingView {
private Collection lastState = null;
public GeneratedRepeatingPanel(RepeatingPanelElement e) {
super(e.getWicketId(), e.getModel());
}
public GeneratedRepeatingPanel(String id) {
super(id);
}
public GeneratedRepeatingPanel(String id, IModel<?> model) {
super(id, model);
}
public Collection<?> collectionAuspacken(Object defaultModel) {
if (defaultModel instanceof Collection) {
return (Collection<?>) defaultModel;
} else if (defaultModel == null) {
return null;
} else if (defaultModel instanceof IModel) {
return collectionAuspacken(((IModel<?>) defaultModel).getObject());
}
return null;
}
@SuppressWarnings({ "rawtypes", "unchecked" })
protected void onBeforeRender() {
/*
* FIXME: vocke03 Das hier ist nur ein Quickfix für DER-Touristik
* (DMDVIER-210), der dafür sorgt, dass beim Rendern von
* GeneratedRepeatingPanels immer jeder bisherige Inhalt weggeworfen
* wird (removeAll()) und danach der korrekt Inhalt neu hinzugefügt
* wird. Vorher hatte die Abfrage von hasBeenRendered() verhindert, dass
* GeneratedRepeatingPanels neu gerendert wurden, sobald in ihren
* Children irgendwo Elemente in einer List-Property hinzugefügt oder
* entfernt wurden (siehe auch test.dmdweb.tests.gen.listviews.OuterView
* als Testfall). Problematisch an dieser Lösung ist, dass jetzt _immer_
* removeAll() aufgerufen und neu gerendert wird, obwohl es in den
* meisten Fällen überhaupt nicht notwendig ist.
*
* Eine Behebung des Problems könnte so aussehen, dass sich im Rahmen
* dieses GeneratedRepeatingPanels der Status der Children in Form eines
* HashCodes gemerkt werden, und beim nächsten Aufruf von onBeforeRender
* geprüft wird, ob sich dieser Status geändert hat und in diesem Fall
* ein removeAll() ausgeführt und das erneute Rendering angestoßen wird.
*/
// removeAll();
//if(!hasBeenRendered()) {
Collection<?> collection = collectionAuspacken(getDefaultModel());
List<Component> listWithNewModels = new ArrayList<Component>();
List<Component> existingModels = new ArrayList<Component>();
for (Iterator<Component> iterator = iterator(); iterator.hasNext();) {
Component component = iterator.next();
if (isRemoved(component, collection)) {
iterator.remove();
continue;
} else {
existingModels.add(component);
}
}
addNewObjects(existingModels, collection);
lastState = collection;
super.onBeforeRender();
}
private void addNewObjects(List<Component> existingComponents, Collection<?> collection) {
Collection existingModelObjects = new ArrayList(existingComponents.size());
for (Component component : existingComponents) {
existingModelObjects.add(component.getDefaultModelObject());
}
Collection subtract = CollectionUtils.subtract(collection, existingModelObjects);
ArrayList items = new ArrayList(subtract);
for (int i = 0; i < items.size(); i++) {
Object view = items.get(i);
// Wenn die Liste ein Nullelement liefert, ist es das Problem des Lieferanten der Liste.
// Also wird das Element kommentarlos übergangen.
if (view != null) {
Panel panel = DMDPanelFactory.getViewPanelInstance(view, newChildId());
panel.add(new Behavior() {
@Override
public void onComponentTag(Component component, ComponentTag tag) {
// Hiermit wird der Tag-Name des Parents geändert. Ziel ist es das <ul> in ein <div> zu verändern, so dass wir nicht dem ul-CSS unterliegen. Warum Wicket das aber bei dem Panel macht, weiß nur Wicket!
tag.setName("div");
super.onComponentTag(component, tag);
}
});
add(panel);
}
}
}
private boolean isRemoved(Component component, Collection<?> collection) {
Object modelObject = component.getDefaultModelObject();
for (Object object : collection) {
if (modelObject != null && modelObject.equals(object)) {
return false;
}
}
return true;
}
private boolean isNew() {
// TODO Auto-generated method stub
return false;
}
}