Makro: Markierten Text bis zum Dokumentende ersetzen

Jetzt habe ich gedacht, ich hätte das mit dem Textcursor und dem Viewcursor verstanden (das ist sehr gut in den Büchern “Makro Grundlagen” von Thomas Krumbein erläutert), und dann funktioniert ein Makro nicht. Das Makro soll das Vorkommen eines Textes, der einmal markiert ist, bis zum Dokumentende ersetzen (aber nicht vor der Markierung). Dazu habe ich aus dem hervorragenden Buch von Pitonyak Code verwendet:

Sub Markierung_ersetzen
' Dieses Makro soll einen markierten Text ersetzen und alle Vorkommen bis zum Ende des Dokuments;
' nicht aber vor der Markierung.
' Quelle: Andrew Pitonyak: BASIC-Makros für OpenOffice und LibreOffice. 
' Von den Grundlagen zu konkreten Praxisbeispielen.
' Ins Deutsche übertragen und bearbeitet von Volker Lenhardt
' Mit Beiträgen von Andreas Heier und Volker Lenhardt
' Seite 154, Listing 130
' https://makromador.wordpress.com/oome-open-office-macros-explained/
Dim vSelections 'Mehrere unverbundene Selektionen
Dim vSel 'Eine einzelne Selektion
Dim vCursor 'OOo-Dokument-Cursor
Dim i As Integer 'Indexvariable
Dim s As String 's: Temporärer Hilfsstring
Dim bIsSelected As Boolean 'Ist überhaupt Text selektiert?
' Nicht von Pitonyak:
Dim oViewC, oTextC, oTextC2, oTextC3 as Object
Dim oDoc as Object
Dim d1 As Integer
Dim ersetzendatei As String
bIsSelected = True 'Angenommen, dass ja

' Wieder von Pitonyak:
'Die aktuelle Selektion im aktuellen Controller.
'Wenn es aktuell keinen Controller gibt, wird NULL zurückgegeben.
'ThisComponent referenziert das aktuelle Dokument.
vSelections = ThisComponent.getCurrentSelection()
If IsNull(vSelections) Or IsEmpty(vSelections) Then
bIsSelected = False
ElseIf vSelections.getCount() = 0 Then
bIsSelected = False
End If
If Not bIsSelected Then
'Wenn nichts selektiert ist, wird das mitgeteilt
Print "Es ist nichts selektiert" 'und die Subroutine beendet.
Exit Sub
End If

'Die Selektionen werden von null aufwärts gezählt.
'Ausgabe der ASCII-Werte einer jeden Selektion.
For i = 0 To vSelections.getCount() - 1
vSel = vSelections.getByIndex(i)
vCursor = ThisComponent.Text.createTextCursorByRange(vSel)
s = vCursor.getString()
If Len(s) > 0 Then
' ---------------- Ende des Codes von Pitonyak --------------------------------------------------

' --------------------- Es wurde etwas ausgewählt (nämlich s): Also: Auswahl ersetzen  
oDoc = ThisComponent
oViewC = oDoc.getCurrentController.getViewCursor()
oTextC3 = ThisComponent.Text.createTextCursorByRange(oViewC)
oTextC3.goRight(1,true)
oTextC3.collapseToEnd()

' Alle Vorkommen bis zum Textende durch "xxx" ersetzen:
oViewC.gotoEnd(True)
oViewC.String = Replace (oViewC.String, s, "xxx")
oViewC.String = Replace (oViewC.String, Chr(10), Chr(13))

' Cursor ans nächste Wort der ursprünglichen Auswahl (nicht des Textes) setzen:
oTextC3.collapseToStart()
oViewC.gotoRange(oTextC3, False) 

' wieder Code von Pitonyak:
ElseIf vSelections.getCount() = 1 Then 
Print "Es ist nichts selektiert"
End If
Next

End Sub

Leider steht der Cursor aber am Ende des Textes und nicht da, so er stehen sollte, nämlich vor dem Wort, das auf die ursprüngliche Markierung folgte.
Was mache ich falsch? Wie mache ich’s richtig?
Wie kriege ich den Cursor dort hin?
Für sachdienliche Hinweise wäre ich außerordentlich dankbar!

Ich denke, das Problem ist, dass du den Cursor durch das Ersetzen veränderst, mit folgendem Code geht’s:

Sub Markierung_setzen_F3K
   sNewstring = "xxx"
    oViewCursor = ThisComponent.getCurrentController.getViewCursor()
    if oViewCursor.String = "" then
        Print "Es ist nichts selektiert"
        exit sub
    else
        s = oViewCursor.String
    endif
    oTextCursor1 = ThisComponent.Text.createTextCursorByRange(oViewCursor)
    oTextCursor2 = ThisComponent.Text.createTextCursorByRange(oViewCursor)
    oTextCursor2.gotoStartofParagraph(false)
    oTextCursor1.gotoEnd(true)
    oTCEnum = oTextCursor1.createEnumeration
    while oTCEnum.hasmoreelements
        oPara = oTCEnum.nextelement
        oPara.String = Replace (oPara.String, s, sNewstring)
    wend
    oTextCursor2.gotoStartOfParagraph(false)
    oTextCursor2.gotoEndOfParagraph(true)
    n = instr(oTextCursor2.string,sNewstring)
    oTextCursor2.gotoStartOfParagraph(false)
    oTextCursor2.goright(n+len(sNewstring),false)
    oViewCursor.gotorange(oTextCursor2,false)
end sub

Der TextCursor2 wird vor und nach dem Ersetzen des Strings an den Anfang des aktuellen Paragraphen gesetzt, dann wird im geänderten String nach sNewString gesucht und der Viewcursor dahinter gesetzt.

Danke!! Das hilft schon etwas weiter. Und der Code ist wesentlich kürzer als der, den ich bei Pitonyak gefunden habe.
Allerdings ersetzt dieser Code das Vorkommen des markierten Textes überall im aktuellen Absatz, auch vor der Markierung; es soll aber erst ab der Markierung ersetzt werden. Hat das etwas mit der Enumeration zu tun?

jo

Sub Markierung_setzen_F3K
   sNewstring = "xxx"
    oViewCursor = ThisComponent.getCurrentController.getViewCursor()
    if oViewCursor.String = "" then
        Print "Es ist nichts selektiert"
        exit sub
    else
        s = oViewCursor.String
    endif
    oTextCursor1 = ThisComponent.Text.createTextCursorByRange(oViewCursor)
    oTextCursor2 = ThisComponent.Text.createTextCursorByRange(oViewCursor)
    oTextCursor2.gotoStartofParagraph(false)
    oTextCursor1.gotoendofParagraph(true)
    oTextCursor1.String = Replace (oTextCursor1.String, s, sNewstring)
    oTextCursor1.gotonextParagraph(False)
    oTextCursor1.gotoEnd(true)
    oTCEnum = oTextCursor1.createEnumeration
    while oTCEnum.hasmoreelements
        oPara = oTCEnum.nextelement
        oPara.String = Replace (oPara.String, s, sNewstring)
    wend
    oTextCursor2.gotoStartOfParagraph(false)
    oTextCursor2.gotoEndOfParagraph(true)
    n = instr(oTextCursor2.string,sNewstring)
    oTextCursor2.gotoStartOfParagraph(false)
    oTextCursor2.goright(n+len(sNewstring),false)
    oViewCursor.gotorange(oTextCursor2,false)
end sub

Super! Das tut’s. Danke!!

Gerade habe ich gemerkt: Das Ersetzen ist korrekt. Der Cursor wird aber nicht immer an die richtige Stelle gesetzt: Wenn im Absatz vor der Schreibmarke schon ein “xxx” steht, wird sie vom Makro vor dieses xxx gesetzt und nicht vor das xxx, bei dem das Makro gestartet wurde. Mit diesem Schönheitsfehler kann ich aber leben. Daher immer noch mein herzlicher Dank an F3KTotal!

nun denn:

Sub Markierung_setzen_F3K
   sNewstring = "xxx"
    oViewCursor = ThisComponent.getCurrentController.getViewCursor()
    if oViewCursor.String = "" then
        Print "Es ist nichts selektiert"
        exit sub
    else
        s = oViewCursor.String
        oViewCursor.String = sNewstring
    endif
    oTextCursor1 = ThisComponent.Text.createTextCursorByRange(oViewCursor)
    oTextCursor2 = ThisComponent.Text.createTextCursorByRange(oViewCursor)
    oTextCursor2.gotoStartofParagraph(true)
    nlength = len(oTextCursor2.string)
    oTextCursor2.gotoStartofParagraph(false)
    oTextCursor1.gotoendofParagraph(true)
    oTextCursor1.String = Replace (oTextCursor1.String, s, sNewstring)
    oTextCursor1.gotonextParagraph(False)
    oTextCursor1.gotoEnd(true)
    oTCEnum = oTextCursor1.createEnumeration
    while oTCEnum.hasmoreelements
        oPara = oTCEnum.nextelement
        oPara.String = Replace (oPara.String, s, sNewstring)
    wend
    oTextCursor2.goright(nlength+1,false)
    oViewCursor.gotorange(oTextCursor2,false)
end sub

Jetzt ist auch das kleine Schönheitsfehlerchen nicht mehr da - der Code macht genau, was er soll. Herzlichen Dank!!