Xcode 2.1 cleanup, universal binary experiments
[TestXSLT.git] / src / XMLTextView.m
1 //
2 //  XMLTextView.m
3 //  TestXSLT
4 //
5 //  Created by Marc Liyanage on Fri Aug 02 2002.
6 //  Copyright (c) 2002 __MyCompanyName__. All rights reserved.
7 //
8
9 #import "XMLTextView.h"
10
11
12 @implementation XMLTextView
13
14
15
16 -(void)awakeFromNib {
17
18         [self setRichText:NO];
19         resultstack = NULL;
20         defaults = [NSUserDefaults standardUserDefaults];
21         
22         // register our two input text views to receive file drags
23         //
24  //     [xmlView registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType, nil]];
25  //     [xsltView registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType, nil]];
26         
27         NSFont *computerFont = [NSFont fontWithName:@"Courier" size:12.0];
28         [self setFont:computerFont];
29         
30         [self setAllowsUndo:YES];
31         
32 }
33
34
35 - (void)dealloc {
36         
37         if (resultstack)
38                 free(resultstack);
39         [errorString release];
40         [tagStack release];
41         [super dealloc];
42
43 }
44
45
46
47
48 -(void)selectLineByNumber:(int)line {
49
50         NSString *data = [self string];
51         unsigned int i, startIndex, lineEndIndex;
52         NSRange aRange;
53
54         if (line == 0) {
55                 return;
56         }
57
58
59         aRange.location = 0;
60         aRange.length = 0;
61
62         for (i = 1; i <= line; i++) {
63
64                 [data getLineStart:&startIndex end:&lineEndIndex contentsEnd:nil forRange:aRange];
65                 aRange.location = lineEndIndex;
66
67         }
68
69         aRange.location = startIndex;
70         aRange.length = lineEndIndex - startIndex;
71
72         [self setSelectedRange:aRange];
73         [self scrollRangeToVisible:aRange];
74
75         
76 }
77
78
79
80
81
82 - (void)keyDown:(NSEvent *)event {
83
84         NSRange selectedRange;
85         
86         if (![defaults boolForKey:@"enableSyntaxAnalysis"]) {
87                 [super keyDown:event];
88                 return;
89         }
90         
91         if ([[event characters] isEqual:@"\033"]) {
92
93                 if ([event modifierFlags] || [event isARepeat]) {
94                         return;
95                 }
96                 [self complete:nil];
97                 return;
98
99         } else if ([[event characters] isEqual:@"/"]) {
100
101                 selectedRange = [self selectedRange];
102                 if (selectedRange.location < 2 || selectedRange.length > 0) {
103                         [super keyDown:event];
104                         return;
105                 }
106
107                 if ([[[self string] substringWithRange:NSMakeRange(selectedRange.location - 1, 1)] isEqual:@"<"]) {
108                         if([self completeAfterSlash]) {
109                                 return;
110                         }
111                 }
112         }
113
114         
115         /*
116         if ([event modifierFlags] & NSFunctionKeyMask) {
117                 [self didChangeText];
118         }
119         */
120         
121         //NSFunctionKeyMask
122         
123         
124         [super keyDown:event];
125
126 }
127
128
129
130 - (BOOL)completeAfterSlash {
131
132         int location = [self selectedRange].location - 1;
133         
134         [self calculateTagStackAtLocation:location];
135         
136         if (stackresult) {
137                 return NO;
138         }
139
140         NSTextStorage *storage = [self textStorage];
141         [storage beginEditing];
142         [storage deleteCharactersInRange:NSMakeRange(location, 1)];
143         [storage endEditing];
144
145         [self setSelectedRange:NSMakeRange(location, 0)];
146
147         [self complete:nil];
148
149         
150         return YES;
151 }
152
153
154
155 - (void)flashRange:(NSRange)range {
156
157         NSRect tagNameRect;
158
159         tagNameRect = [self firstRectForCharacterRange:range];
160
161         tagNameRect.origin = [[self window] convertScreenToBase:tagNameRect.origin];
162
163         tagNameRect = [self convertRect:tagNameRect fromView:[[self window] contentView]];
164
165
166         [self lockFocus];
167         [[[NSColor selectedControlColor] colorWithAlphaComponent:0.75] set];
168 /*
169         NSFrameRectWithWidth(tagNameRect, 2);
170  */
171         [NSBezierPath fillRect:tagNameRect];
172         [self unlockFocus];
173         [[self window] flushWindow];
174
175         usleep(100000);
176
177         [self setNeedsDisplay:YES];
178
179         
180 }
181
182
183 - (void)calculateTagStack {
184         [self calculateTagStackAtLocation:[self selectedRange].location];
185 }
186
187
188 - (BOOL)checkWellFormed {
189
190         int result;
191         NSData *data = [XMLUtils getDataWithEncodingFromString:[self string]];
192
193         parser = XML_ParserCreate(NULL);
194
195         if (!parser) {
196                 NSLog(@"Unable to allocate expat parser in XMLTextView:checkWellFormed!");
197                 return NO;
198         }
199
200         result = XML_Parse(parser, [data bytes], [data length], 1);
201
202         if (!result) {
203                 [self setError:[NSString stringWithFormat:@"%s, line %d, column %d", XML_ErrorString(XML_GetErrorCode(parser)), XML_GetCurrentLineNumber(parser), XML_GetCurrentColumnNumber(parser)] atLine:XML_GetCurrentLineNumber(parser) atColumn:XML_GetCurrentColumnNumber(parser)];
204         } else if (hasError) {
205                 [self clearError];
206         }
207         
208         XML_ParserFree(parser);
209         
210         return result > 0;
211 }
212
213
214 - (void)clearError {
215         errorLine = errorColumn = 0;
216         [self setValue:[NSNumber numberWithBool:NO] forKey:@"hasError"];
217         [errorString release];
218         errorString = @"";
219 }
220
221
222
223 - (void)setError:(NSString *)errstring atLine:(int)line atColumn:(int)column {
224         [self setValue:[NSNumber numberWithInt:line] forKey:@"errorLine"];
225         [self setValue:[NSNumber numberWithInt:column] forKey:@"errorColumn"];
226         [self setValue:[NSNumber numberWithBool:YES] forKey:@"hasError"];
227         [self setValue:errstring forKey:@"errorString"];        
228 }
229
230
231
232 - (void)calculateTagStackAtLocation:(int)location {
233
234         const char *buffer;
235         int i;
236         NSRange selectedRange;
237         NSMutableString *mystack;
238
239         if (![[NSUserDefaults standardUserDefaults] boolForKey:@"enableSyntaxAnalysis"]) {
240                 return;
241         }
242         
243         buffer = [[self string] lossyCString];
244         selectedRange = [self selectedRange];
245         
246         if (resultstack)
247                 free(resultstack);
248
249         stackresult = 0;
250         resultstack = findCompletion(buffer, strlen(buffer), location, &stackresult, tagpositions);
251
252         mystack = [NSMutableString stringWithCapacity:1000];
253         
254         for (i = 0; resultstack && *(resultstack[i]); i++) {
255                 if (*(resultstack[i+1])) {
256                         [mystack appendFormat:@"%s/", resultstack[i]];
257                 } else {
258                         if (stackresult) {
259                                 [mystack appendFormat:@"%s", resultstack[i]];
260                         } else {
261                                 [mystack appendFormat:@"<%s>", resultstack[i]];
262                         }
263                         
264                         
265                 }
266
267         }
268
269
270         switch (stackresult) {
271         
272                 case 1:
273                         [mystack appendString:@" (In tag)"];
274                         break;
275
276                 case 3:
277                         [mystack appendString:@" (In comment section)"];
278                         break;
279                 case 5:
280                         [mystack appendString:@" (In CDATA section)"];
281                         break;
282                         
283                 case 8:
284                         [mystack appendString:@" (No open tags)"];
285                         break;
286                         
287                 case 16:
288                         [mystack appendString:@" (Tags are balanced)"];
289                         break;
290         }
291         
292         [self setValue:mystack forKey:@"tagStack"];
293         
294 }
295
296 - (void)complete:(id)sender {
297
298         NSRange selectedRange, tagNameRange;
299         NSString *tagName = nil;
300         int location, i;
301
302 //      data = [self string];
303
304         selectedRange = [self selectedRange];
305         location = selectedRange.location;
306
307         /* May not have a selection, and insertion point must be preceded by at
308                 * least one tag, which means at least 3 characters must be to its left
309                 */
310         if (selectedRange.length > 0 || location < 3 || stackresult) {
311                 NSBeep();
312                 return;
313         }
314
315
316         for (i = 0; resultstack && *(resultstack[i]); i++) {
317                 if (!*(resultstack[i+1])) {
318                         tagName = [NSString stringWithCString:resultstack[i]];
319                         tagNameRange = NSMakeRange(tagpositions[i*2], tagpositions[i*2+1]- tagpositions[i*2]);
320                 }
321         }
322         
323
324         [self insertText:[NSString stringWithFormat:@"</%@>", tagName]];
325         [self setSelectedRange:selectedRange];
326
327         [self flashRange:tagNameRange];
328         [self calculateTagStack];
329         
330 }
331
332
333
334
335
336 @end