3914: Add a new markup for creating links to URLs and for gramps objects
svn: r15340
This commit is contained in:
@ -213,6 +213,7 @@ src/gui/editors/editeventref.py
|
|||||||
src/gui/editors/editfamily.py
|
src/gui/editors/editfamily.py
|
||||||
src/gui/editors/editldsord.py
|
src/gui/editors/editldsord.py
|
||||||
src/gui/editors/editlocation.py
|
src/gui/editors/editlocation.py
|
||||||
|
src/gui/editors/editlink.py
|
||||||
src/gui/editors/editmedia.py
|
src/gui/editors/editmedia.py
|
||||||
src/gui/editors/editmediaref.py
|
src/gui/editors/editmediaref.py
|
||||||
src/gui/editors/editname.py
|
src/gui/editors/editname.py
|
||||||
@ -839,6 +840,7 @@ src/glade/editrepository.glade
|
|||||||
src/glade/editreporef.glade
|
src/glade/editreporef.glade
|
||||||
src/glade/editpersonref.glade
|
src/glade/editpersonref.glade
|
||||||
src/glade/editlocation.glade
|
src/glade/editlocation.glade
|
||||||
|
src/glade/editlink.glade
|
||||||
src/glade/editfamily.glade
|
src/glade/editfamily.glade
|
||||||
src/glade/editchildref.glade
|
src/glade/editchildref.glade
|
||||||
src/glade/editattribute.glade
|
src/glade/editattribute.glade
|
||||||
|
@ -56,6 +56,7 @@ class StyledTextTagType(GrampsType):
|
|||||||
FONTCOLOR = 5
|
FONTCOLOR = 5
|
||||||
HIGHLIGHT = 6
|
HIGHLIGHT = 6
|
||||||
SUPERSCRIPT = 7
|
SUPERSCRIPT = 7
|
||||||
|
LINK = 8
|
||||||
|
|
||||||
_CUSTOM = NONE_TYPE
|
_CUSTOM = NONE_TYPE
|
||||||
_DEFAULT = NONE_TYPE
|
_DEFAULT = NONE_TYPE
|
||||||
@ -69,6 +70,7 @@ class StyledTextTagType(GrampsType):
|
|||||||
(FONTCOLOR, _("Fontcolor"), "fontcolor"),
|
(FONTCOLOR, _("Fontcolor"), "fontcolor"),
|
||||||
(HIGHLIGHT, _("Highlight"), "highlight"),
|
(HIGHLIGHT, _("Highlight"), "highlight"),
|
||||||
(SUPERSCRIPT, _("Superscript"), "superscript"),
|
(SUPERSCRIPT, _("Superscript"), "superscript"),
|
||||||
|
(LINK, _("Link"), "link"),
|
||||||
]
|
]
|
||||||
|
|
||||||
STYLE_TYPE = {
|
STYLE_TYPE = {
|
||||||
@ -80,6 +82,7 @@ class StyledTextTagType(GrampsType):
|
|||||||
FONTFACE: str,
|
FONTFACE: str,
|
||||||
FONTSIZE: int,
|
FONTSIZE: int,
|
||||||
SUPERSCRIPT: bool,
|
SUPERSCRIPT: bool,
|
||||||
|
LINK: str,
|
||||||
}
|
}
|
||||||
|
|
||||||
STYLE_DEFAULT = {
|
STYLE_DEFAULT = {
|
||||||
@ -91,6 +94,7 @@ class StyledTextTagType(GrampsType):
|
|||||||
FONTFACE: 'Sans',
|
FONTFACE: 'Sans',
|
||||||
FONTSIZE: 10,
|
FONTSIZE: 10,
|
||||||
SUPERSCRIPT: False,
|
SUPERSCRIPT: False,
|
||||||
|
LINK: '',
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, value=None):
|
def __init__(self, value=None):
|
||||||
|
@ -99,6 +99,7 @@ class DocBackend(object):
|
|||||||
FONTCOLOR = 5
|
FONTCOLOR = 5
|
||||||
HIGHLIGHT = 6
|
HIGHLIGHT = 6
|
||||||
SUPERSCRIPT = 7
|
SUPERSCRIPT = 7
|
||||||
|
LINK = 8
|
||||||
|
|
||||||
SUPPORTED_MARKUP = []
|
SUPPORTED_MARKUP = []
|
||||||
|
|
||||||
@ -115,6 +116,7 @@ class DocBackend(object):
|
|||||||
ITALIC : ("", ""),
|
ITALIC : ("", ""),
|
||||||
UNDERLINE : ("", ""),
|
UNDERLINE : ("", ""),
|
||||||
SUPERSCRIPT : ("", ""),
|
SUPERSCRIPT : ("", ""),
|
||||||
|
LINK : ("", ""),
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, filename=None):
|
def __init__(self, filename=None):
|
||||||
@ -216,7 +218,7 @@ class DocBackend(object):
|
|||||||
if not self.STYLETYPE_MAP or \
|
if not self.STYLETYPE_MAP or \
|
||||||
self.CLASSMAP != tagtype.__class__.__name__ :
|
self.CLASSMAP != tagtype.__class__.__name__ :
|
||||||
self.CLASSMAP == tagtype.__class__.__name__
|
self.CLASSMAP == tagtype.__class__.__name__
|
||||||
self.STYLETYPE_MAP[tagtype.__class__.BOLD] = self.BOLD
|
self.STYLETYPE_MAP[tagtype.BOLD] = self.BOLD
|
||||||
self.STYLETYPE_MAP[tagtype.ITALIC] = self.ITALIC
|
self.STYLETYPE_MAP[tagtype.ITALIC] = self.ITALIC
|
||||||
self.STYLETYPE_MAP[tagtype.UNDERLINE] = self.UNDERLINE
|
self.STYLETYPE_MAP[tagtype.UNDERLINE] = self.UNDERLINE
|
||||||
self.STYLETYPE_MAP[tagtype.FONTFACE] = self.FONTFACE
|
self.STYLETYPE_MAP[tagtype.FONTFACE] = self.FONTFACE
|
||||||
@ -224,7 +226,10 @@ class DocBackend(object):
|
|||||||
self.STYLETYPE_MAP[tagtype.FONTCOLOR] = self.FONTCOLOR
|
self.STYLETYPE_MAP[tagtype.FONTCOLOR] = self.FONTCOLOR
|
||||||
self.STYLETYPE_MAP[tagtype.HIGHLIGHT] = self.HIGHLIGHT
|
self.STYLETYPE_MAP[tagtype.HIGHLIGHT] = self.HIGHLIGHT
|
||||||
self.STYLETYPE_MAP[tagtype.SUPERSCRIPT] = self.SUPERSCRIPT
|
self.STYLETYPE_MAP[tagtype.SUPERSCRIPT] = self.SUPERSCRIPT
|
||||||
|
self.STYLETYPE_MAP[tagtype.LINK] = self.LINK
|
||||||
|
|
||||||
|
if s_tag.name == 'link':
|
||||||
|
return self.format_link(s_tag.value)
|
||||||
typeval = int(s_tag.name)
|
typeval = int(s_tag.name)
|
||||||
s_tagvalue = s_tag.value
|
s_tagvalue = s_tag.value
|
||||||
tag_name = None
|
tag_name = None
|
||||||
@ -351,3 +356,13 @@ class DocBackend(object):
|
|||||||
otext += opentag[1]
|
otext += opentag[1]
|
||||||
|
|
||||||
return otext
|
return otext
|
||||||
|
|
||||||
|
def format_link(self, value):
|
||||||
|
"""
|
||||||
|
Default format for links. Override for better support.
|
||||||
|
|
||||||
|
value is: "TYPE DATA" where TYPE is 'url' or 'ref'.
|
||||||
|
|
||||||
|
"""
|
||||||
|
return self.STYLETAG_MARKUP[DocBackend.UNDERLINE]
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@ dist_pkgdata_DATA = \
|
|||||||
editreporef.glade \
|
editreporef.glade \
|
||||||
editpersonref.glade \
|
editpersonref.glade \
|
||||||
editlocation.glade \
|
editlocation.glade \
|
||||||
|
editlink.glade \
|
||||||
editfamily.glade \
|
editfamily.glade \
|
||||||
editchildref.glade \
|
editchildref.glade \
|
||||||
editattribute.glade \
|
editattribute.glade \
|
||||||
|
212
src/glade/editlink.glade
Normal file
212
src/glade/editlink.glade
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<interface>
|
||||||
|
<!-- interface-requires gtk+ 2.12 -->
|
||||||
|
<!-- interface-naming-policy project-wide -->
|
||||||
|
<object class="GtkDialog" id="editurl">
|
||||||
|
<property name="modal">True</property>
|
||||||
|
<property name="default_width">600</property>
|
||||||
|
<property name="destroy_with_parent">True</property>
|
||||||
|
<property name="type_hint">dialog</property>
|
||||||
|
<property name="has_separator">False</property>
|
||||||
|
<child internal-child="vbox">
|
||||||
|
<object class="GtkVBox" id="dialog-vbox29">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkVBox" id="vbox37">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkTable" id="table27">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="border_width">12</property>
|
||||||
|
<property name="n_rows">3</property>
|
||||||
|
<property name="n_columns">3</property>
|
||||||
|
<property name="column_spacing">12</property>
|
||||||
|
<property name="row_spacing">6</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="label219">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
<property name="label" translatable="yes">Gramps item:</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="justify">center</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="top_attach">1</property>
|
||||||
|
<property name="bottom_attach">2</property>
|
||||||
|
<property name="x_options">GTK_FILL</property>
|
||||||
|
<property name="y_options"></property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="label220">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
<property name="label" translatable="yes">Web Address:</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="justify">center</property>
|
||||||
|
<property name="mnemonic_widget">entry1</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="top_attach">2</property>
|
||||||
|
<property name="bottom_attach">3</property>
|
||||||
|
<property name="x_options">GTK_FILL</property>
|
||||||
|
<property name="y_options"></property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="label591">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
<property name="label" translatable="yes">Type:</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="x_options">GTK_FILL</property>
|
||||||
|
<property name="y_options"></property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkEntry" id="entry1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="invisible_char">●</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="right_attach">3</property>
|
||||||
|
<property name="top_attach">2</property>
|
||||||
|
<property name="bottom_attach">3</property>
|
||||||
|
<property name="y_options"></property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="button1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage" id="image1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="stock">gtk-index</property>
|
||||||
|
<property name="icon-size">2</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">2</property>
|
||||||
|
<property name="right_attach">3</property>
|
||||||
|
<property name="x_options"></property>
|
||||||
|
<property name="y_options"></property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkFrame" id="frame1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label_xalign">0</property>
|
||||||
|
<property name="shadow_type">in</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkAlignment" id="alignment1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="label1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child type="label_item">
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="right_attach">3</property>
|
||||||
|
<property name="top_attach">1</property>
|
||||||
|
<property name="bottom_attach">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child internal-child="action_area">
|
||||||
|
<object class="GtkHButtonBox" id="dialog-action_area29">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="layout_style">end</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="button125">
|
||||||
|
<property name="label">gtk-cancel</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="can_default">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="button124">
|
||||||
|
<property name="label">gtk-ok</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="can_default">True</property>
|
||||||
|
<property name="has_default">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
<property name="has_tooltip">True</property>
|
||||||
|
<property name="tooltip_markup">Accept changes and close window</property>
|
||||||
|
<property name="tooltip_text" translatable="yes">Accept changes and close window</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="button130">
|
||||||
|
<property name="label">gtk-help</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="can_default">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
<property name="position">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="pack_type">end</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<action-widgets>
|
||||||
|
<action-widget response="-6">button125</action-widget>
|
||||||
|
<action-widget response="-5">button124</action-widget>
|
||||||
|
<action-widget response="-11">button130</action-widget>
|
||||||
|
</action-widgets>
|
||||||
|
</object>
|
||||||
|
</interface>
|
@ -19,6 +19,7 @@ pkgdata_PYTHON = \
|
|||||||
editfamily.py \
|
editfamily.py \
|
||||||
editldsord.py \
|
editldsord.py \
|
||||||
editlocation.py \
|
editlocation.py \
|
||||||
|
editlink.py \
|
||||||
editmedia.py \
|
editmedia.py \
|
||||||
editmediaref.py \
|
editmediaref.py \
|
||||||
editname.py \
|
editname.py \
|
||||||
|
@ -38,8 +38,9 @@ from editreporef import EditRepoRef
|
|||||||
from editsource import EditSource, DeleteSrcQuery
|
from editsource import EditSource, DeleteSrcQuery
|
||||||
from editsourceref import EditSourceRef
|
from editsourceref import EditSourceRef
|
||||||
from editurl import EditUrl
|
from editurl import EditUrl
|
||||||
|
from editlink import EditLink
|
||||||
|
|
||||||
# Map from gen.obj name to Editor:
|
# Map from gen.lib name to Editor:
|
||||||
EDITORS = {
|
EDITORS = {
|
||||||
'Person': EditPerson,
|
'Person': EditPerson,
|
||||||
'Event': EditEvent,
|
'Event': EditEvent,
|
||||||
@ -58,18 +59,23 @@ def EditObject(dbstate, uistate, track, obj_class, prop, value):
|
|||||||
prop is 'handle' or 'gramps_id'
|
prop is 'handle' or 'gramps_id'
|
||||||
value is string handle or string gramps_id
|
value is string handle or string gramps_id
|
||||||
"""
|
"""
|
||||||
|
import logging
|
||||||
|
LOG = logging.getLogger(".Edit")
|
||||||
if obj_class in dbstate.db.get_table_names():
|
if obj_class in dbstate.db.get_table_names():
|
||||||
if prop in ("gramps_id", "handle"):
|
if prop in ("gramps_id", "handle"):
|
||||||
obj = dbstate.db.get_table_metadata(obj_class)[prop + "_func"](value)
|
obj = dbstate.db.get_table_metadata(obj_class)[prop + "_func"](value)
|
||||||
if obj:
|
if obj:
|
||||||
|
try:
|
||||||
EDITORS[obj_class](dbstate, uistate, track, obj)
|
EDITORS[obj_class](dbstate, uistate, track, obj)
|
||||||
|
except Exception as msg:
|
||||||
|
LOG.warn(str(msg))
|
||||||
else:
|
else:
|
||||||
raise AttributeError("gramps://%s/%s/%s not found" %
|
LOG.warn("gramps://%s/%s/%s not found" %
|
||||||
(obj_class, prop, value))
|
(obj_class, prop, value))
|
||||||
else:
|
else:
|
||||||
raise AttributeError("unknown property to edit '%s'; "
|
LOG.warn("unknown property to edit '%s'; "
|
||||||
"should be 'gramps_id' or 'handle'" % prop)
|
"should be 'gramps_id' or 'handle'" % prop)
|
||||||
else:
|
else:
|
||||||
raise AttributeError("unknown object to edit '%s'; "
|
LOG.warn("unknown object to edit '%s'; "
|
||||||
"should be one of %s" % (obj_class, EDITORS.keys()))
|
"should be one of %s" % (obj_class, EDITORS.keys()))
|
||||||
|
|
||||||
|
219
src/gui/editors/editlink.py
Normal file
219
src/gui/editors/editlink.py
Normal file
@ -0,0 +1,219 @@
|
|||||||
|
#
|
||||||
|
# Gramps - a GTK+/GNOME based genealogy program
|
||||||
|
#
|
||||||
|
# Copyright (C) 2010 Doug Blank <doug.blank@gmail.com>
|
||||||
|
#
|
||||||
|
# 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: $
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# python modules
|
||||||
|
#
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
import gtk
|
||||||
|
import re
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# gramps modules
|
||||||
|
#
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
from gen.ggettext import gettext as _
|
||||||
|
import ManagedWindow
|
||||||
|
import GrampsDisplay
|
||||||
|
from glade import Glade
|
||||||
|
from Simple import SimpleAccess
|
||||||
|
|
||||||
|
WEB, EVENT, FAMILY, MEDIA, NOTE, PERSON, PLACE, REPOSITORY, SOURCE = range(9)
|
||||||
|
OBJECT_MAP = {
|
||||||
|
EVENT: "Event",
|
||||||
|
FAMILY: "Family",
|
||||||
|
MEDIA: "Media",
|
||||||
|
NOTE: "Note",
|
||||||
|
PERSON: "Person",
|
||||||
|
PLACE: "Place",
|
||||||
|
REPOSITORY: "Repository",
|
||||||
|
SOURCE: "Source",
|
||||||
|
}
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# EditUrl class
|
||||||
|
#
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
class EditLink(ManagedWindow.ManagedWindow):
|
||||||
|
|
||||||
|
def __init__(self, dbstate, uistate, track, url, callback):
|
||||||
|
self.url = url
|
||||||
|
self.dbstate = dbstate
|
||||||
|
self.simple_access = SimpleAccess(self.dbstate.db)
|
||||||
|
self.callback = callback
|
||||||
|
|
||||||
|
ManagedWindow.ManagedWindow.__init__(self, uistate, track, url)
|
||||||
|
|
||||||
|
self._local_init()
|
||||||
|
self._connect_signals()
|
||||||
|
self.show()
|
||||||
|
|
||||||
|
def _local_init(self):
|
||||||
|
self.top = Glade()
|
||||||
|
self.set_window(self.top.toplevel,
|
||||||
|
self.top.get_object("title"),
|
||||||
|
_('Link Editor'))
|
||||||
|
self.table = self.top.get_object('table27')
|
||||||
|
self.uri_list = gtk.combo_box_new_text()
|
||||||
|
for text in [_("Web Address"), # 0 this order range above
|
||||||
|
_("Gramps Event"), # 1
|
||||||
|
_("Gramps Family"), # 2
|
||||||
|
_("Gramps Media"), # 3
|
||||||
|
_("Gramps Note"), # 4
|
||||||
|
_("Gramps Person"), # 5
|
||||||
|
_("Gramps Place"), # 6
|
||||||
|
_("Gramps Repository"), # 7
|
||||||
|
_("Gramps Source"), # 8
|
||||||
|
]:
|
||||||
|
self.uri_list.append_text(text)
|
||||||
|
self.table.attach(self.uri_list, 1, 2, 0, 1)
|
||||||
|
self.pick_item = self.top.get_object('button1')
|
||||||
|
#self.edit_item = self.top.get_object('button2')
|
||||||
|
self.selected = self.top.get_object('label1')
|
||||||
|
self.url_link = self.top.get_object('entry1')
|
||||||
|
self.uri_list.connect("changed", self._on_type_changed)
|
||||||
|
self.pick_item.connect("clicked", self._on_pick_one)
|
||||||
|
#self.edit_item.connect("clicked", self._on_edit_one)
|
||||||
|
if self.url.startswith("gramps://"):
|
||||||
|
object_class, prop, value = self.url[9:].split("/", 2)
|
||||||
|
if object_class == "Event":
|
||||||
|
self.uri_list.set_active(EVENT)
|
||||||
|
elif object_class == "Family":
|
||||||
|
self.uri_list.set_active(FAMILY)
|
||||||
|
elif object_class == "Media":
|
||||||
|
self.uri_list.set_active(MEDIA)
|
||||||
|
elif object_class == "Note":
|
||||||
|
self.uri_list.set_active(NOTE)
|
||||||
|
elif object_class == "Person":
|
||||||
|
self.uri_list.set_active(PERSON)
|
||||||
|
elif object_class == "Place":
|
||||||
|
self.uri_list.set_active(PLACE)
|
||||||
|
elif object_class == "Repository":
|
||||||
|
self.uri_list.set_active(REPOSITORY)
|
||||||
|
elif object_class == "Source":
|
||||||
|
self.uri_list.set_active(SOURCE)
|
||||||
|
# set texts:
|
||||||
|
self.selected.set_text(self.display_link(
|
||||||
|
object_class, prop, value))
|
||||||
|
self.url_link.set_text("gramps://%s/%s/%s" %
|
||||||
|
(object_class, prop, value))
|
||||||
|
else:
|
||||||
|
self.uri_list.set_active(WEB)
|
||||||
|
self.url_link.set_text(self.url)
|
||||||
|
self.url_link.connect("changed", self.update_ui)
|
||||||
|
|
||||||
|
def update_ui(self, widget):
|
||||||
|
url = self.url_link.get_text()
|
||||||
|
# text needs to have 3 or more chars://and at least one char
|
||||||
|
match = re.match("\w{3,}://\w+", url)
|
||||||
|
if match:
|
||||||
|
self.ok_button.set_sensitive(True)
|
||||||
|
else:
|
||||||
|
self.ok_button.set_sensitive(False)
|
||||||
|
|
||||||
|
def display_link(self, obj_class, prop, value):
|
||||||
|
return self.simple_access.display(obj_class, prop, value)
|
||||||
|
|
||||||
|
def _on_edit_one(self, widget):
|
||||||
|
from gui.editors import EditObject
|
||||||
|
uri = self.url_link.get_text()
|
||||||
|
if uri.startswith("gramps://"):
|
||||||
|
obj_class, prop, value = uri[9:].split("/", 2)
|
||||||
|
EditObject(self.dbstate,
|
||||||
|
self.uistate,
|
||||||
|
self.track,
|
||||||
|
obj_class, prop, value)
|
||||||
|
|
||||||
|
def _on_pick_one(self, widget):
|
||||||
|
from gui.selectors import SelectorFactory
|
||||||
|
object_class = OBJECT_MAP[self.uri_list.get_active()]
|
||||||
|
Select = SelectorFactory(object_class)
|
||||||
|
uri = self.url_link.get_text()
|
||||||
|
default = None
|
||||||
|
if uri.startswith("gramps://"):
|
||||||
|
obj_class, prop, value = uri[9:].split("/", 2)
|
||||||
|
if object_class == obj_class:
|
||||||
|
if prop == "handle":
|
||||||
|
default = value
|
||||||
|
elif (prop == "gramps_id" and
|
||||||
|
object_class in self.dbstate.db.get_table_names()):
|
||||||
|
person = self.dbstate.db.get_table_metadata(object_class)["gramps_id_func"](value)
|
||||||
|
if person:
|
||||||
|
default = person.handle
|
||||||
|
d = Select(self.dbstate, self.uistate, self.track,
|
||||||
|
default=default)
|
||||||
|
|
||||||
|
result = d.run()
|
||||||
|
if result:
|
||||||
|
prop = "handle"
|
||||||
|
value = result.handle
|
||||||
|
self.selected.set_text(self.display_link(
|
||||||
|
object_class, prop, value))
|
||||||
|
self.url_link.set_text("gramps://%s/%s/%s" %
|
||||||
|
(object_class, prop, value))
|
||||||
|
|
||||||
|
def _on_type_changed(self, widget):
|
||||||
|
self.selected.set_text("")
|
||||||
|
if self.uri_list.get_active() == WEB:
|
||||||
|
self.url_link.set_sensitive(True)
|
||||||
|
self.pick_item.set_sensitive(False)
|
||||||
|
else:
|
||||||
|
self.url_link.set_sensitive(False)
|
||||||
|
self.pick_item.set_sensitive(True)
|
||||||
|
|
||||||
|
def get_uri(self):
|
||||||
|
if self.uri_list.get_active() == WEB:
|
||||||
|
return self.url_link.get_text()
|
||||||
|
else:
|
||||||
|
#object_class = OBJECT_MAP[self.uri_list.get_active()]
|
||||||
|
#prop = "handle"
|
||||||
|
#value = ""
|
||||||
|
#return "gramps://%s/%s/%s" % (object_class, prop, value)
|
||||||
|
return self.url_link.get_text()
|
||||||
|
|
||||||
|
def _connect_signals(self):
|
||||||
|
self.define_cancel_button(self.top.get_object('button125'))
|
||||||
|
self.ok_button = self.top.get_object('button124')
|
||||||
|
self.define_ok_button(self.ok_button, self.save)
|
||||||
|
self.define_help_button(self.top.get_object('button130'))
|
||||||
|
self.update_ui(self.url_link)
|
||||||
|
|
||||||
|
def build_menu_names(self, obj):
|
||||||
|
etitle =_('Link Editor')
|
||||||
|
return (etitle, etitle)
|
||||||
|
|
||||||
|
def define_ok_button(self,button,function):
|
||||||
|
button.connect('clicked',function)
|
||||||
|
|
||||||
|
def save(self, widget):
|
||||||
|
self.callback(self.get_uri())
|
||||||
|
self.close()
|
||||||
|
|
||||||
|
def define_cancel_button(self,button):
|
||||||
|
button.connect('clicked',self.close)
|
||||||
|
|
||||||
|
def define_help_button(self, button, webpage='', section=''):
|
||||||
|
button.connect('clicked', lambda x: GrampsDisplay.help(webpage,
|
||||||
|
section))
|
@ -45,7 +45,7 @@ from baseselector import BaseSelector
|
|||||||
class SelectPerson(BaseSelector):
|
class SelectPerson(BaseSelector):
|
||||||
|
|
||||||
def __init__(self, dbstate, uistate, track=[], title=None, filter=None,
|
def __init__(self, dbstate, uistate, track=[], title=None, filter=None,
|
||||||
skip=set(), show_search_bar = False):
|
skip=set(), show_search_bar=False, default=None):
|
||||||
|
|
||||||
# SelectPerson may have a title passed to it which should be used
|
# SelectPerson may have a title passed to it which should be used
|
||||||
# instead of the default defined for get_window_title()
|
# instead of the default defined for get_window_title()
|
||||||
@ -53,7 +53,7 @@ class SelectPerson(BaseSelector):
|
|||||||
self.title = title
|
self.title = title
|
||||||
|
|
||||||
BaseSelector.__init__(self, dbstate, uistate, track, filter,
|
BaseSelector.__init__(self, dbstate, uistate, track, filter,
|
||||||
skip, show_search_bar)
|
skip, show_search_bar, default)
|
||||||
|
|
||||||
def _local_init(self):
|
def _local_init(self):
|
||||||
"""
|
"""
|
||||||
|
@ -82,6 +82,25 @@ STYLE_TO_PROPERTY = {
|
|||||||
MATCH_FLAVOR,
|
MATCH_FLAVOR,
|
||||||
MATCH_STRING,) = range(4)
|
MATCH_STRING,) = range(4)
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# LinkTag class
|
||||||
|
#
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
class LinkTag(gtk.TextTag):
|
||||||
|
"""
|
||||||
|
Class for keeping track of link data.
|
||||||
|
"""
|
||||||
|
lid = 0
|
||||||
|
def __init__(self, buffer, data, **properties):
|
||||||
|
LinkTag.lid += 1
|
||||||
|
self.data = data
|
||||||
|
gtk.TextTag.__init__(self, "link-%d" % LinkTag.lid)
|
||||||
|
tag_table = buffer.get_tag_table()
|
||||||
|
for property in properties:
|
||||||
|
self.set_property(property, properties[property])
|
||||||
|
tag_table.add(self)
|
||||||
|
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
#
|
#
|
||||||
# GtkSpellState class
|
# GtkSpellState class
|
||||||
@ -433,6 +452,29 @@ class StyledTextBuffer(gtk.TextBuffer):
|
|||||||
self.get_iter_at_offset(start),
|
self.get_iter_at_offset(start),
|
||||||
self.get_iter_at_offset(end+1))
|
self.get_iter_at_offset(end+1))
|
||||||
|
|
||||||
|
def clear_selection(self):
|
||||||
|
"""
|
||||||
|
Clear tags from selection.
|
||||||
|
"""
|
||||||
|
start, end = self._get_selection()
|
||||||
|
tags = self._get_tag_from_range(start.get_offset(), end.get_offset())
|
||||||
|
removed_something = False
|
||||||
|
for tag_name, tag_data in tags.iteritems():
|
||||||
|
if tag_name.startswith("link"):
|
||||||
|
for start_pos, end_pos in tag_data:
|
||||||
|
self.remove_tag_by_name(tag_name,
|
||||||
|
self.get_iter_at_offset(start_pos),
|
||||||
|
self.get_iter_at_offset(end_pos+1))
|
||||||
|
removed_something = True
|
||||||
|
|
||||||
|
for style in ALLOWED_STYLES:
|
||||||
|
value = self.style_state[style]
|
||||||
|
if value and (value != StyledTextTagType.STYLE_DEFAULT[style]):
|
||||||
|
self.remove_tag(self._find_tag_by_name(style, value),
|
||||||
|
start, end)
|
||||||
|
removed_something = True
|
||||||
|
return removed_something
|
||||||
|
|
||||||
def _get_tag_from_range(self, start=None, end=None):
|
def _get_tag_from_range(self, start=None, end=None):
|
||||||
"""Extract gtk.TextTags from buffer.
|
"""Extract gtk.TextTags from buffer.
|
||||||
|
|
||||||
@ -474,7 +516,9 @@ class StyledTextBuffer(gtk.TextBuffer):
|
|||||||
If TextTag does not exist yet, it is created.
|
If TextTag does not exist yet, it is created.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if StyledTextTagType.STYLE_TYPE[style] == bool:
|
if style not in StyledTextTagType.STYLE_TYPE:
|
||||||
|
return None
|
||||||
|
elif StyledTextTagType.STYLE_TYPE[style] == bool:
|
||||||
tag_name = str(style)
|
tag_name = str(style)
|
||||||
elif StyledTextTagType.STYLE_TYPE[style] == str:
|
elif StyledTextTagType.STYLE_TYPE[style] == str:
|
||||||
tag_name = "%d %s" % (style, value)
|
tag_name = "%d %s" % (style, value)
|
||||||
@ -507,6 +551,11 @@ class StyledTextBuffer(gtk.TextBuffer):
|
|||||||
|
|
||||||
s_tags = s_text.get_tags()
|
s_tags = s_text.get_tags()
|
||||||
for s_tag in s_tags:
|
for s_tag in s_tags:
|
||||||
|
if s_tag.name == 'Link':
|
||||||
|
g_tag = LinkTag(self, s_tag.value,
|
||||||
|
foreground="blue",
|
||||||
|
underline=UNDERLINE_SINGLE)
|
||||||
|
else:
|
||||||
g_tag = self._find_tag_by_name(int(s_tag.name), s_tag.value)
|
g_tag = self._find_tag_by_name(int(s_tag.name), s_tag.value)
|
||||||
if g_tag is not None:
|
if g_tag is not None:
|
||||||
for (start, end) in s_tag.ranges:
|
for (start, end) in s_tag.ranges:
|
||||||
@ -533,6 +582,13 @@ class StyledTextBuffer(gtk.TextBuffer):
|
|||||||
s_tags = []
|
s_tags = []
|
||||||
|
|
||||||
for g_tagname, g_ranges in g_tags.items():
|
for g_tagname, g_ranges in g_tags.items():
|
||||||
|
if g_tagname.startswith('link'):
|
||||||
|
tag = self.get_tag_table().lookup(g_tagname)
|
||||||
|
s_ranges = [(start, end+1) for (start, end) in g_ranges]
|
||||||
|
s_value = tag.data
|
||||||
|
s_tag = StyledTextTag('Link', s_value, s_ranges)
|
||||||
|
s_tags.append(s_tag)
|
||||||
|
else:
|
||||||
style_and_value = g_tagname.split(' ', 1)
|
style_and_value = g_tagname.split(' ', 1)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -51,7 +51,8 @@ from pango import UNDERLINE_SINGLE
|
|||||||
from gen.lib import StyledTextTagType
|
from gen.lib import StyledTextTagType
|
||||||
from gui.widgets.styledtextbuffer import (StyledTextBuffer, ALLOWED_STYLES,
|
from gui.widgets.styledtextbuffer import (StyledTextBuffer, ALLOWED_STYLES,
|
||||||
MATCH_START, MATCH_END,
|
MATCH_START, MATCH_END,
|
||||||
MATCH_FLAVOR, MATCH_STRING)
|
MATCH_FLAVOR, MATCH_STRING,
|
||||||
|
LinkTag)
|
||||||
from gui.widgets.valueaction import ValueAction
|
from gui.widgets.valueaction import ValueAction
|
||||||
from gui.widgets.toolcomboentry import ToolComboEntry
|
from gui.widgets.toolcomboentry import ToolComboEntry
|
||||||
from gui.widgets.springseparator import SpringSeparatorAction
|
from gui.widgets.springseparator import SpringSeparatorAction
|
||||||
@ -76,6 +77,7 @@ FORMAT_TOOLBAR = '''
|
|||||||
<toolitem action="%d"/>
|
<toolitem action="%d"/>
|
||||||
<toolitem action="%d"/>
|
<toolitem action="%d"/>
|
||||||
<toolitem action="%d"/>
|
<toolitem action="%d"/>
|
||||||
|
<toolitem action="%d"/>
|
||||||
<toolitem action="spring"/>
|
<toolitem action="spring"/>
|
||||||
<toolitem action="clear"/>
|
<toolitem action="clear"/>
|
||||||
</toolbar>
|
</toolbar>
|
||||||
@ -87,6 +89,7 @@ FORMAT_TOOLBAR = '''
|
|||||||
StyledTextTagType.FONTSIZE,
|
StyledTextTagType.FONTSIZE,
|
||||||
StyledTextTagType.FONTCOLOR,
|
StyledTextTagType.FONTCOLOR,
|
||||||
StyledTextTagType.HIGHLIGHT,
|
StyledTextTagType.HIGHLIGHT,
|
||||||
|
StyledTextTagType.LINK,
|
||||||
)
|
)
|
||||||
|
|
||||||
FONT_SIZES = [8, 9, 10, 11, 12, 13, 14, 16, 18, 20, 22,
|
FONT_SIZES = [8, 9, 10, 11, 12, 13, 14, 16, 18, 20, 22,
|
||||||
@ -101,7 +104,18 @@ SCHEME = "(file:/|https?:|ftps?:|webcal:)"
|
|||||||
USER = "[" + USERCHARS + "]+(:[" + PASSCHARS + "]+)?"
|
USER = "[" + USERCHARS + "]+(:[" + PASSCHARS + "]+)?"
|
||||||
URLPATH = "/[" + PATHCHARS + "]*[^]'.}>) \t\r\n,\\\"]"
|
URLPATH = "/[" + PATHCHARS + "]*[^]'.}>) \t\r\n,\\\"]"
|
||||||
|
|
||||||
(GENURL, HTTP, MAIL) = range(3)
|
(GENURL, HTTP, MAIL, LINK) = 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
|
||||||
|
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
#
|
#
|
||||||
@ -204,6 +218,9 @@ class StyledTextEditor(gtk.TextView):
|
|||||||
self.textbuffer.apply_tag_by_name('hyperlink', start, end)
|
self.textbuffer.apply_tag_by_name('hyperlink', start, end)
|
||||||
window.set_cursor(HAND_CURSOR)
|
window.set_cursor(HAND_CURSOR)
|
||||||
self.url_match = match
|
self.url_match = match
|
||||||
|
elif match and (match[MATCH_FLAVOR] in (LINK,)):
|
||||||
|
window.set_cursor(HAND_CURSOR)
|
||||||
|
self.url_match = match
|
||||||
else:
|
else:
|
||||||
window.set_cursor(REGULAR_CURSOR)
|
window.set_cursor(REGULAR_CURSOR)
|
||||||
self.url_match = None
|
self.url_match = None
|
||||||
@ -256,15 +273,37 @@ class StyledTextEditor(gtk.TextView):
|
|||||||
int(event.x), int(event.y))
|
int(event.x), int(event.y))
|
||||||
iter_at_location = self.get_iter_at_location(x, y)
|
iter_at_location = self.get_iter_at_location(x, y)
|
||||||
self.match = self.textbuffer.match_check(iter_at_location.get_offset())
|
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:
|
if self.match != self.last_match:
|
||||||
self.emit('match-changed', self.match)
|
self.emit('match-changed', self.match)
|
||||||
|
|
||||||
self.last_match = self.match
|
self.last_match = self.match
|
||||||
|
|
||||||
self.window.get_pointer()
|
self.window.get_pointer()
|
||||||
|
self.set_tooltip_text(tooltip)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def make_tooltip_from_link(self, link_tag):
|
||||||
|
"""
|
||||||
|
Return a string useful for a tooltip given a LinkTag object.
|
||||||
|
"""
|
||||||
|
from 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):
|
def on_button_release_event(self, widget, event):
|
||||||
"""
|
"""
|
||||||
Copy selection to clipboard for left click if selection given
|
Copy selection to clipboard for left click if selection given
|
||||||
@ -325,6 +364,14 @@ class StyledTextEditor(gtk.TextView):
|
|||||||
open_menu = gtk.MenuItem(_('_Open Link'))
|
open_menu = gtk.MenuItem(_('_Open Link'))
|
||||||
copy_menu = gtk.MenuItem(_('Copy _Link Address'))
|
copy_menu = gtk.MenuItem(_('Copy _Link Address'))
|
||||||
|
|
||||||
|
if flavor == LINK:
|
||||||
|
edit_menu = gtk.MenuItem(_('_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.connect('activate', self._copy_url_cb, url, flavor)
|
||||||
copy_menu.show()
|
copy_menu.show()
|
||||||
menu.prepend(copy_menu)
|
menu.prepend(copy_menu)
|
||||||
@ -373,6 +420,8 @@ class StyledTextEditor(gtk.TextView):
|
|||||||
_('Font Color'), self._on_action_activate),
|
_('Font Color'), self._on_action_activate),
|
||||||
(str(StyledTextTagType.HIGHLIGHT), 'gramps-font-bgcolor', None, None,
|
(str(StyledTextTagType.HIGHLIGHT), 'gramps-font-bgcolor', None, None,
|
||||||
_('Background Color'), self._on_action_activate),
|
_('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', gtk.STOCK_CLEAR, None, None,
|
||||||
_('Clear Markup'), self._format_clear_cb),
|
_('Clear Markup'), self._format_clear_cb),
|
||||||
]
|
]
|
||||||
@ -487,6 +536,34 @@ class StyledTextEditor(gtk.TextView):
|
|||||||
_LOG.debug("applying style '%d' with value '%s'" % (style, str(value)))
|
_LOG.debug("applying style '%d' with value '%s'" % (style, str(value)))
|
||||||
self.textbuffer.apply_style(style, 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:
|
||||||
|
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=UNDERLINE_SINGLE,
|
||||||
|
foreground="blue")
|
||||||
|
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):
|
def _on_action_activate(self, action):
|
||||||
"""Apply a format set from a gtk.Action type of action."""
|
"""Apply a format set from a gtk.Action type of action."""
|
||||||
style = int(action.get_name())
|
style = int(action.get_name())
|
||||||
@ -533,15 +610,28 @@ class StyledTextEditor(gtk.TextView):
|
|||||||
(text, StyledTextTagType.STYLE_TYPE[style]))
|
(text, StyledTextTagType.STYLE_TYPE[style]))
|
||||||
|
|
||||||
def _format_clear_cb(self, action):
|
def _format_clear_cb(self, action):
|
||||||
"""Remove all formats from the selection.
|
"""
|
||||||
|
Remove all formats from the selection or from all.
|
||||||
|
|
||||||
Remove only our own tags without touching other ones (e.g. gtk.Spell),
|
Remove only our own tags without touching other ones (e.g. gtk.Spell),
|
||||||
thus remove_all_tags() can not be used.
|
thus remove_all_tags() can not be used.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
clear_anything = self.textbuffer.clear_selection()
|
||||||
|
if not clear_anything:
|
||||||
for style in ALLOWED_STYLES:
|
for style in ALLOWED_STYLES:
|
||||||
self.textbuffer.remove_style(style)
|
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.iteritems():
|
||||||
|
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_style_changed(self, buffer, changed_styles):
|
def _on_buffer_style_changed(self, buffer, changed_styles):
|
||||||
"""Synchronize actions as the format changes at the buffer's cursor."""
|
"""Synchronize actions as the format changes at the buffer's cursor."""
|
||||||
for style, style_value in changed_styles.iteritems():
|
for style, style_value in changed_styles.iteritems():
|
||||||
@ -574,9 +664,23 @@ class StyledTextEditor(gtk.TextView):
|
|||||||
url = 'mailto:' + url
|
url = 'mailto:' + url
|
||||||
elif flavor == GENURL:
|
elif flavor == GENURL:
|
||||||
pass
|
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:
|
||||||
|
obj_class, prop, value = url[9:].split("/")
|
||||||
|
from gui.editors import EditObject
|
||||||
|
EditObject(win_obj.dbstate,
|
||||||
|
win_obj.uistate,
|
||||||
|
win_obj.track,
|
||||||
|
obj_class, prop, value)
|
||||||
|
return
|
||||||
else:
|
else:
|
||||||
return
|
return
|
||||||
|
# If ok, then let's open
|
||||||
display_url(url)
|
display_url(url)
|
||||||
|
|
||||||
def _copy_url_cb(self, menuitem, url, flavor):
|
def _copy_url_cb(self, menuitem, url, flavor):
|
||||||
@ -587,6 +691,14 @@ class StyledTextEditor(gtk.TextView):
|
|||||||
clipboard = gtk.Clipboard(selection="PRIMARY")
|
clipboard = gtk.Clipboard(selection="PRIMARY")
|
||||||
clipboard.set_text(url)
|
clipboard.set_text(url)
|
||||||
|
|
||||||
|
|
||||||
|
def _edit_url_cb(self, menuitem, link_tag):
|
||||||
|
"""
|
||||||
|
Edit the URI of the link.
|
||||||
|
"""
|
||||||
|
uri_dialog(self, link_tag.data,
|
||||||
|
lambda uri: self.setlink_callback(uri, link_tag))
|
||||||
|
|
||||||
# public methods
|
# public methods
|
||||||
|
|
||||||
def set_text(self, text):
|
def set_text(self, text):
|
||||||
@ -617,6 +729,24 @@ class StyledTextEditor(gtk.TextView):
|
|||||||
"""
|
"""
|
||||||
return self.toolbar
|
return self.toolbar
|
||||||
|
|
||||||
|
def uri_dialog(self, uri, callback):
|
||||||
|
"""
|
||||||
|
Function to spawn the link editor.
|
||||||
|
"""
|
||||||
|
from gui.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
|
# Module functions
|
||||||
|
@ -75,7 +75,9 @@ class HtmlBackend(DocBackend):
|
|||||||
DocBackend.FONTSIZE,
|
DocBackend.FONTSIZE,
|
||||||
DocBackend.FONTCOLOR,
|
DocBackend.FONTCOLOR,
|
||||||
DocBackend.HIGHLIGHT,
|
DocBackend.HIGHLIGHT,
|
||||||
DocBackend.SUPERSCRIPT ]
|
DocBackend.SUPERSCRIPT,
|
||||||
|
DocBackend.LINK,
|
||||||
|
]
|
||||||
|
|
||||||
STYLETAG_MARKUP = {
|
STYLETAG_MARKUP = {
|
||||||
DocBackend.BOLD : ("<strong>", "</strong>"),
|
DocBackend.BOLD : ("<strong>", "</strong>"),
|
||||||
@ -85,7 +87,7 @@ class HtmlBackend(DocBackend):
|
|||||||
DocBackend.SUPERSCRIPT : ("<sup>", "</sup>"),
|
DocBackend.SUPERSCRIPT : ("<sup>", "</sup>"),
|
||||||
}
|
}
|
||||||
|
|
||||||
ESCAPE_FUNC = lambda x: escape
|
ESCAPE_FUNC = lambda self: escape
|
||||||
|
|
||||||
def __init__(self, filename=None):
|
def __init__(self, filename=None):
|
||||||
"""
|
"""
|
||||||
@ -97,6 +99,7 @@ class HtmlBackend(DocBackend):
|
|||||||
self.html_body = None
|
self.html_body = None
|
||||||
self._subdir = None
|
self._subdir = None
|
||||||
self.title = None
|
self.title = None
|
||||||
|
self.build_link = None
|
||||||
|
|
||||||
def _create_xmltag(self, tagtype, value):
|
def _create_xmltag(self, tagtype, value):
|
||||||
"""
|
"""
|
||||||
@ -111,7 +114,6 @@ class HtmlBackend(DocBackend):
|
|||||||
elif tagtype == DocBackend.FONTFACE:
|
elif tagtype == DocBackend.FONTFACE:
|
||||||
#fonts can have strange symbols in them, ' needs to be escaped
|
#fonts can have strange symbols in them, ' needs to be escaped
|
||||||
value = value.replace("'", "\\'")
|
value = value.replace("'", "\\'")
|
||||||
|
|
||||||
return ('<span style="%s">' % (self.STYLETAG_TO_PROPERTY[tagtype] %
|
return ('<span style="%s">' % (self.STYLETAG_TO_PROPERTY[tagtype] %
|
||||||
(value)),
|
(value)),
|
||||||
'</span>')
|
'</span>')
|
||||||
@ -172,3 +174,22 @@ class HtmlBackend(DocBackend):
|
|||||||
full path of the datadir directory
|
full path of the datadir directory
|
||||||
"""
|
"""
|
||||||
return os.path.join(os.path.dirname(self.getf()), self.datadir())
|
return os.path.join(os.path.dirname(self.getf()), self.datadir())
|
||||||
|
|
||||||
|
def format_link(self, value):
|
||||||
|
"""
|
||||||
|
Override of base method.
|
||||||
|
"""
|
||||||
|
if value.startswith("gramps://"):
|
||||||
|
if self.build_link:
|
||||||
|
obj_class, prop, handle = value[9:].split("/", 3)
|
||||||
|
if prop in ["handle", "gramps_id"]:
|
||||||
|
value = self.build_link(prop, handle, obj_class, up=True)
|
||||||
|
if not value:
|
||||||
|
return self.STYLETAG_MARKUP[DocBackend.UNDERLINE]
|
||||||
|
else:
|
||||||
|
return self.STYLETAG_MARKUP[DocBackend.UNDERLINE]
|
||||||
|
else:
|
||||||
|
return self.STYLETAG_MARKUP[DocBackend.UNDERLINE]
|
||||||
|
return ('<a href="%s">' % self.ESCAPE_FUNC()(value),
|
||||||
|
'</a>')
|
||||||
|
|
||||||
|
@ -81,7 +81,9 @@ class OdfBackend(DocBackend):
|
|||||||
DocBackend.FONTSIZE,
|
DocBackend.FONTSIZE,
|
||||||
DocBackend.FONTCOLOR,
|
DocBackend.FONTCOLOR,
|
||||||
DocBackend.HIGHLIGHT,
|
DocBackend.HIGHLIGHT,
|
||||||
DocBackend.SUPERSCRIPT ]
|
DocBackend.SUPERSCRIPT,
|
||||||
|
DocBackend.LINK,
|
||||||
|
]
|
||||||
|
|
||||||
STYLETAG_MARKUP = {
|
STYLETAG_MARKUP = {
|
||||||
DocBackend.BOLD :
|
DocBackend.BOLD :
|
||||||
@ -129,3 +131,14 @@ class OdfBackend(DocBackend):
|
|||||||
return ('<text:span text:style-name=\"FontHighlight__%s__\">' %
|
return ('<text:span text:style-name=\"FontHighlight__%s__\">' %
|
||||||
self.ESCAPE_FUNC()(value),
|
self.ESCAPE_FUNC()(value),
|
||||||
'</text:span>')
|
'</text:span>')
|
||||||
|
|
||||||
|
def format_link(self, value):
|
||||||
|
"""
|
||||||
|
Override of base method.
|
||||||
|
"""
|
||||||
|
if value.startswith("gramps://"):
|
||||||
|
return self.STYLETAG_MARKUP[DocBackend.UNDERLINE]
|
||||||
|
else:
|
||||||
|
return ('<text:a xlink:href="%s">' % self.ESCAPE_FUNC()(value),
|
||||||
|
'</text:a>')
|
||||||
|
|
||||||
|
@ -304,6 +304,7 @@ class BasePage(object):
|
|||||||
self.up = False
|
self.up = False
|
||||||
# class to do conversion of styled notes to html markup
|
# class to do conversion of styled notes to html markup
|
||||||
self._backend = HtmlBackend()
|
self._backend = HtmlBackend()
|
||||||
|
self._backend.build_link = report.build_link
|
||||||
|
|
||||||
self.report = report
|
self.report = report
|
||||||
self.title_str = title
|
self.title_str = title
|
||||||
@ -5557,6 +5558,41 @@ class NavWebReport(Report):
|
|||||||
def build_url_fname_html(self, fname, subdir = None, up = False):
|
def build_url_fname_html(self, fname, subdir = None, up = False):
|
||||||
return self.build_url_fname(fname, subdir, up) + self.ext
|
return self.build_url_fname(fname, subdir, up) + self.ext
|
||||||
|
|
||||||
|
def build_link(self, prop, handle, obj_class, up = False):
|
||||||
|
"""
|
||||||
|
Build a link to an item.
|
||||||
|
"""
|
||||||
|
if prop == "gramps_id":
|
||||||
|
if obj_class in self.database.get_table_names():
|
||||||
|
obj = self.database.get_table_metadata(obj_class)["gramps_id_func"](handle)
|
||||||
|
if obj:
|
||||||
|
handle = obj.handle
|
||||||
|
else:
|
||||||
|
raise AttributeError("gramps_id '%s' not found in '%s'" %
|
||||||
|
handle, obj_class)
|
||||||
|
else:
|
||||||
|
raise AttributeError("invalid gramps_id lookup "
|
||||||
|
"in table name '%s'" % obj_class)
|
||||||
|
# handle, ppl
|
||||||
|
if obj_class == "Person":
|
||||||
|
if handle in self.person_handles:
|
||||||
|
return self.build_url_fname(handle, "ppl", up) + self.ext
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
elif obj_class == "Source":
|
||||||
|
subdir = "src"
|
||||||
|
elif obj_class == "Place":
|
||||||
|
subdir = "plc"
|
||||||
|
elif obj_class == "Event":
|
||||||
|
subdir = "evt"
|
||||||
|
elif obj_class == "Media":
|
||||||
|
subdir = "img"
|
||||||
|
elif obj_class == "Repository":
|
||||||
|
subdir = "repo"
|
||||||
|
else:
|
||||||
|
raise AttributeError("unknown object type '%s'" % obj_class)
|
||||||
|
return self.build_url_fname(handle, subdir, up) + self.ext
|
||||||
|
|
||||||
def build_url_fname(self, fname, subdir = None, up = False):
|
def build_url_fname(self, fname, subdir = None, up = False):
|
||||||
"""
|
"""
|
||||||
Create part of the URL given the filename and optionally the subdirectory.
|
Create part of the URL given the filename and optionally the subdirectory.
|
||||||
|
Reference in New Issue
Block a user