// BlogBridge -- RSS feed reader, manager, and web based service
// Copyright (C) 2002-2007 by R. Pito Salas
//
// 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
//
// Contact: R. Pito Salas
// mailto:pitosalas@users.sourceforge.net
// More information: about BlogBridge
// http://www.blogbridge.com
// http://sourceforge.net/projects/blogbridge
//
// $Id: ToolbarPlugin.java,v 1.1 2007/08/24 09:04:03 spyromus Exp $
//
package com.salas.bb.plugins.domain;
import com.jgoodies.uif.action.ActionManager;
import com.jgoodies.uif.util.ResourceUtils;
import com.salas.bb.views.mainframe.BBToolBarBuilder;
import org.jdom.Element;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Plugin for toolbar modification.
*/
public class ToolbarPlugin implements IPlugin
{
private final Element plugin;
/**
* Creates the plug-in and initializes it with data from the element.
*
* @param plugin plug-in node.
*/
public ToolbarPlugin(Element plugin)
{
this.plugin = plugin;
}
// ------------------------------------------------------------------------
// IPlugin implementation
// ------------------------------------------------------------------------
/**
* Returns the name of plug-in type (Theme, Actions ...).
*
* @return the name of plug-in type.
*/
public String getTypeName()
{
return "Toolbar";
}
/** Initializes plug-in. */
public void initialize()
{
List<Element> nodes = (List<Element>)plugin.getChildren();
BBToolBarBuilder.ToolbarLayout layout = BBToolBarBuilder.getLayout();
layout.clear();
for (Element node : nodes)
{
String name = node.getName();
if ("separator".equalsIgnoreCase(name))
{
layout.appendLargeGap();
} else if ("action".equalsIgnoreCase(name))
{
layout.appendAction(new LazyAction(node));
}
}
}
// ------------------------------------------------------------------------
/**
* Lazy action that is constructed from the toolbar plug-in 'action' subnodes.
*/
private static class LazyAction implements Action, PropertyChangeListener
{
private static final String LABEL = "label";
private static final String SHORT_DESCRIPTION = "tooltip";
private static final String LONG_DESCRIPTION = "helptext";
private static final String ICON = "icon";
private static final String GRAY_ICON = ICON + ".gray";
private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
private Action action;
private String actionName;
private Map<String, Object> overrides;
/**
* Creates a lazy action from the XML element.
*
* @param action action node.
*/
private LazyAction(Element action)
{
// Get the action name
actionName = action.getAttributeValue("name");
if (actionName == null) throw new IllegalArgumentException("Property 'name' should hold the action name");
// Optional overrides
overrides = new HashMap<String, Object>();
overrides.put(Action.NAME, action.getAttributeValue(LABEL));
overrides.put(Action.SHORT_DESCRIPTION, action.getAttributeValue(SHORT_DESCRIPTION));
overrides.put(Action.LONG_DESCRIPTION, action.getAttributeValue(LONG_DESCRIPTION));
// Optional icon overrides. We save only keys here to
// be able to pick them later during the action first access
overrides.put(Action.SMALL_ICON, action.getAttributeValue(ICON));
overrides.put(ActionManager.SMALL_GRAY_ICON, action.getAttributeValue(GRAY_ICON));
}
/**
* Returns the action instance.
*
* @return action.
*/
private synchronized Action getAction()
{
if (action == null)
{
action = ActionManager.get(actionName);
action.addPropertyChangeListener(this);
convertImage(Action.SMALL_ICON);
convertImage(ActionManager.SMALL_GRAY_ICON);
}
return action;
}
/**
* Converts an image path into an image.
*
* @param key key of the icons in the action overrides.
*/
private void convertImage(String key)
{
Object val = overrides.get(key);
if (val instanceof String)
{
String k = (String)val;
if (k.indexOf('/') != -1 || k.indexOf('\\') != -1 || k.matches("\\.(gif|jpg|png)\\s*$"))
{
overrides.put(key, ResourceUtils.readImageIcon(k));
} else if (k.matches("^[a-zA-Z0-9\\.]+$"))
{
overrides.put(key, ResourceUtils.getIcon(k));
}
}
}
/**
* Invoked when an action occurs.
*
* @param e event.
*/
public void actionPerformed(ActionEvent e)
{
getAction().actionPerformed(e);
}
/**
* Gets one of this object's properties using the associated key.
*
* @see #putValue
*/
public Object getValue(String key)
{
Object val = overrides.get(key);
if (val == null) val = getAction().getValue(key);
return val;
}
/**
* Sets one of this object's properties using the associated key. If the value has changed, a
* <code>PropertyChangeEvent</code> is sent to listeners.
*
* @param key a <code>String</code> containing the key
* @param value an <code>Object</code> value
*/
public void putValue(String key, Object value)
{
Object old = getValue(key);
overrides.put(key, value);
pcs.firePropertyChange(key, old, value);
}
/**
* Sets the enabled state of the <code>Action</code>. When enabled, any component associated with this object is
* active and able to fire this object's <code>actionPerformed</code> method. If the value has changed, a
* <code>PropertyChangeEvent</code> is sent to listeners.
*
* @param b true to enable this <code>Action</code>, false to disable it
*/
public void setEnabled(boolean b)
{
getAction().setEnabled(b);
}
/**
* Returns the enabled state of the <code>Action</code>. When enabled, any component associated with this object is
* active and able to fire this object's <code>actionPerformed</code> method.
*
* @return true if this <code>Action</code> is enabled
*/
public boolean isEnabled()
{
return getAction().isEnabled();
}
/**
* Adds a <code>PropertyChange</code> listener. Containers and attached components use these methods to register
* interest in this <code>Action</code> object. When its enabled state or other property changes, the registered
* listeners are informed of the change.
*
* @param listener a <code>PropertyChangeListener</code> object
*/
public void addPropertyChangeListener(PropertyChangeListener listener)
{
pcs.addPropertyChangeListener(listener);
}
/**
* Removes a <code>PropertyChange</code> listener.
*
* @param listener a <code>PropertyChangeListener</code> object
*
* @see #addPropertyChangeListener
*/
public void removePropertyChangeListener(PropertyChangeListener listener)
{
pcs.removePropertyChangeListener(listener);
}
/**
* This method gets called when a bound property is changed.
*
* @param evt event.
*/
public void propertyChange(PropertyChangeEvent evt)
{
// WARN: Probably this isn't correct. If we override a property the new value may be
// not what we really have.
pcs.firePropertyChange(evt.getPropertyName(), evt.getOldValue(), evt.getNewValue());
}
}
}