Fixed autocompletion, WriteXML is now a class
svn: r695
This commit is contained in:
parent
c8943dc65e
commit
910b857712
@ -49,6 +49,7 @@ import Date
|
|||||||
from RelLib import *
|
from RelLib import *
|
||||||
import ImageSelect
|
import ImageSelect
|
||||||
import sort
|
import sort
|
||||||
|
import AutoComp
|
||||||
|
|
||||||
from intl import gettext
|
from intl import gettext
|
||||||
_ = gettext
|
_ = gettext
|
||||||
@ -231,7 +232,8 @@ class EditPerson:
|
|||||||
self.window.editable_enters(self.ddate);
|
self.window.editable_enters(self.ddate);
|
||||||
self.window.editable_enters(self.dplace);
|
self.window.editable_enters(self.dplace);
|
||||||
|
|
||||||
utils.attach_surnames(self.get_widget("lastNameList"))
|
if Config.autocomp:
|
||||||
|
AutoComp.AutoComp(self.surname_field,const.surnames)
|
||||||
|
|
||||||
self.gid.set_text(person.getId())
|
self.gid.set_text(person.getId())
|
||||||
self.gid.set_editable(Config.id_edit)
|
self.gid.set_editable(Config.id_edit)
|
||||||
|
@ -29,6 +29,7 @@ import const
|
|||||||
import utils
|
import utils
|
||||||
import string
|
import string
|
||||||
import gtk
|
import gtk
|
||||||
|
import AutoComp
|
||||||
|
|
||||||
class Find:
|
class Find:
|
||||||
"""Opens find person dialog for gramps"""
|
"""Opens find person dialog for gramps"""
|
||||||
@ -51,14 +52,13 @@ class Find:
|
|||||||
|
|
||||||
self.top = self.xml.get_widget("find")
|
self.top = self.xml.get_widget("find")
|
||||||
self.entry = self.xml.get_widget("entry")
|
self.entry = self.xml.get_widget("entry")
|
||||||
|
|
||||||
|
self.nlist = []
|
||||||
|
for n in plist:
|
||||||
|
self.nlist.append(n.getPrimaryName().getName())
|
||||||
|
|
||||||
if Config.autocomp:
|
if Config.autocomp:
|
||||||
self.nlist = [("","")]
|
AutoComp.AutoComp(self.entry,self.nlist)
|
||||||
for n in plist:
|
|
||||||
n1 = n.getPrimaryName().getName()
|
|
||||||
n2 = string.lower(n1)
|
|
||||||
self.nlist.append((n2,n1))
|
|
||||||
self.nlist.sort()
|
|
||||||
self.entry.connect("insert-text",self.insert_text)
|
|
||||||
|
|
||||||
self.next = self.xml.get_widget("next")
|
self.next = self.xml.get_widget("next")
|
||||||
self.top.editable_enters(self.entry)
|
self.top.editable_enters(self.entry)
|
||||||
@ -139,83 +139,3 @@ class Find:
|
|||||||
"""Callback for dialog box that causes the previous person to be found"""
|
"""Callback for dialog box that causes the previous person to be found"""
|
||||||
self.find_prev()
|
self.find_prev()
|
||||||
|
|
||||||
#-------------------------------------------------------------------------
|
|
||||||
#
|
|
||||||
# Sets up a delayed (0.005 sec) handler for text completion. Text
|
|
||||||
# completion cannot be handled directly in this routine because, for
|
|
||||||
# some reason, the select_region() function doesn't work when called
|
|
||||||
# from signal handlers. Go figure.
|
|
||||||
#
|
|
||||||
# Thanks to iain@nodata.demon.co.uk (in mail from 1999) for the idea
|
|
||||||
# to use a timer to get away from the problems with signal handlers
|
|
||||||
# and the select_region function.
|
|
||||||
#
|
|
||||||
#-------------------------------------------------------------------------
|
|
||||||
def insert_text(self,entry,new_text,new_text_len,i_dont_care):
|
|
||||||
# One time setup to clear selected region when user moves on
|
|
||||||
if (not entry.get_data("signal_set")):
|
|
||||||
entry.set_data("signal_set",1)
|
|
||||||
entry.signal_connect("focus_out_event", self.lost_focus, entry)
|
|
||||||
|
|
||||||
# Nuke the current timer if the user types fast enough
|
|
||||||
timer = entry.get_data("timer");
|
|
||||||
if (timer):
|
|
||||||
gtk.timeout_remove(timer)
|
|
||||||
|
|
||||||
# Setup a callback timer so we can operate outside of a signal handler
|
|
||||||
timer = gtk.timeout_add(5, self.timer_callback, entry)
|
|
||||||
entry.set_data("timer", timer);
|
|
||||||
|
|
||||||
#-------------------------------------------------------------------------
|
|
||||||
#
|
|
||||||
# The entry box entry field lost focus. Go clear any selection. Why
|
|
||||||
# this form of a select_region() call works in a signal handler and
|
|
||||||
# the other form doesn't is a mystery.
|
|
||||||
#
|
|
||||||
#-------------------------------------------------------------------------
|
|
||||||
def lost_focus(self,entry,a,b):
|
|
||||||
entry.select_region(0, 0)
|
|
||||||
|
|
||||||
#-------------------------------------------------------------------------
|
|
||||||
#
|
|
||||||
# The workhorse routine of file completion. This routine grabs the
|
|
||||||
# current text of the entry box, and grubs through the list item
|
|
||||||
# looking for any case insensitive matches. This routine relies on
|
|
||||||
# public knowledge of the GtkEntry data structure, not on any private
|
|
||||||
# data.
|
|
||||||
#
|
|
||||||
# These three completion routines have only one gramps specific hook,
|
|
||||||
# and can be easily ported to any program.
|
|
||||||
#
|
|
||||||
#-------------------------------------------------------------------------
|
|
||||||
def timer_callback(self,entry):
|
|
||||||
# Clear any timer
|
|
||||||
timer = entry.get_data("timer");
|
|
||||||
if (timer):
|
|
||||||
gtk.timeout_remove(timer)
|
|
||||||
|
|
||||||
# Get the user's text
|
|
||||||
typed = entry.get_text()
|
|
||||||
if (not typed):
|
|
||||||
return
|
|
||||||
typed_lc = string.lower(typed)
|
|
||||||
|
|
||||||
# Walk the GtkList in the entry box
|
|
||||||
for nl,n in self.nlist:
|
|
||||||
if (not nl):
|
|
||||||
continue
|
|
||||||
|
|
||||||
# If equal, no need to add any text
|
|
||||||
if (typed_lc == nl):
|
|
||||||
return
|
|
||||||
|
|
||||||
# If typed text is a substring of the label text, then fill in
|
|
||||||
# the entry field with the full text (and correcting
|
|
||||||
# capitalization), and then select all the characters that
|
|
||||||
# don't match. With the user's enxt keystroke these will be
|
|
||||||
# replaced if they are incorrect.
|
|
||||||
if (string.find(nl,typed_lc) == 0):
|
|
||||||
entry.set_text(n)
|
|
||||||
entry.set_position(len(typed))
|
|
||||||
entry.select_region(len(typed), -1)
|
|
||||||
return
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -2185,29 +2185,117 @@
|
|||||||
</widget>
|
</widget>
|
||||||
|
|
||||||
<widget>
|
<widget>
|
||||||
<class>GtkLabel</class>
|
<class>GtkHBox</class>
|
||||||
<child_name>CList:title</child_name>
|
<child_name>CList:title</child_name>
|
||||||
<name>glabel13</name>
|
<name>hbox70</name>
|
||||||
<label>ID</label>
|
<homogeneous>True</homogeneous>
|
||||||
<justify>GTK_JUSTIFY_CENTER</justify>
|
<spacing>0</spacing>
|
||||||
<wrap>False</wrap>
|
|
||||||
<xalign>0.5</xalign>
|
<widget>
|
||||||
<yalign>0.5</yalign>
|
<class>GtkHBox</class>
|
||||||
<xpad>0</xpad>
|
<name>hbox71</name>
|
||||||
<ypad>0</ypad>
|
<homogeneous>False</homogeneous>
|
||||||
|
<spacing>0</spacing>
|
||||||
|
<child>
|
||||||
|
<padding>0</padding>
|
||||||
|
<expand>False</expand>
|
||||||
|
<fill>False</fill>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<widget>
|
||||||
|
<class>GtkLabel</class>
|
||||||
|
<child_name>CList:title</child_name>
|
||||||
|
<name>label294</name>
|
||||||
|
<label>ID</label>
|
||||||
|
<justify>GTK_JUSTIFY_CENTER</justify>
|
||||||
|
<wrap>False</wrap>
|
||||||
|
<xalign>0.5</xalign>
|
||||||
|
<yalign>0.5</yalign>
|
||||||
|
<xpad>0</xpad>
|
||||||
|
<ypad>0</ypad>
|
||||||
|
<child>
|
||||||
|
<padding>0</padding>
|
||||||
|
<expand>False</expand>
|
||||||
|
<fill>False</fill>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
|
||||||
|
<widget>
|
||||||
|
<class>GtkArrow</class>
|
||||||
|
<name>cIDSort</name>
|
||||||
|
<width>10</width>
|
||||||
|
<height>10</height>
|
||||||
|
<visible>False</visible>
|
||||||
|
<arrow_type>GTK_ARROW_DOWN</arrow_type>
|
||||||
|
<shadow_type>GTK_SHADOW_OUT</shadow_type>
|
||||||
|
<xalign>0.5</xalign>
|
||||||
|
<yalign>0.5</yalign>
|
||||||
|
<xpad>0</xpad>
|
||||||
|
<ypad>0</ypad>
|
||||||
|
<child>
|
||||||
|
<padding>5</padding>
|
||||||
|
<expand>False</expand>
|
||||||
|
<fill>True</fill>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
|
|
||||||
<widget>
|
<widget>
|
||||||
<class>GtkLabel</class>
|
<class>GtkHBox</class>
|
||||||
<child_name>CList:title</child_name>
|
<child_name>CList:title</child_name>
|
||||||
<name>label14</name>
|
<name>hbox72</name>
|
||||||
<label>Gender</label>
|
<homogeneous>True</homogeneous>
|
||||||
<justify>GTK_JUSTIFY_CENTER</justify>
|
<spacing>0</spacing>
|
||||||
<wrap>False</wrap>
|
|
||||||
<xalign>0.5</xalign>
|
<widget>
|
||||||
<yalign>0.5</yalign>
|
<class>GtkHBox</class>
|
||||||
<xpad>0</xpad>
|
<name>hbox73</name>
|
||||||
<ypad>0</ypad>
|
<homogeneous>False</homogeneous>
|
||||||
|
<spacing>0</spacing>
|
||||||
|
<child>
|
||||||
|
<padding>0</padding>
|
||||||
|
<expand>False</expand>
|
||||||
|
<fill>False</fill>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<widget>
|
||||||
|
<class>GtkLabel</class>
|
||||||
|
<child_name>CList:title</child_name>
|
||||||
|
<name>label295</name>
|
||||||
|
<label>Gender</label>
|
||||||
|
<justify>GTK_JUSTIFY_CENTER</justify>
|
||||||
|
<wrap>False</wrap>
|
||||||
|
<xalign>0.5</xalign>
|
||||||
|
<yalign>0.5</yalign>
|
||||||
|
<xpad>0</xpad>
|
||||||
|
<ypad>0</ypad>
|
||||||
|
<child>
|
||||||
|
<padding>0</padding>
|
||||||
|
<expand>False</expand>
|
||||||
|
<fill>False</fill>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
|
||||||
|
<widget>
|
||||||
|
<class>GtkArrow</class>
|
||||||
|
<name>cGenderSort</name>
|
||||||
|
<width>10</width>
|
||||||
|
<height>10</height>
|
||||||
|
<visible>False</visible>
|
||||||
|
<arrow_type>GTK_ARROW_DOWN</arrow_type>
|
||||||
|
<shadow_type>GTK_SHADOW_OUT</shadow_type>
|
||||||
|
<xalign>0.5</xalign>
|
||||||
|
<yalign>0.5</yalign>
|
||||||
|
<xpad>0</xpad>
|
||||||
|
<ypad>0</ypad>
|
||||||
|
<child>
|
||||||
|
<padding>5</padding>
|
||||||
|
<expand>False</expand>
|
||||||
|
<fill>True</fill>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
|
|
||||||
<widget>
|
<widget>
|
||||||
|
@ -118,11 +118,14 @@ DataFilter = Filter.Filter("")
|
|||||||
c_birth_order = 0
|
c_birth_order = 0
|
||||||
c_name = 1
|
c_name = 1
|
||||||
c_id = 2
|
c_id = 2
|
||||||
|
c_gender = 3
|
||||||
c_birth_date = 4
|
c_birth_date = 4
|
||||||
c_details = 6
|
c_details = 6
|
||||||
c_sort_column = c_birth_order
|
c_sort_column = c_birth_order
|
||||||
c_sort_direct = GTK.SORT_ASCENDING
|
c_sort_direct = GTK.SORT_ASCENDING
|
||||||
cNameArrow = None
|
cNameArrow = None
|
||||||
|
cGenderArrow = None
|
||||||
|
cIDArrow = None
|
||||||
cDateArrow = None
|
cDateArrow = None
|
||||||
|
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
@ -843,7 +846,7 @@ def set_sort_arrow(column,direct):
|
|||||||
else:
|
else:
|
||||||
arrow.set(GTK.ARROW_UP,2)
|
arrow.set(GTK.ARROW_UP,2)
|
||||||
|
|
||||||
def change_sort(column):
|
def change_sort(column,change=1):
|
||||||
global sort_direct
|
global sort_direct
|
||||||
global sort_column
|
global sort_column
|
||||||
|
|
||||||
@ -855,22 +858,24 @@ def change_sort(column):
|
|||||||
a.hide()
|
a.hide()
|
||||||
arrow.show()
|
arrow.show()
|
||||||
|
|
||||||
if sort_column == column:
|
|
||||||
if sort_direct == GTK.SORT_DESCENDING:
|
|
||||||
sort_direct = GTK.SORT_ASCENDING
|
|
||||||
arrow.set(GTK.ARROW_DOWN,2)
|
|
||||||
else:
|
|
||||||
sort_direct = GTK.SORT_DESCENDING
|
|
||||||
arrow.set(GTK.ARROW_UP,2)
|
|
||||||
else:
|
|
||||||
sort_direct = GTK.SORT_ASCENDING
|
|
||||||
arrow.set(GTK.ARROW_DOWN,2)
|
|
||||||
sort_column = column
|
|
||||||
|
|
||||||
person_list.set_sort_column(col_map[column])
|
person_list.set_sort_column(col_map[column])
|
||||||
person_list.set_sort_type(sort_direct)
|
person_list.set_sort_type(sort_direct)
|
||||||
|
|
||||||
sort_person_list()
|
sort_person_list()
|
||||||
|
|
||||||
|
if change:
|
||||||
|
if sort_column == column:
|
||||||
|
if sort_direct == GTK.SORT_DESCENDING:
|
||||||
|
sort_direct = GTK.SORT_ASCENDING
|
||||||
|
arrow.set(GTK.ARROW_DOWN,2)
|
||||||
|
else:
|
||||||
|
sort_direct = GTK.SORT_DESCENDING
|
||||||
|
arrow.set(GTK.ARROW_UP,2)
|
||||||
|
else:
|
||||||
|
sort_direct = GTK.SORT_ASCENDING
|
||||||
|
arrow.set(GTK.ARROW_DOWN,2)
|
||||||
|
sort_column = column
|
||||||
|
|
||||||
if id2col.has_key(active_person):
|
if id2col.has_key(active_person):
|
||||||
row = person_list.find_row_from_data(id2col[active_person])
|
row = person_list.find_row_from_data(id2col[active_person])
|
||||||
person_list.moveto(row)
|
person_list.moveto(row)
|
||||||
@ -997,9 +1002,13 @@ def on_child_list_select_row(obj,row,b,c):
|
|||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
def on_child_list_click_column(clist,column):
|
def on_child_list_click_column(clist,column):
|
||||||
if column == c_name:
|
if column == c_name:
|
||||||
child_change_sort(clist,c_name,gtop.get_widget("cNameSort"))
|
child_change_sort(clist,c_name,cNameArrow)
|
||||||
|
elif column == c_gender:
|
||||||
|
child_change_sort(clist,c_gender,cGenderArrow)
|
||||||
|
elif column == c_id:
|
||||||
|
child_change_sort(clist,c_id,cIDArrow)
|
||||||
elif (column == c_birth_order) or (column == c_birth_date):
|
elif (column == c_birth_order) or (column == c_birth_date):
|
||||||
child_change_sort(clist,c_birth_order,gtop.get_widget("cDateSort"))
|
child_change_sort(clist,c_birth_order,cDateArrow)
|
||||||
else:
|
else:
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -1019,6 +1028,8 @@ def child_change_sort(clist,column,arrow):
|
|||||||
|
|
||||||
cNameArrow.hide()
|
cNameArrow.hide()
|
||||||
cDateArrow.hide()
|
cDateArrow.hide()
|
||||||
|
cIDArrow.hide()
|
||||||
|
cGenderArrow.hide()
|
||||||
arrow.show()
|
arrow.show()
|
||||||
|
|
||||||
if c_sort_column == column:
|
if c_sort_column == column:
|
||||||
@ -1034,7 +1045,6 @@ def child_change_sort(clist,column,arrow):
|
|||||||
clist.set_sort_type(c_sort_direct)
|
clist.set_sort_type(c_sort_direct)
|
||||||
clist.set_sort_column(c_sort_column)
|
clist.set_sort_column(c_sort_column)
|
||||||
clist.set_reorderable(c_sort_column == c_birth_order)
|
clist.set_reorderable(c_sort_column == c_birth_order)
|
||||||
|
|
||||||
|
|
||||||
def sort_child_list(clist):
|
def sort_child_list(clist):
|
||||||
clist.freeze()
|
clist.freeze()
|
||||||
@ -1982,7 +1992,7 @@ def main(arg):
|
|||||||
global person_list
|
global person_list
|
||||||
global topWindow, preview, merge_button
|
global topWindow, preview, merge_button
|
||||||
global nameArrow, dateArrow, deathArrow, idArrow, genderArrow
|
global nameArrow, dateArrow, deathArrow, idArrow, genderArrow
|
||||||
global cNameArrow, cDateArrow, toolbar
|
global cNameArrow, cDateArrow, cIDArrow, cGenderArrow, toolbar
|
||||||
global sort_column, sort_direct
|
global sort_column, sort_direct
|
||||||
|
|
||||||
gtk.rc_parse(const.gtkrcFile)
|
gtk.rc_parse(const.gtkrcFile)
|
||||||
@ -2027,6 +2037,8 @@ def main(arg):
|
|||||||
media_view = MediaView(database,gtop,update_display)
|
media_view = MediaView(database,gtop,update_display)
|
||||||
|
|
||||||
cNameArrow = gtop.get_widget("cNameSort")
|
cNameArrow = gtop.get_widget("cNameSort")
|
||||||
|
cGenderArrow= gtop.get_widget("cGenderSort")
|
||||||
|
cIDArrow = gtop.get_widget("cIDSort")
|
||||||
cDateArrow = gtop.get_widget("cDateSort")
|
cDateArrow = gtop.get_widget("cDateSort")
|
||||||
person_list.set_column_visibility(5,0)
|
person_list.set_column_visibility(5,0)
|
||||||
person_list.set_column_visibility(6,0)
|
person_list.set_column_visibility(6,0)
|
||||||
@ -2040,8 +2052,9 @@ def main(arg):
|
|||||||
topWindow.set_icon(gtk.GtkPixmap(topWindow,const.icon))
|
topWindow.set_icon(gtk.GtkPixmap(topWindow,const.icon))
|
||||||
|
|
||||||
person_list.column_titles_active()
|
person_list.column_titles_active()
|
||||||
|
|
||||||
|
change_sort(sort_column,sort_direct==GTK.SORT_DESCENDING)
|
||||||
set_sort_arrow(sort_column,sort_direct)
|
set_sort_arrow(sort_column,sort_direct)
|
||||||
change_sort(sort_column)
|
|
||||||
|
|
||||||
gtop.signal_autoconnect({
|
gtop.signal_autoconnect({
|
||||||
"delete_event" : delete_event,
|
"delete_event" : delete_event,
|
||||||
|
@ -94,7 +94,7 @@ class DetAncestorReport(Report):
|
|||||||
self.doc.start_paragraph("ChildList")
|
self.doc.start_paragraph("ChildList")
|
||||||
t= child.getPrimaryName().getRegularName()
|
t= child.getPrimaryName().getRegularName()
|
||||||
#print "getBirth()", child.getBirth().__dict__
|
#print "getBirth()", child.getBirth().__dict__
|
||||||
if child.getBirth().getDate() != "" and \
|
if child.getBirth().getDate() != "" or \
|
||||||
child.getBirth().getPlaceName() != "":
|
child.getBirth().getPlaceName() != "":
|
||||||
#print child.getBirth().getPlace().__dict__
|
#print child.getBirth().getPlace().__dict__
|
||||||
t= t+ _(" Born: ")+child.getBirth().getDate() + \
|
t= t+ _(" Born: ")+child.getBirth().getDate() + \
|
||||||
@ -339,7 +339,7 @@ class DetAncestorReport(Report):
|
|||||||
elif fulldate == "" and place != "":
|
elif fulldate == "" and place != "":
|
||||||
t= _(" %s married %s in %s." % (heshe, spouse, place))
|
t= _(" %s married %s in %s." % (heshe, spouse, place))
|
||||||
elif fulldate != "" and place == "":
|
elif fulldate != "" and place == "":
|
||||||
t= _(" %s married %s on %s" % (heshe, spouse, fulldate))
|
t= _(" %s married %s on %s." % (heshe, spouse, fulldate))
|
||||||
else: t= _(" %s married %s on %s in %s." % \
|
else: t= _(" %s married %s on %s in %s." % \
|
||||||
(heshe, spouse, fulldate, place))
|
(heshe, spouse, fulldate, place))
|
||||||
else:
|
else:
|
||||||
@ -348,7 +348,7 @@ class DetAncestorReport(Report):
|
|||||||
elif fulldate == "" and place != "":
|
elif fulldate == "" and place != "":
|
||||||
t= _(" %s married in %s." % (heshe, place))
|
t= _(" %s married in %s." % (heshe, place))
|
||||||
elif fulldate != "" and place == "":
|
elif fulldate != "" and place == "":
|
||||||
t= _(" %s married on %s" % (heshe, fulldate))
|
t= _(" %s married on %s." % (heshe, fulldate))
|
||||||
else: t= _(" %s married on %s in %s." % \
|
else: t= _(" %s married on %s in %s." % \
|
||||||
(heshe, fulldate, place))
|
(heshe, fulldate, place))
|
||||||
|
|
||||||
@ -700,11 +700,11 @@ class reportOptions:
|
|||||||
if birth.getDayValid() and death.getDayValid():
|
if birth.getDayValid() and death.getDayValid():
|
||||||
if birth.getMonth() == death.getMonth() and birth.getDay() > death.getDay():
|
if birth.getMonth() == death.getMonth() and birth.getDay() > death.getDay():
|
||||||
self.age= self.age -1
|
self.age= self.age -1
|
||||||
self.units= "month"
|
|
||||||
if self.age == 0:
|
if self.age == 0:
|
||||||
self.age= death.getMonth() - birth.getMonth() # calc age in months
|
self.age= death.getMonth() - birth.getMonth() # calc age in months
|
||||||
if birth.getDay() > death.getDay():
|
if birth.getDay() > death.getDay():
|
||||||
self.age= self.age - 1
|
self.age= self.age - 1
|
||||||
|
self.units= "month"
|
||||||
if self.age == 0:
|
if self.age == 0:
|
||||||
self.age= death.getDay() + 31 - birth.getDay() # calc age in days
|
self.age= death.getDay() + 31 - birth.getDay() # calc age in days
|
||||||
self.units= "day"
|
self.units= "day"
|
||||||
|
Loading…
Reference in New Issue
Block a user