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 }
|