2011-10-12 27 views
14

tôi có mã này để chứng minh vấn đề:Làm một JEditorPane với html đưa định dạng đúng văn bản trong clipboard

public static void main(String[] args) { 
    JFrame frame = new JFrame(); 
    frame.getContentPane().add(new JEditorPane("text/html", "Hello cruel world<br>\n<font color=red>Goodbye cruel world</font><br>\n<br>\nHello again<br>\n")); 
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    frame.pack(); 
    frame.setLocationRelativeTo(null); 
    frame.setVisible(true); 
} 

Nếu bạn chọn tất cả các văn bản xuất hiện trong khung khi ứng dụng bắt đầu, bạn có thể sao chép nó và dán nó vào MS Word, Trang của Apple hoặc Thư và văn bản được định dạng chính xác. Nhưng nếu bạn dán nó vào một trình soạn thảo văn bản thuần túy như TextEdit, Smultron hoặc cửa sổ trò chuyện Skype, tất cả nội dung được dán đều nằm trên một dòng.

Tôi có thể làm gì để sao chép văn bản vào khay nhớ tạm có thể dán bằng dòng mới được lưu giữ?

Tôi đang chạy mã của tôi trên Mac OS X 10.7

+0

Có thể TextEdit chỉ đơn giản là không hiển thị những thứ như vậy? Điều gì sẽ xảy ra khi bạn dán nó vào một trình soạn thảo văn bản khác? –

+0

@Shakedown, vấn đề là với các trình soạn thảo văn bản thuần túy khác, chẳng hạn như Smultron –

+0

+1 câu hỏi hay, hãy trả lời – mKorbel

Trả lời

19

Sau khi nhận được câu trả lời, tôi xắn tay áo của tôi và đã làm rất nhiều nghiên cứu và học tập. Giải pháp là tạo một TransferHandler tùy chỉnh cho thành phần và xoa bóp văn bản HTML theo cách thủ công. Nó không phải là dễ dàng để làm việc tất cả điều này ra, mà có thể giải thích cho các câu trả lời số không tôi nhận được.

Dưới đây là một giải pháp làm việc:

import javax.swing.*; 
import javax.swing.text.MutableAttributeSet; 
import javax.swing.text.html.HTML; 
import javax.swing.text.html.HTMLEditorKit; 
import javax.swing.text.html.parser.ParserDelegator; 
import java.awt.datatransfer.Clipboard; 
import java.awt.datatransfer.DataFlavor; 
import java.awt.datatransfer.Transferable; 
import java.awt.datatransfer.UnsupportedFlavorException; 
import java.io.IOException; 
import java.io.Reader; 
import java.io.StringReader; 
import java.util.ArrayList; 

public class ScratchSpace { 

    public static void main(String[] args) { 
     final JFrame frame = new JFrame(); 
     final JEditorPane pane = new JEditorPane("text/html", "<html><font color=red>Hello</font><br>\u2663<br>World"); 
     pane.setTransferHandler(new MyTransferHandler()); 
     frame.getContentPane().add(pane); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.pack(); 
     frame.setLocationRelativeTo(null); 
     frame.setVisible(true); 
    } 

} 

class MyTransferHandler extends TransferHandler { 

    protected Transferable createTransferable(JComponent c) { 
     final JEditorPane pane = (JEditorPane) c; 
     final String htmlText = pane.getText(); 
     final String plainText = extractText(new StringReader(htmlText)); 
     return new MyTransferable(plainText, htmlText); 
    } 

    public String extractText(Reader reader) { 
     final ArrayList<String> list = new ArrayList<String>(); 

     HTMLEditorKit.ParserCallback parserCallback = new HTMLEditorKit.ParserCallback() { 
      public void handleText(final char[] data, final int pos) { 
       list.add(new String(data)); 
      } 

      public void handleStartTag(HTML.Tag tag, MutableAttributeSet attribute, int pos) { 
      } 

      public void handleEndTag(HTML.Tag t, final int pos) { 
      } 

      public void handleSimpleTag(HTML.Tag t, MutableAttributeSet a, final int pos) { 
       if (t.equals(HTML.Tag.BR)) { 
        list.add("\n"); 
       } 
      } 

      public void handleComment(final char[] data, final int pos) { 
      } 

      public void handleError(final String errMsg, final int pos) { 
      } 
     }; 
     try { 
      new ParserDelegator().parse(reader, parserCallback, true); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
     String result = ""; 
     for (String s : list) { 
      result += s; 
     } 
     return result; 
    } 


    @Override 
    public void exportToClipboard(JComponent comp, Clipboard clip, int action) throws IllegalStateException { 
     if (action == COPY) { 
      clip.setContents(this.createTransferable(comp), null); 
     } 
    } 

    @Override 
    public int getSourceActions(JComponent c) { 
     return COPY; 
    } 

} 

class MyTransferable implements Transferable { 

    private static final DataFlavor[] supportedFlavors; 

    static { 
     try { 
      supportedFlavors = new DataFlavor[]{ 
        new DataFlavor("text/html;class=java.lang.String"), 
        new DataFlavor("text/plain;class=java.lang.String") 
      }; 
     } catch (ClassNotFoundException e) { 
      throw new ExceptionInInitializerError(e); 
     } 
    } 

    private final String plainData; 
    private final String htmlData; 

    public MyTransferable(String plainData, String htmlData) { 
     this.plainData = plainData; 
     this.htmlData = htmlData; 
    } 

    public DataFlavor[] getTransferDataFlavors() { 
     return supportedFlavors; 
    } 

    public boolean isDataFlavorSupported(DataFlavor flavor) { 
     for (DataFlavor supportedFlavor : supportedFlavors) { 
      if (supportedFlavor == flavor) { 
       return true; 
      } 
     } 
     return false; 
    } 

    public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException { 
     if (flavor.equals(supportedFlavors[0])) { 
      return htmlData; 
     } 
     if (flavor.equals(supportedFlavors[1])) { 
      return plainData; 
     } 
     throw new UnsupportedFlavorException(flavor); 
    } 
} 
1

Cảm ơn bạn đã mã bưu điện của bạn! Tôi đang làm việc để ứng dụng và chạy dưới JNLP cho phép người dùng tạo trích dẫn MLA và sau đó sao chép/dán chúng vào một trình xử lý văn bản. Vì vậy, các định dạng cần được bảo tồn.

Xem http://proctinator.com/citation/

Có một cách dễ dàng hơn, nhưng tôi nghĩ rằng tôi sẽ cần các loại phương pháp bạn chứng minh ở trên để có được ứng dụng của tôi làm việc với jnlp.

Mã bên dưới hoạt động tìm một JEditorPane chạy trong môi trường không hạn chế. Nhưng copy/paste là không trực tiếp có sẵn khi bạn ứng dụng được trong một sandbox (chẳng hạn như sẽ là trường hợp cho một applet hoặc file JNLP mà không yêu cầu quyền đầy đủ.)

JEditorPane citEditorPane; 
//user fills pane with MLA citations. 
citEditorPane.selectAll(); 
citEditorPane.copy(); 
citEditorPane.select(0, 0); 
+0

để sao chép giấy phép cho webstartable trong hộp cát, xem tôi không-trả lời-nhưng-nhận xét :-) – kleopatra

3

Lưu ý: đây là không một câu trả lời cho câu hỏi, chỉ là một nhận xét có mã cho câu trả lời của @Thorn, liên quan đến các hạn chế bảo mật

Trong các webstartables với quyền mặc định (nghĩa là, không ;-) bạn có thể yêu cầu SecurityManager trong thời gian chạy cho một ClipboardService: nó sẽ bật lên một hộp thoại yêu cầu người dùng một lần để cho phép (hoặc không cho phép) bản sao. Với điều đó, bạn có thể thay thế hành động sao chép mặc định trong textComponent. Trong SwingX demo, chúng tôi hỗ trợ dán mã từ khu vực nguồn theo:

/** 
* Replaces the editor's default copy action in security restricted 
* environments with one messaging the ClipboardService. Does nothing 
* if not restricted. 
* 
* @param editor the editor to replace 
*/ 
public static void replaceCopyAction(final JEditorPane editor) { 
    if (!isRestricted()) return; 
    Action safeCopy = new AbstractAction() { 

     @Override 
     public void actionPerformed(ActionEvent e) { 
      try { 
       ClipboardService cs = (ClipboardService)ServiceManager.lookup 
        ("javax.jnlp.ClipboardService"); 
       StringSelection transferable = new StringSelection(editor.getSelectedText()); 
       cs.setContents(transferable); 
      } catch (Exception e1) { 
       // do nothing 
      } 
     } 
    }; 
    editor.getActionMap().put(DefaultEditorKit.copyAction, safeCopy); 
} 

private static boolean isRestricted() { 
    SecurityManager manager = System.getSecurityManager(); 
    if (manager == null) return false; 
    try { 
     manager.checkSystemClipboardAccess(); 
     return false; 
    } catch (SecurityException e) { 
     // nothing to do - not allowed to access 
    } 
    return true; 
} 
Các vấn đề liên quan