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