com.eviware.soapui.impl.wsdl.panels.request.AbstractWsdlRequestDesktopPanel.java Source code

Java tutorial

Introduction

Here is the source code for com.eviware.soapui.impl.wsdl.panels.request.AbstractWsdlRequestDesktopPanel.java

Source

/*
 *  soapui, copyright (C) 2006 eviware.com 
 *
 *  SoapUI is free software; you can redistribute it and/or modify it under the 
 *  terms of the GNU Lesser General Public License as published by the Free Software Foundation; 
 *  either version 2.1 of the License, or (at your option) any later version.
 *
 *  SoapUI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 
 *  even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
 *  See the GNU Lesser General Public License for more details at gnu.org.
 */

package com.eviware.soapui.impl.wsdl.panels.request;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JSeparator;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import javax.swing.JToggleButton;
import javax.swing.JToolBar;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.eviware.soapui.SoapUI;
import com.eviware.soapui.impl.wsdl.WsdlInterface;
import com.eviware.soapui.impl.wsdl.WsdlOperation;
import com.eviware.soapui.impl.wsdl.WsdlRequest;
import com.eviware.soapui.impl.wsdl.WsdlSubmitContext;
import com.eviware.soapui.impl.wsdl.actions.request.AddWSSSignature;
import com.eviware.soapui.impl.wsdl.actions.request.AddWSSUsernameTokenAction;
import com.eviware.soapui.impl.wsdl.actions.request.AddWSTimestampAction;
import com.eviware.soapui.impl.wsdl.actions.request.CleanHeader;
import com.eviware.soapui.impl.wsdl.actions.request.CloneRequestAction;
import com.eviware.soapui.impl.wsdl.actions.request.CreateEmptyRequestAction;
import com.eviware.soapui.impl.wsdl.actions.request.RecreateRequestAction;
import com.eviware.soapui.impl.wsdl.actions.support.ShowOnlineHelpAction;
import com.eviware.soapui.impl.wsdl.panels.attachments.AttachmentPanel;
import com.eviware.soapui.impl.wsdl.panels.request.actions.WSIValidateAction;
import com.eviware.soapui.impl.wsdl.panels.request.components.RequestXmlDocument;
import com.eviware.soapui.impl.wsdl.panels.request.components.ResponseXmlDocument;
import com.eviware.soapui.impl.wsdl.panels.request.components.SoapMessageXmlEditor;
import com.eviware.soapui.impl.wsdl.panels.request.components.editor.XmlDocument;
import com.eviware.soapui.impl.wsdl.panels.request.components.editor.XmlEditor;
import com.eviware.soapui.impl.wsdl.panels.request.components.editor.support.ValidationError;
import com.eviware.soapui.impl.wsdl.panels.request.components.editor.views.XmlOutlineEditor;
import com.eviware.soapui.impl.wsdl.panels.request.components.editor.views.XmlSourceEditor;
import com.eviware.soapui.impl.wsdl.panels.support.EndpointsComboBoxModel;
import com.eviware.soapui.impl.wsdl.submit.transports.http.WsdlResponse;
import com.eviware.soapui.impl.wsdl.support.HelpUrls;
import com.eviware.soapui.impl.wsdl.support.wsdl.WsdlValidator;
import com.eviware.soapui.model.ModelItem;
import com.eviware.soapui.model.iface.Submit;
import com.eviware.soapui.model.iface.SubmitContext;
import com.eviware.soapui.model.iface.SubmitListener;
import com.eviware.soapui.model.iface.Request.SubmitException;
import com.eviware.soapui.model.iface.Submit.Status;
import com.eviware.soapui.settings.UISettings;
import com.eviware.soapui.support.UISupport;
import com.eviware.soapui.support.actions.ChangeSplitPaneOrientationAction;
import com.eviware.soapui.support.components.JEditorStatusBarWithProgress;
import com.eviware.soapui.support.swing.SoapUISplitPaneUI;
import com.eviware.soapui.support.xml.JXEditTextArea;
import com.eviware.soapui.ui.support.AbstractDesktopPanel;

/**
 * DesktopPanel for WsdlRequests
 * 
 * @author Ole.Matzura
 */

public class AbstractWsdlRequestDesktopPanel<T extends ModelItem, T2 extends WsdlRequest>
        extends AbstractDesktopPanel<T> {
    private final static Log log = LogFactory.getLog(AbstractWsdlRequestDesktopPanel.class);

    private JComboBox endpointCombo;
    private JButton submitButton;
    private JButton cancelButton;
    private EndpointsComboBoxModel endpointsModel;
    private JEditorStatusBarWithProgress statusBar;
    private JButton splitButton;
    private Submit submit;
    private JButton recreateButton;
    private JButton cloneButton;
    private JButton createEmptyButton;
    private InternalSubmitListener internalSubmitListener;
    private JSplitPane requestSplitPane;
    private MoveFocusAction moveFocusAction;
    private ClosePanelAction closePanelAction = new ClosePanelAction();
    private T2 request;

    private SoapMessageXmlEditor requestEditor;
    private SoapMessageXmlEditor responseEditor;

    public WSIValidateAction wsiValidateAction;

    private JTabbedPane requestTabs;
    private JPanel requestTabPanel;
    private JToggleButton tabsButton;

    public boolean responseHasFocus;

    private JTabbedPane requestEditorTabs;
    private JTabbedPane responseEditorTabs;

    private JPanel requestEditorTabPanel;

    private JPanel responseEditorTabPanel;

    private AttachmentPropertyChangeListener attachmentsPropertyChangeListener = new AttachmentPropertyChangeListener();;

    public AbstractWsdlRequestDesktopPanel(T modelItem) {
        super(modelItem);
    }

    protected void init(T2 request) {
        this.request = request;

        this.endpointsModel = new EndpointsComboBoxModel(request);
        internalSubmitListener = createSubmitListener();

        request.addSubmitListener(internalSubmitListener);

        add(buildContent(), BorderLayout.CENTER);
        add(buildToolbar(), BorderLayout.NORTH);
        add(buildStatusLabel(), BorderLayout.SOUTH);

        setPreferredSize(new Dimension(600, 500));

        request.addPropertyChangeListener(attachmentsPropertyChangeListener);
    }

    protected InternalSubmitListener createSubmitListener() {
        return new InternalSubmitListener();
    }

    public final T2 getRequest() {
        return request;
    }

    public final SoapMessageXmlEditor getRequestEditor() {
        return requestEditor;
    }

    public final SoapMessageXmlEditor getResponseEditor() {
        return responseEditor;
    }

    public Submit getSubmit() {
        return submit;
    }

    protected JComponent buildStatusLabel() {
        statusBar = new JEditorStatusBarWithProgress();
        statusBar.setBorder(BorderFactory.createEmptyBorder(1, 0, 0, 0));

        return statusBar;
    }

    protected JComponent buildContent() {
        requestSplitPane = UISupport.createHorizontalSplit();
        requestSplitPane.setResizeWeight(0.5);
        requestSplitPane.setBorder(null);

        submitButton = createActionButton(new SubmitAction(), true);
        cancelButton = createActionButton(new CancelAction(), false);
        splitButton = createActionButton(new ChangeSplitPaneOrientationAction(requestSplitPane), true);

        tabsButton = new JToggleButton(new ChangeToTabsAction());
        tabsButton.setPreferredSize(UISupport.TOOLBAR_BUTTON_DIMENSION);

        recreateButton = createActionButton(new RecreateRequestAction(request), true);
        cloneButton = createActionButton(new CloneRequestAction(request), true);
        createEmptyButton = createActionButton(new CreateEmptyRequestAction(request), true);

        submitButton.setEnabled(request.getEndpoint() != null && request.getEndpoint().trim().length() > 0);

        moveFocusAction = new MoveFocusAction();
        wsiValidateAction = new WSIValidateAction(request);
        wsiValidateAction.setEnabled(request.getResponse() != null);

        requestEditor = buildRequestEditor();
        responseEditor = buildResponseEditor();

        requestEditorTabs = new JTabbedPane(JTabbedPane.BOTTOM);
        requestEditorTabs.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
        requestEditorTabs.addTab("SOAP Request", requestEditor);
        requestEditorTabs.addTab("Request Attachments (" + request.getAttachmentCount() + ")",
                new AttachmentPanel(request, true));

        responseEditorTabs = new JTabbedPane(JTabbedPane.BOTTOM);
        responseEditorTabs.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
        responseEditorTabs.addTab("SOAP Response", responseEditor);
        responseEditorTabs.addTab(
                "Response Attachments ("
                        + (request.getResponse() == null ? 0 : request.getResponse().getAttachments().length) + ")",
                new AttachmentPanel(request, false));

        requestTabs = new JTabbedPane();
        requestTabPanel = UISupport.createTabPanel(requestTabs, true);

        requestEditorTabPanel = UISupport.createTabPanel(requestEditorTabs, false);
        responseEditorTabPanel = UISupport.createTabPanel(responseEditorTabs, false);

        if (request.getSettings().getBoolean(UISettings.START_WITH_REQUEST_TABS)) {
            requestTabs.addTab("Request", requestEditorTabPanel);
            requestTabs.addTab("Response", responseEditorTabPanel);
            splitButton.setEnabled(false);
            tabsButton.setSelected(true);
            return requestTabPanel;
        } else {
            requestSplitPane.setTopComponent(requestEditorTabPanel);
            requestSplitPane.setBottomComponent(responseEditorTabPanel);
            requestSplitPane.setDividerLocation(0.5);
            return requestSplitPane;
        }
    }

    protected JButton createActionButton(Action action, boolean enabled) {
        JButton button = UISupport.createToolbarButton(action, enabled);
        action.putValue(Action.NAME, null);
        return button;
    }

    protected SoapMessageXmlEditor buildResponseEditor() {
        return new ResponseMessageEditor(new ResponseXmlDocument(request));
    }

    protected SoapMessageXmlEditor buildRequestEditor() {
        return new RequestMessageEditor(new RequestXmlDocument(request));
    }

    protected JComponent buildToolbar() {
        endpointCombo = new JComboBox(endpointsModel);
        endpointCombo.setToolTipText(endpointsModel.getSelectedItem().toString());

        endpointCombo.addItemListener(new ItemListener() {
            public void itemStateChanged(ItemEvent e) {
                Object item = endpointCombo.getSelectedItem();
                if (item == null) {
                    endpointCombo.setToolTipText("- no endpoint set for request -");
                } else {
                    String selectedItem = item.toString();
                    endpointCombo.setToolTipText(selectedItem);
                }

                submitButton.setEnabled(submit == null && request.getEndpoint() != null
                        && request.getEndpoint().trim().length() > 0);
            }
        });

        JToolBar toolbar = UISupport.createToolbar();

        toolbar.add(submitButton);
        insertButtons(toolbar);
        toolbar.add(recreateButton);
        toolbar.add(createEmptyButton);
        toolbar.add(cloneButton);
        toolbar.add(cancelButton);
        toolbar.addSeparator();
        toolbar.add(endpointCombo);

        toolbar.add(Box.createHorizontalGlue());
        toolbar.add(tabsButton);
        toolbar.add(splitButton);
        toolbar.add(UISupport.createToolbarButton(new ShowOnlineHelpAction(getHelpUrl())));

        return toolbar;
    }

    protected String getHelpUrl() {
        return HelpUrls.REQUESTEDITOR_HELP_URL;
    }

    protected void insertButtons(JToolBar toolbar) {
    }

    public void setEnabled(boolean enabled) {
        endpointCombo.setEnabled(enabled);
        requestEditor.getSourceEditor().setEditable(enabled);
        responseEditor.getSourceEditor().setEditable(enabled);

        submitButton
                .setEnabled(enabled && request.getEndpoint() != null && request.getEndpoint().trim().length() > 0);
        recreateButton.setEnabled(enabled);
        createEmptyButton.setEnabled(enabled);
        cloneButton.setEnabled(enabled);
    }

    private final class AttachmentPropertyChangeListener implements PropertyChangeListener {
        public void propertyChange(PropertyChangeEvent evt) {
            if (evt.getPropertyName().equals(WsdlRequest.ATTACHMENTS_PROPERTY)) {
                requestEditorTabs.setTitleAt(1, "Request Attachments (" + request.getAttachmentCount() + ")");
            } else if (evt.getPropertyName().equals(WsdlRequest.RESPONSE_PROPERTY)) {
                responseEditorTabs.setTitleAt(1, "Response Attachments ("
                        + (request.getResponse() == null ? 0 : request.getResponse().getAttachments().length)
                        + ")");
            }
        }
    }

    public class RequestMessageEditor extends SoapMessageXmlEditor {
        public RequestMessageEditor(XmlDocument document) {
            super(document, request);

            //addEditorView( new WsdlRequestFormEditor( request ) );
        }

        protected XmlSourceEditor buildSourceEditor() {
            RequestXmlSourceEditor editor = buildRequestSourceEditor();

            JXEditTextArea inputArea = editor.getInputArea();

            inputArea.addFocusListener(new InputAreaFocusListener());

            inputArea.getInputHandler().addKeyBinding("A+ENTER", submitButton.getAction());
            inputArea.getInputHandler().addKeyBinding("A+X", cancelButton.getAction());
            inputArea.getInputHandler().addKeyBinding("AC+TAB", moveFocusAction);
            inputArea.getInputHandler().addKeyBinding("F5", recreateButton.getAction());
            inputArea.getInputHandler().addKeyBinding("C+F4", closePanelAction);

            return editor;
        }

        protected RequestXmlSourceEditor buildRequestSourceEditor() {
            return new RequestXmlSourceEditor(this);
        }

        protected XmlOutlineEditor buildOutlineEditor() {
            XmlOutlineEditor editor = super.buildOutlineEditor();
            if (editor != null) {
                editor.getOutlineTable().addFocusListener(new InputAreaFocusListener());
            }

            return editor;
        }
    }

    public class RequestXmlSourceEditor extends XmlSourceEditor {
        public RequestXmlSourceEditor(XmlEditor xmlEditor) {
            super(xmlEditor);
        }

        protected ValidationError[] validateXml(String xml) {
            return validateRequestXml();
        }

        protected void buildPopup(JPopupMenu inputPopup, JXEditTextArea editArea) {
            super.buildPopup(inputPopup, editArea);

            inputPopup.insert(new JSeparator(), 2);
            inputPopup.insert(new AddWSSUsernameTokenAction(request), 3);
            inputPopup.insert(new AddWSTimestampAction(request), 4);
            //Aqui pode-se adicionar novos itens de popup
            inputPopup.insert(new AddWSSSignature(request), 5);
            inputPopup.insert(new CleanHeader(request), 6);

        }
    }

    public class ResponseMessageEditor extends SoapMessageXmlEditor {
        public ResponseMessageEditor(XmlDocument document) {
            super(document, request);
        }

        protected XmlSourceEditor buildSourceEditor() {
            ResponseXmlSourceEditor editor = buildResponseSourceEditor();

            JXEditTextArea inputArea = editor.getInputArea();
            inputArea.addFocusListener(new ResultAreaFocusListener());

            inputArea.getInputHandler().addKeyBinding("A+ENTER", submitButton.getAction());
            inputArea.getInputHandler().addKeyBinding("A+X", cancelButton.getAction());
            inputArea.getInputHandler().addKeyBinding("AC+TAB", moveFocusAction);
            inputArea.getInputHandler().addKeyBinding("C+F4", closePanelAction);

            return editor;
        }

        protected ResponseXmlSourceEditor buildResponseSourceEditor() {
            return new ResponseXmlSourceEditor(this);
        }

        protected XmlOutlineEditor buildOutlineEditor() {
            XmlOutlineEditor editor = super.buildOutlineEditor();
            if (editor != null) {
                editor.getOutlineTable().addFocusListener(new ResultAreaFocusListener());
            }

            return editor;
        }
    }

    public class ResponseXmlSourceEditor extends XmlSourceEditor {
        public ResponseXmlSourceEditor(XmlEditor xmlEditor) {
            super(xmlEditor);
            // TODO Auto-generated constructor stub
        }

        protected ValidationError[] validateXml(String xml) {
            return validateResponseXml();
        }

        protected void buildPopup(JPopupMenu inputPopup, JXEditTextArea editArea) {
            super.buildPopup(inputPopup, editArea);

            inputPopup.insert(new JSeparator(), 2);
            inputPopup.insert(wsiValidateAction, 3);
        }
    }

    protected final class InputAreaFocusListener implements FocusListener {
        public void focusGained(FocusEvent e) {
            responseHasFocus = false;

            statusBar.setTarget(requestEditor.getSourceEditor().getInputArea());
            if (!splitButton.isEnabled()) {
                requestTabs.setSelectedIndex(0);
                return;
            }

            if (getModelItem().getSettings().getBoolean(UISettings.NO_RESIZE_REQUEST_EDITOR))
                return;

            // dont resize if split has been dragged
            if (((SoapUISplitPaneUI) requestSplitPane.getUI()).hasBeenDragged())
                return;

            int pos = requestSplitPane.getDividerLocation();
            if (pos >= 600)
                return;
            if (requestSplitPane.getMaximumDividerLocation() > 700)
                requestSplitPane.setDividerLocation(600);
            else
                requestSplitPane.setDividerLocation(0.8);
        }

        public void focusLost(FocusEvent e) {
        }
    }

    protected final class ResultAreaFocusListener implements FocusListener {
        public void focusGained(FocusEvent e) {
            responseHasFocus = true;

            statusBar.setTarget(responseEditor.getSourceEditor().getInputArea());
            if (!splitButton.isEnabled()) {
                requestTabs.setSelectedIndex(1);
                return;
            }

            if (request.getSettings().getBoolean(UISettings.NO_RESIZE_REQUEST_EDITOR))
                return;

            // dont resize if split has been dragged or result is empty
            if (((SoapUISplitPaneUI) requestSplitPane.getUI()).hasBeenDragged() || request.getResponse() == null)
                return;

            int pos = requestSplitPane.getDividerLocation();
            int maximumDividerLocation = requestSplitPane.getMaximumDividerLocation();
            if (pos + 600 < maximumDividerLocation)
                return;

            if (maximumDividerLocation > 700)
                requestSplitPane.setDividerLocation(maximumDividerLocation - 600);
            else
                requestSplitPane.setDividerLocation(0.2);
        }

        public void focusLost(FocusEvent e) {
        }
    }

    public class SubmitAction extends AbstractAction {
        public SubmitAction() {
            putValue(Action.SMALL_ICON, UISupport.createImageIcon("/submit_request.gif"));
            putValue(Action.SHORT_DESCRIPTION, "Submit request to specified endpoint URL");
            putValue(Action.ACCELERATOR_KEY, UISupport.getKeyStroke("alt ENTER"));
        }

        public void actionPerformed(ActionEvent e) {
            if (submit != null && submit.getStatus() == Submit.Status.RUNNING) {
                if (UISupport.confirm("Cancel current request?", "Submit Request")) {
                    submit.cancel();
                } else
                    return;
            }

            try {
                submit = doSubmit();
            } catch (SubmitException e1) {
                e1.printStackTrace();
            }
        }
    }

    protected Submit doSubmit() throws SubmitException {
        return request.submit(new WsdlSubmitContext(null), true);
    }

    private class CancelAction extends AbstractAction {
        public CancelAction() {
            super();
            putValue(Action.SMALL_ICON, UISupport.createImageIcon("/cancel_request.gif"));
            putValue(Action.SHORT_DESCRIPTION, "Aborts ongoing request");
            putValue(Action.ACCELERATOR_KEY, UISupport.getKeyStroke("alt X"));
        }

        public void actionPerformed(ActionEvent e) {
            if (submit == null)
                return;

            cancelButton.setEnabled(false);
            submit.cancel();
            setEnabled(true);
            submit = null;
        }
    }

    private class ClosePanelAction extends AbstractAction {
        public void actionPerformed(ActionEvent e) {
            SoapUI.getDesktop().closeDesktopPanel(getModelItem());
        }
    }

    private class MoveFocusAction extends AbstractAction {
        public void actionPerformed(ActionEvent e) {
            if (requestEditor.hasFocus()) {
                responseEditor.requestFocus();
            } else {
                requestEditor.requestFocus();
            }
        }
    }

    protected class InternalSubmitListener implements SubmitListener {
        protected InternalSubmitListener() {
        }

        public boolean beforeSubmit(Submit submit, SubmitContext context) {
            if (submit.getRequest() != request)
                return true;

            if (getModelItem().getSettings().getBoolean(UISettings.AUTO_VALIDATE_REQUEST)) {
                boolean result = requestEditor.getSourceEditor().validate();
                if (!result && getModelItem().getSettings().getBoolean(UISettings.ABORT_ON_INVALID_REQUEST)) {
                    statusBar.setInfo("Cancelled request due to invalid content");
                    return false;
                }
            }

            setEnabled(false);
            cancelButton.setEnabled(AbstractWsdlRequestDesktopPanel.this.submit != null);
            statusBar.setIndeterminate(true);
            return true;
        }

        public void afterSubmit(Submit submit, SubmitContext context) {
            if (submit.getRequest() != request)
                return;

            statusBar.setIndeterminate(false);

            Status status = submit.getStatus();
            WsdlResponse response = (WsdlResponse) submit.getResponse();
            if (status != Status.CANCELED) {
                request.setResponse(response, context);
            }

            cancelButton.setEnabled(false);
            setEnabled(true);

            String message = null;
            String infoMessage = null;
            String requestName = request.getOperation().getInterface().getName() + "."
                    + request.getOperation().getName() + ":" + request.getName();

            wsiValidateAction.setEnabled(false);

            if (status == Status.CANCELED) {
                message = "CANCELED";
                infoMessage = "[" + requestName + "] - CANCELED";
            } else {
                if (status == Status.ERROR || response == null) {
                    message = "Error getting response; " + submit.getError();
                    infoMessage = "Error getting response for [" + requestName + "]; " + submit.getError();
                } else {
                    message = "response time: " + response.getTimeTaken() + "ms (" + response.getContentLength()
                            + " bytes)";
                    infoMessage = "Got response for [" + requestName + "] in " + response.getTimeTaken() + "ms ("
                            + response.getContentLength() + " bytes)";

                    if (!splitButton.isEnabled())
                        requestTabs.setSelectedIndex(1);

                    responseEditor.requestFocus();
                    wsiValidateAction.setEnabled(true);
                }
            }

            logMessages(message, infoMessage);

            if (getModelItem().getSettings().getBoolean(UISettings.AUTO_VALIDATE_RESPONSE))
                responseEditor.getSourceEditor().validate();

            AbstractWsdlRequestDesktopPanel.this.submit = null;
        }

        protected void logMessages(String message, String infoMessage) {
            log.info(infoMessage);
            statusBar.setInfo(message);
        }
    }

    public boolean onClose(boolean canCancel) {
        if (canCancel) {
            if (submit != null && submit.getStatus() == Submit.Status.RUNNING) {
                Boolean retVal = UISupport.confirmOrCancel("Cancel request before closing?", "Closing window");
                if (retVal == null)
                    return false;

                if (retVal.booleanValue() && submit.getStatus() == Submit.Status.RUNNING)
                    submit.cancel();
            }
        } else if (submit != null && submit.getStatus() == Submit.Status.RUNNING) {
            submit.cancel();
        }

        request.removeSubmitListener(internalSubmitListener);
        request.removePropertyChangeListener(attachmentsPropertyChangeListener);
        endpointsModel.release();

        return true;
    }

    public boolean dependsOn(ModelItem modelItem) {
        return modelItem == request || modelItem == request.getOperation()
                || modelItem == request.getOperation().getInterface()
                || modelItem == request.getOperation().getInterface().getProject();
    }

    public String getTitle() {
        return "Request: [" + request.getName() + "] - " + request.getOperation().getInterface().getName() + "#"
                + request.getOperation().getName();
    }

    private final class ChangeToTabsAction extends AbstractAction {
        public ChangeToTabsAction() {
            putValue(Action.SMALL_ICON, UISupport.createImageIcon("/toggle_tabs.gif"));
            putValue(Action.SHORT_DESCRIPTION, "Toggles to tab-based layout");
        }

        public void actionPerformed(ActionEvent e) {
            if (splitButton.isEnabled()) {
                splitButton.setEnabled(false);
                removeContent(requestSplitPane);
                setContent(requestTabPanel);
                requestTabs.addTab("Request", requestEditorTabPanel);
                requestTabs.addTab("Response", responseEditorTabPanel);

                if (responseHasFocus) {
                    requestTabs.setSelectedIndex(1);
                    requestEditorTabs.requestFocus();
                } else {
                    responseEditorTabs.requestFocus();
                }
            } else {
                int selectedIndex = requestTabs.getSelectedIndex();

                splitButton.setEnabled(true);
                removeContent(requestTabPanel);
                setContent(requestSplitPane);
                requestSplitPane.setTopComponent(requestEditorTabPanel);
                requestSplitPane.setBottomComponent(responseEditorTabPanel);
                requestSplitPane.setDividerLocation(0.5);

                if (selectedIndex == 0)
                    requestEditor.requestFocus();
                else
                    responseEditor.requestFocus();
            }

            revalidate();
        }
    }

    public void setContent(JComponent content) {
        add(content, BorderLayout.CENTER);
    }

    public void removeContent(JComponent content) {
        remove(content);
    }

    protected ValidationError[] validateResponseXml() {
        WsdlOperation operation = (WsdlOperation) request.getOperation();
        WsdlValidator validator = new WsdlValidator(((WsdlInterface) operation.getInterface()).getWsdlContext());

        return validator.assertResponse(request);
    }

    protected ValidationError[] validateRequestXml() {
        WsdlOperation operation = (WsdlOperation) request.getOperation();
        WsdlValidator validator = new WsdlValidator(((WsdlInterface) operation.getInterface()).getWsdlContext());

        return validator.assertRequest(request);
    }
}