/* * Created on Nov 25, 2007 */ package net.atlanticbb.tantlinger.ui.text.actions; import java.awt.Toolkit; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.awt.event.ActionEvent; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.swing.Action; import javax.swing.JEditorPane; import javax.swing.KeyStroke; import net.atlanticbb.tantlinger.ui.UIUtils; import net.atlanticbb.tantlinger.ui.text.CompoundUndoManager; import net.atlanticbb.tantlinger.ui.text.HTMLUtils; import org.bushe.swing.action.ActionManager; import org.bushe.swing.action.ShouldBeEnabledDelegate; /** * @author Bob Tantlinger * */ public class PasteFormattedAction extends HTMLTextEditAction { private static final long serialVersionUID = 1L; /** * @param name */ public PasteFormattedAction() { super(i18n.str("paste_formatted")); putValue(MNEMONIC_KEY, new Integer(i18n.mnem("paste_formatted"))); putValue(SMALL_ICON, UIUtils.getIcon(UIUtils.X16, "paste.png")); putValue(ActionManager.LARGE_ICON, UIUtils.getIcon(UIUtils.X24, "paste.png")); putValue(ACCELERATOR_KEY,KeyStroke.getKeyStroke("shift ctrl V")); addShouldBeEnabledDelegate(new ShouldBeEnabledDelegate() { public boolean shouldBeEnabled(Action a) { if(getCurrentEditor() == null) return false; Transferable content = Toolkit.getDefaultToolkit().getSystemClipboard().getContents(PasteFormattedAction.this); if(content == null) return false; DataFlavor flv = DataFlavor.selectBestTextFlavor(content.getTransferDataFlavors()); return flv != null && flv.getMimeType().startsWith("text/html"); } }); putValue(Action.SHORT_DESCRIPTION, getValue(Action.NAME)); } protected void updateWysiwygContextState(JEditorPane wysEditor) { this.updateEnabledState(); } protected void updateSourceContextState(JEditorPane srcEditor) { this.updateEnabledState(); } /* (non-Javadoc) * @see net.atlanticbb.tantlinger.ui.text.actions.HTMLTextEditAction#sourceEditPerformed(java.awt.event.ActionEvent, javax.swing.JEditorPane) */ protected void sourceEditPerformed(ActionEvent e, JEditorPane editor) { String htmlFragment = null; try { htmlFragment = getHTMLFragment(); } catch(Exception ex) { ex.printStackTrace(); } if(htmlFragment != null) { CompoundUndoManager.beginCompoundEdit(editor.getDocument()); editor.replaceSelection(htmlFragment); CompoundUndoManager.endCompoundEdit(editor.getDocument()); } } /* (non-Javadoc) * @see net.atlanticbb.tantlinger.ui.text.actions.HTMLTextEditAction#wysiwygEditPerformed(java.awt.event.ActionEvent, javax.swing.JEditorPane) */ protected void wysiwygEditPerformed(ActionEvent e, JEditorPane editor) { String htmlFragment = null; try { htmlFragment = getHTMLFragment(); } catch(Exception ex) { ex.printStackTrace(); } if(htmlFragment != null) { CompoundUndoManager.beginCompoundEdit(editor.getDocument()); //HTMLUtils.insertHTML("<div>" + htmlFragment + "</div>", HTML.Tag.DIV, editor); HTMLUtils.insertArbitraryHTML(htmlFragment, editor); CompoundUndoManager.endCompoundEdit(editor.getDocument()); } } /** * Get the HTML text from the content if any * * @return returns the html fragment, or null if this content isn't HTML * @throws UnsupportedFlavorException * @throws IOException */ private String getHTMLFragment() throws IOException, UnsupportedFlavorException { Clipboard clip = Toolkit.getDefaultToolkit().getSystemClipboard(); Transferable c = clip.getContents(this); if(c == null) return null; DataFlavor flv = DataFlavor.selectBestTextFlavor(c.getTransferDataFlavors()); if(!flv.getMimeType().startsWith("text/html")) return null; String text = read((flv.getReaderForText(c))); //when html content is retrieved from the transferable, the copied part //is enclosed in a <body> tag, so only get the contents we want... int flags = Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE; Pattern p = Pattern.compile(("<\\s*body\\b([^<>]*)>"), flags); Matcher m = p.matcher(text); if(m.find()) { text = text.substring(m.end(), text.length()); } p = Pattern.compile("<\\s*/\\s*body\\s*>", flags); m = p.matcher(text); if(m.find()) { text = text.substring(0, m.start()); } //when html content is retrieved from the transferable, the copied part //is surrounded with the comments <!--StartFragment--> and <!--EndFragment--> on windows text = text.replaceAll("<\\!\\-\\-StartFragment\\-\\->", ""); text = text.replaceAll("<\\!\\-\\-EndFragment\\-\\->", ""); //gets rid of 'class' and 'id' attributes in the tags. //It really doesn't make much sense to include these attribs in HTML //pasted in from the wild. String r = "<([^>]*)(?:class|id)\\s*=\\s*(?:'[^']*'|\"\"[^\"\"]*\"\"|[^\\s>]+)([^>]*)>"; p = Pattern.compile(r, flags); //run it twice for each attrib m = p.matcher(text); text = m.replaceAll("<$1$2>"); m = p.matcher(text); text = m.replaceAll("<$1$2>"); return text; } public String read(Reader input) throws IOException { BufferedReader reader = new BufferedReader(input); StringBuffer sb = new StringBuffer(); int ch; try { while((ch = reader.read()) != -1) { //System.err.print((char)ch); sb.append((char)ch); } } catch(IOException ex) { throw ex; } finally { try { reader.close(); } catch(IOException ioe){} } return sb.toString(); } }