/* * Copyright 2011 gitblit.com. * * 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.gitblit.client; import java.io.IOException; import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; import com.gitblit.Constants; import com.gitblit.Constants.AccessPermission; import com.gitblit.Constants.AccessRestrictionType; import com.gitblit.Constants.AuthorizationControl; import com.gitblit.Constants.PermissionType; import com.gitblit.Constants.RegistrantType; import com.gitblit.GitBlitException.ForbiddenException; import com.gitblit.GitBlitException.NotAllowedException; import com.gitblit.GitBlitException.UnauthorizedException; import com.gitblit.GitBlitException.UnknownRequestException; import com.gitblit.Keys; import com.gitblit.models.FederationModel; import com.gitblit.models.FeedEntryModel; import com.gitblit.models.FeedModel; import com.gitblit.models.RegistrantAccessPermission; import com.gitblit.models.RepositoryModel; import com.gitblit.models.ServerSettings; import com.gitblit.models.ServerStatus; import com.gitblit.models.TeamModel; import com.gitblit.models.UserModel; import com.gitblit.utils.ArrayUtils; import com.gitblit.utils.RpcUtils; import com.gitblit.utils.StringUtils; import com.gitblit.utils.SyndicationUtils; /** * GitblitClient is a object that retrieves data from a Gitblit server, caches * it for local operations, and allows updating or creating Gitblit objects. * * @author James Moger * */ public class GitblitClient implements Serializable { private static final long serialVersionUID = 1L; private static final Date NEVER = new Date(0); protected final GitblitRegistration reg; public final String url; public final String account; private final char[] password; private volatile int protocolVersion; private volatile boolean allowManagement; private volatile boolean allowAdministration; private volatile ServerSettings settings; private final List allRepositories; private final List allUsers; private final List allTeams; private final List federationRegistrations; private final List availableFeeds; private final List syndicatedEntries; private final Set subscribedRepositories; private ServerStatus status; public GitblitClient(GitblitRegistration reg) { this.reg = reg; this.url = reg.url; this.account = reg.account; this.password = reg.password; this.allUsers = new ArrayList(); this.allTeams = new ArrayList(); this.allRepositories = new ArrayList(); this.federationRegistrations = new ArrayList(); this.availableFeeds = new ArrayList(); this.syndicatedEntries = new ArrayList(); this.subscribedRepositories = new HashSet(); } public void login() throws IOException { protocolVersion = RpcUtils.getProtocolVersion(url, account, password); refreshSettings(); refreshAvailableFeeds(); refreshRepositories(); refreshSubscribedFeeds(0); try { // credentials may not have administrator access // or server may have disabled rpc management refreshUsers(); if (protocolVersion > 1) { refreshTeams(); } allowManagement = true; } catch (UnauthorizedException e) { } catch (ForbiddenException e) { } catch (NotAllowedException e) { } catch (UnknownRequestException e) { } catch (IOException e) { e.printStackTrace(); } try { // credentials may not have administrator access // or server may have disabled rpc administration refreshStatus(); allowAdministration = true; } catch (UnauthorizedException e) { } catch (ForbiddenException e) { } catch (NotAllowedException e) { } catch (UnknownRequestException e) { } catch (IOException e) { e.printStackTrace(); } } public int getProtocolVersion() { return protocolVersion; } public boolean allowManagement() { return allowManagement; } public boolean allowAdministration() { return allowAdministration; } public boolean isOwner(RepositoryModel model) { return model.isOwner(account); } public String getURL(String action, String repository, String objectId) { boolean mounted = settings.get(Keys.web.mountParameters).getBoolean(true); StringBuilder sb = new StringBuilder(); sb.append(url); sb.append('/'); sb.append(action); sb.append('/'); if (mounted) { // mounted url/action/repository/objectId sb.append(StringUtils.encodeURL(repository)); if (!StringUtils.isEmpty(objectId)) { sb.append('/'); sb.append(objectId); } return sb.toString(); } else { // parameterized url/action/&r=repository&h=objectId sb.append("?r="); sb.append(repository); if (!StringUtils.isEmpty(objectId)) { sb.append("&h="); sb.append(objectId); } return sb.toString(); } } public AccessRestrictionType getDefaultAccessRestriction() { String restriction = "PUSH"; if (settings.hasKey(Keys.git.defaultAccessRestriction)) { restriction = settings.get(Keys.git.defaultAccessRestriction).currentValue; } return AccessRestrictionType.fromName(restriction); } public AuthorizationControl getDefaultAuthorizationControl() { String authorization = null; if (settings.hasKey(Keys.git.defaultAuthorizationControl)) { authorization = settings.get(Keys.git.defaultAuthorizationControl).currentValue; } return AuthorizationControl.fromName(authorization); } /** * Returns the list of pre-receive scripts the repository inherited from the * global settings and team affiliations. * * @param repository * if null only the globally specified scripts are returned * @return a list of scripts */ public List getPreReceiveScriptsInherited(RepositoryModel repository) { Set scripts = new LinkedHashSet(); // Globals for (String script : settings.get(Keys.groovy.preReceiveScripts).getStrings()) { if (script.endsWith(".groovy")) { scripts.add(script.substring(0, script.lastIndexOf('.'))); } else { scripts.add(script); } } // Team Scripts if (repository != null) { for (String teamname : getPermittedTeamnames(repository)) { TeamModel team = getTeamModel(teamname); if (!ArrayUtils.isEmpty(team.preReceiveScripts)) { scripts.addAll(team.preReceiveScripts); } } } return new ArrayList(scripts); } /** * Returns the list of all available Groovy pre-receive push hook scripts * that are not already inherited by the repository. Script files must have * .groovy extension * * @param repository * optional parameter * @return list of available hook scripts */ public List getPreReceiveScriptsUnused(RepositoryModel repository) { Set inherited = new TreeSet(getPreReceiveScriptsInherited(repository)); // create list of available scripts by excluding inherited scripts List scripts = new ArrayList(); for (String script : settings.pushScripts) { if (!inherited.contains(script)) { scripts.add(script); } } return scripts; } /** * Returns the list of post-receive scripts the repository inherited from * the global settings and team affiliations. * * @param repository * if null only the globally specified scripts are returned * @return a list of scripts */ public List getPostReceiveScriptsInherited(RepositoryModel repository) { Set scripts = new LinkedHashSet(); // Global Scripts for (String script : settings.get(Keys.groovy.postReceiveScripts).getStrings()) { if (script.endsWith(".groovy")) { scripts.add(script.substring(0, script.lastIndexOf('.'))); } else { scripts.add(script); } } // Team Scripts if (repository != null) { for (String teamname : getPermittedTeamnames(repository)) { TeamModel team = getTeamModel(teamname); if (!ArrayUtils.isEmpty(team.postReceiveScripts)) { scripts.addAll(team.postReceiveScripts); } } } return new ArrayList(scripts); } /** * Returns the list of unused Groovy post-receive push hook scripts that are * not already inherited by the repository. Script files must have .groovy * extension * * @param repository * optional parameter * @return list of available hook scripts */ public List getPostReceiveScriptsUnused(RepositoryModel repository) { Set inherited = new TreeSet(getPostReceiveScriptsInherited(repository)); // create list of available scripts by excluding inherited scripts List scripts = new ArrayList(); if (!ArrayUtils.isEmpty(settings.pushScripts)) { for (String script : settings.pushScripts) { if (!inherited.contains(script)) { scripts.add(script); } } } return scripts; } public ServerSettings getSettings() { return settings; } public ServerStatus getStatus() { return status; } public String getSettingDescription(String key) { return settings.get(key).description; } public List refreshRepositories() throws IOException { Map repositories = RpcUtils .getRepositories(url, account, password); allRepositories.clear(); allRepositories.addAll(repositories.values()); Collections.sort(allRepositories); markSubscribedFeeds(); return allRepositories; } public List refreshUsers() throws IOException { List users = RpcUtils.getUsers(url, account, password); allUsers.clear(); allUsers.addAll(users); Collections.sort(users); return allUsers; } public List refreshTeams() throws IOException { List teams = RpcUtils.getTeams(url, account, password); allTeams.clear(); allTeams.addAll(teams); Collections.sort(teams); return allTeams; } public ServerSettings refreshSettings() throws IOException { settings = RpcUtils.getSettings(url, account, password); return settings; } public ServerStatus refreshStatus() throws IOException { status = RpcUtils.getStatus(url, account, password); return status; } public List getBranches(String repository) { List feeds = getAvailableFeeds(repository); List branches = new ArrayList(); for (FeedModel feed : feeds) { branches.add(feed.branch); } Collections.sort(branches); return branches; } public List getAvailableFeeds() { return availableFeeds; } public List getAvailableFeeds(RepositoryModel repository) { return getAvailableFeeds(repository.name); } public List getAvailableFeeds(String repository) { List repositoryFeeds = new ArrayList(); if (repository == null) { return repositoryFeeds; } for (FeedModel feed : availableFeeds) { if (feed.repository.equalsIgnoreCase(repository)) { repositoryFeeds.add(feed); } } return repositoryFeeds; } public List refreshAvailableFeeds() throws IOException { List feeds = RpcUtils.getBranchFeeds(url, account, password); availableFeeds.clear(); availableFeeds.addAll(feeds); markSubscribedFeeds(); return availableFeeds; } public List refreshSubscribedFeeds(int page) throws IOException { Set allEntries = new HashSet(); if (reg.feeds.size() > 0) { for (FeedModel feed : reg.feeds) { feed.lastRefreshDate = feed.currentRefreshDate; feed.currentRefreshDate = new Date(); List entries = SyndicationUtils.readFeed(url, feed.repository, feed.branch, -1, page, account, password); allEntries.addAll(entries); } } reg.cacheFeeds(); syndicatedEntries.clear(); syndicatedEntries.addAll(allEntries); Collections.sort(syndicatedEntries); return syndicatedEntries; } public void updateSubscribedFeeds(List list) { reg.updateSubscribedFeeds(list); markSubscribedFeeds(); } private void markSubscribedFeeds() { subscribedRepositories.clear(); for (FeedModel feed : availableFeeds) { // mark feed in the available list as subscribed feed.subscribed = reg.feeds.contains(feed); if (feed.subscribed) { subscribedRepositories.add(feed.repository.toLowerCase()); } } } public Date getLastFeedRefresh(String repository, String branch) { FeedModel feed = new FeedModel(); feed.repository = repository; feed.branch = branch; if (reg.feeds.contains(feed)) { int idx = reg.feeds.indexOf(feed); feed = reg.feeds.get(idx); return feed.lastRefreshDate; } return NEVER; } public boolean isSubscribed(RepositoryModel repository) { return subscribedRepositories.contains(repository.name.toLowerCase()); } public List getSyndicatedEntries() { return syndicatedEntries; } public List log(String repository, String branch, int numberOfEntries, int page) throws IOException { return SyndicationUtils.readFeed(url, repository, branch, numberOfEntries, page, account, password); } public List search(String repository, String branch, String fragment, Constants.SearchType type, int numberOfEntries, int page) throws IOException { return SyndicationUtils.readSearchFeed(url, repository, branch, fragment, type, numberOfEntries, page, account, password); } public List refreshFederationRegistrations() throws IOException { List list = RpcUtils.getFederationRegistrations(url, account, password); federationRegistrations.clear(); federationRegistrations.addAll(list); return federationRegistrations; } public List getUsers() { return allUsers; } public UserModel getUser(String username) { for (UserModel user : getUsers()) { if (user.username.equalsIgnoreCase(username)) { return user; } } return null; } public List getUsernames() { List usernames = new ArrayList(); for (UserModel user : this.allUsers) { usernames.add(user.username); } Collections.sort(usernames); return usernames; } public List getPermittedUsernames(RepositoryModel repository) { List usernames = new ArrayList(); for (UserModel user : this.allUsers) { if (user.hasRepositoryPermission(repository.name)) { usernames.add(user.username); } } return usernames; } /** * Returns the effective list of permissions for this user, taking into account * team memberships, ownerships. * * @param user * @return the effective list of permissions for the user */ public List getUserAccessPermissions(UserModel user) { Set set = new LinkedHashSet(); set.addAll(user.getRepositoryPermissions()); // Flag missing repositories for (RegistrantAccessPermission permission : set) { if (permission.mutable && PermissionType.EXPLICIT.equals(permission.permissionType)) { RepositoryModel rm = getRepository(permission.registrant); if (rm == null) { permission.permissionType = PermissionType.MISSING; permission.mutable = false; continue; } } } // TODO reconsider ownership as a user property // manually specify personal repository ownerships for (RepositoryModel rm : allRepositories) { if (rm.isUsersPersonalRepository(user.username) || rm.isOwner(user.username)) { RegistrantAccessPermission rp = new RegistrantAccessPermission(rm.name, AccessPermission.REWIND, PermissionType.OWNER, RegistrantType.REPOSITORY, null, false); // user may be owner of a repository to which they've inherited // a team permission, replace any existing perm with owner perm set.remove(rp); set.add(rp); } } List list = new ArrayList(set); Collections.sort(list); return list; } public List getUserAccessPermissions(RepositoryModel repository) { List list = new ArrayList(); if (AccessRestrictionType.NONE.equals(repository.accessRestriction)) { // no permissions needed, REWIND for everyone! return list; } if (AuthorizationControl.AUTHENTICATED.equals(repository.authorizationControl)) { // no permissions needed, REWIND for authenticated! return list; } // NAMED users and teams for (UserModel user : allUsers) { RegistrantAccessPermission ap = user.getRepositoryPermission(repository); if (ap.permission.exceeds(AccessPermission.NONE)) { list.add(ap); } } return list; } public boolean setUserAccessPermissions(RepositoryModel repository, List permissions) throws IOException { return RpcUtils.setRepositoryMemberPermissions(repository, permissions, url, account, password); } public List getTeams() { return allTeams; } public List getTeamnames() { List teamnames = new ArrayList(); for (TeamModel team : this.allTeams) { teamnames.add(team.name); } Collections.sort(teamnames); return teamnames; } public List getPermittedTeamnames(RepositoryModel repository) { List teamnames = new ArrayList(); for (TeamModel team : this.allTeams) { if (team.hasRepositoryPermission(repository.name)) { teamnames.add(team.name); } } return teamnames; } public List getTeamAccessPermissions(RepositoryModel repository) { List list = new ArrayList(); for (TeamModel team : allTeams) { RegistrantAccessPermission ap = team.getRepositoryPermission(repository); if (ap.permission.exceeds(AccessPermission.NONE)) { list.add(ap); } } Collections.sort(list); return list; } public boolean setTeamAccessPermissions(RepositoryModel repository, List permissions) throws IOException { return RpcUtils.setRepositoryTeamPermissions(repository, permissions, url, account, password); } public TeamModel getTeamModel(String name) { for (TeamModel team : allTeams) { if (team.name.equalsIgnoreCase(name)) { return team; } } return null; } public List getFederationSets() { return settings.get(Keys.federation.sets).getStrings(); } public List getRepositories() { return allRepositories; } public RepositoryModel getRepository(String name) { for (RepositoryModel repository : allRepositories) { if (repository.name.equalsIgnoreCase(name)) { return repository; } } return null; } public boolean createRepository(RepositoryModel repository, List userPermissions) throws IOException { return createRepository(repository, userPermissions, null); } public boolean createRepository(RepositoryModel repository, List userPermissions, List teamPermissions) throws IOException { boolean success = true; success &= RpcUtils.createRepository(repository, url, account, password); if (userPermissions != null && userPermissions.size() > 0) { // if new repository has named members, set them success &= RpcUtils.setRepositoryMemberPermissions(repository, userPermissions, url, account, password); } if (teamPermissions != null && teamPermissions.size() > 0) { // if new repository has named teams, set them success &= RpcUtils.setRepositoryTeamPermissions(repository, teamPermissions, url, account, password); } return success; } public boolean updateRepository(String name, RepositoryModel repository, List userPermissions) throws IOException { return updateRepository(name, repository, userPermissions, null); } public boolean updateRepository(String name, RepositoryModel repository, List userPermissions, List teamPermissions) throws IOException { boolean success = true; success &= RpcUtils.updateRepository(name, repository, url, account, password); // set the repository members if (userPermissions != null) { success &= RpcUtils.setRepositoryMemberPermissions(repository, userPermissions, url, account, password); } if (teamPermissions != null) { success &= RpcUtils.setRepositoryTeamPermissions(repository, teamPermissions, url, account, password); } return success; } public boolean deleteRepository(RepositoryModel repository) throws IOException { return RpcUtils.deleteRepository(repository, url, account, password); } public boolean clearRepositoryCache() throws IOException { return RpcUtils.clearRepositoryCache(url, account, password); } public boolean createUser(UserModel user) throws IOException { return RpcUtils.createUser(user, url, account, password); } public boolean updateUser(String name, UserModel user) throws IOException { return RpcUtils.updateUser(name, user, url, account, password); } public boolean deleteUser(UserModel user) throws IOException { return RpcUtils.deleteUser(user, url, account, password); } public boolean createTeam(TeamModel team) throws IOException { return RpcUtils.createTeam(team, url, account, password); } public boolean updateTeam(String name, TeamModel team) throws IOException { return RpcUtils.updateTeam(name, team, url, account, password); } public boolean deleteTeam(TeamModel team) throws IOException { return RpcUtils.deleteTeam(team, url, account, password); } public boolean updateSettings(Map newSettings) throws IOException { return RpcUtils.updateSettings(newSettings, url, account, password); } } f='#n416'>416 417 418 419 420 421 422
/*
 * Copyright 2000-2021 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.List;
import java.util.logging.Logger;

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.shared.HandlerRegistration;
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.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.ui.ShortcutActionHandler.ShortcutActionHandlerOwner;
import com.vaadin.client.ui.TouchScrollDelegate.TouchScrollHandler;
import com.vaadin.client.ui.ui.UIConnector;
import com.vaadin.shared.ApplicationConstants;

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

    private static final 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 resizeLazy = false;

    private TouchScrollHandler touchScrollHandler;

    private VLazyExecutor delayedResizeExecutor = new VLazyExecutor(200,
            () -> 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);
        }
    }

    /**
     * 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);
            getLogger().info("New window width: " + windowWidth);
        }
        if (windowHeight != newWindowHeight) {
            windowHeight = newWindowHeight;
            changed = true;
            connector.getLayoutManager().reportOuterHeight(connector,
                    newWindowHeight);
            getLogger().info("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;
                getLogger().info("New parent width: " + parentWidth);
            }
            if (parentHeight != newParentHeight) {
                parentHeight = newParentHeight;
                changed = true;
                getLogger().info("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.)
             */
            getLogger().info(
                    "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();
    }

    /*
     * (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() {
        /*
         * We may 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;

        if (lazy) {
            delayedResizeExecutor.trigger();
        } else {
            performSizeCheck();
        }
    }

    /**
     * Send new dimensions to the server.
     * <p>
     * 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 static native void goTo(String url)
    /*-{
       $wnd.location = url;
     }-*/;

    @Override
    public void onWindowClosing(Window.ClosingEvent event) {
        // Ensure that any change in the currently focused component is noted
        // before refreshing. Ensures that e.g. text in the focused text field
        // does not disappear on refresh (when preserve on refresh is enabled)
        connection.flushActiveConnector();
    }

    private static native void loadAppIdListFromDOM(List<String> list)
    /*-{
         for (var j in $wnd.vaadin.vaadinConfigurations) {
            // $entry not needed as function is not exported
            list.@java.util.Collection::add(Ljava/lang/Object;)(j);
         }
     }-*/;

    @Override
    public ShortcutActionHandler getShortcutActionHandler() {
        return actionHandler;
    }

    @Override
    public void focus() {
        setFocus(true);
    }

    /**
     * Ensures the widget is scrollable e.g. after style name changes.
     * <p>
     * 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
     */
    public void focusStoredElement() {
        if (storedFocus != null) {
            storedFocus.focus();
        }
    }

    private static Logger getLogger() {
        return Logger.getLogger(VUI.class.getName());
    }
}