001    // License: GPL. For details, see LICENSE file.
002    package org.openstreetmap.josm.gui.util;
003    
004    import static org.openstreetmap.josm.tools.I18n.tr;
005    
006    import java.awt.Component;
007    import java.awt.Container;
008    import java.awt.Dialog;
009    import java.awt.Dimension;
010    import java.awt.Image;
011    import java.awt.Toolkit;
012    import java.awt.Window;
013    import java.awt.event.HierarchyEvent;
014    import java.awt.event.HierarchyListener;
015    import java.awt.image.FilteredImageSource;
016    import java.lang.reflect.InvocationTargetException;
017    
018    import javax.swing.GrayFilter;
019    import javax.swing.Icon;
020    import javax.swing.ImageIcon;
021    import javax.swing.JOptionPane;
022    import javax.swing.SwingUtilities;
023    
024    import org.openstreetmap.josm.Main;
025    import org.openstreetmap.josm.gui.ExtendedDialog;
026    import org.openstreetmap.josm.tools.ImageProvider;
027    
028    /**
029     * basic gui utils
030     */
031    public class GuiHelper {
032        /**
033         * disable / enable a component and all its child components
034         */
035        public static void setEnabledRec(Container root, boolean enabled) {
036            root.setEnabled(enabled);
037            Component[] children = root.getComponents();
038            for (Component child : children) {
039                if(child instanceof Container) {
040                    setEnabledRec((Container) child, enabled);
041                } else {
042                    child.setEnabled(enabled);
043                }
044            }
045        }
046    
047        public static void runInEDT(Runnable task) {
048            if (SwingUtilities.isEventDispatchThread()) {
049                task.run();
050            } else {
051                SwingUtilities.invokeLater(task);
052            }
053        }
054    
055        public static void runInEDTAndWait(Runnable task) {
056            if (SwingUtilities.isEventDispatchThread()) {
057                task.run();
058            } else {
059                try {
060                    SwingUtilities.invokeAndWait(task);
061                } catch (InterruptedException e) {
062                    e.printStackTrace();
063                } catch (InvocationTargetException e) {
064                    e.printStackTrace();
065                }
066            }
067        }
068        
069        /**
070         * returns true if the user wants to cancel, false if they
071         * want to continue
072         */
073        public static final boolean warnUser(String title, String content, ImageIcon baseActionIcon, String continueToolTip) {
074            ExtendedDialog dlg = new ExtendedDialog(Main.parent,
075                    title, new String[] {tr("Cancel"), tr("Continue")});
076            dlg.setContent(content);
077            dlg.setButtonIcons(new Icon[] {
078                    ImageProvider.get("cancel"),
079                    ImageProvider.overlay(
080                            ImageProvider.get("upload"),
081                            new ImageIcon(ImageProvider.get("warning-small").getImage().getScaledInstance(10 , 10, Image.SCALE_SMOOTH)),
082                            ImageProvider.OverlayPosition.SOUTHEAST)});
083            dlg.setToolTipTexts(new String[] {
084                    tr("Cancel"),
085                    continueToolTip});
086            dlg.setIcon(JOptionPane.WARNING_MESSAGE);
087            dlg.setCancelButton(1);
088            return dlg.showDialog().getValue() != 2;
089        }
090        
091        /**
092         * Replies the disabled (grayed) version of the specified image.
093         * @param image The image to disable
094         * @return The disabled (grayed) version of the specified image, brightened by 20%.
095         * @since 5484
096         */
097        public static final Image getDisabledImage(Image image) {
098            return Toolkit.getDefaultToolkit().createImage(
099                    new FilteredImageSource(image.getSource(), new GrayFilter(true, 20)));
100        }
101    
102        /**
103         * Replies the disabled (grayed) version of the specified icon.
104         * @param icon The icon to disable
105         * @return The disabled (grayed) version of the specified icon, brightened by 20%.
106         * @since 5484
107         */
108        public static final ImageIcon getDisabledIcon(ImageIcon icon) {
109            return new ImageIcon(getDisabledImage(icon.getImage()));
110        }
111        
112        /**
113         * Attaches a {@code HierarchyListener} to the specified {@code Component} that
114         * will set its parent dialog resizeable. Use it before a call to JOptionPane#showXXXXDialog
115         * to make it resizeable.
116         * @param pane The component that will be displayed
117         * @param minDimension The minimum dimension that will be set for the dialog. Ignored if null
118         * @return {@code pane}
119         * @since 5493
120         */
121        public static final Component prepareResizeableOptionPane(final Component pane, final Dimension minDimension) {
122            if (pane != null) {
123                pane.addHierarchyListener(new HierarchyListener() {
124                    public void hierarchyChanged(HierarchyEvent e) {
125                        Window window = SwingUtilities.getWindowAncestor(pane);
126                        if (window instanceof Dialog) {
127                            Dialog dialog = (Dialog)window;
128                            if (!dialog.isResizable()) {
129                                dialog.setResizable(true);
130                                if (minDimension != null) {
131                                    dialog.setMinimumSize(minDimension);
132                                }
133                            }
134                        }
135                    }
136                });
137            }
138            return pane;
139        }
140    }