com.data2semantics.yasgui.client.ViewElements.java Source code

Java tutorial

Introduction

Here is the source code for com.data2semantics.yasgui.client.ViewElements.java

Source

package com.data2semantics.yasgui.client;

/*
 * #%L
 * YASGUI
 * %%
 * Copyright (C) 2013 Laurens Rietveld
 * %%
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 * #L%
 */

import java.util.HashMap;
import java.util.Map.Entry;

import com.data2semantics.yasgui.client.configmenu.Compatabilities;
import com.data2semantics.yasgui.client.configmenu.ConfigMenu;
import com.data2semantics.yasgui.client.helpers.GoogleAnalytics;
import com.data2semantics.yasgui.client.helpers.GoogleAnalyticsEvent;
import com.data2semantics.yasgui.client.helpers.Helper;
import com.data2semantics.yasgui.client.helpers.JsMethods;
import com.data2semantics.yasgui.client.helpers.LocalStorageHelper;
import com.data2semantics.yasgui.client.helpers.TooltipProperties;
import com.data2semantics.yasgui.client.settings.ExternalLinks;
import com.data2semantics.yasgui.client.settings.Imgs;
import com.data2semantics.yasgui.client.settings.TooltipText;
import com.data2semantics.yasgui.client.settings.ZIndexes;
import com.data2semantics.yasgui.client.tab.QueryTab;
import com.data2semantics.yasgui.client.tab.optionbar.LinkCreator;
import com.data2semantics.yasgui.shared.exceptions.ElementIdException;
import com.google.gwt.dom.client.Style.Cursor;
import com.google.gwt.dom.client.Style.Position;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.logical.shared.ResizeEvent;
import com.google.gwt.event.logical.shared.ResizeHandler;
import com.google.gwt.http.client.URL;
import com.smartgwt.client.types.Alignment;
import com.smartgwt.client.types.Overflow;
import com.smartgwt.client.widgets.Button;
import com.smartgwt.client.widgets.HTMLFlow;
import com.smartgwt.client.widgets.IButton;
import com.smartgwt.client.widgets.ImgButton;
import com.smartgwt.client.widgets.Label;
import com.smartgwt.client.widgets.Window;
import com.smartgwt.client.widgets.events.ClickEvent;
import com.smartgwt.client.widgets.events.ClickHandler;
import com.smartgwt.client.widgets.events.CloseClickEvent;
import com.smartgwt.client.widgets.events.CloseClickHandler;
import com.smartgwt.client.widgets.layout.HLayout;
import com.smartgwt.client.widgets.layout.LayoutSpacer;
import com.smartgwt.client.widgets.layout.VLayout;
import com.smartgwt.client.widgets.menu.IconMenuButton;

public class ViewElements {
    private static int TOOLTIP_VERSION_MENU_CONFIG = 7;
    private View view;
    private ImgButton queryButton;
    private ImgButton queryLoading;
    private LinkCreator linkCreator;
    public IconMenuButton configButton;
    public static String DEFAULT_LOADING_MESSAGE = "Loading...";
    private static int QUERY_BUTTON_POS_TOP = 5;
    private static int QUERY_BUTTON_POS_RIGHT = 2;
    private static int QUERY_BUTTON_HEIGHT = 48;
    private static int QUERY_BUTTON_WIDTH = 48;
    private static int CONSENT_WINDOW_HEIGHT = 130;
    private static int CONSENT_WINDOW_WIDTH = 750;
    private static int CONSENT_BUTTON_HEIGHT = 40;
    private static int CONSENT_BUTTON_WIDTH = 175;
    private Window consentWindow;
    private Label loading;

    public ViewElements(View view) {
        this.view = view;
        addQueryButton();
        addLogo();
        initLoadingWidget();
        drawConfigMenu();
        checkOpera();
    }

    /**
     * Add Query button. Position absolute, as it hovers slightly over the tabbar. Also adds a loading icon on the same place
     */
    public void addQueryButton() {
        queryLoading = getQueryIcon(Imgs.get(Imgs.LOADING), new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {
                cancelQuery();
            }
        });
        queryLoading.hide();

        if (queryLoading.isDrawn()) {
            queryLoading.redraw();
        } else {
            queryLoading.draw();
        }

        queryButton = getQueryIcon(Imgs.get(Imgs.EXECUTE_QUERY), new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {
                executeQuery();
            }
        });

        if (queryButton.isDrawn()) {
            queryButton.redraw();
        } else {
            queryButton.draw();
        }
    }

    private ImgButton getQueryIcon(String icon, ClickHandler clickHandler) {
        ImgButton imgButton = new ImgButton();
        imgButton.setHeight(QUERY_BUTTON_HEIGHT);
        imgButton.setWidth(QUERY_BUTTON_WIDTH);
        imgButton.setSrc(icon);
        imgButton.setShowRollOver(false);
        imgButton.setShowDown(false);
        imgButton.setZIndex(ZIndexes.TAB_CONTROLS);
        imgButton.setShowOverCanvas(false);
        imgButton.addClickHandler(clickHandler);
        imgButton.getElement().getStyle().setPosition(Position.ABSOLUTE);
        imgButton.getElement().getStyle().setTop(QUERY_BUTTON_POS_TOP, Unit.PX);
        imgButton.getElement().getStyle().setRight(QUERY_BUTTON_POS_RIGHT, Unit.PX);
        imgButton.setCursor(com.smartgwt.client.types.Cursor.POINTER);
        imgButton.getElement().getStyle().setZIndex(ZIndexes.TAB_CONTROLS);

        return imgButton;
    }

    /**
     * Cancel query request, en redraw query icon
     */
    public void cancelQuery() {
        JsMethods.cancelQuery();
        onQueryFinish();
    }

    /**
     * execute query
     */
    public void executeQuery() {
        //clear current result container -before- query, not after
        view.getSelectedTab().getResultContainer().reset();

        view.getHistory().setHistoryCheckpoint();

        if (JsMethods.stringToDownloadSupported()) {
            view.getSelectedTab().getDownloadLink().showDisabledIcon();
        }
        //onblur might not always fire (will have to check that). for now, store query in settings before query execution just to be sure
        view.getCallableJsMethods().storeQueryInCookie();

        String tabId = view.getSelectedTab().getID();
        String endpoint = view.getSelectedTabSettings().getEndpoint();
        String queryString = view.getSelectedTabSettings().getQueryString();

        String mainAcceptHeader;
        if (view.getSelectedTab().getQueryType().equals("CONSTRUCT")) {
            //Change content type automatically for construct queries
            mainAcceptHeader = view.getSelectedTabSettings().getConstructContentType();
        } else {
            mainAcceptHeader = view.getSelectedTabSettings().getSelectContentType();
        }
        String acceptHeaders = Helper.getAcceptHeaders(mainAcceptHeader);

        String argsString = view.getSelectedTabSettings().getQueryArgsAsJsonString();
        String requestMethod = view.getSelectedTabSettings().getRequestMethod();

        JsMethods.query(tabId, queryString, endpoint, acceptHeaders, argsString, requestMethod);
        view.checkAndAddEndpointToDs(endpoint);
        if (view.getSettings().useGoogleAnalytics()) {
            GoogleAnalyticsEvent queryEvent = new GoogleAnalyticsEvent(endpoint, queryString);
            GoogleAnalytics.trackEvents(queryEvent);
        }
    }

    /**
     * initialize loading widget in top right corner
     */
    public void initLoadingWidget() {
        loading = new Label();
        loading.setIcon(Imgs.get(Imgs.LOADING));
        loading.setBackgroundColor("#f0f0f0");
        loading.setBorder("1px solid #C0C3C7");
        loading.getElement().getStyle().setPosition(Position.FIXED);
        loading.getElement().getStyle().setTop(0, Unit.PX);
        loading.getElement().getStyle().setLeft(50, Unit.PCT);
        loading.getElement().getStyle().setMarginLeft(-25, Unit.PX);
        loading.setHeight(24);
        loading.setAutoWidth();
        loading.setOverflow(Overflow.VISIBLE);
        loading.setWrap(false);
        loading.setAlign(Alignment.CENTER);
        loading.adjustForContent(false);
        loading.setZIndex(ZIndexes.LOADING_WIDGET);
        loading.hide();
        loading.redraw();
    }

    public void showPlayButton(String queryValid) {
        if (queryValid.equals("1")) {
            queryButton.setSrc(Imgs.get(Imgs.EXECUTE_QUERY));
        } else {
            queryButton.setSrc(Imgs.get(Imgs.QUERY_ERROR));
        }
    }

    public void onLoadingStart() {
        onLoadingStart(DEFAULT_LOADING_MESSAGE);
    }

    public void onLoadingStart(String message) {
        //Add spaces to end of message, as we have autowidth enabled to this Label
        loading.setContents(message + "  ");
        loading.show();
    }

    public void onLoadingFinish() {
        loading.hide();
    }

    public void onQueryStart() {
        queryButton.hide();
        queryLoading.show();
    }

    public void onQueryFinish() {
        queryButton.show();
        queryLoading.hide();
    }

    public void onQueryError(String tabId, String error) {
        onQueryFinish();
        QueryTab tab = (QueryTab) view.getTabs().getTab(tabId);
        onQueryError(error, tab.getTabSettings().getEndpoint(), tab.getTabSettings().getQueryString(),
                tab.getTabSettings().getQueryArgs());
    }

    /**
     * Show the error window for a trowable. Prints the complete stack trace
     * @param throwable
     */
    public void onError(Throwable e) {
        String errorMsg;

        if (Helper.inDebugMode()) {
            errorMsg = Helper.getStackTraceAsString(e);
            errorMsg += "\nCaused by:\n" + Helper.getCausesStackTraceAsString(e);
        } else {
            errorMsg = e.getMessage();
        }

        onError(errorMsg);
    }

    /**
     * Modal popup window to show on error
     * 
     * @param error
     */
    public void onError(String error) {
        onLoadingFinish();
        Window window = getErrorWindow();
        Label label = new Label(error);
        label.setMargin(4);
        label.setHeight100();
        window.addItem(label);
        window.setIsModal(true);
        window.draw();
    }

    private Window getErrorWindow() {
        final Window window = new Window();
        window.setDismissOnOutsideClick(true);
        window.setIsModal(true);
        window.setZIndex(ZIndexes.MODAL_WINDOWS);
        window.setAutoSize(true);
        window.setMinWidth(400);
        window.setShowMinimizeButton(false);
        window.setAutoCenter(true);
        window.setCanDragResize(true);
        window.addCloseClickHandler(new CloseClickHandler() {
            public void onCloseClick(CloseClickEvent event) {
                window.destroy();
            }
        });
        window.setShowTitle(false);
        return window;
    }

    /**
     * Display error when querying endpoint failed. Has buttons for opening query result page of endpoint itself on new page
     * 
     * @param error Html error msg
     * @param endpoint Used endpoint
     * @param query Used query
     * @param args 
     */
    public void onQueryError(String error, final String endpoint, final String query,
            final HashMap<String, String> args) {
        final Window window = getErrorWindow();
        window.setZIndex(ZIndexes.MODAL_WINDOWS);
        VLayout vLayout = new VLayout();
        vLayout.setWidth100();
        Label label = new Label(error);
        label.setMargin(4);
        label.setHeight100();
        label.setWidth100();
        vLayout.addMember(label);

        HLayout buttons = new HLayout();
        buttons.setAlign(Alignment.CENTER);
        Button executeQuery = new Button("Open endpoint in new window");
        executeQuery.addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {
                String url = endpoint + "?query=" + URL.encodeQueryString(query);
                for (Entry<String, String> entry : args.entrySet()) {
                    url += "&" + entry.getKey() + "=" + URL.encodeQueryString(entry.getValue());
                }
                com.google.gwt.user.client.Window.open(url, "_blank", null);
            }
        });
        executeQuery.setWidth(200);
        Button closeWindow = new Button("Close window");
        closeWindow.addClickHandler(new ClickHandler() {

            @Override
            public void onClick(ClickEvent event) {
                window.destroy();
            }
        });

        buttons.addMember(executeQuery);
        buttons.addMember(closeWindow);
        buttons.setWidth100();
        buttons.setLayoutAlign(Alignment.CENTER);
        vLayout.addMember(buttons);
        window.addItem(vLayout);
        window.setWidth(350);
        window.draw();
    }

    public void addLogo() {
        HTMLFlow html = getYasguiLogo(31, "Show YASGUI page");
        html.getElement().getStyle().setPosition(Position.ABSOLUTE);
        html.getElement().getStyle().setTop(-2, Unit.PX);
        html.getElement().getStyle().setLeft(4, Unit.PX);
        html.getElement().getStyle().setCursor(Cursor.POINTER);
        html.getElement().getStyle().setZIndex(ZIndexes.LOGO);

        if (html.isDrawn()) {
            html.redraw();
        } else {
            html.draw();
        }
    }

    public HTMLFlow getYasguiLogo(int fontSize, String title) {
        HTMLFlow html = new HTMLFlow();
        html.setContents("<span title='" + title + "' style=\"font-family: 'Audiowide'; font-size: " + fontSize
                + "px;cursor:pointer;\" onclick=\"window.open('" + ExternalLinks.YASGUI_HTML
                + "')\">YASGUI</span>");
        html.setWidth(100);
        html.setHeight(30);
        return html;
    }

    public void askCookieConsent() {
        consentWindow = new Window();
        int pageWidth = com.google.gwt.user.client.Window.getClientWidth();
        int pageHeight = com.google.gwt.user.client.Window.getClientHeight();

        consentWindow.setRect((pageWidth / 2) - (CONSENT_WINDOW_WIDTH / 2), pageHeight - CONSENT_WINDOW_HEIGHT,
                CONSENT_WINDOW_WIDTH, CONSENT_WINDOW_HEIGHT);

        VLayout windowCanvas = new VLayout();

        HTMLFlow consentMessage = new HTMLFlow();
        consentMessage.setContents(
                "<p style='text-align:center; margin:0px;'>We track user actions (including used endpoints and queries). This data is solely used for research purposes and to get insight into how users use the site. <strong>We would appreciate your consent!</strong></p>");

        consentMessage.setMargin(8);
        consentMessage.setWidth(CONSENT_WINDOW_WIDTH - 20);
        consentMessage.setAlign(Alignment.CENTER);
        windowCanvas.addMember(consentMessage);

        LayoutSpacer vSpacer = new LayoutSpacer();
        vSpacer.setHeight100();
        windowCanvas.addMember(vSpacer);

        HLayout buttons = new HLayout();
        buttons.setAlign(Alignment.CENTER);
        IButton yesButton = new IButton("Yes, allow");
        yesButton.setWidth(CONSENT_BUTTON_WIDTH);
        yesButton.setShowRollOver(true);
        yesButton.setHeight(CONSENT_BUTTON_HEIGHT);
        yesButton.setIcon(Imgs.get(Imgs.CHECKMARK));
        yesButton.setIconOrientation("left");
        yesButton.addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {
                GoogleAnalyticsEvent consentEvent = new GoogleAnalyticsEvent("consent", "yes");
                GoogleAnalytics.trackEvents(consentEvent);
                consentWindow.destroy();
                view.getSettings().setTrackingConsent(true);
                view.getSettings().setTrackingQueryConsent(true);
                LocalStorageHelper.storeSettingsInCookie(view.getSettings());
            }
        });
        yesButton.setShowDownIcon(false);

        LayoutSpacer spacer1 = new LayoutSpacer();
        spacer1.setWidth(10);

        buttons.setAlign(Alignment.CENTER);
        IButton noQueriesButton = new IButton("Yes, track site usage, but not <br>the queries/endpoints I use");
        noQueriesButton.setWidth(CONSENT_BUTTON_WIDTH);
        noQueriesButton.setHeight(CONSENT_BUTTON_HEIGHT);
        noQueriesButton.setShowRollOver(true);
        noQueriesButton.setIcon(Imgs.get(Imgs.CHECK_CROSS));
        noQueriesButton.setIconOrientation("left");
        noQueriesButton.addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {
                GoogleAnalyticsEvent consentEvent = new GoogleAnalyticsEvent("consent", "yes/no");
                GoogleAnalytics.trackEvents(consentEvent);
                consentWindow.destroy();
                view.getSettings().setTrackingConsent(true);
                view.getSettings().setTrackingQueryConsent(false);
                LocalStorageHelper.storeSettingsInCookie(view.getSettings());
            }
        });
        noQueriesButton.setShowDownIcon(false);

        LayoutSpacer spacer2 = new LayoutSpacer();
        spacer2.setWidth(10);

        IButton noButton = new IButton("No, disable tracking");
        noButton.setShowRollOver(true);
        noButton.setWidth(CONSENT_BUTTON_WIDTH);
        noButton.setHeight(CONSENT_BUTTON_HEIGHT);
        noButton.setIcon(Imgs.get(Imgs.CROSS));
        noButton.setIconOrientation("left");
        noButton.addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {
                GoogleAnalyticsEvent consentEvent = new GoogleAnalyticsEvent("consent", "no");
                GoogleAnalytics.trackEvents(consentEvent);
                consentWindow.destroy();
                view.getSettings().setTrackingConsent(false);
                view.getSettings().setTrackingQueryConsent(false);
                LocalStorageHelper.storeSettingsInCookie(view.getSettings());
            }
        });
        noButton.setShowDownIcon(false);

        LayoutSpacer spacer3 = new LayoutSpacer();
        spacer3.setWidth(10);

        IButton askLater = new IButton("Ask me later");
        askLater.setShowRollOver(true);
        askLater.setWidth(CONSENT_BUTTON_WIDTH - 30);
        askLater.setHeight(CONSENT_BUTTON_HEIGHT);
        askLater.setIconOrientation("left");
        askLater.setShowDownIcon(false);
        askLater.addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {
                consentWindow.destroy();
            }
        });

        buttons.addMembers(yesButton, spacer1, noQueriesButton, spacer2, noButton, spacer3, askLater);
        buttons.setMargin(5);
        windowCanvas.addMember(buttons);
        consentWindow.setTitle("Tracking site usage");

        consentWindow.addItem(windowCanvas);
        consentWindow.draw();
    }

    public void drawOptionsInQueryField() {
        linkCreator = new LinkCreator(view);
        com.google.gwt.user.client.Window.addResizeHandler(new ResizeHandler() {

            @Override
            public void onResize(ResizeEvent event) {
                linkCreator.changeHorizontalOffset();
            }

        });
        linkCreator.changeHorizontalOffset();
        linkCreator.draw();
    }

    /**
     * Draw main YASGUI configuration menu
     */
    public void drawConfigMenu() {
        Compatabilities compatabilities = new Compatabilities(view);
        String icon = "";
        if (!compatabilities.allSupported()
                && LocalStorageHelper.getCompatabilitiesShownVersionNumber() < Compatabilities.VERSION_NUMBER) {
            icon = Imgs.get(Imgs.WARNING);
        } else {
            icon = Imgs.get(Imgs.TOOLS);
        }

        String label = "Configure YASGUI";
        if (!view.getSettings().isDbSet()) {
            //openid not supported. leave label as-is
        } else if (view.getOpenId() != null && view.getOpenId().isLoggedIn()) {
            label += " (" + view.getOpenId().getDisplayName() + ")";
        } else {
            label += " (not logged in)";
        }

        configButton = new IconMenuButton(label);
        configButton.getElement().getStyle().setPosition(Position.ABSOLUTE);
        configButton.getElement().getStyle().setTop(2, Unit.PX);
        configButton.getElement().getStyle().setRight(50, Unit.PX);
        configButton.setIcon(icon);
        configButton.setZIndex(ZIndexes.TAB_CONTROLS);
        configButton.setMenu(new ConfigMenu(view));
        configButton.setCanFocus(false);
        configButton.addClickHandler(new ClickHandler() {

            @Override
            public void onClick(ClickEvent event) {
                configButton.showMenu();
            }

        });
        if (configButton.isDrawn()) {
            configButton.redraw();
        } else {
            configButton.draw();
        }

    }

    /**
     * Redraw configuration menu
     */
    public void redrawConfigMenu() {
        configButton.destroy();
        configButton = null;
        drawConfigMenu();
    }

    private void showConfigMenuTooltip(int fromVersionId) throws ElementIdException {
        if (fromVersionId < TOOLTIP_VERSION_MENU_CONFIG) {
            TooltipProperties tProp = new TooltipProperties();
            tProp.setId(configButton.getDOM().getId());
            tProp.setContent(TooltipText.CONFIG_MENU);
            tProp.setMy(TooltipProperties.POS_RIGHT_TOP);
            tProp.setAt(TooltipProperties.POS_LEFT_TOP);
            Helper.drawTooltip(tProp);
        }
    }

    public void showTooltips(int fromVersionId) {
        showConfigMenuTooltip(fromVersionId);
    }

    private void checkOpera() {
        //the newest opera version (15) uses webkit, works on yasgui, and is identified as 'chrome'.
        //All incompatible opera versions are 0-14
        //therefore, just check whether we have as name 'opera'
        if (JsMethods.getBrowserName().equals("opera")) {
            onError("You are using an opera browser. Users are known to encounter issues in YASGUI using this browser. <br>"
                    + "We recommend you switch to Opera 15+, or to any other modern browser");
        }
    }

}