jshm.gui.GuiUtil.java Source code

Java tutorial

Introduction

Here is the source code for jshm.gui.GuiUtil.java

Source

/*
 * -----LICENSE START-----
 * JSHManager - A Java-based tool for managing one's ScoreHero account.
 * Copyright (C) 2008 Tim Mullin
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 * -----LICENSE END-----
 */
package jshm.gui;

import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.swing.DefaultComboBoxModel;
import javax.swing.ImageIcon;
import javax.swing.JComboBox;
import javax.swing.ListCellRenderer;
import javax.swing.ProgressMonitor;
import javax.swing.ProgressMonitorInputStream;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.plaf.FontUIResource;
import javax.swing.tree.TreePath;

import jshm.Config;
import jshm.JSHManager;
import jshm.Song;
import jshm.gui.components.SpInfoViewer;
import jshm.gui.renderers.ScoreEditorSongComboRenderer;
import jshm.sh.Client;
import jshm.util.Util;

import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.methods.GetMethod;
import org.jdesktop.swingx.JXErrorPane;
import org.jdesktop.swingx.JXTreeTable;
import org.jdesktop.swingx.autocomplete.AutoCompleteDecorator;
import org.jdesktop.swingx.autocomplete.ObjectToStringConverter;
import org.jdesktop.swingx.error.ErrorInfo;
import org.jdesktop.swingx.graphics.GraphicsUtilities;
import org.jdesktop.swingx.treetable.TreeTableModel;

public class GuiUtil {
    static final Logger LOG = Logger.getLogger(GuiUtil.class.getName());

    /**
     * This sets the default L&F as well as sets some icons
     */
    public static void init() {
        try {
            // Set the Look & Feel to match the current system
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (Exception e) {
        }

        // http://www.java2s.com/Tutorial/Java/0240__Swing/CustomizingaJOptionPaneLookandFeel.htm
        UIManager.put("OptionPane.errorIcon",
                new ImageIcon(GuiUtil.class.getResource("/jshm/resources/images/toolbar/delete.png")));
        UIManager.put("OptionPane.informationIcon",
                new ImageIcon(GuiUtil.class.getResource("/jshm/resources/images/toolbar/infoabout.png")));
        UIManager.put("OptionPane.questionIcon",
                new ImageIcon(GuiUtil.class.getResource("/jshm/resources/images/toolbar/help.png")));
        UIManager.put("OptionPane.warningIcon",
                new ImageIcon(GuiUtil.class.getResource("/jshm/resources/images/toolbar/pause.png")));
        UIManager.put("OptionPane.yesIcon",
                new ImageIcon(GuiUtil.class.getResource("/jshm/resources/images/toolbar/accept32.png")));
        UIManager.put("OptionPane.noIcon",
                new ImageIcon(GuiUtil.class.getResource("/jshm/resources/images/toolbar/delete32.png")));

        float scale = Config.getFloat("font.scale");

        if (1f != scale) {
            LOG.finest("setting ui font scale to + " + scale);

            Enumeration<Object> keys = UIManager.getDefaults().keys();
            while (keys.hasMoreElements()) {
                Object key = keys.nextElement();
                Object value = UIManager.get(key);

                if (value instanceof FontUIResource) {
                    FontUIResource f = (FontUIResource) value;
                    f = new FontUIResource(f.deriveFont(scale * f.getSize2D()));
                    UIManager.put(key, f);
                }
            }
        }

        // hook into the wizard displayer
        System.setProperty("WizardDisplayer.default", "jshm.gui.wizards.displayer.WizardDisplayerImpl");
    }

    /**
     * Expands all nodes of the supplied tree starting at startDepth.
     * This should only be used when there is a known maximum depth.
     * @param tree
     * @param startDepth
     */
    public static void expandTreeFromDepth(JXTreeTable tree, int startDepth) {
        TreeTableModel model = tree.getTreeTableModel();
        Object root = model.getRoot();

        tree.expandAll();
        //      expandTreeFromDepth(tree, model, root, null, 0, startDepth);
        collapseTreeToDepth(tree, model, root, new TreePath(root), 0, startDepth);
    }

    /**
     * Recursively expands all children of path.
     * @param tree
     * @param path
     */
    public static void expandTreeBelowNode(JXTreeTable tree, TreePath path) {
        expandTreeBelowNode(tree, tree.getTreeTableModel(), path);
    }

    private static void expandTreeBelowNode(JXTreeTable tree, TreeTableModel model, TreePath path) {
        Object parent = path.getLastPathComponent();

        int childCount = model.getChildCount(parent);

        for (int i = 0; i < childCount; i++) {
            TreePath childPath = path.pathByAddingChild(model.getChild(parent, i));

            // using childCount is faster and plain better than isLeaf
            // since a non-leaf might have 0 children which would be
            // useless to expand
            if (0 < model.getChildCount(childPath.getLastPathComponent())) {
                tree.expandPath(childPath);
                expandTreeBelowNode(tree, model, childPath);
            }
        }
    }

    //   private static void expandTreeFromDepth(JXTreeTable tree, TreeTableModel model, Object parent, TreePath path, int curDepth, int startDepth) {      
    //      if (curDepth >= startDepth && model.isLeaf(parent)) {
    //         System.out.println("expanding: " + path);
    //         tree.expandPath(path);
    //         return;
    //      } else {
    //         path = 
    //            null != path
    //            ? path.pathByAddingChild(parent)
    //            : new TreePath(parent);
    //      }
    //      
    //      for (int i = 0; i < model.getChildCount(parent); i++) {
    //         Object child = model.getChild(parent, i);
    //         
    //         expandTreeFromDepth(tree, model, child,
    //            path,
    //            curDepth + 1, startDepth);
    //         
    //         if (model.isLeaf(child)) {
    //            continue;
    //         }
    //      }
    //   }

    private static void collapseTreeToDepth(JXTreeTable tree, TreeTableModel model, Object parent, TreePath path,
            int curDepth, int stopDepth) {
        curDepth++;

        if (curDepth == stopDepth) {
            //         System.out.println("collapsing: " + path);
            tree.collapsePath(path);
            return;
        }

        for (int i = 0; i < model.getChildCount(parent); i++) {
            Object child = model.getChild(parent, i);

            if (model.isLeaf(child)) {
                continue;
            }

            collapseTreeToDepth(tree, model, child, path.pathByAddingChild(child), curDepth, stopDepth);
        }
    }

    public static List<TreePath> getExpandedPaths(final JXTreeTable tree) {
        final TreeTableModel model = tree.getTreeTableModel();
        final List<TreePath> paths = new ArrayList<TreePath>();

        getExpandedPaths(tree, model, new TreePath(model.getRoot()), paths);

        for (TreePath p : paths)
            System.out.println(p);

        return paths;
    }

    private static void getExpandedPaths(JXTreeTable tree, TreeTableModel model, TreePath path,
            List<TreePath> paths) {
        //      System.out.println("Checking: " + path);

        Object parent = path.getLastPathComponent();
        final int childCount = model.getChildCount(parent);

        for (int i = 0; i < childCount; i++) {
            Object curNode = model.getChild(parent, i);
            TreePath curPath = path.pathByAddingChild(curNode);

            if (model.isLeaf(curNode))
                continue;

            if (tree.isExpanded(curPath))
                paths.add(curPath);

            getExpandedPaths(tree, model, curPath, paths);
        }
    }

    public static void restoreExpandedPaths(final JXTreeTable tree, final List<TreePath> paths) {
        //      System.out.println("Restoring " + paths.size());

        for (TreePath p : paths) {
            tree.expandPath(p);
        }
    }

    public static final String SELECT_A_SONG = "Type a song name...";
    private static final ListCellRenderer SONG_COMBO_RENDERER = new ScoreEditorSongComboRenderer();
    private static final ObjectToStringConverter SONG_COMBO_CONVERTER = new ObjectToStringConverter() {
        @Override
        public String getPreferredStringForItem(Object item) {
            if (null == item)
                return null;
            if (item instanceof Song)
                return ((Song) item).getTitle();
            return item.toString();
        }
    };

    public static void createSongCombo(JComboBox cb, List<? extends Song> songs) {
        cb.setRenderer(SONG_COMBO_RENDERER);
        DefaultComboBoxModel model = (DefaultComboBoxModel) cb.getModel();
        model.removeAllElements();

        model.addElement(SELECT_A_SONG);
        for (Song s : songs)
            model.addElement(s);

        AutoCompleteDecorator.decorate(cb, SONG_COMBO_CONVERTER);
    }

    // icon stuff

    public final static javax.swing.ImageIcon resizeIcon(ImageIcon icon, float scale) {
        return resizeIcon(icon, (int) (scale * icon.getIconWidth()), (int) (scale * icon.getIconHeight()));
    }

    /**
     * Resize an ImageIcon to the specified size.
     * @param icon The ImageIcon to resize
     * @param width The new width
     * @param height The new height
     */
    public final static javax.swing.ImageIcon resizeIcon(ImageIcon icon, int width, int height) {
        LOG.info("Resizing to " + width + "x" + height);
        Image img = icon.getImage();
        BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);

        Graphics g = bi.createGraphics();
        g.drawImage(img, 0, 0, width, height, null);
        g.dispose();

        return new javax.swing.ImageIcon(bi);
    }

    public static void openImageOrBrowser(final Frame owner, final String urlStr) {
        new SwingWorker<Void, Void>() {
            private BufferedImage image = null;
            private Throwable t = null;
            private boolean canceled = false;

            protected Void doInBackground() throws Exception {
                ProgressMonitor progress = null;

                try {
                    // try to see if it's an image before downloading the
                    // whole thing
                    GetMethod method = new GetMethod(urlStr);
                    Client.getHttpClient().executeMethod(method);
                    Header h = method.getResponseHeader("Content-type");

                    if (null != h && h.getValue().toLowerCase().startsWith("image/")) {
                        //                  jshm.util.TestTimer.start();
                        ProgressMonitorInputStream pmis = new ProgressMonitorInputStream(owner, "Loading image...",
                                method.getResponseBodyAsStream());
                        progress = pmis.getProgressMonitor();
                        //                  System.out.println("BEFORE max: " + progress.getMaximum());
                        h = method.getResponseHeader("Content-length");

                        if (null != h) {
                            try {
                                progress.setMaximum(Integer.parseInt(h.getValue()));
                            } catch (NumberFormatException e) {
                            }
                        }
                        //                  System.out.println("AFTER max: " + progress.getMaximum());

                        progress.setMillisToDecideToPopup(250);
                        progress.setMillisToPopup(1000);

                        image = javax.imageio.ImageIO.read(pmis);
                        pmis.close();
                        //                  jshm.util.TestTimer.stop();
                        //                  jshm.util.TestTimer.start();
                        image = GraphicsUtilities.toCompatibleImage(image);
                        //                  jshm.util.TestTimer.stop();
                    }

                    method.releaseConnection();
                } catch (OutOfMemoryError e) {
                    LOG.log(Level.WARNING, "OutOfMemoryError trying to load image", e);
                    image = null; // make it open in browser
                } catch (Throwable e) {
                    if (null != progress && progress.isCanceled()) {
                        canceled = true;
                    } else {
                        t = e;
                    }
                }

                return null;
            }

            public void done() {
                if (canceled)
                    return;

                if (null == image) {
                    if (null == t) {
                        // no error, just the url wasn't an image, so launch the browser
                        Util.openURL(urlStr);
                    } else {
                        LOG.log(Level.WARNING, "Error opening image URL", t);
                        ErrorInfo ei = new ErrorInfo("Error", "Error opening image URL", null, null, t, null, null);
                        JXErrorPane.showDialog(owner, ei);
                    }
                } else {
                    SpInfoViewer viewer = new SpInfoViewer();
                    viewer.setTitle(urlStr);
                    viewer.setImage(image, true);
                    viewer.setLocationRelativeTo(owner);
                    viewer.setVisible(true);
                }
            }
        }.execute();
    }

    private static Map<String, ImageIcon> iconCache = new HashMap<String, ImageIcon>();

    /**
     * Retrieves an image icon for the provided path relative to
     * "/jshm/resources/images/". The image is cached
     * if found for subsequent retrievals.
     * @param path
     * @return
     */
    public static ImageIcon getIcon(String path) {
        path = "/jshm/resources/images/" + path;

        if (null == iconCache.get(path)) {
            try {
                iconCache.put(path, new ImageIcon(JSHManager.class.getResource(path)));
            } catch (Exception e) {
            }
        }

        return iconCache.get(path);
    }
}