""" Draws Canvas with Card """ # Copyright (C) 2004 Henning Jacobs # # 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. # # $Id: ContactViewWidget.py 93 2004-11-28 16:05:34Z henning $ from Tkinter import * import vcard import debug import Preferences from AbstractContactView import * import IconImages import broadcaster import ToolTip # Canvas Width and Height: CANVASWD = 506 CANVASHT = 406 class ContactViewWidget(AbstractContactView, Frame): hide_fields = ["FormattedName", "DisplayName", "SortName", "Rev", "Photo", "Logo"] def __init__(self, master, **kws): self.savedialog = None self.canvas_items = [] self._selectcommand = kws.get("selectcommand", None) AbstractContactView.__init__(self) Frame.__init__(self, master, class_="ContactView") self.__createWidgets() def bind_contact(self, contact): AbstractContactView.bind_contact(self, contact) self.rebindWidgets() def renderAddress(self, adr, realadrobj, x, y, font): # adr is a dictionary (Fieldname: Value) # realadrobj is a real contact.adr[n] Object id = self.canvas.create_text( x, y, font=font, anchor=NW, text="Address:") self.canvas_items.append(id) zeilen = [adr["POBox"], adr["Extended"], adr["Street"], " ".join(filter(None, [adr["PostalCode"], adr["City"]])), ", ".join(filter(None, [adr["Region"], adr["Country"]]))] adrright = 0; adrtop = y; adrheight = 0; for zeile in filter(None, zeilen): id = self.canvas.create_text( 100, y, font=font, anchor=NW, text=zeile, width=CANVASWD-110) self.bindCopyToClipboard(id) self.canvas_items.append(id) self.makeLink(id, command=lambda x=realadrobj: self.composeLetter(x)) x1, y1, x2, y2 = self.canvas.bbox(id) y += (y2 - y1) + 2 adrright = max(adrright, x2) adrheight += (y2 - y1) +2 image_x = adrright+8; image_y = adrtop + adrheight/2 self.renderIcons(vcard.vC_adr_types, realadrobj.params.get("type"), image_x, image_y) return y def renderIcons(self, typelist, set, x, y): "Render GIF-Icons specified in set (typelist defines the ordering)" for type in typelist: if type in set: try: self.canvas_items.append(self.canvas.create_image(x, y, anchor=W, image=IconImages.IconImages[type])) x += 20 except: # Icons are not _that_ important.. print "renderIcons(): ERROR: Could not render icon '%s'" % (type,) def renderPhoto(self, imagedata, x, y): "draw photographic picture" msg = "" photoimage = None try: try: import ImageTk except: msg = "renderPhoto(): Could not import ImageTK - \n" msg += " You must install PIL (Python Imaging Library).\n" import base64 photoimage = ImageTk.PhotoImage(data=base64.decodestring(imagedata)) self.canvas_items.append(self.canvas.create_image(x, y, anchor=NE, image=photoimage)) except: msg += "renderPhoto(): Could not render PhotoImage." broadcaster.Broadcast('Notification', 'Error', {'message':msg}) return photoimage def rebindWidgets(self): "Redraw our Canvas" normalfont = ("Helvetica", -12) # delete all previous canvas items for x in self.canvas_items: self.canvas.delete(x) del self.canvas_items[:] y = 38 # first, draw picture in the background if not self._contact.photo.is_empty(): self._photoimage = self.renderPhoto(self._contact.photo.get(), CANVASWD-10, y) if self._photoimage: y += self._photoimage.height() + 6 # draw company logo if not self._contact.logo.is_empty(): self._logoimage = self.renderPhoto(self._contact.logo.get(), CANVASWD-10, y) # card title self.canvas.itemconfig(self.fn, text=self._contact.fn.get()) # revision date self.canvas.itemconfig(self.rev, text="Rev: %s" % self._contact.rev.get()) y = 40 previous_fieldname = "" addresses = [] for fieldname in vcard.FIELDNAMES: value = self._contact.getFieldValue(fieldname) valuecount = 0 while value: valuecount += 1 font = normalfont if fieldname in vcard.ADRFIELDS: # Collect all necessary address fields: if len(addresses) < valuecount: addresses.append({}) adr = addresses[valuecount-1] adr[fieldname] = value.get() if len(adr) == len(vcard.ADRFIELDS): # Now draw our complete address at once: y = self.renderAddress(adr, self._contact.adr[valuecount-1], 10, y, font) elif not value.is_empty() and fieldname not in self.hide_fields: if previous_fieldname != fieldname: self.canvas_items.append(self.canvas.create_text( 10, y, font=normalfont, anchor=NW, text=fieldname+":")) id = self.canvas.create_text( 100, y, font=font, anchor=NW, text=value.get(), width=CANVASWD-110) self.bindCopyToClipboard(id) self.canvas_items.append(id) if fieldname == "Email": self.makeLink(id, command=lambda x=value.get(): self.sendEMail(x)) elif fieldname == "URL": self.makeLink(id, command=lambda x=value.get(): self.viewURL(x)) elif fieldname == "Phone" and value.params.get("type").contains("fax"): self.makeLink(id, command=lambda name=self._contact.fn.get(),number=value.get(): self.sendFax(name, number)) x1, y1, x2, y2 = self.canvas.bbox(id) image_x = x2+8; image_y = y+(y2-y1)/2 if fieldname == "Phone": self.renderIcons(vcard.vC_tel_types, value.params.get("type"), image_x, image_y) elif fieldname == "Email": self.renderIcons(vcard.vC_email_types, value.params.get("type"), image_x, image_y) y += (y2 - y1) + 2 previous_fieldname = fieldname value = self._contact.getFieldValue(fieldname) def makeLink(self, canvas_id, command): # Special handling of hypertext links: hyperfont = ("Helvetica", -12, "underline") def MouseOver(event, canvas=self.canvas): canvas["cursor"] = "hand2" def MouseOut(event, canvas=self.canvas): canvas["cursor"] = "" def MouseClick(event, command=command): command() self.canvas.itemconfigure(canvas_id, font=hyperfont) self.canvas.tag_bind(canvas_id, "", MouseOver) self.canvas.tag_bind(canvas_id, "", MouseOut) self.canvas.tag_bind(canvas_id, "<1>", MouseClick) def bindCopyToClipboard(self, canvas_id): def copyToClipboard(event, canvas=self.canvas, id=canvas_id): text = self.canvas.itemcget(id, "text") canvas.clipboard_clear() canvas.clipboard_append(text) self.canvas.tag_bind(canvas_id, "<3>", copyToClipboard) def composeLetter(self, adr): broadcaster.Broadcast('Command', 'Compose Letter', data={'card':self._contact, 'adr':adr}) def sendEMail(self, recipient): "Start the preferred Mail Client and compose" import mailtowrapper recipient = "%s <%s>" % (self._contact.fn.get(), recipient) mailtowrapper.mailto(recipient) def sendFax(self, recipient, telnumber): "Send a Fax" import faxtowrapper faxtowrapper.faxto(recipient, telnumber) def viewURL(self, url): "Fire up the preferred browser and go to url" browserprog = Preferences.get("client.url_viewer").split(' ') if browserprog[0]: import os os.spawnvp(os.P_NOWAIT, browserprog[0], browserprog + [url]) else: import webbrowser webbrowser.open(url) def asksavefile(self): import os import tkFileDialog try: dir = os.getcwd() except os.error: dir = "" if not self.savedialog: filetypes = [ ("Encapsulated PostScript", "*.eps *.ps"), ("All files", "*"), ] self.savedialog = tkFileDialog.SaveAs(master=self, filetypes=filetypes) root, ext = os.path.splitext( self.savedialog.show(initialdir=dir)) if root and not ext: ext = ".eps" return root+ext def save_as_postscript(self): filename = self.asksavefile() if filename: self.canvas.postscript(file=filename) return "break" def __createWidgets(self): self.rowconfigure(0, weight=1) self.columnconfigure(0, weight=1) self.canvas = Canvas(self, width=CANVASWD, height=CANVASHT, borderwidth=0, highlightthickness=0) if self._selectcommand: def selectcommand(event, self=self): self._selectcommand(self.cardhandle()) self.canvas.bind("", selectcommand) self.canvas.grid() ToolTip.ToolTip(self.canvas, "Click Right Mouse-Button to copy text to clipboard") # 'Export to EPS' is not very useful, so hide the button: # self.btnSavePostscript = Button(self, # text="Save as Encapsulated PostScript (.eps)", # command=self.save_as_postscript) # self.btnSavePostscript.grid(sticky=S+E) # Draw card shadow: self.canvas.create_rectangle(10, 10, CANVASWD, CANVASHT, outline='', fill='#666666') # Draw card paper: self.canvas.create_rectangle(2, 2, CANVASWD-6, CANVASHT-6, width=1, fill='white') # Draw head box (here goes the card title): self.canvas.create_rectangle(2, 2, CANVASWD-6, 33, width=1, fill='#ffbb88') self.fn = self.canvas.create_text(10,4, font=("Helvetica",-24,"bold"),anchor=NW) self.bindCopyToClipboard(self.fn) self.rev = self.canvas.create_text(CANVASWD-10,CANVASHT-6, font=("Helvetica",-10),anchor=SE, fill="#888888") self.bindCopyToClipboard(self.rev)