Xcode 2.1 cleanup, universal binary experiments
[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
12
13
14 @implementation MyDocument
15
16 + (void)initialize {
17         [MyDocument setKeys:[NSArray arrayWithObject:@"xmlDirty"] triggerChangeNotificationsForDependentKey:@"canSaveXmlNow"];
18         [MyDocument setKeys:[NSArray arrayWithObject:@"xsltDirty"] triggerChangeNotificationsForDependentKey:@"canSaveXsltNow"];
19         [MyDocument setKeys:[NSArray arrayWithObject:@"resultDirty"] triggerChangeNotificationsForDependentKey:@"canSaveResultNow"];
20 }
21
22
23 - (id)init {
24
25         if (self = [super init]) {
26                 workset = [[Workset alloc] init];
27                 processor = [XSLTProcessorFactory makeProcessorOfType:PROCESSORTYPE_SABLOTRON];
28                 wellFormedParser = [[XMLParserLibxml alloc] init];
29                 [self setValue:[NSNumber numberWithBool:NO] forKey:@"xmlDirty"];
30                 [self setValue:[NSNumber numberWithBool:NO] forKey:@"xsltDirty"];
31                 [self setValue:[NSNumber numberWithBool:NO] forKey:@"resultDirty"];
32                 [self setValue:@"" forKey:@"messageLog"];
33         }
34
35         defaults = [NSUserDefaults standardUserDefaults];
36
37         [self setValue:[NSNumber numberWithInt:2] forKey:@"processorType"];
38
39         return self;
40 }
41
42 - (void)dealloc {
43
44 //      NSLog(@"doc dealloc");
45
46         [workset release];
47         [processor release];
48         [wellFormedParser release];
49         [findPanelController release];
50         [jumpToLinePanelController release];
51         [unsavedChangesPanelController release];
52         [messageLog release];
53         [super dealloc];
54
55 }
56
57
58
59
60 - (void)windowWillClose:(NSNotification *)aNotification {
61
62         [uiUpdateTimer invalidate];
63         [uiUpdateTimer release];
64         uiUpdateTimer = nil;
65
66 //      NSLog(@"windowwillclose");
67
68 }
69
70
71 - (IBAction)selectTab:(id)sender {
72
73         [self selectTabById:[sender tag]];
74         
75 }
76
77
78 - (IBAction)selectTabById:(int)tabId {
79
80         NSString *tabName;
81
82         switch (tabId) {
83
84                 case XML:
85                         tabName = @"xmlTab";
86                         break;
87
88                 case XSLT:
89                         tabName = @"xsltTab";
90                         break;
91
92                 case PARAMETERS:
93                         tabName = @"parametersTab";
94                         break;
95
96                 case RESULT:
97                 default:
98                         tabName = @"resultTab";
99                         break;
100
101         }
102
103         [tabView selectTabViewItemWithIdentifier:tabName];
104
105 }
106
107
108 - (void)textViewDidChangeSelection:(NSNotification *)aNotification {
109         [self updateUI];
110 }
111
112
113 - (void)tabView:(NSTabView *)tabView didSelectTabViewItem:(NSTabViewItem *)tabViewItem {
114
115         [[self undoManager] removeAllActions];
116
117         [self doUpdateUI];
118 }
119
120
121 - (void)updateUI {
122         
123 //      NSLog(@"updateUI running...");
124
125         [uiUpdateTimer invalidate];
126         [uiUpdateTimer release];
127
128         uiUpdateTimer = [NSTimer scheduledTimerWithTimeInterval:0.2 target:self selector:@selector(uiUpdateTimerTarget:) userInfo:nil repeats:NO];
129
130         [uiUpdateTimer retain];
131
132         
133 }
134
135
136 - (void)uiUpdateTimerTarget:(NSTimer *)timer {
137
138 //      NSLog(@"timer target");
139
140         [timer release];
141         uiUpdateTimer = nil;
142         [self doUpdateUI];
143
144 }
145
146
147
148 - (void)doUpdateUI {
149
150 //      NSLog(@"keypath test: %@", [self valueForKeyPath:@"xmlView.hasError"]);
151
152         NSString *activeTabIdentifier = [[tabView selectedTabViewItem] identifier];
153         NSString *activeResultTabIdentifier = [[resultTabView selectedTabViewItem] identifier];
154
155         BOOL xmlTabIsVisible = [activeTabIdentifier isEqualToString:@"xmlTab"];
156         BOOL xsltTabIsVisible = !xmlTabIsVisible && [activeTabIdentifier isEqualToString:@"xsltTab"];
157         BOOL paramTabIsVisible = !(xmlTabIsVisible || xsltTabIsVisible) && [activeTabIdentifier isEqualToString:@"parametersTab"];
158         BOOL resultTabIsVisible = !(xmlTabIsVisible || xsltTabIsVisible || paramTabIsVisible);
159         BOOL resultTabHtmlIsVisible = resultTabIsVisible && [activeResultTabIdentifier isEqualToString:@"htmlResult"];
160         BOOL resultTabXslfoIsVisible = resultTabIsVisible && !resultTabHtmlIsVisible && [activeResultTabIdentifier isEqualToString:@"xslfoResult"];
161 //      BOOL resultTabTextIsVisible = resultTabIsVisible && !(resultTabHtmlIsVisible || resultTabXslfoIsVisible);
162         
163 //      NSLog(@"xml: %d, xslt: %d, param: %d, result: %d, reshtml: %d, resxslfo: %d, restext: %d", xmlTabIsVisible, xsltTabIsVisible, paramTabIsVisible, resultTabIsVisible, resultTabHtmlIsVisible, resultTabXslfoIsVisible, resultTabTextIsVisible);
164         
165         if (xmlTabIsVisible) {
166                 [xmlView calculateTagStack];
167
168                 if ([defaults boolForKey:@"enableWellformedCheck"]) {
169                         [xmlView checkWellFormed];
170                         if ([workset hasXmlCode] && [xmlView valueForKey:@"hasError"]) {
171 //                              [self setValue:[xmlView valueForKey:@"errorString"] forKey:@"drawerMessage"];
172                                 [self logMessage:[xmlView valueForKey:@"errorString"]];
173                         } else {
174                                 [self clearMessageLog];
175 //                              [self setValue:nil forKey:@"drawerMessage"];
176                         }
177                 }
178
179         } else if (xsltTabIsVisible) {
180                 [xsltView calculateTagStack];
181
182                 if ([defaults boolForKey:@"enableWellformedCheck"]) {
183                         [xsltView checkWellFormed];
184                         if ([workset hasXsltCode] && [xsltView valueForKey:@"hasError"]) {
185 //                              [self setValue:[xsltView valueForKey:@"errorString"] forKey:@"drawerMessage"];
186                         } else {
187 //                              [self setValue:nil forKey:@"drawerMessage"];
188                         }
189                 }
190                 
191         } else if (paramTabIsVisible) {
192                 [paramRemoveButton setEnabled:[parameterTable selectedRow] != -1];
193                 [parameterTable reloadData];
194         } else if (resultTabIsVisible) {
195                 [autoShowCheckbox setEnabled:[openResultURLButton isEnabled]];
196
197                 if (resultTabHtmlIsVisible) {
198                         [self resizeWebView];
199                         [self updateResultWebView];
200                 } else if (resultTabXslfoIsVisible) {
201                         [self updateResultPDFView];
202                         [pdfCurrentPageField setIntValue: (pdfPageCount ? (pdfCurrentPage + 1) : 0)];
203                         [pdfPageCountField setIntValue:pdfPageCount];
204                         
205 //                      [pdfPreviousPageButton setEnabled:pdfCurrentPage > 0];
206 //                      [pdfNextPageButton setEnabled:pdfCurrentPage < (pdfPageCount - 1)];
207                         [pdfSaveAsButton setEnabled:(pdfPageCount > 0)];
208 //              } else if (resultTabTextIsVisible) {
209                         
210                 }
211         }
212         
213
214         [processButton setEnabled:[self canProcessNow]];
215         
216         // move this to xmlview.
217 //      [self updateWellFormedIcons];
218
219 }
220
221
222 - (void)updateResultWebView {
223         if (!webViewUpToDate) {
224                 WebFrame *mainFrame = [resultWebView mainFrame];
225                 [mainFrame loadHTMLString:[workset stringResult] baseURL:[NSURL URLWithString:[webViewBaseURL stringValue]]];
226                 webViewUpToDate = YES;
227         }
228 }
229
230
231 - (void)updateResultPDFView {
232         if (!PDFViewUpToDate) { // todo rename method name and instance variable
233                 [self renderFo:self];
234                 PDFViewUpToDate = YES;
235         }
236 }
237
238
239 - (BOOL)canProcessNow {
240         return [workset hasXmlCode] && [workset hasXsltCode];
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 [workset hasXmlCode];
294                         } else if (xsltTabIsVisible) {
295                                 return [workset hasXsltCode];
296                         } else if (resultTabIsVisible) {
297                                 return [workset hasResult];
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 valueForKey:@"xmlCode"]];
321         [xsltView setString:[workset valueForKey:@"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 setValue:[xmlView string] forKey:@"xmlCode"];
332                 [self setValue:[NSNumber numberWithBool:YES] forKey:@"xmlDirty"];
333         } else if ([sender isEqual:xsltView]) {
334                 [workset setValue:[xsltView string] forKey:@"xsltCode"];
335                 [self setValue:[NSNumber numberWithBool:YES] forKey:@"xsltDirty"];
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 - (IBAction)process:(id)sender {
540
541         const char **params = [[workset valueForKey:@"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 valueForKey:@"xsltFilename"]]];
550         }
551
552         if (![processor processStrings:[XMLUtils getDataWithEncodingFromString:[workset valueForKey:@"xmlCode"]] withXslt:[XMLUtils getDataWithEncodingFromString:[workset valueForKey:@"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 setValue:[processor result] forKey:@"result"];
567                 [workset setResultEncoding:[processor resultEncoding]];
568                 [self setValue:[NSNumber numberWithBool:YES] forKey:@"resultDirty"];
569                 [self autoSave];
570 //              [errorDrawer close];
571                 [self selectTabById:RESULT];
572                 [processingTimeField setStringValue:[NSString stringWithFormat:@"Time: %ldms", processingTime]];
573         }
574
575         webViewUpToDate = NO;
576         PDFViewUpToDate = 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
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 setValue:[XMLUtils getStringWithEncodingFromFile:[[panel filenames] objectAtIndex:0]] forKey:@"xmlCode"];
610                 [workset setValue:[[panel filenames] objectAtIndex:0] forKey:@"xmlFilename"];
611                 [self updateChangeCount:NSChangeDone];
612                 [self updateCompleteUI];
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 setValue:[XMLUtils getStringWithEncodingFromFile:[[panel filenames] objectAtIndex:0]] forKey:@"xsltCode"];
627                 [workset setValue:[[panel filenames] objectAtIndex:0] forKey:@"xsltFilename"];
628                 [self updateChangeCount:NSChangeDone];
629                 [self updateCompleteUI];
630
631         }
632 }
633
634
635
636
637 - (BOOL)canSaveXmlNow {
638         return [workset hasXmlFilename] && xmlDirty;
639 }
640
641 - (BOOL)canSaveXsltNow {
642         return [workset hasXsltFilename] && xsltDirty;
643 }
644
645 - (BOOL)canSaveResultNow {
646         return [workset hasResultFilename] && resultDirty;
647 }
648
649
650
651
652 - (IBAction)saveXmlAs:(id)sender {
653
654         NSSavePanel *panel = [NSSavePanel savePanel];
655
656         if ([panel runModal] == NSFileHandlingPanelOKButton) {
657
658                 [workset setValue:[panel filename] forKey:@"xmlFilename"];
659                 [self saveXml:nil];
660
661         }
662 }
663
664
665
666 - (IBAction)saveXml:(id)sender {
667
668
669         if ([workset hasXmlFilename]) {
670                 [workset saveXml];
671                 [self setValue:[NSNumber numberWithBool:NO] forKey:@"xmlDirty"];
672         }
673
674         [self updateUI];
675 }
676
677
678 - (IBAction)saveXsltAs:(id)sender {
679
680         NSSavePanel *panel = [NSSavePanel savePanel];
681
682         if ([panel runModal] == NSFileHandlingPanelOKButton) {
683
684                 [workset setValue:[panel filename] forKey:@"xsltFilename"];
685                 [self saveXslt:nil];
686
687         }
688 }
689
690
691
692 - (IBAction)saveXslt:(id)sender {
693
694         if ([workset hasXsltFilename]) {
695                 [workset saveXslt];
696                 [self setValue:[NSNumber numberWithBool:NO] forKey:@"xsltDirty"];
697         }
698
699         [self updateUI];
700 }
701
702
703
704 - (IBAction)saveResultAs:(id)sender {
705
706         NSSavePanel *panel = [NSSavePanel savePanel];
707
708         if ([panel runModal] == NSFileHandlingPanelOKButton) {
709
710                 [workset setValue:[panel filename] forKey:@"resultFilename"];
711
712                 [self saveResult:nil];
713                 
714         }
715 }
716
717 - (IBAction)saveResult:(id)sender {
718
719         [workset saveResult];
720         [self setValue:[NSNumber numberWithBool:NO] forKey:@"resultDirty"];
721         [self updateUI];
722         [self autoShow];
723         
724 }
725
726
727 - (IBAction)saveCurrentAs:(id)sender {
728         
729         NSString *activeTabIdentifier = [[tabView selectedTabViewItem] identifier];
730         BOOL xmlTabIsVisible = [activeTabIdentifier isEqualToString:@"xmlTab"];
731         BOOL xsltTabIsVisible = !xmlTabIsVisible && [activeTabIdentifier isEqualToString:@"xsltTab"];
732         BOOL paramTabIsVisible = !(xmlTabIsVisible || xsltTabIsVisible) && [activeTabIdentifier isEqualToString:@"parametersTab"];
733         BOOL resultTabIsVisible = !(xmlTabIsVisible || xsltTabIsVisible || paramTabIsVisible);
734         
735         if (xmlTabIsVisible) {
736                 [self saveXmlAs:sender];
737         } else if (xsltTabIsVisible) {
738                 [self saveXsltAs:sender];
739         } else if (resultTabIsVisible) {
740                 [self saveResultAs:sender];
741         }
742
743 }
744
745
746
747
748 - (IBAction)saveCurrent:(id)sender {
749
750         NSString *activeTabIdentifier = [[tabView selectedTabViewItem] identifier];
751         BOOL xmlTabIsVisible = [activeTabIdentifier isEqualToString:@"xmlTab"];
752         BOOL xsltTabIsVisible = !xmlTabIsVisible && [activeTabIdentifier isEqualToString:@"xsltTab"];
753         BOOL paramTabIsVisible = !(xmlTabIsVisible || xsltTabIsVisible) && [activeTabIdentifier isEqualToString:@"parametersTab"];
754         BOOL resultTabIsVisible = !(xmlTabIsVisible || xsltTabIsVisible || paramTabIsVisible);
755         
756         if (xmlTabIsVisible) {
757                 [self saveXml:sender];
758         } else if (xsltTabIsVisible) {
759                 [self saveXslt:sender];
760         } else if (resultTabIsVisible) {
761                 [self saveResult:sender];
762         }
763         
764 }
765
766
767
768
769
770
771 - (IBAction)openResultURL:(id)sender {
772
773 //      NSLog(@"openResultURL running...");
774         
775         if ([workset hasResultFilename]) {
776
777                 [[NSWorkspace sharedWorkspace] openURL:[NSURL fileURLWithPath:[workset valueForKey:@"resultFilename"]]];
778
779         }
780 }
781
782
783 - (IBAction)newParameter:(id)sender {
784
785         [[workset valueForKey:@"parameterSet"] addParameter:@"name" withValue:@"value"];
786         [self doUpdateUI];
787         
788 }
789
790 - (IBAction)removeParameter:(id)sender {
791
792         int row = [parameterTable selectedRow];
793
794         if (row != -1) {
795                 [[workset valueForKey:@"parameterSet"] removeParameterAtIndex:row];
796                 [self doUpdateUI];
797         } else {
798                 NSBeep();
799         }
800
801 }
802
803 - (int)numberOfRowsInTableView:(NSTableView *)aTableView {
804         return [(ParameterSet *)[workset valueForKey:@"parameterSet"] count];
805 }
806
807 - (id)tableView:(NSTableView *)aTableView
808 objectValueForTableColumn:(NSTableColumn *)aTableColumn
809                                          row:(int)rowIndex {
810
811         return [[workset valueForKey:@"parameterSet"] getField:[aTableColumn identifier] atIndex:rowIndex];
812 }
813
814
815
816 - (void)tableView:(NSTableView *)aTableView
817    setObjectValue:(id)anObject
818    forTableColumn:(NSTableColumn *)aTableColumn
819                           row:(int)rowIndex {
820
821         [[workset valueForKey:@"parameterSet"] setField:[aTableColumn identifier] atIndex:rowIndex toString:anObject];
822 }
823
824
825
826 /*
827 - (IBAction)setProcessorType:(id)sender {
828
829         int newType = [sender tag];
830
831         if ([processor processorType] == newType) {
832                 return;
833         }
834
835         [self switchProcessorToType:newType updateUI:NO];
836
837 }
838 */
839
840 - (IBAction)switchProcessor:(id)sender {
841 // sender -> selected item?
842 //      [self setValue:[NSNumber numberWithInt:[[sender selectedItem] tag]] forKey:@"processorType"];
843         [self switchProcessorToType:[[sender selectedItem] tag] updateUI:YES];
844
845 }
846
847 - (IBAction)switchProcessorToType:(int)newType updateUI:(BOOL)updateUI {
848
849         XSLTProcessor *newProcessor = nil;
850
851         newProcessor = [XSLTProcessorFactory makeProcessorOfType:newType];
852
853         if (!newProcessor) {
854                 NSLog(@"Unable to create new processor of type '%d'", newType);
855         }
856
857         [self setValue:newProcessor forKey:@"processor"];
858         [self setValue:[NSNumber numberWithInt:newType] forKey:@"processorType"];
859         
860         if (updateUI) {
861                 [processorTypePopUp selectItemAtIndex:[processorTypePopUp indexOfItemWithTag:newType]];
862         }
863
864 }
865
866
867
868 - (id)handleProcessScriptCommand:(NSScriptCommand *)command {
869
870         if ([self canProcessNow]) {
871                 [self process:nil];
872         }
873
874         return nil;
875         
876 }
877
878
879 - (id)handleExportScriptCommand:(NSScriptCommand *)command {
880
881         NSDictionary *args = [command evaluatedArguments];
882     NSString *file = [args objectForKey:@"File"];
883
884 //      NSLog(file);
885
886         if (file != nil) {
887
888                 [workset setValue:file forKey:@"resultFilename"];
889
890                 [self saveResult:nil];
891         }
892
893         return nil;
894         
895 }
896
897 - (id)handleSetParamScriptCommand:(NSScriptCommand *)command {
898
899         NSDictionary *args = [command evaluatedArguments];
900     NSString *paramName = [args objectForKey:@"Name"];
901     NSString *paramValue = [args objectForKey:@"Value"];
902
903         [[workset valueForKey:@"parameterSet"] removeParameterByName:paramName];
904         
905         [[workset valueForKey:@"parameterSet"] addParameter:paramName withValue:paramValue];
906         [self doUpdateUI];
907
908         return nil;
909         
910 }
911
912 - (id)handleClearParamScriptCommand:(NSScriptCommand *)command {
913
914         NSDictionary *args = [command evaluatedArguments];
915     NSString *paramName = [args objectForKey:@"Name"];
916
917         [[workset valueForKey:@"parameterSet"] removeParameterByName:paramName];
918         return nil;
919         
920 }
921
922 - (id)handleSetProcessorTypeScriptCommand:(NSScriptCommand *)command {
923
924         NSDictionary *args = [command evaluatedArguments];
925     NSString *processorTypeString = [args objectForKey:@"Name"];
926         
927         if ([processorTypeString caseInsensitiveCompare:@"libxslt"] == NSOrderedSame) {
928
929                 [self switchProcessorToType:PROCESSORTYPE_LIBXSLT updateUI:YES];
930
931         } else if ([processorTypeString caseInsensitiveCompare:@"sablotron"] == NSOrderedSame) {
932
933                 [self switchProcessorToType:PROCESSORTYPE_SABLOTRON updateUI:YES];
934
935         } else if ([processorTypeString caseInsensitiveCompare:@"saxon"] == NSOrderedSame) {
936
937                 [self switchProcessorToType:PROCESSORTYPE_SAXON updateUI:YES];
938
939         } else if ([processorTypeString caseInsensitiveCompare:@"xalan-j"] == NSOrderedSame) {
940                 
941                 [self switchProcessorToType:PROCESSORTYPE_XALAN_J updateUI:YES];
942                 
943         } else {
944                 NSLog(@"unknown processor");
945         }
946
947         [self doUpdateUI];
948         return nil;
949
950 }
951
952 - (BOOL)handleDroppedFile:(NSString *)filename forTextView:(NSTextView *)sender {
953
954         NSString *fileContents = [XMLUtils getStringWithEncodingFromFile:filename];
955
956         if ([sender isEqual: xmlView]) {
957
958                 [self setXmlcode:fileContents];
959                 [workset setValue:filename forKey:@"xmlFilename"];
960                 
961         } else if ([sender isEqual:xsltView]) {
962
963                 [self setXsltcode:fileContents];
964                 [workset setValue:filename forKey:@"xsltFilename"];
965                 
966         } else {
967
968                 NSLog(@"Unknown sender view");
969
970         }
971
972         [self updateUI];
973         return YES;
974         
975 }
976
977
978 - (void)logMessage:(NSString *)string {
979         [self setValue:[NSString stringWithFormat:@"%@\n---\n%@", string, messageLog] forKey:@"messageLog"];
980 }
981
982 - (void)clearMessageLog {
983         [self setValue:@"" forKey:@"messageLog"];
984 }
985
986
987
988 - (NSString *)xmlcode {
989         return [workset valueForKey:@"xmlCode"];
990 }
991
992 - (void)setXmlcode:(NSString *)s {
993
994         NSString *currentContents = [[[NSString alloc] initWithString:[self xmlcode]] autorelease];
995
996         [[self undoManager] registerUndoWithTarget:self
997                                                                    selector:@selector(setXmlcode:)
998                                                                          object:currentContents];
999
1000         [workset setValue:s forKey:@"xmlCode"];
1001         [self updateCompleteUI];
1002 }
1003
1004
1005
1006 - (NSString *)xsltcode {
1007         return [workset valueForKey:@"xsltCode"];
1008 }
1009
1010 - (void)setXsltcode:(NSString *)s {
1011
1012         NSString *currentContents = [[[NSString alloc] initWithString:[self xsltcode]] autorelease];
1013
1014         [[self undoManager] registerUndoWithTarget:self
1015                                                                           selector:@selector(setXsltcode:)
1016                                                                             object:currentContents];
1017
1018         [workset setValue:s forKey:@"xsltCode"];
1019         [self updateCompleteUI];
1020 }
1021
1022
1023 - (NSString *)result {
1024         return [workset stringResult];
1025 }
1026
1027
1028
1029 - (void)tableViewSelectionDidChange:(NSNotification *)notification {
1030         [self doUpdateUI];
1031 }
1032
1033
1034 - (void)checkForExternalModifications {
1035
1036         BOOL keep = NO;
1037         
1038         if ([workset xmlModifiedExternally] && xmlDirty || [workset xsltModifiedExternally] && xsltDirty) {
1039
1040                 /* external changes conflicting with local changes detected.
1041                  * Ask the user if we should keep the local unsaved changes
1042                  */
1043                 keep = [self showUnsavedChangesPanel];
1044
1045         }
1046
1047         if ([workset xmlModifiedExternally] && !(xmlDirty && keep)) {
1048                 [workset reloadXmlFromFile];
1049                 [self updateChangeCount:NSChangeDone];
1050                 [self updateCompleteUI];
1051                 [self setValue:[NSNumber numberWithBool:NO] forKey:@"xmlDirty"];
1052         }
1053
1054         if ([workset xsltModifiedExternally] && !(xsltDirty && keep)) {
1055                 [workset reloadXsltFromFile];
1056                 [self updateChangeCount:NSChangeDone];
1057                 [self updateCompleteUI];
1058                 [self setValue:[NSNumber numberWithBool:NO] forKey:@"xsltDirty"];
1059         }
1060
1061         [self updateUI];
1062         
1063 }
1064
1065
1066 - (BOOL)showUnsavedChangesPanel {
1067
1068         [NSApp beginSheet:[unsavedChangesPanelController window]
1069         modalForWindow:[[[self windowControllers] objectAtIndex:0] window]
1070          modalDelegate:nil
1071         didEndSelector:nil
1072            contextInfo:nil];
1073
1074     [NSApp runModalForWindow:[unsavedChangesPanelController window]];
1075     [NSApp endSheet:[unsavedChangesPanelController window]];
1076     [[unsavedChangesPanelController window] orderOut:self];
1077
1078         return ([unsavedChangesPanelController keepChanges]);
1079
1080 }
1081
1082 - (void)xslfoRenderThread {
1083
1084         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1085         
1086         XSL_FO_Renderer *xfr = [[[XSL_FO_Renderer alloc] init] autorelease];
1087         xslfoRendererResultData = [xfr render:[workset valueForKey:@"result"]];
1088
1089         [pool release];
1090         [xslfoRendererLock unlockWithCondition:2];
1091         
1092 }
1093
1094
1095 - (IBAction)renderFo:(id)sender {
1096
1097         xslfoRendererLock = [[[NSConditionLock alloc] initWithCondition:1] autorelease];
1098         [NSThread detachNewThreadSelector:@selector(xslfoRenderThread) toTarget:self withObject:nil];
1099         [xslfoRendererLock lockWhenCondition:2];
1100         [xslfoRendererLock unlock];
1101         
1102         if (!xslfoRendererResultData) {
1103                 NSLog(@"Unable to render, NULL result");
1104                 return;
1105         }
1106         
1107         [self setValue:xslfoRendererResultData forKey:@"pdfData"];
1108
1109 // todo fixe these
1110 //      pdfPageCount = [[[pdfImage representations] objectAtIndex:0] pageCount];
1111 //      pdfCurrentPage = 0;
1112
1113         PDFDocument *doc = [[[PDFDocument alloc] initWithData:xslfoRendererResultData] autorelease];
1114         [resultPDFView setDocument:doc];
1115         NSLog(@"pdfview %@", resultPDFView);
1116                 
1117 }
1118
1119
1120
1121
1122 - (IBAction)pdfSaveAs:(id)sender {
1123
1124         NSSavePanel *panel = [NSSavePanel savePanel];
1125         
1126         if ([panel runModal] == NSFileHandlingPanelOKButton) {
1127                 
1128                 [pdfData writeToFile:[panel filename] atomically:YES];
1129
1130         }
1131         
1132 }
1133
1134
1135
1136
1137 - (void)windowDidBecomeMain:(NSNotification *)aNotification {
1138
1139         [self checkForExternalModifications];
1140
1141 }
1142
1143 - (void)windowDidResize:(NSNotification *)aNotification {
1144
1145         [self resizeWebView];
1146         
1147 }
1148
1149 - (void)resizeWebView {
1150         
1151 //      [[[resultWebView mainFrame] frameView] setFrame:[resultWebView frame]];
1152         [resultWebView setNeedsDisplay:YES];
1153
1154 }
1155
1156
1157
1158
1159
1160 - (NSString *)windowNibName
1161 {
1162     // Override returning the nib file name of the document
1163     // 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.
1164     return @"MyDocument";
1165 }
1166
1167
1168 //- (void)awakeFromNib {
1169 //      NSLog(@"awake %@", [self valueForKey:@"processorType"]);
1170 //      [self switchProcessorToType:2 updateUI:YES];
1171 //}
1172
1173 - (void)windowControllerDidLoadNib:(NSWindowController *) aController {
1174
1175         NSSize errorDrawerSize;
1176
1177         [super windowControllerDidLoadNib:aController];
1178         
1179         [resultWebView setTextSizeMultiplier:0.9];
1180         
1181         warningIcon = [xmlWellFormedIcon image];
1182         
1183         [self updateCompleteUI];
1184         
1185         errorDrawerSize = [errorDrawer contentSize];
1186         errorDrawerSize.height = 130;
1187         [errorDrawer setContentSize:errorDrawerSize];
1188         
1189         NSFont *computerFont = [NSFont fontWithName:@"Courier" size:12.0];
1190         [resultView setFont:computerFont];
1191
1192         [tabView registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType, nil]];
1193         
1194         if (findPanelController == nil) {
1195                 findPanelController = [[FindPanelController alloc] initWithWindowNibName:@"FindPanel"];
1196 //              NSLog(@"init find panel controller: %@", findPanelController);
1197         }
1198
1199         if (jumpToLinePanelController == nil) {
1200                 jumpToLinePanelController = [[JumpToLinePanelController alloc] initWithWindowNibName:@"JumpToLine"];
1201 //              NSLog(@"init jump to line panel controller: %@", jumpToLinePanelController);
1202         }
1203
1204         if (unsavedChangesPanelController == nil) {
1205                 unsavedChangesPanelController = [[UnsavedChangesPanelController alloc] initWithWindowNibName:@"UnsavedChanges"];
1206 //              NSLog(@"init unsaved changes panel controller: %@", unsavedChangesPanelController);
1207         }
1208
1209 //      [self switchProcessorToType:2 updateUI:YES];
1210
1211 //      [processorTypePopUp selectItemAtIndex:[processorTypePopUp indexOfItemWithTag:[[self valueForKey:@"processorType"] intValue]]];
1212
1213         [self switchProcessorToType:[[self valueForKey:@"processorType"] intValue] updateUI:YES];
1214
1215 }
1216
1217
1218 - (void)canCloseDocumentWithDelegate:(id)delegate shouldCloseSelector:(SEL)shouldCloseSelector contextInfo:(void *)contextInfo {
1219
1220         [uiUpdateTimer invalidate];
1221         [super canCloseDocumentWithDelegate:delegate shouldCloseSelector:shouldCloseSelector contextInfo:contextInfo];
1222 }
1223
1224
1225
1226
1227
1228
1229
1230
1231 - (IBAction)showErrorLocation:(id)sender {
1232
1233         XMLTextView *textView;
1234         int errorLine = 0;
1235
1236         if ([processor errorSource] == XSLT_ERROR_SOURCE_XML) {
1237                 [self selectTabById:XML];
1238                 textView = xmlView;
1239         } else {
1240                 [self selectTabById:XSLT];
1241                 textView = xsltView;
1242         }
1243
1244         errorLine = [processor errorLine];
1245
1246         [textView selectLineByNumber:errorLine];
1247 }
1248
1249
1250 - (NSData *)dataRepresentationOfType:(NSString *)aType {
1251         NSMutableData *data = [[[NSMutableData alloc] init] autorelease];
1252         NSKeyedArchiver *archiver = [[[NSKeyedArchiver alloc] initForWritingWithMutableData:data] autorelease];
1253         [archiver setOutputFormat:NSPropertyListXMLFormat_v1_0];
1254         [archiver encodeObject:workset forKey:@"workset"];
1255         [archiver encodeInt:[processor processorType] forKey:@"processorType"];
1256         [archiver finishEncoding];
1257         return data;
1258 }
1259
1260
1261 - (BOOL)loadDataRepresentation:(NSData *)data ofType:(NSString *)aType {
1262
1263         NSKeyedUnarchiver *unarchiver = [[[NSKeyedUnarchiver alloc] initForReadingWithData:data] autorelease];
1264         
1265         [self setValue:[unarchiver decodeObjectForKey:@"workset"] forKey:@"workset"];
1266
1267         int docProcessorType = [unarchiver decodeIntForKey:@"processorType"];
1268
1269         if (docProcessorType) {
1270                 [self setValue:[NSNumber numberWithInt:docProcessorType] forKey:@"processorType"];
1271         }
1272
1273         [unarchiver finishDecoding];
1274     return YES;
1275 }
1276
1277
1278
1279 @end