def build_gui(self): """ Build the GUI interface. """ top = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) hbox = Gtk.Box() self.left = SimpleButton('go-previous', self.left_clicked) self.left.set_sensitive(False) hbox.pack_start(self.left, False, False, 0) self.right = SimpleButton('go-next', self.right_clicked) self.right.set_sensitive(False) hbox.pack_start(self.right, False, False, 0) self.page = Gtk.Label() hbox.pack_end(self.page, False, False, 10) scrolledwindow = Gtk.ScrolledWindow() scrolledwindow.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) self.texteditor = StyledTextEditor() self.texteditor.set_editable(False) self.texteditor.set_wrap_mode(Gtk.WrapMode.WORD) scrolledwindow.add(self.texteditor) top.pack_start(hbox, False, False, 0) top.pack_start(scrolledwindow, True, True, 0) top.show_all() return top
def build_gui(self): """ Build the GUI interface. """ top = Gtk.VBox(homogeneous=False) hbox = Gtk.HBox() self.left = SimpleButton(Gtk.STOCK_GO_BACK, self.left_clicked) self.left.set_sensitive(False) hbox.pack_start(self.left, False, False, 0) self.right = SimpleButton(Gtk.STOCK_GO_FORWARD, self.right_clicked) self.right.set_sensitive(False) hbox.pack_start(self.right, False, False, 0) self.page = Gtk.Label() hbox.pack_end(self.page, False, False, 10) scrolledwindow = Gtk.ScrolledWindow() scrolledwindow.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) self.texteditor = StyledTextEditor() self.texteditor.set_editable(False) self.texteditor.set_wrap_mode(Gtk.WrapMode.WORD) scrolledwindow.add(self.texteditor) top.pack_start(hbox, False, False, 0) top.pack_start(scrolledwindow, True, True, 0) top.show_all() return top
def build_gui(self): """ Build the GUI interface. """ top = Gtk.VBox(homogeneous=False) scrolledwindow = Gtk.ScrolledWindow() scrolledwindow.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) self.texteditor = StyledTextEditor() self.texteditor.set_editable(False) self.texteditor.set_wrap_mode(Gtk.WrapMode.WORD) scrolledwindow.add(self.texteditor) self.set_text() top.pack_start(scrolledwindow, True, True, 0) top.show_all() return top
def build_gui(self): """ Build the GUI interface. """ top = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) hbox = Gtk.Box() self.left = SimpleButton(Gtk.STOCK_GO_BACK, self.left_clicked) self.left.set_tooltip_text(_('Previous To Do note')) self.left.set_sensitive(False) hbox.pack_start(self.left, False, False, 0) self.right = SimpleButton(Gtk.STOCK_GO_FORWARD, self.right_clicked) self.right.set_tooltip_text(_('Next To Do note')) self.right.set_sensitive(False) hbox.pack_start(self.right, False, False, 0) self.edit = SimpleButton(Gtk.STOCK_EDIT, self.edit_clicked) self.edit.set_tooltip_text(_('Edit the selected To Do note')) self.edit.set_sensitive(False) hbox.pack_start(self.edit, False, False, 0) self.new = SimpleButton(Gtk.STOCK_NEW, self.new_clicked) self.new.set_tooltip_text(_('Add a new To Do note')) hbox.pack_start(self.new, False, False, 0) self.page = Gtk.Label() hbox.pack_end(self.page, False, False, 10) self.title = Gtk.Label() self.title.set_alignment(0, 0) self.title.set_line_wrap(True) scrolledwindow = Gtk.ScrolledWindow() scrolledwindow.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) self.texteditor = StyledTextEditor() self.texteditor.set_editable(False) self.texteditor.set_wrap_mode(Gtk.WrapMode.WORD) scrolledwindow.add(self.texteditor) top.pack_start(hbox, False, False, 0) top.pack_start(self.title, False, False, 4) top.pack_start(scrolledwindow, True, True, 0) top.show_all() return top
def build_gui(self): """ Build the GUI interface. """ top = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) scrolledwindow = Gtk.ScrolledWindow() scrolledwindow.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) self.texteditor = StyledTextEditor() self.texteditor.set_editable(False) self.texteditor.set_wrap_mode(Gtk.WrapMode.WORD) scrolledwindow.add(self.texteditor) self.set_text() top.pack_start(scrolledwindow, True, True, 0) top.show_all() return top
def build_gui(self): """ Build the GUI interface. """ top = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) hbox = Gtk.Box() self.left = SimpleButton('go-previous', self.left_clicked) self.left.set_tooltip_text(_('Previous To Do note')) self.left.set_sensitive(False) hbox.pack_start(self.left, False, False, 0) self.right = SimpleButton('go-next', self.right_clicked) self.right.set_tooltip_text(_('Next To Do note')) self.right.set_sensitive(False) hbox.pack_start(self.right, False, False, 0) self.edit = SimpleButton('gtk-edit', self.edit_clicked) self.edit.set_tooltip_text(_('Edit the selected To Do note')) self.edit.set_sensitive(False) hbox.pack_start(self.edit, False, False, 0) self.new = SimpleButton('document-new', self.new_clicked) self.new.set_tooltip_text(_('Add a new To Do note')) hbox.pack_start(self.new, False, False, 0) self.page = Gtk.Label() hbox.pack_end(self.page, False, False, 10) self.title = Gtk.Label(halign=Gtk.Align.START) self.title.set_line_wrap(True) scrolledwindow = Gtk.ScrolledWindow() scrolledwindow.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) self.texteditor = StyledTextEditor() self.texteditor.set_editable(False) self.texteditor.set_wrap_mode(Gtk.WrapMode.WORD) scrolledwindow.add(self.texteditor) top.pack_start(hbox, False, False, 0) top.pack_start(self.title, False, False, 4) top.pack_start(scrolledwindow, True, True, 0) top.show_all() return top
class ToDoGramplet(Gramplet): """ Displays all the To Do notes in the database. """ def init(self): self.gui.WIDGET = self.build_gui() self.gui.get_container_widget().remove(self.gui.textview) self.gui.get_container_widget().add(self.gui.WIDGET) self.gui.WIDGET.show() def build_gui(self): """ Build the GUI interface. """ top = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) hbox = Gtk.Box() self.left = SimpleButton('go-previous', self.left_clicked) self.left.set_tooltip_text(_('Previous To Do note')) self.left.set_sensitive(False) hbox.pack_start(self.left, False, False, 0) self.right = SimpleButton('go-next', self.right_clicked) self.right.set_tooltip_text(_('Next To Do note')) self.right.set_sensitive(False) hbox.pack_start(self.right, False, False, 0) self.edit = SimpleButton('gtk-edit', self.edit_clicked) self.edit.set_tooltip_text(_('Edit the selected To Do note')) self.edit.set_sensitive(False) hbox.pack_start(self.edit, False, False, 0) self.new = SimpleButton('document-new', self.new_clicked) self.new.set_tooltip_text(_('Add a new To Do note')) hbox.pack_start(self.new, False, False, 0) self.page = Gtk.Label() hbox.pack_end(self.page, False, False, 10) self.title = Gtk.Label(halign=Gtk.Align.START) self.title.set_line_wrap(True) scrolledwindow = Gtk.ScrolledWindow() scrolledwindow.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) self.texteditor = StyledTextEditor() self.texteditor.set_editable(False) self.texteditor.set_wrap_mode(Gtk.WrapMode.WORD) scrolledwindow.add(self.texteditor) top.pack_start(hbox, False, False, 0) top.pack_start(self.title, False, False, 4) top.pack_start(scrolledwindow, True, True, 0) top.show_all() return top def main(self): self.get_notes() def get_note_list(self): """ Get a list of all To Do notes. """ all_notes = self.dbstate.db.get_note_handles() FilterClass = GenericFilterFactory('Note') filter = FilterClass() filter.add_rule(rules.note.HasType(["To Do"])) note_list = filter.apply(self.dbstate.db, all_notes) return note_list def get_notes(self): """ Display all the To Do notes. """ self.left.set_sensitive(False) self.right.set_sensitive(False) self.edit.set_sensitive(False) self.texteditor.set_text(StyledText()) self.note_list = self.get_note_list() self.page.set_text('') self.title.set_text('') if len(self.note_list) > 0: self.set_has_data(True) self.edit.set_sensitive(True) if len(self.note_list) > 1: self.right.set_sensitive(True) self.current = 0 self.display_note() else: self.set_has_data(False) def clear_text(self): self.left.set_sensitive(False) self.right.set_sensitive(False) self.edit.set_sensitive(False) self.texteditor.set_text(StyledText()) self.page.set_text('') self.title.set_text('') self.current = 0 def display_note(self): """ Display the current note. """ note_handle = self.note_list[self.current] note = self.dbstate.db.get_note_from_handle(note_handle) obj = [x for x in self.dbstate.db.find_backlink_handles(note_handle)] if obj: name, obj = navigation_label(self.dbstate.db, obj[0][0], obj[0][1]) self.title.set_text(name) else: self.title.set_text(_("Unattached")) self.texteditor.set_text(note.get_styledtext()) self.page.set_text(_('%(current)d of %(total)d') % {'current': self.current + 1, 'total': len(self.note_list)}) def left_clicked(self, button): """ Display the previous note. """ if self.current > 0: self.current -= 1 self.right.set_sensitive(True) if self.current == 0: self.left.set_sensitive(False) self.display_note() def right_clicked(self, button): """ Display the next note. """ if self.current < len(self.note_list) - 1: self.current += 1 self.left.set_sensitive(True) if self.current == len(self.note_list) - 1: self.right.set_sensitive(False) self.display_note() def get_has_data(self): """ Return True if the gramplet has data, else return False. """ if self.get_note_list(): return True return False def edit_clicked(self, obj): """ Edit current To Do note. """ from gramps.gui.editors import EditNote note_handle = self.note_list[self.current] note = self.dbstate.db.get_note_from_handle(note_handle) try: EditNote(self.gui.dbstate, self.gui.uistate, [], note) except AttributeError: pass def new_clicked(self, obj): """ Create a new To Do note. """ from gramps.gui.editors import EditNote note = Note() note.set_type(NoteType.TODO) try: EditNote(self.gui.dbstate, self.gui.uistate, [], note) except AttributeError: pass def update_has_data(self): self.set_has_data(self.get_has_data()) def db_changed(self): self.connect(self.dbstate.db, 'note-add', self.update) self.connect(self.dbstate.db, 'note-delete', self.update) self.connect(self.dbstate.db, 'note-update', self.update)
class WelcomeGramplet(Gramplet): """ Displays a welcome note to the user. """ def init(self): self.gui.WIDGET = self.build_gui() self.gui.get_container_widget().remove(self.gui.textview) self.gui.get_container_widget().add(self.gui.WIDGET) self.gui.WIDGET.show() def build_gui(self): """ Build the GUI interface. """ top = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) scrolledwindow = Gtk.ScrolledWindow() scrolledwindow.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) self.texteditor = StyledTextEditor() self.texteditor.set_editable(False) self.texteditor.set_wrap_mode(Gtk.WrapMode.WORD) scrolledwindow.add(self.texteditor) self.set_text() top.pack_start(scrolledwindow, True, True, 0) top.show_all() return top def set_text(self): """ Display the welcome text. """ welcome = boldst(_('Intro')) + '\n\n' welcome += _( 'Gramps is a software package designed for genealogical research.' ' Although similar to other genealogical programs, Gramps offers ' 'some unique and powerful features.\n\n') welcome += boldst(_('Links')) + '\n\n' welcome += linkst(_('Home Page'), URL_HOMEPAGE) + '\n' welcome += linkst(_('Start with Genealogy and Gramps'), '%(gramps_wiki_url)sStart_with_Genealogy' % {'gramps_wiki_url': URL_WIKISTRING} ) + '\n' welcome += linkst(_('Gramps online manual'), URL_WIKISTRING + URL_MANUAL_PAGE + _('locale_suffix|')) + '\n' welcome += linkst(_('Ask questions on gramps-users mailing list'), '%(gramps_home_url)scontact/' % {'gramps_home_url': URL_HOMEPAGE} ) + '\n\n' welcome += boldst(_('Who makes Gramps?')) + '\n\n' + _( 'Gramps is created by genealogists for genealogists, organized in the' ' Gramps Project.' ' Gramps is an Open Source Software package, which means you are ' 'free to make copies and distribute it to anyone you like. It\'s ' 'developed and maintained by a worldwide team of volunteers whose' ' goal is to make Gramps powerful, yet easy to use.\n\n') welcome += boldst(_('Getting Started')) + '\n\n' + _( 'The first thing you must do is to create a new Family Tree. To ' 'create a new Family Tree (sometimes called \'database\') select ' '"Family Trees" from the menu, pick "Manage Family Trees", press ' '"New" and name your Family Tree. For more details, please read the ' 'information at the links above\n\n') welcome += boldst(_('Dashboard View')) + '\n\n' + _( 'You are currently reading from the "Dashboard" view, where you can' ' add your own gramplets. You can also add gramplets to any view by' ' adding a sidebar and/or bottombar, and right-clicking to the right' ' of the tab.\n\n' 'You can click the configuration icon in the toolbar to add additional' ' columns, while right-click on the background allows to add gramplets.' ' You can also drag the Properties button to reposition the gramplet ' ' on this page, and detach the gramplet to float above Gramps.' ) self.texteditor.set_text(welcome) def get_has_data(self, obj): """ Return True if the gramplet has data, else return False. """ return True
def write_media(self, media_list, event): for media_ref in media_list: mobj = self.dbstate.db.get_media_from_handle(media_ref.ref) button = self.get_thumbnail(media_ref, size=SIZE_LARGE) if button: self.vbox2.add(button) vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) if event: etype = str(event.get_type()) label = Gtk.Label(etype) vbox.pack_start(label, False, False, 0) who = get_participant_from_event(self.dbstate.db, event.handle) label = Gtk.Label(who) vbox.pack_start(label, False, False, 0) date_place = self.format_event(event) label = Gtk.Label(date_place) vbox.pack_start(label, False, False, 0) notes = mobj.get_note_list() if len(notes) > 0: note = self.dbstate.db.get_note_from_handle(notes[0]) texteditor = StyledTextEditor() texteditor.set_editable(False) texteditor.set_wrap_mode(Gtk.WrapMode.WORD) texteditor.set_text(note.get_styledtext()) texteditor.set_hexpand(True) texteditor.show() vbox.pack_start(texteditor, True, True, 0) vbox.show_all() self.vbox2.attach_next_to(vbox, button, Gtk.PositionType.RIGHT, 1, 1)
class Notes(Gramplet): """ Displays the notes for an object. """ def init(self): self.gui.WIDGET = self.build_gui() self.gui.get_container_widget().remove(self.gui.textview) self.gui.get_container_widget().add(self.gui.WIDGET) self.gui.WIDGET.show() def build_gui(self): """ Build the GUI interface. """ top = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) hbox = Gtk.Box() self.left = SimpleButton('go-previous', self.left_clicked) self.left.set_sensitive(False) hbox.pack_start(self.left, False, False, 0) self.right = SimpleButton('go-next', self.right_clicked) self.right.set_sensitive(False) hbox.pack_start(self.right, False, False, 0) self.page = Gtk.Label() hbox.pack_end(self.page, False, False, 10) scrolledwindow = Gtk.ScrolledWindow() scrolledwindow.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) self.texteditor = StyledTextEditor() self.texteditor.set_editable(False) self.texteditor.set_wrap_mode(Gtk.WrapMode.WORD) scrolledwindow.add(self.texteditor) top.pack_start(hbox, False, False, 0) top.pack_start(scrolledwindow, True, True, 0) top.show_all() return top def get_notes(self, obj): """ Get the note list for the current object. """ self.left.set_sensitive(False) self.right.set_sensitive(False) self.texteditor.set_text(StyledText()) self.note_list = obj.get_note_list() self.page.set_text('') if len(self.note_list) > 0: self.set_has_data(True) if len(self.note_list) > 1: self.right.set_sensitive(True) self.current = 0 self.display_note() else: self.set_has_data(False) def clear_text(self): self.left.set_sensitive(False) self.right.set_sensitive(False) self.texteditor.set_text(StyledText()) self.page.set_text('') self.current = 0 def display_note(self): """ Display the current note. """ note_handle = self.note_list[self.current] note = self.dbstate.db.get_note_from_handle(note_handle) self.texteditor.set_text(note.get_styledtext()) self.page.set_text(_('%(current)d of %(total)d') % {'current': self.current + 1, 'total': len(self.note_list)}) def left_clicked(self, button): """ Display the previous note. """ if self.current > 0: self.current -= 1 self.right.set_sensitive(True) if self.current == 0: self.left.set_sensitive(False) self.display_note() def right_clicked(self, button): """ Display the next note. """ if self.current < len(self.note_list) - 1: self.current += 1 self.left.set_sensitive(True) if self.current == len(self.note_list) - 1: self.right.set_sensitive(False) self.display_note() def get_has_data(self, obj): """ Return True if the gramplet has data, else return False. """ if obj is None: return False if obj.get_note_list(): return True return False
class WelcomeGramplet(Gramplet): """ Displays a welcome note to the user. """ def init(self): self.gui.WIDGET = self.build_gui() self.gui.get_container_widget().remove(self.gui.textview) self.gui.get_container_widget().add(self.gui.WIDGET) self.gui.WIDGET.show() def build_gui(self): """ Build the GUI interface. """ top = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) scrolledwindow = Gtk.ScrolledWindow() scrolledwindow.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) self.texteditor = StyledTextEditor() self.texteditor.set_editable(False) self.texteditor.set_wrap_mode(Gtk.WrapMode.WORD) scrolledwindow.add(self.texteditor) self.set_text() top.pack_start(scrolledwindow, True, True, 0) top.show_all() return top def set_text(self): """ Display the welcome text. """ welcome = boldst(_('Intro')) + '\n\n' welcome += _( 'Gramps is a software package designed for genealogical research.' ' Although similar to other genealogical programs, Gramps offers ' 'some unique and powerful features.\n\n') welcome += boldst(_('Links')) + '\n\n' welcome += linkst(_('Home Page'), URL_HOMEPAGE) + '\n' welcome += linkst( _('Start with Genealogy and Gramps'), '%(gramps_wiki_url)sStart_with_Genealogy' % {'gramps_wiki_url': URL_WIKISTRING}) + '\n' welcome += linkst( _('Gramps online manual'), URL_WIKISTRING + URL_MANUAL_PAGE + _('locale_suffix|')) + '\n' welcome += linkst( _('Ask questions on gramps-users mailing list'), '%(gramps_home_url)scontact/' % {'gramps_home_url': URL_HOMEPAGE}) + '\n\n' welcome += boldst(_('Who makes Gramps?')) + '\n\n' + _( 'Gramps is created by genealogists for genealogists, organized in the' ' Gramps Project.' ' Gramps is an Open Source Software package, which means you are ' 'free to make copies and distribute it to anyone you like. It\'s ' 'developed and maintained by a worldwide team of volunteers whose' ' goal is to make Gramps powerful, yet easy to use.\n\n') welcome += boldst(_('Getting Started')) + '\n\n' + _( 'The first thing you must do is to create a new Family Tree. To ' 'create a new Family Tree (sometimes called \'database\') select ' '"Family Trees" from the menu, pick "Manage Family Trees", press ' '"New" and name your Family Tree. For more details, please read the ' 'information at the links above\n\n') welcome += boldst(_('Dashboard View')) + '\n\n' + _( 'You are currently reading from the "Dashboard" view, where you can' ' add your own gramplets. You can also add gramplets to any view by' ' adding a sidebar and/or bottombar, and right-clicking to the right' ' of the tab.\n\n' 'You can click the configuration icon in the toolbar to add additional' ' columns, while right-click on the background allows to add gramplets.' ' You can also drag the Properties button to reposition the gramplet ' ' on this page, and detach the gramplet to float above Gramps.') self.texteditor.set_text(welcome) def get_has_data(self, obj): """ Return True if the gramplet has data, else return False. """ return True
class NoteCleanup(tool.Tool, ManagedWindow): def __init__(self, dbstate, user, options_class, name, callback=None): uistate = user.uistate tool.Tool.__init__(self, dbstate, options_class, name) self.window_name = _('Note Cleanup Tool') ManagedWindow.__init__(self, uistate, [], self.__class__) self.dbstate = dbstate self.trans = None self.moved_files = [] self.titles = [_('Cleaned Notes'), _('Links Only'), _('Issues')] self.models = [] self.views = [] self.changelist = [] self.changelistidx = 0 window = MyWindow(self.dbstate, self.uistate, []) vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) hbox.set_homogeneous(True) rvbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=2, width_request=400) vbox.pack_start(hbox, True, True, 5) self.notebook = Gtk.Notebook() self.notebook.set_scrollable(True) self.notebook.connect('switch-page', self.pagesw) for title in self.titles: self.create_tab(title) hbox.pack_start(self.notebook, True, True, 3) hbox.pack_start(rvbox, True, True, 3) bbox = Gtk.ButtonBox(orientation=Gtk.Orientation.HORIZONTAL) vbox.pack_start(bbox, False, False, 5) close = Gtk.Button(_('Close')) close.set_tooltip_text(_('Close the Note Cleanup Tool')) close.connect('clicked', self.close) save = Gtk.Button(_('Save All')) save.set_tooltip_text(_('Save All Changes')) save.connect('clicked', self.saveit) search = Gtk.Button(_('Search')) search.set_tooltip_text(_('Search for Untidy Notes')) search.connect('clicked', self.cleanup) testnote = Gtk.Button(_('Generate Test Notes')) testnote.set_tooltip_text(_( 'Generate Test notes in range N99996-N99999.\n' 'These are added to your database, so you may want to work with' ' a test database or delete them later.')) testnote.connect('clicked', self.gentest) export = Gtk.Button(_('Export')) export.set_tooltip_text(_('Export the results to a text file')) export.connect('clicked', self.export_results) bbox.add(search) bbox.add(testnote) bbox.add(export) bbox.add(save) bbox.add(close) self.tb = StyledTextEditor() self.tb.set_editable(False) self.tb.set_wrap_mode(Gtk.WrapMode.WORD) tbw = Gtk.ScrolledWindow() tbw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) tbw.add(self.tb) rvbox.pack_start(tbw, True, True, 0) self.ta = StyledTextEditor() self.ta.set_editable(True) self.ta.set_wrap_mode(Gtk.WrapMode.WORD) taw = Gtk.ScrolledWindow() taw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) taw.add(self.ta) tat=self.ta.get_toolbar() tat.set_icon_size(Gtk.IconSize.SMALL_TOOLBAR) tatb=tat.get_nth_item(5) tat.remove(tatb) tatb=tat.get_nth_item(5) tat.remove(tatb) rvbox.pack_start(tat, False, False, 0) rvbox.pack_start(taw, True, True, 0) self.clear_models() vbox.show_all() window.add(vbox) window.set_size_request(800, 400) self.set_window(window, None, self.window_name) self.show() self.show_tabs() WarningDialog(self.window_name, _("Please back up your database before running this tool.\n\n" "Start the tool by pressing the 'Search' button, then review" " the results.\n" "When satisifed press the 'Save All' button to save your work.\n" "You may export a summary list of the notes that" " were found using the 'Export' button."), self.window) def build_menu_names(self, obj): return (_('Clean up Notes'), self.window_name) def create_tab(self, title): """ Create a page in the notebook. """ scrolled_window = Gtk.ScrolledWindow() scrolled_window.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) view = Gtk.TreeView() column = Gtk.TreeViewColumn(_('Notes')) view.append_column(column) cell = Gtk.CellRendererText() column.pack_start(cell, True) column.add_attribute(cell, 'text', 0) column.set_sort_column_id(0) column.set_sort_indicator(True) model = Gtk.ListStore(str, int) view.set_model(model) page = self.notebook.get_n_pages() view.connect('button-press-event', self.button_press, page) selection = view.get_selection() selection.connect('changed', self.selection_changed, page) scrolled_window.add(view) self.models.append(model) self.views.append(view) label = Gtk.Label(title) self.notebook.append_page(scrolled_window, label) def button_press(self, view, event, page): """ Called when a button is pressed on a treeview. """ if event.type == Gdk.EventType._2BUTTON_PRESS and event.button == 1: model, iter_ = view.get_selection().get_selected() if iter_: value = model.get_value(iter_, 1) self.edit(value) def selection_changed(self, selection, page): """ Called when selection changed within the notebook tab """ model, iter_ = selection.get_selected() if iter_: value = model.get_value(iter_, 1) self.showit(value) def pagesw(self, notebook, page, pagenum): """ called when we switch tabs in the notebook """ selection = self.views[pagenum].get_selection() model, iter_ = selection.get_selected() if iter_: value = model.get_value(iter_, 1) self.showit(value) def edit(self,indx): """ Edit the note object with the given handle. """ handle = self.changelist[indx][0] note = self.db.get_note_from_handle(handle) try: EditNote(self.dbstate, self.uistate, [], note) except WindowActiveError: pass def showit(self, indx): """ Show the selection on right hand panes """ self.update_changelist() self.indx = indx value = self.changelist[indx] self.tb.set_text(value[1]) self.ta.set_text(value[2]) def update_changelist(self): if self.indx != []: y=self.ta.get_text() z=self.changelist[self.indx][2] if y.serialize() != z.serialize(): # if y != z: doesn't work!!! x=(self.changelist[self.indx][0],\ self.changelist[self.indx][1], y) self.changelist[self.indx] = x def gentest(self, button): """ Create some test notes. """ with DbTxn(_("Cleanup Test Notes"), self.db) as trans: gid = 'N99996' text='A note with <a target=new href="'\ 'http://seekingmichigan.org">'\ 'http://seekingmichigan.org</a>.' self.add_note(gid, text, trans) gid = 'N99997' text='http://www.google.com' self.add_note(gid, text, trans) gid = 'N99998' text= 'Quick test of <i>italics</i>, <b>bold</b>, <u>underline'\ '</u>, and <a href="http://www.google.com">Google</a>.' self.add_note(gid, text, trans) gid = 'N99999' text = 'An <??>issue</??> with this note' self.add_note(gid, text, trans) def add_note(self, gid, text, trans): new_note = self.db.get_note_from_gramps_id(gid) if new_note: new_note.set(text) self.db.commit_note(new_note, trans) msg = _("Add Test Note") else: new_note = Note(text) new_note.set_gramps_id(gid) self.db.add_note(new_note, trans) msg = _("Add Test Note") trans.set_description(msg) def export_results(self, button): """ Export the results to a text file. """ chooser = Gtk.FileChooserDialog( _("Export results to a text file"), self.uistate.window, Gtk.FileChooserAction.SAVE, (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_SAVE, Gtk.ResponseType.OK)) chooser.set_do_overwrite_confirmation(True) while True: value = chooser.run() filename = chooser.get_filename() if value == Gtk.ResponseType.OK: if filename: chooser.destroy() break else: chooser.destroy() return try: with io.open(filename, 'w') as report_file: for title, model in zip(self.titles, self.models): self.export_page(report_file, title, model) except IOError as err: WarningDialog(self.window_name, _('Error when writing the report: %s') % err.strerror, self.window) def export_page(self, report_file, title, model): """ Export a page of the report to a text file. """ if len(model) == 0: return report_file.write(title + '\n') for row in model: report_file.write(' %s\n' % row[0]) def show_tabs(self): """ Show notebook tabs containing data. """ for page, model in enumerate(self.models): tab = self.notebook.get_nth_page(page) if len(model) > 0: selection = self.views[page].get_selection() selection.select_path(Gtk.TreePath.new_first()) tab.show() else: tab.hide() def clear_models(self): """ Clear the models. """ for model in self.models: model.clear() self.changelist = [] self.indx =[] self.tb.set_text(StyledText(_('\n\n' 'Notes selected on the left pane are shown Before cleanup in' ' this box.'))) self.ta.set_text(StyledText(_('\n\n' 'Notes selected on the left pane are shown After cleanup in this' ' box.\n' 'If you wish to make changes, you can make them here and' ' use the style controls in the toolbar above.'))) def saveit(self, button): """ Commit the changes to the database """ self.update_changelist() progress = ProgressMeter(self.window_name, can_cancel=True, parent=self.window) length = len(self.changelist) progress.set_pass(_('Saving Notes'), length) with DbTxn(_("Saving Cleaned Notes"), self.db, batch=False) as trans: for changed in self.changelist: note = self.db.get_note_from_handle(changed[0]) note.set_styledtext(changed[2]) self.db.commit_note(note, trans) msg = _("Note Cleanup") trans.set_description(msg) progress.step() if progress.get_cancelled(): break self.clear_models() self.show_tabs() progress.close() def cleanup(self, button): """ Cleanup Notes. """ self.clear_models() progress = ProgressMeter(self.window_name, can_cancel=True, parent=self.window) length = self.db.get_number_of_notes() progress.set_pass(_('Scanning Notes'), length) for handle in self.db.get_note_handles(): note = self.db.get_note_from_handle(handle) g_id = note.gramps_id stext = note.get_styledtext() optype = -1 ## find the notes and do cleanup if not stext.tags: result = self.convert_to_styled(stext.string) indx = len(self.changelist) for styledtext_tag in result.tags: if int(styledtext_tag.name) == StyledTextTagType.HIGHLIGHT: optype = ISSUE break elif int(styledtext_tag.name) == StyledTextTagType.LINK: optype = LINK while True: if optype == ISSUE: # make list of notes with errors self.models[ISSUE].append((self.preview(stext, g_id), indx)) elif stext.string != result.string: # Make list of edited notes self.models[CLEANED].append((self.preview(stext, g_id), indx)) elif optype == LINK: # make list of notes with only links self.models[LINK].append((self.preview(stext, g_id), indx)) else: break self.changelist.append((handle, stext, result)) break progress.step() if progress.get_cancelled(): break self.show_tabs() progress.close() def preview(self, stext, g_id): prev = " ".join(str(stext).split()) if len(prev) > 80: text = '%s -> %s' % (g_id, prev[:80] + "...") else: text = '%s -> %s' % (g_id, prev) return text def convert_to_styled(self, data): """ This scans incoming notes for possible html. It converts a select few tags into StyledText and removes the rest of the tags. Notes of this type occur in data from FTM and ancestry.com. Result is a much cleaner note. @param data: a string of text possibly containg html @type data: str """ token_specification = [ # Italics: must not be nested, any tag terminates ('ITALIC', r'<i>.*?(?=<)'), # bolds: must not be nested, any tag terminates ('BOLD', r'<b>.*?(?=<)'), # Underlines: must not be nested, any tag terminates ('UNDER', r'<u>.*?(?=<)'), # Table Header Begin (start Bold) ('TBLHDRB', r'<tr><th>'), # Table Header End (end Bold and \n) ('TBLHDRE', r'</th></tr>'), # Table Header Cell (repl with ': ') ('TBLHDRC', r'(<\th>)?<th>'), # Table Cell break (repl with ': ') ('TBLCELL', r'</td><td>'), # Table ('TABLE', r'</?table.*?>'), # Href start to end ('HREF', r'<+a .*?href=["\' ]*(?P<HREFL>.*?)'\ r'["\' ].*?>(?P<HREFT>.*?)</a>+'), # HTTP start to end (have to rstrip(' .:') for link) ('HTTP', r'https?:.*?(\s|$)'), # Paragraph end ('PARAEND', r'</p>|</li>|<tr>|<br>'), # Skip over these tags ('SKIP', r'<ul>|</ul>|<li>|<p>|</tr>|<td>|</td>|<th>|'\ r'</a>|</i>|</b>|</u>'), # Unimplemented HTTP tags ('UNKNWN', r'<.*?>'), ] tok_regex = '|'.join('(?P<%s>%s)' % pair for pair in token_specification) prev = 0 chunkpos = 0 chunks = [] italics = [] bolds = [] unders = [] links = [] reds = [] bldpos = -1 data = html.unescape(data) # clean up escaped html "<" etc. for mo in re.finditer(tok_regex, data, flags=(re.DOTALL | re.I)): kind = mo.lastgroup st_txt = mo.group(kind) in_start = mo.start() in_end = mo.end() if kind == 'SKIP' or kind == 'TABLE': if prev != in_start: chunks.append(data[prev:in_start]) chunkpos += (in_start - prev) elif kind == 'PARAEND': chunks.append(data[prev:in_start] + '\n') chunkpos += (in_start - prev + 1) elif kind == 'ITALIC': chunks.append(data[prev:in_start] + data[(in_start + 3):in_end]) newpos = chunkpos - prev + in_end - 3 italics.append((chunkpos + in_start - prev, newpos)) chunkpos = newpos elif kind == 'BOLD': chunks.append(data[prev:in_start] + data[(in_start + 3):in_end]) newpos = chunkpos - prev + in_end - 3 bolds.append((chunkpos + in_start - prev, newpos)) chunkpos = newpos elif kind == 'UNDER': chunks.append(data[prev:in_start] + data[(in_start + 3):in_end]) newpos = chunkpos - prev + in_end - 3 unders.append((chunkpos + in_start - prev, newpos)) chunkpos = newpos elif kind == 'HTTP': #HTTP found st_txt = mo.group('HTTP') oldpos = chunkpos + in_start - prev chunks.append(data[prev:in_start] + st_txt) chunkpos += (in_start - prev + len(st_txt)) st_txt = st_txt.rstrip(' .:)') newpos = oldpos + len(st_txt) links.append((st_txt, oldpos, newpos)) elif kind == 'HREF': #HREF found st_txt = mo.group('HREFT') lk_txt = mo.group('HREFL') # fix up relative links emmitted by ancestry.com if lk_txt.startswith("/search/dbextra") \ or lk_txt.startswith("/handler/domain"): lk_txt = "http://search.ancestry.com" + lk_txt oldpos = chunkpos + in_start - prev # if tag (minus any trailing '.') is substring of link if st_txt[0:-1] in lk_txt: st_txt = lk_txt # just use the link else: # use link and tag st_txt = " " + lk_txt + " (" + st_txt + ")" newpos = oldpos + len(st_txt) chunks.append(data[prev:in_start] + st_txt) chunkpos += (in_start - prev + len(st_txt)) links.append((lk_txt, oldpos, newpos)) elif kind == 'TBLCELL' or kind == 'TBLHDRC': #Table cell break chunks.append(data[prev:in_start] + ': ') chunkpos += (in_start - prev + 3) elif kind == 'TBLHDRB': #header start if prev != in_start: chunks.append(data[prev:in_start]) chunkpos += (in_start - prev) bldpos = chunkpos elif kind == 'TBLHDRE': #Header end if bldpos == -1: if prev != in_start: chunks.append(data[prev:in_end]) newpos = chunkpos - prev + in_end reds.append((chunkpos + in_start - prev, newpos)) chunkpos = newpos print('Invalid table header, no start tag found') else: if prev != in_start: chunks.append(data[prev:in_start]) chunkpos += (in_start - prev) bolds.append((bldpos, chunkpos)) bldpos = -1 elif kind == 'UNKNWN': if prev != in_start: chunks.append(data[prev:in_end]) newpos = chunkpos - prev + in_end reds.append((chunkpos + in_start - prev, newpos)) chunkpos = newpos print('Unexpected or unimplemented HTML tag', st_txt) else: print("shouldn't get here") prev = in_end chunks.append(data[prev:]) result = ''.join(chunks) tags = [] for link in links: tags.append(StyledTextTag(StyledTextTagType.LINK, link[0], [(link[1], link[2])])) if italics: tags.append(StyledTextTag(StyledTextTagType.ITALIC, False , italics)) if bolds: tags.append(StyledTextTag(StyledTextTagType.BOLD, False , bolds)) if unders: tags.append(StyledTextTag(StyledTextTagType.UNDERLINE, False , unders)) if reds: tags.append(StyledTextTag(StyledTextTagType.HIGHLIGHT, '#FFFF00' , reds)) return StyledText(result,tags)
class Notes(Gramplet): """ Displays the notes for an object. """ def init(self): self.gui.WIDGET = self.build_gui() self.gui.get_container_widget().remove(self.gui.textview) self.gui.get_container_widget().add(self.gui.WIDGET) self.gui.WIDGET.show() def build_gui(self): """ Build the GUI interface. """ top = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) hbox = Gtk.Box() self.left = SimpleButton('go-previous', self.left_clicked) self.left.set_sensitive(False) hbox.pack_start(self.left, False, False, 0) self.right = SimpleButton('go-next', self.right_clicked) self.right.set_sensitive(False) hbox.pack_start(self.right, False, False, 0) self.page = Gtk.Label() hbox.pack_end(self.page, False, False, 10) scrolledwindow = Gtk.ScrolledWindow() scrolledwindow.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) self.texteditor = StyledTextEditor() self.texteditor.set_editable(False) self.texteditor.set_wrap_mode(Gtk.WrapMode.WORD) scrolledwindow.add(self.texteditor) top.pack_start(hbox, False, False, 0) top.pack_start(scrolledwindow, True, True, 0) top.show_all() return top def get_notes(self, obj): """ Get the note list for the current object. """ self.left.set_sensitive(False) self.right.set_sensitive(False) self.texteditor.set_text(StyledText()) self.note_list = obj.get_note_list() self.page.set_text('') if len(self.note_list) > 0: self.set_has_data(True) if len(self.note_list) > 1: self.right.set_sensitive(True) self.current = 0 self.display_note() else: self.set_has_data(False) def clear_text(self): self.left.set_sensitive(False) self.right.set_sensitive(False) self.texteditor.set_text(StyledText()) self.page.set_text('') self.current = 0 def display_note(self): """ Display the current note. """ note_handle = self.note_list[self.current] note = self.dbstate.db.get_note_from_handle(note_handle) self.texteditor.set_text(note.get_styledtext()) self.page.set_text( _('%(current)d of %(total)d') % { 'current': self.current + 1, 'total': len(self.note_list) }) def left_clicked(self, button): """ Display the previous note. """ if self.current > 0: self.current -= 1 self.right.set_sensitive(True) if self.current == 0: self.left.set_sensitive(False) self.display_note() def right_clicked(self, button): """ Display the next note. """ if self.current < len(self.note_list) - 1: self.current += 1 self.left.set_sensitive(True) if self.current == len(self.note_list) - 1: self.right.set_sensitive(False) self.display_note() def get_has_data(self, obj): """ Return True if the gramplet has data, else return False. """ if obj is None: return False if obj.get_note_list(): return True return False
class ToDo(Gramplet): """ Displays the To Do notes for an object. """ def init(self): self.gui.WIDGET = self.build_gui() self.gui.get_container_widget().remove(self.gui.textview) self.gui.get_container_widget().add(self.gui.WIDGET) self.gui.WIDGET.show() def build_gui(self): """ Build the GUI interface. """ top = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) hbox = Gtk.Box() self.left = SimpleButton('go-previous', self.left_clicked) self.left.set_tooltip_text(_('Previous To Do note')) self.left.set_sensitive(False) hbox.pack_start(self.left, False, False, 0) self.right = SimpleButton('go-next', self.right_clicked) self.right.set_tooltip_text(_('Next To Do note')) self.right.set_sensitive(False) hbox.pack_start(self.right, False, False, 0) self.edit = SimpleButton('gtk-edit', self.edit_clicked) self.edit.set_tooltip_text(_('Edit the selected To Do note')) self.edit.set_sensitive(False) hbox.pack_start(self.edit, False, False, 0) self.new = SimpleButton('document-new', self.new_clicked) self.new.set_tooltip_text(_('Add a new To Do note')) hbox.pack_start(self.new, False, False, 0) self.page = Gtk.Label() hbox.pack_end(self.page, False, False, 10) scrolledwindow = Gtk.ScrolledWindow() scrolledwindow.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) self.texteditor = StyledTextEditor() self.texteditor.set_editable(False) self.texteditor.set_wrap_mode(Gtk.WrapMode.WORD) scrolledwindow.add(self.texteditor) top.pack_start(hbox, False, False, 0) top.pack_start(scrolledwindow, True, True, 0) top.show_all() return top def get_note_list(self, obj): """ Get a list of To Do notes for the current object. """ note_list = [] for note_handle in obj.get_note_list(): note = self.dbstate.db.get_note_from_handle(note_handle) if int(note.get_type()) == NoteType.TODO: note_list.append(note.get_handle()) return note_list def get_notes(self, obj): """ Display the To Do notes for the current object. """ self.obj = obj self.left.set_sensitive(False) self.right.set_sensitive(False) self.edit.set_sensitive(False) self.texteditor.set_text(StyledText()) self.note_list = self.get_note_list(obj) self.page.set_text('') if len(self.note_list) > 0: self.set_has_data(True) self.edit.set_sensitive(True) if len(self.note_list) > 1: self.right.set_sensitive(True) self.current = 0 self.display_note() else: self.set_has_data(False) def clear_text(self): self.left.set_sensitive(False) self.right.set_sensitive(False) self.edit.set_sensitive(False) self.texteditor.set_text(StyledText()) self.page.set_text('') self.current = 0 def display_note(self): """ Display the current note. """ note_handle = self.note_list[self.current] note = self.dbstate.db.get_note_from_handle(note_handle) self.texteditor.set_text(note.get_styledtext()) self.page.set_text( _('%(current)d of %(total)d') % { 'current': self.current + 1, 'total': len(self.note_list) }) def left_clicked(self, button): """ Display the previous note. """ if self.current > 0: self.current -= 1 self.right.set_sensitive(True) if self.current == 0: self.left.set_sensitive(False) self.display_note() def right_clicked(self, button): """ Display the next note. """ if self.current < len(self.note_list) - 1: self.current += 1 self.left.set_sensitive(True) if self.current == len(self.note_list) - 1: self.right.set_sensitive(False) self.display_note() def get_has_data(self, obj): """ Return True if the gramplet has data, else return False. """ if obj is None: return False if self.get_note_list(obj): return True return False def edit_clicked(self, obj): """ Edit current To Do note. """ from gramps.gui.editors import EditNote note_handle = self.note_list[self.current] note = self.dbstate.db.get_note_from_handle(note_handle) try: EditNote(self.gui.dbstate, self.gui.uistate, [], note) except WindowActiveError: pass def new_clicked(self, obj): """ Create a new To Do note. """ nav_type = self.uistate.viewmanager.active_page.navigation_type() active_handle = self.get_active(nav_type) if active_handle: from gramps.gui.editors import EditNote note = Note() note.set_type(NoteType.TODO) try: EditNote(self.gui.dbstate, self.gui.uistate, [], note, self.created) except WindowActiveError: pass else: WarningDialog( _("No active object"), _("First select the object to which you want to attach a note") + _(":") + _(nav_type), parent=self.uistate.window)
class NoteCleanup(tool.Tool, ManagedWindow): def __init__(self, dbstate, user, options_class, name, callback=None): uistate = user.uistate tool.Tool.__init__(self, dbstate, options_class, name) self.window_name = _('Note Cleanup Tool') ManagedWindow.__init__(self, uistate, [], self.__class__) self.dbstate = dbstate self.trans = None self.moved_files = [] self.titles = [_('Cleaned Notes'), _('Links Only'), _('Issues')] self.models = [] self.views = [] self.changelist = [] self.changelistidx = 0 window = MyWindow(self.dbstate, self.uistate, []) vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) hbox.set_homogeneous(True) rvbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=2, width_request=400) vbox.pack_start(hbox, True, True, 5) self.notebook = Gtk.Notebook() self.notebook.set_scrollable(True) self.notebook.connect('switch-page', self.pagesw) for title in self.titles: self.create_tab(title) hbox.pack_start(self.notebook, True, True, 3) hbox.pack_start(rvbox, True, True, 3) bbox = Gtk.ButtonBox(orientation=Gtk.Orientation.HORIZONTAL) vbox.pack_start(bbox, False, False, 5) close = Gtk.Button(label=_('Close')) close.set_tooltip_text(_('Close the Note Cleanup Tool')) close.connect('clicked', self.close) save = Gtk.Button(label=_('Save All')) save.set_tooltip_text(_('Save All Changes')) save.connect('clicked', self.saveit) search = Gtk.Button(label=_('Search')) search.set_tooltip_text(_('Search for Untidy Notes')) search.connect('clicked', self.cleanup) testnote = Gtk.Button(label=_('Generate Test Notes')) testnote.set_tooltip_text(_( 'Generate Test notes in range N99996-N99999.\n' 'These are added to your database, so you may want to work with' ' a test database or delete them later.')) testnote.connect('clicked', self.gentest) export = Gtk.Button(label=_('Export')) export.set_tooltip_text(_('Export the results to a text file')) export.connect('clicked', self.export_results) bbox.add(search) bbox.add(testnote) bbox.add(export) bbox.add(save) bbox.add(close) self.tb = StyledTextEditor() self.tb.set_editable(False) self.tb.set_wrap_mode(Gtk.WrapMode.WORD) tbw = Gtk.ScrolledWindow() tbw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) tbw.add(self.tb) rvbox.pack_start(tbw, True, True, 0) self.ta = StyledTextEditor() self.ta.set_transient_parent(window) self.ta.set_editable(True) self.ta.set_wrap_mode(Gtk.WrapMode.WORD) taw = Gtk.ScrolledWindow() taw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) taw.add(self.ta) # tat=self.ta.get_toolbar() tat, self.action_group = self.ta.create_toolbar( uistate.uimanager, window) tat.set_icon_size(Gtk.IconSize.SMALL_TOOLBAR) tatb = tat.get_nth_item(5) tat.remove(tatb) tatb = tat.get_nth_item(5) tat.remove(tatb) rvbox.pack_start(tat, False, False, 0) rvbox.pack_start(taw, True, True, 0) self.clear_models() vbox.show_all() window.add(vbox) window.set_size_request(800, 400) self.set_window(window, None, self.window_name) self.show() self.show_tabs() WarningDialog( self.window_name, _("Please back up your database before running this tool.\n\n" "Start the tool by pressing the 'Search' button, then review" " the results.\n" "When satisifed press the 'Save All' button to save your work.\n" "You may export a summary list of the notes that" " were found using the 'Export' button."), self.window) def build_menu_names(self, _obj): return (_('Clean up Notes'), self.window_name) def create_tab(self, title): """ Create a page in the notebook. """ scrolled_window = Gtk.ScrolledWindow() scrolled_window.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) view = Gtk.TreeView() column = Gtk.TreeViewColumn(_('Notes')) view.append_column(column) cell = Gtk.CellRendererText() column.pack_start(cell, True) column.add_attribute(cell, 'text', 0) column.set_sort_column_id(0) column.set_sort_indicator(True) model = Gtk.ListStore(str, int) view.set_model(model) page = self.notebook.get_n_pages() view.connect('button-press-event', self.button_press, page) selection = view.get_selection() selection.connect('changed', self.selection_changed, page) scrolled_window.add(view) self.models.append(model) self.views.append(view) label = Gtk.Label(label=title) self.notebook.append_page(scrolled_window, label) def button_press(self, view, event, _page): """ Called when a button is pressed on a treeview. """ if event.type == Gdk.EventType._2BUTTON_PRESS and event.button == 1: model, iter_ = view.get_selection().get_selected() if iter_: value = model.get_value(iter_, 1) self.edit(value) def selection_changed(self, selection, _page): """ Called when selection changed within the notebook tab """ model, iter_ = selection.get_selected() if iter_: value = model.get_value(iter_, 1) self.showit(value) def pagesw(self, _notebook, _page, pagenum): """ called when we switch tabs in the notebook """ selection = self.views[pagenum].get_selection() model, iter_ = selection.get_selected() if iter_: value = model.get_value(iter_, 1) self.showit(value) def edit(self, indx): """ Edit the note object with the given handle. """ handle = self.changelist[indx][0] note = self.db.get_note_from_handle(handle) try: EditNote(self.dbstate, self.uistate, [], note) except WindowActiveError: pass def showit(self, indx): """ Show the selection on right hand panes """ self.update_changelist() self.indx = indx value = self.changelist[indx] self.tb.set_text(value[1]) self.ta.set_text(value[2]) def update_changelist(self): if self.indx != []: y = self.ta.get_text() z = self.changelist[self.indx][2] if y.serialize() != z.serialize(): # if y != z: doesn't work!!! x = (self.changelist[self.indx][0], self.changelist[self.indx][1], y) self.changelist[self.indx] = x def gentest(self, _button): """ Create some test notes. """ with DbTxn(_("Cleanup Test Notes"), self.db) as trans: gid = 'N99996' text = 'A note with <a target=new href="'\ 'http://seekingmichigan.org">'\ 'http://seekingmichigan.org</a>.' self.add_note(gid, text, trans) gid = 'N99997' text = 'http://www.google.com' self.add_note(gid, text, trans) gid = 'N99998' text = 'Quick test of <i>italics</i>, <b>bold</b>, <u>underline'\ '</u>, and <a href="http://www.google.com">Google</a>.' self.add_note(gid, text, trans) gid = 'N99999' text = 'An <??>issue</??> with this note' self.add_note(gid, text, trans) def add_note(self, gid, text, trans): new_note = self.db.get_note_from_gramps_id(gid) if new_note: new_note.set(text) self.db.commit_note(new_note, trans) msg = _("Add Test Note") else: new_note = Note(text) new_note.set_gramps_id(gid) self.db.add_note(new_note, trans) msg = _("Add Test Note") trans.set_description(msg) def export_results(self, _button): """ Export the results to a text file. """ chooser = Gtk.FileChooserDialog( _("Export results to a text file"), self.uistate.window, Gtk.FileChooserAction.SAVE, (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_SAVE, Gtk.ResponseType.OK)) chooser.set_do_overwrite_confirmation(True) while True: value = chooser.run() filename = chooser.get_filename() if value == Gtk.ResponseType.OK: if filename: chooser.destroy() break else: chooser.destroy() return try: with io.open(filename, 'w') as report_file: for title, model in zip(self.titles, self.models): self.export_page(report_file, title, model) except IOError as err: WarningDialog(self.window_name, _('Error when writing the report: %s') % err.strerror, self.window) def export_page(self, report_file, title, model): """ Export a page of the report to a text file. """ if len(model) == 0: return report_file.write(title + '\n') for row in model: report_file.write(' %s\n' % row[0]) def show_tabs(self): """ Show notebook tabs containing data. """ for page, model in enumerate(self.models): tab = self.notebook.get_nth_page(page) if len(model) > 0: selection = self.views[page].get_selection() selection.select_path(Gtk.TreePath.new_first()) tab.show() else: tab.hide() def clear_models(self): """ Clear the models. """ for model in self.models: model.clear() self.changelist = [] self.indx = [] self.tb.set_text(StyledText(_( '\n\nNotes selected on the left pane are shown Before cleanup in' ' this box.'))) self.ta.set_text(StyledText(_( '\n\n' 'Notes selected on the left pane are shown After cleanup in this' ' box.\n' 'If you wish to make changes, you can make them here and' ' use the style controls in the toolbar above.'))) def saveit(self, _button): """ Commit the changes to the database """ self.update_changelist() progress = ProgressMeter(self.window_name, can_cancel=True, parent=self.window) length = len(self.changelist) progress.set_pass(_('Saving Notes'), length) with DbTxn(_("Saving Cleaned Notes"), self.db, batch=False) as trans: for changed in self.changelist: note = self.db.get_note_from_handle(changed[0]) note.set_styledtext(changed[2]) self.db.commit_note(note, trans) msg = _("Note Cleanup") trans.set_description(msg) progress.step() if progress.get_cancelled(): break self.clear_models() self.show_tabs() progress.close() def cleanup(self, _button): """ Cleanup Notes. """ self.clear_models() progress = ProgressMeter(self.window_name, can_cancel=True, parent=self.window) length = self.db.get_number_of_notes() progress.set_pass(_('Scanning Notes'), length) for handle in self.db.get_note_handles(): note = self.db.get_note_from_handle(handle) g_id = note.gramps_id stext = note.get_styledtext() optype = -1 # find the notes and do cleanup if not stext.tags: result = self.convert_to_styled(stext.string) indx = len(self.changelist) for styledtext_tag in result.tags: if int(styledtext_tag.name) == StyledTextTagType.HIGHLIGHT: optype = ISSUE break elif int(styledtext_tag.name) == StyledTextTagType.LINK: optype = LINK while True: if optype == ISSUE: # make list of notes with errors self.models[ISSUE].append((self.preview(stext, g_id), indx)) elif stext.string != result.string: # Make list of edited notes self.models[CLEANED].append((self.preview(stext, g_id), indx)) elif optype == LINK: # make list of notes with only links self.models[LINK].append((self.preview(stext, g_id), indx)) else: break self.changelist.append((handle, stext, result)) break progress.step() if progress.get_cancelled(): break self.show_tabs() progress.close() def preview(self, stext, g_id): prev = " ".join(str(stext).split()) if len(prev) > 80: text = '%s -> %s' % (g_id, prev[:80] + "...") else: text = '%s -> %s' % (g_id, prev) return text def convert_to_styled(self, data): """ This scans incoming notes for possible html. It converts a select few tags into StyledText and removes the rest of the tags. Notes of this type occur in data from FTM and ancestry.com. Result is a much cleaner note. @param data: a string of text possibly containg html @type data: str """ token_specification = [ # Italics: must not be nested, any tag terminates ('ITALIC', r'<i>.*?(?=<)'), # bolds: must not be nested, any tag terminates ('BOLD', r'<b>.*?(?=<)'), # Underlines: must not be nested, any tag terminates ('UNDER', r'<u>.*?(?=<)'), # Table Header Begin (start Bold) ('TBLHDRB', r'<tr><th>'), # Table Header End (end Bold and \n) ('TBLHDRE', r'</th></tr>'), # Table Header Cell (repl with ': ') ('TBLHDRC', r'(<\th>)?<th>'), # Table Cell break (repl with ': ') ('TBLCELL', r'</td><td>'), # Table ('TABLE', r'</?table.*?>'), # Href start to end ('HREF', r'<+a .*?href=["\' ]*(?P<HREFL>.*?)'\ r'["\' ].*?>(?P<HREFT>.*?)</a>+'), # HTTP start to end (have to rstrip(' .:') for link) ('HTTP', r'https?:.*?(\s|$)'), # Paragraph end ('PARAEND', r'</p>|</li>|<tr>|<br>'), # Skip over these tags ('SKIP', r'<ul>|</ul>|<li>|<p>|</tr>|<td>|</td>|<th>|'\ r'</a>|</i>|</b>|</u>'), # Unimplemented HTTP tags ('UNKNWN', r'<.*?>'), ] tok_regex = '|'.join('(?P<%s>%s)' % pair for pair in token_specification) prev = 0 chunkpos = 0 chunks = [] italics = [] bolds = [] unders = [] links = [] reds = [] bldpos = -1 data = html.unescape(data) # clean up escaped html "<" etc. for mo in re.finditer(tok_regex, data, flags=(re.DOTALL | re.I)): kind = mo.lastgroup st_txt = mo.group(kind) in_start = mo.start() in_end = mo.end() if kind == 'SKIP' or kind == 'TABLE': if prev != in_start: chunks.append(data[prev:in_start]) chunkpos += (in_start - prev) elif kind == 'PARAEND': chunks.append(data[prev:in_start] + '\n') chunkpos += (in_start - prev + 1) elif kind == 'ITALIC': chunks.append(data[prev:in_start] + data[(in_start + 3):in_end]) newpos = chunkpos - prev + in_end - 3 italics.append((chunkpos + in_start - prev, newpos)) chunkpos = newpos elif kind == 'BOLD': chunks.append(data[prev:in_start] + data[(in_start + 3):in_end]) newpos = chunkpos - prev + in_end - 3 bolds.append((chunkpos + in_start - prev, newpos)) chunkpos = newpos elif kind == 'UNDER': chunks.append(data[prev:in_start] + data[(in_start + 3):in_end]) newpos = chunkpos - prev + in_end - 3 unders.append((chunkpos + in_start - prev, newpos)) chunkpos = newpos elif kind == 'HTTP': # HTTP found st_txt = mo.group('HTTP') oldpos = chunkpos + in_start - prev chunks.append(data[prev:in_start] + st_txt) chunkpos += (in_start - prev + len(st_txt)) st_txt = st_txt.rstrip(' .:)') newpos = oldpos + len(st_txt) links.append((st_txt, oldpos, newpos)) elif kind == 'HREF': # HREF found st_txt = mo.group('HREFT') lk_txt = mo.group('HREFL') # fix up relative links emmitted by ancestry.com if(lk_txt.startswith("/search/dbextra") or lk_txt.startswith("/handler/domain")): lk_txt = "http://search.ancestry.com" + lk_txt oldpos = chunkpos + in_start - prev # if tag (minus any trailing '.') is substring of link if st_txt[0:-1] in lk_txt: st_txt = lk_txt # just use the link else: # use link and tag st_txt = " " + lk_txt + " (" + st_txt + ")" newpos = oldpos + len(st_txt) chunks.append(data[prev:in_start] + st_txt) chunkpos += (in_start - prev + len(st_txt)) links.append((lk_txt, oldpos, newpos)) elif kind == 'TBLCELL' or kind == 'TBLHDRC': # Table cell break chunks.append(data[prev:in_start] + ': ') chunkpos += (in_start - prev + 3) elif kind == 'TBLHDRB': # header start if prev != in_start: chunks.append(data[prev:in_start]) chunkpos += (in_start - prev) bldpos = chunkpos elif kind == 'TBLHDRE': # Header end if bldpos == -1: if prev != in_start: chunks.append(data[prev:in_end]) newpos = chunkpos - prev + in_end reds.append((chunkpos + in_start - prev, newpos)) chunkpos = newpos print('Invalid table header, no start tag found') else: if prev != in_start: chunks.append(data[prev:in_start]) chunkpos += (in_start - prev) bolds.append((bldpos, chunkpos)) bldpos = -1 elif kind == 'UNKNWN': if prev != in_start: chunks.append(data[prev:in_end]) newpos = chunkpos - prev + in_end reds.append((chunkpos + in_start - prev, newpos)) chunkpos = newpos print('Unexpected or unimplemented HTML tag', st_txt) else: print("shouldn't get here") prev = in_end chunks.append(data[prev:]) result = ''.join(chunks) tags = [] for link in links: tags.append(StyledTextTag(StyledTextTagType.LINK, link[0], [(link[1], link[2])])) if italics: tags.append(StyledTextTag(StyledTextTagType.ITALIC, False , italics)) if bolds: tags.append(StyledTextTag(StyledTextTagType.BOLD, False , bolds)) if unders: tags.append(StyledTextTag(StyledTextTagType.UNDERLINE, False , unders)) if reds: tags.append(StyledTextTag(StyledTextTagType.HIGHLIGHT, '#FFFF00', reds)) return StyledText(result, tags)
def __init__(self, dbstate, user, options_class, name, callback=None): uistate = user.uistate tool.Tool.__init__(self, dbstate, options_class, name) self.window_name = _('Note Cleanup Tool') ManagedWindow.__init__(self, uistate, [], self.__class__) self.dbstate = dbstate self.trans = None self.moved_files = [] self.titles = [_('Cleaned Notes'), _('Links Only'), _('Issues')] self.models = [] self.views = [] self.changelist = [] self.changelistidx = 0 window = MyWindow(self.dbstate, self.uistate, []) vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) hbox.set_homogeneous(True) rvbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=2, width_request=400) vbox.pack_start(hbox, True, True, 5) self.notebook = Gtk.Notebook() self.notebook.set_scrollable(True) self.notebook.connect('switch-page', self.pagesw) for title in self.titles: self.create_tab(title) hbox.pack_start(self.notebook, True, True, 3) hbox.pack_start(rvbox, True, True, 3) bbox = Gtk.ButtonBox(orientation=Gtk.Orientation.HORIZONTAL) vbox.pack_start(bbox, False, False, 5) close = Gtk.Button(label=_('Close')) close.set_tooltip_text(_('Close the Note Cleanup Tool')) close.connect('clicked', self.close) save = Gtk.Button(label=_('Save All')) save.set_tooltip_text(_('Save All Changes')) save.connect('clicked', self.saveit) search = Gtk.Button(label=_('Search')) search.set_tooltip_text(_('Search for Untidy Notes')) search.connect('clicked', self.cleanup) testnote = Gtk.Button(label=_('Generate Test Notes')) testnote.set_tooltip_text(_( 'Generate Test notes in range N99996-N99999.\n' 'These are added to your database, so you may want to work with' ' a test database or delete them later.')) testnote.connect('clicked', self.gentest) export = Gtk.Button(label=_('Export')) export.set_tooltip_text(_('Export the results to a text file')) export.connect('clicked', self.export_results) bbox.add(search) bbox.add(testnote) bbox.add(export) bbox.add(save) bbox.add(close) self.tb = StyledTextEditor() self.tb.set_editable(False) self.tb.set_wrap_mode(Gtk.WrapMode.WORD) tbw = Gtk.ScrolledWindow() tbw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) tbw.add(self.tb) rvbox.pack_start(tbw, True, True, 0) self.ta = StyledTextEditor() self.ta.set_transient_parent(window) self.ta.set_editable(True) self.ta.set_wrap_mode(Gtk.WrapMode.WORD) taw = Gtk.ScrolledWindow() taw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) taw.add(self.ta) # tat=self.ta.get_toolbar() tat, self.action_group = self.ta.create_toolbar( uistate.uimanager, window) tat.set_icon_size(Gtk.IconSize.SMALL_TOOLBAR) tatb = tat.get_nth_item(5) tat.remove(tatb) tatb = tat.get_nth_item(5) tat.remove(tatb) rvbox.pack_start(tat, False, False, 0) rvbox.pack_start(taw, True, True, 0) self.clear_models() vbox.show_all() window.add(vbox) window.set_size_request(800, 400) self.set_window(window, None, self.window_name) self.show() self.show_tabs() WarningDialog( self.window_name, _("Please back up your database before running this tool.\n\n" "Start the tool by pressing the 'Search' button, then review" " the results.\n" "When satisifed press the 'Save All' button to save your work.\n" "You may export a summary list of the notes that" " were found using the 'Export' button."), self.window)
def __init__(self, dbstate, user, options_class, name, callback=None): uistate = user.uistate tool.Tool.__init__(self, dbstate, options_class, name) self.window_name = _('Note Cleanup Tool') ManagedWindow.__init__(self, uistate, [], self.__class__) self.dbstate = dbstate self.trans = None self.moved_files = [] self.titles = [_('Cleaned Notes'), _('Links Only'), _('Issues')] self.models = [] self.views = [] self.changelist = [] self.changelistidx = 0 window = MyWindow(self.dbstate, self.uistate, []) vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) hbox.set_homogeneous(True) rvbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=2, width_request=400) vbox.pack_start(hbox, True, True, 5) self.notebook = Gtk.Notebook() self.notebook.set_scrollable(True) self.notebook.connect('switch-page', self.pagesw) for title in self.titles: self.create_tab(title) hbox.pack_start(self.notebook, True, True, 3) hbox.pack_start(rvbox, True, True, 3) bbox = Gtk.ButtonBox(orientation=Gtk.Orientation.HORIZONTAL) vbox.pack_start(bbox, False, False, 5) close = Gtk.Button(_('Close')) close.set_tooltip_text(_('Close the Note Cleanup Tool')) close.connect('clicked', self.close) save = Gtk.Button(_('Save All')) save.set_tooltip_text(_('Save All Changes')) save.connect('clicked', self.saveit) search = Gtk.Button(_('Search')) search.set_tooltip_text(_('Search for Untidy Notes')) search.connect('clicked', self.cleanup) testnote = Gtk.Button(_('Generate Test Notes')) testnote.set_tooltip_text(_( 'Generate Test notes in range N99996-N99999.\n' 'These are added to your database, so you may want to work with' ' a test database or delete them later.')) testnote.connect('clicked', self.gentest) export = Gtk.Button(_('Export')) export.set_tooltip_text(_('Export the results to a text file')) export.connect('clicked', self.export_results) bbox.add(search) bbox.add(testnote) bbox.add(export) bbox.add(save) bbox.add(close) self.tb = StyledTextEditor() self.tb.set_editable(False) self.tb.set_wrap_mode(Gtk.WrapMode.WORD) tbw = Gtk.ScrolledWindow() tbw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) tbw.add(self.tb) rvbox.pack_start(tbw, True, True, 0) self.ta = StyledTextEditor() self.ta.set_editable(True) self.ta.set_wrap_mode(Gtk.WrapMode.WORD) taw = Gtk.ScrolledWindow() taw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) taw.add(self.ta) tat=self.ta.get_toolbar() tat.set_icon_size(Gtk.IconSize.SMALL_TOOLBAR) tatb=tat.get_nth_item(5) tat.remove(tatb) tatb=tat.get_nth_item(5) tat.remove(tatb) rvbox.pack_start(tat, False, False, 0) rvbox.pack_start(taw, True, True, 0) self.clear_models() vbox.show_all() window.add(vbox) window.set_size_request(800, 400) self.set_window(window, None, self.window_name) self.show() self.show_tabs() WarningDialog(self.window_name, _("Please back up your database before running this tool.\n\n" "Start the tool by pressing the 'Search' button, then review" " the results.\n" "When satisifed press the 'Save All' button to save your work.\n" "You may export a summary list of the notes that" " were found using the 'Export' button."), self.window)
class ToDo(Gramplet): """ Displays the To Do notes for an object. """ def init(self): self.gui.WIDGET = self.build_gui() self.gui.get_container_widget().remove(self.gui.textview) self.gui.get_container_widget().add_with_viewport(self.gui.WIDGET) self.gui.WIDGET.show() def build_gui(self): """ Build the GUI interface. """ top = Gtk.VBox(homogeneous=False) hbox = Gtk.HBox() self.left = SimpleButton(Gtk.STOCK_GO_BACK, self.left_clicked) self.left.set_tooltip_text(_('Previous To Do note')) self.left.set_sensitive(False) hbox.pack_start(self.left, False, False, 0) self.right = SimpleButton(Gtk.STOCK_GO_FORWARD, self.right_clicked) self.right.set_tooltip_text(_('Next To Do note')) self.right.set_sensitive(False) hbox.pack_start(self.right, False, False, 0) self.edit = SimpleButton(Gtk.STOCK_EDIT, self.edit_clicked) self.edit.set_tooltip_text(_('Edit the selected To Do note')) self.edit.set_sensitive(False) hbox.pack_start(self.edit, False, False, 0) self.new = SimpleButton(Gtk.STOCK_NEW, self.new_clicked) self.new.set_tooltip_text(_('Add a new To Do note')) hbox.pack_start(self.new, False, False, 0) self.page = Gtk.Label() hbox.pack_end(self.page, False, False, 10) scrolledwindow = Gtk.ScrolledWindow() scrolledwindow.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) self.texteditor = StyledTextEditor() self.texteditor.set_editable(False) self.texteditor.set_wrap_mode(Gtk.WrapMode.WORD) scrolledwindow.add(self.texteditor) top.pack_start(hbox, False, False, 0) top.pack_start(scrolledwindow, True, True, 0) top.show_all() return top def get_note_list(self, obj): """ Get a list of To Do notes for the current object. """ note_list = [] for note_handle in obj.get_note_list(): note = self.dbstate.db.get_note_from_handle(note_handle) if int(note.get_type()) == NoteType.TODO: note_list.append(note.get_handle()) return note_list def get_notes(self, obj): """ Display the To Do notes for the current object. """ self.obj = obj self.left.set_sensitive(False) self.right.set_sensitive(False) self.edit.set_sensitive(False) self.texteditor.set_text(StyledText()) self.note_list = self.get_note_list(obj) self.page.set_text('') if len(self.note_list) > 0: self.set_has_data(True) self.edit.set_sensitive(True) if len(self.note_list) > 1: self.right.set_sensitive(True) self.current = 0 self.display_note() else: self.set_has_data(False) def clear_text(self): self.left.set_sensitive(False) self.right.set_sensitive(False) self.edit.set_sensitive(False) self.texteditor.set_text(StyledText()) self.page.set_text('') self.current = 0 def display_note(self): """ Display the current note. """ note_handle = self.note_list[self.current] note = self.dbstate.db.get_note_from_handle(note_handle) self.texteditor.set_text(note.get_styledtext()) self.page.set_text( _('%(current)d of %(total)d') % { 'current': self.current + 1, 'total': len(self.note_list) }) def left_clicked(self, button): """ Display the previous note. """ if self.current > 0: self.current -= 1 self.right.set_sensitive(True) if self.current == 0: self.left.set_sensitive(False) self.display_note() def right_clicked(self, button): """ Display the next note. """ if self.current < len(self.note_list) - 1: self.current += 1 self.left.set_sensitive(True) if self.current == len(self.note_list) - 1: self.right.set_sensitive(False) self.display_note() def get_has_data(self, obj): """ Return True if the gramplet has data, else return False. """ if obj is None: return False if self.get_note_list(obj): return True return False def edit_clicked(self, obj): """ Edit current To Do note. """ from gramps.gui.editors import EditNote note_handle = self.note_list[self.current] note = self.dbstate.db.get_note_from_handle(note_handle) try: EditNote(self.gui.dbstate, self.gui.uistate, [], note) except AttributeError: pass def new_clicked(self, obj): """ Create a new To Do note. """ from gramps.gui.editors import EditNote note = Note() note.set_type(NoteType.TODO) try: EditNote(self.gui.dbstate, self.gui.uistate, [], note, self.created) except AttributeError: pass
class ToDoGramplet(Gramplet): """ Displays all the To Do notes in the database. """ def init(self): self.gui.WIDGET = self.build_gui() self.gui.get_container_widget().remove(self.gui.textview) self.gui.get_container_widget().add(self.gui.WIDGET) self.gui.WIDGET.show() def build_gui(self): """ Build the GUI interface. """ top = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) hbox = Gtk.Box() self.left = SimpleButton('go-previous', self.left_clicked) self.left.set_tooltip_text(_('Previous To Do note')) self.left.set_sensitive(False) hbox.pack_start(self.left, False, False, 0) self.right = SimpleButton('go-next', self.right_clicked) self.right.set_tooltip_text(_('Next To Do note')) self.right.set_sensitive(False) hbox.pack_start(self.right, False, False, 0) self.edit = SimpleButton('gtk-edit', self.edit_clicked) self.edit.set_tooltip_text(_('Edit the selected To Do note')) self.edit.set_sensitive(False) hbox.pack_start(self.edit, False, False, 0) self.new = SimpleButton('document-new', self.new_clicked) self.new.set_tooltip_text(_('Add a new To Do note')) hbox.pack_start(self.new, False, False, 0) self.page = Gtk.Label() hbox.pack_end(self.page, False, False, 10) self.title = Gtk.Label(halign=Gtk.Align.START) self.title.set_line_wrap(True) scrolledwindow = Gtk.ScrolledWindow() scrolledwindow.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) self.texteditor = StyledTextEditor() self.texteditor.set_editable(False) self.texteditor.set_wrap_mode(Gtk.WrapMode.WORD) scrolledwindow.add(self.texteditor) top.pack_start(hbox, False, False, 0) top.pack_start(self.title, False, False, 4) top.pack_start(scrolledwindow, True, True, 0) top.show_all() return top def main(self): self.get_notes() def get_note_list(self): """ Get a list of all To Do notes. """ all_notes = self.dbstate.db.get_note_handles() FilterClass = GenericFilterFactory('Note') filter = FilterClass() filter.add_rule(rules.note.HasType(["To Do"])) note_list = filter.apply(self.dbstate.db, all_notes) return note_list def get_notes(self): """ Display all the To Do notes. """ self.left.set_sensitive(False) self.right.set_sensitive(False) self.edit.set_sensitive(False) self.texteditor.set_text(StyledText()) self.note_list = self.get_note_list() self.page.set_text('') self.title.set_text('') if len(self.note_list) > 0: self.set_has_data(True) self.edit.set_sensitive(True) if len(self.note_list) > 1: self.right.set_sensitive(True) self.current = 0 self.display_note() else: self.set_has_data(False) def clear_text(self): self.left.set_sensitive(False) self.right.set_sensitive(False) self.edit.set_sensitive(False) self.texteditor.set_text(StyledText()) self.page.set_text('') self.title.set_text('') self.current = 0 def display_note(self): """ Display the current note. """ note_handle = self.note_list[self.current] note = self.dbstate.db.get_note_from_handle(note_handle) obj = [x for x in self.dbstate.db.find_backlink_handles(note_handle)] if obj: name, obj = navigation_label(self.dbstate.db, obj[0][0], obj[0][1]) self.title.set_text(name) else: self.title.set_text(_("Unattached")) self.texteditor.set_text(note.get_styledtext()) self.page.set_text( _('%(current)d of %(total)d') % { 'current': self.current + 1, 'total': len(self.note_list) }) def left_clicked(self, button): """ Display the previous note. """ if self.current > 0: self.current -= 1 self.right.set_sensitive(True) if self.current == 0: self.left.set_sensitive(False) self.display_note() def right_clicked(self, button): """ Display the next note. """ if self.current < len(self.note_list) - 1: self.current += 1 self.left.set_sensitive(True) if self.current == len(self.note_list) - 1: self.right.set_sensitive(False) self.display_note() def get_has_data(self): """ Return True if the gramplet has data, else return False. """ if self.get_note_list(): return True return False def edit_clicked(self, obj): """ Edit current To Do note. """ from gramps.gui.editors import EditNote note_handle = self.note_list[self.current] note = self.dbstate.db.get_note_from_handle(note_handle) try: EditNote(self.gui.dbstate, self.gui.uistate, [], note) except AttributeError: pass def new_clicked(self, obj): """ Create a new To Do note. """ from gramps.gui.editors import EditNote note = Note() note.set_type(NoteType.TODO) try: EditNote(self.gui.dbstate, self.gui.uistate, [], note) except AttributeError: pass def update_has_data(self): self.set_has_data(self.get_has_data()) def db_changed(self): self.dbstate.db.connect('note-add', self.update) self.dbstate.db.connect('note-delete', self.update) self.dbstate.db.connect('note-update', self.update)
class ToDo(Gramplet): """ Displays the To Do notes for an object. """ def init(self): self.gui.WIDGET = self.build_gui() self.gui.get_container_widget().remove(self.gui.textview) self.gui.get_container_widget().add(self.gui.WIDGET) self.gui.WIDGET.show() def build_gui(self): """ Build the GUI interface. """ top = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) hbox = Gtk.Box() self.left = SimpleButton('go-previous', self.left_clicked) self.left.set_tooltip_text(_('Previous To Do note')) self.left.set_sensitive(False) hbox.pack_start(self.left, False, False, 0) self.right = SimpleButton('go-next', self.right_clicked) self.right.set_tooltip_text(_('Next To Do note')) self.right.set_sensitive(False) hbox.pack_start(self.right, False, False, 0) self.edit = SimpleButton('gtk-edit', self.edit_clicked) self.edit.set_tooltip_text(_('Edit the selected To Do note')) self.edit.set_sensitive(False) hbox.pack_start(self.edit, False, False, 0) self.new = SimpleButton('document-new', self.new_clicked) self.new.set_tooltip_text(_('Add a new To Do note')) hbox.pack_start(self.new, False, False, 0) self.page = Gtk.Label() hbox.pack_end(self.page, False, False, 10) scrolledwindow = Gtk.ScrolledWindow() scrolledwindow.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) self.texteditor = StyledTextEditor() self.texteditor.set_editable(False) self.texteditor.set_wrap_mode(Gtk.WrapMode.WORD) scrolledwindow.add(self.texteditor) top.pack_start(hbox, False, False, 0) top.pack_start(scrolledwindow, True, True, 0) top.show_all() return top def get_note_list(self, obj): """ Get a list of To Do notes for the current object. """ note_list = [] for note_handle in obj.get_note_list(): note = self.dbstate.db.get_note_from_handle(note_handle) if int(note.get_type()) == NoteType.TODO: note_list.append(note.get_handle()) return note_list def get_notes(self, obj): """ Display the To Do notes for the current object. """ self.obj = obj self.left.set_sensitive(False) self.right.set_sensitive(False) self.edit.set_sensitive(False) self.texteditor.set_text(StyledText()) self.note_list = self.get_note_list(obj) self.page.set_text('') if len(self.note_list) > 0: self.set_has_data(True) self.edit.set_sensitive(True) if len(self.note_list) > 1: self.right.set_sensitive(True) self.current = 0 self.display_note() else: self.set_has_data(False) def clear_text(self): self.left.set_sensitive(False) self.right.set_sensitive(False) self.edit.set_sensitive(False) self.texteditor.set_text(StyledText()) self.page.set_text('') self.current = 0 def display_note(self): """ Display the current note. """ note_handle = self.note_list[self.current] note = self.dbstate.db.get_note_from_handle(note_handle) self.texteditor.set_text(note.get_styledtext()) self.page.set_text(_('%(current)d of %(total)d') % {'current': self.current + 1, 'total': len(self.note_list)}) def left_clicked(self, button): """ Display the previous note. """ if self.current > 0: self.current -= 1 self.right.set_sensitive(True) if self.current == 0: self.left.set_sensitive(False) self.display_note() def right_clicked(self, button): """ Display the next note. """ if self.current < len(self.note_list) - 1: self.current += 1 self.left.set_sensitive(True) if self.current == len(self.note_list) - 1: self.right.set_sensitive(False) self.display_note() def get_has_data(self, obj): """ Return True if the gramplet has data, else return False. """ if obj is None: return False if self.get_note_list(obj): return True return False def edit_clicked(self, obj): """ Edit current To Do note. """ from gramps.gui.editors import EditNote note_handle = self.note_list[self.current] note = self.dbstate.db.get_note_from_handle(note_handle) try: EditNote(self.gui.dbstate, self.gui.uistate, [], note) except AttributeError: pass def new_clicked(self, obj): """ Create a new To Do note. """ from gramps.gui.editors import EditNote note = Note() note.set_type(NoteType.TODO) try: EditNote(self.gui.dbstate, self.gui.uistate, [], note, self.created) except AttributeError: pass
class WelcomeGramplet(Gramplet): """ Displays a welcome note to the user. """ def init(self): self.gui.WIDGET = self.build_gui() self.gui.get_container_widget().remove(self.gui.textview) self.gui.get_container_widget().add(self.gui.WIDGET) self.gui.WIDGET.show() def build_gui(self): """ Build the GUI interface. """ top = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) scrolledwindow = Gtk.ScrolledWindow() scrolledwindow.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) self.texteditor = StyledTextEditor() self.texteditor.set_editable(False) self.texteditor.set_wrap_mode(Gtk.WrapMode.WORD) scrolledwindow.add(self.texteditor) self.display_text() top.pack_start(scrolledwindow, True, True, 0) top.show_all() return top def display_text(self): """ Display the welcome text. """ welcome = boldst(_('Intro')) + '\n\n' welcome += _( 'Gramps is a software package designed for genealogical research.' ' Although similar to other genealogical programs, Gramps offers' ' some unique and powerful features.\n\n') welcome += linkst(_('Home Page'), URL_HOMEPAGE) + '\n\n' welcome += boldst(_('Who makes Gramps?')) + '\n\n' + _( 'Gramps is created by genealogists for genealogists, organized in' ' the Gramps Project. ' 'Gramps is an Open Source Software package, which means you are' ' free to make copies and distribute it to anyone you like. It\'s' ' developed and maintained by a worldwide team of volunteers whose' ' goal is to make Gramps powerful, yet easy to use.\n\n') welcome += _( 'There is an active community of users available on the mailing' ' lists and Discourse forum to share ideas and techniques.\n\n') welcome += linkst(_('Gramps online manual'), wiki( '', manual=True)) + '\n\n' welcome += linkst( _('Ask questions on gramps-users mailing list'), '%(gramps_home_url)scontact/' % {'gramps_home_url': URL_HOMEPAGE}) + '\n\n' welcome += linkst(_('Gramps Discourse Forum'), 'https://gramps.discourse.group/') + '\n\n' welcome += boldst(_('Getting Started')) + '\n\n' + _( 'The first time Gramps is started all of the Views are blank. There' ' are very few menu options. A Family Tree is needed for any activity' ' to happen.\n\n' 'To create a new Family Tree (sometimes called \'database\') select' ' "Family Trees" from the menu, pick "Manage Family Trees", press' ' "New" and name your Family Tree. "Load Family Tree" to make the' ' tree active and ready to accept data by entering your first' ' family, or importing a family tree. For more details, please' ' read the information at the links below.\n\n') welcome += linkst(_('Start with Genealogy and Gramps'), wiki('Start_with_Genealogy')) + '\n\n' welcome += boldst(_('Enter your first Family')) + '\n\n' + _( 'You will now want to start entering your first Family and that' ' starts with the first Person.\n\n' 'Switch to the "People" view and from the menu clicking "Add" and then' ' clicking "Person" (or using the [+] icon) will bring up the window' ' to enter a person. Entering the basic information and saving the' ' record gives you a starting point. Select this Person\'s record and' ' now switch to the "Relationships" view.\n\n' 'With this first person, all of the menu options and icon functions' ' have become available. Spend some time moving your mouse over the' ' icons. As your cursor passes over an icon, a message will appear' ' telling you the icon\'s function. The same is true for any of the' ' edit windows. Moving the mouse cursor over an item will tell you' ' what it will do.\n\n' 'You can now create families by adding parents, a spouse and children.' ' Once started, you will be able to add Events to People and Families.' ' You can provide Sources and Citations to provide documentation for' ' your entries.\n\n' 'As you start using Gramps, you will find that information can be' ' entered from all the various Views. There are multiple ways of' ' doing most activities in Gramps. The flexibility allows you to' ' choose which fits your work style.\n\n') welcome += linkst( _('Entering and editing data (brief)'), wiki('_-_Entering_and_editing_data:_brief', manual=True)) + '\n\n' welcome += boldst(_('Importing a Family Tree')) + '\n\n' + _( 'To import a Family Tree from another program first create' ' a GEDCOM (or other data) file from the previous program.\n\n' 'Once you have created a new Gramps database file, use the "Import"' ' option under the "Family Trees" menu to import the GEDCOM data.\n\n' ) welcome += linkst( _('Import from another genealogy program'), wiki('Import_from_another_genealogy_program')) + '\n\n' welcome += boldst(_('Dashboard View')) + '\n\n' + _( 'You are currently reading from the "Dashboard" view, where you can' ' add your own gramplets. You can also add gramplets to any view by' ' adding a sidebar and/or bottombar, and right-clicking to the' ' right of the tab.\n\n' 'You can click the configuration icon in the toolbar to add' ' additional columns, while right-click on the background allows to' ' add gramplets. You can also drag the Properties button to' ' reposition the gramplet on this page, and detach the gramplet to' ' float above Gramps.') welcome += '\n\n' welcome += linkst(_('Gramps View Categories'), wiki('_-_Categories', manual=True)) + '\n\n' welcome += boldst(_('Addons and "Gramplets"')) + '\n\n' + _( 'There many Addons or "Gramplets" that are available to assist you' ' in data entry and visualizing your family tree. Many of these tools' ' are already available to you. Many more are available to download' ' and install.\n\n') welcome += linkst(_('Addons and "Gramplets"'), wiki(WIKI_EXTRAPLUGINS)) + '\n\n' welcome += boldst(_('Example Database')) + '\n\n' + _( 'Want to see Gramps in use. Create and Import the Example database.\n\n' 'Create a new Family Tree as described above. Suggest that you name' ' the Family Tree “EXAMPLE”.\n\n' 'Import the Gramps file example.gramps.\n\n' 'Follow the instructions for the location of the file stored with' ' the Gramps program.\n\n') welcome += linkst(_('Example.gramps'), wiki('Example.gramps')) + '\n\n' self.texteditor.set_text(welcome) def get_has_data(self, obj): """ Return True if the gramplet has data, else return False. """ return True