5 // Created by Marc Liyanage on Fri Aug 02 2002.
6 // Copyright (c) 2002 __MyCompanyName__. All rights reserved.
9 #import "XMLTextView.h"
12 @implementation XMLTextView
18 [self setRichText:NO];
22 // register our two input text views to receive file drags
24 // [xmlView registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType, nil]];
25 // [xsltView registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType, nil]];
27 NSFont *computerFont = [NSFont fontWithName:@"Courier" size:12.0];
28 [self setFont:computerFont];
30 [self setAllowsUndo:YES];
39 [errorString release];
42 -(void)selectLineByNumber:(int)line {
44 NSString *data = [self string];
45 unsigned int i, startIndex, lineEndIndex;
56 for (i = 1; i <= line; i++) {
58 [data getLineStart:&startIndex end:&lineEndIndex contentsEnd:nil forRange:aRange];
59 aRange.location = lineEndIndex;
63 aRange.location = startIndex;
64 aRange.length = lineEndIndex - startIndex;
66 [self setSelectedRange:aRange];
67 [self scrollRangeToVisible:aRange];
76 - (void)keyDown:(NSEvent *)event {
78 NSRange selectedRange;
80 if ([[event characters] isEqual:@"\033"]) {
82 if ([event modifierFlags] || [event isARepeat]) {
88 } else if ([[event characters] isEqual:@"/"]) {
90 selectedRange = [self selectedRange];
91 if (selectedRange.location < 2 || selectedRange.length > 0) {
92 [super keyDown:event];
96 if ([[[self string] substringWithRange:NSMakeRange(selectedRange.location - 1, 1)] isEqual:@"<"]) {
97 if([self completeAfterSlash]) {
105 if ([event modifierFlags] & NSFunctionKeyMask) {
106 [self didChangeText];
113 [super keyDown:event];
119 - (BOOL)completeAfterSlash {
121 int location = [self selectedRange].location - 1;
123 [self calculateTagStackAtLocation:location];
129 NSTextStorage *storage = [self textStorage];
130 [storage beginEditing];
131 [storage deleteCharactersInRange:NSMakeRange(location, 1)];
132 [storage endEditing];
134 [self setSelectedRange:NSMakeRange(location, 0)];
144 - (void)flashRange:(NSRange)range {
148 tagNameRect = [self firstRectForCharacterRange:range];
150 tagNameRect.origin = [[self window] convertScreenToBase:tagNameRect.origin];
152 tagNameRect = [self convertRect:tagNameRect fromView:[[self window] contentView]];
156 [[[NSColor selectedControlColor] colorWithAlphaComponent:0.75] set];
158 NSFrameRectWithWidth(tagNameRect, 2);
160 [NSBezierPath fillRect:tagNameRect];
162 [[self window] flushWindow];
166 [self setNeedsDisplay:YES];
171 -(NSString *)calculateTagStack {
173 return [self calculateTagStackAtLocation:[self selectedRange].location];
177 -(BOOL)checkWellFormed {
180 NSData *data = [XMLUtils getDataWithEncodingFromString:[self string]];
182 parser = XML_ParserCreate(NULL);
185 NSLog(@"Unable to allocate expat parser in XMLTextView:checkWellFormed!");
189 result = XML_Parse(parser, [data bytes], [data length], 1);
192 [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)];
197 XML_ParserFree(parser);
206 errorLine = errorColumn = 0;
208 [errorString release];
218 -(void)setError:(NSString *)errstring atLine:(int)line atColumn:(int)column {
221 errorColumn = column;
224 [errorString release];
225 errorString = errstring;
235 -(NSString *)calculateTagStackAtLocation:(int)location {
239 NSRange selectedRange;
240 NSMutableString *mystack;
242 buffer = [[self string] lossyCString];
243 selectedRange = [self selectedRange];
249 resultstack = findCompletion(buffer, strlen(buffer), location, &stackresult, tagpositions);
251 mystack = [NSMutableString stringWithCapacity:1000];
253 for (i = 0; resultstack && *(resultstack[i]); i++) {
254 if (*(resultstack[i+1])) {
255 [mystack appendFormat:@"%s/", resultstack[i]];
258 [mystack appendFormat:@"%s", resultstack[i]];
260 [mystack appendFormat:@"<%s>", resultstack[i]];
269 switch (stackresult) {
272 [mystack appendString:@" (In tag)"];
276 [mystack appendString:@" (In comment section)"];
279 [mystack appendString:@" (In CDATA section)"];
283 [mystack appendString:@" (No open tags)"];
287 [mystack appendString:@" (Tags are balanced)"];
296 - (void)complete:(id)sender {
298 NSRange selectedRange, tagNameRange;
299 NSString *tagName = nil;
302 // data = [self string];
304 selectedRange = [self selectedRange];
305 location = selectedRange.location;
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
310 if (selectedRange.length > 0 || location < 3 || stackresult) {
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]);
324 [self insertText:[NSString stringWithFormat:@"</%@>", tagName]];
325 [self setSelectedRange:selectedRange];
327 [self flashRange:tagNameRange];
328 [self calculateTagStack];