/* * Copyright 2016 Igor Maznitsa. * * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.igormaznitsa.sciareto.ui; import com.igormaznitsa.sciareto.ui.editors.mmeditors.UriEditPanel; import com.igormaznitsa.sciareto.ui.misc.ColorChooserButton; import com.igormaznitsa.sciareto.ui.editors.mmeditors.NoteEditor; import com.igormaznitsa.sciareto.ui.editors.mmeditors.FileEditPanel; import static com.igormaznitsa.mindmap.swing.panel.utils.Utils.html2color; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Desktop; import java.awt.Dialog; import java.awt.Dimension; import java.awt.Graphics; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; import java.awt.Image; import java.awt.MouseInfo; import java.awt.Point; import java.awt.Rectangle; import java.awt.Toolkit; import java.awt.Window; import java.awt.event.HierarchyEvent; import java.awt.event.HierarchyListener; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.util.List; import java.util.ResourceBundle; import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.imageio.ImageIO; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JWindow; import javax.swing.SwingUtilities; import javax.swing.UIManager; import org.apache.commons.lang.SystemUtils; import com.igormaznitsa.meta.annotation.MustNotContainNull; import com.igormaznitsa.meta.common.utils.IOUtils; import com.igormaznitsa.mindmap.model.MMapURI; import com.igormaznitsa.mindmap.model.Topic; import com.igormaznitsa.mindmap.model.logger.Logger; import com.igormaznitsa.mindmap.model.logger.LoggerFactory; import com.igormaznitsa.sciareto.Main; public final class UiUtils { private static final Logger LOGGER = LoggerFactory.getLogger(UiUtils.class); public static final ResourceBundle BUNDLE = java.util.ResourceBundle.getBundle("com/igormaznitsa/nbmindmap/i18n/Bundle"); public static final MMapURI EMPTY_URI; public static final boolean DARK_THEME; static { try { EMPTY_URI = new MMapURI("http://igormaznitsa.com/specialuri#empty"); //NOI18N } catch (URISyntaxException ex) { throw new Error("Unexpected exception", ex); //NOI18N } final Color color = UIManager.getColor("Panel.background"); //NOI18N if (color == null) { DARK_THEME = false; } else { DARK_THEME = calculateBrightness(color) < 150; } } public static final class SplashScreen extends JWindow { private static final long serialVersionUID = 2481671028674534278L; private final Image image; public SplashScreen(@Nonnull final Image image) { super(); this.setAlwaysOnTop(true); this.image = image; final JLabel label = new JLabel(new ImageIcon(this.image)); final JPanel root = new JPanel(new BorderLayout(0, 0)); root.add(label, BorderLayout.CENTER); this.setContentPane(root); this.pack(); this.setLocation(getPointForCentering(this)); invalidate(); repaint(); } } private UiUtils() { } public static void makeOwningDialogResizable(@Nonnull final Component component, @Nonnull @MustNotContainNull final Runnable ... extraActions) { final HierarchyListener listener = new HierarchyListener() { @Override public void hierarchyChanged(@Nonnull final HierarchyEvent e) { final Window window = SwingUtilities.getWindowAncestor(component); if (window instanceof Dialog) { final Dialog dialog = (Dialog) window; if (!dialog.isResizable()) { dialog.setResizable(true); component.removeHierarchyListener(this); for(final Runnable r : extraActions){ r.run(); } } } } }; component.addHierarchyListener(listener); } @Nonnull public static Point getPointForCentering(@Nonnull final Window window) { try { final Point mousePoint = MouseInfo.getPointerInfo().getLocation(); final GraphicsDevice[] devices = GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices(); for (final GraphicsDevice device : devices) { final Rectangle bounds = device.getDefaultConfiguration().getBounds(); if (mousePoint.x >= bounds.x && mousePoint.y >= bounds.y && mousePoint.x <= (bounds.x + bounds.width) && mousePoint.y <= (bounds.y + bounds.height)) { int screenWidth = bounds.width; int screenHeight = bounds.height; int width = window.getWidth(); int height = window.getHeight(); return new Point(((screenWidth - width) / 2) + bounds.x, ((screenHeight - height) / 2) + bounds.y); } } } catch (final Exception e) { LOGGER.error("Can't get point", e); //NOI18N } final Dimension scrSize = Toolkit.getDefaultToolkit().getScreenSize(); return new Point((scrSize.width-window.getWidth())/2,(scrSize.height-window.getHeight())/2); } @Nullable @MustNotContainNull public static List<File> showSelectAffectedFiles(@Nonnull @MustNotContainNull final List<File> files) { final FileListPanel panel = new FileListPanel(files); if (DialogProviderManager.getInstance().getDialogProvider().msgOkCancel("Affected files", panel)) { return panel.getSelectedFiles(); } return null; } public static int calculateBrightness(@Nonnull final Color color) { return (int) Math.sqrt( color.getRed() * color.getRed() * .241d + color.getGreen() * color.getGreen() * .691d + color.getBlue() * color.getBlue() * .068d); } @Nonnull public static Image iconToImage(@Nonnull Component context, @Nullable final Icon icon) { if (icon instanceof ImageIcon) { return ((ImageIcon) icon).getImage(); } final int width = icon == null ? 16 : icon.getIconWidth(); final int height = icon == null ? 16 : icon.getIconHeight(); final BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); if (icon != null) { final Graphics g = image.getGraphics(); try { icon.paintIcon(context, g, 0, 0); } finally { g.dispose(); } } return image; } @Nonnull public static Image makeBadgedRightBottom(@Nonnull final Image base, @Nonnull final Image badge) { final int width = Math.max(base.getWidth(null), badge.getWidth(null)); final int height = Math.max(base.getHeight(null), badge.getHeight(null)); final BufferedImage result = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); final Graphics gfx = result.getGraphics(); try { gfx.drawImage(base, (width - base.getWidth(null)) / 2, (height - base.getHeight(null)) / 2, null); gfx.drawImage(badge, width - badge.getWidth(null) - 1, height - badge.getHeight(null) - 1, null); } finally { gfx.dispose(); } return result; } @Nonnull public static Image makeBadgedRightTop(@Nonnull final Image base, @Nonnull final Image badge) { final int width = Math.max(base.getWidth(null), badge.getWidth(null)); final int height = Math.max(base.getHeight(null), badge.getHeight(null)); final BufferedImage result = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); final Graphics gfx = result.getGraphics(); try { gfx.drawImage(base, (width - base.getWidth(null)) / 2, (height - base.getHeight(null)) / 2, null); gfx.drawImage(badge, width - badge.getWidth(null) - 1, 1, null); } finally { gfx.dispose(); } return result; } @Nullable public static Image loadIcon(@Nonnull final String name) { final InputStream inStream = UiUtils.class.getClassLoader().getResourceAsStream("icons/" + name); //NOI18N Image result = null; if (inStream != null) { try { result = ImageIO.read(inStream); } catch (IOException ex) { result = null; } finally { IOUtils.closeQuetly(inStream); } } return result; } @Nullable public static MMapURI editURI(@Nonnull final String title, @Nullable final MMapURI uri) { final UriEditPanel textEditor = new UriEditPanel(uri == null ? null : uri.asString(false, false)); textEditor.doLayout(); textEditor.setPreferredSize(new Dimension(450, textEditor.getPreferredSize().height)); if (DialogProviderManager.getInstance().getDialogProvider().msgOkCancel(title, textEditor)) { final String text = textEditor.getText(); if (text.isEmpty()) { return EMPTY_URI; } try { return new MMapURI(text.trim()); } catch (URISyntaxException ex) { DialogProviderManager.getInstance().getDialogProvider().msgError(String.format(BUNDLE.getString("NbUtils.errMsgIllegalURI"), text)); return null; } } else { return null; } } public static boolean msgOkCancel(@Nonnull final String title, @Nonnull final Object component) { return JOptionPane.showConfirmDialog(Main.getApplicationFrame(), component, title, JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE, null) == JOptionPane.OK_OPTION; } @Nullable public static Color extractCommonColorForColorChooserButton(@Nonnull final String colorAttribute, @Nonnull @MustNotContainNull final Topic[] topics) { Color result = null; for (final Topic t : topics) { final Color color = html2color(t.getAttribute(colorAttribute), false); if (result == null) { result = color; } else if (!result.equals(color)) { return ColorChooserButton.DIFF_COLORS; } } return result; } @Nullable public static FileEditPanel.DataContainer editFilePath(@Nonnull final String title, @Nullable final File projectFolder, @Nullable final FileEditPanel.DataContainer data) { final FileEditPanel filePathEditor = new FileEditPanel(projectFolder, data); filePathEditor.doLayout(); filePathEditor.setPreferredSize(new Dimension(450, filePathEditor.getPreferredSize().height)); FileEditPanel.DataContainer result = null; if (DialogProviderManager.getInstance().getDialogProvider().msgOkCancel(title, filePathEditor)) { result = filePathEditor.getData(); if (!result.isValid()) { DialogProviderManager.getInstance().getDialogProvider().msgError(String.format(BUNDLE.getString("MMDGraphEditor.editFileLinkForTopic.errorCantFindFile"), result.getPath())); result = null; } } return result; } @Nullable public static String editText(@Nonnull final String title, @Nonnull final String text) { final NoteEditor textEditor = new NoteEditor(text); try { if (DialogProviderManager.getInstance().getDialogProvider().msgOkCancel(title, textEditor)) { return textEditor.getText(); } else { return null; } } finally { textEditor.dispose(); } } public static void openInSystemViewer(@Nonnull final File file) { final Runnable startEdit = new Runnable() { @Override public void run() { boolean ok = false; if (Desktop.isDesktopSupported()) { final Desktop dsk = Desktop.getDesktop(); if (dsk.isSupported(Desktop.Action.OPEN)) { try { dsk.open(file); ok = true; } catch (Throwable ex) { LOGGER.error("Can't open file in system viewer : " + file, ex);//NOI18N //NOI18N } } } if (!ok) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { DialogProviderManager.getInstance().getDialogProvider().msgError("Can't open file in system viewer! See the log!");//NOI18N Toolkit.getDefaultToolkit().beep(); } }); } } }; final Thread thr = new Thread(startEdit, " MMDStartFileEdit");//NOI18N thr.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { @Override public void uncaughtException(final Thread t, final Throwable e) { LOGGER.error("Detected uncaught exception in openInSystemViewer() for file " + file, e); //NOI18N } }); thr.setDaemon(true); thr.start(); } private static void showURL(@Nonnull final URL url) { showURLExternal(url); } private static void showURLExternal(@Nonnull final URL url) { if (Desktop.isDesktopSupported()) { final Desktop desktop = Desktop.getDesktop(); if (desktop.isSupported(Desktop.Action.BROWSE)) { try { desktop.browse(url.toURI()); } catch (Exception x) { LOGGER.error("Can't browse URL in Desktop", x); //NOI18N } } else if (SystemUtils.IS_OS_LINUX) { final Runtime runtime = Runtime.getRuntime(); try { runtime.exec("xdg-open " + url); //NOI18N } catch (IOException e) { LOGGER.error("Can't browse URL under Linux", e); //NOI18N } } else if (SystemUtils.IS_OS_MAC) { final Runtime runtime = Runtime.getRuntime(); try { runtime.exec("open " + url); //NOI18N } catch (IOException e) { LOGGER.error("Can't browse URL on MAC", e); //NOI18N } } } } public static boolean browseURI(@Nonnull final URI uri, final boolean preferInsideBrowserIfPossible) { try { if (preferInsideBrowserIfPossible) { showURL(uri.toURL()); } else { showURLExternal(uri.toURL()); } return true; } catch (MalformedURLException ex) { LOGGER.error("MalformedURLException", ex); //NOI18N return false; } } }