com.google.appinventor.client.editor.simple.components.MockButtonBase.java Source code

Java tutorial

Introduction

Here is the source code for com.google.appinventor.client.editor.simple.components.MockButtonBase.java

Source

// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0

package com.google.appinventor.client.editor.simple.components;

import static com.google.appinventor.client.Ode.MESSAGES;
import com.google.appinventor.client.editor.simple.SimpleEditor;
import com.google.appinventor.client.output.OdeLog;
import com.google.gwt.event.dom.client.ErrorEvent;
import com.google.gwt.event.dom.client.ErrorHandler;
import com.google.gwt.event.dom.client.LoadEvent;
import com.google.gwt.event.dom.client.LoadHandler;
import com.google.gwt.resources.client.ImageResource;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DeckPanel;
import com.google.gwt.user.client.ui.Image;

/**
 * Abstract superclass for button based mock components.
 *
 * @author lizlooney@google.com (Liz Looney)
 */
abstract class MockButtonBase extends MockVisibleComponent {
    // Property names
    private static final String PROPERTY_NAME_IMAGE = "Image";

    // GWT widget used to mock a Simple Button
    private final Button buttonWidget;
    private int[] preferredSizeOfButton;
    private final Image image;
    private String imagePropValue;
    private boolean hasImage;

    // We need to maintain these so we can show color and shape only when
    // there is no image.
    private String backgroundColor;
    // Legal values for shape are defined in
    // com.google.appinventor.components.runtime.Component.java.
    private int shape;

    /**
     * Creates a new MockButtonBase component.
     *
     * @param editor  editor of source file the component belongs to
     */
    MockButtonBase(SimpleEditor editor, String type, ImageResource icon) {
        super(editor, type, icon);

        // Initialize mock button UI
        buttonWidget = new Button();
        buttonWidget.addStyleName("ode-SimpleMockButton");
        image = new Image();
        image.addErrorHandler(new ErrorHandler() {
            @Override
            public void onError(ErrorEvent event) {
                if (imagePropValue != null && !imagePropValue.isEmpty()) {
                    OdeLog.elog("Error occurred while loading image " + imagePropValue);
                }
                refreshForm();
            }
        });
        image.addLoadHandler(new LoadHandler() {
            @Override
            public void onLoad(LoadEvent event) {
                refreshForm();
            }
        });
        DeckPanel deckPanel = new DeckPanel();
        deckPanel.setStylePrimaryName("ode-SimpleMockComponent");
        deckPanel.add(buttonWidget);
        deckPanel.add(image);
        deckPanel.showWidget(0);
        initComponent(deckPanel);
    }

    /**
     * Class that extends Button so we can use a protected constructor.
     *
     * <p/>The purpose of this class is to create a clone of the Button passed to
     * the constructor. It will be used to determine the preferred size of the
     * Button, without having the size constrained by its parent, since the
     * cloned Button won't have a parent.
     */
    static class ClonedButton extends Button {
        ClonedButton(Button b) {
            // Get the Element from the Button.
            // Call DOM.clone to make a deep clone of that element.
            // Pass that cloned element to the super constructor.
            super(DOM.clone(b.getElement(), true)); // true for a deep clone
        }
    }

    private Button createClonedButton() {
        return new ClonedButton(buttonWidget);
    }

    @Override
    public void onCreateFromPalette() {
        // Change button caption to component name
        changeProperty(PROPERTY_NAME_TEXT, MESSAGES.textPropertyValue(getName()));
    }

    /*
     * Sets the button's TextAlignment property to a new value.
     */
    private void setTextAlignmentProperty(String text) {
        MockComponentsUtil.setWidgetTextAlign(buttonWidget, text);
    }

    /*
     * Sets the button's Shape property to a new value.
     */
    private void setShapeProperty(String text) {
        shape = Integer.parseInt(text);
        // Android Buttons with images take the shape of the image and do not
        // use one of the defined Shapes.
        if (hasImage) {
            return;
        }
        switch (shape) {
        case 0:
            // Default Button
            DOM.setStyleAttribute(buttonWidget.getElement(), "borderRadius", "0px");
            break;
        case 1:
            // Rounded Button.
            // The corners of the Button are rounded by 10 px.
            // The value 10 px was chosen strictly for style.
            // 10 px is the same as ROUNDED_CORNERS_RADIUS defined in
            // com.google.appinventor.components.runtime.ButtonBase.
            DOM.setStyleAttribute(buttonWidget.getElement(), "borderRadius", "10px");
            break;
        case 2:
            // Rectangular Button
            DOM.setStyleAttribute(buttonWidget.getElement(), "borderRadius", "0px");
            break;
        case 3:
            // Oval Button
            String height = DOM.getStyleAttribute(buttonWidget.getElement(), "height");
            DOM.setStyleAttribute(buttonWidget.getElement(), "borderRadius", height);
            break;
        default:
            // This should never happen
            throw new IllegalArgumentException("shape:" + shape);
        }
    }

    /*
     * Sets the button's BackgroundColor property to a new value.
     */
    private void setBackgroundColorProperty(String text) {
        backgroundColor = text;
        // Android Buttons do not show a background color if they have an image.
        if (hasImage) {
            return;
        }
        if (MockComponentsUtil.isDefaultColor(text)) {
            // CSS background-color for ode-SimpleMockButton (copied from Ya.css)
            text = "&HFFE8E8E8";
        }
        MockComponentsUtil.setWidgetBackgroundColor(buttonWidget, text);
    }

    /*
     * Sets the button's Enabled property to a new value.
     */
    private void setEnabledProperty(String text) {
        MockComponentsUtil.setEnabled(this, text);
    }

    /*
     * Sets the button's FontBold property to a new value.
     */
    private void setFontBoldProperty(String text) {
        MockComponentsUtil.setWidgetFontBold(buttonWidget, text);
        updatePreferredSizeOfButton();
    }

    /*
     * Sets the button's FontItalic property to a new value.
     */
    private void setFontItalicProperty(String text) {
        MockComponentsUtil.setWidgetFontItalic(buttonWidget, text);
        updatePreferredSizeOfButton();
    }

    /*
     * Sets the button's FontSize property to a new value.
     */
    private void setFontSizeProperty(String text) {
        MockComponentsUtil.setWidgetFontSize(buttonWidget, text);
        updatePreferredSizeOfButton();
    }

    /*
     * Sets the button's FontTypeface property to a new value.
     */
    private void setFontTypefaceProperty(String text) {
        MockComponentsUtil.setWidgetFontTypeface(buttonWidget, text);
        updatePreferredSizeOfButton();
    }

    /*
     * Sets the button's Image property to a new value.
     */
    private void setImageProperty(String text) {
        imagePropValue = text;
        String url = convertImagePropertyValueToUrl(text);
        if (url == null) {
            hasImage = false;
            url = "";
            setBackgroundColorProperty(backgroundColor);
            setShapeProperty(Integer.toString(shape));
        } else {
            hasImage = true;
            // Android Buttons do not show a background color if they have an image.
            // The container's background color shows through any transparent
            // portions of the Image, an effect we can get in the browser by
            // setting the widget's background color to COLOR_NONE.
            MockComponentsUtil.setWidgetBackgroundColor(buttonWidget, "&H" + COLOR_NONE);
            DOM.setStyleAttribute(buttonWidget.getElement(), "borderRadius", "0px");
        }
        MockComponentsUtil.setWidgetBackgroundImage(buttonWidget, url);
        image.setUrl(url);
    }

    /*
     * Sets the button's Text property to a new value.
     */
    private void setTextProperty(String text) {
        buttonWidget.setText(text);
        updatePreferredSizeOfButton();
    }

    /*
     * Sets the button's TextColor property to a new value.
     */
    private void setTextColorProperty(String text) {
        if (MockComponentsUtil.isDefaultColor(text)) {
            text = "&HFF000000"; // black
        }
        MockComponentsUtil.setWidgetTextColor(buttonWidget, text);
    }

    private final void updatePreferredSizeOfButton() {
        preferredSizeOfButton = MockComponentsUtil.getPreferredSizeOfDetachedWidget(createClonedButton());
    }

    @Override
    public int getPreferredWidth() {
        // The superclass uses getOffsetWidth of the DeckPanel, which won't work for us.
        if (preferredSizeOfButton == null) {
            updatePreferredSizeOfButton();
        }
        int width = preferredSizeOfButton[0];
        if (hasImage) {
            int imageWidth = image.getWidth();
            if (imageWidth > width) {
                width = imageWidth;
            }
        }
        return width;
    }

    @Override
    public int getPreferredHeight() {
        // The superclass uses getOffsetHeight of the DeckPanel, which won't work for us.
        if (preferredSizeOfButton == null) {
            updatePreferredSizeOfButton();
        }
        int height = preferredSizeOfButton[1];
        if (hasImage) {
            int imageHeight = image.getHeight();
            if (imageHeight > height) {
                height = imageHeight;
            }
        }
        return height;
    }

    // PropertyChangeListener implementation

    @Override
    public void onPropertyChange(String propertyName, String newValue) {
        super.onPropertyChange(propertyName, newValue);

        // Apply changed properties to the mock component
        if (propertyName.equals(PROPERTY_NAME_TEXTALIGNMENT)) {
            setTextAlignmentProperty(newValue);
        } else if (propertyName.equals(PROPERTY_NAME_BACKGROUNDCOLOR)) {
            setBackgroundColorProperty(newValue);
        } else if (propertyName.equals(PROPERTY_NAME_ENABLED)) {
            setEnabledProperty(newValue);
        } else if (propertyName.equals(PROPERTY_NAME_FONTBOLD)) {
            setFontBoldProperty(newValue);
            refreshForm();
        } else if (propertyName.equals(PROPERTY_NAME_FONTITALIC)) {
            setFontItalicProperty(newValue);
            refreshForm();
        } else if (propertyName.equals(PROPERTY_NAME_FONTSIZE)) {
            setFontSizeProperty(newValue);
            refreshForm();
        } else if (propertyName.equals(PROPERTY_NAME_FONTTYPEFACE)) {
            setFontTypefaceProperty(newValue);
            refreshForm();
        } else if (propertyName.equals(PROPERTY_NAME_IMAGE)) {
            setImageProperty(newValue);
            refreshForm();
        } else if (propertyName.equals(PROPERTY_NAME_TEXT)) {
            setTextProperty(newValue);
            refreshForm();
        } else if (propertyName.equals(PROPERTY_NAME_TEXTCOLOR)) {
            setTextColorProperty(newValue);
        } else if (propertyName.equals(PROPERTY_NAME_BUTTONSHAPE)) {
            setShapeProperty(newValue);
        }
    }
}