Page 1 of 1

[Solved] Working with Writer only?

Posted: Wed Feb 25, 2015 11:08 am
by _savage
I've got the whole Office package installed, and using the UNO API I create a desktop instance:

Code: Select all

desktop = context.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", context)
It turns out though that I can now load any kind of file type: text documents, images, tables, ... However, I'd like to restrict the file types to supported text documents only (i.e. open Writer only) and reject the rest. Is that possible?

Re: Working with Writer only?

Posted: Wed Feb 25, 2015 11:22 am
by RoryOF
I don't know for certain, but look at XSingleComponentFactory. Also, on your existing implementation there may be restrictive parameters that you have omitted/overlooked.

Re: Working with Writer only?

Posted: Wed Feb 25, 2015 11:28 am
by _savage
You refer to using createInstanceWithArgumentsAndContext instead of what I use? I didn't find more detail on the ServiceSpecifier parameter—is that where I could say something like "Writer only"?

How would an attempt to open a non-Writer document manifest? An exception?

Re: Working with Writer only?

Posted: Sun Mar 15, 2015 4:30 am
by _savage
I can open an empty Writer instance, which returns an empty document object. That object implements the XLoadable interface, and I assume I can just call its load() method. However, I found the documentation not very helpful, even reading through the MediaDescriptors which are supposed to be passed to the load() method as a sequence of property values. There is some help on how to map types into Python over at the PyUNO bridge documentation.

Code: Select all

>>> from com.sun.star.beans import PropertyValue
>>> propVal = PropertyValue()
>>> propVal.Name = "URL" # or "FileName"?
>>> propVal.Value = "file:///path/to/document.odt"
>>> document = desktop.loadComponentFromURL("private:factory/swriter", "_blank", 0, (propVal,))
This just opens an empty document again. Trying to use load() didn't work either:

Code: Select all

>>> document = desktop.loadComponentFromURL("private:factory/swriter", "_blank", 0, ())
>>> document.load( (propVal,) )
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
__main__.DoubleInitializationException
Not sure what I am doing wrong here.

Alternatively, I can just open the document and have Office decide what component (Writer, Draw, ...) to open it with. But then, how can I query that document object once it's open? It seems that a Writer document supports only a certain set of services:

Code: Select all

>>> document = desktop.loadComponentFromURL("file:///path/to/document.odt", "_blank", 0, ())
>>> document
pyuno object (com.sun.star.lang.XComponent)0x7fb7a1c89328{implementationName=SwXTextDocument, supportedServices={com.sun.star.document.OfficeDocument,com.sun.star.text.GenericTextDocument,com.sun.star.text.TextDocument}, supportedInterfaces={...}}
How do I query for a service, or that implementationName?

Re: Working with Writer only?

Posted: Sun Mar 15, 2015 10:22 am
by B Marcelly
_savage wrote:It turns out though that I can now load any kind of file type: text documents, images, tables, ... However, I'd like to restrict the file types to supported text documents only (i.e. open Writer only) and reject the rest. Is that possible?
Do what the user interface does: open only documents having specific extensions.
Types of documents
Types of documents
Note that a Writer document may be an OpenOffice Writer, Microsoft Word, etc. The extension (and sometimes the structure of the document) is used by OpenOffice to find the filter required to load the document.
_savage wrote:how can I query that document object once it's open? It seems that a Writer document supports only a certain set of services
Once the document is loaded, it provides some services and interfaces, as you can see with MRI or Xray.
With Python or Basic the supported services and their interfaces are directly usable, no need for invocation (contrary to Java, C++).
The available services of the object need to be invoked from the object, but you have to know how to use them. Example, inserting a text section in a Writer document:

Code: Select all

...
myText = myDoc.getText()
aCursor = myText.createTextCursor()
aCursor.gotoEnd(False)
'   invocation of a service of a Writer document
aSection = myDoc.createInstance("com.sun.star.text.TextSection")
myText.insertTextContent(aCursor, aSection, False)
With Python, Basic, etc, you cannot invoke an interface. You can only use the interfaces provided by a service.
Some services are independent of a document.

Code: Select all

' *** Basic ***
Dim dispatcher As Object
dispatcher = CreateUnoService("com.sun.star.frame.DispatchHelper")
Internally CreateUnoService invokes the service from a primary object : the Service Manager.
With Python you have to do it yourself : get the Service Manager, then use method createInstance or createInstanceWith Context.

Re: Working with Writer only?

Posted: Sun Mar 15, 2015 2:54 pm
by _savage
B Marcelly wrote:Do what the user interface does: open only documents having specific extensions. Note that a Writer document may be an OpenOffice Writer, Microsoft Word, etc. The extension (and sometimes the structure of the document) is used by OpenOffice to find the filter required to load the document.
I wanted to avoid maintaining a list of supported document types, and then having to check them before invoking office. That's redundant and error prone. Thus, I tried two different ways of solving the problem, but I get stuck with both.

* Create a Writer instance and load the document. I figure that unsupported file formats will fail to load into Writer. Problem: I haven't quite figured out how to load a document into the Writer instance, something goes awry with the properties or property list. See my previous post for more details on what goes wrong.

* Load any document into office, let office decide what to open it with. If it's a Writer-supported document, then it seems that the object should provide only certain kind of services. Problem: How do I check for these services? See below.
B Marcelly wrote:Once the document is loaded, it provides some services and interfaces, as you can see with MRI or Xray.
Correct, see the code snippet in my previous post. Note that I'd like to invoke this from a Python script, and not manually through an introspection tool.
B Marcelly wrote:With Python or Basic the supported services and their interfaces are directly usable, no need for invocation (contrary to Java, C++).
The available services of the object need to be invoked from the object, but you have to know how to use them. Example, inserting a text section in a Writer document:

Code: Select all

...
myText = myDoc.getText()
aCursor = myText.createTextCursor()
aCursor.gotoEnd(False)
'   invocation of a service of a Writer document
aSection = myDoc.createInstance("com.sun.star.text.TextSection")
myText.insertTextContent(aCursor, aSection, False)
With Python, Basic, etc, you cannot invoke an interface. You can only use the interfaces provided by a service.
You're saying: just invoke a text-service specific function and see what happens? If office had loaded anything else but a Writer document in your example, the first line had already failed, correct?

Code: Select all

>>> document.getText()
AttributeError: getText
This tells me: that's not a Writer document?

Re: Working with Writer only?

Posted: Sun Mar 15, 2015 5:08 pm
by Villeroy
_savage wrote:This tells me: that's not a Writer document?
Are you a programmer?

Re: Working with Writer only?

Posted: Sun Mar 15, 2015 5:32 pm
by _savage
Villeroy wrote:Are you a programmer?
:bravo: I'm a passionate code monkey.

Re: Working with Writer only?

Posted: Sun Mar 15, 2015 5:51 pm
by Villeroy
_savage wrote:
Villeroy wrote:Are you a programmer?
:bravo: I'm a passionate code monkey.
Monkeys can catch very well. In this case all you need to do is catching an error.

Re: Working with Writer only?

Posted: Sun Mar 15, 2015 6:07 pm
by _savage
Villeroy wrote:Monkeys can catch very well. In this case all you need to do is catching an error.
Oh yes, of course, that's not what I'm asking. What I'm asking is: Is calling getText() on a document object sufficient to make sure that this is a Writer document?

I would assume so because it's defined for XTextDocument. I just want to make sure that this is the official way of going about solving the problem in this thread, because there are other ways as well (see further up in this thread) :-)

For example, I am still puzzled as to what properties to pass to load() for an empty Writer document object.

Re: Working with Writer only?

Posted: Sun Mar 15, 2015 9:40 pm
by B Marcelly
_savage wrote:I wanted to avoid maintaining a list of supported document types, and then having to check them before invoking office. That's redundant and error prone. Thus, I tried two different ways of solving the problem, but I get stuck with both.
Then you don't have a solution better than the proposed one. Which is neither redundant nor error prone, but working on existing text documents. A working solution is better than none.
_savage wrote:I'd like to invoke this from a Python script, and not manually through an introspection tool.
MRI or Xray is only used to show you what you can expect from an object. It's up to you to understand what it displays and use available properties and methods, with the help of all documentation available on the OpenOffice API.
_savage wrote:I am still puzzled as to what properties to pass to load() for an empty Writer document object.
Here is a Python example.

Code: Select all

import uno

def _ctx():
   return uno.getComponentContext()

def createUnoService(serviceName):
  """ same as Basic CreateUnoService """
  sm = uno.getComponentContext().ServiceManager
  result = sm.createInstanceWithContext(serviceName, _ctx())
  return result

# ----- the program starts here ------
def HelloWorldNewDoc( ):
    """Prints the string 'Hello World(in Python)' into a new Writer document"""    
    desktop =  createUnoService("com.sun.star.frame.Desktop")
    document = desktop.loadComponentFromURL("private:factory/swriter", "_blank", 0, ())
    myText = document.getText()
    myText.String = "Hello World in a new Writer document"
    return None

g_exportedScripts = (HelloWorldNewDoc)

Re: Working with Writer only?

Posted: Sun Mar 15, 2015 10:20 pm
by Villeroy
_savage wrote:
Villeroy wrote:Monkeys can catch very well. In this case all you need to do is catching an error.
Oh yes, of course, that's not what I'm asking. What I'm asking is: Is calling getText() on a document object sufficient to make sure that this is a Writer document?
It takes no more than a few minutes to check this out for a text, spreadsheet, drawing, presentation, database and math formula. Without an object inspector (XRay, MRI) you won't get far anyway. An inspector can tell you that every document has SupportedServiceNames and an ImplementationName to describe the document type.

Re: Working with Writer only?

Posted: Mon Mar 16, 2015 1:14 am
by pietvo
To check if document is a Writer document:

Code: Select all

 if document.supportsService('com.sun.star.text.TextDocument'):

Re: Working with Writer only?

Posted: Mon Mar 16, 2015 7:43 am
by _savage
pietvo wrote:To check if document is a Writer document:

Code: Select all

 if document.supportsService('com.sun.star.text.TextDocument'):
Thanks Piet, I saw your post on the mailing list. This works perfectly!