/* * Copyright (c) 2005-2016 Vincent Vandenschrick. All rights reserved. * * This file is part of the Jspresso framework. * * Jspresso 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 3 of the License, or * (at your option) any later version. * * Jspresso 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 Jspresso. If not, see <http://www.gnu.org/licenses/>. */ package org.jspresso.framework.view.swing; import java.awt.Component; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.MouseEvent; import java.util.Collections; import java.util.EventObject; import java.util.HashMap; import java.util.Map; import javax.swing.AbstractButton; import javax.swing.AbstractCellEditor; import javax.swing.JComponent; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.JTree; import javax.swing.SwingConstants; import javax.swing.table.TableCellEditor; import javax.swing.tree.TreeCellEditor; import org.jspresso.framework.binding.IMvcBinder; import org.jspresso.framework.binding.IValueConnector; import org.jspresso.framework.binding.basic.BasicValueConnector; import org.jspresso.framework.binding.model.IModelConnectorFactory; import org.jspresso.framework.gui.swing.components.JActionField; import org.jspresso.framework.gui.swing.components.JDateField; import org.jspresso.framework.model.descriptor.IComponentDescriptorProvider; import org.jspresso.framework.security.ISecurityHandler; import org.jspresso.framework.util.accessor.IAccessor; import org.jspresso.framework.util.event.IValueChangeListener; import org.jspresso.framework.util.event.ValueChangeEvent; import org.jspresso.framework.view.IView; /** * This class is an adapter around a SwingView to be able to use it as a cell * editor. * * @author Vincent Vandenschrick */ public class SwingViewCellEditorAdapter extends AbstractCellEditor implements TableCellEditor, TreeCellEditor { private static final Map<String, Object> NULLMAP = Collections.unmodifiableMap( new HashMap<String, Object>()); private static final long serialVersionUID = 8182961519931949735L; private final IView<JComponent> editorView; /** * Constructs a new {@code SwingViewCellEditorAdapter} instance. * * @param editorView * the swing view used as editor. * @param modelConnectorFactory * the model connector factory. * @param mvcBinder * the mvc binder. * @param securityHandler * the security handler. */ public SwingViewCellEditorAdapter(IView<JComponent> editorView, IModelConnectorFactory modelConnectorFactory, IMvcBinder mvcBinder, ISecurityHandler securityHandler) { this.editorView = editorView; if (editorView.getPeer() instanceof AbstractButton) { ((AbstractButton) editorView.getPeer()).setHorizontalAlignment(SwingConstants.CENTER); } if ((editorView.getPeer() instanceof AbstractButton)) { editorView.getConnector().addValueChangeListener(new IValueChangeListener() { @Override public void valueChange(ValueChangeEvent evt) { stopCellEditing(); } }); } // To prevent the editor from being read-only. IValueConnector modelConnector; String modelConnectorId = editorView.getConnector() // To prevent the model connector to believe it's on a nested property .getId().replace(IAccessor.NESTED_DELIM, '_'); if (editorView.getDescriptor().getModelDescriptor() instanceof IComponentDescriptorProvider<?>) { modelConnector = modelConnectorFactory.createModelConnector(modelConnectorId, ((IComponentDescriptorProvider<?>) editorView.getDescriptor().getModelDescriptor()).getComponentDescriptor(), securityHandler); } else { modelConnector = new BasicValueConnector(modelConnectorId); } mvcBinder.bind(editorView.getConnector(), modelConnector); } /** * Returns the value of the swing view's connector. * <p/> * {@inheritDoc} */ @Override public Object getCellEditorValue() { Object cellEditorValue = editorView.getConnector().getConnectorValue(); if (cellEditorValue == NULLMAP) { return null; } return cellEditorValue; } /** * Returns the JComponent peer of the swing view. * <p/> * {@inheritDoc} */ @Override public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { IValueConnector editorConnector = editorView.getConnector(); Object connectorValue; if (value instanceof IValueConnector) { connectorValue = ((IValueConnector) value).getConnectorValue(); } else { connectorValue = value; } if (connectorValue == null && editorConnector.getModelDescriptor() instanceof IComponentDescriptorProvider<?>) { // To prevent the editor to be read-only. connectorValue = NULLMAP; } editorConnector.setConnectorValue(connectorValue); Component editorComponent = editorView.getPeer(); if (editorComponent instanceof JTextField) { ((JTextField) editorComponent).selectAll(); } else if (editorComponent instanceof JActionField) { ((JActionField) editorComponent).selectAll(); } else if (editorComponent instanceof JDateField) { ((JDateField) editorComponent).getFormattedTextField().selectAll(); } if (!(editorComponent instanceof JTextArea || editorComponent instanceof JScrollPane)) { JPanel wrapperPanel = new JPanel(); wrapperPanel.setLayout(new GridBagLayout()); wrapperPanel.add(editorComponent, new GridBagConstraints(0, 0, 1, 1, 1.0, 1.0, GridBagConstraints.NORTH, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0)); editorComponent = wrapperPanel; } return editorComponent; } /** * Gets the component peer of the editor view. * <p/> * {@inheritDoc} */ @Override public Component getTreeCellEditorComponent(JTree tree, Object value, boolean isSelected, boolean expanded, boolean leaf, int row) { return editorView.getPeer(); } /** * Returns false if the event object is a single mouse click. * <p/> * {@inheritDoc} */ @Override public boolean isCellEditable(EventObject anEvent) { if (anEvent instanceof MouseEvent) { if (editorView.getPeer() instanceof AbstractButton) { return ((MouseEvent) anEvent).getClickCount() >= 1; } return ((MouseEvent) anEvent).getClickCount() >= 2; } return super.isCellEditable(anEvent); } /** * Gets the editorView. * * @return the editorView. */ protected IView<JComponent> getEditorView() { return editorView; } }