Ask Your Question
0

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

asked 2018-02-28 15:28:00 +0200

michaelof gravatar image

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?

edit retag flag offensive close merge delete

1 Answer

Sort by » oldest newest most voted
3

answered 2021-01-14 11:58:57 +0200

CaveMan gravatar image

updated 2021-01-14 12:07:29 +0200

'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 :)

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]

C:\fakepath\sortTextWithHeadings.odt

edit flag offensive delete link more

Comments

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

torreone gravatar imagetorreone ( 2021-01-14 13:50:18 +0200 )edit

@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 :) 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 :) 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 :D

So thanks again, will takes your example ...(more)

michaelof gravatar imagemichaelof ( 2021-01-26 17:55:52 +0200 )edit

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

CaveMan gravatar imageCaveMan ( 2021-02-01 14:13:39 +0200 )edit

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

blashrkh gravatar imageblashrkh ( 2021-03-15 04:07:16 +0200 )edit
Login/Signup to Answer

Question Tools

3 followers

Stats

Asked: 2018-02-28 15:28:00 +0200

Seen: 156 times

Last updated: Jan 14