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