Пример #1
0
 def edit_filter(self, obj):
     """
     Callback which invokes the EditFilter dialog. Will create new
     filter if called if none is selected.
     """
     from ...editors import EditFilter
     from gramps.gen.filters import FilterList, GenericFilterFactory
     from gramps.gen.const import CUSTOM_FILTERS
     the_filter = None
     filterdb = FilterList(CUSTOM_FILTERS)
     filterdb.load()
     if self.generic.get_active() != 0:
         model = self.generic.get_model()
         node = self.generic.get_active_iter()
         if node:
             sel_filter = model.get_value(node, 1)
             # the_filter needs to be a particular object for editor
             for filt in filterdb.get_filters(self.namespace):
                 if filt.get_name() == sel_filter.get_name():
                     the_filter = filt
     else:
         the_filter = GenericFilterFactory(self.namespace)()
     if the_filter:
         EditFilter(self.namespace, self.dbstate, self.uistate, [],
                    the_filter, filterdb,
                    selection_callback=self.edit_filter_save)
Пример #2
0
 def edit_filter(self, namespace, filter_obj):
     """
     Callback which invokes the EditFilter dialog. Will create new
     filter if called if none is selected.
     """
     from ...editors import EditFilter
     from gramps.gen.filters import FilterList, GenericFilterFactory
     from gramps.gen.const import CUSTOM_FILTERS
     the_filter = None
     filterdb = FilterList(CUSTOM_FILTERS)
     filterdb.load()
     if filter_obj.get_active() != 0:
         model = filter_obj.get_model()
         node = filter_obj.get_active_iter()
         if node:
             sel_filter = model.get_value(node, 1)
             # the_filter needs to be a particular object for editor
             for filt in filterdb.get_filters(namespace):
                 if filt.get_name() == sel_filter.get_name():
                     the_filter = filt
     else:
         the_filter = GenericFilterFactory(namespace)()
     if the_filter:
         EditFilter(namespace, self.dbstate, self.uistate, self.track,
                    the_filter, filterdb,
                    lambda : self.edit_filter_save(filterdb, namespace))
     else: # can't edit this filter
         from ...dialog import ErrorDialog
         ErrorDialog(_("Cannot edit a system filter"),
                     _("Please select a different filter to edit"),
                     parent=self.window)
Пример #3
0
 def edit_filter(self, obj):
     """
     Callback which invokes the EditFilter dialog. Will create new
     filter if called if none is selected.
     """
     from ...editors import EditFilter
     from gramps.gen.filters import FilterList, GenericFilterFactory
     from gramps.gen.const import CUSTOM_FILTERS
     the_filter = None
     filterdb = FilterList(CUSTOM_FILTERS)
     filterdb.load()
     if self.generic.get_active() != 0:
         model = self.generic.get_model()
         node = self.generic.get_active_iter()
         if node:
             sel_filter = model.get_value(node, 1)
             # the_filter needs to be a particular object for editor
             for filt in filterdb.get_filters(self.namespace):
                 if filt.get_name() == sel_filter.get_name():
                     the_filter = filt
     else:
         the_filter = GenericFilterFactory(self.namespace)()
     if the_filter:
         EditFilter(self.namespace,
                    self.dbstate,
                    self.uistate, [],
                    the_filter,
                    filterdb,
                    selection_callback=self.edit_filter_save)
Пример #4
0
 def edit_filter(self, namespace, filter_obj):
     """
     Callback which invokes the EditFilter dialog. Will create new
     filter if called if none is selected.
     """
     from ...editors import EditFilter
     from gramps.gen.filters import FilterList, GenericFilterFactory
     from gramps.gen.const import CUSTOM_FILTERS
     the_filter = None
     filterdb = FilterList(CUSTOM_FILTERS)
     filterdb.load()
     if filter_obj.get_active() != 0:
         model = filter_obj.get_model()
         node = filter_obj.get_active_iter()
         if node:
             sel_filter = model.get_value(node, 1)
             # the_filter needs to be a particular object for editor
             for filt in filterdb.get_filters(namespace):
                 if filt.get_name() == sel_filter.get_name():
                     the_filter = filt
     else:
         the_filter = GenericFilterFactory(namespace)()
     if the_filter:
         EditFilter(namespace, self.dbstate, self.uistate, [], the_filter,
                    filterdb,
                    lambda: self.edit_filter_save(filterdb, namespace))
     else:  # can't edit this filter
         from ...dialog import ErrorDialog
         ErrorDialog(_("Cannot edit a system filter"),
                     _("Please select a different filter to edit"))
Пример #5
0
def make_filter(dbstate, uistate, objclass, gramps_ids, title=None):
    """
    Makes a Gramps Filter through dialog from a enumeration (list,
    set, etc.) of gramps_ids of type objclass.

    >>> make_filter(dbstate, uistate, 'Person', ['I0003', ...])
    """
    FilterClass = GenericFilterFactory(objclass)
    rule = getattr(getattr(rules, objclass),'RegExpIdOf')
    filter = FilterClass()
    if title is None:
        title = _("Filter %s from Clipboard") % objclass
    if isinstance(title, collections.Callable):
        title = title()
    filter.set_name(title)
    struct_time = time.localtime()
    filter.set_comment( _("Created on %(year)4d/%(month)02d/%(day)02d") % { 
        'year': struct_time.tm_year,
        'month': struct_time.tm_mon,
        'day': struct_time.tm_mday})
    re = "|".join(["^%s$" % gid for gid in sorted(gramps_ids)])
    filter.add_rule(rule([re]))
    filterdb = FilterList(CUSTOM_FILTERS)
    filterdb.load()
    EditFilter(objclass, dbstate, uistate, [],
               filter, filterdb,
               lambda : edit_filter_save(uistate, filterdb, objclass))
Пример #6
0
def make_filter(dbstate, uistate, objclass, gramps_ids, title=None):
    """
    Makes a Gramps Filter through dialog from a enumeration (list,
    set, etc.) of gramps_ids of type objclass.

    >>> make_filter(dbstate, uistate, 'Person', ['I0003', ...])
    """
    FilterClass = GenericFilterFactory(objclass)
    rule = getattr(getattr(rules, objclass.lower()),'RegExpIdOf')
    filter = FilterClass()
    if title is None:
        title = _("Filter %s from Clipboard") % objclass
    if isinstance(title, abc.Callable):
        title = title()
    filter.set_name(title)
    struct_time = time.localtime()
    filter.set_comment( _("Created on %(year)4d/%(month)02d/%(day)02d") % {
        'year': struct_time.tm_year,
        'month': struct_time.tm_mon,
        'day': struct_time.tm_mday})
    re = "|".join(["^%s$" % gid for gid in sorted(gramps_ids)])
    re_rule = rule([re])
    re_rule.use_regex = True
    filter.add_rule(re_rule)
    filterdb = FilterList(CUSTOM_FILTERS)
    filterdb.load()
    EditFilter(objclass, dbstate, uistate, [],
               filter, filterdb,
               lambda : edit_filter_save(uistate, filterdb, objclass))
Пример #7
0
 def filterfunc(filtername):
     if not Filterfactory.filterdb:
         Filterfactory.filterdb = FilterList(CUSTOM_FILTERS)
         Filterfactory.filterdb.load()
     filter_dict = Filterfactory.filterdb.get_filters_dict(namespace)
     filt = filter_dict[filtername]
     return lambda obj: filt.match(obj.handle, self.db)
Пример #8
0
    def __init__(self, namespace, filterdb, dbstate, uistate):

        ManagedWindow.__init__(self, uistate, [], FilterEditor)
        self.dbstate = dbstate
        self.db = dbstate.db
        self.filterdb = FilterList(filterdb)
        self.filterdb.load()
        self.width_key = "interface.filter-editor-width"
        self.height_key = "interface.filter-editor-height"
        self.namespace = namespace

        self.define_glade('filter_list', RULE_GLADE)
        self.filter_list = self.get_widget('filters')
        self.edit = self.get_widget('filter_list_edit')
        self.clone = self.get_widget('filter_list_clone')
        self.delete = self.get_widget('filter_list_delete')
        self.test = self.get_widget('filter_list_test')

        self.edit.set_sensitive(False)
        self.clone.set_sensitive(False)
        self.delete.set_sensitive(False)
        self.test.set_sensitive(False)

        self.set_window(self.get_widget('filter_list'),
                        self.get_widget('filter_list_title'),
                        _TITLES[self.namespace])

        self.edit.connect('clicked', self.edit_filter)
        self.clone.connect('clicked', self.clone_filter)
        self.test.connect('clicked', self.test_clicked)
        self.delete.connect('clicked', self.delete_filter)

        self.connect_button('filter_list_help', self.help_clicked)
        self.connect_button('filter_list_close', self.close)
        self.connect_button('filter_list_add', self.add_new_filter)

        self.uistate.connect('filter-name-changed', self.clean_after_rename)

        self.clist = ListModel(
                            self.filter_list,
                            [(_('Filter'), 0, 150), (_('Comment'), 1, 150)],
                            self.filter_select_row,
                            self.edit_filter)
        self.draw_filters()
        self._set_size()
        self.show()
Пример #9
0
    def __init__(self, namespace, filterdb, dbstate, uistate):

        ManagedWindow.__init__(self, uistate, [], FilterEditor)
        self.dbstate = dbstate
        self.db = dbstate.db
        self.filterdb = FilterList(filterdb)
        self.filterdb.load()
        self.width_key = "interface.filter-editor-width"
        self.height_key = "interface.filter-editor-height"
        self.namespace = namespace

        self.define_glade('filter_list', RULE_GLADE)
        self.filter_list = self.get_widget('filters')
        self.edit = self.get_widget('filter_list_edit')
        self.clone = self.get_widget('filter_list_clone')
        self.delete = self.get_widget('filter_list_delete')
        self.test = self.get_widget('filter_list_test')

        self.edit.set_sensitive(False)
        self.clone.set_sensitive(False)
        self.delete.set_sensitive(False)
        self.test.set_sensitive(False)

        self.set_window(self.get_widget('filter_list'),
                        self.get_widget('filter_list_title'),
                        _TITLES[self.namespace]) 

        self.edit.connect('clicked', self.edit_filter)
        self.clone.connect('clicked', self.clone_filter)
        self.test.connect('clicked', self.test_clicked)
        self.delete.connect('clicked', self.delete_filter)

        self.connect_button('filter_list_help', self.help_clicked)
        self.connect_button('filter_list_close', self.close)
        self.connect_button('filter_list_add', self.add_new_filter)
        
        self.uistate.connect('filter-name-changed', self.clean_after_rename)

        self.clist = ListModel(
                            self.filter_list,
                            [(_('Filter'), 0, 150), (_('Comment'), 1, 150)],
                            self.filter_select_row,
                            self.edit_filter)
        self.draw_filters()
        self._set_size()
        self.show()
Пример #10
0
class FilterEditor(ManagedWindow):
    def __init__(self, namespace, filterdb, dbstate, uistate):

        ManagedWindow.__init__(self, uistate, [], FilterEditor)
        self.dbstate = dbstate
        self.db = dbstate.db
        self.filterdb = FilterList(filterdb)
        self.filterdb.load()
        self.width_key = "interface.filter-editor-width"
        self.height_key = "interface.filter-editor-height"
        self.namespace = namespace

        self.define_glade('filter_list', RULE_GLADE)
        self.filter_list = self.get_widget('filters')
        self.edit = self.get_widget('filter_list_edit')
        self.clone = self.get_widget('filter_list_clone')
        self.delete = self.get_widget('filter_list_delete')
        self.test = self.get_widget('filter_list_test')

        self.edit.set_sensitive(False)
        self.clone.set_sensitive(False)
        self.delete.set_sensitive(False)
        self.test.set_sensitive(False)

        self.set_window(self.get_widget('filter_list'),
                        self.get_widget('filter_list_title'),
                        _TITLES[self.namespace])

        self.edit.connect('clicked', self.edit_filter)
        self.clone.connect('clicked', self.clone_filter)
        self.test.connect('clicked', self.test_clicked)
        self.delete.connect('clicked', self.delete_filter)

        self.connect_button('filter_list_help', self.help_clicked)
        self.connect_button('filter_list_close', self.close)
        self.connect_button('filter_list_add', self.add_new_filter)

        self.uistate.connect('filter-name-changed', self.clean_after_rename)

        self.clist = ListModel(self.filter_list, [(_('Filter'), 0, 150),
                                                  (_('Comment'), 1, 150)],
                               self.filter_select_row, self.edit_filter)
        self.draw_filters()
        self._set_size()
        self.show()

    def build_menu_names(self, obj):
        return (_("Custom Filter Editor"), _("Custom Filter Editor"))

    def help_clicked(self, obj):
        """Display the relevant portion of Gramps manual"""
        display_help(webpage=WIKI_HELP_PAGE, section=WIKI_HELP_SEC3)

    def filter_select_row(self, obj):
        store, node = self.clist.get_selected()
        if node:
            self.edit.set_sensitive(True)
            self.clone.set_sensitive(True)
            self.delete.set_sensitive(True)
            self.test.set_sensitive(True)
        else:
            self.edit.set_sensitive(False)
            self.clone.set_sensitive(False)
            self.delete.set_sensitive(False)
            self.test.set_sensitive(False)

    def close(self, *obj):
        self.filterdb.save()
        reload_custom_filters()
        #reload_system_filters()
        self.uistate.emit('filters-changed', (self.namespace, ))
        ManagedWindow.close(self, *obj)

    def draw_filters(self):
        self.clist.clear()
        for f in self.filterdb.get_filters(self.namespace):
            self.clist.add([f.get_name(), f.get_comment()], f)

    def add_new_filter(self, obj):
        the_filter = GenericFilterFactory(self.namespace)()
        EditFilter(self.namespace, self.dbstate, self.uistate, self.track,
                   the_filter, self.filterdb, self.draw_filters)

    def edit_filter(self, obj):
        store, node = self.clist.get_selected()
        if node:
            gfilter = self.clist.get_object(node)
            EditFilter(self.namespace, self.dbstate, self.uistate, self.track,
                       gfilter, self.filterdb, self.draw_filters)

    def clone_filter(self, obj):
        store, node = self.clist.get_selected()
        if node:
            old_filter = self.clist.get_object(node)
            the_filter = GenericFilterFactory(self.namespace)(old_filter)
            the_filter.set_name('')
            EditFilter(self.namespace, self.dbstate, self.uistate, self.track,
                       the_filter, self.filterdb, self.draw_filters)

    def test_clicked(self, obj):
        store, node = self.clist.get_selected()
        if node:
            filt = self.clist.get_object(node)
            handle_list = filt.apply(self.db, self.get_all_handles())
            ShowResults(self.db, self.uistate, self.track, handle_list,
                        filt.get_name(), self.namespace)

    def delete_filter(self, obj):
        store, node = self.clist.get_selected()
        if node:
            gfilter = self.clist.get_object(node)
            name = gfilter.get_name()
            if self.check_recursive_filters(self.namespace, name):
                QuestionDialog(
                    _('Delete Filter?'),
                    _('This filter is currently being used '
                      'as the base for other filters. Deleting'
                      'this filter will result in removing all '
                      'other filters that depend on it.'), _('Delete Filter'),
                    self._do_delete_selected_filter, self.window)
            else:
                self._do_delete_selected_filter()

    def _do_delete_selected_filter(self):
        store, node = self.clist.get_selected()
        if node:
            gfilter = self.clist.get_object(node)
            self._do_delete_filter(self.namespace, gfilter)
            self.draw_filters()

    def _do_delete_filter(self, space, gfilter):
        # Find everything we need to remove
        filter_set = set()
        self._find_dependent_filters(space, gfilter, filter_set)

        # Remove what we found
        filters = self.filterdb.get_filters(space)
        list(map(filters.remove, filter_set))

    def _find_dependent_filters(self, space, gfilter, filter_set):
        """
        This method recursively calls itself to find all filters that
        depend on the given filter, either directly through one of the rules,
        or through the chain of dependencies.

        The filter_set is amended with the found filters.
        """
        filters = self.filterdb.get_filters(space)
        name = gfilter.get_name()
        for the_filter in filters:
            if the_filter.get_name() == name:
                continue
            for rule in the_filter.get_rules():
                values = list(rule.values())
                if issubclass(rule.__class__, MatchesFilterBase) \
                       and (name in values):
                    self._find_dependent_filters(space, the_filter, filter_set)
                    break
        # Add itself to the filter_set
        filter_set.add(gfilter)

    def get_all_handles(self):
        # Why use iter for some and get for others?
        if self.namespace == 'Person':
            return self.db.iter_person_handles()
        elif self.namespace == 'Family':
            return self.db.iter_family_handles()
        elif self.namespace == 'Event':
            return self.db.get_event_handles()
        elif self.namespace == 'Source':
            return self.db.get_source_handles()
        elif self.namespace == 'Citation':
            return self.db.get_citation_handles()
        elif self.namespace == 'Place':
            return self.db.iter_place_handles()
        elif self.namespace == 'Media':
            return self.db.get_media_object_handles()
        elif self.namespace == 'Repository':
            return self.db.get_repository_handles()
        elif self.namespace == 'Note':
            return self.db.get_note_handles()

    def clean_after_rename(self, space, old_name, new_name):
        if old_name == "":
            return

        if old_name == new_name:
            return

        for the_filter in self.filterdb.get_filters(space):
            for rule in the_filter.get_rules():
                values = list(rule.values())
                if issubclass(rule.__class__, MatchesFilterBase) \
                       and (old_name in values):
                    ind = values.index(old_name)
                    values[ind] = new_name

    def check_recursive_filters(self, space, name):
        for the_filter in self.filterdb.get_filters(space):
            for rule in the_filter.get_rules():
                values = list(rule.values())
                if issubclass(rule.__class__, MatchesFilterBase) \
                       and (name in values):
                    return True
        return False
Пример #11
0
class FilterEditor(ManagedWindow):
    def __init__(self, namespace, filterdb, dbstate, uistate):

        ManagedWindow.__init__(self, uistate, [], FilterEditor)
        self.dbstate = dbstate
        self.db = dbstate.db
        self.filterdb = FilterList(filterdb)
        self.filterdb.load()
        self.namespace = namespace

        self.define_glade('filter_list', RULE_GLADE)
        self.filter_list = self.get_widget('filters')
        self.edit = self.get_widget('filter_list_edit')
        self.clone = self.get_widget('filter_list_clone')
        self.delete = self.get_widget('filter_list_delete')
        self.test = self.get_widget('filter_list_test')

        self.edit.set_sensitive(False)
        self.clone.set_sensitive(False)
        self.delete.set_sensitive(False)
        self.test.set_sensitive(False)

        self.set_window(self.get_widget('filter_list'),
                        self.get_widget('filter_list_title'),
                        _TITLES[self.namespace])
        self.setup_configs('interface.filter-editor', 400, 350)

        self.edit.connect('clicked', self.edit_filter)
        self.clone.connect('clicked', self.clone_filter)
        self.test.connect('clicked', self.test_clicked)
        self.delete.connect('clicked', self.delete_filter)

        self.connect_button('filter_list_help', self.help_clicked)
        self.connect_button('filter_list_close', self.close)
        self.connect_button('filter_list_add', self.add_new_filter)

        self.uistate.connect('filter-name-changed', self.clean_after_rename)

        self.clist = ListModel(
                            self.filter_list,
                            [(_('Filter'), 0, 150), (_('Comment'), 1, 150)],
                            self.filter_select_row,
                            self.edit_filter)
        self.draw_filters()
        self._set_size()
        self.show()

    def build_menu_names(self, obj):
        return (_("Custom Filter Editor"), _("Custom Filter Editor"))

    def help_clicked(self, obj):
        """Display the relevant portion of Gramps manual"""
        display_help(webpage=WIKI_HELP_PAGE,
                                   section=WIKI_HELP_SEC3)

    def filter_select_row(self, obj):
        store, node = self.clist.get_selected()
        if node:
            self.edit.set_sensitive(True)
            self.clone.set_sensitive(True)
            self.delete.set_sensitive(True)
            self.test.set_sensitive(True)
        else:
            self.edit.set_sensitive(False)
            self.clone.set_sensitive(False)
            self.delete.set_sensitive(False)
            self.test.set_sensitive(False)

    def close(self, *obj):
        self.filterdb.save()
        reload_custom_filters()
        #reload_system_filters()
        self.uistate.emit('filters-changed', (self.namespace,))
        ManagedWindow.close(self, *obj)

    def draw_filters(self):
        self.clist.clear()
        for f in self.filterdb.get_filters(self.namespace):
            self.clist.add([f.get_name(), f.get_comment()], f)

    def add_new_filter(self, obj):
        the_filter = GenericFilterFactory(self.namespace)()
        EditFilter(self.namespace, self.dbstate, self.uistate, self.track,
                   the_filter, self.filterdb, self.draw_filters)

    def edit_filter(self, obj):
        store, node = self.clist.get_selected()
        if node:
            gfilter = self.clist.get_object(node)
            EditFilter(self.namespace, self.dbstate, self.uistate, self.track,
                       gfilter, self.filterdb, self.draw_filters)

    def clone_filter(self, obj):
        store, node = self.clist.get_selected()
        if node:
            old_filter = self.clist.get_object(node)
            the_filter = GenericFilterFactory(self.namespace)(old_filter)
            the_filter.set_name('')
            EditFilter(self.namespace, self.dbstate, self.uistate, self.track,
                       the_filter, self.filterdb, self.draw_filters)

    def test_clicked(self, obj):
        store, node = self.clist.get_selected()
        if node:
            filt = self.clist.get_object(node)
            try:
                handle_list = filt.apply(self.db, self.get_all_handles())
            except FilterError as msg:
                (msg1, msg2) = msg.messages()
                ErrorDialog(msg1, msg2, parent=self.window)
                return
            ShowResults(self.db, self.uistate, self.track, handle_list,
                        filt.get_name(),self.namespace)

    def delete_filter(self, obj):
        store, node = self.clist.get_selected()
        if node:
            gfilter = self.clist.get_object(node)
            name = gfilter.get_name()
            if self.check_recursive_filters(self.namespace, name):
                QuestionDialog( _('Delete Filter?'),
                                _('This filter is currently being used '
                                  'as the base for other filters. Deleting'
                                  'this filter will result in removing all '
                                  'other filters that depend on it.'),
                                _('Delete Filter'),
                                self._do_delete_selected_filter,
                                parent=self.window)
            else:
                self._do_delete_selected_filter()

    def _do_delete_selected_filter(self):
        store, node = self.clist.get_selected()
        if node:
            gfilter = self.clist.get_object(node)
            self._do_delete_filter(self.namespace, gfilter)
            self.draw_filters()

    def _do_delete_filter(self, space, gfilter):
        # Find everything we need to remove
        filter_set = set()
        self._find_dependent_filters(space, gfilter, filter_set)

        # Remove what we found
        filters = self.filterdb.get_filters(space)
        list(map(filters.remove, filter_set))

    def _find_dependent_filters(self, space, gfilter, filter_set):
        """
        This method recursively calls itself to find all filters that
        depend on the given filter, either directly through one of the rules,
        or through the chain of dependencies.

        The filter_set is amended with the found filters.
        """
        filters = self.filterdb.get_filters(space)
        name = gfilter.get_name()
        for the_filter in filters:
            if the_filter.get_name() == name:
                continue
            for rule in the_filter.get_rules():
                values = list(rule.values())
                if issubclass(rule.__class__, MatchesFilterBase) \
                       and (name in values):
                    self._find_dependent_filters(space, the_filter, filter_set)
                    break
        # Add itself to the filter_set
        filter_set.add(gfilter)

    def get_all_handles(self):
        # Why use iter for some and get for others?
        if self.namespace == 'Person':
            return self.db.iter_person_handles()
        elif self.namespace == 'Family':
            return self.db.iter_family_handles()
        elif self.namespace == 'Event':
            return self.db.get_event_handles()
        elif self.namespace == 'Source':
            return self.db.get_source_handles()
        elif self.namespace == 'Citation':
            return self.db.get_citation_handles()
        elif self.namespace == 'Place':
            return self.db.iter_place_handles()
        elif self.namespace == 'Media':
            return self.db.get_media_handles()
        elif self.namespace == 'Repository':
            return self.db.get_repository_handles()
        elif self.namespace == 'Note':
            return self.db.get_note_handles()

    def clean_after_rename(self, space, old_name, new_name):
        if old_name == "":
            return

        if old_name == new_name:
            return

        for the_filter in self.filterdb.get_filters(space):
            for rule in the_filter.get_rules():
                values = list(rule.values())
                if issubclass(rule.__class__, MatchesFilterBase) \
                       and (old_name in values):
                    ind = values.index(old_name)
                    values[ind] = new_name

    def check_recursive_filters(self, space, name):
        for the_filter in self.filterdb.get_filters(space):
            for rule in the_filter.get_rules():
                values = list(rule.values())
                if issubclass(rule.__class__, MatchesFilterBase) \
                       and (name in values):
                    return True
        return False