gramps/src/DataViews/_MapView.py

688 lines
30 KiB
Python
Raw Normal View History

#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2001-2006 Donald N. Allingham
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# $Id$
#-------------------------------------------------------------------------
#
# Python modules
#
#-------------------------------------------------------------------------
from gettext import gettext as _
import gc
import logging
2006-03-04 05:18:11 +05:30
import os
import math
log = logging.getLogger(".")
#-------------------------------------------------------------------------
#
# GTK/Gnome modules
#
#-------------------------------------------------------------------------
import gobject
import gtk
import gtk.gdk
#-------------------------------------------------------------------------
#
# Gramps Modules
#
#-------------------------------------------------------------------------
import PageView
2006-03-04 05:18:11 +05:30
import const
# Some initial places for debugging
glob_loc_data = [ # (Name, longitude, latitude)
("_Center", 0,0),
("_North",0,90),
("_South",0,-90),
("_West",-180,0),
("_East",180,0),
("Chicago",-87.75,41.83),
("Berlin",13.42,52.53),
("Honolulu",-157.83,21.32),
("Madrid",-3.72,40.42),
("Moscow",37.70,55.75),
("Vienna",16.37,48.22),
("Sidney",151.17,-33.92),
("Rio de Janeiro",-43.28,-22.88),
("Tokyo",139.75,35.67),
("Cape Town",18.47,-33.93),
("Anchorage",-150.00,61.17),
("Mannheim-Wallstadt",8.55,49.48),
("Mannheim-Neckarau",8.48,49.45),
("Gorxheimertal",8.73,49.53)]
enable_debug = False
# Draws a map image and tries to allocate space in the correct aspect ratio
class GuideMap(gtk.DrawingArea):
def __init__(self, map_pixbuf):
gtk.DrawingArea.__init__(self)
self.map_pixbuf = map_pixbuf
self.connect("expose-event", self.expose_cb)
self.connect("size-allocate", self.size_allocate_cb)
self.gc = None
self.current_area = None
self.current_spot = None
self.old_size = (-1,-1)
# Set hightlight region
def hightlight_area( self, area):
self.current_area = area
self.queue_draw()
# Set hightlight region
def hightlight_spot( self, spot):
self.current_spot = spot
self.queue_draw()
# Redraw the image
def expose_cb(self,widget,event):
if not self.gc:
self.gc = self.window.new_gc()
self.gc.set_foreground( self.get_colormap().alloc_color("red"))
self.gc.set_background( self.get_colormap().alloc_color("blue"))
if self.backbuf and self.gc:
self.window.draw_pixbuf( self.gc, self.backbuf, 0,0, 0,0, -1,-1)
if self.current_area:
r = self.map_to_screen(self.current_area[0],
self.current_area[1],
self.current_area[2],
self.current_area[3])
self.window.draw_rectangle( self.gc, False,
r[0],r[1],r[2],r[3])
if self.current_spot:
r = self.map_to_screen(self.current_spot[0],
self.current_spot[1])
self.window.draw_line( self.gc,0,r[1],
self.backbuf.get_width(),r[1])
self.window.draw_line( self.gc,r[0],0,
r[0],self.backbuf.get_height())
# Scale backbuffer
def size_allocate_cb(self,widget,allocation):
# Always request a height, that is half of the width
w = max( 128,allocation.width)
self.set_size_request(-1,w/2)
# only create new backbuffer if size is different
new_size = (allocation.width,allocation.height)
if new_size is not self.old_size:
self.old_size = new_size
self.backbuf = self.map_pixbuf.scale_simple(
self.old_size[0],
self.old_size[1],
gtk.gdk.INTERP_BILINEAR)
gc.collect()
def map_to_screen( self, x,y,w=None,h=None):
px = int((float(x) + 180.0) / 360.0 * self.backbuf.get_width())
py = int((90-float(y)) / 180.0 * self.backbuf.get_height())
if w and h:
pw = int(float(w) / 360.0 * self.backbuf.get_width())
ph = int(float(h) / 180.0 * self.backbuf.get_height())
return (px,py,pw,ph)
return (px,py)
# Map tile files used by the ZoomMap
class MapTile:
def __init__( self, filename, x, y, w, h, pw, ph):
self.filename = filename
self.full_path = os.path.join(const.image_dir,filename)
self.map_x = float(x)
self.map_y = float(y)
self.map_width = float(w)
self.map_height = float(h)
self.map_pixel_width = float(pw)
self.map_pixel_height = float(ph)
self.source_pixbuf = None
self.source_scale = self.map_pixel_width / self.map_width
self.scale = None
self.scaled_pixbuf = None
self.scaled_map_x = None
self.scaled_map_y = None
def set_viewport( self, target_scale, x_in, y_in, w_in, h_in):
# intersect viewport with map area
x = max(self.map_x, max(-180.0,x_in))
y = min(self.map_y, min( 90.0,y_in))
xmax = min( min(180.0,x_in+w_in), self.map_x+self.map_width)
ymin = max( max(-90.0,y_in-h_in), self.map_y-self.map_width)
w = xmax-x
h = y-ymin
if w > 0.0 and h > 0.0:
# crop source tile to not scale the whole image_dir
xoffset = max(0,math.floor((x - self.map_x) * self.source_scale))
xmax = max(0,math.ceil((x+w - self.map_x) * self.source_scale))
yoffset = min(self.map_pixel_width,math.floor(-(y - self.map_y) * self.source_scale))
ymax = min(self.map_pixel_height,math.ceil(-(y-h - self.map_y) * self.source_scale))
rescale = target_scale / self.source_scale
if int((xmax-xoffset)*rescale) > 0 and int((ymax-yoffset)*rescale) > 0:
self.scaled_map_x = self.map_x + xoffset / self.source_scale
self.scaled_map_y = self.map_y - yoffset / self.source_scale
self.scaled_map_pixel_w = int((xmax-xoffset)*rescale)
self.scaled_map_pixel_h = int((ymax-yoffset)*rescale)
if enable_debug:
print
print "Source-Map origin: %f x %f, %f, %f" % (self.map_x,self.map_y,self.map_width,self.map_height)
print "Source-Map pixels: %f x %f" % (self.map_pixel_width,self.map_pixel_height)
print "Source-Map scale: %f" % self.source_scale
print "Target origin: %f x %f, %f, %f" % (x,y,w,h)
print "Target scale: %f" % target_scale
print "Target crop: %f x %f, %f x %f" % (xoffset,yoffset,xmax,ymax)
print "Origin of crop: %f x %f" % (self.scaled_map_x,self.scaled_map_y)
print "scaled tile size: %f x %f pix" % (self.scaled_map_pixel_w,self.scaled_map_pixel_h)
try:
if not self.source_pixbuf:
self.source_pixbuf = gtk.gdk.pixbuf_new_from_file( self.full_path)
clip_pixbuf = self.source_pixbuf.subpixbuf(int(xoffset),int(yoffset),int(xmax-xoffset),int(ymax-yoffset))
self.scale = target_scale
self.scaled_pixbuf = clip_pixbuf.scale_simple( int((xmax-xoffset)*rescale), int((ymax-yoffset)*rescale), gtk.gdk.INTERP_BILINEAR)
clip_pixbuf = None
except:
pass
else:
self.scale = None
self.scaled_pixbuf = None
else:
self.scale = None
self.scaled_pixbuf = None
def free(self):
self.scale = None
self.scaled_pixbuf = None
# Zoomable map image
class ZoomMap( gtk.DrawingArea):
def __init__( self, place_marker_pixbuf, hightlight_marker_pixbuf):
gtk.DrawingArea.__init__(self)
self.place_marker_pixbuf = place_marker_pixbuf
self.hightlight_marker_pixbuf = hightlight_marker_pixbuf
self.add_events(gtk.gdk.POINTER_MOTION_MASK) # position overlay
self.connect("expose-event", self.expose_cb)
self.connect("size-allocate", self.size_allocate_cb)
if enable_debug:
self.connect("motion-notify-event", self.motion_notify_event_cb)
self.gc = None
self.current_pixel_size = (-1,-1)
self.zoom_pos = (0,0)
self.magnifer = 0.0 # in pixel per degree
self.guide = None
self.textlayout = self.create_pango_layout("")
self.map_sources = {}
self.initial_exposed = False
def add_map_source( self,filename, x, y, w, h,pw,ph):
tile = MapTile( filename, x, y, w, h, pw, ph)
if not tile.source_scale in self.map_sources:
self.map_sources[tile.source_scale] = []
self.map_sources[tile.source_scale].append( tile)
# Set the guide map that should follow the zoom area
def set_guide( self, guide):
self.guide = guide
def set_location_model( self, model, idx_name, idx_long, idx_lat):
self.location_model = model
self.idx_name = idx_name
self.idx_long = idx_long
self.idx_lat = idx_lat
def motion_notify_event_cb(self,widget,event):
self.textlayout.set_text( "Position: %03.0f,%03.0f pixel" % (event.x,event.y))
(w,h) = self.textlayout.get_pixel_size()
self.gc.set_foreground( self.get_colormap().alloc_color("white"))
self.window.draw_rectangle( self.gc, True, 10,50,w,h)
self.gc.set_foreground( self.get_colormap().alloc_color("red"))
self.window.draw_layout( self.gc, 10, 50, self.textlayout)
(lon,lat) = self.screen_to_map(event.x,event.y)
self.textlayout.set_text( "Position: %03.0f,%03.0f degree" % (lon,lat))
(w,h) = self.textlayout.get_pixel_size()
self.gc.set_foreground( self.get_colormap().alloc_color("white"))
self.window.draw_rectangle( self.gc, True, 10,70,w,h)
self.gc.set_foreground( self.get_colormap().alloc_color("red"))
self.window.draw_layout( self.gc, 10, 70, self.textlayout)
# Redraw the image
def expose_cb(self,widget,event):
if not self.gc:
self.gc = self.window.new_gc()
self.gc.set_foreground( self.get_colormap().alloc_color("red"))
self.gc.set_background( self.get_colormap().alloc_color("blue"))
if not self.backbuf:
self.size_allocate_cb( self,self.get_allocation())
if self.backbuf and self.gc:
#draw all maps
scales = self.map_sources.keys()
scales.sort()
for scale in scales:
for map in self.map_sources[scale]:
if map.scaled_pixbuf:
(px,py) = self.map_to_screen( map.scaled_map_x, map.scaled_map_y)
self.window.draw_pixbuf( self.gc, map.scaled_pixbuf, 0,0, px,py)
if enable_debug:
self.window.draw_rectangle( self.gc, False, px,py,map.scaled_map_pixel_w,map.scaled_map_pixel_h)
self.window.draw_line( self.gc, px,py,px+map.scaled_map_pixel_w,py+map.scaled_map_pixel_h)
self.window.draw_line( self.gc, px,py+map.scaled_map_pixel_h,px+map.scaled_map_pixel_w,py)
gc.collect()
# draw all available locations
if self.location_model:
iter = self.location_model.get_iter_first()
while iter:
(n,x,y) = self.location_model.get( iter, self.idx_name, self.idx_long, self.idx_lat)
(px,py) = self.map_to_screen( x, y)
#if px > 0 and py > 0 and px < self.backbuf.get_width() and py < self.backbuf.get_height():
# draw only visible markers
#self.window.draw_pixbuf(
# self.gc,
# self.place_marker_pixbuf,
# 0,0,
# px-self.place_marker_pixbuf.get_width()/2,
# py-self.place_marker_pixbuf.get_height()/2,
# -1,-1)
self.textlayout.set_text(n)
self.window.draw_layout(
self.gc,
px,py,
self.textlayout)
iter = self.location_model.iter_next( iter)
# hightlight current location
(px,py) = self.map_to_screen( self.zoom_pos[0], self.zoom_pos[1])
self.window.draw_pixbuf(
self.gc,
self.hightlight_marker_pixbuf,
0,0,
px-self.hightlight_marker_pixbuf.get_width()/2,
py-self.hightlight_marker_pixbuf.get_height()/2,
-1,-1)
#self.window.draw_rectangle( self.gc, False, px-3,py-3, 6,6)
#(px1,py1) = self.map_to_screen(-180, 90)
#(px2,py2) = self.map_to_screen( 180,-90)
#self.window.draw_rectangle( self.gc, False, px1,py1,px2-px1,py2-py1)
#self.window.draw_line( self.gc, px1,py1,px2,py2)
#self.window.draw_line( self.gc, px1,py2,px2,py1)
if enable_debug:
# Output debugging info
self.textlayout.set_text( "Magnifer: %f pixel per degree" % self.magnifer)
self.window.draw_layout( self.gc, 10, 10, self.textlayout)
self.textlayout.set_text( "Current map: %f pixel per degree" % self.selected_map_scale)
self.window.draw_layout( self.gc, 10, 30, self.textlayout)
def map_to_screen( self, lon, lat):
px = int(self.current_pixel_size[0] / 2.0 + (lon - self.zoom_pos[0]) * self.magnifer)
py = int(self.current_pixel_size[1] / 2.0 - (lat - self.zoom_pos[1]) * self.magnifer)
return( px, py)
def screen_to_map( self, px, py):
px = float(px)
py = float(py)
lon = (px - self.current_pixel_size[0]/2) / self.magnifer + self.zoom_pos[0];
lat = -(py - self.current_pixel_size[1]/2) / self.magnifer + self.zoom_pos[1];
return( lon, lat)
# Scale backbuffer
def size_allocate_cb(self,widget,allocation):
# only create new backbuffer if size is different
new_size = (allocation.width,allocation.height)
if new_size is not self.current_pixel_size or not self.backbuf:
self.backbuf = True
self.current_pixel_size = new_size
if self.magnifer == 0.0:
# scale map to full width
self.magnifer = self.current_pixel_size[0] / 360.0
x0,y0 = self.screen_to_map( 0, 0)
x1,y1 = self.screen_to_map( new_size[0], new_size[1])
self.guide.hightlight_area( (x0,y0,x1-x0, y0-y1))
def cmpfunc(s):
return((self.magnifer-s)*(self.magnifer-s))
# select best matching tile set
self.selected_map_scale = None
smallest_scale = None
largest_scale = None
for s in self.map_sources.keys():
if not self.selected_map_scale or cmpfunc(s) < cmpfunc(self.selected_map_scale):
self.selected_map_scale = s
if not smallest_scale or s < smallest_scale:
smallest_scale = s
if not largest_scale or s > largest_scale:
largest_scale = s
if enable_debug:
print "scale of display: %f" % self.magnifer
print "available map scales:"
print self.map_sources.keys()
print "largest scale: %f" % largest_scale
print "smallest scale: %f" % smallest_scale
print "selected scale: %f" % self.selected_map_scale
for s in self.map_sources.keys():
for map in self.map_sources[s]:
if s == self.selected_map_scale or s == smallest_scale:
map.set_viewport( self.magnifer, x0, y0, x1-x0, y0-y1)
else:
map.free()
# Scroll to requested position
def scroll_to( self, long, lat):
self.zoom_pos = (float( min(180,(max(-180,long)))), float(min(90,(max(-90,lat)))))
self.backbuf = None
if self.guide:
self.guide.hightlight_spot( self.zoom_pos)
self.queue_draw()
def zoom_out(self):
self.magnifer = max( 1.0, self.magnifer * 2.0/3.0)
self.backbuf = None
self.queue_draw()
def zoom_in(self):
self.magnifer = min( 500.0, self.magnifer * 1.5)
self.backbuf = None
self.queue_draw()
def zoom_normal(self):
self.magnifer = 1.0
self.magnifer = self.selected_map_scale
self.backbuf = None
self.queue_draw()
def zoom_fit(self):
self.magnifer = self.current_pixel_size[0] / 360.0
self.backbuf = None
self.queue_draw()
# Place list widget
class MapPlacesList(gtk.TreeView):
def __init__(self, data):
self.lstore = gtk.ListStore(
gobject.TYPE_STRING,
gobject.TYPE_FLOAT,
gobject.TYPE_FLOAT)
self.change_data( data)
gtk.TreeView.__init__(self, self.lstore)
self.set_rules_hint(True)
self.set_search_column(0)
column = gtk.TreeViewColumn('Place', gtk.CellRendererText(), text=0)
column.set_sort_column_id(0)
self.append_column(column)
column = gtk.TreeViewColumn('Lat', gtk.CellRendererText(), text=1)
column.set_sort_column_id(1)
self.append_column(column)
column = gtk.TreeViewColumn('Long', gtk.CellRendererText(),text=2)
column.set_sort_column_id(2)
self.append_column(column)
def change_data( self, data):
self.lstore.clear()
for item in data:
iter = self.lstore.append()
self.lstore.set(iter,
0, item[0],
1, item[1],
2, item[2])
# Map View main class
class MapView(PageView.PageView):
def __init__(self,dbstate,uistate):
PageView.PageView.__init__(self, ('Maps'), dbstate, uistate)
dbstate.connect('database-changed',self.change_db)
self.current_marker = None
def navigation_type(self):
return PageView.NAVIGATION_NONE
def define_actions(self):
self.add_action('ZoomIn',gtk.STOCK_ZOOM_IN,
"Zoom _In",callback=self.zoom_in_cb)
self.add_action('ZoomOut',gtk.STOCK_ZOOM_OUT,
"Zoom _Out",callback=self.zoom_out_cb)
self.add_action('ZoomNormal',gtk.STOCK_ZOOM_100,
"_Normal Size", callback=self.zoom_100_cb)
self.add_action('ZoomFit',gtk.STOCK_ZOOM_FIT,
"Best _Fit",callback=self.zoom_fit_cb)
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.
"""
2005-08-12 08:05:27 +05:30
return 'gramps-map'
# For debugging: Reads in location from xearth
def get_xearth_markers(self):
data = []
2005-09-17 01:41:47 +05:30
try:
f = open("/etc/xearth/xearth.markers")
l = f.readline()
2005-09-17 01:41:47 +05:30
#linere = re.compile('[^0-9.-]*(-?[0-9]+\.[0-9]+)[^0-9.-]*(-?[0-9]+\.[0-9]+).*"([^"])".*', "I")
while l:
if not l[0] == "#":
l = l.strip().replace('"',"").replace(" "," ").replace(" "," ").replace(" "," ").replace(" # ",", ")
m = l.split( None, 2)
if len(m) == 3:
data.append( (m[2],float(m[1]),float(m[0])))
l = f.readline()
except IOError:
pass
return data
# Reads in locations from current GRAMPS database
def get_markers_from_database(self, db):
data = []
for place_handle in db.get_place_handles():
place = db.get_place_from_handle( place_handle)
if place:
try:
data.append( (place.get_title(),float(place.get_longitude()),float(place.get_latitude())))
except (TypeError, ValueError):
# ignore places that dont have usable data
pass
return data
# Reads in textfiles from NIMA:
# http://earth-info.nga.mil/gns/html/cntry_files.html
def parse_nima_countryfile(self, filename):
import csv
data = []
try:
2005-09-17 01:41:47 +05:30
csvreader = csv.reader(open(filename), "excel-tab")
l = csvreader.next() # skip header
l = csvreader.next()
line = 1
while l:
if l[17] == "N" and l[9] == "P":
city = l[22]
lat = float( l[3])
lon = float( l[4])
if line % 10 == 0:
data.append( (city, lon, lat))
l = csvreader.next()
line = line + 1
2005-09-17 01:41:47 +05:30
except (IOError,StopIteration):
pass
return data
def build_widget(self):
hbox = gtk.HBox( False, 4)
hbox.set_border_width( 4)
2006-03-03 02:58:27 +05:30
no = gtk.Image()
# The large zoomable map
self.zoom_map = ZoomMap(
2006-03-04 05:18:11 +05:30
gtk.gdk.pixbuf_new_from_file(os.path.join(const.image_dir,"bad.png")),
gtk.gdk.pixbuf_new_from_file(os.path.join(const.image_dir,"good.png")))
self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_0_0.jpg', -180,90, 45,45, 400,400)
self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_0_1.jpg', -135,90, 45,45, 400,400)
self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_0_2.jpg', -90,90, 45,45, 400,400)
self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_0_3.jpg', -45,90, 45,45, 400,400)
self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_0_4.jpg', 0,90, 45,45, 400,400)
self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_0_5.jpg', 45,90, 45,45, 400,400)
self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_0_6.jpg', 90,90, 45,45, 400,400)
self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_0_7.jpg', 135,90, 45,45, 400,400)
self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_1_0.jpg', -180,45, 45,45, 400,400)
self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_1_1.jpg', -135,45, 45,45, 400,400)
self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_1_2.jpg', -90,45, 45,45, 400,400)
self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_1_3.jpg', -45,45, 45,45, 400,400)
self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_1_4.jpg', 0,45, 45,45, 400,400)
self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_1_5.jpg', 45,45, 45,45, 400,400)
self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_1_6.jpg', 90,45, 45,45, 400,400)
self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_1_7.jpg', 135,45, 45,45, 400,400)
self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_2_0.jpg', -180,0, 45,45, 400,400)
self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_2_1.jpg', -135,0, 45,45, 400,400)
self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_2_2.jpg', -90,0, 45,45, 400,400)
self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_2_3.jpg', -45,0, 45,45, 400,400)
self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_2_4.jpg', 0,0, 45,45, 400,400)
self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_2_5.jpg', 45,0, 45,45, 400,400)
self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_2_6.jpg', 90,0, 45,45, 400,400)
self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_2_7.jpg', 135,0, 45,45, 400,400)
self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_3_0.jpg', -180,-45, 45,45, 400,400)
self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_3_1.jpg', -135,-45, 45,45, 400,400)
self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_3_2.jpg', -90,-45, 45,45, 400,400)
self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_3_3.jpg', -45,-45, 45,45, 400,400)
self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_3_4.jpg', 0,-45, 45,45, 400,400)
self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_3_5.jpg', 45,-45, 45,45, 400,400)
self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_3_6.jpg', 90,-45, 45,45, 400,400)
self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_3_7.jpg', 135,-45, 45,45, 400,400)
self.zoom_map.add_map_source('world.topo.200407.3x1600x800_tile_0_0.jpg', -180,90, 90,90, 400,400)
self.zoom_map.add_map_source('world.topo.200407.3x1600x800_tile_0_1.jpg', -90,90, 90,90, 400,400)
self.zoom_map.add_map_source('world.topo.200407.3x1600x800_tile_0_2.jpg', 0,90, 90,90, 400,400)
self.zoom_map.add_map_source('world.topo.200407.3x1600x800_tile_0_3.jpg', 90,90, 90,90, 400,400)
self.zoom_map.add_map_source('world.topo.200407.3x1600x800_tile_1_0.jpg', -180,0, 90,90, 400,400)
self.zoom_map.add_map_source('world.topo.200407.3x1600x800_tile_1_1.jpg', -90,0, 90,90, 400,400)
self.zoom_map.add_map_source('world.topo.200407.3x1600x800_tile_1_2.jpg', 0,0, 90,90, 400,400)
self.zoom_map.add_map_source('world.topo.200407.3x1600x800_tile_1_3.jpg', 90,0, 90,90, 400,400)
self.zoom_map.add_map_source('world.topo.200407.3x800x400.jpg', -180,90, 360,180, 800,400)
self.zoom_map.add_map_source('world.topo.200407.3x400x200.jpg', -180,90, 360,180, 400,200)
self.zoom_map.add_map_source('world.topo.200407.3x128x60.jpg', -180,90, 360,180, 128,60)
#self.zoom_map.add_map_source("europe_2_0.jpg",0,90,90,90,1024,1024)
self.zoom_map.set_size_request(300,300)
hbox.pack_start( self.zoom_map, True, True, 0)
# On the right side
vbox = gtk.VBox( False, 4)
hbox.pack_start( vbox, False, False, 0)
# The small guide map
self.guide_map = GuideMap(
gtk.gdk.pixbuf_new_from_file(os.path.join(const.image_dir,"world.topo.200407.3x128x60.jpg")))
self.guide_map.set_size_request(128,64)
vbox.pack_start( self.guide_map, False, True, 0)
self.zoom_map.set_guide(self.guide_map)
# and the place list
self.place_list_view = MapPlacesList( [])
self.zoom_map.set_location_model(self.place_list_view.get_model(), 0,1,2)
self.place_list_view.connect("cursor-changed", self.entry_select_cb)
self.place_list_view.set_size_request(128,-1)
vport = gtk.ScrolledWindow()
vbox.pack_start(vport,True,True,0)
vport.add( self.place_list_view)
self.rebuild_places()
return hbox
def ui_definition(self):
"""
Specifies the UIManager XML code that defines the menus and buttons
associated with the interface.
"""
return '''<ui>
<toolbar name="ToolBar">
<toolitem action="ZoomIn"/>
<toolitem action="ZoomOut"/>
<toolitem action="ZoomNormal"/>
<toolitem action="ZoomFit"/>
</toolbar>
</ui>'''
def change_db(self,db):
"""
Callback associated with DbState. Whenenver the database
changes, this task is called. In this case, we rebuild the
columns, and connect signals to the connected database. Tere
is no need to store the database, since we will get the value
from self.state.db
"""
db.connect('place-rebuild',self.rebuild_places)
db.connect('place-update',self.rebuild_places)
def rebuild_places(self,handle_list=None):
d = glob_loc_data
try:
d = d + self.get_xearth_markers()
#d = self.parse_nima_countryfile("/tmp/gm.txt")
d = d + self.get_markers_from_database( self.dbstate.db)
except:
log.error("Failed to rebuild places.", exc_info=True)
self.place_list_view.change_data( d)
def entry_select_cb(self,treeview):
s = treeview.get_selection()
(model,sel) = s.get_selected_rows()
for path in sel:
iter = model.get_iter(path)
self.zoom_map.scroll_to(model.get_value(iter,1),
model.get_value(iter,2))
break
def zoom_in_cb(self,obj):
self.zoom_map.zoom_in()
def zoom_out_cb(self,obj):
self.zoom_map.zoom_out()
def zoom_100_cb(self,obj):
self.zoom_map.zoom_normal()
def zoom_fit_cb(self,obj):
self.zoom_map.zoom_fit()