OpenOffice.org Forum at OOoForum.orgThe OpenOffice.org Forum
 
 [Home]   [FAQ]   [Search]   [Memberlist]   [Usergroups]   [Register
 [Profile]   [Log in to check your private messages]   [Log in

Convert documents in OpenOffice from python

 
Post new topic   Reply to topic    OOoForum.org Forum Index -> OpenOffice.org Macros and API
View previous topic :: View next topic  
Author Message
StudInc
Newbie
Newbie


Joined: 21 Oct 2003
Posts: 1
Location: Oslo, Norway

PostPosted: Thu Oct 23, 2003 9:10 am    Post subject: Convert documents in OpenOffice from python Reply with quote

I have a few questions that I hope that someone could help me find answers to...

I would like to convert documents (mainly MS Word to PDF) using the filters in OpenOffice..
This I want to from a python-script by using the python-bridge....

The problem is that I can't find much information about using python and OpenOffice, so I hope that someone here could give me some tips about examples in python, or links to more documentation....

Question So the main questions are:
- is this possible?
- how shuold I get started with this?

PS: I have done the "Hello world"-example in the python-bridge manual.....
Back to top
View user's profile Send private message
DannyB
Moderator
Moderator


Joined: 02 Apr 2003
Posts: 3991
Location: Lawrence, Kansas, USA

PostPosted: Fri Oct 24, 2003 6:19 am    Post subject: Reply with quote

Quote:
I have a few questions that I hope that someone could help me find answers to.


I have a few answers that I hope someone will find helpful. Unfortunantly, the answer turned out with me posting a much longer set of code than I had intended. (See below.)


I have found that I can pretty much do anything in Python that I can do in Basic. The API, of course, works exactly the same way as in any other language.

So I would divide your question into two sub-problems.
1. How do I use the OOo API to convert documents from MS-Word to PDF.
2. How do I use python programs to drive OOo.

The first question has been answered countless times here in Macros and API. Basically get the Desktop object. Call it's loadComponentFromURL() method to import the word document. Now that you have the document, call its storeToURL() method to save it. Pass an array of com.sun.star.beans.PropertyValue arguments to the storeToURL to specify that you want it saved as PDF. I have written a Basic macro that converts batches of documents at a time. You can get it at OOoMacros.org, or the very latest version from here...
http://kosh.datateamsys.com/~danny/OOo/Tools/
I have posted other conversion examples in Basic here in Macros and API.

The second question has not been answered very well. I'm not sure that I can answer it very well either.

OOo includes its own Python interpreter, because of some sillyness in how the binary stdC library in OOo is different than the standard python distributions. So apparently, OOo compiles its own python such that it shares the same stdC lib as OOo.

You must run the python interpreter that is under the program directory in your OOo installation.

On Win XP I've managed to get IDLE to work from OOo's python interpreter. I did this by also having the same version of standard python installed on my machine. Then I wrote a BAT file in OOo's python directory which I use to start python. Without explaining how it works, here is MY own BAT file which I use to start up OOo's python with the interactive IDLE development environment....

Code:
@echo off
set PATH="C:\Program Files\OpenOffice.org1.1\program;%PATH%"

set PYTHONPATH=

Set PYTHONPATH=%PYTHONPATH%;C:\Danny\Danny's Python\Modules

set PYTHONPATH=%PYTHONPATH%;C:\Python22\
set PYTHONPATH=%PYTHONPATH%;C:\Python22\DLLs
set PYTHONPATH=%PYTHONPATH%;C:\Python22\lib
set PYTHONPATH=%PYTHONPATH%;C:\Python22\lib\lib-tk
set PYTHONPATH=%PYTHONPATH%;C:\Python22\lib\site-packages
set PYTHONPATH=%PYTHONPATH%;C:\python22\Tools\idle

set PYTHONPATH=%PYTHONPATH%;C:\Program Files\OpenOffice.org1.1\program
set PYTHONPATH=%PYTHONPATH%;C:\Program Files\OpenOffice.org1.1\program\python-core-2.2.2\lib

set PYTHONHOME=C:\Program Files\OpenOffice.org1.1\program\python-core-2.2.2

"C:\Program Files\OpenOffice.org1.1\program\python-core-2.2.2\bin\python.exe" C:\python22\Tools\idle\idle.py %1 %2 %3 %4 %5 %6 %7 %8 %9


As you can see, what it basically does is condition the environment variables so that OOo's python first finds its own stuff in its own directories, and then last will look in the standard python installation for stuff. Then I launch OOo's python, with a first argument that starts the idle.py file.

NOTE added on 2005-01-08
Be sure to see this additional note I added below.....
http://www.oooforum.org/forum/viewtopic.php?p=61477#61477

I get the benefit of an interactive IDLE development environment that drives OOo. Talk about productive! I can type in statements one at a time, and watch their effect on OOo. Even in Basic I usually have to type a few statements and run it. Type a few statements and run it. I can do the same in IDLE, but I can additionally type in single statements that alter live global variables that I have, and see the immediate effect on documents.
_________________
Want to make OOo Drawings like the colored flower design to the left?


Last edited by DannyB on Sat Jan 08, 2005 9:20 am; edited 2 times in total
Back to top
View user's profile Send private message
DannyB
Moderator
Moderator


Joined: 02 Apr 2003
Posts: 3991
Location: Lawrence, Kansas, USA

PostPosted: Fri Oct 24, 2003 6:44 am    Post subject: Reply with quote

Forgive me for rambling on, but I'll add some more to my last post.

Here is an example of a simple Python program that I just used.

Code:
import OOoLib
from OOoLib import *

cSourceFile = r'C:\Documents and Settings\dbrewer\Desktop\test.doc'
cSourceURL = pathnameToUrl( cSourceFile )

cTargetFile = r'C:\Documents and Settings\dbrewer\Desktop\test.pdf'
cTargetURL = pathnameToUrl( cTargetFile )

# Open the source document.
# No filter necessary.  OOo will figure it out from the .DOC extension.
oDoc = openURL( cSourceURL )

# Save the newly opened document.
# Use a tupple of property values.
# The only property value is the specification of what Filter to use for saving.
oDoc.storeToURL( cTargetURL, (createPropertyValue("FilterName","writer_pdf_Export"),) )


Does what you want. Short and simple.

I suppose I should have added an oDoc.dispose() to close the document, but I neglected to do this in a quickly thrown together example.

Did you NOT want the document to appear on screen? Well, then we need to pass an array of property values to the loadComponentFromURL(), which is actually inside my openURL function. The array would contain one PropertyValue whose name is "Hidden" and value is True.

Of course, the shortness is due to my standard library of useful routines. Lots of stuff is being imported from the import OOoLib statement.

Here is my standard library, which I've never posted before.

Code:


#   OOoLib          2003-08-29-01
#   by Danny Brewer
#
#   A module to easily work with OpenOffice.org.
#
#   Copyright (c) 2003 Danny Brewer
#   Anyone may run this code.
#   If you wish to modify or distribute this code, then
#    you are granted a license to do so under the terms
#    of the Gnu Lesser General Public License.
#   See:  http://www.gnu.org/licenses/lgpl.html




# Python libraries
import math
import string

# Danny's libraries
import HSBConversions

# OOo's libraries
import uno


#------------------------------------------------------------
#   Uno convenience functions
#------------------------------------------------------------


# The ServiceManager of the running OOo.
oServiceManager = False

def getServiceManager( cHost="localhost", cPort="8100" ):
    """Get the ServiceManager from the running OpenOffice.org.
        Then retain it in the global variable oServiceManager for future use.
    """
    global oServiceManager
    if not oServiceManager:
        # Get the uno component context from the PyUNO runtime
        oLocalContext = uno.getComponentContext()
       
        # Create the UnoUrlResolver on the Python side.
        oLocalResolver = oLocalContext.ServiceManager.createInstanceWithContext(
                                    "com.sun.star.bridge.UnoUrlResolver", oLocalContext )
       
        # Connect to the running OpenOffice.org and get its context.
        oContext = oLocalResolver.resolve( "uno:socket,host=" + cHost + ",port=" + cPort + ";urp;StarOffice.ComponentContext" )
       
        # Get the ServiceManager object
        oServiceManager = oContext.ServiceManager
    return oServiceManager


# This is the same as ServiceManager.createInstance( ... )
def createUnoService( cClass ):
    """A handy way to create a global objects within the running OOo.
    """
    oServiceManager = getServiceManager()
    oObj = oServiceManager.createInstance( cClass )
    return oObj




# The Desktop object.
oDesktop = False

def getDesktop():
    """An easy way to obtain the Desktop object from a running OOo.
    """
    global oDesktop
    if not oDesktop:
        oDesktop = createUnoService( "com.sun.star.frame.Desktop" )
    return oDesktop



# The CoreReflection object.
oCoreReflection = False

def getCoreReflection():
    global oCoreReflection
    if not oCoreReflection:
        oCoreReflection = createUnoService( "com.sun.star.reflection.CoreReflection" )
    return oCoreReflection



def createUnoStruct( cTypeName ):
    """Create a UNO struct and return it.
    """
    oCoreReflection = getCoreReflection()

    # Get the IDL class for the type name
    oXIdlClass = oCoreReflection.forName( cTypeName )

    # Create the struct.
    oReturnValue, oStruct = oXIdlClass.createObject( None )

    return oStruct



def createPropertyValue( cName=None, uValue=None, nHandle=None, nState=None ):
    """Create a com.sun.star.beans.PropertyValue struct and return it.
    """
    oPropertyValue = createUnoStruct( "com.sun.star.beans.PropertyValue" )

    if cName != None:
        oPropertyValue.Name = cName
    if uValue != None:
        oPropertyValue.Value = uValue
    if nHandle != None:
        oPropertyValue.Handle = nHandle
    if nState != None:
        oPropertyValue.State = nState

    return oPropertyValue




#------------------------------------------------------------
#   High level general purpose functions
#------------------------------------------------------------


def openURL( cUrl, tProperties=() ):
    """Open or Create a document from it's URL.
    New documents are created from URL's such as:
        private:factory/sdraw
        private:factory/swriter
        private:factory/scalc
        private:factory/simpress
    """
    oDesktop = getDesktop()
    oDocument = oDesktop.loadComponentFromURL( cUrl, "_blank", 0, tProperties )
    return oDocument


def makeDrawDocument():
    """Create a new OOo Draw document."""
    return openURL( "private:factory/sdraw" )


def makeWriterDocument():
    """Create a new OOo Writer document."""
    return openURL( "private:factory/swriter" )


def makeCalcDocument():
    """Create a new OOo Calc document."""
    return openURL( "private:factory/scalc" )


def makeImpressDocument():
    """Create a new OOo Impress document."""
    return openURL( "private:factory/simpress" )



#------------------------------------------------------------
#   Functions for working with Draw documents.
#------------------------------------------------------------



#   Notes about some properties and constants for shape objects...

    # LineStyle can be one of...
    #   com.sun.star.drawing.LineStyle.NONE
    #   com.sun.star.drawing.LineStyle.SOLID
    #   com.sun.star.drawing.LineStyle.DASH

    # CircleKind can be one of...
    #   com.sun.star.drawing.CircleKind.FULL
    #   com.sun.star.drawing.CircleKind.SECTION   ' a circle with a cut connected by two lines
    #   com.sun.star.drawing.CircleKind.CUT ' a circle with a cut connected by a line
    #   com.sun.star.drawing.CircleKind.ARC ' a circle with an open cut
   
    # FillStyle can be one of...
    #   com.sun.star.drawing.FillStyle.NONE
    #   com.sun.star.drawing.FillStyle.SOLID
    #   com.sun.star.drawing.FillStyle.GRADIENT
    #   com.sun.star.drawing.FillStyle.HATCH
    #   com.sun.star.drawing.FillStyle.BITMAP
   
    # TextHorizontalAdjust can be one of...
    #   com.sun.star.drawing.TextHorizontalAdjust.LEFT
    #   com.sun.star.drawing.TextHorizontalAdjust.CENTER
    #   com.sun.star.drawing.TextHorizontalAdjust.RIGHT
    #   com.sun.star.drawing.TextHorizontalAdjust.BLOCK
   
    # TextVerticalAdjust can be one of...
    #   com.sun.star.drawing.TextVerticalAdjust.TOP
    #   com.sun.star.drawing.TextVerticalAdjust.CENTER
    #   com.sun.star.drawing.TextVerticalAdjust.BOTTOM
    #   com.sun.star.drawing.TextVerticalAdjust.BLOCK
   
    # TextFitToSize can be one of...
    #    com.sun.star.drawing.TextFitToSizeType.NONE
    #    com.sun.star.drawing.TextFitToSizeType.PROPORTIONAL
    #    com.sun.star.drawing.TextFitToSizeType.ALLLINES
    #    com.sun.star.drawing.TextFitToSizeType.RESIZEATTR

# Useful code snippets...

    # Accessing pages of a drawing document.
    #   oDrawPage = oDrawDoc.getDrawPages().getByIndex( 0 )
    #   oDrawPage = oDrawDoc.getDrawPages().getCount()
    #   oDrawPage = oDrawDoc.getDrawPages().insertByIndex( 1 )



#------------------------------------------------------------
#   Document functions
#------------------------------------------------------------


def setDrawPageOrientationLandscape( oDrawPage ):
    """Pass in any GenericDrawPage object, and this changes it to landscape orientation,
     in addition to swapping the height/width as you would expect.
    """
    # Save some settings
    nOldWidth = oDrawPage.Width
    nOldHeight = oDrawPage.Height
    nOldBorderTop = oDrawPage.BorderTop
    nOldBorderLeft = oDrawPage.BorderLeft
    nOldBorderRight = oDrawPage.BorderRight
    nOldBorderBottom = oDrawPage.BorderBottom
   
    # Change so that it will PRINT in landscape
    oDrawPage.Orientation = uno.getConstantByName( "com.sun.star.view.PaperOrientation.LANDSCAPE" )

    # Now change some paper dimensions to match
    oDrawPage.Width = nOldHeight
    oDrawPage.Height = nOldWidth
    oDrawPage.BorderTop = nOldBorderRight
    oDrawPage.BorderLeft = nOldBorderTop
    oDrawPage.BorderRight = nOldBorderBottom
    oDrawPage.BorderBottom = nOldBorderLeft



#------------------------------------------------------------
#   Shape functions
#------------------------------------------------------------



def makeRectangleShape( oDrawDoc, oPosition=None, oSize=None ):
    """Create a new RectangleShape with an optional position and size."""
    oShape = makeShape( oDrawDoc, "com.sun.star.drawing.RectangleShape", oPosition, oSize )
    return oShape


def makeEllipseShape( oDrawDoc, oPosition=None, oSize=None ):
    """Create a new EllipseShape with an optional position and size."""
    oShape = makeShape( oDrawDoc, "com.sun.star.drawing.EllipseShape", oPosition, oSize )
    return oShape


def makeLineShape( oDrawDoc, oPosition=None, oSize=None ):
    """Create a new LineShape with an optional position and size."""
    oShape = makeShape( oDrawDoc, "com.sun.star.drawing.LineShape", oPosition, oSize )
    return oShape


def makeTextShape( oDrawDoc, oPosition=None, oSize=None ):
    """Create a new TextShape with an optional position and size."""
    oShape = makeShape( oDrawDoc, "com.sun.star.drawing.TextShape", oPosition, oSize )
    return oShape


def makePoint( nX, nY ):
    """Create a com.sun.star.awt.Point struct."""
    oPoint = createUnoStruct( "com.sun.star.awt.Point" )
    oPoint.X = nX
    oPoint.Y = nY
    return oPoint


def makeSize( nWidth, nHeight ):
    """Create a com.sun.star.awt.Size struct."""
    oSize = createUnoStruct( "com.sun.star.awt.Size" )
    oSize.Width = nWidth
    oSize.Height = nHeight
    return oSize


def findShapeByName( oShapes, cShapeName ):
    """Find a named shape within an XShapes interface.
    oShapes can be a drawing page, which supports the XShapes interface.
    Thus, you can find a named shape within a draw page, or within a grouped shape,
     or within a selection of sseveral shapes.
    """
    nNumShapes = oShapes.getCount()
    for i in range( nNumShapes ):
        oShape = oShapes.getByIndex( i )
        cTheShapeName = oShape.getName()
        if cTheShapeName == cShapeName:
            return oShape
    return None


def makeShape( oDrawDoc, cShapeClassName, oPosition=None, oSize=None ):
    """Create a new shape of the specified class.
    Position and size arguments are optional.
    """
    oShape = oDrawDoc.createInstance( cShapeClassName )

    if oPosition != None:
        oShape.Position = oPosition
    if oSize != None:
        oShape.Size = oSize

    return oShape



#------------------------------------------------------------
#   Color manipulation
#------------------------------------------------------------


def rgbColor( nRed, nGreen, nBlue ):
    """Return an integer which repsents a color.
    The color is specified in RGB notation.
    Each of nRed, nGreen and nBlue must be a number from 0 to 255.
    """
    return (int( nRed ) & 255) << 16 | (int( nGreen ) & 255) << 8 | (int( nBlue ) & 255)


def hsbColor( nHue, nSaturation, nBrightness ):
    """Return an integer which repsents a color.
    The color is specified in HSB notation.
    Each of nHue, nSaturation and nBrightness must be a number from 0.0 to 1.0.
    """
    nRed, nGreen, nBlue = HSBConversions.HSBtoRGB( nHue, nSaturation, nBrightness )
    return rgbColor( nRed, nGreen, nBlue )


def redColor( nColor ):
    """Return the Red component of a color as an integer from 0 to 255.
    nColor is an integer representing a color.
    This function is complimentary to the rgbColor function.
    """
    return (int( nColor ) >> 16) & 255


def greenColor( nColor ):
    """Return the Green component of a color as an integer from 0 to 255.
    nColor is an integer representing a color.
    This function is complimentary to the rgbColor function.
    """
    return (int( nColor ) >> 8) & 255


def blueColor( nColor ):
    """Return the Blue component of a color as an integer from 0 to 255.
    nColor is an integer representing a color.
    This function is complimentary to the rgbColor function.
    """
    return int( nColor ) & 255





#------------------------------------------------------------
#   Drawing routines
#------------------------------------------------------------


# Multiply this number by an OOo angle in 100'ths of a degree
#  to convert to radians.
nRadiansPerHundredthDegree = math.pi / 18000


def drawLine( oDrawDoc, oDrawPage, x1,y1, x2,y2, nLineColor=None ):
    """Draw a line from x1,y1 to x2,y2.  Optionally specify line color.
    This adds the LineShape to the page.
    The LineShape is returned.
    """
    # make sure size is non-zero
    #if x1 = x2: x2 = x1 + 1
    #if y1 = y2: y2 = y1 + 1

    oPosition = makePoint( x1, y1 )
    oSize = makeSize( x2-x1, y2-y1 )

    oShape = makeLineShape( oDrawDoc, oPosition, oSize )

    if nLineColor != None:
        oShape.LineColor = nLineColor
    #oShape.LineWidth = 0

    oDrawPage.add( oShape )
    return oShape


def drawLineVector( oDrawDoc, oDrawPage, x1,y1, nAngle,nDistance, nLineColor=None ):
    """Draw a line from x1,y1 in the direction of nAngle, for a distance of nDistance.
    nAngle is measured in radians, clockwise from the 3 O'Clock (east) direction.
    nDistance is in 1000ths of a centimeter.
    This adds the LineShape to the page.
    The LineShape is returned.
    """
    nDX = math.cos( nAngle ) * nDistance
    nDY = math.sin( nAngle ) * nDistance

    return drawLine( oDrawDoc, oDrawPage, x1,y1, x1+nDX,y1+nDY, nLineColor )


def drawAutoSizingText( oDrawDoc, oDrawPage,
                        cText, nHeight, nExtraWidthPercent=40 ):
    """Create a TextShape that will automatically resize its characters
     to its shape bounding rectangle.
    The TextShape is created with a specified height.
    The width is determined based on the natural character width of the
     text.
    The initial position of the text is -10000,-10000, so that the text is not visible.
    This returns the TextShape, which has already been added to the drawing page,
     at coordinates which make it invisible.
    You must set the object's Position property to make the text visible.
    (Hint: You may look at the Size property to help you determine where
     you want to place the text, for instance if you are trying to center
     it, or place it relative to some other shape object.)
    If you don't supply nExtraWidthPercent, then a default fudge factor is used.
    This is the percentage of the average character width, which is added to the shape's
     total width.
    """
    # Create TextShape
    oShape = makeTextShape( oDrawDoc, makePoint( -10000, -10000 ), makeSize( 1, 1 ) )

    # Add it to the page.
    oDrawPage.add( oShape )

    # Make text stick to upper left corner of the shape rather than centered within the shape.
    oShape.TextHorizontalAdjust = uno.getConstantByName( "com.sun.star.drawing.TextHorizontalAdjust.LEFT" )
    oShape.TextVerticalAdjust = uno.getConstantByName( "com.sun.star.drawing.TextVerticalAdjust.TOP" )

    # Make the shape auto-grow in size, based on the text.
    # Once we set the text, in the next step, the shape will grow to some
    #  unknown size, based on the current font in use.
    #oShape.TextAutoGrowHeight = True
    oShape.TextAutoGrowWidth = True

    # Set the text of the TextShape.
    # Because of the TextAutoGrowWidth, the shape now occupies some unknown size.
    oShape.setString( cText )

    # Get the shape's current size.
    nSaveHeight = oShape.Size.Height
    nSaveWidth = oShape.Size.Width

    # Make the shape NOT auto-grow in size, based on the text.
    #oShape.TextAutoGrowHeight = False
    oShape.TextAutoGrowWidth = False

    # This next setting causes the TextShape to automatically resize its characters
    #  to fit the size of the text shape.
    oShape.TextFitToSize = uno.getConstantByName( "com.sun.star.drawing.TextFitToSizeType.PROPORTIONAL" )

    # Calculate the new width, based on the desired height,
    #  and saved width/height ratio for the current font in use.
    nWidth = nSaveWidth * (float(nHeight) / nSaveHeight)

    nAverageCharacterWidth = nWidth / len( cText )

    nExtraWidth = nAverageCharacterWidth * (nExtraWidthPercent / 100.0)

    oShape.TextLeftDistance = nExtraWidth
    oShape.TextRightDistance = nExtraWidth
    nWidth = nWidth + 2 * nExtraWidth

    # Now resize the TextShape.
    oShape.Size.Width = nWidth
    oShape.Size.Height = nHeight

    return oShape


def drawArcPath( oDrawDoc, oDrawPage,
                 nStartX, nStartY, nStartAngle,
                 nArcAngle, nArcRadius, bTurnLeft ):
    """Draw an arc of a circle from a starting position and direction.
    The arc has a certian radius and arc angle,
     and turns either to the left or to the right.
    Parameters:
    nStartX and nStartY are the starting position of the "turtle".
    nStartAngle is the angle direction that the turtle is pointing,
     in 100'ths of a degree.
    An arc is drawn by moving the turtle forward and turning either left or right as it moves.
    nArcAngle is the angle of the arc describing the turtle's path,
     in 100'ths of a degree.
    nArcRadius is the radius of the arc describing the turtle's path.
    bTurnLeft is True if the turtle turns to the left, or False to turn to the right.
    Four values are returned.
    (1) the circle shape, (2) the new X position, (3) new Y position, and (4) new angle.
    Use the last three return values as initial values to draw another arc
     which is connected to the ending position of the arc just drawn.
    """

    # Figure out how big of a circle that the arc is a part of.
    nCircleDiameter = nArcRadius + nArcRadius
    oCircleSize = makeSize( nCircleDiameter, nCircleDiameter )

    # Figure out the position of the circle (ellipse) shape object.
    #
    # Determine the angle of the center point from the starting position.
    if bTurnLeft:
        nCenterPointAngle = nStartAngle + 9000
    else:
        nCenterPointAngle = nStartAngle - 9000
    # Convert to radians.
    nCenterPointAngle = nCenterPointAngle * nRadiansPerHundredthDegree
    # Determine where the center of the circle shape should be.
    nCenterX = nStartX + (nArcRadius * math.cos( nCenterPointAngle ))
    nCenterY = nStartY - (nArcRadius * math.sin( nCenterPointAngle ))
    oCirclePosition = makePoint( nCenterX - nArcRadius, nCenterY - nArcRadius )

    # Figure out what arc portion of the circle needs to be drawn.
    # Angles measures in 100'ths of a degree.
    if bTurnLeft:
        nCircleStartAngle = nStartAngle - 9000
        nCircleEndAngle = nCircleStartAngle + nArcAngle
    else:
        nCircleEndAngle = nStartAngle + 9000
        nCircleStartAngle = nCircleEndAngle - nArcAngle
 
    # Make the circle shape.
    oCircle = makeEllipseShape( oDrawDoc, oCirclePosition, oCircleSize )
    # Fill in its properties
    oCircle.FillStyle = uno.getConstantByName( "com.sun.star.drawing.FillStyle.NONE" )
    oCircle.CircleKind = uno.getConstantByName( "com.sun.star.drawing.CircleKind.ARC" )
    oCircle.CircleStartAngle = nCircleStartAngle
    oCircle.CircleEndAngle = nCircleEndAngle
    # Put it on the drawing
    oDrawPage.add( oCircle )

    # Figure out the ending turtle location and direction.
    if bTurnLeft:
        nEndAngle = nStartAngle - 9000 + nArcAngle
    else:
        nEndAngle = nStartAngle + 9000 - nArcAngle
    # Convert to radians
    nEndAngleRad = nEndAngle * nRadiansPerHundredthDegree
    # Ending Position
    nEndX = nCenterX + (nArcRadius * math.cos( nEndAngleRad ))
    nEndY = nCenterY - (nArcRadius * math.sin( nEndAngleRad ))
    # Ending angle
    if bTurnLeft:
        nEndAngle = normalizeOOoAngle( nEndAngle + 9000 )
    else:
        nEndAngle = normalizeOOoAngle( nEndAngle - 9000 )

    return oCircle, nEndX, nEndY, nEndAngle


def drawSpiralOfArcs( oDrawDoc, oDrawPage,
                      nStartX, nStartY, nStartAngle,
                      nArcAngle, nArcRadius, bTurnLeft,
                      nNumArcs,
                      nRadiusGrowthMultiplier=1.0, nRadiusGrowthAddIn=0 ):
    """Draw a spiral starting from a certian position and direction.
    The spiral turns either towards the left or towards the right.
    Parameters:
    nStartX and nStartY are the starting position of the "turtle".
    nStartAngle is the angle direction that the turtle is pointing,
     in 100'ths of a degree.
    A spiral is drawn by moving the turtle forward and turning either left or right as it moves.
    nArcAngle is the angle of the first arc of the spiral,
     in 100'ths of a degree.
    nArcRadius is the radius of the first arc of the spiral.
    bTurnLeft is True if the turtle turns to the left, or False to turn to the right.
    nNumArcs is the number of arcs which are drawn.
    nRadiusGrowthMultiplier - the radius of the arc is multiplied by this after each arc is drawn.
     Use a number such as 1.1 to cause the radius to grow geometrically as the spiral turns.
    nRadiusGrowthAddIn - this is added to the radius after each arc.
     Use a number, such as the original nArcRadius / number of arcs in a complete circle to cause the radius to grow arithmeteically as the spiral turns.
    Four values are returned.
    (1) the spiral shape, (2) the new X position, (3) new Y position, and (4) new angle.
    Use the last three return values as initial values to draw another arc
     which is connected to the ending position of the arc just drawn.
    """
    nX = nStartX
    nY = nStartY
    nAngle = nStartAngle

    oShapesToGroup = createUnoService( "com.sun.star.drawing.ShapeCollection" )
    for i in range( nNumArcs - 1 ):
        oArcShape, nX, nY, nAngle = drawArcPath( oDrawDoc, oDrawPage, nX, nY, nAngle, nArcAngle, nArcRadius, bTurnLeft )
        nArcRadius = nArcRadius * nRadiusGrowthMultiplier + nRadiusGrowthAddIn

        oShapesToGroup.add( oArcShape )
    oSpiralShape = oDrawPage.group( oShapesToGroup )
    return oSpiralShape, nX, nY, nAngle



#------------------------------------------------------------
#   Styles
#------------------------------------------------------------


def defineStyle( oDrawDoc, cStyleFamily, cStyleName, cParentStyleName=None ):
    """Add a new style to the style catalog if it is not already present.
    This returns the style object so that you can alter its properties.
    """

    oStyleFamily = oDrawDoc.getStyleFamilies().getByName( cStyleFamily )

    # Does the style already exist?
    if oStyleFamily.hasByName( cStyleName ):
        # then get it so we can return it.
        oStyle = oStyleFamily.getByName( cStyleName )
    else:
        # Create new style object.
        oStyle = oDrawDoc.createInstance( "com.sun.star.style.Style" )

        # Set its parent style
        if cParentStyleName != None:
            oStyle.setParentStyle( cParentStyleName )

        # Add the new style to the style family.
        oStyleFamily.insertByName( cStyleName, oStyle )

    return oStyle


def defineGraphicsStyle( oDrawDoc, cStyleName, cParentStyleName=None ):
    """Add a new style to the style catalog if it is not already present.
    This returns the style object so that you can alter its properties.
    """
    return defineStyle( oDrawDoc, "graphics", cStyleName, cParentStyleName )


def getStyle( oDrawDoc, cStyleFamily, cStyleName ):
    """Lookup and return a style from the document.
    """
    return oDrawDoc.getStyleFamilies().getByName( cStyleFamily ).getByName( cStyleName )


def getGraphicsStyle( oDrawDoc, cStyleName ):
    """Lookup and return a graphics style from the document.
    """
    return getStyle( oDrawDoc, "graphics", cStyleName )



#------------------------------------------------------------
#   General Utility functions
#------------------------------------------------------------

def normalizeOOoAngle( nAngleOOo ):
    """Given an angle in 100'ths of a degree,
    adjust it to be from 0 to 360 degrees."""
    if nAngleOOo < 0:
        nSign = -1
    else:
        nSign = 1
    nAngleOOo = nAngleOOo - (int( abs( nAngleOOo ) / 36000.0 ) * 36000 * nSign)
    if nAngleOOo < 0:
        nAngleOOo += 36000
    return nAngleOOo

def pathnameToUrl( cPathname ):
    """Convert a Windows or Linux pathname into an OOo URL."""
    if len( cPathname ) > 1:
        if cPathname[1:2] == ":":
            cPathname = "/" + cPathname[0] + "|" + cPathname[2:]
    cPathname = string.replace( cPathname, "\\", "/" )
    cPathname = "file://" + cPathname
    return cPathname


You'll note that the functions in my library allow a high degree of similarity to how I write my Basic and Java code.
_________________
Want to make OOo Drawings like the colored flower design to the left?


Last edited by DannyB on Fri Oct 24, 2003 6:59 am; edited 2 times in total
Back to top
View user's profile Send private message
DannyB
Moderator
Moderator


Joined: 02 Apr 2003
Posts: 3991
Location: Lawrence, Kansas, USA

PostPosted: Fri Oct 24, 2003 6:53 am    Post subject: Reply with quote

Sorry again, but I just noticed that the above code OOoLib.py depends on another of my modules HSBConversions.py.

Code:

#   HSBConversions        2003-08-21-01
#   by Danny Brewer
#
#   HSB to RGB color space conversion routines.
#   Copyright (c) 2003 Danny Brewer
#   Anyone may run this code.
#   If you wish to modify or distribute this code, then
#    you are granted a license to do so under the terms
#    of the Gnu Lesser General Public License.
#   See:  http://www.gnu.org/licenses/lgpl.html



def RGBtoHSB( nRed, nGreen, nBlue ):
    """RGB to HSB color space conversion routine.
    nRed, nGreen and nBlue are all numbers from 0 to 255.
    This routine returns three floating point numbers, nHue, nSaturation, nBrightness.
    nHue, nSaturation and nBrightness are all from 0.0 to 1.0.
    """
    nMin = min( nRed, nGreen, nBlue )
    nMax = max( nRed, nGreen, nBlue )

    if nMin == nMax:
        # Grayscale
        nHue = 0.0
        nSaturation = 0.0
        nBrightness = nMax
    else:
        if nRed == nMin:
            d = nGreen = nBlue
            h = 3.0
        elif nGreen == nMin:
            d = nBlue - nRed
            h = 5.0
        else:
            d = nRed - nGreen
            h = 1.0

        nHue = ( h - ( float( d ) / (nMax - nMin) ) ) / 6.0
        nSaturation = (nMax - nMin) / float( nMax )
        nBrightness = nMax / 255.0

    return nHue, nSaturation, nBrightness



def HSBtoRGB( nHue, nSaturation, nBrightness ):
    """HSB to RGB color space conversion routine.
    nHue, nSaturation and nBrightness are all from 0.0 to 1.0.
    This routine returns three integer numbers, nRed, nGreen, nBlue.
    nRed, nGreen and nBlue are all numbers from 0 to 255.
    """
    # Scale the brightness from a range of 0.0 thru 1.0
    #  to a range of 0.0 thru 255.0
    # Then truncate to an integer.
    nBrightness = int( min( nBrightness * 256.0, 255.0 ) )

    if nSaturation == 0.0:
        # Grayscale because there is no saturation
        nRed = nBrightness
        nGreen = nBrightness
        nBlue = nBrightness
    else:
        # Make hue angle be within a single rotation.
        # If the hue is > 1.0 or < 0.0, then it has
        #  "gone around the color wheel" too many times.
        #  For example, a value of 1.2 means that it has
        #  gone around the wheel 1.2 times, which is really
        #  the same ending angle as 0.2 trips around the wheel.
        # Scale it back to the 0.0 to 1.0 range.
        if nHue > 1.0:
            nHue = nHue - int( nHue )
        elif nHue < 0.0:
            nHue = abs( nHue )
            if nHue > 1.0:
                nHue = nHue - int( nHue )
            nHue = 1.0 - nHue
        # Rescale hue to a range of 0.0 thru 6.0
        nHue = nHue * 6.0
        # Separate hue into int and fractional parts
        iHue = int( nHue )
        fHue = nHue - iHue
        # Is hue even?
        if iHue % 2 == 0:
            fHue = 1.0 - fHue
        #
        m = nBrightness * (1.0 - nSaturation)
        n = nBrightness * (1.0 - (nSaturation * fHue))

        if iHue == 1:
            nRed = n
            nGreen = nBrightness
            nBlue = m
        elif iHue == 2:
            nRed = m
            nGreen = nBrightness
            nBlue = n
        elif iHue == 3:
            nRed = m
            nGreen = n
            nBlue = nBrightness
        elif iHue == 4:
            nRed = n
            nGreen = m
            nBlue = nBrightness
        elif iHue == 5:
            nRed = nBrightness
            nGreen = m
            nBlue = n
        else:
            nRed = nBrightness
            nGreen = n
            nBlue = m
   
    return nRed, nGreen, nBlue


This is getting longer than I planned just to give you a short example program.
_________________
Want to make OOo Drawings like the colored flower design to the left?
Back to top
View user's profile Send private message
ianperryman
General User
General User


Joined: 16 Jan 2004
Posts: 7
Location: Ottawa

PostPosted: Fri Jan 16, 2004 12:16 pm    Post subject: tried to make example work in "batch" mode caused Reply with quote

I modified your example slightly to run the command as you suggested in Hidden mode. I also opened soffice in invisible mode. I used your tool UnoConnectionListener-2003-11-03-01.sxd to setup UNO with my local host.

# I could not remember the python syntax for a boolean true, so I used 1==1 which evalutates to true
oDoc = openURL( cSourceURL,(createPropertyValue("Hidden",1==1),) )

I opened OO with "soffice -invisible"

It core dumped when I after I executed the storeToURL ....
oDoc.storeToURL( cTargetURL, (createPropertyValue("FilterName","writer_pdf_Export"),) )

It works fine if I don't use the "Hidden" property.

I was using a Linux OO 1.1.0
Back to top
View user's profile Send private message
DannyB
Moderator
Moderator


Joined: 02 Apr 2003
Posts: 3991
Location: Lawrence, Kansas, USA

PostPosted: Sat Jan 17, 2004 10:35 am    Post subject: Reply with quote

I don't know if this post might be helpful, or even applicable....
http://www.oooforum.org/forum/viewtopic.php?p=18836#18836

Exporting to PDF can only be done using storeToURL, but not storeAsURL. This does not appear to be the problem.

Quote:
It works fine if I don't use the "Hidden" property.


Interesting.
_________________
Want to make OOo Drawings like the colored flower design to the left?
Back to top
View user's profile Send private message
accabrown
Power User
Power User


Joined: 21 Apr 2004
Posts: 75
Location: England

PostPosted: Wed Apr 21, 2004 4:26 am    Post subject: another ooo python library Reply with quote

which might be some use to someone

Code:

#!/usr/bin/python
# acb's first try at a python/ooo script
# cribbed from all sorts of examples.


# round up the usual suspects
import sys,os,os.path,string
import re
import uno
import unohelper

from com.sun.star.uno import RuntimeException
from com.sun.star.connection import NoConnectException
from com.sun.star.lang import IllegalArgumentException
from com.sun.star.io import IOException
from com.sun.star.beans import UnknownPropertyException



# bootstrap uno component context
# make some stuff generally available -- a desktop, pathsetter, and anything else that seems useful
class Writerslice:
   def __init__(self):
      try:
         localContext = uno.getComponentContext()
         resolver = localContext.ServiceManager.createInstanceWithContext(
            "com.sun.star.bridge.UnoUrlResolver", localContext )
         try:
            smgr = resolver.resolve( "uno:socket,host=localhost,port=2002;urp;StarOffice.ServiceManager" )
         except NoConnectException, e:
            print "OpenOffice process not found or not listening"
            print e.Message
         except RuntimeException, e:
            print "An unknown error occured: " + e.Message
            raise e
         remoteContext = smgr.getPropertyValue( "DefaultContext" )
         self.pathsetter=smgr.createInstanceWithContext("com.sun.star.util.PathSettings",remoteContext)
         self.desktop = smgr.createInstanceWithContext( "com.sun.star.frame.Desktop",remoteContext)
         try:
            self.ActiveDocument=self.desktop.getCurrentComponent()
         except RuntimeException, e:
            print "Failed to load Active document ( "+ e.Message+ ")"
            raise e
         if self.ActiveDocument==None:
            print "no active document when initialising"
      except RuntimeException, e:
         print 'failure in __init__ routine'
         print e.Message
         raise e

   def getActiveDocument(self):
      ''' returns the current open component as an object'''
      try:
         self.ActiveDocument=self.desktop.getCurrentComponent()
      except RuntimeException, e:
         print "Failed to load Active document ( "+ e.Message+ ")"


   def dumbquoteToascii(self,astring):
      '''returns a copy of astring with all the smartquotes
      and dashes stripped out and replaced by ascii chars'''
      tmpstring=astring.replace(u'\u201c',r'"')
      astring=tmpstring.replace(u'\u201d',r'"')
      tmpstring=astring.replace(u'\u2018',r"'")
      astring=tmpstring.replace(u'\u2019',r"'")
      tmpstring=astring.replace(u'\u2013',r"--") # OOO uses en dashes (2013) not word's em dashes (2014)
      tmpstring=astring.replace(u'\u2014',r"--") # OOO uses en dashes (2013) not word's em dashes (2014)
      astring=tmpstring.replace(u'\u2026',r'...') # ellipsis (...)
      return astring

   def getTextFromDoc(self):
      ''' gets a document object and returns the cleaned text to stdout
      returns None on Failure, with an error message to stdout, so can check for success'''
      try:
         mytext=self.ActiveDocument.Text
         rawtext= mytext.getString()
         cleantext=self.dumbquoteToascii(rawtext)
         try:
            return cleantext.encode('utf-8') # maybe
            #return cleantext
         except UnicodeError, e:
            print 'unicode error in getTextFromDoc'
            print e
            return None
      except:
         print "error retrieving text in getTextfromDoc"
         #print e
         return None

   def getAllStyledText(self,astyle):
      '''accepts a style name; checks it for sanity; returns a list of the text contents of
      all pars in that style in the AD)'''
      if not astyle in self.listActiveStyles():
#         print 'The Style named %s not found in this document' %(astyle)
         return None
      else:
         listopars=[]
         oSD=self.ActiveDocument.createSearchDescriptor()
         oSD.SearchStyles=1
         oSD.SearchString=astyle
         gotmany=self.ActiveDocument.findAll(oSD)
         if gotmany.getCount()>0:
            for numpars in range(gotmany.getCount()):
               partext=gotmany.getByIndex(numpars).getString()
               if partext<>'\r': # don't want empty pars
                  listopars.append(partext)
         return listopars

   def getWordCount(self):
      return str(self.ActiveDocument.WordCount)

   def isFileOpen(self,systempath):
      fileURL=unohelper.systemPathToFileUrl(systempath)
      openfiles=self.desktop.getComponents().createEnumeration()
      while openfiles.hasMoreElements():
         anotherfile=openfiles.nextElement()
         try:
            if anotherfile.getLocation()==fileURL:
               foundit=1
         except:
            continue # it may not have a location -- ignore it if so
      return foundit


   def loadFile(self,systempath):
      '''makes ActiveDocument the file whose system path is given as a string.
      either by loading it from disk, or if it is open, switching to it'''
      fileURL=unohelper.systemPathToFileUrl(systempath)
      # the next section sorts through the open files
      openfiles=self.desktop.getComponents().createEnumeration()
      while openfiles.hasMoreElements():
         anotherfile=openfiles.nextElement()
         if anotherfile.getLocation()==fileURL:
            anotherfile.getCurrentController().getFrame().activate()
            self.ActiveDocument=anotherfile
            break
      self.ActiveDocument = self.desktop.loadComponentFromURL( fileURL,"_blank", 0, () )


   def loadHiddenFile(self,systempath):
      '''chesks to see file not open; switches to it if it is; loads invisibly otherwise.'''
      from com.sun.star.container import NoSuchElementException
      alreadyopen=0
      fileURL=unohelper.systemPathToFileUrl(systempath)
      # the next section sorts through the open files
      openfiles=self.desktop.getComponents().createEnumeration()
      while openfiles.hasMoreElements():
         try:
            anotherfile=openfiles.nextElement()
         except NoSuchElementException:
            break
         try:
            if anotherfile.getLocation()==fileURL:
               alreadyopen=1
               anotherfile.getCurrentController().getFrame().activate()
               self.ActiveDocument=anotherfile
               break
         except:
            break
      if not alreadyopen:
         from com.sun.star.beans import PropertyValue
         myProps=PropertyValue()
         myProps.Name="Hidden"
         myProps.Value=1
         try:
            self.ActiveDocument= self.desktop.loadComponentFromURL( fileURL,"_blank", 0, (myProps,) )
         except:
            print "Failure to load %s" %systempath


   def closefile(self):
      '''closes the active cdocument'''
      self.ActiveDocument.close(1)



   def chdir(self,adir):
      ''' accepts a string and changes the active directory to it. So wants a fully qualified path'''
      self.pathsetter.Work=unohelper.systemPathToFileUrl(adir)

   def getCurrentOOODir(self):
      '''just prints out the active directrory, for checking'''
      print self.pathsetter.Work


   def convertToURL(self,astring):
      '''now just a wrapper for a less memorable name'''
      return unohelper.systemPathToFileUrl(astring)

   def convertFromURL(self,anURL):
      '''now just a wrapper for the unohelper funciton I forget'''
      return unohelper.fileUrlToSystemPath(anURL)

   def listAllStyles(self):
      '''provides a (very long) list of all the paragraph styles available to a document'''
      listostyles=[]
      if self.ActiveDocument:
         allstyles=self.ActiveDocument.getStyleFamilies().getByName('ParagraphStyles')
         for things in range(allstyles.getCount()):
            listostyles.append(allstyles.getByIndex(things).DisplayName)
      return listostyles

   def listActiveStyles(self):
      '''returns a list containing only the paragraph styles in use in a document'''
      listostyles=[]
      if self.ActiveDocument:
         allstyles=self.ActiveDocument.getStyleFamilies().getByName('ParagraphStyles')
         for things in range(allstyles.getCount()):
            if allstyles.getByIndex(things).isInUse():
               listostyles.append(allstyles.getByIndex(things).DisplayName)
      return listostyles


   def listCharStyles(self):
      '''provides a (very long) list of all the Character styles available to a document'''
      listostyles=[]
      if self.ActiveDocument:
         allstyles=self.ActiveDocument.getStyleFamilies().getByName('CharacterStyles')
         for things in range(allstyles.getCount()):
            listostyles.append(allstyles.getByIndex(things).DisplayName)
      return listostyles

   def setBoldasHTML(self):
      '''replaces OO writer's Bold with HTML formatting'''
      repldesc=self.ActiveDocument.createReplaceDescriptor()
      repldesc.ValueSearch=1
      from com.sun.star.beans import PropertyValue
      from com.sun.star.awt.FontWeight import BOLD
      myStruct=PropertyValue()
      myStruct.Name="CharWeight"
      myStruct.Value=BOLD
      repldesc.setSearchAttributes((myStruct,))
      repldesc.SearchRegularExpression=1
      repldesc.SearchString='.*'
      repldesc.ReplaceString = "<strong>&</strong>"
      numdone=self.ActiveDocument.replaceAll(repldesc)
      print ' %s Bold occurences tarted up ' %numdone

   def setItalasHTML(self):
      '''replaces OO writer's Italics with HTML formatting'''
      repldesc=self.ActiveDocument.createReplaceDescriptor()
      repldesc.ValueSearch=1
      from com.sun.star.beans import PropertyValue
      from com.sun.star.awt.FontSlant import ITALIC
      myStruct=PropertyValue()
      myStruct.Name="CharPosture"
      myStruct.Value=ITALIC
      repldesc.setSearchAttributes((myStruct,))
      repldesc.SearchRegularExpression=1
      repldesc.SearchString='.*'
      repldesc.ReplaceString = "<em>&</em>"
      numdone=self.ActiveDocument.replaceAll(repldesc)
      print ' %s Italic occurences tarted up ' %numdone

   def getslug(self):
      '''extracts from the active document a string containing
      all paragraphs written in the styles 'slug', 'heading1', or
      (for word documents) 'Heading 1'.
      or, failing those, the title'''
      listostuff=[]
#      print 'looking for slug text (enhanced)'
      possibleheadings=('Slug',
                     'slug',
                     'heading1',
                     'Heading 1')
      for styles in possibleheadings:
         if self.getAllStyledText(styles):
            listostuff=self.getAllStyledText(styles)
            break
      if not listostuff:
         return None
      else:
         return string.join(listostuff,' ')



   def getSmallPrint(self):
      '''returns a string of the small printed text'''
      listostuff=self.getAllStyledText("Small Print")
      if listostuff:
         return string.join(listostuff,' ')


   def listNormalPars(self):
      return getAllStyledText("Default")

   def lastThreeWords(self,randomstring):
         ''' pass in a string of chars and spaces,
         returns the last a string with the last three words in it'''
         import string
         return string.join(randomstring.split(' ')[-3:])

   def getAllQuotes(self):
      '''returns a list of all the double-quoted strings in the ActiveDocument)'''
      import string
      import re
      listoquotes=[]
      doublequotes=re.compile(u'\u201c(.+?)\u201d',re.DOTALL)
      stringoftext=self.ActiveDocument.getText().getString()
      listoquotes=doublequotes.findall(stringoftext)
      return listoquotes

   def dategrabber(self,maybedate):
      '''Takes a string and checks the last three words
      to see if they form a date. Returns a date value if they do.'''
      from mx.DateTime.Parser import DateFromString
      try:
         testbit=self.lastThreeWords(maybedate) # last three words
      except:
         return None
      try:
         DateFromString(testbit)
         return testbit
      except:
         return None


   def insertbq(self,listoquotes,astring):
      ''' accepts a list of strings from getallquotes:
         writes long ones back between blockquote tags to 'astring'.
         These may or may not contain paragraph returns and inner quotes.
      '''
      import string
      for quotes in listoquotes :
         if string.count(quotes,' ')>50 :
            newquote='<blockquote>'+quotes+'</blockquote>'
            snurfle=astring.replace(quotes,newquote)
            astring=snurfle # the old soft-shoe shuffle
      return astring

   def dumbquoteToHTML(self,astring):
      '''returns a copy of astring with all the smartquotes
      and dashes stripped out and replaced by HTML entities'''
      tmpstring=astring.replace(u'\u201c',r'&#8220;')
      astring=tmpstring.replace(u'\u201d',r'&#8221;')
      tmpstring=astring.replace(u'\u2018',r"&#8216")
      astring=tmpstring.replace(u'\u2019',r"&#8217;")
      tmpstring=astring.replace(u'\u2013',r"&#8195;") # em dashes are #2013 in OOo
      astring=tmpstring.replace(u'\u2026',r'&#8230;') # and the ellipsis (...)
      return astring

if __name__=="__main__":
   ws=Writerslice()
[/quote]
Back to top
View user's profile Send private message Visit poster's website
DannyB
Moderator
Moderator


Joined: 02 Apr 2003
Posts: 3991
Location: Lawrence, Kansas, USA

PostPosted: Sat Jan 08, 2005 9:15 am    Post subject: Reply with quote

When setting up a batch file to run OOo's python, but use the IDLE development system from a standard Python 2.2 installation, be sure to copy the "tcl" folder form the C:\Python22 folder into OOo's python, so that OOo's python-core-2.2.2 folder ends up having "bin", "lib" and the new "tcl" folder.
http://www.oooforum.org/forum/viewtopic.php?p=60941#60941

See also....
http://www.oooforum.org/forum/viewtopic.php?t=4818
_________________
Want to make OOo Drawings like the colored flower design to the left?
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    OOoForum.org Forum Index -> OpenOffice.org Macros and API All times are GMT - 8 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group