Number or string representation of a Writer TextRange

Shared Libraries
Forum rules
For sharing working examples of macros / scripts. These can be in any script language supported by OpenOffice.org [Basic, Python, Netbean] or as source code files in Java or C# even - but requires the actual source code listing. This section is not for asking questions about writing your own macros.
Post Reply
JeJe
Volunteer
Posts: 2779
Joined: Wed Mar 09, 2016 2:40 pm

Number or string representation of a Writer TextRange

Post by JeJe »

Posting this as wanted it a while ago but didn't think it was available from Basic.

Every paragraph has an id no so a text paragraph's textrange position will be that ID plus the character offset from the start of the paragraph.

Below example gets the paragraph ID and character positions of the selection (viewcursor), clears that selection, then restores it using that information. Select some text in a document, run main.

Tested on OO only, may not work with something more complicated than just text paragraphs.

Code: Select all




Sub Main
	dim paraID1 as string,charNO1 as string,paraID2 as string,charNO2 as string

	'get paraID and charno representation of viewcursor start and end of textranges
	tc =thiscomponent.text.createtextcursorbyrange(thiscomponent.currentcontroller.viewcursor.getstart)
	getTextRangeParaIDAndCharNo(tc,paraID1,charNO1)
	tc =thiscomponent.text.createtextcursorbyrange(thiscomponent.currentcontroller.viewcursor.getend)
	getTextRangeParaIDAndCharNo(tc,paraID2,charNO2)

	thiscomponent.currentcontroller.select(thiscomponent.text.getstart) 'clear selection by moving viewcursor to start


	msgbox paraID1 & "," &  charno1 & chr(10) &  paraID2 & "," &  charno2
	'restore selection from paraIDs and charno
	tc3 = setTextRangeFromParaIDAndCharNo(thiscomponent,paraID1,charno1)
	tc4 = setTextRangeFromParaIDAndCharNo(thiscomponent,paraID2,charno2)
	tc3.gotorange(tc4,true)
	thiscomponent.currentcontroller.select(tc3,false)

end sub

sub getTextRangeParaIDAndCharNo(tc,byref paraID as string,byref charNo as string)
	tc.gotostartofparagraph(true)
	cno= len(tc.string)
	en = tc.createenumeration
	do until en.hasmoreelements = false
		p =en.nextelement
		paraID =endval( p.localname)
		charNo = cno
		exit do
	loop
End sub

function setTextRangeFromParaIDAndCharNo(componentv,paraID as string,charNo as string)
	lenno = len(paraID)
	en = componentv.text.createenumeration
	do until en.hasmoreelements = false
		p =en.nextelement
		if right (p.localname,lenno) = paraID then
			tc =componentV.text.createtextcursorbyrange(p)
			tc.gotoStartOfParagraph(false)
			tc.goright(val(charNO),false)
			setTextRangeFromParaIDAndCharNo=tc
			exit do
		end if
	loop
End function

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


Edit: didn't include the endval function to get the number at the end of a string - added.
Last edited by JeJe on Wed Mar 04, 2020 2:12 am, edited 3 times in total.
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: Number or string representation of a Writer TextRange

Post by musikai »

Didn't know about paragraph Id's.
Usage?
Why not just use cursor.gotorange()?
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: Number or string representation of a Writer TextRange

Post by JeJe »

The point is its a way of saving the range position... to a text file/property/for later whatever. Otherwise you can only know where a textrange is in relation to another text range and you can't do that.

Para Ids are potentially very useful to me. If you identify a paragraph by number... say the 15th para in the document... then the position may change if the document is edited. Using the para id the correct para can still be found. I could have a note or data for that para (in a property or an external file) without there needing to be a placeholder in the document marking the note.
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: Number or string representation of a Writer TextRange

Post by JeJe »

With some help from Lupp, a bit more involved version that handles a selection that is in a textframe, texttable, header or footer too.

Code: Select all

Sub Main
	on error goto hr
	txt=thiscomponent.currentcontroller.viewcursor.text

	vcstart=getrangestring(true)
	vcend = getrangestring(false)

	thiscomponent.currentcontroller.select(txt.start)
	msgbox vcstart & chr(10) & vcend
	tc3 = getrangefromstring(vcstart)
	tc4 = getrangefromstring(vcend)
	tc3.gotorange(tc4,true)
	thiscomponent.currentcontroller.select(tc3,false)

	hr: 'possibly no text selection
End Sub

function getrangefromstring(st)
	dim found as boolean
	vc= thiscomponent.currentcontroller.viewcursor
	sts = split(st,"|")

	select case sts(0)
	case "SwXBodyText"
		getrangefromstring =setTextRangeFromParaIDAndCharNo(thiscomponent.gettext,sts(1),sts(2),found)
	case "SwXTextFrame" 'text frame
		For Each frame In thiscomponent.textFrames

			getrangefromstring =setTextRangeFromParaIDAndCharNo(frame.gettext,sts(1),sts(2),found)
			if found then exit for
		next frame

	case "SwXCell" 'text table

		doc = ThisComponent
		tts = ThisComponent.TextTables ' this bit pinched from Lupp
		if tts.count > 0 then
		For j = 0 To tts.Count - 1
			j_tt = tts(j)
			cns = j_tt.CellNames
			For k = 0 To Ubound(cns)
				cell = j_tt.getCellByName(cns(k))
				getrangefromstring =setTextRangeFromParaIDAndCharNo( cell.Text,sts(1),sts(2),found)
				if found then goto hr
			Next k
		Next j
	end if
hr:
	case "SwXHeadFootText"


		ps =thiscomponent.StyleFamilies.getByName("PageStyles")
		for i = 0 to ps.count -1
			s = ps.getbyindex(i)
			if s.headerison then
				getrangefromstring =setTextRangeFromParaIDAndCharNo( s.headertext,sts(1),sts(2),found)
				if found then exit for
			end if
			if s.footerison then
				getrangefromstring =setTextRangeFromParaIDAndCharNo(s.footertext,sts(1),sts(2),found)
				if found then exit for
			end if

		next



	case else

		exit function
	end select

end function


function getrangestring(isstart)
	vc= thiscomponent.currentcontroller.viewcursor
	getrangestring =vc.text.implementationname & "|"
	select case vc.text.implementationname
	case "SwXCell"
		tc= vc.cell.gettext.createTextCursorByRange( vc)
	case "SwXTextFrame"
		tc = vc.textframe.gettext.createTextCursorByRange( vc)
	case "SwXBodyText"
		tc = thiscomponent.gettext.createTextCursorByRange(vc)
	case "SwXHeadFootText"
		tc = vc.gettext.createTextCursorByRange(vc)
	case else
		exit function
	end select

	if isstart then TC.collapsetostart else TC.COLLAPSETOEND
	en = tc.createenumeration
	do until en.hasmoreelements = false
		p = en.nextelement
		getrangestring = getrangestring & p.localname
		exit do
	loop

	tc.gotostartofparagraph(true)
	getrangestring = getrangestring & "|" & len(tc.string)

	select case vc.text.implementationname
	case "SwXCell"
		getrangestring = getrangestring & "|" &  vc.texttable.name & "|" & vc.cell.cellname
	case "SwXTextFrame"
		getrangestring = getrangestring & "|" & vc.textframe.name
	case "SwXBodyText"

	end select

end function

function setTextRangeFromParaIDAndCharNo(txt,paraid as string,charno as string,byref found as boolean)
	en = txt.createenumeration
	do until en.hasmoreelements = false
		p =en.nextelement
		if p.supportsService("com.sun.star.text.Paragraph") Then
			if p.localname= paraID then
				found = true
				tc =txt.createtextcursorbyrange(p)
				tc.gotoStartOfParagraph(false)
				tc.goright(val(charNO),false)
				setTextRangeFromParaIDAndCharNo=tc
				exit do
			end if
		end if
	loop
end function

Edit: Added fixes for table
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: Number or string representation of a Writer TextRange

Post by JeJe »

Final (probably) bit more involved version again that handles footnotes and endnotes as well.

Code: Select all


sub testsub
CURRENTSelection
end sub


sub SelectRangeFromString(vcstart,vcend)
	tc3 = getrangefromstring(vcstart)
	tc4 = getrangefromstring(vcend)
	tc3.gotorange(tc4,true)
	thiscomponent.currentcontroller.select(tc3,false)
end sub
function createrangeFromString(vcstart,vcend)
	tc3 = getrangefromstring(vcstart)
	tc4 = getrangefromstring(vcend)
	tc3.gotorange(tc4,true)
	createrangeFromString =tc3
end function


function GetMultipleSelections()
	sel= thiscomponent.currentcontroller.selection

	if sel.count>0 then
		for i =0 to  sel.count-1
			vcstart =getrangestring2(sel.getbyindex(i),true)
			vcend = getrangestring2(sel.getbyindex(i),false)
			if i <>0 then st = st & chr(13)
			st = st & vcstart & "," & vcend
		next
		GetMultipleSelections= st
		msgbox st
	end if
End function


Sub currentSelection
	on error goto hr
	
	vcstart=getrangestring(true)
	if vcstart =nullstring then exit sub
	vcend = getrangestring(false)


	thiscomponent.currentcontroller.select(thiscomponent.gettext.start)


	msgbox vcstart & chr(10) & vcend

	tc3 = getrangefromstring(vcstart)
	tc4 = getrangefromstring(vcend)
	tc3.gotorange(tc4,true)
	thiscomponent.currentcontroller.select(tc3,false)

	hr: 'possibly no text selection
End Sub

function getrangefromstring(st)
	dim found as boolean
	vc= thiscomponent.currentcontroller.viewcursor
	sts = split(st,"|")

	select case sts(0)
	case "SwXBodyText"
		getrangefromstring =setTextRangeFromParaIDAndCharNo(thiscomponent.gettext,sts(1),sts(2),found)
	case "SwXTextFrame" 'text frame
		For Each frame In thiscomponent.textFrames

			getrangefromstring =setTextRangeFromParaIDAndCharNo(frame.gettext,sts(1),sts(2),found)
			if found then exit for
		next frame

	case "SwXCell" 'text table

		'if thiscomponent.texttables.hasbyname( sts(3)) then
		'tbl =thiscomponent.texttables.getbyname( sts(3))
		'		cns = tbl.CellNames
		'			For k = 0 To Ubound(cns)
		'				if cns(k) = sts(4) then
		'				getrangefromstring =setTextRangeFromParaIDAndCharNo( tbl.getcellbyname(sts(4)).Text,sts(1),sts(2),found)
		'				exit for
		'				end if
		'				next
		'				if not found then getrangefromstring =getrangefromstring2(st)
		'end if

		tts = ThisComponent.TextTables ' this bit pinched from Lupp
		if tts.count > 0 then
			For j = 0 To tts.Count - 1
				j_tt = tts(j)
				cns = j_tt.CellNames
				For k = 0 To Ubound(cns)
					cell = j_tt.getCellByName(cns(k))
					getrangefromstring =setTextRangeFromParaIDAndCharNo( cell.Text,sts(1),sts(2),found)
					if found then goto hr
				Next k
			Next j
		end if
hr:
	case "SwXHeadFootText"


		ps =thiscomponent.StyleFamilies.getByName("PageStyles")
		for i = 0 to ps.count -1
			s = ps.getbyindex(i)
			if s.headerison then
				getrangefromstring =setTextRangeFromParaIDAndCharNo( s.headertext,sts(1),sts(2),found)
				if found then exit for
			end if
			if s.footerison then
				getrangefromstring =setTextRangeFromParaIDAndCharNo(s.footertext,sts(1),sts(2),found)
				if found then exit for
			end if

		next


	CASE "SwXFootnote"

		fnotes = thiscomponent.footnotes
		if fnotes.count > 0 then
			for i = 0 to fnotes.count -1
				getrangefromstring =setTextRangeFromParaIDAndCharNo(fnotes.getbyindex(i).gettext,sts(1),sts(2),found)

				if found = true then exit for
			next
		end if
		if found = false then
			enotes = thiscomponent.endnotes
			if enotes.count > 0 then
				for i = 0 to enotes.count -1
					getrangefromstring =setTextRangeFromParaIDAndCharNo(enotes.getbyindex(i).gettext,sts(1),sts(2),found)
					if found = true then exit for
				next
			end if
		end if


	CASE "SwXTextViewCursor"
	end select

end function


function getrangestring(isstart)
	vc= thiscomponent.currentcontroller.viewcursor

	if hastextinterface(vc) = false then exit function

		getrangestring =vc.text.implementationname & "|"

		select case vc.text.implementationname
		case "SwXCell"
			tc= vc.cell.gettext.createTextCursorByRange( vc)
		case "SwXTextFrame"
			tc = vc.textframe.gettext.createTextCursorByRange( vc)
		case "SwXBodyText"
			tc = thiscomponent.gettext.createTextCursorByRange(vc)
		case "SwXHeadFootText"
			tc = vc.gettext.createTextCursorByRange(vc)
		CASE "SwXFootnote"
			tc = vc.gettext.createTextCursorByRange(vc)
		CASE "SwXTextViewCursor"
		case else
			exit function
		end select
	if isstart then TC.collapsetostart else TC.COLLAPSETOEND
	en = tc.createenumeration
	do until en.hasmoreelements = false
		p = en.nextelement
		getrangestring = getrangestring & p.localname
		exit do
	loop

	tc.gotostartofparagraph(true)
	getrangestring = getrangestring & "|" & len(tc.string)

	select case vc.text.implementationname
	case "SwXCell"
		getrangestring = getrangestring & "|" &  vc.texttable.name & "|" & vc.cell.cellname
	case "SwXTextFrame"
		getrangestring = getrangestring & "|" & vc.textframe.name
'	case "SwXBodyText"
'	case "SwXHeadFootText"
	CASE "SwXFootnote"
		getrangestring = getrangestring & "|" &	 tc.parastylename
	end select

		'note for comments gettext is empty. The text is found from textfield.textrange.text
		'But may return void for the textfield and the viewcursor does not appear to give information to identify the
		'selected paragraph when void is not returned. So not been implemented
		'if isempty(vc.TEXTFIELD) =false then
		'getrangestring ="SwXTextViewCursor|" 
		'getrangestring =getrangestring & vc.textfield.Author
		'tc=vc.textfield.textrange.text.createTextCursorByRange(vc.textfield.textrange) ' .ImplementationName 'SvxUnoTextBase
		'with vc.textfield.datetimevalue
		'tmp =cstr(.Year) & "," & cstr(.Month)  & "," & cstr(.Day) & "," & cstr(.Hours) & "," & cstr(.Minutes) &  "," & cstr(.Seconds) & "," & cstr(.HundredthSeconds) & "|"
		'end with

end function

function setTextRangeFromParaIDAndCharNo(txt,paraid as string,charno as string,byref found as boolean)
	en = txt.createenumeration
	do until en.hasmoreelements = false
		p =en.nextelement
		if p.supportsService("com.sun.star.text.Paragraph") Then
			if p.localname= paraID then
				found = true
				tc =txt.createtextcursorbyrange(p)
				tc.gotoStartOfParagraph(false)
				tc.goright(val(charNO),false)
				setTextRangeFromParaIDAndCharNo=tc
				exit do
			end if
		end if
	loop
end function


function hastextinterface(vc) as boolean
	hastextinterface = false
	on error goto hr
	txt = vc.text
	hastextinterface = true
	exit function
hr:
end function




function getrangefromstring2(st) 'SEARCHES ALL TEXT RANGES
	dim found as boolean
	vc= thiscomponent.currentcontroller.viewcursor
	sts = split(st,"|")

		getrangefromstring2 =setTextRangeFromParaIDAndCharNo(thiscomponent.gettext,sts(1),sts(2),found)


	if (found = false and thiscomponent.textFrames.count > 0) then 'text frames
	For Each frame In thiscomponent.textFrames
		getrangefromstring2 =setTextRangeFromParaIDAndCharNo(frame.gettext,sts(1),sts(2),found)
		if found then exit for
	next frame
	end if


	if (found = false and thiscomponent.texttables.count > 0) then 'text table
		tts = ThisComponent.TextTables ' this bit pinched from Lupp
		if tts.count > 0 then
			For j = 0 To tts.Count - 1
				j_tt = tts(j)
				cns = j_tt.CellNames
				For k = 0 To Ubound(cns)
					cell = j_tt.getCellByName(cns(k))
					getrangefromstring2 =setTextRangeFromParaIDAndCharNo( cell.Text,sts(1),sts(2),found)
					if found then goto hr
				Next k
			Next j
		end if
	end if
	hr:

		if found = false then 'footnote
		fnotes = thiscomponent.footnotes
		if fnotes.count > 0 then
			for i = 0 to fnotes.count -1
				getrangefromstring2 =setTextRangeFromParaIDAndCharNo(fnotes.getbyindex(i).gettext,sts(1),sts(2),found)

				if found = true then exit for
			next
		end if
		end if
		
		if found = false then 'end note
			enotes = thiscomponent.endnotes
			if enotes.count > 0 then
				for i = 0 to enotes.count -1
					getrangefromstring2 =setTextRangeFromParaIDAndCharNo(enotes.getbyindex(i).gettext,sts(1),sts(2),found)
					if found = true then exit for
				next
			end if
		end if

		if found = false then 'header, footer
		ps =thiscomponent.StyleFamilies.getByName("PageStyles")
		for i = 0 to ps.count -1
			s = ps.getbyindex(i)
			if s.headerison then
				getrangefromstring2 =setTextRangeFromParaIDAndCharNo( s.headertext,sts(1),sts(2),found)
				if found then exit for
			end if
			if s.footerison then
				getrangefromstring2 =setTextRangeFromParaIDAndCharNo(s.footertext,sts(1),sts(2),found)
				if found then exit for
			end if

		next
		end if
end function




Edit: spoke too soon...
was also missing getrangestring2
Last edited by JeJe on Fri Mar 20, 2020 6:32 pm, edited 3 times in total.
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: Number or string representation of a Writer TextRange

Post by JeJe »

Added support for multiple selections as saw Ms Ruth's post on viewtopic.php?f=20&t=79676

And included sub missing in last post

to run testsub - create multiple selections in a document
when the msgbox is shown you can check that the selections are no longer there as the viewcursor is moved to the start of the document
the selections are then restored using the string shown in the msgbox

Code: Select all

sub testsub
	st=GetMultipleSelections()
	thiscomponent.currentcontroller.select(thiscomponent.gettext.start)
	msgbox st

	setMultipleSelections(st)
	'CURRENTSelection
end sub


sub SelectRangeFromString(vcstart,vcend)
	tc3 = getrangefromstring(vcstart)
	tc4 = getrangefromstring(vcend)
	tc3.gotorange(tc4,true)
	thiscomponent.currentcontroller.select(tc3,false)
end sub
function createrangeFromString(vcstart,vcend)
	tc3 = getrangefromstring(vcstart)
	tc4 = getrangefromstring(vcend)
	tc3.gotorange(tc4,true)
	createrangeFromString =tc3
end function


function GetMultipleSelections()
	sel= thiscomponent.currentcontroller.selection

	if sel.count>0 then
		for i =0 to  sel.count-1
			vcstart =getrangestring2(sel.getbyindex(i),true)
			vcend = getrangestring2(sel.getbyindex(i),false)
			if i <>0 then st = st & chr(13)
			st = st & vcstart & "," & vcend
		next
		GetMultipleSelections= st

	end if
End function

sub SetMultipleSelections(st)
	on error goto hr
	Dim SrchAttributes(0) As New com.sun.star.beans.PropertyValue
	doc = thiscomponent

	doc.lockcontrollers
	sts = split(st,chr(13))
	for i =0 to ubound(sts)
		startend = split(sts(i),",")
		tc3 = getrangefromstring(startend(0))
		tc4 = getrangefromstring(startend(1))
		tc3.gotorange(tc4,true)
		tc3.CharFlash= true
	next

	vc= doc.currentcontroller.viewcursor
	SrchAttributes(0).Name = "CharFlash": SrchAttributes(0).Value =true
	'SrchAttributes(0).Name = "CharOverline": SrchAttributes(0).Value =1
	txtsearch = doc.createsearchdescriptor
	txtsearch.setSearchAttributes SrchAttributes
	txtsearch.setvaluesearch(false)
	Found = Doc.findAll(TxtSearch)

	' include the first selection using  Ms Ruth's trick at https://forum.openoffice.org/en/forum/viewtopic.php?f=20&t=79676
	thiscomponent.currentcontroller.select(Found)
	VC.gotoRange(Found(0).Start, True)

	' undo the property change leaving the selection
	VC.charflash = false

hr:
	doc.unlockcontrollers
end sub


Sub currentSelection
	on error goto hr

	vcstart=getrangestring(true)
	if vcstart =nullstring then exit sub
	vcend = getrangestring(false)


	thiscomponent.currentcontroller.select(thiscomponent.gettext.start)


	msgbox vcstart & chr(10) & vcend

	tc3 = getrangefromstring(vcstart)
	tc4 = getrangefromstring(vcend)
	tc3.gotorange(tc4,true)
	thiscomponent.currentcontroller.select(tc3,false)

	hr: 'possibly no text selection
End Sub

function getrangefromstring(st)
	dim found as boolean
	vc= thiscomponent.currentcontroller.viewcursor
	sts = split(st,"|")

	select case sts(0)
	case "SwXBodyText"
		getrangefromstring =setTextRangeFromParaIDAndCharNo(thiscomponent.gettext,sts(1),sts(2),found)
	case "SwXTextFrame" 'text frame
		For Each frame In thiscomponent.textFrames

			getrangefromstring =setTextRangeFromParaIDAndCharNo(frame.gettext,sts(1),sts(2),found)
			if found then exit for
		next frame

	case "SwXCell" 'text table

		'if thiscomponent.texttables.hasbyname( sts(3)) then
		'tbl =thiscomponent.texttables.getbyname( sts(3))
		'		cns = tbl.CellNames
		'			For k = 0 To Ubound(cns)
		'				if cns(k) = sts(4) then
		'				getrangefromstring =setTextRangeFromParaIDAndCharNo( tbl.getcellbyname(sts(4)).Text,sts(1),sts(2),found)
		'				exit for
		'				end if
		'				next
		'				if not found then getrangefromstring =getrangefromstring2(st)
		'end if

		tts = ThisComponent.TextTables ' this bit pinched from Lupp
		if tts.count > 0 then
			For j = 0 To tts.Count - 1
				j_tt = tts(j)
				cns = j_tt.CellNames
				For k = 0 To Ubound(cns)
					cell = j_tt.getCellByName(cns(k))
					getrangefromstring =setTextRangeFromParaIDAndCharNo( cell.Text,sts(1),sts(2),found)
					if found then goto hr
				Next k
			Next j
		end if
hr:
	case "SwXHeadFootText"


		ps =thiscomponent.StyleFamilies.getByName("PageStyles")
		for i = 0 to ps.count -1
			s = ps.getbyindex(i)
			if s.headerison then
				getrangefromstring =setTextRangeFromParaIDAndCharNo( s.headertext,sts(1),sts(2),found)
				if found then exit for
			end if
			if s.footerison then
				getrangefromstring =setTextRangeFromParaIDAndCharNo(s.footertext,sts(1),sts(2),found)
				if found then exit for
			end if

		next


	CASE "SwXFootnote"

		fnotes = thiscomponent.footnotes
		if fnotes.count > 0 then
			for i = 0 to fnotes.count -1
				getrangefromstring =setTextRangeFromParaIDAndCharNo(fnotes.getbyindex(i).gettext,sts(1),sts(2),found)

				if found = true then exit for
			next
		end if
		if found = false then
			enotes = thiscomponent.endnotes
			if enotes.count > 0 then
				for i = 0 to enotes.count -1
					getrangefromstring =setTextRangeFromParaIDAndCharNo(enotes.getbyindex(i).gettext,sts(1),sts(2),found)
					if found = true then exit for
				next
			end if
		end if


	CASE "SwXTextViewCursor"
	end select

end function


function getrangestring(isstart)
	vc= thiscomponent.currentcontroller.viewcursor

	if hastextinterface(vc) = false then exit function

	getrangestring =vc.text.implementationname & "|"

	select case vc.text.implementationname
	case "SwXCell"
		tc= vc.cell.gettext.createTextCursorByRange( vc)
	case "SwXTextFrame"
		tc = vc.textframe.gettext.createTextCursorByRange( vc)
	case "SwXBodyText"
		tc = thiscomponent.gettext.createTextCursorByRange(vc)
	case "SwXHeadFootText"
		tc = vc.gettext.createTextCursorByRange(vc)
	CASE "SwXFootnote"
		tc = vc.gettext.createTextCursorByRange(vc)
	CASE "SwXTextViewCursor"
	case else
		exit function
	end select
	if isstart then TC.collapsetostart else TC.COLLAPSETOEND
	en = tc.createenumeration
	do until en.hasmoreelements = false
		p = en.nextelement
		getrangestring = getrangestring & p.localname
		exit do
	loop

	tc.gotostartofparagraph(true)
	getrangestring = getrangestring & "|" & len(tc.string)

	select case vc.text.implementationname
	case "SwXCell"
		getrangestring = getrangestring & "|" &  vc.texttable.name & "|" & vc.cell.cellname
	case "SwXTextFrame"
		getrangestring = getrangestring & "|" & vc.textframe.name
		'	case "SwXBodyText"
		'	case "SwXHeadFootText"
	CASE "SwXFootnote"
		getrangestring = getrangestring & "|" &	 tc.parastylename
	end select

	'note for comments gettext is empty. The text is found from textfield.textrange.text
	'But may return void for the textfield and the viewcursor does not appear to give information to identify the
	'selected paragraph when void is not returned. So not been implemented
	'if isempty(vc.TEXTFIELD) =false then
	'getrangestring ="SwXTextViewCursor|"
	'getrangestring =getrangestring & vc.textfield.Author
	'tc=vc.textfield.textrange.text.createTextCursorByRange(vc.textfield.textrange) ' .ImplementationName 'SvxUnoTextBase
	'with vc.textfield.datetimevalue
	'tmp =cstr(.Year) & "," & cstr(.Month)  & "," & cstr(.Day) & "," & cstr(.Hours) & "," & cstr(.Minutes) &  "," & cstr(.Seconds) & "," & cstr(.HundredthSeconds) & "|"
	'end with

end function

function setTextRangeFromParaIDAndCharNo(txt,paraid as string,charno as string,byref found as boolean)
	en = txt.createenumeration
	do until en.hasmoreelements = false
		p =en.nextelement
		if p.supportsService("com.sun.star.text.Paragraph") Then
			if p.localname= paraID then
				found = true
				tc =txt.createtextcursorbyrange(p)
				tc.gotoStartOfParagraph(false)
				tc.goright(val(charNO),false)
				setTextRangeFromParaIDAndCharNo=tc
				exit do
			end if
		end if
	loop
end function


function hastextinterface(vc) as boolean
	hastextinterface = false
	on error goto hr
	txt = vc.text
	hastextinterface = true
	exit function
hr:
end function




function getrangefromstring2(st) 'SEARCHES ALL TEXT RANGES
	dim found as boolean
	vc= thiscomponent.currentcontroller.viewcursor
	sts = split(st,"|")

	getrangefromstring2 =setTextRangeFromParaIDAndCharNo(thiscomponent.gettext,sts(1),sts(2),found)


	if (found = false and thiscomponent.textFrames.count > 0) then 'text frames
		For Each frame In thiscomponent.textFrames
			getrangefromstring2 =setTextRangeFromParaIDAndCharNo(frame.gettext,sts(1),sts(2),found)
			if found then exit for
		next frame
	end if


	if (found = false and thiscomponent.texttables.count > 0) then 'text table
		tts = ThisComponent.TextTables ' this bit pinched from Lupp
		if tts.count > 0 then
			For j = 0 To tts.Count - 1
				j_tt = tts(j)
				cns = j_tt.CellNames
				For k = 0 To Ubound(cns)
					cell = j_tt.getCellByName(cns(k))
					getrangefromstring2 =setTextRangeFromParaIDAndCharNo( cell.Text,sts(1),sts(2),found)
					if found then goto hr
				Next k
			Next j
		end if
	end if
hr:

	if found = false then 'footnote
		fnotes = thiscomponent.footnotes
		if fnotes.count > 0 then
			for i = 0 to fnotes.count -1
				getrangefromstring2 =setTextRangeFromParaIDAndCharNo(fnotes.getbyindex(i).gettext,sts(1),sts(2),found)

				if found = true then exit for
			next
		end if
	end if

	if found = false then 'end note
		enotes = thiscomponent.endnotes
		if enotes.count > 0 then
			for i = 0 to enotes.count -1
				getrangefromstring2 =setTextRangeFromParaIDAndCharNo(enotes.getbyindex(i).gettext,sts(1),sts(2),found)
				if found = true then exit for
			next
		end if
	end if

	if found = false then 'header, footer
		ps =thiscomponent.StyleFamilies.getByName("PageStyles")
		for i = 0 to ps.count -1
			s = ps.getbyindex(i)
			if s.headerison then
				getrangefromstring2 =setTextRangeFromParaIDAndCharNo( s.headertext,sts(1),sts(2),found)
				if found then exit for
			end if
			if s.footerison then
				getrangefromstring2 =setTextRangeFromParaIDAndCharNo(s.footertext,sts(1),sts(2),found)
				if found then exit for
			end if

		next
	end if
end function



function getrangestring2(vc,isstart)
	'	vc= thiscomponent.currentcontroller.viewcursor

	if hastextinterface(vc) = false then exit function

	getrangestring2 =vc.text.implementationname & "|"

	select case vc.text.implementationname
	case "SwXCell"
		tc= vc.cell.gettext.createTextCursorByRange( vc)
	case "SwXTextFrame"
		tc = vc.textframe.gettext.createTextCursorByRange( vc)
	case "SwXBodyText"
		tc = thiscomponent.gettext.createTextCursorByRange(vc)
	case "SwXHeadFootText"
		tc = vc.gettext.createTextCursorByRange(vc)
	CASE "SwXFootnote"
		tc = vc.gettext.createTextCursorByRange(vc)
	CASE "SwXTextViewCursor"
	case else
		exit function
	end select
	if isstart then TC.collapsetostart else TC.COLLAPSETOEND
	en = tc.createenumeration
	do until en.hasmoreelements = false
		p = en.nextelement
		getrangestring2 = getrangestring2 & p.localname
		exit do
	loop

	tc.gotostartofparagraph(true)
	getrangestring2 = getrangestring2 & "|" & len(tc.string)

	select case vc.text.implementationname
	case "SwXCell"
		getrangestring2 = getrangestring & "|" &  vc.texttable.name & "|" & vc.cell.cellname
	case "SwXTextFrame"
		getrangestring2 = getrangestring & "|" & vc.textframe.name
		'	case "SwXBodyText"
		'	case "SwXHeadFootText"
	CASE "SwXFootnote"
		getrangestring2 = getrangestring & "|" &	 tc.parastylename
	end select

	'note for comments gettext is empty. The text is found from textfield.textrange.text
	'But may return void for the textfield and the viewcursor does not appear to give information to identify the
	'selected paragraph when void is not returned. So not been implemented
	'if isempty(vc.TEXTFIELD) =false then
	'getrangestring ="SwXTextViewCursor|"
	'getrangestring =getrangestring & vc.textfield.Author
	'tc=vc.textfield.textrange.text.createTextCursorByRange(vc.textfield.textrange) ' .ImplementationName 'SvxUnoTextBase
	'with vc.textfield.datetimevalue
	'tmp =cstr(.Year) & "," & cstr(.Month)  & "," & cstr(.Day) & "," & cstr(.Hours) & "," & cstr(.Minutes) &  "," & cstr(.Seconds) & "," & cstr(.HundredthSeconds) & "|"
	'end with

end function


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