I would like to display an RTF document in an SWT (actually Eclipse RCP) application.
I know there is a Swing widget for displaying and editing RTF text, but it is Swing and quite alien in look and feel when used in the otherwise platform (not to mention that to the last of my knowledge it did not display images and had only limited support for formatting)
Other options is to use COM interface on windows, but that works only on the windows platform and requires that an ActiveX RichEdit contol be installed on the customer machine... which can make the deployment of the application quite horrendous...
What are the other options for displaying rich documents inside Eclipse/SWT application?
-
You may use swt.custom.StyledText. That has many features to change the look of the text. But I don't think it can load or save RTF right now.
I once wrote an HTML editor with it, but it is quite difficult, since the StyledText model to add styles to a part of the text is so alien compared to the way HTML/RTF works.
AFAIK you can directly print from this control, which internally creates an RTF representation of the contents. But that's not exactly what you asked for.
Heath Borders : StyledText will save RTF to the clipboard if copied. A total hack way to get the RTF values would be to select all, copy, and extract the RTF value from the clipboard.Roland Tepp : Yesm you are right, it is not what I asked. StyledText can only copy text to clipboard as RTF and does not handle RTF as an input at all... Using StyledText as a base for RTF viewer/editor would probably be one way to start, but as a widget itself, it is not what I wanted... -
I'm not sure of a way to do it without using ActiveX. If you do go this direction you might want to look into the IBM Container for ActiveX Documents, which is supposed to allow better integration of documents.
Roland Tepp : What we have now come up with is halfway what I wanted. Basically we used JNI to call upon native Windows RTF control (the one used by WodPad) - this way we don't have to worry about nasty ActiveX deployment issues, but still it's a hack -
Why not first read the RTF text into a StyledDocument using the RTFEditorKit and then writing the StyledDocument to a StringWriter using the HTMLEditorKit?
String rtf = "whatever"; BufferedReader input = new BufferedReader(new StringReader(rtf)); RTFEditorKit rtfKit = new RTFEditorKit(); StyledDocument doc = (StyledDocument) rtfKit.createDefaultDocument(); rtfEdtrKt.read( input, doc, 0 ); input.close(); HTMLEditorKit htmlKit = new HTMLEditorKit(); StringWriter output = new StringWriter(); htmlKit.write( output, doc, 0, doc.getLength()); String html = output.toString();
And then display the HTML?
Roland Tepp : Nice hack ... although I am bit afraid of how does this conversion play along with various tab stop options we presently use in our RTF documents. -
You might want to use the Swing control with the AWT/SWT bridge. I used this to embed OpenOffice into an SWT app:
package ooswtviewer; import java.awt.Panel; import com.sun.star.awt.XView; import com.sun.star.beans.Property; import com.sun.star.beans.UnknownPropertyException; import com.sun.star.beans.XPropertySet; import com.sun.star.comp.beans.Frame; import com.sun.star.comp.beans.NoConnectionException; import com.sun.star.comp.beans.OOoBean; import com.sun.star.comp.beans.OfficeDocument; import com.sun.star.drawing.XDrawView; import com.sun.star.frame.XController; import com.sun.star.frame.XDesktop; import com.sun.star.frame.XFrame; import com.sun.star.frame.XFramesSupplier; import com.sun.star.frame.XLayoutManager; import com.sun.star.frame.XModel; import com.sun.star.lang.WrappedTargetException; import com.sun.star.ui.XUIElement; import com.sun.star.uno.Any; import com.sun.star.uno.UnoRuntime; import com.sun.star.uno.XInterface; import com.sun.star.view.XViewSettingsSupplier; /** * Code based on example from http://www.eclipsezone.com/eclipse/forums/t48966.html * * @author Aaron digulla */ public class OOoSwtViewer extends Panel { private static final String RESOURCE_TOOLBAR_TEXTOBJECTBAR = "private:resource/toolbar/textobjectbar"; private static final String RESOURCE_TOOLBAR_STANDARDBAR = "private:resource/toolbar/standardbar"; private static final String RESOURCE_MENUBAR = "private:resource/menubar/menubar"; private static final long serialVersionUID = -1408623115735065822L; private OOoBean aBean; public OOoSwtViewer() { super(); aBean = new OOoBean(); setLayout(new java.awt.BorderLayout()); add(aBean, java.awt.BorderLayout.CENTER); aBean.setAllBarsVisible (false); } public XPropertySet getXPropertySet () { return getXPropertySet (getFrame ()); } public XPropertySet getXPropertySet (Object o) { return (XPropertySet)UnoRuntime.queryInterface (XPropertySet.class, o); } public Frame getFrame () { try { return aBean.getFrame (); } catch (NoConnectionException e) { throw new OOException ("Error getting frame from bean", e); } } public XLayoutManager getXLayoutManager () { try { return (XLayoutManager)UnoRuntime.queryInterface (XLayoutManager.class, getXPropertySet ().getPropertyValue ("LayoutManager")); } catch (Exception e) { throw new OOException ("Error getting LayoutManager from bean's properties", e); } } public void setMenuBarVisible (boolean visible) { if (visible) getXLayoutManager ().showElement (RESOURCE_MENUBAR); else getXLayoutManager ().hideElement (RESOURCE_MENUBAR); } public void setStandardBarVisible (boolean visible) { if (visible) getXLayoutManager ().showElement (RESOURCE_TOOLBAR_STANDARDBAR); else getXLayoutManager ().hideElement (RESOURCE_TOOLBAR_STANDARDBAR); } public void setTextObjectBarVisible (boolean visible) { if (visible) getXLayoutManager ().showElement (RESOURCE_TOOLBAR_TEXTOBJECTBAR); else getXLayoutManager ().hideElement (RESOURCE_TOOLBAR_TEXTOBJECTBAR); } private Thread loadThread; private Exception loadException; public void setDocument(final String url) { loadThread = new Thread () { public void run() { try { aBean.loadFromURL(url, null); aBean.aquireSystemWindow(); setTextObjectBarVisible (false); // for (XUIElement e: getXLayoutManager ().getElements ()) // { // XInterface i = (XInterface)e.getRealInterface (); // System.out.println (e); // System.out.println (i); // printProperties (getXPropertySet (e)); // } /* System.out.println ("frame:"); printProperties (getXPropertySet ()); frame: Title=test - OpenOffice.org Writer IndicatorInterception=Any[Type[com.sun.star.task.XStatusIndicator], null] LayoutManager=Any[Type[com.sun.star.frame.XLayoutManager], [Proxy:26506390,717ea70;msci[0];342169f1a1164ee688893a857f65b3e1,Type[com.sun.star.frame.XLayoutManager]]] DispatchRecorderSupplier=Any[Type[com.sun.star.frame.XDispatchRecorderSupplier], null] IsHidden=false */ XController controller = aBean.getDocument ().getCurrentController (); /* System.out.println ("controller:"); printProperties (getXPropertySet (controller)); controller: IsConstantSpellcheck=true IsHideSpellMarks=false LineCount=1 PageCount=1 */ /* System.out.println ("layoutManager:"); printProperties (getXPropertySet (getXLayoutManager ())); layoutManager: AutomaticToolbars=true HideCurrentUI=false LockCount=0 MenuBarCloser=true RefreshContextToolbarVisibility=false */ /* System.out.println ("document:"); printProperties (getXPropertySet (aBean.getDocument ())); OfficeDocument doc = aBean.getDocument (); ApplyFormDesignMode=false ApplyWorkaroundForB6375613=false AutomaticControlFocus=false BasicLibraries=Any[Type[com.sun.star.script.XLibraryContainer], [Proxy:14806696,73ca178;msci[0];342169f1a1164ee688893a857f65b3e1,Type[com.sun.star.script.XLibraryContainer]]] BuildId=680$9310 CharFontCharSet=1 CharFontCharSetAsian=1 CharFontCharSetComplex=1 CharFontFamily=3 CharFontFamilyAsian=6 CharFontFamilyComplex=6 CharFontName=Times New Roman CharFontNameAsian=Arial Unicode MS CharFontNameComplex=Tahoma CharFontPitch=2 CharFontPitchAsian=2 CharFontPitchComplex=2 CharFontStyleName= CharFontStyleNameAsian= CharFontStyleNameComplex= CharLocale=com.sun.star.lang.Locale@fb6354 CharacterCount=20 DialogLibraries=Any[Type[com.sun.star.script.XLibraryContainer], [Proxy:3556929,73a39c0;msci[0];342169f1a1164ee688893a857f65b3e1,Type[com.sun.star.script.XLibraryContainer]]] ForbiddenCharacters=Any[Type[com.sun.star.i18n.XForbiddenCharacters], [Proxy:11544872,7669148;msci[0];342169f1a1164ee688893a857f65b3e1,Type[com.sun.star.i18n.XForbiddenCharacters]]] HasValidSignatures=false HideFieldTips=false IndexAutoMarkFileURL= LockUpdates=false ParagraphCount=1 RecordChanges=false RedlineDisplayType=2 RedlineProtectionKey=[B@f593af RuntimeUID=10 ShowChanges=true TwoDigitYear=1930 WordCount=5 WordSeparator=() */ // System.out.println ("viewData:"); // printProperties (getXPropertySet (controller.getFrame ().getContainerWindow ())); XViewSettingsSupplier settingsSupplier = (XViewSettingsSupplier)UnoRuntime.queryInterface (XViewSettingsSupplier.class, controller); // System.out.println ("settingsSupplier:"); // printProperties (settingsSupplier.getViewSettings ()); settingsSupplier.getViewSettings ().setPropertyValue ("ShowVertRuler", Boolean.FALSE); settingsSupplier.getViewSettings ().setPropertyValue ("ShowHoriRuler", Boolean.FALSE); // Switch to Web Layout. This layout mode comes without gray border and the page borders automatically adujst to the frame settingsSupplier.getViewSettings ().setPropertyValue ("ShowOnlineLayout", Boolean.TRUE); // settingsSupplier.getViewSettings ().setPropertyValue ("ShowTextBoundaries", Boolean.TRUE); // XView view = (XView)UnoRuntime.queryInterface (XView.class, getFrame ()); // System.out.println ("drawView="+view); // printProperties (getXPropertySet (view)); /* XModel model = (XModel)UnoRuntime.queryInterface (XModel.class, doc); printProperties ("model", model); Same as getDocument() */ /* System.out.println ("Interfaces implemented by aBean.getDocument():"); for (Class c: OOoInspector.queryInterface (aBean.getDocument ())) System.out.println (" "+c.getName ()); com.sun.star.datatransfer.XTransferable com.sun.star.document.XDocumentInfoSupplier com.sun.star.document.XDocumentLanguages com.sun.star.document.XDocumentSubStorageSupplier com.sun.star.document.XEmbeddedScripts com.sun.star.document.XEventBroadcaster com.sun.star.document.XEventsSupplier com.sun.star.document.XLinkTargetSupplier com.sun.star.document.XRedlinesSupplier com.sun.star.document.XStorageBasedDocument com.sun.star.document.XViewDataSupplier com.sun.star.drawing.XDrawPageSupplier com.sun.star.embed.XVisualObject com.sun.star.frame.XLoadable com.sun.star.frame.XModel com.sun.star.frame.XModel2 com.sun.star.frame.XModule com.sun.star.frame.XStorable com.sun.star.frame.XStorable2 com.sun.star.script.provider.XScriptProviderSupplier com.sun.star.style.XAutoStylesSupplier com.sun.star.style.XStyleFamiliesSupplier com.sun.star.text.XBookmarksSupplier com.sun.star.text.XChapterNumberingSupplier com.sun.star.text.XDocumentIndexesSupplier com.sun.star.text.XEndnotesSupplier com.sun.star.text.XFootnotesSupplier com.sun.star.text.XLineNumberingProperties com.sun.star.text.XNumberingRulesSupplier com.sun.star.text.XPagePrintable com.sun.star.text.XReferenceMarksSupplier com.sun.star.text.XTextDocument com.sun.star.text.XTextEmbeddedObjectsSupplier com.sun.star.text.XTextFieldsSupplier com.sun.star.text.XTextFramesSupplier com.sun.star.text.XTextGraphicObjectsSupplier com.sun.star.text.XTextSectionsSupplier com.sun.star.text.XTextTablesSupplier com.sun.star.ui.XUIConfigurationManagerSupplier com.sun.star.util.XCloseable com.sun.star.util.XCloseBroadcaster com.sun.star.util.XLinkUpdate com.sun.star.util.XModifiable com.sun.star.util.XModifiable2 com.sun.star.util.XModifyBroadcaster com.sun.star.util.XNumberFormatsSupplier com.sun.star.util.XRefreshable com.sun.star.util.XReplaceable com.sun.star.util.XSearchable com.sun.star.view.XPrintable com.sun.star.view.XPrintJobBroadcaster com.sun.star.view.XRenderable com.sun.star.xforms.XFormsSupplier */ /* System.out.println ("Interfaces implemented by controller:"); for (Class c: OOoInspector.queryInterface (controller)) System.out.println (" "+c.getName ()); com.sun.star.awt.XUserInputInterception com.sun.star.datatransfer.XTransferableSupplier com.sun.star.frame.XController com.sun.star.frame.XControllerBorder com.sun.star.frame.XDispatchInformationProvider com.sun.star.frame.XDispatchProvider com.sun.star.task.XStatusIndicatorSupplier com.sun.star.text.XRubySelection com.sun.star.text.XTextViewCursorSupplier com.sun.star.ui.XContextMenuInterception com.sun.star.view.XControlAccess com.sun.star.view.XFormLayerAccess com.sun.star.view.XSelectionSupplier com.sun.star.view.XViewSettingsSupplier */ /* System.out.println ("Interfaces implemented by frame:"); for (Class c: OOoInspector.queryInterface (getFrame ())) System.out.println (" "+c.getName ()); com.sun.star.awt.XFocusListener com.sun.star.awt.XTopWindowListener com.sun.star.awt.XWindowListener com.sun.star.document.XActionLockable com.sun.star.frame.XComponentLoader com.sun.star.frame.XDispatchInformationProvider com.sun.star.frame.XDispatchProvider com.sun.star.frame.XDispatchProviderInterception com.sun.star.frame.XFrame com.sun.star.frame.XFramesSupplier com.sun.star.task.XStatusIndicatorFactory com.sun.star.util.XCloseable com.sun.star.util.XCloseBroadcaster */ /* XFramesSupplier frames = OOoInspector.queryInterface (XFramesSupplier.class, getFrame ()); printProperties ("frames", frames); for (int i=0; i<frames.getFrames ().getCount (); i++) { XFrame frame = (XFrame)frames.getFrames ().getByIndex (i); printProperties ("Frame "+i, frame); } frames=[Proxy:16382237,6ace84c;msci[0];342169f1a1164ee688893a857f65b3e1,Type[com.sun.star.frame.XFramesSupplier]] Title=test - OpenOffice.org Writer IndicatorInterception=Any[Type[com.sun.star.task.XStatusIndicator], null] LayoutManager=Any[Type[com.sun.star.frame.XLayoutManager], [Proxy:22149392,76bd794;msci[0];342169f1a1164ee688893a857f65b3e1,Type[com.sun.star.frame.XLayoutManager]]] DispatchRecorderSupplier=Any[Type[com.sun.star.frame.XDispatchRecorderSupplier], null] IsHidden=false */ XPropertySet p = getXPropertySet (getFrame ()); Any any = (Any)p.getPropertyValue ("LayoutManager"); System.out.println (any); System.out.println (any.getClass ().getName ()); XLayoutManager layoutManager = (XLayoutManager)any.getObject (); printProperties ("layoutManager", layoutManager); /* printProperties ("containerWindow", getFrame ().getContainerWindow ()); containerWindow=[Proxy:11970262,6d33e60;msci[0];342169f1a1164ee688893a857f65b3e1,Type[com.sun.star.awt.XWindow]] null */ /* printProperties ("componentWindow", getFrame ().getComponentWindow ()); componentWindow=[Proxy:25380515,8657cc4;msci[0];342169f1a1164ee688893a857f65b3e1,Type[com.sun.star.awt.XWindow]] null */ } catch (Exception e) { e.printStackTrace (); } } }; if (1 == 1) loadThread.start (); else loadThread.run (); } /** closes the bean viewer and tries to terminate OOo. */ public void terminate() throws NoConnectionException { setVisible(false); XDesktop xDesktop = null; xDesktop = aBean.getOOoDesktop(); aBean.stopOOoConnection(); if (xDesktop != null) xDesktop.terminate(); } /** closes the bean viewer, leaves OOo running. */ public void close() { setVisible(false); aBean.stopOOoConnection(); } public void printProperties (String name, Object obj) { System.out.println (name+"="+obj); if (obj != null) printProperties (getXPropertySet (obj)); } public void printProperties (XPropertySet set) { if (set == null) { System.out.println ("null"); return; } for (Property p: set.getPropertySetInfo ().getProperties ()) { try { System.out.println (p.Name+"="+set.getPropertyValue (p.Name)); } catch (Exception e) { throw new OOException ("Error getting value of property "+p.Name, e); } } } }
You can use the control like this:
package ooswtviewer; import java.awt.BorderLayout; import java.awt.Frame; import java.awt.Panel; import java.io.File; import javax.swing.JRootPane; import org.eclipse.swt.SWT; import org.eclipse.swt.awt.SWT_AWT; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; /** * Code based on example from http://www.eclipsezone.com/eclipse/forums/t48966.html * * @author Aaron Digulla */ public class OOoSwtSnippet { public static void main(String[] args) { OOoSwtSnippet obj = new OOoSwtSnippet (); try { obj.run (args); } catch (Exception e) { e.printStackTrace (); } } public void run (String[] args) throws Exception { final Display display = new Display(); final Shell shell = new Shell(display); shell.setLayout(new FillLayout()); Composite composite = new Composite(shell, SWT.NO_BACKGROUND | SWT.EMBEDDED); System.setProperty("sun.awt.noerasebackground", "true"); /* Create and setting up frame */ Frame frame = SWT_AWT.new_Frame(composite); Panel panel = new Panel(new BorderLayout()) { public void update(java.awt.Graphics g) { paint(g); } }; frame.add(panel); JRootPane root = new JRootPane(); panel.add(root); java.awt.Container contentPane = root.getContentPane(); shell.setSize(800, 600); final OOoSwtViewer viewer = new OOoSwtViewer(); contentPane.add(viewer); // viewer.setDocument(NEW_WRITTER_DOCUMENT); File document = new File ("test.odt"); String url = document.getAbsoluteFile ().toURL ().toString (); url = "file:///" + url.substring (6); System.out.println ("Loading "+url); viewer.setDocument(url); shell.setText ("OOoSwtSnippet"); shell.open(); shell.addDisposeListener(new DisposeListener() { public void widgetDisposed(DisposeEvent e) { try { viewer.close(); } catch (RuntimeException exception) { exception.printStackTrace(); } } }); while (!shell.isDisposed()) { if (!display.readAndDispatch()) display.sleep(); } display.dispose(); } }
OOException is a RuntimeException:
package ooswtviewer; /** * Wrapper for all OO exceptions to keep throws clauses in check * * @author Aaron Digulla */ public class OOException extends RuntimeException { public OOException () { super (); } public OOException (String message, Throwable cause) { super (message, cause); } public OOException (String message) { super (message); } public OOException (Throwable cause) { super (cause); } }
Roland Tepp : Not really - I can't force everyone to install OOo alongside with my application and neither can I expect people to have OOo installed on every desktop (hell, even MS Office is not available on every target desktop)Aaron Digulla : I'm not sure how much "install" you'd have to do. It should be enough to have the JAR and all DLLs of the OO install in the application directory, set -Djava.library.path correctly and it should work.Roland Tepp : Still, this would pump up the already significant install package even more...Aaron Digulla : That you can do something doesn't mean you should. I'm giving you options; you must decide which option fits all those petty details which you didn't mention since you didn't want to spend three days on the question :) -
http://sites.google.com/site/anshunjain/eclipse-musings/eclipse-hacks/eclipse-richt-text-editor
-
Actuall, I've just found another widget that is quite promising atm:
0 comments:
Post a Comment