# -*- python -*- # -*- coding: utf-8 -*- # # Gramps - a GTK+/GNOME based genealogy program # # Copyright (C) 2007-2008 Serge Noiraud # Copyright (C) 2008 Benny Malengier # # 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$ """ Geo View """ #------------------------------------------------------------------------- # # Python modules # #------------------------------------------------------------------------- from gettext import gettext as _ import os import urlparse import const import operator #------------------------------------------------------------------------- # # GTK/Gnome modules # #------------------------------------------------------------------------- import gtk #------------------------------------------------------------------------- # # Gramps Modules # #------------------------------------------------------------------------- import gen.lib import PageView import Utils import Config from const import TEMP_DIR from BasicUtils import name_displayer as _nd from PlaceUtils import conv_lat_lon #------------------------------------------------------------------------- # # Web interfaces # #------------------------------------------------------------------------- NOWEB = 0 WEBKIT = 1 MOZIL = 2 TOOLKIT = NOWEB try: import webkit TOOLKIT = WEBKIT except: pass if TOOLKIT == NOWEB: try: import gtkmozembed TOOLKIT = MOZIL except: pass #no interfaces present, raise Error so that options for GeoView do not show if TOOLKIT == NOWEB : Config.set(Config.GEOVIEW, False) raise ImportError, 'No GTK html plugin found' #------------------------------------------------------------------------- # # Constants # #------------------------------------------------------------------------- # I think we should set the two following variable in const.py # They are used only with gtkmozembed. MOZEMBED_PATH = TEMP_DIR MOZEMBED_SUBPATH = Utils.get_empty_tempdir('mozembed_gramps') GEOVIEW_SUBPATH = Utils.get_empty_tempdir('geoview') NB_MARKERS_PER_PAGE = 200 #------------------------------------------------------------------------- # # Functions # #------------------------------------------------------------------------- def _alternate_map(): """ return the alternate name of the map provider. """ if Config.get(Config.GEOVIEW_GOOGLEMAPS): alternate_map = "google" elif Config.get(Config.GEOVIEW_OPENLAYERS): alternate_map = "openlayers" elif Config.get(Config.GEOVIEW_YAHOO): alternate_map = "yahoo" elif Config.get(Config.GEOVIEW_MICROSOFT): alternate_map = "microsoft" return alternate_map #------------------------------------------------------------------------- # # Renderer # #------------------------------------------------------------------------- class Renderer(): """ Renderer renders the webpage. Several backend implementations are possible """ def __init__(self): self.window = None self.fct = () def get_window(self): """ Returns a container class with the widget that contains browser window """ return self.window def get_uri(self): """ Get the current url """ raise NotImplementedError def show_all(self): """ show all in the main window. """ self.window.show_all() def open(self, url): """ open the webpage at url """ raise NotImplementedError def refresh(self): """ We need to reload the page. """ raise NotImplementedError def go_back(self): """ Go to the previous page. """ self.window.go_back() def can_go_back(self): """ is the browser able to go backward ? """ return self.window.can_go_back() def go_forward(self): """ Go to the next page. """ self.window.go_forward() def can_go_forward(self): """ is the browser able to go forward ? """ return self.window.can_go_forward() def execute_script(self, url): """ execute javascript in the current html page """ raise NotImplementedError def page_loaded(self, *args): """ The page is completely loaded. """ raise NotImplementedError def set_button_sensitivity(self): """ We must set the back and forward button in the HtmlView class. """ self.fct() #------------------------------------------------------------------------- # # Renderer with WebKit # #------------------------------------------------------------------------- class RendererWebkit(Renderer): """ Implementation of Renderer with Webkit """ def __init__(self): Renderer.__init__(self) self.window = webkit.WebView() self.browser = WEBKIT self.frame = self.window.get_main_frame() self.frame.connect("load-done", self.page_loaded) def page_loaded(self, *args): """ We just loaded one page in the browser. Set the button sensitivity """ self.set_button_sensitivity() def open(self, url): """ We need to load the page in the browser. """ self.window.open(url) def refresh(self): """ We need to reload the page in the browser. """ self.window.reload() def execute_script(self, url): """ We need to execute a javascript function into the browser """ self.window.execute_script(url) def get_uri(self): """ What is the uri loaded in the browser ? """ return self.window.get_main_frame().get_uri() class RendererMozilla(Renderer): """ Implementation of Renderer with gtkmozembed """ def __init__(self): Renderer.__init__(self) if hasattr(gtkmozembed, 'set_profile_path'): set_profile_path = gtkmozembed.set_profile_path else: set_profile_path = gtkmozembed.gtk_moz_embed_set_profile_path set_profile_path(MOZEMBED_PATH, MOZEMBED_SUBPATH) self.__set_mozembed_proxy() self.window = gtkmozembed.MozEmbed() self.browser = MOZIL self.handler = self.window.connect("net-stop", self.page_loaded) def page_loaded(self, *args): """ We just loaded one page in the browser. Set the button sensitivity """ self.set_button_sensitivity() def open(self, url): """ We need to load the page in the browser. """ self.window.load_url(url) def execute_script(self, url): """ We need to execute a javascript function into the browser """ self.window.load_url(url) def get_uri(self): """ What is the uri loaded in the browser ? """ return self.window.get_location() def refresh(self): """ We need to reload the page in the browser. """ self.window.reload(0) def __set_mozembed_proxy(self): """ Try to see if we have some proxy environment variable. http_proxy in our case. The standard format is : http://[user:password@]proxy:port/ """ try: proxy = os.environ['http_proxy'] if proxy: host_port = None prefs = open(MOZEMBED_SUBPATH+"/prefs.js", "w+") parts = urlparse.urlparse(proxy) if not parts[0] or parts[0] == 'http': host_port = parts[1] hport = host_port.split(':') host = hport[0].strip() if host: try: port = int(hport[1]) except: user = host uprox = hport[1].split('@') password = uprox[0] host = uprox[1] port = int(hport[2]) if port and host: port = str(port) prefs.write('user_pref("network.proxy') prefs.write('.type", 1);\r\n') prefs.write('user_pref("network.proxy') prefs.write('.http", "'+host+'");\r\n') prefs.write('user_pref("network.proxy') prefs.write('.http_port", '+port+');\r\n') prefs.write('user_pref("network.proxy') prefs.write('.no_proxies_on",') prefs.write(' "127.0.0.1,localhost,localhost') prefs.write('.localdomain");\r\n') prefs.write('user_pref("network.proxy') prefs.write('.share_proxy_settings", true);\r\n') prefs.write('user_pref("network.http') prefs.write('.proxy.pipelining", true);\r\n') prefs.write('user_pref("network.http') prefs.write('.proxy.keep-alive", true);\r\n') prefs.write('user_pref("network.http') prefs.write('.proxy.version", 1.1);\r\n') prefs.write('user_pref("network.http') prefs.write('.sendRefererHeader, 0);\r\n') prefs.close() except: try: # trying to remove pref.js in case of proxy change. os.remove(MOZEMBED_SUBPATH+"/prefs.js") except: pass #------------------------------------------------------------------------- # # HtmlView # #------------------------------------------------------------------------- class HtmlView(PageView.PageView): """ HtmlView is a view showing a top widget with controls, and a bottom part with an embedded webbrowser showing a given URL """ def __init__(self, dbstate, uistate, title=_('HtmlView')): PageView.PageView.__init__(self, title, dbstate, uistate) self.dbstate = dbstate self.external_url = False self.need_to_resize = False self.back_action = None self.forward_action = None self.renderer = None self.urlfield = "" self.htmlfile = "" self.table = "" self.bootstrap_handler = None self.box = None def build_widget(self): """ Builds the interface and returns a gtk.Container type that contains the interface. This containter will be inserted into a gtk.Notebook page. """ self.box = gtk.VBox(False, 4) #top widget at the top self.box.pack_start(self.top_widget(), False, False, 0 ) #web page under it in a scrolled window self.table = gtk.Table(1, 1, False) frame = gtk.ScrolledWindow(None, None) frame.set_shadow_type(gtk.SHADOW_NONE) frame.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) frame.add_with_viewport(self.table) self.bootstrap_handler = self.box.connect("size-request", self.init_parent_signals_for_map) self.table.get_parent().set_shadow_type(gtk.SHADOW_NONE) self.table.set_row_spacings(1) self.table.set_col_spacings(0) if (TOOLKIT == WEBKIT) : # We use webkit self.renderer = RendererWebkit() elif (TOOLKIT == MOZIL) : # We use gtkmozembed self.renderer = RendererMozilla() self.table.add(self.renderer.get_window()) self.box.pack_start(frame, True, True, 0) # this is used to activate the back and forward button # from the renderer class. self.renderer.fct = self.set_button_sensitivity self.renderer.show_all() #load a welcome html page urlhelp = self._create_start_page() self.open(urlhelp) return self.box def top_widget(self): """ The default class gives a widget where user can type an url """ hbox = gtk.HBox(False, 4) self.urlfield = gtk.Entry() self.urlfield.set_text("http://gramps-project.org") self.urlfield.connect('activate', self._on_activate) hbox.pack_start(self.urlfield, True, True, 4) button = gtk.Button(stock=gtk.STOCK_APPLY) button.connect('clicked', self._on_activate) hbox.pack_start(button, False, False, 4) return hbox def set_button_sensitivity(self): """ Set the backward and forward button in accordance to the browser. """ self.forward_action.set_sensitive(self.renderer.can_go_forward()) self.back_action.set_sensitive(self.renderer.can_go_back()) def open(self, url): """ open an url """ self.renderer.open(url) def go_back(self, button): """ Go to the previous loaded url. """ self.renderer.go_back() self.set_button_sensitivity() self.external_uri() def go_forward(self, button): """ Go to the next loaded url. """ self.renderer.go_forward() self.set_button_sensitivity() self.external_uri() def refresh(self, button): """ Force to reload the page. """ self.renderer.refresh() def external_uri(self): """ used to resize or not resize depending on external or local file. """ uri = self.renderer.get_uri() if self.external_url: self.external_url = False self.need_to_resize = True else: try: if uri.find(self.htmlfile) == -1: # external web page or start_page self.need_to_resize = True else: self.need_to_resize = False except: pass def _on_activate(self, nobject): """ Here when we activate the url button. """ url = self.urlfield.get_text() if url.find('://') == -1: url = 'http://'+ url self.external_url = True self.open(url) def build_tree(self): """ Rebuilds the current display. Called from ViewManager """ pass #htmlview is build on click and startup def get_stock(self): """ Returns the name of the stock icon to use for the display. This assumes that this icon has already been registered with GNOME as a stock icon. """ return 'gramps-geo' def ui_definition(self): """ Specifies the UIManager XML code that defines the menus and buttons associated with the interface. """ return ''' ''' def define_actions(self): """ Required define_actions function for PageView. Builds the action group information required. """ HtmlView._define_actions_fw_bw(self) def _define_actions_fw_bw(self): """ prepare the forward and backward buttons. add the Backward action to handle the Backward button accel doesn't work in webkit and gtkmozembed ! we must do that ... """ self.back_action = gtk.ActionGroup(self.title + '/Back') self.back_action.add_actions([ ('Back', gtk.STOCK_GO_BACK, _("_Back"), "Left", _("Go to the previous page in the history"), self.go_back) ]) self._add_action_group(self.back_action) # add the Forward action to handle the Forward button self.forward_action = gtk.ActionGroup(self.title + '/Forward') self.forward_action.add_actions([ ('Forward', gtk.STOCK_GO_FORWARD, _("_Forward"), "Right", _("Go to the next page in the history"), self.go_forward) ]) self._add_action_group(self.forward_action) # add the Refresh action to handle the Refresh button self._add_action('Refresh', gtk.STOCK_REFRESH, _("_Refresh"), callback=self.refresh, accel="R", tip=_("Stop and reload the page.")) def init_parent_signals_for_map(self, widget, event): """ Required to properly bootstrap the signal handlers. This handler is connected by build_widget. After the outside ViewManager has placed this widget we are able to access the parent container. """ pass def _create_start_page(self): """ This command creates a default start page, and returns the URL of this page. """ tmpdir = GEOVIEW_SUBPATH data = """ %(title)s

%(content)s

""" % { 'height' : 600, 'title' : _('Start page for the Html View'), 'content': _('Type a webpage address at the top, and hit' ' the execute button to load a webpage in this' ' page\n
\n' 'For example: http://gramps-project.org

') } filename = os.path.join(tmpdir, 'startpage') ufd = file(filename, "w+") ufd.write(data) ufd.close() return 'file://'+filename #------------------------------------------------------------------------- # # GeoView # #------------------------------------------------------------------------- class GeoView(HtmlView): """ The view used to render html pages. """ def __init__(self, dbstate, uistate): HtmlView.__init__(self, dbstate, uistate, title=_('GeoView')) self.usedmap = "openstreetmap" self.displaytype = "person" self.nbmarkers = 0 self.without = 0 self.nbpages = 0 self.yearinmarker = [] self.mustcenter = False self.centerlat = 0.0 self.centerlon = 0.0 self.setattr = True self.latit = 0.0 self.longt = 0.0 self.maxlat = 0.0 self.maxlon = 0.0 self.height = 0.0 self.width = 0.0 self.zoom = 1 self.minyear = 1 self.maxyear = 1 self.maxgen = 1 self.mapview = None self.yearint = 0 self.centered = True self.center = True self.place_list = [] self.htmlfile = "" self.places = [] self.sort = [] self.without_coord_file = [] self.place_without_coordinates = [] self.minlat = float(0.0) self.maxlat = float(0.0) self.minlon = float(0.0) self.key_active_changed = None def top_widget(self): """ The top widget to use, for GeoView, none """ return gtk.Label() def on_delete(self): """ We need to suppress temporary files here. """ pass def init_parent_signals_for_map(self, widget, event): """ Required to properly bootstrap the signal handlers. This handler is connected by build_widget. After the outside ViewManager has placed this widget we are able to access the parent container. """ self.box.disconnect(self.bootstrap_handler) self.box.parent.connect("size-allocate", self._size_request_for_map) self._size_request_for_map(widget.parent, event) def _size_request_for_map(self, widget, event, data=None): """ We need to resize the map """ gws = widget.get_allocation() self.width = gws.width self.height = gws.height #uri = self.renderer.get_uri() self.external_uri() if self.need_to_resize != True: try: self._geo_places(self.displaytype) except: pass def set_active(self): """ Set view active when we enter into this view. """ self.key_active_changed = self.dbstate.connect('active-changed', self.goto_active_person) def set_inactive(self): """ Set view inactive when switching to another view. """ HtmlView.set_inactive(self) self.dbstate.disconnect(self.key_active_changed) def _change_map(self, usedmap): """ Tell the browser to change the current map. """ self.renderer.execute_script( "javascript:swap_map('"+usedmap+"','"+usedmap+"')") def ui_definition(self): """ Specifies the UIManager XML code that defines the menus and buttons associated with the interface. """ return ''' ''' % _alternate_map() def define_actions(self): """ Required define_actions function for PageView. Builds the action group information required. """ HtmlView._define_actions_fw_bw(self) self.forward_action.set_sensitive(False) self.back_action.set_sensitive(False) self._add_action('OpenStreetMap', 'gramps-geoview', _('_OpenStreetMap'), callback=self._select_openstreetmap_map, tip=_("Select OpenStreetMap Maps")) if Config.get(Config.GEOVIEW_GOOGLEMAPS): self._add_action('google', 'gramps-geoview-alt', _('_Google Maps'), callback=self._select_google_map, tip=_("Select Google Maps.")) elif Config.get(Config.GEOVIEW_OPENLAYERS): self._add_action('openlayers', 'gramps-geoview-alt', _('_OpenLayers Maps'), callback=self._select_openlayers_map, tip=_("Select OpenLayers Maps.")) elif Config.get(Config.GEOVIEW_YAHOO): self._add_action('yahoo', 'gramps-geoview-alt', _('_Yahoo! Maps'), callback=self._select_yahoo_map, tip=_("Select Yahoo Maps.")) elif Config.get(Config.GEOVIEW_MICROSOFT): self._add_action('microsoft', 'gramps-geoview-alt', _('_Microsoft Maps'), callback=self._select_microsoft_map, tip=_("Select Microsoft Maps")) self._add_action('AllPlacesMaps', gtk.STOCK_HOME, _('_All Places'), callback=self._all_places, tip=_("Attempt to view all places in " "the family tree.")) self._add_action('PersonMaps', 'gramps-person', _('_Person'), callback=self._person_places, tip=_("Attempt to view all the places " "where the selected people lived.")) self._add_action('FamilyMaps', 'gramps-parents-add', _('_Family'), callback=self._family_places, tip=_("Attempt to view places of the selected people's family.")) self._add_action('EventMaps', 'gramps-event', _('_Event'), callback=self._event_places, tip=_("Attempt to view places connected to all events.")) def goto_active_person(self, handle=None): """ Here when the GeoView page is loaded """ self._geo_places(self.displaytype) def _all_places(self, hanle=None): """ Specifies the place for the home person to display with mapstraction. """ self.displaytype = "places" self._geo_places(self.displaytype) def _person_places(self, handle=None): """ Specifies the person places. """ self.displaytype = "person" self._geo_places(self.displaytype) def _family_places(self, hanle=None): """ Specifies the family places to display with mapstraction. """ self.displaytype = "family" self._geo_places(self.displaytype) def _event_places(self, hanle=None): """ Specifies all event places to display with mapstraction. """ self.displaytype = "event" self._geo_places(self.displaytype) def _geo_places(self, displaytype): """ Specifies the places to display with mapstraction. """ self.external_url = False self.nbmarkers = 0 self.without = 0 self._createmapstraction(displaytype) self.open("file://"+self.htmlfile) def _select_openstreetmap_map(self, handle): """ Make openstreetmap the default map. """ self.usedmap = "openstreetmap" self._change_map("openstreetmap") def _select_openlayers_map(self, handle): """ Make openstreetmap the default map. """ self.usedmap = "openlayers" self._change_map("openlayers") def _select_google_map(self, handle): """ Specifies google is the default map """ self.usedmap = "google" self._change_map("google") def _select_yahoo_map(self, handle): """ Make yahoo map the default map. """ self.usedmap = "yahoo" self._change_map("yahoo") def _select_microsoft_map(self, handle): """ Make microsoft the default map. """ self.usedmap = "microsoft" self._change_map("microsoft") def _createpageplaceswithoutcoord(self): """ Create a page with the list of all places without coordinates page. """ data = """ %(title)s

%(content)s

""" % { 'title' : _('List of places without coordinates'), 'content': _('Here is the list of all places in the family tree' ' for which we have no coordinates.
' ' This means no longitude or latitude.

') } end = """ """ ufd = open(self.without_coord_file, "w+") ufd.write(data) self.places = sorted(self.place_without_coordinates) i = 1 ufd.write("") ufd.write("") for place in self.places: ufd.write("" % ( i, place[0], place[1] )) i += 1 ufd.write(end) ufd.close() def _createmapstractionpostheader(self, h3mess, h4mess, maxpages, curpage, ftype): """ This is needed to add infos to the header. This can't be in createmapstractionheader because we need to know something which is known only after some work. """ self.maxgen = Config.get(Config.GENERATION_DEPTH) if self.maxyear == 0: self.maxyear = 2100 if self.minyear == 9999: self.minyear = 1500 period = (self.maxyear-self.minyear) intvl = (period/self.maxgen) modulo = intvl - ( intvl % 10 ) if modulo == 0: modulo = 10 self.minyear = ( self.minyear - ( self.minyear % 10 ) ) self.maxyear = ( self.maxyear - ( self.maxyear % 10 ) ) self.yearint = (self.maxyear-self.minyear)/self.maxgen self.yearint = ( self.yearint - ( self.yearint % modulo ) ) if self.yearint == 0: self.yearint = 10 self.mapview.write("\n") self.mapview.write("\n") self.mapview.write("\n") if maxpages > 1: message = _("There are %d markers to display. They are split up " "over %d pages of %d markers : " % (self.nbmarkers, maxpages, NB_MARKERS_PER_PAGE)) self.mapview.write("
%s
\n" % message) if curpage != 1: priorfile = GEOVIEW_SUBPATH+"/GeoV-%c-%05d.html" % \ (ftype, curpage-1) self.mapview.write("--" % priorfile) else: self.mapview.write(" --") for page in range(1, maxpages+1, 1): if page == curpage: self.mapview.write(" %d" % page) else: if ( page < curpage + 11 ) and ( page > curpage - 11 ): nextfile = GEOVIEW_SUBPATH+"/GeoV-%c-%05d.html" % \ (ftype, page) self.mapview.write(" %d" % \ (nextfile, page)) if curpage != maxpages: nextfile = GEOVIEW_SUBPATH+"/GeoV-%c-%05d.html" % \ (ftype, curpage+1) self.mapview.write(" ++" % nextfile) else: self.mapview.write(" ++") self.mapview.write("\n
\n") if self.without != 0: self.without_coord_file = GEOVIEW_SUBPATH+"/without_coord.html" self.mapview.write("\n" ) self._createpageplaceswithoutcoord() if self.displaytype != "places": #self.mapview.write("
\n") self.mapview.write("
\n") self.mapview.write(" %s\n" % _("All")) for year in range(self.minyear, self.maxyear+self.yearint, self.yearint): self.mapview.write(" %s\n" % ( year, year )) self.mapview.write(" \n") #self.mapview.write("
\n") self.mapview.write("

%s

" % h3mess) if h4mess: self.mapview.write("

%s

" % h4mess) margin = 10 self.mapview.write("\n
\n" % (self.height * 0.74)) self.mapview.write("
\n" % \ ((self.width - margin*4), (self.height * 0.74 ))) self.mapview.write("\n") self.mapview.write("\n") if self.usedmap == "microsoft": self.mapview.write("\n") elif self.usedmap == "yahoo": self.mapview.write("\n") elif self.usedmap == "openlayers": self.mapview.write("\n") def _createmapstractiontrailer(self): """ Add the last directives for the html page. """ self.mapview.write(" setcenterandzoom(mapstraction);\n") self.mapview.write(" setmarkers(mapstraction);\n") self.mapview.write("\n") self.mapview.write("\n") self.mapview.write("\n") self.mapview.close() def _set_center_and_zoom(self, ptype): """ Calculate the zoom. """ # Select the center of the map and the zoom self.centered = False if ptype == 2: # Sort by year for events self.sort = sorted(self.place_list, key=operator.itemgetter(7)) else: # Sort by place self.sort = sorted(self.place_list) if self.minlon < 0.0: signminlon = 1 else: signminlon = 0 if self.maxlon < 0.0: signmaxlon = 1 else: signmaxlon = 0 if self.minlat < 0.0: signminlat = 1 else: signminlat = 0 if self.maxlat < 0.0: signmaxlat = 1 else: signmaxlat = 0 if signminlon == signmaxlon: maxlong = abs(abs(self.minlon)-abs(self.maxlon)) else: maxlong = abs(abs(self.minlon)+abs(self.maxlon)) if signminlat == signmaxlat: maxlat = abs(abs(self.minlat)-abs(self.maxlat)) else: maxlat = abs(abs(self.minlat)+abs(self.maxlat)) # Calculate the zoom. all places must be displayed on the map. zoomlat = 2 if maxlat < 80.0 : zoomlat = 3 if maxlat < 40.0 : zoomlat = 4 if maxlat < 20.0 : zoomlat = 5 if maxlat < 10.0 : zoomlat = 6 if maxlat < 3.0 : zoomlat = 7 if maxlat < 2.0 : zoomlat = 8 if maxlat < 1.0 : zoomlat = 9 if maxlat < 0.5 : zoomlat = 10 if maxlat < 0.2 : zoomlat = 11 if maxlat < 0.1 : zoomlat = 12 zoomlong = 2 if maxlong < 120.0 : zoomlong = 3 if maxlong < 60.0 : zoomlong = 4 if maxlong < 30.0 : zoomlong = 5 if maxlong < 15.0 : zoomlong = 6 if maxlong < 7.0 : zoomlong = 7 if maxlong < 4.0 : zoomlong = 8 if maxlong < 2.0 : zoomlong = 9 if maxlong < 1.0 : zoomlong = 10 if maxlong < 0.5 : zoomlong = 11 if maxlong < 0.2 : zoomlong = 12 if maxlong < 0.1 : zoomlong = 13 if zoomlat < zoomlong: self.zoom = zoomlat else: self.zoom = zoomlong self.zoom -= 1 if self.zoom < 2: self.zoom = 2 # We center the map on a point at the center of all markers self.centerlat = maxlat/2 self.centerlon = maxlong/2 latit = 0.0 longt = 0.0 for mark in self.sort: cent = int(mark[6]) if cent: self.centered = True if ( signminlat == signmaxlat ): if signminlat == 1: latit = self.minlat+self.centerlat else: latit = self.maxlat-self.centerlat elif self.maxlat > self.centerlat: latit = self.maxlat-self.centerlat else: latit = self.minlat+self.centerlat if ( signminlon == signmaxlon ): if signminlon == 1: longt = self.minlon+self.centerlon else: longt = self.maxlon-self.centerlon elif self.maxlon > self.centerlon: longt = self.maxlon-self.centerlon else: longt = self.minlon+self.centerlon # all maps: 0.0 for longitude and latitude means no location. if latit == 0.0 and longt == 0.0: latit = 0.00000001 longt = 0.00000001 self.mustcenter = False if latit != 0.0 or longt != 0.0: self.latit = latit self.longt = longt self.mustcenter = True def _create_pages(self, ptype, h3mess, h4mess): """ Do we need to create a multi-pages document ? Do we have too many markers ? """ nbmarkers = 0 self.nbpages = 0 pages = ( self.nbmarkers / NB_MARKERS_PER_PAGE ) + 1 if (nbmarkers % NB_MARKERS_PER_PAGE) == 0: try: self._createmapstractiontrailer() except: pass self._set_center_and_zoom(ptype) for page in range(0, pages, 1): self.nbpages += 1 if ptype == 1: ftype = "P" elif ptype == 2: ftype = "E" elif ptype == 3: ftype = "F" elif ptype == 4: ftype = "I" else: ftype = "X" filename = GEOVIEW_SUBPATH+"/GeoV-%c-%05d.html" % \ (ftype, self.nbpages) if self.nbpages == 1: self.htmlfile = filename self._createmapstractionheader(filename) self._create_needed_javascript() first = ( self.nbpages - 1 ) * NB_MARKERS_PER_PAGE last = ( self.nbpages * NB_MARKERS_PER_PAGE ) - 1 self._create_markers(ptype, first, last) self._createmapstractionpostheader(h3mess, h4mess, pages, self.nbpages, ftype) self._createmapstractiontrailer() if self.nbpages == 1: self.open(self.htmlfile) def _createmapstraction(self, displaytype): """ Which kind of map are we going to create ? """ if displaytype == "places": self._createmapstractionplaces(self.dbstate) elif displaytype == "family": self._createmapstractionfamily(self.dbstate) elif displaytype == "person": self._createmapstractionperson(self.dbstate) elif displaytype == "event": self._createmapstractionevents(self.dbstate) else: self._createmapstractionheader(GEOVIEW_SUBPATH+"/error.html") self._createmapnotimplemented() self._createmapstractiontrailer() def _append_to_places_without_coord(self, gid, place): """ Create a list of places without coordinates. """ self.place_without_coordinates.append([gid, place]) self.without += 1 def _append_to_places_list(self, place, evttype, name, lat, longit, descr, center, year): """ Create a list of places with coordinates. """ self.place_list.append([place, name, evttype, lat, longit, descr, int(center), year]) self.nbmarkers += 1 tfa = float(lat) tfb = float(longit) if year is not None: tfc = int(year) if tfc != 0: if tfc < self.minyear: self.minyear = tfc if tfc > self.maxyear: self.maxyear = tfc if tfa < 0.0: tfa = tfa - 0.00000001 else: tfa = tfa + 0.00000001 if tfb < 0.0: tfb = tfb - 0.00000001 else: tfb = tfb + 0.00000001 if self.minlat == 0.0: self.minlat = tfa if tfa < self.minlat: if tfa < 0.0: self.minlat = tfa if self.maxlat == 0.0: self.maxlat = tfa if tfa > self.maxlat: if tfa > 0.0: self.maxlat = tfa if self.minlon == 0.0: self.minlon = tfb if tfb < self.minlon: if tfb < 0.0: self.minlon = tfb if self.maxlon == 0.0: self.maxlon = tfb if tfb > self.maxlon: if tfb > 0.0: self.maxlon = tfb def _create_markers(self, format, firstm, lastm): """ Create all markers for the specified person. """ last = "" indm = 0 divclose = True self.yearinmarker = [] ininterval = False self.setattr = True self.mapview.write(" function setcenterandzoom(mapstraction) {\n") if self.mustcenter: self.centered = True self.mapview.write(" var point = new LatLonPoint") self.mapview.write("(%s,%s);" % (self.latit, self.longt)) self.mapview.write("mapstraction.setCenterAndZoom") self.mapview.write("(point, %s);\n" % self.zoom) self.setattr = False self.mapview.write("}\n") self.mapview.write(" function setmarkers(mapstraction) {\n") for mark in self.sort: if ( indm >= firstm ) and ( indm <= lastm ): ininterval = True if ininterval: if last != mark[0]: if not divclose: if ininterval: self.mapview.write("\");") divclose = True years = "" if mark[2]: for year in self.yearinmarker: years += "%d " % year years += "end" self.mapview.write("my_marker.setAttribute") self.mapview.write("('year','%s');" % years) self.yearinmarker = [] self.mapview.write("mapstraction.addMarker(my_marker);") indm += 1 if ( indm > lastm ): if (indm % NB_MARKERS_PER_PAGE) == 0: ininterval = False last = mark[0] if ( indm >= firstm ) and ( indm <= lastm ): self.mapview.write("\n var point = new LatLonPoint") self.mapview.write("(%s,%s);" % (mark[3], mark[4])) self.mapview.write("my_marker = new Marker(point);") self.mapview.write("gmarkers[%d]=my_marker;" % \ (( indm - 1 ) % NB_MARKERS_PER_PAGE)) self.mapview.write("my_marker.setLabel") self.mapview.write("(\"%s\");" % mark[0]) self.yearinmarker.append(mark[7]) divclose = False self.mapview.write("my_marker.setInfoBubble(\"
") if format == 1: self.mapview.write("%s
____________
" % \ mark[0]) self.mapview.write("
%s" % mark[5]) elif format == 2: self.mapview.write("%s____________
" % mark[1]) self.mapview.write("
%s - %s" % (mark[7], mark[5])) elif format == 3: self.mapview.write("%s
____________
" % \ mark[0]) self.mapview.write("
%s - %s" % (mark[7], mark[5])) elif format == 4: self.mapview.write("%s
____________
" % \ mark[0]) self.mapview.write("
%s - %s" % (mark[7], mark[5])) else: # This marker already exists. add info. self.mapview.write("
%s - %s" % (mark[7], mark[5])) ret = 1 for year in self.yearinmarker: if year == mark[7]: ret = 0 if (ret): self.yearinmarker.append(mark[7]) else: indm += 1 if self.nbmarkers > 0 and ininterval: years = "" if mark[2]: for year in self.yearinmarker: years += "%d " % year years += "end" self.mapview.write("
\");") self.mapview.write("my_marker.setAttribute('year','%s');" % years) self.mapview.write("mapstraction.addMarker(my_marker);") if self.nbmarkers == 0: # We have no valid geographic point to center the map. # So you'll see the street where I live. # I think another place should be better : # Where is the place where the gramps project began ? # # I think we should put here all gramps developpers. # not only me ... # longitude = 0.0 latitude = 0.0 self.mapview.write("\nvar point = new LatLonPoint") self.mapview.write("(%s,%s);\n" % (latitude, longitude)) self.mapview.write(" mapstraction.setCenterAndZoom") self.mapview.write("(point, %d);\n" % 2) self.mapview.write(" my_marker = new Marker(point);\n") self.mapview.write(" my_marker.setLabel") self.mapview.write("(\"%s\");\n" % _("No location.")) self.mapview.write(" my_marker.setInfoBubble(\"
") self.mapview.write(_("You have no places in your family tree " " with coordinates.")) self.mapview.write("
") self.mapview.write(_("You are looking at the default map.")) self.mapview.write("
\");\n") self.mapview.write(" mapstraction.addMarker(my_marker);") self.mapview.write("\n}") self.mapview.write("\n\n") def _createpersonmarkers(self, dbstate, person, comment): """ Create all markers for the specified person. """ latitude = "" longitude = "" if person: birth_ref = person.get_birth_ref() if birth_ref: birth = dbstate.db.get_event_from_handle(birth_ref.ref) birthdate = birth.get_date_object() birthyear = birthdate.get_year() bplace_handle = birth.get_place_handle() if bplace_handle: place = dbstate.db.get_place_from_handle(bplace_handle) if place: longitude = place.get_longitude() latitude = place.get_latitude() latitude, longitude = conv_lat_lon(latitude, longitude, "D.D8") if comment: descr1 = _("%(comment)s : birth place.") % { 'comment': comment} else: descr1 = _("birth place.") descr = place.get_title() # place.get_longitude and place.get_latitude return # one string. We have coordinates when the two values # contains non null string. if ( longitude and latitude ): self._append_to_places_list(descr, gen.lib.EventType.BIRTH, _nd.display(person), latitude, longitude, descr1, int(self.center), birthyear) self.center = False else: self._append_to_places_without_coord( place.gramps_id, descr) latitude = "" longitude = "" death_ref = person.get_death_ref() if death_ref: death = dbstate.db.get_event_from_handle(death_ref.ref) deathdate = death.get_date_object() deathyear = deathdate.get_year() dplace_handle = death.get_place_handle() if dplace_handle: place = dbstate.db.get_place_from_handle(dplace_handle) if place: longitude = place.get_longitude() latitude = place.get_latitude() latitude, longitude = conv_lat_lon(latitude, longitude, "D.D8") descr = place.get_title() if comment: descr1 = _("%(comment)s : death place.") % { 'comment': comment} else: descr1 = _("death place.") # place.get_longitude and place.get_latitude return # one string. We have coordinates when the two values # contains non null string. if ( longitude and latitude ): self._append_to_places_list(descr, gen.lib.EventType.DEATH, _nd.display(person), latitude, longitude, descr1, int(self.center), deathyear) self.center = False else: self._append_to_places_without_coord( place.gramps_id, descr) def _createmapstractionplaces(self, dbstate): """ Create the marker for each place in the database which has a lat/lon. """ self.place_list = [] self.place_without_coordinates = [] self.minlat = float(0.0) self.maxlat = float(0.0) self.minlon = float(0.0) self.maxlon = float(0.0) self.minyear = int(9999) self.maxyear = int(0) latitude = "" longitude = "" self.center = True for place_handle in dbstate.db.iter_place_handles(): place = dbstate.db.get_place_from_handle( place_handle) if place: descr = place.get_title() descr1 = _("Id : %s") % place.gramps_id longitude = place.get_longitude() latitude = place.get_latitude() latitude, longitude = conv_lat_lon(latitude, longitude, "D.D8") # place.get_longitude and place.get_latitude return # one string. We have coordinates when the two values # contains non null string. if ( longitude and latitude ): self._append_to_places_list(descr, None, "", latitude, longitude, descr1, self.center, None) self.center = False else: self._append_to_places_without_coord(place.gramps_id, descr) if self.center: mess = _("Cannot center the map. No location with coordinates.") else: mess = "" self._create_pages(1, _("All places in the family tree with coordinates."), mess) def _createmapstractionevents(self, dbstate): """ Create one marker for each place associated with an event in the database which has a lat/lon. """ self.place_list = [] self.place_without_coordinates = [] self.minlat = float(0.0) self.maxlat = float(0.0) self.minlon = float(0.0) self.maxlon = float(0.0) self.minyear = int(9999) self.maxyear = int(0) latitude = "" longitude = "" self.center = True for event_handle in dbstate.db.get_event_handles(): event = dbstate.db.get_event_from_handle( event_handle) if event: place_handle = event.get_place_handle() eventdate = event.get_date_object() eventyear = eventdate.get_year() descr1 = _("Id : %(id)s (%(year)s)") % { 'id' : event.gramps_id, 'year' : eventyear} if place_handle: place = dbstate.db.get_place_from_handle(place_handle) if place: longitude = place.get_longitude() latitude = place.get_latitude() latitude, longitude = conv_lat_lon(latitude, longitude, "D.D8") city = place.get_main_location().get_city() country = place.get_main_location().get_country() descr2 = "%s; %s" % (city, country) # place.get_longitude and place.get_latitude return # one string. We have coordinates when the two values # contains non null string. if ( longitude and latitude ): person_list = [ dbstate.db.get_person_from_handle(ref_handle) for (ref_type, ref_handle) in \ dbstate.db.find_backlink_handles( event_handle) if ref_type == 'Person' ] if person_list: descr = "
" for person in person_list: descr = ("%(description)s%(name)s
") % { 'description' : descr, 'name' : _nd.display(person)} #) % { 'eventtype': gen.lib.EventType( descr = ("%(eventtype)s;"+ " %(place)s%(description)s" ) % { 'eventtype': gen.lib.EventType( event.get_type() ), 'place': place.get_title(), 'description': descr} else: descr = ("%(eventtype)s; %(place)s
") % { 'eventtype': gen.lib.EventType( event.get_type() ), 'place': place.get_title()} self._append_to_places_list(descr1, descr, descr, latitude, longitude, descr2, self.center, eventyear) self.center = False else: descr = place.get_title() self._append_to_places_without_coord( place.gramps_id, descr) if self.center: mess = _("Cannot center the map. No location with coordinates.") else: mess = "" self._create_pages(2, _("All events in the family tree with coordinates."), mess) def _createmapstractionfamily(self, dbstate): """ Create all markers for each people of a family in the database which has a lat/lon. """ self.place_list = [] self.place_without_coordinates = [] self.minlat = float(0.0) self.maxlat = float(0.0) self.minlon = float(0.0) self.maxlon = float(0.0) self.minyear = int(9999) self.maxyear = int(0) self.center = True person = None if dbstate.active: person = dbstate.active if person is not None: family_list = person.get_family_handle_list() if len(family_list) > 0: fhandle = family_list[0] # first is primary fam = dbstate.db.get_family_from_handle(fhandle) handle = fam.get_father_handle() father = dbstate.db.get_person_from_handle(handle) if father: comment = _("Id : Father : %s") % father.gramps_id self._createpersonmarkers(dbstate, father, comment) handle = fam.get_mother_handle() mother = dbstate.db.get_person_from_handle(handle) if mother: comment = _("Id : Mother : %s") % mother.gramps_id self._createpersonmarkers(dbstate, mother, comment) index = 0 child_ref_list = fam.get_child_ref_list() if child_ref_list: for child_ref in child_ref_list: child = dbstate.db.get_person_from_handle(child_ref.ref) if child: index += 1 comment = _("Id : Child : %(id)s %(index)d") % { 'id' : child.gramps_id, 'index': index} self._createpersonmarkers(dbstate, child, comment) if self.center: mess = _("Cannot center the map. No location with coordinates.") if person is not None: self._create_pages(3, _("The active person's family members " "have no places with coordinates."), mess) else: self._create_pages(3, _("No active person set."), mess) else: mess = "" self._create_pages(3, ( _("All %(name)s people's family places in the " "family tree with coordinates.") % { 'name' :_nd.display(person) }), mess) def _createmapstractionperson(self, dbstate): """ Create all markers for each people's event in the database which has a lat/lon. """ self.place_list = [] self.place_without_coordinates = [] self.minlat = float(0.0) self.maxlat = float(0.0) self.minlon = float(0.0) self.maxlon = float(0.0) self.minyear = int(9999) self.maxyear = int(0) latitude = "" longitude = "" person = None if dbstate.active: person = dbstate.active self.center = True if person is not None: # For each event, if we have a place, set a marker. for event_ref in person.get_event_ref_list(): if not event_ref: continue if event_ref.role != gen.lib.EventRoleType.PRIMARY: # Only match primaries, no witnesses continue event = dbstate.db.get_event_from_handle(event_ref.ref) eventdate = event.get_date_object() eventyear = eventdate.get_year() place_handle = event.get_place_handle() if place_handle: place = dbstate.db.get_place_from_handle(place_handle) if place: longitude = place.get_longitude() latitude = place.get_latitude() latitude, longitude = conv_lat_lon(latitude, longitude, "D.D8") descr = place.get_title() evt = gen.lib.EventType(event.get_type()) descr1 = _("%(eventtype)s : %(name)s") % { 'eventtype': evt, 'name': _nd.display(person)} # place.get_longitude and place.get_latitude return # one string. We have coordinates when the two values # contains non null string. if ( longitude and latitude ): self._append_to_places_list(descr, evt, _nd.display(person), latitude, longitude, descr1, self.center, eventyear) self.center = False else: self._append_to_places_without_coord( place.gramps_id, descr) if self.center: mess = _("Cannot center the map. No location with coordinates.") if person is not None: self._create_pages(4, _("The active person has no places with coordinates."), mess) else: self._create_pages(4, _("No active person set."), mess) else: mess = "" self._create_pages(4, ( _("All event places for %s.") % _nd.display(person) ), mess) def _createmapnotimplemented(self): """ Inform the user this work is not implemented. """ self.mapview.write("

%s

" % _("Not yet implemented ..."))
NBGramps IDPlace
%d%s%s