/* * WPCleaner: A tool to help on Wikipedia maintenance tasks. * Copyright (C) 2013 Nicolas Vervelle * * See README.txt file for licensing information. */ package org.wikipediacleaner.gui.swing.basic; import java.awt.Component; import java.awt.Toolkit; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.util.Arrays; import java.util.List; import javax.swing.AbstractButton; import javax.swing.ImageIcon; import javax.swing.InputMap; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JCheckBoxMenuItem; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JRadioButton; import javax.swing.JTable; import javax.swing.JTextField; import javax.swing.JToggleButton; import javax.swing.KeyStroke; import javax.swing.SwingUtilities; import javax.swing.table.TableModel; import javax.swing.text.JTextComponent; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.wikipediacleaner.Version; import org.wikipediacleaner.api.APIException; import org.wikipediacleaner.api.constants.EnumWikipedia; import org.wikipediacleaner.gui.swing.action.ActionClick; import org.wikipediacleaner.i18n.GT; import org.wikipediacleaner.images.EnumImageSize; import org.wikipediacleaner.utils.Configuration; import org.wikipediacleaner.utils.ConfigurationValueBoolean; import org.wikipediacleaner.utils.ConfigurationValueShortcut; import org.wikipediacleaner.utils.StringChecker; import org.wikipediacleaner.utils.ConfigurationValueShortcut.ShortcutProperties; /** * Utilities for the Swing GUI. */ public class Utilities { private static Log log = LogFactory.getLog(Utilities.class); public final static int YES_ALL_OPTION = 101; public final static int NO_ALL_OPTION = 102; private final static String URL_CONFIGURATION_HELP = "http://en.wikipedia.org/wiki/Wikipedia:WPCleaner/Configuration/Help"; // ========================================================================== // Manage event thread // ========================================================================== /** * Utility method to run a task in the event dispatch thread. * * @param doRun Task to be run. */ public static void runInEventDispatchThread(Runnable doRun) { if (doRun == null) { return; } if (SwingUtilities.isEventDispatchThread()) { doRun.run(); } else { try { SwingUtilities.invokeAndWait(doRun); } catch (InvocationTargetException | InterruptedException e) { log.error("Error waiting for execution on event dispatch thread", e); } } } // ========================================================================== // Display message box // ========================================================================== /** * Display an error message. * * @param parent Parent component. * @param exception Exception. */ public static void displayError( Component parent, Throwable exception) { if ((exception != null) && !(exception instanceof APIException)) { exception.printStackTrace(); } if (exception != null) { if (exception instanceof APIException) { displayMessage( parent, GT._("An error occurred: {0}", exception.getMessage()), null, JOptionPane.ERROR_MESSAGE); } else { displayMessage( parent, GT._("An error occurred: {0}", exception.getMessage() + " - " + exception.getClass().getName()), null, JOptionPane.ERROR_MESSAGE); } } else { displayMessage( parent, GT._("An unknown error occurred"), null, JOptionPane.ERROR_MESSAGE); } } /** * Display an error message. * * @param parent Parent component. * @param message Message. */ public static void displayError( Component parent, String message) { displayMessage(parent, message, null, JOptionPane.ERROR_MESSAGE); } /** * Display an error message. * * @param parent Parent component. * @param message Message. * @param focus Component to give focus to. */ public static void displayError(Component parent, String message, Component focus) { displayMessage(parent, message, focus, JOptionPane.ERROR_MESSAGE); } /** * Display a warning message. * * @param parent Parent component. * @param message Message. */ public static void displayWarning( Component parent, String message) { displayMessage(parent, message, null, JOptionPane.WARNING_MESSAGE); } /** * Display a warning message. * * @param parent Parent component. * @param message Message. * @param focus Component to give focus to. */ public static void displayWarning(Component parent, String message, Component focus) { displayMessage(parent, message, focus, JOptionPane.WARNING_MESSAGE); } /** * Display a message about a missing parameter in configuration. * * @param parent Parent component. * @param parameterName Missing parameter. */ public static void displayMessageForMissingConfiguration(Component parent, String parameterName) { displayMissingConfiguration( parent, GT._("You need to define the ''{0}'' property in WPCleaner configuration.", parameterName)); } /** * Display a message about a missing parameters in configuration. * * @param parent Parent component. * @param parametersName Missing parameters. */ public static void displayMessageForMissingConfiguration(Component parent, List<String> parametersName) { if ((parametersName == null) || (parametersName.isEmpty())) { return; } if (parametersName.size() == 1) { displayWarning(parent, parametersName.get(0)); return; } StringBuilder sb = new StringBuilder(); for (String parameterName : parametersName) { if (sb.length() > 0) { sb.append(", "); } sb.append("'"); sb.append(parameterName); sb.append("'"); } displayMissingConfiguration( parent, GT._("You need to define the {0} properties in WPCleaner configuration.", sb.toString())); } /** * Display a message about missing elements in configuration. * * @param parent Parent component. * @param message Message. */ public static void displayMissingConfiguration(Component parent, String message) { String fullMessage = GT._("This function requires some configuration."); if ((message != null) && (message.trim().length() > 0)) { fullMessage += "\n" + message; } if (Utilities.isDesktopSupported()) { int answer = displayYesNoWarning( parent, fullMessage + "\n" + GT._("Do you want to display help on configuring WPCleaner ?")); if (answer == JOptionPane.YES_OPTION) { Utilities.browseURL(URL_CONFIGURATION_HELP); } } else { displayWarning(parent, message); } } /** * Display a message. * * @param parent Parent component. * @param message Message. * @param focus Component to give focus to. * @param messageType Message type. */ private static void displayMessage( Component parent, String message, Component focus, int messageType) { runInEventDispatchThread( new TaskMessageDialog(parent, message, focus, messageType)); } /** * Display an information message. * * @param parent Parent component. * @param message Message. */ public static void displayInformationMessage(Component parent, String message) { displayMessage(parent, message, null, JOptionPane.INFORMATION_MESSAGE); } /** * Display a message to request a value. * * @param parent Parent component. * @param message Message. * @param value Default value. * @param checker String checker to verify the value. * @return Value provided by the user. */ public static String askForValue( Component parent, String message, String value, StringChecker checker) { String defaultValue = value; while (true) { TaskInputDialog task = new TaskInputDialog( parent, message, null, defaultValue); runInEventDispatchThread(task); Object result = task.getResult(); if (result == null) { return null; } defaultValue = result.toString(); if (checker == null) { return defaultValue; } StringChecker.Result ok = checker.checkString(defaultValue); if (ok == null) { return defaultValue; } if (ok.isOk()) { return ok.getText(); } defaultValue = ok.getText(); String errorMessage = ok.getMessage(); if (message != null) { displayError(parent, errorMessage); } } } /** * Display a message to request a value. * * @param parent Parent component. * @param message Message. * @param possibleValues Possible values. * @param onlyList Restrict selection to the possible values. * @param value Default value. * @param checker String checker to verify the value. * @return Value provided by the user. */ public static String askForValue( Component parent, String message, Object[] possibleValues, boolean onlyList, String value, StringChecker checker) { if ((possibleValues == null) || (possibleValues.length == 0)) { return askForValue(parent, message, value, checker); } String defaultValue = value; String other = GT._("Other..."); Object[] possibles = possibleValues; if (!onlyList) { possibles = Arrays.copyOf(possibleValues, possibleValues.length + 1); possibles[possibles.length - 1] = other; } while (true) { TaskInputDialog task = new TaskInputDialog( parent, message, possibles, defaultValue); runInEventDispatchThread(task); Object result = task.getResult(); if (result == null) { return null; } if (result == other) { return askForValue(parent, message, defaultValue, checker); } defaultValue = result.toString(); if (checker == null) { return defaultValue; } StringChecker.Result ok = checker.checkString(defaultValue); if (ok == null) { return defaultValue; } if (ok.isOk()) { return ok.getText(); } defaultValue = ok.getText(); String errorMessage = ok.getMessage(); if (message != null) { displayError(parent, errorMessage); } } } /** * Display a message to request a value. * * @param parent Parent component. * @param message Message. * @param possibleValues Possible values. * @param value Default value. * @return Value provided by the user. */ public static Object askForValue( Component parent, String message, Object[] possibleValues, Object value) { if ((possibleValues == null) || (possibleValues.length == 0)) { return null; } TaskInputDialog task = new TaskInputDialog( parent, message, possibleValues, value); runInEventDispatchThread(task); return task.getResult(); } /** * Display a question with Yes/No answers. * * @param parent Parent component. * @param message Message. * @return Answer {@link JOptionPane#YES_OPTION} or {@link JOptionPane#NO_OPTION}. */ public static int displayYesNoWarning(Component parent, String message) { TaskConfirmDialog task = new TaskConfirmDialog( parent, message, JOptionPane.YES_NO_OPTION); runInEventDispatchThread(task); return task.getResult(); } /** * Display a question with Yes/No/Cancel answers. * * @param parent Parent component. * @param message Message. * @return Answer {@link JOptionPane#YES_OPTION}, {@link JOptionPane#NO_OPTION} or {@link JOptionPane#CANCEL_OPTION}. */ public static int displayYesNoCancelWarning(Component parent, String message) { TaskConfirmDialog task = new TaskConfirmDialog( parent, message, JOptionPane.YES_NO_CANCEL_OPTION); runInEventDispatchThread(task); return task.getResult(); } /** * Display a question with Yes/Yes all/No/No all answers. * * @param parent Parent component. * @param message Message. * @return Answer {@link JOptionPane#YES_OPTION} or {@link JOptionPane#NO_OPTION} or YES_ALL_OPTION or NO_ALL_OPTION. */ public static int displayYesNoAllWarning(Component parent, String message) { Object[] options = new Object[] { GT._("Yes"), GT._("Yes to all"), GT._("No"), GT._("No to all"), }; JOptionPane pane = new JOptionPane( message, JOptionPane.WARNING_MESSAGE, JOptionPane.YES_NO_OPTION, null, options); JDialog dialog = pane.createDialog(parent, Version.PROGRAM); dialog.setVisible(true); Object selectedValue = pane.getValue(); if (selectedValue == null) { return JOptionPane.CLOSED_OPTION; } if (options[0].equals(selectedValue)) { return JOptionPane.YES_OPTION; } if (options[1].equals(selectedValue)) { return YES_ALL_OPTION; } if (options[2].equals(selectedValue)) { return JOptionPane.NO_OPTION; } if (options[3].equals(selectedValue)) { return NO_ALL_OPTION; } return JOptionPane.CLOSED_OPTION; } /** * Display a question with possible values. * * @param parent Parent component. * @param message Message. * @param values Possible values. * @return Selected value. */ public static int displayQuestion(Component parent, String message, Object[] values) { TaskOptionDialog task = new TaskOptionDialog(parent, message, values); runInEventDispatchThread(task); return task.getResult(); } // ========================================================================== // Shortcut management // ========================================================================== /** * Apply a shortcut to a button. * * @param button Button. * @param shortcut Shortcut. * @param message Related message. */ private static void setShortcut( AbstractButton button, ShortcutProperties shortcut, String message) { if ((shortcut == null) || (shortcut.useMnemonic())) { int mnemonic = getMnemonic(message); if ((mnemonic == -1) && (shortcut != null)) { mnemonic = shortcut.getKey(); } if (mnemonic != -1) { button.setMnemonic(mnemonic); } } else if (shortcut.getEnabled()) { String actionName = "action_" + shortcut.getName(); InputMap inputMap = button.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); inputMap.put(KeyStroke.getKeyStroke(shortcut.getKey(), shortcut.getModifiers()), actionName); button.getActionMap().put(actionName, new ActionClick(button)); if (message != null) { int index = message.indexOf(shortcut.getKey()); if ((index >= 0) && (index < button.getText().length())) { button.setDisplayedMnemonicIndex(index); } } } } /** * @param shortcut Shortcut definition. * @return Shortcut. */ private static ShortcutProperties getShortcut(ConfigurationValueShortcut shortcut) { if (shortcut == null) { return null; } Configuration config = Configuration.getConfiguration(); return config.getShortcut(shortcut); } /** * Return the label to display. * * @param label Label with optional mnemonic (&). * @return Label without optional mnemonic. */ private static String getLabelWithoutMnemonic(String label) { if (label == null) { return null; } int index = label.indexOf('&'); if (index == -1) { return label; } return label.substring(0, index) + ((index < label.length() - 1) ? label.substring(index + 1) : ""); } /** * Return the mnemonic of the label. * * @param label Label with optional mnemonic (&). * @return Mnemonic. */ private static int getMnemonic(String label) { if (label == null) { return 0; } int index = label.indexOf('&'); if ((index == -1) || (index == label.length() - 1)){ return -1; } return label.charAt(index + 1); } // ========================================================================== // Button management // ========================================================================== /** * Create a JButton. * * @param message Label text with optional mnemonic inside. * @param shortcut Shortcut information. * @return Button initialized with text and mnemonic. */ public static JButton createJButton( String message, ConfigurationValueShortcut shortcut) { String label = getLabelWithoutMnemonic(message); JButton button = new JButton(label); ShortcutProperties shortcutP = getShortcut(shortcut); if ((shortcutP != null) && (shortcutP.getEnabled())) { String fullLabel = label + shortcutP.getDescription(); button.setToolTipText(fullLabel); } setShortcut(button, shortcutP, message); return button; } /** * Create a JButton. * * @param iconName Icon name. * @param size Icon size. * @param message Label text with optional mnemonic inside. * @param showMessage Use message for the button text or for tooltip. * @param shortcut Shortcut information. * @return Button initialized with text and mnemonic. */ public static JButton createJButton( String iconName, EnumImageSize size, String message, boolean showMessage, ConfigurationValueShortcut shortcut) { ShortcutProperties shortcutP = getShortcut(shortcut); return createJButton(iconName, size, message, showMessage, shortcutP); } /** * Create a JButton. * * @param iconName Icon name. * @param size Icon size. * @param message Label text with optional mnemonic inside. * @param showMessage Use message for the button text or for tooltip. * @param shortcut Shortcut information. * @return Button initialized with text and mnemonic. */ private static JButton createJButton( String iconName, EnumImageSize size, String message, boolean showMessage, ShortcutProperties shortcut) { ImageIcon icon = getImageIcon(iconName, size); JButton button = null; String label = getLabelWithoutMnemonic(message); String fullLabel = (shortcut != null) ? label + shortcut.getDescription() : label; if (icon != null) { if (showMessage) { button = new JButton(label, icon); } else { button = new JButton(icon); label = null; } } else { button = new JButton(label); } button.setToolTipText(fullLabel); setShortcut(button, shortcut, message); return button; } // ========================================================================== // Toggle Button management // ========================================================================== /** * Create a JToggleButton. * * @param message Label text with optional mnemonic inside. * @return Button initialized with text and mnemonic. */ public static JToggleButton createJToggleButton(String message) { JToggleButton button = new JToggleButton(getLabelWithoutMnemonic(message)); int mnemonic = getMnemonic(message); if (mnemonic != -1) { button.setMnemonic(mnemonic); } return button; } /** * Create a JToggleButton. * * @param iconName Icon name. * @param size Icon size. * @param message Label text with optional mnemonic inside. * @param showMessage Use message for the button text or for tooltip. * @return Button initialized with text and mnemonic. */ public static JToggleButton createJToggleButton( String iconName, EnumImageSize size, String message, boolean showMessage) { ImageIcon icon = getImageIcon(iconName, size); JToggleButton button = null; if (icon != null) { if (showMessage) { button = new JToggleButton(getLabelWithoutMnemonic(message), icon); } else { button = new JToggleButton(icon); button.setToolTipText(getLabelWithoutMnemonic(message)); } } else { button = new JToggleButton(getLabelWithoutMnemonic(message)); } setShortcut(button, null, message); return button; } // ========================================================================== // Check box and radio button management // ========================================================================== /** * Create a JCheckBox. * * @param message Label text with optional mnemonic inside. * @param selected Flag indicating if the check box is selected. * @return Check Box initialized with text and mnemonic. */ public static JCheckBox createJCheckBox(String message, boolean selected) { JCheckBox checkbox = new JCheckBox(getLabelWithoutMnemonic(message), selected); setShortcut(checkbox, null, message); return checkbox; } /** * Create a JRadioButton. * * @param message Label text with optional mnemonic inside. * @param selected Flag indicating if the check box is selected. * @return Check Box initialized with text and mnemonic. */ public static JRadioButton createJRadioButton(String message, boolean selected) { JRadioButton button = new JRadioButton(getLabelWithoutMnemonic(message), selected); setShortcut(button, null, message); return button; } // ========================================================================== // Label management // ========================================================================== /** * Create a JLabel. * * @param message Label text with optional mnemonic inside. * @return Label initialized with text and mnemonic. */ public static JLabel createJLabel(String message) { JLabel label = new JLabel(getLabelWithoutMnemonic(message)); int mnemonic = getMnemonic(message); if (mnemonic != -1) { label.setDisplayedMnemonic(mnemonic); } return label; } // ========================================================================== // Text management // ========================================================================== /** * Create a JTextField. * * @param value Default value. * @param columns Number of columns. * @return JTextField. */ public static JTextField createJTextField(String value, int columns) { JTextField text = new JTextField(value, columns); text.addKeyListener(new CopyPasteListener(text)); return text; } /** * Copy/Paste listener. */ private static class CopyPasteListener implements KeyListener { /** * Text field. */ private final JTextComponent text; /** * @param text Text component. */ public CopyPasteListener(JTextComponent text) { this.text = text; } /** * Listener for KeyTyped events. * * @param e Event. * @see java.awt.event.KeyListener#keyTyped(java.awt.event.KeyEvent) */ @Override public void keyTyped(KeyEvent e) { // } /** * Listener for KeyPressed events. * * @param e Event. * @see java.awt.event.KeyListener#keyPressed(java.awt.event.KeyEvent) */ @Override public void keyPressed(KeyEvent e) { if ((e.getKeyCode() == KeyEvent.VK_V) && ((e.getModifiersEx() & InputEvent.CTRL_DOWN_MASK) != 0)) { Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); Transferable clipData = clipboard.getContents(clipboard); try { String s = (String) clipData.getTransferData(DataFlavor.stringFlavor); int start = text.getSelectionStart(); int end = text.getSelectionEnd(); if (end > start) { text.getDocument().remove(start, end - start); } text.getDocument().insertString(start, s, null); e.consume(); } catch (Exception ex) { // } } } /** * Listener for KeyRelease events. * * @param e Event. * @see java.awt.event.KeyListener#keyReleased(java.awt.event.KeyEvent) */ @Override public void keyReleased(KeyEvent e) { // } } // ========================================================================== // Icon management // ========================================================================== /** * Retrieve an icon. * * @param iconName Icon name. * @param size Icon size. * @return Icon. */ public static ImageIcon getImageIcon(String iconName, EnumImageSize size) { ImageIcon icon = null; if ((iconName != null) && (size != null)) { URL url = Utilities.class.getClassLoader().getResource( "org/wikipediacleaner/images/" + size.getFolder() + "/" + iconName); if (url != null) { icon = new ImageIcon(url); } } return icon; } // ========================================================================== // Menu management // ========================================================================== /** * Create a JMenu. * * @param message Label text with optional mnemonic inside. * @return Menu initialized with text and mnemonic. */ public static JMenu createJMenu(String message) { JMenu menu = new JMenu(getLabelWithoutMnemonic(message)); setShortcut(menu, null, message); return menu; } /** * Create a JMenuItem. * * @param message Label text with optional mnemonic inside. * @param asIs True if the message should be used as is (no mnemonic). * @return Menu item initialized with text and mnemonic. */ public static JMenuItem createJMenuItem(String message, boolean asIs) { JMenuItem menuItem = new JMenuItem(asIs ? message : getLabelWithoutMnemonic(message)); if (!asIs) { setShortcut(menuItem, null, message); } return menuItem; } /** * Create a JCheckBoxMenuItem. * * @param message Label text with optional mnemonic inside. * @param checked Flag indicating if menu item should be checked. * @return Menu item initialized with text and mnemonic. */ public static JCheckBoxMenuItem createJCheckBoxMenuItm(String message, boolean checked) { JCheckBoxMenuItem menuItem = new JCheckBoxMenuItem( getLabelWithoutMnemonic(message), checked); setShortcut(menuItem, null, message); return menuItem; } /* ========================================================================== */ /* Desktop management */ /* ========================================================================== */ /** * @return Flag indicating if desktop is supported. */ public static boolean isDesktopSupported() { try { Class<?> desktop = Class.forName("java.awt.Desktop"); Method method = desktop.getMethod("isDesktopSupported", (Class[]) null); return (Boolean) method.invoke(null, (Object[]) null); } catch (ClassNotFoundException e) { log.debug("ClassNotFoundException: " + e.getMessage()); // Nothing to be done, JVM < 6 } catch (NoSuchMethodException e) { log.error("NoSuchMethodException: " + e.getMessage()); } catch (InvocationTargetException e) { log.error("InvocationTargetException: " + e.getMessage()); } catch (IllegalAccessException e) { log.error("IllegalAccessException: " + e.getMessage()); } catch (ClassCastException e) { log.error("ClassCastException: " + e.getMessage()); } catch (Throwable e) { log.error("Throwable: " + e.getClass().getName() + " - " + e.getMessage()); } return false; } /** * Display an URI in the default browser. * * @param uri URI. */ public static void browseURL(URI uri) { if (isDesktopSupported()) { try { Class<?> desktopClass = Class.forName("java.awt.Desktop"); Method method = desktopClass.getMethod("getDesktop", (Class[]) null); Object desktop = method.invoke(null, (Object[]) null); method = desktopClass.getMethod("browse", new Class[] { URI.class }); method.invoke(desktop, new Object[] { uri }); } catch (ClassNotFoundException e) { log.debug("ClassNotFoundException: " + e.getMessage()); // Nothing to be done, JVM < 6 } catch (NoSuchMethodException e) { log.error("NoSuchMethodException: " + e.getMessage()); } catch (InvocationTargetException e) { log.error("InvocationTargetException: " + e.getMessage()); } catch (IllegalAccessException e) { log.error("IllegalAccessException: " + e.getMessage()); } catch (ClassCastException e) { log.error("ClassCastException: " + e.getMessage()); } catch (Throwable e) { log.error("Throwable: " + e.getClass().getName() + " - " + e.getMessage()); } } } /** * Display an URL in the default browser. * * @param wiki Wiki. * @param title Page title. * @param action Page action. */ public static void browseURL(EnumWikipedia wiki, String title, String action) { Configuration config = Configuration.getConfiguration(); boolean secured = config.getBoolean(null, ConfigurationValueBoolean.SECURE_URL); browseURL(wiki.getSettings().getURL(title, action, secured)); } /** * Display an URL in the default browser. * * @param wiki Wiki. * @param title Page title. * @param redirect Flag indicating if redirects should be followed. */ public static void browseURL(EnumWikipedia wiki, String title, boolean redirect) { Configuration config = Configuration.getConfiguration(); boolean secured = config.getBoolean(null, ConfigurationValueBoolean.SECURE_URL); browseURL(wiki.getSettings().getURL(title, redirect, secured)); } /** * Display an URL in the default browser. * * @param url URL. */ public static void browseURL(String url) { try { browseURL(new URI(url)); } catch (URISyntaxException e) { // Nothing to be done log.error("Error viewing page: " + e.getMessage()); } } /* ========================================================================== */ /* Various utilities */ /* ========================================================================== */ /** * Create a RowSorter for a JTable (work only for JDK 6). * @see JTable#setRowSorter(javax.swing.RowSorter) * * @param table Table. * @param model Table model. */ public static void addRowSorter(JTable table, TableModel model) { try { Class<?> tableRowSorterClass = Class.forName("javax.swing.table.TableRowSorter"); Constructor ctor = tableRowSorterClass.getConstructor(new Class[] { TableModel.class }); Object rowSorter = ctor.newInstance(model); Class rowSorterClass = Class.forName("javax.swing.RowSorter"); Method method = table.getClass().getMethod("setRowSorter", new Class[] { rowSorterClass }); method.invoke(table, new Object[] { rowSorter }); } catch (ClassNotFoundException e) { log.debug("ClassNotFoundException: " + e.getMessage()); // Nothing to be done, JVM < 6 } catch (NoSuchMethodException e) { log.error("NoSuchMethodException: " + e.getMessage()); } catch (InvocationTargetException e) { log.error("InvocationTargetException: " + e.getMessage()); } catch (IllegalAccessException e) { log.error("IllegalAccessException: " + e.getMessage()); } catch (ClassCastException e) { log.error("ClassCastException: " + e.getMessage()); } catch (Throwable e) { log.error("Throwable: " + e.getClass().getName() + " - " + e.getMessage()); } } /** * Convert a table row index to model index (work only for JDK 6). * @see JTable#convertRowIndexToModel(int) * * @param table Table. * @param row Row. * @return Converted row. */ public static int convertRowIndexToModel(JTable table, int row) { try { Method method = table.getClass().getMethod("convertRowIndexToModel", new Class[] { int.class }); Object result = method.invoke(table, new Object[] { row }); row = ((Integer) result).intValue(); } catch (NoSuchMethodException e) { log.debug("NoSuchMethodException: " + e.getMessage()); // Nothing to be done, JVM < 6 } catch (InvocationTargetException e) { log.error("InvocationTargetException: " + e.getMessage()); } catch (IllegalAccessException e) { log.error("IllegalAccessException: " + e.getMessage()); } catch (ClassCastException e) { log.error("ClassCastException: " + e.getMessage()); } catch (Throwable e) { log.error("Throwable: " + e.getClass().getName() + " - " + e.getMessage()); } return row; } }