001: /*
002: * soapUI, copyright (C) 2004-2007 eviware.com
003: *
004: * soapUI is free software; you can redistribute it and/or modify it under the
005: * terms of version 2.1 of the GNU Lesser General Public License as published by
006: * the Free Software Foundation.
007: *
008: * soapUI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
009: * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
010: * See the GNU Lesser General Public License for more details at gnu.org.
011: */
012:
013: package com.eviware.soapui.impl.wsdl.panels.request.components.editor;
014:
015: import java.awt.BorderLayout;
016: import java.awt.CardLayout;
017: import java.awt.Color;
018: import java.awt.event.ActionEvent;
019: import java.beans.PropertyChangeEvent;
020: import java.beans.PropertyChangeListener;
021: import java.util.ArrayList;
022: import java.util.HashMap;
023: import java.util.List;
024: import java.util.Map;
025:
026: import javax.swing.AbstractAction;
027: import javax.swing.JComponent;
028: import javax.swing.JPanel;
029: import javax.swing.JSplitPane;
030: import javax.swing.JTabbedPane;
031: import javax.swing.JToggleButton;
032: import javax.swing.SwingUtilities;
033: import javax.swing.event.ChangeEvent;
034: import javax.swing.event.ChangeListener;
035:
036: import com.eviware.soapui.support.UISupport;
037: import com.eviware.soapui.support.components.JXToolBar;
038: import com.eviware.soapui.support.components.VTextIcon;
039: import com.eviware.soapui.support.components.VerticalTabbedPaneUI;
040:
041: /**
042: * Editor-framework for Xml Documents
043: *
044: * @author ole.matzura
045: */
046:
047: @SuppressWarnings("serial")
048: public class XmlEditor extends JPanel implements
049: PropertyChangeListener, XmlLocationListener {
050: private static final float DEFAULT_DIVIDER_LOCATION = 0.7F;
051: private JTabbedPane inputTabs;
052: private List<XmlEditorView> views = new ArrayList<XmlEditorView>();
053: private XmlEditorView currentView;
054: private XmlDocument xmlDocument;
055: private List<XmlInspector> inspectors = new ArrayList<XmlInspector>();
056: protected JSplitPane mainSplit;
057: private JXToolBar inspectToolbar;
058: private Map<XmlInspector, JToggleButton> inspectorButtons = new HashMap<XmlInspector, JToggleButton>();
059: private XmlInspector currentInspector;
060: private JPanel inspectorPanel;
061: private int lastDividerLocation = 0;
062: private InputTabsChangeListener inputTabsChangeListener;
063:
064: public XmlEditor(XmlDocument xmlDocument) {
065: super (new BorderLayout());
066: this .xmlDocument = xmlDocument;
067:
068: setBackground(Color.LIGHT_GRAY);
069: inputTabs = new JTabbedPane(JTabbedPane.LEFT,
070: JTabbedPane.SCROLL_TAB_LAYOUT);
071: inputTabs.setUI(new VerticalTabbedPaneUI());
072:
073: inputTabs.setFont(inputTabs.getFont().deriveFont(8));
074: inputTabsChangeListener = new InputTabsChangeListener();
075: inputTabs.addChangeListener(inputTabsChangeListener);
076:
077: inspectorPanel = new JPanel(new CardLayout());
078: inspectorPanel.setVisible(false);
079:
080: mainSplit = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
081: inputTabs, inspectorPanel);
082: mainSplit.setDividerSize(10);
083: mainSplit.setBorder(null);
084: mainSplit.setOneTouchExpandable(false);
085:
086: add(mainSplit, BorderLayout.CENTER);
087: add(createInspectButtons(), BorderLayout.PAGE_END);
088:
089: mainSplit.setResizeWeight(0.8);
090: }
091:
092: private JComponent createInspectButtons() {
093: inspectToolbar = UISupport.createToolbar();
094: inspectToolbar.addSpace(10);
095: inspectToolbar.setBackground(Color.WHITE);
096: inspectToolbar.setOpaque(true);
097: return inspectToolbar;
098: }
099:
100: public void addInspector(XmlInspector inspector) {
101: if (inspectors.size() > 0) {
102: inspectToolbar.addSeparator();
103: }
104:
105: inspectors.add(inspector);
106: inspector.addPropertyChangeListener(this );
107:
108: inspectorPanel.add(inspector.getComponent(), inspector
109: .getClass().getName());
110:
111: JToggleButton button = new JToggleButton(
112: 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: views.add(editorView);
125:
126: inputTabs.addTab(null, new VTextIcon(inputTabs, editorView
127: .getTitle(), VTextIcon.ROTATE_LEFT), editorView
128: .getComponent());
129:
130: editorView.addPropertyChangeListener(this );
131: editorView.addLocationListener(this );
132:
133: editorView.setXmlDocument(xmlDocument);
134: }
135:
136: public void propertyChange(PropertyChangeEvent evt) {
137: if (evt.getPropertyName().equals(XmlEditorView.TITLE_PROPERTY)) {
138: int ix = views.indexOf(evt.getSource());
139: if (ix == -1)
140: return;
141:
142: inputTabs.setTitleAt(ix, (String) evt.getNewValue());
143: } else if (evt.getPropertyName().equals(
144: XmlInspector.ENABLED_PROPERTY)) {
145: JToggleButton toggleButton = inspectorButtons.get(evt
146: .getSource());
147: toggleButton.setEnabled((Boolean) evt.getNewValue());
148: }
149: }
150:
151: public void selectView(int viewIndex) {
152: inputTabs.setSelectedIndex(viewIndex);
153: }
154:
155: public void selectView(String viewId) {
156: for (int c = 0; c < views.size(); c++) {
157: if (views.get(c).getViewId().equals(viewId)) {
158: inputTabs.setSelectedIndex(c);
159: return;
160: }
161: }
162: }
163:
164: public void requestFocus() {
165: if (currentView != null)
166: currentView.getComponent().requestFocus();
167: }
168:
169: public final XmlDocument getXmlDocument() {
170: return xmlDocument;
171: }
172:
173: public boolean saveDocument(boolean validate) {
174: return currentView == null ? true : currentView
175: .saveDocument(validate);
176: }
177:
178: public boolean hasFocus() {
179: return currentView == null ? false : currentView.getComponent()
180: .hasFocus();
181: }
182:
183: public final void setXmlDocument(XmlDocument xmlDocument) {
184: if (this .xmlDocument != null)
185: this .xmlDocument.release();
186:
187: this .xmlDocument = xmlDocument;
188:
189: for (XmlEditorView view : views) {
190: view.setXmlDocument(xmlDocument);
191: }
192: }
193:
194: public final XmlEditorView getCurrentView() {
195: return currentView;
196: }
197:
198: public final JTabbedPane getInputTabs() {
199: return inputTabs;
200: }
201:
202: public final List<XmlEditorView> getViews() {
203: return views;
204: }
205:
206: public XmlEditorView getView(String viewId) {
207: for (XmlEditorView view : views) {
208: if (view.getViewId().equals(viewId))
209: return view;
210: }
211:
212: return null;
213: }
214:
215: public XmlInspector getInspector(String inspectorId) {
216: for (XmlInspector inspector : inspectors) {
217: if (inspector.getInspectorId().equals(inspectorId))
218: return inspector;
219: }
220:
221: return null;
222: }
223:
224: public void locationChanged(XmlLocation location) {
225: if (location != null) {
226: for (XmlInspector inspector : inspectors) {
227: inspector.locationChanged(location);
228: }
229: }
230: }
231:
232: public void setEditable(boolean enabled) {
233: for (XmlEditorView view : views) {
234: view.setEditable(enabled);
235: }
236: }
237:
238: private final class InputTabsChangeListener implements
239: ChangeListener {
240: public void stateChanged(ChangeEvent e) {
241: int currentViewIndex = views.indexOf(currentView);
242:
243: if (currentView != null) {
244: if (inputTabs.getSelectedIndex() == currentViewIndex)
245: return;
246:
247: if (!currentView.deactivate()) {
248: inputTabs.setSelectedIndex(currentViewIndex);
249: return;
250: }
251: }
252:
253: XmlEditorView previousView = currentView;
254: int selectedIndex = inputTabs.getSelectedIndex();
255: if (selectedIndex == -1) {
256: currentView = null;
257: return;
258: }
259:
260: currentView = views.get(selectedIndex);
261:
262: if (currentView != null
263: && !currentView
264: .activate(previousView == null ? null
265: : previousView.getLocation())) {
266: inputTabs.setSelectedIndex(currentViewIndex);
267: if (currentViewIndex == -1)
268: return;
269: }
270:
271: if (!currentView.isInspectable()
272: && currentInspector != null)
273: lastDividerLocation = mainSplit.getDividerLocation();
274:
275: inspectorPanel.setVisible(currentView.isInspectable()
276: && currentInspector != null);
277: inspectToolbar.setVisible(currentView.isInspectable());
278:
279: if (currentView.isInspectable() && currentInspector != null) {
280: if (lastDividerLocation == 0)
281: mainSplit
282: .setDividerLocation(DEFAULT_DIVIDER_LOCATION);
283: else
284: mainSplit.setDividerLocation(lastDividerLocation);
285: }
286:
287: SwingUtilities.invokeLater(new Runnable() {
288:
289: public void run() {
290: if (currentView != null)
291: currentView.getComponent().requestFocus();
292: }
293: });
294:
295: }
296: }
297:
298: public class SelectInspectorAction extends AbstractAction implements
299: PropertyChangeListener {
300: private final XmlInspector inspector;
301:
302: public SelectInspectorAction(XmlInspector inspector) {
303: super (inspector.getTitle());
304: this .inspector = inspector;
305: inspector.addPropertyChangeListener(this );
306: }
307:
308: public void actionPerformed(ActionEvent arg0) {
309: JToggleButton button = inspectorButtons.get(inspector);
310: if (!button.isSelected()) {
311: currentInspector = null;
312: button.setBackground(inspectToolbar.getBackground());
313: lastDividerLocation = mainSplit.getDividerLocation();
314: inspectorPanel.setVisible(false);
315: } else {
316: if (currentInspector != null)
317: inspectorButtons.get(currentInspector).setSelected(
318: false);
319:
320: currentInspector = inspector;
321: button.setBackground(Color.WHITE);
322:
323: if (!inspectorPanel.isVisible()) {
324: inspectorPanel.setVisible(true);
325: if (lastDividerLocation == 0)
326: mainSplit
327: .setDividerLocation(DEFAULT_DIVIDER_LOCATION);
328: else
329: mainSplit
330: .setDividerLocation(lastDividerLocation);
331: }
332:
333: CardLayout cards = (CardLayout) inspectorPanel
334: .getLayout();
335: cards.show(inspectorPanel, inspector.getClass()
336: .getName());
337: }
338: }
339:
340: public void propertyChange(PropertyChangeEvent evt) {
341: if (evt.getPropertyName().equals(
342: XmlInspector.TITLE_PROPERTY))
343: putValue(AbstractAction.NAME, evt.getNewValue());
344: else if (evt.getPropertyName().equals(
345: XmlInspector.DESCRIPTION_PROPERTY))
346: putValue(AbstractAction.SHORT_DESCRIPTION, evt
347: .getNewValue());
348: else if (evt.getPropertyName().equals(
349: XmlInspector.ENABLED_PROPERTY)) {
350: boolean enable = ((Boolean) evt.getNewValue())
351: .booleanValue();
352: setEnabled(enable);
353:
354: if (!enable && currentInspector == inspector) {
355: inspectorButtons.get(currentInspector).setSelected(
356: false);
357: }
358: }
359: }
360: }
361:
362: public void release() {
363: for (XmlEditorView view : views) {
364: view.release();
365: view.removeLocationListener(this );
366: view.removePropertyChangeListener(this );
367: }
368:
369: views.clear();
370:
371: for (XmlInspector inspector : inspectors) {
372: inspector.removePropertyChangeListener(this);
373: inspector.release();
374: }
375:
376: inspectors.clear();
377:
378: inputTabs.removeChangeListener(inputTabsChangeListener);
379: inputTabs.removeAll();
380: inspectorPanel.removeAll();
381:
382: mainSplit.removeAll();
383:
384: xmlDocument.release();
385: }
386: }
|