/* * Copyright (C) 2011 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.parameter.schema; import com.google.api.explorer.client.base.Schema; import com.google.api.explorer.client.parameter.schema.SchemaForm.SchemaEditor; import com.google.common.annotations.VisibleForTesting; import com.google.gwt.core.client.GWT; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.dom.client.MouseOutEvent; import com.google.gwt.event.dom.client.MouseOverEvent; import com.google.gwt.event.shared.HandlerManager; import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.json.client.JSONNull; import com.google.gwt.json.client.JSONValue; 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.HTMLPanel; import com.google.gwt.user.client.ui.Image; import com.google.gwt.user.client.ui.InlineLabel; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.Panel; import com.google.gwt.user.client.ui.PopupPanel; import com.google.gwt.user.client.ui.Widget; /** * Encapsulates the key/value of one key/value pair in an * {@link ObjectSchemaEditor}. * * @author jasonhall@google.com (Jason Hall) */ public class ObjectElement extends Composite implements SchemaEditor, HasRemovalHandlers { private static RowUiBinder uiBinder = GWT.create(RowUiBinder.class); interface RowUiBinder extends UiBinder<Widget, ObjectElement> { } @UiField Panel panel; @UiField InlineLabel label; @UiField InlineLabel nullText; @UiField HTMLPanel placeholder; @UiField Image remove; @UiField Image info; @UiField Label nullify; @UiField PopupPanel docsTooltip; @UiField PopupPanel patchTooltip; @UiField PopupPanel deleteTooltip; @UiField Label description; @UiField Label required; @VisibleForTesting final SchemaEditor innerEditor; final String key; private boolean isNull; private boolean isNullable; private final HandlerManager handlerManager = new HandlerManager(this); /** * Creates an instance. * * @param key Key in the object under which this object can be found. * @param editor Editor which should be shown for the value portion of the object element. * @param property Schema which is used to represent values of this object element. * @param isRemovable Whether or not this object can request to be removed from the object. * @param isNullable Whether or not the object can be explicitly set to null. */ public ObjectElement( String key, SchemaEditor editor, Schema property, boolean isRemovable, boolean isNullable) { initWidget(uiBinder.createAndBindUi(this)); this.key = key; this.innerEditor = editor; this.isNullable = isNullable; label.setText("\"" + key + "\""); info.setVisible(!isRemovable || property.getDescription() != null); required.setVisible(!isRemovable); remove.setVisible(isRemovable); description.setVisible(property.getDescription() != null); description.setText(property.getDescription()); // Default to showing the editor. isNull = false; updateDisplay(); placeholder.add(editor.render(property)); // Initialize the tooltip popup. docsTooltip.show(); docsTooltip.hide(); // Initialize the patch tooltip popup. patchTooltip.show(); patchTooltip.hide(); // Initialize the delete tooltip popup. deleteTooltip.show(); deleteTooltip.hide(); } @UiHandler("nullText") void activateInnerEditor(ClickEvent event) { isNull = false; updateDisplay(); } @UiHandler("nullify") void nullifyValue(ClickEvent event) { isNull = true; updateDisplay(); } private void updateDisplay() { nullText.setVisible(isNull); nullify.setVisible(!isNull && isNullable); placeholder.setVisible(!isNull); // If the editor is not an Object or Array editor, it can contain inner // elements, and will have its own inner remove link to manage them. If // that's the case, move the remove link to after the editor. if (!innerEditor.isComposite() || isNull) { moveControlsAfterEditor(); } else { moveEditorAfterControls(); } } @UiHandler("info") void discloseInfo(ClickEvent event) { EditorHelper.discloseLowerRight(docsTooltip, info); } @UiHandler("info") void discloseInfoHover(MouseOverEvent event) { EditorHelper.discloseLowerRight(docsTooltip, info); } @UiHandler("info") void hideInfoHover(MouseOutEvent event) { docsTooltip.hide(); } @UiHandler("nullify") void disclosePatchInfo(MouseOverEvent event) { EditorHelper.discloseLowerRight(patchTooltip, nullify); } @UiHandler("nullify") void disclosePatchInfo(MouseOutEvent event) { patchTooltip.hide(); } @UiHandler("remove") void removeClicked(ClickEvent event) { // Fire the remove event. handlerManager.fireEvent(new ClickEvent(){}); } @UiHandler("remove") void discloseRemoveHover(MouseOverEvent event) { EditorHelper.discloseLowerRight(deleteTooltip, remove); } @UiHandler("remove") void hideRemoveHover(MouseOutEvent event) { deleteTooltip.hide(); } private void moveControlsAfterEditor() { // By removing these widgets and re-adding them we move them to the end of the object panel. panel.remove(info); panel.remove(nullify); panel.remove(remove); // The order that these objects are added determines their order next to the element, and should // match the order from the declarative layout. panel.add(info); panel.add(nullify); panel.add(remove); } private void moveEditorAfterControls() { // By removing these widgets and re-adding them we move them to the end of the object panel. panel.remove(placeholder); panel.add(placeholder); } @Override public Widget render(Schema property) { return this; } @Override public JSONValue getJSONValue() { return isNull ? JSONNull.getInstance() : innerEditor.getJSONValue(); } @Override public void setJSONValue(JSONValue value) { if (value.isNull() != null) { isNull = true; } else { isNull = false; innerEditor.setJSONValue(value); } updateDisplay(); } @Override public void prettyPrint(StringBuilder resultSoFar, int indentation) { if (isNull) { resultSoFar.append("null"); } else { innerEditor.prettyPrint(resultSoFar, indentation); } } @Override public boolean isComposite() { return innerEditor.isComposite(); } @Override public HandlerRegistration registerRemoveClickedHandler(ClickHandler handler) { return handlerManager.addHandler(ClickEvent.getType(), handler); } }