View Javadoc

    1   /*
    2    *  soapUI, copyright (C) 2004-2007 eviware.com
    3    *
    4    *  soapUI is free software; you can redistribute it and/or modify it under the
    5    *  terms of version 2.1 of the GNU Lesser General Public License as published by
    6    *  the Free Software Foundation.
    7    *
    8    *  soapUI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
    9    *  even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    10   *  See the GNU Lesser General Public License for more details at gnu.org.
    11   */
    12
    13  package com.eviware.soapui.impl.wsdl.panels.request.components.editor;
    14
    15  import java.awt.BorderLayout;
    16  import java.awt.CardLayout;
    17  import java.awt.Color;
    18  import java.awt.event.ActionEvent;
    19  import java.beans.PropertyChangeEvent;
    20  import java.beans.PropertyChangeListener;
    21  import java.util.ArrayList;
    22  import java.util.HashMap;
    23  import java.util.List;
    24  import java.util.Map;
    25
    26  import javax.swing.AbstractAction;
    27  import javax.swing.JComponent;
    28  import javax.swing.JPanel;
    29  import javax.swing.JSplitPane;
    30  import javax.swing.JTabbedPane;
    31  import javax.swing.JToggleButton;
    32  import javax.swing.SwingUtilities;
    33  import javax.swing.event.ChangeEvent;
    34  import javax.swing.event.ChangeListener;
    35
    36  import com.eviware.soapui.support.UISupport;
    37  import com.eviware.soapui.support.components.JXToolBar;
    38  import com.eviware.soapui.support.components.VTextIcon;
    39  import com.eviware.soapui.support.components.VerticalTabbedPaneUI;
    40
    41  /***
    42   * Editor-framework for Xml Documents
    43   *
    44   * @author ole.matzura
    45   */
    46
    47  @SuppressWarnings("serial")
    48  public class XmlEditor extends JPanel implements PropertyChangeListener, XmlLocationListener
    49  {
    50  	private static final float DEFAULT_DIVIDER_LOCATION = 0.7F;
    51  	private JTabbedPane inputTabs;
    52  	private List<XmlEditorView> views = new ArrayList<XmlEditorView>();
    53  	private XmlEditorView currentView;
    54  	private XmlDocument xmlDocument;
    55  	private List<XmlInspector> inspectors = new ArrayList<XmlInspector>();
    56  	protected JSplitPane mainSplit;
    57  	private JXToolBar inspectToolbar;
    58  	private Map<XmlInspector,JToggleButton> inspectorButtons = new HashMap<XmlInspector,JToggleButton>();
    59  	private XmlInspector currentInspector;
    60  	private JPanel inspectorPanel;
    61  	private int lastDividerLocation = 0;
    62  	private InputTabsChangeListener inputTabsChangeListener;
    63
    64  	public XmlEditor( XmlDocument xmlDocument )
    65  	{
    66  		super( new BorderLayout() );
    67  		this.xmlDocument = xmlDocument;
    68
    69  		setBackground(Color.LIGHT_GRAY);
    70  	   inputTabs = new JTabbedPane(JTabbedPane.LEFT, JTabbedPane.SCROLL_TAB_LAYOUT);
    71     	inputTabs.setUI(new VerticalTabbedPaneUI());
    72
    73  		inputTabs.setFont(inputTabs.getFont().deriveFont(8));
    74  		inputTabsChangeListener = new InputTabsChangeListener();
    75  		inputTabs.addChangeListener( inputTabsChangeListener );
    76
    77  		inspectorPanel = new JPanel(new CardLayout());
    78  		inspectorPanel.setVisible( false );
    79
    80  		mainSplit = new JSplitPane( JSplitPane.VERTICAL_SPLIT, inputTabs, inspectorPanel );
    81  		mainSplit.setDividerSize( 10 );
    82  		mainSplit.setBorder( null );
    83  		mainSplit.setOneTouchExpandable( false );
    84
    85  		add(mainSplit, BorderLayout.CENTER);
    86  		add( createInspectButtons(), BorderLayout.PAGE_END  );
    87
    88  		mainSplit.setResizeWeight( 0.8 );
    89  	}
    90
    91  	private JComponent createInspectButtons()
    92  	{
    93  		inspectToolbar = UISupport.createToolbar();
    94  		inspectToolbar.addSpace( 10 );
    95  		inspectToolbar.setBackground( Color.WHITE );
    96  		inspectToolbar.setOpaque( true );
    97  		return inspectToolbar;
    98  	}
    99
    100 	public void addInspector( XmlInspector inspector )
    101 	{
    102 		if( inspectors.size() > 0 )
    103 		{
    104 			inspectToolbar.addSeparator();
    105 		}
    106
    107 		inspectors.add( inspector );
    108 		inspector.addPropertyChangeListener( this );
    109
    110 		inspectorPanel.add( inspector.getComponent(), inspector.getClass().getName() );
    111
    112 		JToggleButton button = new JToggleButton( new SelectInspectorAction( inspector ));
    113
    114 		button.setToolTipText( inspector.getDescription() );
    115 		button.setOpaque( true );
    116 		button.setEnabled( inspector.isEnabled() );
    117
    118 		inspectorButtons.put( inspector, button );
    119 		inspectToolbar.add( button );
    120 		inspectToolbar.addRelatedGap();
    121 	}
    122
    123 	public void addEditorView( XmlEditorView editorView )
    124 	{
    125 		views.add( editorView );
    126
    127 		inputTabs.addTab( null, new VTextIcon(inputTabs, editorView.getTitle(), VTextIcon.ROTATE_LEFT ),
    128 				editorView.getComponent() );
    129
    130 		editorView.addPropertyChangeListener( this );
    131 		editorView.addLocationListener( this );
    132
    133 		editorView.setXmlDocument( xmlDocument );
    134 	}
    135
    136 	public void propertyChange(PropertyChangeEvent evt)
    137 	{
    138 		if( evt.getPropertyName().equals( XmlEditorView.TITLE_PROPERTY ))
    139 		{
    140 			int ix = views.indexOf( evt.getSource() );
    141 			if( ix == -1 )
    142 				return;
    143
    144 			inputTabs.setTitleAt( ix, (String) evt.getNewValue() );
    145 		}
    146 		else if( evt.getPropertyName().equals( XmlInspector.ENABLED_PROPERTY ))
    147 		{
    148 			JToggleButton toggleButton = inspectorButtons.get( evt.getSource() );
    149 			toggleButton.setEnabled( ( Boolean ) evt.getNewValue() );
    150 		}
    151 	}
    152
    153 	public void selectView( int viewIndex )
    154 	{
    155 		inputTabs.setSelectedIndex( viewIndex );
    156 	}
    157
    158 	public void selectView( String viewId )
    159 	{
    160 		for( int c = 0; c < views.size(); c++ )
    161 		{
    162 			if( views.get( c ).getViewId().equals( viewId ))
    163 			{
    164 				inputTabs.setSelectedIndex( c );
    165 				return;
    166 			}
    167 		}
    168 	}
    169
    170
    171 	public void requestFocus()
    172 	{
    173 		if( currentView != null )
    174 			currentView.getComponent().requestFocus();
    175 	}
    176
    177 	public final XmlDocument getXmlDocument()
    178 	{
    179 		return xmlDocument;
    180 	}
    181
    182 	public boolean saveDocument( boolean validate )
    183 	{
    184 	   return currentView == null ? true : currentView.saveDocument( validate );
    185 	}
    186
    187 	public boolean hasFocus()
    188 	{
    189 		return currentView == null ? false : currentView.getComponent().hasFocus();
    190 	}
    191
    192 	public final void setXmlDocument(XmlDocument xmlDocument)
    193 	{
    194 		if( this.xmlDocument != null )
    195 			this.xmlDocument.release();
    196
    197 		this.xmlDocument = xmlDocument;
    198
    199 		for( XmlEditorView view : views )
    200 		{
    201 			view.setXmlDocument( xmlDocument );
    202 		}
    203 	}
    204
    205 	public final XmlEditorView getCurrentView()
    206 	{
    207 		return currentView;
    208 	}
    209
    210 	public final JTabbedPane getInputTabs()
    211 	{
    212 		return inputTabs;
    213 	}
    214
    215 	public final List<XmlEditorView> getViews()
    216 	{
    217 		return views;
    218 	}
    219
    220 	public XmlEditorView getView( String viewId )
    221 	{
    222 		for( XmlEditorView view : views )
    223 		{
    224 			if( view.getViewId().equals( viewId ))
    225 				return view;
    226 		}
    227
    228 		return null;
    229 	}
    230
    231 	public XmlInspector getInspector( String inspectorId  )
    232 	{
    233 		for( XmlInspector inspector : inspectors )
    234 		{
    235 			if( inspector.getInspectorId().equals( inspectorId ))
    236 				return inspector;
    237 		}
    238
    239 		return null;
    240 	}
    241
    242 	public void locationChanged(XmlLocation location)
    243 	{
    244 		if( location != null )
    245 		{
    246 			for( XmlInspector inspector : inspectors )
    247 			{
    248 				inspector.locationChanged( location );
    249 			}
    250 		}
    251 	}
    252
    253 	public void setEditable( boolean enabled )
    254 	{
    255 		for( XmlEditorView view : views )
    256 		{
    257 			view.setEditable( enabled );
    258 		}
    259 	}
    260
    261 	private final class InputTabsChangeListener implements ChangeListener
    262 	{
    263 		public void stateChanged( ChangeEvent e )
    264 		{
    265 			int currentViewIndex = views.indexOf( currentView );
    266
    267 			if( currentView != null )
    268 			{
    269 				if( inputTabs.getSelectedIndex() == currentViewIndex)
    270 					return;
    271
    272 				if( !currentView.deactivate() )
    273 				{
    274 					inputTabs.setSelectedIndex( currentViewIndex );
    275 					return;
    276 				}
    277 			}
    278
    279 			XmlEditorView previousView = currentView;
    280 			int selectedIndex = inputTabs.getSelectedIndex();
    281 			if( selectedIndex == -1 )
    282 			{
    283 				currentView = null;
    284 				return;
    285 			}
    286
    287 			currentView = views.get( selectedIndex );
    288
    289 			if( currentView != null && !currentView.activate( previousView == null ? null : previousView.getLocation() ))
    290 			{
    291 				inputTabs.setSelectedIndex( currentViewIndex );
    292 				if( currentViewIndex == -1 )
    293 					return;
    294 			}
    295
    296 			if( !currentView.isInspectable() && currentInspector != null )
    297 				lastDividerLocation = mainSplit.getDividerLocation();
    298
    299 			inspectorPanel.setVisible( currentView.isInspectable() && currentInspector != null );
    300 			inspectToolbar.setVisible( currentView.isInspectable()  );
    301
    302 			if( currentView.isInspectable() && currentInspector != null )
    303 			{
    304 				if( lastDividerLocation == 0 )
    305 					mainSplit.setDividerLocation( DEFAULT_DIVIDER_LOCATION );
    306 				else
    307 					mainSplit.setDividerLocation( lastDividerLocation );
    308 			}
    309
    310 			SwingUtilities.invokeLater( new Runnable() {
    311
    312 				public void run()
    313 				{
    314 					if( currentView != null )
    315 						currentView.getComponent().requestFocus();
    316 				}} );
    317
    318 		}
    319 	}
    320
    321 	public class SelectInspectorAction extends AbstractAction implements PropertyChangeListener
    322 	{
    323 		private final XmlInspector inspector;
    324
    325 		public SelectInspectorAction( XmlInspector inspector )
    326 		{
    327 			super( inspector.getTitle());
    328 			this.inspector = inspector;
    329 			inspector.addPropertyChangeListener( this );
    330 		}
    331
    332 		public void actionPerformed( ActionEvent arg0 )
    333 		{
    334 			JToggleButton button = inspectorButtons.get( inspector );
    335 			if( !button.isSelected() )
    336 			{
    337 				currentInspector = null;
    338 				button.setBackground( inspectToolbar.getBackground() );
    339 				lastDividerLocation = mainSplit.getDividerLocation();
    340 				inspectorPanel.setVisible( false );
    341 			}
    342 			else
    343 			{
    344 				if( currentInspector != null )
    345 					inspectorButtons.get( currentInspector ).setSelected( false );
    346
    347 				currentInspector = inspector;
    348 				button.setBackground( Color.WHITE );
    349
    350 				if( !inspectorPanel.isVisible() )
    351 				{
    352 					inspectorPanel.setVisible( true );
    353 					if( lastDividerLocation == 0 )
    354 						mainSplit.setDividerLocation( DEFAULT_DIVIDER_LOCATION );
    355 					else
    356 						mainSplit.setDividerLocation( lastDividerLocation );
    357 				}
    358
    359 				CardLayout cards = ( CardLayout ) inspectorPanel.getLayout();
    360 				cards.show( inspectorPanel, inspector.getClass().getName() );
    361 			}
    362 		}
    363
    364 		public void propertyChange( PropertyChangeEvent evt )
    365 		{
    366 			if( evt.getPropertyName().equals( XmlInspector.TITLE_PROPERTY ))
    367 				putValue( AbstractAction.NAME, evt.getNewValue() );
    368 			else if( evt.getPropertyName().equals( XmlInspector.DESCRIPTION_PROPERTY ))
    369 				putValue( AbstractAction.SHORT_DESCRIPTION, evt.getNewValue() );
    370 			else if( evt.getPropertyName().equals( XmlInspector.ENABLED_PROPERTY ))
    371 			{
    372 				boolean enable = ((Boolean)evt.getNewValue()).booleanValue();
    373 				setEnabled( enable );
    374
    375 				if( !enable && currentInspector == inspector )
    376 				{
    377 					inspectorButtons.get( currentInspector ).setSelected( false );
    378 				}
    379 			}
    380 		}
    381 	}
    382
    383 	public void release()
    384 	{
    385 		for( XmlEditorView view : views )
    386 		{
    387 			view.release();
    388 			view.removeLocationListener( this );
    389 			view.removePropertyChangeListener( this );
    390 		}
    391
    392 		views.clear();
    393
    394 		for( XmlInspector inspector : inspectors )
    395 		{
    396 			inspector.removePropertyChangeListener( this );
    397 			inspector.release();
    398 		}
    399
    400 		inspectors.clear();
    401
    402 		inputTabs.removeChangeListener( inputTabsChangeListener );
    403 		inputTabs.removeAll();
    404 		inspectorPanel.removeAll();
    405
    406 		mainSplit.removeAll();
    407
    408 		xmlDocument.release();
    409 	}
    410 }