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