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 }