001 /*
002 * Copyright 2002-2006 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.richclient.application.support;
017
018 import java.awt.BorderLayout;
019 import java.awt.event.WindowAdapter;
020 import java.awt.event.WindowEvent;
021 import java.awt.event.WindowFocusListener;
022 import java.util.Iterator;
023
024 import javax.swing.JComponent;
025 import javax.swing.JFrame;
026 import javax.swing.JMenuBar;
027 import javax.swing.WindowConstants;
028
029 import org.apache.commons.logging.Log;
030 import org.apache.commons.logging.LogFactory;
031 import org.springframework.context.ApplicationContext;
032 import org.springframework.richclient.application.Application;
033 import org.springframework.richclient.application.ApplicationPage;
034 import org.springframework.richclient.application.ApplicationPageFactory;
035 import org.springframework.richclient.application.ApplicationServices;
036 import org.springframework.richclient.application.ApplicationServicesLocator;
037 import org.springframework.richclient.application.ApplicationWindow;
038 import org.springframework.richclient.application.PageDescriptor;
039 import org.springframework.richclient.application.PageListener;
040 import org.springframework.richclient.application.ViewDescriptor;
041 import org.springframework.richclient.application.WindowManager;
042 import org.springframework.richclient.application.config.ApplicationLifecycleAdvisor;
043 import org.springframework.richclient.application.config.ApplicationWindowConfigurer;
044 import org.springframework.richclient.application.statusbar.StatusBar;
045 import org.springframework.richclient.command.CommandGroup;
046 import org.springframework.richclient.command.CommandManager;
047 import org.springframework.richclient.util.EventListenerListHelper;
048 import org.springframework.richclient.util.WindowUtils;
049 import org.springframework.util.Assert;
050
051 /**
052 * Abstract helper implementation for <code>ApplicationWindow</code>.
053 */
054 public abstract class AbstractApplicationWindow implements ApplicationWindow, WindowFocusListener {
055 protected Log logger = LogFactory.getLog( getClass() );
056
057 private final EventListenerListHelper pageListeners = new EventListenerListHelper( PageListener.class );
058
059 private int number;
060
061 private ApplicationWindowCommandManager commandManager;
062
063 private CommandGroup menuBarCommandGroup;
064
065 private CommandGroup toolBarCommandGroup;
066
067 private StatusBar statusBar;
068
069 private ApplicationWindowConfigurer windowConfigurer;
070
071 private JFrame control;
072
073 private ApplicationPage currentPage;
074
075 private WindowManager windowManager;
076
077 public AbstractApplicationWindow() {
078 this( Application.instance().getWindowManager().size() );
079 }
080
081 public AbstractApplicationWindow( int number ) {
082 this.number = number;
083 getAdvisor().setOpeningWindow( this );
084 init();
085 getAdvisor().onCommandsCreated( this );
086 }
087
088 protected void init() {
089 this.commandManager = getAdvisor().createWindowCommandManager();
090 this.menuBarCommandGroup = getAdvisor().getMenuBarCommandGroup();
091 this.toolBarCommandGroup = getAdvisor().getToolBarCommandGroup();
092 this.statusBar = getAdvisor().getStatusBar();
093 }
094
095 public int getNumber() {
096 return number;
097 }
098
099 public ApplicationPage getPage() {
100 return currentPage;
101 }
102
103 protected ApplicationLifecycleAdvisor getAdvisor() {
104 return Application.instance().getLifecycleAdvisor();
105 }
106
107 protected ApplicationServices getServices() {
108 return ApplicationServicesLocator.services();
109 }
110
111 protected ApplicationWindowConfigurer getWindowConfigurer() {
112 if( windowConfigurer == null ) {
113 this.windowConfigurer = initWindowConfigurer();
114 }
115 return windowConfigurer;
116 }
117
118 protected ApplicationWindowConfigurer initWindowConfigurer() {
119 return new DefaultApplicationWindowConfigurer( this );
120 }
121
122 public CommandManager getCommandManager() {
123 return commandManager;
124 }
125
126 public Iterator getSharedCommands() {
127 return commandManager.getSharedCommands();
128 }
129
130 public CommandGroup getMenuBar() {
131 return menuBarCommandGroup;
132 }
133
134 public CommandGroup getToolBar() {
135 return toolBarCommandGroup;
136 }
137
138 public StatusBar getStatusBar() {
139 return statusBar;
140 }
141
142 public void setWindowManager( WindowManager windowManager ) {
143 this.windowManager = windowManager;
144 }
145
146 /**
147 * Show the given page in this window.
148 *
149 * @param pageId the page to show, identified by id
150 *
151 * @throws IllegalArgumentException if pageId == null
152 */
153 public void showPage( String pageId ) {
154 if( pageId == null )
155 throw new IllegalArgumentException( "pageId == null" );
156
157 if( getPage() == null || !getPage().getId().equals( pageId ) ) {
158 showPage( createPage( this, pageId ) );
159 } else {
160 // asking for the same page, so ignore
161 }
162 }
163
164 public void showPage( PageDescriptor pageDescriptor ) {
165 Assert.notNull( pageDescriptor, "pageDescriptor == null" );
166
167 if( getPage() == null || !getPage().getId().equals( pageDescriptor.getId() ) ) {
168 showPage( createPage( pageDescriptor ) );
169 } else {
170 // asking for the same page, so ignore
171 }
172 }
173
174 /**
175 * Show the given page in this window.
176 *
177 * @param page the page to show
178 *
179 * @throws IllegalArgumentException if page == null
180 */
181 public void showPage( ApplicationPage page ) {
182 if( page == null )
183 throw new IllegalArgumentException( "page == null" );
184
185 if( this.currentPage == null ) {
186 this.currentPage = page;
187 getAdvisor().onPreWindowOpen( getWindowConfigurer() );
188 this.control = createNewWindowControl();
189 this.control.addWindowFocusListener( this );
190 initWindowControl( this.control );
191 getAdvisor().onWindowCreated( this );
192 setActivePage( page );
193 this.control.setVisible( true );
194 getAdvisor().onWindowOpened( this );
195 } else {
196 if( !currentPage.getId().equals( page.getId() ) ) {
197 final ApplicationPage oldPage = this.currentPage;
198 this.currentPage = page;
199 setActivePage( page );
200 pageListeners.fire( "pageClosed", oldPage );
201 } else {
202 // asking for the same page, so ignore
203 }
204 }
205 pageListeners.fire( "pageOpened", this.currentPage );
206 }
207
208 protected final ApplicationPage createPage( ApplicationWindow window, String pageDescriptorId ) {
209 PageDescriptor descriptor = getPageDescriptor( pageDescriptorId );
210 return createPage( descriptor );
211 }
212
213 /**
214 * Factory method for creating the page area managed by this window. Subclasses may
215 * override to return a custom page implementation.
216 *
217 * @param descriptor The page descriptor
218 *
219 * @return The window's page
220 */
221 protected ApplicationPage createPage( PageDescriptor descriptor ) {
222 ApplicationPageFactory windowFactory = (ApplicationPageFactory) getServices().getService(
223 ApplicationPageFactory.class );
224 return windowFactory.createApplicationPage( this, descriptor );
225 }
226
227 protected PageDescriptor getPageDescriptor( String pageDescriptorId ) {
228 ApplicationContext ctx = Application.instance().getApplicationContext();
229 Assert.state( ctx.containsBean( pageDescriptorId ), "Do not know about page or view descriptor with name '"
230 + pageDescriptorId + "' - check your context config" );
231 Object desc = ctx.getBean( pageDescriptorId );
232 if( desc instanceof PageDescriptor ) {
233 return (PageDescriptor) desc;
234 } else if( desc instanceof ViewDescriptor ) {
235 return new SingleViewPageDescriptor( (ViewDescriptor) desc );
236 } else {
237 throw new IllegalArgumentException( "Page id '" + pageDescriptorId
238 + "' is not backed by an ApplicationPageDescriptor" );
239 }
240 }
241
242 protected void initWindowControl( JFrame windowControl ) {
243 ApplicationWindowConfigurer configurer = getWindowConfigurer();
244 applyStandardLayout( windowControl, configurer );
245 prepareWindowForView( windowControl, configurer );
246 }
247
248 protected void applyStandardLayout( JFrame windowControl, ApplicationWindowConfigurer configurer ) {
249 windowControl.setTitle( configurer.getTitle() );
250 windowControl.setIconImage( configurer.getImage() );
251 windowControl.setJMenuBar( createMenuBarControl() );
252 windowControl.getContentPane().setLayout( new BorderLayout() );
253 windowControl.getContentPane().add( createToolBarControl(), BorderLayout.NORTH );
254 windowControl.getContentPane().add( createWindowContentPane() );
255 windowControl.getContentPane().add( createStatusBarControl(), BorderLayout.SOUTH );
256 }
257
258 /**
259 * Set the given <code>ApplicationPage</code> active (visible + selected if
260 * applicable)
261 *
262 * @param page the <code>ApplicationPage</code>
263 */
264 protected abstract void setActivePage( ApplicationPage page );
265
266 protected void prepareWindowForView( JFrame windowControl, ApplicationWindowConfigurer configurer ) {
267 windowControl.pack();
268 windowControl.setSize( configurer.getInitialSize() );
269
270 WindowUtils.centerOnScreen(windowControl);
271 }
272
273 protected JFrame createNewWindowControl() {
274 JFrame frame = new JFrame();
275 frame.setDefaultCloseOperation( WindowConstants.DO_NOTHING_ON_CLOSE );
276 WindowAdapter windowCloseHandler = new WindowAdapter() {
277 public void windowClosing( WindowEvent e ) {
278 close();
279 }
280 };
281 frame.addWindowListener( windowCloseHandler );
282 return frame;
283 }
284
285 public JFrame getControl() {
286 return control;
287 }
288
289 public boolean isControlCreated() {
290 return control != null;
291 }
292
293 protected JMenuBar createMenuBarControl() {
294 JMenuBar menuBar = menuBarCommandGroup.createMenuBar();
295 menuBarCommandGroup.setVisible( getWindowConfigurer().getShowMenuBar() );
296 return menuBar;
297 }
298
299 protected JComponent createToolBarControl() {
300 JComponent toolBar = toolBarCommandGroup.createToolBar();
301 toolBarCommandGroup.setVisible( getWindowConfigurer().getShowToolBar() );
302 return toolBar;
303 }
304
305 protected JComponent createStatusBarControl() {
306 JComponent statusBarControl = statusBar.getControl();
307 statusBarControl.setVisible( getWindowConfigurer().getShowStatusBar() );
308 return statusBarControl;
309 }
310
311 public void addPageListener( PageListener listener ) {
312 this.pageListeners.add( listener );
313 }
314
315 public void removePageListener( PageListener listener ) {
316 this.pageListeners.remove( listener );
317 }
318
319 /**
320 * Close this window. First checks with the advisor by calling the
321 * {@link ApplicationLifecycleAdvisor#onPreWindowClose(ApplicationWindow)}
322 * method. Then tries to close it's currentPage. If both are successfull,
323 * the window will be disposed and removed from the {@link WindowManager}.
324 *
325 * @return boolean <code>true</code> if both, the advisor and the
326 * currentPage allow the closing action.
327 */
328 public boolean close() {
329 boolean canClose = getAdvisor().onPreWindowClose( this );
330 if( canClose ) {
331 // check if page can be closed
332 if( currentPage != null ) {
333 canClose = currentPage.close();
334 // page cannot be closed, exit method and do not dispose
335 if (!canClose)
336 return canClose;
337 }
338
339 if( control != null ) {
340 control.dispose();
341 control = null;
342 }
343
344 if( windowManager != null ) {
345 windowManager.remove( this );
346 }
347 windowManager = null;
348 }
349 return canClose;
350 }
351
352 /**
353 * When gaining focus, set this window as the active one on it's manager.
354 */
355 public void windowGainedFocus( WindowEvent e ) {
356 if( this.windowManager != null )
357 this.windowManager.setActiveWindow( this );
358 }
359
360 /**
361 * When losing focus no action is done. This way the last focussed window will stay
362 * listed as the activeWindow.
363 */
364 public void windowLostFocus( WindowEvent e ) {
365 }
366
367 /**
368 * Implementors create the component that contains the contents of this window.
369 *
370 * @return the content pane
371 */
372 protected abstract JComponent createWindowContentPane();
373 }