Page 1 of 1

[Solved] Accessing the content of a "Transient Document"

Posted: Fri Apr 14, 2017 10:00 am
by pjoyez
I am trying to write a macro that operates on graphics that are embedded in documents. The basics for this can be taken in viewtopic.php?f=21&t=43010. However, that macro accesses images in the DocumentStorage which reflects the last saved state of the document. I would like my macro to work also on unsaved documents. For this, I understand that I need to get the images from the "Transient Document" whose url I can get using ThisComponent.NameSpace or ThisComponent.StringValue, but at the moment I cannot figure how to access the content of the "Pictures" subfolder of that transient document. I guess I would need to use stuff like com.sun.star.comp.ucb.TransientDocumentsContentProvider, but I cannot understand how it is supposed to be used just by reading the doc, and I could not find any example code snippet... Could anyone guide me for achieving this?

Re: accessing the content of a "Transient Document"

Posted: Fri Apr 14, 2017 10:04 am
by RoryOF
The usual starting point for information on detailed macro programming is Andrew Pitonyak's work on macro programming, downloadable from
http://www.pitonyak.org/oo.php

Re: accessing the content of a "Transient Document"

Posted: Fri Apr 14, 2017 1:40 pm
by pjoyez
Thank you RoryOF, I know Andrew Pitonyak's macro examples and book. AFAICT the only place where transient documents are mentioned in Pitonyak's documents is when he explains how to "Access OOo's internal storage system" using "The coolest trick [he] know[s]", which is typing "vnd.sun.star.tdoc:/" in the open file dialog (which, by the way, does not work on my system).

I came here precisely because I have not found there (nor elsewhere) how to access an url such as : vnd.sun.star.tdoc:/3/Pictures/10004E0F00001A84000006CF85DF5AD8B99B01BB.svg. It is probably not that difficult, but you cannot just pretend you open a regular file.

Re: accessing the content of a "Transient Document"

Posted: Fri Apr 14, 2017 5:45 pm
by ms777
... maybe this helps a bit as a starter. Run it in a writer doc with one or more jpg embedded

Good luck,

ms777

Code: Select all

Sub Main

'get the images in ThisComponent.GraphicObjects
sMes = "pictures contained in GraphicObjects: " & ThisComponent.GraphicObjects.Count

for k=0 to ThisComponent.GraphicObjects.Count-1
  sMes = sMes & Chr(13) & Chr(10) & ThisComponent.GraphicObjects.getByIndex(k).graphicUrl
  next
msgbox sMes

'get the images in ThisComponent.DocumentStorage
asElementNames = ThisComponent.DocumentStorage.getByName("Pictures").ElementNames
sMes = "pictures contained in DocumentStorage: " & (UBound(asElementNames)+1)
for k=0 to UBound(asElementNames)
  sMes = sMes & Chr(13) & Chr(10) & asElementNames(k)
  next
msgbox sMes


oPicGraphicObjects = ThisComponent.GraphicObjects.getByIndex(0)
xray oPicGraphicObjects

oPicStorage = ThisComponent.DocumentStorage.getByName("Pictures").getByName(asElementNames(0))
xray oPicStorage


'Example: insert the first image into an ImageControl. The ImageControl must already be present, on the first form, and must be named "ImageControl".

oImageControl = ThisComponent.DrawPage.Forms.getByIndex(0).getByName("ImageControl")

oProvider = createUnoService("com.sun.star.graphic.GraphicProvider") 
Dim oPropsIN(1)as new com.sun.star.beans.PropertyValue 
oPropsIN(0).Name  = "InputStream" 
oPropsIN(0).Value = oPicStorage.InputStream
oImageControl.Graphic = oProvider.queryGraphic(oPropsIN()) 

End Sub

Re: accessing the content of a "Transient Document"

Posted: Fri Apr 14, 2017 6:58 pm
by pjoyez
What you propose is more or less what I started with : it accesses images in the DocumentStorage, but this does not work with unsaved documents. I'd like a macro that works in all cases. Thanks anyway ms777.

Re: accessing the content of a "Transient Document"

Posted: Fri Apr 14, 2017 7:01 pm
by RoryOF
Why not cause your macro to Save the document to a temporary name before looking for the pictures? If you do not subsequently require the document, your macro could afterwards delete it.

Re: Accessing the content of a "Transient Document"

Posted: Fri Apr 14, 2017 10:10 pm
by karolus
Hallo

I use regulary the "Trick" mentioned above to write python-code directly into embedded python-scripts, it works also with unsaved docs.
Below parts of the python-code for the job:

Code: Select all


#…<snip>…        
        sfa = createUnoService( "com.sun.star.ucb.SimpleFileAccess")
        
        pythonfolder = ('vnd.sun.star.tdoc:/'
                     '{}/Scripts/python'.format(doc.RuntimeUID))

        fileuri = "{}/{}".format(pythonfolder, filename)
        if sfa.exists(fileuri):
            if mode == 'a':
                message = ("Appending to %s in doc: %s" % (filename , doc.Title))            
            else:
                print("Overwriting %s in doc: %s" % (filename, doc.Title))
        else:
            print("Writing to %s in doc: %s" %(filename, doc.Title))
                        
        sfa.createFolder(pythonfolder)    
        tempfile = NamedTemporaryFile(mode=mode)
        temppath = tempfile.name
        tempuri = uno.systemPathToFileUrl(temppath)
                        
        if sfa.exists(fileuri) and mode=='a':
            sfa.copy(fileuri, tempuri)
            with open(temppath) as t:
                t = t.read()
            doublefuncs = test_unique_func_names(t, content)
            if doublefuncs:
                tempfile.delete
                print('Interrupt appending to {} @ {}, '
                      'because double Functionnames: ``{}´'
                      ''.format(filename, doc.Title, ', '.join(doublefuncs)))               
                return
            print(message)             
            
        with io.open(temppath, mode, encoding='utf-8') as f:
            f.write(content)
        sfa.copy(tempuri, fileuri)
        tempfile.delete

Re: Accessing the content of a "Transient Document"

Posted: Sat Apr 15, 2017 5:57 pm
by ms777
... and if storing the doc to disk is not possible due to lack of rights you can also store your document to a storage in memory:

Code: Select all

oDoc = ThisComponent

oStorageFac = createUnoService("com.sun.star.embed.StorageFactory") 
oStorage    = oStorageFac.createInstance
oStream     = oStorage.openStreamElement("ms777", com.sun.star.embed.ElementModes.READWRITE) 

Dim storeProps(0) as new com.sun.star.beans.PropertyValue
storeProps(0).Name = "OutputStream"
storeProps(0).Value = oStream
oDoc.storeToUrl("private:stream", storeProps())

Re: Accessing the content of a "Transient Document"

Posted: Sun Apr 16, 2017 6:47 pm
by pjoyez
Many thanks Karolus, your reply blew away some of my misconceptions!

1) The content of transient docs IS accessible as any other file (you can even write to it!). I was thinking opposite because I got an error when trying to access my image in it, but this was because:

2) the transient document does NOT contain the image, unless the document was already saved (So it's just the same as accessing the Document storage!). I was mislead to think that would be different based on the documentation found here : https://www.openoffice.org/ucb/docs/ucp ... c-ucp.html
"All documents that have been loaded – regardless of their persistent document format--- or that have been created but not yet saved to any storage medium, are supported.[...] The document contents provided by the [Transient Document Content Provider] represent live data, which may differ from any persistent representation of the document, for instance, because the user modified the document after loading, but did not yet save it."
Your post also gives me the workaround: I'll be able write the image myself in the transient document at the time I insert it.

Thanks too, ms777. I was thinking to use the temporary files, but using that temporary storage in memory could be useful in some cases.