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.ui;
17  
18  import java.util.ArrayList;
19  import java.util.List;
20  
21  import org.eclipse.jface.action.MenuManager;
22  import org.eclipse.jface.window.ApplicationWindow;
23  import org.eclipse.swt.SWT;
24  import org.eclipse.swt.widgets.Composite;
25  import org.eclipse.swt.widgets.Control;
26  import org.eclipse.swt.widgets.Display;
27  import org.eclipse.swt.widgets.Shell;
28  import org.seasar.framework.container.annotation.tiger.AutoBindingType;
29  import org.seasar.framework.container.annotation.tiger.Component;
30  import org.seasar.framework.util.StringUtil;
31  import org.seasar.uruma.binding.context.ApplicationContextBinder;
32  import org.seasar.uruma.binding.enables.EnablesDependingListenerSupport;
33  import org.seasar.uruma.binding.method.MethodBindingSupport;
34  import org.seasar.uruma.binding.method.WindowCloseListener;
35  import org.seasar.uruma.binding.value.ValueBindingSupport;
36  import org.seasar.uruma.component.Template;
37  import org.seasar.uruma.component.jface.WindowComponent;
38  import org.seasar.uruma.context.ApplicationContext;
39  import org.seasar.uruma.context.ContextFactory;
40  import org.seasar.uruma.context.PartContext;
41  import org.seasar.uruma.context.WidgetHandle;
42  import org.seasar.uruma.context.WindowContext;
43  import org.seasar.uruma.core.ComponentUtil;
44  import org.seasar.uruma.core.UrumaConstants;
45  import org.seasar.uruma.core.UrumaMessageCodes;
46  import org.seasar.uruma.core.UrumaWindowManager;
47  import org.seasar.uruma.desc.PartActionDesc;
48  import org.seasar.uruma.desc.PartActionDescFactory;
49  import org.seasar.uruma.exception.NotFoundException;
50  import org.seasar.uruma.exception.RenderException;
51  import org.seasar.uruma.renderer.impl.WindowRenderer;
52  import org.seasar.uruma.util.AssertionUtil;
53  
54  /**
55   * {@link Template} オブジェクトを元にして画面描画を行う、{@link ApplicationWindow} です。
56   * 
57   * @author y-komori
58   */
59  @Component(autoBinding = AutoBindingType.NONE)
60  public class UrumaApplicationWindow extends ApplicationWindow implements
61          UrumaConstants, UrumaMessageCodes {
62      private UrumaWindowManager windowManager;
63  
64      private WindowComponent windowComponent;
65  
66      private WindowContext windowContext;
67  
68      private PartContext partContext;
69  
70      private PartActionDesc desc;
71  
72      private Object partActionComponent;
73  
74      private List<WindowCloseListener> closeListeners;
75  
76      private boolean block;
77  
78      /**
79       * {@link UrumaApplicationWindow} を構築します。<br />
80       */
81      public UrumaApplicationWindow(final UrumaWindowManager manager) {
82          super(null);
83          AssertionUtil.assertNotNull("manager", manager);
84  
85          this.windowManager = manager;
86      }
87  
88      /**
89       * {@link UrumaApplicationWindow} を構築します。<br />
90       * 
91       * @param context
92       *            {@link WindowContext} オブジェクト
93       * @param component
94       *            {@link WindowComponent} オブジェクト
95       * @param modal
96       *            <code>true</code> の場合、モーダルウィンドウとして開く。<code>false</code>
97       *            の場合、モーダレスウィンドウとして開く。
98       */
99      public UrumaApplicationWindow(final UrumaWindowManager manager,
100             final WindowContext context, final WindowComponent component,
101             final boolean modal) {
102         this(manager);
103         init(context, component, modal);
104     }
105 
106     /**
107      * {@link UrumaApplicationWindow} を初期化します。<br/>
108      * <p>
109      * デフォルトコンストラクタを使用して本クラスを生成した場合は、必ず本メソッドを呼び出してから利用してください。
110      * </p>
111      * 
112      * @param context
113      *            {@link ApplicationContext} オブジェクト
114      * @param component
115      *            {@link WindowComponent} オブジェクト
116      * @param modal
117      *            <code>true</code> の場合、モーダルウィンドウとして開く
118      */
119     public void init(final WindowContext context,
120             final WindowComponent component, final boolean modal) {
121         this.windowComponent = component;
122         this.windowContext = context;
123         this.partContext = ContextFactory.createPartContext(windowContext,
124                 component.getId());
125 
126         // プリレンダリング処理を実施
127         component.preRender(null, windowContext);
128 
129         setupActionComponent();
130         ComponentUtil.setupFormComponent(partContext, windowComponent.getId());
131 
132         setupMenuBar();
133         setupShellStyle(component, modal);
134         setupStatusLine();
135 
136         // パートアクションの @Initialize メソッドを呼び出す
137         ComponentUtil
138                 .invokeInitMethodOnAction(partActionComponent, partContext);
139     }
140 
141     protected void setupActionComponent() {
142         partActionComponent = ComponentUtil.setupPartAction(partContext,
143                 windowComponent.getId());
144         if (partActionComponent != null) {
145             this.desc = PartActionDescFactory
146                     .getPartActionDesc(partActionComponent.getClass());
147         }
148     }
149 
150     protected void setupShellStyle(final WindowComponent component,
151             final boolean modal) {
152         WindowRenderer renderer = (WindowRenderer) component.getRenderer();
153         int style = (renderer.getShellStyle(component));
154 
155         if (modal) {
156             if ((style & (SWT.APPLICATION_MODAL | SWT.PRIMARY_MODAL | SWT.SYSTEM_MODAL)) == 0) {
157                 style |= SWT.PRIMARY_MODAL;
158             }
159         } else {
160             style &= ~(SWT.APPLICATION_MODAL | SWT.PRIMARY_MODAL | SWT.SYSTEM_MODAL);
161         }
162         setShellStyle(style);
163     }
164 
165     protected void setupMenuBar() {
166         if (StringUtil.isNotBlank(windowComponent.menu)) {
167             addMenuBar();
168         }
169     }
170 
171     /*
172      * @see org.eclipse.jface.window.ApplicationWindow#createMenuManager()
173      */
174     @Override
175     protected MenuManager createMenuManager() {
176         String menuId = windowComponent.menu;
177 
178         WidgetHandle handle = partContext.getWindowContext().getWidgetHandle(
179                 menuId);
180         if (handle != null) {
181             if (handle.instanceOf(MenuManager.class)) {
182                 return handle.<MenuManager> getCastWidget();
183             } else {
184                 throw new RenderException(UNSUPPORTED_TYPE_ERROR, menuId,
185                         MenuManager.class.getName());
186             }
187         } else {
188             throw new NotFoundException(UICOMPONENT_NOT_FOUND, menuId);
189         }
190     }
191 
192     protected void setupStatusLine() {
193         String statusLine = windowComponent.statusLine;
194         if ("true".equals(statusLine)) {
195             addStatusLine();
196             WidgetHandle handle = ContextFactory
197                     .createWidgetHandle(getStatusLineManager());
198             handle.setId(STATUS_LINE_MANAGER_CID);
199             partContext.putWidgetHandle(handle);
200         }
201     }
202 
203     /*
204      * @see org.eclipse.jface.window.Window#createContents(org.eclipse.swt.widgets.Composite)
205      */
206     @Override
207     protected Control createContents(final Composite parent) {
208         // ウィンドウのレンダリングを開始する
209         WidgetHandle windowHandle = ContextFactory.createWidgetHandle(this);
210         windowHandle.setId(WINDOW_CID);
211         partContext.putWidgetHandle(windowHandle);
212 
213         WidgetHandle shellHandle = ContextFactory.createWidgetHandle(parent);
214         shellHandle.setId(SHELL_CID);
215         partContext.putWidgetHandle(shellHandle);
216 
217         windowComponent.render(shellHandle, partContext);
218 
219         MethodBindingSupport.createListeners(partContext);
220 
221         // 画面初期表示時の、フォームから画面へのエクスポート処理を実施
222         ValueBindingSupport.exportValue(partContext);
223         ValueBindingSupport.exportSelection(partContext);
224 
225         EnablesDependingListenerSupport
226                 .setupEnableDependingListeners(windowContext);
227 
228         return parent;
229     }
230 
231     /**
232      * パートアクションコンポーネントを取得します。<br />
233      * 
234      * @return パートアクションコンポーネント
235      */
236     public Object getPartActionComponent() {
237         return this.partActionComponent;
238     }
239 
240     /**
241      * ウィンドウIDを返します。<br />
242      * 
243      * @return ウィンドウID
244      */
245     public String getWindowId() {
246         return windowComponent.getId();
247     }
248 
249     /**
250      * {@link WindowCloseListener} を追加します。<br />
251      * 
252      * @param listener
253      *            {@link WindowCloseListener} オブジェクト
254      */
255     public void addWindowCloseListener(final WindowCloseListener listener) {
256         AssertionUtil.assertNotNull("listener", listener);
257 
258         if (closeListeners == null) {
259             closeListeners = new ArrayList<WindowCloseListener>();
260         }
261         closeListeners.add(listener);
262     }
263 
264     /*
265      * @see org.eclipse.jface.window.Window#open()
266      */
267     @Override
268     public int open() {
269         super.open();
270 
271         ComponentUtil.invokePostOpenMethodOnAction(partActionComponent,
272                 partContext);
273 
274         if (block) {
275             Shell shell = getShell();
276             Display display;
277             if (shell == null) {
278                 display = Display.getCurrent();
279             } else {
280                 display = shell.getDisplay();
281             }
282 
283             while (shell != null && !shell.isDisposed()) {
284                 if (!display.readAndDispatch()) {
285                     display.sleep();
286                 }
287                 // TODO ExceptionHandlerによる例外処理を行う
288             }
289             display.update();
290         }
291 
292         return getReturnCode();
293     }
294 
295     /*
296      * @see org.eclipse.jface.window.ApplicationWindow#close()
297      */
298     @Override
299     public boolean close() {
300         // ウィンドウをクローズしてよいか確認する
301         boolean canClose = true;
302         if (closeListeners != null) {
303             for (WindowCloseListener listener : closeListeners) {
304                 canClose &= listener.canWindowClose(this);
305             }
306         }
307 
308         if (canClose && super.close()) {
309             // ApplicationContext へのエクスポート処理
310             if (partActionComponent != null) {
311                 ApplicationContextBinder.exportObjects(partActionComponent,
312                         desc.getApplicationContextDefList(), windowContext
313                                 .getApplicationContext());
314             }
315 
316             if (closeListeners != null) {
317                 closeListeners.clear();
318                 closeListeners = null;
319             }
320 
321             this.windowManager.close(getWindowId());
322 
323             return true;
324         } else {
325             return false;
326         }
327     }
328 
329     /*
330      * @see org.eclipse.jface.window.Window#setBlockOnOpen(boolean)
331      */
332     @Override
333     public void setBlockOnOpen(final boolean shouldBlock) {
334         this.block = shouldBlock;
335     }
336 }