/* * 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.binding.swing; import java.awt.Color; import javax.swing.JComponent; import org.jspresso.framework.binding.AbstractValueConnector; import org.jspresso.framework.binding.ConnectorInputException; import org.jspresso.framework.util.swing.SwingUtil; /** * This abstract class serves as the base class for all JComponent connectors. * Subclasses can access the JComponent using the parametrized method * {@code getConnectedJComponent()} which returns the parametrized type of * the class. * * @param <E> * The actual class of the subclass of {@code JComponent}. * @author Vincent Vandenschrick */ public abstract class JComponentConnector<E extends JComponent> extends AbstractValueConnector { private E connectedJComponent; private Color savedForeground; private Object value; /** * Constructs a new {@code JComponentConnector} instance. * * @param id * the connector identifier. * @param connectedJComponent * the connected JComponent. */ public JComponentConnector(String id, E connectedJComponent) { super(id); this.connectedJComponent = connectedJComponent; bindJComponent(); readabilityChange(); writabilityChange(); } /** * Turn read-only if not bound. * <p> * {@inheritDoc} * * @return the boolean */ @Override public boolean isWritable() { return (getModelConnector() != null) && super.isWritable(); } /** * This implementation takes care of having the peer component modifications * ran on the Swing event dispatch thread. It actually delegates the connectee * modification to the {@code protectedReadabilityChange} method. * * @see #protectedReadabilityChange() #protectedReadabilityChange() */ @Override public final void readabilityChange() { super.readabilityChange(); if (getConnectedJComponent() != null) { SwingUtil.updateSwingGui(new Runnable() { /** * {@inheritDoc} */ @Override public void run() { protectedReadabilityChange(); } }); } } /** * This implementation takes care of having the peer component modifications * ran on the Swing event dispatch thread. It actually delegates the connectee * modification to the {@code protectedWritabilityChange} method. * * @see #protectedWritabilityChange() #protectedWritabilityChange() */ @Override public final void writabilityChange() { super.writabilityChange(); if (getConnectedJComponent() != null) { SwingUtil.updateSwingGui(new Runnable() { /** * {@inheritDoc} */ @Override public void run() { protectedWritabilityChange(); } }); } } /** * Attaches the JComponent to the connector. */ protected abstract void bindJComponent(); /** * This method has been overridden to take care of long-running operations not * to have the swing gui blocked. It uses the foxtrot library to achieve this. * <p> * {@inheritDoc} */ @Override protected final void fireConnectorValueChange() { try { protectedFireConnectorValueChange(); } catch (ConnectorInputException ex) { // It's an input error. ignore } catch (RuntimeException ex) { handleException(ex); } } /** * Gets the connectedJComponent. * * @return the connectedJComponent. */ protected E getConnectedJComponent() { return connectedJComponent; } /** * This method can be overridden by subclasses in lieu of * {@code fireConnectorValueChange} that has been made final to take care * of the swing EDT. */ protected void protectedFireConnectorValueChange() { super.fireConnectorValueChange(); } /** * Implementation of connectee readability state modifications which normally * would have been coded in the {@code readabilityChange} method should * go here to preserve the connector modification to be handled in the event * dispatch thread. */ protected void protectedReadabilityChange() { if (isReadable()) { if (savedForeground != null) { getConnectedJComponent().setForeground(savedForeground); } savedForeground = null; } else if (savedForeground == null) { savedForeground = getConnectedJComponent().getForeground(); getConnectedJComponent().setForeground(getConnectedJComponent().getBackground()); } } /** * Implementation of connectee modifications which normally would have been * coded in the {@code setConnecteeValue} should go here to preserve the * connector modification to be handled in the event dispatch thread. * * @param aValue * the connectee value to set. */ protected abstract void protectedSetConnecteeValue(Object aValue); /** * Implementation of connectee writability state modifications which normally * would have been coded in the {@code writabilityChange} method should * go here to preserve the connector modification to be handled in the event * dispatch thread. */ protected void protectedWritabilityChange() { // Empty implementation. } /** * This implementation takes care of having the peer component modifications * ran on the Swing event dispatch thread. It actually delegates the connectee * modification to the {@code protectedSetConnecteeValue} method. * <p> * {@inheritDoc} * * @param aValue * the a value * @see #protectedSetConnecteeValue(Object) #protectedSetConnecteeValue(Object) */ @Override protected final void setConnecteeValue(final Object aValue) { if (getConnectedJComponent() != null) { SwingUtil.updateSwingGui(new Runnable() { @Override public void run() { protectedSetConnecteeValue(aValue); } }); } else { value = aValue; } } /** * Gets connectee value. * * @return the connectee value */ protected final Object getConnecteeValue() { if (getConnectedJComponent() != null) { return protectedGetConnecteeValue(); } else { return value; } } /** * Protected get connectee value object. * * @return the object */ protected abstract Object protectedGetConnecteeValue(); /** * Clone j component connector. * * @return the j component connector */ @SuppressWarnings("unchecked") @Override public JComponentConnector<E> clone() { JComponentConnector<E> clone = (JComponentConnector<E>) super.clone(); clone.connectedJComponent = null; clone.savedForeground = null; return clone; } }