Saving Textsection to new document

Creating a macro - Writing a Script - Using the API (OpenOffice Basic, Python, BeanShell, JavaScript)
Post Reply
ponc
Posts: 86
Joined: Mon Dec 09, 2013 7:34 pm

Saving Textsection to new document

Post by ponc »

Hi,

as the title suggests, I try to save a textsection with all his formated text to a new document.
I've got a couple of textsections in my document and some of them are visible, some are not.
The only solution I found until now, is to use copy and paste with the viewcursor. Like this:

Code: Select all

Copy and Paste
             dispatcher = createUnoService("com.sun.star.frame.DispatchHelper") 
             dispatcher.executeDispatch(doc1.CurrentController.Frame,".uno:Copy","",0,())
             dispatcher.executeDispatch(doc2.CurrentController.Frame ,".uno:Paste","",0,()) 
When I do it this way, I have to make every section visible. But I want my code to run in the background, so that the user won't see all of the action, which is going on.

I also tried another way: creating a new section in the new document and attach the old section to it. But it didn't work. The code is roughly like this:

Code: Select all

newSection = self.doc.createInstance("com.sun.star.text.TextSection")
        new_text.insertTextContent(newTextSectionCursor, oldSection.Anchor, False)
The documentation says: "Some implementations may only accept contents which were created by the factory that supplied the same text or the document which contains the text"
http://www.openoffice.org/api/docs/comm ... XText.html
That might be the reason.

Does anyone know a better way to save a textsection to a new document?

Thanks for help,
ponc
OO 4.0.1 , LO 4.4.3.2 on win7 // LO 4.4.3.2 on Ubuntu 14.04
https://github.com/XRoemer/Organon
User avatar
Charlie Young
Volunteer
Posts: 1559
Joined: Fri May 14, 2010 1:07 am

Re: Saving Textsection to new document

Post by Charlie Young »

Here is my effort to do it by linking the sections in the new document into the old one. Notice that there is a struct com.sun.star.text.SectionFileLink which is used in the FileLink property of a TextSection to specify the source file, and there is a LinkRegion property which specifies the name of the source TextSection.

Code: Select all

Function LoadNewDoc() As Object
	Dim NewDoc As Object
	Dim Args(1) As new com.sun.star.beans.PropertyValue
	
	Args(0).Name = "Hidden"
 	Args(0).Value = False
 	Args(1).Name = "MacroExecutionMode"
 	Args(1).Value = 4
 	 	
 	NewDoc = StarDesktop.loadComponentFromURL("private:factory/swriter", "_Blank", 0, Args)
 	LoadNewDoc = NewDoc
End Function

Sub LinkSections
	Dim oDoc As Object
	Dim NewDoc As Object
	Dim oldSection As Object, newSection As Object
	Dim LinkStuff As New com.sun.star.text.SectionFileLink
	Dim i As Long
		
	oDoc = ThisComponent
	
	NewDoc = LoadNewDoc()
	
	For i = 0 To oDoc.getTextSections().getCount() - 1
		oldSection = oDoc.getTextSections().getByIndex(i)
		newSection = NewDoc.createInstance("com.sun.star.text.TextSection")
		NewDoc.getText().insertTextContent(NewDoc.getText().getEnd(),newSection,False)
		LinkStuff.FileURL = oDoc.URL
		newSection.setName(oldSection.getName())
		newSection.setPropertyValue("FileLink",LinkStuff)
		newSection.setPropertyValue("LinkRegion",oldSection.getName())
	Next i
	
End Sub
I haven' t tried it with anything but fairly simple, visible, TextSections, but it does preserve the source formatting.

You can, in the new doc, go to Edit > Links, then break the links one-by-one. This keeps the formatted sections in the new doc.

I have tried some experiments to try to break the links via program, with results varying from partly successful to outright bizarre. I'll post more when I've figured out how to explain this.
Apache OpenOffice 4.1.1
Windows XP
User avatar
Charlie Young
Volunteer
Posts: 1559
Joined: Fri May 14, 2010 1:07 am

Re: Saving Textsection to new document

Post by Charlie Young »

Interesting lesson here.

Version 1 attempting to break the section links

Code: Select all

Sub BreakSectionLinks1(oDoc As Object)
	Dim oSection As Object
	Dim BlankLink As New com.sun.star.text.SectionFileLink
	Dim SectionCount As Long, i As Long
	
	BlankLink.FileURL = ""
	BlankLink.FilterName = ""
	
	SectionCount = oDoc.getTextSections().getCount() - 1
		
	For i = 0 To SectionCount
		oSection = oDoc.getTextSections().getByIndex(i)
		oSection.setPropertyValue("LinkRegion","")
		oSection.setPropertyValue("FileLink",BlankLink)
	Next i
End Sub
If this is used, say by adding BreakSectionLinks1(NewDoc) at the end of the above LinkSections, when LinkRegion is set to "", then the section is given a child section for each of the sections in the original document, so if the original document has N sections, we wind up with N^2 sections in the new document, though the links are indeed broken.

If we reverse the property assignments

Code: Select all

	For i = 0 To SectionCount
		oSection = oDoc.getTextSections().getByIndex(i)
		oSection.setPropertyValue("FileLink",BlankLink)
		oSection.setPropertyValue("LinkRegion","")
	Next i
Then the link to the original document is broken first, and though we wind up with N unlinked sections, they are empty.

the trick seems to be to use setPropertyValues to set both FileLink and LinkRegion simultaneously. This works!

Code: Select all

Sub BreakSectionLinks(oDoc As Object)
	Dim oSection As Object
	Dim BlankLink As New com.sun.star.text.SectionFileLink
	Dim SectionCount As Long, i As Long
	Dim SectionPropNames(1) As String
	Dim SectionPropValues(1)
	
	BlankLink.FileURL = ""
	BlankLink.FilterName = ""
	
	SectionPropNames(0) = "FileLink"
	SectionPropNames(1) = "LinkRegion"
	
	SectionPropValues(0) = BlankLink
	SectionPropValues(1) = ""
	
	SectionCount = oDoc.getTextSections().getCount() - 1
	
	For i = 0 To SectionCount
		oSection = oDoc.getTextSections().getByIndex(i)
		oSection.setPropertyValues(SectionPropNames,SectionPropValues)
	Next i
End Sub
With that lesson learned, it seems expedient to rejigger LinkSections a bit as well

Code: Select all


Sub LinkSections
	Dim oDoc As Object
	Dim NewDoc As Object
	Dim oldSection As Object, newSection As Object
	Dim LinkStuff As New com.sun.star.text.SectionFileLink
	Dim i As Long
	Dim SectionPropNames(1) As String
	Dim SectionPropValues(1)
		
	SectionPropNames(0) = "FileLink"
	SectionPropNames(1) = "LinkRegion"
		
	oDoc = ThisComponent
	
	NewDoc = LoadNewDoc()
	
	For i = 0 To oDoc.getTextSections().getCount() - 1
		oldSection = oDoc.getTextSections().getByIndex(i)
		newSection = NewDoc.createInstance("com.sun.star.text.TextSection")
		NewDoc.getText().insertTextContent(NewDoc.getText().getEnd(),newSection,False)
		newSection.setName(oldSection.getName())
		LinkStuff.FileURL = oDoc.URL
		SectionPropValues(0) = LinkStuff
		SectionPropValues(1) = oldSection.getName()
		newSection.setPropertyValues(SectionPropNames,SectionPropValues)
	Next i
	BreakSectionLinks(NewDoc)
End Sub
I still want to try some more complex examples.
Last edited by Charlie Young on Sun Feb 02, 2014 9:28 pm, edited 2 times in total.
Apache OpenOffice 4.1.1
Windows XP
User avatar
Charlie Young
Volunteer
Posts: 1559
Joined: Fri May 14, 2010 1:07 am

Re: Saving Textsection to new document

Post by Charlie Young »

Charlie Young wrote:I still want to try some more complex examples.
Okay, here's a complicating situation: suppose in my source document I have five sections - Section1, Section2, Section3, Section4, Section5 - and Section5 is a ChildSection of Section2. Then what happens is Section5 is first linked as part of Section2, and when the loop gets to Section5, the program bombs on the line

Code: Select all

newSection.setName(oldSection.getName())
because the name is already in use in the new document. A solution seems to be to skip the ChildSections in the loop

Code: Select all

Sub LinkSections
	Dim oDoc As Object
	Dim NewDoc As Object
	Dim oldSection As Object, newSection As Object
	Dim LinkStuff As New com.sun.star.text.SectionFileLink
	Dim i As Long
	Dim SectionPropNames(1) As String
	Dim SectionPropValues(1)
		
	SectionPropNames(0) = "FileLink"
	SectionPropNames(1) = "LinkRegion"
		
	oDoc = ThisComponent
	
	NewDoc = LoadNewDoc()
	
	For i = 0 To oDoc.getTextSections().getCount() - 1
		oldSection = oDoc.getTextSections().getByIndex(i)
		If IsNull(oldSection.getParentSection()) Then
			newSection = NewDoc.createInstance("com.sun.star.text.TextSection")
			NewDoc.getText().insertTextContent(NewDoc.getText().getEnd(),newSection,False)
			newSection.setName(oldSection.getName())
			LinkStuff.FileURL = oDoc.URL
			SectionPropValues(0) = LinkStuff
			SectionPropValues(1) = oldSection.getName()
			newSection.setPropertyValues(SectionPropNames,SectionPropValues)
		End If
	Next i
	BreakSectionLinks(NewDoc)
End Sub
This seems to solve that problem.

This approach seems to work with nested tables, at least, but I'm still trying to think of other possible complications (any ideas?). If the source section is hidden, it will not be hidden in the new document unless it is a ChildSection. It should be possible to deal with this if it's any kind of an issue.
Apache OpenOffice 4.1.1
Windows XP
ponc
Posts: 86
Joined: Mon Dec 09, 2013 7:34 pm

Re: Saving Textsection to new document

Post by ponc »

Thanks for your replies and sorry for my late answer. But I needed a lot of testing

My situation is a bit complicated as I create an empty document at runtime, create dozens of textsections and link files to them. After working with the document I want to save the changes to the linked files.
For performance reasons I want to keep saving actions, iterations on the whole document and creating of new blank and hidden documents as low as possible.

So there is no original document. Maybe I'll change that in future. I have to think about it. But saving a large odt file needs some time and if you have to do it two or three times, it can last an incredibly long time.

My first solution to my problem was to create a second hidden document and use copy and paste between these two hidden documents. It seemed to work, but I prefer your solution. Thanks a lot. Linking to the region worked well.

In the moment I try to figure out if I can use MetadataReference. If you take a look at the content.xml in the .odt file, you'll find all the listed textsections in a quite comfortable way. It would be a nice and easy solution to be able to link them directly. In that case I wouldn't to have take care, if there are other sections - hidden or not - inside of them.

I tried this:

Code: Select all

TS = doc.TextSections
for i in range(TS.Count):
    sec = TS.getByIndex(i)
    sec.ensureMetadataReference()
    MD_ref = section.MetadataReference
    newDoc.addMetadataFile('some_name',MD_ref)
But I get this error:

2014-02-03 09:15:16,903 [CALL,tid 3000]: error py->uno[0x56406e0].addMetadataFile = (com.sun.star.script.CannotConvertException){ (com.sun.star.uno.Exception){ Message = (string)"conversion not possible!", Context = (com.sun.star.uno.XInterface)0x0 }, DestinationTypeClass = (com.sun.star.uno.TypeClass)SEQUENCE, Reason = (long)0x8, ArgumentIndex = (long)0x1 }


I don't know if the addMetadataFile asks for something else than the MetadataReference?
The documentation says I need a FileName and a Sequence of type XURI.
http://www.openoffice.org/api/docs/comm ... tadataFile
http://www.openoffice.org/api/docs/comm ... /XURI.html

I thought my MD_ref is a type XURI. But that seemes to be wrong.

Many thanks for your help,
ponc
OO 4.0.1 , LO 4.4.3.2 on win7 // LO 4.4.3.2 on Ubuntu 14.04
https://github.com/XRoemer/Organon
ponc
Posts: 86
Joined: Mon Dec 09, 2013 7:34 pm

Re: Saving Textsection to new document

Post by ponc »

It seemes that the metadata leads me nowhere and does other things then I expected.
'addMetadataFile' adds a file to the .odt zip package and an entry to the manifest.rdf, but there is no new content in the created file itself.
OO 4.0.1 , LO 4.4.3.2 on win7 // LO 4.4.3.2 on Ubuntu 14.04
https://github.com/XRoemer/Organon
ponc
Posts: 86
Joined: Mon Dec 09, 2013 7:34 pm

Re: Saving Textsection to new document

Post by ponc »

Accidently I discovered that adding a TextSection and removing it directly afterwards does the job as well. The section is gone and the formated text stays with images or nested sections.

So my code is like this:

Code: Select all

StatusIndicator = desktop.getCurrentFrame().createStatusIndicator()
StatusIndicator.start('saving ... , please wait',total)

Path = 'file:///<some_path>/doc.odt'
doc.storeToURL(Path,())                
			 
prop = uno.createUnoStruct("com.sun.star.beans.PropertyValue")
prop.Name = 'Hidden'
prop.Value = True      

newDoc = doc.CurrentController.Frame.loadComponentFromURL("private:factory/swriter","_blank",0,(prop,))
cur = newDoc.Text.createTextCursor()

SFLink = uno.createUnoStruct("com.sun.star.text.SectionFileLink")
SFLink.FileURL = Path
counter = 1

for i in range(TS.Count):
		
	sec = TS.getByIndex(i)

	if 'whatever_you_have_called_your_sections' in sec.Name:
			 
	    newSection = doc.createInstance("com.sun.star.text.TextSection")
	    newSection.setPropertyValue('FileLink',SFLink)
	    newSection.setName(sec.Name)
	    newSection.setPropertyValue("LinkRegion",sec.Name)
											 
		cur.gotoStart(False)
		cur.gotoEnd(True)
				
		newDoc.Text.insertTextContent(cur, newSection, True)
		newDoc.Text.removeTextContent(newSection)

		Path2 = 'file:///<some_path>/newFile%s.odt' % counter
		newDoc.storeToURL(Path2,())
				
		#StatusIndicator.setText(' saved: %s of %s ' % (counter,total))
		counter += 1
    
newDoc.close(False)
StatusIndicator.end()

But now I'm fighting with the status indicator. The indicator doesn't like to update in my application while working on a hidden document. I'm not sure yet what's the exact reason.
OO 4.0.1 , LO 4.4.3.2 on win7 // LO 4.4.3.2 on Ubuntu 14.04
https://github.com/XRoemer/Organon
ponc
Posts: 86
Joined: Mon Dec 09, 2013 7:34 pm

Re: Saving Textsection to new document

Post by ponc »

The status indicator can't be used while storing a document. This is mentioned here: (in german)
http://de.openoffice.info/viewtopic.php?f=18&t=61870

To do at least an update every 10 or 20 files, one has to close the document and reopen it again after updating the status indicator.
OO 4.0.1 , LO 4.4.3.2 on win7 // LO 4.4.3.2 on Ubuntu 14.04
https://github.com/XRoemer/Organon
Post Reply