/* * (c) Copyright 2010-2011 AgileBirds * * This file is part of OpenFlexo. * * OpenFlexo is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * OpenFlexo 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with OpenFlexo. If not, see <http://www.gnu.org/licenses/>. * */ package org.openflexo.fib.view.widget; import java.awt.Component; import java.awt.Dimension; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.List; import java.util.StringTokenizer; import java.util.Vector; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.DefaultListCellRenderer; import javax.swing.JComponent; import javax.swing.JList; import javax.swing.ListModel; import javax.swing.SwingUtilities; import javax.swing.event.ListDataListener; import org.openflexo.antar.binding.AbstractBinding; import org.openflexo.fib.controller.FIBController; import org.openflexo.fib.controller.FIBMultipleValuesDynamicModel; import org.openflexo.fib.model.FIBModelObject; import org.openflexo.fib.model.FIBMultipleValues; import org.openflexo.fib.view.FIBWidgetView; import org.openflexo.localization.FlexoLocalization; import org.openflexo.toolbox.StringUtils; public abstract class FIBMultipleValueWidget<W extends FIBMultipleValues, C extends JComponent, T> extends FIBWidgetView<W, C, T> { static final Logger logger = Logger.getLogger(FIBMultipleValueWidget.class.getPackage().getName()); public FIBMultipleValueWidget(W model, FIBController controller) { super(model, controller); } protected class FIBMultipleValueModel implements ListModel { private List list = null; private Object[] array = null; protected FIBMultipleValueModel() { super(); logger.fine("Build FIBListModel"); if (getWidget().getList() != null && getWidget().getList().isSet() && getDataObject() != null) { Object accessedList = getWidget().getList().getBindingValue(getController()); if (accessedList instanceof List) { list = (List) accessedList; } } else if (getWidget().getArray() != null && getWidget().getArray().isSet() && getDataObject() != null) { Object accessedArray = getWidget().getArray().getBindingValue(getController()); // System.out.println("accessedArray="+accessedArray); try { array = (Object[]) accessedArray; } catch (ClassCastException e) { logger.warning("ClassCastException " + e.getMessage()); } /*for (int i=0; i<array.length; i++) { System.out.println("> "+array[i]); }*/ } else if (getWidget().getData() != null && getWidget().getData().getBinding() != null && getDataObject() != null) { /*System.out.println("Binding: "+getWidget().getData().getBinding()); System.out.println("isBindingValid: "+getWidget().getData().getBinding().isBindingValid()); if (!getWidget().getData().getBinding().isBindingValid()) { System.out.println("Owner: "+getWidget().getData().getOwner()); System.out.println("BindingModel: "+getWidget().getData().getOwner().getBindingModel()); BindingExpression.logger.setLevel(Level.FINE); AbstractBinding binding = AbstractBinding.abstractBindingConverter.convertFromString(getWidget().getData().getBinding().toString()); binding.isBindingValid(); }*/ Type type = getWidget().getData().getBinding().getAccessedType(); if (type instanceof Class && ((Class) type).isEnum()) { array = ((Class) type).getEnumConstants(); } } if (list == null && array == null && getWidget().getIteratorClass() != null && getWidget().getIteratorClass().isEnum()) { array = getWidget().getIteratorClass().getEnumConstants(); } if (list == null && array == null && StringUtils.isNotEmpty(getWidget().getStaticList())) { list = new Vector(); StringTokenizer st = new StringTokenizer(getWidget().getStaticList(), ","); while (st.hasMoreTokens()) { list.add(st.nextToken()); } } // logger.info("Built list model: " + this); } private boolean requireChange = true; private boolean requireChange() { // Always return true first time if (requireChange) { return true; } requireChange = false; if (getWidget().getList() != null && getWidget().getList().isSet() && getDataObject() != null) { Object accessedList = getWidget().getList().getBindingValue(getController()); return accessedList != null && !accessedList.equals(list); } else if (getWidget().getArray() != null && getWidget().getArray().isSet() && getDataObject() != null) { Object accessedArray = getWidget().getArray().getBindingValue(getController()); // TODO: you can do better return true; } else if (getWidget().getData() != null && getWidget().getData().getBinding() != null && getDataObject() != null) { Type type = getWidget().getData().getBinding().getAccessedType(); if (type instanceof Class && ((Class<?>) type).isEnum()) { return false; } } else if (StringUtils.isNotEmpty(getWidget().getStaticList())) { return false; } return true; } @Override public int getSize() { if (list != null) { return list.size(); } if (array != null) { return array.length; } return 0; } @Override public Object getElementAt(int index) { if (list != null && index >= 0 && index < list.size()) { return list.get(index); } if (array != null && index >= 0 && index < array.length) { return array[index]; } return null; } @Override public void addListDataListener(ListDataListener l) { // Interface } @Override public void removeListDataListener(ListDataListener l) { // Interface } public int indexOf(Object cur) { for (int i = 0; i < getSize(); i++) { if (getElementAt(i).equals(cur)) { return i; } } return -1; } /*@Override public FIBMultipleValueModel clone() { FIBMultipleValueModel returned = new FIBMultipleValueModel(); if (list != null) { returned.list = new ArrayList(list); } else if (array != null) { returned.array = new Object[array.length]; for (int i = 0; i < array.length; i++) { returned.array[i] = array[i]; } } return returned; }*/ @Override public String toString() { return getClass().getSimpleName() + "[" + (list != null ? list.size() + " " + list.toString() : "null") + "]"; } protected ArrayList<Object> toArrayList() { ArrayList<Object> returned = new ArrayList<Object>(); for (int i = 0; i < getSize(); i++) { returned.add(getElementAt(i)); } return returned; } protected boolean equalsToList(List l) { if (l == null) { return getSize() == 0; } if (getSize() == l.size()) { for (int i = 0; i < getSize(); i++) { if (!getElementAt(i).equals(l.get(i))) { return false; } } return true; } else { return false; } } } protected boolean listModelRequireChange() { return getListModel().requireChange(); } protected class FIBMultipleValueCellRenderer extends DefaultListCellRenderer { private Dimension nullDimesion; @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { FIBMultipleValueCellRenderer label = (FIBMultipleValueCellRenderer) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); if (value != null && nullDimesion == null) { nullDimesion = ((JComponent) getListCellRendererComponent(list, null, -1, false, false)).getPreferredSize(); } if (getWidget().getShowText()) { if (value != null) { String stringRepresentation = getStringRepresentation(value); if (stringRepresentation == null || stringRepresentation.length() == 0) { stringRepresentation = "<html><i>" + FlexoLocalization.localizedForKey(FIBModelObject.LOCALIZATION, "empty_string") + "</i></html>"; } label.setText(stringRepresentation); } else { label.setText(FlexoLocalization.localizedForKey(FIBModelObject.LOCALIZATION, "no_selection")); } if (FIBMultipleValueWidget.this.getFont() != null) { label.setFont(FIBMultipleValueWidget.this.getFont()); } } else { label.setText(null); } // label.setBorder(BorderFactory.createEmptyBorder(1, 2, 1, 2)); if (getWidget().getShowIcon()) { if (getWidget().getIcon() != null && getWidget().getIcon().isValid()) { label.setIcon(getIconRepresentation(value)); } } // System.out.println("Actual preferred= "+list.getPreferredSize().getWidth()); // System.out.println("I will prefer "+label.getPreferredSize().getWidth()); return label; } @Override public Dimension getPreferredSize() { Dimension preferredSize = super.getPreferredSize(); if (nullDimesion != null) { preferredSize.width = Math.max(preferredSize.width, nullDimesion.width); preferredSize.height = Math.max(preferredSize.height, nullDimesion.height); } return preferredSize; } @Override public void updateUI() { nullDimesion = null; super.updateUI(); } } private FIBMultipleValueCellRenderer listCellRenderer; protected FIBMultipleValueModel listModel; public FIBMultipleValueCellRenderer getListCellRenderer() { if (listCellRenderer == null) { listCellRenderer = new FIBMultipleValueCellRenderer(); } return listCellRenderer; } public FIBMultipleValueModel getListModel() { if (listModel == null) { updateListModelWhenRequired(); } return listModel; } protected FIBMultipleValueModel updateListModelWhenRequired() { if (listModel == null) { listModel = new FIBMultipleValueModel(); } else { FIBMultipleValueModel aNewListModel = new FIBMultipleValueModel(); if (!aNewListModel.equals(listModel) || didLastKnownValuesChange()) { listModel = aNewListModel; } } return listModel; } protected FIBMultipleValueModel updateListModel() { listModel = null; updateListModelWhenRequired(); return listModel; } private ArrayList<Object> lastKnownValues = null; /** * Return a flag indicating if last known values declared as ListModel have changed since the last time this method was called. * * @return */ protected boolean didLastKnownValuesChange() { boolean returned; if (listModel != null) { returned = !listModel.equalsToList(lastKnownValues); lastKnownValues = listModel.toArrayList(); } else { returned = lastKnownValues != null; lastKnownValues = null; } return returned; } /*protected final FIBListModel rebuildListModel() { return listModel = buildListModel(); } protected final FIBListModel buildListModel() { return new FIBListModel(); }*/ @Override public final void updateDataObject(final Object dataObject) { if (!SwingUtilities.isEventDispatchThread()) { if (logger.isLoggable(Level.WARNING)) { logger.warning("Update data object invoked outside the EDT!!! please investigate and make sure this is no longer the case. \n\tThis is a very SERIOUS problem! Do not let this pass."); } SwingUtilities.invokeLater(new Runnable() { @Override public void run() { updateDataObject(dataObject); } }); return; } updateListModelWhenRequired(); super.updateDataObject(dataObject); } @Override public FIBMultipleValuesDynamicModel<T, ?> createDynamicModel() { return buildDynamicModel(getWidget().getIteratorClass()); } private <O> FIBMultipleValuesDynamicModel<T, O> buildDynamicModel(Class<O> aClass) { return new FIBMultipleValuesDynamicModel<T, O>(null); } @Override public FIBMultipleValuesDynamicModel<T, Object> getDynamicModel() { return (FIBMultipleValuesDynamicModel<T, Object>) super.getDynamicModel(); } @Override public void updateLanguage() { super.updateLanguage(); if (getComponent().getLocalize()) { FIBMultipleValueModel mvModel = getListModel(); for (int i = 0; i < mvModel.getSize(); i++) { String s = getStringRepresentation(mvModel.getElementAt(i)); getLocalized(s); } } } @Override public List<AbstractBinding> getDependencyBindings() { List<AbstractBinding> returned = super.getDependencyBindings(); appendToDependingObjects(getWidget().getList(), returned); appendToDependingObjects(getWidget().getArray(), returned); return returned; } }