class CT_ShapeNonVisual(BaseShapeElement): """ ``<p:nvSpPr>`` custom element class """ cNvPr = OneAndOnlyOne('p:cNvPr') cNvSpPr = OneAndOnlyOne('p:cNvSpPr') nvPr = OneAndOnlyOne('p:nvPr')
class CT_GraphicalObjectFrameNonVisual(BaseOxmlElement): """`<p:nvGraphicFramePr>` element. This contains the non-visual properties of a graphic frame, such as name, id, etc. """ cNvPr = OneAndOnlyOne("p:cNvPr") nvPr = OneAndOnlyOne("p:nvPr")
class CT_PictureNonVisual(BaseOxmlElement): """ ``<p:nvPicPr>`` element, containing non-visual properties for a picture shape. """ cNvPr = OneAndOnlyOne("p:cNvPr") nvPr = OneAndOnlyOne("p:nvPr")
class CT_CommonSlideData(BaseOxmlElement): """`p:cSld` element.""" _tag_seq = ("p:bg", "p:spTree", "p:custDataLst", "p:controls", "p:extLst") bg = ZeroOrOne("p:bg", successors=_tag_seq[1:]) spTree = OneAndOnlyOne("p:spTree") del _tag_seq name = OptionalAttribute("name", XsdString, default="") def get_or_add_bgPr(self): """Return `p:bg/p:bgPr` grandchild. If no such grandchild is present, any existing `p:bg` child is first removed and a new default `p:bg` with noFill settings is added. """ bg = self.bg if bg is None or bg.bgPr is None: self._change_to_noFill_bg() return self.bg.bgPr def _change_to_noFill_bg(self): """Establish a `p:bg` child with no-fill settings. Any existing `p:bg` child is first removed. """ self._remove_bg() bg = self.get_or_add_bg() bg.add_noFill_bgPr() return bg
class CT_RegularTextRun(BaseOxmlElement): """`a:r` custom element class""" rPr = ZeroOrOne("a:rPr", successors=("a:t", )) t = OneAndOnlyOne("a:t") @property def text(self): """(unicode) str containing text of (required) `a:t` child""" text = self.t.text # t.text is None when t element is empty, e.g. '<a:t/>' return to_unicode(text) if text is not None else "" @text.setter def text(self, str): """*str* is unicode value to replace run text.""" self.t.text = self._escape_ctrl_chars(str) @staticmethod def _escape_ctrl_chars(s): """Return str after replacing each control character with a plain-text escape. For example, a BEL character (x07) would appear as "_x0007_". Horizontal-tab (x09) and line-feed (x0A) are not escaped. All other characters in the range x00-x1F are escaped. """ return re.sub(r"([\x00-\x08\x0B-\x1F])", lambda match: "_x%04X_" % ord(match.group(1)), s)
class CT_NotesSlide(BaseOxmlElement): """ ``<p:notes>`` element, root of a notesSlide part """ cSld = OneAndOnlyOne('p:cSld') clrMapOvr = ZeroOrOne('p:clrMapOvr', successors=('p:transition', 'p:timing', 'p:extLst')) @classmethod def new(cls): """ Return a new ``<p:notes>`` element configured as a base slide shape. """ return parse_xml(cls._notes_xml()) @staticmethod def _notes_xml(): """From http://msdn.microsoft.com/en-us/library/office/gg278319%28v=office.15%29.aspx#sectionSection4 """ return ( '<p:notes %s>\n' ' <p:cSld>\n' ' <p:spTree>\n' ' <p:nvGrpSpPr>\n' ' <p:cNvPr id="1"\n' ' name="" />\n' ' <p:cNvGrpSpPr />\n' ' <p:nvPr />\n' ' </p:nvGrpSpPr>\n' ' <p:grpSpPr>\n' ' <a:xfrm xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" />\n' ' </p:grpSpPr>\n' ' <p:sp>\n' ' <p:nvSpPr>\n' ' <p:cNvPr id="2"\n' ' name="" />\n' ' <p:cNvSpPr>\n' ' <a:spLocks noGrp="1"\n' ' xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" />\n' ' </p:cNvSpPr>\n' ' <p:nvPr>\n' ' <p:ph />\n' ' </p:nvPr>\n' ' </p:nvSpPr>\n' ' <p:spPr />\n' ' <p:txBody>\n' ' <a:bodyPr xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" />\n' ' <a:lstStyle xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" />\n' ' <a:p xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">\n' ' <a:endParaRPr />\n' ' </a:p>\n' ' </p:txBody>\n' ' </p:sp>\n' ' </p:spTree>\n' ' </p:cSld>\n' ' <p:clrMapOvr>\n' ' <a:masterClrMapping xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" />\n' ' </p:clrMapOvr>\n' '</p:notes>\n' % nsdecls('p', 'a', 'r'))
class CT_SlideLayout(_BaseSlideElement): """ ``<p:sldLayout>`` element, root of a slide layout part """ _tag_seq = ('p:cSld', 'p:clrMapOvr', 'p:transition', 'p:timing', 'p:hf', 'p:extLst') cSld = OneAndOnlyOne('p:cSld') del _tag_seq
class CT_SlideLayout(_BaseSlideElement): """ ``<p:sldLayout>`` element, root of a slide layout part """ _tag_seq = ("p:cSld", "p:clrMapOvr", "p:transition", "p:timing", "p:hf", "p:extLst") cSld = OneAndOnlyOne("p:cSld") del _tag_seq
class CT_SlideMaster(_BaseSlideElement): """ ``<p:sldMaster>`` element, root of a slide master part """ _tag_seq = ('p:cSld', 'p:clrMap', 'p:sldLayoutIdLst', 'p:transition', 'p:timing', 'p:hf', 'p:txStyles', 'p:extLst') cSld = OneAndOnlyOne('p:cSld') sldLayoutIdLst = ZeroOrOne('p:sldLayoutIdLst', successors=_tag_seq[3:]) del _tag_seq
class ThemeDefinition(CT_OfficeStyleSheet): name = RequiredAttribute("name", XsdString) themeElements = OneAndOnlyOne("a:themeElements") @classmethod def new(cls, xml): """Return theme definition""" t = oxml.parse_xml(xml) return t
class CT_SlideMasterUpdated(_BaseSlideElement): """ ``<p:sldMaster>`` element, root of a slide master part """ _tag_seq = ( "p:cSld", "p:clrMap", "p:sldLayoutIdLst", "p:transition", "p:timing", "p:hf", "p:txStyles", "p:extLst", ) cSld = OneAndOnlyOne("p:cSld") clrMap = OneAndOnlyOne("p:clrMap") ### We need access to clrMap sldLayoutIdLst = ZeroOrOne("p:sldLayoutIdLst", successors=_tag_seq[3:]) del _tag_seq
class CT_RegularTextRun(BaseOxmlElement): """`a:r` custom element class""" rPr = ZeroOrOne('a:rPr', successors=('a:t', )) t = OneAndOnlyOne('a:t') @property def text(self): """(unicode) str containing text of (required) `a:t` child""" text = self.t.text # t.text is None when t element is empty, e.g. '<a:t/>' return to_unicode(text) if text is not None else u''
class CT_GraphicalObject(BaseOxmlElement): """ ``<a:graphic>`` element, which is the container for the reference to or definition of the framed graphical object (table, chart, etc.). """ graphicData = OneAndOnlyOne("a:graphicData") @property def chart(self): """ The ``<c:chart>`` grandchild element, or |None| if not present. """ return self.graphicData.chart
class CT_NotesMaster(_BaseSlideElement): """ ``<p:notesMaster>`` element, root of a notes master part """ _tag_seq = ('p:cSld', 'p:clrMap', 'p:hf', 'p:notesStyle', 'p:extLst') cSld = OneAndOnlyOne('p:cSld') del _tag_seq @classmethod def new_default(cls): """ Return a new ``<p:notesMaster>`` element based on the built-in default template. """ return parse_from_template('notesMaster')
class CT_RegularTextRun(BaseOxmlElement): """ Custom element class for <a:r> elements. """ rPr = ZeroOrOne('a:rPr', successors=('a:t', )) t = OneAndOnlyOne('a:t') @property def text(self): """ The text of the ``<a:t>`` child element. """ text = self.t.text # t.text is None when t element is empty, e.g. '<a:t/>' return to_unicode(text) if text is not None else u''
class CT_Parent(BaseOxmlElement): """ ``<p:parent>`` element, an invented element for use in testing. """ eg_zooChoice = ZeroOrOneChoice( (Choice('p:choice'), Choice('p:choice2')), successors=('p:oomChild', 'p:oooChild') ) oomChild = OneOrMore('p:oomChild', successors=( 'p:oooChild', 'p:zomChild', 'p:zooChild' )) oooChild = OneAndOnlyOne('p:oooChild') zomChild = ZeroOrMore('p:zomChild', successors=('p:zooChild',)) zooChild = ZeroOrOne('p:zooChild', successors=()) optAttr = OptionalAttribute('p:optAttr', ST_IntegerType) reqAttr = RequiredAttribute('reqAttr', ST_IntegerType)
class CT_NotesSlide(_BaseSlideElement): """ ``<p:notes>`` element, root of a notes slide part """ _tag_seq = ('p:cSld', 'p:clrMapOvr', 'p:extLst') cSld = OneAndOnlyOne('p:cSld') del _tag_seq @classmethod def new(cls): """ Return a new ``<p:notes>`` element based on the default template. Note that the template does not include placeholders, which must be subsequently cloned from the notes master. """ return parse_from_template('notes')
class CT_Path2DLineTo(BaseOxmlElement): """ """ pt = OneAndOnlyOne('a:pt') @classmethod def new(cls): xml = cls._tmpl() return parse_xml(xml) @classmethod def _tmpl(self): return ( '<a:lnTo %s>\n' ' <a:pt x="%s" y="%s" />\n' '</a:lnTo>' ) % (nsdecls('a'), '%d', '%d')
class CT_DateAx(BaseAxisElement): """`c:dateAx` element, defining a date (category) axis.""" _tag_seq = ( "c:axId", "c:scaling", "c:delete", "c:axPos", "c:majorGridlines", "c:minorGridlines", "c:title", "c:numFmt", "c:majorTickMark", "c:minorTickMark", "c:tickLblPos", "c:spPr", "c:txPr", "c:crossAx", "c:crosses", "c:crossesAt", "c:auto", "c:lblOffset", "c:baseTimeUnit", "c:majorUnit", "c:majorTimeUnit", "c:minorUnit", "c:minorTimeUnit", "c:extLst", ) scaling = OneAndOnlyOne("c:scaling") delete_ = ZeroOrOne("c:delete", successors=_tag_seq[3:]) majorGridlines = ZeroOrOne("c:majorGridlines", successors=_tag_seq[5:]) minorGridlines = ZeroOrOne("c:minorGridlines", successors=_tag_seq[6:]) title = ZeroOrOne("c:title", successors=_tag_seq[7:]) numFmt = ZeroOrOne("c:numFmt", successors=_tag_seq[8:]) majorTickMark = ZeroOrOne("c:majorTickMark", successors=_tag_seq[9:]) minorTickMark = ZeroOrOne("c:minorTickMark", successors=_tag_seq[10:]) tickLblPos = ZeroOrOne("c:tickLblPos", successors=_tag_seq[11:]) spPr = ZeroOrOne("c:spPr", successors=_tag_seq[12:]) txPr = ZeroOrOne("c:txPr", successors=_tag_seq[13:]) crosses = ZeroOrOne("c:crosses", successors=_tag_seq[15:]) crossesAt = ZeroOrOne("c:crossesAt", successors=_tag_seq[16:]) lblOffset = ZeroOrOne("c:lblOffset", successors=_tag_seq[18:]) del _tag_seq
class CT_ValAx(BaseAxisElement): """`c:valAx` element, defining a value axis.""" _tag_seq = ( "c:axId", "c:scaling", "c:delete", "c:axPos", "c:majorGridlines", "c:minorGridlines", "c:title", "c:numFmt", "c:majorTickMark", "c:minorTickMark", "c:tickLblPos", "c:spPr", "c:txPr", "c:crossAx", "c:crosses", "c:crossesAt", "c:crossBetween", "c:majorUnit", "c:minorUnit", "c:dispUnits", "c:extLst", ) scaling = OneAndOnlyOne("c:scaling") delete_ = ZeroOrOne("c:delete", successors=_tag_seq[3:]) majorGridlines = ZeroOrOne("c:majorGridlines", successors=_tag_seq[5:]) minorGridlines = ZeroOrOne("c:minorGridlines", successors=_tag_seq[6:]) title = ZeroOrOne("c:title", successors=_tag_seq[7:]) numFmt = ZeroOrOne("c:numFmt", successors=_tag_seq[8:]) majorTickMark = ZeroOrOne("c:majorTickMark", successors=_tag_seq[9:]) minorTickMark = ZeroOrOne("c:minorTickMark", successors=_tag_seq[10:]) tickLblPos = ZeroOrOne("c:tickLblPos", successors=_tag_seq[11:]) spPr = ZeroOrOne("c:spPr", successors=_tag_seq[12:]) txPr = ZeroOrOne("c:txPr", successors=_tag_seq[13:]) crossAx = ZeroOrOne("c:crossAx", successors=_tag_seq[14:]) crosses = ZeroOrOne("c:crosses", successors=_tag_seq[15:]) crossesAt = ZeroOrOne("c:crossesAt", successors=_tag_seq[16:]) majorUnit = ZeroOrOne("c:majorUnit", successors=_tag_seq[18:]) minorUnit = ZeroOrOne("c:minorUnit", successors=_tag_seq[19:]) del _tag_seq
class CT_SlideNotes(BaseOxmlElement): # This is a hack. notes_id = 1000 """ ``<p:notes>`` element, root of a notesSlide part """ cSld = OneAndOnlyOne('p:cSld') clrMapOvr = ZeroOrOne('p:clrMapOvr', successors=('p:transition', 'p:timing', 'p:extLst')) @classmethod def new(cls): """ Return a new ``<p:notes>`` element configured as a base slide shape. """ return parse_xml(cls._notes_xml()) @staticmethod def _notes_xml(): """From http://msdn.microsoft.com/en-us/library/office/gg278319%28v=office.15%29.aspx#sectionSection4 """ return ('<p:notes %s>\n' ' <p:cSld>\n' ' <p:spTree>\n' ' <p:nvGrpSpPr>\n' ' <p:cNvPr id="1" name=""/>\n' ' <p:cNvGrpSpPr/>\n' ' <p:nvPr/>\n' ' </p:nvGrpSpPr>\n' ' <p:grpSpPr/>\n' ' </p:spTree>\n' ' </p:cSld>\n' ' <p:clrMapOvr>\n' ' <a:masterClrMapping/>\n' ' </p:clrMapOvr>\n' '</p:notes>\n' % nsdecls('p', 'a', 'r'))
class CT_ChartSpace(BaseOxmlElement): """`c:chartSpace` root element of a chart part.""" _tag_seq = ( "c:date1904", "c:lang", "c:roundedCorners", "c:style", "c:clrMapOvr", "c:pivotSource", "c:protection", "c:chart", "c:spPr", "c:txPr", "c:externalData", "c:printSettings", "c:userShapes", "c:extLst", ) date1904 = ZeroOrOne("c:date1904", successors=_tag_seq[1:]) style = ZeroOrOne("c:style", successors=_tag_seq[4:]) chart = OneAndOnlyOne("c:chart") txPr = ZeroOrOne("c:txPr", successors=_tag_seq[10:]) externalData = ZeroOrOne("c:externalData", successors=_tag_seq[11:]) del _tag_seq @property def catAx_lst(self): return self.chart.plotArea.catAx_lst @property def date_1904(self): """ Return |True| if the `c:date1904` child element resolves truthy, |False| otherwise. This value indicates whether date number values are based on the 1900 or 1904 epoch. """ date1904 = self.date1904 if date1904 is None: return False return date1904.val @property def dateAx_lst(self): return self.xpath("c:chart/c:plotArea/c:dateAx") def get_or_add_title(self): """Return the `c:title` grandchild, newly created if not present.""" return self.chart.get_or_add_title() @property def plotArea(self): """ Return the required `c:chartSpace/c:chart/c:plotArea` grandchild element. """ return self.chart.plotArea @property def valAx_lst(self): return self.chart.plotArea.valAx_lst @property def xlsx_part_rId(self): """ The string in the required ``r:id`` attribute of the `<c:externalData>` child, or |None| if no externalData element is present. """ externalData = self.externalData if externalData is None: return None return externalData.rId def _add_externalData(self): """ Always add a ``<c:autoUpdate val="0"/>`` child so auto-updating behavior is off by default. """ externalData = self._new_externalData() externalData._add_autoUpdate(val=False) self._insert_externalData(externalData) return externalData def _new_txPr(self): return CT_TextBody.new_txPr()
class CT_Chart(BaseOxmlElement): """`c:chart` custom element class.""" _tag_seq = ( "c:title", "c:autoTitleDeleted", "c:pivotFmts", "c:view3D", "c:floor", "c:sideWall", "c:backWall", "c:plotArea", "c:legend", "c:plotVisOnly", "c:dispBlanksAs", "c:showDLblsOverMax", "c:extLst", ) title = ZeroOrOne("c:title", successors=_tag_seq[1:]) autoTitleDeleted = ZeroOrOne("c:autoTitleDeleted", successors=_tag_seq[2:]) plotArea = OneAndOnlyOne("c:plotArea") legend = ZeroOrOne("c:legend", successors=_tag_seq[9:]) rId = RequiredAttribute("r:id", XsdString) _chart_tmpl = '<c:chart %s %s r:id="%%s"/>' % (nsdecls("c"), nsdecls("r")) @property def has_legend(self): """ True if this chart has a legend defined, False otherwise. """ legend = self.legend if legend is None: return False return True @has_legend.setter def has_legend(self, bool_value): """ Add, remove, or leave alone the ``<c:legend>`` child element depending on current state and *bool_value*. If *bool_value* is |True| and no ``<c:legend>`` element is present, a new default element is added. When |False|, any existing legend element is removed. """ if bool(bool_value) is False: self._remove_legend() else: if self.legend is None: self._add_legend() @staticmethod def new_chart(rId): """ Return a new ``<c:chart>`` element """ xml = CT_Chart._chart_tmpl % (rId) chart = parse_xml(xml) return chart def _new_title(self): return CT_Title.new_title()
class CT_TextBody(BaseOxmlElement): """ ``<p:txBody>`` custom element class, also used for ``<c:txPr>`` in charts and perhaps other elements. """ bodyPr = OneAndOnlyOne('a:bodyPr') p = OneOrMore('a:p') @property def defRPr(self): """ ``<a:defRPr>`` element of required first ``p`` child, added with its ancestors if not present. Used when element is a ``<c:txPr>`` in a chart and the ``p`` element is used only to specify formatting, not content. """ p = self.p_lst[0] pPr = p.get_or_add_pPr() defRPr = pPr.get_or_add_defRPr() return defRPr @classmethod def new(cls): """ Return a new ``<p:txBody>`` element tree """ xml = cls._txBody_tmpl() txBody = parse_xml(xml) return txBody @classmethod def new_a_txBody(cls): """ Return a new ``<a:txBody>`` element tree, suitable for use in a table cell and possibly other situations. """ xml = cls._a_txBody_tmpl() txBody = parse_xml(xml) return txBody @classmethod def new_p_txBody(cls): """ Return a new ``<p:txBody>`` element tree, suitable for use in an ``<p:sp>`` element. """ xml = cls._p_txBody_tmpl() return parse_xml(xml) @classmethod def new_txPr(cls): """ Return a ``<c:txPr>`` element tree suitable for use in a chart object like data labels or tick labels. """ xml = ('<c:txPr %s>\n' ' <a:bodyPr/>\n' ' <a:lstStyle/>\n' ' <a:p>\n' ' <a:pPr>\n' ' <a:defRPr/>\n' ' </a:pPr>\n' ' </a:p>\n' '</c:txPr>\n') % nsdecls('c', 'a') txPr = parse_xml(xml) return txPr @classmethod def _a_txBody_tmpl(cls): return ('<a:txBody %s>\n' ' <a:bodyPr/>\n' ' <a:p/>\n' '</a:txBody>\n' % (nsdecls('a'))) @classmethod def _p_txBody_tmpl(cls): return ('<p:txBody %s>\n' ' <a:bodyPr/>\n' ' <a:p/>\n' '</p:txBody>\n' % (nsdecls('p', 'a'))) @classmethod def _txBody_tmpl(cls): return ('<p:txBody %s>\n' ' <a:bodyPr/>\n' ' <a:lstStyle/>\n' ' <a:p/>\n' '</p:txBody>\n' % (nsdecls('a', 'p')))
class CT_Shape(BaseShapeElement): """ ``<p:sp>`` custom element class """ nvSpPr = OneAndOnlyOne("p:nvSpPr") spPr = OneAndOnlyOne("p:spPr") txBody = ZeroOrOne("p:txBody", successors=("p:extLst", )) def add_path(self, w, h): """Reference to `a:custGeom` descendant or |None| if not present.""" custGeom = self.spPr.custGeom if custGeom is None: raise ValueError("shape must be freeform") pathLst = custGeom.get_or_add_pathLst() return pathLst.add_path(w=w, h=h) def get_or_add_ln(self): """ Return the <a:ln> grandchild element, newly added if not present. """ return self.spPr.get_or_add_ln() @property def has_custom_geometry(self): """True if this shape has custom geometry, i.e. is a freeform shape. A shape has custom geometry if it has a `p:spPr/a:custGeom` descendant (instead of `p:spPr/a:prstGeom`). """ return self.spPr.custGeom is not None @property def is_autoshape(self): """ True if this shape is an auto shape. A shape is an auto shape if it has a ``<a:prstGeom>`` element and does not have a txBox="1" attribute on cNvSpPr. """ prstGeom = self.prstGeom if prstGeom is None: return False if self.nvSpPr.cNvSpPr.txBox is True: return False return True @property def is_textbox(self): """ True if this shape is a text box. A shape is a text box if it has a ``txBox`` attribute on cNvSpPr that resolves to |True|. The default when the txBox attribute is missing is |False|. """ if self.nvSpPr.cNvSpPr.txBox is True: return True return False @property def ln(self): """ ``<a:ln>`` grand-child element or |None| if not present """ return self.spPr.ln @staticmethod def new_autoshape_sp(id_, name, prst, left, top, width, height): """ Return a new ``<p:sp>`` element tree configured as a base auto shape. """ tmpl = CT_Shape._autoshape_sp_tmpl() xml = tmpl % (id_, name, left, top, width, height, prst) sp = parse_xml(xml) return sp @staticmethod def new_freeform_sp(shape_id, name, x, y, cx, cy): """Return new `p:sp` element tree configured as freeform shape. The returned shape has a `a:custGeom` subtree but no paths in its path list. """ tmpl = CT_Shape._freeform_sp_tmpl() xml = tmpl % (shape_id, name, x, y, cx, cy) sp = parse_xml(xml) return sp @staticmethod def new_placeholder_sp(id_, name, ph_type, orient, sz, idx): """ Return a new ``<p:sp>`` element tree configured as a placeholder shape. """ tmpl = CT_Shape._ph_sp_tmpl() xml = tmpl % (id_, name) sp = parse_xml(xml) ph = sp.nvSpPr.nvPr.get_or_add_ph() ph.type = ph_type ph.idx = idx ph.orient = orient ph.sz = sz placeholder_types_that_have_a_text_frame = ( PP_PLACEHOLDER.TITLE, PP_PLACEHOLDER.CENTER_TITLE, PP_PLACEHOLDER.SUBTITLE, PP_PLACEHOLDER.BODY, PP_PLACEHOLDER.OBJECT, ) if ph_type in placeholder_types_that_have_a_text_frame: sp.append(CT_TextBody.new()) return sp @staticmethod def new_textbox_sp(id_, name, left, top, width, height): """ Return a new ``<p:sp>`` element tree configured as a base textbox shape. """ tmpl = CT_Shape._textbox_sp_tmpl() xml = tmpl % (id_, name, left, top, width, height) sp = parse_xml(xml) return sp @property def prst(self): """ Value of ``prst`` attribute of ``<a:prstGeom>`` element or |None| if not present. """ prstGeom = self.prstGeom if prstGeom is None: return None return prstGeom.prst @property def prstGeom(self): """ Reference to ``<a:prstGeom>`` child element or |None| if this shape doesn't have one, for example, if it's a placeholder shape. """ return self.spPr.prstGeom @staticmethod def _autoshape_sp_tmpl(): return ("<p:sp %s>\n" " <p:nvSpPr>\n" ' <p:cNvPr id="%s" name="%s"/>\n' " <p:cNvSpPr/>\n" " <p:nvPr/>\n" " </p:nvSpPr>\n" " <p:spPr>\n" " <a:xfrm>\n" ' <a:off x="%s" y="%s"/>\n' ' <a:ext cx="%s" cy="%s"/>\n' " </a:xfrm>\n" ' <a:prstGeom prst="%s">\n' " <a:avLst/>\n" " </a:prstGeom>\n" " </p:spPr>\n" " <p:style>\n" ' <a:lnRef idx="1">\n' ' <a:schemeClr val="accent1"/>\n' " </a:lnRef>\n" ' <a:fillRef idx="3">\n' ' <a:schemeClr val="accent1"/>\n' " </a:fillRef>\n" ' <a:effectRef idx="2">\n' ' <a:schemeClr val="accent1"/>\n' " </a:effectRef>\n" ' <a:fontRef idx="minor">\n' ' <a:schemeClr val="lt1"/>\n' " </a:fontRef>\n" " </p:style>\n" " <p:txBody>\n" ' <a:bodyPr rtlCol="0" anchor="ctr"/>\n' " <a:lstStyle/>\n" " <a:p>\n" ' <a:pPr algn="ctr"/>\n' " </a:p>\n" " </p:txBody>\n" "</p:sp>" % (nsdecls("a", "p"), "%d", "%s", "%d", "%d", "%d", "%d", "%s")) @staticmethod def _freeform_sp_tmpl(): return ("<p:sp %s>\n" " <p:nvSpPr>\n" ' <p:cNvPr id="%s" name="%s"/>\n' " <p:cNvSpPr/>\n" " <p:nvPr/>\n" " </p:nvSpPr>\n" " <p:spPr>\n" " <a:xfrm>\n" ' <a:off x="%s" y="%s"/>\n' ' <a:ext cx="%s" cy="%s"/>\n' " </a:xfrm>\n" " <a:custGeom>\n" " <a:avLst/>\n" " <a:gdLst/>\n" " <a:ahLst/>\n" " <a:cxnLst/>\n" ' <a:rect l="l" t="t" r="r" b="b"/>\n' " <a:pathLst/>\n" " </a:custGeom>\n" " </p:spPr>\n" " <p:style>\n" ' <a:lnRef idx="1">\n' ' <a:schemeClr val="accent1"/>\n' " </a:lnRef>\n" ' <a:fillRef idx="3">\n' ' <a:schemeClr val="accent1"/>\n' " </a:fillRef>\n" ' <a:effectRef idx="2">\n' ' <a:schemeClr val="accent1"/>\n' " </a:effectRef>\n" ' <a:fontRef idx="minor">\n' ' <a:schemeClr val="lt1"/>\n' " </a:fontRef>\n" " </p:style>\n" " <p:txBody>\n" ' <a:bodyPr rtlCol="0" anchor="ctr"/>\n' " <a:lstStyle/>\n" " <a:p>\n" ' <a:pPr algn="ctr"/>\n' " </a:p>\n" " </p:txBody>\n" "</p:sp>" % (nsdecls("a", "p"), "%d", "%s", "%d", "%d", "%d", "%d")) def _new_txBody(self): return CT_TextBody.new_p_txBody() @staticmethod def _ph_sp_tmpl(): return ("<p:sp %s>\n" " <p:nvSpPr>\n" ' <p:cNvPr id="%s" name="%s"/>\n' " <p:cNvSpPr>\n" ' <a:spLocks noGrp="1"/>\n' " </p:cNvSpPr>\n" " <p:nvPr/>\n" " </p:nvSpPr>\n" " <p:spPr/>\n" "</p:sp>" % (nsdecls("a", "p"), "%d", "%s")) @staticmethod def _textbox_sp_tmpl(): return ("<p:sp %s>\n" " <p:nvSpPr>\n" ' <p:cNvPr id="%s" name="%s"/>\n' ' <p:cNvSpPr txBox="1"/>\n' " <p:nvPr/>\n" " </p:nvSpPr>\n" " <p:spPr>\n" " <a:xfrm>\n" ' <a:off x="%s" y="%s"/>\n' ' <a:ext cx="%s" cy="%s"/>\n' " </a:xfrm>\n" ' <a:prstGeom prst="rect">\n' " <a:avLst/>\n" " </a:prstGeom>\n" " <a:noFill/>\n" " </p:spPr>\n" " <p:txBody>\n" ' <a:bodyPr wrap="none">\n' " <a:spAutoFit/>\n" " </a:bodyPr>\n" " <a:lstStyle/>\n" " <a:p/>\n" " </p:txBody>\n" "</p:sp>" % (nsdecls("a", "p"), "%d", "%s", "%d", "%d", "%d", "%d"))
class CT_Slide(_BaseSlideElement): """`p:sld` element, root element of a slide part (XML document).""" _tag_seq = ("p:cSld", "p:clrMapOvr", "p:transition", "p:timing", "p:extLst") cSld = OneAndOnlyOne("p:cSld") clrMapOvr = ZeroOrOne("p:clrMapOvr", successors=_tag_seq[2:]) timing = ZeroOrOne("p:timing", successors=_tag_seq[4:]) del _tag_seq @classmethod def new(cls): """Return new `p:sld` element configured as base slide shape.""" return parse_xml(cls._sld_xml()) @property def bg(self): """Return `p:bg` grandchild or None if not present.""" return self.cSld.bg def get_or_add_childTnLst(self): """Return parent element for a new `p:video` child element. The `p:video` element causes play controls to appear under a video shape (pic shape containing video). There can be more than one video shape on a slide, which causes the precondition to vary. It needs to handle the case when there is no `p:sld/p:timing` element and when that element already exists. If the case isn't simple, it just nukes what's there and adds a fresh one. This could theoretically remove desired existing timing information, but there isn't any evidence available to me one way or the other, so I've taken the simple approach. """ childTnLst = self._childTnLst if childTnLst is None: childTnLst = self._add_childTnLst() return childTnLst def _add_childTnLst(self): """Add `./p:timing/p:tnLst/p:par/p:cTn/p:childTnLst` descendant. Any existing `p:timing` child element is ruthlessly removed and replaced. """ self.remove(self.get_or_add_timing()) timing = parse_xml(self._childTnLst_timing_xml()) self._insert_timing(timing) return timing.xpath("./p:tnLst/p:par/p:cTn/p:childTnLst")[0] @property def _childTnLst(self): """Return `./p:timing/p:tnLst/p:par/p:cTn/p:childTnLst` descendant. Return None if that element is not present. """ childTnLsts = self.xpath("./p:timing/p:tnLst/p:par/p:cTn/p:childTnLst") if not childTnLsts: return None return childTnLsts[0] @staticmethod def _childTnLst_timing_xml(): return ( "<p:timing %s>\n" " <p:tnLst>\n" " <p:par>\n" ' <p:cTn id="1" dur="indefinite" restart="never" nodeType="' 'tmRoot">\n' " <p:childTnLst/>\n" " </p:cTn>\n" " </p:par>\n" " </p:tnLst>\n" "</p:timing>" % nsdecls("p") ) @staticmethod def _sld_xml(): return ( "<p:sld %s>\n" " <p:cSld>\n" " <p:spTree>\n" " <p:nvGrpSpPr>\n" ' <p:cNvPr id="1" name=""/>\n' " <p:cNvGrpSpPr/>\n" " <p:nvPr/>\n" " </p:nvGrpSpPr>\n" " <p:grpSpPr/>\n" " </p:spTree>\n" " </p:cSld>\n" " <p:clrMapOvr>\n" " <a:masterClrMapping/>\n" " </p:clrMapOvr>\n" "</p:sld>" % nsdecls("a", "p", "r") )
class CT_Table(BaseOxmlElement): """`a:tbl` custom element class""" _tag_seq = ("a:tblPr", "a:tblGrid", "a:tr") tblPr = ZeroOrOne("a:tblPr", successors=_tag_seq[1:]) tblGrid = OneAndOnlyOne("a:tblGrid") tr = ZeroOrMore("a:tr", successors=_tag_seq[3:]) del _tag_seq def add_tr(self, height): """ Return a reference to a newly created <a:tr> child element having its ``h`` attribute set to *height*. """ return self._add_tr(h=height) @property def bandCol(self): return self._get_boolean_property("bandCol") @bandCol.setter def bandCol(self, value): self._set_boolean_property("bandCol", value) @property def bandRow(self): return self._get_boolean_property("bandRow") @bandRow.setter def bandRow(self, value): self._set_boolean_property("bandRow", value) @property def firstCol(self): return self._get_boolean_property("firstCol") @firstCol.setter def firstCol(self, value): self._set_boolean_property("firstCol", value) @property def firstRow(self): return self._get_boolean_property("firstRow") @firstRow.setter def firstRow(self, value): self._set_boolean_property("firstRow", value) def iter_tcs(self): """Generate each `a:tc` element in this tbl. tc elements are generated left-to-right, top-to-bottom. """ return (tc for tr in self.tr_lst for tc in tr.tc_lst) @property def lastCol(self): return self._get_boolean_property("lastCol") @lastCol.setter def lastCol(self, value): self._set_boolean_property("lastCol", value) @property def lastRow(self): return self._get_boolean_property("lastRow") @lastRow.setter def lastRow(self, value): self._set_boolean_property("lastRow", value) @classmethod def new_tbl(cls, rows, cols, width, height, tableStyleId=None): """Return a new ``<p:tbl>`` element tree.""" # working hypothesis is this is the default table style GUID if tableStyleId is None: tableStyleId = "{5C22544A-7EE6-4342-B048-85BDC9FD1C3A}" xml = cls._tbl_tmpl() % (tableStyleId) tbl = parse_xml(xml) # add specified number of rows and columns rowheight = height // rows colwidth = width // cols for col in range(cols): # adjust width of last col to absorb any div error if col == cols - 1: colwidth = width - ((cols - 1) * colwidth) tbl.tblGrid.add_gridCol(width=colwidth) for row in range(rows): # adjust height of last row to absorb any div error if row == rows - 1: rowheight = height - ((rows - 1) * rowheight) tr = tbl.add_tr(height=rowheight) for col in range(cols): tr.add_tc() return tbl def tc(self, row_idx, col_idx): """Return `a:tc` element at *row_idx*, *col_idx*.""" return self.tr_lst[row_idx].tc_lst[col_idx] def _get_boolean_property(self, propname): """ Generalized getter for the boolean properties on the ``<a:tblPr>`` child element. Defaults to False if *propname* attribute is missing or ``<a:tblPr>`` element itself is not present. """ tblPr = self.tblPr if tblPr is None: return False propval = getattr(tblPr, propname) return {True: True, False: False, None: False}[propval] def _set_boolean_property(self, propname, value): """ Generalized setter for boolean properties on the ``<a:tblPr>`` child element, setting *propname* attribute appropriately based on *value*. If *value* is True, the attribute is set to "1"; a tblPr child element is added if necessary. If *value* is False, the *propname* attribute is removed if present, allowing its default value of False to be its effective value. """ if value not in (True, False): raise ValueError( "assigned value must be either True or False, got %s" % value ) tblPr = self.get_or_add_tblPr() setattr(tblPr, propname, value) @classmethod def _tbl_tmpl(cls): return ( "<a:tbl %s>\n" ' <a:tblPr firstRow="1" bandRow="1">\n' " <a:tableStyleId>%s</a:tableStyleId>\n" " </a:tblPr>\n" " <a:tblGrid/>\n" "</a:tbl>" % (nsdecls("a"), "%s") )
class CT_GroupShapeNonVisual(BaseShapeElement): """ ``<p:nvGrpSpPr>`` element. """ cNvPr = OneAndOnlyOne('p:cNvPr')
class CT_TextBody(BaseOxmlElement): """`p:txBody` custom element class. Also used for `c:txPr` in charts and perhaps other elements. """ bodyPr = OneAndOnlyOne("a:bodyPr") p = OneOrMore("a:p") def clear_content(self): """Remove all `a:p` children, but leave any others. cf. lxml `_Element.clear()` method which removes all children. """ for p in self.p_lst: self.remove(p) @property def defRPr(self): """ ``<a:defRPr>`` element of required first ``p`` child, added with its ancestors if not present. Used when element is a ``<c:txPr>`` in a chart and the ``p`` element is used only to specify formatting, not content. """ p = self.p_lst[0] pPr = p.get_or_add_pPr() defRPr = pPr.get_or_add_defRPr() return defRPr @property def is_empty(self): """True if only a single empty `a:p` element is present.""" ps = self.p_lst if len(ps) > 1: return False if not ps: raise InvalidXmlError("p:txBody must have at least one a:p") if ps[0].text != "": return False return True @classmethod def new(cls): """ Return a new ``<p:txBody>`` element tree """ xml = cls._txBody_tmpl() txBody = parse_xml(xml) return txBody @classmethod def new_a_txBody(cls): """ Return a new ``<a:txBody>`` element tree, suitable for use in a table cell and possibly other situations. """ xml = cls._a_txBody_tmpl() txBody = parse_xml(xml) return txBody @classmethod def new_p_txBody(cls): """ Return a new ``<p:txBody>`` element tree, suitable for use in an ``<p:sp>`` element. """ xml = cls._p_txBody_tmpl() return parse_xml(xml) @classmethod def new_txPr(cls): """ Return a ``<c:txPr>`` element tree suitable for use in a chart object like data labels or tick labels. """ xml = ("<c:txPr %s>\n" " <a:bodyPr/>\n" " <a:lstStyle/>\n" " <a:p>\n" " <a:pPr>\n" " <a:defRPr/>\n" " </a:pPr>\n" " </a:p>\n" "</c:txPr>\n") % nsdecls("c", "a") txPr = parse_xml(xml) return txPr def unclear_content(self): """Ensure p:txBody has at least one a:p child. Intuitively, reverse a ".clear_content()" operation to minimum conformance with spec (single empty paragraph). """ if len(self.p_lst) > 0: return self.add_p() @classmethod def _a_txBody_tmpl(cls): return ("<a:txBody %s>\n" " <a:bodyPr/>\n" " <a:p/>\n" "</a:txBody>\n" % (nsdecls("a"))) @classmethod def _p_txBody_tmpl(cls): return ("<p:txBody %s>\n" " <a:bodyPr/>\n" " <a:p/>\n" "</p:txBody>\n" % (nsdecls("p", "a"))) @classmethod def _txBody_tmpl(cls): return ("<p:txBody %s>\n" " <a:bodyPr/>\n" " <a:lstStyle/>\n" " <a:p/>\n" "</p:txBody>\n" % (nsdecls("a", "p")))
class CT_TLMediaNodeVideo(BaseOxmlElement): """`p:video` element, specifying video media details.""" _tag_seq = ("p:cMediaNode",) cMediaNode = OneAndOnlyOne("p:cMediaNode") del _tag_seq