/* Copyright (C) 2006 Christian Schneider
*
* This file is part of Nomad.
*
* Nomad 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.
*
* Nomad 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 Nomad; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
* Created on Nov 19, 2006
*/
package net.sf.nmedit.nomad.core.menulayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.PrintStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Queue;
import javax.swing.AbstractAction;
import javax.swing.ImageIcon;
import javax.swing.JMenuItem;
import javax.swing.event.EventListenerList;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import net.sf.nmedit.nmutils.iterator.BFSIterator;
/**
* A node in the menu layout.
*
* @author Christian Schneider
*/
public class MLEntry extends AbstractAction
{
/**
*
*/
private static final long serialVersionUID = -3695182855344600135L;
// the enabled icon source uri
private String enabledIconSrc = null;
// the disabled icon source uri
private String disabledIconSrc = null;
// the enabled icon at the specified source uri
private ImageIcon enabledIcon = null;
// the disabled icon at the specified source uri
private ImageIcon disabledIcon = null;
// the local identifier of this menu layout entry
private String localEntryPoint;
// the global identifier of this menu layout entry
private String globalEntryPoint = null;
// a list of child entries
private List<MLEntry> entryList = null;
// the parent entry
private MLEntry parent = null;
// the flat option - if this is flat==true and this entry
// also has children, then it is not treated as a sub menu owner
// but as a list of menu entries surrounded by menu separators.
private boolean flat = false;
// event listeners
private EventListenerList listenerList = null;
// additional key to identify the disabled icon
public final static String SMALL_DISABLED_ICON = "SmallIcon$disabled";
/**
* Creates a new menu layout entry with the specified (local) entry point.
* @param localEntryPoint the local entry point
*/
public MLEntry(String localEntryPoint)
{
this.localEntryPoint = localEntryPoint;
}
/**
* Returns the parent entry
* @return the parent entry
*/
public MLEntry getParent()
{
return parent;
}
public boolean isInstalled(JMenuItem item)
{
return item.getAction() == this;
}
/**
* Returns the global entryPoint
* @return
*/
public String getGlobalEntryPoint()
{
if (globalEntryPoint == null)
{
if (parent == null)
{
globalEntryPoint = (localEntryPoint == null ? "" : localEntryPoint);
}
else
{
globalEntryPoint = parent.getGlobalEntryPoint()+"."+localEntryPoint;
}
}
return globalEntryPoint;
}
public String getLocalEntryPoint()
{
return localEntryPoint;
}
public void setEnabledIconSrc(String src)
{
if (this.enabledIconSrc != src)
{
this.enabledIconSrc = src;
enabledIcon = null;
putValue(SMALL_ICON, getEnabledIcon());
}
}
public void setDisabledIconSrc(String src)
{
if (this.disabledIconSrc != src)
{
this.disabledIconSrc = src;
disabledIcon = null;
putValue(SMALL_DISABLED_ICON, getDisabledIcon());
}
}
private URL getIconURL(String iconName)
{
return getClass().getClassLoader().getResource(iconName);
}
private static Log log = LogFactory.getLog(MLEntry.class);
private ImageIcon getImageIcon(String src)
{
URL url = getIconURL(src);
if (url == null)
{
if (log.isWarnEnabled())
{
log.debug("MLEntry:getImageIcon, could not find '"+src+"'.");
}
return null;
}
return new ImageIcon(url);
}
public ImageIcon getEnabledIcon()
{
if (enabledIcon == null)
{
if (enabledIconSrc != null)
enabledIcon = getImageIcon(enabledIconSrc);
}
return enabledIcon;
}
public ImageIcon getDisabledIcon()
{
if (disabledIcon == null)
{
if (disabledIconSrc != null)
disabledIcon = getImageIcon(disabledIconSrc);
}
return disabledIcon;
}
public String getEnabledIconSrc()
{
return this.enabledIconSrc;
}
public String getDisabledIconSrc()
{
return this.disabledIconSrc;
}
private void checkAdd(MLEntry entry)
{
if (entry.parent != null)
throw new RuntimeException("cannot reparent entry: "+entry);
if (entryList == null)
entryList = new ArrayList<MLEntry>(2);
}
public void add(MLEntry entry)
{
checkAdd(entry);
entryList.add(entry);
entry.parent = this;
}
public void add(int index, MLEntry entry)
{
checkAdd(entry);
entryList.add(index, entry);
entry.parent = this;
}
public int size()
{
return entryList == null ? 0 : entryList.size();
}
public MLEntry getEntryAt(int index)
{
if (entryList == null)
throw new IndexOutOfBoundsException("invalid index: "+index);
return entryList.get(index);
}
/*
public void printKeys(PrintStream out)
{
Iterator<MLEntry> i = bfsIterator();
while (i.hasNext())
{
System.out.println(i.next());
}
}*/
public void printXML(PrintStream out)
{
printXML(out, "");
}
private void printXML(PrintStream out, String ident)
{
String p = "<entry ";
if (parent == null)
{
out.println("<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>");
p += "xmlns=\"http://nmedit.sf.net/MenuLayout\"\n ";
}
if (flat)
{
p+= "flat=\"true\" ";
}
if ((enabledIconSrc == null) && (disabledIconSrc == null) && (entryList == null))
{
out.println(ident+p+"entryPoint=\""+localEntryPoint+"\" />");
}
else
{
out.println(ident+p+"entryPoint=\""+localEntryPoint+"\">");
if (enabledIconSrc != null)
out.println(ident+" <icon src=\""+enabledIconSrc+"\" />");
if (disabledIconSrc != null)
out.println(ident+" <icon src=\""+disabledIconSrc+"\" type=\"disabledIcon\" />");
if (entryList!=null)
{
for (int i=0;i<entryList.size();i++)
entryList.get(i).printXML(out, ident+" ");
}
out.println(ident+"</entry>");
}
}
public Iterator<MLEntry> bfsIterator()
{
return new BFSIterator<MLEntry>(this)
{
@Override
protected void enqueueChildren( Queue<MLEntry> queue, MLEntry parent )
{
List<MLEntry> l = parent.entryList;
if (l!=null)
queue.addAll(l);
}
};
}
public String toString()
{
return getGlobalEntryPoint();
}
/**
* Sets the flat option.
* @param flat
*/
public void setIsFlat( boolean flat )
{
this.flat = flat;
}
/**
* Returns the flat option.
* @return
*/
public boolean isFlat()
{
return flat;
}
public int getListenerCount()
{
return listenerList == null ? 0 : listenerList.getListenerCount();
}
/**
* Adds the specified ActionListener.
* @param l
*/
public void addActionListener(ActionListener l)
{
if (listenerList == null)
listenerList = new EventListenerList();
listenerList.add(ActionListener.class, l);
}
/**
* Removes the specified ActionListener.
* @param l
*/
public void removeActionListener(ActionListener l)
{
if (listenerList != null)
listenerList.remove(ActionListener.class, l);
}
/**
* notifies all listeners
*/
public void actionPerformed( ActionEvent e )
{
if (listenerList != null)
{
// Guaranteed to return a non-null array
Object[] listeners = listenerList.getListenerList();
// Process the listeners last to first, notifying
// those that are interested in this event
for (int i = listeners.length-2; i>=0; i-=2)
{
if (listeners[i]==ActionListener.class)
{
ActionListener al = (ActionListener)listeners[i+1];
if (al != this) // for savety
{
al.actionPerformed(e);
}
}
}
}
}
public MLEntry cloneTree()
{
MLEntry clone = new MLEntry(getGlobalEntryPoint());
cloneTree(clone, this);
return clone;
}
private static void cloneTree(MLEntry clone, MLEntry entry)
{
cloneSettings(clone, entry);
List<MLEntry> l = entry.entryList;
if (l == null)
return;
for (int i=0;i<l.size();i++)
{
MLEntry child = l.get(i);
MLEntry childClone = new MLEntry(child.getLocalEntryPoint());
clone.add(childClone);
cloneTree(childClone, child);
}
}
public static final String SELECTED_KEY = "SwingSelectedKey";
public static final String DISPLAYED_MNEMONIC_INDEX_KEY = "SwingDisplayedMnemonicIndexKey";
public static final String LARGE_ICON_KEY = "SwingLargeIconKey";
private static void cloneSettings(MLEntry clone, MLEntry entry)
{
clone.disabledIcon = entry.disabledIcon;
clone.enabledIcon = entry.enabledIcon;
clone.disabledIconSrc = entry.enabledIconSrc;
clone.enabled = entry.enabled;
clone.enabledIcon = entry.enabledIcon;
clone.enabledIconSrc = entry.enabledIconSrc;
clone.flat = entry.flat;
// auto: clone.globalEntryPoint = entry.globalEntryPoint;
clone.putValue(NAME, entry.getValue(NAME));
clone.putValue(SHORT_DESCRIPTION, entry.getValue(SHORT_DESCRIPTION));
clone.putValue(LONG_DESCRIPTION, entry.getValue(LONG_DESCRIPTION));
clone.putValue(SMALL_ICON, entry.getValue(SMALL_ICON));
clone.putValue(ACTION_COMMAND_KEY, entry.getValue(ACTION_COMMAND_KEY));
clone.putValue(ACCELERATOR_KEY, entry.getValue(ACCELERATOR_KEY));
clone.putValue(MNEMONIC_KEY, entry.getValue(MNEMONIC_KEY));
clone.putValue(SELECTED_KEY, entry.getValue(SELECTED_KEY));
clone.putValue(DISPLAYED_MNEMONIC_INDEX_KEY, entry.getValue(DISPLAYED_MNEMONIC_INDEX_KEY));
clone.putValue(LARGE_ICON_KEY, entry.getValue(LARGE_ICON_KEY));
}
}