-
Bug
-
Resolution: Not an Issue
-
P3
-
None
-
8, 9, 10, 11
-
x86_64
-
generic
ADDITIONAL SYSTEM INFORMATION :
Linux 4.8.0-53-generic #56~16.04.1-Ubuntu SMP Tue May 16 01:18:56 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
A DESCRIPTION OF THE PROBLEM :
When mouse is moved over a hyperlink in a JEditorPane component and then leaves both the hyperlink and the component area, javax.swing.event.HyperlinkListener#hyperlinkUpdate is not called for listeners registered on the component.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the attached HyperlinkListenerExample class.
Move the mouse horizontally throughout the text "Move mouse over the link horizontally, then vertically".
Output will contain as expected:
hyperlinkUpdate for url: my-link, eventType: ENTERED
hyperlinkUpdate for url: my-link, eventType: EXITED
Now move the mouse vertically throughout the underlined link (i.e. "link" word).
Actual output:
hyperlinkUpdate for url: my-link, eventType: ENTERED
Expected output:
hyperlinkUpdate for url: my-link, eventType: ENTERED
hyperlinkUpdate for url: my-link, eventType: EXITED
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
When mouse enters a hyperlink and then leaves the hyperlink and the component area, javax.swing.event.HyperlinkListener#hyperlinkUpdate is called with e.getEventType() == "EXITED".
ACTUAL -
No "EXITED" HyperlinkEvent is fired.
---------- BEGIN SOURCE ----------
import javax.swing.*;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
import javax.swing.text.html.HTMLEditorKit;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
public class HyperlinkListenerExample {
private HyperlinkListenerExample() {
}
private JPanel createPanel() {
JPanel panel = new JPanel(new BorderLayout());
panel.add(Box.createVerticalStrut(100), BorderLayout.NORTH);
JEditorPane pane = createPane();
pane.setText("<html><body>Move mouse over the <a href='my-link'>link</a> horizontally, then vertically</body></html>");
panel.add(pane, BorderLayout.CENTER);
panel.add(Box.createVerticalStrut(100), BorderLayout.SOUTH);
return panel;
}
private static JEditorPane createPane() {
JEditorPane textPane = new JEditorPane();
textPane.setEditorKit(new HTMLEditorKit());
textPane.setEditable(false);
textPane.setOpaque(false);
textPane.setFocusable(false);
textPane.setBorder(null);
textPane.addHyperlinkListener(new HyperlinkListener() {
@Override
public void hyperlinkUpdate(HyperlinkEvent e) {
System.out.println("hyperlinkUpdate for url: " + e.getDescription() + ", eventType: " + e.getEventType());
}
});
return textPane;
}
private static void createAndShowGUI() {
JFrame frame = new JFrame("HyperlinkListenerExample");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new HyperlinkListenerExample().createPanel());
frame.pack();
frame.setVisible(true);
frame.setLocationRelativeTo(null);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(HyperlinkListenerExample::createAndShowGUI);
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
As a workaround, it's possible to extend javax.swing.text.html.HTMLEditorKit.LinkController and emulate mouseMoved event when mouse exits the component area:
import javax.swing.*;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
import javax.swing.text.html.HTMLEditorKit;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
public class WorkaroundHyperlinkListenerExample {
private WorkaroundHyperlinkListenerExample() {
}
private JPanel createPanel() {
JPanel panel = new JPanel(new BorderLayout());
panel.add(Box.createVerticalStrut(100), BorderLayout.NORTH);
JEditorPane pane = createPane();
pane.setText("<html><body>Move mouse over the <a href='my-link'>link</a> horizontally, then vertically</body></html>");
panel.add(pane, BorderLayout.CENTER);
panel.add(Box.createVerticalStrut(100), BorderLayout.SOUTH);
return panel;
}
private static JEditorPane createPane() {
JEditorPane textPane = new JEditorPane();
textPane.setEditorKit(new MyHTMLEditorKit());
textPane.setEditable(false);
textPane.setOpaque(false);
textPane.setFocusable(false);
textPane.setBorder(null);
textPane.addHyperlinkListener(new HyperlinkListener() {
@Override
public void hyperlinkUpdate(HyperlinkEvent e) {
System.out.println("hyperlinkUpdate for url: " + e.getDescription() + ", eventType: " + e.getEventType());
}
});
return textPane;
}
private static void createAndShowGUI() {
JFrame frame = new JFrame("WorkaroundHyperlinkListenerExample");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new WorkaroundHyperlinkListenerExample().createPanel());
frame.pack();
frame.setVisible(true);
frame.setLocationRelativeTo(null);
}
public static class MyHTMLEditorKit extends HTMLEditorKit {
public void install(JEditorPane c) {
MouseListener[] oldMouseListeners = c.getMouseListeners();
MouseMotionListener[] oldMouseMotionListeners = c.getMouseMotionListeners();
super.install(c);
for (MouseListener l : c.getMouseListeners()) {
c.removeMouseListener(l);
}
for (MouseListener l : oldMouseListeners) {
c.addMouseListener(l);
}
for (MouseMotionListener l : c.getMouseMotionListeners()) {
c.removeMouseMotionListener(l);
}
for (MouseMotionListener l : oldMouseMotionListeners) {
c.addMouseMotionListener(l);
}
MyHTMLEditorKit.MyLinkController handler = new MyHTMLEditorKit.MyLinkController();
c.addMouseListener(handler);
c.addMouseMotionListener(handler);
}
public class MyLinkController extends LinkController {
@Override
public void mouseExited(MouseEvent e) {
mouseMoved(new MouseEvent(e.getComponent(), e.getID(), e.getWhen(), e.getModifiersEx(), -1, -1, e.getClickCount(), e.isPopupTrigger(), e.getButton()));
}
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(WorkaroundHyperlinkListenerExample::createAndShowGUI);
}
}
FREQUENCY : always
Linux 4.8.0-53-generic #56~16.04.1-Ubuntu SMP Tue May 16 01:18:56 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
A DESCRIPTION OF THE PROBLEM :
When mouse is moved over a hyperlink in a JEditorPane component and then leaves both the hyperlink and the component area, javax.swing.event.HyperlinkListener#hyperlinkUpdate is not called for listeners registered on the component.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the attached HyperlinkListenerExample class.
Move the mouse horizontally throughout the text "Move mouse over the link horizontally, then vertically".
Output will contain as expected:
hyperlinkUpdate for url: my-link, eventType: ENTERED
hyperlinkUpdate for url: my-link, eventType: EXITED
Now move the mouse vertically throughout the underlined link (i.e. "link" word).
Actual output:
hyperlinkUpdate for url: my-link, eventType: ENTERED
Expected output:
hyperlinkUpdate for url: my-link, eventType: ENTERED
hyperlinkUpdate for url: my-link, eventType: EXITED
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
When mouse enters a hyperlink and then leaves the hyperlink and the component area, javax.swing.event.HyperlinkListener#hyperlinkUpdate is called with e.getEventType() == "EXITED".
ACTUAL -
No "EXITED" HyperlinkEvent is fired.
---------- BEGIN SOURCE ----------
import javax.swing.*;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
import javax.swing.text.html.HTMLEditorKit;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
public class HyperlinkListenerExample {
private HyperlinkListenerExample() {
}
private JPanel createPanel() {
JPanel panel = new JPanel(new BorderLayout());
panel.add(Box.createVerticalStrut(100), BorderLayout.NORTH);
JEditorPane pane = createPane();
pane.setText("<html><body>Move mouse over the <a href='my-link'>link</a> horizontally, then vertically</body></html>");
panel.add(pane, BorderLayout.CENTER);
panel.add(Box.createVerticalStrut(100), BorderLayout.SOUTH);
return panel;
}
private static JEditorPane createPane() {
JEditorPane textPane = new JEditorPane();
textPane.setEditorKit(new HTMLEditorKit());
textPane.setEditable(false);
textPane.setOpaque(false);
textPane.setFocusable(false);
textPane.setBorder(null);
textPane.addHyperlinkListener(new HyperlinkListener() {
@Override
public void hyperlinkUpdate(HyperlinkEvent e) {
System.out.println("hyperlinkUpdate for url: " + e.getDescription() + ", eventType: " + e.getEventType());
}
});
return textPane;
}
private static void createAndShowGUI() {
JFrame frame = new JFrame("HyperlinkListenerExample");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new HyperlinkListenerExample().createPanel());
frame.pack();
frame.setVisible(true);
frame.setLocationRelativeTo(null);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(HyperlinkListenerExample::createAndShowGUI);
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
As a workaround, it's possible to extend javax.swing.text.html.HTMLEditorKit.LinkController and emulate mouseMoved event when mouse exits the component area:
import javax.swing.*;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
import javax.swing.text.html.HTMLEditorKit;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
public class WorkaroundHyperlinkListenerExample {
private WorkaroundHyperlinkListenerExample() {
}
private JPanel createPanel() {
JPanel panel = new JPanel(new BorderLayout());
panel.add(Box.createVerticalStrut(100), BorderLayout.NORTH);
JEditorPane pane = createPane();
pane.setText("<html><body>Move mouse over the <a href='my-link'>link</a> horizontally, then vertically</body></html>");
panel.add(pane, BorderLayout.CENTER);
panel.add(Box.createVerticalStrut(100), BorderLayout.SOUTH);
return panel;
}
private static JEditorPane createPane() {
JEditorPane textPane = new JEditorPane();
textPane.setEditorKit(new MyHTMLEditorKit());
textPane.setEditable(false);
textPane.setOpaque(false);
textPane.setFocusable(false);
textPane.setBorder(null);
textPane.addHyperlinkListener(new HyperlinkListener() {
@Override
public void hyperlinkUpdate(HyperlinkEvent e) {
System.out.println("hyperlinkUpdate for url: " + e.getDescription() + ", eventType: " + e.getEventType());
}
});
return textPane;
}
private static void createAndShowGUI() {
JFrame frame = new JFrame("WorkaroundHyperlinkListenerExample");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new WorkaroundHyperlinkListenerExample().createPanel());
frame.pack();
frame.setVisible(true);
frame.setLocationRelativeTo(null);
}
public static class MyHTMLEditorKit extends HTMLEditorKit {
public void install(JEditorPane c) {
MouseListener[] oldMouseListeners = c.getMouseListeners();
MouseMotionListener[] oldMouseMotionListeners = c.getMouseMotionListeners();
super.install(c);
for (MouseListener l : c.getMouseListeners()) {
c.removeMouseListener(l);
}
for (MouseListener l : oldMouseListeners) {
c.addMouseListener(l);
}
for (MouseMotionListener l : c.getMouseMotionListeners()) {
c.removeMouseMotionListener(l);
}
for (MouseMotionListener l : oldMouseMotionListeners) {
c.addMouseMotionListener(l);
}
MyHTMLEditorKit.MyLinkController handler = new MyHTMLEditorKit.MyLinkController();
c.addMouseListener(handler);
c.addMouseMotionListener(handler);
}
public class MyLinkController extends LinkController {
@Override
public void mouseExited(MouseEvent e) {
mouseMoved(new MouseEvent(e.getComponent(), e.getID(), e.getWhen(), e.getModifiersEx(), -1, -1, e.getClickCount(), e.isPopupTrigger(), e.getButton()));
}
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(WorkaroundHyperlinkListenerExample::createAndShowGUI);
}
}
FREQUENCY : always