001    /*
002     * $Id: LinkModelAction.java,v 1.7 2006/04/10 11:59:38 kleopatra Exp $
003     *
004     * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
005     * Santa Clara, California 95054, U.S.A. All rights reserved.
006     *
007     * This library is free software; you can redistribute it and/or
008     * modify it under the terms of the GNU Lesser General Public
009     * License as published by the Free Software Foundation; either
010     * version 2.1 of the License, or (at your option) any later version.
011     * 
012     * This library is distributed in the hope that it will be useful,
013     * but WITHOUT ANY WARRANTY; without even the implied warranty of
014     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
015     * Lesser General Public License for more details.
016     * 
017     * You should have received a copy of the GNU Lesser General Public
018     * License along with this library; if not, write to the Free Software
019     * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
020     */
021    package org.jdesktop.swingx.action;
022    
023    import java.awt.event.ActionEvent;
024    import java.awt.event.ActionListener;
025    import java.beans.PropertyChangeEvent;
026    import java.beans.PropertyChangeListener;
027    
028    import javax.swing.Action;
029    
030    import org.jdesktop.swingx.LinkModel;
031    
032    /**
033     * Specialized LinkAction for a target of type {@link LinkModel}. 
034     * <p>
035     * 
036     * This action delegates actionPerformed to vistingDelegate.
037     * 
038     * PENDING: move to swingx package?
039     * 
040     * @author Jeanette Winzenburg
041     */
042    public class LinkModelAction<T extends LinkModel> extends LinkAction<T> {
043        
044        private ActionListener delegate;
045        public static final String VISIT_ACTION = "visit";
046        private PropertyChangeListener linkListener;
047        
048    
049        public LinkModelAction() {
050            this((T) null);
051        }
052    
053        public LinkModelAction(ActionListener visitingDelegate) {
054            this(null, visitingDelegate);
055        }
056        
057        public LinkModelAction(T target) {
058            this(target, null);
059        }
060        
061        public LinkModelAction(T target, ActionListener visitingDelegate) {
062            super(target);
063            setVisitingDelegate(visitingDelegate);
064        }
065        
066        /**
067         * The delegate to invoke on actionPerformed.
068         * <p>
069         * The delegates actionPerformed is invoked with an ActionEvent
070         * having the target as source. Delegates are expected to
071         * cope gracefully with the T. 
072         * <p>
073         * 
074         * PENDING: JW - How to formalize? 
075         * 
076         * @param delegate the action invoked on the target.
077         */
078        public void setVisitingDelegate(ActionListener delegate) {
079            this.delegate = delegate;
080        }
081        
082        /**
083         * This action delegates to the visitingDelegate if both
084         * delegate and target are != null, does nothing otherwise.
085         * The actionEvent carries the target as source.
086         * 
087         * PENDING: pass through a null target? - most probably!
088         * 
089         * 
090         * 
091         */
092        public void actionPerformed(ActionEvent e) {
093            if ((delegate != null) && (getTarget() != null)) {
094                delegate.actionPerformed(new ActionEvent(getTarget(), ActionEvent.ACTION_PERFORMED, VISIT_ACTION));
095            }
096            
097        }
098    
099        /**
100         * installs a propertyChangeListener on the target and
101         * updates the visual properties from the target.
102         */
103        @Override
104        protected void installTarget() {
105            if (getTarget() != null) {
106                getTarget().addPropertyChangeListener(getTargetListener());
107            }
108            updateFromTarget();
109        }
110    
111        /**
112         * removes the propertyChangeListener. <p>
113         * 
114         * Implementation NOTE: this does not clean-up internal state! There is
115         * no need to because updateFromTarget handles both null and not-null
116         * targets. Hmm...
117         * 
118         */
119        @Override
120        protected void uninstallTarget() {
121            if (getTarget() == null) return;
122           getTarget().removePropertyChangeListener(getTargetListener());
123        }
124    
125        protected void updateFromTarget() {
126            if (getTarget() != null) {
127                putValue(Action.NAME, getTarget().getText());
128                putValue(Action.SHORT_DESCRIPTION, getTarget().getURL().toString());
129                putValue(VISITED_KEY, new Boolean(getTarget().getVisited()));
130            } else {
131                Object[] keys = getKeys();
132                if (keys == null) return;
133                for (int i = 0; i < keys.length; i++) {
134                   putValue(keys[i].toString(), null); 
135                }
136            }
137        }
138    
139        private PropertyChangeListener getTargetListener() {
140            if (linkListener == null) {
141             linkListener = new PropertyChangeListener() {
142    
143                public void propertyChange(PropertyChangeEvent evt) {
144                    updateFromTarget();
145                }
146                
147            };
148            }
149            return linkListener;
150        }
151    
152        
153    }