BHoM / PowerPoint_Toolkit

GNU Lesser General Public License v3.0
0 stars 0 forks source link

Create new slides from slide master layout #16

Open Tom-Kingstone opened 3 months ago

Tom-Kingstone commented 3 months ago

I think it would also be valuable to be able to create a new slide from a slide master layout, and to be able to replace shapes with pictures as well (as picture placeholders are defined as Shape in the ShapeTree). I have a bit of code here that creates new slides from the master layout:

        public static void CreateNewSlideFromLayout(PresentationPart presentationPart, SlideAddCommand command)
        {
            Slide slide = new Slide();
            SlidePart slidePart = presentationPart.AddNewPart<SlidePart>();
            slide.Save(slidePart);

            SlideMasterPart slideMasterPart = presentationPart.SlideMasterParts.FirstOrDefault();
            SlideLayoutPart slideLayoutPart = slideMasterPart.SlideLayoutParts.SingleOrDefault(sl => sl.SlideLayout.CommonSlideData.Name.Value.Equals(command.LayoutName, StringComparison.OrdinalIgnoreCase));

            slidePart.AddPart(slideLayoutPart, slideMasterPart.GetIdOfPart(slideLayoutPart));
            slidePart.Slide.CommonSlideData = (CommonSlideData)slideLayoutPart.SlideLayout.CommonSlideData.Clone();

            string id = slideMasterPart.GetIdOfPart(slideLayoutPart);

            slideMasterPart.AddPart(slideLayoutPart, id);
            presentationPart.SetSlideID(slidePart, command.SlideNumber);
        }

Where SetSlideID is the following:

private static void SetSlideID(this PresentationPart presentationPart, SlidePart slidePart, int position = -1)
{
    SlideIdList slideIdList = presentationPart.Presentation.SlideIdList;
    if (slideIdList == null)
    {
        slideIdList = new SlideIdList();
        presentationPart.Presentation.SlideIdList = slideIdList;
    }

    if (position >= slideIdList.Count())
        throw new InvalidOperationException($"Unable to set slide to position '{position}'. There are only '{slideIdList.Count()}' slides.");

    uint newId = slideIdList.ChildElements.Count() == 0 ? 256 : slideIdList.GetMaxSlideId() + 1;
    if (position < 0)
    {
        var newSlideId = slideIdList.AppendChild(new SlideId());
        newSlideId.Id = newId;
        newSlideId.RelationshipId = presentationPart.GetIdOfPart(slidePart);
    }
    else if (slideIdList.Count() == 0)
    {
        var newSlideId = slideIdList.AppendChild(new SlideId());
        newSlideId.Id = newId;
        newSlideId.RelationshipId = presentationPart.GetIdOfPart(slidePart);
    }
    else
    {
        SlideId nextSlideId = (SlideId)slideIdList.ChildElements[position];
        var newSlideId = slideIdList.InsertBefore(new SlideId(), nextSlideId);
        newSlideId.Id = newId;
        newSlideId.RelationshipId = presentationPart.GetIdOfPart(slidePart);
    }
}

private static uint GetMaxSlideId(this SlideIdList slideIdList)
{
    uint maxSlideId = 0;
    if (slideIdList.ChildElements.Count() > 0)
        maxSlideId = slideIdList.ChildElements
            .Cast<SlideId>()
            .Max(x => x.Id.Value);
    return maxSlideId;
}

It needs a bit of tidying up (I think setting slide ID could be done better), but it's a good start

_Originally posted by @Tom-Kingstone in https://github.com/BHoM/PowerPoint_Toolkit/issues/15#issuecomment-2167416276_

Tom-Kingstone commented 3 months ago

@jamesramsden-bh suggested an extra layer of abstraction that would allow a user to use the template file to create slides without having to know the names of every element in the layouts. This would template the 11 default office theme slide layouts.

The original intention of the functionality would remain so that users can use custom slide masters.