Example #1
0
    def resolve_paragraph(self, p):
        ans = self.para_cache.get(p, None)
        if ans is None:
            ans = self.para_cache[p] = ParagraphStyle()
            ans.style_name = None
            direct_formatting = None
            for pPr in XPath('./w:pPr')(p):
                ps = ParagraphStyle(pPr)
                if direct_formatting is None:
                    direct_formatting = ps
                else:
                    direct_formatting.update(ps)

            if direct_formatting is None:
                direct_formatting = ParagraphStyle()
            parent_styles = []
            if self.default_paragraph_style is not None:
                parent_styles.append(self.default_paragraph_style)
            ts = self.tables.para_style(p)
            if ts is not None:
                parent_styles.append(ts)

            default_para = self.default_styles.get('paragraph', None)
            if direct_formatting.linked_style is not None:
                ls = self.get(direct_formatting.linked_style)
                if ls is not None:
                    ans.style_name = ls.name
                    ps = ls.paragraph_style
                    if ps is not None:
                        parent_styles.append(ps)
                    if ls.character_style is not None:
                        self.para_char_cache[p] = ls.character_style
            elif default_para is not None:
                if default_para.paragraph_style is not None:
                    parent_styles.append(default_para.paragraph_style)
                if default_para.character_style is not None:
                    self.para_char_cache[p] = default_para.character_style

            is_numbering = direct_formatting.numbering is not inherit
            if is_numbering:
                num_id, lvl = direct_formatting.numbering
                if num_id is not None:
                    p.set('calibre_num_id', '%s:%s' % (lvl, num_id))
                if num_id is not None and lvl is not None:
                    ps = self.numbering.get_para_style(num_id, lvl)
                    if ps is not None:
                        parent_styles.append(ps)

            for attr in ans.all_properties:
                if not (is_numbering and attr
                        == 'text_indent'):  # skip text-indent for lists
                    setattr(
                        ans, attr,
                        self.para_val(parent_styles, direct_formatting, attr))
            ans.linked_style = direct_formatting.linked_style
        return ans
Example #2
0
 def resolve_based_on(self, parent):
     if parent.table_style is not None:
         if self.table_style is None:
             self.table_style = TableStyle(self.namespace)
         self.table_style.resolve_based_on(parent.table_style)
     if parent.paragraph_style is not None:
         if self.paragraph_style is None:
             self.paragraph_style = ParagraphStyle(self.namespace)
         self.paragraph_style.resolve_based_on(parent.paragraph_style)
     if parent.character_style is not None:
         if self.character_style is None:
             self.character_style = RunStyle(self.namespace)
         self.character_style.resolve_based_on(parent.character_style)
Example #3
0
 def __init__(self, namespace, tblPr=None):
     self.namespace = namespace
     if tblPr is None:
         for p in self.all_properties:
             setattr(self, p, inherit)
     else:
         self.overrides = inherit
         self.bidi = binary_property(tblPr, 'bidiVisual', namespace.XPath,
                                     namespace.get)
         for x in ('width', 'float', 'padding', 'shd', 'justification',
                   'spacing', 'indent', 'borders', 'band_size', 'look'):
             f = globals()['read_%s' % x]
             f(tblPr, self, self.namespace.XPath, self.namespace.get)
         parent = tblPr.getparent()
         if self.namespace.is_tag(parent, 'w:style'):
             self.overrides = {}
             for tblStylePr in self.namespace.XPath(
                     './w:tblStylePr[@w:type]')(parent):
                 otype = self.namespace.get(tblStylePr, 'w:type')
                 orides = self.overrides[otype] = {}
                 for tblPr in self.namespace.XPath('./w:tblPr')(tblStylePr):
                     orides['table'] = TableStyle(self.namespace, tblPr)
                 for trPr in self.namespace.XPath('./w:trPr')(tblStylePr):
                     orides['row'] = RowStyle(self.namespace, trPr)
                 for tcPr in self.namespace.XPath('./w:tcPr')(tblStylePr):
                     orides['cell'] = CellStyle(self.namespace, tcPr)
                 for pPr in self.namespace.XPath('./w:pPr')(tblStylePr):
                     orides['para'] = ParagraphStyle(self.namespace, pPr)
                 for rPr in self.namespace.XPath('./w:rPr')(tblStylePr):
                     orides['run'] = RunStyle(self.namespace, rPr)
     self._css = None
Example #4
0
 def __init__(self, tblPr=None):
     if tblPr is None:
         for p in self.all_properties:
             setattr(self, p, inherit)
     else:
         self.overrides = inherit
         for x in ('width', 'padding', 'shd', 'justification', 'spacing',
                   'indent', 'borders', 'band_size', 'look'):
             f = globals()['read_%s' % x]
             f(tblPr, self)
         parent = tblPr.getparent()
         if is_tag(parent, 'w:style'):
             self.overrides = {}
             for tblStylePr in XPath('./w:tblStylePr[@w:type]')(parent):
                 otype = get(tblStylePr, 'w:type')
                 orides = self.overrides[otype] = {}
                 for tblPr in XPath('./w:tblPr')(tblStylePr):
                     orides['table'] = TableStyle(tblPr)
                 for trPr in XPath('./w:trPr')(tblStylePr):
                     orides['row'] = RowStyle(trPr)
                 for tcPr in XPath('./w:tcPr')(tblStylePr):
                     orides['cell'] = tcPr
                 for pPr in XPath('./w:pPr')(tblStylePr):
                     orides['para'] = ParagraphStyle(pPr)
                 for rPr in XPath('./w:rPr')(tblStylePr):
                     orides['run'] = RunStyle(rPr)
Example #5
0
    def read_from_xml(self, lvl, override=False):
        XPath, get = self.namespace.XPath, self.namespace.get
        for lr in XPath('./w:lvlRestart[@w:val]')(lvl):
            try:
                self.restart = int(get(lr, 'w:val'))
            except (TypeError, ValueError):
                pass

        for lr in XPath('./w:start[@w:val]')(lvl):
            try:
                self.start = int(get(lr, 'w:val'))
            except (TypeError, ValueError):
                pass

        for rPr in XPath('./w:rPr')(lvl):
            ps = RunStyle(self.namespace, rPr)
            if self.character_style is None:
                self.character_style = ps
            else:
                self.character_style.update(ps)

        lt = None
        for lr in XPath('./w:lvlText[@w:val]')(lvl):
            lt = get(lr, 'w:val')

        for lr in XPath('./w:numFmt[@w:val]')(lvl):
            val = get(lr, 'w:val')
            if val == 'bullet':
                self.is_numbered = False
                cs = self.character_style
                if lt in {
                        '\uf0a7', 'o'
                } or (cs is not None and cs.font_family is not inherit
                      and cs.font_family.lower() in {'wingdings', 'symbol'}):
                    self.fmt = {
                        '\uf0a7': 'square',
                        'o': 'circle'
                    }.get(lt, 'disc')
                else:
                    self.bullet_template = lt
                for lpid in XPath('./w:lvlPicBulletId[@w:val]')(lvl):
                    self.pic_id = get(lpid, 'w:val')
            else:
                self.is_numbered = True
                self.fmt = STYLE_MAP.get(val, 'decimal')
                if lt and re.match(r'%\d+\.$', lt) is None:
                    self.num_template = lt

        for lr in XPath('./w:pStyle[@w:val]')(lvl):
            self.para_link = get(lr, 'w:val')

        for pPr in XPath('./w:pPr')(lvl):
            ps = ParagraphStyle(self.namespace, pPr)
            if self.paragraph_style is None:
                self.paragraph_style = ps
            else:
                self.paragraph_style.update(ps)
Example #6
0
 def resolve_based_on(self, parent):
     if parent.table_style is not None:
         if self.table_style is None:
             self.table_style = TableStyle(self.namespace)
         self.table_style.resolve_based_on(parent.table_style)
     if parent.paragraph_style is not None:
         if self.paragraph_style is None:
             self.paragraph_style = ParagraphStyle(self.namespace)
         self.paragraph_style.resolve_based_on(parent.paragraph_style)
     if parent.character_style is not None:
         if self.character_style is None:
             self.character_style = RunStyle(self.namespace)
         self.character_style.resolve_based_on(parent.character_style)
Example #7
0
    def __init__(self, namespace, elem):
        self.namespace = namespace
        self.name_path = namespace.XPath('./w:name[@w:val]')
        self.based_on_path = namespace.XPath('./w:basedOn[@w:val]')
        self.resolved = False
        self.style_id = namespace.get(elem, 'w:styleId')
        self.style_type = namespace.get(elem, 'w:type')
        names = self.name_path(elem)
        self.name = namespace.get(names[-1], 'w:val') if names else None
        based_on = self.based_on_path(elem)
        self.based_on = namespace.get(based_on[0],
                                      'w:val') if based_on else None
        if self.style_type == 'numbering':
            self.based_on = None
        self.is_default = namespace.get(elem,
                                        'w:default') in {'1', 'on', 'true'}

        self.paragraph_style = self.character_style = self.table_style = None

        if self.style_type in {'paragraph', 'character', 'table'}:
            if self.style_type == 'table':
                for tblPr in namespace.XPath('./w:tblPr')(elem):
                    ts = TableStyle(namespace, tblPr)
                    if self.table_style is None:
                        self.table_style = ts
                    else:
                        self.table_style.update(ts)
            if self.style_type in {'paragraph', 'table'}:
                for pPr in namespace.XPath('./w:pPr')(elem):
                    ps = ParagraphStyle(namespace, pPr)
                    if self.paragraph_style is None:
                        self.paragraph_style = ps
                    else:
                        self.paragraph_style.update(ps)

            for rPr in namespace.XPath('./w:rPr')(elem):
                rs = RunStyle(namespace, rPr)
                if self.character_style is None:
                    self.character_style = rs
                else:
                    self.character_style.update(rs)

        if self.style_type in {'numbering', 'paragraph'}:
            self.numbering_style_link = None
            for x in namespace.XPath('./w:pPr/w:numPr/w:numId[@w:val]')(elem):
                self.numbering_style_link = namespace.get(x, 'w:val')
Example #8
0
    def read_from_xml(self, lvl, override=False):
        for lr in XPath('./w:lvlRestart[@w:val]')(lvl):
            try:
                self.restart = int(get(lr, 'w:val'))
            except (TypeError, ValueError):
                pass

        for lr in XPath('./w:start[@w:val]')(lvl):
            try:
                self.start = int(get(lr, 'w:val'))
            except (TypeError, ValueError):
                pass

        lt = None
        for lr in XPath('./w:lvlText[@w:val]')(lvl):
            lt = get(lr, 'w:val')

        for lr in XPath('./w:numFmt[@w:val]')(lvl):
            val = get(lr, 'w:val')
            if val == 'bullet':
                self.is_numbered = False
                self.fmt = {'\uf0a7': 'square', 'o': 'circle'}.get(lt, 'disc')
                for lpid in XPath('./w:lvlPicBulletId[@w:val]')(lvl):
                    self.pic_id = get(lpid, 'w:val')
            else:
                self.is_numbered = True
                self.fmt = STYLE_MAP.get(val, 'decimal')
                if lt and re.match(r'%\d+\.$', lt) is None:
                    self.num_template = lt

        for lr in XPath('./w:pStyle[@w:val]')(lvl):
            self.para_link = get(lr, 'w:val')

        for pPr in XPath('./w:pPr')(lvl):
            ps = ParagraphStyle(pPr)
            if self.paragraph_style is None:
                self.paragraph_style = ps
            else:
                self.paragraph_style.update(ps)

        for rPr in XPath('./w:rPr')(lvl):
            ps = RunStyle(rPr)
            if self.character_style is None:
                self.character_style = ps
            else:
                self.character_style.update(ps)
Example #9
0
    def __call__(self, root, fonts, theme):
        self.fonts, self.theme = fonts, theme
        self.default_paragraph_style = self.default_character_style = None
        if root is not None:
            for s in self.namespace.XPath('//w:style')(root):
                s = Style(self.namespace, s)
                if s.style_id:
                    self.id_map[s.style_id] = s
                if s.is_default:
                    self.default_styles[s.style_type] = s
                if getattr(s, 'numbering_style_link', None) is not None:
                    self.numbering_style_links[
                        s.style_id] = s.numbering_style_link

            for dd in self.namespace.XPath('./w:docDefaults')(root):
                for pd in self.namespace.XPath('./w:pPrDefault')(dd):
                    for pPr in self.namespace.XPath('./w:pPr')(pd):
                        ps = ParagraphStyle(self.namespace, pPr)
                        if self.default_paragraph_style is None:
                            self.default_paragraph_style = ps
                        else:
                            self.default_paragraph_style.update(ps)
                for pd in self.namespace.XPath('./w:rPrDefault')(dd):
                    for pPr in self.namespace.XPath('./w:rPr')(pd):
                        ps = RunStyle(self.namespace, pPr)
                        if self.default_character_style is None:
                            self.default_character_style = ps
                        else:
                            self.default_character_style.update(ps)

        def resolve(s, p):
            if p is not None:
                if not p.resolved:
                    resolve(p, self.get(p.based_on))
                s.resolve_based_on(p)
            s.resolved = True

        for s in self:
            if not s.resolved:
                resolve(s, self.get(s.based_on))
Example #10
0
class Style(object):
    '''
    Class representing a <w:style> element. Can contain block, character, etc. styles.
    '''

    def __init__(self, namespace, elem):
        self.namespace = namespace
        self.name_path = namespace.XPath('./w:name[@w:val]')
        self.based_on_path = namespace.XPath('./w:basedOn[@w:val]')
        self.resolved = False
        self.style_id = namespace.get(elem, 'w:styleId')
        self.style_type = namespace.get(elem, 'w:type')
        names = self.name_path(elem)
        self.name = namespace.get(names[-1], 'w:val') if names else None
        based_on = self.based_on_path(elem)
        self.based_on = namespace.get(based_on[0], 'w:val') if based_on else None
        if self.style_type == 'numbering':
            self.based_on = None
        self.is_default = namespace.get(elem, 'w:default') in {'1', 'on', 'true'}

        self.paragraph_style = self.character_style = self.table_style = None

        if self.style_type in {'paragraph', 'character', 'table'}:
            if self.style_type == 'table':
                for tblPr in namespace.XPath('./w:tblPr')(elem):
                    ts = TableStyle(namespace, tblPr)
                    if self.table_style is None:
                        self.table_style = ts
                    else:
                        self.table_style.update(ts)
            if self.style_type in {'paragraph', 'table'}:
                for pPr in namespace.XPath('./w:pPr')(elem):
                    ps = ParagraphStyle(namespace, pPr)
                    if self.paragraph_style is None:
                        self.paragraph_style = ps
                    else:
                        self.paragraph_style.update(ps)

            for rPr in namespace.XPath('./w:rPr')(elem):
                rs = RunStyle(namespace, rPr)
                if self.character_style is None:
                    self.character_style = rs
                else:
                    self.character_style.update(rs)

        if self.style_type in {'numbering', 'paragraph'}:
            self.numbering_style_link = None
            for x in namespace.XPath('./w:pPr/w:numPr/w:numId[@w:val]')(elem):
                self.numbering_style_link = namespace.get(x, 'w:val')

    def resolve_based_on(self, parent):
        if parent.table_style is not None:
            if self.table_style is None:
                self.table_style = TableStyle(self.namespace)
            self.table_style.resolve_based_on(parent.table_style)
        if parent.paragraph_style is not None:
            if self.paragraph_style is None:
                self.paragraph_style = ParagraphStyle(self.namespace)
            self.paragraph_style.resolve_based_on(parent.paragraph_style)
        if parent.character_style is not None:
            if self.character_style is None:
                self.character_style = RunStyle(self.namespace)
            self.character_style.resolve_based_on(parent.character_style)
Example #11
0
class Style(object):
    '''
    Class representing a <w:style> element. Can contain block, character, etc. styles.
    '''
    def __init__(self, namespace, elem):
        self.namespace = namespace
        self.name_path = namespace.XPath('./w:name[@w:val]')
        self.based_on_path = namespace.XPath('./w:basedOn[@w:val]')
        self.resolved = False
        self.style_id = namespace.get(elem, 'w:styleId')
        self.style_type = namespace.get(elem, 'w:type')
        names = self.name_path(elem)
        self.name = namespace.get(names[-1], 'w:val') if names else None
        based_on = self.based_on_path(elem)
        self.based_on = namespace.get(based_on[0],
                                      'w:val') if based_on else None
        if self.style_type == 'numbering':
            self.based_on = None
        self.is_default = namespace.get(elem,
                                        'w:default') in {'1', 'on', 'true'}

        self.paragraph_style = self.character_style = self.table_style = None

        if self.style_type in {'paragraph', 'character', 'table'}:
            if self.style_type == 'table':
                for tblPr in namespace.XPath('./w:tblPr')(elem):
                    ts = TableStyle(namespace, tblPr)
                    if self.table_style is None:
                        self.table_style = ts
                    else:
                        self.table_style.update(ts)
            if self.style_type in {'paragraph', 'table'}:
                for pPr in namespace.XPath('./w:pPr')(elem):
                    ps = ParagraphStyle(namespace, pPr)
                    if self.paragraph_style is None:
                        self.paragraph_style = ps
                    else:
                        self.paragraph_style.update(ps)

            for rPr in namespace.XPath('./w:rPr')(elem):
                rs = RunStyle(namespace, rPr)
                if self.character_style is None:
                    self.character_style = rs
                else:
                    self.character_style.update(rs)

        if self.style_type in {'numbering', 'paragraph'}:
            self.numbering_style_link = None
            for x in namespace.XPath('./w:pPr/w:numPr/w:numId[@w:val]')(elem):
                self.numbering_style_link = namespace.get(x, 'w:val')

    def resolve_based_on(self, parent):
        if parent.table_style is not None:
            if self.table_style is None:
                self.table_style = TableStyle(self.namespace)
            self.table_style.resolve_based_on(parent.table_style)
        if parent.paragraph_style is not None:
            if self.paragraph_style is None:
                self.paragraph_style = ParagraphStyle(self.namespace)
            self.paragraph_style.resolve_based_on(parent.paragraph_style)
        if parent.character_style is not None:
            if self.character_style is None:
                self.character_style = RunStyle(self.namespace)
            self.character_style.resolve_based_on(parent.character_style)
Example #12
0
    def resolve_paragraph(self, p):
        ans = self.para_cache.get(p, None)
        if ans is None:
            linked_style = None
            ans = self.para_cache[p] = ParagraphStyle(self.namespace)
            ans.style_name = None
            direct_formatting = None
            is_section_break = False
            for pPr in self.namespace.XPath('./w:pPr')(p):
                ps = ParagraphStyle(self.namespace, pPr)
                if direct_formatting is None:
                    direct_formatting = ps
                else:
                    direct_formatting.update(ps)
                if self.namespace.XPath('./w:sectPr')(pPr):
                    is_section_break = True

            if direct_formatting is None:
                direct_formatting = ParagraphStyle(self.namespace)
            parent_styles = []
            if self.default_paragraph_style is not None:
                parent_styles.append(self.default_paragraph_style)
            ts = self.tables.para_style(p)
            if ts is not None:
                parent_styles.append(ts)

            default_para = self.default_styles.get('paragraph', None)
            if direct_formatting.linked_style is not None:
                ls = linked_style = self.get(direct_formatting.linked_style)
                if ls is not None:
                    ans.style_name = ls.name
                    ps = ls.paragraph_style
                    if ps is not None:
                        parent_styles.append(ps)
                    if ls.character_style is not None:
                        self.para_char_cache[p] = ls.character_style
            elif default_para is not None:
                if default_para.paragraph_style is not None:
                    parent_styles.append(default_para.paragraph_style)
                if default_para.character_style is not None:
                    self.para_char_cache[p] = default_para.character_style

            def has_numbering(block_style):
                num_id, lvl = getattr(block_style, 'numbering_id',
                                      inherit), getattr(
                                          block_style, 'numbering_level',
                                          inherit)
                return num_id is not None and num_id is not inherit and lvl is not None and lvl is not inherit

            is_numbering = has_numbering(direct_formatting)
            is_section_break = is_section_break and not self.namespace.XPath(
                './w:r')(p)

            if is_numbering and not is_section_break:
                num_id, lvl = direct_formatting.numbering_id, direct_formatting.numbering_level
                p.set('calibre_num_id', '%s:%s' % (lvl, num_id))
                ps = self.numbering.get_para_style(num_id, lvl)
                if ps is not None:
                    parent_styles.append(ps)
            if (not is_numbering and not is_section_break
                    and linked_style is not None
                    and has_numbering(linked_style.paragraph_style)):
                num_id, lvl = linked_style.paragraph_style.numbering_id, linked_style.paragraph_style.numbering_level
                p.set('calibre_num_id', '%s:%s' % (lvl, num_id))
                is_numbering = True
                ps = self.numbering.get_para_style(num_id, lvl)
                if ps is not None:
                    parent_styles.append(ps)

            for attr in ans.all_properties:
                if not (is_numbering and attr
                        == 'text_indent'):  # skip text-indent for lists
                    setattr(
                        ans, attr,
                        self.para_val(parent_styles, direct_formatting, attr))
            ans.linked_style = direct_formatting.linked_style
        return ans
Example #13
0
class Style(object):
    """
    Class representing a <w:style> element. Can contain block, character, etc. styles.
    """

    name_path = XPath("./w:name[@w:val]")
    based_on_path = XPath("./w:basedOn[@w:val]")

    def __init__(self, elem):
        self.resolved = False
        self.style_id = get(elem, "w:styleId")
        self.style_type = get(elem, "w:type")
        names = self.name_path(elem)
        self.name = get(names[-1], "w:val") if names else None
        based_on = self.based_on_path(elem)
        self.based_on = get(based_on[0], "w:val") if based_on else None
        if self.style_type == "numbering":
            self.based_on = None
        self.is_default = get(elem, "w:default") in {"1", "on", "true"}

        self.paragraph_style = self.character_style = self.table_style = None

        if self.style_type in {"paragraph", "character", "table"}:
            if self.style_type == "table":
                for tblPr in XPath("./w:tblPr")(elem):
                    ts = TableStyle(tblPr)
                    if self.table_style is None:
                        self.table_style = ts
                    else:
                        self.table_style.update(ts)
            if self.style_type in {"paragraph", "table"}:
                for pPr in XPath("./w:pPr")(elem):
                    ps = ParagraphStyle(pPr)
                    if self.paragraph_style is None:
                        self.paragraph_style = ps
                    else:
                        self.paragraph_style.update(ps)

            for rPr in XPath("./w:rPr")(elem):
                rs = RunStyle(rPr)
                if self.character_style is None:
                    self.character_style = rs
                else:
                    self.character_style.update(rs)

        if self.style_type == "numbering":
            self.numbering_style_link = None
            for x in XPath("./w:pPr/w:numPr/w:numId[@w:val]")(elem):
                self.numbering_style_link = get(x, "w:val")

    def resolve_based_on(self, parent):
        if parent.table_style is not None:
            if self.table_style is None:
                self.table_style = TableStyle()
            self.table_style.resolve_based_on(parent.table_style)
        if parent.paragraph_style is not None:
            if self.paragraph_style is None:
                self.paragraph_style = ParagraphStyle()
            self.paragraph_style.resolve_based_on(parent.paragraph_style)
        if parent.character_style is not None:
            if self.character_style is None:
                self.character_style = RunStyle()
            self.character_style.resolve_based_on(parent.character_style)