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 }