Writer: Is it possible to sort a document's content based on headings?

I’ve some sort of my own FAQ documents for several themes, where I make notes about whatever issues I was able to solve after a while of searching the net, chat on IRC channels etc.

These docs are structured, each FAQ entry starts with a “heading 1” paragraph, followed by some non-heading paragraphs. The “heading 1” starts always with keywords

After a while these documents are getting pretty big, so it would be cool to sort the chapters, based on “heading 1” content.

As I’ve only found a “move up”/“move down” functionality in LO’s Navigator, I guess this sort functionality does not exist, right?

Any hints if and how this might be possible with macros?

‘Bit’ late, but thought your questions was interesting.

So given the attached file which resembles your FAQ docs based on what you wrote, here is the code to sort the headings accordingly. Code could be cleaner but its late and I couldn’t be bothered :slight_smile:

Code runs fine on v6 and v7 of LO that I tested. The attached document includes the macro.

[Sub sortHeadings()

    Dim oDoc: oDoc = ThisComponent
    
    Dim allSorted: allSorted = false
    
    do
	    Dim SDescript 
	    SDescript = oDoc.createSearchDescriptor
	    SDescript.setPropertyValue("SearchStyles", True)
	    SDescript.setSearchString("Heading 1")
	    
	    Dim FoundRanges 
	    FoundRanges = oDoc.findAll(SDescript)
	    
	    Dim Count
	    Count = FoundRanges.Count
	    
	    'Print Count
	    
	    Dim i As integer
	    For i=0 To (Count -2)
	    
		    Dim aRange, aText
		    aRange = FoundRanges.getByIndex(i)	
			aText = aRange.getString()
			
			Dim bRange, bText
			bRange = FoundRanges.getByIndex(i+1)	
			bText = bRange.getString()
			
			If UCASE(bText) < ucase(aText) Then
				
				Dim aTC, bTC
				
				aTC = oDoc.Text.createTextCursorByRange(aRange)
				aTC.gotoRange(bRange.start(),true)
				
				bTC = oDoc.Text.createTextCursorByRange(bRange)
				If i+2 = Count Then	'at last two blocks?
					Dim dText
					dText = oDoc.getText()
					bTC.gotoRange(dText.end(),true)
					
					'msgbox "B-Block: " & bTC.getString()
				Else
					Dim nRange
					nRange = FoundRanges.getByIndex(i+2)
					bTC.gotoRange(nRange.start(),true)
					'msgbox "B-Block: " & bTC.getString()
				End If
				
				'
				' Swap text blocks
				'
				
				' Grab a copy
				Dim oCC: oCC = ThisComponent.CurrentController
				oCC.Select(bTC)
				Dim o: o = oCC.getTransferable()
				
				' Remove copied text
				bTC.setString("")
				
				' Move Cursor and Insert text
				Dim oVC: oVC = oCC.getViewCursor()
				oVC.gotoRange(aRange.getStart(),false)
				oCC.insertTransferable(o)	

				'restart loop to account for block moving...
				Exit For
			Else
				
				' Last two didnt need to be swapped we are done.
				If i+2 = Count 	Then 
					allSorted = true
				End if
			End If
		Next 
	Loop While Not allSorted
	
	Print "Sorting completed!!"
End Sub]

sortTextWithHeadings.odt

It was a function that I wanted to try to make in the future, you saved me a lot of work.

It works perfectly.

Very thanks

@CaveMan: very cool, THANKS!

Lean and self explaning code, I’ve never did anything with LO macros before. But as your macro, at first, did absolutely NOTHING, it took me not that long, less than a minute, to find out that your

SDescript.setSearchString("Heading 1")

will not find anything in my German document with “Überschrift 1”, instead :slight_smile:
Changed, and now works like a charm!

2nd funny thing is that my small and noiseless (no fan) linux box is as a sideeffect somewhat slow, so it makes a lot of fun watching your macro life at work :slight_smile: Took a while for my completely unsorted document. Let it run a 2nd time, recognizes at once “nothing to do”. Being nasty and move the first two sections at the end, ran again. Some room for sorting improvement - but who cares, I’m completely happy :smiley:

So thanks again, will takes your example as a base for maybe future own macros.

@torreone You are welcome
@michaelof No problem. It was a fun bit of coding. Glad I was able to help.

very nice work CaveMan. Thank you for posting. A useful script!