Hello allirpa,

On Friday 06 March 2009, 23:38, allirpa wrote:
> is there a way how to access math objects available in open office using
> java?

the API to *access* differs a little in Writer from the other apps. In Writer 
you have com.sun.star.text.XTextEmbeddedObjectsSupplier to access all the 
embedded objects, then check the CLSID (078B7ABA-54FC-457F-8551-6147e776a997) 
to see if it's an OOo Math object [see code attached]

> i am trying to make an addon for open office which will enable users to
> insert equations without using OO.o Math.
>
> Here's how it should work: there will be a button in the toolbar and when
> it is clicked, a WYSIWYG editor would popup and the user would just have to
> click buttons to insert math objects and make their own equations. when

isn't this what already does OOo Math when called from within another 
application (vs. standalone)?

> they're done, they should be able to insert the equation that they made in
> the document.
>
> is that even possible?

inserting an OOo Math embedded object is very simple [see code attached]

> i am using OpenOffice 2.4, 

then you're done, you'll better update to OOo 3.0, because IIRC there are 
issue on OOo 2.4 that don't let the object resize [see code attached for a 
work-around]

> java, netbeans 6.5.
the code attached uses the Scripting framework [put both files attached in your 
OOo user dir.: user/Scripts/java/HelloMath/], but works with NetBeans, 
following the instructions in 
http://wiki.services.openoffice.org/wiki/Scripting_in_Java_with_NetBeans_IDE 
[didn't have time to update this completely, just the Linux text. Feel free to 
fix it if you find Windows errors]


Regards
-- 
Ariel Constenla-Haile
La Plata, Argentina


"Aus der Kriegsschule des Lebens
                - Was mich nicht umbringt,
        macht mich härter."
                Nietzsche Götzendämmerung, Sprüche und Pfeile, 8.
import com.sun.star.beans.XPropertySet;
import com.sun.star.container.XIndexAccess;
import com.sun.star.container.XNameAccess;
import com.sun.star.document.XEmbeddedObjectSupplier2;
import com.sun.star.frame.XController;
import com.sun.star.frame.XModel;
import com.sun.star.lang.Locale;
import com.sun.star.lang.XComponent;
import com.sun.star.lang.XMultiServiceFactory;
import com.sun.star.lang.XServiceInfo;
import com.sun.star.script.provider.XScriptContext;
import com.sun.star.text.ControlCharacter;
import com.sun.star.text.TextContentAnchorType;
import com.sun.star.text.XDependentTextField;
import com.sun.star.uno.UnoRuntime;
import com.sun.star.text.XTextDocument;
import com.sun.star.text.XTextRange;
import com.sun.star.text.XTextContent;
import com.sun.star.text.XTextCursor;
import com.sun.star.text.XTextEmbeddedObjectsSupplier;
import com.sun.star.text.XTextFieldsSupplier;
import com.sun.star.uno.AnyConverter;
import com.sun.star.util.XNumberFormats;
import com.sun.star.util.XNumberFormatsSupplier;
import com.sun.star.util.XRefreshable;
import com.sun.star.view.XSelectionSupplier;

public class HelloMath {

    /**
     * this is FIXED
     */
    public static String OOO_MATH_CLSID = "078B7ABA-54FC-457F-8551-6147e776a997";
    /**
     * this can be customized (d.i. only "OOoMathFormula" part, the field master name)
     */
    public static String OOO_MATH_SEQ_FIELDMASTER_NAME = "OOoMathFormula";
    public static String OOO_MATH_SEQ_FIELDMASTER = "com.sun.star.text.FieldMaster.SetExpression";

    /**
     *
     * @param xScriptContext
     */
    public static void accessFormulae(XScriptContext xScriptContext) {
        XTextDocument xTextDocument = (XTextDocument) UnoRuntime.queryInterface(
                XTextDocument.class, xScriptContext.getDocument());
        if (xTextDocument == null) {
            System.out.println("This isn't a text document!");
            return;
        }

        XTextEmbeddedObjectsSupplier xSupplier =
                (XTextEmbeddedObjectsSupplier) UnoRuntime.queryInterface(
                XTextEmbeddedObjectsSupplier.class, xTextDocument);

        XNameAccess xEmbeddedObjects = xSupplier.getEmbeddedObjects();
        XIndexAccess xIndexAccess = (XIndexAccess) UnoRuntime.queryInterface(
                XIndexAccess.class, xEmbeddedObjects);

        for (int i = 0; i < xIndexAccess.getCount(); i++) {
            try {
                Object object = xIndexAccess.getByIndex(i);

                XPropertySet xPropertySet = (XPropertySet) UnoRuntime.queryInterface(
                        XPropertySet.class, object);
                String sCLSID = AnyConverter.toString(xPropertySet.getPropertyValue("CLSID"));

                if (sCLSID.equals(OOO_MATH_CLSID)) {

                    XEmbeddedObjectSupplier2 xEmbeddedObjectSupplier =
                            (XEmbeddedObjectSupplier2) UnoRuntime.queryInterface(
                            XEmbeddedObjectSupplier2.class, object);
                    XComponent xEmbeddedObjectModel = xEmbeddedObjectSupplier.getEmbeddedObject();

                    XPropertySet xFormulaProperties = (XPropertySet) UnoRuntime.queryInterface(
                            XPropertySet.class, xEmbeddedObjectModel);

                    String sFormula = AnyConverter.toString(
                            xFormulaProperties.getPropertyValue("Formula"));

                    System.out.printf(
                            "Found an OOo Math formula.\nFormula: %s%n%n",
                            sFormula);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }


    /**
     *
     * @param xScriptContext
     */
    public static void insertFormula(XScriptContext xScriptContext) {
        XTextDocument xTextDocument = (XTextDocument) UnoRuntime.queryInterface(
                XTextDocument.class, xScriptContext.getDocument());
        if (xTextDocument == null) {
            System.out.println("This isn't a text document!");
            return;
        }
        
        XModel xModel = (XModel) UnoRuntime.queryInterface(
                XModel.class, xTextDocument);
        
        XController xController = xModel.getCurrentController();
        // that the Model knows about the View's selection is a non-sense
        // Object aSelection = xModel.getCurrentSelection();

        /**
         * The writer controller implementation supports the interface
         * com.sun.star.view.XSelectionSupplier that returns the object
         * that is currently selected in the user interface.
         *
         * Its method getSelection() returns an any that may contain
         * different kind of objects depending on the selection:
         */
        XSelectionSupplier xSelectionSupplier = (XSelectionSupplier)
                UnoRuntime.queryInterface(XSelectionSupplier.class, xController);
        XServiceInfo xServiceInfo = (XServiceInfo) UnoRuntime.queryInterface(
                XServiceInfo.class, xSelectionSupplier.getSelection());

        if ( xServiceInfo.supportsService("com.sun.star.text.TextRanges") ) {
            /**
             * Selection: Text
             *
             * In this case, not only text in the body text may be selected,
             * but also text inside a frame, or atext table's cell
             * (but only the text inside the cell, not the whole cell).
             *
             * As the user can select multiple texts at the same time
             * (selecting while pressing Ctrl key), for example
             * text inside a frame, a text table, the body text, a foot note, etc.
             * getSelection() returns an XIndexAccess.
             *
             * Note that when there is nothing selected, and there is only the
             * insertion point, getSelection() will NOT return a null reference,
             * BUT an XIndexAccess with only one text range at index zero
             * pointing to the view cursor.
             */

            XIndexAccess xIndexAccess = (XIndexAccess)
                    UnoRuntime.queryInterface(XIndexAccess.class, xServiceInfo);
            int nCount = xIndexAccess.getCount();

            /**
             *  Testing possible getCount() return values...
             *
             *      * no selection, just the insertion point ==> getCount() = 1
             *      * 1 selection   ==>     getCount() = 1
             *      * 2 selections  ==>     getCount() = 3
             *      * 3 selections  ==>     getCount() = 4
             *      * 4 selections  ==>     getCount() = 5
             *
             * When nothing is selected, getCount() returns ONE: a XTextRange
             * pointing to the current view cursor's insertion point.
             *
             * When only one text range is selected, getCount() still returns ONE.
             *
             * When there are two or more text ranges selected, getCount()
             * always returns the actual number of text ranges selected PLUS one:
             * the current view cursor's insertion point.
             * For example, with 2 text ranges selected, getCount() returns 3:
             * the two text ranges and the insertion point.
             *
             * When getCount() returns 0 (zero), there is nothing selected
             * and not even an insertion point (for example when you are drawing
             * a drawing shape, a control or a text frame).
             *
             * The PROBLEM is when getCount() return 1 : is there actually a
             * text range selected, or is it only the cursor's  insertion point?
             *
             * The solution to this problem is to create a text cursor for
             * this text range and check the text cursor's state employing
             * XTextCursor::isCollapsed(), to see if the start and end positions
             * of this cursor are the same. If yes, then nothing is selected,
             * and it's just the cursor's insertion point.
             *
             * Cheking the lenght of the text range's string is not a
             * languege independent solution (for example, OOo Basic strings
             * can only hold up to 65535 characters, so a longer string will
             * have a length of zero).
             */

            XTextRange xTextRange = null;
            XTextCursor xTextCursor = null;

            // check that this is only the insertion point...
            if ( nCount == 1 ) {
                try {
                    // create a text cursor and check if it is collapsed
                    xTextRange = (XTextRange) UnoRuntime.queryInterface(
                        XTextRange.class, xIndexAccess.getByIndex(0));
                    xTextCursor = xTextRange.getText().createTextCursorByRange(xTextRange);

                    if ( xTextCursor.isCollapsed() ){
                        System.out.println("\nNothing selected, " +
                                "it is only the insertion point;" +
                                "so we can safely insert a formula...");
                        XMultiServiceFactory xDocFactory =
                                (XMultiServiceFactory) UnoRuntime.queryInterface(
                                XMultiServiceFactory.class, xTextDocument);
                        insertMathFormula(xDocFactory, xTextRange,
                                "{ { 6 over 7  times  8 }  + 5 }  over 10");
                    }
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        }
    }

    /**
     *
     * @param xScriptContext
     */
    public static void insertFormulaWithField(XScriptContext xScriptContext) {
        XTextDocument xTextDocument = (XTextDocument) UnoRuntime.queryInterface(
                XTextDocument.class, xScriptContext.getDocument());
        if (xTextDocument == null) {
            System.out.println("This isn't a text document!");
            return;
        }

        XModel xModel = (XModel) UnoRuntime.queryInterface(
                XModel.class, xTextDocument);
        XController xController = xModel.getCurrentController();
        XSelectionSupplier xSelectionSupplier = (XSelectionSupplier)
                UnoRuntime.queryInterface(XSelectionSupplier.class, xController);
        XServiceInfo xServiceInfo = (XServiceInfo) UnoRuntime.queryInterface(
                XServiceInfo.class, xSelectionSupplier.getSelection());

        if ( xServiceInfo.supportsService("com.sun.star.text.TextRanges") ) {
            XIndexAccess xIndexAccess = (XIndexAccess)
                    UnoRuntime.queryInterface(XIndexAccess.class, xServiceInfo);
            int nCount = xIndexAccess.getCount();

            XTextRange xTextRange = null;
            XTextCursor xTextCursor = null;
            if ( nCount == 1 ) {
                try {
                    // create a text cursor and check if it is collapsed
                    xTextRange = (XTextRange) UnoRuntime.queryInterface(
                        XTextRange.class, xIndexAccess.getByIndex(0));
                    xTextCursor = xTextRange.getText().createTextCursorByRange(xTextRange);

                    if ( xTextCursor.isCollapsed() ){
                        System.out.println("\nNothing selected, " +
                                "it is only the insertion point;" +
                                "so we can safely insert a formula...");
                        XMultiServiceFactory xDocFactory =
                                (XMultiServiceFactory) UnoRuntime.queryInterface(
                                XMultiServiceFactory.class, xTextDocument);
                        insertMathFormulaWithSeqField(xDocFactory, xTextRange,
                                "{ { 6 over 7  times  8 }  + 5 }  over 10",
                                "Formula Nr. $ ");
                        refreshTextFields(xTextDocument);
                    }
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        }
    }


    /**
     *
     * @param xDocFactory
     * @param xTextRange
     * @param sFormula
     * @return
     */
    private static XTextContent insertMathFormula(
            XMultiServiceFactory xDocFactory, XTextRange xTextRange, String sFormula) {
        XTextContent xTextContent = null;
        try {
            xTextContent = (XTextContent) UnoRuntime.queryInterface(
                    XTextContent.class, xDocFactory.createInstance(
                    "com.sun.star.text.TextEmbeddedObject"));

            XPropertySet xPropertySet = (XPropertySet) UnoRuntime.queryInterface(
                    XPropertySet.class, xTextContent);

            xPropertySet.setPropertyValue("CLSID", OOO_MATH_CLSID);
            xPropertySet.setPropertyValue("AnchorType", TextContentAnchorType.AS_CHARACTER);

            insertTextContent(xTextRange, xTextContent);

            XEmbeddedObjectSupplier2 xEmbeddedObjectSupplier =
                    (XEmbeddedObjectSupplier2) UnoRuntime.queryInterface(
                    XEmbeddedObjectSupplier2.class, xTextContent);
            XComponent xEmbeddedObjectModel = xEmbeddedObjectSupplier.getEmbeddedObject();

            XPropertySet xFormulaProperties = (XPropertySet) UnoRuntime.queryInterface(
                    XPropertySet.class, xEmbeddedObjectModel);

            xFormulaProperties.setPropertyValue("Formula", sFormula);

            /**
             * to solve the issue with the formula size:
             */
            /*XGraphic xGraphic = xEmbeddedObjectSupplier.getReplacementGraphic();
            XPropertySet xGraphicPropertySet = (XPropertySet) UnoRuntime.queryInterface(
                    XPropertySet.class, xGraphic);
            Object any = xGraphicPropertySet.getPropertyValue("Size100thMM");
            Size aSize = null;
            try {
                if (!AnyConverter.isVoid(any)) {
                    aSize = (Size) AnyConverter.toObject(Size.class, any);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            if (aSize != null && aSize.Width > 0 && aSize.Height > 0) {
                xPropertySet.setPropertyValue("Width", aSize.Width);
                xPropertySet.setPropertyValue("Height", aSize.Height);
            }*/
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            return xTextContent;
        }
    }

    /**
     *
     * @param xDocFactory
     * @param xTextRange
     * @param sFormula
     * @param sCaption
     * @return
     */
    private static XTextContent insertMathFormulaWithSeqField(
            XMultiServiceFactory xDocFactory, XTextRange xTextRange, String sFormula, String sCaption) {
        XTextContent xTextContent = null;
        try {
            xTextContent = insertMathFormula(xDocFactory, xTextRange, sFormula);

            XDependentTextField xSeqField = createSequentialField(
                    xDocFactory, getOrCreateFieldMaster(xDocFactory));

            XTextRange xFormulaAnchor = xTextContent.getAnchor();
            XTextCursor xFormulaCursor = xFormulaAnchor.getText().createTextCursorByRange(
                    xFormulaAnchor.getStart());
            insertText(xFormulaCursor, sCaption);

            int idx = sCaption.lastIndexOf('$');
            if (idx > -1) {
                xFormulaCursor.goLeft( (short)(sCaption.length() - idx), false);
                xFormulaCursor.goRight( (short)1, true);
                insertTextContent(xFormulaCursor, xSeqField, true);
            } else
                insertTextContent(xFormulaCursor, xSeqField, false);

        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            return xTextContent;
        }
    }

    private static XDependentTextField createSequentialField(
            XMultiServiceFactory xDocFactory,XPropertySet xFieldMaster){
        return createSetExpression( xDocFactory, xFieldMaster,
                OOO_MATH_SEQ_FIELDMASTER_NAME + "+1",
                queryOrAddNumberFormat( (XComponent) UnoRuntime.queryInterface(
                XComponent.class, xDocFactory), "#.##0,00"),
                com.sun.star.style.NumberingType.ARABIC,
                com.sun.star.text.SetVariableType.SEQUENCE);
    }


    private static XPropertySet getOrCreateFieldMaster(XMultiServiceFactory xDocFactory){
        return createMasterSetExpression(
                xDocFactory, OOO_MATH_SEQ_FIELDMASTER_NAME, (byte)-1,
                "", com.sun.star.text.SetVariableType.SEQUENCE);
    }


    private static void refreshTextFields(XTextDocument xTextDocument) {
        XTextFieldsSupplier xTextFieldsSupplier =
                (XTextFieldsSupplier) UnoRuntime.queryInterface(
                XTextFieldsSupplier.class,  xTextDocument);
        XRefreshable xRefreshable = (XRefreshable) UnoRuntime.queryInterface(
                XRefreshable.class, xTextFieldsSupplier.getTextFields());
        xRefreshable.refresh();
    }

    //**************************************************************************

    /**
     *
     * @param xDocFactory
     * @param sFieldName
     * @param nChapNumLevel
     * @param sNumSeparator
     * @param nSubType
     * @return
     */
    private static XPropertySet createMasterSetExpression(
                                                    XMultiServiceFactory xDocFactory,
                                                    String sFieldName,
                                                    byte nChapNumLevel,
                                                    String sNumSeparator,
                                                    short nSubType) {

        XPropertySet xFieldMaster = null;
        String fieldMasterName = OOO_MATH_SEQ_FIELDMASTER + "." + sFieldName;
        try {
            XTextFieldsSupplier xTextFieldsSupplier =
                    (XTextFieldsSupplier) UnoRuntime.queryInterface(
                    XTextFieldsSupplier.class, xDocFactory);

            XNameAccess xFieldMasterAccess = xTextFieldsSupplier.getTextFieldMasters();

            if (xFieldMasterAccess.hasByName(fieldMasterName)) {

                xFieldMaster = (XPropertySet) UnoRuntime.queryInterface(
                        XPropertySet.class,
                        xFieldMasterAccess.getByName(fieldMasterName));
            } else {
                xFieldMaster = (XPropertySet) UnoRuntime.queryInterface(
                        XPropertySet.class, xDocFactory.createInstance(OOO_MATH_SEQ_FIELDMASTER));

                if (xFieldMaster != null) {

                    xFieldMaster.setPropertyValue("Name", sFieldName);
                    xFieldMaster.setPropertyValue("ChapterNumberingLevel", new Byte(nChapNumLevel));
                    xFieldMaster.setPropertyValue("NumberingSeparator",  sNumSeparator);
                    xFieldMaster.setPropertyValue("SubType", new Short(nSubType));
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            return xFieldMaster;
        }
    }

    private static XDependentTextField createSetExpression(
                                                            XMultiServiceFactory xDocFactory,
                                                            XPropertySet xFieldMaster,
                                                            String sContent,
                                                            int nNumberFormat,
                                                            short nNumberingType,
                                                            short nSubType) {
        XDependentTextField xDependentTextField = null;
        try {
            xDependentTextField = (XDependentTextField) UnoRuntime.queryInterface(
                    XDependentTextField.class, xDocFactory.createInstance(
                    "com.sun.star.text.TextField.SetExpression"));
            XPropertySet xSetExpression = (XPropertySet) UnoRuntime.queryInterface(
                    XPropertySet.class, xDependentTextField);

            xSetExpression.setPropertyValue("Content", sContent);
            xSetExpression.setPropertyValue("SubType", new Short(nSubType));
            xSetExpression.setPropertyValue("NumberFormat", new Integer(nNumberFormat));
            xSetExpression.setPropertyValue("NumberingType", new Short(nNumberingType));

            xDependentTextField.attachTextFieldMaster(xFieldMaster);
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            return xDependentTextField;
        }
    }

    /**
     *
     * @param xComponent
     * @param sFormat
     * @return
     */
    private static int queryOrAddNumberFormat(XComponent xComponent, String sFormat){
        int nFormatCode = 0;
        try {
            XNumberFormatsSupplier xNumberFormatsSupplier =
                    (XNumberFormatsSupplier) UnoRuntime.queryInterface(
                    XNumberFormatsSupplier.class, xComponent);

            XNumberFormats xNumberFormats = xNumberFormatsSupplier.getNumberFormats();
            Locale aLocale = new Locale();
            nFormatCode = xNumberFormats.queryKey(sFormat, aLocale, false);
            if (nFormatCode == -1) {
                nFormatCode = xNumberFormats.addNew(sFormat, aLocale);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            return nFormatCode;
        }
    }

    private static void insertText(XTextRange xTextRange, String string) {
        xTextRange.getText().insertString(xTextRange, string, false);
    }

    private static void insertParaBreak(XTextRange xTextRange) {
        try {
            xTextRange.getText().insertControlCharacter(
                    xTextRange, ControlCharacter.PARAGRAPH_BREAK, false);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    private static void insertTextContent(XTextRange xTextRange, XTextContent xContent) {
        insertTextContent(xTextRange, xContent, false);
    }

    private static void insertTextContent(XTextRange xTextRange, XTextContent xContent, boolean bAbsorb) {
        try {
            xTextRange.getText().insertTextContent(xTextRange, xContent, bAbsorb);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

Attachment: parcel-descriptor.xml
Description: XML document

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to