Apache OpenOffice (AOO) Bugzilla – Issue 92831
Serializing the selected text in Writer and preserving its formatting (in Java)
Last modified: 2017-05-20 10:44:31 UTC
I was trying to create a serializable class that would hold the XTransferable data of the current selection in a Writer document. I need this in order to be able to store the selection to the database (preserving the formatting) and later retrieve it and insert it in some other document. I created the following class: package test; import java.io.Serializable; import com.sun.star.datatransfer.DataFlavor; import com.sun.star.datatransfer.UnsupportedFlavorException; import com.sun.star.datatransfer.XTransferable; import com.sun.star.io.IOException; import com.sun.star.uno.Type; public class FormattedText implements Serializable, XTransferable { private static final long serialVersionUID = 1L; public static final DataFlavor textFlavor = new DataFlavor("text/plain;charset=utf-16", "Text", new Type(String.class)); public static final DataFlavor htmlFlavor = new DataFlavor("text/html", "HTML (HyperText Markup Language)", new Type(byte[].class)); public static final DataFlavor richtextFlavor = new DataFlavor("text/richtext", "Rich Text Format", new Type(byte[].class)); public static final DataFlavor starObjectFlavor = new DataFlavor("application/x-openoffice-objectdescriptor-xml;windows_formatname=\"Star Object Descriptor (XML)\"", "Star Object Descriptor (XML)", new Type(byte[].class)); public static final DataFlavor starEmbededSourceFlavor = new DataFlavor("application/x-openoffice-embed-source-xml;windows_formatname=\"Star Embed Source (XML)\"", "Star Embed Source (XML)", new Type(byte[].class)); public static final DataFlavor starLinkFlavor = new DataFlavor("application/x-openoffice-link;windows_formatname=\"Link\"", "Link", new Type(byte[].class)); private static final DataFlavor[] SUPPORTED_DATA_FLAVORS = { starEmbededSourceFlavor, starObjectFlavor, richtextFlavor, htmlFlavor, textFlavor, starLinkFlavor }; private String text; private byte[] html; private byte[] richtext; private byte[] starObject; private byte[] starEmbededSource; private byte[] starLink; public FormattedText(XTransferable transferable) throws IOException { try { if(transferable.isDataFlavorSupported(textFlavor)) { text = (String)transferable.getTransferData(textFlavor); } if(transferable.isDataFlavorSupported(htmlFlavor)) { html = (byte[])transferable.getTransferData(htmlFlavor);; } if(transferable.isDataFlavorSupported(richtextFlavor)) { richtext = (byte[])transferable.getTransferData(richtextFlavor); } if(transferable.isDataFlavorSupported(starObjectFlavor)) { starObject = (byte[])transferable.getTransferData(starObjectFlavor); } if(transferable.isDataFlavorSupported(starEmbededSourceFlavor)) { starEmbededSource = (byte[])transferable.getTransferData(starEmbededSourceFlavor); } if(transferable.isDataFlavorSupported(starLinkFlavor)) { starLink = (byte[])transferable.getTransferData(starLinkFlavor); } } catch (UnsupportedFlavorException e) { e.printStackTrace(); } } public Object getTransferData(DataFlavor df) throws UnsupportedFlavorException, IOException { if(df.MimeType.toString().equals(textFlavor.MimeType.toString())) { return text; } else if(df.MimeType.toString().equals(htmlFlavor.MimeType.toString())) { return html; } else if(df.MimeType.toString().equals(richtextFlavor.MimeType.toString())) { return richtext; } else if(df.MimeType.toString().equals(starObjectFlavor.MimeType.toString())) { return starObject; } else if(df.MimeType.toString().equals(starEmbededSourceFlavor.MimeType.toString())) { return starEmbededSource; } else if(df.MimeType.toString().equals(starLinkFlavor.MimeType.toString())) { return starLink; } throw new UnsupportedFlavorException(df.HumanPresentableName); } public DataFlavor[] getTransferDataFlavors() { return SUPPORTED_DATA_FLAVORS; } public boolean isDataFlavorSupported(DataFlavor df) { for(int i = 0; i < SUPPORTED_DATA_FLAVORS.length; i++) { if(SUPPORTED_DATA_FLAVORS[i].equals(df)) return true; } return false; } } I use this class like this: XTextViewCursorSupplier svc = (XTextViewCursorSupplier)UnoRuntime.queryInterface(XTextViewCursorSupplier.class, xTextDocument.getCurrentController()); XTransferableSupplier sts = (XTransferableSupplier) UnoRuntime.queryInterface( XTransferableSupplier.class, svc); XTransferable transferable = sts.getTransferable(); FormattedText ft = new FormattedText(transferable); ByteArrayOutputStream bout = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(bout); out.writeObject(ft); byte[] result = bout.toByteArray(); Later, I'm recreating the FormattedText object like this and insert (paste) it in the document like this: ByteArrayInputStream bin = new ByteArrayInputStream(result); ObjectInputStream in = new ObjectInputStream(bin); transferable = (XTransferable)in.readObject(); XTextViewCursorSupplier vcs = (XTextViewCursorSupplier)UnoRuntime.queryInterface(XTextViewCursorSupplier.class, xTextDocument.getCurrentController()); XTransferableSupplier ts = (XTransferableSupplier) UnoRuntime.queryInterface(XTransferableSupplier.class, vcs); ts.insertTransferable(transferable); The problem is that some information is lost in the process and the following bug occurs: When i paste the serialized (and unformatted) text in a location where some sentence (or a paragraph) is formatted (e.g. it is red), the formatting of the rest of the sentence becomes the same as the formatting of the serialized text (unformatted). Here is an example: Imagine that the following numbers are some formatted (ones) and unformatted (zeros) letters. The brackets show the current selection. State 1. This is our document 00000000000000000000000000000000000000 0001111111111111111111111111 111111111111111111111111111 00000000000000000000000000000000 State 2. I mark some text and copy (serialize) it with the code above 000[0000000000]0000000000000000000000000 0001111111111111111111111111 111111111111111111111111111 00000000000000000000000000000000 State 3. I place the cursor in the middle of some formatted text 00000000000000000000000000000000000000 00011111111[]11111111111111111 111111111111111111111111111 00000000000000000000000000000000 State 4. I paste the serialized text with the code above 00000000000000000000000000000000000000 00011111111[0000000000]11111111111111111 111111111111111111111111111 00000000000000000000000000000000 State 5. This is the bug. The formatted text which should not be affected, loses its formatting. 00000000000000000000000000000000000000 00011111111[0000000000]00000000000000000 000000000000000000000000000 00000000000000000000000000000000 I have done some hacking and i believe that this is a bug in the implementation because some data in the original transferable is not accessible through the UNO interface. The bug does not occur when the transferable is not serialized, but it is pasted as it is in its original state. Also, i have found that the 'oid' of the IQueryInterface that the XTransferable implements has something to do with the bug. I had the FormattedText class implement the IQueryInterface and override the getOid() method, and i had the oid serialized too. Sometimes, when the oid of the serialized text was the same with the oid of the document where i pasted the text, the bug did not occur. However, this behavior is not acceptable because the oid will always be different when the text is serialized and stored in the database for a long time. It is VERY important to me to find a solution fast. I will gladly assist you anyway i can. Please don't hesitate to ask me anything. If there is some other way of serializing an XTransferable, please let me know. Thank you
The same problem occurs in versions older than 3.0 so I'm changing the version attribute to 2.4.1 which is the current stable version. If it helps, I can send you an eclipse project so that you can easily test. Is there anyone interested in resolving this issue? If not, then how can I resolve the issue myself? Where should I look? It is really important for me to fix this problem so I am willing to help as much as I can. Thanks
MRU->JSC: is this something for you?
I have found a workaround that works in my case only. When I paste the text, I have some text selected so that the pasted text overwrites the selected text (this is a requirement in my case). The workaround is to clear the formatting of the selected text before pasting. This way, the rest of the sentence does not lose its formatting. The problem remains when there is no text selected when pasting. I think that this bug report should be converted to a feature request, requesting that the XTransferable interface becomes Serializable so that it can be stored in some database. Thanks
jsc -> os can you take a look on it and comment
.
Reset the assignee to the default "issues@openoffice.apache.org".