Gallery drag/drop functionality

svn: r1169
This commit is contained in:
Don Allingham 2002-11-08 03:42:25 +00:00
parent af1a55d986
commit 291a4c7dcb
11 changed files with 2491 additions and 2616 deletions

Binary file not shown.

View File

@ -1426,7 +1426,6 @@ def disp_url(url):
#
#-------------------------------------------------------------------------
def disp_attr(attr):
detail = Utils.get_detail_flags(attr)
return [const.display_pattr(attr.getType()),attr.getValue()]
#-------------------------------------------------------------------------
@ -1444,7 +1443,6 @@ def disp_addr(addr):
#
#-------------------------------------------------------------------------
def disp_event(event):
attr = Utils.get_detail_flags(event)
return [const.display_pevent(event.getName()),event.getDescription(),
event.getQuoteDate(),event.getPlaceName()]

View File

@ -62,6 +62,7 @@ from intl import gettext as _
_IMAGEX = 140
_IMAGEY = 150
_PAD = 5
#-------------------------------------------------------------------------
#
@ -77,9 +78,12 @@ class ImageSelect:
self.path = path;
self.db = db
self.dataobj = None
self.parent = parent
self.canvas_list = []
self.parent = parent
self.canvas_list = {}
self.item_map = {}
self.item_map = {}
self.p_map = {}
def add_thumbnail(self, photo):
"should be overrridden"
pass
@ -189,6 +193,13 @@ class ImageSelect:
"""Save the photo in the dataobj object - must be overridden"""
pass
_drag_targets = [
('STRING', 0, 0),
('text/plain',0,0),
('text/uri-list',0,2),
('application/x-rootwin-drop',0,1)]
#-------------------------------------------------------------------------
#
# Gallery class - This class handles all the logic underlying a
@ -200,22 +211,15 @@ class Gallery(ImageSelect):
def __init__(self, dataobj, path, icon_list, db, parent):
ImageSelect.__init__(self, path, db, parent)
t = [
('STRING', 0, 0),
('text/plain',0,0),
('text/uri-list',0,2),
('application/x-rootwin-drop',0,1)]
if path:
icon_list.drag_dest_set(gtk.DEST_DEFAULT_ALL, t,
icon_list.drag_dest_set(gtk.DEST_DEFAULT_ALL, _drag_targets,
gtk.gdk.ACTION_COPY | gtk.gdk.ACTION_MOVE)
icon_list.connect('event',self.item_event)
icon_list.connect("drag_data_received",
self.on_photolist_drag_data_received)
icon_list.drag_source_set(gtk.gdk.BUTTON1_MASK|gtk.gdk.BUTTON3_MASK,t,
gtk.gdk.ACTION_COPY | gtk.gdk.ACTION_MOVE)
icon_list.connect("drag_data_get",
self.on_photolist_drag_data_get)
# Remember arguments
self.path = path;
self.dataobj = dataobj;
@ -226,24 +230,60 @@ class Gallery(ImageSelect):
self.selectedIcon = -1
self.x = 0
self.y = 0
self.remember_x = -1
self.remember_y = -1
self.button = None
self.drag_item = None
self.sel = None
self.photo = None
def on_canvas1_event(self,obj,event):
"""Handle resize events over the canvas, redrawing if the size changes"""
def item_event(self, widget, event=None):
if self.button and event.type == gtk.gdk.MOTION_NOTIFY :
if widget.drag_check_threshold(self.remember_x,self.remember_y,event.x,event.y):
self.drag_item = widget.get_item_at(self.remember_x,self.remember_y)
if self.drag_item:
context = widget.drag_begin(_drag_targets,
gtk.gdk.ACTION_COPY|gtk.gdk.ACTION_MOVE,
self.button, event)
return gtk.TRUE
photo = widget.get_data('obj')
if event.type == gtk.gdk.BUTTON_PRESS:
if event.button == 1:
# Remember starting position.
item = widget.get_item_at(event.x,event.y)
if item:
(i,t,b,self.photo) = self.p_map[item]
style = self.iconlist.get_style()
t.set(fill_color_gdk=style.fg[gtk.STATE_SELECTED])
b.set(fill_color_gdk=style.bg[gtk.STATE_SELECTED])
if self.sel:
(i,t,b,photo) = self.p_map[self.sel]
t.set(fill_color_gdk=style.fg[gtk.STATE_NORMAL])
b.set(fill_color_gdk=style.bg[gtk.STATE_NORMAL])
self.sel = item
self.remember_x = event.x
self.remember_y = event.y
self.button = event.button
return gtk.TRUE
elif event.button == 3:
self.show_popup(photo)
item = widget.get_item_at(event.x,event.y)
if item:
(i,t,b,self.photo) = self.p_map[item]
self.show_popup(self.photo)
return gtk.TRUE
elif event.type == gtk.gdk.BUTTON_RELEASE:
self.button = 0
elif event.type == gtk.gdk._2BUTTON_PRESS and event.button == 1:
#Change the item's color.
print photo,self.path,self
LocalMediaProperties(photo,self.path,self)
return gtk.TRUE
@ -258,13 +298,8 @@ class Gallery(ImageSelect):
return gtk.TRUE
elif event.type == gtk.gdk.ENTER_NOTIFY:
# Make the outline wide.
return gtk.TRUE
elif event.type == gtk.gdk.LEAVE_NOTIFY:
# Make the outline thin.
return gtk.TRUE
if event.type == gtk.gdk.EXPOSE:
self.load_images()
return gtk.FALSE
@ -279,58 +314,79 @@ class Gallery(ImageSelect):
def add_thumbnail(self, photo):
"""Scale the image and add it to the IconList."""
object = photo.getReference()
name = Utils.thumb_path(self.db.getSavePath(),object)
description = object.getDescription()
if len(description) > 20:
description = "%s..." % description[0:20]
image = gtk.gdk.pixbuf_new_from_file(name)
x = image.get_width()
y = image.get_height()
grp = self.root.add(gnome.canvas.CanvasGroup,x=self.cx,y=self.cy)
grp.connect('event',self.item_event)
grp.set_data('obj',photo)
xloc = (_IMAGEX-x)/2
yloc = (_IMAGEX-y)/2
item = grp.add(gnome.canvas.CanvasPixbuf,
pixbuf=image,
x=xloc,
y=yloc)
text = grp.add(gnome.canvas.CanvasText,
x=_IMAGEX/2,
y=_IMAGEX,
anchor=gtk.ANCHOR_CENTER,
text=description)
oid = object.getId()
self.cx = 10 + _IMAGEX + self.cx
if self.cx + 10 + _IMAGEX > self.x:
self.cx = 10
self.cy = self.cy + 10 + _IMAGEY
if self.canvas_list.has_key(oid):
(grp,item,text,bg,x,y) = self.canvas_list[oid]
if x != self.cx or y != self.cy:
grp.move(self.cx-x,self.cy-y)
else:
name = Utils.thumb_path(self.db.getSavePath(),object)
description = object.getDescription()
if len(description) > 20:
description = "%s..." % description[0:20]
image = gtk.gdk.pixbuf_new_from_file(name)
x = image.get_width()
y = image.get_height()
grp = self.root.add(gnome.canvas.CanvasGroup,x=self.cx,y=self.cy)
xloc = (_IMAGEX-x)/2
yloc = (_IMAGEY-y)/2
bg = grp.add(gnome.canvas.CanvasRect,
x1=0,
x2=_IMAGEX,
y2=_IMAGEY,
y1=_IMAGEY-20)
item = grp.add(gnome.canvas.CanvasPixbuf,
pixbuf=image,
x=xloc,
y=yloc)
text = grp.add(gnome.canvas.CanvasText,
x=_IMAGEX/2,
y=_IMAGEX,
anchor=gtk.ANCHOR_CENTER,
text=description)
self.item_map[item] = oid
self.item_map[text] = oid
self.item_map[grp] = oid
self.item_map[bg] = oid
self.p_map[item] = (item,text,bg,photo)
self.p_map[text] = (item,text,bg,photo)
self.p_map[grp] = (item,text,bg,photo)
self.p_map[bg] = (item,text,bg,photo)
item.show()
text.show()
self.canvas_list.append(grp)
self.canvas_list.append(item)
self.canvas_list.append(text)
item.show()
text.show()
bg.show()
self.canvas_list[oid] = (grp,item,text,bg,self.cx,self.cy)
if self.cx + _PAD + _IMAGEX > self.x:
self.cx = _PAD
self.cy = self.cy + _PAD + _IMAGEY
else:
self.cx = _PAD + self.cx + _IMAGEX
def load_images(self):
"""clears the currentImages list to free up any cached
Imlibs. Then add each photo in the place's list of photos to the
photolist window."""
for item in self.canvas_list:
item.destroy()
self.pos = 0
self.cx = 10
self.cy = 10
self.cx = _PAD
self.cy = _PAD
(self.x,self.y) = self.iconlist.get_size()
self.max = (self.x)/(_IMAGEX+10)
self.max = (self.x)/(_IMAGEX+_PAD)
for photo in self.dataobj.getPhotoList():
self.add_thumbnail(photo)
@ -345,13 +401,12 @@ class Gallery(ImageSelect):
self.selectedIcon = iconNumber
def get_index(self,obj,x,y):
x_offset = x/(_IMAGEX+10)
y_offset = y/(_IMAGEY+10)
index = (y_offset*self.max)+x_offset
x_offset = x/(_IMAGEX+_PAD)
y_offset = y/(_IMAGEY+_PAD)
index = (y_offset*(1+self.max))+x_offset
return min(index,len(self.dataobj.getPhotoList()))
def on_photolist_drag_data_received(self,w, context, x, y, data, info, time):
print "receive",w
if data and data.format == 8:
icon_index = self.get_index(w,x,y)
d = string.strip(string.replace(data.data,'\0',' '))
@ -441,20 +496,14 @@ class Gallery(ImageSelect):
if GrampsCfg.globalprop:
LocalMediaProperties(oref,self.path,self)
Utils.modified()
#w.drag_finish(context, 1, 0, time)
else:
pass
#w.drag_finish(context, 0, 0, time)
def on_photolist_drag_data_get(self,w, context, selection_data, info, time):
print "drag data get",w
if info == 1:
return
if self.selectedIcon != -1:
ref = self.dataobj.getPhotoList()[self.selectedIcon]
id = ref.getReference().getId()
selection_data.set(selection_data.target, 8, id)
id = self.item_map[self.drag_item]
selection_data.set(selection_data.target, 8, id)
self.drag_item = None
def on_add_photo_clicked(self, obj):
"""User wants to add a new photo. Create a dialog to find out
which photo they want."""
@ -479,7 +528,6 @@ class Gallery(ImageSelect):
def show_popup(self, photo):
"""Look for right-clicks on a picture and create a popup
menu of the available actions."""
menu = gtk.Menu()
item = gtk.TearoffMenuItem()

View File

@ -25,29 +25,7 @@ class ListModel:
def __init__(self,tree,dlist):
self.tree = tree
l = len(dlist)
if l == 1:
self.model = gtk.ListStore(TYPE_STRING)
elif l == 2:
self.model = gtk.ListStore(TYPE_STRING, TYPE_STRING)
elif l == 3:
self.model = gtk.ListStore(TYPE_STRING, TYPE_STRING, TYPE_STRING)
elif l == 4:
self.model = gtk.ListStore(TYPE_STRING, TYPE_STRING, TYPE_STRING,
TYPE_STRING)
elif l == 5:
self.model = gtk.ListStore(TYPE_STRING, TYPE_STRING, TYPE_STRING,
TYPE_STRING, TYPE_STRING)
elif l == 6:
self.model = gtk.ListStore(TYPE_STRING, TYPE_STRING, TYPE_STRING,
TYPE_STRING, TYPE_STRING, TYPE_STRING)
elif l == 7:
self.model = gtk.ListStore(TYPE_STRING, TYPE_STRING, TYPE_STRING,
TYPE_STRING, TYPE_STRING, TYPE_STRING,
TYPE_STRING)
elif l == 8:
self.model = gtk.ListStore(TYPE_STRING, TYPE_STRING, TYPE_STRING,
TYPE_STRING, TYPE_STRING, TYPE_STRING,
TYPE_STRING, TYPE_STRING)
self.model = gtk.ListStore(*[TYPE_STRING]*l)
self.selection = self.tree.get_selection()
self.tree.set_model(self.model)

View File

@ -121,21 +121,21 @@ class SelectChild:
bday = self.person.getBirth().getDateObj()
dday = self.person.getDeath().getDateObj()
slist = []
slist = {}
for f in self.person.getParentList():
if f:
if f[0].getFather():
slist.append(f[0].getFather())
slist[f[0].getFather().getId()] = 1
elif f[0].getMother():
slist.append(f[0].getMother())
slist[f[0].getMother().getId()] = 1
for c in f[0].getChildList():
slist.append(c)
slist[c.getId()] = 1
person_list = []
for key in self.db.getPersonKeys():
person = self.db.getPerson(key)
if filter:
if person in slist or person.getMainParents():
if slist.has_key(key) or person.getMainParents():
continue
pdday = person.getDeath().getDateObj()
@ -167,10 +167,10 @@ class SelectChild:
if pdday.getLowYear() > dday.getHighYear() + 150:
continue
person_list.append(person)
person_list.append(person.getId())
for person in person_list:
dinfo = self.db.getPersonDisplay(id)
for idval in person_list:
dinfo = self.db.getPersonDisplay(idval)
rdata = [dinfo[0],dinfo[1],dinfo[3],dinfo[5],dinfo[6]]
self.refmodel.add(rdata)

View File

@ -4274,8 +4274,8 @@
<widget class="GtkScrolledWindow" id="scrolledwindow22">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hscrollbar_policy">GTK_POLICY_ALWAYS</property>
<property name="vscrollbar_policy">GTK_POLICY_ALWAYS</property>
<property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
<property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
<property name="shadow_type">GTK_SHADOW_NONE</property>
<property name="window_placement">GTK_CORNER_TOP_LEFT</property>

View File

@ -5450,6 +5450,7 @@
<property name="type">GTK_WINDOW_TOPLEVEL</property>
<property name="window_position">GTK_WIN_POS_NONE</property>
<property name="modal">False</property>
<property name="default_width">300</property>
<property name="resizable">True</property>
<property name="destroy_with_parent">False</property>
<property name="has_separator">True</property>

File diff suppressed because it is too large Load Diff

View File

@ -31,10 +31,10 @@ import Utils
import string
import const
import GenericFilter
import ListModel
from TextDoc import *
from OpenSpreadSheet import *
import intl
_ = intl.gettext
from intl import gettext as _
import gnome.ui
import gtk
@ -167,11 +167,8 @@ def by_value(first,second):
#
#-------------------------------------------------------------------------
def fix(line):
l = string.strip(line)
l = string.replace(l,'&','&amp;')
l = string.replace(l,'>','&gt;')
l = string.replace(l,'<','&lt;')
return string.replace(l,'"','&quot;')
l = line.strip().replace('&','&amp;').replace(l,'>','&gt;')
return l.replace(l,'<','&lt;').replace(l,'"','&quot;')
#-------------------------------------------------------------------------
#
@ -193,7 +190,7 @@ class DisplayChart:
})
self.top = self.topDialog.get_widget("view")
self.table = self.topDialog.get_widget("addarea")
self.eventlist = self.topDialog.get_widget('treeview')
self.my_list.sort(sort.by_last_name)
@ -204,17 +201,19 @@ class DisplayChart:
def draw_clist_display(self):
eventlist = gtk.CList(len(self.event_titles),self.event_titles)
self.table.add(eventlist)
eventlist.show()
titles = []
index = 0
for v in self.event_titles:
titles.append((v,150,index))
index = index + 1
self.list = ListModel.ListModel(self.eventlist,titles)
for data in self.row_data:
self.list.add(data)
for (top,bottom) in self.row_data:
eventlist.append(top)
eventlist.append(bottom)
for index in range(0,len(self.event_titles)):
width = min(150,eventlist.optimal_column_width(index))
eventlist.set_column_width(index,width)
# for index in range(0,len(self.event_titles)):
# width = min(150,eventlist.optimal_column_width(index))
# self.eventlist.set_column_width(index,width)
def build_row_data(self):
for individual in self.my_list:
@ -235,29 +234,26 @@ class DisplayChart:
while done == 0:
added = 0
if first:
tlist = [name,birth.getDate(),death.getDate()]
blist = ["",birth.getPlaceName(),death.getPlaceName()]
tlist = [name,"%s\n%s" % (birth.getDate(),birth.getPlaceName()),
"%s\n%s" % (death.getDate(),death.getPlaceName())]
else:
tlist = ["","",""]
blist = ["","",""]
for ename in self.event_titles[3:]:
if map.has_key(ename) and len(map[ename]) > 0:
event = map[ename][0]
del map[ename][0]
tlist.append(event.getDate())
blist.append(event.getPlaceName())
tlist.append("%s\n%s" % (event.getDate(), event.getPlaceName()))
added = 1
else:
tlist.append("")
blist.append("")
if first:
first = 0
self.row_data.append((tlist,blist))
self.row_data.append(tlist)
elif added == 0:
done = 1
else:
self.row_data.append((tlist,blist))
self.row_data.append(tlist)
def make_event_titles(self):
"""Creates the list of unique event types, along with the person's
@ -330,6 +326,8 @@ register_tool(
runTool,
_("Compare individual events"),
category=_("Analysis and Exploration"),
description=_("Aids in the analysis of data by allowing the development of custom filters that can be applied to the database to find similar events")
description=_("Aids in the analysis of data by allowing the "
"development of custom filters that can be applied "
"to the database to find similar events")
)

View File

@ -24,6 +24,7 @@ import RelLib
import Utils
import soundex
import GrampsCfg
import ListModel
from intl import gettext as _
import string
@ -43,11 +44,16 @@ def is_initial(name):
if len(name) > 2:
return 0
elif len(name) == 2:
if name[0] in string.uppercase and name[1] == '.':
if name[0] == name[0].upper() and name[1] == '.':
return 1
else:
return name[0] in string.uppercase
return name[0] == name[0].upper()
#-------------------------------------------------------------------------
#
#
#
#-------------------------------------------------------------------------
def ancestors_of(p1,list):
if p1 == None or p1 in list:
return
@ -113,9 +119,11 @@ class Merge:
self.show()
def progress_update(self,val):
self.progress.set_value(val)
while gtk.events_pending():
gtk.mainiteration()
pass
# self.progress.set_value(val)
# while gtk.events_pending():
# gtk.mainiteration()
def find_potentials(self,thresh):
top = gtk.glade.XML(self.glade_file,"message")
@ -131,19 +139,20 @@ class Merge:
key = self.gen_key(p1.getPrimaryName().getSurname())
if p1.getGender() == RelLib.Person.male:
if males.has_key(key):
males[key].append(p1)
males[key].append(p1.getId())
else:
males[key] = [p1]
males[key] = [p1.getId()]
else:
if females.has_key(key):
females[key].append(p1)
females[key].append(p1.getId())
else:
females[key] = [p1]
females[key] = [p1.getId()]
length = len(self.person_list)
num = 0
for p1 in self.person_list:
p1key = p1.getId()
if num % 25 == 0:
self.progress_update((float(num)/float(length))*100)
num = num + 1
@ -155,26 +164,27 @@ class Merge:
remaining = females[key]
index = 0
for p2 in remaining:
for p2key in remaining:
index = index + 1
if p1 == p2:
if p1key == p2key:
continue
if self.map.has_key(p2):
(v,c) = self.map[p2]
p2 = self.db.getPerson(p2key)
if self.map.has_key(p2key):
(v,c) = self.map[p2key]
if v == p1:
continue
chance = self.compare_people(p1,p2)
if chance >= thresh:
if self.map.has_key(p1):
val = self.map[p1]
if self.map.has_key(p1key):
val = self.map[p1key]
if val[1] > chance:
self.map[p1] = (p2,chance)
self.map[p1key] = (p2,chance)
else:
self.map[p1] = (p2,chance)
self.map[p1key] = (p2,chance)
self.list = self.map.keys()[:]
self.list.sort(by_id)
self.list = self.map.keys()
self.list.sort()
self.length = len(self.list)
self.topWin.destroy()
self.dellist = {}
@ -188,6 +198,12 @@ class Merge:
"on_do_merge_clicked" : self.on_do_merge_clicked,
})
self.mlist.connect('button-press-event',self.button_press_event)
self.list = ListModel.ListModel(self.mlist,
[(_('Rating'),75,0),
(_('First Person'),200,1),
(_('Second Person'),200,2)])
self.redraw()
def redraw(self):
@ -196,39 +212,41 @@ class Merge:
if self.dellist.has_key(p1):
continue
(p2,c) = self.map[p1]
if self.dellist.has_key(p2):
p2 = self.dellist[p2]
p2key = p2.getId()
if self.dellist.has_key(p2key):
p2 = self.dellist[p2key]
if p1 == p2:
continue
list.append((c,p1,p2))
list.append((c,p1,p2.getId()))
list.sort()
list.reverse()
index = 0
self.mlist.freeze()
self.mlist.clear()
self.match_map = {}
self.list.clear()
for (c,p1,p2) in list:
c = "%5.2f" % c
self.mlist.append([c, name_of(p1), name_of(p2)])
self.mlist.set_row_data(index,(p1,p2))
pn1 = self.db.getPerson(p1)
pn2 = self.db.getPerson(p2)
self.list.add([c, name_of(pn1), name_of(pn2)])
self.match_map[index] = (p1,p2)
index = index + 1
self.mlist.thaw()
def button_press_event(self,obj,event):
if event.button != 1 or event.type != GDK._2BUTTON_PRESS:
if event.button != 1 or event.type != gtk.gdk._2BUTTON_PRESS:
return
if len(self.mlist.selection) <= 0:
return
row = self.mlist.selection[0]
(p1,p2) = self.mlist.get_row_data(row)
MergeData.MergePeople(self.db,p1,p2,self.on_update)
self.on_do_merge_clicked(obj)
def on_do_merge_clicked(self,obj):
if len(self.mlist.selection) != 1:
store,iter = self.list.selection.get_selected()
if not iter:
return
row = self.mlist.selection[0]
(p1,p2) = self.mlist.get_row_data(row)
MergeData.MergePeople(self.db,p1,p2,self.on_update)
row = self.list.model.get_path(iter)
(p1,p2) = self.match_map[row[0]]
pn1 = self.db.getPerson(p1)
pn2 = self.db.getPerson(p2)
MergeData.MergePeople(self.db,pn1,pn2,self.on_update)
def on_update(self,p1,p2):
self.dellist[p2] = p1
@ -389,7 +407,7 @@ class Merge:
name1 = p1.getPrimaryName()
name2 = p2.getPrimaryName()
chance = self.name_match(name1,name2)
if chance == -1 :
return -1
@ -524,6 +542,7 @@ register_tool(
runTool,
_("Find possible duplicate people"),
category=_("Database Processing"),
description=_("Searches the entire database, looking for individual entries that may represent the same person.")
description=_("Searches the entire database, looking for "
"individual entries that may represent the same person.")
)

File diff suppressed because it is too large Load Diff