Styled Note Markup trimmer gramplet?

The Note Editor has a Clear Markup feature. It clears ALL stylings applied to the selected text in a Note.

But you cannot clear text with multiple stylings without clearing all markup on that text. (I had to boost text size on a few notes to be readable on high-res monitor. Beginning with 5.2, the base font size in Themes began working with notes too. Yay! But now I want to eliminate those no-longer-needed re-sizings without clearing all the other stylings.)


It would be useful to have a Gramplet for the Notes category (only) that lists the stylings in a table with columns for: a checkbox, startswith, styling type, and the 1st 40 chars of text.

The first generation of the addon could just allow sorting on the columns and have a Delete for the selected checkboxes. Selecting a row could navigate the Note Editor focus to the string and select that string. (Which would allow adding another styling from the Note Editor toolbar.)

A future generation could have a ‘paintbrush’ that adds temporary Rows to the table with the Active styling. If the Active styling was “Link”, then you could paint all the Names (or Places or text to be hotlinked) to create a placeholder row for each startswith string, undock the gramplet, change to a Category and drag objects (or paste URLs) to finish the linking.

1 Like

Prior to Gramps 5.2, The Notes display of base font size was absolute. It ignored when the Themes addon preferences selection that was used to increase the font size in the rest of the interface.

So, to increase the tiny default of 9pt to something readable by the eyes of … ahem… mature users, it was necessary to Edit the styling of the Note content to increase the font size. Note Displays were enhanced for 5.2 … found the Enhancement Request but I cannot find the PR.)

Now that the Note Editor uses the Themes to set the base font size, I need to clear those extra stylings out of the Notes. (The varying manually-set sizes make Notes in Reports appear irregular.)

But the (Clear Markup) button clears ALL the markup for the selected text. And I really don’t want to clear the Links and rebuild them. They are too painful to set.

Individual Note cannot be targeted for export. So editing the XML and overwriting is not an option. There is no “exploded” view for an object that allows direct editing outside the klutz proofing of the GUI

Perhaps it might be possible to use SuperTool by @kku to generate a table of stylings for a particular Note… (with columns for styling type, begin, end, and a 20 character snippet of the affected text) and allow row to be selected, then that style deleted? I did not find the font decorations listed in the SuperTool help for Note objects.

I posted an idea that had no response. So maybe a scaled back idea would raise comments?

(Gramps 5.22 and Fedora 37)

I wrote a quick Supertool script as a proof-of-concept:

Is this something you had in mind? I can tweak it as needed or e.g. make it a gramplet or something.

This is Great! Thank you! I will have to try it out. With this example, I should be able puzzle out how to filter for notes that have a “Fontsize” (or other) markup too. Then filter to walk through just that problem.

Thanks again!

This was a good experiment for trying the @include in the SuperTool Initialization statements too.

I always forget what the fallback paths would be when looking for SuperTool Include files (Since the first fallback is the location of the script, I wondered where it would look when the script was loaded from a Note… which is my preferred organizational method.)

There are sure to be some typos. The text in the errors section cannot be selected for copying. And isn’t piped to the “Capture output”. So the following is transcribed.

Include file 'note-markup.py' not found; looked at
- /home/<username>/.gramps/plugins/SuperTool/scripts/note-markup.py
- /home/<username>/supertool/note-markup.py
- /home/<username>/.gramps/plugins/SuperTool/note-markup.py
- /home/<username>/note-markup.py

After a bit of experimenting to discover when changes are applied, this worked extremely well. Thank you!

It did feel more safe after changing the checkboxes to default to be deselected. With them set to True, it was too easy to clear markup unintentionally.

Paste the following into a new Note of type “SuperTool script” and save
Change to Notes category
Run Tools → Isotammi tools → SuperTool
File → Load from Note
select the record(s) in the Notes view (select only a small number …25 for fewer)
Click Execute

Select the checkbox of the style(s) to cleared and click Clear markup
The Undo is only effective until clicking Next or Quit

[Gramps SuperTool script file]
version=1

[title]
Note markup cleanup

[description]
Open a dialog listing text stylings in selected Notes, allow deleting from a list

https://gramps.discourse.group/t/styled-note-markup-trimmer-gramplet/5396

created by Kari Kujansuu Feb 2025
https://github.com/kkujansuu/supertool-scripts/tree/main/note-markup

[category]
Notes

[initial_statements]
# @include note-markup.py
from gi.repository import Gtk
from gramps.gen.lib import StyledTextTag
from gramps.gui.widgets import StyledTextEditor

def get_markup(note):
    for tag in note.get_styledtext().tags:
	    print(tag.name, tag.value, tag.ranges)
#	    s = note.get_styledtext()._string
	    s = note.get()
	    for a,b in tag.ranges:
		    print("-", s[a:b])
		    yield (tag.name, tag.value, (a,b), s[a:b])

def show_note(note):
    grid = Gtk.Grid()
    grid.set_column_spacing(5)
    grid.set_row_spacing(2)
    cb_list = []
    for row, (name, value, range, text) in enumerate(get_markup(note)):
        if not value: value = ""
        cb = Gtk.CheckButton()
        cb.set_active(False)
        lbl_name = Gtk.Label(name)
        lbl_name.set_halign(Gtk.Align.START)
        lbl_value = Gtk.Label(value)
        lbl_value.set_halign(Gtk.Align.START)
        lbl_text = Gtk.Label(text)
        lbl_text.set_halign(Gtk.Align.START)
        grid.attach(cb, 0, row, 1, 1)
        grid.attach(lbl_name, 1, row, 1, 1)
        grid.attach(lbl_value, 2, row, 1, 1)
        grid.attach(lbl_text, 3, row, 1, 1)
        tag = StyledTextTag(name, value, [range])
        cb_list.append((cb, tag))
    if len(cb_list) == 0:
        return
    dlg = Gtk.Dialog()
    dlg.set_title("Note markup")
    c = dlg.get_content_area()
    c.add(Gtk.Label("Note " + note.gramps_id))
    c.add(grid)
    c.pack_start(Gtk.HSeparator(), False, False, 10)

    scrolledwindow = Gtk.ScrolledWindow()
    scrolledwindow.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
    texteditor = StyledTextEditor()
    texteditor.set_editable(False)
    texteditor.set_wrap_mode(Gtk.WrapMode.WORD)
    texteditor.set_text(note.get_styledtext())
    scrolledwindow.set_size_request(600, 300)
    scrolledwindow.add(texteditor)
    c.add(scrolledwindow) #, True, True, 0)

    dlg.add_button("Clear markup", 1)
    dlg.add_button("Undo", 6)
    dlg.add_button("Next", 2)
    dlg.add_button("Quit", 3)
    dlg.show_all()
    old_text = None
    old_tags = note.get_styledtext().tags[:]
    while True:
        rsp = dlg.run()
        if rsp == 2:
            break
        if rsp == 6:
            note.get_styledtext().tags = old_tags
            db.commit_note(note, trans)
            texteditor.set_text(note.get_styledtext())
        if rsp == 3:
            dlg.destroy()
            raise RuntimeError("Canceled")
        if rsp == 1:
            tags = []
            for cb, tag in cb_list:
                print(cb.get_active())
                if not cb.get_active():
                    tags.append(tag)
            note.get_styledtext().tags = tags
            db.commit_note(note, trans)
            texteditor.set_text(note.get_styledtext())
    dlg.destroy()

[statements]
show_note(note)

[scope]
selected