Stanislav
Stanislav

Reputation: 425

Drag and drop styled text to another JTextPane

Good day to everyone!

I'm working on text editor with styles support. And in the application there will be several text editors. I think it will be a good idea to allow drag styled text from one JTextPane to another. Looks like JTextPane supports dragging of text with styles within itself. You can launch the code below to check it. But when I drag styled text to another JTextPane, the text being inserted is PLAIN. :( I watched through source codes and found one interesting class - TextTransferHandler. After debugging it became obvious this TextTransferHandler handles drag and drop. As I see in its code it supports dragging of styled text by converting the text to RTF or HTML. I tried this:

_tp.setEditorKit(new RTFEditorKit());

but without success.

Am I'm missing something?

The code:

package apps.editor;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.ResourceBundle;

import javax.swing.Action;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.JTextPane;
import javax.swing.JToolBar;
import javax.swing.KeyStroke;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import javax.swing.text.DefaultEditorKit;
import javax.swing.text.DefaultStyledDocument;
import javax.swing.text.JTextComponent;
import javax.swing.text.Keymap;
import javax.swing.text.rtf.RTFEditorKit;

class EditorUtil2 {
    Action[] _actions;
    HashMap<String, Action> _actionHashMap = new HashMap<String, Action>();
    ResourceBundle _resourceBundle = BundleFactory.getBundle();
    JTextPane _initTextPane;
    Keymap _keymap;
    JPopupMenu _popupMenu; 
    ArrayList<JTextPane> _editors = new ArrayList<JTextPane>();

    public EditorUtil2() {
        _initTextPane = new JTextPane();
        hashDefaultActions();
        makeActionsPretty();
        makeKeymap();
        createPopupMenu();
    }

    private String getProperty(String key) {
        return _resourceBundle.getString(key);
    }

    private void hashDefaultActions() {
        _actions = _initTextPane.getActions();
        String name = null;
        for (int i=0; i<_actions.length; i++) {
            name = (String)_actions[i].getValue( Action.NAME );
            _actionHashMap.put( name, _actions[i] );
        }
    }    

    private Action getHashedAction(String name) {
        return (Action)_actionHashMap.get( name );
    }

    private void makeActionsPretty() {
        Action a;
        a = getHashedAction( DefaultEditorKit.cutAction );
        a.putValue( Action.SMALL_ICON, loadImage( getProperty("Toolbar.Icons.cut") ) );
        a.putValue( Action.NAME, getProperty("Toolbar.cut") );

        a = getHashedAction( DefaultEditorKit.copyAction );
        a.putValue( Action.SMALL_ICON, loadImage( getProperty("Toolbar.Icons.copy") ) );
        a.putValue( Action.NAME, getProperty("Toolbar.copy") );

        a = getHashedAction( DefaultEditorKit.pasteAction );
        a.putValue( Action.SMALL_ICON, loadImage( getProperty("Toolbar.Icons.paste") ) );
        a.putValue( Action.NAME, getProperty("Toolbar.paste") );

        a = getHashedAction("font-bold");
        a.putValue( Action.SMALL_ICON, loadImage( getProperty("Toolbar.Icons.bold") ) );
        a.putValue( Action.NAME, getProperty("Toolbar.bold") );

        a = getHashedAction("font-italic");
        a.putValue( Action.SMALL_ICON, loadImage( getProperty("Toolbar.Icons.italic") ) );
        a.putValue( Action.NAME, getProperty("Toolbar.italic") );

        a = getHashedAction("font-underline");
        a.putValue( Action.SMALL_ICON, loadImage( getProperty("Toolbar.Icons.underline") ) );
        a.putValue( Action.NAME, getProperty("Toolbar.underline") );
    }    

    private void makeKeymap() {
        _keymap = JTextComponent.addKeymap( "NewKeymap", _initTextPane.getKeymap() );

        //KeyStroke next       = KeyStroke.getKeyStroke( KeyEvent.VK_RIGHT, InputEvent.CTRL_MASK, false);
        //KeyStroke prev       = KeyStroke.getKeyStroke( KeyEvent.VK_LEFT, InputEvent.CTRL_MASK, false);
        //KeyStroke selectNext = KeyStroke.getKeyStroke( KeyEvent.VK_RIGHT, InputEvent.CTRL_MASK | InputEvent.SHIFT_MASK, false);
        //KeyStroke selectPrev = KeyStroke.getKeyStroke( KeyEvent.VK_LEFT, InputEvent.CTRL_MASK | InputEvent.SHIFT_MASK, false);
        KeyStroke cut        = KeyStroke.getKeyStroke( KeyEvent.VK_X, InputEvent.CTRL_MASK, false);
        KeyStroke copy       = KeyStroke.getKeyStroke( KeyEvent.VK_C, InputEvent.CTRL_MASK, false);
        KeyStroke paste      = KeyStroke.getKeyStroke( KeyEvent.VK_V, InputEvent.CTRL_MASK, false);
        KeyStroke bold       = KeyStroke.getKeyStroke( KeyEvent.VK_B, InputEvent.CTRL_MASK, false);
        KeyStroke italic     = KeyStroke.getKeyStroke( KeyEvent.VK_I, InputEvent.CTRL_MASK, false);
        KeyStroke underline  = KeyStroke.getKeyStroke( KeyEvent.VK_U, InputEvent.CTRL_MASK, false);

        //_keymap.addActionForKeyStroke( next, getHashedAction( DefaultEditorKit.nextWordAction ) );
        //_keymap.addActionForKeyStroke( prev, getHashedAction( DefaultEditorKit.previousWordAction ) );
        //_keymap.addActionForKeyStroke( selectNext, getHashedAction( DefaultEditorKit.selectionNextWordAction ) );
        //_keymap.addActionForKeyStroke( selectPrev, getHashedAction( DefaultEditorKit.selectionPreviousWordAction ) );
        _keymap.addActionForKeyStroke( cut, getHashedAction( DefaultEditorKit.cutAction) );
        _keymap.addActionForKeyStroke( copy, getHashedAction( DefaultEditorKit.copyAction ) );
        _keymap.addActionForKeyStroke( paste, getHashedAction( DefaultEditorKit.pasteAction ) );
        _keymap.addActionForKeyStroke( bold, getHashedAction( "font-bold" ) );
        _keymap.addActionForKeyStroke( italic, getHashedAction( "font-italic" ) );
        _keymap.addActionForKeyStroke( underline, getHashedAction( "font-underline" ) );
    }

    private ImageIcon loadImage(String path) {
        URL imageURL = this.getClass().getResource( path );
        return new ImageIcon( imageURL );
    }

    private void createPopupMenu() {
        _popupMenu = new JPopupMenu();

        ArrayList<Action> actions = new ArrayList<Action>();
        actions.add( getHashedAction( DefaultEditorKit.cutAction ) );
        actions.add( getHashedAction( DefaultEditorKit.copyAction ) );
        actions.add( getHashedAction( DefaultEditorKit.pasteAction ) );

        JMenuItem mi = null;
        for (Action a : actions) {
            mi = new JMenuItem();
            mi.setAction(a);
            mi.setAccelerator(_keymap.getKeyStrokesForAction( a )[0] );
            _popupMenu.add(mi);
        }

        _popupMenu.addPopupMenuListener(new PopupMenuListener() {

            @Override
            public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
                System.out.println("will be visible");

            }

            @Override
            public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
                System.out.println("will be invisible");
                System.out.println("stop freeze");
                JTextPane tp = (JTextPane)_popupMenu.getInvoker();
                tp.getCaret().setBlinkRate(500);
                tp.getCaret().setVisible(false);
                //_popupOpened = false;
                tp.repaint();
                //tp.requestFocus();                
            }

            @Override
            public void popupMenuCanceled(PopupMenuEvent e) {
                System.out.println("menu canceled");
            }
        } );

        _popupMenu.addComponentListener( new ComponentAdapter() {
            @Override
            public void componentShown(ComponentEvent e) {
                System.out.println("menu shown");
            }
            @Override
            public void componentHidden(ComponentEvent e) {

            }

        });
    }

    boolean _popupOpened = false;

    public JTextPane createTextEditor() {
        final JTextPane tp = new JTextPane();
        _editors.add( tp );
        tp.setKeymap(_keymap);

        tp.addFocusListener(new FocusAdapter() {
            @Override
            public void focusLost(FocusEvent e) {
                if (_popupMenu.isShowing() && _popupMenu.getInvoker() == tp) {
                    JTextPane tp = (JTextPane)_popupMenu.getInvoker();
                    tp.getCaret().setBlinkRate(0);
                    tp.getCaret().setVisible(true);
                    tp.repaint();  
                }
            }
            @Override
            public void focusGained(FocusEvent e) {
                System.out.println("focus gained");
                for ( JTextPane t : _editors )
                    if ( t != tp )
                        t.setCaretPosition( t.getCaretPosition() );
            }
        });

        tp.addMouseListener(new MouseAdapter() {
            @Override
            public void mousePressed(final MouseEvent e) {
                System.out.println("mouse pressed");
                tp.requestFocus();
                if ( tp.getSelectionStart() == tp.getSelectionEnd() )
                    tp.setCaretPosition( tp.viewToModel( e.getPoint() ) );


                if ( e.isPopupTrigger() ) {
                    _popupMenu.show( e.getComponent(), e.getX(), e.getY() );
                }
            }
            @Override
            public void mouseReleased(MouseEvent e) {
                System.out.println("mouse released");
//                tp.requestFocus();
//                if ( e.isPopupTrigger() ) {
//                    _popupMenu.show( e.getComponent(), e.getX(), e.getY() );
//                }
            }
        });

        return tp;
    }

    public ArrayList<Action> getActionsForToolBar() {
        ArrayList<Action> actions = new ArrayList<Action>();
        actions.add( getHashedAction( DefaultEditorKit.cutAction ) );
        actions.add( getHashedAction( DefaultEditorKit.copyAction ) );
        actions.add( getHashedAction( DefaultEditorKit.pasteAction ) );
        actions.add( getHashedAction("font-bold") );
        actions.add( getHashedAction("font-italic") );
        actions.add( getHashedAction("font-underline") );
        return actions;
    }

    public ArrayList<JMenuItem> getMenuItems() {
        ArrayList<JMenuItem> items = new ArrayList<JMenuItem>();

        ArrayList<Action> actions = new ArrayList<Action>();
        actions.add( getHashedAction( DefaultEditorKit.cutAction ) );
        actions.add( getHashedAction( DefaultEditorKit.copyAction ) );
        actions.add( getHashedAction( DefaultEditorKit.pasteAction ) );

        JMenuItem mi = null;
        for (Action a : actions) {
            mi = new JMenuItem();
            mi.setAction(a);
            mi.setAccelerator(_keymap.getKeyStrokesForAction( a )[0] );
            items.add(mi);
        }            
        return items;
    }

}

public class TextEditorFrame2 extends LFrame {
    EditorUtil _editorUtil = new EditorUtil();
    JTextPane _tp;
    JTextPane _tp2;
    HashMap<String, Action> actionHashMap = new HashMap<String, Action>();

    public TextEditorFrame2() {
        setTitle("Editor");
        setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
        _tp = _editorUtil.createTextEditor();
        _tp2 = _editorUtil.createTextEditor();

        add( createToolBar(), BorderLayout.NORTH );
        add( _tp, BorderLayout.CENTER );
        add( _tp2, BorderLayout.SOUTH );

        setJMenuBar( createMenuBar() );

        _tp.setDragEnabled(true);
        _tp2.setDragEnabled(true);

        //_tp.setContentType("text/rtf");
        _tp.setEditorKit(new RTFEditorKit());
        _tp2.setEditorKit(new RTFEditorKit());
        //_tp2.setContentType("text/rtf");

        System.out.println(_tp.getEditorKit());

        pack();
        setVisible(true);
        setLocation(200, 300);
    }

    private JToolBar createToolBar() {
        JToolBar tb = new JToolBar();
        ArrayList<Action> actions = _editorUtil.getActionsForToolBar();
        for (Action a : actions)
            tb.add( a );

        JButton button = new JButton("dump");
        tb.add(button);
        button.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                DefaultStyledDocument doc = (DefaultStyledDocument)_tp.getStyledDocument();
                doc.dump(System.out);
            }
        });

        return tb;
    }

    private JMenuBar createMenuBar() {
        JMenuBar mb = new JMenuBar();
        JMenu edit = new JMenu("Edit");
        mb.add(edit);

        ArrayList<JMenuItem> items = _editorUtil.getMenuItems();
        for (JMenuItem i : items)
            edit.add( i );

        return mb;
    }

    public static void main(String[] args) {
        new TextEditorFrame();
    }
}

Upvotes: 2

Views: 745

Answers (1)

StanislavL
StanislavL

Reputation: 57421

You can try the kit http://java-sl.com/advanced_rtf_editor_kit.html

It supports much more RTF features than default one. Also it supports copy/paste styled content. Guess it will work ok with D&D as well.

Upvotes: 2

Related Questions