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    }