1# encoding: utf-8
2
3"""
4Paragraph-related proxy types.
5"""
6
7from __future__ import (
8    absolute_import, division, print_function, unicode_literals
9)
10
11from ..enum.style import WD_STYLE_TYPE
12from .parfmt import ParagraphFormat
13from .run import Run
14from ..shared import Parented
15
16
17class Paragraph(Parented):
18    """
19    Proxy object wrapping ``<w:p>`` element.
20    """
21    def __init__(self, p, parent):
22        super(Paragraph, self).__init__(parent)
23        self._p = self._element = p
24
25    def add_run(self, text=None, style=None):
26        """
27        Append a run to this paragraph containing *text* and having character
28        style identified by style ID *style*. *text* can contain tab
29        (``\\t``) characters, which are converted to the appropriate XML form
30        for a tab. *text* can also include newline (``\\n``) or carriage
31        return (``\\r``) characters, each of which is converted to a line
32        break.
33        """
34        r = self._p.add_r()
35        run = Run(r, self)
36        if text:
37            run.text = text
38        if style:
39            run.style = style
40        return run
41
42    @property
43    def alignment(self):
44        """
45        A member of the :ref:`WdParagraphAlignment` enumeration specifying
46        the justification setting for this paragraph. A value of |None|
47        indicates the paragraph has no directly-applied alignment value and
48        will inherit its alignment value from its style hierarchy. Assigning
49        |None| to this property removes any directly-applied alignment value.
50        """
51        return self._p.alignment
52
53    @alignment.setter
54    def alignment(self, value):
55        self._p.alignment = value
56
57    def clear(self):
58        """
59        Return this same paragraph after removing all its content.
60        Paragraph-level formatting, such as style, is preserved.
61        """
62        self._p.clear_content()
63        return self
64
65    def insert_paragraph_before(self, text=None, style=None):
66        """
67        Return a newly created paragraph, inserted directly before this
68        paragraph. If *text* is supplied, the new paragraph contains that
69        text in a single run. If *style* is provided, that style is assigned
70        to the new paragraph.
71        """
72        paragraph = self._insert_paragraph_before()
73        if text:
74            paragraph.add_run(text)
75        if style is not None:
76            paragraph.style = style
77        return paragraph
78
79    @property
80    def paragraph_format(self):
81        """
82        The |ParagraphFormat| object providing access to the formatting
83        properties for this paragraph, such as line spacing and indentation.
84        """
85        return ParagraphFormat(self._element)
86
87    @property
88    def runs(self):
89        """
90        Sequence of |Run| instances corresponding to the <w:r> elements in
91        this paragraph.
92        """
93        return [Run(r, self) for r in self._p.r_lst]
94
95    @property
96    def style(self):
97        """
98        Read/Write. |_ParagraphStyle| object representing the style assigned
99        to this paragraph. If no explicit style is assigned to this
100        paragraph, its value is the default paragraph style for the document.
101        A paragraph style name can be assigned in lieu of a paragraph style
102        object. Assigning |None| removes any applied style, making its
103        effective value the default paragraph style for the document.
104        """
105        style_id = self._p.style
106        return self.part.get_style(style_id, WD_STYLE_TYPE.PARAGRAPH)
107
108    @style.setter
109    def style(self, style_or_name):
110        style_id = self.part.get_style_id(
111            style_or_name, WD_STYLE_TYPE.PARAGRAPH
112        )
113        self._p.style = style_id
114
115    @property
116    def text(self):
117        """
118        String formed by concatenating the text of each run in the paragraph.
119        Tabs and line breaks in the XML are mapped to ``\\t`` and ``\\n``
120        characters respectively.
121
122        Assigning text to this property causes all existing paragraph content
123        to be replaced with a single run containing the assigned text.
124        A ``\\t`` character in the text is mapped to a ``<w:tab/>`` element
125        and each ``\\n`` or ``\\r`` character is mapped to a line break.
126        Paragraph-level formatting, such as style, is preserved. All
127        run-level formatting, such as bold or italic, is removed.
128        """
129        text = ''
130        for run in self.runs:
131            text += run.text
132        return text
133
134    @text.setter
135    def text(self, text):
136        self.clear()
137        self.add_run(text)
138
139    def _insert_paragraph_before(self):
140        """
141        Return a newly created paragraph, inserted directly before this
142        paragraph.
143        """
144        p = self._p.add_p_before()
145        return Paragraph(p, self._parent)
146