gramps/gramps/gui/widgets/styledtexteditor.py
Benny Malengier bb5fc7cb7c 2620: GEPS 031: Python 3 support - 3.2
This does patch updates Gramps to the 3.2 syntax, it does not yet mean Gramps works with python 3.2
Expect next day commits to fix further issues, but this is the main 2to3 tool created patch changed
where needed to have python 2.7 work. 
Specific issues might be:
  1. next has been changed, must be checked
  2. new division as on the wiki page listed is to do
  3. ...


svn: r20634
2012-11-07 17:53:14 +00:00

859 lines
33 KiB
Python

#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2008 Zsolt Foldvari
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# $Id$
"Text editor subclassed from Gtk.TextView handling L{StyledText}."
__all__ = ["StyledTextEditor"]
#-------------------------------------------------------------------------
#
# Python modules
#
#-------------------------------------------------------------------------
from gramps.gen.ggettext import gettext as _
import logging
_LOG = logging.getLogger(".widgets.styledtexteditor")
#-------------------------------------------------------------------------
#
# GTK libraries
#
#-------------------------------------------------------------------------
from gi.repository import GObject
from gi.repository import Gdk
from gi.repository import Gtk
from gi.repository import Pango
#-------------------------------------------------------------------------
#
# GRAMPS modules
#
#-------------------------------------------------------------------------
from gramps.gen.lib import StyledTextTagType
from .styledtextbuffer import (ALLOWED_STYLES,
MATCH_START, MATCH_END,
MATCH_FLAVOR, MATCH_STRING,
LinkTag)
from .undoablestyledbuffer import UndoableStyledBuffer
from .valueaction import ValueAction
from .toolcomboentry import ToolComboEntry
from .springseparator import SpringSeparatorAction
from ..spell import Spell
from ..display import display_url
from ..utils import SystemFonts, rgb_to_hex, hex_to_color, color_to_hex
from gramps.gen.config import config
from gramps.gen.constfunc import has_display
#-------------------------------------------------------------------------
#
# Constants
#
#-------------------------------------------------------------------------
if has_display():
HAND_CURSOR = Gdk.Cursor.new(Gdk.CursorType.HAND2)
REGULAR_CURSOR = Gdk.Cursor.new(Gdk.CursorType.XTERM)
FORMAT_TOOLBAR = '''
<ui>
<toolbar name="ToolBar">
<toolitem action="%d"/>
<toolitem action="%d"/>
<toolitem action="%d"/>
<toolitem action="Undo"/>
<toolitem action="Redo"/>
<toolitem action="%d"/>
<toolitem action="%d"/>
<toolitem action="%d"/>
<toolitem action="%d"/>
<toolitem action="%d"/>
<toolitem action="spring"/>
<toolitem action="clear"/>
</toolbar>
</ui>
''' % (StyledTextTagType.ITALIC,
StyledTextTagType.BOLD,
StyledTextTagType.UNDERLINE,
StyledTextTagType.FONTFACE,
StyledTextTagType.FONTSIZE,
StyledTextTagType.FONTCOLOR,
StyledTextTagType.HIGHLIGHT,
StyledTextTagType.LINK,
)
FONT_SIZES = [8, 9, 10, 11, 12, 13, 14, 16, 18, 20, 22,
24, 26, 28, 32, 36, 40, 48, 56, 64, 72]
USERCHARS = "-A-Za-z0-9"
PASSCHARS = "-A-Za-z0-9,?;.:/!%$^*&~\"#'"
HOSTCHARS = "-A-Za-z0-9"
PATHCHARS = "-A-Za-z0-9_$.+!*(),;:@&=?/~#%"
#SCHEME = "(news:|telnet:|nntp:|file:/|https?:|ftps?:|webcal:)"
SCHEME = "(file:/|https?:|ftps?:|webcal:)"
USER = "[" + USERCHARS + "]+(:[" + PASSCHARS + "]+)?"
URLPATH = "/[" + PATHCHARS + "]*[^]'.}>) \t\r\n,\\\"]"
(GENURL, HTTP, MAIL, LINK) = list(range(4))
def find_parent_with_attr(self, attr="dbstate"):
"""
"""
# Find a parent with attr:
obj = self
while obj:
if hasattr(obj, attr):
break
obj = obj.get_parent()
return obj
#-------------------------------------------------------------------------
#
# StyledTextEditor
#
#-------------------------------------------------------------------------
class StyledTextEditor(Gtk.TextView):
"""StyledTextEditor is an enhanced Gtk.TextView to edit L{StyledText}.
StyledTextEditor is a gui object for L{StyledTextBuffer}. It offers
L{set_text} and L{get_text} convenience methods to set and get the
buffer's text.
StyledTextEditor provides a formatting toolbar, which can be retrieved
by the L{get_toolbar} method.
StyledTextEdit defines a new signal: 'match-changed', which is raised
whenever the mouse cursor reaches or leaves a matched string in the text.
The feature uses the regexp pattern mathing mechanism of
L{StyledTextBuffer}.
The signal's default handler highlights the URL strings. URL's can be
followed from the editor's popup menu or by pressing the <CTRL>Left
mouse button.
@ivar last_match: previously matched string, used for generating the
'match-changed' signal.
@type last_match: tuple or None
@ivar match: currently matched string, used for generating the
'match-changed' signal.
@type match: tuple or None
@ivar show_unicode: stores the user's Gtk.settings['gtk-show-unicode-menu']
value.
@type show_unicode: bool
@ivar spellcheck: spell checker object created for the editor instance.
@type spellcheck: L{Spell}
@ivar textbuffer: text buffer assigned to the edit instance.
@type textbuffer: L{StyledTextBuffer}
@ivar toolbar: toolbar to be used for text formatting.
@type toolbar: Gtk.Toolbar
@ivar url_match: stores the matched URL and other mathing parameters.
@type url_match: tuple or None
"""
__gtype_name__ = 'StyledTextEditor'
__gsignals__ = {
'match-changed': (GObject.SignalFlags.RUN_FIRST,
None, #return value
(GObject.TYPE_PYOBJECT,)), # arguments
}
def __init__(self):
"""Setup initial instance variable values."""
self.textbuffer = UndoableStyledBuffer()
self.textbuffer.connect('style-changed', self._on_buffer_style_changed)
self.textbuffer.connect('changed', self._on_buffer_changed)
GObject.GObject.__init__(self, buffer=self.textbuffer)
st_cont = self.get_style_context()
col = st_cont.lookup_color('link_color')
if col[0]:
self.linkcolor = rgb_to_hex((col[1].red, col[1].green, col[1].blue))
else:
self.linkcolor = 'blue'
self.textbuffer.linkcolor = self.linkcolor
self.match = None
self.last_match = None
self._init_url_match()
self.url_match = None
self.toolbar = self._create_toolbar()
self.spellcheck = Spell(self)
self._internal_style_change = False
self._connect_signals()
# we want to disable the unicode menu in the popup
settings = Gtk.Settings.get_default()
self.show_unicode = settings.get_property('gtk-show-unicode-menu')
settings.set_property('gtk-show-unicode-menu', False)
# variable to not copy to clipboard on double/triple click
self.selclick = False
# virtual methods
def do_match_changed(self, match):
"""Default signal handler.
URL highlighting.
@param match: the new match parameters
@type match: tuple or None
@attention: Do not override the handler, but connect to the signal.
"""
window = self.get_window(Gtk.TextWindowType.TEXT)
start, end = self.textbuffer.get_bounds()
self.textbuffer.remove_tag_by_name('hyperlink', start, end)
if match and (match[MATCH_FLAVOR] in (GENURL, HTTP, MAIL)):
start_offset = match[MATCH_START]
end_offset = match[MATCH_END]
start = self.textbuffer.get_iter_at_offset(start_offset)
end = self.textbuffer.get_iter_at_offset(end_offset)
self.textbuffer.apply_tag_by_name('hyperlink', start, end)
window.set_cursor(HAND_CURSOR)
self.url_match = match
elif match and (match[MATCH_FLAVOR] in (LINK,)):
window.set_cursor(HAND_CURSOR)
self.url_match = match
else:
window.set_cursor(REGULAR_CURSOR)
self.url_match = None
def on_unrealize(self, widget):
"""Signal handler.
Set the default Gtk settings back before leaving.
"""
settings = Gtk.Settings.get_default()
settings.set_property('gtk-show-unicode-menu', self.show_unicode)
def on_key_press_event(self, widget, event):
"""Signal handler.
Handle formatting shortcuts.
"""
if ((Gdk.keyval_name(event.keyval) == 'Z') and
(event.get_state() & Gdk.ModifierType.CONTROL_MASK) and
(event.get_state() & Gdk.ModifierType.SHIFT_MASK)):
self.redo()
return True
elif ((Gdk.keyval_name(event.keyval) == 'z') and
(event.get_state() & Gdk.ModifierType.CONTROL_MASK)):
self.undo()
return True
else:
for accel, accel_name in self.action_accels.items():
key, mod = Gtk.accelerator_parse(accel)
if ((event.keyval == key) and (event.get_state() & mod)):
action_name = accel_name
action = self.action_group.get_action(action_name)
action.activate()
return True
return False
def on_insert_at_cursor(self, widget, string):
"""Signal handler. for debugging only."""
_LOG.debug("Textview insert '%s'" % string)
def on_delete_from_cursor(self, widget, mode, count):
"""Signal handler. for debugging only."""
_LOG.debug("Textview delete type %d count %d" % (mode, count))
def on_paste_clipboard(self, widget):
"""Signal handler. for debugging only."""
_LOG.debug("Textview paste clipboard")
def on_motion_notify_event(self, widget, event):
"""Signal handler.
As the mouse cursor moves the handler checks if there's a new
regexp match at the new location. If match changes the
'match-changed' signal is raised.
"""
x, y = self.window_to_buffer_coords(Gtk.TextWindowType.WIDGET,
int(event.x), int(event.y))
iter_at_location = self.get_iter_at_location(x, y)
self.match = self.textbuffer.match_check(iter_at_location.get_offset())
tooltip = None
if not self.match:
for tag in (tag for tag in iter_at_location.get_tags()
if tag.get_property('name').startswith("link")):
self.match = (x, y, LINK, tag.data, tag)
tooltip = self.make_tooltip_from_link(tag)
break
if self.match != self.last_match:
self.emit('match-changed', self.match)
self.last_match = self.match
self.get_root_window().get_pointer()
if tooltip:
self.set_tooltip_text(tooltip)
return False
def make_tooltip_from_link(self, link_tag):
"""
Return a string useful for a tooltip given a LinkTag object.
"""
from gramps.gen.simple import SimpleAccess
win_obj = find_parent_with_attr(self, attr="dbstate")
display = link_tag.data
if win_obj:
simple_access = SimpleAccess(win_obj.dbstate.db)
url = link_tag.data
if url.startswith("gramps://"):
obj_class, prop, value = url[9:].split("/")
display = simple_access.display(obj_class, prop, value) or url
return display
def on_button_release_event(self, widget, event):
"""
Copy selection to clipboard for left click if selection given
"""
if (event.type == Gdk.EventType.BUTTON_RELEASE and self.selclick and
event.button == 1):
bounds = self.textbuffer.get_selection_bounds()
if bounds:
clip = Gtk.Clipboard.get_for_display(Gdk.Display.get_default(),
Gdk.SELECTION_PRIMARY)
clip.set_text(str(self.textbuffer.get_text(bounds[0],
bounds[1], True)), -1)
return False
def on_button_press_event(self, widget, event):
"""Signal handler.
Handles the <CTRL> + Left click over a URL match.
"""
self.selclick=False
if ((event.type == Gdk.EventType.BUTTON_PRESS) and
(event.button == 1) and
(event.get_state() and Gdk.ModifierType.CONTROL_MASK) and
(self.url_match)):
flavor = self.url_match[MATCH_FLAVOR]
url = self.url_match[MATCH_STRING]
self._open_url_cb(None, url, flavor)
elif (event.type == Gdk.EventType.BUTTON_PRESS and event.button == 1) :
#on release we will copy selected data to clipboard
self.selclick = True
#propagate click
return False
def on_populate_popup(self, widget, menu):
"""Signal handler.
Insert extra menuitems:
1. Insert spellcheck selector submenu for spell checking.
2. Insert extra menus depending on ULR match result.
"""
# spell checker submenu
spell_menu = Gtk.MenuItem(label=_('Spellcheck'))
spell_menu.set_submenu(self._create_spell_menu())
spell_menu.show_all()
menu.prepend(spell_menu)
search_menu = Gtk.MenuItem(label=_("Search selection on web"))
search_menu.connect('activate', self.search_web)
search_menu.show_all()
menu.append(search_menu)
# url menu items
if self.url_match:
flavor = self.url_match[MATCH_FLAVOR]
url = self.url_match[MATCH_STRING]
if flavor == MAIL:
open_menu = Gtk.MenuItem(label=_('_Send Mail To...'))
copy_menu = Gtk.MenuItem(label=_('Copy _E-mail Address'))
else:
open_menu = Gtk.MenuItem(label=_('_Open Link'))
copy_menu = Gtk.MenuItem(label=_('Copy _Link Address'))
if flavor == LINK:
edit_menu = Gtk.MenuItem(label=_('_Edit Link'))
edit_menu.connect('activate', self._edit_url_cb,
self.url_match[-1], # tag
)
edit_menu.show()
menu.prepend(edit_menu)
copy_menu.connect('activate', self._copy_url_cb, url, flavor)
copy_menu.show()
menu.prepend(copy_menu)
open_menu.connect('activate', self._open_url_cb, url, flavor)
open_menu.show()
menu.prepend(open_menu)
def search_web(self, widget):
"""
Search the web for selected text.
"""
selection = self.textbuffer.get_selection_bounds()
if len(selection) > 0:
display_url(config.get("behavior.web-search-url") %
{'text':
self.textbuffer.get_text(selection[0],
selection[1], True)})
def reset(self):
"""
Reset the undoable buffer
"""
self.textbuffer.reset()
self.undo_action.set_sensitive(False)
self.redo_action.set_sensitive(False)
# private methods
def _connect_signals(self):
"""Connect to several signals of the super class Gtk.TextView."""
self.connect('key-press-event', self.on_key_press_event)
self.connect('insert-at-cursor', self.on_insert_at_cursor)
self.connect('delete-from-cursor', self.on_delete_from_cursor)
self.connect('paste-clipboard', self.on_paste_clipboard)
self.connect('motion-notify-event', self.on_motion_notify_event)
self.connect('button-press-event', self.on_button_press_event)
self.connect('button-release-event', self.on_button_release_event)
self.connect('populate-popup', self.on_populate_popup)
self.connect('unrealize', self.on_unrealize)
def _create_toolbar(self):
"""Create a formatting toolbar.
@returns: toolbar containing text formatting toolitems.
@returntype: Gtk.Toolbar
"""
# define the actions...
# ...first the toggle actions, which have a ToggleToolButton as proxy
format_toggle_actions = [
(str(StyledTextTagType.ITALIC), Gtk.STOCK_ITALIC, None, None,
_('Italic'), self._on_toggle_action_activate),
(str(StyledTextTagType.BOLD), Gtk.STOCK_BOLD, None, None,
_('Bold'), self._on_toggle_action_activate),
(str(StyledTextTagType.UNDERLINE), Gtk.STOCK_UNDERLINE, None, None,
_('Underline'), self._on_toggle_action_activate),
]
self.toggle_actions = [action[0] for action in format_toggle_actions]
# ...then the normal actions, which have a ToolButton as proxy
format_actions = [
(str(StyledTextTagType.FONTCOLOR), 'gramps-font-color', None, None,
_('Font Color'), self._on_action_activate),
(str(StyledTextTagType.HIGHLIGHT), 'gramps-font-bgcolor', None, None,
_('Background Color'), self._on_action_activate),
(str(StyledTextTagType.LINK), Gtk.STOCK_JUMP_TO, None, None,
_('Link'), self._on_link_activate),
('clear', Gtk.STOCK_CLEAR, None, None,
_('Clear Markup'), self._format_clear_cb),
]
# ...last the custom actions, which have custom proxies
default = StyledTextTagType.STYLE_DEFAULT[StyledTextTagType.FONTFACE]
fonts = SystemFonts()
fontface_action = ValueAction(str(StyledTextTagType.FONTFACE),
_("Font family"),
default,
ToolComboEntry,
fonts.get_system_fonts(),
False, #editable
True, #shortlist
None) # validator
fontface_action.connect('changed', self._on_valueaction_changed)
items = FONT_SIZES
default = StyledTextTagType.STYLE_DEFAULT[StyledTextTagType.FONTSIZE]
fontsize_action = ValueAction(str(StyledTextTagType.FONTSIZE),
_("Font size"),
default,
ToolComboEntry,
items,
True, #editable
False, #shortlist
is_valid_fontsize) #validator
fontsize_action.connect('changed', self._on_valueaction_changed)
spring = SpringSeparatorAction("spring", "", "", None)
# action accelerators
self.action_accels = {
'<PRIMARY>i': str(StyledTextTagType.ITALIC),
'<PRIMARY>b': str(StyledTextTagType.BOLD),
'<PRIMARY>u': str(StyledTextTagType.UNDERLINE),
}
# create the action group and insert all the actions
self.action_group = Gtk.ActionGroup('Format')
self.action_group.add_toggle_actions(format_toggle_actions)
self.undo_action = Gtk.Action("Undo", _('Undo'), _('Undo'),
Gtk.STOCK_UNDO)
self.undo_action.connect('activate', self.undo)
self.redo_action = Gtk.Action("Redo", _('Redo'), _('Redo'),
Gtk.STOCK_REDO)
self.redo_action.connect('activate', self.redo)
self.action_group.add_action(self.undo_action)
self.action_group.add_action(self.redo_action)
self.action_group.add_actions(format_actions)
self.action_group.add_action(fontface_action)
self.action_group.add_action(fontsize_action)
self.action_group.add_action(spring)
# define the toolbar and create the proxies via ensure_update()
uimanager = Gtk.UIManager()
uimanager.insert_action_group(self.action_group, 0)
uimanager.add_ui_from_string(FORMAT_TOOLBAR)
uimanager.ensure_update()
# get the toolbar and set it's style
toolbar = uimanager.get_widget('/ToolBar')
toolbar.set_style(Gtk.ToolbarStyle.ICONS)
self.undo_action.set_sensitive(False)
self.redo_action.set_sensitive(False)
return toolbar
def _init_url_match(self):
"""Setup regexp matching for URL match."""
self.textbuffer.create_tag('hyperlink',
underline=Pango.Underline.SINGLE,
foreground=self.linkcolor)
self.textbuffer.match_add(SCHEME + "//(" + USER + "@)?[" +
HOSTCHARS + ".]+" + "(:[0-9]+)?(" +
URLPATH + ")?/?", GENURL)
self.textbuffer.match_add("(www|ftp)[" + HOSTCHARS + "]*\\.[" +
HOSTCHARS + ".]+" + "(:[0-9]+)?(" +
URLPATH + ")?/?", HTTP)
self.textbuffer.match_add("(mailto:)?[a-z0-9][a-z0-9.-]*@[a-z0-9]"
"[a-z0-9-]*(\\.[a-z0-9][a-z0-9-]*)+", MAIL)
def _create_spell_menu(self):
"""Create a menu with all the installed spellchecks.
It is called each time the popup menu is opened. Each spellcheck
forms a radio menu item, and the selected spellcheck is set as active.
@returns: menu containing all the installed spellchecks.
@returntype: Gtk.Menu
"""
active_spellcheck = self.spellcheck.get_active_spellcheck()
menu = Gtk.Menu()
group = None
for lang in self.spellcheck.get_all_spellchecks():
menuitem = Gtk.RadioMenuItem(label=lang)
menuitem.set_active(lang == active_spellcheck)
menuitem.connect('activate', self._spell_change_cb, lang)
menu.append(menuitem)
if group is None:
group = menuitem
return menu
# Callback functions
def _on_toggle_action_activate(self, action):
"""Toggle a style.
Toggle styles are e.g. 'bold', 'italic', 'underline'.
"""
if self._internal_style_change:
return
style = int(action.get_name())
value = action.get_active()
_LOG.debug("applying style '%d' with value '%s'" % (style, str(value)))
self.textbuffer.apply_style(style, value)
def _on_link_activate(self, action):
"""
Create a link of a selected region of text.
"""
# Send in a default link. Could be based on active person.
selection_bounds = self.textbuffer.get_selection_bounds()
if selection_bounds:
# Paste text to clipboards
text = str(self.textbuffer.get_text(selection_bounds[0],
selection_bounds[1], True))
clipboard = Gtk.Clipboard.get_for_display(Gdk.Display.get_default(),
Gdk.SELECTION_CLIPBOARD)
clipboard.set_text(text, -1)
clipboard = Gtk.Clipboard.get_for_display(Gdk.Display.get_default(),
Gdk.SELECTION_PRIMARY)
clipboard.set_text(text, -1)
uri_dialog(self, None, self.setlink_callback)
def setlink_callback(self, uri, tag=None):
"""
Callback for setting or editing a link's object.
"""
if uri:
_LOG.debug("applying style 'link' with value '%s'" % uri)
if not tag:
tag = LinkTag(self.textbuffer,
data=uri,
underline=Pango.Underline.SINGLE,
foreground=self.linkcolor)
selection_bounds = self.textbuffer.get_selection_bounds()
self.textbuffer.apply_tag(tag,
selection_bounds[0],
selection_bounds[1])
else:
tag.data = uri
def _on_action_activate(self, action):
"""Apply a format set from a Gtk.Action type of action."""
style = int(action.get_name())
current_value = self.textbuffer.get_style_at_cursor(style)
if style == StyledTextTagType.FONTCOLOR:
color_dialog = Gtk.ColorSelectionDialog(_("Select font color"))
elif style == StyledTextTagType.HIGHLIGHT:
color_dialog = Gtk.ColorSelectionDialog(_("Select "
"background color"))
else:
_LOG.debug("unknown style: '%d'" % style)
return
color_selection = color_dialog.get_color_selection()
if current_value:
color_selection.set_current_color(hex_to_color(current_value))
response = color_dialog.run()
color = color_selection.get_current_color()
value = color_to_hex(color)
color_dialog.destroy()
if response == Gtk.ResponseType.OK:
_LOG.debug("applying style '%d' with value '%s'" %
(style, str(value)))
self.textbuffer.apply_style(style, value)
def _on_valueaction_changed(self, action):
"""Apply a format set by a ValueAction type of action."""
if self._internal_style_change:
return
style = int(action.get_name())
value = action.get_value()
try:
value = StyledTextTagType.STYLE_TYPE[style](value)
_LOG.debug("applying style '%d' with value '%s'" %
(style, str(value)))
self.textbuffer.apply_style(style, value)
except ValueError:
_LOG.debug("unable to convert '%s' to '%s'" %
(text, StyledTextTagType.STYLE_TYPE[style]))
def _format_clear_cb(self, action):
"""
Remove all formats from the selection or from all.
Remove only our own tags without touching other ones (e.g. Gtk.Spell),
thus remove_all_tags() can not be used.
"""
clear_anything = self.textbuffer.clear_selection()
if not clear_anything:
for style in ALLOWED_STYLES:
self.textbuffer.remove_style(style)
start, end = self.textbuffer.get_bounds()
tags = self.textbuffer._get_tag_from_range(start.get_offset(),
end.get_offset())
for tag_name, tag_data in tags.items():
if tag_name.startswith("link"):
for start, end in tag_data:
self.textbuffer.remove_tag_by_name(tag_name,
self.textbuffer.get_iter_at_offset(start),
self.textbuffer.get_iter_at_offset(end+1))
def _on_buffer_changed(self, buffer):
"""synchronize the undo/redo buttons with what is possible"""
self.undo_action.set_sensitive(self.textbuffer.can_undo)
self.redo_action.set_sensitive(self.textbuffer.can_redo)
def _on_buffer_style_changed(self, buffer, changed_styles):
"""Synchronize actions as the format changes at the buffer's cursor."""
for style, style_value in changed_styles.items():
if str(style) in self.toggle_actions:
action = self.action_group.get_action(str(style))
self._internal_style_change = True
action.set_active(style_value)
self._internal_style_change = False
if ((style == StyledTextTagType.FONTFACE) or
(style == StyledTextTagType.FONTSIZE)):
action = self.action_group.get_action(str(style))
self._internal_style_change = True
action.set_value(style_value)
self._internal_style_change = False
def _spell_change_cb(self, menuitem, spellcheck):
"""Set spell checker spellcheck according to user selection."""
self.spellcheck.set_active_spellcheck(spellcheck)
def _open_url_cb(self, menuitem, url, flavor):
"""Open the URL in a browser."""
if not url:
return
if flavor == HTTP:
url = 'http:' + url
elif flavor == MAIL:
if not url.startswith('mailto:'):
url = 'mailto:' + url
elif flavor == GENURL:
pass
elif flavor == LINK:
# gramps://person/id/VALUE
# gramps://person/handle/VALUE
if url.startswith("gramps://"):
# if in a window:
win_obj = find_parent_with_attr(self, attr="dbstate")
if win_obj:
# Edit the object:
obj_class, prop, value = url[9:].split("/")
from ..editors import EditObject
EditObject(win_obj.dbstate,
win_obj.uistate,
win_obj.track,
obj_class, prop, value)
return
else:
return
# If ok, then let's open
obj = find_parent_with_attr(self, attr="dbstate")
display_url(url, obj.uistate)
def _copy_url_cb(self, menuitem, url, flavor):
"""Copy url to both useful selections."""
clipboard = Gtk.Clipboard.get_for_display(Gdk.Display.get_default(),
Gdk.SELECTION_CLIPBOARD)
clipboard.set_text(url, -1)
clipboard = Gtk.Clipboard.get_for_display(Gdk.Display.get_default(),
Gdk.SELECTION_PRIMARY)
clipboard.set_text(url, -1)
def _edit_url_cb(self, menuitem, link_tag):
"""
Edit the URI of the link.
"""
# Paste text to clipboards
bounds = self.textbuffer.get_selection_bounds()
if bounds:
text = str(self.textbuffer.get_text(bounds[0], bounds[1], True))
clipboard = Gtk.Clipboard.get_for_display(Gdk.Display.get_default(),
Gdk.SELECTION_CLIPBOARD)
clipboard.set_text(text, -1)
clipboard = Gtk.Clipboard.get_for_display(Gdk.Display.get_default(),
Gdk.SELECTION_PRIMARY)
clipboard.set_text(text, -1)
uri_dialog(self, link_tag.data,
lambda uri: self.setlink_callback(uri, link_tag))
# public methods
def set_text(self, text):
"""Set the text of the text buffer of the editor.
@param text: formatted text to edit in the view.
@type text: L{StyledText}
"""
self.textbuffer.set_text(text)
self.textbuffer.place_cursor(self.textbuffer.get_start_iter())
def get_text(self):
"""Get the text of the text buffer of the editor.
@returns: the formatted text from the editor.
@returntype: L{StyledText}
"""
start, end = self.textbuffer.get_bounds()
return self.textbuffer.get_text(start, end, True)
def get_toolbar(self):
"""Get the formatting toolbar of the editor.
@returns: toolbar widget to use as formatting GUI.
@returntype: Gtk.Toolbar
"""
return self.toolbar
def undo(self, obj=None):
self.textbuffer.undo()
def redo(self, obj=None):
self.textbuffer.redo()
def uri_dialog(self, uri, callback):
"""
Function to spawn the link editor.
"""
from ..editors.editlink import EditLink
obj = find_parent_with_attr(self, attr="dbstate")
if obj:
if uri is None:
# make a default link
uri = "http://"
# Check in order for an open page:
for object_class in ["Person", "Place", "Event", "Family",
"Repository", "Source", "Media"]:
handle = obj.uistate.get_active(object_class)
if handle:
uri = "gramps://%s/handle/%s" % (object_class, handle)
EditLink(obj.dbstate, obj.uistate, obj.track, uri, callback)
#-------------------------------------------------------------------------
#
# Module functions
#
#-------------------------------------------------------------------------
def is_valid_fontsize(size):
"""Validator function for font size selector widget."""
return (size > 0) and (size < 73)