Geography: convert to gtk3 and some cleaning. not finished, but it works.

svn: r20358
This commit is contained in:
Serge Noiraud 2012-09-10 18:55:23 +00:00
parent 136438c5c5
commit 1fe42b7f49
8 changed files with 86 additions and 77 deletions

View File

@ -46,6 +46,7 @@ _LOG = logging.getLogger("maps.datelayer")
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
from gi.repository import Gtk from gi.repository import Gtk
from gi.repository import Gdk
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
# #
@ -109,11 +110,10 @@ class DateLayer(GObject.GObject, osmgpsmap.MapLayer):
if date > self.last or self.last == " ": if date > self.last or self.last == " ":
self.last = date self.last = date
def do_draw(self, gpsmap, drawable): def do_draw(self, gpsmap, ctx):
""" """
Draw the two extreme dates Draw the two extreme dates
""" """
ctx = drawable.cairo_create()
ctx.select_font_face(self.font, ctx.select_font_face(self.font,
cairo.FONT_SLANT_NORMAL, cairo.FONT_SLANT_NORMAL,
cairo.FONT_WEIGHT_NORMAL) cairo.FONT_WEIGHT_NORMAL)

View File

@ -41,6 +41,7 @@ from math import pi
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
from gi.repository import Gtk from gi.repository import Gtk
from gi.repository import GdkPixbuf from gi.repository import GdkPixbuf
import cairo
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
# #
@ -145,14 +146,12 @@ class GeoGraphyView(OsmGps, NavigationView):
self.place_list = [] self.place_list = []
self.places_found = [] self.places_found = []
self.select_fct = None self.select_fct = None
self.geo_mainmap = GdkPixbuf.Pixbuf.new_from_file_at_size( self.geo_mainmap = cairo.ImageSurface.create_from_png(
os.path.join(ROOT_DIR, "images", "48x48", os.path.join(ROOT_DIR, "images", "48x48",
('gramps-geo-mainmap' + '.png' )), ('gramps-geo-mainmap' + '.png' )))
48, 48) self.geo_altmap = cairo.ImageSurface.create_from_png(
self.geo_altmap = GdkPixbuf.Pixbuf.new_from_file_at_size(
os.path.join(ROOT_DIR, "images", "48x48", os.path.join(ROOT_DIR, "images", "48x48",
('gramps-geo-altmap' + '.png' )), ('gramps-geo-altmap' + '.png' )))
48, 48)
if ( config.get('geography.map_service') in if ( config.get('geography.map_service') in
( constants.OPENSTREETMAP, constants.OPENSTREETMAP_RENDERER )): ( constants.OPENSTREETMAP, constants.OPENSTREETMAP_RENDERER )):
default_image = self.geo_mainmap default_image = self.geo_mainmap
@ -162,10 +161,9 @@ class GeoGraphyView(OsmGps, NavigationView):
for ident in ( gen.lib.EventType.BIRTH, for ident in ( gen.lib.EventType.BIRTH,
gen.lib.EventType.DEATH, gen.lib.EventType.DEATH,
gen.lib.EventType.MARRIAGE ): gen.lib.EventType.MARRIAGE ):
self.geo_othermap[ident] = GdkPixbuf.Pixbuf.new_from_file_at_size( self.geo_othermap[ident] = cairo.ImageSurface.create_from_png(
os.path.join(ROOT_DIR, "images", "48x48", os.path.join(ROOT_DIR, "images", "48x48",
(constants.ICONS.get(int(ident), default_image) + '.png' )), (constants.ICONS.get(int(ident), default_image) + '.png' )))
48, 48)
def change_page(self): def change_page(self):
""" """
@ -175,6 +173,29 @@ class GeoGraphyView(OsmGps, NavigationView):
self.uistate.clear_filter_results() self.uistate.clear_filter_results()
self.end_selection = None self.end_selection = None
def do_size_request(self, requisition):
"""
Overridden method to handle size request events.
"""
requisition.width = 400
requisition.height = 300
def do_get_preferred_width(self):
""" GTK3 uses width for height sizing model. This method will
override the virtual method
"""
req = Gtk.Requisition()
self.do_size_request(req)
return req.width, req.width
def do_get_preferred_height(self):
""" GTK3 uses width for height sizing model. This method will
override the virtual method
"""
req = Gtk.Requisition()
self.do_size_request(req)
return req.height, req.height
def on_delete(self): def on_delete(self):
""" """
Save all modified environment Save all modified environment
@ -585,10 +606,6 @@ class GeoGraphyView(OsmGps, NavigationView):
level_start = self.osm.props.zoom level_start = self.osm.props.zoom
p1lat, p1lon = self.begin_selection.get_degrees() p1lat, p1lon = self.begin_selection.get_degrees()
p2lat, p2lon = self.end_selection.get_degrees() p2lat, p2lon = self.end_selection.get_degrees()
#p1lat = 180 * self.begin_selection.rlat / pi
#p1lon = 180 * self.begin_selection.rlon / pi
#p2lat = 180 * self.end_selection.rlat / pi
#p2lon = 180 * self.end_selection.rlon / pi
lat = p1lat + ( p2lat - p1lat ) / 2 lat = p1lat + ( p2lat - p1lat ) / 2
lon = p1lon + ( p2lon - p1lon ) / 2 lon = p1lon + ( p2lon - p1lon ) / 2
# We center the map on the center of the region # We center the map on the center of the region
@ -754,7 +771,6 @@ class GeoGraphyView(OsmGps, NavigationView):
Edit the selected family at the marker position Edit the selected family at the marker position
""" """
_LOG.debug("edit_family : %s" % mark[11]) _LOG.debug("edit_family : %s" % mark[11])
# need to add code here to edit the family.
family = self.dbstate.db.get_family_from_gramps_id(mark[11]) family = self.dbstate.db.get_family_from_gramps_id(mark[11])
try: try:
EditFamily(self.dbstate, self.uistate, [], family) EditFamily(self.dbstate, self.uistate, [], family)
@ -766,7 +782,6 @@ class GeoGraphyView(OsmGps, NavigationView):
Edit the selected event at the marker position Edit the selected event at the marker position
""" """
_LOG.debug("edit_event : %s" % mark[10]) _LOG.debug("edit_event : %s" % mark[10])
# need to add code here to edit the event.
event = self.dbstate.db.get_event_from_gramps_id(mark[10]) event = self.dbstate.db.get_event_from_gramps_id(mark[10])
try: try:
EditEvent(self.dbstate, self.uistate, [], event) EditEvent(self.dbstate, self.uistate, [], event)
@ -833,7 +848,6 @@ class GeoGraphyView(OsmGps, NavigationView):
""" """
Edit the selected place at the marker position Edit the selected place at the marker position
""" """
# need to add code here to edit the event.
self.select_fct.close() self.select_fct.close()
place = self.dbstate.db.get_place_from_gramps_id(self.mark[9]) place = self.dbstate.db.get_place_from_gramps_id(self.mark[9])
place.set_latitude(str(plat)) place.set_latitude(str(plat))

View File

@ -45,6 +45,7 @@ _LOG = logging.getLogger("maps.lifeway")
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
from gi.repository import Gtk from gi.repository import Gtk
from gi.repository import Gdk
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
# #
@ -98,31 +99,31 @@ class LifeWayLayer(GObject.GObject, osmgpsmap.MapLayer):
""" """
Add a track or life way. Add a track or life way.
""" """
if isinstance(color,str):
color = Gdk.color_parse(color)
self.lifeways.append((points, color)) self.lifeways.append((points, color))
def do_draw(self, gpsmap, drawable): def do_draw(self, gpsmap, ctx):
""" """
Draw all tracks or life ways. Draw all tracks or life ways.
""" """
ctx = drawable.cairo_create()
for lifeway in self.lifeways_ref: for lifeway in self.lifeways_ref:
ctx.set_line_cap(cairo.LINE_CAP_ROUND) ctx.set_line_cap(cairo.LINE_CAP_ROUND)
ctx.set_line_join(cairo.LINE_JOIN_ROUND) ctx.set_line_join(cairo.LINE_JOIN_ROUND)
ctx.set_line_width(3) ctx.set_line_width(3)
color = Gdk.color_parse(lifeway[1]) color = lifeway[1]
ctx.set_source_rgba(float(color.red / 65535.0), ctx.set_source_rgba(float(color.red / 65535.0),
float(color.green / 65535.0), float(color.green / 65535.0),
float(color.blue / 65535.0), float(color.blue / 65535.0),
0.1) # transparency 0.1) # transparency
ggc = drawable.new_gc()
rds = float(lifeway[2]) rds = float(lifeway[2])
for point in lifeway[0]: for point in lifeway[0]:
conv_pt1 = osmgpsmap.point_new_degrees(point[0], point[1]) conv_pt1 = osmgpsmap.MapPoint.new_degrees(point[0], point[1])
coord_x1, coord_y1 = gpsmap.convert_geographic_to_screen(conv_pt1) coord_x1, coord_y1 = gpsmap.convert_geographic_to_screen(conv_pt1)
conv_pt2 = osmgpsmap.point_new_degrees(point[0]+rds, point[1]) conv_pt2 = osmgpsmap.MapPoint.new_degrees(point[0]+rds, point[1])
coord_x2, coord_y2 = gpsmap.convert_geographic_to_screen(conv_pt2) coord_x2, coord_y2 = gpsmap.convert_geographic_to_screen(conv_pt2)
coy = abs(coord_y2-coord_y1) coy = abs(coord_y2-coord_y1)
conv_pt2 = osmgpsmap.point_new_degrees(point[0], point[1]+rds) conv_pt2 = osmgpsmap.MapPoint.new_degrees(point[0], point[1]+rds)
coord_x2, coord_y2 = gpsmap.convert_geographic_to_screen(conv_pt2) coord_x2, coord_y2 = gpsmap.convert_geographic_to_screen(conv_pt2)
cox = abs(coord_x2-coord_x1) cox = abs(coord_x2-coord_x1)
cox = cox if cox > 0.001 else 0.001 cox = cox if cox > 0.001 else 0.001
@ -135,25 +136,21 @@ class LifeWayLayer(GObject.GObject, osmgpsmap.MapLayer):
ctx.translate(coord_x1, coord_y1/coz) ctx.translate(coord_x1, coord_y1/coz)
ctx.arc(0.0, 0.0, cox, 0.0, 2*pi) ctx.arc(0.0, 0.0, cox, 0.0, 2*pi)
ctx.fill() ctx.fill()
ctx.set_line_width(2.0)
ctx.arc(0.0, 0.0, cox, 0.0, 2*pi)
ctx.set_source_rgba(1.0,0.0,0.0,0.5)
ctx.stroke()
ctx.restore() ctx.restore()
top_left = osmgpsmap.point_new_degrees(point[0] + lifeway[2],
point[1] - lifeway[2])
bottom_right = osmgpsmap.point_new_degrees(point[0] - lifeway[2],
point[1] + lifeway[2])
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 lifeway in self.lifeways: for lifeway in self.lifeways:
ctx.set_operator(cairo.OPERATOR_ATOP) ctx.set_operator(cairo.OPERATOR_ATOP)
ctx.set_line_width(3.0) ctx.set_line_width(3.0)
map_points = [] map_points = []
for point in lifeway[0]: for point in lifeway[0]:
conv_pt = osmgpsmap.point_new_degrees(point[0], point[1]) conv_pt = osmgpsmap.MapPoint.new_degrees(point[0], point[1])
coord_x, coord_y = gpsmap.convert_geographic_to_screen(conv_pt) coord_x, coord_y = gpsmap.convert_geographic_to_screen(conv_pt)
map_points.append((coord_x, coord_y)) map_points.append((coord_x, coord_y))
color = Gdk.color_parse(lifeway[1]) color = lifeway[1]
ctx.set_source_rgb(float(color.red / 65535.0), ctx.set_source_rgb(float(color.red / 65535.0),
float(color.green / 65535.0), float(color.green / 65535.0),
float(color.blue / 65535.0)) float(color.blue / 65535.0))

View File

@ -115,13 +115,12 @@ class MarkerLayer(GObject.GObject, osmgpsmap.MapLayer):
self.min_value = count self.min_value = count
self.nb_ref_by_places = self.max_references / self.max_places self.nb_ref_by_places = self.max_references / self.max_places
def do_draw(self, gpsmap, drawable): def do_draw(self, gpsmap, ctx):
""" """
Draw all markers here. Calculate where to draw the marker. Draw all markers here. Calculate where to draw the marker.
Depending of the average, minimum and maximum value, resize the marker. Depending of the average, minimum and maximum value, resize the marker.
We use cairo to resize the marker. We use cairo to resize the marker.
""" """
ctx = drawable.cairo_create()
max_interval = self.max_value - self.nb_ref_by_places max_interval = self.max_value - self.nb_ref_by_places
min_interval = self.nb_ref_by_places - self.min_value min_interval = self.nb_ref_by_places - self.min_value
if max_interval == 0: # This to avoid divide by zero if max_interval == 0: # This to avoid divide by zero
@ -144,7 +143,7 @@ class MarkerLayer(GObject.GObject, osmgpsmap.MapLayer):
size -= (0.3 * ((self.nb_ref_by_places - mark) size -= (0.3 * ((self.nb_ref_by_places - mark)
/ min_interval) ) / min_interval) )
conv_pt = osmgpsmap.point_new_degrees(float(marker[0][0]), conv_pt = osmgpsmap.MapPoint.new_degrees(float(marker[0][0]),
float(marker[0][1])) float(marker[0][1]))
coord_x, coord_y = gpsmap.convert_geographic_to_screen(conv_pt) coord_x, coord_y = gpsmap.convert_geographic_to_screen(conv_pt)
ctx.translate(coord_x, coord_y) ctx.translate(coord_x, coord_y)
@ -156,7 +155,7 @@ class MarkerLayer(GObject.GObject, osmgpsmap.MapLayer):
# So we shift the image position. # So we shift the image position.
posY = - int( 48 * size + 0.5 ) - 10 posY = - int( 48 * size + 0.5 ) - 10
posX = - int(( 48 * size ) / 6 + 0.5 ) - 10 posX = - int(( 48 * size ) / 6 + 0.5 ) - 10
ctx.set_source_pixbuf(marker[1], posX, posY) ctx.set_source_surface(marker[1], posX, posY)
ctx.paint() ctx.paint()
ctx.restore() ctx.restore()
_LOG.debug("%s" % time.strftime("end drawing : " _LOG.debug("%s" % time.strftime("end drawing : "

View File

@ -48,6 +48,7 @@ _LOG = logging.getLogger("maps.messagelayer")
from gi.repository import Gdk from gi.repository import Gdk
#from gi.repository import Cairo #from gi.repository import Cairo
import cairo import cairo
import pangocairo
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
# #
@ -112,11 +113,10 @@ class MessageLayer(GObject.GObject, osmgpsmap.MapLayer):
""" """
self.message.append(message) self.message.append(message)
def do_draw(self, gpsmap, drawable): def do_draw(self, gpsmap, ctx):
""" """
Draw the two extreme dates Draw the two extreme dates
""" """
ctx = drawable.cairo_create()
ctx.select_font_face(self.font, ctx.select_font_face(self.font,
cairo.FONT_SLANT_NORMAL, cairo.FONT_SLANT_NORMAL,
cairo.FONT_WEIGHT_NORMAL) cairo.FONT_WEIGHT_NORMAL)
@ -128,12 +128,19 @@ class MessageLayer(GObject.GObject, osmgpsmap.MapLayer):
0.9) # transparency 0.9) # transparency
coord_x = 100 coord_x = 100
coord_y = int(self.size) # Show the first line under the zoom button coord_y = int(self.size) # Show the first line under the zoom button
(d_width, d_height) = drawable.get_size() #(d_width, d_height) = drawable.get_size()
pcr = pangocairo.CairoContext(ctx)
ctx_layout = pcr.create_layout()
(d_width, d_height) = ctx_layout.get_size()
print d_width, d_height
d_width -= 100 d_width -= 100
for line in self.message: for line in self.message:
line_to_print = line line_to_print = line
(x_bearing, y_bearing, width, height, x_advance, y_advance) = ctx.text_extents(line_to_print) (x_bearing, y_bearing, width, height, x_advance, y_advance) = ctx.text_extents(line_to_print)
while ( width > d_width): #while ( width > d_width):
# BUG here d_with is negative
while ( width > 1000):
print width, " > ", d_width
line_length = len(line_to_print) line_length = len(line_to_print)
character_length = int(width/line_length) + 1 character_length = int(width/line_length) + 1
max_length = int(d_width / character_length) - 5 max_length = int(d_width / character_length) - 5

View File

@ -28,7 +28,6 @@
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
import os import os
from math import pi
from gi.repository import GObject from gi.repository import GObject
#------------------------------------------------------------------------ #------------------------------------------------------------------------
@ -250,9 +249,6 @@ class OsmGps():
""" """
current = osmmap.convert_screen_to_geographic(int(event.x), int(event.y)) current = osmmap.convert_screen_to_geographic(int(event.x), int(event.y))
lat, lon = current.get_degrees() lat, lon = current.get_degrees()
#lat = 180 * current.rlat / pi
#lon = 180 * current.rlon / pi
#print event.x, event.y, lat, lon
if self.zone_selection: if self.zone_selection:
# We draw a rectangle to show the selected region. # We draw a rectangle to show the selected region.
layer = self.get_selection_layer() layer = self.get_selection_layer()
@ -307,12 +303,8 @@ class OsmGps():
mouse button 3 : call the menu mouse button 3 : call the menu
""" """
lat, lon = self.osm.get_event_location(event).get_degrees() lat, lon = self.osm.get_event_location(event).get_degrees()
#lat = 180 * self.osm.get_event_location(event).rlat / pi
#lon = 180 * self.osm.get_event_location(event).rlon / pi
current = osm.convert_screen_to_geographic(int(event.x), int(event.y)) current = osm.convert_screen_to_geographic(int(event.x), int(event.y))
lat, lon = current.get_degrees() lat, lon = current.get_degrees()
#lat = 180 * current.rlat / pi
#lon = 180 * current.rlon / pi
if event.button == 1: if event.button == 1:
if self.end_selection is not None: if self.end_selection is not None:
self.activate_selection_zoom(osm, event) self.activate_selection_zoom(osm, event)

View File

@ -76,20 +76,20 @@ class SelectionLayer(GObject.GObject, osmgpsmap.MapLayer):
""" """
self.rectangles.append((cp1, cp2)) self.rectangles.append((cp1, cp2))
def do_draw(self, gpsmap, drawable): def do_draw(self, gpsmap, ctx):
""" """
draw the circles and the rectangles draw the circles and the rectangles
""" """
ggc = drawable.new_gc()
for circle in self.circles: for circle in self.circles:
top_left = osmgpsmap.point_new_degrees(circle[1] + circle[0], top_left = osmgpsmap.MapPoint.new_degrees(circle[1] + circle[0],
circle[2] - circle[0]) circle[2] - circle[0])
bottom_right = osmgpsmap.point_new_degrees(circle[1] - circle[0], bottom_right = osmgpsmap.MapPoint.new_degrees(circle[1] - circle[0],
circle[2] + circle[0]) circle[2] + circle[0])
crd_x, crd_y = gpsmap.convert_geographic_to_screen(top_left) crd_x, crd_y = gpsmap.convert_geographic_to_screen(top_left)
crd_x2, crd_y2 = gpsmap.convert_geographic_to_screen(bottom_right) crd_x2, crd_y2 = gpsmap.convert_geographic_to_screen(bottom_right)
drawable.draw_arc(ggc, False, crd_x, crd_y, crd_x2 - crd_x, #drawable.draw_arc(ggc, False, crd_x, crd_y, crd_x2 - crd_x,
crd_y2 - crd_y, 0, 360*64) # crd_y2 - crd_y, 0, 360*64)
ctx.arc(crd_x, crd_y, crd_x2 - crd_x, crd_y2 - crd_y, 0, 360*64)
for rectangle in self.rectangles: for rectangle in self.rectangles:
top_left, bottom_right = rectangle top_left, bottom_right = rectangle
crd_x, crd_y = gpsmap.convert_geographic_to_screen(top_left) crd_x, crd_y = gpsmap.convert_geographic_to_screen(top_left)
@ -97,18 +97,22 @@ class SelectionLayer(GObject.GObject, osmgpsmap.MapLayer):
# be sure when can select a region in all case. # be sure when can select a region in all case.
if ( crd_x < crd_x2 ): if ( crd_x < crd_x2 ):
if ( crd_y < crd_y2 ): if ( crd_y < crd_y2 ):
drawable.draw_rectangle(ggc, False, crd_x, crd_y, #drawable.draw_rectangle(ggc, False, crd_x, crd_y,
crd_x2 - crd_x, crd_y2 - crd_y) # crd_x2 - crd_x, crd_y2 - crd_y)
ctx.rectangle(crd_x, crd_y, crd_x2 - crd_x, crd_y2 - crd_y)
else: else:
drawable.draw_rectangle(ggc, False, crd_x, crd_y2, #drawable.draw_rectangle(ggc, False, crd_x, crd_y2,
crd_x2 - crd_x, crd_y - crd_y2) # crd_x2 - crd_x, crd_y - crd_y2)
ctx.rectangle(crd_x, crd_y2, crd_x2 - crd_x, crd_y - crd_y2)
else: else:
if ( crd_y < crd_y2 ): if ( crd_y < crd_y2 ):
drawable.draw_rectangle(ggc, False, crd_x2, crd_y, #drawable.draw_rectangle(ggc, False, crd_x2, crd_y,
crd_x - crd_x2, crd_y2 - crd_y) # crd_x - crd_x2, crd_y2 - crd_y)
ctx.rectangle(crd_x2, crd_y, crd_x - crd_x2, crd_y2 - crd_y)
else: else:
drawable.draw_rectangle(ggc, False, crd_x2, crd_y2, #drawable.draw_rectangle(ggc, False, crd_x2, crd_y2,
crd_x - crd_x2, crd_y - crd_y2) # crd_x - crd_x2, crd_y - crd_y2)
ctx.rectangle(crd_x2, crd_y2, crd_x - crd_x2, crd_y - crd_y2)
def do_render(self, gpsmap): def do_render(self, gpsmap):
""" """

View File

@ -521,30 +521,26 @@ class GeoMoves(GeoGraphyView):
death = high_date death = high_date
new_list.append([level, plxp, birth, death]) new_list.append([level, plxp, birth, death])
pidx = 0; pidx = 0;
color = Gdk.color_parse(color) if isinstance(color, str) :
#try: color = Gdk.color_parse(color)
# color = Gdk.color_parse(color)
#except:
# # We have already a Gdk.color
# pass
for (level, plxp, birth, death) in sorted(new_list, key=operator.itemgetter(0,2)): for (level, plxp, birth, death) in sorted(new_list, key=operator.itemgetter(0,2)):
if index == int(self._config.get("geography.maximum_generations")): if index == int(self._config.get("geography.maximum_generations")):
break break
if level == index: if level == index:
pidx += 1 pidx += 1
self._createmap_for_one_person(plxp, str(color)) self._createmap_for_one_person(plxp, color)
color.red = (float(color.red - (index)*3000)) color.red = (float(color.red - (index)*3000)%65535)
if ( index % 2 ): if ( index % 2 ):
color.green = float((color.green + (index)*3000)) color.green = float((color.green + (index)*3000)%65535)
else: else:
color.blue = float((color.blue + (index)*3000)) color.blue = float((color.blue + (index)*3000)%65535)
self._createmap_for_one_person(person, str(color)) self._createmap_for_one_person(person, color)
if index < int(self._config.get("geography.maximum_generations")): if index < int(self._config.get("geography.maximum_generations")):
time_to_wait = int(self._config.get("geography.generation_interval")) time_to_wait = int(self._config.get("geography.generation_interval"))
self._create_markers() self._create_markers()
# process next generation in a few milliseconds # process next generation in a few milliseconds
GObject.timeout_add(time_to_wait, self.animate_moves, GObject.timeout_add(time_to_wait, self.animate_moves,
index+1, person, str(color)) index+1, person, color)
else: else:
self.started = False self.started = False
return False return False