@@ -15,45 +15,7 @@ import TextStory
15
15
/// - Grouping pasted text
16
16
///
17
17
/// If needed, the automatic undo grouping can be overridden using the `beginGrouping()` and `endGrouping()` methods.
18
- public class CEUndoManager {
19
- /// An `UndoManager` subclass that forwards relevant actions to a `CEUndoManager`.
20
- /// Allows for objects like `TextView` to use the `UndoManager` API
21
- /// while CETV manages the undo/redo actions.
22
- public class DelegatedUndoManager : UndoManager {
23
- weak var parent : CEUndoManager ?
24
-
25
- public override var isUndoing : Bool { parent? . isUndoing ?? false }
26
- public override var isRedoing : Bool { parent? . isRedoing ?? false }
27
- public override var canUndo : Bool { parent? . canUndo ?? false }
28
- public override var canRedo : Bool { parent? . canRedo ?? false }
29
-
30
- public func registerMutation( _ mutation: TextMutation ) {
31
- parent? . registerMutation ( mutation)
32
- removeAllActions ( )
33
- }
34
-
35
- public override func undo( ) {
36
- parent? . undo ( )
37
- }
38
-
39
- public override func redo( ) {
40
- parent? . redo ( )
41
- }
42
-
43
- public override func beginUndoGrouping( ) {
44
- parent? . beginUndoGrouping ( )
45
- }
46
-
47
- public override func endUndoGrouping( ) {
48
- parent? . endUndoGrouping ( )
49
- }
50
-
51
- public override func registerUndo( withTarget target: Any , selector: Selector , object anObject: Any ? ) {
52
- // no-op, but just in case to save resources:
53
- removeAllActions ( )
54
- }
55
- }
56
-
18
+ public class CEUndoManager : UndoManager {
57
19
/// Represents a group of mutations that should be treated as one mutation when undoing/redoing.
58
20
private struct UndoGroup {
59
21
var mutations : [ Mutation ]
@@ -65,16 +27,17 @@ public class CEUndoManager {
65
27
var inverse : TextMutation
66
28
}
67
29
68
- public let manager : DelegatedUndoManager
69
- private( set) public var isUndoing : Bool = false
70
- private( set) public var isRedoing : Bool = false
30
+ private var _isUndoing : Bool = false
31
+ private var _isRedoing : Bool = false
71
32
72
- public var canUndo : Bool {
73
- !undoStack. isEmpty
74
- }
75
- public var canRedo : Bool {
76
- !redoStack. isEmpty
77
- }
33
+ override public var isUndoing : Bool { _isUndoing }
34
+ override public var isRedoing : Bool { _isRedoing }
35
+
36
+ override public var undoCount : Int { undoStack. count }
37
+ override public var redoCount : Int { redoStack. count }
38
+
39
+ override public var canUndo : Bool { !undoStack. isEmpty }
40
+ override public var canRedo : Bool { !redoStack. isEmpty }
78
41
79
42
/// A stack of operations that can be undone.
80
43
private var undoStack : [ UndoGroup ] = [ ]
@@ -93,10 +56,7 @@ public class CEUndoManager {
93
56
94
57
// MARK: - Init
95
58
96
- public init ( ) {
97
- self . manager = DelegatedUndoManager ( )
98
- manager. parent = self
99
- }
59
+ override public init ( ) { }
100
60
101
61
convenience init ( textView: TextView ) {
102
62
self . init ( )
@@ -106,37 +66,49 @@ public class CEUndoManager {
106
66
// MARK: - Undo/Redo
107
67
108
68
/// Performs an undo operation if there is one available.
109
- public func undo( ) {
110
- guard !isDisabled, let item = undoStack. popLast ( ) , let textView else {
69
+ override public func undo( ) {
70
+ guard !isDisabled, let textView else {
71
+ return
72
+ }
73
+
74
+ guard let item = undoStack. popLast ( ) else {
75
+ NSSound . beep ( )
111
76
return
112
77
}
113
- isUndoing = true
114
- NotificationCenter . default. post ( name: . NSUndoManagerWillUndoChange, object: self . manager)
78
+
79
+ _isUndoing = true
80
+ NotificationCenter . default. post ( name: . NSUndoManagerWillUndoChange, object: self )
115
81
textView. textStorage. beginEditing ( )
116
82
for mutation in item. mutations. reversed ( ) {
117
83
textView. replaceCharacters ( in: mutation. inverse. range, with: mutation. inverse. string)
118
84
}
119
85
textView. textStorage. endEditing ( )
120
- NotificationCenter . default. post ( name: . NSUndoManagerDidUndoChange, object: self . manager )
86
+ NotificationCenter . default. post ( name: . NSUndoManagerDidUndoChange, object: self )
121
87
redoStack. append ( item)
122
- isUndoing = false
88
+ _isUndoing = false
123
89
}
124
90
125
91
/// Performs a redo operation if there is one available.
126
- public func redo( ) {
127
- guard !isDisabled, let item = redoStack. popLast ( ) , let textView else {
92
+ override public func redo( ) {
93
+ guard !isDisabled, let textView else {
94
+ return
95
+ }
96
+
97
+ guard let item = redoStack. popLast ( ) else {
98
+ NSSound . beep ( )
128
99
return
129
100
}
130
- isRedoing = true
131
- NotificationCenter . default. post ( name: . NSUndoManagerWillRedoChange, object: self . manager)
101
+
102
+ _isRedoing = true
103
+ NotificationCenter . default. post ( name: . NSUndoManagerWillRedoChange, object: self )
132
104
textView. textStorage. beginEditing ( )
133
105
for mutation in item. mutations {
134
106
textView. replaceCharacters ( in: mutation. mutation. range, with: mutation. mutation. string)
135
107
}
136
108
textView. textStorage. endEditing ( )
137
- NotificationCenter . default. post ( name: . NSUndoManagerDidRedoChange, object: self . manager )
109
+ NotificationCenter . default. post ( name: . NSUndoManagerDidRedoChange, object: self )
138
110
undoStack. append ( item)
139
- isRedoing = false
111
+ _isRedoing = false
140
112
}
141
113
142
114
/// Clears the undo/redo stacks.
@@ -147,11 +119,17 @@ public class CEUndoManager {
147
119
148
120
// MARK: - Mutations
149
121
122
+ public override func registerUndo( withTarget target: Any , selector: Selector , object anObject: Any ? ) {
123
+ // no-op, but just in case to save resources:
124
+ removeAllActions ( )
125
+ }
126
+
150
127
/// Registers a mutation into the undo stack.
151
128
///
152
129
/// Calling this method while the manager is in an undo/redo operation will result in a no-op.
153
130
/// - Parameter mutation: The mutation to register for undo/redo
154
131
public func registerMutation( _ mutation: TextMutation ) {
132
+ removeAllActions ( )
155
133
guard let textView,
156
134
let textStorage = textView. textStorage,
157
135
!isUndoing,
@@ -178,15 +156,15 @@ public class CEUndoManager {
178
156
// MARK: - Grouping
179
157
180
158
/// Groups all incoming mutations.
181
- public func beginUndoGrouping( ) {
159
+ override public func beginUndoGrouping( ) {
182
160
guard !isGrouping else { return }
183
161
isGrouping = true
184
162
// This is a new undo group, break for it.
185
163
shouldBreakNextGroup = true
186
164
}
187
165
188
166
/// Stops grouping all incoming mutations.
189
- public func endUndoGrouping( ) {
167
+ override public func endUndoGrouping( ) {
190
168
guard isGrouping else { return }
191
169
isGrouping = false
192
170
// We just ended a group, do not allow the next mutation to be added to the group we just made.
0 commit comments