com.google.api.explorer.client.embedded.RequestBodyForm.java Source code

Java tutorial

Introduction

Here is the source code for com.google.api.explorer.client.embedded.RequestBodyForm.java

Source

/*
 * Copyright (C) 2012 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.google.api.explorer.client.embedded;

import com.google.api.explorer.client.Resources;
import com.google.api.explorer.client.Resources.Css;
import com.google.api.explorer.client.base.ApiMethod;
import com.google.api.explorer.client.base.ApiService;
import com.google.api.explorer.client.base.Schema;
import com.google.api.explorer.client.parameter.schema.SchemaForm;
import com.google.api.explorer.client.widgets.DescendantFocusPanel;
import com.google.api.explorer.client.widgets.FocusInHandler;
import com.google.api.explorer.client.widgets.FocusOutHandler;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Strings;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.FocusEvent;
import com.google.gwt.event.dom.client.FocusHandler;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.event.dom.client.KeyUpEvent;
import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.json.client.JSONException;
import com.google.gwt.json.client.JSONParser;
import com.google.gwt.resources.client.CssResource;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.PopupPanel.PositionCallback;
import com.google.gwt.user.client.ui.PushButton;
import com.google.gwt.user.client.ui.TextArea;
import com.google.gwt.user.client.ui.Widget;

/**
 * Form which shows a request body in an editor that can be used in both structured and freeform
 * mode, with special styling to collapse the editor when it doesn't have focus.
 *
 */
public class RequestBodyForm extends Composite {
    private static Css globalStyle = Resources.INSTANCE.style();

    @VisibleForTesting
    enum BodyEditor {
        SCHEMA, FREEFORM,
    }

    interface RequestBodyFormUiBinder extends UiBinder<Widget, RequestBodyForm> {
    }

    interface RequestBodyFormStyle extends CssResource {
        String hiddenControls();
    }

    private BodyEditor selectedEditor;

    @UiField
    public DescendantFocusPanel requestPanel;

    @UiField(provided = true)
    SchemaForm schemaForm;
    @UiField
    TextArea requestBody;
    @UiField
    Label editorSwitchError;
    @UiField
    RequestBodyFormStyle style;

    @UiField
    PushButton switchEditorMenu;
    @UiField
    PopupPanel menuPopup;
    @UiField
    PushButton showStructured;
    @UiField
    PushButton showFreeform;

    @UiHandler("switchEditorMenu")
    void discloseSwitchEditorMenu(ClickEvent event) {
        menuPopup.setPopupPositionAndShow(new PositionCallback() {
            @Override
            public void setPosition(int offsetWidth, int offsetHeight) {
                int left = switchEditorMenu.getAbsoluteLeft() + switchEditorMenu.getOffsetWidth() - offsetWidth;
                int top = switchEditorMenu.getAbsoluteTop() + switchEditorMenu.getOffsetHeight();
                menuPopup.setPopupPosition(left, top);
            }
        });
    }

    @UiHandler("showStructured")
    void selectStructuredEditor(ClickEvent event) {
        showEditor(BodyEditor.SCHEMA, /* Focus the editor after switching. */ true);
        menuPopup.hide();
    }

    @UiHandler("showFreeform")
    void selectFreeformEditor(ClickEvent event) {
        showEditor(BodyEditor.FREEFORM, /* Focus the editor after switching. */ true);
        menuPopup.hide();
    }

    /**
     * Create an empty request body form.
     */
    public RequestBodyForm() {
        schemaForm = new SchemaForm();

        initWidget(((RequestBodyFormUiBinder) GWT.create(RequestBodyFormUiBinder.class)).createAndBindUi(this));

        requestPanel.addFocusInHandler(new FocusInHandler() {
            @Override
            public void onFocusIn(Event event) {
                // Fade in the style for the controls.
                requestPanel.removeStyleName(style.hiddenControls());
            }
        });

        requestPanel.addFocusOutHandler(new FocusOutHandler() {
            @Override
            public void onFocusOut(Event event) {
                // Fade out the style for the controls
                requestPanel.addStyleName(style.hiddenControls());
            }
        });

        setupEditorDataBinding();

        // Remove the popup from the flow.
        menuPopup.show();
        menuPopup.hide();
    }

    /**
     * Bind the free form and schema based editors together so that when the user switches the data is
     * moved between editors.
     */
    private void setupEditorDataBinding() {
        // Add a handler to clear body error message when the user intends to edit
        // the text.
        requestBody.addFocusHandler(new FocusHandler() {
            @Override
            public void onFocus(FocusEvent event) {
                editorSwitchError.setVisible(false);
            }
        });

        requestBody.addValueChangeHandler(new ValueChangeHandler<String>() {
            @Override
            public void onValueChange(ValueChangeEvent<String> event) {
                resizeTextArea();
            }
        });

        requestBody.addKeyPressHandler(new KeyPressHandler() {
            @Override
            public void onKeyPress(KeyPressEvent event) {
                resizeTextArea();
            }
        });

        requestBody.addKeyUpHandler(new KeyUpHandler() {

            @Override
            public void onKeyUp(KeyUpEvent event) {
                resizeTextArea();
            }
        });
    }

    /**
     * Returns the text associated with the contents of the editor.
     */
    public String getRequestBodyText() {
        return selectedEditor == BodyEditor.SCHEMA ? schemaForm.getStringValue() : requestBody.getText();
    }

    /**
     * Sets the text of the currently selected editor to the value provided.
     *
     * @param value Json or free-form text that should be used to populate the form.
     */
    public void setRequestBodyText(String value) {
        if (selectedEditor == BodyEditor.SCHEMA) {
            try {
                schemaForm.setJSONValue(JSONParser.parseStrict(value));
            } catch (Exception e) {
                showEditor(BodyEditor.FREEFORM, /* Do not focus on this content fill. */ false);
            }
        }

        // This may have been the original selection, or it may have been switched to by a json parsing
        // error or an error when assigning the json to the schema editor.
        if (selectedEditor == BodyEditor.FREEFORM) {
            requestBody.setText(value);
        }
    }

    /**
     * Initialize the body editors based on the schema provided, starting with an
     * empty request.
     *
     * @param service Service which is used to find schemas.
     * @param method Method for which this form is being displayed.
     * @param requestSchema Schema for which to enable the editor of {@code null}
     *        if none.
     * @param initialText Initial text which should populate the editor.
     */
    public void setContent(ApiService service, ApiMethod method, Schema requestSchema, String initialText) {

        selectedEditor = null;
        BodyEditor editorToShow;

        if (requestSchema != null) {
            editorToShow = BodyEditor.SCHEMA;
            schemaForm.setSchema(service, method, requestSchema);
        } else {
            editorToShow = BodyEditor.FREEFORM;
        }

        showEditor(editorToShow, /* Do not focus on the content event. */ false);

        String textToShow = Strings.emptyToNull(initialText) == null ? "{}" : initialText;
        setRequestBodyText(textToShow);
    }

    private void resizeTextArea() {
        int rows = requestBody.getVisibleLines();
        while (rows > 1) {
            requestBody.setVisibleLines(--rows);
        }

        while (requestBody.getElement().getScrollHeight() > requestBody.getElement().getClientHeight()) {
            requestBody.setVisibleLines(requestBody.getVisibleLines() + 1);
        }
    }

    /**
     * When the user switches tabs, the data is persistent.
     */
    @VisibleForTesting
    void showEditor(BodyEditor editorType, boolean isFocused) {
        String text = getRequestBodyText();

        switch (editorType) {
        case SCHEMA:
            // About to switch to guided view
            if (selectedEditor != BodyEditor.SCHEMA) {
                try {
                    // If the user cleared the text, use an empty object
                    if (text.isEmpty()) {
                        text = "{}";
                    }

                    schemaForm.setJSONValue(JSONParser.parseStrict(text));
                    schemaForm.setVisible(true);
                    requestBody.setVisible(false);
                    selectedEditor = BodyEditor.SCHEMA;
                    showStructured.addStyleName(globalStyle.checked());
                    showFreeform.removeStyleName(globalStyle.checked());
                    requestPanel.setFocus(isFocused);
                } catch (JSONException e) {
                    // If there was an error parsing the JSON abort the switch and show the cause message to
                    // the user.
                    editorSwitchError.setVisible(true);
                    editorSwitchError.setText(e.getMessage());
                }
            }
            break;

        case FREEFORM:
            // About to switch to free form view
            schemaForm.setVisible(false);
            requestBody.setVisible(true);
            requestBody.setText(text);
            resizeTextArea();
            requestBody.setFocus(isFocused);
            selectedEditor = BodyEditor.FREEFORM;
            showStructured.removeStyleName(globalStyle.checked());
            showFreeform.addStyleName(globalStyle.checked());
            break;
        }
    }
}