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