def __init__(self, parent, text = None, translator = None): parent += self self.text = text self.translator_cfg = translator if self.translator_cfg: self.translator = get_singleton(**self.translator_cfg) else: self.translator = None
def render(self, max_width, width_mode): # counting the calls is needed to decide if lines must be # deleted from cache in case of multiple rendering due to unresolved references. self.render_count += 1 # Instantiate the wrapper, if any if self.wrapper_cfg: self.wrapper_cfg['width'] = max_width # add optional hyphenator to the wrapper. this is # supported by textwrap2 which is part of the PyHyphen hyphenation library. if self.hyphenator_cfg: self.wrapper_cfg['use_hyphenator'] = self.hyphenator_cfg self.wrapper = get_singleton(**self.wrapper_cfg) else: self.wrapper = None # instantiate the optional translator. Note that each element may have # its own translator. However, the content manager's translator # works on the entire content rather than separately on each element. if self.translator_cfg: self.translator = get_singleton(**self.translator_cfg) else: self.translator = None # Render each element and put the results together. Future versions # may need to handle other content types. raw_content = [] # containers for all refs and targets whether resolved or not self.refs = [] self.targets = [] given_pager = None # to store a potential Pager instance for child in self: if isinstance(child, GenericText): raw_content.append(child.render()) elif isinstance(child, Reference): tmp = child.render() if not tmp: if child.enabled: # unresolved Reference tmp = u'{r' + unicode(len(self.refs)) + u'}' self.refs.append(child) else: tmp = u'' raw_content.append(tmp) elif isinstance(child, Target): raw_content.append(u'{t' + unicode(len(self.targets)) + u'}') self.targets.append(child) elif isinstance(child, Pager): given_pager = child # Translate the frame's content altogether, if required, # skipping any placeholders for later substitution. if self.translator: i = 0 previous_is_marker = False while i < len(raw_content): is_marker = markers_re.match(raw_content[i]) if is_marker and is_marker.group() == raw_content[i]: # only then is it a reference or target marker # check if previous element must be translated if i > 0 and not previous_is_marker: raw_content[i-1] = self.translator.run(raw_content[i-1]) previous_is_marker = True # retain this for next iteration i += 1 else: # normal text: # join with previous text element if any if i == 0: i += 1 elif not previous_is_marker: raw_content[i-1] += raw_content[i] raw_content.pop(i) previous_is_marker = False # Translate the last text element if not previous_is_marker: raw_content[-1] = self.translator.run(raw_content[-1]) # join the translated results to a single string before wrapping it raw_content = u''.join(raw_content) # and wrap it into lines if self.wrapper: raw_content = self.wrapper.wrap(raw_content) else: raw_content = [raw_content] # get the relevant width depending on the length of each # line and on whether width_mode is fixed or auto. The width is used when rendering each Line instance. # Note that due to unresolved references auto width can yield too large results at this stage. if width_mode == 'fixed': width = max_width else: # it must be 'auto': width = max((len(l) for l in raw_content)) # Get the lines cache: root = self.parent.parent while not hasattr(root, 'cache'): root = root.parent cache = root.cache # pack the strings into Line objects. lrc = len(raw_content) for j in range(lrc): # check for reference and target markers # first, create containers for refs and targets to be passed on to the Lin instances cur_refs = [] cur_targets = [] # Iterate over any reference and target markers within the line: reftargets = ref_targets_re.finditer(raw_content[j]) for r in reftargets: # extract the index of the Reference or Target object idx = int(r.group()[2:-1]) # this cuts off '{r' and '}' if r.group()[1] == u'r': # it is a reference cur_refs.append(self.refs[idx]) elif r.group()[1] == u't': # it is a target cur_targets.append(self.targets[idx]) # delete the target marker. We do not need it anymore as we have found its Line instance raw_content[j] = raw_content[j].replace(r.group(), u'') # generate page break info to be used by the paginator: cur_pager = None if (j == 0) or (j == lrc - 2): cur_pager = Pager(self, mode = 2) # avoid widows and orphans if given_pager and (j == lrc - 1): cur_pager = given_pager # last line of paragraph should not be block-aligned by Line-render() if j == lrc - 1: last_in_para = True else: last_in_para = False # Generate and store the Line instance cache.append(Line(raw_content[j], width, j, self.parent, self.x_align, last_in_para, refs = cur_refs, targets = cur_targets, pager = cur_pager)) self.lines = raw_content # is this really needed? return (width, len(raw_content))