Page 1 of 1

ToC incorrectly updated with automated script

Posted: Wed Apr 22, 2009 11:09 am
by Beld
I have an automated script that pulls data from a database and then places it in an OpenOffice document.
In this document I have specified a Table of Content, I want to update this Table of Content and then save the file in any format I please.

For this I use the following script:

Code: Select all

' Save document as the given type.
Sub SaveAs( cType, cExtension, cFile )
   On Error Goto test
   cURL = ConvertToURL( cFile )
   ' Open the document. Just blindly assume that the document 
   ' is of a type that OOo will correctly recognize and open 
   ' without specifying an import filter.
   oDoc = StarDesktop.loadComponentFromURL( cURL, "_blank", 0, _
            Array(MakePropertyValue( "Hidden", True ),))
   
   ' in case OOo doesn't recognize the type then do nothing at all.
   If Not IsNull(oDoc) Then
   
   oIndexes = oDoc.getDocumentIndexes()

   for i = 0 to oIndexes.getCount () - 1
    oIndexes (i).update
   next i

   cFile = Left( cFile, Len( cFile ) - 4 ) + cExtension
   cURL = ConvertToURL( cFile )
   
   ' Save the document using a filter.   
   oDoc.storeToURL( cURL, Array(_
            MakePropertyValue( "FilterName", cType ),)
   
   oDoc.close( True )
   
   EndIf
   
   Exit Sub
 test:
   ' We do not want any errors displayed.
   On Error Goto End
   If Not IsNull(oDoc) and Not IsEmpty(oDoc) Then
      oDoc.close( True )
   EndIf
End Sub
The result is sadly a ToC like this:

Topic 1 .................. 2
Topic 2 .................. 3
Topic 3 .................. 4

The headers Topic 1, Topic 2, and Topic 3 are respectively on pages: 2,3,7

When I open the file and manually update the ToC it displays the page numbers correctly,
but when I use my automated script it doesn't.

I think the problem here is that I load the document and while it's not entirely loaded I update the ToC.

Is there a way to check if the document is fully loaded and at that time update the ToC?

Re: ToC incorrectly updated with automated script

Posted: Wed Apr 22, 2009 4:53 pm
by FJCC
I don't know how to check if a document is fully loaded. I think you could test your theory by adding a Wait step immediately after the loadComponentFromURL step. The unit of Wait is milliseconds, so you could put in

Wait 10000

to create a 10 second pause. If your ToC is then correct, you will at least know that there is not some other problem.

Re: ToC incorrectly updated with automated script

Posted: Wed Apr 22, 2009 5:01 pm
by Beld
I've been testing with this.
at wait 2000 the ToC is close to correct (1 page off at topic 3)
at wait 5000 the ToC is correct.

But I don't know the size of the documents that will go through it so I need it to be always correct no matter the size.

so it looks like the problem is cause by parallel execution of the macro and document laoding.

Re: ToC incorrectly updated with automated script

Posted: Wed Apr 22, 2009 5:06 pm
by FJCC
Thanks for running the test. I'll look around for a way to confirm that the document is loaded. I might not be able to work on this until tonight. (It is morning in my part of the world.)

Re: ToC incorrectly updated with automated script

Posted: Wed Apr 22, 2009 8:57 pm
by Hardy
Hi Beld, why don't you attach an event listener and wait for the OnLoad event?

Re: ToC incorrectly updated with automated script

Posted: Thu Apr 23, 2009 11:21 am
by Beld
Hardy, thanks for that link it helped quite a bit.

ok I currently have the following code,
this appears to work but I'm not satisfied with it:

Code: Select all

Dim DocumentLoaded as boolean  '<-- changes to previous code are marked with these arrows

Sub RegisterListener (ThisComponent) '<--
 
   oListener = CreateUnoListener( "DocumentListener_","com.sun.star.document.XEventListener" ) '<--
 
   ThisComponent.com_sun_star_document_XEventBroadcaster_addEventListener( oListener ) '<--
 
End Sub '<--
 
Sub DocumentListener_notifyEvent( o as object ) '<--
   
   DocumentLoaded = true '<--
 
end sub '<--
 
Sub DocumentListener_disposing() '<--
End Sub '<--


' Save document as the given type.
Sub SaveAs( cType, cExtension, cFile )
'   On Error Goto test
   DocumentLoaded = false '<--
   
   cURL = ConvertToURL( cFile )
   ' Open the document. Just blindly assume that the document 
   ' is of a type that OOo will correctly recognize and open 
   ' without specifying an import filter.
   oDoc = StarDesktop.loadComponentFromURL( cURL, "_blank", 0, _
            Array(MakePropertyValue( "Hidden", True ),))
   
  RegisterListener(oDoc) '<--
   ' in case OOo doesn't recognize the type then do nothing at all.
   If Not IsNull(oDoc) Then
   
   oIndexes = oDoc.getDocumentIndexes()
   
    If oIndexes.getCount () > 0 Then '<--
   
  Do Until DocumentLoaded  '<--
     wait 100 '<--
   Loop '<--

   for i = 0 to oIndexes.getCount () - 1
    oIndexes (i).update
   next i
   
   EndIf '<--

   cFile = Left( cFile, Len( cFile ) - 4 ) + cExtension
   cURL = ConvertToURL( cFile )
   
   ' Save the document using a filter.   
   oDoc.storeToURL( cURL, Array(_
            MakePropertyValue( "FilterName", cType ),)
   
   oDoc.close( True )
   
   EndIf
   
   Exit Sub
 test:
   ' We do not want any errors displayed.
   On Error Goto End
   If Not IsNull(oDoc) and Not IsEmpty(oDoc) Then
      oDoc.close( True )
   EndIf
End Sub
I don't know if the event that is triggered is the onLoad event.
when I try to get the Event Name at the Sub DocumentListener_notifyEvent it returns an empty string.

I used the link from Hardy's post to get this far, and in that link also has an example using the event name.

Code: Select all

 
   IF o.EventName = "OnPrepareUnload" THEN
         print o.Source.URL
   ENDIF
I changed this to see what event(s) are triggered like this:

Code: Select all

   MsgBox(o.EventName)
and all I got was an empty MsgBox.

This might be a bug or a feature, I don't know which ;)

Now I am wondering if the first event that is triggered is ALWAYS the onload event and not some other event,
that might ruin the workings of this Macro.

Re: ToC incorrectly updated with automated script

Posted: Thu Apr 23, 2009 2:10 pm
by Hardy
Hi Beld
I don't understand what you want to achieve with that part of your code:
Beld wrote:

Code: Select all

... 
Sub DocumentListener_notifyEvent( o as object ) '<--
   
   DocumentLoaded = true '<--
 
end sub '<--
...
I thought you'd try something like:

Code: Select all

Sub DocumentListener_notifyEvent( o as object ) '<--
   
   if "OnLoad"=o.EventName then doMakeToC ' or however you called the routine
 
end sub 
Beld wrote:Now I am wondering if the first event that is triggered is ALWAYS the onload event and not some other event,
that might ruin the workings of this Macro.
The first events (if you open a document via GUI) are "OnTitleChanged", "OnModifyChanged", ...
The ""-named event surprised me too (if that be the "OnLoad"?). I currently don't get a complete list, because I haven't got the log file working.

Re: ToC incorrectly updated with automated script

Posted: Thu Apr 23, 2009 2:38 pm
by Beld
well as I stated before it is an automated script.
This macro is called from outside OpenOffice as follows: (ps. it isn't always saved in MS Word format)
"C:/progra~1/openoffice.org 3/program/soffice" -invisible -headless macro:///LLinxx.Conversions.SaveAsDoc("MS Word 97", ".doc","C:/MyFile.odt")
after this macro is done executing I use it again in my automated script.
My script nicely waits for the openoffice macro to finish before continuing with it's own tasks.

In order to make the Macro wait till the event is triggered I added a somewhat global Boolean.

Code: Select all

 Dim DocumentLoaded as boolean 
This boolean is not listed in the sub but outside it so that the event can change this value and the macro can notice the change.

Then in my macro that updates the ToC and then saves the file I add the code that makes it wait until the event is fired:

Code: Select all

  Do Until DocumentLoaded 
     wait 100 ' check every 100 ms if DocumentLoaded is true
   Loop
Now when the event fires I set the DocumentLoaded boolean to true so that the macro continues at that point.

I haven't put any of my variables (cType, cExtension, cFile) outside the sub SaveAs.

So with the current setup I can't wait for the event to fire, and on another note.
I never found that the OnLoad event fires.
I did find the events:
"OnTitleChanged"
"OnModifyChanged"
... (several others also fired don't remember which ones)
but before these were fired an event without an eventname was fired.
the cause for that might be that I run my macro with "-invisible -headless"
Or perhaps because I open the document hidden:

Code: Select all

   oDoc = StarDesktop.loadComponentFromURL( cURL, "_blank", 0, _
            Array(MakePropertyValue( "Hidden", True ),))
In short the actions that my Macro currently contain are:
1. Open the document
2. reset the global boolean
3. Register event handler to notice when the document is done loading
4. check if there are indexes
a. wait for the document to finish loading
b. update the indexes
5. save the document in the specified file format
6. close the document

In short the actions that I need:
1. open the document
2. update the indexes if any
3. save the document in the specified file format
4. close the document

Re: ToC incorrectly updated with automated script

Posted: Thu Apr 23, 2009 4:50 pm
by Hardy
Beld wrote:

Code: Select all

 Dim DocumentLoaded as boolean 
Then in my macro that updates the ToC and then saves the file I add the code that makes it wait until the event is fired:

Code: Select all

  Do Until DocumentLoaded 
     wait 100 ' check every 100 ms if DocumentLoaded is true
   Loop
But your code...
Beld wrote:

Code: Select all

... 
Sub DocumentListener_notifyEvent( o as object ) '<--
   
   DocumentLoaded = true '<--
 
end sub '<--
...
... doesn't wait for anythig, but for the first event whatever that is.
To fire it for "OnLoad" you might change it to:

Code: Select all

... 
Sub DocumentListener_notifyEvent( o as object ) '<--
   
   if NOT DocumentLoaded then DocumentLoaded = ("OnLoad"=o.EventName) '<--
 
end sub '<--
...
But you wouldn't need the wait loop, if you triggered the launch of your ToC-routine directly by the event.

Re: ToC incorrectly updated with automated script

Posted: Thu Apr 23, 2009 5:03 pm
by Beld
Hardy wrote:But you wouldn't need the wait loop, if you triggered the launch of your ToC-routine directly by the event.
true but how would I transfer the variables passed through to the subroutine.
Cause at the end of my function I use the given variables to save the document.
Hardy wrote:...
doesn't wait for anythig, but for the first event whatever that is.
To fire it for "OnLoad" you might change it to:

Code: Select all

... 
Sub DocumentListener_notifyEvent( o as object ) '<--

if NOT DocumentLoaded then DocumentLoaded = ("OnLoad"=o.EventName) '<--

end sub '<--
...
OnLoad event doesn't seem to trigger, so either it's the first event without text or it simply never triggers because the view isn't rendered.
That's the reason why my code currently triggers at the first event is because else it would end up doing nothing at all.....
so in other words triggering at the first event that comes is a quickfix that I want to get rid off.

Re: ToC incorrectly updated with automated script

Posted: Thu Apr 23, 2009 5:42 pm
by Hardy
ok, "OnLoad" never occurs - that's interesting, but not exactly helpful for you...
Do you have a list of all events that are fired during the first few seconds?
If so, please let me know how you got it (I'm still fighting to get that into a log file, because my document isn't hidden and so the focus events don't allow me to use messsage boxes or the like) and...
... consider to trigger on the last observed event that occurs, before your subsequent code interferes.

Re: ToC incorrectly updated with automated script

Posted: Thu Apr 23, 2009 6:12 pm
by Beld
Sequence when no Indexes in document
""
"OnCopyTo"
"OnCopyToDone"
"OnTitleChanged"
"OnViewClosed"
"OnUnload"

Sequence with Indexes in document
during loop:
""
when updating indexes:
"OnTitleChanged"
"OnModifyChanged"

When saving the file:
"OnCopyTo"
"OnCopyToDone"

When closing the file:
"OnTitleChanged"
"OnViewClosed"
"OnUnload"

randomly during runtime???:
""

how I got the info:
open the Macro window,
place breakpoint at the location where I set the boolean
place several other breakpoints to determine when what events is triggered.
at the variable watch screen add the Event object (o) to the list.

run the macro (with manual call if need be)
now when the runtime reaches the breakpoint you can check what the content of the Event object is.

In this picture you can see the Macro standing in LLinxx/Conversions.
Location of Macro.jpg
In this picture you can see the breakpoints (see in green square) that I set and the Watch (see in lightblue square) that I set.
My Macro window.jpg
example of running the macro I made (using the standard OpenOffice 3.0 directory) assuming the macro is placed at Standard/Module1:
"C:/progra~1/openoffice.org 3/program/soffice" -invisible -headless macro:///Standard.Module1.SaveAs("MS Word 97", ".doc","C:/MyFile.odt")

The complete Macro so you can copy and paste it to test it (most of it was found online as tutorial information) :
Made it as small as possible to save room. most of it is already available in other posts so ;)

Code: Select all

REM  *****  BASIC  *****

Dim DocumentLoaded as boolean

Sub RegisterListener (ThisComponent)
 
   oListener = CreateUnoListener( "DocumentListener_","com.sun.star.document.XEventListener" )
 
   ThisComponent.com_sun_star_document_XEventBroadcaster_addEventListener( oListener )
 
End Sub
 
Sub DocumentListener_notifyEvent( o as object )
   
   DocumentLoaded = true
 
end sub
 
Sub DocumentListener_disposing()
End Sub


' Save document as the given type.
Sub SaveAs( cType, cExtension, cFile )
'   On Error Goto test
   DocumentLoaded = false
   
   cURL = ConvertToURL( cFile )
   ' Open the document. Just blindly assume that the document 
   ' is of a type that OOo will correctly recognize and open 
   ' without specifying an import filter.
   oDoc = StarDesktop.loadComponentFromURL( cURL, "_blank", 0, _
            Array(MakePropertyValue( "Hidden", True ),))
   
   RegisterListener(oDoc)
   ' in case OOo doesn't recognize the type then do nothing at all.
   If Not IsNull(oDoc) Then
   
   oIndexes = oDoc.getDocumentIndexes()
   
   If oIndexes.getCount () > 0 Then
   
   Do Until DocumentLoaded 
     wait 100
   Loop

   for i = 0 to oIndexes.getCount () - 1
    oIndexes (i).update
   next i
   
   EndIf

   cFile = Left( cFile, Len( cFile ) - 4 ) + cExtension
   cURL = ConvertToURL( cFile )
   
   ' Save the document using a filter.   
   oDoc.storeToURL( cURL, Array(_
            MakePropertyValue( "FilterName", cType ),)
   
   oDoc.close( True )
   
   EndIf
   
   Exit Sub
 test:
   ' We do not want any errors displayed.
   On Error Goto End
   If Not IsNull(oDoc) and Not IsEmpty(oDoc) Then
      oDoc.close( True )
   EndIf
End Sub

Function MakePropertyValue( Optional cName As String, Optional uValue ) _
   As com.sun.star.beans.PropertyValue
   Dim oPropertyValue As New com.sun.star.beans.PropertyValue
   If Not IsMissing( cName ) Then
      oPropertyValue.Name = cName
   EndIf
   If Not IsMissing( uValue ) Then
      oPropertyValue.Value = uValue
   EndIf
   MakePropertyValue() = oPropertyValue
End Function
[/size]

Re: ToC incorrectly updated with automated script

Posted: Thu Apr 23, 2009 6:57 pm
by Hardy
Well these breakpoints might work for you, since your document is hidden. Mine is visible and each such breakpoint fires a series (minimum 14) events including, of course, the focus events but these cause a row of other resulting events (either before or after the focus events). That's why I want to write it to a log file in the background, but that file seems always to be closed prematurely.

Re: ToC incorrectly updated with automated script

Posted: Tue Apr 28, 2009 12:21 pm
by Hardy
Hi Beld
Just found some more document events (event property of the document object (thisComponent)).
The ElementNames Pseudoproperty contains the following array:
(0) = OnStartApp
(1) = OnCloseApp
(2) = OnNew
(3) = OnLoad
(4) = OnSaveAs
(5) = OnSaveAsDone
(6) = OnSave
(7) = OnSaveDone
(8) = OnPrepareUnload
(9) = OnUnload
(10) = OnFocus
(11) = OnUnfocus
(12) = OnPrint
(13) = OnModifyChanged
(14) = OnCopyTo
(15) = OnCopyToDone
(16) = OnViewCreated
(17) = OnPrepareViewClosing
(18) = OnViewClosed
(19) = OnVisAreaChanged
(20) = OnCreate
(21) = OnLoadFinished
(22) = OnSaveAsFailed
(23) = OnSaveFailed
(24) = OnCopyToFailed
(25) = OnTitleChanged
(26) = OnModeChanged
(27) = OnMailMerge
(28) = OnPageCountChange

Perhaps "OnLoadFinished" occurs for your document and is the one that helps?

Re: ToC incorrectly updated with automated script

Posted: Tue Apr 28, 2009 12:31 pm
by Beld
wel the events with these names are triggered according to my test:

"" (not listed, and no EventName specified)
"OnTitleChanged" (nr 25 in that list of yours)
"OnModifyChanged" (nr 13)
"OnCopyTo" (nr 14)
"OnCopyToDone" (nr 15)
"OnViewClosed" (nr 18)
"OnUnload" (nr 9)

I've reported that empty event as a bug because it should have an EventName and according to my tests it doesn't.

Re: ToC incorrectly updated with automated script

Posted: Tue Apr 28, 2009 1:06 pm
by Hardy
The numbers in my post above are array indices, no relation to sequence of occurence.
My suspicion is that the ""-event is actually the the "OnLoad", but that it is triggered before the load and thus lacks some space (allocated memory) to store the string.
Under the events you could log, have you tried all of them for suitability? ("OnViewClosed" or "OnUnload" which might occur before actually unloading (wonder whether there is such a thing as "CancelEvent" for this one, then closing the doc after having written the ToC)?)

Re: ToC incorrectly updated with automated script

Posted: Sun Dec 17, 2017 11:51 pm
by _savage
Was there ever a proper solution to this problem? I noticed that a Writer document’s statistics are similarly incomplete when the initial call to loadComponentFromURL() returns. A related discussion is Is there any loading status for LoadComponentFromURL.