mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-11-04 18:47:21 +00:00
78 lines
3.8 KiB
C#
78 lines
3.8 KiB
C#
using DocumentFormat.OpenXml;
|
|||
|
|
|
||
|
|
using A = DocumentFormat.OpenXml.Drawing;
|
||
|
|
using P = DocumentFormat.OpenXml.Presentation;
|
||
|
|
|
||
|
|
namespace AIStudio.Tools.PowerPoint;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Which shapes of a slide fill which slots of its layout.
|
||
|
|
/// </summary>
|
||
|
|
/// <remarks>
|
||
|
|
/// Reading a template and editing one of its slides ask the same question, so they share the answer:
|
||
|
|
/// what the model is told a slot holds is what a new content replaces.
|
||
|
|
/// </remarks>
|
||
|
|
internal static class TemplateSlideShapes
|
||
|
|
{
|
||
|
|
/// <summary>
|
||
|
|
/// Finds the shapes of a slide which fill the slots of its layout.
|
||
|
|
/// </summary>
|
||
|
|
/// <remarks>
|
||
|
|
/// A placeholder fills the slot of its type and index; of two placeholders for one slot, the
|
||
|
|
/// first counts, while the second may be read as a copy of the slot, as a text box copied from
|
||
|
|
/// the placeholder is. A table slot whose placeholder holds no table, or which the slide leaves out,
|
||
|
|
/// takes a table which is no placeholder at all: an author who pastes a table onto the slide,
|
||
|
|
/// or whose table lost the link to its placeholder on the way, still means it as the table of
|
||
|
|
/// the slide. Such tables fill these table slots in the order of the slide.
|
||
|
|
/// </remarks>
|
||
|
|
/// <param name="shapeTree">The shape tree of the slide.</param>
|
||
|
|
/// <param name="layout">The layout the slide is based on.</param>
|
||
|
|
/// <returns>The top-level shape filling each slot; slots the slide leaves out are missing.</returns>
|
||
|
|
public static Dictionary<TemplateSlot, OpenXmlElement> SlotShapesOf(P.ShapeTree? shapeTree, TemplateLayout layout)
|
||
|
|
{
|
||
|
|
var elements = shapeTree?.Elements().ToList() ?? [];
|
||
|
|
var shapesBySlot = new Dictionary<TemplateSlot, OpenXmlElement>();
|
||
|
|
foreach (var element in elements)
|
||
|
|
{
|
||
|
|
if (PlaceholderOf(element) is { } placeholder && layout.SlotOf(placeholder.Type?.InnerText ?? "obj", placeholder.Index?.Value) is { } slot)
|
||
|
|
shapesBySlot.TryAdd(slot, element);
|
||
|
|
}
|
||
|
|
|
||
|
|
var freeTables = new Queue<OpenXmlElement>(elements.Where(element => PlaceholderOf(element) is null && HoldsTable(element)));
|
||
|
|
foreach (var slot in layout.Slots.Where(slot => slot.Role is PlaceholderRole.TABLE && !(shapesBySlot.GetValueOrDefault(slot) is { } shape && HoldsTable(shape))))
|
||
|
|
{
|
||
|
|
if (!freeTables.TryDequeue(out var table))
|
||
|
|
break;
|
||
|
|
|
||
|
|
shapesBySlot[slot] = table;
|
||
|
|
}
|
||
|
|
|
||
|
|
return shapesBySlot;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static bool HoldsTable(OpenXmlElement element) => element is P.GraphicFrame frame && frame.Graphic?.GraphicData?.GetFirstChild<A.Table>() is not null;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// The ID of a top-level element of a slide: a shape, a picture, a graphic frame, a group, a
|
||
|
|
/// connector, or something wrapped for newer versions of PowerPoint.
|
||
|
|
/// </summary>
|
||
|
|
/// <returns>The ID, or null for anything else, e.g., the properties of the shape tree itself.</returns>
|
||
|
|
public static uint? ShapeIdOf(OpenXmlElement element) => element switch
|
||
|
|
{
|
||
|
|
P.Shape or P.Picture or P.GraphicFrame or P.GroupShape or P.ConnectionShape or AlternateContent => element.Descendants<P.NonVisualDrawingProperties>().FirstOrDefault()?.Id?.Value,
|
||
|
|
|
||
|
|
_ => null,
|
||
|
|
};
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// The placeholder a shape, a picture or a table of a slide fills; null for anything else.
|
||
|
|
/// </summary>
|
||
|
|
public static P.PlaceholderShape? PlaceholderOf(OpenXmlElement element) => element switch
|
||
|
|
{
|
||
|
|
P.Shape shape => shape.NonVisualShapeProperties?.ApplicationNonVisualDrawingProperties?.PlaceholderShape,
|
||
|
|
P.Picture picture => picture.NonVisualPictureProperties?.ApplicationNonVisualDrawingProperties?.PlaceholderShape,
|
||
|
|
P.GraphicFrame frame => frame.NonVisualGraphicFrameProperties?.ApplicationNonVisualDrawingProperties?.PlaceholderShape,
|
||
|
|
|
||
|
|
_ => null,
|
||
|
|
};
|
||
|
|
}
|