fi.jyu.student.jatahama.onlineinquirytool.client.OnlineInquiryTool.java Source code

Java tutorial

Introduction

Here is the source code for fi.jyu.student.jatahama.onlineinquirytool.client.OnlineInquiryTool.java

Source

/**
 * Copyright (c) 2014, Jari Hmlinen, Carita Kiili and Julie Coiro
 * All rights reserved.
 * 
 * See LICENSE for full license text.
 * 
 * @author Jari Hmlinen
 */
package fi.jyu.student.jatahama.onlineinquirytool.client;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyDownEvent;
import com.google.gwt.event.dom.client.KeyDownHandler;
import com.google.gwt.event.dom.client.MouseOutEvent;
import com.google.gwt.event.dom.client.MouseOutHandler;
import com.google.gwt.event.dom.client.MouseOverEvent;
import com.google.gwt.event.dom.client.MouseOverHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.http.client.Request;
import com.google.gwt.http.client.RequestBuilder;
import com.google.gwt.http.client.RequestCallback;
import com.google.gwt.http.client.RequestException;
import com.google.gwt.http.client.Response;
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.Anchor;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DeckPanel;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.FormPanel;
import com.google.gwt.user.client.ui.FormPanel.SubmitCompleteEvent;
import com.google.gwt.user.client.ui.FormPanel.SubmitCompleteHandler;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Hyperlink;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.ScrollPanel;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.TextArea;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;

import fi.jyu.student.jatahama.onlineinquirytool.client.i18n.OnlineInquiryToolConstants;
import fi.jyu.student.jatahama.onlineinquirytool.client.i18n.OnlineInquiryToolMessages;
import fi.jyu.student.jatahama.onlineinquirytool.shared.ClaimAnalysis;
import fi.jyu.student.jatahama.onlineinquirytool.shared.Utils;

/**
 * Entry point classes define <code>onModuleLoad()</code>.
 */
public class OnlineInquiryTool implements EntryPoint, ValueChangeHandler<String>, ClickHandler, ChangeHandler,
        ClaimIOHandler, MouseOutHandler, MouseOverHandler, SubmitCompleteHandler, KeyDownHandler, RequestCallback {

    /** 
     * Dirty popup possible sources
     */
    private enum DirtyPopupSource {
        CREATE, OPEN
    };

    /**
     * Last dirty popup source
     */
    private DirtyPopupSource dirtySource = null;

    /** 
     * Do we need to build ui? Used in servlet check reply handling to figure out if we need UI or not.
     */
    private boolean needUI = true;

    /**
     * Try to reach servlet this many times if not getting (right) reply.
     */
    private int servletRetriesLeft = 3;

    /**
     * Servlet check retry interval in seconds.
     */
    private static final int servletRetryInterval = 15;

    /**
     * Servlet retry timer.
     */
    private Timer servletRetryTimer = new Timer() {
        @Override
        public void run() {
            try {
                checkServlet();
            } catch (RequestException e) {
                // Just run onError with nulls
                onError(null, null);
            }
        }
    };

    /**
     * For i18n 
     */
    public static final OnlineInquiryToolConstants constants = GWT.create(OnlineInquiryToolConstants.class);
    public static final OnlineInquiryToolMessages messages = GWT.create(OnlineInquiryToolMessages.class);

    /**
     * Servlet URL
     */
    public static final String loadsaveServletUrl = GWT.getModuleBaseURL() + "loadsave";

    /**
     * Session ID
     */
    public static String sessionID = null;

    /**
     * Resources
     */
    public static final Resources resources = GWT.create(Resources.class);

    /**
     * App loading popup
     */
    final PopupPanel appLoadingPopup = new PopupPanel(false, true);

    /**
     * Main deck for different views
     */
    private final DeckPanel mainDeck = new DeckPanel();

    /**
     * Claim analysis panel for analyzing.
     */
    private final ClaimAnalysisPanel claimAnalysisPanel = new ClaimAnalysisPanel(this);

    /**
     * Popup for help
     */
    private final PopupPanel helpPanel = new PopupPanel(false, false);

    /** 
     * Create Anchor
     */
    private Anchor createAnchor = new Anchor(OnlineInquiryTool.constants.tcBtnCreateChart());

    /** 
     * Open Anchor
     */
    private Anchor openAnchor = new Anchor(OnlineInquiryTool.constants.tcBtnOpenChart());

    /** 
     * Open Button (will be invisible over the Open Anchor)
     */
    private FileButton openButton = new FileButton();

    /**
     * Timer to run open "for real". Maybe ugliest hack ever, but IE doesn't seem to
     * show loading popup otherwise (when loadingPopup.center() and
     * ClaimIO.loadClaim("file-input", this) are called subsequently).
     */
    private Timer openImplRunTimer = new Timer() {
        @Override
        public void run() {
            openImpl();
        }
    };

    /** 
     * Save Anchor
     */
    private Anchor saveAnchor = new Anchor(OnlineInquiryTool.constants.tcBtnSaveChart());

    /**
     * Popup for "Loading..."
     */
    private final PopupPanel loadingPopup = new PopupPanel(false, true);

    /**
     * Popup for "Failed to load"
     */
    private final PopupPanel loadingFailedPopup = new PopupPanel(false, true);

    /**
     * Label to notify about failed loading.
     */
    private final Label loadingFailLabel = new Label();

    /**
     * Copyright notice label
     */
    private final Anchor copyAnchor = new Anchor();

    /**
     * Version label
     */
    private final Anchor versionAnchor = new Anchor();

    /**
     * Popup for copyright and app info
     */
    private final PopupPanel infoPopup = new PopupPanel(true, false);

    // Save and load form components
    final FormPanel saveForm = new FormPanel();
    final TextArea chartData = new TextArea();
    final TextBox chartName = new TextBox();
    final FormPanel loadForm = new FormPanel();

    /**
     * Popup for Save as
     */
    private final PopupPanel saveAsPopup = new PopupPanel(false, false);

    /**
     * Popup for dirty prompt
     */
    private final PopupPanel dirtyPopup = new PopupPanel(false, false);

    /**
     * Is dirty popup pending under save?
     */
    private boolean dirtyPending = false;

    /**
     * Save name text box
     */
    private final TextBox saveName = new TextBox();

    /**
     * Save ok button
     */
    private final Button btnSaveOk = new Button(constants.tcBtnSave());

    /**
     * Save cancel button
     */
    private final Button btnSaveCancel = new Button(constants.tcBtnCancel());

    /**
     * Dirty yes button
     */
    private final Button btnDirtyYes = new Button(constants.tcBtnYes());

    /**
     * Dirty no button
     */
    private final Button btnDirtyNo = new Button(constants.tcBtnNo());

    /**
     * Dirty cancel button
     */
    private final Button btnDirtyCancel = new Button(constants.tcBtnCancel());

    /**
     * Is file saver supported
     */
    final boolean saverSupported = ClaimIO.isFileSaverSupportedImpl();

    /**
     * Is file reader supported
     */
    final boolean readerSupported = ClaimIO.isFileReaderSupportedImpl();

    /**
     * Is remove server available
     */
    boolean remoteServerAvailable = false;

    /**
     * Info text on (c) / version click
     */
    final HTML infoText = new HTML();

    /**
     * This is the entry point method.
     */
    public void onModuleLoad() {
        // Quick loading popup
        final Label appLoadingLabel = new Label(OnlineInquiryTool.constants.tcLblAppLoading());
        appLoadingLabel.setStyleName("loading-text", true);
        appLoadingPopup.setStyleName("popup-z", true);
        appLoadingPopup.setGlassEnabled(true);
        appLoadingPopup.setWidget(appLoadingLabel);
        appLoadingPopup.center();

        // Check servlet existence and then create UI (either exception or in handlers)
        try {
            checkServlet();
        } catch (RequestException e) {
            // Not much to do, just createUI
            createUI();
        }
    }

    /**
     * Check servlet existence
     */
    private void checkServlet() throws RequestException {
        RequestBuilder rb = new RequestBuilder(RequestBuilder.GET, loadsaveServletUrl);
        rb.setTimeoutMillis(10000);
        rb.setRequestData("Hello!");
        rb.setCallback(this);
        rb.send();
    }

    /**
     * UI Creator. Called after we have checked servlet existence
     */
    public void createUI() {
        // Won't need this anymore because will build it right here!
        needUI = false;

        // Set window title
        Window.setTitle(constants.tcLblToolTitle());

        // Create anchor
        createAnchor.addClickHandler(this);
        createAnchor.setStyleName("nav");

        // Open anchor
        // NOTE: Because we use input (type=file), we wrap anchor inside a div which has invisible input over our anchor.
        openAnchor.setStyleName("nav");

        // Open button
        openButton.addChangeHandler(this);
        openButton.getElement().setId("file-input");
        openButton.setName("file-input");
        openButton.setStyleName("file-open");
        openButton.addMouseOutHandler(this);
        openButton.addMouseOverHandler(this);
        openButton.setTitle("");

        // Wrapper for open stuff
        final FlowPanel openWrap = new FlowPanel();
        openWrap.setStyleName("file-wrap");
        openWrap.add(openAnchor);
        loadForm.setAction(loadsaveServletUrl);
        loadForm.setEncoding(FormPanel.ENCODING_MULTIPART);
        loadForm.setMethod(FormPanel.METHOD_POST);
        loadForm.add(openButton);
        loadForm.addSubmitCompleteHandler(this);
        openWrap.add(loadForm);

        // Save anchor
        saveAnchor.addClickHandler(this);
        saveAnchor.setStyleName("nav");

        // Save as popup
        saveAsPopup.setStylePrimaryName("save-popup");
        final VerticalPanel sv = new VerticalPanel();
        sv.setStylePrimaryName("save-wrap");
        final Label slbl = new Label(constants.tcLblSaveAs());
        slbl.setStyleName("save-label");
        sv.add(slbl);
        final HorizontalPanel sh1 = new HorizontalPanel();
        sh1.setStylePrimaryName("save-name-wrap");
        saveName.setStylePrimaryName("save-name");
        sh1.add(saveName);
        saveName.setText(constants.tcTxtDefaultChartFilename());
        saveName.addKeyDownHandler(this);
        final Label ssuf = new Label(".xhtml");
        ssuf.setStylePrimaryName("save-suffix");
        sh1.add(ssuf);
        sv.add(sh1);
        final HorizontalPanel sh2 = new HorizontalPanel();
        sh2.setStylePrimaryName("save-button-wrap");
        //      btnSaveOk.setStylePrimaryName("save-button");
        //      btnSaveCancel.setStylePrimaryName("save-button");
        sh2.add(btnSaveCancel);
        sh2.add(btnSaveOk);
        sv.add(sh2);
        btnSaveCancel.addClickHandler(this);
        btnSaveOk.addClickHandler(this);
        saveAsPopup.setWidget(sv);
        saveAsPopup.setGlassEnabled(true);
        saveAsPopup.setGlassStyleName("save-glass");

        // (hidden) Form panel for save
        saveForm.setAction(loadsaveServletUrl);
        saveForm.setEncoding(FormPanel.ENCODING_MULTIPART);
        saveForm.setMethod(FormPanel.METHOD_POST);
        saveForm.setStylePrimaryName("no-display");
        chartData.setStylePrimaryName("no-display");
        chartData.setName("chartDataXML");
        chartName.setStylePrimaryName("no-display");
        chartName.setName("chartFilename");
        final FlowPanel sp = new FlowPanel();
        // Ordering is important because server expects name first!
        // Otherwise default filename would be used on server side.
        sp.add(chartName);
        sp.add(chartData);
        saveForm.add(sp);

        // loadingPopup
        final Label loadingLabel = new Label(OnlineInquiryTool.constants.tcLblLoading());
        loadingLabel.setStyleName("loading-text", true);
        loadingPopup.setStyleName("popup-z", true);
        loadingPopup.setGlassEnabled(true);
        loadingPopup.setWidget(loadingLabel);

        // loadingFailed
        final VerticalPanel loadingFailContent = new VerticalPanel();
        loadingFailContent.setStyleName("black-border");
        loadingFailLabel.setStyleName("fail-label");

        loadingFailedPopup.setStyleName("popup-z", true);
        loadingFailedPopup.setGlassEnabled(true);
        final ClickHandler failCloseHandler = new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {
                loadingFailedPopup.hide();
            }
        };
        final Button failPopClose = new Button(constants.tcBtnOk(), failCloseHandler);
        final SimplePanel failCloseHolder = new SimplePanel();
        failCloseHolder.setStyleName("popup-button-holder");
        failCloseHolder.add(failPopClose);
        loadingFailContent.add(loadingFailLabel);
        loadingFailContent.add(failCloseHolder);
        loadingFailedPopup.add(loadingFailContent);

        // Dirty popup
        dirtyPopup.setStylePrimaryName("dirty-popup");
        final VerticalPanel sv2 = new VerticalPanel();
        sv2.setStylePrimaryName("dirty-wrap");
        final Label dlbl = new Label(constants.tcLblNotSaved());
        dlbl.setStyleName("dirty-header");
        sv2.add(dlbl);
        final Label dlbl2 = new Label(constants.tcLblPromptSave());
        dlbl2.setStylePrimaryName("dirty-label");
        sv2.add(dlbl2);
        final HorizontalPanel sh3 = new HorizontalPanel();
        sh3.setStylePrimaryName("dirty-button-wrap");
        sh3.add(btnDirtyCancel);
        sh3.add(btnDirtyNo);
        sh3.add(btnDirtyYes);
        sv2.add(sh3);
        btnDirtyCancel.addClickHandler(this);
        btnDirtyNo.addClickHandler(this);
        btnDirtyYes.addClickHandler(this);
        dirtyPopup.setWidget(sv2);
        dirtyPopup.setGlassEnabled(true);
        dirtyPopup.setGlassStyleName("dirty-glass");

        // Navigation
        Hyperlink instructionsLink = new Hyperlink(constants.tcBtnInstructions(), "instructions");
        instructionsLink.setStyleName("nav");
        final Label spacer1 = new Label(); // Spacer for second column
        spacer1.setStyleName("nav-spacer");
        final Label spacer2 = new Label(); // Spacer for second column
        spacer2.setStyleName("nav-spacer");
        final FlowPanel navWrap1 = new FlowPanel();
        navWrap1.setStyleName("clear-wrap nav-wrap rmargin10");
        navWrap1.add(createAnchor);
        navWrap1.add(openWrap);
        navWrap1.add(saveAnchor);
        final FlowPanel navWrap2 = new FlowPanel();
        navWrap2.setStyleName("clear-wrap nav-wrap");
        navWrap2.add(spacer1);
        navWrap2.add(spacer2);
        navWrap2.add(instructionsLink);

        final FlowPanel navPanel = new FlowPanel();
        navPanel.setStyleName("blue-border page-nav");
        navPanel.add(navWrap1);
        navPanel.add(navWrap2);
        RootPanel.get("content").add(navPanel);

        // Site title
        Label siteTitle = new Label(constants.tcLblToolTitle());
        siteTitle.setStyleName("site-title");
        RootPanel.get("content").add(siteTitle);

        // Check load save states
        checkLoadSaveState();

        // Build main deck
        final FlowPanel contentWrap = new FlowPanel();
        contentWrap.setStyleName("blue-border page-main-content");
        mainDeck.setStyleName("clear-wrap");
        contentWrap.add(mainDeck);
        RootPanel.get("content").add(contentWrap);
        mainDeck.add(claimAnalysisPanel);
        mainDeck.showWidget(0);

        // Help popup
        final HTML helpText = new HTML(constants.tcTxtInstructionsText());
        final ScrollPanel textWrapper = new ScrollPanel();
        textWrapper.setStyleName("help-text-wrap", true);
        textWrapper.add(helpText);
        final VerticalPanel popContent = new VerticalPanel();
        final ClickHandler closeHandler = new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {
                helpPanel.hide();
            }
        };
        final Button popClose = new Button(constants.tcBtnClose(), closeHandler);
        final SimplePanel holder = new SimplePanel();
        holder.setStyleName("popup-button-holder");
        holder.add(popClose);
        popContent.setStyleName("help-popup-wrap");
        popContent.add(textWrapper);
        popContent.add(holder);
        helpPanel.setGlassEnabled(true);
        helpPanel.setWidget(popContent);
        helpPanel.setStyleName("popup-z", true);
        //       helpPanel.setWidth("500px");

        // Add history listener and set initial state
        History.addValueChangeHandler(this);
        String initToken = History.getToken();
        if (initToken.length() == 0) {
            History.newItem("welcome");
        } else {
            // Fire initial history state.
            History.fireCurrentHistoryState();
        }

        claimAnalysisPanel.setClaim(null);
        claimAnalysisPanel.updateLayout();
        claimAnalysisPanel.updateClaimTitleAndConclusionWidgets();

        // App info (hidden)
        RootPanel.get("appinfo").add(
                new HTML("Version: " + AppInfo.getBuildVersion() + (AppInfo.isBuildClean() ? "-clean" : "-dirty")
                        + "<br />" + "Date: " + AppInfo.getBuildDate() + "<br />" + "Branch: "
                        + AppInfo.getBuildBranch() + "<br />" + "Commit: " + AppInfo.getBuildCommit()));

        // Copyright stuff + version
        VerticalPanel copyWrap = new VerticalPanel();
        copyWrap.setStyleName("copyright-wrap");
        copyAnchor.setStyleName("copyright-text");
        copyAnchor.setText(constants.tcLblCopyright());
        copyAnchor.addClickHandler(this);
        copyWrap.add(copyAnchor);
        versionAnchor.setStyleName("copyright-text");
        versionAnchor.setText(constants.tcLblVersion() + " " + AppInfo.getBuildVersion());
        versionAnchor.addClickHandler(this);
        copyWrap.add(versionAnchor);
        contentWrap.add(copyWrap);

        // Copyright and appinfo
        final SimplePanel infoWrapper = new SimplePanel();
        infoWrapper.setStyleName("help-text-wrap", true);
        infoWrapper.add(infoText);
        final VerticalPanel infoPopContent = new VerticalPanel();
        final ClickHandler infoCloseHandler = new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {
                infoPopup.hide();
            }
        };
        final Button infoPopClose = new Button(constants.tcBtnClose(), infoCloseHandler);
        final SimplePanel infoBtnHolder = new SimplePanel();
        infoBtnHolder.setStyleName("popup-button-holder");
        infoBtnHolder.add(infoPopClose);
        infoPopContent.setStyleName("info-popup-wrap");
        infoPopContent.add(infoWrapper);
        infoPopContent.add(infoBtnHolder);
        infoPopup.setGlassEnabled(true);
        infoPopup.setWidget(infoPopContent);
        infoPopup.setStyleName("popup-z", true);

        // Confirm page leave if not saved
        Window.addWindowClosingHandler(new Window.ClosingHandler() {
            public void onWindowClosing(Window.ClosingEvent closingEvent) {
                ClaimAnalysis claim = claimAnalysisPanel.getClaim();
                if (claim != null) {
                    if (claim.isDirty()) {
                        closingEvent.setMessage(constants.tcLblNotSaved());
                    }
                }
            }
        });

        // Save form must be on doc or it will not work
        RootPanel.get().add(saveForm);
    }

    private void checkLoadSaveState() {
        // Check if FileSaver, FileReader and remove server are supported/available and disable open/save buttons accordingly.
        if (!ClaimIO.isFileSaverSupportedImpl() && !remoteServerAvailable) {
            saveAnchor.setEnabled(false);
            saveAnchor.setStyleName("file-disabled", true);
            saveAnchor.setTitle(constants.tcTipSaveNotSupported());
        } else {
            saveAnchor.setEnabled(true);
            saveAnchor.setStyleName("file-disabled", false);
            saveAnchor.setTitle("");
        }
        if (!ClaimIO.isFileReaderSupportedImpl() && !remoteServerAvailable) {
            openAnchor.setEnabled(false);
            openAnchor.setStyleName("file-disabled", true);
            openButton.setEnabled(false);
            openButton.setTitle(constants.tcTipOpenNotSupported());
            openButton.setStyleName("file-open-disabled", true);
        } else {
            openAnchor.setEnabled(true);
            openAnchor.setStyleName("file-disabled", false);
            openButton.setEnabled(true);
            openButton.setTitle("");
            openButton.setStyleName("file-open-disabled", false);
        }

        // Update infotext
        infoText.setHTML(
                "<div class=\"app-info-header\">" + constants.tcLblToolTitle() + "<div class=\"license-text\">"
                        + constants.tcTextLicense() + "</div>" + "</div>" + "<div class=\"app-info-text\">"
                        + "Version: " + AppInfo.getBuildVersion() + (AppInfo.isBuildClean() ? "-clean" : "-dirty")
                        + "<br />" + "Remote load/save: " + (remoteServerAvailable ? "available" : "unavailable")
                        + "<br />" + "Local load: " + (readerSupported ? "available" : "unavailable") + "<br />"
                        + "Local save: " + (saverSupported ? "available" : "unavailable") + "<br />"
                        + "User-agent: " + Window.Navigator.getUserAgent() + "<br />" + "</div>");
    }

    @Override
    public void onValueChange(ValueChangeEvent<String> event) {
        if ("welcome".equals(event.getValue())) {
            claimAnalysisPanel.setClaim(null);
            claimAnalysisPanel.updateLayout();
            claimAnalysisPanel.updateClaimTitleAndConclusionWidgets();
        } else if ("instructions".equals(event.getValue())) {
            helpPanel.center();
            // Just to get create link working when clicking multiple times in a row
            // TODO: Check if there's a better way to do this!
            History.newItem("edit");
        }
    }

    @Override
    public void onChange(ChangeEvent event) {
        if (event.getSource() == openButton) {
            // TODO Might be smarter do intercept click and simulate it after dialog. Not sure if possible with fileupload
            // TODO See also: http://code.google.com/p/google-web-toolkit/issues/detail?id=2262
            // TODO           may have workaround
            ClaimAnalysis c = claimAnalysisPanel.getClaim();
            dirtySource = DirtyPopupSource.OPEN;
            if (c != null && c.isDirty()) {
                dirtyPopup.showRelativeTo(createAnchor);
            } else {
                doLoad();
            }
        }
    }

    private void doLoad() {
        loadingPopup.center();
        openImplRunTimer.schedule(0);
    }

    private void openImpl() {
        if (readerSupported) {
            ClaimIO.loadClaim("file-input", this);
        } else {
            loadForm.submit();
        }
    }

    @Override
    public void loadStringFinished(String result, String filename) {
        ClaimAnalysis claim = new ClaimAnalysis(); //claimAnalysisPanel.getClaim();
        boolean ok = claim.fromString(result);
        loadingPopup.hide();
        openAnchor.setStyleName("nav");
        if (ok) {
            claimAnalysisPanel.setClaim(claim);
            try {
                saveName.setText(filename.substring(0, filename.lastIndexOf(".")));
            } catch (StringIndexOutOfBoundsException e) {
                saveName.setText(constants.tcTxtDefaultChartFilename());
            }
        } else {
            loadStringError(filename);
        }
        doDirtyCleanUp();
        claimAnalysisPanel.updateLayout();
        claimAnalysisPanel.updateClaimTitleAndConclusionWidgets();
    }

    @Override
    public void loadStringAborted(String filename) {
        openAnchor.setStyleName("nav");
        loadingFailLabel.setText(OnlineInquiryTool.messages.tmLblFileOpenAborted(filename));
        loadingPopup.hide();
        loadingFailedPopup.center();
        doDirtyCleanUp();
        claimAnalysisPanel.updateLayout();
        claimAnalysisPanel.updateClaimTitleAndConclusionWidgets();
    }

    @Override
    public void loadStringError(String filename) {
        openAnchor.setStyleName("nav");
        loadingFailLabel.setText(OnlineInquiryTool.messages.tmLblErrorWhenOpeningFile(filename));
        loadingPopup.hide();
        loadingFailedPopup.center();
        doDirtyCleanUp();
        claimAnalysisPanel.updateLayout();
        claimAnalysisPanel.updateClaimTitleAndConclusionWidgets();
    }

    @Override
    public void onClick(ClickEvent event) {
        Object src = event.getSource();
        if (src instanceof Anchor) {
            // Prevent default because IE will fire onWindowClosing on every anchor click
            // (and leave page confirm pops up if chart is dirty)!
            event.preventDefault();

            Anchor a = (Anchor) src;
            if (a == saveAnchor) {
                showSaveAs();
            } else if (a == copyAnchor || a == versionAnchor) {
                infoPopup.center();
            } else if (a == createAnchor) {
                ClaimAnalysis c = claimAnalysisPanel.getClaim();
                dirtySource = DirtyPopupSource.CREATE;
                if (c != null && c.isDirty()) {
                    dirtyPopup.showRelativeTo(createAnchor);
                } else {
                    doCreateNew();
                }
            }
        } else if (src instanceof Button) {
            if (src == btnSaveCancel) {
                doSaveCancel();
            } else if (src == btnSaveOk) {
                doSaveOk();
            } else if (src == btnDirtyCancel) {
                dirtyPopup.hide();
                doDirtyCleanUp();
            } else if (src == btnDirtyNo) {
                dirtyPopup.hide();
                doDirtyAction();
            } else if (src == btnDirtyYes) {
                dirtyPending = true;
                showSaveAs();
            }
        }

    }

    private void doDirtyCleanUp() {
        switch (dirtySource) {
        case CREATE:
            break;
        case OPEN:
            loadForm.reset();
            break;
        default:
            break;
        }
    }

    private void doDirtyAction() {
        switch (dirtySource) {
        case CREATE:
            doCreateNew();
            break;
        case OPEN:
            doLoad();
            break;
        default:
            break;
        }
    }

    private void showSaveAs() {
        saveAsPopup.showRelativeTo(saveAnchor);
        try {
            // In try-catch because scared of exception :-)
            // Got one with IE in another project and didn't know why
            saveName.setCursorPos(saveName.getText().length());
        } catch (Exception e) {
        }
        saveName.setFocus(true);
    }

    private void doCreateNew() {
        claimAnalysisPanel.setClaim(null);
        claimAnalysisPanel.updateLayout();
        claimAnalysisPanel.updateClaimTitleAndConclusionWidgets();
        saveName.setText(constants.tcTxtDefaultChartFilename());
    }

    private void doSaveCancel() {
        dirtyPending = false;
        saveAsPopup.hide();
    }

    private void doSaveOk() {
        saveAsPopup.hide();
        ClaimAnalysis claim = claimAnalysisPanel.getClaim();
        String title = saveName.getText();

        if (saverSupported) {
            // Use local JS saver
            ClaimIO.saveClaim(claim, title + ".xhtml");
            //ClaimIO.saveClaimToJson(claim,  title+".json");
        } else {
            // User remote server save
            String chartStr = claim.toXHTMLString();
            chartData.setValue(chartStr);
            chartName.setValue(title + ".xhtml");
            saveForm.submit();
        }
        claim.setDirty(false);
        if (dirtyPending) {
            dirtyPending = false;
            dirtyPopup.hide();
            doDirtyAction();
        }
    }

    @Override
    public void onMouseOver(MouseOverEvent event) {
        if (event.getSource() == openButton) {
            openAnchor.setStyleName("nav-manual-hover");
        }
    }

    @Override
    public void onMouseOut(MouseOutEvent event) {
        if (event.getSource() == openButton) {
            openAnchor.setStyleName("nav");
        }
    }

    @Override
    public void onSubmitComplete(SubmitCompleteEvent event) {
        String filename = openButton.getFilename();
        int fs = Math.max(filename.lastIndexOf("/") + 1, 0);
        int bs = Math.max(filename.lastIndexOf("\\") + 1, 0);
        try {
            filename = filename.substring(fs > bs ? fs : bs);
        } catch (IndexOutOfBoundsException e) {
            filename = constants.tcTxtDefaultChartFilename();
        }
        String result = event.getResults();
        ClaimAnalysis claim = new ClaimAnalysis(); //claimAnalysisPanel.getClaim();
        boolean ok = claim.fromString(result);
        loadingPopup.hide();
        openAnchor.setStyleName("nav");
        if (ok) {
            claimAnalysisPanel.setClaim(claim);
            try {
                saveName.setText(filename.substring(0, filename.lastIndexOf(".")));
            } catch (StringIndexOutOfBoundsException e) {
                saveName.setText(constants.tcTxtDefaultChartFilename());
            }
        } else {
            loadStringError(filename);
        }
        doDirtyCleanUp();
        claimAnalysisPanel.updateLayout();
        claimAnalysisPanel.updateClaimTitleAndConclusionWidgets();
    }

    @Override
    public void onKeyDown(KeyDownEvent event) {
        int keyCode = event.getNativeEvent().getKeyCode();
        switch (keyCode) {
        case KeyCodes.KEY_ENTER:
            doSaveOk();
            break;
        case KeyCodes.KEY_ESCAPE:
            doSaveCancel();
            break;
        }
    }

    @Override
    public void onResponseReceived(Request request, Response response) {
        String serverHello = null;
        try {
            // Let's check both header and content in case some proxy filters custom headers or something
            serverHello = response.getHeader(Utils.httpHeaderNameHello);
            boolean helloInText = response.getText().contains(Utils.httpHeaderNameHello);
            if ((serverHello != null && serverHello.length() > 0) || helloInText) {
                remoteServerAvailable = true;
            } else {
                remoteServerAvailable = false;
                servletRetry();
            }
        } catch (Exception e) {
            remoteServerAvailable = false;
            servletRetry();
        }
        // Do we want UI or just check load/save link states
        if (needUI) {
            appLoadingPopup.hide();
            createUI();
        } else {
            checkLoadSaveState();
        }
    }

    @Override
    public void onError(Request request, Throwable exception) {
        remoteServerAvailable = false;
        servletRetry();

        // Do we want UI or just check load/save link states
        if (needUI) {
            appLoadingPopup.hide();
            createUI();
        } else {
            checkLoadSaveState();
        }
    }

    private void servletRetry() {
        if (servletRetriesLeft > 0) {
            servletRetriesLeft--;
            servletRetryTimer.schedule(servletRetryInterval * 1000);
        }
    }
}