com.google.gwt.widgetideas.client.ResizableWidgetCollection.java Source code

Java tutorial

Introduction

Here is the source code for com.google.gwt.widgetideas.client.ResizableWidgetCollection.java

Source

/*
 * Copyright 2008 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.gwt.widgetideas.client;

import com.google.gwt.event.logical.shared.ResizeEvent;
import com.google.gwt.event.logical.shared.ResizeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.WindowResizeListener;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * A collection of {@link ResizableWidget} that periodically checks the outer
 * dimensions of a widget and redraws it as necessary. Every
 * {@link ResizableWidgetCollection} uses a timer, so consider the cost when
 * adding one.
 * 
 * Typically, a {@link ResizableWidgetCollection} is only needed if you expect
 * your widgets to resize based on window resizing or other events. Fixed sized
 * Widgets do not need to be added to a {@link ResizableWidgetCollection} as
 * they cannot be resized.
 */
@SuppressWarnings("deprecation")
public class ResizableWidgetCollection implements WindowResizeListener, Iterable<ResizableWidget> {
    /**
     * Information about a widgets size.
     */
    private static class ResizableWidgetInfo {
        /**
         * The current clientHeight.
         */
        private int curHeight = 0;

        /**
         * The current clientWidth.
         */
        private int curWidth = 0;

        /**
         * Constructor.
         * 
         * @param widget the widget that will be monitored
         */
        public ResizableWidgetInfo(ResizableWidget widget) {
            curWidth = DOM.getElementPropertyInt(widget.getElement(), "clientWidth");
            curHeight = DOM.getElementPropertyInt(widget.getElement(), "clientHeight");
        }

        /**
         * Set the new dimensions of the widget if they changed.
         * 
         * @param width the new width
         * @param height the new height
         * @return true if the dimensions have changed
         */
        public boolean setClientSize(int width, int height) {
            if (width != curWidth || height != curHeight) {
                this.curWidth = width;
                this.curHeight = height;
                return true;
            } else {
                return false;
            }
        }
    }

    /**
     * The default delay between resize checks in milliseconds.
     */
    private static final int DEFAULT_RESIZE_CHECK_DELAY = 400;

    /**
     * A static {@link ResizableWidgetCollection} that can be used in most cases.
     */
    private static ResizableWidgetCollection staticCollection = null;

    /**
     * Get the globally accessible {@link ResizableWidgetCollection}. In most
     * cases, the global collection can be used for all {@link ResizableWidget}s.
     * 
     * @return the global {@link ResizableWidgetCollection}
     */
    public static ResizableWidgetCollection get() {
        if (staticCollection == null) {
            staticCollection = new ResizableWidgetCollection();
        }
        return staticCollection;
    }

    /**
     * The timer used to periodically compare the dimensions of elements to their
     * old dimensions.
     */
    private Timer resizeCheckTimer = new Timer() {
        @Override
        public void run() {
            // Ignore changes that result from window resize events
            if (windowHeight != Window.getClientHeight() || windowWidth != Window.getClientWidth()) {
                windowHeight = Window.getClientHeight();
                windowWidth = Window.getClientWidth();
                schedule(resizeCheckDelay);
                return;
            }

            // Look for elements that have new dimensions
            checkWidgetSize();

            // Start checking again
            if (resizeCheckingEnabled) {
                schedule(resizeCheckDelay);
            }
        }
    };

    /**
     * A hash map of the resizable widgets this collection is checking.
     */
    private Map<ResizableWidget, ResizableWidgetInfo> widgets = new HashMap<ResizableWidget, ResizableWidgetInfo>();

    /**
     * The current window height.
     */
    private int windowHeight = 0;

    /**
     * The current window width.
     */
    private int windowWidth = 0;

    /**
     * The hook used to remove the window handler.
     */
    private HandlerRegistration windowHandler;

    /**
     * The delay between resize checks.
     */
    private int resizeCheckDelay = DEFAULT_RESIZE_CHECK_DELAY;

    /**
     * A boolean indicating that resize checking should run.
     */
    private boolean resizeCheckingEnabled;

    /**
     * Create a ResizableWidget.
     */
    public ResizableWidgetCollection() {
        this(DEFAULT_RESIZE_CHECK_DELAY);
    }

    /**
     * Constructor.
     * 
     * @param resizeCheckingEnabled false to disable resize checking
     */
    public ResizableWidgetCollection(boolean resizeCheckingEnabled) {
        this(DEFAULT_RESIZE_CHECK_DELAY, resizeCheckingEnabled);
    }

    /**
     * Constructor.
     * 
     * @param resizeCheckDelay the delay between checks in milliseconds
     */
    public ResizableWidgetCollection(int resizeCheckDelay) {
        this(resizeCheckDelay, true);
    }

    /**
     * Constructor.
     */
    protected ResizableWidgetCollection(int resizeCheckDelay, boolean resizeCheckingEnabled) {
        setResizeCheckDelay(resizeCheckDelay);
        setResizeCheckingEnabled(resizeCheckingEnabled);
    }

    /**
     * Add a resizable widget to the collection.
     * 
     * @param widget the resizable widget to add
     */
    public void add(ResizableWidget widget) {
        widgets.put(widget, new ResizableWidgetInfo(widget));
    }

    /**
     * Check to see if any Widgets have been resized and call their handlers
     * appropriately.
     */
    public void checkWidgetSize() {
        for (Map.Entry<ResizableWidget, ResizableWidgetInfo> entry : widgets.entrySet()) {
            ResizableWidget widget = entry.getKey();
            ResizableWidgetInfo info = entry.getValue();
            int curWidth = widget.getElement().getPropertyInt("clientWidth");
            int curHeight = widget.getElement().getPropertyInt("clientHeight");

            // Call the onResize method only if the widget is attached
            if (info.setClientSize(curWidth, curHeight)) {
                if (curWidth > 0 && curHeight > 0 && widget.isAttached()) {
                    widget.onResize(curWidth, curHeight);
                }
            }
        }
    }

    /**
     * Get the delay between resize checks in milliseconds.
     * 
     * @return the resize check delay
     */
    public int getResizeCheckDelay() {
        return resizeCheckDelay;
    }

    /**
     * Check whether or not resize checking is enabled.
     * 
     * @return true is resize checking is enabled
     */
    public boolean isResizeCheckingEnabled() {
        return resizeCheckingEnabled;
    }

    public Iterator<ResizableWidget> iterator() {
        return widgets.keySet().iterator();
    }

    /**
     * Called when the browser window is resized.
     * 
     * @param width the width of the window's client area.
     * @param height the height of the window's client area.
     */
    @Deprecated
    public void onWindowResized(int width, int height) {
        checkWidgetSize();
    }

    /**
     * Remove a {@link ResizableWidget} from the collection.
     * 
     * @param widget the widget to remove
     */
    public void remove(ResizableWidget widget) {
        widgets.remove(widget);
    }

    /**
     * Set the delay between resize checks in milliseconds.
     * 
     * @param resizeCheckDelay the new delay
     */
    public void setResizeCheckDelay(int resizeCheckDelay) {
        this.resizeCheckDelay = resizeCheckDelay;
    }

    /**
     * Set whether or not resize checking is enabled. If disabled, elements will
     * still be resized on window events, but the timer will not check their
     * dimensions periodically.
     * 
     * @param enabled true to enable the resize checking timer
     */
    public void setResizeCheckingEnabled(boolean enabled) {
        if (enabled && !resizeCheckingEnabled) {
            resizeCheckingEnabled = true;
            if (windowHandler == null) {
                windowHandler = Window.addResizeHandler(new ResizeHandler() {
                    public void onResize(ResizeEvent event) {
                        onWindowResized(event.getWidth(), event.getHeight());
                    }
                });
            }
            resizeCheckTimer.schedule(resizeCheckDelay);
        } else if (!enabled && resizeCheckingEnabled) {
            resizeCheckingEnabled = false;
            if (windowHandler != null) {
                windowHandler.removeHandler();
                windowHandler = null;
            }
            resizeCheckTimer.cancel();
        }
    }

    /**
     * Inform the {@link ResizableWidgetCollection} that the size of a widget has
     * changed and already been redrawn. This will prevent the widget from being
     * redrawn on the next loop.
     * 
     * @param widget the widget's size that changed
     */
    public void updateWidgetSize(ResizableWidget widget) {
        if (!widget.isAttached()) {
            return;
        }

        ResizableWidgetInfo info = widgets.get(widget);
        if (info != null) {
            int curWidth = widget.getElement().getPropertyInt("clientWidth");
            int curHeight = widget.getElement().getPropertyInt("clientHeight");
            info.setClientSize(curWidth, curHeight);
        }
    }

}