Есть ли виджет отображения RTF в SWT

Я хотел бы отобразить документ RTF в приложении SWT (фактически Eclipse RCP).

Я знаю, что есть виджет Swing для отображения и редактирования текста RTF, но это Swing, и он совершенно чужд по внешнему виду при использовании на другой платформе (не говоря уже о том, что, насколько мне известно, он не отображал изображения и имел только ограниченная поддержка форматирования)

Другие варианты - использовать COM-интерфейс в Windows, но это работает только на платформе Windows и требует, чтобы на клиентской машине был установлен ActiveX RichEdit... что может сделать развертывание приложения довольно ужасным...

Каковы другие варианты отображения форматированных документов в приложении Eclipse/SWT?


person Roland Tepp    schedule 17.09.2008    source источник


Ответы (6)


Вы можете использовать swt.custom.StyledText. Он имеет множество функций для изменения внешнего вида текста. Но я не думаю, что он может загрузить или сохранить RTF прямо сейчас.

Я когда-то писал HTML-редактор с его помощью, но это довольно сложно, так как модель StyledText для добавления стилей к части текста настолько чужда по сравнению с тем, как работает HTML/RTF.

Насколько я знаю, вы можете напрямую печатать из этого элемента управления, который внутренне создает RTF-представление содержимого. Но это не совсем то, о чем вы просили.

person jrudolph    schedule 17.09.2008
comment
StyledText сохранит RTF в буфер обмена при копировании. Полным способом взломать значения RTF было бы выбрать все, скопировать и извлечь значение RTF из буфера обмена. - person Heath Borders; 18.09.2008
comment
Да, вы правы, это не то, что я спросил. StyledText может только копировать текст в буфер обмена как RTF и вообще не обрабатывает RTF в качестве входных данных... Использование StyledText в качестве основы для средства просмотра/редактора RTF, вероятно, было бы одним из способов начать, но как сам виджет, это не то, что Я хотел... - person Roland Tepp; 04.11.2008

Почему бы сначала не прочитать текст RTF в StyledDocument с помощью RTFEditorKit, а затем записать StyledDocument в StringWriter с помощью 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();

А затем отображать HTML?

person extraneon    schedule 04.10.2008
comment
Хороший хак ... хотя я немного боюсь того, как это преобразование сочетается с различными вариантами табуляции, которые мы сейчас используем в наших RTF-документах. - person Roland Tepp; 04.11.2008

Возможно, вы захотите использовать элемент управления Swing с мостом AWT/SWT. Я использовал это для встраивания OpenOffice в приложение SWT:

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);
            }
        }
    }

}

Вы можете использовать элемент управления следующим образом:

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 является 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);
    }

}
person Aaron Digulla    schedule 06.11.2008
comment
Не совсем - я не могу заставить всех устанавливать OOo вместе с моим приложением, и я также не могу ожидать, что люди будут устанавливать OOo на каждый рабочий стол (черт возьми, даже MS Office не доступен на каждом целевом рабочем столе) - person Roland Tepp; 17.02.2009
comment
Я не уверен, сколько вам нужно будет установить. Должно быть достаточно, чтобы JAR и все библиотеки DLL OO были установлены в каталоге приложения, правильно установили -Djava.library.path, и все должно работать. - person Aaron Digulla; 17.02.2009
comment
То, что вы можете что-то сделать, не означает, что вы должны это делать. Я даю вам варианты; вы должны решить, какой вариант подходит ко всем тем мелочам, которые вы не упомянули, так как не хотели тратить три дня на вопрос :) - person Aaron Digulla; 28.09.2009


На самом деле, я только что нашел еще один виджет, который весьма многообещающ:

http://onpositive.com/richtext

person Community    schedule 19.02.2010

Я не уверен, как это сделать без использования ActiveX. Если вы пойдете в этом направлении, возможно, вам стоит изучить контейнер IBM для Документы ActiveX, которые должны обеспечивать лучшую интеграцию документов.

person BlueVoid    schedule 03.10.2008
comment
То, что мы сейчас придумали, — это половина того, что я хотел. По сути, мы использовали JNI для вызова собственного элемента управления Windows RTF (того, который используется WodPad) — таким образом, нам не нужно беспокоиться о неприятных проблемах с развертыванием ActiveX, но все же это хак. - person Roland Tepp; 04.11.2008