001    /*
002     * Copyright 2002-2004 the original author or authors.
003     * 
004     * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005     * use this file except in compliance with the License. You may obtain a copy of
006     * the License at
007     * 
008     * http://www.apache.org/licenses/LICENSE-2.0
009     * 
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012     * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013     * License for the specific language governing permissions and limitations under
014     * the License.
015     */
016    package org.springframework.richclient.command;
017    
018    import java.util.Iterator;
019    import java.util.List;
020    
021    import javax.swing.AbstractButton;
022    import javax.swing.JMenuItem;
023    
024    import org.springframework.core.style.ToStringCreator;
025    import org.springframework.richclient.command.config.CommandButtonConfigurer;
026    import org.springframework.richclient.factory.ButtonFactory;
027    import org.springframework.richclient.factory.MenuFactory;
028    import org.springframework.richclient.util.Assert;
029    
030    /**
031     * A simple implementation of the {@link GroupMember} interface that manages normal commands that
032     * can be associated with instances of {@link AbstractButton}s.
033     *
034     */
035    public class SimpleGroupMember extends GroupMember {
036    
037        private final CommandGroup parent;
038    
039        private final AbstractCommand command;
040    
041        /**
042         * Creates a new {@code SimpleGroupMember} belonging to the given command group and wrapping
043         * the given command.
044         *
045         * @param parentGroup The command group that this member belongs to.
046         * @param command The command that this group member represents.
047         * 
048         * @throws IllegalArgumentException if either argument is null.
049         * @throws InvalidGroupMemberException if the given command group does not support the type of
050         * the given command.
051         */
052        public SimpleGroupMember(CommandGroup parentGroup, AbstractCommand command) {
053            this.parent = parentGroup;
054            this.command = command;
055            
056            if (!parentGroup.isAllowedMember(command)) {
057                throw new InvalidGroupMemberException(command.getClass(), parentGroup.getClass());
058            }
059            
060        }
061    
062        /**
063         * Sets the enabled flag of the underlying command.
064         */
065        public void setEnabled(boolean enabled) {
066            command.setEnabled(enabled);
067        }
068    
069        
070        protected void fill(GroupContainerPopulator containerPopulator, 
071                            Object controlFactory,
072                            CommandButtonConfigurer buttonConfigurer, 
073                            List previousButtons) {
074            
075            Assert.required(containerPopulator, "containerPopulator");
076            Assert.required(buttonConfigurer, "buttonConfigurer");
077            
078            if (controlFactory instanceof MenuFactory) {
079                JMenuItem menu = findMenu(command, previousButtons);
080    
081                if (menu == null) {
082                    menu = command.createMenuItem(((MenuFactory)controlFactory), buttonConfigurer);
083                }
084                
085                logger.debug("Adding menu item to container");
086                containerPopulator.add(menu);
087            }
088            else if (controlFactory instanceof ButtonFactory) {
089                AbstractButton button = findButton(command, previousButtons);
090                
091                if (button == null) {
092                    button = command.createButton(((ButtonFactory)controlFactory), buttonConfigurer);
093                }
094                
095                logger.debug("Adding button to container");
096                containerPopulator.add(button);
097            }
098            
099        }
100    
101        /**
102         * {@inheritDoc}
103         */
104        public boolean managesCommand(String commandId) {
105            //FIXME isn't this supposed to recursively check subcommands if command is a commandgroup?
106            
107            if (commandId == null) {
108                return false;
109            }
110            
111            return commandId.equals(this.command.getId());
112            
113        }
114    
115        /**
116         * Returns the underlying command, never null.
117         * @return The underlying command.
118         */
119        public AbstractCommand getCommand() {
120            return command;
121        }
122    
123        /**
124         * Searches the given list of {@link AbstractButton}s for one that is an instance of a 
125         * {@link JMenuItem} and has the given command attached to it. If found, the menu item will be
126         * removed from the list.
127         *
128         * @param attachedCommand The command that we are checking to see if it attached to any item in the list.
129         * @param abstractButtons The collection of {@link AbstractButton}s that will be checked to
130         * see if they have the given command attached to them. May be null or empty.
131         *  
132         * @return The element from the list that the given command is attached to, or null if no
133         * such element could be found.
134         * 
135         */
136        protected JMenuItem findMenu(AbstractCommand attachedCommand, List abstractButtons) {
137            
138            if (abstractButtons == null) {
139                return null;
140            }
141            
142            for (Iterator it = abstractButtons.iterator(); it.hasNext();) {
143                AbstractButton button = (AbstractButton)it.next();
144                if (button instanceof JMenuItem && attachedCommand.isAttached(button)) {
145                    it.remove();
146                    return (JMenuItem)button;
147                }
148            }
149            return null;
150        }
151    
152        /**
153         * Searches the given list of {@link AbstractButton}s for one that is not an instance of a 
154         * {@link JMenuItem} and has the given command attached to it. If found, the button will be
155         * removed from the list.
156         *
157         * @param attachedCommand The command that we are checking to see if it attached to any item in the list.
158         * @param abstractButtons The collection of {@link AbstractButton}s that will be checked to
159         * see if they have the given command attached to them. May be null or empty.
160         *  
161         * @return The element from the list that the given command is attached to, or null if no
162         * such element could be found.
163         * 
164         */
165        protected AbstractButton findButton(AbstractCommand attachedCommand, List buttons) {
166            
167            if (buttons == null) {
168                return null;
169            }
170            
171            for (Iterator it = buttons.iterator(); it.hasNext();) {
172                AbstractButton button = (AbstractButton)it.next();
173                if (!(button instanceof JMenuItem) && attachedCommand.isAttached(button)) {
174                    it.remove();
175                    return button;
176                }
177            }
178            return null;
179        }
180    
181        /**
182         * {@inheritDoc}
183         */
184        protected void onAdded() {
185            if (parent instanceof ExclusiveCommandGroup) {
186                ((ExclusiveCommandGroup)parent).getSelectionController().add((ToggleCommand)command);
187            }
188        }
189    
190        /**
191         * {@inheritDoc}
192         */
193        protected void onRemoved() {
194            if (parent instanceof ExclusiveCommandGroup) {
195                ((ExclusiveCommandGroup)parent).getSelectionController().remove((ToggleCommand)command);
196            }
197        }
198    
199        /**
200         * {@inheritDoc}
201         */
202        public String toString() {
203            return new ToStringCreator(this).append("command", command).toString();
204        }
205        
206    }