/* * (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.util.Vector; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.BorderFactory; import javax.swing.JList; import javax.swing.ListSelectionModel; import javax.swing.SwingUtilities; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import org.openflexo.fib.controller.FIBController; import org.openflexo.fib.controller.FIBListDynamicModel; import org.openflexo.fib.controller.FIBSelectable; import org.openflexo.fib.model.FIBList; public class FIBListWidget extends FIBMultipleValueWidget<FIBList, JList, Object> implements FIBSelectable { static final Logger logger = Logger.getLogger(FIBListWidget.class.getPackage().getName()); protected JList _list; public FIBListWidget(FIBList model, FIBController controller) { super(model, controller); Object[] listData = { "Item1", "Item2", "Item3" }; _list = new JList(listData); _list.setCellRenderer(getListCellRenderer()); _list.setSelectionMode(model.getSelectionMode().getMode()); if (model.getVisibleRowCount() != null) { _list.setVisibleRowCount(model.getVisibleRowCount()); } // _list.setPrototypeCellValue("0123456789012345"); if (model.getRowHeight() != null) { _list.setFixedCellHeight(model.getRowHeight()); } _list.setLayoutOrientation(model.getLayoutOrientation().getSwingValue()); _list.addFocusListener(this); _list.setBorder(BorderFactory.createEtchedBorder()); // _list.setMinimumSize(new Dimension(60,60)); // _list.setPreferredSize(new Dimension(60,60)); _list.revalidate(); _list.repaint(); updateListModelWhenRequired(); updateFont(); } @Override public synchronized boolean updateWidgetFromModel() { updateListModelWhenRequired(); if (getWidget().getData() != null && notEquals(getValue(), _list.getSelectedValue())) { if (logger.isLoggable(Level.FINE)) { logger.fine("updateWidgetFromModel()"); } widgetUpdating = true; // updateList(); _list.setSelectedValue(getValue(), true); widgetUpdating = false; return true; } return false; } /** * Update the model given the actual state of the widget */ @Override public synchronized boolean updateModelFromWidget() { if (notEquals(getValue(), _list.getSelectedValue())) { modelUpdating = true; if (logger.isLoggable(Level.FINE)) { logger.fine("updateModelFromWidget with " + _list.getSelectedValue()); } if (_list.getSelectedValue() != null && !widgetUpdating) { setValue(_list.getSelectedValue()); } modelUpdating = false; return true; } return false; } @Override public FIBListModel getListModel() { return (FIBListModel) super.getListModel(); } protected synchronized void updateList() { if (listModel == null) { updateListModelWhenRequired(); } else { _list.getSelectionModel().removeListSelectionListener((FIBListModel) listModel); listModel = new FIBListModel(); setListModel((FIBListModel) listModel); } } @Override protected FIBListModel updateListModelWhenRequired() { if (listModel == null) { listModel = new FIBListModel(); setListModel((FIBListModel) listModel); } else { FIBListModel newListModel = new FIBListModel(); if (!newListModel.equals(listModel) || didLastKnownValuesChange()) { _list.getSelectionModel().removeListSelectionListener((FIBListModel) listModel); listModel = newListModel; setListModel((FIBListModel) listModel); } } return (FIBListModel) listModel; } private FIBListModel oldListModel = null; private void setListModel(FIBListModel aListModel) { // logger.info("************* Updating GUI with " + aListModel); widgetUpdating = true; if (oldListModel != null) { _list.getSelectionModel().removeListSelectionListener(oldListModel); } oldListModel = aListModel; _list.setLayoutOrientation(getWidget().getLayoutOrientation().getSwingValue()); _list.setSelectionMode(getWidget().getSelectionMode().getMode()); if (getWidget().getVisibleRowCount() != null) { _list.setVisibleRowCount(getWidget().getVisibleRowCount()); } else { _list.setVisibleRowCount(-1); } if (getWidget().getRowHeight() != null) { _list.setFixedCellHeight(getWidget().getRowHeight()); } else { _list.setFixedCellHeight(-1); } _list.setModel(aListModel); _list.revalidate(); _list.repaint(); _list.getSelectionModel().addListSelectionListener(aListModel); widgetUpdating = false; Object objectToSelect = null; if (getComponent().getSelected().isValid()) { objectToSelect = getComponent().getSelected().getBindingValue(getController()); } if (objectToSelect == null && getWidget().getAutoSelectFirstRow() && _list.getModel().getSize() > 0) { objectToSelect = _list.getModel().getElementAt(0); } if (objectToSelect != null) { for (int i = 0; i < _list.getModel().getSize(); i++) { if (_list.getModel().getElementAt(i) == objectToSelect) { final int index = i; SwingUtilities.invokeLater(new Runnable() { @Override public void run() { _list.setSelectedIndex(index); } }); } } } /*if (getWidget().getAutoSelectFirstRow() && _list.getModel().getSize() > 0) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { _list.setSelectedIndex(0); } }); }*/ } protected class FIBListModel extends FIBMultipleValueModel implements ListSelectionListener { private Object selectedObject; private Vector<Object> selection; public FIBListModel() { super(); selectedObject = null; selection = new Vector<Object>(); } public Object getSelectedObject() { return selectedObject; } public Vector<Object> getSelection() { return selection; } @Override public void valueChanged(ListSelectionEvent e) { // Ignore extra messages. if (e.getValueIsAdjusting()) { return; } if (widgetUpdating) { return; } if (logger.isLoggable(Level.FINE)) { logger.fine("valueChanged() selected index=" + getListSelectionModel().getMinSelectionIndex()); } updateModelFromWidget(); int i = getListSelectionModel().getMinSelectionIndex(); int leadIndex = getListSelectionModel().getLeadSelectionIndex(); if (!getListSelectionModel().isSelectedIndex(leadIndex)) { leadIndex = getListSelectionModel().getAnchorSelectionIndex(); } while (!getListSelectionModel().isSelectedIndex(leadIndex) && i <= getListSelectionModel().getMaxSelectionIndex()) { leadIndex = i; i++; } selectedObject = getElementAt(leadIndex); Vector<Object> oldSelection = selection; selection = new Vector<Object>(); for (i = getListSelectionModel().getMinSelectionIndex(); i <= getListSelectionModel().getMaxSelectionIndex(); i++) { if (getListSelectionModel().isSelectedIndex(i)) { selection.add(getElementAt(i)); } } getDynamicModel().setSelected(selectedObject); getDynamicModel().setSelectedIndex(leadIndex); getDynamicModel().selection = selection; notifyDynamicModelChanged(); if (getComponent().getSelected().isValid()) { logger.fine("Sets SELECTED binding with " + selectedObject); getComponent().getSelected().setBindingValue(selectedObject, getController()); } updateFont(); if (!ignoreNotifications) { getController().updateSelection(FIBListWidget.this, oldSelection, selection); } logger.fine((isFocused() ? "LEADER" : "SECONDARY") + " Selected is " + selectedObject); logger.fine((isFocused() ? "LEADER" : "SECONDARY") + " Selection is " + selection); } private boolean ignoreNotifications = false; public void addToSelectionNoNotification(Object o) { int index = indexOf(o); ignoreNotifications = true; getListSelectionModel().addSelectionInterval(index, index); ignoreNotifications = false; } public void removeFromSelectionNoNotification(Object o) { int index = indexOf(o); ignoreNotifications = true; getListSelectionModel().removeSelectionInterval(index, index); ignoreNotifications = false; } public void resetSelectionNoNotification() { ignoreNotifications = true; getListSelectionModel().clearSelection(); ignoreNotifications = false; } public void addToSelection(Object o) { int index = indexOf(o); getListSelectionModel().addSelectionInterval(index, index); } public void removeFromSelection(Object o) { int index = indexOf(o); getListSelectionModel().removeSelectionInterval(index, index); } public void resetSelection() { getListSelectionModel().clearSelection(); } } public ListSelectionModel getListSelectionModel() { return _list.getSelectionModel(); } @Override public JList getJComponent() { return _list; } @Override public JList getDynamicJComponent() { return _list; } @Override public void updateFont() { super.updateFont(); if (getFont() != null) { _list.setFont(getFont()); } } @Override public FIBListDynamicModel createDynamicModel() { return new FIBListDynamicModel(null); } @Override public FIBListDynamicModel getDynamicModel() { return (FIBListDynamicModel) super.getDynamicModel(); } @Override public boolean mayRepresent(Object o) { return getListModel().indexOf(o) > -1; } @Override public void objectAddedToSelection(Object o) { getListModel().addToSelectionNoNotification(o); } @Override public void objectRemovedFromSelection(Object o) { getListModel().removeFromSelectionNoNotification(o); } @Override public void selectionResetted() { getListModel().resetSelectionNoNotification(); } @Override public void addToSelection(Object o) { getListModel().addToSelection(o); } @Override public void removeFromSelection(Object o) { getListModel().removeFromSelection(o); } @Override public void resetSelection() { getListModel().resetSelection(); } @Override public Object getSelectedObject() { return getListModel().getSelectedObject(); } @Override public Vector<Object> getSelection() { return getListModel().getSelection(); } @Override public boolean synchronizedWithSelection() { return getWidget().getBoundToSelectionManager(); } public boolean isLastFocusedSelectable() { return getController().getLastFocusedSelectable() == this; } private FIBListCellRenderer listCellRenderer; @Override public FIBListCellRenderer getListCellRenderer() { if (listCellRenderer == null) { listCellRenderer = new FIBListCellRenderer(); } return listCellRenderer; } protected class FIBListCellRenderer extends FIBMultipleValueCellRenderer { public FIBListCellRenderer() { // Dimension s = getJComponent().getSize(); // setPreferredSize(new Dimension(100,getWidget().getRowHeight())); } @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { FIBListCellRenderer label = (FIBListCellRenderer) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); // ((JComponent)label).setPreferredSize(new Dimension(label.getWidth(),getWidget().getRowHeight())); if (isSelected) { if (isLastFocusedSelectable()) { if (getWidget().getTextSelectionColor() != null) { setForeground(getWidget().getTextSelectionColor()); } if (getWidget().getBackgroundSelectionColor() != null) { setBackground(getWidget().getBackgroundSelectionColor()); } } else { if (getWidget().getTextNonSelectionColor() != null) { setForeground(getWidget().getTextNonSelectionColor()); } if (getWidget().getBackgroundSecondarySelectionColor() != null) { setBackground(getWidget().getBackgroundSecondarySelectionColor()); } } } else { if (getWidget().getTextNonSelectionColor() != null) { setForeground(getWidget().getTextNonSelectionColor()); } if (getWidget().getBackgroundNonSelectionColor() != null) { setBackground(getWidget().getBackgroundNonSelectionColor()); } } return label; } } }