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