/* * GeneralChooserFacadeBase.java * Copyright James Dempsey, 2012 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Created on 06/01/2012 9:23:01 AM * * $Id$ */ package pcgen.core.chooser; import java.util.ArrayList; import java.util.List; import org.apache.commons.lang3.StringUtils; import pcgen.base.lang.StringUtil; import pcgen.cdom.base.CDOMObject; import pcgen.cdom.enumeration.ListKey; import pcgen.cdom.enumeration.ObjectKey; import pcgen.cdom.enumeration.SourceFormat; import pcgen.cdom.enumeration.Type; import pcgen.core.Globals; import pcgen.core.PObject; import pcgen.facade.core.ChooserFacade; import pcgen.facade.util.DefaultReferenceFacade; import pcgen.facade.core.InfoFacade; import pcgen.facade.core.InfoFactory; import pcgen.facade.util.ReferenceFacade; import pcgen.facade.util.DefaultListFacade; import pcgen.facade.util.ListFacade; import pcgen.system.LanguageBundle; /** * The Class {@code GeneraChooserFacadeBase} is a base from which a * ChooserFacade may be simply implemented. The implementing class need only call * the constructor and implement the commit to process the selections. * * @param <T> The type of objects being chosen from. * * <br> * * @author James Dempsey <jdempsey@users.sourceforge.net> */ public class CDOMChooserFacadeImpl<T> implements ChooserFacade { private final String name; private final List<T> origAvailable; private final List<? extends T> origSelected; private final int maxNewSelections; private final List<T> finalSelected; private DefaultListFacade<InfoFacade> availableList; private DefaultListFacade<InfoFacade> selectedList; private DefaultReferenceFacade<Integer> numSelectionsRemain; private final String availableTableTypeNameTitle; private final String selectedTableTitle; private final String selectionCountName; private final String addButtonName; private final String removeButtonName; private final String availableTableTitle; private ChooserTreeViewType defaultView = ChooserTreeViewType.TYPE_NAME; private boolean dupsAllowed = false; private boolean requireCompleteSelection; private boolean preferRadioSelection = false; private boolean userInput = false; private final String stringDelimiter; private boolean infoAvailable = false; private InfoFactory infoFactory = null; /** * Create a new instance of GeneraChooserFacadeBase with default localised * text for the chooser. Note none of the supplied lists will be directly * modified. * * @param name The title of the chooser. * @param available The list of items to select from. * @param selected The list of items already selected. The user may choose to deselect items from this list. * @param maxNewSelections The number of selections the user may make in addition to those in the selected list. */ public CDOMChooserFacadeImpl(String name, List<T> available, List<? extends T> selected, int maxNewSelections) { this(name, available, selected, maxNewSelections, LanguageBundle.getString("in_available"), //$NON-NLS-1$ LanguageBundle.getString("in_typeName"), //$NON-NLS-1$ LanguageBundle.getString("in_selected"), //$NON-NLS-1$ LanguageBundle.getString("in_selRemain"), //$NON-NLS-1$ LanguageBundle.getString("in_add"), //$NON-NLS-1$ LanguageBundle.getString("in_remove"), null); //$NON-NLS-1$ } /** * Create a new instance of GeneraChooserFacadeBase with default localised * text for the chooser. Note none of the supplied lists will be directly * modified. * * @param name The title of the chooser. * @param available The list of items to select from. * @param selected The list of items already selected. The user may choose to deselect items from this list. * @param maxNewSelections The number of selections the user may make in addition to those in the selected list. * @param stringDelimiter A string used to split the user viewable part of a string option from the full string. */ public CDOMChooserFacadeImpl(String name, List<T> available, List<? extends T> selected, int maxNewSelections, String stringDelimiter) { this(name, available, selected, maxNewSelections, LanguageBundle.getString("in_available"), //$NON-NLS-1$ LanguageBundle.getString("in_typeName"), //$NON-NLS-1$ LanguageBundle.getString("in_selected"), //$NON-NLS-1$ LanguageBundle.getString("in_selRemain"), //$NON-NLS-1$ LanguageBundle.getString("in_add"), //$NON-NLS-1$ LanguageBundle.getString("in_remove"), stringDelimiter); //$NON-NLS-1$ } /** * Create a new instance of GeneraChooserFacadeBase with supplied text for * the chooser. Note none of the supplied lists will be directly modified. * @param name The title of the chooser. * @param available The list of items to select from. * @param selected The list of items already selected. The user may choose to deselect items from this list. * @param maxNewSelections The number of selections the user may make in addition to those in the selected list. * @param availableTableTitle The title for the available list in flat mode. * @param availableTableTypeNameTitle The title for the available list in tree mode. * @param selectedTableTitle The title for the selected list. * @param selectionCountName The label for the number of selections remaining. * @param addButtonName The label for the add button. * @param removeButtonName The label for the remove button. * @param stringDelimiter A string used to split the user viewable part of a string option from the full string. */ public CDOMChooserFacadeImpl(String name, List<T> available, List<? extends T> selected, int maxNewSelections, String availableTableTitle, String availableTableTypeNameTitle, String selectedTableTitle, String selectionCountName, String addButtonName, String removeButtonName, String stringDelimiter) { this.name = name; this.origAvailable = available; this.origSelected = selected; this.maxNewSelections = maxNewSelections; this.availableTableTitle = availableTableTitle; this.availableTableTypeNameTitle = availableTableTypeNameTitle; this.selectedTableTitle = selectedTableTitle; this.selectionCountName = selectionCountName; this.addButtonName = addButtonName; this.removeButtonName = removeButtonName; this.stringDelimiter = stringDelimiter; // Build working content availableList = new DefaultListFacade<>(createInfoFacadeList(origAvailable, stringDelimiter)); selectedList = new DefaultListFacade<>(createInfoFacadeList(origSelected, stringDelimiter)); numSelectionsRemain = new DefaultReferenceFacade<>(maxNewSelections); finalSelected = new ArrayList<>(origSelected); } private List<InfoFacade> createInfoFacadeList(List<? extends T> origAvailable2, String stringDelimiter) { List<InfoFacade> infoFacadeList = new ArrayList<>(origAvailable2.size()); for (T object : origAvailable2) { if (object instanceof InfoFacade) { infoFacadeList.add((InfoFacade) object); infoAvailable = true; } else if (object instanceof CDOMObject) { CDOMInfoWrapper wrapper = new CDOMInfoWrapper((CDOMObject) object); infoFacadeList.add(wrapper); } else if (!StringUtils.isEmpty(stringDelimiter) && (object instanceof String)) { DelimitedStringInfoWrapper wrapper = new DelimitedStringInfoWrapper((String) object, stringDelimiter); infoFacadeList.add(wrapper); } else { InfoWrapper wrapper = new InfoWrapper(object); infoFacadeList.add(wrapper); } } return infoFacadeList; } @Override public final ListFacade<InfoFacade> getAvailableList() { return availableList; } @Override public final ListFacade<InfoFacade> getSelectedList() { return selectedList; } @Override public final void addSelected(InfoFacade item) { if (numSelectionsRemain.get() <= 0) { return; } selectedList.addElement(item); if (!dupsAllowed) { availableList.removeElement(item); } numSelectionsRemain.set(numSelectionsRemain.get()-1); } @Override public final void removeSelected(InfoFacade item) { selectedList.removeElement(item); if (!dupsAllowed) { availableList.addElement(item); } numSelectionsRemain.set(numSelectionsRemain.get()+1); } @Override public ReferenceFacade<Integer> getRemainingSelections() { return numSelectionsRemain; } @Override public void commit() { finalSelected.clear(); for (InfoFacade object : selectedList) { T selected; if (object instanceof CDOMChooserFacadeImpl.CDOMInfoWrapper) { selected = (T) ((CDOMChooserFacadeImpl.CDOMInfoWrapper) object).getCdomObj(); } else if (object instanceof InfoWrapper) { selected = (T) ((InfoWrapper) object).getObj(); } else { selected = (T) object; } finalSelected.add(selected); } } @Override public final void rollback() { availableList.setContents(createInfoFacadeList(origAvailable, stringDelimiter)); selectedList.setContents(createInfoFacadeList(origSelected, stringDelimiter)); numSelectionsRemain.set(maxNewSelections); finalSelected.clear(); finalSelected.addAll(origSelected); } @Override public final String getName() { return name; } @Override public String getAvailableTableTypeNameTitle() { return availableTableTypeNameTitle; } @Override public String getAvailableTableTitle() { return availableTableTitle; } @Override public String getSelectedTableTitle() { return selectedTableTitle; } @Override public String getAddButtonName() { return addButtonName; } @Override public String getRemoveButtonName() { return removeButtonName; } @Override public String getSelectionCountName() { return selectionCountName; } @Override public List<String> getBranchNames(InfoFacade item) { List<String> branches = new ArrayList<>(); if (item instanceof PObject) { PObject pObject = (PObject) item; for (Type type : pObject.getTrueTypeList(true)) { branches.add(type.toString()); } } return branches; } @Override public ChooserTreeViewType getDefaultView() { return defaultView; } /** * @param defaultView the flatDefault to set */ public void setDefaultView(ChooserTreeViewType defaultView) { this.defaultView = defaultView; } /** * @return the finalSelected */ public List<T> getFinalSelected() { return finalSelected; } /** * @param dupsAllowed Should the chooser allow an entry to be selected multiple times. */ public void setAllowsDups(boolean dupsAllowed) { this.dupsAllowed = dupsAllowed; } /** * Identify if the user must use up all remaining selections before closing the chooser. * @param requireCompleteSelection the requireCompleteSelection to set */ public void setRequireCompleteSelection(boolean requireCompleteSelection) { this.requireCompleteSelection = requireCompleteSelection; } @Override public boolean isRequireCompleteSelection() { return requireCompleteSelection; } /** * @param preferRadioSelection Should this choice be displayed using radio buttons? */ public void setPreferRadioSelection(boolean preferRadioSelection) { this.preferRadioSelection = preferRadioSelection; } @Override public boolean isPreferRadioSelection() { return preferRadioSelection; } public boolean isUserInput() { return userInput; } public void setUserInput(boolean userInput) { this.userInput = userInput; } @Override public boolean isInfoAvailable() { return infoAvailable; } /** * @return the infoFactory */ public InfoFactory getInfoFactory() { return infoFactory; } /** * @param infoFactory the infoFactory to set */ public void setInfoFactory(InfoFactory infoFactory) { this.infoFactory = infoFactory; } private class CDOMInfoWrapper implements InfoFacade { private final CDOMObject cdomObj; public CDOMInfoWrapper(CDOMObject cdomObj) { this.cdomObj = cdomObj; } @Override public String toString() { return String.valueOf(cdomObj); } @Override public String getSource() { return SourceFormat.getFormattedString(cdomObj, Globals.getSourceDisplay(), true); } @Override public String getSourceForNodeDisplay() { return SourceFormat.getFormattedString(cdomObj, SourceFormat.LONG, false); } @Override public String getKeyName() { return cdomObj.getKeyName(); } @Override public boolean isNamePI() { return cdomObj.getSafe(ObjectKey.NAME_PI); } /** * @return the cdomObj */ public CDOMObject getCdomObj() { return cdomObj; } @Override public String getType() { final List<Type> types = cdomObj.getSafeListFor(ListKey.TYPE); return StringUtil.join(types, "."); } } private class DelimitedStringInfoWrapper implements InfoFacade { private final String string; private final String delimiter; public DelimitedStringInfoWrapper(String string, String delimiter) { this.string = string; this.delimiter = StringUtils.trimToNull(delimiter); } @Override public String toString() { if (delimiter != null) { final int idx = string.indexOf(delimiter); if (idx > -1) { return string.substring(0, idx); } } return string; } @Override public String getSource() { return ""; } @Override public String getSourceForNodeDisplay() { return ""; } @Override public String getKeyName() { return string; } @Override public boolean isNamePI() { return false; } @Override public String getType() { return ""; } } }