def add_contacts(self, *nodes, **kwargs): context = kwargs.pop("context", None) if kwargs: raise TypeError("%r is ann invalid keyword argument for this function" % next(iter(kwargs.keys()))) contacts = [] for node in filter(bool, nodes): for typ in (Has_postal_address, Has_mobile, Has_fixed, Has_fax, Has_email): for link in node.links(outgoing & is_link(typ)): self._is_not_empty() label = "" if isinstance(link, Has_postal_address): self.add_address(link, link.postal) elif isinstance(link, Has_email): bullet = EMAIL_BULLET cnode = link.email contact = escape_xml(str(cnode).replace(" ", NBSP)) if isinstance(link, At_work): if context != At_work: label = str(qual_work).capitalize() elif isinstance(link, At_home): if context != At_home: label = str(qual_home).capitalize() if label: label = "<i>" + label + "</i>" else: bullet = TELEPHONE_BULLET cnode = link.tel contact = "<b>" + escape_xml(str(link.tel.relative(self.local))) + "</b>" if isinstance(link, Has_fixed): if isinstance(link, At_work): label = str(qual_work).capitalize() elif isinstance(link, At_home): label = str(qual_home).capitalize() else: label = str(multilang(en="Tel", es="Tlf")) else: if isinstance(link, Has_mobile): label = str(multilang(en="Mob", es="Móv")) else: assert isinstance(link, Has_fax) label = "Fax" if isinstance(link, At_work): label += " " + str(qual_work) elif isinstance(link, At_home): label += " " + str(qual_home) comments = [] for n in cnode, link: comment = getattr(n, "comment", None) if comment: comments.append(comment) if comments: comments = NBSP + "<i>" + "; ".join(escape_xml(str(c)) for c in comments) + "</i>" else: comments = "" if label: label += ": " label = bullet + " " + label contacts.append((label + contact).replace(" ", NBSP) + comments) self._para(" ".join(contacts), contacts_style)
def dump_person(per, tree, seen=frozenset(), show_family=True, show_work=True, show_data=True): dump_comments(per, tree) if per.birthday(): tree.add(multilang(en='Birthday', es='F.nac.')) tree.add(': ') tree.add(per.birthday()) tree.nl() telephones(per, tree) dump_email(per, tree) dump_postal(per, tree) dump_residences(per, tree) # Avoid endless recursion in dump_family() and dump_organisation(). seen = seen | set([per]) if show_family: for link in per.links(outgoing & is_link(Belongs_to)): refonly = link.family in seen if refonly: tree.add('-> ') tree.add(next(link.family.sort_keys(tree.sort_mode))) else: tree.add('-- ') add_name(link.family, tree, link) tree.nl() sub = tree.sub() dump_comments(link, sub) telephones(link, sub) dump_email(link, sub) if not refonly: dump_family(link.family, sub, seen, show_members=False, show_data=False) if show_work: for link in per.links(outgoing & is_link(Works_at)): refonly = link.org in seen if refonly: tree.add('-> ') else: tree.add('-- ') if link.position: tree.add(link.position, ', ') if refonly: tree.add(next(link.org.sort_keys(tree.sort_mode))) else: add_name(link.org, tree, link) tree.nl() sub = tree.sub() dump_comments(link, sub) telephones(link, sub) dump_email(link, sub) dump_postal(link, sub) if not refonly: dump_organisation(link.org, sub, seen, show_workers=False, show_data=False) if show_data: dump_data(per, tree)
def telephone(link, tree, qual=None, comment=None, bold=False): if isinstance(link, Has_mobile): tree.add(multilang(en='Mob', es='Móv')) elif isinstance(link, Has_fax): tree.add('Fax') else: assert isinstance(link, Has_fixed) tree.add(multilang(en='Tel', es='Tlf')) if qual: tree.add(' ', qual) elif isinstance(link, At_work): tree.add(' ', qual_work) elif isinstance(link, At_home): tree.add(' ', qual_home) tree.add(': ') tree.set_wrapmargin() tree.add(link.tel.relative(tree.local), bold=bold) wrap_comments(link.tel, tree) wrap_comments(link, tree) if comment: tree.wrap(' -- ', comment)
def __init__(self, predicate, refs, local, page_size, sections): self.predicate = predicate self.refs = refs self.local = local self.page_size = page_size self.sections = sections self.section = 0 best_paper_size = best_paper_margins = None best_n = 0 best_np = None for psize, pmarg in [(paper_size, paper_margins), (rotated(paper_size), rotated(paper_margins))]: np = [None, None] for i in 0, 1: np[i] = int((psize[i] - pmarg[i] * 2 + self.gutter) / (self.page_size.size[i] + self.gutter)) n = np[0] * np[1] if n > best_n: best_paper_size, best_paper_margins = psize, pmarg best_n = n best_np = np assert best_n >= 1 assert best_paper_size frames = [] for iy in range(best_np[1]): for ix in range(best_np[0]): frames.append( CutFrame( x1=best_paper_margins[0] + ix * (self.page_size.size[0] + self.gutter), y1=best_paper_margins[1] + iy * (self.page_size.size[1] + self.gutter), width=self.page_size.size[0], height=self.page_size.size[1], leftPadding=3 * mm + self.page_size.margin_left, rightPadding=3 * mm, topPadding=3 * mm, bottomPadding=3 * mm, showBoundary=True, ) ) self.page_width = self.page_size.size[0] - 6 * mm - self.page_size.margin_left self.page = PageTemplate(frames=frames) self.doc = BookletDoc( None, initialSection=self.sections[self.section] if self.sections else "A-Z", headerLeft=time.strftime(r"%-d %b %Y"), headerRight=str(multilang(en="Page", es="Página")) + ' <seq id="page" />', pagesize=best_paper_size, pageTemplates=[self.page], leftMargin=0, rightMargin=0, topMargin=0, bottomMargin=0, ) self.flowables = [] self._keeptogether_stack = []
dump_data(org, tree) for link in org.links(outgoing & is_link(Has_department)): refonly = link.dept in seen if refonly: tree.add('-> ') tree.add(next(link.dept.sort_keys(tree.sort_mode))) tree.nl() else: dump_names(link.dept, tree, link) sub = tree.sub() dump_comments(link, sub) if not refonly: dump_organisation(link.dept, sub, seen, show_workers=show_workers, show_data=show_data) qual_home = multilang(en='home', es='casa') qual_work = multilang(en='work', es='trab') def dump_works_at(org, tree, seen): assert org in seen for link in sorted(org.links(incoming & is_link(Works_at))): refonly = link.person in seen if refonly: tree.add('-> ') tree.add(next(link.person.sort_keys(tree.sort_mode))) if link.position: tree.add(', ', link.position) tree.nl() else: tree.add('-- ') dump_names(link.person, tree, link)
def add_person(self, per, link=None, show_family=True, show_work=True): self.add_comments(per) if per.birthday(): self._is_not_empty() self._para(str(multilang(en="Birthday", es="Fecha nac.")) + ": " + str(per.birthday()), birthday_style) self.indent += 1 self.add_addresses(per) self.add_contacts(per, link) self.indent -= 1 if show_family: for link in per.links(outgoing & is_link(Belongs_to)): # If this person's family has no top level entry, or has a top # level reference to this person, then list the family here. # Otherwise, just list a reference to the family. top = self.refs.get(link.family, per) if top is per: self.add_names(link.family.names(), bullet=EM_DASH) self.indent += 1 self.add_comments(link) self.add_family(link.family, link, show_members=False) self.indent -= 1 else: self.add_names( [next(link.family.sort_keys())], bullet=RIGHT_ARROW, bold=False, comments=self.all_comments(link), ) self.indent += 2 self.add_contacts(link, context=At_home) self.indent -= 2 if show_work: for link in per.links(outgoing & is_link(Works_at)): position = "" if link.position: self._is_not_empty() position = escape_xml(str(link.position)) + ", " # If the organisation/residence where this person works has no # top level entry or has a top level reference to this person, # then list the organisation/residence here. Otherwise, just # list a reference to its top level entry. top = self.refs.get(link.org, per) if top is per: if isinstance(link.org, Residence): self.indent += 1 self.add_address(link, link.org, prefix="<i>" + str(qual_work).capitalize() + ":</i> ") self.indent -= 1 else: self.add_names(link.org.names(), bullet=EM_DASH, prefix=position) self.indent += 1 self.add_comments(link) self.add_organisation(link.org, link, show_parents=True, show_workers=False) self.indent -= 1 else: self.add_names( [next(link.org.sort_keys())], bullet=RIGHT_ARROW, bold=False, prefix=position, comments=self.all_comments(link), ) self.indent += 2 self.add_contacts(link, context=At_work) self.indent -= 2
contacts_style = ParagraphStyle(name="Contacts", fontName="Times-Roman", fontSize=9, leading=10) address_style = ParagraphStyle(name="Address", fontName="Times-Roman", fontSize=9, leading=10) header_style = ParagraphStyle(name="Header", fontName="Times-Bold", alignment=TA_CENTER) header_left_style = ParagraphStyle(name="HeaderLeft", fontName="Times-Italic", fontSize=8, alignment=TA_LEFT, leading=0) header_right_style = ParagraphStyle( name="HeaderRight", fontName="Times-Italic", fontSize=8, alignment=TA_RIGHT, leading=0 ) continue_style = ParagraphStyle(name="Continue", fontName="Times-Italic", fontSize=8, leading=9) qual_home = multilang(en="home", es="casa") qual_work = multilang(en="work", es="trab") NBSP = "\u00a0" EN_DASH = "\u2013" EM_DASH = "\u2014" RIGHT_ARROW = "\u2192" BLACK_DIAMOND = "\u25c6" HEAVY_VERTICAL_BAR = "\u275a" EMAIL_BULLET = BLACK_DIAMOND_MINUS_WHITE_X = "\u2756" TELEPHONE_BULLET = BLACK_TELEPHONE = "\u260e" class Booklet(object): r"""A booklet object is used to construct a booklet of entries that is designed to be cut to size and bound in a filofax.