/* * Copyright 2002-2010 the original author or authors. * * Licensed 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.jdal.swing; import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.Iterator; import java.util.List; import javax.annotation.PostConstruct; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.Box; import javax.swing.Icon; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JList; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextField; import javax.swing.event.EventListenerList; import org.jdal.swing.form.BoxFormBuilder; import org.jdal.swing.form.FormUtils; import org.jdal.swing.list.ListListModel; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.MessageSource; import org.springframework.context.support.MessageSourceAccessor; import org.springframework.context.support.ResourceBundleMessageSource; /** * A Twing List editor. * * @author Jose Luis Martin - (jlm@joseluismartin.info) */ public class Selector<T> extends JPanel { private String name; /** available list items */ private ListListModel<T> available = new ListListModel<T>(); /** selected list items */ private ListListModel<T> selected = new ListListModel<T>(); /** all items */ private List<T> all = new ArrayList<T>(); private JList<T> availableList; private JList<T> selectedList; private JTextField availableSearch = new JTextField(); private JTextField selectedSearch = new JTextField(); private Icon rightArrow = FormUtils.getIcon("images/button_right.png"); private Icon leftArrow = FormUtils.getIcon("images/button_left.png"); /** A list of event listeners for this component. */ protected EventListenerList listenerList = new EventListenerList(); protected boolean firingActionEvent = false; @Autowired private MessageSource messageSource; private int buttonWidth = 30; private int buttonHeight = 30; private int listWidth = 300; private int listheight = 100; private boolean showSearchFields = false; private Comparator<T> comparator; public Selector() { } public Selector(List<T> all) { this(all, new ArrayList<T>()); this.all = all; } public Selector(List<T> available, List<T> selected) { this.available.addAll(available); this.selected.addAll(selected); all.addAll(available); all.addAll(selected); } /** * Initialize component after construction. */ @PostConstruct public void init() { if (availableList == null) { availableList = new JList<T>(available); } else { availableList.setModel(available); } if (selectedList == null) { selectedList = new JList<T>(selected); } else { selectedList.setModel(selected); } availableSearch.setVisible(showSearchFields); selectedSearch.setVisible(showSearchFields); JButton addButton = new JButton(new AddSelectedAction()); JButton removeButton = new JButton(new RemoveSelectedAction()); addButton.setMinimumSize(new Dimension(buttonWidth, buttonHeight)); removeButton.setMinimumSize(new Dimension(buttonWidth, buttonHeight)); JScrollPane availableScroll = new JScrollPane(availableList); JScrollPane selectedScroll = new JScrollPane(selectedList); availableScroll.setPreferredSize(new Dimension(listWidth, listheight)); selectedScroll.setPreferredSize(new Dimension(listWidth, listheight)); availableScroll.setMinimumSize(new Dimension(listWidth, listheight)); selectedScroll.setMinimumSize(new Dimension(listWidth, listheight)); // test message source if (messageSource == null) { messageSource= new ResourceBundleMessageSource(); ((ResourceBundleMessageSource) messageSource).setBasename("i18n.jdal"); } MessageSourceAccessor msa = new MessageSourceAccessor(messageSource); BoxFormBuilder fb = new BoxFormBuilder(); fb.row(Short.MAX_VALUE); fb.startBox(); fb.row(); fb.add(availableSearch); fb.row(); fb.add(FormUtils.newLabelForBox(msa.getMessage("Selector.available"))); fb.row(Short.MAX_VALUE); fb.add(availableScroll); fb.endBox(); fb.startBox(); fb.row(Short.MAX_VALUE); fb.add(Box.createVerticalGlue()); fb.row(buttonHeight); fb.add(removeButton); fb.row(Short.MAX_VALUE); fb.add(Box.createVerticalGlue()); fb.endBox(); fb.setMaxWidth(buttonWidth); fb.startBox(); fb.row(Short.MAX_VALUE); fb.add(Box.createVerticalGlue()); fb.row(buttonHeight); fb.add(addButton); fb.row(Short.MAX_VALUE); fb.add(Box.createVerticalGlue()); fb.endBox(); fb.setMaxWidth(buttonWidth); fb.startBox(); fb.row(); fb.add(selectedSearch); fb.row(); fb.add(FormUtils.newLabelForBox(msa.getMessage("Selector.selected"))); fb.row(Short.MAX_VALUE); fb.add(selectedScroll); fb.endBox(); setLayout(new BorderLayout()); add(fb.getForm(), BorderLayout.CENTER); } /** * Add selected values to selected list. */ private void addSelected() { List<T> selectedValues = availableList.getSelectedValuesList(); addSelected(selectedValues); } /** * Add selected values from available list. * @param values values to add */ public void addSelected(List<T> values) { if (values.size() > 0) { List<T> toAdd = new ArrayList<T>(values); removeNotInList(toAdd, this.available.getList()); this.available.removeAll(toAdd); this.selected.addAll(toAdd); sort(); clearSelections(); fireActionEvent(); } } /** * Clear selections on both lists */ private void clearSelections() { availableList.clearSelection(); selectedList.clearSelection(); } /** * Remove selected values from selected list */ private void removeSelected() { removeSelected(this.selectedList.getSelectedValuesList()); } /** * Remove list of selected element from selected list. * @param values values to remove */ public void removeSelected(List<T> values) { removeNotInList(values, this.selected.getList()); this.selected.removeAll(values); this.available.addAll(values); sort(); clearSelections(); fireActionEvent(); } /** * Remove elements that aren't in master list * @param values values to test * @param master master list. */ private void removeNotInList(List<T> values, List<T> master) { Iterator<T> iter = values.iterator(); while (iter.hasNext()) { T item = iter.next(); if (!master.contains(item)) iter.remove(); } } /** * Sort list elements using internal comparator. */ public void sort() { if (this.comparator != null) { this.selected.sort(this.comparator); this.available.sort(this.comparator); } } /** * Notify listeners that selected values changes */ protected void fireActionEvent() { if (!firingActionEvent) { firingActionEvent = true; ActionEvent event = new ActionEvent(this, ActionEvent.ACTION_PERFORMED, "selectorChanged"); for (ActionListener listener : listenerList.getListeners(ActionListener.class)) listener.actionPerformed(event); firingActionEvent = false; } } /** * Get Available list * @return List with available values */ public List<T> getAvailable() { return available.getList(); } /** * Sets the available list * @param available list to set */ public void setAvailable(List<T> available) { this.available.clear(); this.available.addAll(available); List<T> l = new ArrayList<T>(all); l.removeAll(available); selected.clear(); selected.addAll(l); } /** * Gets the selected values * @return List with selected values */ public List<T> getSelected() { return selected.getList(); } public void setSelected(List<T> selected) { this.selected.clear(); available.clear(); available.addAll(all); if (selected != null) { this.selected.addAll(selected); available.removeAll(selected); } } public String getName() { return name; } public void setName(String name) { this.name = name; } public Icon getRightArrow() { return rightArrow; } public void setRightArrow(Icon rightArrow) { this.rightArrow = rightArrow; } public Icon getLeftArrow() { return leftArrow; } public void setLeftArrow(Icon leftArrow) { this.leftArrow = leftArrow; } /** * Add an ActionListener * @param listener ActionListener to add */ public void addActionListener(ActionListener listener) { if (listener != null) listenerList.add(ActionListener.class, listener); } /** * Remove an ActionListener * @param listener ActionListener to remove */ public void removeActionListner(ActionListener listener) { listenerList.remove(ActionListener.class, listener); } /** * @return the all */ public List<T> getAll() { return all; } /** * @param all the all to set */ public void setAll(List<T> all) { this.all = all; } /** * @return the buttonWidth */ public int getButtonWidth() { return buttonWidth; } /** * @param buttonWidth the buttonWidth to set */ public void setButtonWidth(int buttonWidth) { this.buttonWidth = buttonWidth; } /** * @return the buttonHeight */ public int getButtonHeight() { return buttonHeight; } /** * @param buttonHeight the buttonHeight to set */ public void setButtonHeight(int buttonHeight) { this.buttonHeight = buttonHeight; } /** * @return the showSearchFields */ public boolean isShowSearchFields() { return showSearchFields; } /** * @param showSearchFields the showSearchFields to set */ public void setShowSearchFields(boolean showSearchFields) { this.showSearchFields = showSearchFields; } public static void main(String[] args) { ApplicationContextGuiFactory.setPlasticLookAndFeel(); Selector<Object> selector = new Selector<Object>(); selector.setAvailable((Arrays.asList(new Object[] {"lala"}))); selector.init(); JFrame f = new JFrame(); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.add(selector); f.setSize(800, 800); f.setVisible(true); } private class AddSelectedAction extends AbstractAction { private static final long serialVersionUID = 1L; public AddSelectedAction() { putValue(Action.SMALL_ICON, rightArrow); } public void actionPerformed(ActionEvent e) { addSelected(); } } private class RemoveSelectedAction extends AbstractAction { private static final long serialVersionUID = 1L; public RemoveSelectedAction() { putValue(Action.SMALL_ICON, leftArrow); } public void actionPerformed(ActionEvent e) { removeSelected(); } } /** * @return the messageSource */ public MessageSource getMessageSource() { return messageSource; } /** * @param messageSource the messageSource to set */ public void setMessageSource(MessageSource messageSource) { this.messageSource = messageSource; } /** * @return the listWidth */ public int getListWidth() { return listWidth; } /** * @param listWidth the listWidth to set */ public void setListWidth(int listWidth) { this.listWidth = listWidth; } /** * @return the listheight */ public int getListheight() { return listheight; } /** * @param listheight the listheight to set */ public void setListheight(int listheight) { this.listheight = listheight; } /** * @return the availableList */ public JList<T> getAvailableList() { return availableList; } /** * @param availableList the availableList to set */ public void setAvailableList(JList<T> availableList) { this.availableList = availableList; this.availableList.setModel(this.available); } /** * @return the selectedList */ public JList<T> getSelectedList() { return selectedList; } /** * @param selectedList the selectedList to set */ public void setSelectedList(JList<T> selectedList) { this.selectedList = selectedList; this.selectedList.setModel(this.selected); } public Comparator<T> getComparator() { return comparator; } public void setComparator(Comparator<T> comparator) { this.comparator = comparator; } }