Results 1 to 2 of 2
  1. #1
    Gudradain is offline Member
    Join Date
    Nov 2008
    Posts
    44
    Rep Power
    0

    Default Cut, copy and Paste in JTextPane

    Hello

    -- Introduction --

    I'm trying to implements cut,copy and paste in a JTextPane and I want to be able to keep the Style information intact while doing theses operations between 2 JTextPanes or between a JTextPane and a native program.

    I have a lot of question so I create this thread to put them together since they are related.

    -- The work I did so far --

    I create a TransferHandler for a JTextPane that permits to transfer the text keeping the style between JTextPanes that has this TransferHandler and transfer plain text to other JTextPane and native application.

    To do this, I create a Transferable Object that support the following DataFlavor:

    1. DefaultStyledDocumentFlavor (I create it)
    2. StringFlavor

    My program is below

    -- Unsolved Questions --

    1. What DataFlavor should I use to transfer data between Microsoft Word and my JTextPane? Please suggest. (Question : post #2) (Answer : post ?)

    -- Solved Questions --

    -- My Knowledge --
    (Pls tell me if I got something wrong)

    Cut,copy and paste are already implemented in JTextComponent and have key binding associated to them. The text copied by these methods is in a String format (no style).

    TransferHandler is the class that transfer the data. If you want to change the behavior of a cut,copy or paste action in a component you need to create a subclass of TransferHandler and set the TransferHandler of your component to your new TransferHandler. The method you need to redo in your subclass of TransferHandler are the followings.

    To export data you overwrite :

    1. getSourceActions //Define the actions that are valid for this component
    2. createTransferable //Create the object to be transfered
    3. exportDone //Action you do at the end of the export (useful to implements cut)

    To import data you overWrite :

    1. canImport //Check if there is a common dataflavor between the 2 component/program transfering data
    2. importData //Transfer the data from the clipboard in the program

    The object that you put in the Clipboard (data being transfered) need to implements the interface Transferable (and ClipboardOwner). Your Transferable Object need to define all the DataFlavor supported by this object. This list will be used by canImport in your TransferHandler to check if the data in the Clipboard can be transfered.

    A DataFlavor represents the type of Data of a content. For example stringFlavor represents plain text data and imagaFlavor represents an Image. A data flavor can either work only inside the JVM (Java Virtual Machine) or with any other native programs. When you transfer data to a native application, you use Object serialization, so the class you use to transfer the data must implement the Serializable interface.

    One way to know what DataFlavor are supported by a native application is to get access to a Transferable Object coming from this application then call the method getTransferDataFlavors and print every DataFlavors returned. When you copy from a native application then paste the content in your Component that has your TransferHandler, the Transferable Object of the native application will be sent to the method importData. This way you can determine what DataFlavor your TransferHandler and your Transferable Object need to support in order to make the desired cut,copy and paste.

    -- Useful link --

    TransferHandler Class (The Java™ Tutorials > Creating a GUI with JFC/Swing > Drag and Drop and Data Transfer)
    New Data Transfer Capabilities
    Swing - Cut/copy/paste with style information intact [Locked]
    J2TextPrinter

    Here is my program so far. It works for what I write in the "The work I did so far" section.

    Java Code:
    package Clipboard;
    
    import javax.swing.JFrame;
    //Import for createTextPanes
    import javax.swing.JTextPane;
    import javax.swing.JPanel;
    import java.awt.GridLayout;
    import javax.swing.JScrollPane;
    //Import for initialize
    import javax.swing.text.StyledDocument;
    import javax.swing.ImageIcon;
    import javax.swing.JButton;
    //Import for createStyles
    import javax.swing.text.Style;
    import javax.swing.text.StyleConstants;
    import java.awt.Color;
    //Import for setContent
    import javax.swing.text.BadLocationException;
    //Import for getMenuBar
    import javax.swing.JMenu;
    import javax.swing.JMenuBar;
    import javax.swing.JMenuItem;
    import java.awt.event.KeyEvent;
    import javax.swing.text.DefaultEditorKit;
    //Import for StringTransferHandler
    import javax.swing.TransferHandler;
    import javax.swing.JComponent;
    import java.awt.datatransfer.DataFlavor;
    import java.awt.datatransfer.StringSelection; //Was in use before
    import java.awt.datatransfer.Transferable;
    import java.awt.datatransfer.Clipboard;
    import javax.swing.text.Element;
    import javax.swing.text.SimpleAttributeSet;
    //Import for StringTransferSelection
    import java.awt.datatransfer.ClipboardOwner;
    import java.awt.datatransfer.UnsupportedFlavorException;
    import java.io.IOException;
    import javax.swing.text.DefaultStyledDocument;
    
    
    public class JTextPaneTransfer {
        
        public JPanel createTextPanes(){
            JTextPane myTextPane1 = new JTextPane();
            initialize(myTextPane1);
            myTextPane1.setTransferHandler(new JTextPaneTransferHandler());
            
            JTextPane myTextPane2 = new JTextPane();
            myTextPane2.setTransferHandler(new JTextPaneTransferHandler());
            
            JPanel myPanel = new JPanel(new GridLayout(0,1));
            myPanel.add(new JScrollPane(myTextPane1));
            myPanel.add(new JScrollPane(myTextPane2));
            
            return myPanel;
        }
        
        private void initialize(JTextPane textPane) {
            String text = "This component models paragraphs that are composed of " +
                "runs of character level attributes. Each paragraph may have a " +
                "logical style attached to it which contains the default attributes " +
                "to use if not overridden by attributes set on the paragraph or " +
                "character run. Components and images may be embedded in the flow " +
                "of text."; // 0 - 319
            StyledDocument doc = textPane.getStyledDocument();
            createStyles(doc);
            setContent(doc, text);
            styleContent(doc);
            //textPane.insertIcon(new ImageIcon("C:\\Documents and Settings\\Marc\\My Documents\\My Pictures\\bg_3dots.gif"));
            textPane.insertComponent(new JButton("Hello"));
        }
    
        private void createStyles(StyledDocument doc) {
            Style baseStyle = doc.addStyle("base", null);
            StyleConstants.setFontFamily(baseStyle, "Lucida Sans Unicode");
            StyleConstants.setFontSize(baseStyle, 18);
            StyleConstants.setLeftIndent(baseStyle, 10f);
     
            Style style = doc.addStyle("bold", baseStyle);
            StyleConstants.setBold(style, true);
     
            style = doc.addStyle("italic", baseStyle);
            StyleConstants.setItalic(style, true);
     
            style = doc.addStyle("blue", baseStyle);
            StyleConstants.setForeground(style, Color.blue);
     
            style = doc.addStyle("underline", baseStyle);
            StyleConstants.setUnderline(style, true);
     
            style = doc.addStyle("green", baseStyle);
            StyleConstants.setForeground(style, Color.green.darker());
            StyleConstants.setUnderline(style, true);
     
            style = doc.addStyle("highlight", baseStyle);
            StyleConstants.setForeground(style, Color.yellow);
            StyleConstants.setBackground(style, Color.black);
        } 
         
        private void setContent(StyledDocument doc, String text) {
            try {
                doc.insertString(0, text, doc.getStyle("base"));
            } catch(BadLocationException e) {
                System.out.printf("bad location error: %s%n", e.getMessage());
            }
        }
        
        //Put the style in the text
        private void styleContent(StyledDocument doc) {
            String[] names = {
                "underline", "highlight", "blue", "italic",
                "green", "green", "bold", "bold"
            };
            int[] starts  = { 22, 62, 116, 164, 233, 246, 261, 276 };
            int[] lengths = { 10, 26,  13,  18,   9,   9,  10,   6 };
            Style style = doc.getStyle("base");
            doc.setLogicalStyle(0, style);
            for(int j = 0; j < names.length; j++) {
                style = doc.getStyle(names[j]);
                doc.setCharacterAttributes(starts[j], lengths[j], style, false);
            }
        }
        
        public JMenuBar getMenuBar () {
            JMenuItem menuItem = null;
            JMenuBar menuBar = new JMenuBar();
            
            JMenu menu = new JMenu("Edit");
            menu.setMnemonic(KeyEvent.VK_E);
            
            menuItem = new JMenuItem(new DefaultEditorKit.CutAction());
            menuItem.setText("Cut");
            menuItem.setMnemonic(KeyEvent.VK_T);
            menu.add(menuItem);
            
            menuItem = new JMenuItem(new DefaultEditorKit.CopyAction());
            menuItem.setText("Copy");
            menuItem.setMnemonic(KeyEvent.VK_C);
            menu.add(menuItem);
            
            menuItem = new JMenuItem(new DefaultEditorKit.PasteAction());
            menuItem.setText("Paste");
            menuItem.setMnemonic(KeyEvent.VK_P);
            menu.add(menuItem);
            
            menuBar.add(menu);
            return menuBar;
        }
        
        public static void main(String [] args){
            JTextPaneTransfer test = new JTextPaneTransfer();
            JFrame myFrame = new JFrame("String Transfer");
            myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            
            myFrame.setJMenuBar(test.getMenuBar());
            myFrame.getContentPane().add(test.createTextPanes());
            
            myFrame.setSize(600,500);
            myFrame.setVisible(true);
        }
        //END OF THE CLASS StringTransfer
    }
    class JTextPaneTransferHandler extends TransferHandler{
        
        public JTextPaneTransferHandler(){
            System.out.println("Constructeur de StringTransferHandler");
        }
        
        public boolean canImport(JComponent comp, DataFlavor[] transferFlavors){
            System.out.println("method canImport");
            JTextPaneSelection s = new JTextPaneSelection(""); //Dummy object
            boolean retour = false;
            for(int i=0; i<transferFlavors.length; i++){
                System.out.println(transferFlavors[i]);
                if(s.isDataFlavorSupported(transferFlavors[i])){
                    retour = true;
                }
            }
            return retour;
        }
        
        protected Transferable createTransferable(JComponent c){
            System.out.println("method createTransferable");
            JTextPane aTextPane = (JTextPane)c;
            int start = aTextPane.getSelectionStart();
            int end = aTextPane.getSelectionEnd();
            
            StyledDocument aSDoc = aTextPane.getStyledDocument();
            DefaultStyledDocument dSDocSelection = copyDocument(aSDoc, start, end);
            return (new JTextPaneSelection(dSDocSelection));
        }
        
        public static DefaultStyledDocument copyDocument(StyledDocument src, int selectionStart, int selectionEnd) { 
            System.out.println("copyDocument Commence");
            Element rootElement, paragraphElement, textElement; 
            SimpleAttributeSet copyAttrs;
            int startOffset, endOffset;
            String copy_string;
            
            rootElement = src.getDefaultRootElement();
            DefaultStyledDocument copyDoc = new DefaultStyledDocument();
            
            for (int lpParagraph=0; lpParagraph<rootElement.getElementCount(); lpParagraph++){
                paragraphElement = rootElement.getElement(lpParagraph);
                
                //Check if the paragraph need to be copy
                if(paragraphElement.getEndOffset() < selectionStart){
                    System.out.println("Continue paragraph");
                    continue; //Go to the next paragraph
                }
                if(paragraphElement.getStartOffset() > selectionEnd){
                    System.out.println("Break paragraph");
                    break; //Exit the boucle
                }
                
                for (int lpText=0; lpText<paragraphElement.getElementCount(); lpText++) {
                    System.out.println("Text Boucle");
                    //Insert a Element in the new Document    
                    textElement = paragraphElement.getElement(lpText);
                    
                    //Check if the Element need to be copy
                    if(textElement.getEndOffset() < selectionStart){
                        System.out.println("Continue text");
                        continue; //Go to the next Element
                    }
                    if(textElement.getStartOffset() > selectionEnd){
                        System.out.println("Break text");
                        break; //Exit the boucle
                    }
                    
                    copyAttrs = new SimpleAttributeSet(textElement.getAttributes());
                    
                    //Find the value of startOffset and endOffset
                    if(textElement.getStartOffset() < selectionStart){
                        startOffset = selectionStart;
                    }else{
                        startOffset = textElement.getStartOffset();
                    }
                    if(textElement.getEndOffset() > selectionEnd){
                        endOffset = selectionEnd;
                    }else{
                        endOffset = textElement.getEndOffset();
                    }
                        
                    try{
                        copy_string = src.getText(startOffset, (endOffset-startOffset));
                        copyDoc.insertString(copyDoc.getLength(), copy_string, copyAttrs);
                    }catch (BadLocationException e){
                        System.out.println("Pogner une exception");
                    }
                }
                //Modify the Style of the paragraph
                copyAttrs = new SimpleAttributeSet(paragraphElement.getAttributes());
                startOffset = paragraphElement.getStartOffset();
                endOffset = paragraphElement.getEndOffset();
                
                copyDoc.setParagraphAttributes(startOffset, (endOffset-startOffset), copyAttrs, true);
            }
          
            return copyDoc;
        }
        
        public void exportToClipboard(JComponent comp, Clipboard clip, int action) {
            System.out.println("method exportToClipboard");
            super.exportToClipboard(comp, clip, action);
        }
        
        public int getSourceActions(JComponent c) {
            System.out.println("method getSourceActions");
            return COPY_OR_MOVE;
        }
        
        protected void exportDone(JComponent source, Transferable data, int action){
            System.out.println("method exportDone");
            JTextPane srcTextPane = (JTextPane)source;
            if(action == MOVE){
                srcTextPane.replaceSelection("");
            }
        }
        
        public boolean importData(JComponent comp, Transferable t){
            System.out.println("method importData");
            if(canImport(comp, t.getTransferDataFlavors())){
                
                if(t.isDataFlavorSupported(JTextPaneSelection.DSDocFlavor)){
                    JTextPane theTextPane = (JTextPane)comp;
                    theTextPane.replaceSelection("");
                    StyledDocument theSDoc = new DefaultStyledDocument();
                    try{
                        theSDoc = (StyledDocument)t.getTransferData(JTextPaneSelection.DSDocFlavor);
                    }catch(Exception e){
                        System.out.println("importData with StyledDocument failed");
                    }
                    int thePos = theTextPane.getCaretPosition();
                    insertDocument(theSDoc, thePos, theTextPane);
                    return true;
                    
                }else{
                        
                    System.out.println("canImport is true");
                    String textString = "";
                    try{
                        textString = (String)t.getTransferData(DataFlavor.stringFlavor);
                        JTextPane aTextPane = (JTextPane)comp;
                        aTextPane.replaceSelection(textString);
                    }catch(Exception e){
                        System.out.println("Exception in importData");
                    }
                    return true;
                }
            }
            System.out.println("canImport is false");
            return false;
        }
        
        //Insert a Document in a another Document
        public static void insertDocument(StyledDocument srcSDoc, int srcPos, JTextPane theTextPane){
            StyledDocument theSDoc = theTextPane.getStyledDocument();
            Element rootElement, paragraphElement, textElement;
            SimpleAttributeSet copyAttrs;
            int startOffset, endOffset;
            int pos = srcPos;
            String copy_string;
            
            rootElement = srcSDoc.getDefaultRootElement();
            
            for (int lpParagraph=0; lpParagraph<rootElement.getElementCount(); lpParagraph++){
                paragraphElement = rootElement.getElement(lpParagraph);
                
                for (int lpText=0; lpText<paragraphElement.getElementCount(); lpText++) {
                    textElement = paragraphElement.getElement(lpText);
                    copyAttrs = new SimpleAttributeSet(textElement.getAttributes());
                    startOffset = textElement.getStartOffset();
                    endOffset = textElement.getEndOffset();
                    //A Verifier
                    try{
                        copy_string = srcSDoc.getText(startOffset, (endOffset-startOffset));
                        theSDoc.insertString(pos, copy_string, copyAttrs);
                    }catch (BadLocationException e){
                        System.out.println("Pogner une exception");
                    }
                    pos += endOffset-startOffset;
                }
                //Modify the Style of the paragraph
                copyAttrs = new SimpleAttributeSet(paragraphElement.getAttributes());
                startOffset = paragraphElement.getStartOffset();
                endOffset = paragraphElement.getEndOffset();
                
                theSDoc.setParagraphAttributes(startOffset, (endOffset-startOffset), copyAttrs, true);
            }
            try{
                theSDoc.remove(pos-1, 1);
            }catch(BadLocationException e){
                System.out.println("Didn't work");
            }
        }
        
        //END OF THE CLASS StringTransferHandler
    }
    
    class JTextPaneSelection implements Transferable, ClipboardOwner{
        private String dataString;
        private DefaultStyledDocument dataDoc;
        public static DataFlavor DSDocFlavor = new DataFlavor(DefaultStyledDocument.class, "DSDocFlavor");
        private DataFlavor [] supportedFlavors = {DSDocFlavor, DataFlavor.stringFlavor};
        
        //Usefull for Dummy StringTransferSelection Object
        public JTextPaneSelection(String dataString){
            System.out.println("Constructeur StringTransferSelection avec String");
            this.dataString = dataString;
        }
        
        public JTextPaneSelection(DefaultStyledDocument dataDoc){
            System.out.println("Constructeur StringTransferSelection avec DSDoc");
            this.dataDoc = dataDoc;
            try{
                dataString = dataDoc.getText(0, dataDoc.getLength());
            }catch(BadLocationException e){
                //It won't happen
            }
        }
        
        public DataFlavor[] getTransferDataFlavors(){
            System.out.println("method getTransferDataFlavors");
            return supportedFlavors;
        }
        
        public boolean isDataFlavorSupported(DataFlavor flavor){
            //System.out.println("method isDataFlavorSupported");
            if(flavor.equals(DataFlavor.stringFlavor)){
                return true;
            }
            if(flavor.equals(DSDocFlavor)){
                return true;
            }
            return false;
        }
        
        //Throw a weird exception if the part with DataFlavor.stringFlavor is not there (FIX)
        //When you create the Transferable the method getTransferDataFlavors is called
        //then getTransferData is called for every type in supportedFlavors
        //It must be some inner working of the Clipboard
        public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException{
            System.out.println("method getTransferData");
            if(flavor.equals(DataFlavor.stringFlavor)){
                return dataString;
            }else if(flavor.equals(DSDocFlavor)){
                return dataDoc;
            }else{
                throw new UnsupportedFlavorException(flavor);
            }
        }
        
        public void lostOwnership(Clipboard clipboard, Transferable contents){
            System.out.println("method lostOwnership");
        }
    }
    Last edited by Gudradain; 01-04-2009 at 12:29 AM. Reason: Program didn't work on other comp because of new ImageICon("My directory")

  2. #2
    Gudradain is offline Member
    Join Date
    Nov 2008
    Posts
    44
    Rep Power
    0

    Default

    Question 1

    I want to make it possible to copy a text from Microsoft Word to my JTextPane and keep the style information intact.

    I think that to do it, my JTextPane need to have a compatible dataflavor with Microsoft Word and this flavor need to keep the style attributes intact.

    The list of DataFlavor supported by the Transferable Object return by Microsoft Word is pretty big and I don't recognize them. I try searching for some flavors on google using their name but I didn't find really usefull information.

    Usually the DataFlavor are listed from the preferred one to the least preferred one, so I guess that the good one should be one of the first. They seems to have one thing in common : mimetype=text/html. But which one would work and in what form my data will be transfered.

    Any suggestions on which DataFlavor would work or some suggested reading?

    Here is a list of the DataFlavor supported by Microsoft Word (it's big)

    1. java.awt.datatransfer.DataFlavor[mimetype=application/x-java-text-encoding;representationclass=[B]
    2. java.awt.datatransfer.DataFlavor[mimetype=text/html;representationclass=java.io.Reader]
    3. java.awt.datatransfer.DataFlavor[mimetype=text/html;representationclass=java.lang.String]
    4. java.awt.datatransfer.DataFlavor[mimetype=text/html;representationclass=java.nio.CharBuffer]
    5. java.awt.datatransfer.DataFlavor[mimetype=text/html;representationclass=[C]
    6. java.awt.datatransfer.DataFlavor[mimetype=text/html;representationclass=java.io.InputStream;chars et=UTF-16]
    7. java.awt.datatransfer.DataFlavor[mimetype=text/html;representationclass=java.nio.ByteBuffer;chars et=UTF-16]
    8. java.awt.datatransfer.DataFlavor[mimetype=text/html;representationclass=[B;charset=UTF-16]
    9. java.awt.datatransfer.DataFlavor[mimetype=text/html;representationclass=java.io.InputStream;chars et=UTF-8]
    10. java.awt.datatransfer.DataFlavor[mimetype=text/html;representationclass=java.nio.ByteBuffer;chars et=UTF-8]
    11. java.awt.datatransfer.DataFlavor[mimetype=text/html;representationclass=[B;charset=UTF-8]
    12. java.awt.datatransfer.DataFlavor[mimetype=text/html;representationclass=java.io.InputStream;chars et=UTF-16BE]
    13. java.awt.datatransfer.DataFlavor[mimetype=text/html;representationclass=java.nio.ByteBuffer;chars et=UTF-16BE]
    14. java.awt.datatransfer.DataFlavor[mimetype=text/html;representationclass=[B;charset=UTF-16BE]
    15. java.awt.datatransfer.DataFlavor[mimetype=text/html;representationclass=java.io.InputStream;chars et=UTF-16LE]
    16. java.awt.datatransfer.DataFlavor[mimetype=text/html;representationclass=java.nio.ByteBuffer;chars et=UTF-16LE]
    17. java.awt.datatransfer.DataFlavor[mimetype=text/html;representationclass=[B;charset=UTF-16LE]
    18. java.awt.datatransfer.DataFlavor[mimetype=text/html;representationclass=java.io.InputStream;chars et=ISO-8859-1]
    19. java.awt.datatransfer.DataFlavor[mimetype=text/html;representationclass=java.nio.ByteBuffer;chars et=ISO-8859-1]
    20. java.awt.datatransfer.DataFlavor[mimetype=text/html;representationclass=[B;charset=ISO-8859-1]
    21. java.awt.datatransfer.DataFlavor[mimetype=text/html;representationclass=java.io.InputStream;chars et=windows-1252]
    22. java.awt.datatransfer.DataFlavor[mimetype=text/html;representationclass=java.nio.ByteBuffer;chars et=windows-1252]
    23. java.awt.datatransfer.DataFlavor[mimetype=text/html;representationclass=[B;charset=windows-1252]
    24. java.awt.datatransfer.DataFlavor[mimetype=text/html;representationclass=java.io.InputStream;chars et=US-ASCII]
    25. java.awt.datatransfer.DataFlavor[mimetype=text/html;representationclass=java.nio.ByteBuffer;chars et=US-ASCII]
    26. java.awt.datatransfer.DataFlavor[mimetype=text/html;representationclass=[B;charset=US-ASCII]
    27. java.awt.datatransfer.DataFlavor[mimetype=text/rtf;representationclass=java.io.InputStream]
    28. java.awt.datatransfer.DataFlavor[mimetype=text/rtf;representationclass=java.nio.ByteBuffer]
    29. java.awt.datatransfer.DataFlavor[mimetype=text/rtf;representationclass=[B]
    30. java.awt.datatransfer.DataFlavor[mimetype=application/x-java-serialized-object;representationclass=java.lang.String]
    31. java.awt.datatransfer.DataFlavor[mimetype=image/x-java-image;representationclass=java.awt.Image]
    32. java.awt.datatransfer.DataFlavor[mimetype=text/plain;representationclass=java.io.Reader]
    33. java.awt.datatransfer.DataFlavor[mimetype=text/plain;representationclass=java.lang.String]

Similar Threads

  1. Problems with copy paste
    By fredand44 in forum Eclipse
    Replies: 0
    Last Post: 12-17-2008, 04:14 PM
  2. How to copy and paste data with the clipboard
    By Java Tip in forum SWT Tips
    Replies: 0
    Last Post: 07-07-2008, 04:35 PM
  3. Replies: 1
    Last Post: 06-23-2008, 06:46 AM
  4. Replies: 0
    Last Post: 02-06-2008, 03:55 PM
  5. java copy paste cut and undo functions
    By Mr tuition in forum AWT / Swing
    Replies: 1
    Last Post: 12-09-2007, 12:02 AM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •