Initial revision
[TestXSLT.git] / MyDocument.m
1 //
2 //  MyDocument.m
3 //  TestXSLT
4 //
5 //  Created by Marc Liyanage on Sun Mar 03 2002.
6 //  Copyright (c) 2001 __MyCompanyName__. All rights reserved.
7 //
8 // $Id$
9
10 #import "MyDocument.h"
11 #import "Workset.h"
12
13
14
15
16 @implementation MyDocument
17
18 - (id)init {
19
20         if (self = [super init]) {
21                 workset = [[Workset alloc] init];
22                 processor = [XSLTProcessorFactory makeProcessorOfType:PROCESSORTYPE_SABLOTRON];
23                 wellFormedParser = [[XMLParserLibxml alloc] init];
24                 xmlDirty = NO;
25                 xsltDirty = NO;
26         }
27
28         
29         
30         return self;
31 }
32
33 - (void)dealloc {
34
35         [workset release];
36         [processor release];
37         [wellFormedParser release];
38         [findPanelController release];
39         [jumpToLinePanelController release];
40         [unsavedChangesPanelController release];
41
42 }
43
44 - (IBAction)selectTab:(id)sender {
45
46         [self selectTabById:[sender tag]];
47         
48 }
49
50
51
52
53
54
55 - (IBAction)selectTabById:(int)tabId {
56
57         NSString *tabName;
58
59         switch (tabId) {
60
61                 case XML:
62                         tabName = @"xmlTab";
63                         break;
64
65                 case XSLT:
66                         tabName = @"xsltTab";
67                         break;
68
69                 case PARAMETERS:
70                         tabName = @"parametersTab";
71                         break;
72
73                 case RESULT:
74                 default:
75                         tabName = @"resultTab";
76                         break;
77
78
79         }
80
81         [tabView selectTabViewItemWithIdentifier:tabName];
82
83 }
84
85
86 - (void)tabView:(NSTabView *)tabView didSelectTabViewItem:(NSTabViewItem *)tabViewItem {
87
88         NSLog(@"switch tab xyz x");
89         [[self undoManager] removeAllActions];
90
91         if ([[tabViewItem identifier] isEqualToString:@"htmlResult"]) {
92                 [self resizeWebView];
93         }
94         
95 }
96
97
98
99
100 - (void)updateUI {
101         
102 //      NSLog(@"updateUI running...");
103
104         [uiUpdateTimer invalidate];
105         [uiUpdateTimer release];
106
107         uiUpdateTimer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(uiUpdateTimerTarget:) userInfo:nil repeats:NO];
108
109         [uiUpdateTimer retain];
110
111 }
112
113 - (void)uiUpdateTimerTarget:(NSTimer *)timer {
114
115         [self doUpdateUI];
116         [timer release];
117         uiUpdateTimer = nil;
118 }
119
120
121
122 - (void)doUpdateUI {
123
124 //      NSLog(@"doUpdateUI running...");
125 //      NSLog(@"debug: %@", [[[NSApp mainWindow] document] tabView]);
126
127
128         [saveXmlAsButton setEnabled:[workset hasXmlCode]];
129         [saveXsltAsButton setEnabled:[workset hasXsltCode]];
130         [saveResultAsButton setEnabled:[workset hasResult]];
131
132         [saveResultButton setEnabled:[workset hasResultFilename] && resultDirty];
133         [autoSaveCheckbox setEnabled:[workset hasResultFilename]];
134
135         [openResultURLButton setEnabled:[workset hasResultFilename]];
136         [autoShowCheckbox setEnabled:[openResultURLButton isEnabled]];
137
138         [paramRemoveButton setEnabled:[parameterTable selectedRow] != -1];
139
140         [processButton setEnabled:[self canProcessNow]];
141
142         [saveResultFilenameField setObjectValue:[workset resultFilename]];
143         [saveResultFilenameField setToolTip:[workset resultFilename]];
144
145
146         [saveXmlFilenameField setObjectValue:[workset xmlFilename]];
147         [saveXmlFilenameField setToolTip:[workset xmlFilename]];
148         [saveXmlButton setEnabled:[workset hasXmlFilename] && xmlDirty];
149
150         
151         [saveXsltFilenameField setObjectValue:[workset xsltFilename]];
152         [saveXsltFilenameField setToolTip:[workset xsltFilename]];
153         [saveXsltButton setEnabled:[workset hasXsltFilename] && xsltDirty];
154
155         [self updateWellFormedIcons];
156         
157         [parameterTable reloadData];
158         
159         [resultView setString:[workset result]];
160         
161         WebFrame *mainFrame = [resultWebView mainFrame];
162         [mainFrame loadHTMLString:[workset result] baseURL:nil];
163
164         /*
165         NSLog(@"webview frame: %@", NSStringFromRect([resultWebView frame]));
166         NSLog(@"webview main frame: %@", NSStringFromRect([[mainFrame frameView] frame]));
167         NSLog(@"textview frame: %@", NSStringFromRect([resultView frame]));
168         */
169         
170         
171 }
172
173
174 - (void)updateWellFormedIcons {
175
176         if (![workset hasXmlCode] || [wellFormedParser checkWellFormedString:[workset xmlCode]]) {
177                 [xmlWellFormedIcon setImage:nil];
178                 [xmlWellFormedIcon setToolTip:nil];
179         } else {
180                 [xmlWellFormedIcon setImage:warningIcon];
181                 [xmlWellFormedIcon setToolTip:[NSString stringWithFormat:@"The XML code is not well-formed, error at line %d:\n%@", [wellFormedParser errorLine], [wellFormedParser errorMessage]]];
182         }
183
184
185         if (![workset hasXsltCode] || [wellFormedParser checkWellFormedString:[workset xsltCode]]) {
186                 [xsltWellFormedIcon setImage:nil];
187                 [xsltWellFormedIcon setToolTip:nil];
188         } else {
189                 [xsltWellFormedIcon setImage:warningIcon];
190                 [xsltWellFormedIcon setToolTip:[NSString stringWithFormat:@"The XSLT code is not well-formed, error at line %d:\n%@", [wellFormedParser errorLine], [wellFormedParser errorMessage]]];
191         }
192
193         
194 }
195
196
197 - (BOOL)canProcessNow {
198
199         return [workset hasXmlCode] && [workset hasXsltCode];
200
201 }
202
203 - (BOOL)validateMenuItem:(NSMenuItem *)menuItem {
204
205 //      NSLog(@"validate: %@, tag: %d", menuItem, [menuItem tag]);
206
207         switch ([menuItem tag]) {
208
209                 case 10:        // Process
210                         return [self canProcessNow];
211                         break;
212
213                 case 11:        // Save
214                         return [workset hasResultFilename];
215                         break;
216
217                 case 12:        // Find
218                         return [self canFindNow];
219                         break;
220
221                 case 13:        // Find Next
222                 case 14:        // Find Previous
223                         return [self canFindAgainNow];
224                         break;
225
226                 case 15:        // Use Selection for Find
227                         return [self canUseSelectionForFindNow];
228                         break;
229
230                 case 16:        // Jump to Line
231                         return [self canJumpToLineNow];
232                         break;
233
234                 default:
235                         return YES;
236                         break;
237
238         }
239
240
241 }
242
243 - (IBAction)showInBrowser:(id)sender {
244
245         
246
247 }
248
249
250 - (void)updateCompleteUI {
251
252         [xmlView setString:[workset xmlCode]];
253         [xsltView setString:[workset xsltCode]];
254         [self doUpdateUI];
255         
256 }
257
258
259
260 - (void)textDidChange:(NSNotification *)aNotification {
261
262         id sender = [aNotification object];
263
264         if ([sender isEqual:xmlView]) {
265                 [workset setXmlCode:[xmlView string]];
266                 xmlDirty = YES;
267         } else if ([sender isEqual:xsltView]) {
268                 [workset setXsltCode:[xsltView string]];
269                 xsltDirty = YES;
270         }
271
272         [self updateChangeCount:NSChangeDone];
273         [self updateUI];
274         
275 }
276
277
278
279 - (NSTabView *)tabView {
280
281         return tabView;
282
283 }
284
285 - (BOOL)canJumpToLineNow {
286
287         NSTextView *view = [self currentTextView];
288
289         return (view == xmlView) || (view == xsltView);
290         
291 }
292
293
294 - (IBAction)showJumpToLinePanel:(id)sender {
295
296         [NSApp beginSheet:[jumpToLinePanelController window]
297        modalForWindow:[[[self windowControllers] objectAtIndex:0] window]
298         modalDelegate:nil
299        didEndSelector:nil
300           contextInfo:nil];
301
302     [NSApp runModalForWindow:[jumpToLinePanelController window]];
303     [NSApp endSheet:[jumpToLinePanelController window]];
304     [[jumpToLinePanelController window] orderOut:self];
305
306         if ([jumpToLinePanelController lineNumber] == 0) {
307                 return;
308         }
309
310         [((XMLTextView *)[self currentTextView]) selectLineByNumber:[jumpToLinePanelController lineNumber]];
311
312 //      NSLog(@"jump to line: %d", [jumpToLinePanelController lineNumber]);
313
314 }
315
316
317 - (IBAction)showFindPanel:(id)sender {
318
319         [findPanelController refresh];
320
321         [NSApp beginSheet:[findPanelController window]
322        modalForWindow:[[[self windowControllers] objectAtIndex:0] window]
323         modalDelegate:nil
324        didEndSelector:nil
325           contextInfo:nil];
326         
327     [NSApp runModalForWindow:[findPanelController window]];
328     [NSApp endSheet:[findPanelController window]];
329     [[findPanelController window] orderOut:self];
330
331         if ([findPanelController aborted]) {
332                 return;
333         }
334
335         [self findStringWithSearchFlags:[findPanelController searchFlags]];
336         
337 }
338
339
340
341
342 - (IBAction)findNext:(id)sender {
343
344         [self findStringWithSearchFlags:[findPanelController searchFlags] & NSCaseInsensitiveSearch];
345
346 }
347
348
349 - (IBAction)findPrevious:(id)sender {
350
351         [self findStringWithSearchFlags:([findPanelController searchFlags] | NSBackwardsSearch)];
352
353 }
354
355 - (BOOL)canUseSelectionForFindNow {
356
357         NSTextView *view = [self currentTextView];
358         NSRange selectedRange;
359
360         if (view == nil) {
361                 return NO;
362         }
363
364         selectedRange = [view selectedRange];
365
366         if (selectedRange.length < 1) {
367                 return NO;
368         }
369
370         return YES;
371         
372 }
373
374
375
376 - (IBAction)useSelectionForFind:(id)sender {
377
378         NSString *text;
379         NSTextView *view = [self currentTextView];
380         
381         text = [[view string] substringWithRange:[view selectedRange]];
382
383         [findPanelController setFindString:text];
384         
385 }
386
387
388
389
390 - (BOOL)canFindNow {
391
392         NSString *currentTabViewItem = [[[self tabView] selectedTabViewItem] identifier];
393         
394         if ([currentTabViewItem isEqualToString:@"xmlTab"]
395             || [currentTabViewItem isEqualToString:@"xsltTab"]
396             || [currentTabViewItem isEqualToString:@"resultTab"]) {
397                 return YES;
398         }
399
400         return NO;
401         
402 }
403
404 - (BOOL)canFindAgainNow {
405
406         return ([findPanelController findString] != nil) && [self canFindNow];
407
408 }
409
410
411 - (void)findStringWithSearchFlags:(int)flags {
412
413         NSTextView *currentView;
414         NSString *text;
415         NSString *string;
416         NSRange selectedRange, leftRange, rightRange, resultRange, searchRange;
417
418         NSPasteboard *findBoard = [NSPasteboard pasteboardWithName:NSFindPboard];
419         [findBoard types];
420         string = [findBoard stringForType:NSStringPboardType];
421
422         currentView = [self currentTextView];
423         if (currentView == nil) {
424                 return;
425         }
426
427         text = [currentView string];
428         
429         selectedRange = [currentView selectedRange];
430         leftRange = NSMakeRange(0, selectedRange.location);
431         rightRange = NSMakeRange(NSMaxRange(selectedRange), [text length] - NSMaxRange(selectedRange));
432         
433         if (flags & NSBackwardsSearch) {
434                 searchRange = leftRange;
435         } else {
436                 searchRange = rightRange;
437         }
438         
439         resultRange = [text rangeOfString:string options:flags range:searchRange];
440
441         if (resultRange.location == NSNotFound) {
442                 NSBeep();
443                 return;
444         }
445
446         [currentView setSelectedRange:resultRange];
447         [currentView scrollRangeToVisible:resultRange];
448
449 }
450
451
452
453
454 - (NSTextView *)currentTextView {
455
456         NSString *currentTabViewItem = [[[self tabView] selectedTabViewItem] identifier];
457
458         if ([currentTabViewItem isEqualToString:@"xmlTab"]) {
459                 return xmlView;
460         } else if ([currentTabViewItem isEqualToString:@"xsltTab"]) {
461                 return xsltView;
462         } else if ([currentTabViewItem isEqualToString:@"resultTab"]) {
463                 return resultView;
464         }
465
466         return nil;
467
468 }
469
470
471
472
473
474 - (IBAction)process:(id)sender {
475
476         
477         const char **params = [[workset parameterSet] cArray];
478         
479         struct timeval tstart, tend;
480         gettimeofday(&tstart, NULL);
481         
482         long processingTime;
483
484         if ([workset hasXsltFilename]) {
485                 [processor setBaseUri:[NSString stringWithFormat:@"file://%@", [workset xsltFilename]]];
486         }
487
488         if (![processor processStrings:[workset xmlCode] withXslt:[workset xsltCode] andParameters:params]) {
489
490                 [drawerMessageField setStringValue:[NSString stringWithFormat:@"Error on line %d of your %@ code:\n%@", [processor errorLine], ([processor errorSource] == XSLT_ERROR_SOURCE_XML ? @"XML" : @"XSLT"), [processor errorMessage]]];
491
492                 NSBeep();
493                 [errorDrawer openOnEdge:NSMinYEdge];
494                 [self showErrorLocation:nil];
495
496         } else {
497
498                 gettimeofday(&tend, NULL);
499
500                 processingTime = ((tend.tv_sec * 1000000 + tend.tv_usec) - (tstart.tv_sec * 1000000 + tstart.tv_usec)) / 1000;
501                 
502                 [workset setResult:[processor result]];
503                 resultDirty = YES;
504                 [self autoSave];
505                 [errorDrawer close];
506                 [self selectTabById:RESULT];
507                 [processingTimeField setStringValue:[NSString stringWithFormat:@"Time: %ldms", processingTime]];
508         }
509
510         [self updateUI];
511 }
512
513
514 - (void)autoSave {
515
516         if (resultDirty && [autoSaveCheckbox state] == NSOnState) {
517                 [self saveResult:nil];
518         }
519
520 }
521
522 - (void)autoShow {
523
524         if ([autoShowCheckbox state] == NSOnState) {
525                 [self openResultURL:nil];
526         }
527
528 }
529
530
531 - (IBAction)loadXml:(id)sender {
532
533         NSOpenPanel *panel = [NSOpenPanel openPanel];
534
535         if ([panel runModalForDirectory:nil file:nil types:nil] == NSOKButton) {
536
537                 //      NSLog(@"choosen: %@", [[panel filenames] objectAtIndex:0]);
538
539                 [workset setXmlCode:[NSString stringWithContentsOfFile:[[panel filenames] objectAtIndex:0]]];
540                 [workset setXmlFilename:[[panel filenames] objectAtIndex:0]];
541                 [self updateChangeCount:NSChangeDone];
542                 [self updateCompleteUI];
543         }
544 }
545
546
547
548
549
550 - (IBAction)loadXslt:(id)sender {
551
552         NSOpenPanel *panel = [NSOpenPanel openPanel];
553
554         if ([panel runModalForDirectory:nil file:nil types:nil] == NSOKButton) {
555
556                 //      NSLog(@"choosen: %@", [[panel filenames] objectAtIndex:0]);
557
558                 [workset setXsltCode:[NSString stringWithContentsOfFile:[[panel filenames] objectAtIndex:0]]];
559                 [workset setXsltFilename:[[panel filenames] objectAtIndex:0]];
560                 [self updateChangeCount:NSChangeDone];
561                 [self updateCompleteUI];
562
563         }
564 }
565
566
567
568 - (IBAction)saveXmlAs:(id)sender {
569
570         NSSavePanel *panel = [NSSavePanel savePanel];
571
572         if ([panel runModal] == NSFileHandlingPanelOKButton) {
573
574                 [workset setXmlFilename:[panel filename]];
575                 [self saveXml:nil];
576
577         }
578 }
579
580
581
582 - (IBAction)saveXml:(id)sender {
583
584
585         if ([workset hasXmlFilename]) {
586                 [workset saveXml];
587                 xmlDirty = NO;
588         }
589
590         [self updateUI];
591 }
592
593
594 - (IBAction)saveXsltAs:(id)sender {
595
596         NSSavePanel *panel = [NSSavePanel savePanel];
597
598         if ([panel runModal] == NSFileHandlingPanelOKButton) {
599
600                 [workset setXsltFilename:[panel filename]];
601                 [self saveXslt:nil];
602
603         }
604 }
605
606
607
608 - (IBAction)saveXslt:(id)sender {
609
610         if ([workset hasXsltFilename]) {
611                 [workset saveXslt];
612                 xsltDirty = NO;
613         }
614
615         [self updateUI];
616 }
617
618
619
620 - (IBAction)saveResultAs:(id)sender {
621
622         NSSavePanel *panel = [NSSavePanel savePanel];
623
624         if ([panel runModal] == NSFileHandlingPanelOKButton) {
625
626                 [workset setResultFilename:[panel filename]];
627
628                 [self saveResult:nil];
629                 
630         }
631 }
632
633 - (IBAction)saveResult:(id)sender {
634
635         if ([workset hasResultFilename]) {
636
637                 [[workset result] writeToFile:[workset resultFilename] atomically:NO];
638                 resultDirty = NO;
639
640         }
641
642         [self updateUI];
643         [self autoShow];
644         
645 }
646
647
648 - (IBAction)openResultURL:(id)sender {
649
650 //      NSLog(@"openResultURL running...");
651         
652         if ([workset hasResultFilename]) {
653
654                 [[NSWorkspace sharedWorkspace] openURL:[NSURL fileURLWithPath:[workset resultFilename]]];
655
656         }
657 }
658
659
660 - (IBAction)newParameter:(id)sender {
661
662         [[workset parameterSet] addParameter:@"name" withValue:@"value"];
663         [self doUpdateUI];
664         
665 }
666
667 - (IBAction)removeParameter:(id)sender {
668
669         int row = [parameterTable selectedRow];
670
671         if (row != -1) {
672                 [[workset parameterSet] removeParameterAtIndex:row];
673                 [self doUpdateUI];
674         } else {
675                 NSBeep();
676         }
677
678 }
679
680 - (int)numberOfRowsInTableView:(NSTableView *)aTableView {
681         return [[workset parameterSet] count];
682 }
683
684 - (id)tableView:(NSTableView *)aTableView
685 objectValueForTableColumn:(NSTableColumn *)aTableColumn
686                                          row:(int)rowIndex {
687
688         return [[workset parameterSet] getField:[aTableColumn identifier] atIndex:rowIndex];
689 }
690
691
692
693 - (void)tableView:(NSTableView *)aTableView
694    setObjectValue:(id)anObject
695    forTableColumn:(NSTableColumn *)aTableColumn
696                           row:(int)rowIndex {
697
698         [[workset parameterSet] setField:[aTableColumn identifier] atIndex:rowIndex toString:anObject];
699 }
700
701
702
703
704 - (IBAction)setProcessorType:(id)sender {
705
706         int newType = [sender tag];
707
708         if ([processor processorType] == newType) {
709                 return;
710         }
711
712         [self switchProcessorToType:newType updateUI:NO];
713
714         NSLog(@"change processor type menu: %d", [sender tag]);
715
716 }
717
718
719 - (IBAction)switchProcessorToType:(int)newType updateUI:(BOOL)updateUI {
720
721         XSLTProcessor *newProcessor = nil;
722
723         newProcessor = [XSLTProcessorFactory makeProcessorOfType:newType];
724
725         if (!newProcessor) {
726                 NSLog(@"Unable to create new processor of type '%d'", newType);
727         }
728
729         [processor release];
730         processor = newProcessor;
731
732         if (updateUI) {
733                 [processorTypePopUp selectItemAtIndex:[processorTypePopUp indexOfItemWithTag:newType]];
734         }
735
736
737 }
738
739
740
741 - (id)handleProcessScriptCommand:(NSScriptCommand *)command {
742
743         if ([self canProcessNow]) {
744                 [self process:nil];
745         }
746
747         return nil;
748         
749 }
750
751
752 - (id)handleExportScriptCommand:(NSScriptCommand *)command {
753
754         NSDictionary *args = [command evaluatedArguments];
755     NSString *file = [args objectForKey:@"File"];
756
757 //      NSLog(file);
758
759         if (file != nil) {
760
761                 [workset setResultFilename:file];
762
763                 [self saveResult:nil];
764         }
765
766         return nil;
767         
768 }
769
770 - (id)handleSetParamScriptCommand:(NSScriptCommand *)command {
771
772         NSDictionary *args = [command evaluatedArguments];
773     NSString *paramName = [args objectForKey:@"Name"];
774     NSString *paramValue = [args objectForKey:@"Value"];
775
776         [[workset parameterSet] removeParameterByName:paramName];
777         
778         [[workset parameterSet] addParameter:paramName withValue:paramValue];
779         [self doUpdateUI];
780
781         return nil;
782         
783 }
784
785 - (id)handleClearParamScriptCommand:(NSScriptCommand *)command {
786
787         NSDictionary *args = [command evaluatedArguments];
788     NSString *paramName = [args objectForKey:@"Name"];
789
790         [[workset parameterSet] removeParameterByName:paramName];
791         return nil;
792         
793 }
794
795 - (id)handleSetProcessorTypeScriptCommand:(NSScriptCommand *)command {
796
797         NSDictionary *args = [command evaluatedArguments];
798     NSString *processorType = [args objectForKey:@"Name"];
799         
800         if ([processorType caseInsensitiveCompare:@"libxslt"] == NSOrderedSame) {
801
802                 [self switchProcessorToType:PROCESSORTYPE_LIBXSLT updateUI:YES];
803
804         } else if ([processorType caseInsensitiveCompare:@"sablotron"] == NSOrderedSame) {
805
806                 [self switchProcessorToType:PROCESSORTYPE_SABLOTRON updateUI:YES];
807
808         } else if ([processorType caseInsensitiveCompare:@"saxon"] == NSOrderedSame) {
809
810                 [self switchProcessorToType:PROCESSORTYPE_SAXON updateUI:YES];
811
812         } else {
813                 NSLog(@"unknown processor");
814         }
815
816         [self doUpdateUI];
817         return nil;
818
819 }
820
821 - (BOOL)handleDroppedFile:(NSString *)filename forTextView:(NSTextView *)sender {
822
823         
824         NSString *fileContents = [NSString stringWithContentsOfFile:filename];
825
826         if (fileContents == nil) {
827                 return NO;
828         }
829
830         if ([sender isEqual:xmlView]) {
831
832                 [self setXmlcode:fileContents];
833                 [workset setXmlFilename:filename];
834                 
835         } else if ([sender isEqual:xsltView]) {
836
837                 [self setXsltcode:fileContents];
838                 [workset setXsltFilename:filename];
839                 
840         } else {
841
842                 NSLog(@"Unknown sender view");
843
844         }
845
846         [self updateUI];
847         return YES;
848         
849 }
850
851
852 - (NSString *)xmlcode {
853         return [workset xmlCode];
854 }
855
856 - (void)setXmlcode:(NSString *)s {
857
858         NSString *currentContents = [[[NSString alloc] initWithString:[self xmlcode]] autorelease];
859
860         [[self undoManager] registerUndoWithTarget:self
861                                                                    selector:@selector(setXmlcode:)
862                                                                          object:currentContents];
863
864         [workset setXmlCode:s];
865         [self updateCompleteUI];
866 }
867
868
869
870 - (NSString *)xsltcode {
871         return [workset xsltCode];
872 }
873
874 - (void)setXsltcode:(NSString *)s {
875
876         NSString *currentContents = [[[NSString alloc] initWithString:[self xsltcode]] autorelease];
877
878         [[self undoManager] registerUndoWithTarget:self
879                                                                           selector:@selector(setXsltcode:)
880                                                                             object:currentContents];
881
882         [workset setXsltCode:s];
883         [self updateCompleteUI];
884 }
885
886
887 - (NSString *)result {
888         return [workset result];
889 }
890
891
892
893 - (void)tableViewSelectionDidChange:(NSNotification *)notification {
894         [self doUpdateUI];
895 }
896
897
898 - (void)checkForExternalModifications {
899
900         BOOL keep = NO;
901         
902         if ([workset xmlModifiedExternally] && xmlDirty || [workset xsltModifiedExternally] && xsltDirty) {
903
904                 /* external changes conflicting with local changes detected.
905                  * Ask the user if we should keep the local unsaved changes
906                  */
907                 keep = [self showUnsavedChangesPanel];
908
909         }
910
911         if ([workset xmlModifiedExternally] && !(xmlDirty && keep)) {
912                         [workset reloadXmlFromFile];
913                         [self updateChangeCount:NSChangeDone];
914                         [self updateCompleteUI];
915                         xmlDirty = NO;
916         }
917
918         if ([workset xsltModifiedExternally] && !(xsltDirty && keep)) {
919                         [workset reloadXsltFromFile];
920                         [self updateChangeCount:NSChangeDone];
921                         [self updateCompleteUI];
922                         xsltDirty = NO;
923         }
924
925         [self updateUI];
926         
927 }
928
929
930 - (BOOL)showUnsavedChangesPanel {
931
932         [NSApp beginSheet:[unsavedChangesPanelController window]
933         modalForWindow:[[[self windowControllers] objectAtIndex:0] window]
934          modalDelegate:nil
935         didEndSelector:nil
936            contextInfo:nil];
937
938     [NSApp runModalForWindow:[unsavedChangesPanelController window]];
939     [NSApp endSheet:[unsavedChangesPanelController window]];
940     [[unsavedChangesPanelController window] orderOut:self];
941
942         return ([unsavedChangesPanelController keepChanges]);
943
944 }
945
946
947 - (void)windowDidBecomeMain:(NSNotification *)aNotification {
948
949         [self checkForExternalModifications];
950
951 }
952
953 - (void)windowDidResize:(NSNotification *)aNotification {
954
955         [self resizeWebView];
956         
957 }
958
959 - (void)resizeWebView {
960         
961         [[[resultWebView mainFrame] frameView] setFrame:[resultWebView frame]];
962         [resultWebView setNeedsDisplay:YES];
963
964 }
965
966
967
968
969
970 - (NSString *)windowNibName
971 {
972     // Override returning the nib file name of the document
973     // If you need to use a subclass of NSWindowController or if your document supports multiple NSWindowControllers, you should remove this method and override -makeWindowControllers instead.
974     return @"MyDocument";
975 }
976
977 - (void)windowControllerDidLoadNib:(NSWindowController *) aController
978 {
979         NSFont *computerFont = [resultView font];
980         
981         NSLog(@"resultview: ", resultView);
982         NSLog(@"font: ", computerFont);
983                 
984         NSSize errorDrawerSize;
985
986         [super windowControllerDidLoadNib:aController];
987
988
989         // Add any code here that need to be executed once the windowController has loaded the document's window.
990
991         // register our two input text views to receive file drags
992         //
993 //      [xmlView registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType, nil]];
994 //      [xsltView registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType, nil]];
995
996 /*
997         [xmlView setFont:computerFont];
998         [xsltView setFont:computerFont];
999 */
1000         [xmlView setAllowsUndo:YES];
1001         [xsltView setAllowsUndo:YES];
1002
1003         [resultWebView setTextSizeMultiplier:0.9];
1004         
1005         warningIcon = [xmlWellFormedIcon image];
1006         
1007         [self updateCompleteUI];
1008
1009         errorDrawerSize = [errorDrawer contentSize];
1010         errorDrawerSize.height = 130;
1011         [errorDrawer setContentSize:errorDrawerSize];
1012
1013         if (findPanelController == nil) {
1014                 findPanelController = [[FindPanelController alloc] initWithWindowNibName:@"FindPanel"];
1015 //              NSLog(@"init find panel controller: %@", findPanelController);
1016         }
1017
1018         if (jumpToLinePanelController == nil) {
1019                 jumpToLinePanelController = [[JumpToLinePanelController alloc] initWithWindowNibName:@"JumpToLine"];
1020 //              NSLog(@"init jump to line panel controller: %@", jumpToLinePanelController);
1021         }
1022
1023         if (unsavedChangesPanelController == nil) {
1024                 unsavedChangesPanelController = [[UnsavedChangesPanelController alloc] initWithWindowNibName:@"UnsavedChanges"];
1025 //              NSLog(@"init unsaved changes panel controller: %@", unsavedChangesPanelController);
1026         }
1027
1028         
1029
1030         
1031 }
1032
1033
1034
1035 - (IBAction)showErrorLocation:(id)sender {
1036
1037         XMLTextView *textView;
1038         int errorLine = 0;
1039
1040         if ([processor errorSource] == XSLT_ERROR_SOURCE_XML) {
1041                 [self selectTabById:XML];
1042                 textView = xmlView;
1043         } else {
1044                 [self selectTabById:XSLT];
1045                 textView = xsltView;
1046         }
1047
1048         errorLine = [processor errorLine];
1049
1050         [textView selectLineByNumber:errorLine];
1051 }
1052
1053
1054 - (NSData *)dataRepresentationOfType:(NSString *)aType
1055 {
1056     // Insert code here to write your document from the given data.  You can also choose to override -fileWrapperRepresentationOfType: or -writeToFile:ofType: instead.
1057         return [NSArchiver archivedDataWithRootObject:workset];
1058 }
1059
1060 - (BOOL)loadDataRepresentation:(NSData *)data ofType:(NSString *)aType
1061 {
1062     // Insert code here to read your document from the given data.  You can also choose to override -loadFileWrapperRepresentation:ofType: or -readFromFile:ofType: instead.
1063
1064         [workset release];
1065         workset = [[NSUnarchiver unarchiveObjectWithData:data] retain];
1066         [self updateCompleteUI];
1067
1068         return YES;
1069 }
1070
1071 @end