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