org.rstudio.studio.client.workbench.ui.MainSplitPanel.java Source code

Java tutorial

Introduction

Here is the source code for org.rstudio.studio.client.workbench.ui.MainSplitPanel.java

Source

/*
 * MainSplitPanel.java
 *
 * Copyright (C) 2009-12 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */
package org.rstudio.studio.client.workbench.ui;

import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.SplitterResizedEvent;
import com.google.gwt.user.client.ui.SplitterResizedHandler;
import com.google.gwt.user.client.ui.Widget;
import com.google.inject.Inject;
import org.rstudio.core.client.js.JsObject;
import org.rstudio.studio.client.application.events.EventBus;
import org.rstudio.studio.client.common.NotifyingSplitLayoutPanel;
import org.rstudio.studio.client.workbench.model.ClientState;
import org.rstudio.studio.client.workbench.model.Session;
import org.rstudio.studio.client.workbench.model.helper.JSObjectStateValue;

public class MainSplitPanel extends NotifyingSplitLayoutPanel implements SplitterResizedHandler {
    private static class State extends JavaScriptObject {
        protected State() {
        }

        public native final boolean hasSplitterPos() /*-{
                                                     return typeof(this.splitterpos) != 'undefined';
                                                     }-*/;

        public native final int getSplitterPos() /*-{
                                                 return this.splitterpos;
                                                 }-*/;

        public native final void setSplitterPos(int pos) /*-{
                                                         this.splitterpos = pos;
                                                         }-*/;

        public native final boolean hasPanelWidth() /*-{
                                                    return typeof(this.panelwidth) != 'undefined';
                                                    }-*/;

        public native final int getPanelWidth() /*-{
                                                return this.panelwidth;
                                                }-*/;

        public native final void setPanelWidth(int width) /*-{
                                                          this.panelwidth = width;
                                                          }-*/;

        public native final boolean hasWindowWidth() /*-{
                                                     return typeof(this.windowwidth) != 'undefined';
                                                     }-*/;

        public native final int getWindowWidth() /*-{
                                                 return this.windowwidth;
                                                 }-*/;

        public native final void setWindowWidth(int width) /*-{
                                                           this.windowwidth = width;
                                                           }-*/;

        public static boolean equals(State a, State b) {
            if (a == null ^ b == null)
                return false;
            if (a == null)
                return true;

            if (a.hasSplitterPos() ^ b.hasSplitterPos())
                return false;
            if (a.hasSplitterPos() && a.getSplitterPos() != b.getSplitterPos())
                return false;

            if (a.hasPanelWidth() ^ b.hasPanelWidth())
                return false;
            if (a.hasPanelWidth() && a.getPanelWidth() != b.getPanelWidth())
                return false;

            if (a.hasWindowWidth() ^ b.hasWindowWidth())
                return false;
            if (a.hasWindowWidth() && a.getWindowWidth() != b.getWindowWidth())
                return false;

            return true;
        }
    }

    @Inject
    public MainSplitPanel(EventBus events, Session session) {
        super(3, events);
        session_ = session;
        addSplitterResizedHandler(this);
    }

    public void initialize(Widget left, Widget right) {
        left_ = left;
        right_ = right;

        new JSObjectStateValue(GROUP_WORKBENCH, KEY_RIGHTPANESIZE, ClientState.PERSISTENT,
                session_.getSessionInfo().getClientState(), false) {

            @Override
            protected void onInit(JsObject value) {
                State state = value == null ? null : (State) value.cast();
                if (state != null && state.hasSplitterPos()) {
                    if (state.hasPanelWidth() && state.hasWindowWidth()
                            && state.getWindowWidth() != Window.getClientWidth()) {
                        int delta = state.getWindowWidth() - state.getPanelWidth();
                        int offsetWidth = Window.getClientWidth() - delta;
                        double pct = (double) state.getSplitterPos() / state.getPanelWidth();
                        addEast(right_, pct * offsetWidth);
                    } else {
                        addEast(right_, state.getSplitterPos());
                    }
                } else {
                    addEast(right_, Window.getClientWidth() * 0.45);
                }

                Scheduler.get().scheduleDeferred(new ScheduledCommand() {
                    public void execute() {
                        enforceBoundaries();
                    }
                });
            }

            @Override
            protected JsObject getValue() {
                State state = JavaScriptObject.createObject().cast();
                state.setPanelWidth(getOffsetWidth());
                state.setWindowWidth(Window.getClientWidth());
                state.setSplitterPos(right_.getOffsetWidth());
                return state.cast();
            }

            @Override
            protected boolean hasChanged() {
                JsObject newValue = getValue();
                if (!State.equals(lastKnownValue_, (State) newValue.cast())) {
                    lastKnownValue_ = newValue.cast();
                    return true;
                }
                return false;
            }

            private State lastKnownValue_;
        };

        add(left);
        setWidgetMinSize(right_, 0);
    }

    @Override
    protected void onLoad() {
        super.onLoad();
        deferredSaveWidthPercent();
    }

    public void onSplitterResized(SplitterResizedEvent event) {
        enforceBoundaries();
        deferredSaveWidthPercent();
    }

    private void enforceBoundaries() {
        LayoutData layoutData = (LayoutData) right_.getLayoutData();
        if (layoutData != null && getOffsetWidth() != 0 && layoutData.size > getOffsetWidth() - 3) {
            layoutData.size = getOffsetWidth() - 3;
            forceLayout();
        }
    }

    private void deferredSaveWidthPercent() {
        Scheduler.get().scheduleDeferred(new ScheduledCommand() {
            public void execute() {
                splitPercent_ = null;
                int panelWidth = getOffsetWidth();
                assert panelWidth > 0;
                assert isVisible() && isAttached();
                if (panelWidth > 0)
                    splitPercent_ = (double) right_.getOffsetWidth() / panelWidth;
                previousOffsetWidth_ = panelWidth;
            }
        });
    }

    @Override
    public void onResize() {
        super.onResize();

        int offsetWidth = getOffsetWidth();
        if ((previousOffsetWidth_ == null || offsetWidth != previousOffsetWidth_.intValue())
                && splitPercent_ != null) {
            LayoutData layoutData = (LayoutData) right_.getLayoutData();
            if (layoutData == null)
                return;
            layoutData.size = splitPercent_ * offsetWidth;

            previousOffsetWidth_ = offsetWidth;

            // Defer actually updating the layout, so that if we receive many
            // mouse events before layout/paint occurs, we'll only update once.
            if (layoutCommand_ == null) {
                layoutCommand_ = new Command() {
                    public void execute() {
                        layoutCommand_ = null;
                        forceLayout();
                    }
                };
                Scheduler.get().scheduleDeferred(layoutCommand_);
            }
        }
    }

    private Double splitPercent_ = null;
    private Integer previousOffsetWidth_ = null;

    private final Session session_;
    @SuppressWarnings("unused")
    private Widget left_;
    private Widget right_;
    private static final String GROUP_WORKBENCH = "workbenchp";
    private static final String KEY_RIGHTPANESIZE = "rightpanesize";
    private Command layoutCommand_;
}