forked from erkyrath/Inform7-IDE-Mac
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathIFRestrictedTextStorage.m
266 lines (206 loc) · 7.43 KB
/
IFRestrictedTextStorage.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
//
// IFRestrictedTextStorage.m
// Inform-xc2
//
// Created by Andrew Hunter on 04/01/2008.
// Copyright 2008 Andrew Hunter. All rights reserved.
//
#import "IFRestrictedTextStorage.h"
@implementation IFRestrictedTextStorage
// Initialisation
- (id) init {
return [self initWithTextStorage: [[[NSTextStorage alloc] init] autorelease]];
}
- (id) initWithTextStorage: (NSTextStorage*) newStorage {
self = [super init];
if (self) {
// Set up the storage object
storage = [newStorage retain];
restriction = NSMakeRange(0, [storage length]);
string = [[IFRestrictedString alloc] initWithString: [storage string]];
[string setRestriction: restriction];
// Register for notifications from the storage object
if ([newStorage isKindOfClass: [IFSyntaxStorage class]]) {
[(IFSyntaxStorage*)newStorage addDerivativeStorage: self];
} else {
[[NSNotificationCenter defaultCenter] addObserver: self
selector: @selector(didEdit:)
name: NSTextStorageDidProcessEditingNotification
object: storage];
}
}
return self;
}
- (void) dealloc {
[[NSNotificationCenter defaultCenter] removeObserver: self];
if ([storage isKindOfClass: [IFSyntaxStorage class]]) {
[(IFSyntaxStorage*)storage removeDerivativeStorage: self];
}
[storage release]; storage = nil;
[string release]; string = nil;
[super dealloc];
}
- (NSTextStorage*) restrictedStorage {
return storage;
}
// = Mandatory NSTextStorage function implementations =
- (NSString*) string {
return string;
}
- (int) length {
return restriction.length;
}
- (NSDictionary*) attributesAtIndex: (NSUInteger) index
effectiveRange: (NSRangePointer) range {
if (index < 0 || index >= restriction.length) {
[NSException raise: NSRangeException
format: @"Index outside the bounds of the restricted string"];
if (range) {
range->location = restriction.length;
range->length = 0;
}
return [NSDictionary dictionary];
}
NSRange effectiveRange;
NSDictionary* result;
result = [storage attributesAtIndex: index + restriction.location
effectiveRange: &effectiveRange];
if (effectiveRange.location < restriction.location) {
effectiveRange.length -= restriction.location - effectiveRange.location;
effectiveRange.location = restriction.location;
}
effectiveRange.location -= restriction.location;
if (effectiveRange.location + effectiveRange.length > restriction.length) {
effectiveRange.length = restriction.length - effectiveRange.location;
}
if (range) {
*range = effectiveRange;
}
return result;
}
- (void) replaceCharactersInRange: (NSRange) range
withString: (NSString*) newString {
range.location += restriction.location;
[storage replaceCharactersInRange: range
withString: newString];
}
- (void) setAttributes: (NSDictionary*) attributes
range: (NSRange) range {
range.location += restriction.location;
[storage setAttributes: attributes
range: range];
}
// = Handling NSTextStorage notification events =
- (void) didBeginEditing: (NSTextStorage*) storage {
[self beginEditing];
}
- (void) didEdit: (NSTextStorage*) storage
mask: (unsigned int) mask
changeInLength: (int) changeInLength
range: (NSRange) editRange {
// If the edit is before the start of the restriction, then do nothing
if (editRange.location + editRange.length < restriction.location) {
restriction.location += changeInLength;
[string setRestriction: restriction];
return;
}
// If this edit is beyond the end of the restriction, then do nothing
if (editRange.length != 0 || editRange.location != restriction.location + restriction.length)
{
if (editRange.location >= restriction.location + restriction.length) {
return;
}
}
NSRange restrictedEditRange = editRange;
// If the change in length is non-zero and the edited range extends below the restriction location,
// perform the update by changing the restriction range
if (editRange.location < restriction.location) {
int extraCharacters = restriction.location - editRange.location;
NSRange newRestriction = restriction;
newRestriction.location -= extraCharacters;
newRestriction.length += extraCharacters + changeInLength;
if (editRange.location + editRange.length > restriction.location + restriction.length) {
newRestriction.length += (editRange.location + editRange.length) - (restriction.location + restriction.length);
}
[self setRestriction: newRestriction];
return;
}
// If the change in length is non-zero and the edited range extends beyonds the restriction location, perform the update by changing the restriction range
if (changeInLength != 0 && editRange.location + editRange.length > restriction.location + restriction.length) {
NSRange newRestriction = restriction;
newRestriction.length += (editRange.location + editRange.length) - (restriction.location + restriction.length);
[self setRestriction: newRestriction];
return;
}
// If the edited range extends below the restriction location, restrict it
if (restrictedEditRange.location < restriction.location) {
restrictedEditRange.length -= (restriction.location - restrictedEditRange.location);
restrictedEditRange.location = restriction.location;
}
// Move the range according to where the restriction is
restrictedEditRange.location -= restriction.location;
// If the edited range extends above the current restriction, then reduce it
if (restrictedEditRange.location + restrictedEditRange.length > restriction.length) {
restrictedEditRange.length = restriction.length - restrictedEditRange.location;
}
// Change the size of the restriction
restriction.length += changeInLength;
[string setRestriction: restriction];
// Report the edit
[self edited: mask
range: restrictedEditRange
changeInLength: changeInLength];
}
- (void) didEndEditing: (NSTextStorage*) storage {
[self endEditing];
}
- (void) didEdit: (NSNotification*) not {
// NSNotification (this is less than ideal as we can get confused more easily)
if ([not object] != storage) return;
// Get the details about the edit that has occurred
NSRange editRange = [storage editedRange];
int changeInLength = [storage changeInLength];
int mask = [storage editedMask];
// Pass to the didEdit: method
[self didEdit: storage
mask: mask
changeInLength: changeInLength
range: editRange];
}
// = Restricting the range that is being displayed by the storage object =
- (BOOL) isRestricted {
if (restriction.location != 0 || restriction.length != [storage length]) {
return YES;
} else {
return NO;
}
}
- (void) setRestriction: (NSRange) range {
// Do nothing if the restriction is the same as before
if (NSEqualRanges(range, restriction)) {
return;
}
if (range.location < 0) range.location = 0;
if (range.location > [storage length]) {
range.location = [storage length];
range.length = 0;
}
if (range.location + range.length > [storage length]) {
range.length = [storage length] - range.location;
}
// Update the range that this text storage is displaying
NSRange oldRange = restriction;
restriction = range;
[string setRestriction: restriction];
// Send an edited event marking the change
[self edited: NSTextStorageEditedAttributes | NSTextStorageEditedCharacters
range: NSMakeRange(0, oldRange.length)
changeInLength: (int)restriction.length - (int)oldRange.length];
}
- (void) removeRestriction {
[self setRestriction: NSMakeRange(0, [storage length])];
}
- (NSRange) restrictionRange {
return restriction;
}
@end