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

'Das Modul enthält 9 Subs:
'haupt_stichworte_verlinken -> das zu startende Makro

'erstelle_dialog -> ein Untermakro, um den Dialog zur Laufzeit zu erstellen aus dem heraus die anderen Makros gestartet werden:
'	verweise_setzen -> das eigentliche Programm, um Seitenzahlen im Stichwortverzeichnis mit Querverweisen zu versehen
'	butlist1_ActionPerformed, butlist2_ActionPerformed -> Makros für den ActionListener für die Button im Dialog
'	win_windowClosing, win_windowClosed, win_windowActivated, win_windowDeactivated -> Makros für den Fensterlistener, um auf das Schließen des Dialogs reagieren zu können


public warten_dialog as object
public abbruch as boolean 'beendet Hauptschleife wenn der Benutzer den Dialog vorfristig schließt


Const praefix="x_" 'Präfix für die Stichwortlesezeichen, zur Unterscheidung ggf. anderer Lesezeichen

Sub haupt_stichworte_verlinken

	erstelle_dialog

End Sub

Sub verweise_setzen()
	'Originalautor: www.jm-schmidt.de
	'be- und umgearbeitet im  April 2023: de.openoffice.info, mikeleb

	startzeit = time()

	warten_dialog.getcontrol("but2").visible=false
	warten_dialog.getcontrol("but1").model.label="Stop"
	warten_dialog.getcontrol("but1").model.enabled=false

	oDoc=ThisComponent
	cur = oDoc.Text.createTextCursor
	oViewCursor = oDoc.CurrentController.getViewCursor
	indexes = ThisComponent.getDocumentIndexes()
	For i = 0 To Indexes.getCount() - 1
		oIndex = Indexes.getByIndex(i)
		If oIndex.supportsService("com.sun.star.text.DocumentIndex") Then
			warten_dialog.getcontrol("warten1").text="gefundenes Stichwortverzeichnis: " & oIndex.Name
			warten_dialog.getcontrol("warten3").text="Das Stichwortverzeichnis wird aktualisiert ..."
	
			oindex.update
			wait 1000
			
			warten_dialog.getcontrol("warten3").text="Die Verzeichnisstruktur wird geprüft ..."
			'Prüfen der Verzeichnisstruktur und Auslesen von zusätzlichem Text hinter Eintrag bzw. vor Seitennummer
			fehler=0
			ReDim level(2)
			for lv=0 to 2
				level1=oindex.levelformat.getbyindex(2+lv)
				suffix_lv=""
				praefix_lv=""
				for token=0 to ubound(level1)
					if level1(token)(0).value="TokenEntryText" then
						if token>0 then
							fehler=1	'das 1. Token muss der Verzeichniseintrag sein
						end if
						if level1(token+1)(0).value="TokenText" then
							suffix_lv=level1(token+1)(2).value
						end if
					end if
					if level1(token)(0).value="TokenPageNumber" then
						if token<ubound(level1) then
							fehler=2	'das letzte Token muss die Seitennummer sein
						end if
						if level1(token-1)(0).value="TokenText" then
							praefix_lv=level1(token-1)(2).value
							if level1(token-2)(0).value<>"TokenTabStop" then
								fehler=3	'vor dem Text vor der Seitennummer muss ein TabStop sein
							end if
						elseif level1(token-1)(0).value<>"TokenTabStop" then
							fehler=3	'wenn kein text vor der Seitennummer dann muss da ein TabStop sein
						end if
					end if
				next
				level(lv)=array(suffix_lv, praefix_lv)
			next
			if not(oIndex.UseCombinedEntries) then
				fehler=4
			end if
			if fehler>0 then
				warten_dialog.getcontrol("warten3").text="Diese Strukur des Stichwortverzeichnisses kann nicht verarbeitet werden!" 
			end if
			wait 1000		
	
			If fehler=0 then
	
				warten_dialog.getcontrol("but1").model.enabled=true
	
				warten_dialog.getControl("warten3").Text = "alte Lesezeichen werden gelöscht ..."
				'Alle ursprünglichen Lesezeichen entfernen
				oMarks=ThisComponent.Bookmarks
				for k=oMarks.count-1 to 0 step -1
					oMark=oMarks.getbyindex(k)
					if left(oMark.Name,len(praefix))=praefix then
						oMark.anchor.getText().removeTextContent(oMark)
					end if
				next
	
				'Alle Stichwortvorkommen im Dokument einlesen und Lesezeichen setzen
				oindex=odoc.documentindexes(i)
				
				Dim aStichworte(ubound(oindex.documentindexmarks))
				n_sw=-1
				Do while not(abbruch) and n_sw < ubound(aStichworte)
					n_sw=n_sw+1	
					warten_dialog.getControl("warten3").Text = "Stichwörter werden eingelesen, Lesezeichen gesetzt ... " & n_sw+1 & " von " & ubound(aStichworte)+1
					oMark=oindex.DocumentIndexMarks(n_sw)
					'zur Textstelle gehen
					oViewCursor.gotoRange(oMark.anchor, false)
					aStichworte(n_sw)=DimArray(4)
					aStichworte(n_sw)(0)=rtrim(oMark.markEntry & oMark.anchor.string)	'Text des Eintrages, ggf. Leerzeichen am Ende werden entfernt, da sie im Verzeichnis ebenfalls automatisch entfernt werden
					aStichworte(n_sw)(1)=oViewCursor.getpage							'Seite des Vorkommens
					aStichworte(n_sw)(2)=oviewcursor.position.x							'Position des Vorkommens
					aStichworte(n_sw)(3)=oviewcursor.position.y				
					aStichworte(n_sw)(4)=praefix & aStichworte(n_sw)(0) & "-" & n_sw	'Name des Lesezeichens
					'Lesezeichen erstellen
					oBookmark = ThisComponent.createInstance("com.sun.star.text.Bookmark")
			      	oBookmark.setName(aStichworte(n_sw)(4))
			      	ocurtmp=oViewcursor.Text.createTextCursor
			      	ocurtmp.gotoRange(oMark.anchor, false)
			      	oViewCursor.Text.insertTextContent(ocurtmp, oBookmark, False)
				Loop
	
				warten_dialog.getControl("warten3").Text ="Querverweise werden erstellt ..."
	
				
				cur.gotoRange(oIndex.getAnchor, false)
				cur.CollapseToStart 'vorderste Position im Verzeichnis
		
				'Anzahl Einträge ermitteln
				anzahl_eintraege = 0
				Do
					IF cur.ParaStyleName = oIndex.ParaStyleLevel1 OR cur.ParaStyleName = oIndex.ParaStyleLevel2 OR cur.ParaStyleName = oIndex.ParaStyleLevel3 Then 
							anzahl_eintraege = anzahl_eintraege + 1
					Elseif cur.ParaStyleName <> oIndex.ParaStyleHeading AND cur.ParaStyleName <> oIndex.ParaStyleSeparator Then
							Exit Do
					End If
					cur.GotoNextParagraph(False)
				Loop	
				
				cur.gotoRange(oIndex.getAnchor, false)
				cur.CollapseToStart
	
				dd = 0
				
				Do While not(abbruch) and dd<anzahl_eintraege
					
					cur.GotoEndOfParagraph(False)
					select case cur.ParaStyleName
					
						case oIndex.ParaStyleLevel1
							lv=0
						case oIndex.ParaStyleLevel2
							lv=1
						case oIndex.ParaStyleLevel3
							lv=2										
						case else
							lv=-1
					end select
					'Verzeichniseintrag?
					IF lv>-1 Then
						dd = dd + 1
						
						cur.GotoStartOfParagraph(False)
						cur.GotoEndOfParagraph(True)
						'Auslesen des gesamten Eintrags in Array tmp()
						tmp = Split(cur.String, CHR(9)) 
	
						'Finden aller Lesezeichen zu diesem Eintrag, sortiert
						sEintrag=left(tmp(0),len(tmp(0))-len(level(lv)(0)))
						warten_dialog.getControl("warten3").Text ="Querverweise werden erstellt ... " & dd & " von " & anzahl_eintraege &_
							chr(10) & chr(10) & "aktueller Eintrag: " & sEintrag
	
						n=-1
						for z=0 to ubound(aStichworte)
							if aStichworte(z)(0)=sEintrag then
								n=n+1
								ReDim preserve aEintrag(n)
								aEintrag(n)=aStichworte(z)
								tausch=1
								k=n-1
								do while tausch=1 and k>-1
									if (aEintrag(k+1)(3)>aEintrag(k)(3)) or (aEintrag(k+1)(3)=aEintrag(k)(3) and aEintrag(k+1)(2)>aEintrag(k)(2)) then
										tausch=0
									else 
										swp=aEintrag(k)
										aEintrag(k)=aEintrag(k+1)
										aEintrag(k+1)=swp
									end if
									k=k-1
								loop
							end if
						next
	
						'Auslesen der ggf. mehreren Seitenzahlen
						
						tmp2 = Split(join(split(tmp(ubound(tmp)),level(lv)(1)),""), ", ")
	
						tmp(ubound(tmp))=level(lv)(1)
	
						'.UseCombinedEntries ?
						'.UsesDash ? .UsePP ? 
						'es können drei Fälle auftreten (.UsesCombinedEntries=True und .UsesDash=False und .UsePP=True):
						'	45		Stichwort nur auf der Seite
						'	45f.	Stichwort auf der Seite und der folgenden
						'	45ff.	Stichwort auf der Seite und den folgenden
						'der Link wird, in diesem Beispiel, immer nur zum Stichwort auf Seite 45 führen - ein Link zu mehreren Zielen ist nicht möglich
						
						'es können zwei Fälle auftreten (.UsesCombinedEntries=True und .UsesDash=True und .UsePP=False):
						'	45		Stichwort nur auf der Seite 45
						'	45-47	Stichwort auf der Seite 45 bis einschließlich Seite 46
						'
						
						'wenn .UsesCombinedEntries=False oder .UsesDash=False und .UsePP=False, dann gibt es zu jedem Eintrag eine Liste nur einzelner Seiten
						'der Fall muss nicht extra betrachtet werden
						
						if ubound(tmp2)>-1 then	'mindestens eine Seitennummer vorhanden?
							
							if oIndex.UsePP then
								sTrenner="f"
							else
								sTrenner="-"
							end if								
							
							'aktuelle Zeile im Verzeichnis
							cur.GotoStartOfParagraph(False)
							'lösche alles hinter dem Tabulator
							cur.goRight(LEN(join(tmp,chr(9))), False)
							cur.GotoEndOfParagraph(True)
							cur.String = ""
							
							'Aufspalten einer Seitennumer mit ggf. f. oder ff.
							tmp3=split(tmp2(0),sTrenner)
							'die Seitenzahl weg
							nseite=val(tmp3(0)) 
							
							tmp3(0)=""
							'neuer Text ohne Seitenzahl
							neu=join(tmp3,sTrenner)
							'Suche das Lesezeichen auf der richtigen Seite
							nr=0
							do until aEintrag(nr)(1)=nseite or nr=ubound(aEintrag)
								nr=nr+1
							loop
							'msgbox nr
							if aEintrag(nr)(1)=nseite then 'Lesezeichen auf der Seite existiert
								oReference = ThisComponent.createInstance("com.sun.star.text.textfield.GetReference")
								oReference.SourceName = aEintrag(nr)(4)
								oReference.SequenceNumber = 0
								oReference.ReferenceFieldPart = com.sun.star.text.ReferenceFieldPart.PAGE
								oReference.ReferenceFieldSource = com.sun.star.text.ReferenceFieldSource.BOOKMARK
								oDoc.getText.insertTextContent(cur, oReference, False)
								cur.GotoEndOfParagraph(False)
							else							'Lesezeichen nicht vorhanden
								cur.String = nSeite
								cur.collapsetoend
							end if
							cur.String = neu
							cur.collapsetoend
							'falls noch mehr Seiten zu dem Eintrag	
							for j=1 to ubound(tmp2)
								cur.String = ", "
								cur.collapsetoend
								tmp3=split(tmp2(j),sTrenner)
								nseite=val(tmp3(0))
								tmp3(0)=""
								neu=join(tmp3,sTrenner)
								do until aEintrag(nr)(1)=nseite or nr=ubound(aEintrag)
									nr=nr+1
								loop
								'msgbox nr
								if aEintrag(nr)(1)=nseite then 'Lesezeichen auf der Seite existiert, Querverweis setzen
									oReference = ThisComponent.createInstance("com.sun.star.text.textfield.GetReference")
									oReference.SourceName = aEintrag(nr)(4)
									oReference.SequenceNumber = 0
									oReference.ReferenceFieldPart = com.sun.star.text.ReferenceFieldPart.PAGE
									oReference.ReferenceFieldSource = com.sun.star.text.ReferenceFieldSource.BOOKMARK
									oDoc.getText.insertTextContent(cur, oReference, False)
									cur.GotoEndOfParagraph(False)
								else							'Lesezeichen nicht vorhanden, es wird der ursprüngliche Text gesetzt
									cur.String =nSeite
									cur.collapsetoend
								end if
								cur.String = neu
								cur.collapsetoend
							next
						end if
					end if
					cur.GotoNextParagraph(False)
				loop
				oviewcursor.gotoRange(oIndex.getAnchor, false)
				oviewcursor.collapsetostart
			end if
		end if
	next
	
	ThisComponent.getTextfields.refresh()

	warten_dialog.getControl("warten4").Text ="Start: " & startzeit & "     " & "Ende: " & time()
	warten_dialog.getControl("but1").Label="Ende"
		
End Sub	


Sub erstelle_dialog

			'warten-Dialog--------------------------
			warten_model = CreateUnoService("com.sun.star.awt.UnoControlDialogModel")
			warten_model.setPropertyValue("Width",  300) '343
			warten_model.setPropertyValue("Height", 120) '65
			warten_model.setPropertyValue("PositionX", 100)
			warten_model.setPropertyValue("PositionY", 100)
			warten_model.SetPropertyValue("Title","Stichwortverzeichnisse verlinken")
		
			oMod_warten = warten_model.createInstance("com.sun.star.awt.UnoControlFixedTextModel")
			With oMod_warten
				.setPropertyValue("Name","warten1")
				.setPropertyValue("PositionX",5) '192
				.setPropertyValue("PositionY",5) 
				.setPropertyValue("Width",180)
				.setPropertyValue("Height",15)
				.setPropertyValue("MultiLine", True)
				.setPropertyValue("Label",ThisComponent.Title)
			End With
			warten_model.insertByName("warten1", oMod_warten)

			oMod_warten2 = warten_model.createInstance("com.sun.star.awt.UnoControlButtonModel")
			With oMod_warten2
				.setPropertyValue("Name","but1")
				.setPropertyValue("PositionX",10)
				.setPropertyValue("PositionY",95) '45
				.setPropertyValue("Width",60)
				.setPropertyValue("Height",16)
				.setPropertyValue("Label", "Abbruch")
				.setPropertyValue("DefaultButton", True)
				'.setPropertyValue("Enabled", False)
			End With
			warten_model.insertByName("but1", oMod_warten2)
			
			oMod_warten5 = warten_model.createInstance("com.sun.star.awt.UnoControlButtonModel")
			With oMod_warten5
				.setPropertyValue("Name","but2")
				.setPropertyValue("PositionX",100)
				.setPropertyValue("PositionY",95) '45
				.setPropertyValue("Width",60)
				.setPropertyValue("Height",16)
				.setPropertyValue("Label", "OK")
'				.setPropertyValue("DefaultButton", True)
'				.setPropertyValue("Enabled", False)
			End With
			warten_model.insertByName("but2", oMod_warten5)
			
			oListbut1 = createUnoListener("butlist1_","com.sun.star.awt.XActionListener")
			oListbut2 = createUnoListener("butlist2_","com.sun.star.awt.XActionListener")
			
			oMod_warten3 = warten_model.createInstance("com.sun.star.awt.UnoControlFixedTextModel")
			With oMod_warten3
				.setPropertyValue("Name","warten3")
				.setPropertyValue("PositionX",5) '192
				.setPropertyValue("PositionY",25) 
				.setPropertyValue("Width",180)
				.setPropertyValue("Height",45)
				.setPropertyValue("MultiLine", True)
				.setPropertyValue("Label","Wollen Sie die Einträge im Stichwortverzeichnis verlinken? " &_
					CHR(13) & CHR(13) & "Das Stichwortverzeichnis wird zunächst automatisch aktualisiert.")
			End With
			warten_model.insertByName("warten3", oMod_warten3)
			
			oMod_warten4 = warten_model.createInstance("com.sun.star.awt.UnoControlFixedTextModel")
			With oMod_warten4
				.setPropertyValue("Name","warten4")
				.setPropertyValue("PositionX",5) '192
				.setPropertyValue("PositionY",75) 
				.setPropertyValue("Width",180)
				.setPropertyValue("Height",15)
				.setPropertyValue("MultiLine", True)
				.setPropertyValue("Label","")
			End With
			warten_model.insertByName("warten4", oMod_warten4)
			
			oWinLis = createUnoListener("win_","com.sun.star.awt.XTopWindowListener")
			 
			warten_dialog = CreateUnoService("com.sun.star.awt.UnoControlDialog")
			warten_dialog.addTopWindowListener(oWinLis)
			warten_dialog.setModel(warten_model)
			
			warten_dialog.getControl("but1").addActionListener(oListbut1)
			warten_dialog.getControl("but2").addActionListener(oListbut2)
			
			oWin2 = CreateUnoService("com.sun.star.awt.Toolkit")
			warten_dialog.createPeer(oWin2, null)
			warten_dialog.execute

End Sub


Sub butlist1_ActionPerformed(oevent)
	
	warten_dialog.endexecute

end sub

Sub butlist2_ActionPerformed(oevent)
	
	verweise_setzen

end sub

sub win_windowClosing()

	abbruch=true

end sub

sub win_windowActivated
	'
end sub

sub win_windowDeactivated
	'
end sub

sub win_windowClosed()

	abbruch=true

end sub

