Java tutorial
/******************************************************************************* * Copyright 2012 Pawe Pszty * * 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 org.rest.client.ui.desktop.widget; import java.util.ArrayList; import org.rest.client.RestClient; import org.rest.client.SyncAdapter; import org.rest.client.analytics.GoogleAnalytics; import org.rest.client.analytics.GoogleAnalyticsApp; import org.rest.client.codemirror.CodeMirror; import org.rest.client.codemirror.CodeMirrorChangeHandler; import org.rest.client.codemirror.CodeMirrorImpl; import org.rest.client.codemirror.CodeMirrorOptions; import org.rest.client.event.BoundaryChangeEvent; import org.rest.client.event.HttpEncodingChangeEvent; import org.rest.client.request.FilesObject; import org.rest.client.request.FormPayloadData; import org.rest.client.request.RequestPayloadParser; import org.rest.client.ui.IsHideable; import org.rest.client.ui.html5.HTML5Element; import org.rest.client.ui.html5.HTML5FileUpload; import org.rest.client.ui.html5.ListItem; import org.rest.client.ui.html5.ListPanel; import org.rest.client.util.Units; import com.google.gwt.core.client.GWT; import com.google.gwt.dom.client.DivElement; import com.google.gwt.dom.client.InputElement; import com.google.gwt.dom.client.Style.Display; import com.google.gwt.event.dom.client.ChangeEvent; import com.google.gwt.event.dom.client.ChangeHandler; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.dom.client.KeyUpEvent; import com.google.gwt.event.dom.client.KeyUpHandler; import com.google.gwt.event.dom.client.MouseOutEvent; import com.google.gwt.event.dom.client.MouseOutHandler; import com.google.gwt.event.dom.client.MouseOverEvent; import com.google.gwt.event.dom.client.MouseOverHandler; import com.google.gwt.event.logical.shared.ValueChangeEvent; import com.google.gwt.event.logical.shared.ValueChangeHandler; import com.google.gwt.file.client.File; import com.google.gwt.file.client.FileList; 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.ui.Composite; import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.HTMLPanel; import com.google.gwt.user.client.ui.HasText; import com.google.gwt.user.client.ui.InlineLabel; import com.google.gwt.user.client.ui.TextArea; import com.google.gwt.user.client.ui.TextBox; import com.google.gwt.user.client.ui.Widget; public class RequestBodyWidget extends Composite implements IsHideable, HasText { interface Binder extends UiBinder<Widget, RequestBodyWidget> { } public enum TABS { RAW, FORM, FILES } private class FormInputs { public FormInputs(TextBox keyBox, TextBox valueBox) { this.key = keyBox; this.value = valueBox; } final TextBox key; final TextBox value; } @UiField InlineLabel rawTab; @UiField InlineLabel formTab; @UiField InlineLabel filesTab; @UiField DivElement tabContent; @UiField HTMLPanel payloadFormPanel; @UiField HTMLPanel filesFormPanel; @UiField TextArea payloadRawInput; private TABS currentTab = TABS.RAW; private int fileFieldNumber = 0; private String fileFieldName = "fileUpload"; private String payloadData = ""; private ArrayList<FormInputs> formInputs = new ArrayList<FormInputs>(); private String requestEncoding = "application/x-www-form-urlencoded"; //default private CodeMirror bodyCodeMirror = null; /** * A category name for Google Analytics events. * Event will measure how often tabs are switched by the user. * It will help to decide if different editors are required. */ public final static String ANALYTICS_EVENT_CATEGORY = "Payload editor"; public RequestBodyWidget() { initWidget(GWT.<Binder>create(Binder.class).createAndBindUi(this)); payloadRawInput.addKeyUpHandler(new KeyUpHandler() { @Override public void onKeyUp(KeyUpEvent event) { payloadData = payloadRawInput.getValue(); } }); rawTab.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { if (currentTab.equals(TABS.RAW)) return; String tabHandlercurrent = "inlineButtonChecked"; HTML5Element tab = (HTML5Element) rawTab.getElement().cast(); ((HTML5Element) tab.getParentElement()).querySelector("." + tabHandlercurrent).getClassList() .remove(tabHandlercurrent); tab.getClassList().add(tabHandlercurrent); HTML5Element contentParent = (HTML5Element) tabContent.getParentElement(); contentParent.querySelector("." + "tabsContent" + " ." + "tabContent" + "." + "tabContentCurrent") .getClassList().remove("tabContentCurrent"); contentParent.querySelector("." + "tabsContent" + " ." + "tabContent" + "[data-tab=\"raw\"]") .getClassList().add("tabContentCurrent"); if (bodyCodeMirror != null) { bodyCodeMirror.refresh(); } currentTab = TABS.RAW; GoogleAnalytics.sendEvent(ANALYTICS_EVENT_CATEGORY, "Tab switched", "Raw tab"); GoogleAnalyticsApp.sendEvent(ANALYTICS_EVENT_CATEGORY, "Tab switched", "Raw tab"); } }); rawTab.addMouseOverHandler(new MouseOverHandler() { @Override public void onMouseOver(MouseOverEvent event) { HTML5Element tab = (HTML5Element) rawTab.getElement().cast(); if (!tab.getClassList().contains("inlineButtonChecked")) tab.getClassList().add("inlineButtonHover"); } }); rawTab.addMouseOutHandler(new MouseOutHandler() { @Override public void onMouseOut(MouseOutEvent event) { HTML5Element tab = (HTML5Element) rawTab.getElement().cast(); if (!tab.getClassList().contains("inlineButtonHover")) tab.getClassList().remove("inlineButtonHover"); } }); formTab.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { if (currentTab.equals(TABS.FORM)) return; updateForm(); ensureFormHasRow(); String tabHandlercurrent = "inlineButtonChecked"; HTML5Element tab = (HTML5Element) formTab.getElement().cast(); ((HTML5Element) tab.getParentElement()).querySelector("." + tabHandlercurrent).getClassList() .remove(tabHandlercurrent); tab.getClassList().add(tabHandlercurrent); HTML5Element contentParent = (HTML5Element) tabContent.getParentElement(); contentParent.querySelector("." + "tabsContent" + " ." + "tabContent" + "." + "tabContentCurrent") .getClassList().remove("tabContentCurrent"); contentParent.querySelector("." + "tabsContent" + " ." + "tabContent" + "[data-tab=\"form\"]") .getClassList().add("tabContentCurrent"); currentTab = TABS.FORM; GoogleAnalytics.sendEvent(ANALYTICS_EVENT_CATEGORY, "Tab switched", "Form tab"); GoogleAnalyticsApp.sendEvent(ANALYTICS_EVENT_CATEGORY, "Tab switched", "Form tab"); } }); formTab.addMouseOverHandler(new MouseOverHandler() { @Override public void onMouseOver(MouseOverEvent event) { HTML5Element tab = (HTML5Element) formTab.getElement().cast(); if (!tab.getClassList().contains("inlineButtonChecked")) tab.getClassList().add("inlineButtonHover"); } }); formTab.addMouseOutHandler(new MouseOutHandler() { @Override public void onMouseOut(MouseOutEvent event) { HTML5Element tab = (HTML5Element) formTab.getElement().cast(); if (tab.getClassList().contains("inlineButtonHover")) tab.getClassList().remove("inlineButtonHover"); } }); filesTab.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { if (currentTab.equals(TABS.FILES)) return; ensureFilesHasRow(); String tabHandlercurrent = "inlineButtonChecked"; HTML5Element tab = (HTML5Element) filesTab.getElement().cast(); ((HTML5Element) tab.getParentElement()).querySelector("." + tabHandlercurrent).getClassList() .remove(tabHandlercurrent); tab.getClassList().add(tabHandlercurrent); HTML5Element contentParent = (HTML5Element) tabContent.getParentElement(); contentParent.querySelector("." + "tabsContent" + " ." + "tabContent" + "." + "tabContentCurrent") .getClassList().remove("tabContentCurrent"); contentParent.querySelector("." + "tabsContent" + " ." + "tabContent" + "[data-tab=\"file\"]") .getClassList().add("tabContentCurrent"); currentTab = TABS.FILES; GoogleAnalytics.sendEvent(ANALYTICS_EVENT_CATEGORY, "Tab switched", "Files tab"); GoogleAnalyticsApp.sendEvent(ANALYTICS_EVENT_CATEGORY, "Tab switched", "Files tab"); } }); filesTab.addMouseOverHandler(new MouseOverHandler() { @Override public void onMouseOver(MouseOverEvent event) { HTML5Element tab = (HTML5Element) filesTab.getElement().cast(); if (!tab.getClassList().contains("inlineButtonChecked")) tab.getClassList().add("inlineButtonHover"); } }); filesTab.addMouseOutHandler(new MouseOutHandler() { @Override public void onMouseOut(MouseOutEvent event) { HTML5Element tab = (HTML5Element) filesTab.getElement().cast(); if (tab.getClassList().contains("inlineButtonHover")) tab.getClassList().remove("inlineButtonHover"); } }); HttpEncodingChangeEvent.register(RestClient.getClientFactory().getEventBus(), new HttpEncodingChangeEvent.Handler() { @Override public void onChange(String method) { requestEncoding = method; setEditorCurrentMode(); } }); loadCodeMirrorForBody(); } /** * Reset widget */ public void clear() { clearForm(); payloadData = ""; filesFormPanel.clear(); fileFieldNumber = 0; payloadRawInput.setValue(null); allFilesCount = 0; filesTab.setText("Files (0)"); if (bodyCodeMirror != null) { bodyCodeMirror.setValue(""); } } @Override public void hide() { if (!isHidden()) this.getElement().getStyle().setDisplay(Display.NONE); } @Override public void show() { if (isHidden()) this.getElement().getStyle().clearDisplay(); } @Override public boolean isHidden() { String display = this.getElement().getStyle().getDisplay(); if (display.toLowerCase().equals("none")) { return true; } return false; } @UiHandler("addValue") void onAddValue(ClickEvent e) { e.preventDefault(); addNewFormRow(null, null); } @UiHandler("addFile") void onAddFile(ClickEvent e) { e.preventDefault(); addNewFileRow(null); } ValueChangeHandler<String> formRowChange = new ValueChangeHandler<String>() { @Override public void onValueChange(ValueChangeEvent<String> event) { updateRaw(); } }; private void addNewFormRow(String key, String value) { final HTMLPanel row = new HTMLPanel(""); row.setStyleName("Request_Body_Widget_flex"); TextBox keyBox = new TextBox(); TextBox valueBox = new TextBox(); InlineLabel removeButton = new InlineLabel("x"); final FormInputs inputsListItem = new FormInputs(keyBox, valueBox); formInputs.add(inputsListItem); if (key != null) { keyBox.setValue(key); } if (value != null) { valueBox.setValue(value); } keyBox.getElement().setAttribute("placeholder", "key"); valueBox.getElement().setAttribute("placeholder", "value"); valueBox.addStyleName("formValueInput"); removeButton.addStyleName("removeButton"); removeButton.setTitle("Remove"); keyBox.addValueChangeHandler(formRowChange); valueBox.addValueChangeHandler(formRowChange); final FlowPanel keyContainer = new FlowPanel(); keyContainer.add(keyBox); keyContainer.addStyleName("Request_Body_Widget_flex"); final FlowPanel valueContainer = new FlowPanel(); valueContainer.add(valueBox); valueContainer.addStyleName("Request_Body_Widget_flex" + " " + "Request_Body_Widget_valueBlock"); final FlowPanel actionsContainer = new FlowPanel(); actionsContainer.add(removeButton); actionsContainer.addStyleName("Request_Body_Widget_flex"); row.add(keyContainer); row.add(valueContainer); row.add(actionsContainer); payloadFormPanel.add(row); removeButton.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { formInputs.remove(inputsListItem); row.removeFromParent(); updateRaw(); } }); keyBox.getElement().focus(); } private int allFilesCount = 0; private ArrayList<HTML5FileUpload> fileInputs = new ArrayList<HTML5FileUpload>(); private void addNewFileRow(String key) { final HTMLPanel row = new HTMLPanel(""); final ListPanel listPanel = new ListPanel(); listPanel.setStyleName("selectedFilesList"); row.setStyleName("formRow"); TextBox keyBox = new TextBox(); final HTML5FileUpload valueBox = new HTML5FileUpload(); InlineLabel removeButton = new InlineLabel("x"); fileInputs.add(valueBox); keyBox.getElement().setAttribute("placeholder", "Field name"); String value = null; if (key == null) { value = fileFieldName; if (fileFieldNumber > 0) { value += "" + fileFieldNumber; } } else { value = key; } keyBox.setValue(value); removeButton.addStyleName("removeButton"); removeButton.setTitle("Remove"); valueBox.setMultiple(true); valueBox.addChangeHandler(new ChangeHandler() { @Override public void onChange(ChangeEvent event) { int prevCnt = listPanel.getWidgetCount(); allFilesCount -= prevCnt; listPanel.clear(); FileList files = valueBox.getFiles(); int cnt = files.size(); allFilesCount += cnt; filesTab.setText("Files (" + allFilesCount + ")"); for (int i = 0; i < cnt; i++) { File file = files.get(i); double sizeLong = file.getSize(); String fileSize = Units.swithFileSize(sizeLong); String html = file.getName() + " "; html += "(" + fileSize + ")"; ListItem li = new ListItem(); li.setHTML(html); listPanel.add(li); } } }); row.add(valueBox); row.add(keyBox); row.add(removeButton); row.add(listPanel); filesFormPanel.add(row); removeButton.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { int cnt = listPanel.getWidgetCount(); allFilesCount -= cnt; filesTab.setText("Files (" + allFilesCount + ")"); fileInputs.remove(valueBox); row.removeFromParent(); } }); fileFieldNumber++; keyBox.selectAll(); keyBox.getElement().focus(); } @Override public String getText() { return payloadData; } @Override public void setText(String text) { this.payloadData = text; //propagate new value through widgets propagateCurrentPayload(); } /** * Set new value in raw text box and in form. */ void propagateCurrentPayload() { payloadRawInput.setValue(payloadData); if (bodyCodeMirror != null) { bodyCodeMirror.setValue(payloadData); bodyCodeMirror.refresh(); } updateForm(); } /** * Ensure that form has at least one row. */ void ensureFormHasRow() { if (payloadFormPanel.getWidgetCount() > 0) return; addNewFormRow(null, null); } void ensureFilesHasRow() { if (filesFormPanel.getWidgetCount() > 0) return; addNewFileRow(null); } /** * Clear form values */ void clearForm() { payloadFormPanel.clear(); formInputs.clear(); } /** * Get current payload value and fill up form. */ void updateForm() { clearForm(); ArrayList<FormPayloadData> list = RequestPayloadParser.stringToFormArrayList(payloadData, true, requestEncoding.equals("multipart/form-data")); for (FormPayloadData payload : list) { addNewFormRow(payload.getKey(), payload.getValue()); } } void updateRaw() { boolean useBoundary = requestEncoding.contains("multipart/form-data"); String currentBoundary = null; if (useBoundary) { currentBoundary = RequestPayloadParser.recognizeBoundary(payloadData); } payloadData = ""; ArrayList<FormPayloadData> list = new ArrayList<FormPayloadData>(); for (FormInputs inputs : formInputs) { list.add(new FormPayloadData(inputs.key.getValue(), inputs.value.getValue())); } payloadData = RequestPayloadParser.parseData(list, true, useBoundary, currentBoundary); payloadRawInput.setValue(payloadData); if (useBoundary) { currentBoundary = RequestPayloadParser.recognizeBoundary(payloadData); BoundaryChangeEvent e = new BoundaryChangeEvent(currentBoundary); RestClient.getClientFactory().getEventBus().fireEvent(e); } if (bodyCodeMirror != null) { bodyCodeMirror.setValue(payloadData); bodyCodeMirror.refresh(); } } public ArrayList<FilesObject> getInputFiles() { ArrayList<FilesObject> fo = new ArrayList<FilesObject>(); for (HTML5FileUpload file : fileInputs) { if (file == null) continue; FileList files = file.getFiles(); if (files == null || files.size() == 0) continue; InputElement ie = (InputElement) file.getElement().getNextSiblingElement(); FilesObject fileObjet = new FilesObject(ie.getValue(), files); fo.add(fileObjet); } return fo; } @UiHandler("decodeParams") void decodeParamsClick(ClickEvent e) { e.preventDefault(); boolean useBoundary = requestEncoding.contains("multipart/form-data"); String currentBoundary = null; if (useBoundary) { currentBoundary = RequestPayloadParser.recognizeBoundary(payloadData); } ArrayList<FormPayloadData> list = RequestPayloadParser.stringToFormArrayList(payloadData, true, requestEncoding.equals("multipart/form-data")); payloadData = RequestPayloadParser.parseData(list, false, useBoundary, currentBoundary); payloadRawInput.setValue(payloadData); if (bodyCodeMirror != null) { bodyCodeMirror.setValue(payloadData); bodyCodeMirror.refresh(); } } @UiHandler("encodeParams") void encodeParamsClick(ClickEvent e) { e.preventDefault(); boolean useBoundary = requestEncoding.contains("multipart/form-data"); String currentBoundary = null; if (useBoundary) { currentBoundary = RequestPayloadParser.recognizeBoundary(payloadData); } ArrayList<FormPayloadData> list = RequestPayloadParser.stringToFormArrayList(payloadData); payloadData = RequestPayloadParser.parseData(list, true, useBoundary, currentBoundary); payloadRawInput.setValue(payloadData); if (bodyCodeMirror != null) { bodyCodeMirror.setValue(payloadData); bodyCodeMirror.refresh(); } } private void loadCodeMirrorForBody() { if (!SyncAdapter.codeMirrorPayload) { if (bodyCodeMirror != null) { bodyCodeMirror.toTextArea(); bodyCodeMirror = null; } tabContent.removeClassName("codeMirror"); return; } tabContent.addClassName("codeMirror"); if (bodyCodeMirror != null) { bodyCodeMirror.refresh(); RestClient.fixChromeLayout(); return; } CodeMirrorOptions opt = CodeMirrorOptions.create(); opt.setLineNumbers(false); opt.setLineWrapping(true); if (!(payloadData == null || payloadData.isEmpty())) { opt.setValue(payloadData); } bodyCodeMirror = CodeMirror.fromTextArea(payloadRawInput.getElement(), opt, new CodeMirrorChangeHandler() { @Override public void onChage() { payloadData = bodyCodeMirror.getValue(); payloadRawInput.setValue(payloadData); } }); bodyCodeMirror.refresh(); RestClient.fixChromeLayout(); } private void setEditorCurrentMode() { if (bodyCodeMirror == null) return; //translate mode String mode = ""; if (requestEncoding.contains("json") || requestEncoding.contains("javascript")) { mode = "javascript"; } else if (requestEncoding.contains("xml") || requestEncoding.contains("atom") || requestEncoding.contains("rss")) { mode = "xml"; } else if (requestEncoding.contains("sql")) { mode = "sql"; } else if (requestEncoding.contains("html")) { mode = "htmlmixed"; } else if (requestEncoding.contains("css")) { mode = "css"; } bodyCodeMirror.setOption("mode", requestEncoding); if (!mode.isEmpty()) setAutoLoadCodeMirror(bodyCodeMirror.getInstance(), mode); } private final native void setAutoLoadCodeMirror(CodeMirrorImpl editor, String requestEncoding) /*-{ $wnd.CodeMirror.autoLoadMode(editor, requestEncoding); }-*/; }