rocket.widget.client.splitter.VerticalSplitterPanel.java Source code

Java tutorial

Introduction

Here is the source code for rocket.widget.client.splitter.VerticalSplitterPanel.java

Source

/*
 * Copyright Miroslav Pokorny
 *
 * 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 rocket.widget.client.splitter;

import java.util.Iterator;
import java.util.List;

import rocket.event.client.MouseMoveEvent;
import rocket.style.client.Css;
import rocket.style.client.CssUnit;
import rocket.style.client.InlineStyle;
import rocket.util.client.Checker;

import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.ui.Widget;

/**
 * A VerticalSplitterPanel is a panel that lays out its widget in a vertical
 * manner. The user can drag the splitter to change the size allocated for each
 * widget.
 * 
 * @author Miroslav Pokorny (mP)
 */
public class VerticalSplitterPanel extends SplitterPanel {

    public VerticalSplitterPanel() {
        super();
    }

    @Override
    protected void afterCreateWidget() {
        this.setItems(createItems());

        final InlineStyle inlineStyle = InlineStyle.getInlineStyle(DOM.getChild(this.getElement(), 0));
        inlineStyle.setString(Css.OVERFLOW_X, "hidden");
        inlineStyle.setString(Css.OVERFLOW_Y, "hidden");
    }

    @Override
    protected String getInitialStyleName() {
        return Constants.VERTICAL_SPLITTER_PANEL_STYLE;
    }

    /**
     * This factory method creates a new splitter on demand.
     * 
     * @return A new Vertical Splitter
     */
    protected Widget createSplitter() {
        return new VerticalSplitter();
    }

    class VerticalSplitter extends Splitter {

        VerticalSplitter() {
            super();
        }

        @Override
        protected void afterCreateElement() {
            super.afterCreateElement();

            this.setWidth("100%");
            this.setHeight(VerticalSplitterPanel.this.getSplitterSize() + "px");
        }

        @Override
        protected String getInitialStyleName() {
            return VerticalSplitterPanel.this.getSplitterStyle();
        }

        @Override
        protected String getDraggingStyleName() {
            return VerticalSplitterPanel.this.getDraggingStyle();
        }
    }

    protected String getSplitterStyle() {
        return Constants.VERTICAL_SPLITTER_PANEL_SPLITTER_STYLE;
    }

    protected String getDraggingStyle() {
        return Constants.VERTICAL_SPLITTER_PANEL_SPLITTER_DRAGGING_STYLE;
    }

    /**
     * This is the most important event handler that takes care of adjusting the
     * widths of the widgets before and after the splitter being moved.
     * 
     * @param splitter
     * @param event
     */
    protected void onMouseMove(final MouseMoveEvent event) {
        Checker.notNull("parameter:event", event);

        while (true) {
            final Splitter splitter = (Splitter) event.getWidget();

            // need to figure out if mouse has moved to the right or left...
            final int mouseY = event.getPageY();
            final int splitterY = DOM.getAbsoluteTop(splitter.getElement());

            // if the mouse has not moved vertically but vertically so exit...
            int delta = mouseY - splitterY;
            if (0 == delta) {
                break;
            }

            // grab the widgets before and after the splitter being dragged...
            final InternalPanel panel = this.getPanel();
            final int panelIndex = panel.indexOf(splitter);
            final Widget beforeWidget = panel.get(panelIndex - 1);
            int beforeWidgetHeight = beforeWidget.getOffsetHeight() + delta;

            final Widget afterWidget = panel.get(panelIndex + 1);
            int afterWidgetHeight = afterWidget.getOffsetHeight() - delta;

            final int heightSum = beforeWidgetHeight + afterWidgetHeight;

            final List<SplitterItem> items = this.getItems();

            // if the mouse moved left make sure the beforeWidget width is not
            // less than its minimumHeight.
            if (delta < 0) {
                final SplitterItem beforeWidgetItem = items.get(panelIndex / 2);
                final int minimumHeight = beforeWidgetItem.getMinimumSize();

                if (beforeWidgetHeight < minimumHeight) {
                    delta = minimumHeight - (beforeWidgetHeight - delta);
                    beforeWidgetHeight = minimumHeight;
                    afterWidgetHeight = heightSum - beforeWidgetHeight;
                }
            }

            // since the mouse moved right make sure the afterWidget width is
            // not less than its minimumHeight
            if (delta > 0) {
                final SplitterItem afterWidgetItem = items.get(panelIndex / 2 + 1);
                final int minimumHeight = afterWidgetItem.getMinimumSize();
                if (afterWidgetHeight < minimumHeight) {
                    delta = afterWidgetHeight + delta - minimumHeight;
                    afterWidgetHeight = minimumHeight;
                    beforeWidgetHeight = heightSum - afterWidgetHeight;
                }
            }

            // save!
            beforeWidget.setHeight(beforeWidgetHeight + "px");
            afterWidget.setHeight(afterWidgetHeight + "px");

            // update the coordinates of both the splitter and after widget...
            adjustYCoordinate(splitter, delta);
            adjustYCoordinate(afterWidget, delta);

            beforeWidget.setWidth("100%");
            splitter.setWidth("100%");
            afterWidget.setWidth("100%");

            // its necessary to prevent the event to stop text selection in
            // opera.
            break;
        }
    }

    protected void adjustYCoordinate(final Widget widget, final int delta) {
        final InlineStyle inlineStyle = InlineStyle.getInlineStyle(widget.getElement());

        final int y = inlineStyle.getInteger(Css.TOP, CssUnit.PX, 0);

        inlineStyle.setString(Css.POSITION, "absolute");
        inlineStyle.setInteger(Css.LEFT, 0, CssUnit.PX);
        inlineStyle.setInteger(Css.TOP, y + delta, CssUnit.PX);
    }

    /**
     * Lays out all added widgets summing their individual weights and then
     * assigns widths to each.
     */
    protected void redraw0() {
        final int weightSum = this.sumWeights();
        final InternalPanel panel = this.getPanel();
        final int availableHeight = DOM.getElementPropertyInt(panel.getParentElement(), "offsetHeight");

        final int splitterCount = (panel.getWidgetCount() - 1) / 2;
        final int splitterHeight = this.getSplitterSize();
        final int allocatedWidgetHeight = availableHeight - splitterCount * splitterHeight;
        final float ratio = (float) allocatedWidgetHeight / weightSum;

        int top = 0;
        final Iterator<SplitterItem> items = this.getItems().iterator();
        final Iterator<Widget> widgets = panel.iterator();

        boolean more = widgets.hasNext();

        while (more) {
            final Widget widget = widgets.next();
            final SplitterItem item = items.next();

            // set the widget position...
            final InlineStyle widgetInlineStyle = InlineStyle.getInlineStyle(widget.getElement());

            widgetInlineStyle.setString(Css.POSITION, "absolute");
            widgetInlineStyle.setInteger(Css.LEFT, 0, CssUnit.PX);
            widgetInlineStyle.setInteger(Css.TOP, top, CssUnit.PX);
            widgetInlineStyle.setString(Css.OVERFLOW, "hidden");

            // set the size(width/height)...
            widget.setWidth("100%");

            // is the last widget ???
            if (false == widgets.hasNext()) {
                widget.setHeight((availableHeight - top) + "px");
                break;
            }

            // calculate the new width...
            final int weight = item.getSizeShare();
            final int height = (int) (ratio * weight);
            widget.setHeight(height + "px");

            top = top + height;

            final Widget splitter = (Widget) widgets.next();

            // set the splitter position...
            final InlineStyle splitterInlineStyle = InlineStyle.getInlineStyle(splitter.getElement());
            splitterInlineStyle.setString(Css.POSITION, "absolute");
            splitterInlineStyle.setInteger(Css.LEFT, 0, CssUnit.PX);
            splitterInlineStyle.setInteger(Css.TOP, top, CssUnit.PX);
            splitterInlineStyle.setString(Css.OVERFLOW, "hidden");

            // set the splitters size...
            splitter.setWidth("100%");
            splitter.setHeight(splitterHeight + "px");

            top = top + splitterHeight;

            more = widgets.hasNext();
        }
    }
}