001    /*
002     * $Id: LinkModelAction.java 3294 2009-03-11 10:50:52Z kleopatra $
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.hyperlink;
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    
031    /**
032     * Specialized LinkAction for a target of type {@link LinkModel}. 
033     * <p>
034     * 
035     * This action delegates actionPerformed to vistingDelegate.
036     * 
037     * PENDING: move to swingx package?
038     * 
039     * @author Jeanette Winzenburg
040     */
041    public class LinkModelAction<T extends LinkModel> extends AbstractHyperlinkAction<T> {
042        
043        private ActionListener delegate;
044        public static final String VISIT_ACTION = "visit";
045        private PropertyChangeListener linkListener;
046        
047    
048        public LinkModelAction() {
049            this((T) null);
050        }
051    
052        public LinkModelAction(ActionListener visitingDelegate) {
053            this(null, visitingDelegate);
054        }
055        
056        public LinkModelAction(T target) {
057            this(target, null);
058        }
059        
060        public LinkModelAction(T target, ActionListener visitingDelegate) {
061            super(target);
062            setVisitingDelegate(visitingDelegate);
063        }
064        
065        /**
066         * The delegate to invoke on actionPerformed.
067         * <p>
068         * The delegates actionPerformed is invoked with an ActionEvent
069         * having the target as source. Delegates are expected to
070         * cope gracefully with the T. 
071         * <p>
072         * 
073         * PENDING: JW - How to formalize? 
074         * 
075         * @param delegate the action invoked on the target.
076         */
077        public void setVisitingDelegate(ActionListener delegate) {
078            this.delegate = delegate;
079        }
080        
081        /**
082         * This action delegates to the visitingDelegate if both
083         * delegate and target are != null, does nothing otherwise.
084         * The actionEvent carries the target as source.
085         * 
086         * PENDING: pass through a null target? - most probably!
087         * 
088         * 
089         * 
090         */
091        public void actionPerformed(ActionEvent e) {
092            if ((delegate != null) && (getTarget() != null)) {
093                delegate.actionPerformed(new ActionEvent(getTarget(), ActionEvent.ACTION_PERFORMED, VISIT_ACTION));
094            }
095            
096        }
097    
098        /**
099         * installs a propertyChangeListener on the target and
100         * updates the visual properties from the target.
101         */
102        @Override
103        protected void installTarget() {
104            if (getTarget() != null) {
105                getTarget().addPropertyChangeListener(getTargetListener());
106            }
107            updateFromTarget();
108        }
109    
110        /**
111         * removes the propertyChangeListener. <p>
112         * 
113         * Implementation NOTE: this does not clean-up internal state! There is
114         * no need to because updateFromTarget handles both null and not-null
115         * targets. Hmm...
116         * 
117         */
118        @Override
119        protected void uninstallTarget() {
120            if (getTarget() == null) return;
121           getTarget().removePropertyChangeListener(getTargetListener());
122        }
123    
124        protected void updateFromTarget() {
125            if (getTarget() != null) {
126                putValue(Action.NAME, getTarget().getText());
127                putValue(Action.SHORT_DESCRIPTION, getTarget().getURL().toString());
128                putValue(VISITED_KEY, new Boolean(getTarget().getVisited()));
129            } else {
130                Object[] keys = getKeys();
131                if (keys == null) return;
132                for (int i = 0; i < keys.length; i++) {
133                   putValue(keys[i].toString(), null); 
134                }
135            }
136        }
137    
138        private PropertyChangeListener getTargetListener() {
139            if (linkListener == null) {
140             linkListener = new PropertyChangeListener() {
141    
142                public void propertyChange(PropertyChangeEvent evt) {
143                    updateFromTarget();
144                }
145                
146            };
147            }
148            return linkListener;
149        }
150    
151        
152    }