001    /*
002     * Copyright 2002-2008 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.docking.flexdock;
017    
018    import java.awt.Component;
019    import java.awt.event.ActionEvent;
020    import java.awt.event.ActionListener;
021    import java.beans.PropertyChangeEvent;
022    import java.beans.PropertyChangeListener;
023    import java.io.IOException;
024    import java.util.HashMap;
025    import java.util.Iterator;
026    import java.util.Map;
027    
028    import javax.swing.AbstractButton;
029    import javax.swing.JComponent;
030    
031    import org.flexdock.docking.Dockable;
032    import org.flexdock.docking.DockableFactory;
033    import org.flexdock.docking.DockingManager;
034    import org.flexdock.docking.state.PersistenceException;
035    import org.flexdock.view.View;
036    import org.flexdock.view.ViewProps;
037    import org.flexdock.view.Viewport;
038    import org.springframework.richclient.application.PageComponent;
039    import org.springframework.richclient.application.ViewDescriptor;
040    import org.springframework.richclient.application.support.AbstractApplicationPage;
041    
042    /**
043     * <code>ApplicationPage</code> that uses FlexDock.
044     * 
045     * @author Peter De Bruycker
046     */
047    public class FlexDockApplicationPage extends AbstractApplicationPage implements DockableFactory {
048        private Viewport port;
049        private Map<String, View> dockables = new HashMap<String, View>();
050        private boolean isLoadingLayout;
051        private boolean creatingDockable;
052    
053        private PropertyChangeListener activeHandler = new PropertyChangeListener() {
054            public void propertyChange( PropertyChangeEvent evt ) {
055                if( ViewProps.ACTIVE.equals( evt.getPropertyName() ) && Boolean.TRUE.equals( evt.getNewValue() ) ) {
056                    View view = (View) evt.getSource();
057                    PageComponent component = findPageComponent( view.getPersistentId() );
058                    setActiveComponent( component );
059                }
060            }
061        };
062    
063        protected View createView( final PageComponent component ) {
064            View view = new View( component.getId() );
065            view.setTitle( component.getDisplayName() );
066            view.setTabText( component.getDisplayName() );
067            view.setTabIcon( component.getIcon() );
068            view.setIcon( component.getIcon() );
069            view.setContentPane( component.getControl() );
070    
071            view.getViewProperties().addPropertyChangeListener( activeHandler );
072    
073            configureView( component, view, getViewDescriptor( component.getId() ) );
074    
075            dockables.put( component.getId(), view );
076    
077            return view;
078        }
079    
080        protected void configureView( final PageComponent component, View view, ViewDescriptor descriptor ) {
081            boolean closable = true;
082            boolean pinnable = true;
083            boolean dockable = true;
084    
085            if( descriptor instanceof FlexDockViewDescriptor ) {
086                FlexDockViewDescriptor desc = (FlexDockViewDescriptor) descriptor;
087                closable = desc.isClosable();
088                pinnable = desc.isPinnable();
089                dockable = desc.isDockable();
090            }
091    
092            if( closable ) {
093                view.addAction( View.CLOSE_ACTION );
094                // TODO fix this: this is the only way I found to find out if a dockable has
095                // been closed by the user.
096                AbstractButton btn = view.getActionButton( View.CLOSE_ACTION );
097                btn.addActionListener( new ActionListener() {
098                    public void actionPerformed( ActionEvent e ) {
099                        close( component );
100                    }
101                } );
102            }
103    
104            if( pinnable ) {
105                view.addAction( View.PIN_ACTION );
106            }
107    
108            view.getViewProperties().setDockingEnabled( dockable );
109        }
110    
111        protected JComponent createControl() {
112            port = new Viewport();
113    
114            return port;
115        }
116    
117        public View getFlexView( String id ) {
118            return dockables.get( id );
119        }
120    
121        protected void doAddPageComponent( PageComponent pageComponent ) {
122            View view = createView( pageComponent );
123            dockables.put( pageComponent.getId(), view );
124    
125            if( !isLoadingLayout ) {
126                DockingManager.display( view );
127            }
128        }
129    
130        protected void doRemovePageComponent( PageComponent pageComponent ) {
131            View view = getFlexView( pageComponent.getId() );
132            if( view != null ) {
133                DockingManager.close( (Dockable) view );
134    
135                // HACK: if we don't repaint here, when closing the last dockable the ui is
136                // not updated
137                port.revalidate();
138                port.repaint();
139    
140                dockables.remove( view );
141            }
142        }
143    
144        protected boolean giveFocusTo( final PageComponent pageComponent ) {
145            if( creatingDockable ) {
146                return false;
147            }
148    
149            View view = getFlexView( pageComponent.getId() );
150    
151            view.setActive( true );
152    
153            // HACK: otherwise the first dockable that was active will still be active
154            for( Iterator iter = DockingManager.getDockableIds().iterator(); iter.hasNext(); ) {
155                String id = (String) iter.next();
156                if( !id.equals( pageComponent.getId() ) ) {
157                    getFlexView( id ).setActive( false );
158                }
159            }
160    
161            return true;
162        }
163    
164        public void loadLayout() {
165            isLoadingLayout = true;
166    
167            // the view port must be created before we attempt to load the layout model or try
168            // to restore the layout
169            getControl();
170    
171            try {
172                DockingManager.loadLayoutModel( true );
173            } catch( IOException e ) {
174                e.printStackTrace();
175            } catch( PersistenceException e ) {
176                e.printStackTrace();
177            }
178    
179            port.revalidate();
180            port.repaint();
181    
182            isLoadingLayout = false;
183    
184            // mark the view associated with the active component as active
185            View view = getFlexView( getActiveComponent().getId() );
186            if( view != null ) {
187                view.setActive( true );
188            }
189        }
190    
191        public Component getDockableComponent( String id ) {
192            // not used, we work with dockables
193            return null;
194        }
195    
196        public Dockable getDockable( String id ) {
197            if( dockables.containsKey( id ) ) {
198                return (Dockable) dockables.get( id );
199            }
200    
201            creatingDockable = true;
202            showView( id );
203            creatingDockable = false;
204            return (Dockable) dockables.get( id );
205        }
206    }