fixed some warnings
[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         return [super validateMenuItem:menuItem];
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                 [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"];
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                 [self saveXmlAs:sender];
755         } else if (xsltTabIsVisible) {
756                 [self saveXsltAs:sender];
757         } else if (resultTabIsVisible) {
758                 [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                 [self saveXml:sender];
776         } else if (xsltTabIsVisible) {
777                 [self saveXslt:sender];
778         } else if (resultTabIsVisible) {
779                 [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 - (void)xslfoRenderThread {
1087
1088         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1089         
1090         XSL_FO_Renderer *xfr = [[[XSL_FO_Renderer alloc] init] autorelease];
1091         xslfoRendererResultData = [xfr render:[workset result]];
1092
1093         [pool release];
1094         [xslfoRendererLock unlockWithCondition:2];
1095         
1096 }
1097
1098
1099 - (IBAction)renderFo:(id)sender {
1100
1101         xslfoRendererLock = [[[NSConditionLock alloc] initWithCondition:1] autorelease];
1102         [NSThread detachNewThreadSelector:@selector(xslfoRenderThread) toTarget:self withObject:nil];
1103         [xslfoRendererLock lockWhenCondition:2];
1104         [xslfoRendererLock unlock];
1105         
1106         if (!xslfoRendererResultData) {
1107                 NSLog(@"Unable to render, NULL result");
1108                 return;
1109         }
1110         
1111         [xslfoRendererResultData retain];
1112         [pdfData release];
1113         pdfData = xslfoRendererResultData;
1114         
1115         NSImage *pdfImage = [[[NSImage alloc] initWithData:xslfoRendererResultData] autorelease];
1116         [pdfImage setBackgroundColor:[NSColor whiteColor]];
1117         [pdfImage recache];
1118         [pdfImage setCacheMode:NSImageCacheNever];
1119         
1120         NSClipView *clipView = (NSClipView *)[resultImageView superview];
1121         NSScrollView *scrollView = (NSScrollView *)[clipView superview];
1122         
1123         [resultImageView setImage:pdfImage];
1124         [resultImageView setFrameSize:[pdfImage size]];
1125         [resultImageView display];
1126
1127         [clipView scrollToPoint:NSMakePoint([resultImageView frame].origin.x, [resultImageView frame].size.height - [clipView frame].size.height + [resultImageView frame].origin.y)];
1128         [scrollView reflectScrolledClipView:clipView];
1129         
1130         pdfPageCount = [[[pdfImage representations] objectAtIndex:0] pageCount];
1131         pdfCurrentPage = 0;
1132                 
1133 }
1134
1135
1136 - (IBAction)pdfPreviousPage:(id)sender {
1137         
1138         if (pdfCurrentPage > 0) {
1139                 pdfCurrentPage--;
1140                 [[[[resultImageView image] representations] objectAtIndex:0] setCurrentPage:pdfCurrentPage];
1141                 [resultImageView setNeedsDisplay:YES];
1142                 [self doUpdateUI];
1143         }
1144         
1145 }
1146
1147 - (IBAction)pdfNextPage:(id)sender {
1148         
1149         if (pdfCurrentPage < (pdfPageCount - 1)) {
1150                 pdfCurrentPage++;
1151                 [[[[resultImageView image] representations] objectAtIndex:0] setCurrentPage:pdfCurrentPage];
1152                 [resultImageView setNeedsDisplay:YES];
1153                 [self doUpdateUI];
1154         }
1155         
1156 }
1157
1158
1159 - (IBAction)pdfSaveAs:(id)sender {
1160
1161         NSSavePanel *panel = [NSSavePanel savePanel];
1162         
1163         if ([panel runModal] == NSFileHandlingPanelOKButton) {
1164                 
1165                 [pdfData writeToFile:[panel filename] atomically:YES];
1166
1167         }
1168         
1169 }
1170
1171
1172
1173
1174 - (void)windowDidBecomeMain:(NSNotification *)aNotification {
1175
1176         [self checkForExternalModifications];
1177
1178 }
1179
1180 - (void)windowDidResize:(NSNotification *)aNotification {
1181
1182         [self resizeWebView];
1183         
1184 }
1185
1186 - (void)resizeWebView {
1187         
1188 //      [[[resultWebView mainFrame] frameView] setFrame:[resultWebView frame]];
1189         [resultWebView setNeedsDisplay:YES];
1190
1191 }
1192
1193
1194
1195
1196
1197 - (NSString *)windowNibName
1198 {
1199     // Override returning the nib file name of the document
1200     // 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.
1201     return @"MyDocument";
1202 }
1203
1204 - (void)windowControllerDidLoadNib:(NSWindowController *) aController
1205 {
1206
1207         
1208                 
1209         NSSize errorDrawerSize;
1210
1211         [super windowControllerDidLoadNib:aController];
1212
1213         [resultImageView setImageFrameStyle:NSImageFramePhoto];
1214         [resultImageView setImageScaling:NSScaleNone];
1215         [resultImageView setImageAlignment:NSImageAlignCenter];
1216         [resultImageView setEditable:NO];
1217         
1218         [resultWebView setTextSizeMultiplier:0.9];
1219         
1220         warningIcon = [xmlWellFormedIcon image];
1221         
1222         [self updateCompleteUI];
1223         
1224         errorDrawerSize = [errorDrawer contentSize];
1225         errorDrawerSize.height = 130;
1226         [errorDrawer setContentSize:errorDrawerSize];
1227         
1228         NSFont *computerFont = [NSFont fontWithName:@"Courier" size:12.0];
1229         [resultView setFont:computerFont];
1230
1231         [tabView registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType, nil]];
1232
1233         
1234         
1235         if (findPanelController == nil) {
1236                 findPanelController = [[FindPanelController alloc] initWithWindowNibName:@"FindPanel"];
1237 //              NSLog(@"init find panel controller: %@", findPanelController);
1238         }
1239
1240         if (jumpToLinePanelController == nil) {
1241                 jumpToLinePanelController = [[JumpToLinePanelController alloc] initWithWindowNibName:@"JumpToLine"];
1242 //              NSLog(@"init jump to line panel controller: %@", jumpToLinePanelController);
1243         }
1244
1245         if (unsavedChangesPanelController == nil) {
1246                 unsavedChangesPanelController = [[UnsavedChangesPanelController alloc] initWithWindowNibName:@"UnsavedChanges"];
1247 //              NSLog(@"init unsaved changes panel controller: %@", unsavedChangesPanelController);
1248         }
1249         
1250 }
1251
1252
1253 - (void)canCloseDocumentWithDelegate:(id)delegate shouldCloseSelector:(SEL)shouldCloseSelector contextInfo:(void *)contextInfo {
1254
1255         [uiUpdateTimer invalidate];
1256         [super canCloseDocumentWithDelegate:delegate shouldCloseSelector:shouldCloseSelector contextInfo:contextInfo];
1257 }
1258
1259
1260
1261
1262
1263
1264
1265
1266 - (IBAction)showErrorLocation:(id)sender {
1267
1268         XMLTextView *textView;
1269         int errorLine = 0;
1270
1271         if ([processor errorSource] == XSLT_ERROR_SOURCE_XML) {
1272                 [self selectTabById:XML];
1273                 textView = xmlView;
1274         } else {
1275                 [self selectTabById:XSLT];
1276                 textView = xsltView;
1277         }
1278
1279         errorLine = [processor errorLine];
1280
1281         [textView selectLineByNumber:errorLine];
1282 }
1283
1284
1285 - (NSData *)dataRepresentationOfType:(NSString *)aType
1286 {
1287     // Insert code here to write your document from the given data.  You can also choose to override -fileWrapperRepresentationOfType: or -writeToFile:ofType: instead.
1288         return [NSArchiver archivedDataWithRootObject:workset];
1289 }
1290
1291 - (BOOL)loadDataRepresentation:(NSData *)data ofType:(NSString *)aType
1292 {
1293     // Insert code here to read your document from the given data.  You can also choose to override -loadFileWrapperRepresentation:ofType: or -readFromFile:ofType: instead.
1294
1295         [workset release];
1296         workset = [[NSUnarchiver unarchiveObjectWithData:data] retain];
1297         [self updateCompleteUI];
1298
1299         return YES;
1300 }
1301
1302 @end