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 }