001 /*
002 * Copyright 2002-2005 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005 * use this file except in compliance with the License. You may obtain a copy of
006 * 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, WITHOUT
012 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013 * License for the specific language governing permissions and limitations under
014 * the License.
015 */
016 package org.springframework.binding.form.support;
017
018 import javax.swing.Icon;
019
020 import org.apache.commons.logging.Log;
021 import org.apache.commons.logging.LogFactory;
022 import org.springframework.binding.form.FieldFace;
023 import org.springframework.binding.form.FormModel;
024 import org.springframework.context.NoSuchMessageException;
025 import org.springframework.context.support.DefaultMessageSourceResolvable;
026 import org.springframework.context.support.MessageSourceAccessor;
027 import org.springframework.core.ReflectiveVisitorHelper;
028 import org.springframework.richclient.application.ApplicationServices;
029 import org.springframework.richclient.application.ApplicationServicesLocator;
030 import org.springframework.richclient.core.LabelInfo;
031 import org.springframework.richclient.image.IconSource;
032
033 /**
034 * An implementation of FieldFaceSource that resolves the FieldFace from the <code>MessageSourceAccessor</code>
035 * provided to the setMessageSourceAccessor method or from the {@link ApplicationServices} singleton if none is
036 * provided.
037 *
038 * <p>
039 * The various properties of the FieldFace are resolved from a message source using message codes. These codes where
040 * generated by a {@link MessageCodeStrategy}. If no other {@link MessageCodeStrategy} is defined an instance of
041 * {@link DefaultMessageCodeStrategy} will be used
042 *
043 * @author Oliver Hutchison
044 * @author Mathias Broekelmann
045 */
046 public class MessageSourceFieldFaceSource extends CachingFieldFaceSource {
047
048 private static final Log log = LogFactory.getLog(MessageSourceFieldFaceSource.class);
049
050 /**
051 * Name for the FieldFace's <code>displayName</code> property.
052 */
053 private static final String[] DISPLAY_NAME_PROPERTY = { "displayName" };
054
055 /**
056 * Name for the FieldFace's <code>caption</code> property.
057 */
058 private static final String[] CAPTION_PROPERTY = { "caption" };
059
060 /**
061 * Name for the FieldFace's <code>description</code> property.
062 */
063 private static final String[] DESCRIPTION_PROPERTY = { "description" };
064
065 /**
066 * Name for the FieldFace's <code>labelInfo</code> property.
067 */
068 private static final String[] ENCODED_LABEL_PROPERTY = { "label", "" };
069
070 /**
071 * Name for the FieldFace's <code>icon</code> property.
072 */
073 private static final String[] ICON_PROPERTY = { "icon" };
074
075 private MessageSourceAccessor messageSourceAccessor;
076
077 private MessageCodeStrategy messageKeyStrategy;
078
079 private IconSource iconSource;
080
081 private final ReflectiveVisitorHelper visitorHelper = new ReflectiveVisitorHelper();
082
083 /**
084 * Constructs a new MessageSourcePropertyFaceDescriptorSource.
085 */
086 public MessageSourceFieldFaceSource() {
087 }
088
089 /**
090 * Set the message source that will be used to resolve the FieldFace's properties.
091 */
092 public void setMessageSourceAccessor(MessageSourceAccessor messageSourceAccessor) {
093 this.messageSourceAccessor = messageSourceAccessor;
094 }
095
096 /**
097 * If a message source was provided to the setMessageSourceAccessor method returns that otherwise returns the
098 * default message source located using the {@link ApplicationServices} singleton
099 */
100 protected MessageSourceAccessor getMessageSourceAccessor() {
101 if (messageSourceAccessor == null) {
102 messageSourceAccessor = (MessageSourceAccessor) ApplicationServicesLocator.services().getService(
103 MessageSourceAccessor.class);
104 }
105 return messageSourceAccessor;
106 }
107
108 /**
109 * Set the icon source that will be used to resolve the FieldFace's icon property.
110 */
111 public void setIconSource(IconSource iconSource) {
112 this.iconSource = iconSource;
113 }
114
115 protected IconSource getIconSource() {
116 if (iconSource == null) {
117 iconSource = (IconSource) ApplicationServicesLocator.services().getService(IconSource.class);
118 }
119 return iconSource;
120 }
121
122 /**
123 * Returns the value of the required property of the FieldFace. Delegates to the getMessageKeys for the message key
124 * generation strategy. This method uses </code>[contextId + "." + ] fieldPath [ + "." + faceDescriptorProperty[0]]</code>
125 * for the default value
126 */
127 protected String getMessage(String contextId, String fieldPath, String[] faceDescriptorProperty) {
128 String[] keys = getMessageKeys(contextId, fieldPath, faceDescriptorProperty);
129 return getMessageSourceAccessor().getMessage(new DefaultMessageSourceResolvable(keys, null, keys[0]));
130 }
131
132 /**
133 * Returns the value of the required property of the FieldFace. Delegates to the getMessageKeys for the message key
134 * generation strategy.
135 */
136 protected String getMessage(String contextId, String fieldPath, String[] faceDescriptorProperties,
137 String defaultValue) {
138 String[] keys = getMessageKeys(contextId, fieldPath, faceDescriptorProperties);
139 try {
140 return getMessageSourceAccessor().getMessage(new DefaultMessageSourceResolvable(keys, null, defaultValue));
141 } catch (NoSuchMessageException e) {
142 if (log.isDebugEnabled()) {
143 log.debug(e.getMessage());
144 }
145 return null;
146 }
147 }
148
149 /**
150 * Returns an array of message keys that are used to resolve the required property of the FieldFace. The property
151 * will be resolved from the message source using the returned message keys in order.
152 * <p>
153 * Subclasses my override this method to provide an alternative to the default message key generation strategy.
154 */
155 protected String[] getMessageKeys(String contextId, String fieldPath, String[] faceDescriptorProperties) {
156 return getMessageKeyStrategy().getMessageCodes(contextId, fieldPath, faceDescriptorProperties);
157 }
158
159 protected FieldFace loadFieldFace(String field, String contextId) {
160 String caption = getMessage(contextId, field, CAPTION_PROPERTY, null);
161 String description = getMessage(contextId, field, DESCRIPTION_PROPERTY, null);
162 String encodedLabel = getMessage(contextId, field, ENCODED_LABEL_PROPERTY);
163 if (encodedLabel == null) {
164 // try loading the default value
165 encodedLabel = getMessage(contextId, field, null);
166 }
167 String iconName = getMessage(contextId, field, ICON_PROPERTY, null);
168 Icon icon = null;
169 if (iconName != null) {
170 icon = getIconSource().getIcon(iconName);
171 }
172 LabelInfo labelInfo = LabelInfo.valueOf(encodedLabel);
173 String displayName = getMessage(contextId, field, DISPLAY_NAME_PROPERTY, labelInfo.getText());
174 return new DefaultFieldFace(displayName, caption, description, labelInfo, icon);
175 }
176
177 protected FieldFace loadFieldFace(String field, Object context) {
178 String contextId = (String) visitorHelper.invokeVisit(this, context);
179 return loadFieldFace(field, contextId);
180 }
181
182 public MessageCodeStrategy getMessageKeyStrategy() {
183 if (messageKeyStrategy == null) {
184 messageKeyStrategy = new DefaultMessageCodeStrategy();
185 }
186 return messageKeyStrategy;
187 }
188
189 public void setMessageKeyStrategy(MessageCodeStrategy messageKeyStrategy) {
190 this.messageKeyStrategy = messageKeyStrategy;
191 }
192
193 // visit methods for getting a context id from various context instances
194
195 String visit(FormModel formModel) {
196 return formModel.getId();
197 }
198
199 String visit(CharSequence contextId) {
200 return contextId.toString();
201 }
202
203 String visitNull() {
204 return null;
205 }
206 }