Skip to content

Commit 00f245b

Browse files
committed
+在更改页码对话框增加修改空跳转连接的目标使用下一个书签目标位置的选项(#224
1 parent 22aaa97 commit 00f245b

File tree

7 files changed

+136
-16
lines changed

7 files changed

+136
-16
lines changed

App/Commands.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ static class Commands
7979
internal const string EditorBookmarkPageNumberIncrement = "_IncrementPageNumber";
8080
internal const string EditorBookmarkPageNumberDecrement = "_DecrementPageNumber";
8181
internal const string EditorBookmarkPageNumberShift = "_ShiftMultiPageNumber";
82+
internal const string EditorBookmarkPageNumberShiftTakeFollowing = "_ShiftMultiPageNumberTakeFollowing";
8283
internal const string EditorBookmarkSetCurrentCoordinates = "_SetCurrentCoordinates";
8384
internal const string EditorOcrPage = "_OcrPage";
8485
internal const string EditorPageProperties = "_PageProperties";

App/Common/XmlHelper.cs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Collections;
23
using System.Collections.Generic;
34
using System.Diagnostics;
45
using System.Xml;
@@ -239,9 +240,65 @@ public static IList<TNode> ToNodeList<TNode>(this XmlNodeList nodes) where TNode
239240
return a;
240241
}
241242

243+
public static IEnumerable<XmlElement> ChildrenOrFollowingSiblings(this XmlElement element) {
244+
return new ChildrenOrFollowingElementEnumerator(element);
245+
}
246+
242247
static class Empty<TNode>
243248
{
244249
public static readonly TNode[] Item = new TNode[0];
245250
}
251+
252+
sealed class ChildrenOrFollowingElementEnumerator(XmlElement baseElement) : IEnumerable<XmlElement>, IEnumerator<XmlElement>
253+
{
254+
readonly XmlElement _base = baseElement;
255+
XmlNode _active = baseElement;
256+
257+
public XmlElement Current => _active as XmlElement;
258+
object IEnumerator.Current => _active;
259+
260+
public void Dispose() {}
261+
262+
public IEnumerator<XmlElement> GetEnumerator() {
263+
return this;
264+
}
265+
266+
public bool MoveNext() {
267+
return _active != null
268+
&& (_active.HasChildNodes && TryGetFirstChildElement(ref _active)
269+
|| TryGetFirstFollowingElement(ref _active));
270+
}
271+
272+
static bool TryGetFirstChildElement(ref XmlNode active) {
273+
var c = active.FirstChild;
274+
do {
275+
if (c.NodeType == XmlNodeType.Element) {
276+
active = c;
277+
return true;
278+
}
279+
}
280+
while ((c = c.NextSibling) != null);
281+
return false;
282+
}
283+
284+
static bool TryGetFirstFollowingElement(ref XmlNode active) {
285+
XmlNode s;
286+
while ((s = active.NextSibling) != null) {
287+
if (s.NodeType == XmlNodeType.Element) {
288+
active = s;
289+
return true;
290+
}
291+
}
292+
return false;
293+
}
294+
295+
public void Reset() {
296+
_active = _base;
297+
}
298+
299+
IEnumerator IEnumerable.GetEnumerator() {
300+
return this;
301+
}
302+
}
246303
}
247304
}

App/Functions/Editor/Commands/BookmarkPageCommand.cs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,26 @@ namespace PDFPatcher.Functions.Editor
77
sealed class BookmarkPageCommand : IEditorCommand
88
{
99
readonly int _number;
10+
bool _takeFollowing;
1011

11-
public BookmarkPageCommand(int number) {
12+
public BookmarkPageCommand(int number, bool takeFollowing = false) {
1213
_number = number;
14+
_takeFollowing = takeFollowing;
1315
}
1416

1517
public void Process(Controller controller, params string[] parameters) {
1618
var n = _number;
1719
if (_number == 0) {
18-
using (var form = new ShiftPageNumberEntryForm()) {
19-
if (form.ShowDialog() != DialogResult.OK || form.ShiftNumber == 0) {
20+
using (var form = new ShiftPageNumberEntryForm() { TakeFollowing = _takeFollowing }) {
21+
if (form.ShowDialog() != DialogResult.OK
22+
|| form.ShiftNumber == 0 && form.TakeFollowing == false) {
2023
return;
2124
}
2225
n = form.ShiftNumber;
26+
_takeFollowing = form.TakeFollowing;
2327
}
2428
}
25-
controller.ProcessBookmarks(new ChangePageNumberProcessor(n, false, true));
29+
controller.ProcessBookmarks(new ChangePageNumberProcessor(n, false, true, _takeFollowing));
2630
}
2731

2832
}

App/Functions/Editor/ShiftPageNumberEntryForm.Designer.cs

Lines changed: 15 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

App/Functions/Editor/ShiftPageNumberEntryForm.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ namespace PDFPatcher.Functions
77
sealed partial class ShiftPageNumberEntryForm : Form
88
{
99
internal int ShiftNumber => (int)_ShiftNumberBox.Value;
10+
internal bool TakeFollowing {
11+
get => _TakeFollowingBox.Checked;
12+
set => _TakeFollowingBox.Checked = value;
13+
}
1014

1115
public ShiftPageNumberEntryForm() {
1216
InitializeComponent();

App/Functions/EditorControl.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ public sealed partial class EditorControl : FunctionControl, IDocumentEditor, Ed
3939
d.Register(new Editor.BookmarkPageCommand(1), Commands.EditorBookmarkPageNumberIncrement);
4040
d.Register(new Editor.BookmarkPageCommand(-1), Commands.EditorBookmarkPageNumberDecrement);
4141
d.Register(new Editor.BookmarkPageCommand(0), Commands.EditorBookmarkPageNumberShift);
42+
d.Register(new Editor.BookmarkPageCommand(0, true), Commands.EditorBookmarkPageNumberShiftTakeFollowing);
4243
d.Register(new Editor.SimpleBookmarkCommand<ClearDestinationOffsetProcessor, ClearDestinationOffsetProcessor.PositionType>(ClearDestinationOffsetProcessor.PositionType.XY), "_ClearPositionXY");
4344
d.Register(new Editor.SimpleBookmarkCommand<ClearDestinationOffsetProcessor, ClearDestinationOffsetProcessor.PositionType>(ClearDestinationOffsetProcessor.PositionType.X), "_ClearPositionX");
4445
d.Register(new Editor.SimpleBookmarkCommand<ClearDestinationOffsetProcessor, ClearDestinationOffsetProcessor.PositionType>(ClearDestinationOffsetProcessor.PositionType.Y), "_ClearPositionY");

App/Processor/InfoXmlProcessors/ChangePageNumberProcessor.cs

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,38 @@
11
using System;
2+
using System.Xml;
23
using PDFPatcher.Common;
34

45
namespace PDFPatcher.Processor
56
{
6-
sealed class ChangePageNumberProcessor(int amount, bool isAbsolute, bool skipZero) : IPdfInfoXmlProcessor
7+
sealed class ChangePageNumberProcessor(int amount, bool isAbsolute, bool skipZero, bool takeFollowing = false) : IPdfInfoXmlProcessor
78
{
89
public bool IsAbsolute { get; } = isAbsolute;
910
public int Amount { get; } = amount;
1011
public bool SkipZero { get; } = skipZero;
12+
public bool TakeFollowing { get; } = takeFollowing;
1113

12-
public ChangePageNumberProcessor(int amount) : this(amount, false, false) { }
14+
public ChangePageNumberProcessor(int amount) : this(amount, false, false, false) { }
1315

1416
#region IInfoDocProcessor 成员
1517

1618
public string Name => "更改目标页码";
1719

18-
public IUndoAction Process(System.Xml.XmlElement item) {
19-
int p;
20-
var a = item.GetAttribute(Constants.DestinationAttributes.Action);
21-
if ((String.IsNullOrEmpty(a) && SkipZero == false
22-
|| a == Constants.ActionType.Goto
23-
|| a == Constants.ActionType.GotoR) == false
20+
public IUndoAction Process(XmlElement item) {
21+
int p = item.GetValue(Constants.DestinationAttributes.Page, 0);
22+
var a = item.GetValue(Constants.DestinationAttributes.Action);
23+
if (a != Constants.ActionType.Goto && a != Constants.ActionType.GotoR
24+
&& (a is null && TakeFollowing) == false
25+
|| String.IsNullOrEmpty(a) == false && p <= 0) {
26+
return null;
27+
}
28+
if (p == 0 && TakeFollowing) {
29+
return TakeFollowingBookmarkDestination(item, Amount);
30+
}
31+
if ((String.IsNullOrEmpty(a) && SkipZero == false) == false
2432
&& item.HasAttribute(Constants.DestinationAttributes.Page) == false) {
2533
return null;
2634
}
27-
if (item.GetAttribute(Constants.DestinationAttributes.Page).TryParse(out p)) {
35+
if (item.GetValue(Constants.DestinationAttributes.Page).TryParse(out p)) {
2836
if (IsAbsolute) {
2937
if (p == Amount) {
3038
return null;
@@ -48,6 +56,39 @@ public IUndoAction Process(System.Xml.XmlElement item) {
4856
}
4957
}
5058

59+
static UndoActionGroup TakeFollowingBookmarkDestination(XmlElement bookmark, int amount) {
60+
foreach (var item in bookmark.ChildrenOrFollowingSiblings()) {
61+
var p = item.GetValue(Constants.DestinationAttributes.Page);
62+
int n;
63+
if (String.IsNullOrEmpty(p) || (n = p.ToInt32()) <= 0) {
64+
continue;
65+
}
66+
var a = item.GetValue(Constants.DestinationAttributes.Action);
67+
if (a != Constants.ActionType.Goto && a != Constants.ActionType.GotoR) {
68+
continue;
69+
}
70+
n += amount;
71+
if (n <= 0) {
72+
break;
73+
}
74+
var undo = new UndoActionGroup();
75+
undo.SetAttribute(bookmark, Constants.DestinationAttributes.Page, (n + amount).ToText());
76+
undo.SetAttribute(bookmark, Constants.DestinationAttributes.Action, a);
77+
CopyAttributes(bookmark, item, undo, Constants.Coordinates.Top, Constants.Coordinates.Left, Constants.Coordinates.Bottom, Constants.Coordinates.Right, Constants.Coordinates.ScaleFactor);
78+
return undo;
79+
}
80+
return null;
81+
}
82+
83+
static void CopyAttributes(XmlElement bookmark, XmlElement item, UndoActionGroup undo, params string[] names) {
84+
foreach (var name in names) {
85+
var value = item.GetValue(name);
86+
if (String.IsNullOrEmpty(value) == false) {
87+
undo.SetAttribute(bookmark, name, value);
88+
}
89+
}
90+
}
91+
5192
#endregion
5293
}
5394
}

0 commit comments

Comments
 (0)