001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.wicket.extensions.markup.html.form.palette.component; 018 019import java.util.ArrayList; 020import java.util.Arrays; 021import java.util.Collection; 022import java.util.HashMap; 023import java.util.Iterator; 024import java.util.List; 025import java.util.Map; 026import java.util.Set; 027import java.util.TreeSet; 028 029import org.apache.wicket.WicketRuntimeException; 030import org.apache.wicket.extensions.markup.html.form.palette.Palette; 031import org.apache.wicket.markup.html.form.HiddenField; 032import org.apache.wicket.markup.html.form.IChoiceRenderer; 033import org.apache.wicket.model.Model; 034import org.apache.wicket.util.string.Strings; 035 036 037/** 038 * Component to keep track of selections on the html side. Also used for encoding and decoding those 039 * selections between html and java. 040 * 041 * @param <T> 042 * Type of the palette 043 * 044 * @author Igor Vaynberg ( ivaynberg ) 045 */ 046public class Recorder<T> extends HiddenField<String> 047{ 048 private static final long serialVersionUID = 1L; 049 050 /** parent palette object */ 051 private final Palette<T> palette; 052 053 /** 054 * @param id 055 * component id 056 * @param palette 057 * parent palette object 058 */ 059 public Recorder(final String id, final Palette<T> palette) 060 { 061 super(id, new Model<String>()); 062 063 this.palette = palette; 064 setOutputMarkupId(true); 065 } 066 067 /** 068 * @return parent Palette object 069 */ 070 public Palette<T> getPalette() 071 { 072 return palette; 073 } 074 075 /** 076 * 077 * @see org.apache.wicket.markup.html.form.AbstractTextComponent#onBeforeRender() 078 */ 079 @Override 080 protected void onBeforeRender() 081 { 082 super.onBeforeRender(); 083 084 initIds(); 085 } 086 087 /** 088 * Synchronize the ids in this' model from the palette's model. 089 */ 090 private void initIds() 091 { 092 // construct the model string based on selection collection 093 IChoiceRenderer<? super T> renderer = getPalette().getChoiceRenderer(); 094 StringBuilder modelStringBuffer = new StringBuilder(); 095 Collection<T> modelCollection = getPalette().getModelCollection(); 096 if (modelCollection == null) 097 { 098 throw new WicketRuntimeException( 099 "Expected getPalette().getModelCollection() to return a non-null value." 100 + " Please make sure you have model object assigned to the palette"); 101 } 102 Iterator<T> selection = modelCollection.iterator(); 103 104 int i = 0; 105 while (selection.hasNext()) 106 { 107 modelStringBuffer.append(renderer.getIdValue(selection.next(), i++)); 108 if (selection.hasNext()) 109 { 110 modelStringBuffer.append(','); 111 } 112 } 113 114 // set model and update ids array 115 String modelString = modelStringBuffer.toString(); 116 setModelObject(modelString); 117 } 118 119 /** 120 * Get the selected choices based on the palette's available choices and the current model or 121 * input data entered by the user. 122 * 123 * @return selected choices 124 * 125 * @see #getValue() 126 */ 127 public List<T> getSelectedList() 128 { 129 final IChoiceRenderer<? super T> renderer = getPalette().getChoiceRenderer(); 130 final Collection<? extends T> choices = getPalette().getChoices(); 131 final List<T> selected = new ArrayList<>(choices.size()); 132 133 // reduce number of method calls by building a lookup table 134 final Map<T, String> idForChoice = new HashMap<>(choices.size()); 135 for (final T choice : choices) 136 { 137 idForChoice.put(choice, renderer.getIdValue(choice, 0)); 138 } 139 140 for (final String id : Strings.split(getValue(), ',')) 141 { 142 for (final T choice : choices) 143 { 144 final String idValue = idForChoice.get(choice); 145 if (id.equals(idValue)) // null-safe compare 146 { 147 selected.add(choice); 148 break; 149 } 150 } 151 } 152 153 return selected; 154 } 155 156 /** 157 * Get the unselected choices based on the palette's available choices and the current model or 158 * input data entered by the user. 159 * 160 * @return unselected choices 161 * 162 * @see #getValue() 163 */ 164 public List<T> getUnselectedList() 165 { 166 final IChoiceRenderer<? super T> renderer = getPalette().getChoiceRenderer(); 167 final Collection<? extends T> choices = getPalette().getChoices(); 168 final List<T> unselected = new ArrayList<>(choices.size()); 169 final Set<String> ids = new TreeSet<>(Arrays.asList(Strings.split(getValue(), ','))); 170 171 for (final T choice : choices) 172 { 173 final String choiceId = renderer.getIdValue(choice, 0); 174 175 if (ids.contains(choiceId) == false) 176 { 177 unselected.add(choice); 178 } 179 } 180 181 return unselected; 182 } 183}