777
This commit is contained in:
@@ -180,7 +180,6 @@ internal static class MultiReplaceExt
|
|||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Клонирует параграф, удаляя все SectionProperties и PageBreakBefore.</summary>
|
|
||||||
private static Paragraph CloneParagraphWithoutSection(Paragraph original)
|
private static Paragraph CloneParagraphWithoutSection(Paragraph original)
|
||||||
{
|
{
|
||||||
var newPara = new Paragraph();
|
var newPara = new Paragraph();
|
||||||
@@ -367,13 +366,12 @@ internal static class MultiReplaceExt
|
|||||||
if (!(sourceIsLandscape && sectionChangeInsideGroup && lastIsPortrait))
|
if (!(sourceIsLandscape && sectionChangeInsideGroup && lastIsPortrait))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
foreach (var bodySec in body.Elements<SectionProperties>())
|
// Удаляем все существующие секции из Body
|
||||||
{
|
var existingSections = body.Elements<SectionProperties>().ToList();
|
||||||
var ps = bodySec.GetFirstChild<PageSize>();
|
foreach (var sec in existingSections)
|
||||||
if (ps is not null && ps.Orient?.Value == PageOrientationValues.Landscape)
|
sec.Remove();
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Создаём новую landscape секцию для Body
|
||||||
var bodySection = new SectionProperties();
|
var bodySection = new SectionProperties();
|
||||||
var pageSizeClone = (PageSize)sourcePageSize.CloneNode(true);
|
var pageSizeClone = (PageSize)sourcePageSize.CloneNode(true);
|
||||||
if (pageSizeClone.Orient?.Value != PageOrientationValues.Landscape)
|
if (pageSizeClone.Orient?.Value != PageOrientationValues.Landscape)
|
||||||
@@ -404,7 +402,6 @@ internal static class MultiReplaceExt
|
|||||||
|
|
||||||
// ---------- ОСНОВНОЙ АЛГОРИТМ ----------
|
// ---------- ОСНОВНОЙ АЛГОРИТМ ----------
|
||||||
|
|
||||||
/// <summary>Основной алгоритм множественной замены с поддержкой разрывов и смены ориентации.</summary>
|
|
||||||
private static List<Paragraph>? ProcessMultiReplacements(
|
private static List<Paragraph>? ProcessMultiReplacements(
|
||||||
Paragraph original,
|
Paragraph original,
|
||||||
IEnumerable<KeyValuePair<string, IEnumerable<string>>>? stringReplacements,
|
IEnumerable<KeyValuePair<string, IEnumerable<string>>>? stringReplacements,
|
||||||
@@ -424,6 +421,22 @@ internal static class MultiReplaceExt
|
|||||||
prevPara = prevPara.PreviousSibling<Paragraph>();
|
prevPara = prevPara.PreviousSibling<Paragraph>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Определяем секцию, которая следует за original (если у original нет секции)
|
||||||
|
SectionProperties? followingSection = null;
|
||||||
|
if (original.ParagraphProperties?.GetFirstChild<SectionProperties>()?.CloneNode(true) is not SectionProperties sourceSection)
|
||||||
|
{
|
||||||
|
var nextPara = original.NextSibling<Paragraph>();
|
||||||
|
if (nextPara is not null)
|
||||||
|
{
|
||||||
|
followingSection = nextPara.ParagraphProperties?.GetFirstChild<SectionProperties>()?.CloneNode(true) as SectionProperties;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
followingSection = sourceSection;
|
||||||
|
}
|
||||||
|
followingSection ??= new SectionProperties();
|
||||||
|
|
||||||
// 1. Сбор определений
|
// 1. Сбор определений
|
||||||
var definitions = new List<MatchDefinition>();
|
var definitions = new List<MatchDefinition>();
|
||||||
if (stringReplacements is not null)
|
if (stringReplacements is not null)
|
||||||
@@ -471,14 +484,7 @@ internal static class MultiReplaceExt
|
|||||||
if (matches.Count == 0) return null;
|
if (matches.Count == 0) return null;
|
||||||
matches.Sort((a, b) => a.Start.CompareTo(b.Start));
|
matches.Sort((a, b) => a.Start.CompareTo(b.Start));
|
||||||
|
|
||||||
// 4. Получаем исходную секцию для копирования (из original или из документа)
|
// 4. Получаем книжную секцию для копирования полей (из документа)
|
||||||
SectionProperties? sourceSection = original.ParagraphProperties?.GetFirstChild<SectionProperties>()?.CloneNode(true) as SectionProperties;
|
|
||||||
if (sourceSection is null && body is not null)
|
|
||||||
{
|
|
||||||
sourceSection = body.Elements<SectionProperties>().LastOrDefault()?.CloneNode(true) as SectionProperties;
|
|
||||||
}
|
|
||||||
sourceSection ??= new SectionProperties();
|
|
||||||
|
|
||||||
SectionProperties? portraitSection = null;
|
SectionProperties? portraitSection = null;
|
||||||
if (body is not null)
|
if (body is not null)
|
||||||
{
|
{
|
||||||
@@ -539,6 +545,29 @@ internal static class MultiReplaceExt
|
|||||||
var values = match.Definition.Values.ToList();
|
var values = match.Definition.Values.ToList();
|
||||||
if (values.Count == 0) continue;
|
if (values.Count == 0) continue;
|
||||||
|
|
||||||
|
// Если это простая замена текста (один элемент и это текст без маркеров),
|
||||||
|
// заменяем текст внутри параграфа, сохраняя все остальные элементы
|
||||||
|
if (values.Count == 1 && !string.IsNullOrEmpty(values[0].Text) && !values[0].BreakValue.HasValue)
|
||||||
|
{
|
||||||
|
// Простая замена текста в текущем параграфе
|
||||||
|
var newText = values[0].Text;
|
||||||
|
// Находим сегмент с совпадением
|
||||||
|
var matchSeg = structure.Segments.FirstOrDefault(s => s.Start >= match.Start && s.End <= match.End);
|
||||||
|
if (matchSeg is not null)
|
||||||
|
{
|
||||||
|
// Заменяем текст в Run
|
||||||
|
var run = matchSeg.Run;
|
||||||
|
// Удаляем все Text элементы
|
||||||
|
foreach (var textElem in run.Elements<Text>().ToList())
|
||||||
|
textElem.Remove();
|
||||||
|
// Добавляем новый Text
|
||||||
|
run.AppendChild(new Text(newText));
|
||||||
|
// Возвращаем null, чтобы не заменять параграф
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// Если не нашли сегмент, продолжаем обычную обработку
|
||||||
|
}
|
||||||
|
|
||||||
// Сбрасываем флаги для новой группы
|
// Сбрасываем флаги для новой группы
|
||||||
pageBreakBeforeNext = false;
|
pageBreakBeforeNext = false;
|
||||||
pendingOrientation = null;
|
pendingOrientation = null;
|
||||||
@@ -563,7 +592,7 @@ internal static class MultiReplaceExt
|
|||||||
original,
|
original,
|
||||||
structure,
|
structure,
|
||||||
match.Start,
|
match.Start,
|
||||||
sourceSection,
|
followingSection,
|
||||||
portraitSection,
|
portraitSection,
|
||||||
resultParas);
|
resultParas);
|
||||||
}
|
}
|
||||||
@@ -582,7 +611,7 @@ internal static class MultiReplaceExt
|
|||||||
ref emptyParagraphCreated,
|
ref emptyParagraphCreated,
|
||||||
hasEmptyParagraphsBefore,
|
hasEmptyParagraphsBefore,
|
||||||
original,
|
original,
|
||||||
sourceSection,
|
followingSection,
|
||||||
portraitSection,
|
portraitSection,
|
||||||
resultParas);
|
resultParas);
|
||||||
}
|
}
|
||||||
@@ -594,26 +623,26 @@ internal static class MultiReplaceExt
|
|||||||
if (currentPara.ParagraphProperties?.GetFirstChild<SectionProperties>() is null)
|
if (currentPara.ParagraphProperties?.GetFirstChild<SectionProperties>() is null)
|
||||||
{
|
{
|
||||||
bool addPageSize = (lastOrientation.Value == BreakType.NewLandscapeSection);
|
bool addPageSize = (lastOrientation.Value == BreakType.NewLandscapeSection);
|
||||||
AddSectionProperties(currentPara, lastOrientation.Value, addPageSize, sourceSection, portraitSection);
|
AddSectionProperties(currentPara, lastOrientation.Value, addPageSize, followingSection, portraitSection);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Если внутри группы не было смены, но есть sourceSection с PageSize,
|
// Если внутри группы не было смены, но есть followingSection с PageSize,
|
||||||
// копируем её в последний параграф группы (если он не имеет секции)
|
// копируем её в последний параграф группы (если он не имеет секции)
|
||||||
if (!sectionChangeInsideGroup && currentPara is not null)
|
if (!sectionChangeInsideGroup && currentPara is not null)
|
||||||
{
|
{
|
||||||
var sourcePageSize = sourceSection.GetFirstChild<PageSize>();
|
var sourcePageSize = followingSection.GetFirstChild<PageSize>();
|
||||||
if (sourcePageSize is not null)
|
if (sourcePageSize is not null)
|
||||||
{
|
{
|
||||||
if (currentPara.ParagraphProperties?.GetFirstChild<SectionProperties>() is null)
|
if (currentPara.ParagraphProperties?.GetFirstChild<SectionProperties>() is null)
|
||||||
{
|
{
|
||||||
currentPara.ParagraphProperties ??= new ParagraphProperties();
|
currentPara.ParagraphProperties ??= new ParagraphProperties();
|
||||||
currentPara.ParagraphProperties.AppendChild(sourceSection.CloneNode(true));
|
currentPara.ParagraphProperties.AppendChild(followingSection.CloneNode(true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EnsureBodyLandscapeSection(body!, sourceSection, sectionChangeInsideGroup, lastOrientation);
|
EnsureBodyLandscapeSection(body!, followingSection, sectionChangeInsideGroup, lastOrientation);
|
||||||
|
|
||||||
currentPos = match.End;
|
currentPos = match.End;
|
||||||
}
|
}
|
||||||
@@ -630,7 +659,7 @@ internal static class MultiReplaceExt
|
|||||||
var breakRun = new Run(new Break { Type = BreakValues.Page });
|
var breakRun = new Run(new Break { Type = BreakValues.Page });
|
||||||
remainderPara.InsertAt(breakRun, 0);
|
remainderPara.InsertAt(breakRun, 0);
|
||||||
bool addPageSize = (pendingOrientation.Value == BreakType.NewLandscapeSection);
|
bool addPageSize = (pendingOrientation.Value == BreakType.NewLandscapeSection);
|
||||||
AddSectionProperties(remainderPara, pendingOrientation.Value, addPageSize, sourceSection, portraitSection);
|
AddSectionProperties(remainderPara, pendingOrientation.Value, addPageSize, followingSection, portraitSection);
|
||||||
pendingOrientation = null;
|
pendingOrientation = null;
|
||||||
}
|
}
|
||||||
else if (sectionChangeInsideGroup && lastOrientation.HasValue)
|
else if (sectionChangeInsideGroup && lastOrientation.HasValue)
|
||||||
@@ -638,16 +667,16 @@ internal static class MultiReplaceExt
|
|||||||
var breakRun = new Run(new Break { Type = BreakValues.Page });
|
var breakRun = new Run(new Break { Type = BreakValues.Page });
|
||||||
remainderPara.InsertAt(breakRun, 0);
|
remainderPara.InsertAt(breakRun, 0);
|
||||||
bool addPageSize = (lastOrientation.Value == BreakType.NewLandscapeSection);
|
bool addPageSize = (lastOrientation.Value == BreakType.NewLandscapeSection);
|
||||||
AddSectionProperties(remainderPara, lastOrientation.Value, addPageSize, sourceSection, portraitSection);
|
AddSectionProperties(remainderPara, lastOrientation.Value, addPageSize, followingSection, portraitSection);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Если нет смены, но есть sourceSection с PageSize, копируем её в остаток
|
// Если нет смены, но есть followingSection с PageSize, копируем её в остаток
|
||||||
var sourcePageSize = sourceSection.GetFirstChild<PageSize>();
|
var sourcePageSize = followingSection.GetFirstChild<PageSize>();
|
||||||
if (sourcePageSize is not null)
|
if (sourcePageSize is not null)
|
||||||
{
|
{
|
||||||
remainderPara.ParagraphProperties ??= new ParagraphProperties();
|
remainderPara.ParagraphProperties ??= new ParagraphProperties();
|
||||||
remainderPara.ParagraphProperties.AppendChild(sourceSection.CloneNode(true));
|
remainderPara.ParagraphProperties.AppendChild(followingSection.CloneNode(true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
resultParas.Add(remainderPara);
|
resultParas.Add(remainderPara);
|
||||||
@@ -679,7 +708,7 @@ internal static class MultiReplaceExt
|
|||||||
Paragraph original,
|
Paragraph original,
|
||||||
ParagraphStructure structure,
|
ParagraphStructure structure,
|
||||||
int position,
|
int position,
|
||||||
SectionProperties sourceSection,
|
SectionProperties followingSection,
|
||||||
SectionProperties portraitSection,
|
SectionProperties portraitSection,
|
||||||
List<Paragraph> resultParas)
|
List<Paragraph> resultParas)
|
||||||
{
|
{
|
||||||
@@ -690,7 +719,7 @@ internal static class MultiReplaceExt
|
|||||||
currentPara = newPara;
|
currentPara = newPara;
|
||||||
|
|
||||||
bool addPageSize = (pendingOrientation.Value == BreakType.NewLandscapeSection);
|
bool addPageSize = (pendingOrientation.Value == BreakType.NewLandscapeSection);
|
||||||
AddSectionProperties(currentPara, pendingOrientation.Value, addPageSize, sourceSection, portraitSection);
|
AddSectionProperties(currentPara, pendingOrientation.Value, addPageSize, followingSection, portraitSection);
|
||||||
lastOrientation = pendingOrientation;
|
lastOrientation = pendingOrientation;
|
||||||
sectionChangeInsideGroup = true;
|
sectionChangeInsideGroup = true;
|
||||||
pendingOrientation = null;
|
pendingOrientation = null;
|
||||||
@@ -738,7 +767,7 @@ internal static class MultiReplaceExt
|
|||||||
ref bool emptyParagraphCreated,
|
ref bool emptyParagraphCreated,
|
||||||
bool hasEmptyParagraphsBefore,
|
bool hasEmptyParagraphsBefore,
|
||||||
Paragraph original,
|
Paragraph original,
|
||||||
SectionProperties sourceSection,
|
SectionProperties followingSection,
|
||||||
SectionProperties portraitSection,
|
SectionProperties portraitSection,
|
||||||
List<Paragraph> resultParas)
|
List<Paragraph> resultParas)
|
||||||
{
|
{
|
||||||
@@ -764,7 +793,7 @@ internal static class MultiReplaceExt
|
|||||||
var newPara = CloneParagraphWithoutSection(original);
|
var newPara = CloneParagraphWithoutSection(original);
|
||||||
resultParas.Add(newPara);
|
resultParas.Add(newPara);
|
||||||
currentPara = newPara;
|
currentPara = newPara;
|
||||||
AddSectionProperties(currentPara, breakType, false, sourceSection, portraitSection);
|
AddSectionProperties(currentPara, breakType, false, followingSection, portraitSection);
|
||||||
lastOrientation = breakType;
|
lastOrientation = breakType;
|
||||||
sectionChangeInsideGroup = true;
|
sectionChangeInsideGroup = true;
|
||||||
firstSplitMarkerHandled = true;
|
firstSplitMarkerHandled = true;
|
||||||
@@ -788,14 +817,14 @@ internal static class MultiReplaceExt
|
|||||||
{
|
{
|
||||||
lastTextPara.ParagraphProperties ??= new ParagraphProperties();
|
lastTextPara.ParagraphProperties ??= new ParagraphProperties();
|
||||||
|
|
||||||
var sourcePageSize = sourceSection.GetFirstChild<PageSize>();
|
var sourcePageSize = followingSection.GetFirstChild<PageSize>();
|
||||||
if (sourcePageSize is not null)
|
if (sourcePageSize is not null)
|
||||||
{
|
{
|
||||||
lastTextPara.ParagraphProperties.AppendChild(sourceSection.CloneNode(true));
|
lastTextPara.ParagraphProperties.AppendChild(followingSection.CloneNode(true));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
AddSectionProperties(lastTextPara, breakType, false, sourceSection, portraitSection);
|
AddSectionProperties(lastTextPara, breakType, false, followingSection, portraitSection);
|
||||||
}
|
}
|
||||||
lastOrientation = breakType;
|
lastOrientation = breakType;
|
||||||
sectionChangeInsideGroup = true;
|
sectionChangeInsideGroup = true;
|
||||||
@@ -805,7 +834,7 @@ internal static class MultiReplaceExt
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
AddSectionProperties(currentPara, breakType, false, sourceSection, portraitSection);
|
AddSectionProperties(currentPara, breakType, false, followingSection, portraitSection);
|
||||||
lastOrientation = breakType;
|
lastOrientation = breakType;
|
||||||
sectionChangeInsideGroup = true;
|
sectionChangeInsideGroup = true;
|
||||||
firstSplitMarkerHandled = true;
|
firstSplitMarkerHandled = true;
|
||||||
|
|||||||
Reference in New Issue
Block a user