BHoM / PowerPoint_Toolkit

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

Add multiple features to enhance presentation production #15

Closed IsakNaslundBh closed 1 week ago

IsakNaslundBh commented 1 month ago

Description:

Tom-Kingstone commented 1 month 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

IsakNaslundBh commented 1 month 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

Sounds like a really good idea @Tom-Kingstone . Not sure I will have time to fix in the current push I am doing though, so please, if you dont mid, think great if you can raise a separate issue for this :)