SwingAction.java
001 /*
002  * Copyright 2008-2017 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 import griffon.core.RunnableWithArgs;
020 
021 import javax.annotation.Nonnull;
022 import javax.annotation.Nullable;
023 import javax.swing.AbstractAction;
024 import javax.swing.Action;
025 import javax.swing.Icon;
026 import javax.swing.KeyStroke;
027 import java.awt.event.ActionEvent;
028 
029 import static griffon.util.GriffonNameUtils.isBlank;
030 import static java.util.Objects.requireNonNull;
031 
032 /**
033  * An action implementation that relies on a closure to handle events.
034  *
035  @author Andres Almiray
036  @since 2.0.0
037  */
038 public class SwingAction extends AbstractAction {
039     private static final long serialVersionUID = 4493562556110760713L;
040     private static final String ERROR_CALLABLE_NULL = "Argument 'callable' must not be null";
041     private static final String ERROR_RUNNABLE_NULL = "Argument 'runnable' must not be null";
042     private transient RunnableWithArgs runnable;
043 
044     /**
045      * Creates a new action.
046      *
047      @param callable
048      @deprecated use the {@code RunnableWithArgs} constructor instead.
049      */
050     @Deprecated
051     public SwingAction(@Nonnull final CallableWithArgs<?> callable) {
052         requireNonNull(callable, ERROR_CALLABLE_NULL);
053         this.runnable = new RunnableWithArgs() {
054             @Override
055             public void run(@Nullable Object... args) {
056                 callable.call(args);
057             }
058         };
059     }
060 
061     public SwingAction(@Nonnull RunnableWithArgs runnable) {
062         this.runnable = requireNonNull(runnable, ERROR_RUNNABLE_NULL);
063     }
064 
065     @Nonnull
066     public static ActionBuilder action() {
067         return new ActionBuilder();
068     }
069 
070     @Nonnull
071     public static ActionBuilder action(@Nullable Action action) {
072         return new ActionBuilder(action);
073     }
074 
075     @Nonnull
076     public static ActionBuilder action(@Nullable String name) {
077         return new ActionBuilder().withName(name);
078     }
079 
080     public final void actionPerformed(ActionEvent evt) {
081         runnable.run(evt);
082     }
083 
084     /**
085      * A builder for actions.
086      *
087      @author Andres Almiray
088      @since 2.0.0
089      */
090     public static class ActionBuilder {
091         private String name;
092         private int mnemonic;
093         private KeyStroke accelerator;
094         private String shortDescription;
095         private String longDescription;
096         private String command;
097         private Icon smallIcon;
098         private Icon largeIcon;
099         private RunnableWithArgs runnable;
100         private boolean enabled = true;
101         private boolean selected = false;
102 
103         private Action action;
104         private boolean mnemonicSet = false;
105         private boolean enabledSet = false;
106         private boolean selectedSet = false;
107 
108         public ActionBuilder() {
109             this(null);
110         }
111 
112         @Nonnull
113         public ActionBuilder(@Nullable Action action) {
114             this.action = action;
115         }
116 
117         @Nonnull
118         public ActionBuilder withName(@Nullable String name) {
119             this.name = name;
120             return this;
121         }
122 
123         @Nonnull
124         public ActionBuilder withShortDescription(@Nullable String shortDescription) {
125             this.shortDescription = shortDescription;
126             return this;
127         }
128 
129         @Nonnull
130         public ActionBuilder withLongDescription(@Nullable String longDescription) {
131             this.longDescription = longDescription;
132             return this;
133         }
134 
135         @Nonnull
136         public ActionBuilder withCommand(@Nullable String command) {
137             this.command = command;
138             return this;
139         }
140 
141         @Nonnull
142         public ActionBuilder withMnemonic(@Nullable String mnemonic) {
143             if (!isBlank(mnemonic)) {
144                 this.mnemonic = KeyStroke.getKeyStroke(mnemonic).getKeyCode();
145             }
146             mnemonicSet = true;
147             return this;
148         }
149 
150         @Nonnull
151         public ActionBuilder withMnemonic(int mnemonic) {
152             this.mnemonic = mnemonic;
153             mnemonicSet = true;
154             return this;
155         }
156 
157         @Nonnull
158         public ActionBuilder withAccelerator(@Nullable String accelerator) {
159             if (!isBlank(accelerator)) {
160                 this.accelerator = KeyStroke.getKeyStroke(accelerator);
161             }
162             return this;
163         }
164 
165         @Nonnull
166         public ActionBuilder withAccelerator(@Nullable KeyStroke accelerator) {
167             this.accelerator = accelerator;
168             return this;
169         }
170 
171         @Nonnull
172         public ActionBuilder withSmallIcon(@Nullable Icon smallIcon) {
173             this.smallIcon = smallIcon;
174             return this;
175         }
176 
177         @Nonnull
178         public ActionBuilder withLargeIcon(@Nullable Icon largeIcon) {
179             this.largeIcon = largeIcon;
180             return this;
181         }
182 
183         @Nonnull
184         @Deprecated
185         public ActionBuilder withRunnable(@Nullable final CallableWithArgs<?> callable) {
186             requireNonNull(callable, ERROR_CALLABLE_NULL);
187             this.runnable = new RunnableWithArgs() {
188                 @Override
189                 public void run(@Nullable Object... args) {
190                     callable.call(args);
191                 }
192             };
193             return this;
194         }
195 
196         @Nonnull
197         public ActionBuilder withRunnable(@Nullable RunnableWithArgs runnable) {
198             this.runnable = runnable;
199             return this;
200         }
201 
202         @Nonnull
203         public ActionBuilder withEnabled(boolean enabled) {
204             this.enabled = enabled;
205             this.enabledSet = true;
206             return this;
207         }
208 
209         @Nonnull
210         public ActionBuilder withSelected(boolean selected) {
211             this.selected = selected;
212             this.enabledSet = true;
213             return this;
214         }
215 
216         @Nonnull
217         public Action build() {
218             if (runnable == null && action == null) {
219                 throw new IllegalArgumentException("Either runnable, callable, or action must have a value.");
220             }
221             if (action == null) {
222                 action = new SwingAction(runnable);
223             }
224             if (!isBlank(command)) {
225                 action.putValue(Action.ACTION_COMMAND_KEY, command);
226             }
227             if (!isBlank(name)) {
228                 action.putValue(Action.NAME, name);
229             }
230             if (mnemonicSet) {
231                 action.putValue(Action.MNEMONIC_KEY, mnemonic);
232             }
233             if (accelerator != null) {
234                 action.putValue(Action.ACCELERATOR_KEY, accelerator);
235             }
236             if (largeIcon != null) {
237                 action.putValue(Action.LARGE_ICON_KEY, largeIcon);
238             }
239             if (smallIcon != null) {
240                 action.putValue(Action.SMALL_ICON, smallIcon);
241             }
242             if (!isBlank(longDescription)) {
243                 action.putValue(Action.LONG_DESCRIPTION, longDescription);
244             }
245             if (!isBlank(shortDescription)) {
246                 action.putValue(Action.SHORT_DESCRIPTION, shortDescription);
247             }
248             if (enabledSet) {
249                 action.setEnabled(enabled);
250             }
251             if (selectedSet) {
252                 action.putValue(Action.SELECTED_KEY, selected);
253             }
254             return action;
255         }
256     }
257 }