1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.springframework.richclient.command;
17
18 import java.awt.Color;
19 import java.awt.Container;
20 import java.beans.PropertyChangeEvent;
21 import java.beans.PropertyChangeListener;
22 import java.util.Collections;
23 import java.util.Iterator;
24 import java.util.Map;
25 import java.util.NoSuchElementException;
26
27 import javax.swing.AbstractButton;
28 import javax.swing.Icon;
29 import javax.swing.JComponent;
30 import javax.swing.JMenuItem;
31 import javax.swing.KeyStroke;
32 import javax.swing.SwingUtilities;
33
34 import org.springframework.beans.factory.BeanNameAware;
35 import org.springframework.beans.factory.InitializingBean;
36 import org.springframework.binding.value.support.AbstractPropertyChangePublisher;
37 import org.springframework.core.style.ToStringCreator;
38 import org.springframework.richclient.application.ApplicationServicesLocator;
39 import org.springframework.richclient.command.config.CommandButtonConfigurer;
40 import org.springframework.richclient.command.config.CommandButtonIconInfo;
41 import org.springframework.richclient.command.config.CommandButtonLabelInfo;
42 import org.springframework.richclient.command.config.CommandFaceDescriptor;
43 import org.springframework.richclient.command.config.CommandFaceDescriptorRegistry;
44 import org.springframework.richclient.command.support.CommandFaceButtonManager;
45 import org.springframework.richclient.core.SecurityControllable;
46 import org.springframework.richclient.factory.ButtonFactory;
47 import org.springframework.richclient.factory.ComponentFactory;
48 import org.springframework.richclient.factory.MenuFactory;
49 import org.springframework.util.Assert;
50 import org.springframework.util.CachingMapDecorator;
51 import org.springframework.util.StringUtils;
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74 public abstract class AbstractCommand extends AbstractPropertyChangePublisher implements InitializingBean,
75 BeanNameAware, GuardedActionCommandExecutor, SecurityControllable {
76
77
78 public static final String ENABLED_PROPERTY_NAME = "enabled";
79
80
81 public static final String VISIBLE_PROPERTY_NAME = "visible";
82
83 private static final String DEFAULT_FACE_DESCRIPTOR_ID = "default";
84
85 private String id;
86
87 private String defaultFaceDescriptorId = DEFAULT_FACE_DESCRIPTOR_ID;
88
89 private boolean enabled = true;
90
91 private boolean visible = true;
92
93 private boolean authorized = true;
94
95 private String securityControllerId = null;
96
97 private Map faceButtonManagers;
98
99 private CommandServices commandServices;
100
101 private CommandFaceDescriptorRegistry faceDescriptorRegistry;
102
103 private Boolean oldEnabledState;
104
105 private Boolean oldVisibleState;
106
107
108
109
110
111
112 protected AbstractCommand() {
113 this(null);
114 }
115
116
117
118
119
120
121 protected AbstractCommand(String id) {
122 super();
123 setId(id);
124
125 addEnabledListener(new ButtonEnablingListener());
126
127 addPropertyChangeListener(VISIBLE_PROPERTY_NAME, new ButtonVisibleListener());
128 }
129
130
131
132
133
134
135
136
137
138 protected AbstractCommand(String id, String encodedLabel) {
139 this(id, new CommandFaceDescriptor(encodedLabel));
140 }
141
142
143
144
145
146
147
148
149
150
151 protected AbstractCommand(String id, String encodedLabel, Icon icon, String caption) {
152 this(id, new CommandFaceDescriptor(encodedLabel, icon, caption));
153 }
154
155
156
157
158
159
160
161 protected AbstractCommand(String id, CommandFaceDescriptor faceDescriptor) {
162 this(id);
163 if (faceDescriptor != null) {
164 setFaceDescriptor(faceDescriptor);
165 }
166 }
167
168
169
170
171
172
173
174
175
176 protected AbstractCommand(String id, Map faceDescriptors) {
177 this(id);
178 setFaceDescriptors(faceDescriptors);
179 }
180
181
182
183
184 public String getId() {
185 return this.id;
186 }
187
188
189
190
191
192
193
194 protected void setId(String id) {
195 if (!StringUtils.hasText(id)) {
196 id = null;
197 }
198 this.id = id;
199 }
200
201
202
203
204 public void setBeanName(String name) {
205 if (getId() == null) {
206 setId(name);
207 }
208 }
209
210
211
212
213
214
215
216 public void setFaceDescriptor(CommandFaceDescriptor faceDescriptor) {
217 setFaceDescriptor(getDefaultFaceDescriptorId(), faceDescriptor);
218 }
219
220
221
222
223
224
225
226 public void setFaceDescriptor(String faceDescriptorId, CommandFaceDescriptor faceDescriptor) {
227 getButtonManager(faceDescriptorId).setFaceDescriptor(faceDescriptor);
228 }
229
230
231
232
233
234
235
236 public void setFaceDescriptors(Map faceDescriptors) {
237 Assert.notNull(faceDescriptors);
238 Iterator it = faceDescriptors.entrySet().iterator();
239 while (it.hasNext()) {
240 Map.Entry entry = (Map.Entry) it.next();
241 String faceDescriptorId = (String) entry.getKey();
242 CommandFaceDescriptor faceDescriptor = (CommandFaceDescriptor) entry.getValue();
243 setFaceDescriptor(faceDescriptorId, faceDescriptor);
244 }
245 }
246
247
248
249
250
251
252
253 public void setDefaultFaceDescriptorId(String defaultFaceDescriptorId) {
254 this.defaultFaceDescriptorId = defaultFaceDescriptorId;
255 }
256
257
258
259
260
261
262
263
264 public void setFaceDescriptorRegistry(CommandFaceDescriptorRegistry faceDescriptorRegistry) {
265 this.faceDescriptorRegistry = faceDescriptorRegistry;
266 }
267
268
269
270
271 public void setCommandServices(CommandServices services) {
272 this.commandServices = services;
273 }
274
275
276
277
278
279
280 public void setLabel(String encodedLabel) {
281 getOrCreateFaceDescriptor().setButtonLabelInfo(encodedLabel);
282 }
283
284
285
286
287
288
289 public void setLabel(CommandButtonLabelInfo label) {
290 getOrCreateFaceDescriptor().setLabelInfo(label);
291 }
292
293
294
295
296
297
298 public void setCaption(String shortDescription) {
299 getOrCreateFaceDescriptor().setCaption(shortDescription);
300 }
301
302
303
304
305
306
307 public void setIcon(Icon icon) {
308 getOrCreateFaceDescriptor().setIcon(icon);
309 }
310
311
312
313
314
315
316 public void setIconInfo(CommandButtonIconInfo iconInfo) {
317 getOrCreateFaceDescriptor().setIconInfo(iconInfo);
318 }
319
320
321
322
323
324
325 public void setForeground(Color foreground) {
326 getOrCreateFaceDescriptor().setForeground(foreground);
327 }
328
329
330
331
332
333
334 public void setBackground(Color background) {
335 getOrCreateFaceDescriptor().setBackground(background);
336 }
337
338
339
340
341
342
343 public void afterPropertiesSet() {
344 if (getId() == null) {
345 logger.info("Command " + this + " has no set id; note: anonymous commands cannot be used in registries.");
346 }
347 if (this instanceof ActionCommand && !isFaceConfigured()) {
348 logger.warn("The face descriptor property is not yet set for action command '" + getId()
349 + "'; command won't render correctly until this is configured");
350 }
351 }
352
353
354
355
356 private CommandFaceDescriptor getOrCreateFaceDescriptor() {
357 if (!isFaceConfigured()) {
358 if (logger.isInfoEnabled()) {
359 logger.info("Lazily instantiating default face descriptor on behalf of caller to prevent npe; "
360 + "command is being configured manually, right?");
361 }
362 setFaceDescriptor(new CommandFaceDescriptor());
363 }
364 return getFaceDescriptor();
365 }
366
367
368
369
370 public String getDefaultFaceDescriptorId() {
371 if (!StringUtils.hasText(defaultFaceDescriptorId)) {
372 return DEFAULT_FACE_DESCRIPTOR_ID;
373 }
374 return defaultFaceDescriptorId;
375 }
376
377
378
379
380 protected CommandFaceDescriptor getFaceDescriptor() {
381 return getDefaultButtonManager().getFaceDescriptor();
382 }
383
384
385
386
387 public boolean isFaceConfigured() {
388 return getDefaultButtonManager().isFaceConfigured();
389 }
390
391
392
393
394
395 public Icon getIcon() {
396 if (isFaceConfigured()) {
397 return getFaceDescriptor().getIcon();
398 }
399 return null;
400 }
401
402
403
404
405
406 public String getText() {
407 if (isFaceConfigured()) {
408 return getFaceDescriptor().getText();
409 }
410 return CommandButtonLabelInfo.BLANK_BUTTON_LABEL.getText();
411 }
412
413
414
415
416
417
418 public int getMnemonic() {
419 if (isFaceConfigured()) {
420 return getFaceDescriptor().getMnemonic();
421 }
422 return CommandButtonLabelInfo.BLANK_BUTTON_LABEL.getMnemonic();
423 }
424
425
426
427
428
429
430 public int getMnemonicIndex() {
431 if (isFaceConfigured()) {
432 return getFaceDescriptor().getMnemonicIndex();
433 }
434 return CommandButtonLabelInfo.BLANK_BUTTON_LABEL.getMnemonicIndex();
435 }
436
437
438
439
440
441
442 public KeyStroke getAccelerator() {
443 if (isFaceConfigured()) {
444 return getFaceDescriptor().getAccelerator();
445 }
446 return CommandButtonLabelInfo.BLANK_BUTTON_LABEL.getAccelerator();
447 }
448
449
450
451
452
453 public CommandFaceDescriptorRegistry getFaceDescriptorRegistry() {
454 return faceDescriptorRegistry;
455 }
456
457
458
459
460 protected CommandServices getCommandServices() {
461 if (commandServices == null) {
462 commandServices = (CommandServices) ApplicationServicesLocator.services().getService(CommandServices.class);
463 }
464 return this.commandServices;
465 }
466
467
468
469
470
471 public void setSecurityControllerId(String controllerId) {
472 this.securityControllerId = controllerId;
473 }
474
475
476
477
478
479
480 public String getSecurityControllerId() {
481 return securityControllerId;
482 }
483
484
485
486
487
488
489
490
491 public void setAuthorized(boolean authorized) {
492 boolean wasAuthorized = isAuthorized();
493 if (hasChanged(wasAuthorized, authorized)) {
494 this.authorized = authorized;
495 firePropertyChange(AUTHORIZED_PROPERTY, wasAuthorized, authorized);
496 updatedEnabledState();
497 }
498 }
499
500
501
502
503 public boolean isAuthorized() {
504 return authorized;
505 }
506
507
508
509
510
511
512
513 public boolean isEnabled() {
514 return enabled && isAuthorized();
515 }
516
517
518
519
520
521
522
523
524
525 protected void updatedEnabledState() {
526 boolean isEnabled = isEnabled();
527 if (oldEnabledState == null || hasChanged(oldEnabledState.booleanValue(), isEnabled)) {
528 firePropertyChange(ENABLED_PROPERTY_NAME, oldEnabledState == null ? !isEnabled : oldEnabledState
529 .booleanValue(), isEnabled);
530 }
531 oldEnabledState = Boolean.valueOf(isEnabled);
532 }
533
534
535
536
537
538
539
540 public void setEnabled(boolean enabled) {
541 if (hasChanged(this.enabled, enabled)) {
542 this.enabled = enabled;
543 updatedEnabledState();
544 }
545 }
546
547
548
549
550
551 private class ButtonEnablingListener implements PropertyChangeListener {
552 public void propertyChange(PropertyChangeEvent evt) {
553
554
555
556
557
558 boolean enabled = evt.getNewValue() == Boolean.TRUE;
559 Iterator it = buttonIterator();
560 while (it.hasNext()) {
561 AbstractButton button = (AbstractButton) it.next();
562 button.setEnabled(enabled);
563 }
564 }
565 }
566
567
568
569
570
571 private class ButtonVisibleListener implements PropertyChangeListener {
572 public void propertyChange(PropertyChangeEvent evt) {
573
574
575
576
577
578 boolean enabled = evt.getNewValue() == Boolean.TRUE;
579 Iterator it = buttonIterator();
580 while (it.hasNext()) {
581 AbstractButton button = (AbstractButton) it.next();
582 button.setVisible(enabled);
583 }
584 }
585 }
586
587
588
589
590 public void addEnabledListener(PropertyChangeListener listener) {
591 addPropertyChangeListener(ENABLED_PROPERTY_NAME, listener);
592 }
593
594
595
596
597 public void removeEnabledListener(PropertyChangeListener listener) {
598 removePropertyChangeListener(ENABLED_PROPERTY_NAME, listener);
599 }
600
601
602
603
604
605
606
607
608
609
610
611 protected final Iterator defaultButtonIterator() {
612 return getDefaultButtonManager().iterator();
613 }
614
615
616
617
618
619 protected final Iterator buttonIterator() {
620
621 if (this.faceButtonManagers == null)
622 return Collections.EMPTY_SET.iterator();
623
624 return new NestedButtonIterator(this.faceButtonManagers.values().iterator());
625 }
626
627
628
629
630
631 private static final class NestedButtonIterator implements Iterator {
632 private final Iterator managerIterator;
633
634 private Iterator currentButtonIterator;
635
636 private AbstractButton nextButton;
637
638 NestedButtonIterator(Iterator it) {
639 this.managerIterator = it;
640 preFetchNextButton();
641 }
642
643 public boolean hasNext() {
644 return nextButton != null;
645 }
646
647 public Object next() {
648 if (nextButton == null) {
649 throw new NoSuchElementException();
650 }
651 AbstractButton lastButton = nextButton;
652 preFetchNextButton();
653 return lastButton;
654 }
655
656 public void remove() {
657 throw new UnsupportedOperationException("Can't use a button-iterator on AbstractCommand to remove buttons.");
658 }
659
660 private void preFetchNextButton() {
661 while (this.currentButtonIterator == null || !this.currentButtonIterator.hasNext()) {
662 if (this.managerIterator.hasNext()) {
663 CommandFaceButtonManager cfbm = (CommandFaceButtonManager) this.managerIterator.next();
664 this.currentButtonIterator = cfbm.iterator();
665 }
666 else {
667 this.currentButtonIterator = null;
668 this.nextButton = null;
669 return;
670 }
671 }
672
673 if (this.currentButtonIterator.hasNext())
674 nextButton = (AbstractButton) this.currentButtonIterator.next();
675 else
676 nextButton = null;
677 }
678 }
679
680
681
682
683 public boolean isAnonymous() {
684 return id == null;
685 }
686
687
688
689
690 public boolean isVisible() {
691 return this.visible;
692 }
693
694
695
696
697 public void setVisible(boolean value) {
698 if (visible != value) {
699 this.visible = value;
700 updatedVisibleState();
701 }
702 }
703
704
705
706
707
708
709
710
711
712
713
714
715 protected void updatedVisibleState() {
716 boolean isVisible = isVisible();
717 if (oldVisibleState == null || hasChanged(oldVisibleState.booleanValue(), isVisible)) {
718 firePropertyChange(VISIBLE_PROPERTY_NAME, oldVisibleState == null ? !isVisible : oldVisibleState
719 .booleanValue(), isVisible);
720 }
721 oldVisibleState = Boolean.valueOf(isVisible);
722 }
723
724
725
726
727
728
729
730 public final AbstractButton createButton() {
731 return createButton(getDefaultFaceDescriptorId(), getButtonFactory(), getDefaultButtonConfigurer());
732 }
733
734
735
736
737
738
739
740 public final AbstractButton createButton(String faceDescriptorId) {
741 return createButton(faceDescriptorId, getButtonFactory(), getDefaultButtonConfigurer());
742 }
743
744
745
746
747
748
749
750 public final AbstractButton createButton(ButtonFactory buttonFactory) {
751 return createButton(getDefaultFaceDescriptorId(), buttonFactory, getDefaultButtonConfigurer());
752 }
753
754
755
756
757
758
759 public final AbstractButton createButton(String faceDescriptorId, ButtonFactory buttonFactory) {
760 return createButton(faceDescriptorId, buttonFactory, getDefaultButtonConfigurer());
761 }
762
763
764
765
766
767
768 public final AbstractButton createButton(ButtonFactory buttonFactory, CommandButtonConfigurer buttonConfigurer) {
769 return createButton(getDefaultFaceDescriptorId(), buttonFactory, buttonConfigurer);
770 }
771
772
773
774
775
776
777
778
779
780
781
782 public AbstractButton createButton(String faceDescriptorId, ButtonFactory buttonFactory,
783 CommandButtonConfigurer buttonConfigurer) {
784 AbstractButton button = buttonFactory.createButton();
785 attach(button, faceDescriptorId, buttonConfigurer);
786 return button;
787 }
788
789
790
791
792
793
794
795 public final JMenuItem createMenuItem() {
796 return createMenuItem(getDefaultFaceDescriptorId(), getMenuFactory(), getMenuItemButtonConfigurer());
797 }
798
799
800
801
802
803
804
805 public final JMenuItem createMenuItem(String faceDescriptorId) {
806 return createMenuItem(faceDescriptorId, getMenuFactory(), getMenuItemButtonConfigurer());
807 }
808
809
810
811
812
813
814
815 public final JMenuItem createMenuItem(MenuFactory menuFactory) {
816 return createMenuItem(getDefaultFaceDescriptorId(), menuFactory, getMenuItemButtonConfigurer());
817 }
818
819
820
821
822
823
824 public final JMenuItem createMenuItem(String faceDescriptorId, MenuFactory menuFactory) {
825 return createMenuItem(faceDescriptorId, menuFactory, getMenuItemButtonConfigurer());
826 }
827
828
829
830
831
832
833 public final JMenuItem createMenuItem(MenuFactory menuFactory, CommandButtonConfigurer buttonConfigurer) {
834 return createMenuItem(getDefaultFaceDescriptorId(), menuFactory, buttonConfigurer);
835 }
836
837
838
839
840
841
842
843
844
845
846
847 public JMenuItem createMenuItem(String faceDescriptorId, MenuFactory menuFactory,
848 CommandButtonConfigurer buttonConfigurer) {
849 JMenuItem menuItem = menuFactory.createMenuItem();
850 attach(menuItem, faceDescriptorId, buttonConfigurer);
851 return menuItem;
852 }
853
854
855
856
857
858
859
860 public void attach(AbstractButton button) {
861 attach(button, getDefaultFaceDescriptorId(), getCommandServices().getDefaultButtonConfigurer());
862 }
863
864
865
866
867
868
869
870 public void attach(AbstractButton button, CommandButtonConfigurer configurer) {
871 attach(button, getDefaultFaceDescriptorId(), configurer);
872 }
873
874
875
876
877
878
879
880
881 public void attach(AbstractButton button, String faceDescriptorId, CommandButtonConfigurer configurer) {
882 getButtonManager(faceDescriptorId).attachAndConfigure(button, configurer);
883 onButtonAttached(button);
884 }
885
886
887
888
889
890
891 protected void onButtonAttached(AbstractButton button) {
892 if (logger.isDebugEnabled()) {
893 logger.debug("Configuring newly attached button for command '" + getId() + "' enabled=" + isEnabled()
894 + ", visible=" + isVisible());
895 }
896 button.setEnabled(isEnabled());
897 button.setVisible(isVisible());
898 }
899
900
901
902
903
904
905 public void detach(AbstractButton button) {
906 if (getDefaultButtonManager().isAttachedTo(button)) {
907 getDefaultButtonManager().detach(button);
908 onButtonDetached();
909 }
910 }
911
912
913
914
915
916
917
918
919
920 public boolean isAttached(AbstractButton b) {
921 return getDefaultButtonManager().isAttachedTo(b);
922 }
923
924
925
926
927 protected void onButtonDetached() {
928
929 }
930
931
932
933
934
935 private CommandFaceButtonManager getDefaultButtonManager() {
936 return getButtonManager(getDefaultFaceDescriptorId());
937 }
938
939
940
941
942
943
944
945
946
947 private CommandFaceButtonManager getButtonManager(String faceDescriptorId) {
948 if (this.faceButtonManagers == null) {
949 this.faceButtonManagers = new CachingMapDecorator() {
950 protected Object create(Object key) {
951 return new CommandFaceButtonManager(AbstractCommand.this, (String) key);
952 }
953 };
954 }
955 CommandFaceButtonManager m = (CommandFaceButtonManager) this.faceButtonManagers.get(faceDescriptorId);
956 return m;
957 }
958
959
960
961
962 protected CommandButtonConfigurer getDefaultButtonConfigurer() {
963 return getCommandServices().getDefaultButtonConfigurer();
964 }
965
966
967
968
969 protected CommandButtonConfigurer getToolBarButtonConfigurer() {
970 return getCommandServices().getToolBarButtonConfigurer();
971 }
972
973
974
975
976 protected ButtonFactory getToolBarButtonFactory() {
977 return getCommandServices().getToolBarButtonFactory();
978 }
979
980
981
982
983 protected CommandButtonConfigurer getMenuItemButtonConfigurer() {
984 return getCommandServices().getMenuItemButtonConfigurer();
985 }
986
987
988
989
990 protected ComponentFactory getComponentFactory() {
991 return getCommandServices().getComponentFactory();
992 }
993
994
995
996
997 protected ButtonFactory getButtonFactory() {
998 return getCommandServices().getButtonFactory();
999 }
1000
1001
1002
1003
1004 protected MenuFactory getMenuFactory() {
1005 return getCommandServices().getMenuFactory();
1006 }
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018 public boolean requestFocusIn(Container container) {
1019 AbstractButton button = getButtonIn(container);
1020 if (button != null) {
1021 return button.requestFocusInWindow();
1022 }
1023 return false;
1024 }
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034 public AbstractButton getButtonIn(Container container) {
1035 Iterator it = buttonIterator();
1036 while (it.hasNext()) {
1037 AbstractButton button = (AbstractButton) it.next();
1038 if (SwingUtilities.isDescendingFrom(button, container)) {
1039 return button;
1040 }
1041 }
1042 return null;
1043 }
1044
1045
1046
1047
1048 public String toString() {
1049 return new ToStringCreator(this).append("id", getId()).append("enabled", enabled).append("visible", visible)
1050 .append("defaultFaceDescriptorId", defaultFaceDescriptorId).toString();
1051 }
1052
1053 }