How do I override JTextPane's selection behavior when Swing D&D is disabled?

476 views Asked by At

Background: I am using custom AWT D&D in my (heavily) customized JTextPane subclass. In other words, I have disabled Swing's D&D with pane.setDragEnabled(false) and I use my own DragSource, DragGestureListener, etc.

The problem: The default selection behavior in JTextPane when Swing's D&D is disabled is as follows:

  1. Select some text using the mouse
  2. Mouse press inside the selection with the intent of starting a drag

Desired: selection is not lost. Actual: upon mouse press, selection is immediately lost, giving no opportunity for me to start my drag operation since there is now nothing to drag.

I have partially traced this back to BasicTextUI$DragListener, since this is the class that calls the pane's getDragEnabled() method, but BasicTestUI doesn't seems to do much with the text component's selection. So, I'm still not exactly where the selection is being cleared, but I need to find it so I can eliminate the behavior.

I have employed a hack that involves setting a persistent highlight from a carat listener, so even though the selection is lost a highlight will remain that my drag can interact with. I am not happy with this and it has other side effects.

Many thanks for any pointers.

1

There are 1 answers

0
BrianY On

After many more hours of reviewing JDK source, I've determined that the selection behavior is controlled by the Caret and not anything in the text component or UI hierarchy.

A mildly customized Caret seems to do the trick. Note that if you don't override mouseDragged(), the custom drag will still work but the selection will typically be altered in the pane after the drag starts, making the user think they're only dragging part of the text they selected.

              textPane.setCaret(new DefaultCaret() {
                @Override
                public void mousePressed(MouseEvent evt) {
                    int pos = textPane.viewToModel(evt.getPoint());
                    if (pos > textPane.getSelectionStart() && pos < textPane.getSelectionEnd()) {
                        return;
                    }
                    super.mousePressed(evt);
                }

                @Override
                public void mouseDragged(MouseEvent e) {
                    if (dragItem != null) return;
                    super.mouseDragged(e);
                }
            });