org.openvpms.web.echo.dialog.HelpDialog.java Source code

Java tutorial

Introduction

Here is the source code for org.openvpms.web.echo.dialog.HelpDialog.java

Source

/*
 * Version: 1.0
 *
 * The contents of this file are subject to the OpenVPMS License Version
 * 1.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.openvpms.org/license/
 *
 * Software distributed under the License is distributed on an 'AS IS' basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * Copyright 2013 (C) OpenVPMS Ltd. All Rights Reserved.
 */

package org.openvpms.web.echo.dialog;

import echopointng.LabelEx;
import echopointng.xhtml.XhtmlFragment;
import nextapp.echo2.app.Alignment;
import nextapp.echo2.app.ApplicationInstance;
import nextapp.echo2.app.Button;
import nextapp.echo2.app.Column;
import nextapp.echo2.app.Component;
import nextapp.echo2.app.Extent;
import nextapp.echo2.app.Grid;
import nextapp.echo2.app.Label;
import nextapp.echo2.app.ResourceImageReference;
import nextapp.echo2.app.Row;
import nextapp.echo2.app.SplitPane;
import nextapp.echo2.app.event.ActionEvent;
import nextapp.echo2.app.layout.RowLayoutData;
import nextapp.echo2.webcontainer.command.BrowserOpenWindowCommand;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.openvpms.component.business.service.archetype.IArchetypeService;
import org.openvpms.component.system.common.util.StringUtilities;
import org.openvpms.web.echo.event.ActionListener;
import org.openvpms.web.echo.factory.ButtonFactory;
import org.openvpms.web.echo.factory.ColumnFactory;
import org.openvpms.web.echo.factory.LabelFactory;
import org.openvpms.web.echo.factory.RowFactory;
import org.openvpms.web.echo.factory.SplitPaneFactory;
import org.openvpms.web.echo.help.HelpContext;
import org.openvpms.web.resource.i18n.Messages;
import org.openvpms.web.resource.subscription.SubscriptionHelper;
import org.openvpms.web.resource.version.Version;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Enumeration;

import static org.openvpms.web.echo.style.Styles.BOLD;
import static org.openvpms.web.echo.style.Styles.INSET;

/**
 * Help dialog.
 *
 * @author Tim Anderson
 */
public class HelpDialog extends PopupDialog {

    /**
     * Features to pass to window.open().
     */
    private final String features;

    /**
     * The project logo.
     */
    private static final String PATH = "/org/openvpms/web/resource/image/openvpms.gif";

    /**
     * The home page.
     */
    private static final String HOME = "http://www.openvpms.org";

    /**
     * The logger.
     */
    private static final Log log = LogFactory.getLog(HelpDialog.class);

    /**
     * Constructs a {@code HelpDialog}.
     *
     * @param service  the archetype service
     * @param features browser feature string. May be {@code null}
     */
    public HelpDialog(IArchetypeService service, String features) {
        this(null, null, service, features);
    }

    /**
     * Constructs a {@code HelpDialog}.
     *
     * @param topic    the topic. May be {@code null}
     * @param topicURL the topic URL. May be {@code null}
     * @param service  the archetype service
     * @param features browser feature string. May be {@code null}
     */
    protected HelpDialog(String topic, final String topicURL, IArchetypeService service, String features) {
        super(Messages.get("helpdialog.title"), "HelpDialog", OK);
        this.features = features;
        setModal(true);

        Component component = null;

        if (topic != null) {
            if (topicURL == null) {
                Label label = LabelFactory.create(true, true);
                label.setStyleName(BOLD);
                label.setText(Messages.format("helpdialog.nohelp.topic", topic));
                component = label;
            } else {
                String parent = getExistingParent(topicURL);
                StringBuilder content = new StringBuilder();
                content.append("<div xmlns='http://www.w3.org/1999/xhtml'>");
                content.append("<p>");
                content.append(Messages.format("helpdialog.nohelp.create", topicURL));
                content.append("</p>");
                if (parent != null) {
                    content.append("<p>");
                    content.append(Messages.format("helpdialog.nohelp.parent", parent));
                    content.append("</p>");
                }
                content.append("</div>");
                LabelEx label = new LabelEx(new XhtmlFragment(content.toString()));
                label.setLineWrap(true);
                component = label;
            }
        }

        Component topics = getTopics();

        Component content;
        if (component != null) {
            Grid hack = new Grid();
            hack.setStyleName("HelpDialog.content.size");
            Row container = RowFactory.create(component, hack);
            content = SplitPaneFactory.create(SplitPane.ORIENTATION_HORIZONTAL, "HelpDialog.content", topics,
                    container);
        } else {
            content = topics;
        }
        SplitPane footer = SplitPaneFactory.create(SplitPane.ORIENTATION_VERTICAL_BOTTOM_TOP, "HelpDialog.footer",
                ColumnFactory.create(INSET, getSubscription(service)), content);
        SplitPane header = SplitPaneFactory.create(SplitPane.ORIENTATION_VERTICAL_TOP_BOTTOM, "HelpDialog.header",
                getHeader(), footer);
        getLayout().add(header);
    }

    /**
     * Displays a help dialog for the specified help context.
     *
     * @param help     the help context. May be {@code null}
     * @param service  the archetype service
     * @param features the browser features. May be {@code null}
     */
    public static void show(HelpContext help, IArchetypeService service, String features) {
        if (help == null) {
            new HelpDialog(service, features).show();
        } else {
            show(help.getTopic(), service, features);
        }
    }

    /**
     * Displays a help dialog for the specified topic.
     *
     * @param topic    the topic identifier
     * @param service  the archetype service
     * @param features the browser features. May be {@code null}
     */
    public static void show(String topic, IArchetypeService service, String features) {
        String url = getTopicURL(topic);
        if (url != null) {
            if (exists(url)) {
                openWindow(url, features);
            } else {
                HelpDialog dialog = new HelpDialog(topic, url, service, features);
                dialog.show();
            }
        } else {
            HelpDialog dialog = new HelpDialog(topic, null, service, features);
            dialog.show();
        }
    }

    /**
     * Returns the topics hyperlink.
     * <p/>
     * This launches a new browser window.
     *
     * @return the topics hyperlink.
     */
    private Component getTopics() {
        Column topics = ColumnFactory.create("WideCellSpacing");

        for (int i = 0;; ++i) {
            String topic = Messages.get("help.topic." + i + ".title", Messages.HELP, true);
            if (topic != null) {
                final String url = Messages.get("help.topic." + i + ".url", Messages.HELP, true);
                if (url != null) {
                    Button helpLink = createHelpURL(topic, url);
                    topics.add(RowFactory.create(helpLink)); // force to minimum width
                } else {
                    break;
                }
            } else {
                break;
            }
        }
        return ColumnFactory.create("Inset.Large", topics);
    }

    /**
     * Creates a help URL button.
     * <p/>
     * When clicked, this opens a new browser window/tab.
     *
     * @param topic the topic name
     * @param url   the topic url
     * @return a new help URL button
     */
    private Button createHelpURL(String topic, final String url) {
        Button helpLink = ButtonFactory.create(null, "hyperlink");
        helpLink.setText(topic);
        helpLink.setBackground(null); // want to inherit style of parent
        helpLink.setToolTipText(url);
        helpLink.addActionListener(new ActionListener() {
            public void onAction(ActionEvent e) {
                launch(url);
            }
        });
        return helpLink;
    }

    /**
     * Returns the header component.
     *
     * @return the header component
     */
    private Component getHeader() {
        Button logo = new Button(new ResourceImageReference(PATH));
        logo.setToolTipText(HOME);
        logo.addActionListener(new ActionListener() {
            public void onAction(ActionEvent e) {
                launch(HOME);
            }
        });
        RowLayoutData centre = new RowLayoutData();
        centre.setAlignment(new Alignment(Alignment.DEFAULT, Alignment.CENTER));
        logo.setLayoutData(centre);

        Label label = LabelFactory.create(null, "small");
        label.setText(Messages.format("helpdialog.version", Version.VERSION, Version.REVISION));

        Row labelRow = RowFactory.create("InsetX", label);
        RowLayoutData right = new RowLayoutData();
        right.setAlignment(new Alignment(Alignment.RIGHT, Alignment.BOTTOM));
        right.setWidth(new Extent(100, Extent.PERCENT));
        labelRow.setLayoutData(right);

        return RowFactory.create(INSET, logo, labelRow);
    }

    /**
     * Launches a URL in a new window, closing the help dialog.
     *
     * @param url the URL
     */
    private void launch(String url) {
        openWindow(url, features);
        close();
    }

    /**
     * Opens a new window for the specified url.
     *
     * @param url the url
     */
    private static void openWindow(String url, String features) {
        ApplicationInstance.getActive().enqueueCommand(new BrowserOpenWindowCommand(url, null, features));
    }

    /**
     * Returns the subscription details.
     *
     * @param service the archetype service
     * @return the subscription details
     */
    private LabelEx getSubscription(IArchetypeService service) {
        String subscription = SubscriptionHelper.formatSubscription(service);
        String content = "<p xmlns='http://www.w3.org/1999/xhtml'>" + subscription + "</p>";
        LabelEx label = new LabelEx(new XhtmlFragment(content));
        label.setLineWrap(true);
        label.setTextAlignment(Alignment.ALIGN_CENTER);
        return label;
    }

    /**
     * Returns the topic URL for a given topic identifier.
     *
     * @param topic the topic identifier
     * @return the topic URL or {@code null} if none is found
     */
    private static String getTopicURL(String topic) {
        String result = null;
        String baseURL = Messages.get("help.url", Messages.HELP, true);
        if (baseURL != null) {
            String fragment = Messages.get(topic, Messages.HELP, true);
            if (fragment == null) {
                Enumeration<String> iter = Messages.getKeys(Messages.HELP);
                while (iter.hasMoreElements()) {
                    String key = iter.nextElement();
                    if (StringUtilities.matches(topic, key)) {
                        fragment = Messages.get(key, Messages.HELP, true);
                        break;
                    }
                }
            }
            if (fragment != null) {
                result = baseURL + "/" + fragment;
            }
        }
        return result;
    }

    /**
     * Tries to locate an existing URL for the given topic URL.
     *
     * @param topicURL the topic URL
     * @return the closest parent URL to the topic that exists, or {@code null} if none is found
     */
    private String getExistingParent(String topicURL) {
        String result = null;
        try {
            URI uri = new URI(topicURL);
            String path = uri.getPath();
            while (!StringUtils.isEmpty(path)) {
                if (!path.endsWith("/")) {
                    uri = uri.resolve(".");
                } else {
                    uri = uri.resolve("..");
                }
                String parent = uri.toURL().toString();
                if (exists(parent)) {
                    result = parent;
                    break;
                }
                path = uri.getPath();
            }
        } catch (URISyntaxException exception) {
            log.debug(exception, exception);
        } catch (MalformedURLException exception) {
            log.debug(exception, exception);
        }
        return result;
    }

    /**
     * Determines if a topic URL exists.
     *
     * @param topicURL the topic URL
     * @return {@code true} if the topic URL exists, otherwise {@code false}
     */
    private static boolean exists(String topicURL) {
        boolean exists = false;
        try {
            URL url = new URL(topicURL);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("HEAD");
            int responseCode = connection.getResponseCode();
            if (responseCode >= 200 && responseCode <= 399) {
                exists = true;
            }
        } catch (IOException exception) {
            log.warn(exception.getMessage(), exception);
        }
        return exists;
    }

}