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