/******************************************************************************* * Copyright (c) 2016 Weasis Team and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Nicolas Roduit - initial API and implementation *******************************************************************************/ package org.weasis.core.api.gui.util; import java.awt.Color; import java.awt.Component; import java.awt.Desktop; import java.awt.Dimension; import java.awt.GraphicsEnvironment; import java.awt.Point; import java.awt.Rectangle; import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.io.IOException; import java.net.URISyntaxException; import java.net.URL; import java.text.ParseException; import java.util.Objects; import javax.media.jai.PlanarImage; import javax.swing.AbstractAction; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JFormattedTextField; import javax.swing.JFormattedTextField.AbstractFormatterFactory; import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPopupMenu; import javax.swing.JSlider; import javax.swing.JSpinner; import javax.swing.JTable; import javax.swing.JTextPane; import javax.swing.KeyStroke; import javax.swing.ListSelectionModel; import javax.swing.SpinnerNumberModel; import javax.swing.SwingConstants; import javax.swing.UIManager; import javax.swing.event.ChangeListener; import javax.swing.event.HyperlinkEvent; import javax.swing.event.HyperlinkListener; import javax.swing.plaf.basic.BasicComboPopup; import javax.swing.table.TableColumn; import javax.swing.table.TableModel; import javax.swing.text.DefaultFormatterFactory; import javax.swing.text.Style; import javax.swing.text.StyleConstants; import javax.swing.text.StyledDocument; import javax.swing.text.html.HTMLEditorKit; import javax.swing.text.html.StyleSheet; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.weasis.core.api.Messages; import org.weasis.core.api.util.StringUtil; /** * The Class JMVUtils. */ public class JMVUtils { private static final Logger LOGGER = LoggerFactory.getLogger(JMVUtils.class); public static final Color TREE_BACKROUND = (Color) javax.swing.UIManager.get("Tree.background"); //$NON-NLS-1$ public static final Color TREE_SELECTION_BACKROUND = (Color) javax.swing.UIManager.get("Tree.selectionBackground"); //$NON-NLS-1$ private JMVUtils() { super(); } public static boolean getNULLtoFalse(Object val) { return Boolean.TRUE.equals(val); } public static boolean getNULLtoTrue(Object val) { if (val instanceof Boolean) { return ((Boolean) val).booleanValue(); } return true; } public static int getNumberOfInvolvedTiles(PlanarImage img, Rectangle bound) { int maxTileIndexX = img.getMinTileX() + img.getNumXTiles(); int maxTileIndexY = img.getMinTileY() + img.getNumYTiles(); int nbTiles = 0; // Loop over tiles within the clipping region for (int tj = img.getMinTileY(); tj < maxTileIndexY; tj++) { for (int ti = img.getMinTileX(); ti < maxTileIndexX; ti++) { if (bound == null || bound.intersects(img.getTileRect(ti, tj))) { nbTiles++; } } } return nbTiles; } public static int getNumberOfInvolvedTilesOnXaxis(PlanarImage img, Rectangle area) { int maxTileIndexX = img.getMinTileX() + img.getNumXTiles(); int nbTiles = 0; Rectangle bound = area.getBounds(); bound.y = img.tileYToY(img.getMinTileY()); // Loop over tiles within the clipping region for (int ti = img.getMinTileX(), tj = img.getMinTileY(); ti < maxTileIndexX; ti++) { if (bound.intersects(img.getTileRect(ti, tj))) { nbTiles++; } } return nbTiles; } public static void setPreferredWidth(JComponent component, int width, int minWidth) { Dimension dim = component.getPreferredSize(); dim.width = width; component.setPreferredSize(dim); dim = component.getMinimumSize(); dim.width = minWidth; component.setMinimumSize(dim); } public static void setPreferredWidth(JComponent component, int width) { setPreferredWidth(component, width, 50); } public static void setPreferredHeight(JComponent component, int height) { Dimension dim = component.getPreferredSize(); dim.height = height; component.setPreferredSize(dim); dim = component.getMinimumSize(); dim.height = 50; component.setMinimumSize(dim); } public static void showCenterScreen(Window window) { try { Rectangle bound = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice() .getDefaultConfiguration().getBounds(); window.setLocation(bound.x + (bound.width - window.getWidth()) / 2, bound.y + (bound.height - window.getHeight()) / 2); } catch (Exception e) { LOGGER.error("Cannot center the window to the screen", e); //$NON-NLS-1$ } window.setVisible(true); } public static void showCenterScreen(Window window, Component parent) { if (parent == null) { showCenterScreen(window); } else { Dimension sSize = parent.getSize(); Dimension wSize = window.getSize(); Point p = parent.getLocationOnScreen(); window.setLocation(p.x + ((sSize.width - wSize.width) / 2), p.y + ((sSize.height - wSize.height) / 2)); window.setVisible(true); } } public static void formatTableHeaders(JTable table, int alignement) { TableHeaderRenderer renderer = new TableHeaderRenderer(); renderer.setHorizontalAlignment(alignement); for (int i = 0; i < table.getColumnCount(); i++) { TableColumn col = table.getColumnModel().getColumn(i); col.setHeaderRenderer(renderer); } } public static void formatTableHeaders(JTable table, int alignement, int columnSize) { TableHeaderRenderer renderer = new TableHeaderRenderer(); renderer.setHorizontalAlignment(alignement); for (int i = 0; i < table.getColumnCount(); i++) { TableColumn col = table.getColumnModel().getColumn(i); col.setHeaderRenderer(renderer); col.setPreferredWidth(columnSize); } } public static String[] getColumnNames(TableModel model) { if (model == null) { return new String[0]; } String[] names = new String[model.getColumnCount()]; for (int i = 0; i < names.length; i++) { names[i] = model.getColumnName(i); } return names; } public static void addChangeListener(JSlider slider, ChangeListener listener) { ChangeListener[] listeners = slider.getChangeListeners(); for (int i = 0; i < listeners.length; i++) { if (listener == listeners[i]) { return; } } slider.addChangeListener(listener); } private static void addCheckActionToJFormattedTextField(final JFormattedTextField textField) { textField.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "check"); //$NON-NLS-1$ textField.getActionMap().put("check", new AbstractAction() { //$NON-NLS-1$ @Override public void actionPerformed(ActionEvent e) { try { textField.commitEdit(); // so use it. textField.postActionEvent(); // stop editing //for DefaultCellEditor } catch (java.text.ParseException pe) { LOGGER.error("Exception when commit value in {}", textField.getClass().getName(), pe); //$NON-NLS-1$ } textField.setValue(textField.getValue()); } }); } public static void addCheckAction(final JFormattedTextField textField) { textField.setHorizontalAlignment(SwingConstants.RIGHT); addCheckActionToJFormattedTextField(textField); } public static void setNumberModel(JSpinner spin, int val, int min, int max, int delta) { spin.setModel(new SpinnerNumberModel(val < min ? min : val > max ? max : val, min, max, delta)); final JFormattedTextField ftf = ((JSpinner.DefaultEditor) spin.getEditor()).getTextField(); addCheckActionToJFormattedTextField(ftf); } public static void formatCheckAction(JSpinner spin) { final JFormattedTextField ftf = ((JSpinner.DefaultEditor) spin.getEditor()).getTextField(); addCheckActionToJFormattedTextField(ftf); } public static Number getFormattedValue(JFormattedTextField textField) { AbstractFormatterFactory formatter = textField.getFormatterFactory(); if (formatter instanceof DefaultFormatterFactory && textField.getFormatter().equals(((DefaultFormatterFactory) formatter).getEditFormatter())) { try { // to be sure that the value is commit (by default it is when the JFormattedTextField losing the focus) textField.commitEdit(); } catch (ParseException pe) { LOGGER.error("Exception when commit value in {}", textField.getClass().getName(), pe); //$NON-NLS-1$ } } Number val = null; try { val = (Number) textField.getValue(); } catch (Exception e) { LOGGER.error("Cannot get number form textField", e); //$NON-NLS-1$ } return val; } // A convenience method for creating menu items public static JMenuItem menuItem(String label, ActionListener listener, String command, int mnemonic, int acceleratorKey) { JMenuItem item = new JMenuItem(label); item.addActionListener(listener); item.setActionCommand(command); if (mnemonic != 0) { item.setMnemonic((char) mnemonic); } if (acceleratorKey != 0) { item.setAccelerator(KeyStroke.getKeyStroke(acceleratorKey, java.awt.Event.CTRL_MASK)); } return item; } public static Dimension getSmallIconButtonSize() { String look = UIManager.getLookAndFeel().getName(); if ("CDE/Motif".equalsIgnoreCase(look)) { //$NON-NLS-1$ return new Dimension(38, 34); } else if (look.startsWith("GTK")) { //$NON-NLS-1$ return new Dimension(28, 28); } else { return new Dimension(22, 22); } } public static Dimension getBigIconButtonSize() { String look = UIManager.getLookAndFeel().getName(); if ("CDE/Motif".equalsIgnoreCase(look)) { //$NON-NLS-1$ return new Dimension(46, 42); } else if ("Mac OS X Aqua".equalsIgnoreCase(look) || look.startsWith("GTK")) { //$NON-NLS-1$ //$NON-NLS-2$ return new Dimension(36, 36); } else { return new Dimension(34, 34); } } public static Dimension getBigIconToogleButtonSize() { String look = UIManager.getLookAndFeel().getName(); if ("Mac OS X Aqua".equalsIgnoreCase(look) || look.startsWith("GTK")) { //$NON-NLS-1$ //$NON-NLS-2$ return new Dimension(36, 36); } else { return new Dimension(30, 30); } } public static HTMLEditorKit buildHTMLEditorKit(JComponent component) { Objects.requireNonNull(component); HTMLEditorKit kit = new HTMLEditorKit(); StyleSheet ss = kit.getStyleSheet(); ss.addRule("body {font-family:sans-serif;font-size:12pt;background-color:#" //$NON-NLS-1$ + Integer.toHexString((component.getBackground().getRGB() & 0xffffff) | 0x1000000).substring(1) + ";color:#" //$NON-NLS-1$ + Integer.toHexString((component.getForeground().getRGB() & 0xffffff) | 0x1000000).substring(1) + ";margin:3;font-weight:normal;}"); //$NON-NLS-1$ return kit; } public static void addStylesToHTML(StyledDocument doc) { // Initialize some styles. Style regular = doc.getStyle("default"); //$NON-NLS-1$; Style s = doc.addStyle("title", regular); //$NON-NLS-1$ StyleConstants.setFontSize(s, 16); StyleConstants.setBold(s, true); s = doc.addStyle("bold", regular); //$NON-NLS-1$ StyleConstants.setBold(s, true); StyleConstants.setFontSize(s, 12); s = doc.addStyle("small", regular); //$NON-NLS-1$ StyleConstants.setFontSize(s, 10); s = doc.addStyle("large", regular); //$NON-NLS-1$ StyleConstants.setFontSize(s, 14); s = doc.addStyle("italic", regular); //$NON-NLS-1$ StyleConstants.setFontSize(s, 12); StyleConstants.setItalic(s, true); } public static int getMaxLength(Rectangle bounds) { if (bounds.width < bounds.height) { return bounds.height; } return bounds.width; } public static void addTooltipToComboList(final JComboBox<?> combo) { Object comp = combo.getUI().getAccessibleChild(combo, 0); if (comp instanceof BasicComboPopup) { final BasicComboPopup popup = (BasicComboPopup) comp; popup.getList().getSelectionModel().addListSelectionListener(e -> { if (!e.getValueIsAdjusting()) { ListSelectionModel model = (ListSelectionModel) e.getSource(); int first = model.getMinSelectionIndex(); if (first >= 0) { Object item = combo.getItemAt(first); ((JComponent) combo.getRenderer()).setToolTipText(item.toString()); } } }); } } public static void openInDefaultBrowser(Component parent, URL url) { if (url != null) { if (AppProperties.OPERATING_SYSTEM.startsWith("linux")) { //$NON-NLS-1$ try { String cmd = String.format("xdg-open %s", url); //$NON-NLS-1$ Runtime.getRuntime().exec(cmd); } catch (IOException e) { LOGGER.error("Cannot open URL to the system browser", e); //$NON-NLS-1$ } } else if (Desktop.isDesktopSupported()) { final Desktop desktop = Desktop.getDesktop(); if (desktop.isSupported(Desktop.Action.BROWSE)) { try { desktop.browse(url.toURI()); } catch (IOException | URISyntaxException e) { LOGGER.error("Cannot open URL to the desktop browser", e); //$NON-NLS-1$ } } } else { JOptionPane.showMessageDialog(parent, Messages.getString("JMVUtils.browser") + StringUtil.COLON_AND_SPACE + url, //$NON-NLS-1$ Messages.getString("JMVUtils.error"), //$NON-NLS-1$ JOptionPane.ERROR_MESSAGE); } } } public static HyperlinkListener buildHyperlinkListener() { return e -> { JTextPane pane = (JTextPane) e.getSource(); if (e.getEventType() == HyperlinkEvent.EventType.ENTERED) { pane.setToolTipText(e.getDescription()); } else if (e.getEventType() == HyperlinkEvent.EventType.EXITED) { pane.setToolTipText(null); } else if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { Component parent = e.getSource() instanceof Component ? (Component) e.getSource() : null; openInDefaultBrowser(parent, e.getURL()); } }; } public static void addItemToMenu(JMenu menu, JMenuItem item) { if (menu != null && item != null) { menu.add(item); } } public static void addItemToMenu(JPopupMenu menu, Component item) { if (menu != null && item != null) { menu.add(item); } } public static Color getComplementaryColor(Color color) { float[] c = new float[3]; Color.RGBtoHSB(color.getRed(), color.getGreen(), color.getBlue(), c); return Color.getHSBColor(c[0] + 0.5F, c[1], c[2]); } public static String getValueRGBasText(Color color) { if (color == null) { return ""; //$NON-NLS-1$ } return "red = " + color.getRed() + ", green = " + color.getGreen() + ", blue = " + color.getBlue(); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } public static String getValueRGBasText2(Color color) { if (color == null) { return ""; //$NON-NLS-1$ } return color.getRed() + ":" + color.getGreen() + ":" + color.getBlue(); //$NON-NLS-1$ //$NON-NLS-2$ } }