All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.globalmentor.swing.ComponentAction Maven / Gradle / Ivy

The newest version!
/*
 * Copyright © 1996-2009 GlobalMentor, Inc. 
 *
 * 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 com.globalmentor.swing;

import java.awt.Component;
import java.awt.Container;
import java.beans.*;
import java.lang.ref.*;

import javax.swing.*;

import static com.globalmentor.java.Objects.*;

/**
 * Action that knows how to create its own component.
 * @author Garret Wilson
 */
public abstract class ComponentAction extends AbstractAction {

	/** The property that represents the selected objects of the component, if the component implements ItemSelectable. */
	//TODO del if not needed	public static final String SELECTED_OBJECTS_PROPERTY="selectedObjects";

	/** The listener we use to find out when the proxied action is changing. */
	//TODO del if not needed	private PropertyChangeListener actionPropertyChangeListener;

	/** Whether action properties should be updated when the proxied action changes. */
	//TODO fix	private boolean shouldUpdateProperties=true;

	/**
	 * Defines a proxy action object with a default description string and default icon.
	 */
	public ComponentAction() {
		super(); //construct the parent
	}

	/**
	 * Defines a proxy action object with the specified description string and a default icon.
	 * @param name The name description of the action.
	 */
	public ComponentAction(final String name) {
		this(); //do the default construction
		putValue(NAME, name);
	}

	/**
	 * Defines a proxy action object with the specified description string and the specified icon.
	 * @param name The name description of the action.
	 * @param icon The icon to represent the action.
	 */
	public ComponentAction(final String name, final Icon icon) {
		this(name); //do the default construction
		putValue(Action.SMALL_ICON, icon);
	}

	/**
	 * Creates a new component and adds it to the container.
	 * @param container The container to which the new component should be added.
	 * @return The component added to the container.
	 * @see #createConfiguredComponent()
	 */
	public C addComponent(final Container container) {
		final C component = createConfiguredComponent(); //create and configure a new component
		container.add(component); //add the configured component
		return component; //return the created component
	}

	/**
	 * Creates and configures a component for use in adding to a container.
	 * @return A new component suitable for adding to a container.
	 * @see #createComponent()
	 * @see #configureComponent(C)
	 */
	public C createConfiguredComponent() {
		final C component = createComponent(); //create the component
		configureComponent(component); //configure the component
		return component; //return the configured component
	}

	/**
	 * Creates a component for the action.
	 * @return A new component for the action.
	 */
	protected abstract C createComponent();

	/**
	 * Configures a created component.
	 * @param component The component to configure.
	 */
	protected void configureComponent(final C component) {
		/*TODO fix		
				component.set
				String text = a!=null? (String)a.getValue(Action.NAME) : null;
				Icon icon   = a!=null? (Icon)a.getValue(Action.SMALL_ICON) : null;
			        boolean enabled = a!=null? a.isEnabled() : true;
			        String tooltip = a!=null?
			            (String)a.getValue(Action.SHORT_DESCRIPTION) : null;
			        JButton b = new JButton(text, icon) {
				    protected PropertyChangeListener createActionPropertyChangeListener(Action a) {
					PropertyChangeListener pcl = createActionChangeListener(this);
					if (pcl==null) {
					    pcl = super.createActionPropertyChangeListener(a);
					}
					return pcl;
				    }
				};
				if (icon !=null) {
				    b.putClientProperty("hideActionText", Boolean.TRUE);
				}
				b.setHorizontalTextPosition(JButton.CENTER);
				b.setVerticalTextPosition(JButton.BOTTOM);
		*/
		final String shortDescription = (String)getValue(SHORT_DESCRIPTION); //get the short description
		component.setEnabled(isEnabled()); //give the component the same enabled status as the action
		if(component instanceof JComponent) { //if this is a JComponent
			final JComponent jComponent = (JComponent)component; //get the component as a JComponent
			jComponent.setToolTipText(shortDescription); //set the tooltip text from the short description
		}
	}

	/**
	 * @return A new property change listener for updating the component based on the status of the action.
	 * @param component The component to change in response to action property changes.
	 */
	protected PropertyChangeListener createActionPropertyChangeListener(final C component) {
		return new ActionPropertyChangeListener(component); //return the default action property change listener
	}

	protected class ActionPropertyChangeListener implements PropertyChangeListener {

		/** The reference to the component; this implementation uses a weak reference. */
		final Reference componentReference;

		/** @return The component, or null if we no longer reference a component. */
		public C getComponent() {
			return componentReference.get();
		}

		/**
		 * Creates a property change listener to update a component based upon action property changes.
		 * @param component The component to be updated.
		 */
		public ActionPropertyChangeListener(final C component) {
			componentReference = new WeakReference(component); //createa  weak reference to the component
		}

		/**
		 * Called when a bound property is changed. This version removes this listener from the action if the component has been garbage-collected.
		 * @param propertyChangeEvent An event object describing the event source and the property that has changed.
		 */
		public void propertyChange(final PropertyChangeEvent propertyChangeEvent) {
			final Action action = (Action)propertyChangeEvent.getSource(); //get the source of the event
			final C component = getComponent(); //get the component we represent
			if(component != null) { //if we have a component
				final JComponent jComponent = asInstance(component, JComponent.class); //get the component as a JComponent, if it is one
				final String propertyName = propertyChangeEvent.getPropertyName(); //get the property name
				if(Components.ENABLED_PROPERTY.equals(propertyName)) { //if the enabled state is changing, we must change the actual property (which will change the property value), rather than just changing the underlying value or the actual property won't change
					component.setEnabled(((Boolean)propertyChangeEvent.getNewValue()).booleanValue()); //update the enabled state
				} else if(SHORT_DESCRIPTION.equals(propertyName)) { //short description
					if(jComponent != null) { //if we have a JComponent
						jComponent.setToolTipText((String)propertyChangeEvent.getNewValue()); //set the tooltip text from the new short description
					}
				}
			} else { //if we don't have a component anymore
				action.removePropertyChangeListener(this); //stop listening for property changes
			}
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy