# -*- 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 '''%(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
') } end = """ """ ufd = open(self.without_coord_file, "w+") ufd.write(data) self.places = sorted(self.place_without_coordinates) i = 1 ufd.write("
NB | ") ufd.write("Gramps ID | Place | ") for place in self.places: ufd.write("
---|---|---|
%d | %s | %s | " % ( 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("