Package com.eteks.sweethome3d.swing

Source Code of com.eteks.sweethome3d.swing.ResourceAction$AbstractDecoratedAction

/*
* ResourceAction.java 8 juil. 2006
*
* Sweet Home 3D, Copyright (c) 2006 Emmanuel PUYBARET / eTeks <info@eteks.com>
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/
package com.eteks.sweethome3d.swing;

import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.lang.ref.WeakReference;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ImageIcon;
import javax.swing.KeyStroke;
import javax.swing.event.SwingPropertyChangeSupport;

import com.eteks.sweethome3d.model.UserPreferences;
import com.eteks.sweethome3d.tools.OperatingSystem;

/**
* An action with properties read from a resource bundle file.
* @author Emmanuel Puybaret
*/
public class ResourceAction extends AbstractAction {
  public static final String POPUP = "Popup";
   
  /**
   * Creates a disabled action with properties retrieved from a resource bundle
   * in which key starts with <code>actionPrefix</code>.
   * @param preferences   user preferences used to retrieve localized properties of the action
   * @param resourceClass the class used as a context to retrieve localized properties of the action
   * @param actionPrefix  prefix used in resource bundle to search action properties
   */
  public ResourceAction(UserPreferences preferences,
                        Class<?> resourceClass,
                        String actionPrefix) {
    this(preferences, resourceClass, actionPrefix, false);
  }
 
  /**
   * Creates an action with properties retrieved from a resource bundle
   * in which key starts with <code>actionPrefix</code>.
   * @param preferences   user preferences used to retrieve localized description of the action
   * @param resourceClass the class used as a context to retrieve localized properties of the action
   * @param actionPrefix  prefix used in resource bundle to search action properties
   * @param enabled <code>true</code> if the action should be enabled at creation.
   */
  public ResourceAction(UserPreferences preferences,
                        Class<?> resourceClass,
                        String actionPrefix,
                        boolean enabled) {
    readActionProperties(preferences, resourceClass, actionPrefix);   
    setEnabled(enabled);
   
    preferences.addPropertyChangeListener(UserPreferences.Property.LANGUAGE,
        new LanguageChangeListener(this, resourceClass, actionPrefix));
  }
   
  /**
   * Preferences property listener bound to this action with a weak reference to avoid
   * strong link between preferences and this action. 
   */
  private static class LanguageChangeListener implements PropertyChangeListener {
    private final WeakReference<ResourceAction> resourceAction;
    private final Class<?>                      resourceClass;
    private final String                        actionPrefix;

    public LanguageChangeListener(ResourceAction resourceAction,
                                  Class<?> resourceClass,
                                  String actionPrefix) {
      this.resourceAction = new WeakReference<ResourceAction>(resourceAction);
      this.resourceClass = resourceClass;
      this.actionPrefix = actionPrefix;
    }

    public void propertyChange(PropertyChangeEvent ev) {
      // If action was garbage collected, remove this listener from preferences
      ResourceAction resourceAction = this.resourceAction.get();
      if (resourceAction == null) {
        ((UserPreferences)ev.getSource()).removePropertyChangeListener(
            UserPreferences.Property.LANGUAGE, this);
      } else {
        resourceAction.readActionProperties((UserPreferences)ev.getSource(),
            this.resourceClass, this.actionPrefix);
      }
    }
  }
 
  /**
   * Reads from the properties of this action.
   */
  private void readActionProperties(UserPreferences preferences,
                                    Class<?> resourceClass,
                                    String actionPrefix) {
    String propertyPrefix = actionPrefix + ".";
    try {
      putValue(NAME, SwingTools.getLocalizedLabelText(preferences, resourceClass, propertyPrefix + NAME));
    } catch (IllegalArgumentException ex) {
      // Ignore unknown resource
    }
    putValue(DEFAULT, getValue(NAME));
    putValue(POPUP, getOptionalString(preferences, resourceClass, propertyPrefix + POPUP));
   
    putValue(SHORT_DESCRIPTION,
        getOptionalString(preferences, resourceClass, propertyPrefix + SHORT_DESCRIPTION));
    putValue(LONG_DESCRIPTION,
        getOptionalString(preferences, resourceClass, propertyPrefix + LONG_DESCRIPTION));
   
    String smallIcon = getOptionalString(preferences, resourceClass, propertyPrefix + SMALL_ICON);
    if (smallIcon != null) {
      putValue(SMALL_ICON, new ImageIcon(resourceClass.getResource(smallIcon)));
    }

    String propertyKey = propertyPrefix + ACCELERATOR_KEY;
    // Search first if there's a key for this OS
    String acceleratorKey = getOptionalString(preferences,
        resourceClass, propertyKey + "." + System.getProperty("os.name"));
    if (acceleratorKey == null) {
      // Then search default value
      acceleratorKey = getOptionalString(preferences, resourceClass, propertyKey);
    }
    if (acceleratorKey !=  null) {
      putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(acceleratorKey));
    }
   
    String mnemonicKey = getOptionalString(preferences, resourceClass, propertyPrefix + MNEMONIC_KEY);
    if (mnemonicKey != null) {
      putValue(MNEMONIC_KEY, Integer.valueOf(KeyStroke.getKeyStroke(mnemonicKey).getKeyCode()));
    }
  }

  /**
   * Returns the value of <code>propertyKey</code> in <code>preferences</code>,
   * or <code>null</code> if the property doesn't exist.
   */
  private String getOptionalString(UserPreferences preferences,
                                   Class<?> resourceClass,
                                   String propertyKey) {
    try {
      String localizedText = preferences.getLocalizedString(resourceClass, propertyKey);
      if (localizedText != null && localizedText.length() > 0) {
        return localizedText;
      } else {
        return null;
      }
    } catch (IllegalArgumentException ex) {
      return null;
    }
  }

  /**
   * Unsupported operation. Subclasses should override this method if they want
   * to associate a real action to this class.
   */
  public void actionPerformed(ActionEvent ev) {
    throw new UnsupportedOperationException();
  }
 
  /**
   * An action decorator. 
   */
  private static class AbstractDecoratedAction implements Action {
    private Action action;
    private SwingPropertyChangeSupport propertyChangeSupport;

    public AbstractDecoratedAction(Action action) {
      this.action = action;
      this.propertyChangeSupport = new SwingPropertyChangeSupport(this);
      action.addPropertyChangeListener(new PropertyChangeListener() {
          public void propertyChange(PropertyChangeEvent ev) {
            String propertyName = ev.getPropertyName();
            if ("enabled".equals(propertyName)) {
              propertyChangeSupport.firePropertyChange(ev);
            } else {
              Object newValue = getValue(propertyName);
              // In case a property value changes, fire the new value decorated in subclasses
              // unless new value is null (most Swing listeners don't check new value is null !)
              if (newValue != null) {
                propertyChangeSupport.firePropertyChange(new PropertyChangeEvent(ev.getSource(),
                    propertyName, ev.getOldValue(), newValue));
              }
            }
          }
        });
    }

    public final void actionPerformed(ActionEvent ev) {
      this.action.actionPerformed(ev);
    }

    public final void addPropertyChangeListener(PropertyChangeListener listener) {
      this.propertyChangeSupport.addPropertyChangeListener(listener);
    }

    public Object getValue(String key) {
      return this.action.getValue(key);
    }

    public final boolean isEnabled() {
      return this.action.isEnabled();
    }

    public final void putValue(String key, Object value) {
      this.action.putValue(key, value);
    }

    public final void removePropertyChangeListener(PropertyChangeListener listener) {
      this.propertyChangeSupport.removePropertyChangeListener(listener);
    }

    public final void setEnabled(boolean enabled) {
      this.action.setEnabled(enabled);
    }
   
    protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
      this.propertyChangeSupport.firePropertyChange(propertyName, oldValue, newValue);
    }
  }
 
  /**
   * An action decorator for menu items. 
   */
  public static class MenuItemAction extends AbstractDecoratedAction {
    public MenuItemAction(Action action) {
      super(action);
    }

    public Object getValue(String key) {
      // Avoid mnemonics, tooltips and icons in Mac OS X menus
      if (OperatingSystem.isMacOSX()
          && (key.equals(MNEMONIC_KEY)
              || key.equals(SMALL_ICON)
              || key.equals(SHORT_DESCRIPTION))) {
        return null;
      }
      return super.getValue(key);
    }
  }
 
  /**
   * An action decorator for popup menu items. 
   */
  public static class PopupMenuItemAction extends MenuItemAction {
    public PopupMenuItemAction(Action action) {
      super(action);
      // Add a listener on POPUP value changes because the value of the
      // POPUP key replaces the one matching NAME if it exists      
      addPropertyChangeListener(new PropertyChangeListener() {
          public void propertyChange(PropertyChangeEvent ev) {
            if (POPUP.equals(ev.getPropertyName())
                && (ev.getOldValue() != null || ev.getNewValue() != null)) {
              firePropertyChange(NAME, ev.getOldValue(), ev.getNewValue());
            }
          }
        });
    }

    public Object getValue(String key) {
      // If it exists, return POPUP key value if NAME key is required
      if (key.equals(NAME)) {
        Object value = super.getValue(POPUP);
        if (value != null) {
          return value;
        }
      } else if (key.equals(SMALL_ICON)) {
        // Avoid icons in popus
        return null;
      } else if (OperatingSystem.isMacOSX()
                 && key.equals(ACCELERATOR_KEY)) {
        // Avoid accelerators in Mac OS X popups
        return null;
      }
      return super.getValue(key);
    }
  }

  /**
   * An action decorator for tool bar buttons. 
   */
  public static class ToolBarAction extends AbstractDecoratedAction {
    public ToolBarAction(Action action) {
      super(action);
    }

    public Object getValue(String key) {
      // Ignore NAME in tool bar
      if (key.equals(NAME)) {       
        return null;
      }
      return super.getValue(key);
    }
  }

  /**
   * An action decorator for  buttons. 
   */
  public static class ButtonAction extends AbstractDecoratedAction {
    public ButtonAction(Action action) {
      super(action);
    }

    public Object getValue(String key) {
      // Avoid mnemonics in Mac OS X menus
      if (OperatingSystem.isMacOSX()
          && key.equals(MNEMONIC_KEY)) {
        return null;
      }
      return super.getValue(key);
    }
  }
}
TOP

Related Classes of com.eteks.sweethome3d.swing.ResourceAction$AbstractDecoratedAction

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.