/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.wicket.extensions.markup.html.form.palette.component;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import org.apache.wicket.WicketRuntimeException;
import org.apache.wicket.extensions.markup.html.form.palette.Palette;
import org.apache.wicket.markup.html.form.HiddenField;
import org.apache.wicket.markup.html.form.IChoiceRenderer;
import org.apache.wicket.model.Model;
import org.apache.wicket.util.string.Strings;
/**
* Component to keep track of selections on the html side. Also used for encoding and decoding those
* selections between html and java.
*
* @param <T>
* Type of the palette
*
* @author Igor Vaynberg ( ivaynberg )
*/
public class Recorder<T> extends HiddenField<String>
{
private static final long serialVersionUID = 1L;
/** parent palette object */
private final Palette<T> palette;
/**
* @param id
* component id
* @param palette
* parent palette object
*/
public Recorder(final String id, final Palette<T> palette)
{
super(id, new Model<String>());
this.palette = palette;
setOutputMarkupId(true);
}
/**
* @return parent Palette object
*/
public Palette<T> getPalette()
{
return palette;
}
/**
*
* @see org.apache.wicket.markup.html.form.AbstractTextComponent#onBeforeRender()
*/
@Override
protected void onBeforeRender()
{
super.onBeforeRender();
initIds();
}
/**
* Synchronize the ids in this' model from the palette's model.
*/
private void initIds()
{
// construct the model string based on selection collection
IChoiceRenderer<? super T> renderer = getPalette().getChoiceRenderer();
StringBuilder modelStringBuffer = new StringBuilder();
Collection<T> modelCollection = getPalette().getModelCollection();
if (modelCollection == null)
{
throw new WicketRuntimeException(
"Expected getPalette().getModelCollection() to return a non-null value."
+ " Please make sure you have model object assigned to the palette");
}
Iterator<T> selection = modelCollection.iterator();
int i = 0;
while (selection.hasNext())
{
modelStringBuffer.append(renderer.getIdValue(selection.next(), i++));
if (selection.hasNext())
{
modelStringBuffer.append(',');
}
}
// set model and update ids array
String modelString = modelStringBuffer.toString();
setModelObject(modelString);
}
/**
* Get the selected choices based on the palette's available choices and the current model or
* input data entered by the user.
*
* @return selected choices
*
* @see #getValue()
*/
public List<T> getSelectedList()
{
final IChoiceRenderer<? super T> renderer = getPalette().getChoiceRenderer();
final Collection<? extends T> choices = getPalette().getChoices();
final List<T> selected = new ArrayList<>(choices.size());
// reduce number of method calls by building a lookup table
final Map<T, String> idForChoice = new HashMap<>(choices.size());
for (final T choice : choices)
{
idForChoice.put(choice, renderer.getIdValue(choice, 0));
}
for (final String id : Strings.split(getValue(), ','))
{
for (final T choice : choices)
{
final String idValue = idForChoice.get(choice);
if (id.equals(idValue)) // null-safe compare
{
selected.add(choice);
break;
}
}
}
return selected;
}
/**
* Get the unselected choices based on the palette's available choices and the current model or
* input data entered by the user.
*
* @return unselected choices
*
* @see #getValue()
*/
public List<T> getUnselectedList()
{
final IChoiceRenderer<? super T> renderer = getPalette().getChoiceRenderer();
final Collection<? extends T> choices = getPalette().getChoices();
final List<T> unselected = new ArrayList<>(choices.size());
final Set<String> ids = new TreeSet<>(Arrays.asList(Strings.split(getValue(), ',')));
for (final T choice : choices)
{
final String choiceId = renderer.getIdValue(choice, 0);
if (ids.contains(choiceId) == false)
{
unselected.add(choice);
}
}
return unselected;
}
}