View Javadoc

1   /*
2    * Copyright 2004-2008 the Seasar Foundation and the Others.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 
13   * either express or implied. See the License for the specific language
14   * governing permissions and limitations under the License.
15   */
16  package org.seasar.uruma.binding.value.binder;
17  
18  import java.lang.reflect.Array;
19  import java.util.ArrayList;
20  import java.util.List;
21  
22  import org.eclipse.jface.viewers.IBaseLabelProvider;
23  import org.eclipse.jface.viewers.IContentProvider;
24  import org.eclipse.jface.viewers.IStructuredSelection;
25  import org.eclipse.jface.viewers.StructuredSelection;
26  import org.eclipse.jface.viewers.StructuredViewer;
27  import org.eclipse.jface.viewers.Viewer;
28  import org.seasar.framework.beans.PropertyDesc;
29  import org.seasar.uruma.binding.value.ValueBinder;
30  import org.seasar.uruma.component.UIComponent;
31  import org.seasar.uruma.core.UrumaConstants;
32  import org.seasar.uruma.core.UrumaMessageCodes;
33  import org.seasar.uruma.exception.BindingException;
34  import org.seasar.uruma.log.UrumaLogger;
35  import org.seasar.uruma.util.AssertionUtil;
36  import org.seasar.uruma.viewer.ContentsHolder;
37  import org.seasar.uruma.viewer.TargetClassHoldingProvider;
38  
39  /**
40   * {@link ValueBinder} のための基底クラスです。<br />
41   * 
42   * @param <WIDGET_TYPE>
43   *            対応するウィジットの型
44   * @author y-komori
45   */
46  public abstract class AbstractValueBinder<WIDGET_TYPE> implements ValueBinder {
47      private UrumaLogger logger = UrumaLogger.getLogger(getClass());
48  
49      private Class<WIDGET_TYPE> widgetType;
50  
51      protected static final String IMPORT_VALUE = "[ImportValue]";
52  
53      protected static final String EXPORT_VALUE = "[ExportValue]";
54  
55      protected static final String IMPORT_SELECTION = "[ImportSelection]";
56  
57      protected static final String EXPORT_SELECTION = "[ExportSelection]";
58  
59      /**
60       * {@link AbstractValueBinder} を構築します。<br />
61       * 
62       * @param widgetType
63       *            ウィジットの型
64       */
65      public AbstractValueBinder(final Class<WIDGET_TYPE> widgetType) {
66          AssertionUtil.assertNotNull("widgetType", widgetType);
67          this.widgetType = widgetType;
68      }
69  
70      /*
71       * @see org.seasar.uruma.binding.value.ValueBinder#importValue(java.lang.Object,
72       *      java.lang.Object, org.seasar.framework.beans.PropertyDesc)
73       */
74      public void importValue(final Object widget, final Object formObj,
75              final PropertyDesc propDesc, final UIComponent uiComp) {
76          doImportValue(getWidgetType().cast(widget), formObj, propDesc, uiComp);
77      }
78  
79      /*
80       * @see org.seasar.uruma.binding.value.ValueBinder#exportValue(java.lang.Object,
81       *      java.lang.Object, org.seasar.framework.beans.PropertyDesc)
82       */
83      public void exportValue(final Object widget, final Object formObj,
84              final PropertyDesc propDesc, final UIComponent uiComp) {
85          doExportValue(getWidgetType().cast(widget), formObj, propDesc, uiComp);
86      }
87  
88      /*
89       * @see org.seasar.uruma.binding.value.ValueBinder#importSelection(java.lang.Object,
90       *      java.lang.Object, org.seasar.framework.beans.PropertyDesc)
91       */
92      public void importSelection(final Object widget, final Object formObj,
93              final PropertyDesc propDesc, final UIComponent uiComp) {
94          doImportSelection(getWidgetType().cast(widget), formObj, propDesc,
95                  uiComp);
96      }
97  
98      /*
99       * @see org.seasar.uruma.binding.value.ValueBinder#exportSelection(java.lang.Object,
100      *      java.lang.Object, org.seasar.framework.beans.PropertyDesc)
101      */
102     public void exportSelection(final Object widget, final Object formObj,
103             final PropertyDesc propDesc, final UIComponent uiComp) {
104         doExportSelection(getWidgetType().cast(widget), formObj, propDesc,
105                 uiComp);
106     }
107 
108     /*
109      * @see org.seasar.uruma.binding.value.ValueBinder#getWidgetType()
110      */
111     public Class<WIDGET_TYPE> getWidgetType() {
112         return this.widgetType;
113     }
114 
115     /**
116      * ウィジットの値をフォームへ設定します。<br />
117      * 本メソッドをサブクラスでオーバーライドしてください。<br />
118      * デフォルトでは何も行いません。
119      * 
120      * @param widget
121      *            ウィジット側オブジェクト
122      * @param formObj
123      *            フォーム側オブジェクト
124      * @param propDesc
125      *            フォーム側のプロパティを表す {@link PropertyDesc} オブジェクト
126      * @param uiComp
127      *            コンポーネント
128      */
129     protected void doImportValue(final WIDGET_TYPE widget,
130             final Object formObj, final PropertyDesc propDesc,
131             final UIComponent uiComp) {
132 
133     }
134 
135     /**
136      * フォームの値をウィジットへ設定します。<br />
137      * デフォルトでは、 <code>widget</code> が {@link StructuredViewer}
138      * のサブクラスかつコンテンツプロバイダが {@link ContentsHolder} の実装クラスである場合に、
139      * <code>propDesc</code> の持つ値をコンテンツプロバイダへ設定します。<br />
140      * デフォルト処理をカスタマイズしたい場合は、サブクラスでオーバーライドしてください。<br />
141      * 
142      * @param widget
143      *            ウィジット側オブジェクト
144      * @param formObj
145      *            フォーム側オブジェクト
146      * @param propDesc
147      *            フォーム側のプロパティを表す {@link PropertyDesc} オブジェクト
148      * @param uiComp
149      *            コンポーネント
150      */
151     protected void doExportValue(final WIDGET_TYPE widget,
152             final Object formObj, final PropertyDesc propDesc,
153             final UIComponent uiComp) {
154         if (widget instanceof StructuredViewer) {
155             StructuredViewer viewer = StructuredViewer.class.cast(widget);
156 
157             Class<?> formFieldType = propDesc.getField().getType();
158             Object contents = propDesc.getValue(formObj);
159             IContentProvider contentProvider = viewer.getContentProvider();
160             IBaseLabelProvider labelProvider = viewer.getLabelProvider();
161 
162             if (contentProvider != null
163                     && contentProvider instanceof ContentsHolder) {
164                 ContentsHolder holder = (ContentsHolder) contentProvider;
165                 if (formFieldType.isArray()) {
166                     if (contents != null) {
167                         holder.setContents((Object[]) contents);
168                     } else {
169                         holder.setContents(new Object[] {});
170                     }
171                     setClassToProvider(labelProvider, formFieldType
172                             .getComponentType());
173                 } else if (List.class.isAssignableFrom(formFieldType)) {
174                     List<?> listContents = (List<?>) contents;
175 
176                     if ((listContents != null) && (listContents.size() > 0)) {
177                         holder.setContents(listContents);
178 
179                         Object content = listContents.get(0);
180                         setClassToProvider(labelProvider, content.getClass());
181                     } else {
182                         holder.setContents(new ArrayList<Object>());
183                         setClassToProvider(labelProvider, Object.class);
184                     }
185                 } else {
186                     if (contents != null) {
187                         holder.setContents(new Object[] { contents });
188                         setClassToProvider(labelProvider, contents.getClass());
189                     } else {
190                         holder.setContents(new Object[] {});
191                         setClassToProvider(labelProvider, Object.class);
192                     }
193                 }
194 
195                 logBinding(EXPORT_VALUE, formObj, propDesc, widget, null,
196                         contents);
197 
198                 viewer.setInput(contents);
199             }
200         }
201     }
202 
203     /**
204      * ウィジットで選択されているオブジェクトをフォームへ設定します。<br />
205      * デフォルトでは、 <code>widget</code> が {@link Viewer} のサブクラスである場合に
206      * <code>propDesc</code> の表すプロパティにビューアから取得した選択中オブジェクトを設定します。<br />
207      * デフォルト処理をカスタマイズしたい場合は、サブクラスでオーバーライドしてください。<br />
208      * 
209      * @param widget
210      *            ウィジット側オブジェクト
211      * @param formObj
212      *            フォーム側オブジェクト
213      * @param propDesc
214      *            フォーム側のプロパティを表す {@link PropertyDesc} オブジェクト
215      * @param uiComp
216      *            コンポーネント
217      * @throws BindingException
218      *             ビューアで選択させれているオブジェクトの型とプロパティの型が一致しなかった場合
219      */
220     protected void doImportSelection(final WIDGET_TYPE widget,
221             final Object formObj, final PropertyDesc propDesc,
222             final UIComponent uiComp) {
223         if (widget instanceof Viewer) {
224             Viewer viewer = Viewer.class.cast(widget);
225 
226             IStructuredSelection selection = (IStructuredSelection) viewer
227                     .getSelection();
228             int size = selection.size();
229             if (size > 0) {
230                 Class<?> propertyType = propDesc.getPropertyType();
231                 Object firstElement = selection.getFirstElement();
232                 if (propertyType.isArray()) {
233                     Object[] selectedArray = selection.toArray();
234                     Object content = Array.newInstance(propertyType
235                             .getComponentType(), selectedArray.length);
236                     System.arraycopy(selectedArray, 0, content, 0,
237                             selectedArray.length);
238 
239                     logBinding(IMPORT_SELECTION, widget, null, formObj,
240                             propDesc, content);
241                     propDesc.setValue(formObj, content);
242                 } else if (propertyType.isAssignableFrom(List.class)) {
243                     List<?> list = selection.toList();
244                     logBinding(IMPORT_SELECTION, widget, null, formObj,
245                             propDesc, list);
246                     propDesc.setValue(formObj, list);
247                 } else if (propertyType.isAssignableFrom(firstElement
248                         .getClass())) {
249                     logBinding(IMPORT_SELECTION, widget, null, formObj,
250                             propDesc, firstElement);
251                     propDesc.setValue(formObj, firstElement);
252                 } else {
253                     throw new BindingException(
254                             UrumaMessageCodes.CLASS_NOT_MUTCH, formObj
255                                     .getClass().getName(), propDesc
256                                     .getPropertyName());
257                 }
258             }
259         }
260     }
261 
262     /**
263      * フォームの持つオブジェクトをウィジットの選択状態として設定します。<br />
264      * デフォルトでは、 <code>widget</code> が {@link Viewer} のサブクラスである場合に
265      * <code>propDesc</code> の持つ値を {@link StructuredSelection}
266      * にラップしてビューアに設定します。<br />
267      * デフォルト処理をカスタマイズしたい場合は、サブクラスでオーバーライドしてください。<br />
268      * 
269      * @param widget
270      *            ウィジット側オブジェクト
271      * @param formObj
272      *            フォーム側オブジェクト
273      * @param propDesc
274      *            フォーム側のプロパティを表す {@link PropertyDesc} オブジェクト
275      * @param uiComp
276      *            コンポーネント
277      */
278     protected void doExportSelection(final WIDGET_TYPE widget,
279             final Object formObj, final PropertyDesc propDesc,
280             final UIComponent uiComp) {
281         if (widget instanceof Viewer) {
282             Viewer viewer = Viewer.class.cast(widget);
283             Object selection = propDesc.getValue(formObj);
284             if (selection != null) {
285                 logBinding(EXPORT_SELECTION, formObj, propDesc, viewer, null,
286                         selection);
287 
288                 viewer.setSelection(new StructuredSelection(selection), true);
289             }
290         }
291     }
292 
293     protected void setClassToProvider(final IBaseLabelProvider provider,
294             final Class<?> clazz) {
295         if ((provider != null)
296                 && (provider instanceof TargetClassHoldingProvider)) {
297             TargetClassHoldingProvider.class.cast(provider).setTargetClass(
298                     clazz);
299         }
300     }
301 
302     /**
303      * バインディングの状況をログ出力します。<br />
304      * 
305      * @param command
306      *            コマンド文字列
307      * @param srcObj
308      *            バインド元オブジェクト
309      * @param srcProp
310      *            バインド元プロパティ
311      * @param destObj
312      *            バインド先オブジェクト
313      * @param destProp
314      *            バインド先オブジェクト
315      * @param value
316      *            値
317      */
318     protected void logBinding(final String command, final Object srcObj,
319             final PropertyDesc srcProp, final Object destObj,
320             final PropertyDesc destProp, final Object value) {
321         if (logger.isInfoEnabled()) {
322             String srcName = UrumaConstants.NULL_STRING;
323             if (srcProp != null) {
324                 srcName = srcProp.getPropertyName();
325             }
326             String destName = UrumaConstants.NULL_STRING;
327             if (destProp != null) {
328                 destName = destProp.getPropertyName();
329             }
330             logger.log(UrumaMessageCodes.DO_BINDING, command, UrumaLogger
331                     .getObjectDescription(srcObj), srcName, UrumaLogger
332                     .getObjectDescription(destObj), destName, value);
333         }
334     }
335 }