gramps/src/gui/plug/quick/_quicktable.py
2012-05-31 23:46:57 +00:00

406 lines
17 KiB
Python

#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2008 Donald N. Allingham
# Copyright (C) 2009 Douglas S. Blank
# Copyright (C) 2011 Tim G L Lyons
#
# 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$
#
"""
Provide a simplified table creation interface
"""
#-------------------------------------------------------------------------
#
# Standard python modules
#
#-------------------------------------------------------------------------
import cPickle as pickle
#-------------------------------------------------------------------------
#
# GNOME modules
#
#-------------------------------------------------------------------------
import gtk
#-------------------------------------------------------------------------
#
# Gramps modules
#
#-------------------------------------------------------------------------
from gen.ggettext import sgettext as _
from gen.simple import SimpleTable
from TransUtils import trans_objclass
import Errors
from gui.widgets.multitreeview import MultiTreeView
from ScratchPad import ScratchPadListView, ACTION_COPY
from DdTargets import DdTargets
from gui.plug.quick import run_quick_report_by_name
from gui.editors import (EditPerson, EditEvent, EditFamily, EditCitation,
EditSource, EditPlace, EditRepository, EditNote,
EditMedia)
#-------------------------------------------------------------------------
#
# QuickTable class
#
#-------------------------------------------------------------------------
class QuickTable(SimpleTable):
"""
Provide a simplified table creation interface.
"""
def set_callback(self, which, callback):
"""
Override (or add) a function for click/double-click
"""
if which == "leftclick":
self._callback_leftclick = callback
elif which == "leftdouble":
self._callback_leftdouble = callback
def button_press_event(self, treeview, event):
index = None
button_code = None
event_time = None
func = None
if type(event) == bool: # enter
button_code = 3
event_time = 0
selection = treeview.get_selection()
store, paths = selection.get_selected_rows()
tpath = paths[0] if len(paths) > 0 else None
node = store.get_iter(tpath) if tpath else None
if node:
treeview.grab_focus()
index = store.get_value(node, 0)
# FIXME: make popup come where cursor is
#rectangle = treeview.get_visible_rect()
#column = treeview.get_column(0)
#rectangle = treeview.get_cell_area("0:0",
#x, y = rectangle.x, rectangle.y
#func = lambda menu: (x, y, True)
elif event.button == 3:
button_code = 3
event_time = event.time
x = int(event.x)
y = int(event.y)
path_info = treeview.get_path_at_pos(x, y)
func = None
if path_info is not None:
path, col, cellx, celly = path_info
selection = treeview.get_selection()
store, paths = selection.get_selected_rows()
tpath = paths[0] if len(paths) > 0 else None
node = store.get_iter(tpath) if tpath else None
if path:
treeview.grab_focus()
treeview.set_cursor(path, col, 0)
if store and node:
index = store.get_value(node, 0) # index Below,
# you need index, treeview, path, button_code,
# func, and event_time
if index is not None:
popup = gtk.Menu()
if (index is not None and self._link[index]):
# See details (edit, etc):
objclass, handle = self._link[index]
menu_item = gtk.MenuItem(_("the object|See %s details") % trans_objclass(objclass))
menu_item.connect("activate",
lambda widget: self.on_table_doubleclick(treeview))
popup.append(menu_item)
menu_item.show()
# Add other items to menu:
if (self._callback_leftclick or
(index is not None and self._link[index])):
objclass, handle = self._link[index]
if objclass == 'Person':
menu_item = gtk.MenuItem(_("the object|Make %s active") % trans_objclass('Person'))
menu_item.connect("activate",
lambda widget: self.on_table_click(treeview))
popup.append(menu_item)
menu_item.show()
if (self.simpledoc.doc.dbstate.db !=
self.simpledoc.doc.dbstate.db.basedb and
(index is not None and self._link[index])):
objclass, handle = self._link[index]
if (objclass == 'Filter' and
handle[0] in ['Person', 'Family', 'Place', 'Event',
'Repository', 'Note', 'MediaObject',
'Citation', 'Source']):
menu_item = gtk.MenuItem(_("See data not in Filter"))
menu_item.connect("activate",
lambda widget: self.show_not_in_filter(handle[0]))
popup.append(menu_item)
menu_item.show()
# Show the popup menu:
popup.popup(None, None, func, button_code, event_time)
return True
return False
def show_not_in_filter(self, obj_class):
run_quick_report_by_name(self.simpledoc.doc.dbstate,
self.simpledoc.doc.uistate,
'filterbyname',
'Inverse %s' % obj_class)
def on_table_doubleclick(self, obj):
"""
Handle events on tables. obj is a treeview
"""
selection = obj.get_selection()
store, paths = selection.get_selected_rows()
tpath = paths[0] if len(paths) > 0 else None
node = store.get_iter(tpath) if tpath else None
if not node:
return
index = store.get_value(node, 0) # index
if self._callback_leftdouble:
self._callback_leftdouble(store.get_value(node, 1))
return True
elif self._link[index]:
objclass, handle = self._link[index]
if isinstance(handle, list):
handle = handle[0]
if objclass == 'Person':
person = self.access.dbase.get_person_from_handle(handle)
if person:
try:
EditPerson(self.simpledoc.doc.dbstate,
self.simpledoc.doc.uistate, [], person)
return True # handled event
except Errors.WindowActiveError:
pass
elif objclass == 'Event':
event = self.access.dbase.get_event_from_handle(handle)
if event:
try:
EditEvent(self.simpledoc.doc.dbstate,
self.simpledoc.doc.uistate, [], event)
return True # handled event
except Errors.WindowActiveError:
pass
elif objclass == 'Family':
ref = self.access.dbase.get_family_from_handle(handle)
if ref:
try:
EditFamily(self.simpledoc.doc.dbstate,
self.simpledoc.doc.uistate, [], ref)
return True # handled event
except Errors.WindowActiveError:
pass
elif objclass == 'Citation':
ref = self.access.dbase.get_citation_from_handle(handle)
if ref:
try:
EditCitation(self.simpledoc.doc.dbstate,
self.simpledoc.doc.uistate, [], ref)
return True # handled event
except Errors.WindowActiveError:
pass
elif objclass == 'Source':
ref = self.access.dbase.get_source_from_handle(handle)
if ref:
try:
EditSource(self.simpledoc.doc.dbstate,
self.simpledoc.doc.uistate, [], ref)
return True # handled event
except Errors.WindowActiveError:
pass
elif objclass == 'Place':
ref = self.access.dbase.get_place_from_handle(handle)
if ref:
try:
EditPlace(self.simpledoc.doc.dbstate,
self.simpledoc.doc.uistate, [], ref)
return True # handled event
except Errors.WindowActiveError:
pass
elif objclass == 'Repository':
ref = self.access.dbase.get_repository_from_handle(handle)
if ref:
try:
EditRepository(self.simpledoc.doc.dbstate,
self.simpledoc.doc.uistate, [], ref)
return True # handled event
except Errors.WindowActiveError:
pass
elif objclass == 'Note':
ref = self.access.dbase.get_note_from_handle(handle)
if ref:
try:
EditNote(self.simpledoc.doc.dbstate,
self.simpledoc.doc.uistate, [], ref)
return True # handled event
except Errors.WindowActiveError:
pass
elif objclass in ['Media', 'MediaObject']:
ref = self.access.dbase.get_object_from_handle(handle)
if ref:
try:
EditMedia(self.simpledoc.doc.dbstate,
self.simpledoc.doc.uistate, [], ref)
return True # handled event
except Errors.WindowActiveError:
pass
elif objclass == 'PersonList':
run_quick_report_by_name(self.simpledoc.doc.dbstate,
self.simpledoc.doc.uistate,
'filterbyname',
'list of people',
handles=handle)
elif objclass == 'Filter':
if isinstance(handle, list):
handle = handle[0]
run_quick_report_by_name(self.simpledoc.doc.dbstate,
self.simpledoc.doc.uistate,
'filterbyname',
handle)
return False # didn't handle event
def on_table_click(self, obj):
"""
Handle events on tables. obj is a treeview
"""
selection = obj.get_selection()
store, paths = selection.get_selected_rows()
tpath = paths[0] if len(paths) > 0 else None
node = store.get_iter(tpath)
if not node:
return
index = store.get_value(node, 0) # index
if self._callback_leftclick:
self._callback_leftclick(store.get_value(node, 1))
return True
elif self._link[index]:
objclass, handle = self._link[index]
if isinstance(handle, list):
handle = handle[0]
if objclass == 'Person':
import gobject
# If you emmit the signal here and it causes this table to be deleted,
# then you'll crash Python:
#self.simpledoc.doc.uistate.set_active(handle, 'Person')
# So, let's return from this, then change the active person:
return gobject.timeout_add(100, self.simpledoc.doc.uistate.set_active, handle, 'Person')
return True
return False # didn't handle event
def object_drag_data_get(self, widget, context, sel_data, info, time):
tree_selection = widget.get_selection()
model, paths = tree_selection.get_selected_rows()
retval = []
for path in paths:
node = model.get_iter(path)
index = model.get_value(node,0)
if (index is not None and self._link[index]):
retval.append(self._link[index])
sel_data.set(sel_data.target, 8, pickle.dumps(retval))
return True
def toggle(self, obj, path, col):
"""
obj - column widget
path - row
col - column
"""
self.treeview.get_model()[path][col] = not \
self.treeview.get_model()[path][col]
def write(self, document):
self.simpledoc = document
buffer = self.simpledoc.doc.buffer
text_view = self.simpledoc.doc.text_view
model_index = 1 # start after index
if self._sort_col:
sort_index = self._columns.index(self._sort_col)
else:
sort_index = 0
treeview = MultiTreeView()
treeview.enable_model_drag_source(gtk.gdk.BUTTON1_MASK,
[(DdTargets.HANDLE_LIST.drag_type, gtk.TARGET_SAME_WIDGET, 0)],
gtk.gdk.ACTION_COPY)
#treeview.enable_model_drag_dest(DdTargets.all_targets(),
# gtk.gdk.ACTION_DEFAULT)
treeview.connect('drag_data_get', self.object_drag_data_get)
treeview.set_grid_lines(gtk.TREE_VIEW_GRID_LINES_BOTH)
#treeview.connect('row-activated', on_table_doubleclick, self)
#treeview.connect('cursor-changed', on_table_click, self)
treeview.connect('button-press-event', self.button_press_event)
treeview.connect('select-cursor-row', self.button_press_event)
renderer = gtk.CellRendererText()
types = [int] # index
cnt = 0
sort_data = []
sort_data_types = []
for col in self._columns:
if self.get_cell_type(cnt) == "text":
types.append(str)
if self.get_cell_markup(cnt):
column = gtk.TreeViewColumn(col,renderer,markup=model_index)
else:
column = gtk.TreeViewColumn(col,renderer,text=model_index)
elif self.get_cell_type(cnt) == "checkbox":
types.append(bool)
toggle_renderer = gtk.CellRendererToggle()
toggle_renderer.set_property('activatable', True)
toggle_renderer.connect("toggled", self.toggle, model_index)
column = gtk.TreeViewColumn(col, toggle_renderer)
column.add_attribute(toggle_renderer, "active", model_index)
column.set_resizable(True)
if self._sort_vals[cnt] != []:
sort_data.append(self._sort_vals[cnt])
column.set_sort_column_id(len(self._columns) +
len(sort_data))
sort_data_types.append(int)
else:
column.set_sort_column_id(model_index)
treeview.append_column(column)
self.model_index_of_column[col] = model_index
#if model_index == sort_index:
# FIXME: what to set here?
model_index += 1
cnt += 1
if self.title:
self.simpledoc.paragraph(self.title)
# Make a GUI to put the tree view in
types += sort_data_types
model = gtk.ListStore(*types)
treeview.set_model(model)
treeview.get_selection().set_mode(gtk.SELECTION_MULTIPLE)
iter = buffer.get_end_iter()
anchor = buffer.create_child_anchor(iter)
text_view.add_child_at_anchor(treeview, anchor)
self.treeview= treeview
count = 0
for data in self._rows:
col = 0
rowdata = []
for cell in data:
rowdata.append(self.get_cell_markup(col, count, cell))
col += 1
try:
model.append(row=([count] + list(rowdata) + [col[count] for col in sort_data]))
except:
print "error in row %d: data: %s, sort data: %d" % (count, rowdata, len(sort_data[0]))
count += 1
text_view.show_all()
self.simpledoc.paragraph("")
self.simpledoc.paragraph("")