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