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.rcp.ui;
17  
18  import java.lang.reflect.Method;
19  import java.lang.reflect.Modifier;
20  import java.util.ArrayList;
21  import java.util.List;
22  
23  import org.eclipse.jface.action.GroupMarker;
24  import org.eclipse.jface.action.MenuManager;
25  import org.eclipse.jface.viewers.ISelectionProvider;
26  import org.eclipse.jface.viewers.TreeViewer;
27  import org.eclipse.jface.viewers.Viewer;
28  import org.eclipse.swt.widgets.Composite;
29  import org.eclipse.swt.widgets.Control;
30  import org.eclipse.swt.widgets.Menu;
31  import org.eclipse.ui.IMemento;
32  import org.eclipse.ui.ISelectionListener;
33  import org.eclipse.ui.IViewPart;
34  import org.eclipse.ui.IViewSite;
35  import org.eclipse.ui.IWorkbenchActionConstants;
36  import org.eclipse.ui.IWorkbenchPage;
37  import org.eclipse.ui.IWorkbenchPartSite;
38  import org.eclipse.ui.PartInitException;
39  import org.eclipse.ui.part.ViewPart;
40  import org.seasar.framework.container.S2Container;
41  import org.seasar.framework.container.factory.S2ContainerFactory;
42  import org.seasar.framework.util.StringUtil;
43  import org.seasar.uruma.annotation.SelectionListener;
44  import org.seasar.uruma.binding.method.MethodBindingSupport;
45  import org.seasar.uruma.binding.method.SingleParamTypeMethodBinding;
46  import org.seasar.uruma.binding.value.ValueBindingSupport;
47  import org.seasar.uruma.component.Template;
48  import org.seasar.uruma.component.UIComponent;
49  import org.seasar.uruma.component.UIComponentContainer;
50  import org.seasar.uruma.component.UIHasMenuCompositeComponent;
51  import org.seasar.uruma.component.rcp.ViewPartComponent;
52  import org.seasar.uruma.context.ApplicationContext;
53  import org.seasar.uruma.context.ContextFactory;
54  import org.seasar.uruma.context.PartContext;
55  import org.seasar.uruma.context.WidgetHandle;
56  import org.seasar.uruma.context.WindowContext;
57  import org.seasar.uruma.core.ComponentUtil;
58  import org.seasar.uruma.core.TemplateManager;
59  import org.seasar.uruma.core.UrumaConstants;
60  import org.seasar.uruma.core.UrumaMessageCodes;
61  import org.seasar.uruma.exception.RenderException;
62  import org.seasar.uruma.log.UrumaLogger;
63  import org.seasar.uruma.rcp.UrumaService;
64  import org.seasar.uruma.rcp.binding.GenericSelectionListener;
65  import org.seasar.uruma.rcp.binding.NullGenericSelectionListener;
66  import org.seasar.uruma.rcp.util.UrumaServiceUtil;
67  import org.seasar.uruma.rcp.util.ViewPartUtil;
68  import org.seasar.uruma.util.AnnotationUtil;
69  import org.seasar.uruma.util.S2ContainerUtil;
70  
71  /**
72   * 汎用的な {@link IViewPart} クラスです。<br />
73   * <p>
74   * 本クラスのインタンスは、Uruma アプリケーションの {@link S2Container} の子コンテナとして、独自の
75   * {@link S2Container} (ローカルコンテナと呼びます)を生成します。<br />
76   * ローカルコンテナh、Uruma アプリケーションの {@link S2Container} をインクルードします。<br />
77   * ローカルコンテナ へは、デフォルトで以下のコンポーネントが登録されており、パートアクション・オブジェクトに対しては、ローカルコンテナから DI
78   * が行われます。
79   * </p>
80   * <dl>
81   * <dt> {@link IViewPart}</dt>
82   * <dd>このパートに対応する {@link GenericViewPart} のインスタンス</dd>
83   * <dt> {@link PartContext}</dt>
84   * <dd>このパートに対応する {@link PartContext} インスタンス</dd>
85   * </dt>
86   * <p>
87   * また、当該 {@link IViewPart} の中で使用されている {@link Viewer} が一つしか存在しない場合、その {@link
88   * Viewer} を自動的に {@link ISelectionProvider} として {@link IWorkbenchPartSite}
89   * へ登録します。<br />
90   * {@link Viewer} が複数存在する場合、自動登録は行いません。<br />
91   * </p>
92   * 
93   * @author y-komori
94   */
95  public class GenericViewPart extends ViewPart implements UrumaViewPart,
96          UrumaMessageCodes {
97      private UrumaService service = UrumaServiceUtil.getService();
98  
99      private static final UrumaLogger logger = UrumaLogger
100             .getLogger(GenericViewPart.class);
101 
102     /**
103      * {@link TemplateManager} オブジェクト
104      */
105     public TemplateManager templateManager;
106 
107     /**
108      * {@link ApplicationContext} オブジェクト
109      */
110     public ApplicationContext applicationContext;
111 
112     private PartContext partContext;
113 
114     private ViewPartComponent viewPart;
115 
116     private String componentId;
117 
118     private String secondaryId;
119 
120     private String fullComponentId;
121 
122     private Object partAction;
123 
124     private List<ISelectionListener> listeners = new ArrayList<ISelectionListener>();
125 
126     private S2Container localContainer;
127 
128     /*
129      * @see org.eclipse.ui.part.ViewPart#init(org.eclipse.ui.IViewSite,
130      *      org.eclipse.ui.IMemento)
131      */
132     @Override
133     public void init(final IViewSite site, final IMemento memento)
134             throws PartInitException {
135         super.init(site, memento);
136         try {
137             initInternal(site, memento);
138 
139             logger.log(VIEW_INIT_END, fullComponentId);
140         } catch (RuntimeException e) {
141             logger.log(VIEW_INIT_FAILED, e, fullComponentId, e.getMessage());
142             throw e;
143         }
144     }
145 
146     protected void initInternal(final IViewSite site, final IMemento memento) {
147         S2ContainerUtil.injectDependency(this, service.getContainer());
148 
149         this.componentId = service.getLocalId(getSite().getId());
150         this.secondaryId = site.getSecondaryId();
151         this.fullComponentId = ViewPartUtil.createFullId(componentId,
152                 secondaryId);
153 
154         logger.log(VIEW_INIT_START, fullComponentId);
155 
156         Template template = templateManager.getTemplateById(componentId);
157         UIComponentContainer root = template.getRootComponent();
158         if (root instanceof ViewPartComponent) {
159             this.viewPart = (ViewPartComponent) root;
160 
161             this.partContext = createPartContext(fullComponentId);
162 
163             createLocalContainer();
164             setupLocalContainer();
165 
166             this.partAction = ComponentUtil.setupPartAction(partContext,
167                     componentId, localContainer);
168 
169             if (partAction != null) {
170                 ComponentUtil.setupFormComponent(partContext, componentId);
171             }
172         } else {
173             throw new RenderException(
174                     UrumaMessageCodes.REQUIRED_VIEWPART_ERROR, template
175                             .getPath());
176         }
177     }
178 
179     /**
180      * {@link GenericViewPart} を構築します。<br />
181      */
182     public GenericViewPart() {
183     }
184 
185     @Override
186     public void createPartControl(final Composite parent) {
187         try {
188             createPartControlInternal(parent);
189             registerContextMenu();
190         } catch (RuntimeException e) {
191             logger.log(e);
192             throw e;
193         }
194     }
195 
196     protected void createPartControlInternal(final Composite parent) {
197         WidgetHandle parentHandle = ContextFactory.createWidgetHandle(parent);
198         parentHandle.setUiComponent(service.getWorkbenchComponent());
199 
200         viewPart.preRender(parentHandle, partContext.getWindowContext());
201         viewPart.render(parentHandle, partContext);
202 
203         prepareSelectionProvider(partContext);
204 
205         setupSelectionListeners();
206 
207         // PartActionの@Initialize メソッドの呼び出し
208         ComponentUtil.invokeInitMethodOnAction(partAction, partContext);
209 
210         // 画面初期表示時の、フォームから画面へのエクスポート処理を実施
211         ValueBindingSupport.exportValue(partContext);
212         ValueBindingSupport.exportSelection(partContext);
213 
214         // // Enable Depending の準備
215         // WindowContext context = UrumaServiceUtil.getService()
216         // .getWorkbenchWindowContext();
217         // EnablesDependingListenerSupport.setupEnableDependingListeners(context
218         // );
219 
220         // Method Binding の準備
221         MethodBindingSupport.createListeners(partContext);
222     }
223 
224     /*
225      * @see org.eclipse.ui.part.WorkbenchPart#setFocus()
226      */
227     @Override
228     public void setFocus() {
229         // Do nothing.
230     }
231 
232     /*
233      * @see org.eclipse.ui.part.WorkbenchPart#dispose()
234      */
235     @Override
236     public void dispose() {
237         IWorkbenchPage page = getSite().getPage();
238         for (ISelectionListener listener : listeners) {
239             page.removeSelectionListener(listener);
240         }
241         WindowContext windowContext = applicationContext
242                 .getWindowContext(UrumaConstants.WORKBENCH_WINDOW_CONTEXT_ID);
243         windowContext.disposePartContext(partContext.getName());
244 
245         super.dispose();
246     }
247 
248     /**
249      * 本 ViewPart 専用のローカル {@link S2Container} を生成します。<br />
250      */
251     protected void createLocalContainer() {
252         S2Container container = S2ContainerFactory.create();
253         container.include(service.getContainer());
254         this.localContainer = container;
255     }
256 
257     protected void setupLocalContainer() {
258         localContainer.register(this);
259         localContainer.register(partContext);
260     }
261 
262     protected PartContext createPartContext(final String id) {
263         WindowContext windowContext = applicationContext
264                 .getWindowContext(UrumaConstants.WORKBENCH_WINDOW_CONTEXT_ID);
265         return ContextFactory.createPartContext(windowContext, id);
266     }
267 
268     protected void prepareSelectionProvider(final PartContext context) {
269         List<WidgetHandle> viewers = context.getWidgetHandles(Viewer.class);
270         if (viewers.size() == 1) {
271             Viewer viewer = viewers.get(0).<Viewer> getCastWidget();
272             getSite().setSelectionProvider(viewer);
273         }
274     }
275 
276     protected void setupSelectionListeners() {
277         if (partAction == null) {
278             return;
279         }
280 
281         List<Method> listenerMethods = AnnotationUtil.getAnnotatedMethods(
282                 partAction.getClass(), SelectionListener.class);
283 
284         for (Method method : listenerMethods) {
285             if (Modifier.isPublic(method.getModifiers())) {
286                 SelectionListener anno = method
287                         .getAnnotation(SelectionListener.class);
288                 boolean nullSelection = anno.nullSelection();
289                 Class<?>[] paramTypes = method.getParameterTypes();
290                 if (paramTypes.length <= 1) {
291                     SingleParamTypeMethodBinding methodBinding = new SingleParamTypeMethodBinding(
292                             partAction, method);
293 
294                     GenericSelectionListener listener;
295                     if (nullSelection) {
296                         listener = new NullGenericSelectionListener(
297                                 partContext, methodBinding);
298                     } else {
299                         listener = new GenericSelectionListener(partContext,
300                                 methodBinding);
301                     }
302 
303                     String partId = anno.partId();
304 
305                     if (StringUtil.isEmpty(partId)) {
306                         getSite().getPage().addSelectionListener(listener);
307                     } else {
308                         partId = UrumaServiceUtil.getService().createRcpId(
309                                 partId);
310                         getSite().getPage().addSelectionListener(partId,
311                                 listener);
312                     }
313 
314                     logger.log(
315                             UrumaMessageCodes.ISELECTION_LISTENER_REGISTERED,
316                             getViewSite().getId(), methodBinding, partId);
317                     listeners.add(listener);
318                 }
319             }
320         }
321     }
322 
323     protected void registerContextMenu() {
324         List<WidgetHandle> handles = partContext
325                 .getWidgetHandles(TreeViewer.class);
326         for (WidgetHandle handle : handles) {
327             UIComponent uiComponent = handle.getUiComponent();
328             if (uiComponent instanceof UIHasMenuCompositeComponent) {
329                 TreeViewer treeViewer = handle.<TreeViewer> getCastWidget();
330 
331                 MenuManager menuMgr = new MenuManager();
332                 GroupMarker groupMarker = new GroupMarker(
333                         IWorkbenchActionConstants.MB_ADDITIONS);
334                 menuMgr.add(groupMarker);
335                 getSite().registerContextMenu(menuMgr, treeViewer);
336 
337                 Control control = treeViewer.getControl();
338                 Menu menu = menuMgr.createContextMenu(control);
339                 control.setMenu(menu);
340             }
341         }
342     }
343 
344     /*
345      * @see org.seasar.uruma.rcp.ui.UrumaViewPart#getId()
346      */
347     public String getId() {
348         return this.componentId;
349     }
350 
351     /*
352      * @see org.seasar.uruma.rcp.ui.UrumaViewPart#getRcpId()
353      */
354     public String getRcpId() {
355         return getSite().getId();
356     }
357 
358     /*
359      * @see org.seasar.uruma.rcp.ui.UrumaViewPart#getSecondaryId()
360      */
361     public String getSecondaryId() {
362         return this.secondaryId;
363     }
364 
365     /*
366      * @see org.eclipse.ui.part.ViewPart#setPartName(java.lang.String)
367      */
368     @Override
369     public void setPartName(final String name) {
370         super.setPartName(name);
371     }
372 }