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 }