Macro for crossreference

Creating a macro - Writing a Script - Using the API (OpenOffice Basic, Python, BeanShell, JavaScript)
Post Reply
clesiopof
Posts: 4
Joined: Wed Feb 26, 2020 9:17 pm

Macro for crossreference

Post by clesiopof »

I am trying to build a cross reference function for my macro in writer, something like this:

Code: Select all

sub crossreference (file, namesection,reference)
   dim oDescriptor,ofound 
  oDescriptor = file.createSearchDescriptor()
  With oDescriptor
    .SearchString =  reference
  End With
  oFound = file.findFirst(oDescriptor)
  if isnull(ofound) then exit sub
  dim oField
  oField = file.createInstance("com.sun.star.text.textfield.GetReference")
  oField.ReferenceFieldPart = com.sun.star.text.ReferenceFieldPart.NUMBER
  oField.ReferenceFieldSource = 2
  oField.SourceName = "__RefNumPara__5813_2658656130"
    dim textcursor as object, oanchor, section as object
    textcursor = file.getText().createTextCursor()
    section = file.getTextSections.GetByName(namesection)
    oanchor = section.getAnchor()
    textcursor.gotoRange(oanchor, False)
    textcursor.collapseToEnd()
    file.getText().insertTextContent(textcursor, oField, false)
end sub
but the problem is that i dont know how to make the search descriptor to return something like "__RefNumPara__5813_2658656130" the reference for the paragraph, probably an enumeration of some sort. Anyone knows how this works?
Openoffice 4.1.7 on Kubuntu 18.04
User avatar
Hagar Delest
Moderator
Posts: 32657
Joined: Sun Oct 07, 2007 9:07 pm
Location: France

Re: Macro for crossreference

Post by Hagar Delest »

Hi and welcome to the forum!

The macros in the extension discussed here may help: [Solved] Cross-reference: Formatting.

Please add [Solved] at the beginning of the title in your first post (top of the topic) with the *EDIT button if your issue has been fixed.
LibreOffice 7.6.2.1 on Xubuntu 23.10 and 7.6.4.1 portable on Windows 10
clesiopof
Posts: 4
Joined: Wed Feb 26, 2020 9:17 pm

Re: Macro for crossreference

Post by clesiopof »

Thanks Hagar, i will look at the code from the extension and post here if i find the answer.
Openoffice 4.1.7 on Kubuntu 18.04
clesiopof
Posts: 4
Joined: Wed Feb 26, 2020 9:17 pm

Re: Macro for crossreference

Post by clesiopof »

Its not what i was looking for Hagar, the extension you pointed me, makes a crossreference based on references and bookmarks.

Code: Select all

oRefMarks = oDoc.Referencemarks
oBookMarks = oDoc.Bookmarks
I was looking on how to make it based on numbered paragraphs.
Openoffice 4.1.7 on Kubuntu 18.04
JeJe
Volunteer
Posts: 2779
Joined: Wed Mar 09, 2016 2:40 pm

Re: Macro for crossreference

Post by JeJe »

Code: Select all

tf =thiscomponent.textfields.createenumeration
 do until tf.hasmoreelements = false
 f =tf.nextelement
 msgbox f.getpropertyvalue ("SourceName")
 loop
 

Sorry, that's not relevant... I think I get what you want and that's to find the reference to the paragraph which is created when you manually create a field by picking from the list of items that appears in the "Selection" listbox of the insert field dialog.

Enumerating the paragraphs and using MRI for each... the only thing that looks remotely similar is something called the StringValue which ends in something like "/content.xml#id1696954595" but that's not the same number.

Edit2:

Creating a simple file with a field and looking at context.xml it looks like paragraphs have an id number but the number you want is different - and is only there when you have created the field - but you'll have to look at that yourself to make sure.
Windows 10, Openoffice 4.1.11, LibreOffice 7.4.0.3 (x64)
musikai
Volunteer
Posts: 294
Joined: Wed Nov 11, 2015 12:19 am

Re: Macro for crossreference

Post by musikai »

problem is that something like "__RefNumPara__5813_2658656130" is only created when you insert a crossreference field via menu.
it is a kind of bookmark.

Say you have
1. first line
2. second line
3. third line

Now manually insert a cross reference for the first.

With the following macro you can find the RefNumPara by the name of the Paragraph.
It will give back a RefNumPara for "first line" but not for "second line" or "third line".

Code: Select all

sub search_for_refs
sSearch="first line"
msgbox get_Ref_from_name2(sSearch)
end sub

rem------------this gets the ReferenceMark (if it exists)
function get_Ref_from_name2(sSearch)
oDoc=ThisComponent

 oParEnum = oDoc.Text.createEnumeration()
Do While oParEnum.hasMoreElements()
 oPar = oParEnum.nextElement()
 If oPar.supportsService("com.sun.star.text.Paragraph")  Then	 
	 oEnum = oPar.createEnumeration()
		  Do While oEnum.hasMoreElements()
		  oSect = oEnum.nextElement()
	 			if oSect.string = sSearch then
					Do While oEnum.hasMoreElements()
					oSect = oEnum.nextElement()		 
						 If NOT IsNULL(oSect.bookmark) Then
	 					 get_Ref_from_name2 = oSect.bookmark.LinkDisplayName
						 exit function
						 End If						 						
					loop
				end if	
		  loop	 
 end if
 
loop
get_Ref_from_name2 = ""
end function
So perhaps there is a way to create custom bookmarks for your numbered paras.
Win7 Pro, Lubuntu 15.10, LO 4.4.7, OO 4.1.3
Free Project: LibreOffice Songbook Architect (LOSA)
http://struckkai.blogspot.de/2015/04/li ... itect.html
JeJe
Volunteer
Posts: 2779
Joined: Wed Mar 09, 2016 2:40 pm

Re: Macro for crossreference

Post by JeJe »

If you add your own bookmark to the paragraph then you can set oField.SourceName = the name you gave the bookmark.
Windows 10, Openoffice 4.1.11, LibreOffice 7.4.0.3 (x64)
JeJe
Volunteer
Posts: 2779
Joined: Wed Mar 09, 2016 2:40 pm

Re: Macro for crossreference

Post by JeJe »

Or you could just use heading paragraphs and hyperlinks.

As each paragraph has a stringvalue identifier you could use that... You'd need a field/hyperlink/other method of calling a macro which finds the paragraph with that stringvalue by enumerating the text. The stringvalue to be found could be stored in some hidden text next to the field.
Windows 10, Openoffice 4.1.11, LibreOffice 7.4.0.3 (x64)
clesiopof
Posts: 4
Joined: Wed Feb 26, 2020 9:17 pm

Re: Macro for crossreference

Post by clesiopof »

For now my code is looking like this using reference marks

Code: Select all

sub crossreference (file, namesection,reference)
   dim oDescriptor,ofound
  oDescriptor = file.createSearchDescriptor()
  With oDescriptor
    .SearchString =  reference
  End With
  oFound = file.findFirst(oDescriptor)
  if isnull(ofound) then exit sub
  dim textcursor as object
  textcursor = file.getText().createTextCursor()
  textcursor.gotorange(ofound,false)
  textcursor.gotostartofparagraph(false)
  textcursor.gotoendofparagraph(true)
  dim oRefField as object, oname as string, i as integer
  	i = 1
	oRefField = file.createInstance("com.sun.star.text.ReferenceMark")
	oname = "reference " & i
	do while file.referencemarks.hasbyname(oname)
		i = i +1
oname = "reference " & i
	loop
	oRefField.setname(oname)
	file.Text.insertTextContent(textcursor, oRefField, False)
  dim oField
  oField = file.createInstance("com.sun.star.text.textfield.GetReference")
  oField.ReferenceFieldPart = com.sun.star.text.ReferenceFieldPart.CHAPTER
  oField.ReferenceFieldSource = 0
  oField.SourceName = oname
    dim oanchor, section as object
    section = file.getTextSections.GetByName(namesection)
    oanchor = section.getAnchor()
    textcursor.gotoRange(oanchor, False)
    textcursor.collapseToEnd()
    file.getText().insertTextContent(textcursor, oField, false)
end sub
Is not what i wanted, but is the closest i could manage to do.
Openoffice 4.1.7 on Kubuntu 18.04
JeJe
Volunteer
Posts: 2779
Joined: Wed Mar 09, 2016 2:40 pm

Re: Macro for crossreference

Post by JeJe »

found this problem interesting... here's my code for using the paragraph id... in case anyone wants it in future.

Code: Select all



	REM  *****  BASIC  *****
'code goes in a document's Standard library/Module1
'set the text of one of the paragraphs to "The fishermen" 
'move the cursor to somewhere else
'run main
'a field will be created at the viewcursor with the same text as the paragraph
'clicking on it will fire the GoToRefPara macro which will go to the required paragraph.
sub Main '
parastring= "The fishermen"
InsertMacroFieldForPara(parastring)
end sub

sub InsertMacroFieldForPara(parastring) 'add a field 
	en =thiscomponent.gettext.createenumeration
	do until en.hasmoreelements = false
		p =en.nextelement
		if p.string=parastring then

			oField = thiscomponent.createInstance("com.sun.star.text.textfield.Macro")
			with oField
				.hint = p.string
				no = endval(p.stringvalue)
				.MacroName = "vnd.sun.star.script:Standard.Module1.GoToRefPara?language=Basic&location=document" & "&id=" & no
				thiscomponent.getText().insertTextContent(thiscomponent.currentcontroller.viewcursor, oField, false)
			end with
			exit do
		end if
	loop

end sub


Sub GoToRefPara()
	dim no as string
	vc = thiscomponent.currentcontroller.viewcursor

	no =endval(vc.textfield.macroname)
	lenno = len(no)
	paras = thiscomponent.gettext.createenumeration

	do until paras.hasmoreelements = false
		p =paras.nextelement
		if right(p.stringvalue,lenno) = no then

			thiscomponent.currentcontroller.select(p)
			exit do
		end if
	loop
End Sub


Function EndVal(st As String) As Long


	Dim i As Long, a As Integer, s As String, res As String
	res = ""
	s = ""
	For i = Len(st) To 1 Step -1
		s = Mid(st, i, 1)
		a = Asc(s)
		If a >= 48 And a <= 57 Then
			res = s & res
		Else
			Exit For
		End If
	Next
	EndVal = Val(res)
End Function



Windows 10, Openoffice 4.1.11, LibreOffice 7.4.0.3 (x64)
Post Reply