Geography : reorganization, add a life way layer, some cleaning.

svn: r19209
This commit is contained in:
Serge Noiraud 2012-04-03 09:44:44 +00:00
parent 47ffcf9bec
commit 8d4906354d
9 changed files with 871 additions and 366 deletions

View File

@ -1,7 +1,7 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2010 Serge Noiraud
# Copyright (C) 2010-2012 Serge Noiraud
#
# 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

View File

@ -1,7 +1,7 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2010 Serge Noiraud
# Copyright (C) 2010-2012 Serge Noiraud
#
# 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
@ -27,7 +27,6 @@
# standard python modules
#
#-------------------------------------------------------------------------
from gen.ggettext import gettext as _
import gen.lib
import os
import const

View File

@ -0,0 +1,91 @@
# -*- python -*-
# -*- coding: utf-8 -*-
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2011-2012 Serge Noiraud
#
# 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: grampsmaps.py 18399 2011-11-02 17:15:20Z noirauds $
#-------------------------------------------------------------------------
#
# Python modules
#
#-------------------------------------------------------------------------
import os
import gobject
#------------------------------------------------------------------------
#
# Set up logging
#
#------------------------------------------------------------------------
import logging
_LOG = logging.getLogger("maps.dummylayer")
#-------------------------------------------------------------------------
#
# Gramps Modules
#
#-------------------------------------------------------------------------
import const
#-------------------------------------------------------------------------
#
# osmGpsMap
#
#-------------------------------------------------------------------------
try:
import osmgpsmap
except:
raise
class DummyLayer(gobject.GObject, osmgpsmap.GpsMapLayer):
def __init__(self):
"""
Initialize the dummy layer
"""
gobject.GObject.__init__(self)
def do_draw(self, gpsmap, gdkdrawable):
"""
Draw the layer
"""
pass
def do_render(self, gpsmap):
"""
Render the layer
"""
pass
def do_busy(self):
"""
The layer is busy
"""
return False
def do_button_press(self, gpsmap, gdkeventbutton):
"""
Someone press a button
"""
return False
gobject.type_register(DummyLayer)

View File

@ -0,0 +1,64 @@
# -*- python -*-
# -*- coding: utf-8 -*-
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2011-2012 Serge Noiraud
#
# 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: grampsmaps.py 18399 2011-11-02 17:15:20Z noirauds $
#-------------------------------------------------------------------------
#
# Python modules
#
#-------------------------------------------------------------------------
import os
import gobject
#------------------------------------------------------------------------
#
# Set up logging
#
#------------------------------------------------------------------------
import logging
_LOG = logging.getLogger("maps.dummynogps")
#-------------------------------------------------------------------------
#
# Gramps Modules
#
#-------------------------------------------------------------------------
import const
#-------------------------------------------------------------------------
#
# osmGpsMap
#
#-------------------------------------------------------------------------
try:
import osmgpsmap
except:
raise
class DummyMapNoGpsPoint(osmgpsmap.GpsMap):
def do_draw_gps_point(self, drawable):
pass
gobject.type_register(DummyMapNoGpsPoint)

View File

@ -3,7 +3,7 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2011 Serge Noiraud
# Copyright (C) 2011-2012 Serge Noiraud
#
# 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
@ -28,21 +28,10 @@
#
#-------------------------------------------------------------------------
from gen.ggettext import sgettext as _
from gen.ggettext import ngettext
import sys
import os
import re
import gobject
import time
import math
#------------------------------------------------------------------------
#
# Set up logging
#
#------------------------------------------------------------------------
import logging
_LOG = logging.getLogger(".geography")
#-------------------------------------------------------------------------
#
@ -65,13 +54,25 @@ import Errors
import Bookmarks
import const
import constfunc
from grampsmaps import *
import constants
import ManagedWindow
from config import config
from gui.editors import EditPlace, EditEvent, EditFamily, EditPerson
from gui.selectors.selectplace import SelectPlace
import osmgpsmap
from . import constants
from osmGps import OsmGps
from selectionlayer import SelectionLayer
from placeselection import PlaceSelection
#------------------------------------------------------------------------
#
# Set up logging
#
#------------------------------------------------------------------------
import logging
_LOG = logging.getLogger("maps.geography")
#-------------------------------------------------------------------------
#
# Functions and variables
@ -89,216 +90,19 @@ def _get_sign(value):
else:
return 0
def _get_zoom_lat(value):
"""
return the zoom value for latitude depending on the distance.
"""
zoomlat = 1
for i, distance in enumerate([80.0, 40.0, 20.0, 10.0, 3.0,
2.0, 1.0, 0.5, 0.2, 0.1]):
if value < distance:
zoomlat = i+1
return zoomlat + 3
def _get_zoom_long(value):
"""
return the zoom value for longitude depending on the distance.
"""
zoomlong = 1
for i, distance in enumerate([120.0, 60.0, 30.0, 15.0, 7.0,
4.0, 2.0, 1.0, .5, .2, .1]):
if value < distance:
zoomlong = i+1
return zoomlong + 3
def match(self, lat, lon, radius):
"""
coordinates matching.
"""
r = float(radius)
self.places = []
# place
for entry in self.place_list:
if (math.hypot(lat-float(entry[3]), lon-float(entry[4])) <= r) == True:
dist = math.sqrt((lat - float(entry[3])) ** 2 + (lon - float(entry[4])) ** 2)
# Do we already have this place ? avoid duplicates
self.get_location(entry[9])
if not [self.country, self.state, self.county] in self.places:
self.places.append([self.country, self.state, self.county])
return self.places
#-------------------------------------------------------------------------
#
# PlaceSelection
#
#-------------------------------------------------------------------------
class PlaceSelection(ManagedWindow.ManagedWindow, osmGpsMap):
def __init__(self, uistate, dbstate, map, layer, places, lat, lon, function, oldvalue=None):
"""
We show a selection box for possible places in a region of the map.
We can select the diameter of the region which is a circle.
Depending of this region, we can show the possible choice.
We select the value depending of our need which open the EditPlace box.
"""
try:
ManagedWindow.ManagedWindow.__init__(self, uistate, [], PlaceSelection)
except Errors.WindowActiveError:
return
self.uistate = uistate
self.dbstate = dbstate
self.lat = lat
self.lon = lon
self.osm = map
self.radius = 1.0
self.circle = None
self.oldvalue = oldvalue
self.place_list = places
self.function = function
self.selection_layer = layer
self.layer = layer
alignment = gtk.Alignment(0,1,0,0)
self.set_window(
gtk.Dialog(_('Place Selection in a region'),
flags=gtk.DIALOG_NO_SEPARATOR,
buttons=(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE)),
None, _('Place Selection in a region'), None)
label = gtk.Label(_('Choose the radius of the selection.\n'
'On the map you should see a circle or an oval depending on the latitude.'))
alignment.add(label)
self.window.vbox.pack_start(alignment, expand=False)
adj = gtk.Adjustment(1.0, 0.1, 3.0, 0.1, 0, 0) # default value is 1.0, minimum is 0.1 and max is 3.0
slider = gtk.HScale(adj)
slider.set_update_policy(gtk.UPDATE_DISCONTINUOUS)
slider.set_digits(1)
slider.set_value_pos(gtk.POS_BOTTOM)
slider.connect('value-changed', self.slider_change, self.lat, self.lon)
self.window.vbox.pack_start(slider, expand=False)
self.vadjust = gtk.Adjustment(page_size=15)
self.scroll = gtk.ScrolledWindow(self.vadjust)
self.scroll.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
self.scroll.set_shadow_type(gtk.SHADOW_IN)
self.plist = gtk.ListStore(str, str, str)
self.choices = gtk.TreeView(self.plist)
self.scroll.add(self.choices)
self.renderer = gtk.CellRendererText()
self.tvcol1 = gtk.TreeViewColumn(_('Country'),self.renderer, markup=0)
self.tvcol2 = gtk.TreeViewColumn(_('State'),self.renderer, markup=1)
self.tvcol3 = gtk.TreeViewColumn(_('County'),self.renderer, markup=2)
self.tvcol1.set_sort_column_id(0)
self.tvcol2.set_sort_column_id(1)
self.tvcol3.set_sort_column_id(2)
self.choices.append_column(self.tvcol1)
self.choices.append_column(self.tvcol2)
self.choices.append_column(self.tvcol3)
self.window.vbox.pack_start(self.scroll, expand=True)
self.label2 = gtk.Label()
self.label2.set_markup('<span background="green" foreground="black">%s</span>' %
_('The green values in the row correspond to the current place values.'))
alignment = gtk.Alignment(0,1,0,0)
alignment.add(self.label2)
self.window.vbox.pack_start(alignment, expand=False)
self.window.set_default_size(400, 300)
self.choices.connect('row-activated', self.selection, function)
self.window.connect('response', self.close)
self.window.show_all()
self.show()
self.label2.hide()
self.slider_change(None,lat,lon)
def close(self, *obj):
self.hide_the_region()
ManagedWindow.ManagedWindow.close(self, *obj)
def slider_change(self, obj, lat, lon):
"""
Display on the map a circle in which we select all the places inside this region.
"""
self.radius = obj.get_value() if obj else 1.0
self.show_the_region(self.radius)
match(self, lat, lon, self.radius)
self.plist.clear()
if self.oldvalue != None:
# The old values are always in the first row.
# In this case, we change the color of the row.
# display the associated message
self.label2.show()
a,b,c = self.oldvalue
self.plist.append((PLACE_STRING % a,
PLACE_STRING % b,
PLACE_STRING % c)
)
for place in self.places:
self.plist.append(place)
# here, we could add value from geography names services ...
# if we found no place, we must create a default place.
self.plist.append((_("New place with empty fields"),"","..."))
def hide_the_region(self):
"""
Hide the layer which contains the circle
"""
layer = self.get_selection_layer()
if layer:
self.remove_layer(layer)
def show_the_region(self, r):
"""
Show a circle in which we select the places.
"""
# circle (r)
self.hide_the_region()
self.selection_layer = self.add_selection_layer()
self.selection_layer.add_circle(r, self.lat, self.lon)
def get_location(self, place):
"""
get location values
"""
place = self.dbstate.db.get_place_from_gramps_id(place)
loc = place.get_main_location()
data = loc.get_text_data_list()
# new background or font color on gtk fields ?
self.country = data[6]
self.state = data[5]
self.county = data[4]
return(self.country, self.state, self.county)
def selection(self, obj, index, column, function):
"""
get location values and call the real function : add_place, edit_place
"""
if self.plist[index][2] == "...":
# case with blank values ( New place with empty fields )
self.function( "", "", "", self.lat, self.lon)
elif self.plist[index][0][1:5] == "span":
# case with old values ( keep the old values of the place )
name = PLACE_REGEXP.search(self.plist[index][0],0)
country = name.group(1)
name = PLACE_REGEXP.search(self.plist[index][1],0)
state = name.group(1)
name = PLACE_REGEXP.search(self.plist[index][2],0)
county = name.group(1)
self.function( country, county, state, self.lat, self.lon)
else:
# Set the new values of the country, county and state fields.
self.function( self.plist[index][0], self.plist[index][2],
self.plist[index][1], self.lat, self.lon)
#-------------------------------------------------------------------------
#
# GeoGraphyView
#
#-------------------------------------------------------------------------
class GeoGraphyView(osmGpsMap, NavigationView):
class GeoGraphyView(OsmGps, NavigationView):
"""
View for pedigree tree.
Displays the ancestors of a selected individual.
"""
#settings in the config file
CONFIGSETTINGS = (
('geography.path', GEOGRAPHY_PATH),
('geography.path', constants.GEOGRAPHY_PATH),
('geography.zoom', 10),
('geography.zoom_when_center', 12),
@ -307,11 +111,6 @@ class GeoGraphyView(osmGpsMap, NavigationView):
('geography.center-lat', 0.0),
('geography.center-lon', 0.0),
#('geography.gps_mode', GPS_DISABLED),
#('geography.gps_update_rate', float(1.0)),
#('geography.max_gps_zoom', 16),
#('geography.gps_increment', GPS_INCREMENT),
('geography.map_service', constants.OPENSTREETMAP),
)
@ -329,7 +128,7 @@ class GeoGraphyView(osmGpsMap, NavigationView):
self.lock = config.get("geography.lock")
if config.get('geography.path') == "" :
config.set('geography.path', GEOGRAPHY_PATH )
osmGpsMap.__init__(self)
OsmGps.__init__(self)
self.format_helper = FormattingHelper(self.dbstate)
self.centerlat = self.centerlon = 0.0
@ -353,16 +152,18 @@ class GeoGraphyView(osmGpsMap, NavigationView):
else:
default_image = self.geo_altmap
self.geo_othermap = {}
for id in ( gen.lib.EventType.BIRTH,
for ident in ( gen.lib.EventType.BIRTH,
gen.lib.EventType.DEATH,
gen.lib.EventType.MARRIAGE ):
self.geo_othermap[id] = gtk.gdk.pixbuf_new_from_file_at_size(
self.geo_othermap[ident] = gtk.gdk.pixbuf_new_from_file_at_size(
os.path.join(const.ROOT_DIR, "images", "22x22",
(constants.ICONS.get(int(id), default_image) + '.png' )),
(constants.ICONS.get(int(ident), default_image) + '.png' )),
22, 22)
def change_page(self):
"""Called when the page changes."""
"""
Called when the page changes.
"""
NavigationView.change_page(self)
self.uistate.clear_filter_results()
self.end_selection = None
@ -374,7 +175,7 @@ class GeoGraphyView(osmGpsMap, NavigationView):
NavigationView.on_delete(self)
self._config.save()
def change_db(self, db):
def change_db(self, dbse):
"""
Callback associated with DbState. Whenever the database
changes, this task is called. In this case, we rebuild the
@ -422,7 +223,9 @@ class GeoGraphyView(osmGpsMap, NavigationView):
#
#-------------------------------------------------------------------------
def build_nav_menu(self, obj, event, lat, lon):
"""Builds the menu for actions on the map."""
"""
Builds the menu for actions on the map.
"""
menu = gtk.Menu()
menu.set_title(_('Map Menu'))
@ -499,7 +302,8 @@ class GeoGraphyView(osmGpsMap, NavigationView):
"""
Center the map at the new position then save it.
"""
self.osm.set_center_and_zoom(lat, lon, config.get("geography.zoom_when_center"))
self.osm.set_center_and_zoom(lat, lon,
config.get("geography.zoom_when_center"))
self.save_center(lat, lon)
#-------------------------------------------------------------------------
@ -563,11 +367,17 @@ class GeoGraphyView(osmGpsMap, NavigationView):
raise NotImplementedError
def add_selection_layer(self):
"""
add the selection layer
"""
selection_layer = SelectionLayer()
self.osm.layer_add(selection_layer)
return selection_layer
def remove_layer(self, layer):
"""
Remove the specified layer
"""
self.osm.remove_layer(layer)
def add_marker(self, menu, event, lat, lon, event_type, differtype):
@ -716,7 +526,8 @@ class GeoGraphyView(osmGpsMap, NavigationView):
s_bbox_lon1 = bbox[1] + 10.0
s_bbox_lat2 = bbox[2] + 10.0
s_bbox_lon2 = bbox[3] + 10.0
result = ( s_bbox_lat1 > s_lat > s_bbox_lat2 ) and ( s_bbox_lon1 < s_lon < s_bbox_lon2 )
result = ( s_bbox_lat1 > s_lat > s_bbox_lat2 ) and \
( s_bbox_lon1 < s_lon < s_bbox_lon2 )
return result
def _autozoom_in(self, lvl, p1lat, p1lon, p2lat, p2lon):
@ -728,9 +539,11 @@ class GeoGraphyView(osmGpsMap, NavigationView):
and lvl < 18 ):
lvl += 1
self.osm.set_zoom(lvl)
gobject.timeout_add(50, self._autozoom_in, lvl, p1lat, p1lon, p2lat, p2lon)
gobject.timeout_add(50, self._autozoom_in, lvl,
p1lat, p1lon, p2lat, p2lon)
else:
gobject.timeout_add(50, self._autozoom_out, lvl, p1lat, p1lon, p2lat, p2lon)
gobject.timeout_add(50, self._autozoom_out, lvl,
p1lat, p1lon, p2lat, p2lon)
def _autozoom_out(self, lvl, p1lat, p1lon, p2lat, p2lon):
"""
@ -741,7 +554,8 @@ class GeoGraphyView(osmGpsMap, NavigationView):
and lvl > 1 ):
lvl -= 1
self.osm.set_zoom(lvl)
gobject.timeout_add(50, self._autozoom_out, lvl, p1lat, p1lon, p2lat, p2lon)
gobject.timeout_add(50, self._autozoom_out, lvl,
p1lat, p1lon, p2lat, p2lon)
else:
layer = self.get_selection_layer()
if layer:
@ -767,7 +581,8 @@ class GeoGraphyView(osmGpsMap, NavigationView):
p2lat = self.end_selection.rlat
p2lon = self.end_selection.rlon
# We zoom in until at least one marker missing.
gobject.timeout_add(50, self._autozoom_in, level_start, p1lat, p1lon, p2lat, p2lon)
gobject.timeout_add(50, self._autozoom_in, level_start,
p1lat, p1lon, p2lat, p2lon)
def _set_center_and_zoom(self):
"""
@ -829,7 +644,7 @@ class GeoGraphyView(osmGpsMap, NavigationView):
self._autozoom()
self.end_selection = None
self.save_center(self.latit, self.longt)
config.set("geography.zoom",self.osm.props.zoom)
config.set("geography.zoom", self.osm.props.zoom)
def _get_father_and_mother_name(self, event):
"""
@ -958,16 +773,23 @@ class GeoGraphyView(osmGpsMap, NavigationView):
place = selector.run()
if place:
loc = place.get_main_location()
oldv = (loc.get_country(), loc.get_state(), loc.get_county()) if loc else None
oldv = (loc.get_country(), loc.get_state(),
loc.get_county()) if loc else None
places_handle = self.dbstate.db.iter_place_handles()
for place_hdl in places_handle:
plce = self.dbstate.db.get_place_from_handle(place_hdl)
if plce.get_title() == place.get_title():
self.mark = [None,None,None,None,None,None,None,
None,None,plce.gramps_id,None,None]
self.select_fct = PlaceSelection(self.uistate, self.dbstate, self.osm,
self.selection_layer, self.place_list,
lat, lon, self.__edit_place, oldv)
self.mark = [None, None, None, None, None, None, None,
None, None, plce.gramps_id, None, None]
self.select_fct = PlaceSelection(self.uistate,
self.dbstate,
self.osm,
self.selection_layer,
self.place_list,
lat,
lon,
self.__edit_place,
oldv)
def __add_place(self, pcountry, pcounty, pstate, plat, plon):
"""
@ -1081,8 +903,9 @@ class GeoGraphyView(osmGpsMap, NavigationView):
Function that builds the widget in the configuration dialog
for the map options.
"""
self._config.set('geography.path',config.get('geography.path'))
self._config.set('geography.zoom_when_center',config.get('geography.zoom_when_center'))
self._config.set('geography.path', config.get('geography.path'))
self._config.set('geography.zoom_when_center',
config.get('geography.zoom_when_center'))
table = gtk.Table(1, 1)
table.set_border_width(12)
table.set_col_spacings(6)

View File

@ -0,0 +1,158 @@
# -*- python -*-
# -*- coding: utf-8 -*-
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2011-2012 Serge Noiraud
#
# 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: grampsmaps.py 18399 2011-11-02 17:15:20Z noirauds $
#-------------------------------------------------------------------------
#
# Python modules
#
#-------------------------------------------------------------------------
import os
import gobject
#------------------------------------------------------------------------
#
# Set up logging
#
#------------------------------------------------------------------------
import logging
_LOG = logging.getLogger("maps.lifeway")
#-------------------------------------------------------------------------
#
# GTK/Gnome modules
#
#-------------------------------------------------------------------------
import gtk
#-------------------------------------------------------------------------
#
# Gramps Modules
#
#-------------------------------------------------------------------------
import const
import cairo
#-------------------------------------------------------------------------
#
# osmGpsMap
#
#-------------------------------------------------------------------------
try:
import osmgpsmap
except:
raise
class LifeWayLayer(gobject.GObject, osmgpsmap.GpsMapLayer):
"""
This is the layer used to display tracks or the life way for one or several
individuals.
"""
def __init__(self):
"""
Initialize the layer
"""
gobject.GObject.__init__(self)
self.lifeways = []
self.lifeways_comment = []
self.comments = []
def clear_ways(self):
"""
reset the layer attributes.
"""
self.lifeways = []
self.lifeways_comment = []
self.comments = []
def add_way(self, points, color):
"""
Add a track or life way.
"""
self.lifeways.append((points, color))
def add_text(self, points, text):
"""
Add a text to the track or life way.
"""
self.lifeways_comment.append((points, text))
def do_draw(self, gpsmap, drawable):
"""
Draw all tracks or life ways.
"""
for lifeway in self.lifeways:
ctx = drawable.cairo_create()
ctx.set_line_width(3.0)
map_points = []
for point in lifeway[0]:
conv_pt = osmgpsmap.point_new_degrees(point[0], point[1])
coord_x, coord_y = gpsmap.convert_geographic_to_screen(conv_pt)
map_points.append((coord_x, coord_y))
color = gtk.gdk.color_parse(lifeway[1])
ctx.set_source_rgb(color.red / 65535,
color.green / 65535,
color.blue / 65535)
first = True
for idx_pt in range(0, len(map_points)):
if first:
first = False
ctx.move_to(map_points[idx_pt][0], map_points[idx_pt][1])
else:
ctx.line_to(map_points[idx_pt][0], map_points[idx_pt][1])
ctx.stroke()
for comment in self.lifeways_comment:
ctx = drawable.cairo_create()
ctx.set_line_width(3.0)
ctx.select_font_face("Purisa",
cairo.FONT_SLANT_NORMAL,
cairo.FONT_WEIGHT_NORMAL)
ctx.set_font_size(13)
points = comment[0]
conv_pt = osmgpsmap.point_new_degrees(points[0][0], points[0][1])
coord_x, coord_y = gpsmap.convert_geographic_to_screen(conv_pt)
ctx.move_to(coord_x, coord_y)
ctx.show_text(comment[1])
def do_render(self, gpsmap):
"""
render the layer
"""
pass
def do_busy(self):
"""
set the layer busy
"""
return False
def do_button_press(self, gpsmap, gdkeventbutton):
"""
When we press a button.
"""
return False
gobject.type_register(LifeWayLayer)

View File

@ -3,7 +3,7 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2011 Serge Noiraud
# Copyright (C) 2011-2012 Serge Noiraud
#
# 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
@ -20,14 +20,13 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# $Id$
# $Id: grampsmaps.py 18399 2011-11-02 17:15:20Z noirauds $
#-------------------------------------------------------------------------
#
# Python modules
#
#-------------------------------------------------------------------------
import sys
import os
import gobject
@ -37,7 +36,7 @@ import gobject
#
#------------------------------------------------------------------------
import logging
_LOG = logging.getLogger("maps.osmgpsmap")
_LOG = logging.getLogger("maps.osmgps")
#-------------------------------------------------------------------------
#
@ -53,21 +52,17 @@ import gtk
#-------------------------------------------------------------------------
import const
import constants
from dummylayer import DummyLayer
from dummynogps import DummyMapNoGpsPoint
from selectionlayer import SelectionLayer
from lifewaylayer import LifeWayLayer
from gen.ggettext import sgettext as _
from gen.ggettext import ngettext
from config import config
from QuestionDialog import ErrorDialog
#-------------------------------------------------------------------------
#
# Constants
#
#-------------------------------------------------------------------------
GEOGRAPHY_PATH = os.path.join(const.HOME_DIR, "maps")
#-------------------------------------------------------------------------
#
# osmGpsMap
# OsmGps
#
#-------------------------------------------------------------------------
@ -76,89 +71,28 @@ try:
except:
raise
class DummyMapNoGpsPoint(osmgpsmap.GpsMap):
def do_draw_gps_point(self, drawable):
pass
gobject.type_register(DummyMapNoGpsPoint)
class DummyLayer(gobject.GObject, osmgpsmap.GpsMapLayer):
def __init__(self):
gobject.GObject.__init__(self)
def do_draw(self, gpsmap, gdkdrawable):
pass
def do_render(self, gpsmap):
pass
def do_busy(self):
return False
def do_button_press(self, gpsmap, gdkeventbutton):
return False
gobject.type_register(DummyLayer)
class SelectionLayer(gobject.GObject, osmgpsmap.GpsMapLayer):
def __init__(self):
gobject.GObject.__init__(self)
self.circles = []
self.rectangles = []
def add_circle(self, r, lat, lon):
self.circles.append((r, lat, lon))
def add_rectangle(self, p1, p2):
self.rectangles.append((p1, p2))
def do_draw(self, gpsmap, drawable):
gc = drawable.new_gc()
for circle in self.circles:
top_left = osmgpsmap.point_new_degrees(circle[1] + circle[0],
circle[2] - circle[0])
bottom_right = osmgpsmap.point_new_degrees(circle[1] - circle[0],
circle[2] + circle[0])
x, y = gpsmap.convert_geographic_to_screen(top_left)
x2, y2 = gpsmap.convert_geographic_to_screen(bottom_right)
drawable.draw_arc(gc, False, x, y, x2 - x, y2 - y, 0, 360*64)
for rectangle in self.rectangles:
top_left, bottom_right = rectangle
x, y = gpsmap.convert_geographic_to_screen(top_left)
x2, y2 = gpsmap.convert_geographic_to_screen(bottom_right)
# be sure when can select a region in all case.
if ( x < x2 ):
if ( y < y2 ):
drawable.draw_rectangle(gc, False, x, y, x2 - x, y2 - y)
else:
drawable.draw_rectangle(gc, False, x, y2, x2 - x, y - y2)
else:
if ( y < y2 ):
drawable.draw_rectangle(gc, False, x2, y, x - x2, y2 - y)
else:
drawable.draw_rectangle(gc, False, x2, y2, x - x2, y - y2)
def do_render(self, gpsmap):
pass
def do_busy(self):
return False
def do_button_press(self, gpsmap, gdkeventbutton):
return False
gobject.type_register(SelectionLayer)
class osmGpsMap():
class OsmGps():
def __init__(self):
"""
Initialize the map
"""
self.vbox = None
self.cross_map = None
self.osm = None
self.show_tooltips = True
self.zone_selection = False
self.selection_layer = None
self.lifeway_layer = None
self.context_id = 0
self.begin_selection = None
self.end_selection = None
self.current_map = None
self.places_found = None
def build_widget(self):
"""
create the vbox
"""
self.vbox = gtk.VBox(False, 0)
cache_path = config.get('geography.path')
if not os.path.isdir(cache_path):
@ -169,16 +103,20 @@ class osmGpsMap():
cache_path )
return self.vbox
self.change_map(None,config.get("geography.map_service"))
self.change_map(None, config.get("geography.map_service"))
return self.vbox
def change_map(self, obj, map_type):
"""
Change the current map
"""
if obj is not None:
self.osm.layer_remove_all()
self.osm.image_remove_all()
self.vbox.remove(self.osm)
self.osm.destroy()
tiles_path=os.path.join(config.get('geography.path'), constants.tiles_path[map_type])
tiles_path = os.path.join(config.get('geography.path'),
constants.tiles_path[map_type])
if not os.path.isdir(tiles_path):
try:
os.makedirs(tiles_path, 0755) # create dir like mkdir -p
@ -197,6 +135,7 @@ class osmGpsMap():
self.osm.layer_add(current_map)
self.osm.layer_add(DummyLayer())
self.selection_layer = self.add_selection_layer()
self.lifeway_layer = self.add_lifeway_layer()
self.cross_map = osmgpsmap.GpsMapOsd( show_crosshair=False)
self.set_crosshair(config.get("geography.show_cross"))
self.osm.set_center_and_zoom(config.get("geography.center-lat"),
@ -209,48 +148,74 @@ class osmGpsMap():
self.osm.connect('changed', self.zoom_changed)
self.osm.show()
self.vbox.pack_start(self.osm)
if obj is not None:
self._createmap(None)
def add_selection_layer(self):
"""
add the selection layer
"""
selection_layer = SelectionLayer()
self.osm.layer_add(selection_layer)
return selection_layer
def get_selection_layer(self):
"""
get the selection layer
"""
return self.selection_layer
def add_lifeway_layer(self):
"""
add the track or life ways layer
"""
lifeway_layer = LifeWayLayer()
self.osm.layer_add(lifeway_layer)
return lifeway_layer
def get_lifeway_layer(self):
"""
get the track or life ways layer
"""
return self.lifeway_layer
def remove_layer(self, layer):
"""
remove the specified layer
"""
self.osm.layer_remove(layer)
def zoom_changed(self, zoom):
config.set("geography.zoom",self.osm.props.zoom)
"""
save the zoom and the position
"""
config.set("geography.zoom", self.osm.props.zoom)
self.save_center(self.osm.props.latitude, self.osm.props.longitude)
def motion_event(self, osmmap, event):
"""
Show the place name if found on the status bar
Moving during selection
"""
current = osmgpsmap.point_new_degrees(0.0,0.0)
current = osmgpsmap.point_new_degrees(0.0, 0.0)
osmmap.convert_screen_to_geographic(int(event.x), int(event.y), current)
lat, lon = current.get_degrees()
if self.zone_selection:
# We draw a rectangle to show the selected region.
layer = self.get_selection_layer()
if layer:
self.osm.layer_remove(layer)
self.selection_layer = self.add_selection_layer()
if self.end_selection == None:
self.selection_layer.add_rectangle(self.begin_selection, current)
else:
self.selection_layer.add_rectangle(self.begin_selection, self.end_selection)
# We draw a rectangle to show the selected region.
layer = self.get_selection_layer()
if layer:
self.osm.layer_remove(layer)
self.selection_layer = self.add_selection_layer()
if self.end_selection == None:
self.selection_layer.add_rectangle(self.begin_selection,
current)
else:
self.selection_layer.add_rectangle(self.begin_selection,
self.end_selection)
else:
places = self.is_there_a_place_here(lat, lon)
mess = ""
for p in places:
for plc in places:
if mess != "":
mess += " || "
mess += p[0]
mess += plc[0]
self.uistate.status.pop(self.context_id)
self.context_id = self.uistate.status.push(1, mess)
@ -260,8 +225,8 @@ class osmGpsMap():
"""
_LOG.debug("save_center : %s,%s" % (lat, lon) )
if ( -90.0 < lat < +90.0 ) and ( -180.0 < lon < +180.0 ):
config.set("geography.center-lat",lat)
config.set("geography.center-lon",lon)
config.set("geography.center-lat", lat)
config.set("geography.center-lon", lon)
else:
_LOG.debug("save_center : new coordinates : %s,%s" % (lat, lon) )
_LOG.debug("save_center : old coordinates : %s,%s" % (lat, lon) )
@ -271,13 +236,22 @@ class osmGpsMap():
config.get("geography.zoom") )
def activate_selection_zoom(self, osm, event):
"""
Zoom when in zone selection
"""
if self.end_selection is not None:
self._autozoom()
return True
def map_clicked(self, osm, event):
lat,lon = self.osm.get_event_location(event).get_degrees()
current = osmgpsmap.point_new_degrees(0.0,0.0)
"""
Someone click on the map. Look at if we have a marker.
mouse button 1 : zone selection or marker selection
mouse button 2 : begin zone selection
mouse button 3 : call the menu
"""
lat, lon = self.osm.get_event_location(event).get_degrees()
current = osmgpsmap.point_new_degrees(0.0, 0.0)
osm.convert_screen_to_geographic(int(event.x), int(event.y), current)
lat, lon = current.get_degrees()
if event.button == 1:
@ -286,24 +260,23 @@ class osmGpsMap():
self.end_selection = None
else:
# do we click on a marker ?
marker = self.is_there_a_marker_here(event, lat, lon)
self.is_there_a_marker_here(event, lat, lon)
elif event.button == 2 and event.type == gtk.gdk.BUTTON_PRESS:
self.begin_selection = current
self.end_selection = None
self.zone_selection = True
self.begin_selection = current
self.end_selection = None
self.zone_selection = True
elif event.button == 2 and event.type == gtk.gdk.BUTTON_RELEASE:
self.end_selection = current
self.zone_selection = False
self.end_selection = current
self.zone_selection = False
elif event.button == 3:
self.build_nav_menu(osm, event, lat, lon )
else:
self.save_center(lat,lon)
self.save_center(lat, lon)
def is_there_a_place_here(self, lat, lon):
"""
Is there a place at this position ?
"""
found = False
mark_selected = []
oldplace = ""
for mark in self.places_found:
@ -312,11 +285,12 @@ class osmGpsMap():
if mark[0] != oldplace:
oldplace = mark[0]
precision = {
1 : '%3.0f', 2 : '%3.1f', 3 : '%3.1f', 4 : '%3.1f',
5 : '%3.2f', 6 : '%3.2f', 7 : '%3.2f', 8 : '%3.3f',
9 : '%3.3f', 10 : '%3.3f', 11 : '%3.3f', 12 : '%3.3f',
13 : '%3.3f', 14 : '%3.4f', 15 : '%3.4f', 16 : '%3.4f',
17 : '%3.4f', 18 : '%3.4f'
1 : '%3.0f', 2 : '%3.1f', 3 : '%3.1f',
4 : '%3.1f', 5 : '%3.2f', 6 : '%3.2f',
7 : '%3.2f', 8 : '%3.3f', 9 : '%3.3f',
10 : '%3.3f', 11 : '%3.3f', 12 : '%3.3f',
13 : '%3.3f', 14 : '%3.4f', 15 : '%3.4f',
16 : '%3.4f', 17 : '%3.4f', 18 : '%3.4f'
}.get(config.get("geography.zoom"), '%3.1f')
shift = {
1 : 5.0, 2 : 5.0, 3 : 3.0,
@ -339,13 +313,21 @@ class osmGpsMap():
lonok = True
if latok and lonok:
mark_selected.append(mark)
found = True
return mark_selected
def is_there_a_marker_here(self, lat, lon):
def build_nav_menu(self, osm, event, lat, lon):
"""
Must be implemented in the caller class
"""
raise NotImplementedError
def set_crosshair(self,active):
def is_there_a_marker_here(self, event, lat, lon):
"""
Must be implemented in the caller class
"""
raise NotImplementedError
def set_crosshair(self, active):
"""
Show or hide the crosshair ?
"""
@ -357,4 +339,3 @@ class osmGpsMap():
self.osm.zoom_out()
else:
self.osm.layer_remove(self.cross_map)
pass

View File

@ -0,0 +1,256 @@
# -*- python -*-
# -*- coding: utf-8 -*-
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2011-2012 Serge Noiraud
#
# 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: geography.py 18338 2011-10-16 20:21:22Z paul-franklin $
#-------------------------------------------------------------------------
#
# Python modules
#
#-------------------------------------------------------------------------
from gen.ggettext import sgettext as _
import re
import gobject
import math
#------------------------------------------------------------------------
#
# Set up logging
#
#------------------------------------------------------------------------
import logging
_LOG = logging.getLogger("maps.placeselection")
#-------------------------------------------------------------------------
#
# GTK/Gnome modules
#
#-------------------------------------------------------------------------
import gtk
#-------------------------------------------------------------------------
#
# Gramps Modules
#
#-------------------------------------------------------------------------
import Errors
import ManagedWindow
from osmGps import OsmGps
#-------------------------------------------------------------------------
#
# Functions and variables
#
#-------------------------------------------------------------------------
PLACE_REGEXP = re.compile('<span background="green">(.*)</span>')
PLACE_STRING = '<span background="green">%s</span>'
def match(self, lat, lon, radius):
"""
coordinates matching.
"""
rds = float(radius)
self.places = []
# place
for entry in self.place_list:
if (math.hypot(lat-float(entry[3]),
lon-float(entry[4])) <= rds) == True:
# Do we already have this place ? avoid duplicates
self.get_location(entry[9])
if not [self.country, self.state, self.county] in self.places:
self.places.append([self.country, self.state, self.county])
return self.places
#-------------------------------------------------------------------------
#
# PlaceSelection
#
#-------------------------------------------------------------------------
class PlaceSelection(ManagedWindow.ManagedWindow, OsmGps):
"""
We show a selection box for possible places in a region of the map.
We can select the diameter of the region which is a circle.
Depending of this region, we can show the possible choice.
We select the value depending of our need which open the EditPlace box.
"""
def __init__(self, uistate, dbstate, maps, layer, places, lat, lon,
function, oldvalue=None):
"""
Place Selection initialization
"""
try:
ManagedWindow.ManagedWindow.__init__(self, uistate, [],
PlaceSelection)
except Errors.WindowActiveError:
return
self.uistate = uistate
self.dbstate = dbstate
self.lat = lat
self.lon = lon
self.osm = maps
self.country = None
self.state = None
self.county = None
self.radius = 1.0
self.circle = None
self.oldvalue = oldvalue
self.place_list = places
self.function = function
self.selection_layer = layer
self.layer = layer
alignment = gtk.Alignment(0, 1, 0, 0)
self.set_window(
gtk.Dialog(_('Place Selection in a region'),
flags=gtk.DIALOG_NO_SEPARATOR,
buttons=(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE)),
None, _('Place Selection in a region'), None)
label = gtk.Label(_('Choose the radius of the selection.\n'
'On the map you should see a circle or an'
' oval depending on the latitude.'))
alignment.add(label)
self.window.vbox.pack_start(alignment, expand=False)
adj = gtk.Adjustment(1.0, 0.1, 3.0, 0.1, 0, 0)
# default value is 1.0, minimum is 0.1 and max is 3.0
slider = gtk.HScale(adj)
slider.set_update_policy(gtk.UPDATE_DISCONTINUOUS)
slider.set_digits(1)
slider.set_value_pos(gtk.POS_BOTTOM)
slider.connect('value-changed', self.slider_change, self.lat, self.lon)
self.window.vbox.pack_start(slider, expand=False)
self.vadjust = gtk.Adjustment(page_size=15)
self.scroll = gtk.ScrolledWindow(self.vadjust)
self.scroll.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
self.scroll.set_shadow_type(gtk.SHADOW_IN)
self.plist = gtk.ListStore(str, str, str)
self.choices = gtk.TreeView(self.plist)
self.scroll.add(self.choices)
self.renderer = gtk.CellRendererText()
self.tvcol1 = gtk.TreeViewColumn(_('Country'), self.renderer, markup=0)
self.tvcol2 = gtk.TreeViewColumn(_('State'), self.renderer, markup=1)
self.tvcol3 = gtk.TreeViewColumn(_('County'), self.renderer, markup=2)
self.tvcol1.set_sort_column_id(0)
self.tvcol2.set_sort_column_id(1)
self.tvcol3.set_sort_column_id(2)
self.choices.append_column(self.tvcol1)
self.choices.append_column(self.tvcol2)
self.choices.append_column(self.tvcol3)
self.window.vbox.pack_start(self.scroll, expand=True)
self.label2 = gtk.Label()
self.label2.set_markup('<span background="green" foreground="black"'
'>%s</span>' %
_('The green values in the row correspond '
'to the current place values.'))
alignment = gtk.Alignment(0, 1, 0, 0)
alignment.add(self.label2)
self.window.vbox.pack_start(alignment, expand=False)
self.window.set_default_size(400, 300)
self.choices.connect('row-activated', self.selection, function)
self.window.connect('response', self.close)
self.window.show_all()
self.show()
self.label2.hide()
self.slider_change(None, lat, lon)
def close(self, *obj):
"""
Close the selection place editor
"""
self.hide_the_region()
ManagedWindow.ManagedWindow.close(self, *obj)
def slider_change(self, obj, lat, lon):
"""
Display on the map a circle in which we select all the places inside this region.
"""
self.radius = obj.get_value() if obj else 1.0
self.show_the_region(self.radius)
match(self, lat, lon, self.radius)
self.plist.clear()
if self.oldvalue != None:
# The old values are always in the first row.
# In this case, we change the color of the row.
# display the associated message
self.label2.show()
field1, field2, field3 = self.oldvalue
self.plist.append((PLACE_STRING % field1,
PLACE_STRING % field2,
PLACE_STRING % field3)
)
for place in self.places:
self.plist.append(place)
# here, we could add value from geography names services ...
# if we found no place, we must create a default place.
self.plist.append((_("New place with empty fields"), "", "..."))
def hide_the_region(self):
"""
Hide the layer which contains the circle
"""
layer = self.get_selection_layer()
if layer:
self.remove_layer(layer)
def show_the_region(self, rds):
"""
Show a circle in which we select the places.
"""
# circle (rds)
self.hide_the_region()
self.selection_layer = self.add_selection_layer()
self.selection_layer.add_circle(rds, self.lat, self.lon)
def get_location(self, place):
"""
get location values
"""
place = self.dbstate.db.get_place_from_gramps_id(place)
loc = place.get_main_location()
data = loc.get_text_data_list()
# new background or font color on gtk fields ?
self.country = data[6]
self.state = data[5]
self.county = data[4]
return(self.country, self.state, self.county)
def selection(self, obj, index, column, function):
"""
get location values and call the real function : add_place, edit_place
"""
if self.plist[index][2] == "...":
# case with blank values ( New place with empty fields )
self.function( "", "", "", self.lat, self.lon)
elif self.plist[index][0][1:5] == "span":
# case with old values ( keep the old values of the place )
name = PLACE_REGEXP.search(self.plist[index][0], 0)
country = name.group(1)
name = PLACE_REGEXP.search(self.plist[index][1], 0)
state = name.group(1)
name = PLACE_REGEXP.search(self.plist[index][2], 0)
county = name.group(1)
self.function( country, county, state, self.lat, self.lon)
else:
# Set the new values of the country, county and state fields.
self.function( self.plist[index][0], self.plist[index][2],
self.plist[index][1], self.lat, self.lon)

View File

@ -0,0 +1,133 @@
# -*- python -*-
# -*- coding: utf-8 -*-
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2011-2012 Serge Noiraud
#
# 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: grampsmaps.py 18399 2011-11-02 17:15:20Z noirauds $
#-------------------------------------------------------------------------
#
# Python modules
#
#-------------------------------------------------------------------------
import os
import gobject
#------------------------------------------------------------------------
#
# Set up logging
#
#------------------------------------------------------------------------
import logging
_LOG = logging.getLogger("maps.selectionlayer")
#-------------------------------------------------------------------------
#
# Gramps Modules
#
#-------------------------------------------------------------------------
import const
#-------------------------------------------------------------------------
#
# osmGpsMap
#
#-------------------------------------------------------------------------
try:
import osmgpsmap
except:
raise
class SelectionLayer(gobject.GObject, osmgpsmap.GpsMapLayer):
def __init__(self):
"""
Initialize thz selection layer
"""
gobject.GObject.__init__(self)
self.circles = []
self.rectangles = []
def add_circle(self, rds, lat, lon):
"""
Add a circle
"""
self.circles.append((rds, lat, lon))
def add_rectangle(self, cp1, cp2):
"""
Add a rectangle
"""
self.rectangles.append((cp1, cp2))
def do_draw(self, gpsmap, drawable):
"""
draw the circles and the rectangles
"""
ggc = drawable.new_gc()
for circle in self.circles:
top_left = osmgpsmap.point_new_degrees(circle[1] + circle[0],
circle[2] - circle[0])
bottom_right = osmgpsmap.point_new_degrees(circle[1] - circle[0],
circle[2] + circle[0])
crd_x, crd_y = gpsmap.convert_geographic_to_screen(top_left)
crd_x2, crd_y2 = gpsmap.convert_geographic_to_screen(bottom_right)
drawable.draw_arc(ggc, False, crd_x, crd_y, crd_x2 - crd_x,
crd_y2 - crd_y, 0, 360*64)
for rectangle in self.rectangles:
top_left, bottom_right = rectangle
crd_x, crd_y = gpsmap.convert_geographic_to_screen(top_left)
crd_x2, crd_y2 = gpsmap.convert_geographic_to_screen(bottom_right)
# be sure when can select a region in all case.
if ( crd_x < crd_x2 ):
if ( crd_y < crd_y2 ):
drawable.draw_rectangle(ggc, False, crd_x, crd_y,
crd_x2 - crd_x, crd_y2 - crd_y)
else:
drawable.draw_rectangle(ggc, False, crd_x, crd_y2,
crd_x2 - crd_x, crd_y - crd_y2)
else:
if ( crd_y < crd_y2 ):
drawable.draw_rectangle(ggc, False, crd_x2, crd_y,
crd_x - crd_x2, crd_y2 - crd_y)
else:
drawable.draw_rectangle(ggc, False, crd_x2, crd_y2,
crd_x - crd_x2, crd_y - crd_y2)
def do_render(self, gpsmap):
"""
render the layer
"""
pass
def do_busy(self):
"""
set the map busy
"""
return False
def do_button_press(self, gpsmap, gdkeventbutton):
"""
Someone press a button
"""
return False
gobject.type_register(SelectionLayer)