View Javadoc

1   /*
2    * Copyright 2002-2004 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5    * use this file except in compliance with the License. You may obtain a copy of
6    * the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations under
14   * the License.
15   */
16  package org.springframework.richclient.command.config;
17  
18  import javax.swing.AbstractButton;
19  import javax.swing.JMenu;
20  import javax.swing.JMenuItem;
21  import javax.swing.KeyStroke;
22  
23  import org.springframework.core.style.ToStringCreator;
24  import org.springframework.richclient.core.LabelInfo;
25  import org.springframework.richclient.factory.ButtonConfigurer;
26  import org.springframework.richclient.util.Assert;
27  import org.springframework.util.ObjectUtils;
28  import org.springframework.util.StringUtils;
29  
30  
31  /**
32   * An immutable parameter object consisting of the text, mnemonic character, mnemonic character
33   * index and keystroke accelerator that may be associated with a labeled command button.
34   *
35   * <p>
36   * This class also acts as a factory for creating instances of itself based on a string descriptor.
37   * The syntax used for this descriptor is described in the javadoc for the {@link #valueOf(String)}
38   * method.
39   *
40   *
41   * @author Keith Donald
42   * @author Kevin Stembridge
43   *
44   * @see LabelInfo
45   * @see KeyStroke
46   */
47  public final class CommandButtonLabelInfo implements ButtonConfigurer {
48  
49      /** A default instance to be used for command buttons with no label information. */
50      public static final CommandButtonLabelInfo BLANK_BUTTON_LABEL = new CommandButtonLabelInfo("");
51  
52      private final LabelInfo labelInfo;
53  
54      private final KeyStroke accelerator;
55  
56      /**
57       * Return an instance of this class, created by parsing the information in the given label
58       * descriptor string. The expected format of this descriptor is the same as that used by
59       * the {@link LabelInfo} class, with the following additions:
60       *
61       * <ul>
62       * <li>The @ symbol is an escapable character.</li>
63       * <li>Everything after the first unescaped @ symbol will be treated as the textual representation
64       * of the keystroke accelerator.</li>
65       * </ul>
66       *
67       * The expected format of the keystroke accelerator string is as described in the javadocs for the
68       * {@link KeyStroke#getKeyStroke(String)} method.
69       *
70       *
71       * @param labelDescriptor The label descriptor. May be null or empty, in which case, a default
72       * blank label info will be returned.
73       * @return A CommandButtonLabelInfo instance, never null.
74       *
75       * @throws IllegalArgumentException if {@code labelDescriptor} contains invalid syntax.
76       *
77       * @see LabelInfo
78       * @see KeyStroke
79       */
80      public static CommandButtonLabelInfo valueOf(String labelDescriptor) {
81  
82          if (!StringUtils.hasText(labelDescriptor)) {
83              return BLANK_BUTTON_LABEL;
84          }
85  
86          StringBuffer labelInfoBuffer = new StringBuffer();
87          char currentChar;
88          KeyStroke keyStroke = null;
89  
90          for (int i = 0, textCharsIndex = 0; i < labelDescriptor.length(); i++, textCharsIndex++) {
91              currentChar = labelDescriptor.charAt(i);
92  
93              if (currentChar == '\\') {
94                  int nextCharIndex = i + 1;
95                  //if this backslash is escaping an @ symbol, we remove the backslash and
96                  //continue with the next char
97                  if (nextCharIndex < labelDescriptor.length()) {
98                      char nextChar = labelDescriptor.charAt(nextCharIndex);
99  
100                     if (nextChar == '@') {
101                         labelInfoBuffer.append(nextChar);
102                         i++;
103                     } else {
104                         labelInfoBuffer.append(currentChar);
105                         labelInfoBuffer.append(nextChar);
106                         i++;
107                     }
108 
109                 }
110 
111             }
112             else if (currentChar == '@') {
113                 //we've found the accelerator indicator
114 
115                 if (i + 1 == labelDescriptor.length()) {
116                     throw new IllegalArgumentException(
117                             "The label descriptor ["
118                             + labelDescriptor
119                             + "] does not specify a valid accelerator after the last "
120                             + "non-espaced @ symbol.");
121                 }
122 
123                 String acceleratorStr = labelDescriptor.substring(i + 1);
124                 keyStroke = KeyStroke.getKeyStroke(acceleratorStr);
125 
126                 if (keyStroke == null) {
127                     throw new IllegalArgumentException(
128                             "The keystroke accelerator string ["
129                             + acceleratorStr
130                             + "] from the label descriptor ["
131                             + labelDescriptor
132                             + "] is not a valid keystroke format.");
133                 }
134 
135                 break;
136 
137             }
138             else {
139                 labelInfoBuffer.append(currentChar);
140             }
141 
142         }
143 
144         LabelInfo info = LabelInfo.valueOf(labelInfoBuffer.toString());
145 
146         return new CommandButtonLabelInfo(info, keyStroke);
147 
148     }
149 
150     /**
151      * Creates a new {@code CommandButtonLabelInfo} that will display the given text on its label.
152      * There will be no associated mnemonic character and no keystroke accelerator.
153      *
154      * @param text The label text to be displayed. Must not be null.
155      *
156      * @throws IllegalArgumentException if {@code text} is null.
157      */
158     public CommandButtonLabelInfo(String text) {
159         this(new LabelInfo(text), null);
160     }
161 
162     /**
163      * Creates a new {@code CommandButtonLabelInfo} with the given label information and keystroke
164      * accelerator.
165      *
166      * @param labelInfo The label information. Must not be null.
167      * @param accelerator The keystroke accelerator. May be null.
168      *
169      * @throws IllegalArgumentException if {@code labelInfo} is null.
170      */
171     public CommandButtonLabelInfo(LabelInfo labelInfo, KeyStroke accelerator) {
172         Assert.required(labelInfo, "labelInfo");
173         this.labelInfo = labelInfo;
174         this.accelerator = accelerator;
175     }
176 
177     /**
178      * Returns the displayable text.
179      *
180      * @return The label text. Maybe an empty string but never null.
181      */
182     public String getText() {
183         return this.labelInfo.getText();
184     }
185 
186     /**
187      * Returns the mnemonic for the label.
188      *
189      * @return The mnemonic for the label.
190      */
191     public int getMnemonic() {
192         return this.labelInfo.getMnemonic();
193     }
194 
195     /**
196      * Returns the zero-based index for the mnemonic character within the label text.
197      *
198      * @return The mnemonic index or -1 to indicate that there is no associated mnemonic character.
199      */
200     public int getMnemonicIndex() {
201         return this.labelInfo.getMnemonicIndex();
202     }
203 
204     /**
205      * Returns the keystroke accelerator for the label.
206      *
207      * @return The keystroke accelerator, or null.
208      */
209     public KeyStroke getAccelerator() {
210         return this.accelerator;
211     }
212 
213     /**
214      * {@inheritDoc}
215      */
216     public int hashCode() {
217         return this.labelInfo.hashCode() + (this.accelerator != null ? this.accelerator.hashCode() : 0);
218     }
219 
220     /**
221      * {@inheritDoc}
222      */
223     public boolean equals(Object obj) {
224 
225         if (obj == this) {
226             return true;
227         }
228 
229         if (!(obj instanceof CommandButtonLabelInfo)) {
230             return false;
231         }
232 
233         CommandButtonLabelInfo other = (CommandButtonLabelInfo)obj;
234 
235         if (!this.labelInfo.equals(other.labelInfo)) {
236             return false;
237         }
238 
239         if (!ObjectUtils.nullSafeEquals(this.accelerator, other.accelerator)) {
240             return false;
241         }
242 
243         return true;
244 
245     }
246 
247     /**
248      * Configures an existing button appropriately based on this label info's
249      * properties.
250      *
251      * @param button
252      */
253     public AbstractButton configure(AbstractButton button) {
254         Assert.notNull(button);
255         button.setText(this.labelInfo.getText());
256         button.setMnemonic(this.labelInfo.getMnemonic());
257         button.setDisplayedMnemonicIndex(this.labelInfo.getMnemonicIndex());
258         configureAccelerator(button, getAccelerator());
259         return button;
260     }
261 
262     /**
263      * Sets the given keystroke accelerator on the given button.
264      *
265      * @param button The button. May be null.
266      * @param keystrokeAccelerator The accelerator. May be null.
267      */
268     protected void configureAccelerator(AbstractButton button, KeyStroke keystrokeAccelerator) {
269         if ((button instanceof JMenuItem) && !(button instanceof JMenu)) {
270             ((JMenuItem)button).setAccelerator(keystrokeAccelerator);
271         }
272     }
273 
274     /**
275      * {@inheritDoc}
276      */
277     public String toString() {
278         return new ToStringCreator(this)
279                 .append("labelInfo", this.labelInfo)
280                 .append("accelerator", this.accelerator)
281                 .toString();
282     }
283 
284 }