SwingAction.java
001 /*
002  * Copyright 2008-2015 the original author or authors.
003  *
004  * Licensed under the Apache License, Version 2.0 (the "License");
005  * you may not use this file except in compliance with the License.
006  * You may obtain a copy of 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,
012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013  * See the License for the specific language governing permissions and
014  * limitations under the License.
015  */
016 package griffon.swing.support;
017 
018 import griffon.core.CallableWithArgs;
019 
020 import javax.annotation.Nonnull;
021 import javax.annotation.Nullable;
022 import javax.swing.AbstractAction;
023 import javax.swing.Action;
024 import javax.swing.Icon;
025 import javax.swing.KeyStroke;
026 import java.awt.event.ActionEvent;
027 
028 import static griffon.util.GriffonNameUtils.isBlank;
029 import static java.util.Objects.requireNonNull;
030 
031 /**
032  * An action implementation that relies on a closure to handle events.
033  *
034  @author Andres Almiray
035  @since 2.0.0
036  */
037 public class SwingAction extends AbstractAction {
038     private static final long serialVersionUID = 4598888514827528435L;
039     private static final String ERROR_CALLABLE_NULL = "Argument 'callable' must not be null";
040     private final CallableWithArgs<?> callable;
041 
042     public SwingAction(@Nonnull CallableWithArgs<?> callable) {
043         this.callable = requireNonNull(callable, ERROR_CALLABLE_NULL);
044     }
045 
046     public final void actionPerformed(ActionEvent evt) {
047         callable.call(evt);
048     }
049 
050     @Nonnull
051     public static ActionBuilder action() {
052         return new ActionBuilder();
053     }
054 
055     @Nonnull
056     public static ActionBuilder action(@Nullable Action action) {
057         return new ActionBuilder(action);
058     }
059 
060     @Nonnull
061     public static ActionBuilder action(@Nullable String name) {
062         return new ActionBuilder().withName(name);
063     }
064 
065     /**
066      * A builder for actions.
067      *
068      @author Andres Almiray
069      @since 2.0.0
070      */
071     public static class ActionBuilder {
072         private String name;
073         private int mnemonic;
074         private KeyStroke accelerator;
075         private String shortDescription;
076         private String longDescription;
077         private String command;
078         private Icon smallIcon;
079         private Icon largeIcon;
080         private CallableWithArgs<?> callable;
081         private boolean enabled = true;
082         private boolean selected = false;
083 
084         private Action action;
085         private boolean mnemonicSet = false;
086         private boolean enabledSet = false;
087         private boolean selectedSet = false;
088 
089         public ActionBuilder() {
090             this(null);
091         }
092 
093         @Nonnull
094         public ActionBuilder(@Nullable Action action) {
095             this.action = action;
096         }
097 
098         @Nonnull
099         public ActionBuilder withName(@Nullable String name) {
100             this.name = name;
101             return this;
102         }
103 
104         @Nonnull
105         public ActionBuilder withShortDescription(@Nullable String shortDescription) {
106             this.shortDescription = shortDescription;
107             return this;
108         }
109 
110         @Nonnull
111         public ActionBuilder withLongDescription(@Nullable String longDescription) {
112             this.longDescription = longDescription;
113             return this;
114         }
115 
116         @Nonnull
117         public ActionBuilder withCommand(@Nullable String command) {
118             this.command = command;
119             return this;
120         }
121 
122         @Nonnull
123         public ActionBuilder withMnemonic(@Nullable String mnemonic) {
124             if (!isBlank(mnemonic)) {
125                 this.mnemonic = KeyStroke.getKeyStroke(mnemonic).getKeyCode();
126             }
127             mnemonicSet = true;
128             return this;
129         }
130 
131         @Nonnull
132         public ActionBuilder withMnemonic(int mnemonic) {
133             this.mnemonic = mnemonic;
134             mnemonicSet = true;
135             return this;
136         }
137 
138         @Nonnull
139         public ActionBuilder withAccelerator(@Nullable String accelerator) {
140             if (!isBlank(accelerator)) {
141                 this.accelerator = KeyStroke.getKeyStroke(accelerator);
142             }
143             return this;
144         }
145 
146         @Nonnull
147         public ActionBuilder withAccelerator(@Nullable KeyStroke accelerator) {
148             this.accelerator = accelerator;
149             return this;
150         }
151 
152         @Nonnull
153         public ActionBuilder withSmallIcon(@Nullable Icon smallIcon) {
154             this.smallIcon = smallIcon;
155             return this;
156         }
157 
158         @Nonnull
159         public ActionBuilder withLargeIcon(@Nullable Icon largeIcon) {
160             this.largeIcon = largeIcon;
161             return this;
162         }
163 
164         @Nonnull
165         public ActionBuilder withRunnable(@Nullable CallableWithArgs<?> callable) {
166             this.callable = callable;
167             return this;
168         }
169 
170         @Nonnull
171         public ActionBuilder withEnabled(boolean enabled) {
172             this.enabled = enabled;
173             this.enabledSet = true;
174             return this;
175         }
176 
177         @Nonnull
178         public ActionBuilder withSelected(boolean selected) {
179             this.selected = selected;
180             this.enabledSet = true;
181             return this;
182         }
183 
184         @Nonnull
185         public Action build() {
186             if (callable == null && action == null) {
187                 throw new IllegalArgumentException("Either closure: or action: must have a value.");
188             }
189             if (action == null) {
190                 action = new SwingAction(callable);
191             }
192             if (!isBlank(command)) {
193                 action.putValue(Action.ACTION_COMMAND_KEY, command);
194             }
195             if (!isBlank(name)) {
196                 action.putValue(Action.NAME, name);
197             }
198             if (mnemonicSet) {
199                 action.putValue(Action.MNEMONIC_KEY, mnemonic);
200             }
201             if (accelerator != null) {
202                 action.putValue(Action.ACCELERATOR_KEY, accelerator);
203             }
204             if (largeIcon != null) {
205                 action.putValue(Action.LARGE_ICON_KEY, largeIcon);
206             }
207             if (smallIcon != null) {
208                 action.putValue(Action.SMALL_ICON, smallIcon);
209             }
210             if (!isBlank(longDescription)) {
211                 action.putValue(Action.LONG_DESCRIPTION, longDescription);
212             }
213             if (!isBlank(shortDescription)) {
214                 action.putValue(Action.SHORT_DESCRIPTION, shortDescription);
215             }
216             if (enabledSet) {
217                 action.setEnabled(enabled);
218             }
219             if (selectedSet) {
220                 action.putValue(Action.SELECTED_KEY, selected);
221             }
222             return action;
223         }
224     }
225 }