def _notify_height_changed(self): """ Called by a row when its height changes, triggering the graphic frame to recalculate its total height (as the sum of the row heights). """ new_table_height = sum([row.height for row in self.rows]) self.__graphicFrame.xfrm[qn("a:ext")].set("cy", str(new_table_height))
def paragraphs(self): """ Immutable sequence of |_Paragraph| instances corresponding to the paragraphs in this text frame. A text frame always contains at least one paragraph. """ return tuple([_Paragraph(p) for p in self.__txBody[qn("a:p")]])
def _notify_height_changed(self): """ Called by a row when its height changes, triggering the graphic frame to recalculate its total height (as the sum of the row heights). """ new_table_height = sum([row.height for row in self.rows]) self.__graphicFrame.xfrm[qn('a:ext')].set('cy', str(new_table_height))
def paragraphs(self): """ Immutable sequence of |_Paragraph| instances corresponding to the paragraphs in this text frame. A text frame always contains at least one paragraph. """ return tuple([_Paragraph(p) for p in self.__txBody[qn('a:p')]])
def _notify_width_changed(self): """ Called by a column when its width changes, triggering the graphic frame to recalculate its total width (as the sum of the column widths). """ new_table_width = sum([col.width for col in self.columns]) self.__graphicFrame.xfrm[qn("a:ext")].set("cx", str(new_table_width))
def _notify_width_changed(self): """ Called by a column when its width changes, triggering the graphic frame to recalculate its total width (as the sum of the column widths). """ new_table_width = sum([col.width for col in self.columns]) self.__graphicFrame.xfrm[qn('a:ext')].set('cx', str(new_table_width))
def test_has_table_return_value(self): """CT_GraphicalObjectFrame.has_table property has correct value""" # setup ------------------------ id_, name = 9, "Table 8" left, top, width, height = 111, 222, 333, 444 tbl_uri = "http://schemas.openxmlformats.org/drawingml/2006/table" chart_uri = "http://schemas.openxmlformats.org/drawingml/2006/chart" graphicFrame = CT_GraphicalObjectFrame.new_graphicFrame(id_, name, left, top, width, height) graphicData = graphicFrame[qn("a:graphic")].graphicData # verify ----------------------- graphicData.set("uri", tbl_uri) assert_that(graphicFrame.has_table, is_(equal_to(True))) graphicData.set("uri", chart_uri) assert_that(graphicFrame.has_table, is_(equal_to(False)))
def __rewrite_sldIdLst(self): """ Rewrite the ``<p:sldIdLst>`` element in ``<p:presentation>`` to reflect current ordering of slide relationships and possible renumbering of ``rId`` values. """ sldIdLst = _child(self._element, 'p:sldIdLst', _nsmap) if sldIdLst is None: sldIdLst = self.__add_sldIdLst() sldIdLst.clear() sld_rels = self._relationships.rels_of_reltype(RT_SLIDE) for idx, rel in enumerate(sld_rels): sldId = _Element('p:sldId', _nsmap) sldIdLst.append(sldId) sldId.set('id', str(256+idx)) sldId.set(qn('r:id'), rel._rId)
def __rewrite_sldIdLst(self): """ Rewrite the ``<p:sldIdLst>`` element in ``<p:presentation>`` to reflect current ordering of slide relationships and possible renumbering of ``rId`` values. """ sldIdLst = _child(self._element, 'p:sldIdLst', _nsmap) if sldIdLst is None: sldIdLst = self.__add_sldIdLst() sldIdLst.clear() sld_rels = self._relationships.rels_of_reltype(RT_SLIDE) for idx, rel in enumerate(sld_rels): sldId = _Element('p:sldId', _nsmap) sldIdLst.append(sldId) sldId.set('id', str(256 + idx)) sldId.set(qn('r:id'), rel._rId)
def width(self): """ Read-only integer width of table in English Metric Units (EMU) """ return int(self.__graphicFrame.xfrm[qn("a:ext")].get("cx"))
def height(self): """ Read-only integer height of table in English Metric Units (EMU) """ return int(self.__graphicFrame.xfrm[qn("a:ext")].get("cy"))
def __init__(self, graphicFrame): super(_Table, self).__init__(graphicFrame) self.__graphicFrame = graphicFrame self.__tbl_elm = graphicFrame[qn("a:graphic")].graphicData.tbl self.__rows = _RowCollection(self.__tbl_elm, self) self.__columns = _ColumnCollection(self.__tbl_elm, self)
def width(self): """ Read-only integer width of table in English Metric Units (EMU) """ return int(self.__graphicFrame.xfrm[qn('a:ext')].get('cx'))
def height(self): """ Read-only integer height of table in English Metric Units (EMU) """ return int(self.__graphicFrame.xfrm[qn('a:ext')].get('cy'))
def __init__(self, graphicFrame): super(_Table, self).__init__(graphicFrame) self.__graphicFrame = graphicFrame self.__tbl_elm = graphicFrame[qn('a:graphic')].graphicData.tbl self.__rows = _RowCollection(self.__tbl_elm, self) self.__columns = _ColumnCollection(self.__tbl_elm, self)
class _ShapeCollection(_BaseShape, Collection): """ Sequence of shapes. Corresponds to CT_GroupShape in pml schema. Note that while spTree in a slide is a group shape, the group shape is recursive in that a group shape can include other group shapes within it. """ _NVGRPSPPR = qn('p:nvGrpSpPr') _GRPSPPR = qn('p:grpSpPr') _SP = qn('p:sp') _GRPSP = qn('p:grpSp') _GRAPHICFRAME = qn('p:graphicFrame') _CXNSP = qn('p:cxnSp') _PIC = qn('p:pic') _CONTENTPART = qn('p:contentPart') _EXTLST = qn('p:extLst') def __init__(self, spTree, slide=None): super(_ShapeCollection, self).__init__(spTree) self.__spTree = spTree self.__slide = slide self.__shapes = self._values # unmarshal shapes for elm in spTree.iterchildren(): if elm.tag in (self._NVGRPSPPR, self._GRPSPPR, self._EXTLST): continue elif elm.tag == self._SP: shape = _Shape(elm) elif elm.tag == self._PIC: shape = _Picture(elm) elif elm.tag == self._GRPSP: shape = _ShapeCollection(elm) elif elm.tag == self._GRAPHICFRAME: if elm.has_table: shape = _Table(elm) else: shape = _BaseShape(elm) elif elm.tag == self._CONTENTPART: msg = ("first time 'contentPart' shape encountered in the " "wild, please let developer know and send example") raise ValueError(msg) else: shape = _BaseShape(elm) self.__shapes.append(shape) @property def placeholders(self): """ Immutable sequence containing the placeholder shapes in this shape collection, sorted in *idx* order. """ placeholders =\ [_Placeholder(sp) for sp in self.__shapes if sp.is_placeholder] placeholders.sort(key=lambda ph: ph.idx) return tuple(placeholders) @property def title(self): """The title shape in collection or None if no title placeholder.""" for shape in self.__shapes: if shape._is_title: return shape return None def add_picture(self, file, left, top, width=None, height=None, z_idx=-1): """ Add picture shape displaying image in *file*, where *file* can be either a path to a file (a string) or a file-like object. """ image, rel = self.__slide._add_image(file) id = self.__next_shape_id name = 'Picture %d' % (id - 1) desc = image._desc rId = rel._rId width, height = image._scale(width, height) pic = CT_Picture.new_pic(id, name, desc, rId, left, top, width, height) idx = len(self.__shapes) if z_idx == -1 else z_idx # self.__spTree.append(pic) self.__spTree.insert(idx + 2, pic) picture = _Picture(pic) # self.__shapes.append(picture) self.__shapes.insert(idx, picture) return picture def add_shape(self, autoshape_type_id, left, top, width, height): """ Add auto shape of type specified by *autoshape_type_id* (like ``MSO.SHAPE_RECTANGLE``) and of specified size at specified position. """ autoshape_type = _AutoShapeType(autoshape_type_id) id_ = self.__next_shape_id name = '%s %d' % (autoshape_type.basename, id_ - 1) sp = CT_Shape.new_autoshape_sp(id_, name, autoshape_type.prst, left, top, width, height) shape = _Shape(sp) self.__spTree.append(sp) self.__shapes.append(shape) return shape def add_table(self, rows, cols, left, top, width, height): """ Add table shape with the specified number of *rows* and *cols* at the specified position with the specified size. *width* is evenly distributed between the *cols* columns of the new table. Likewise, *height* is evenly distributed between the *rows* rows created. """ id = self.__next_shape_id name = 'Table %d' % (id - 1) graphicFrame = CT_GraphicalObjectFrame.new_table( id, name, rows, cols, left, top, width, height) self.__spTree.append(graphicFrame) table = _Table(graphicFrame) self.__shapes.append(table) return table def add_textbox(self, left, top, width, height): """ Add text box shape of specified size at specified position. """ id_ = self.__next_shape_id name = 'TextBox %d' % (id_ - 1) sp = CT_Shape.new_textbox_sp(id_, name, left, top, width, height) shape = _Shape(sp) self.__spTree.append(sp) self.__shapes.append(shape) return shape def _clone_layout_placeholders(self, slidelayout): """ Add placeholder shapes based on those in *slidelayout*. Z-order of placeholders is preserved. Latent placeholders (date, slide number, and footer) are not cloned. """ latent_ph_types = (PH_TYPE_DT, PH_TYPE_SLDNUM, PH_TYPE_FTR) for sp in slidelayout.shapes: if not sp.is_placeholder: continue ph = _Placeholder(sp) if ph.type in latent_ph_types: continue self.__clone_layout_placeholder(ph) def __clone_layout_placeholder(self, layout_ph): """ Add a new placeholder shape based on the slide layout placeholder *layout_ph*. """ id_ = self.__next_shape_id ph_type = layout_ph.type orient = layout_ph.orient shapename = self.__next_ph_name(ph_type, id_, orient) sz = layout_ph.sz idx = layout_ph.idx sp = CT_Shape.new_placeholder_sp(id_, shapename, ph_type, orient, sz, idx) shape = _Shape(sp) self.__spTree.append(sp) self.__shapes.append(shape) return shape def __next_ph_name(self, ph_type, id, orient): """ Next unique placeholder name for placeholder shape of type *ph_type*, with id number *id* and orientation *orient*. Usually will be standard placeholder root name suffixed with id-1, e.g. __next_ph_name(PH_TYPE_TBL, 4, 'horz') ==> 'Table Placeholder 3'. The number is incremented as necessary to make the name unique within the collection. If *orient* is ``'vert'``, the placeholder name is prefixed with ``'Vertical '``. """ basename = slide_ph_basenames[ph_type] # prefix rootname with 'Vertical ' if orient is 'vert' if orient == PH_ORIENT_VERT: basename = 'Vertical %s' % basename # increment numpart as necessary to make name unique numpart = id - 1 names = self.__spTree.xpath('//p:cNvPr/@name', namespaces=_nsmap) while True: name = '%s %d' % (basename, numpart) if name not in names: break numpart += 1 return name @property def __next_shape_id(self): """ Next available drawing object id number in collection, starting from 1 and making use of any gaps in numbering. In practice, the minimum id is 2 because the spTree element is always assigned id="1". """ cNvPrs = self.__spTree.xpath('//p:cNvPr', namespaces=_nsmap) ids = [int(cNvPr.get('id')) for cNvPr in cNvPrs] ids.sort() # first gap in sequence wins, or falls off the end as max(ids)+1 next_id = 1 for id in ids: if id > next_id: break next_id += 1 return next_id