namespace QWERTYkez.WordProcessor;
internal static class ReplaceToTableExt
{
///
/// Заменяет параграф на таблицу, созданную с помощью TableBuilder
///
internal static void ReplaceWithTableBuilder(Paragraph paragraph, Action buildTable, FontProps? baseFont)
{
if (paragraph is null || paragraph.Parent is null || buildTable is null)
return;
var parent = paragraph.Parent;
// 1. Строим таблицу
var builder = TableBuilder.Create(baseFont);
buildTable(builder);
var table = builder.Build();
// 2. Находим индекс параграфа
int paraIndex = -1;
var children = parent.ChildElements;
for (int i = 0; i < children.Count; i++)
{
if (children[i] == paragraph) { paraIndex = i; break; }
}
if (paraIndex == -1) return;
// 3. PageBreakBefore должен сработать ДО таблицы, поэтому снимаем
// его с параграфа и выносим в отдельный пустой параграф-маркер.
bool hasPageBreakBefore = false;
if (paragraph.ParagraphProperties?.GetFirstChild() is { } pbb)
{
hasPageBreakBefore = true;
pbb.Remove();
}
int insertAt = paraIndex;
if (hasPageBreakBefore)
{
var pbbPara = new Paragraph(new ParagraphProperties(new PageBreakBefore()));
parent.InsertAt(pbbPara, insertAt);
insertAt++;
}
// 4. Вставляем таблицу — параграф при этом сдвигается на +1.
// Ссылка на paragraph остаётся валидной.
parent.InsertAt(table, insertAt);
// 5. Чистим содержимое параграфа: pPr остаётся, текст — удаляется,
// run-ы с — сохраняются (с отрезанным текстом).
ClearParagraphContent(paragraph);
}
// ============================================================
// Очистка содержимого параграфа с сохранением «полезных» элементов.
// ============================================================
private static void ClearParagraphContent(Paragraph paragraph)
{
var toRemove = new List();
foreach (var child in paragraph.ChildElements)
{
if (child is ParagraphProperties) continue;
toRemove.Add(child);
}
foreach (var child in toRemove)
{
// Run, содержащий page/column break — оставляем, но убираем из него весь текст.
if (child is Run run && run.Elements().Any())
{
foreach (var t in run.Elements().ToList()) t.Remove();
foreach (var other in run.ChildElements.ToList())
{
if (other is Break || other is RunProperties) continue;
other.Remove();
}
continue;
}
child.Remove();
}
// Если pPr стал пустым — тоже удаляем, чтобы не оставлять мусор.
if (paragraph.ParagraphProperties is { } ppr && !ppr.ChildElements.Any())
ppr.Remove();
// Если параграф теперь полностью пуст (нет ни Runs, ни pPr) — убираем его.
if (!paragraph.ChildElements.Any())
paragraph.Remove();
}
///
/// Заменяет все параграфы, содержащие указанный текст, на таблицы
///
internal static void ReplaceParagraphsContainingTextToTable(Body body,
string oldValue, Action buildTable, FontProps? baseFont = null)
{
if (body is null || string.IsNullOrEmpty(oldValue) || buildTable is null)
return;
var paragraphs = body.Elements().ToList();
if (paragraphs.Count == 0)
return;
for (int i = paragraphs.Count - 1; i >= 0; i--)
{
var paragraph = paragraphs[i];
if (paragraph is null) continue;
var paraText = paragraph.InnerText;
if (string.IsNullOrEmpty(paraText) ||
paraText.IndexOf(oldValue, StringComparison.OrdinalIgnoreCase) < 0)
continue;
// Извлекаем свойства шрифта для передачи в TableBuilder
var fontProps = paragraph.ExtractFontProps(oldValue);
if (fontProps is { } props)
fontProps = props.Override(baseFont);
// Заменяем параграф на таблицу
ReplaceWithTableBuilder(paragraph, buildTable, fontProps);
}
}
}