"""Custom element classes for presentation-related XML elements.""" from __future__ import annotations from typing import TYPE_CHECKING, Callable, cast from pptx.oxml.simpletypes import ST_SlideId, ST_SlideSizeCoordinate, XsdString from pptx.oxml.xmlchemy import BaseOxmlElement, RequiredAttribute, ZeroOrMore, ZeroOrOne if TYPE_CHECKING: from pptx.util import Length class CT_Presentation(BaseOxmlElement): """`p:presentation` element, root of the Presentation part stored as `/ppt/presentation.xml`.""" get_or_add_sldSz: Callable[[], CT_SlideSize] get_or_add_sldIdLst: Callable[[], CT_SlideIdList] get_or_add_sldMasterIdLst: Callable[[], CT_SlideMasterIdList] sldMasterIdLst: CT_SlideMasterIdList | None = ( ZeroOrOne( # pyright: ignore[reportAssignmentType] "p:sldMasterIdLst", successors=( "p:notesMasterIdLst", "p:handoutMasterIdLst", "p:sldIdLst", "p:sldSz", "p:notesSz", ), ) ) sldIdLst: CT_SlideIdList | None = ZeroOrOne( # pyright: ignore[reportAssignmentType] "p:sldIdLst", successors=("p:sldSz", "p:notesSz") ) sldSz: CT_SlideSize | None = ZeroOrOne( # pyright: ignore[reportAssignmentType] "p:sldSz", successors=("p:notesSz",) ) class CT_SlideId(BaseOxmlElement): """`p:sldId` element. Direct child of `p:sldIdLst` that contains an `rId` reference to a slide in the presentation. """ id: int = RequiredAttribute("id", ST_SlideId) # pyright: ignore[reportAssignmentType] rId: str = RequiredAttribute("r:id", XsdString) # pyright: ignore[reportAssignmentType] class CT_SlideIdList(BaseOxmlElement): """`p:sldIdLst` element. Direct child of that contains a list of the slide parts in the presentation. """ sldId_lst: list[CT_SlideId] _add_sldId: Callable[..., CT_SlideId] sldId = ZeroOrMore("p:sldId") def add_sldId(self, rId: str) -> CT_SlideId: """Create and return a reference to a new `p:sldId` child element. The new `p:sldId` element has its r:id attribute set to `rId`. """ return self._add_sldId(id=self._next_id, rId=rId) @property def _next_id(self) -> int: """The next available slide ID as an `int`. Valid slide IDs start at 256. The next integer value greater than the max value in use is chosen, which minimizes that chance of reusing the id of a deleted slide. """ MIN_SLIDE_ID = 256 MAX_SLIDE_ID = 2147483647 used_ids = [int(s) for s in cast("list[str]", self.xpath("./p:sldId/@id"))] simple_next = max([MIN_SLIDE_ID - 1] + used_ids) + 1 if simple_next <= MAX_SLIDE_ID: return simple_next # -- fall back to search for next unused from bottom -- valid_used_ids = sorted(id for id in used_ids if (MIN_SLIDE_ID <= id <= MAX_SLIDE_ID)) return ( next( candidate_id for candidate_id, used_id in enumerate(valid_used_ids, start=MIN_SLIDE_ID) if candidate_id != used_id ) if valid_used_ids else 256 ) class CT_SlideMasterIdList(BaseOxmlElement): """`p:sldMasterIdLst` element. Child of `p:presentation` containing references to the slide masters that belong to the presentation. """ sldMasterId_lst: list[CT_SlideMasterIdListEntry] sldMasterId = ZeroOrMore("p:sldMasterId") class CT_SlideMasterIdListEntry(BaseOxmlElement): """ ```` element, child of ```` containing a reference to a slide master. """ rId: str = RequiredAttribute("r:id", XsdString) # pyright: ignore[reportAssignmentType] class CT_SlideSize(BaseOxmlElement): """`p:sldSz` element. Direct child of that contains the width and height of slides in the presentation. """ cx: Length = RequiredAttribute( # pyright: ignore[reportAssignmentType] "cx", ST_SlideSizeCoordinate ) cy: Length = RequiredAttribute( # pyright: ignore[reportAssignmentType] "cy", ST_SlideSizeCoordinate )