org.geopublishing.atlasViewer.GpCoreUtil.java Source code

Java tutorial

Introduction

Here is the source code for org.geopublishing.atlasViewer.GpCoreUtil.java

Source

/*******************************************************************************
 * Copyright (c) 2010 Stefan A. Tzeggai.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser Public License v2.1
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * 
 * Contributors:
 *     Stefan A. Tzeggai - initial API and implementation
 ******************************************************************************/
package org.geopublishing.atlasViewer;

import java.awt.Component;
import java.awt.FontMetrics;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.net.URISyntaxException;
import java.net.URL;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.Locale;
import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.measure.unit.Unit;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextPane;
import javax.swing.JTree;
import javax.swing.SwingConstants;
import javax.swing.WindowConstants;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.TabSet;
import javax.swing.text.TabStop;
import javax.swing.tree.MutableTreeNode;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import javax.xml.parsers.FactoryConfigurationError;

import net.miginfocom.swing.MigLayout;

import org.apache.commons.lang.SystemUtils;
import org.apache.log4j.Logger;
import org.apache.log4j.xml.DOMConfigurator;
import org.eclipse.emf.ecore.xml.type.internal.RegEx;
import org.geopublishing.atlasViewer.dp.DpEntry;
import org.geopublishing.atlasViewer.map.Map;
import org.geopublishing.atlasViewer.swing.AtlasViewerGUI;
import org.geopublishing.atlasViewer.swing.HTMLInfoJPane;
import org.geopublishing.atlasViewer.swing.HTMLInfoPaneInterface;
import org.geopublishing.atlasViewer.swing.Icons;
import org.geopublishing.geopublisher.GPProps;
import org.geopublishing.geopublisher.GpUtil;
import org.geotools.resources.CRSUtilities;
import org.opengis.referencing.crs.CoordinateReferenceSystem;

import de.schmitzm.geotools.data.amd.AttributeMetadataImpl;
import de.schmitzm.geotools.data.amd.AttributeMetadataInterface;
import de.schmitzm.geotools.styling.StyledFeaturesInterface;
import de.schmitzm.i18n.I18NUtil;
import de.schmitzm.i18n.Translation;
import de.schmitzm.io.IOUtil;
import de.schmitzm.jfree.chart.style.ChartStyle;
import de.schmitzm.jfree.feature.style.FeatureChartStyle;
import de.schmitzm.lang.LangUtil;
import de.schmitzm.lang.ResourceProvider;
import de.schmitzm.swing.ExceptionDialog;
import de.schmitzm.swing.SwingUtil;
import de.schmitzm.versionnumber.ReleaseUtil;

/**
 * Collection of Atlas related static methods.
 * 
 * @author <a href="mailto:skpublic@wikisquare.de">Stefan Alfons Tzeggai</a>
 */
public class GpCoreUtil {
    /***************************************************************************
     * This string is used to identify the temp files of the AV. Any files and
     * folders starting with this string in the temp folder will be deleted when
     * the Atlas ends.
     * 
     * @see DpEntry#cleanupTemp
     **************************************************************************/
    public static final String ATLAS_TEMP_FILE_BASE_ID = "AtlasTempFile_";

    /***************************************************************************
     * This string is used to identify the temp files of the AV. Any files and
     * folders starting with this string in the temp folder will be deleted when
     * the Atlas ends.
     **************************************************************************/
    public static final String ATLAS_TEMP_FILE_INSTANCE_ID = "AtlasTempFile_" + System.currentTimeMillis() + "_";

    /**
     * {@link ResourceProvider}, der die Lokalisation fuer GUI-Komponenten des
     * Package {@code skrueger.swing} zur Verfuegung stellt. Diese sind in
     * properties-Datein unter {@code skrueger.swing.resource.locales}
     * hinterlegt.
     */
    private static ResourceProvider RESOURCE = ResourceProvider.newInstance("locales.AtlasViewerTranslation",
            Locale.ENGLISH);

    /**
     * Convenience method to access the {@link AtlasViewerGUI}s translation
     * resources.
     * 
     * @param key
     *            the key for the AtlasViewerTranslation.properties file
     * @param values
     *            optinal values
     */
    public static String R(final String key, final Object... values) {
        return RESOURCE.getString(key, values);
    }

    /**
     * Convenience method to access the {@link AtlasViewerGUI}s translation
     * resources.
     * 
     * @param key
     *            the key for the AtlasViewerTranslation.properties file
     * @param reqLanguage
     *            requested Language/Locale
     * @param values
     *            optinal values
     */
    public static String R(final String key, Locale reqLanguage, final Object... values) {
        return RESOURCE.getString(key, reqLanguage, values);
    }

    public static final Logger LOGGER = Logger.getLogger(GpCoreUtil.class);

    /**
     * Creates a random number generator mainly used for IDs
     */
    public final static Random RANDOM = new Random();

    public static void setTabs(final JTextPane textPane, final int charactersPerTab) {
        final FontMetrics fm = textPane.getFontMetrics(textPane.getFont());
        final int charWidth = fm.charWidth('w');
        final int tabWidth = charWidth * charactersPerTab;

        final TabStop[] tabs = new TabStop[10];

        for (int j = 0; j < tabs.length; j++) {
            final int tab = j + 1;
            tabs[j] = new TabStop(tab * tabWidth);
        }

        final TabSet tabSet = new TabSet(tabs);
        final SimpleAttributeSet attributes = new SimpleAttributeSet();
        StyleConstants.setTabSet(attributes, tabSet);
        final int length = textPane.getDocument().getLength();
        textPane.getStyledDocument().setParagraphAttributes(0, length, attributes, false);
    }

    /**
     * e1027. Converting a {@link TreeNode} in a {@link JTree} Component to a
     * {@link TreePath} Returns a {@link TreePath} containing the specified
     * node.
     */
    public static final TreePath getPath(TreeNode node) {
        final List<TreeNode> list = new ArrayList<TreeNode>();

        // Add all nodes to list
        while (node != null) {
            list.add(node);
            node = node.getParent();
        }
        Collections.reverse(list);

        // Convert array of nodes to TreePath
        return new TreePath(list.toArray());
    }

    /**
     * If expand is true, expands all nodes in the tree. Otherwise, collapses
     * all nodes in the tree.
     */
    public final static void expandAll(final JTree tree, final boolean expand) {
        final TreeNode root = (TreeNode) tree.getModel().getRoot();

        // Traverse tree from root
        expandAll(tree, new TreePath(root), expand);
    }

    private final static void expandAll(final JTree tree, final TreePath parent, final boolean expand) {
        // Traverse children
        final TreeNode node = (TreeNode) parent.getLastPathComponent();
        if (node.getChildCount() >= 0) {
            for (final Enumeration<TreeNode> e = node.children(); e.hasMoreElements();) {
                final TreeNode n = e.nextElement();
                final TreePath path = parent.pathByAddingChild(n);
                expandAll(tree, path, expand);
            }
        }

        // Expansion or collapse must be done bottom-up
        if (expand) {
            tree.expandPath(parent);
        } else {
            tree.collapsePath(parent);
        }
    }

    /**
     * Expands a tree to the
     * 
     * @param tree
     * @param droppedNode
     * @author <a href="mailto:skpublic@wikisquare.de">Stefan Alfons Tzeggai</a>
     */
    public final static void expandToNode(final JTree tree, final MutableTreeNode droppedNode) {

        TreeNode lookAt = droppedNode;
        final List<TreeNode> parents = new ArrayList<TreeNode>();
        parents.add(lookAt);

        while (lookAt.getParent() != null) {
            lookAt = lookAt.getParent();
            parents.add(lookAt);
        }

        Collections.reverse(parents);
        for (final TreeNode node : parents) {
            final TreePath path = getPath(node);
            tree.expandPath(path);
        }
    }

    /**
     * Copy file or folder recursivly to file or folder. All filenames are
     * turned to lower case!
     * 
     * @param source
     *            File or directory or wildcard to copy
     * @param destination
     *            Directory or filename...
     * 
     * @author <a href="mailto:skpublic@wikisquare.de">Stefan Alfons Tzeggai</a>
     * @throws URISyntaxException
     * @throws IOException
     * 
     * @deprecated Use celanFilenames !
     */
    @Deprecated
    public final static void copyURL(final Logger log, final URL source, final URL destination)
            throws IOException, URISyntaxException {
        copyFile(log, new File(source.getFile()), new File(destination.getFile()));
    }

    /**
     * Copy file or folder recursivly to file or folder. All filenames are
     * turned to lower case!
     * 
     * @param source
     *            File or directory or wildcard to copy
     * @param destination
     *            Directory or filename...
     * 
     * @author <a href="mailto:skpublic@wikisquare.de">Stefan Alfons Tzeggai</a>
     * 
     * @deprecated Use cleanFilenames !
     * 
     * @throws IOException
     */
    @Deprecated
    public final static void copyFile(final Logger log, final File source, final File destination)
            throws IOException {
        IOUtil.copyFile(log, source, destination, false);
    }

    // /**
    // * Provocates caching of the EPSG database.
    // *
    // * @param progressWindow_
    // * @author <a href="mailto:skpublic@wikisquare.de">Stefan Alfons
    // * Tzeggai</a>
    // */
    // public static void cacheEPSG() {
    // // if (progressWindow_ != null)
    // //
    // // progressWindow_.setDescription(AtlasViewer
    // // .R("AtlasViewer.process.EPSG_codes_caching"));
    // try {
    // cacheEPSG();
    // } catch (final Exception e) {
    // progressWindow_.exceptionOccurred(exception)
    // SwingUtilities.invokeLater(new Runnable() {
    //
    // @Override
    // public void run() {
    // ExceptionDialog.show(e);
    // }
    // });
    // }
    // // if (progressWindow_ != null)
    // // progressWindow_.exceptionOccurred(e);
    // // if (progressWindow_ != null)
    // // progressWindow_.complete();
    // }

    /**
     * Checks if the URL points to an existsing file.
     * 
     * @return
     * @author <a href="mailto:skpublic@wikisquare.de">Stefan Alfons Tzeggai</a>
     */
    public static boolean exists(final URL url) {
        try {
            final InputStream openStream = url.openStream();
            openStream.close();
            return true;
        } catch (final Exception e) {
            return false;
        }
    }

    /**
     * @return List of missing language Strings
     * @param ac
     *            {@link AtlasConfig} to determine the languages to expect.
     * @param trans
     *            The {@link Translation} to check.
     */
    public static List<String> getMissingLanguages(final AtlasConfig ac, final Translation trans) {
        if (trans == null)
            return ac.getLanguages();

        final ArrayList<String> result = new ArrayList<String>();
        for (final String l : ac.getLanguages()) {
            final String t = trans.get(l);
            if (I18NUtil.isEmpty(t)) {
                result.add(l);
            }
        }
        return result;
    }

    /**
     * Fix an ugly bug that disables the "Create Folder" button on Windows for
     * the MyDocuments
     * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4847375
     * 
     * @see http://code.google.com/p/winfoldersjava/
     */
    public static void fixBug4847375() {

        try {
            if (SystemUtils.IS_OS_WINDOWS) {
                final String myDocumentsDirectoryName = javax.swing.filechooser.FileSystemView.getFileSystemView()
                        .getDefaultDirectory().getName();
                Runtime.getRuntime().exec("attrib -r \"%USERPROFILE%\\" + myDocumentsDirectoryName + "\"");
            }

        } catch (final Throwable e) {
            LOGGER.error("While fixing bug 4847375: ", e);
        }

        // try {
        // Runtime.getRuntime().exec(
        // "attrib -r \"%USERPROFILE%\\My Documents\"");
        // } catch (IOException e) {
        // }
        // try {
        // Runtime.getRuntime().exec(
        // "attrib -r \"%USERPROFILE%\\Mes documents\"");
        // } catch (IOException e) {
        // }
        // try {
        // String cmd = "attrib -r \"%USERPROFILE%\\Eigene Dateien\"";
        // Runtime.getRuntime().exec(cmd);
        // } catch (IOException e) {
        // }

    }

    /**
     * Convenience method to update the series legend {@link ChartStyle} title
     * and tooltip from given {@link AttributeMetadataImpl}.
     * 
     * @param styledLayer
     * @param chartStyle
     * @param rendererIndex
     * @param seriesIdx
     * @param languages
     */
    public static void applyDefaultTitleAndTranslationToLegend(final StyledFeaturesInterface<?> styledLayer,
            final FeatureChartStyle chartStyle, final int rendererIndex, final int seriesIdx,
            final List<String> languages) {

        final Translation legendTooltipTranslation = chartStyle.getRendererStyle(rendererIndex)
                .getSeriesLegendTooltip(seriesIdx).getLabelTranslation();

        final Translation legendTitleTranslation = chartStyle.getRendererStyle(rendererIndex)
                .getSeriesLegendLabel(seriesIdx).getLabelTranslation();

        /* First series = DOMAIN */
        final String attName = chartStyle.getAttributeName(seriesIdx + 1);

        // AttributeMetadata attMeta =
        // ASUtil.getAttributeMetadataFor(styledLayer,
        // attName);
        final AttributeMetadataImpl attMeta = styledLayer.getAttributeMetaDataMap().get(attName);

        /*
         * This should trigger all listeners
         */
        for (final String lang : languages) {
            String titleValue = attMeta.getTitle().get(lang);

            /* Instead on an empty title, we use the raw attribute name */
            if (I18NUtil.isEmpty(titleValue))
                titleValue = attName;

            legendTitleTranslation.put(lang, titleValue);
            legendTooltipTranslation.put(lang, attMeta.getDesc().get(lang));

            // Try to update the Y-Axis label
            if (chartStyle.getAxisStyle(seriesIdx + 1) != null)
                chartStyle.getAxisStyle(seriesIdx + 1).getLabelTranslation().put(lang, titleValue);

        }

    }

    /**
     * Convenience method to update the series legend {@link ChartStyle} title
     * and tooltip from given {@link AttributeMetadataImpl}.
     * 
     * @param styledLayer
     * @param chartStyle
     * @param rendererIndex
     * @param seriesIdx
     * @param languages
     */
    public static void applyDefaultTitleAndTranslationToAxis(final StyledFeaturesInterface styledLayer,
            final FeatureChartStyle chartStyle, final int axis, final int attribIdx, final List<String> languages) {

        final Translation legendTitleTranslation = chartStyle.getAxisStyle(axis).getLabelTranslation();

        /* First series = DOMAIN */
        final String attName = chartStyle.getAttributeName(attribIdx);

        final AttributeMetadataInterface attMeta = styledLayer.getAttributeMetaDataMap().get(attName);

        /*
         * This should trigger all listeners
         */
        for (final String lang : languages) {
            String titleValue = attMeta.getTitle().get(lang);

            /* Instead on an empty title, we use the raw attribute name */
            if (I18NUtil.isEmpty(titleValue))
                titleValue = attName;

            legendTitleTranslation.put(lang, titleValue);
        }
    }

    /**
     * @param crs
     * @param value
     */
    public static String formatCoord(final CoordinateReferenceSystem crs, final double value) {

        final StringBuffer sb = new StringBuffer(NumberFormat.getNumberInstance().format(value));

        final Unit<?> unit = CRSUtilities.getUnit(crs.getCoordinateSystem());
        if (unit != null) {
            sb.append(unit.toString());
        }

        return sb.toString();
    }

    public static JDialog getWaitDialog(final Component owner, final String msg) {
        final JDialog waitFrame = new JDialog(SwingUtil.getParentWindow(owner));

        waitFrame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);

        final JPanel cp = new JPanel(new MigLayout());
        final JLabel label = new JLabel(msg, Icons.ICON_TASKRUNNING_BIG, SwingConstants.LEADING);
        cp.add(label);
        waitFrame.setContentPane(cp);

        waitFrame.setAlwaysOnTop(true);
        waitFrame.pack();
        SwingUtil.centerFrameOnScreen(waitFrame);
        waitFrame.setVisible(true);

        return waitFrame;
    }

    /**
     * Setting up the logger from a XML configuration file. We do that again in
     * GPPros, as it outputs log messages first. Does not change the
     * configuration if there are already appenders defined.
     */
    public static void initAtlasLogging() throws FactoryConfigurationError {
        ExceptionDialog.setMailDestinationAddress("tzeggai@wikisquare.de");
        ExceptionDialog.setSmtpMailer(GpUtil.bugReportMailer);

        // Add application version number to Exception mails
        ExceptionDialog.addAdditionalAppInfo(ReleaseUtil.getVersionInfo(GpUtil.class));

        if (Logger.getRootLogger().getAllAppenders().hasMoreElements())
            return;
        DOMConfigurator.configure(GPProps.class.getResource("/geopublishing_log4j.xml"));

        Logger.getRootLogger().addAppender(Logger.getLogger("dummy").getAppender("avFileLogger"));

    }

    /**
     * Factory method to create an html viewport.
     * 
     * @param map
     *            a Map
     */
    public static HTMLInfoPaneInterface createHTMLInfoPane(URL url, AtlasConfig ac) {

        HTMLInfoPaneInterface htmlInfoPane = null;
        String htmlString = IOUtil.readURLasString(url);
        if (htmlString.contains("\\"))
            url = convertWindowsToLinuxSlashesInHtmlSrcTags(url);
        // // try to use an HTML view based on DJ project
        // htmlInfoPane = (HTMLInfoPaneInterface)LangUtil.instantiateObject(
        // "org.geopublishing.atlasViewer.swing.HTMLInfoJWebBrowser",
        // true, // fallback if class can not be loaded
        // url, ac // constructor arguments
        // );

        // try to use an HTML view based on Lobo/Cobra
        htmlInfoPane = (HTMLInfoPaneInterface) LangUtil.instantiateObject(
                "org.geopublishing.atlasViewer.swing.HTMLInfoLoboBrowser", true, // fallback if class can not be loaded
                url, ac // constructor arguments
        );

        if (htmlInfoPane != null) {
            LOGGER.info("Using " + LangUtil.getSimpleClassName(htmlInfoPane) + " for HTML view.");
            return htmlInfoPane;
        }

        // use an HTML view based on JEditorPane
        htmlInfoPane = new HTMLInfoJPane(url, ac);

        return htmlInfoPane;
    }

    /**
     * This method converts backslashes to forwardslashes in any html document.
     * Backslashes dont work in linux environments and when using the atlas out
     * of a .jar geopublisher expects forwardslashes
     * 
     * @param url
     * @return
     */
    public static URL convertWindowsToLinuxSlashesInHtmlSrcTags(URL url) {
        String htmlString = IOUtil.readURLasString(url);
        File tempFile = null;
        Pattern p = Pattern.compile("(<[^>]+(?:src|href)=\"[^\"]*)\\\\([^\"]*\"[^>]*>)",
                Pattern.MULTILINE | Pattern.CASE_INSENSITIVE);
        Matcher m = p.matcher(htmlString);

        while (m.find()) {
            htmlString = m.replaceAll("$1/$2");
            m = p.matcher(htmlString);
        }
        try {
            tempFile = IOUtil.createTemporaryFile("tmp", ".html", true);
            InputStream bais = new ByteArrayInputStream(htmlString.getBytes());
            IOUtil.writeStreamToFile(bais, tempFile);
            IOUtil.copyFileNoException(null, tempFile, IOUtil.urlToFile(url), false);
        } catch (IOException e) {
        }

        return url;

    }

    /**
     * Factory method to create an html viewport.
     * 
     * @param map
     *            a Map
     */
    public static HTMLInfoPaneInterface createHTMLInfoPane(Map map) {
        return createHTMLInfoPane(map.getInfoURL(), map.getAc());
    }

}