checking in version 3.0
[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         NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
29     NSDictionary *appDefaults = [NSDictionary
30         dictionaryWithObject:@"YES" forKey:@"AnalyzeCode"];
31         
32     [defaults registerDefaults:appDefaults];
33         
34         
35         return self;
36 }
37
38 - (void)dealloc {
39
40         [workset release];
41         [processor release];
42         [wellFormedParser release];
43         [findPanelController release];
44         [jumpToLinePanelController release];
45         [unsavedChangesPanelController release];
46
47 }
48
49 - (IBAction)selectTab:(id)sender {
50
51         [self selectTabById:[sender tag]];
52         
53 }
54
55
56
57
58
59
60 - (IBAction)selectTabById:(int)tabId {
61
62         NSString *tabName;
63
64         switch (tabId) {
65
66                 case XML:
67                         tabName = @"xmlTab";
68                         break;
69
70                 case XSLT:
71                         tabName = @"xsltTab";
72                         break;
73
74                 case PARAMETERS:
75                         tabName = @"parametersTab";
76                         break;
77
78                 case RESULT:
79                 default:
80                         tabName = @"resultTab";
81                         break;
82
83
84         }
85
86         [tabView selectTabViewItemWithIdentifier:tabName];
87
88 }
89
90 - (void)textViewDidChangeSelection:(NSNotification *)aNotification {
91         [self updateUI];
92 }
93
94
95 - (void)tabView:(NSTabView *)tabView didSelectTabViewItem:(NSTabViewItem *)tabViewItem {
96
97         [[self undoManager] removeAllActions];
98
99         [self doUpdateUI];
100 }
101
102
103
104
105 - (void)updateUI {
106         
107 //      NSLog(@"updateUI running...");
108
109         [uiUpdateTimer invalidate];
110         [uiUpdateTimer release];
111
112         uiUpdateTimer = [NSTimer scheduledTimerWithTimeInterval:0.2 target:self selector:@selector(uiUpdateTimerTarget:) userInfo:nil repeats:NO];
113
114         [uiUpdateTimer retain];
115
116         
117 }
118
119 - (void)uiUpdateTimerTarget:(NSTimer *)timer {
120
121         [self doUpdateUI];
122         [timer release];
123         uiUpdateTimer = nil;
124 }
125
126
127
128
129 - (void)doUpdateUI {
130
131         NSString *activeTabIdentifier = [[tabView selectedTabViewItem] identifier];
132         NSString *activeResultTabIdentifier = [[resultTabView selectedTabViewItem] identifier];
133
134         BOOL xmlTabIsVisible = [activeTabIdentifier isEqualToString:@"xmlTab"];
135         BOOL xsltTabIsVisible = !xmlTabIsVisible && [activeTabIdentifier isEqualToString:@"xsltTab"];
136         BOOL paramTabIsVisible = !(xmlTabIsVisible || xsltTabIsVisible) && [activeTabIdentifier isEqualToString:@"parametersTab"];
137         BOOL resultTabIsVisible = !(xmlTabIsVisible || xsltTabIsVisible || paramTabIsVisible);
138         BOOL resultTabHtmlIsVisible = resultTabIsVisible && [activeResultTabIdentifier isEqualToString:@"htmlResult"];
139         BOOL resultTabXslfoIsVisible = resultTabIsVisible && !resultTabHtmlIsVisible && [activeResultTabIdentifier isEqualToString:@"xslfoResult"];
140         BOOL resultTabTextIsVisible = resultTabIsVisible && !(resultTabHtmlIsVisible || resultTabXslfoIsVisible);
141         
142 //      NSLog(@"xml: %d, xslt: %d, param: %d, result: %d, reshtml: %d, resxslfo: %d, restext: %d", xmlTabIsVisible, xsltTabIsVisible, paramTabIsVisible, resultTabIsVisible, resultTabHtmlIsVisible, resultTabXslfoIsVisible, resultTabTextIsVisible);
143         
144         if (xmlTabIsVisible) {
145                 [saveXmlFilenameField setObjectValue:[workset xmlFilename]];
146                 [saveXmlFilenameField setToolTip:[workset xmlFilename]];
147                 [saveXmlButton setEnabled:[self canSaveXmlNow]];
148                 [saveXmlAsButton setEnabled:[self canSaveXmlAsNow]];
149                 [xmlTagStackField setStringValue:[xmlView calculateTagStack]];
150         
151                 [xmlView checkWellFormed];
152                 if ([workset hasXmlCode] && [xmlView hasError]) {
153                         [xmlWellFormedIcon setImage:warningIcon];
154                         [xmlWellFormedIcon setToolTip:[xmlView valueForKey:@"errorString"]];
155                 } else {
156                         [xmlWellFormedIcon setImage:nil];
157                         [xmlWellFormedIcon setToolTip:nil];
158                 }
159         
160         } else if (xsltTabIsVisible) {
161                 [saveXsltFilenameField setObjectValue:[workset xsltFilename]];
162                 [saveXsltFilenameField setToolTip:[workset xsltFilename]];
163                 [saveXsltButton setEnabled:[self canSaveXsltNow]];
164                 [saveXsltAsButton setEnabled:[self canSaveXsltAsNow]];
165                 [xsltTagStackField setStringValue:[xsltView calculateTagStack]];
166
167                 [xsltView checkWellFormed];
168                 if ([workset hasXsltCode] && [xsltView hasError]) {
169                         [xsltWellFormedIcon setImage:warningIcon];
170                         [xsltWellFormedIcon setToolTip:[xsltView valueForKey:@"errorString"]];
171                 } else {
172                         [xsltWellFormedIcon setImage:nil];
173                         [xsltWellFormedIcon setToolTip:nil];
174                 }
175
176         } else if (paramTabIsVisible) {
177                 [paramRemoveButton setEnabled:[parameterTable selectedRow] != -1];
178                 [parameterTable reloadData];
179         } else if (resultTabIsVisible) {
180                 [saveResultAsButton setEnabled:[self canSaveResultAsNow]];
181                 [saveResultButton setEnabled:[self canSaveResultNow]];
182                 [autoSaveCheckbox setEnabled:[workset hasResultFilename]];
183                 [openResultURLButton setEnabled:[workset hasResultFilename]];
184                 [autoShowCheckbox setEnabled:[openResultURLButton isEnabled]];
185                 [saveResultFilenameField setObjectValue:[workset resultFilename]];
186                 [saveResultFilenameField setToolTip:[workset resultFilename]];
187
188                 if (resultTabHtmlIsVisible) {
189                         [self resizeWebView];
190                         [self updateResultWebView];
191                 } else if (resultTabXslfoIsVisible) {
192                         [self updateResultImageView];
193                         [pdfCurrentPageField setIntValue: (pdfPageCount ? (pdfCurrentPage + 1) : 0)];
194                         [pdfPageCountField setIntValue:pdfPageCount];
195                         
196                         [pdfPreviousPageButton setEnabled:pdfCurrentPage > 0];
197                         [pdfNextPageButton setEnabled:pdfCurrentPage < (pdfPageCount - 1)];
198                         [pdfSaveAsButton setEnabled:(pdfPageCount > 0)];
199 //              } else if (resultTabTextIsVisible) {
200                         
201                 }
202         }
203         
204
205         [processButton setEnabled:[self canProcessNow]];
206         
207         // move this to xmlview.
208 //      [self updateWellFormedIcons];
209         
210
211         
212         [resultView setString:[workset stringResult]];
213         
214 }
215
216
217 - (void)updateResultWebView {
218         if (!webViewUpToDate) {
219                 WebFrame *mainFrame = [resultWebView mainFrame];
220 //              [mainFrame loadHTMLString:[workset stringResult] baseURL:nil];
221                 [mainFrame loadHTMLString:[workset stringResult] baseURL:[NSURL URLWithString:[webViewBaseURL stringValue]]];
222 //              [mainFrame loadHTMLString:[workset stringResult] baseURL:[NSURL URLWithString:@"file:///Users/liyanage/Sites/primavera/images/x"]];
223                 webViewUpToDate = YES;
224         }
225 }
226
227
228 - (void)updateResultImageView {
229         if (!imageViewUpToDate) {
230                 [self renderFo:self];
231                 imageViewUpToDate = YES;
232         }
233 }
234
235
236
237 - (BOOL)canProcessNow {
238
239         return [workset hasXmlCode] && [workset hasXsltCode];
240
241 }
242
243 - (BOOL)validateMenuItem:(NSMenuItem *)menuItem {
244
245 //      NSLog(@"validate: %@, tag: %d", menuItem, [menuItem tag]);
246
247         NSString *activeTabIdentifier = [[tabView selectedTabViewItem] identifier];
248         BOOL xmlTabIsVisible = [activeTabIdentifier isEqualToString:@"xmlTab"];
249         BOOL xsltTabIsVisible = !xmlTabIsVisible && [activeTabIdentifier isEqualToString:@"xsltTab"];
250         BOOL paramTabIsVisible = !(xmlTabIsVisible || xsltTabIsVisible) && [activeTabIdentifier isEqualToString:@"parametersTab"];
251         BOOL resultTabIsVisible = !(xmlTabIsVisible || xsltTabIsVisible || paramTabIsVisible);
252
253         
254         switch ([menuItem tag]) {
255
256                 case 10:        // Process
257                         return [self canProcessNow];
258                         break;
259
260                 case 11:        // Save
261                         return [workset hasResultFilename];
262                         break;
263
264                 case 12:        // Find
265                         return [self canFindNow];
266                         break;
267
268                 case 13:        // Find Next
269                 case 14:        // Find Previous
270                         return [self canFindAgainNow];
271                         break;
272
273                 case 15:        // Use Selection for Find
274                         return [self canUseSelectionForFindNow];
275                         break;
276
277                 case 16:        // Jump to Line
278                         return [self canJumpToLineNow];
279                         break;
280                         
281                 case 17:        // Save Current Pane
282                         if (xmlTabIsVisible) {
283                                 return [self canSaveXmlNow];
284                         } else if (xsltTabIsVisible) {
285                                 return [self canSaveXsltNow];
286                         } else if (resultTabIsVisible) {
287                                 return [self canSaveResultNow];
288                         }
289                         break;
290                         
291                 case 18:        // Save Current Pane As...
292                         if (xmlTabIsVisible) {
293                                 return [self canSaveXmlAsNow];
294                         } else if (xsltTabIsVisible) {
295                                 return [self canSaveXsltAsNow];
296                         } else if (resultTabIsVisible) {
297                                 return [self canSaveResultAsNow];
298                         }
299                         break;
300                         
301                 default:
302                         return YES;
303                         break;
304
305         }
306
307
308 }
309
310 - (IBAction)showInBrowser:(id)sender {
311
312         
313
314 }
315
316
317 - (void)updateCompleteUI {
318
319         [xmlView setString:[workset xmlCode]];
320         [xsltView setString:[workset xsltCode]];
321         [self doUpdateUI];
322         
323 }
324
325 - (void)textDidChange:(NSNotification *)aNotification {
326
327         id sender = [aNotification object];
328
329         if ([sender isEqual:xmlView]) {
330                 [workset setXmlCode:[xmlView string]];
331                 xmlDirty = YES;
332         } else if ([sender isEqual:xsltView]) {
333                 [workset setXsltCode:[xsltView string]];
334                 xsltDirty = YES;
335         }
336
337         [self updateChangeCount:NSChangeDone];
338         [self updateUI];
339         
340 }
341
342
343
344 - (NSTabView *)tabView {
345
346         return tabView;
347
348 }
349
350 - (BOOL)canJumpToLineNow {
351
352         NSTextView *view = [self currentTextView];
353
354         return (view == xmlView) || (view == xsltView);
355         
356 }
357
358
359 - (IBAction)showJumpToLinePanel:(id)sender {
360
361         [NSApp beginSheet:[jumpToLinePanelController window]
362        modalForWindow:[[[self windowControllers] objectAtIndex:0] window]
363         modalDelegate:nil
364        didEndSelector:nil
365           contextInfo:nil];
366
367     [NSApp runModalForWindow:[jumpToLinePanelController window]];
368     [NSApp endSheet:[jumpToLinePanelController window]];
369     [[jumpToLinePanelController window] orderOut:self];
370
371         if ([jumpToLinePanelController lineNumber] == 0) {
372                 return;
373         }
374
375         [((XMLTextView *)[self currentTextView]) selectLineByNumber:[jumpToLinePanelController lineNumber]];
376
377 //      NSLog(@"jump to line: %d", [jumpToLinePanelController lineNumber]);
378
379 }
380
381
382 - (IBAction)showFindPanel:(id)sender {
383
384         [findPanelController refresh];
385
386         [NSApp beginSheet:[findPanelController window]
387        modalForWindow:[[[self windowControllers] objectAtIndex:0] window]
388         modalDelegate:nil
389        didEndSelector:nil
390           contextInfo:nil];
391         
392     [NSApp runModalForWindow:[findPanelController window]];
393     [NSApp endSheet:[findPanelController window]];
394     [[findPanelController window] orderOut:self];
395
396         if ([findPanelController aborted]) {
397                 return;
398         }
399
400         [self findStringWithSearchFlags:[findPanelController searchFlags]];
401         
402 }
403
404
405
406
407 - (IBAction)findNext:(id)sender {
408
409         [self findStringWithSearchFlags:[findPanelController searchFlags] & NSCaseInsensitiveSearch];
410
411 }
412
413
414 - (IBAction)findPrevious:(id)sender {
415
416         [self findStringWithSearchFlags:([findPanelController searchFlags] | NSBackwardsSearch)];
417
418 }
419
420 - (BOOL)canUseSelectionForFindNow {
421
422         NSTextView *view = [self currentTextView];
423         NSRange selectedRange;
424
425         if (view == nil) {
426                 return NO;
427         }
428
429         selectedRange = [view selectedRange];
430
431         if (selectedRange.length < 1) {
432                 return NO;
433         }
434
435         return YES;
436         
437 }
438
439
440
441 - (IBAction)useSelectionForFind:(id)sender {
442
443         NSString *text;
444         NSTextView *view = [self currentTextView];
445         
446         text = [[view string] substringWithRange:[view selectedRange]];
447
448         [findPanelController setFindString:text];
449         
450 }
451
452
453
454
455 - (BOOL)canFindNow {
456
457         NSString *currentTabViewItem = [[[self tabView] selectedTabViewItem] identifier];
458         
459         if ([currentTabViewItem isEqualToString:@"xmlTab"]
460             || [currentTabViewItem isEqualToString:@"xsltTab"]
461             || [currentTabViewItem isEqualToString:@"resultTab"]) {
462                 return YES;
463         }
464
465         return NO;
466         
467 }
468
469 - (BOOL)canFindAgainNow {
470
471         return ([findPanelController findString] != nil) && [self canFindNow];
472
473 }
474
475
476 - (void)findStringWithSearchFlags:(int)flags {
477
478         NSTextView *currentView;
479         NSString *text;
480         NSString *string;
481         NSRange selectedRange, leftRange, rightRange, resultRange, searchRange;
482
483         NSPasteboard *findBoard = [NSPasteboard pasteboardWithName:NSFindPboard];
484         [findBoard types];
485         string = [findBoard stringForType:NSStringPboardType];
486
487         currentView = [self currentTextView];
488         if (currentView == nil) {
489                 return;
490         }
491
492         text = [currentView string];
493         
494         selectedRange = [currentView selectedRange];
495         leftRange = NSMakeRange(0, selectedRange.location);
496         rightRange = NSMakeRange(NSMaxRange(selectedRange), [text length] - NSMaxRange(selectedRange));
497         
498         if (flags & NSBackwardsSearch) {
499                 searchRange = leftRange;
500         } else {
501                 searchRange = rightRange;
502         }
503         
504         resultRange = [text rangeOfString:string options:flags range:searchRange];
505
506         if (resultRange.location == NSNotFound) {
507                 NSBeep();
508                 return;
509         }
510
511         [currentView setSelectedRange:resultRange];
512         [currentView scrollRangeToVisible:resultRange];
513
514 }
515
516
517
518
519 - (NSTextView *)currentTextView {
520
521         NSString *currentTabViewItem = [[[self tabView] selectedTabViewItem] identifier];
522
523         if ([currentTabViewItem isEqualToString:@"xmlTab"]) {
524                 return xmlView;
525         } else if ([currentTabViewItem isEqualToString:@"xsltTab"]) {
526                 return xsltView;
527         } else if ([currentTabViewItem isEqualToString:@"resultTab"]) {
528                 return resultView;
529         }
530
531         return nil;
532
533 }
534
535
536
537
538
539 - (IBAction)process:(id)sender {
540
541         
542         const char **params = [[workset parameterSet] cArray];
543         
544         struct timeval tstart, tend;
545         gettimeofday(&tstart, NULL);
546         
547         long processingTime;
548
549         if ([workset hasXsltFilename]) {
550                 [processor setBaseUri:[NSString stringWithFormat:@"file://%@", [workset xsltFilename]]];
551         }
552
553         if (![processor processStrings:[XMLUtils getDataWithEncodingFromString:[workset xmlCode]] withXslt:[XMLUtils getDataWithEncodingFromString:[workset xsltCode]] andParameters:params]) {
554
555                 [drawerMessageField setStringValue:[NSString stringWithFormat:@"Error on line %d of your %@ code:\n%@", [processor errorLine], ([processor errorSource] == XSLT_ERROR_SOURCE_XML ? @"XML" : @"XSLT"), [processor errorMessage]]];
556
557                 NSBeep();
558                 [errorDrawer openOnEdge:NSMinYEdge];
559                 [self showErrorLocation:nil];
560
561         } else {
562
563                 gettimeofday(&tend, NULL);
564
565                 processingTime = ((tend.tv_sec * 1000000 + tend.tv_usec) - (tstart.tv_sec * 1000000 + tstart.tv_usec)) / 1000;
566                 
567                 [workset setResult:[processor result]];
568                 [workset setResultEncoding:[processor resultEncoding]];
569                 resultDirty = YES;
570                 [self autoSave];
571                 [errorDrawer close];
572                 [self selectTabById:RESULT];
573                 [processingTimeField setStringValue:[NSString stringWithFormat:@"Time: %ldms", processingTime]];
574         }
575
576         webViewUpToDate = NO;
577         imageViewUpToDate = NO;
578         
579         [self updateUI];
580 }
581
582
583 - (void)autoSave {
584
585         if (resultDirty && [autoSaveCheckbox state] == NSOnState) {
586                 [self saveResult:nil];
587         }
588
589 }
590
591 - (void)autoShow {
592
593         if ([autoShowCheckbox state] == NSOnState) {
594                 [self openResultURL:nil];
595         }
596
597 }
598
599
600 - (IBAction)loadXml:(id)sender {
601
602         NSOpenPanel *panel = [NSOpenPanel openPanel];
603
604         if ([panel runModalForDirectory:nil file:nil types:nil] == NSOKButton) {
605
606                 //      NSLog(@"choosen: %@", [[panel filenames] objectAtIndex:0]);
607
608                 [workset setXmlCode:[XMLUtils getStringWithEncodingFromFile:[[panel filenames] objectAtIndex:0]]];
609                 [workset setXmlFilename:[[panel filenames] objectAtIndex:0]];
610                 [self updateChangeCount:NSChangeDone];
611                 [self updateCompleteUI];
612         }
613 }
614
615
616
617
618
619 - (IBAction)loadXslt:(id)sender {
620
621         NSOpenPanel *panel = [NSOpenPanel openPanel];
622
623         if ([panel runModalForDirectory:nil file:nil types:nil] == NSOKButton) {
624
625                 //      NSLog(@"choosen: %@", [[panel filenames] objectAtIndex:0]);
626
627                 [workset setXsltCode:[XMLUtils getStringWithEncodingFromFile:[[panel filenames] objectAtIndex:0]]];
628                 [workset setXsltFilename:[[panel filenames] objectAtIndex:0]];
629                 [self updateChangeCount:NSChangeDone];
630                 [self updateCompleteUI];
631
632         }
633 }
634
635
636
637
638 - (BOOL)canSaveXmlAsNow {
639         return [workset hasXmlCode];
640 }
641
642 - (BOOL)canSaveXmlNow {
643         return [workset hasXmlFilename] && xmlDirty;
644 }
645
646 - (BOOL)canSaveXsltAsNow {
647         return [workset hasXsltCode];
648 }
649
650 - (BOOL)canSaveXsltNow {
651         return [workset hasXsltFilename] && xsltDirty;
652 }
653
654 - (BOOL)canSaveResultAsNow {
655         return [workset hasResult];
656 }
657
658 - (BOOL)canSaveResultNow {
659         return [workset hasResultFilename] && resultDirty;
660 }
661
662
663
664
665 - (IBAction)saveXmlAs:(id)sender {
666
667         NSSavePanel *panel = [NSSavePanel savePanel];
668
669         if ([panel runModal] == NSFileHandlingPanelOKButton) {
670
671                 [workset setXmlFilename:[panel filename]];
672                 [self saveXml:nil];
673
674         }
675 }
676
677
678
679 - (IBAction)saveXml:(id)sender {
680
681
682         if ([workset hasXmlFilename]) {
683                 [workset saveXml];
684                 xmlDirty = NO;
685         }
686
687         [self updateUI];
688 }
689
690
691 - (IBAction)saveXsltAs:(id)sender {
692
693         NSSavePanel *panel = [NSSavePanel savePanel];
694
695         if ([panel runModal] == NSFileHandlingPanelOKButton) {
696
697                 [workset setXsltFilename:[panel filename]];
698                 [self saveXslt:nil];
699
700         }
701 }
702
703
704
705 - (IBAction)saveXslt:(id)sender {
706
707         if ([workset hasXsltFilename]) {
708                 [workset saveXslt];
709                 xsltDirty = NO;
710         }
711
712         [self updateUI];
713 }
714
715
716
717 - (IBAction)saveResultAs:(id)sender {
718
719         NSSavePanel *panel = [NSSavePanel savePanel];
720
721         if ([panel runModal] == NSFileHandlingPanelOKButton) {
722
723                 [workset setResultFilename:[panel filename]];
724
725                 [self saveResult:nil];
726                 
727         }
728 }
729
730 - (IBAction)saveResult:(id)sender {
731
732         if ([workset hasResultFilename]) {
733
734                 [[workset result] writeToFile:[workset resultFilename] atomically:NO];
735                 resultDirty = NO;
736
737         }
738
739         [self updateUI];
740         [self autoShow];
741         
742 }
743
744
745 - (IBAction)saveCurrentAs:(id)sender {
746         
747         NSString *activeTabIdentifier = [[tabView selectedTabViewItem] identifier];
748         BOOL xmlTabIsVisible = [activeTabIdentifier isEqualToString:@"xmlTab"];
749         BOOL xsltTabIsVisible = !xmlTabIsVisible && [activeTabIdentifier isEqualToString:@"xsltTab"];
750         BOOL paramTabIsVisible = !(xmlTabIsVisible || xsltTabIsVisible) && [activeTabIdentifier isEqualToString:@"parametersTab"];
751         BOOL resultTabIsVisible = !(xmlTabIsVisible || xsltTabIsVisible || paramTabIsVisible);
752         
753         if (xmlTabIsVisible) {
754                 return [self saveXmlAs:sender];
755         } else if (xsltTabIsVisible) {
756                 return [self saveXsltAs:sender];
757         } else if (resultTabIsVisible) {
758                 return [self saveResultAs:sender];
759         }
760
761 }
762
763
764
765
766 - (IBAction)saveCurrent:(id)sender {
767
768         NSString *activeTabIdentifier = [[tabView selectedTabViewItem] identifier];
769         BOOL xmlTabIsVisible = [activeTabIdentifier isEqualToString:@"xmlTab"];
770         BOOL xsltTabIsVisible = !xmlTabIsVisible && [activeTabIdentifier isEqualToString:@"xsltTab"];
771         BOOL paramTabIsVisible = !(xmlTabIsVisible || xsltTabIsVisible) && [activeTabIdentifier isEqualToString:@"parametersTab"];
772         BOOL resultTabIsVisible = !(xmlTabIsVisible || xsltTabIsVisible || paramTabIsVisible);
773         
774         if (xmlTabIsVisible) {
775                 return [self saveXml:sender];
776         } else if (xsltTabIsVisible) {
777                 return [self saveXslt:sender];
778         } else if (resultTabIsVisible) {
779                 return [self saveResult:sender];
780         }
781         
782 }
783
784
785
786
787
788
789 - (IBAction)openResultURL:(id)sender {
790
791 //      NSLog(@"openResultURL running...");
792         
793         if ([workset hasResultFilename]) {
794
795                 [[NSWorkspace sharedWorkspace] openURL:[NSURL fileURLWithPath:[workset resultFilename]]];
796
797         }
798 }
799
800
801 - (IBAction)newParameter:(id)sender {
802
803         [[workset parameterSet] addParameter:@"name" withValue:@"value"];
804         [self doUpdateUI];
805         
806 }
807
808 - (IBAction)removeParameter:(id)sender {
809
810         int row = [parameterTable selectedRow];
811
812         if (row != -1) {
813                 [[workset parameterSet] removeParameterAtIndex:row];
814                 [self doUpdateUI];
815         } else {
816                 NSBeep();
817         }
818
819 }
820
821 - (int)numberOfRowsInTableView:(NSTableView *)aTableView {
822         return [[workset parameterSet] count];
823 }
824
825 - (id)tableView:(NSTableView *)aTableView
826 objectValueForTableColumn:(NSTableColumn *)aTableColumn
827                                          row:(int)rowIndex {
828
829         return [[workset parameterSet] getField:[aTableColumn identifier] atIndex:rowIndex];
830 }
831
832
833
834 - (void)tableView:(NSTableView *)aTableView
835    setObjectValue:(id)anObject
836    forTableColumn:(NSTableColumn *)aTableColumn
837                           row:(int)rowIndex {
838
839         [[workset parameterSet] setField:[aTableColumn identifier] atIndex:rowIndex toString:anObject];
840 }
841
842
843
844
845 - (IBAction)setProcessorType:(id)sender {
846
847         int newType = [sender tag];
848
849         if ([processor processorType] == newType) {
850                 return;
851         }
852
853         [self switchProcessorToType:newType updateUI:NO];
854
855 }
856
857
858 - (IBAction)switchProcessorToType:(int)newType updateUI:(BOOL)updateUI {
859
860         XSLTProcessor *newProcessor = nil;
861
862         newProcessor = [XSLTProcessorFactory makeProcessorOfType:newType];
863
864         if (!newProcessor) {
865                 NSLog(@"Unable to create new processor of type '%d'", newType);
866         }
867
868         [processor release];
869         processor = newProcessor;
870
871         if (updateUI) {
872                 [processorTypePopUp selectItemAtIndex:[processorTypePopUp indexOfItemWithTag:newType]];
873         }
874
875
876 }
877
878
879
880 - (id)handleProcessScriptCommand:(NSScriptCommand *)command {
881
882         if ([self canProcessNow]) {
883                 [self process:nil];
884         }
885
886         return nil;
887         
888 }
889
890
891 - (id)handleExportScriptCommand:(NSScriptCommand *)command {
892
893         NSDictionary *args = [command evaluatedArguments];
894     NSString *file = [args objectForKey:@"File"];
895
896 //      NSLog(file);
897
898         if (file != nil) {
899
900                 [workset setResultFilename:file];
901
902                 [self saveResult:nil];
903         }
904
905         return nil;
906         
907 }
908
909 - (id)handleSetParamScriptCommand:(NSScriptCommand *)command {
910
911         NSDictionary *args = [command evaluatedArguments];
912     NSString *paramName = [args objectForKey:@"Name"];
913     NSString *paramValue = [args objectForKey:@"Value"];
914
915         [[workset parameterSet] removeParameterByName:paramName];
916         
917         [[workset parameterSet] addParameter:paramName withValue:paramValue];
918         [self doUpdateUI];
919
920         return nil;
921         
922 }
923
924 - (id)handleClearParamScriptCommand:(NSScriptCommand *)command {
925
926         NSDictionary *args = [command evaluatedArguments];
927     NSString *paramName = [args objectForKey:@"Name"];
928
929         [[workset parameterSet] removeParameterByName:paramName];
930         return nil;
931         
932 }
933
934 - (id)handleSetProcessorTypeScriptCommand:(NSScriptCommand *)command {
935
936         NSDictionary *args = [command evaluatedArguments];
937     NSString *processorType = [args objectForKey:@"Name"];
938         
939         if ([processorType caseInsensitiveCompare:@"libxslt"] == NSOrderedSame) {
940
941                 [self switchProcessorToType:PROCESSORTYPE_LIBXSLT updateUI:YES];
942
943         } else if ([processorType caseInsensitiveCompare:@"sablotron"] == NSOrderedSame) {
944
945                 [self switchProcessorToType:PROCESSORTYPE_SABLOTRON updateUI:YES];
946
947         } else if ([processorType caseInsensitiveCompare:@"saxon"] == NSOrderedSame) {
948
949                 [self switchProcessorToType:PROCESSORTYPE_SAXON updateUI:YES];
950
951         } else if ([processorType caseInsensitiveCompare:@"xalan-j"] == NSOrderedSame) {
952                 
953                 [self switchProcessorToType:PROCESSORTYPE_XALAN_J updateUI:YES];
954                 
955         } else {
956                 NSLog(@"unknown processor");
957         }
958
959         [self doUpdateUI];
960         return nil;
961
962 }
963
964 - (BOOL)handleDroppedFile:(NSString *)filename forTextView:(NSTextView *)sender {
965
966         NSString *fileContents = [XMLUtils getStringWithEncodingFromFile:filename];
967
968         if ([sender isEqual: xmlView]) {
969
970                 [self setXmlcode:fileContents];
971                 [workset setXmlFilename:filename];
972                 
973         } else if ([sender isEqual:xsltView]) {
974
975                 [self setXsltcode:fileContents];
976                 [workset setXsltFilename:filename];
977                 
978         } else {
979
980                 NSLog(@"Unknown sender view");
981
982         }
983
984         [self updateUI];
985         return YES;
986         
987 }
988
989
990
991
992 - (NSString *)xmlcode {
993         return [workset xmlCode];
994 }
995
996 - (void)setXmlcode:(NSString *)s {
997
998         NSString *currentContents = [[[NSString alloc] initWithString:[self xmlcode]] autorelease];
999
1000         [[self undoManager] registerUndoWithTarget:self
1001                                                                    selector:@selector(setXmlcode:)
1002                                                                          object:currentContents];
1003
1004         [workset setXmlCode:s];
1005         [self updateCompleteUI];
1006 }
1007
1008
1009
1010 - (NSString *)xsltcode {
1011         return [workset xsltCode];
1012 }
1013
1014 - (void)setXsltcode:(NSString *)s {
1015
1016         NSString *currentContents = [[[NSString alloc] initWithString:[self xsltcode]] autorelease];
1017
1018         [[self undoManager] registerUndoWithTarget:self
1019                                                                           selector:@selector(setXsltcode:)
1020                                                                             object:currentContents];
1021
1022         [workset setXsltCode:s];
1023         [self updateCompleteUI];
1024 }
1025
1026
1027 - (NSString *)result {
1028         return [workset stringResult];
1029 }
1030
1031
1032
1033 - (void)tableViewSelectionDidChange:(NSNotification *)notification {
1034         [self doUpdateUI];
1035 }
1036
1037
1038 - (void)checkForExternalModifications {
1039
1040         BOOL keep = NO;
1041         
1042         if ([workset xmlModifiedExternally] && xmlDirty || [workset xsltModifiedExternally] && xsltDirty) {
1043
1044                 /* external changes conflicting with local changes detected.
1045                  * Ask the user if we should keep the local unsaved changes
1046                  */
1047                 keep = [self showUnsavedChangesPanel];
1048
1049         }
1050
1051         if ([workset xmlModifiedExternally] && !(xmlDirty && keep)) {
1052                         [workset reloadXmlFromFile];
1053                         [self updateChangeCount:NSChangeDone];
1054                         [self updateCompleteUI];
1055                         xmlDirty = NO;
1056         }
1057
1058         if ([workset xsltModifiedExternally] && !(xsltDirty && keep)) {
1059                         [workset reloadXsltFromFile];
1060                         [self updateChangeCount:NSChangeDone];
1061                         [self updateCompleteUI];
1062                         xsltDirty = NO;
1063         }
1064
1065         [self updateUI];
1066         
1067 }
1068
1069
1070 - (BOOL)showUnsavedChangesPanel {
1071
1072         [NSApp beginSheet:[unsavedChangesPanelController window]
1073         modalForWindow:[[[self windowControllers] objectAtIndex:0] window]
1074          modalDelegate:nil
1075         didEndSelector:nil
1076            contextInfo:nil];
1077
1078     [NSApp runModalForWindow:[unsavedChangesPanelController window]];
1079     [NSApp endSheet:[unsavedChangesPanelController window]];
1080     [[unsavedChangesPanelController window] orderOut:self];
1081
1082         return ([unsavedChangesPanelController keepChanges]);
1083
1084 }
1085
1086 - (IBAction)renderFo:(id)sender {
1087
1088         XSL_FO_Renderer *xfr = [[XSL_FO_Renderer alloc] init];
1089
1090         NSData *resultData = [xfr render:[workset result]];
1091
1092         [xfr release];
1093
1094         if (!resultData) {
1095                 NSLog(@"Unable to render, NULL result");
1096                 return;
1097         }
1098         
1099         [resultData retain];
1100         [pdfData release];
1101         pdfData = resultData;
1102         
1103         NSImage *pdfImage = [[[NSImage alloc] initWithData:resultData] autorelease];
1104         [pdfImage setBackgroundColor:[NSColor whiteColor]];
1105         [pdfImage recache];
1106         [pdfImage setCacheMode:NSImageCacheNever];
1107         
1108         NSClipView *clipView = (NSClipView *)[resultImageView superview];
1109         NSScrollView *scrollView = (NSScrollView *)[clipView superview];
1110         
1111         [resultImageView setImage:pdfImage];
1112         [resultImageView setFrameSize:[pdfImage size]];
1113         [resultImageView display];
1114
1115         [clipView scrollToPoint:NSMakePoint([resultImageView frame].origin.x, [resultImageView frame].size.height - [clipView frame].size.height + [resultImageView frame].origin.y)];
1116         [scrollView reflectScrolledClipView:clipView];
1117         
1118         pdfPageCount = [[[pdfImage representations] objectAtIndex:0] pageCount];
1119         pdfCurrentPage = 0;
1120                 
1121 }
1122
1123
1124 - (IBAction)pdfPreviousPage:(id)sender {
1125         
1126         if (pdfCurrentPage > 0) {
1127                 pdfCurrentPage--;
1128                 [[[[resultImageView image] representations] objectAtIndex:0] setCurrentPage:pdfCurrentPage];
1129                 [resultImageView setNeedsDisplay:YES];
1130                 [self doUpdateUI];
1131         }
1132         
1133 }
1134
1135 - (IBAction)pdfNextPage:(id)sender {
1136         
1137         if (pdfCurrentPage < (pdfPageCount - 1)) {
1138                 pdfCurrentPage++;
1139                 [[[[resultImageView image] representations] objectAtIndex:0] setCurrentPage:pdfCurrentPage];
1140                 [resultImageView setNeedsDisplay:YES];
1141                 [self doUpdateUI];
1142         }
1143         
1144 }
1145
1146
1147 - (IBAction)pdfSaveAs:(id)sender {
1148
1149         NSSavePanel *panel = [NSSavePanel savePanel];
1150         
1151         if ([panel runModal] == NSFileHandlingPanelOKButton) {
1152                 
1153                 [pdfData writeToFile:[panel filename] atomically:YES];
1154
1155         }
1156         
1157 }
1158
1159
1160
1161
1162 - (void)windowDidBecomeMain:(NSNotification *)aNotification {
1163
1164         [self checkForExternalModifications];
1165
1166 }
1167
1168 - (void)windowDidResize:(NSNotification *)aNotification {
1169
1170         [self resizeWebView];
1171         
1172 }
1173
1174 - (void)resizeWebView {
1175         
1176 //      [[[resultWebView mainFrame] frameView] setFrame:[resultWebView frame]];
1177         [resultWebView setNeedsDisplay:YES];
1178
1179 }
1180
1181
1182
1183
1184
1185 - (NSString *)windowNibName
1186 {
1187     // Override returning the nib file name of the document
1188     // 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.
1189     return @"MyDocument";
1190 }
1191
1192 - (void)windowControllerDidLoadNib:(NSWindowController *) aController
1193 {
1194
1195         
1196                 
1197         NSSize errorDrawerSize;
1198
1199         [super windowControllerDidLoadNib:aController];
1200
1201         [resultImageView setImageFrameStyle:NSImageFramePhoto];
1202         [resultImageView setImageScaling:NSScaleNone];
1203         [resultImageView setImageAlignment:NSImageAlignCenter];
1204         [resultImageView setEditable:NO];
1205         
1206         [resultWebView setTextSizeMultiplier:0.9];
1207         
1208         warningIcon = [xmlWellFormedIcon image];
1209         
1210         [self updateCompleteUI];
1211         
1212         errorDrawerSize = [errorDrawer contentSize];
1213         errorDrawerSize.height = 130;
1214         [errorDrawer setContentSize:errorDrawerSize];
1215         
1216         NSFont *computerFont = [NSFont fontWithName:@"Courier" size:12.0];
1217         [resultView setFont:computerFont];
1218
1219         [tabView registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType, nil]];
1220
1221         
1222         
1223         if (findPanelController == nil) {
1224                 findPanelController = [[FindPanelController alloc] initWithWindowNibName:@"FindPanel"];
1225 //              NSLog(@"init find panel controller: %@", findPanelController);
1226         }
1227
1228         if (jumpToLinePanelController == nil) {
1229                 jumpToLinePanelController = [[JumpToLinePanelController alloc] initWithWindowNibName:@"JumpToLine"];
1230 //              NSLog(@"init jump to line panel controller: %@", jumpToLinePanelController);
1231         }
1232
1233         if (unsavedChangesPanelController == nil) {
1234                 unsavedChangesPanelController = [[UnsavedChangesPanelController alloc] initWithWindowNibName:@"UnsavedChanges"];
1235 //              NSLog(@"init unsaved changes panel controller: %@", unsavedChangesPanelController);
1236         }
1237
1238         
1239
1240         
1241 }
1242
1243
1244 - (IBAction)showErrorLocation:(id)sender {
1245
1246         XMLTextView *textView;
1247         int errorLine = 0;
1248
1249         if ([processor errorSource] == XSLT_ERROR_SOURCE_XML) {
1250                 [self selectTabById:XML];
1251                 textView = xmlView;
1252         } else {
1253                 [self selectTabById:XSLT];
1254                 textView = xsltView;
1255         }
1256
1257         errorLine = [processor errorLine];
1258
1259         [textView selectLineByNumber:errorLine];
1260 }
1261
1262
1263 - (NSData *)dataRepresentationOfType:(NSString *)aType
1264 {
1265     // Insert code here to write your document from the given data.  You can also choose to override -fileWrapperRepresentationOfType: or -writeToFile:ofType: instead.
1266         return [NSArchiver archivedDataWithRootObject:workset];
1267 }
1268
1269 - (BOOL)loadDataRepresentation:(NSData *)data ofType:(NSString *)aType
1270 {
1271     // Insert code here to read your document from the given data.  You can also choose to override -loadFileWrapperRepresentation:ofType: or -readFromFile:ofType: instead.
1272
1273         [workset release];
1274         workset = [[NSUnarchiver unarchiveObjectWithData:data] retain];
1275         [self updateCompleteUI];
1276
1277         return YES;
1278 }
1279
1280 @end