All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.vaadin.client.ui.VUI Maven / Gradle / Ivy

Go to download

Vaadin is a web application framework for Rich Internet Applications (RIA). Vaadin enables easy development and maintenance of fast and secure rich web applications with a stunning look and feel and a wide browser support. It features a server-side architecture with the majority of the logic running on the server. Ajax technology is used at the browser-side to ensure a rich and interactive user experience.

There is a newer version: 8.26.0
Show newest version
/*
 * Copyright 2000-2014 Vaadin Ltd.
 * 
 * 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.vaadin.client.ui;

import java.util.ArrayList;

import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.dom.client.Element;
import com.google.gwt.event.dom.client.HasScrollHandlers;
import com.google.gwt.event.dom.client.ScrollEvent;
import com.google.gwt.event.dom.client.ScrollHandler;
import com.google.gwt.event.logical.shared.HasResizeHandlers;
import com.google.gwt.event.logical.shared.ResizeEvent;
import com.google.gwt.event.logical.shared.ResizeHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.http.client.URL;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.History;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.SimplePanel;
import com.vaadin.client.ApplicationConnection;
import com.vaadin.client.BrowserInfo;
import com.vaadin.client.ComponentConnector;
import com.vaadin.client.ConnectorMap;
import com.vaadin.client.Focusable;
import com.vaadin.client.LayoutManager;
import com.vaadin.client.Profiler;
import com.vaadin.client.WidgetUtil;
import com.vaadin.client.VConsole;
import com.vaadin.client.ui.ShortcutActionHandler.ShortcutActionHandlerOwner;
import com.vaadin.client.ui.TouchScrollDelegate.TouchScrollHandler;
import com.vaadin.client.ui.ui.UIConnector;
import com.vaadin.shared.ApplicationConstants;
import com.vaadin.shared.ui.ui.UIConstants;

/**
 * 
 */
public class VUI extends SimplePanel implements ResizeHandler,
        Window.ClosingHandler, ShortcutActionHandlerOwner, Focusable,
        com.google.gwt.user.client.ui.Focusable, HasResizeHandlers,
        HasScrollHandlers {

    private static int MONITOR_PARENT_TIMER_INTERVAL = 1000;

    /** For internal use only. May be removed or replaced in the future. */
    public String id;

    /** For internal use only. May be removed or replaced in the future. */
    public ShortcutActionHandler actionHandler;

    /*
     * Last known window size used to detect whether VView should be layouted
     * again. Detection must check window size, because the VView size might be
     * fixed and thus not automatically adapt to changed window sizes.
     */
    private int windowWidth;
    private int windowHeight;

    /*
     * Last know view size used to detect whether new dimensions should be sent
     * to the server.
     */
    private int viewWidth;
    private int viewHeight;

    /** For internal use only. May be removed or replaced in the future. */
    public ApplicationConnection connection;

    /**
     * Keep track of possible parent size changes when an embedded application.
     * 
     * Uses {@link #parentWidth} and {@link #parentHeight} as an optimization to
     * keep track of when there is a real change.
     */
    private Timer resizeTimer;

    /** stored width of parent for embedded application auto-resize */
    private int parentWidth;

    /** stored height of parent for embedded application auto-resize */
    private int parentHeight;

    /** For internal use only. May be removed or replaced in the future. */
    public boolean immediate;

    /** For internal use only. May be removed or replaced in the future. */
    public boolean resizeLazy = false;

    private HandlerRegistration historyHandlerRegistration;

    private TouchScrollHandler touchScrollHandler;

    /**
     * The current URI fragment, used to avoid sending updates if nothing has
     * changed.
     * 

* For internal use only. May be removed or replaced in the future. */ public String currentFragment; /** * Listener for URI fragment changes. Notifies the server of the new value * whenever the value changes. */ private final ValueChangeHandler historyChangeHandler = new ValueChangeHandler() { @Override public void onValueChange(ValueChangeEvent event) { String newFragment = event.getValue(); // Send the location to the server if the fragment has changed // and flush active connectors in UI. if (!newFragment.equals(currentFragment) && connection != null) { /* * Ensure the fragment is properly encoded in all browsers * (#10769) * * createUrlBuilder does not properly pass an empty fragment to * UrlBuilder on Webkit browsers so do it manually (#11686) */ String location = Window.Location .createUrlBuilder() .setHash( URL.decodeQueryString(Window.Location.getHash())) .buildString(); currentFragment = newFragment; connection.flushActiveConnector(); connection.updateVariable(id, UIConstants.LOCATION_VARIABLE, location, true); } } }; private VLazyExecutor delayedResizeExecutor = new VLazyExecutor(200, new ScheduledCommand() { @Override public void execute() { performSizeCheck(); } }); private Element storedFocus; public VUI() { super(); // Allow focusing the view by using the focus() method, the view // should not be in the document focus flow getElement().setTabIndex(-1); makeScrollable(); } /** * Start to periodically monitor for parent element resizes if embedded * application (e.g. portlet). */ @Override protected void onLoad() { super.onLoad(); if (isMonitoringParentSize()) { resizeTimer = new Timer() { @Override public void run() { // trigger check to see if parent size has changed, // recalculate layouts performSizeCheck(); resizeTimer.schedule(MONITOR_PARENT_TIMER_INTERVAL); } }; resizeTimer.schedule(MONITOR_PARENT_TIMER_INTERVAL); } } @Override protected void onAttach() { super.onAttach(); historyHandlerRegistration = History .addValueChangeHandler(historyChangeHandler); currentFragment = History.getToken(); } @Override protected void onDetach() { super.onDetach(); historyHandlerRegistration.removeHandler(); historyHandlerRegistration = null; } /** * Stop monitoring for parent element resizes. */ @Override protected void onUnload() { if (resizeTimer != null) { resizeTimer.cancel(); resizeTimer = null; } super.onUnload(); } /** * Called when the window or parent div might have been resized. * * This immediately checks the sizes of the window and the parent div (if * monitoring it) and triggers layout recalculation if they have changed. */ protected void performSizeCheck() { windowSizeMaybeChanged(Window.getClientWidth(), Window.getClientHeight()); } /** * Called when the window or parent div might have been resized. * * This immediately checks the sizes of the window and the parent div (if * monitoring it) and triggers layout recalculation if they have changed. * * @param newWindowWidth * The new width of the window * @param newWindowHeight * The new height of the window * * @deprecated use {@link #performSizeCheck()} */ @Deprecated protected void windowSizeMaybeChanged(int newWindowWidth, int newWindowHeight) { if (connection == null) { // Connection is null if the timer fires before the first UIDL // update return; } boolean changed = false; ComponentConnector connector = ConnectorMap.get(connection) .getConnector(this); if (windowWidth != newWindowWidth) { windowWidth = newWindowWidth; changed = true; connector.getLayoutManager().reportOuterWidth(connector, newWindowWidth); VConsole.log("New window width: " + windowWidth); } if (windowHeight != newWindowHeight) { windowHeight = newWindowHeight; changed = true; connector.getLayoutManager().reportOuterHeight(connector, newWindowHeight); VConsole.log("New window height: " + windowHeight); } Element parentElement = getElement().getParentElement(); if (isMonitoringParentSize() && parentElement != null) { // check also for parent size changes int newParentWidth = parentElement.getClientWidth(); int newParentHeight = parentElement.getClientHeight(); if (parentWidth != newParentWidth) { parentWidth = newParentWidth; changed = true; VConsole.log("New parent width: " + parentWidth); } if (parentHeight != newParentHeight) { parentHeight = newParentHeight; changed = true; VConsole.log("New parent height: " + parentHeight); } } if (changed) { /* * If the window size has changed, layout the VView again and send * new size to the server if the size changed. (Just checking VView * size would cause us to ignore cases when a relatively sized VView * should shrink as the content's size is fixed and would thus not * automatically shrink.) */ VConsole.log("Running layout functions due to window or parent resize"); // update size to avoid (most) redundant re-layout passes // there can still be an extra layout recalculation if webkit // overflow fix updates the size in a deferred block if (isMonitoringParentSize() && parentElement != null) { parentWidth = parentElement.getClientWidth(); parentHeight = parentElement.getClientHeight(); } sendClientResized(); LayoutManager layoutManager = connector.getLayoutManager(); if (layoutManager.isLayoutRunning()) { layoutManager.layoutLater(); } else { layoutManager.layoutNow(); } } } /** * @return the name of the theme in use by this UI. * @deprecated as of 7.3. Use {@link UIConnector#getActiveTheme()} instead. */ @Deprecated public String getTheme() { return ((UIConnector) ConnectorMap.get(connection).getConnector(this)) .getActiveTheme(); } /** * Returns true if the body is NOT generated, i.e if someone else has made * the page that we're running in. Otherwise we're in charge of the whole * page. * * @return true if we're running embedded */ public boolean isEmbedded() { return !getElement().getOwnerDocument().getBody().getClassName() .contains(ApplicationConstants.GENERATED_BODY_CLASSNAME); } /** * Returns true if the size of the parent should be checked periodically and * the application should react to its changes. * * @return true if size of parent should be tracked */ protected boolean isMonitoringParentSize() { // could also perform a more specific check (Liferay portlet) return isEmbedded(); } @Override public void onBrowserEvent(Event event) { super.onBrowserEvent(event); int type = DOM.eventGetType(event); if (type == Event.ONKEYDOWN && actionHandler != null) { actionHandler.handleKeyboardEvent(event); return; } } /* * (non-Javadoc) * * @see * com.google.gwt.event.logical.shared.ResizeHandler#onResize(com.google * .gwt.event.logical.shared.ResizeEvent) */ @Override public void onResize(ResizeEvent event) { triggerSizeChangeCheck(); } /** * Called when a resize event is received. * * This may trigger a lazy refresh or perform the size check immediately * depending on the browser used and whether the server side requests * resizes to be lazy. */ private void triggerSizeChangeCheck() { /* * IE (pre IE9 at least) will give us some false resize events due to * problems with scrollbars. Firefox 3 might also produce some extra * events. We postpone both the re-layouting and the server side event * for a while to deal with these issues. * * We may also postpone these events to avoid slowness when resizing the * browser window. Constantly recalculating the layout causes the resize * operation to be really slow with complex layouts. */ boolean lazy = resizeLazy || BrowserInfo.get().isIE8(); if (lazy) { delayedResizeExecutor.trigger(); } else { performSizeCheck(); } } /** * Send new dimensions to the server. *

* For internal use only. May be removed or replaced in the future. */ public void sendClientResized() { Profiler.enter("VUI.sendClientResized"); Element parentElement = getElement().getParentElement(); int viewHeight = parentElement.getClientHeight(); int viewWidth = parentElement.getClientWidth(); ResizeEvent.fire(this, viewWidth, viewHeight); Profiler.leave("VUI.sendClientResized"); } public native static void goTo(String url) /*-{ $wnd.location = url; }-*/; @Override public void onWindowClosing(Window.ClosingEvent event) { // Change focus on this window in order to ensure that all state is // collected from textfields // TODO this is a naive hack, that only works with text fields and may // cause some odd issues. Should be replaced with a decent solution, see // also related BeforeShortcutActionListener interface. Same interface // might be usable here. VTextField.flushChangesFromFocusedTextField(); } private native static void loadAppIdListFromDOM(ArrayList list) /*-{ var j; for(j in $wnd.vaadin.vaadinConfigurations) { // $entry not needed as function is not exported [email protected]::add(Ljava/lang/Object;)(j); } }-*/; @Override public ShortcutActionHandler getShortcutActionHandler() { return actionHandler; } @Override public void focus() { setFocus(true); } /** * Ensures the widget is scrollable eg. after style name changes. *

* For internal use only. May be removed or replaced in the future. */ public void makeScrollable() { if (touchScrollHandler == null) { touchScrollHandler = TouchScrollDelegate.enableTouchScrolling(this); } touchScrollHandler.addElement(getElement()); } @Override public HandlerRegistration addResizeHandler(ResizeHandler resizeHandler) { return addHandler(resizeHandler, ResizeEvent.getType()); } @Override public HandlerRegistration addScrollHandler(ScrollHandler scrollHandler) { return addHandler(scrollHandler, ScrollEvent.getType()); } @Override public int getTabIndex() { return FocusUtil.getTabIndex(this); } @Override public void setAccessKey(char key) { FocusUtil.setAccessKey(this, key); } @Override public void setFocus(boolean focused) { FocusUtil.setFocus(this, focused); } @Override public void setTabIndex(int index) { FocusUtil.setTabIndex(this, index); } /** * Allows to store the currently focused Element. * * Current use case is to store the focus when a Window is opened. Does * currently handle only a single value. Needs to be extended for #12158 * * @param focusedElement */ public void storeFocus() { storedFocus = WidgetUtil.getFocusedElement(); } /** * Restores the previously stored focus Element. * * Current use case is to restore the focus when a Window is closed. Does * currently handle only a single value. Needs to be extended for #12158 * * @return the lastFocusElementBeforeDialogOpened */ public void focusStoredElement() { if (storedFocus != null) { storedFocus.focus(); Scheduler.get().scheduleDeferred(new ScheduledCommand() { @Override public void execute() { storedFocus.focus(); } }); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy