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.support;
017
018 import java.beans.PropertyChangeEvent;
019 import java.beans.PropertyChangeListener;
020 import java.lang.ref.WeakReference;
021 import java.util.HashSet;
022 import java.util.Iterator;
023 import java.util.NoSuchElementException;
024 import java.util.Set;
025
026 import javax.swing.AbstractButton;
027
028 import org.springframework.core.style.ToStringCreator;
029 import org.springframework.richclient.command.AbstractCommand;
030 import org.springframework.richclient.command.config.CommandButtonConfigurer;
031 import org.springframework.richclient.command.config.CommandFaceDescriptor;
032 import org.springframework.util.Assert;
033 import org.springframework.util.ObjectUtils;
034
035 public class CommandFaceButtonManager implements PropertyChangeListener {
036 private Set buttons = new HashSet(6);
037
038 private AbstractCommand command;
039
040 private String faceDescriptorId;
041
042 private CommandFaceDescriptor faceDescriptor;
043
044 private static class ManagedButton {
045 private WeakReference buttonHolder;
046
047 private CommandButtonConfigurer buttonConfigurer;
048
049 private int hashCode;
050
051 public ManagedButton(AbstractButton button, CommandButtonConfigurer buttonConfigurer) {
052 this.buttonHolder = new WeakReference(button);
053 this.buttonConfigurer = buttonConfigurer;
054 this.hashCode = button.hashCode();
055 }
056
057 public AbstractButton getButton() {
058 return (AbstractButton)buttonHolder.get();
059 }
060
061 public boolean equals(Object o) {
062 if (o == null) {
063 return false;
064 }
065 if (this == o) {
066 return true;
067 }
068 return ObjectUtils.nullSafeEquals(getButton(), ((ManagedButton)o).getButton());
069 }
070
071 public int hashCode() {
072 return hashCode;
073 }
074 }
075
076 public CommandFaceButtonManager(AbstractCommand command, String faceDescriptorKey) {
077 Assert.notNull(command, "The command to manage buttons for cannot be null");
078 Assert.hasText(faceDescriptorKey, "The face descriptor key is required");
079 this.command = command;
080 this.faceDescriptorId = faceDescriptorKey;
081 }
082
083 public CommandFaceButtonManager(AbstractCommand command, CommandFaceDescriptor faceDescriptor) {
084 this.command = command;
085 setFaceDescriptor(faceDescriptor);
086 }
087
088 public void setFaceDescriptor(CommandFaceDescriptor faceDescriptor) {
089 Assert.notNull(faceDescriptor, "The face descriptor for managing command button appearance is required");
090 if (!ObjectUtils.nullSafeEquals(this.faceDescriptor, faceDescriptor)) {
091 if (this.faceDescriptor != null) {
092 this.faceDescriptor.removePropertyChangeListener(this);
093 }
094 this.faceDescriptor = faceDescriptor;
095 this.faceDescriptor.addPropertyChangeListener(this);
096 propertyChange(null);
097 }
098 }
099
100 public CommandFaceDescriptor getFaceDescriptor() {
101 return faceDescriptor;
102 }
103
104 public boolean isFaceConfigured() {
105 return this.faceDescriptor != null;
106 }
107
108 public void attachAndConfigure(AbstractButton button, CommandButtonConfigurer strategy) {
109 Assert.notNull(button, "The button to attach and configure is required");
110 Assert.notNull(strategy, "The button configuration strategy is required");
111 if (!isAttachedTo(button)) {
112 ManagedButton managedButton = new ManagedButton(button, strategy);
113 if (buttons.add(managedButton)) {
114 configure(button, strategy);
115 }
116 }
117 }
118
119 private void cleanUp() {
120 for (Iterator i = buttons.iterator(); i.hasNext();) {
121 ManagedButton button = (ManagedButton)i.next();
122 if (button.getButton() == null) {
123 i.remove();
124 }
125 }
126 }
127
128 protected void configure(AbstractButton button, CommandButtonConfigurer strategy) {
129 if (this.faceDescriptor == null) {
130 if (command.getFaceDescriptorRegistry() != null) {
131 setFaceDescriptor(command.getFaceDescriptorRegistry().getFaceDescriptor(command, faceDescriptorId));
132 } else {
133 setFaceDescriptor(new CommandFaceDescriptor());
134 }
135 }
136
137 getFaceDescriptor().configure(button, command, strategy);
138 }
139
140 public void detach(AbstractButton button) {
141 buttons.remove(findManagedButton(button));
142 }
143
144 public void detachAll() {
145 buttons.clear();
146 }
147
148 public boolean isAttachedTo(AbstractButton button) {
149 return findManagedButton(button) != null;
150 }
151
152 protected ManagedButton findManagedButton(AbstractButton button) {
153 Assert.notNull(button, "The button is required");
154 cleanUp();
155 for (Iterator i = buttons.iterator(); i.hasNext();) {
156 ManagedButton managedButton = (ManagedButton)i.next();
157 if (button.equals(managedButton.getButton())) {
158 return managedButton;
159 }
160 }
161 return null;
162 }
163
164 public Iterator iterator() {
165 cleanUp();
166 return new ButtonIterator(buttons.iterator());
167 }
168
169 private static class ButtonIterator implements Iterator {
170 private Iterator it;
171
172 private AbstractButton nextButton;
173
174 public ButtonIterator(Iterator it) {
175 this.it = it;
176 fetchNextButton();
177 }
178
179 public boolean hasNext() {
180 return nextButton != null;
181 }
182
183 public Object next() {
184 if (nextButton == null) {
185 throw new NoSuchElementException();
186 }
187 AbstractButton lastButton = nextButton;
188 fetchNextButton();
189 return lastButton;
190 }
191
192 public void remove() {
193 throw new UnsupportedOperationException();
194 }
195
196 private void fetchNextButton() {
197 while (it.hasNext()) {
198 ManagedButton managedButton = (ManagedButton)it.next();
199 nextButton = managedButton.getButton();
200 if (nextButton != null) {
201 return;
202 }
203 }
204 nextButton = null;
205 }
206 }
207
208 public void propertyChange(PropertyChangeEvent e) {
209 Iterator it = buttons.iterator();
210 while (it.hasNext()) {
211 ManagedButton mb = (ManagedButton)it.next();
212 Assert.notNull(mb, "Managed button reference cannot be null");
213 if (mb.getButton() == null) {
214 it.remove();
215 }
216 else {
217 configure(mb.getButton(), mb.buttonConfigurer);
218 }
219 }
220 }
221
222 public String toString() {
223 return new ToStringCreator(this).append("commandId", command.getId())
224 .append("faceDescriptor", faceDescriptor)
225 .append("attachedButtonCount", buttons.size())
226 .toString();
227 }
228 }