gramps/src/plugins/DefaultGadgets.py

397 lines
14 KiB
Python
Raw Normal View History

from DataViews import register, Gadget
from BasicUtils import name_displayer
import DateHandler
import gen.lib
2007-12-25 03:56:30 +05:30
import sys
2007-12-25 01:41:11 +05:30
import os
import time
2007-12-25 03:56:30 +05:30
import string
#
# Hello World, in Gramps Gadgets
#
# First, you need a function or class that takes a single argument
# a GuiGadget:
def init(gui):
gui.set_text("Hello world!")
# In this function, you can do some things to update the gadget,
# like set text of the main scroll window.
# Then, you need to register the gadget:
register(type="gadget", # case in-senstitive keyword "gadget"
name="Hello World Gadget", # gadget name, unique among gadgets
height = 20,
2007-12-25 01:41:11 +05:30
content = init, # function/class; takes guigadget
title="Sample Gadget", # default title, user changeable
)
# There are a number of arguments that you can provide, including:
2007-12-25 01:41:11 +05:30
# name, height, content, title, expand, state
# Hereare a couple of other examples, with their register lines at the
# bottom:
def make_family_content(gui):
gui.set_text("Families:")
def make_event_content(gui):
gui.set_text("Events:")
# Here is a Gadget object. It has a number of methods possibilities:
# init- run once, on construction
# db_changed- run when db-changed is triggered
# main- run once per db, main process (for fast code)
# background- run once per db, main process (for slow code)
# active_changed- run when active-changed is triggered
# You can also call update to run main and background
class LogGadget(Gadget):
def db_changed(self):
self.dbstate.connect('person-add', self.log_person_add)
self.dbstate.connect('person-delete', self.log_person_delete)
self.dbstate.connect('person-update', self.log_person_update)
self.dbstate.connect('family-add', self.log_family_add)
self.dbstate.connect('family-delete', self.log_family_delete)
self.dbstate.connect('family-update', self.log_family_update)
def active_changed(self, handle):
self.log_active_changed(handle)
def init(self):
self.set_text("Log for this Session\n--------------------\n")
def log_person_add(self, handles):
self.append_text("person-add: ")
self.get_person(handles)
def log_person_delete(self, handles):
self.append_text("person-delete: ")
self.get_person(handles)
def log_person_update(self, handles):
self.append_text("person-update: ")
self.get_person(handles)
def log_family_add(self, handles):
self.append_text("family-add: %s" % handles)
def log_family_delete(self, handles):
self.append_text("family-delete: %s" % handles)
def log_family_update(self, handles):
self.append_text("family-update: %s" % handles)
def log_active_changed(self, handles):
self.append_text("active-changed: ")
self.get_person([handles])
def get_person(self, handles):
for person_handle in handles:
person = self.dbstate.get_person_from_handle(person_handle)
if person:
self.append_text(name_displayer.display(person))
else:
self.append_text(person_handle)
self.append_text("\n")
class TopSurnamesGadget(Gadget):
def main(self):
self.set_text("Processing...\n")
def background(self):
people = self.dbstate.get_person_handles(sort_handles=False)
surnames = {}
cnt = 0
for person_handle in people:
person = self.dbstate.get_person_from_handle(person_handle)
if person:
surname = person.get_primary_name().get_surname().strip()
surnames[surname] = surnames.get(surname, 0) + 1
if cnt % 500 == 0:
yield True
cnt += 1
total_people = cnt
surname_sort = []
total = 0
cnt = 0
for surname in surnames:
surname_sort.append( (surnames[surname], surname) )
total += surnames[surname]
if cnt % 500 == 0:
yield True
cnt += 1
total_surnames = cnt
surname_sort.sort(lambda a,b: -cmp(a,b))
line = 0
### All done!
self.set_text("")
for (count, surname) in surname_sort:
self.append_text(" %s, %d%%\n" %
(surname, int((float(count)/total) * 100)))
line += 1
if line >= 10:
break
self.append_text("\nTotal unique surnames: %d\n" % total_surnames)
self.append_text("Total people: %d" % total_people)
class StatsGadget(Gadget):
def db_changed(self):
self.dbstate.connect('person-add', self.update)
self.dbstate.connect('person-delete', self.update)
self.dbstate.connect('family-add', self.update)
self.dbstate.connect('family-delete', self.update)
def background(self):
self.set_text("Processing...")
database = self.dbstate
personList = database.get_person_handles(sort_handles=False)
familyList = database.get_family_handles()
with_photos = 0
total_photos = 0
incomp_names = 0
disconnected = 0
missing_bday = 0
males = 0
females = 0
unknowns = 0
bytes = 0
namelist = []
notfound = []
pobjects = len(database.get_media_object_handles())
for photo_id in database.get_media_object_handles():
photo = database.get_object_from_handle(photo_id)
try:
bytes = bytes + posixpath.getsize(photo.get_path())
except:
notfound.append(photo.get_path())
cnt = 0
for person_handle in personList:
person = database.get_person_from_handle(person_handle)
if not person:
continue
length = len(person.get_media_list())
if length > 0:
with_photos = with_photos + 1
total_photos = total_photos + length
person = database.get_person_from_handle(person_handle)
name = person.get_primary_name()
if name.get_first_name() == "" or name.get_surname() == "":
incomp_names = incomp_names + 1
if (not person.get_main_parents_family_handle()) and (not len(person.get_family_handle_list())):
disconnected = disconnected + 1
birth_ref = person.get_birth_ref()
if birth_ref:
birth = database.get_event_from_handle(birth_ref.ref)
if not DateHandler.get_date(birth):
missing_bday = missing_bday + 1
else:
missing_bday = missing_bday + 1
if person.get_gender() == gen.lib.Person.FEMALE:
females = females + 1
elif person.get_gender() == gen.lib.Person.MALE:
males = males + 1
else:
unknowns += 1
if name.get_surname() not in namelist:
namelist.append(name.get_surname())
if cnt % 500 == 0:
yield True
cnt += 1
text = _("Individuals") + "\n"
text = text + "----------------------------\n"
text = text + "%s: %d\n" % (_("Number of individuals"),len(personList))
text = text + "%s: %d\n" % (_("Males"),males)
text = text + "%s: %d\n" % (_("Females"),females)
text = text + "%s: %d\n" % (_("Individuals with unknown gender"),unknowns)
text = text + "%s: %d\n" % (_("Individuals with incomplete names"),incomp_names)
text = text + "%s: %d\n" % (_("Individuals missing birth dates"),missing_bday)
text = text + "%s: %d\n" % (_("Disconnected individuals"),disconnected)
text = text + "\n%s\n" % _("Family Information")
text = text + "----------------------------\n"
text = text + "%s: %d\n" % (_("Number of families"),len(familyList))
text = text + "%s: %d\n" % (_("Unique surnames"),len(namelist))
text = text + "\n%s\n" % _("Media Objects")
text = text + "----------------------------\n"
text = text + "%s: %d\n" % (_("Individuals with media objects"),with_photos)
text = text + "%s: %d\n" % (_("Total number of media object references"),total_photos)
text = text + "%s: %d\n" % (_("Number of unique media objects"),pobjects)
text = text + "%s: %d %s\n" % (_("Total size of media objects"),bytes,\
_("bytes"))
if len(notfound) > 0:
text = text + "\n%s\n" % _("Missing Media Objects")
text = text + "----------------------------\n"
for p in notfound:
text = text + "%s\n" % p
self.set_text(text)
2007-12-25 01:41:11 +05:30
class ShellGadget(Gadget):
def init(self):
from os import O_NONBLOCK
from subprocess import Popen, PIPE
try:
from fcntl import fcntl, F_SETFL, F_GETFL
unix = True
except:
unix = False
if unix:
command = ["/bin/bash"]
else:
command = ["cmd.exe"]
self.pipe = Popen(command, shell=False, bufsize=0,
stdin=PIPE, stdout=PIPE, stderr=PIPE,
close_fds=True)
if unix:
for fd in (self.pipe.stdout.fileno(),
self.pipe.stderr.fileno()):
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK)
# GUI setup:
self.gui.textview.set_editable(True)
2007-12-25 03:11:13 +05:30
self.set_text("%s\n$ " % command[0])
2007-12-25 01:41:11 +05:30
self.gui.textview.connect('key-press-event', self.on_enter)
def write(self, text):
self.pipe.stdin.write("%s\n" % text)
def read(self, timeout=0.5,buffer_size=1024):
from errno import EAGAIN
end_time = time.time() + timeout
output = ""
while time.time() < end_time:
try:
output += self.pipe.stdout.read(buffer_size)
except IOError, e:
if e.errno != EAGAIN:
raise
return output
def on_enter(self, widget, event):
if event.keyval == 65293: # enter, where to get this?
# get line, "$ ls -al "
buffer = widget.get_buffer()
line_cnt = buffer.get_line_count()
start = buffer.get_iter_at_line(line_cnt - 1)
end = buffer.get_end_iter()
line = buffer.get_text(start, end)
if line.startswith("$ "):
self.append_text("\n")
line = line[2:]
self.write(line)
output = self.read()
self.append_text(output)
self.append_text("$ ")
else:
self.append_text("\n$ ")
return True
return False
2007-12-25 03:11:13 +05:30
class PythonGadget(Gadget):
def init(self):
2007-12-25 03:56:30 +05:30
self.env = {"dbstate": self.gui.dbstate,
"uistate": self.gui.uistate,
2007-12-25 03:56:30 +05:30
"self": self,
}
2007-12-25 03:11:13 +05:30
# GUI setup:
self.gui.textview.set_editable(True)
self.set_text("Python\n> ")
self.gui.textview.connect('key-press-event', self.on_enter)
2007-12-25 03:56:30 +05:30
def format_exception(self, max_tb_level=10):
retval = ''
cla, exc, trbk = sys.exc_info()
retval += "ERROR: %s %s" %(cla, exc)
return retval
2007-12-25 03:11:13 +05:30
def on_enter(self, widget, event):
if event.keyval == 65293: # enter, where to get this?
buffer = widget.get_buffer()
line_cnt = buffer.get_line_count()
start = buffer.get_iter_at_line(line_cnt - 1)
end = buffer.get_end_iter()
line = buffer.get_text(start, end)
if line.startswith("> "):
self.append_text("\n")
line = line[2:]
# update states, in case of change:
2007-12-25 03:56:30 +05:30
self.env["dbstate"] = self.gui.dbstate
self.env["uistate"] = self.gui.uistate
2007-12-25 03:59:39 +05:30
_retval = None
2007-12-25 03:56:30 +05:30
if "_retval" in self.env:
del self.env["_retval"]
exp1 = """_retval = """ + string.strip(line)
exp2 = string.strip(line)
try:
_retval = eval(exp2, self.env)
except:
try:
exec exp1 in self.env
except:
try:
exec exp2 in self.env
except:
_retval = self.format_exception()
if "_retval" in self.env:
_retval = self.env["_retval"]
if _retval != None:
self.append_text("%s\n" % _retval)
2007-12-25 03:11:13 +05:30
self.append_text("> ")
else:
2007-12-25 03:56:30 +05:30
self.append_text("> ")
2007-12-25 03:11:13 +05:30
return True
return False
register(type="gadget",
name="Families Gadget",
height=300,
content = make_family_content,
title="Favorite Families",
)
register(type="gadget",
name="Events Gadget",
height=100,
content = make_event_content,
title="Favorite Events",
)
register(type="gadget",
name="Top Surnames Gadget",
height=230,
content = TopSurnamesGadget,
title="Top 10 Surnames",
)
register(type="gadget",
name="Stats Gadget",
height=230,
content = StatsGadget,
title="Stats",
)
register(type="gadget",
name="Log Gadget",
height=230,
content = LogGadget,
title="Session Log",
)
2007-12-25 01:41:11 +05:30
register(type="gadget",
name="Shell Gadget",
height=300,
content = ShellGadget,
title="Shell",
)
2007-12-25 03:11:13 +05:30
register(type="gadget",
name="Python Gadget",
height=250,
2007-12-25 03:56:30 +05:30
content = PythonGadget,
title="Python",
2007-12-25 03:11:13 +05:30
)