#import "MyDocument.h"
#import "Workset.h"
-
+#import <Foundation/NSDebug.h>
- (id)init {
+// NSZombieEnabled = YES;
+
if (self = [super init]) {
workset = [[Workset alloc] init];
processor = [XSLTProcessorFactory makeProcessorOfType:PROCESSORTYPE_SABLOTRON];
xsltDirty = NO;
}
-
+ defaults = [NSUserDefaults standardUserDefaults];
return self;
}
- (void)dealloc {
+ [uiUpdateTimer release];
[workset release];
[processor release];
[wellFormedParser release];
}
+- (void)textViewDidChangeSelection:(NSNotification *)aNotification {
+ [self updateUI];
+}
+
- (void)tabView:(NSTabView *)tabView didSelectTabViewItem:(NSTabViewItem *)tabViewItem {
- NSLog(@"switch tab xyz x");
[[self undoManager] removeAllActions];
- if ([[tabViewItem identifier] isEqualToString:@"htmlResult"]) {
- [self resizeWebView];
- }
-
+ [self doUpdateUI];
}
[uiUpdateTimer invalidate];
[uiUpdateTimer release];
- uiUpdateTimer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(uiUpdateTimerTarget:) userInfo:nil repeats:NO];
+ uiUpdateTimer = [NSTimer scheduledTimerWithTimeInterval:0.2 target:self selector:@selector(uiUpdateTimerTarget:) userInfo:nil repeats:NO];
[uiUpdateTimer retain];
+
}
- (void)uiUpdateTimerTarget:(NSTimer *)timer {
-- (void)doUpdateUI {
-
-// NSLog(@"doUpdateUI running...");
-// NSLog(@"debug: %@", [[[NSApp mainWindow] document] tabView]);
-
-
- [saveXmlAsButton setEnabled:[workset hasXmlCode]];
- [saveXsltAsButton setEnabled:[workset hasXsltCode]];
- [saveResultAsButton setEnabled:[workset hasResult]];
-
- [saveResultButton setEnabled:[workset hasResultFilename] && resultDirty];
- [autoSaveCheckbox setEnabled:[workset hasResultFilename]];
-
- [openResultURLButton setEnabled:[workset hasResultFilename]];
- [autoShowCheckbox setEnabled:[openResultURLButton isEnabled]];
-
- [paramRemoveButton setEnabled:[parameterTable selectedRow] != -1];
-
- [processButton setEnabled:[self canProcessNow]];
-
- [saveResultFilenameField setObjectValue:[workset resultFilename]];
- [saveResultFilenameField setToolTip:[workset resultFilename]];
+- (void)doUpdateUI {
- [saveXmlFilenameField setObjectValue:[workset xmlFilename]];
- [saveXmlFilenameField setToolTip:[workset xmlFilename]];
- [saveXmlButton setEnabled:[workset hasXmlFilename] && xmlDirty];
+ NSString *activeTabIdentifier = [[tabView selectedTabViewItem] identifier];
+ NSString *activeResultTabIdentifier = [[resultTabView selectedTabViewItem] identifier];
+ BOOL xmlTabIsVisible = [activeTabIdentifier isEqualToString:@"xmlTab"];
+ BOOL xsltTabIsVisible = !xmlTabIsVisible && [activeTabIdentifier isEqualToString:@"xsltTab"];
+ BOOL paramTabIsVisible = !(xmlTabIsVisible || xsltTabIsVisible) && [activeTabIdentifier isEqualToString:@"parametersTab"];
+ BOOL resultTabIsVisible = !(xmlTabIsVisible || xsltTabIsVisible || paramTabIsVisible);
+ BOOL resultTabHtmlIsVisible = resultTabIsVisible && [activeResultTabIdentifier isEqualToString:@"htmlResult"];
+ BOOL resultTabXslfoIsVisible = resultTabIsVisible && !resultTabHtmlIsVisible && [activeResultTabIdentifier isEqualToString:@"xslfoResult"];
+ BOOL resultTabTextIsVisible = resultTabIsVisible && !(resultTabHtmlIsVisible || resultTabXslfoIsVisible);
- [saveXsltFilenameField setObjectValue:[workset xsltFilename]];
- [saveXsltFilenameField setToolTip:[workset xsltFilename]];
- [saveXsltButton setEnabled:[workset hasXsltFilename] && xsltDirty];
-
- [self updateWellFormedIcons];
+// NSLog(@"xml: %d, xslt: %d, param: %d, result: %d, reshtml: %d, resxslfo: %d, restext: %d", xmlTabIsVisible, xsltTabIsVisible, paramTabIsVisible, resultTabIsVisible, resultTabHtmlIsVisible, resultTabXslfoIsVisible, resultTabTextIsVisible);
+
+ if (xmlTabIsVisible) {
+ [saveXmlFilenameField setObjectValue:[workset xmlFilename]];
+ [saveXmlFilenameField setToolTip:[workset xmlFilename]];
+ [saveXmlButton setEnabled:[self canSaveXmlNow]];
+ [saveXmlAsButton setEnabled:[self canSaveXmlAsNow]];
+ [xmlTagStackField setStringValue:[xmlView calculateTagStack]];
+
+ if ([defaults boolForKey:@"enableWellformedCheck"]) {
+ [xmlView checkWellFormed];
+ if ([workset hasXmlCode] && [xmlView hasError]) {
+ [xmlWellFormedIcon setImage:warningIcon];
+ [xmlWellFormedIcon setToolTip:[xmlView valueForKey:@"errorString"]];
+ [self setValue:[xmlView valueForKey:@"errorString"] forKey:@"drawerMessage"];
+ } else {
+ [xmlWellFormedIcon setImage:nil];
+ [xmlWellFormedIcon setToolTip:nil];
+ [self setValue:nil forKey:@"drawerMessage"];
+ }
+ }
+
+ } else if (xsltTabIsVisible) {
+ [saveXsltFilenameField setObjectValue:[workset xsltFilename]];
+ [saveXsltFilenameField setToolTip:[workset xsltFilename]];
+ [saveXsltButton setEnabled:[self canSaveXsltNow]];
+ [saveXsltAsButton setEnabled:[self canSaveXsltAsNow]];
+ [xsltTagStackField setStringValue:[xsltView calculateTagStack]];
+
+ if ([defaults boolForKey:@"enableWellformedCheck"]) {
+ [xsltView checkWellFormed];
+ if ([workset hasXsltCode] && [xsltView hasError]) {
+ [xsltWellFormedIcon setImage:warningIcon];
+ [xsltWellFormedIcon setToolTip:[xsltView valueForKey:@"errorString"]];
+ [self setValue:[xsltView valueForKey:@"errorString"] forKey:@"drawerMessage"];
+ } else {
+ [xsltWellFormedIcon setImage:nil];
+ [xsltWellFormedIcon setToolTip:nil];
+ [self setValue:nil forKey:@"drawerMessage"];
+ }
+ }
+
+ } else if (paramTabIsVisible) {
+ [paramRemoveButton setEnabled:[parameterTable selectedRow] != -1];
+ [parameterTable reloadData];
+ } else if (resultTabIsVisible) {
+ [saveResultAsButton setEnabled:[self canSaveResultAsNow]];
+ [saveResultButton setEnabled:[self canSaveResultNow]];
+ [autoSaveCheckbox setEnabled:[workset hasResultFilename]];
+ [openResultURLButton setEnabled:[workset hasResultFilename]];
+ [autoShowCheckbox setEnabled:[openResultURLButton isEnabled]];
+ [saveResultFilenameField setObjectValue:[workset resultFilename]];
+ [saveResultFilenameField setToolTip:[workset resultFilename]];
+
+ if (resultTabHtmlIsVisible) {
+ [self resizeWebView];
+ [self updateResultWebView];
+ } else if (resultTabXslfoIsVisible) {
+ [self updateResultImageView];
+ [pdfCurrentPageField setIntValue: (pdfPageCount ? (pdfCurrentPage + 1) : 0)];
+ [pdfPageCountField setIntValue:pdfPageCount];
+
+ [pdfPreviousPageButton setEnabled:pdfCurrentPage > 0];
+ [pdfNextPageButton setEnabled:pdfCurrentPage < (pdfPageCount - 1)];
+ [pdfSaveAsButton setEnabled:(pdfPageCount > 0)];
+// } else if (resultTabTextIsVisible) {
+
+ }
+ }
- [parameterTable reloadData];
+
+ [processButton setEnabled:[self canProcessNow]];
- [resultView setString:[workset result]];
+ // move this to xmlview.
+// [self updateWellFormedIcons];
- WebFrame *mainFrame = [resultWebView mainFrame];
- [mainFrame loadHTMLString:[workset result] baseURL:nil];
- /*
- NSLog(@"webview frame: %@", NSStringFromRect([resultWebView frame]));
- NSLog(@"webview main frame: %@", NSStringFromRect([[mainFrame frameView] frame]));
- NSLog(@"textview frame: %@", NSStringFromRect([resultView frame]));
- */
+ [resultView setString:[workset stringResult]];
}
-- (void)updateWellFormedIcons {
-
- if (![workset hasXmlCode] || [wellFormedParser checkWellFormedString:[workset xmlCode]]) {
- [xmlWellFormedIcon setImage:nil];
- [xmlWellFormedIcon setToolTip:nil];
- } else {
- [xmlWellFormedIcon setImage:warningIcon];
- [xmlWellFormedIcon setToolTip:[NSString stringWithFormat:@"The XML code is not well-formed, error at line %d:\n%@", [wellFormedParser errorLine], [wellFormedParser errorMessage]]];
+- (void)updateResultWebView {
+ if (!webViewUpToDate) {
+ WebFrame *mainFrame = [resultWebView mainFrame];
+// [mainFrame loadHTMLString:[workset stringResult] baseURL:nil];
+ [mainFrame loadHTMLString:[workset stringResult] baseURL:[NSURL URLWithString:[webViewBaseURL stringValue]]];
+// [mainFrame loadHTMLString:[workset stringResult] baseURL:[NSURL URLWithString:@"file:///Users/liyanage/Sites/primavera/images/x"]];
+ webViewUpToDate = YES;
}
+}
- if (![workset hasXsltCode] || [wellFormedParser checkWellFormedString:[workset xsltCode]]) {
- [xsltWellFormedIcon setImage:nil];
- [xsltWellFormedIcon setToolTip:nil];
- } else {
- [xsltWellFormedIcon setImage:warningIcon];
- [xsltWellFormedIcon setToolTip:[NSString stringWithFormat:@"The XSLT code is not well-formed, error at line %d:\n%@", [wellFormedParser errorLine], [wellFormedParser errorMessage]]];
+- (void)updateResultImageView {
+ if (!imageViewUpToDate) {
+ [self renderFo:self];
+ imageViewUpToDate = YES;
}
-
-
}
+
- (BOOL)canProcessNow {
return [workset hasXmlCode] && [workset hasXsltCode];
// NSLog(@"validate: %@, tag: %d", menuItem, [menuItem tag]);
+ NSString *activeTabIdentifier = [[tabView selectedTabViewItem] identifier];
+ BOOL xmlTabIsVisible = [activeTabIdentifier isEqualToString:@"xmlTab"];
+ BOOL xsltTabIsVisible = !xmlTabIsVisible && [activeTabIdentifier isEqualToString:@"xsltTab"];
+ BOOL paramTabIsVisible = !(xmlTabIsVisible || xsltTabIsVisible) && [activeTabIdentifier isEqualToString:@"parametersTab"];
+ BOOL resultTabIsVisible = !(xmlTabIsVisible || xsltTabIsVisible || paramTabIsVisible);
+
+
switch ([menuItem tag]) {
case 10: // Process
case 16: // Jump to Line
return [self canJumpToLineNow];
break;
-
+
+ case 17: // Save Current Pane
+ if (xmlTabIsVisible) {
+ return [self canSaveXmlNow];
+ } else if (xsltTabIsVisible) {
+ return [self canSaveXsltNow];
+ } else if (resultTabIsVisible) {
+ return [self canSaveResultNow];
+ }
+ break;
+
+ case 18: // Save Current Pane As...
+ if (xmlTabIsVisible) {
+ return [self canSaveXmlAsNow];
+ } else if (xsltTabIsVisible) {
+ return [self canSaveXsltAsNow];
+ } else if (resultTabIsVisible) {
+ return [self canSaveResultAsNow];
+ }
+ break;
+
default:
return YES;
break;
}
-
-
- (void)textDidChange:(NSNotification *)aNotification {
id sender = [aNotification object];
[processor setBaseUri:[NSString stringWithFormat:@"file://%@", [workset xsltFilename]]];
}
- if (![processor processStrings:[workset xmlCode] withXslt:[workset xsltCode] andParameters:params]) {
+ if (![processor processStrings:[XMLUtils getDataWithEncodingFromString:[workset xmlCode]] withXslt:[XMLUtils getDataWithEncodingFromString:[workset xsltCode]] andParameters:params]) {
- [drawerMessageField setStringValue:[NSString stringWithFormat:@"Error on line %d of your %@ code:\n%@", [processor errorLine], ([processor errorSource] == XSLT_ERROR_SOURCE_XML ? @"XML" : @"XSLT"), [processor errorMessage]]];
+ [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"];
NSBeep();
[errorDrawer openOnEdge:NSMinYEdge];
processingTime = ((tend.tv_sec * 1000000 + tend.tv_usec) - (tstart.tv_sec * 1000000 + tstart.tv_usec)) / 1000;
[workset setResult:[processor result]];
+ [workset setResultEncoding:[processor resultEncoding]];
resultDirty = YES;
[self autoSave];
- [errorDrawer close];
+// [errorDrawer close];
[self selectTabById:RESULT];
[processingTimeField setStringValue:[NSString stringWithFormat:@"Time: %ldms", processingTime]];
}
+ webViewUpToDate = NO;
+ imageViewUpToDate = NO;
+
[self updateUI];
}
// NSLog(@"choosen: %@", [[panel filenames] objectAtIndex:0]);
- [workset setXmlCode:[NSString stringWithContentsOfFile:[[panel filenames] objectAtIndex:0]]];
+ [workset setXmlCode:[XMLUtils getStringWithEncodingFromFile:[[panel filenames] objectAtIndex:0]]];
[workset setXmlFilename:[[panel filenames] objectAtIndex:0]];
[self updateChangeCount:NSChangeDone];
[self updateCompleteUI];
// NSLog(@"choosen: %@", [[panel filenames] objectAtIndex:0]);
- [workset setXsltCode:[NSString stringWithContentsOfFile:[[panel filenames] objectAtIndex:0]]];
+ [workset setXsltCode:[XMLUtils getStringWithEncodingFromFile:[[panel filenames] objectAtIndex:0]]];
[workset setXsltFilename:[[panel filenames] objectAtIndex:0]];
[self updateChangeCount:NSChangeDone];
[self updateCompleteUI];
+
+- (BOOL)canSaveXmlAsNow {
+ return [workset hasXmlCode];
+}
+
+- (BOOL)canSaveXmlNow {
+ return [workset hasXmlFilename] && xmlDirty;
+}
+
+- (BOOL)canSaveXsltAsNow {
+ return [workset hasXsltCode];
+}
+
+- (BOOL)canSaveXsltNow {
+ return [workset hasXsltFilename] && xsltDirty;
+}
+
+- (BOOL)canSaveResultAsNow {
+ return [workset hasResult];
+}
+
+- (BOOL)canSaveResultNow {
+ return [workset hasResultFilename] && resultDirty;
+}
+
+
+
+
- (IBAction)saveXmlAs:(id)sender {
NSSavePanel *panel = [NSSavePanel savePanel];
}
+- (IBAction)saveCurrentAs:(id)sender {
+
+ NSString *activeTabIdentifier = [[tabView selectedTabViewItem] identifier];
+ BOOL xmlTabIsVisible = [activeTabIdentifier isEqualToString:@"xmlTab"];
+ BOOL xsltTabIsVisible = !xmlTabIsVisible && [activeTabIdentifier isEqualToString:@"xsltTab"];
+ BOOL paramTabIsVisible = !(xmlTabIsVisible || xsltTabIsVisible) && [activeTabIdentifier isEqualToString:@"parametersTab"];
+ BOOL resultTabIsVisible = !(xmlTabIsVisible || xsltTabIsVisible || paramTabIsVisible);
+
+ if (xmlTabIsVisible) {
+ return [self saveXmlAs:sender];
+ } else if (xsltTabIsVisible) {
+ return [self saveXsltAs:sender];
+ } else if (resultTabIsVisible) {
+ return [self saveResultAs:sender];
+ }
+
+}
+
+
+
+
+- (IBAction)saveCurrent:(id)sender {
+
+ NSString *activeTabIdentifier = [[tabView selectedTabViewItem] identifier];
+ BOOL xmlTabIsVisible = [activeTabIdentifier isEqualToString:@"xmlTab"];
+ BOOL xsltTabIsVisible = !xmlTabIsVisible && [activeTabIdentifier isEqualToString:@"xsltTab"];
+ BOOL paramTabIsVisible = !(xmlTabIsVisible || xsltTabIsVisible) && [activeTabIdentifier isEqualToString:@"parametersTab"];
+ BOOL resultTabIsVisible = !(xmlTabIsVisible || xsltTabIsVisible || paramTabIsVisible);
+
+ if (xmlTabIsVisible) {
+ return [self saveXml:sender];
+ } else if (xsltTabIsVisible) {
+ return [self saveXslt:sender];
+ } else if (resultTabIsVisible) {
+ return [self saveResult:sender];
+ }
+
+}
+
+
+
+
+
+
- (IBAction)openResultURL:(id)sender {
// NSLog(@"openResultURL running...");
[self switchProcessorToType:newType updateUI:NO];
- NSLog(@"change processor type menu: %d", [sender tag]);
-
}
[self switchProcessorToType:PROCESSORTYPE_SAXON updateUI:YES];
+ } else if ([processorType caseInsensitiveCompare:@"xalan-j"] == NSOrderedSame) {
+
+ [self switchProcessorToType:PROCESSORTYPE_XALAN_J updateUI:YES];
+
} else {
NSLog(@"unknown processor");
}
- (BOOL)handleDroppedFile:(NSString *)filename forTextView:(NSTextView *)sender {
-
- NSString *fileContents = [NSString stringWithContentsOfFile:filename];
-
- if (fileContents == nil) {
- return NO;
- }
+ NSString *fileContents = [XMLUtils getStringWithEncodingFromFile:filename];
- if ([sender isEqual:xmlView]) {
+ if ([sender isEqual: xmlView]) {
[self setXmlcode:fileContents];
[workset setXmlFilename:filename];
}
+
+
- (NSString *)xmlcode {
return [workset xmlCode];
}
- (NSString *)result {
- return [workset result];
+ return [workset stringResult];
}
}
+- (void)xslfoRenderThread {
+
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ XSL_FO_Renderer *xfr = [[[XSL_FO_Renderer alloc] init] autorelease];
+ xslfoRendererResultData = [xfr render:[workset result]];
+
+ [pool release];
+ [xslfoRendererLock unlockWithCondition:2];
+
+}
+
+
+- (IBAction)renderFo:(id)sender {
+
+ xslfoRendererLock = [[[NSConditionLock alloc] initWithCondition:1] autorelease];
+ [NSThread detachNewThreadSelector:@selector(xslfoRenderThread) toTarget:self withObject:nil];
+ [xslfoRendererLock lockWhenCondition:2];
+ [xslfoRendererLock unlock];
+
+ if (!xslfoRendererResultData) {
+ NSLog(@"Unable to render, NULL result");
+ return;
+ }
+
+ [xslfoRendererResultData retain];
+ [pdfData release];
+ pdfData = xslfoRendererResultData;
+
+ NSImage *pdfImage = [[[NSImage alloc] initWithData:xslfoRendererResultData] autorelease];
+ [pdfImage setBackgroundColor:[NSColor whiteColor]];
+ [pdfImage recache];
+ [pdfImage setCacheMode:NSImageCacheNever];
+
+ NSClipView *clipView = (NSClipView *)[resultImageView superview];
+ NSScrollView *scrollView = (NSScrollView *)[clipView superview];
+
+ [resultImageView setImage:pdfImage];
+ [resultImageView setFrameSize:[pdfImage size]];
+ [resultImageView display];
+
+ [clipView scrollToPoint:NSMakePoint([resultImageView frame].origin.x, [resultImageView frame].size.height - [clipView frame].size.height + [resultImageView frame].origin.y)];
+ [scrollView reflectScrolledClipView:clipView];
+
+ pdfPageCount = [[[pdfImage representations] objectAtIndex:0] pageCount];
+ pdfCurrentPage = 0;
+
+}
+
+
+- (IBAction)pdfPreviousPage:(id)sender {
+
+ if (pdfCurrentPage > 0) {
+ pdfCurrentPage--;
+ [[[[resultImageView image] representations] objectAtIndex:0] setCurrentPage:pdfCurrentPage];
+ [resultImageView setNeedsDisplay:YES];
+ [self doUpdateUI];
+ }
+
+}
+
+- (IBAction)pdfNextPage:(id)sender {
+
+ if (pdfCurrentPage < (pdfPageCount - 1)) {
+ pdfCurrentPage++;
+ [[[[resultImageView image] representations] objectAtIndex:0] setCurrentPage:pdfCurrentPage];
+ [resultImageView setNeedsDisplay:YES];
+ [self doUpdateUI];
+ }
+
+}
+
+
+- (IBAction)pdfSaveAs:(id)sender {
+
+ NSSavePanel *panel = [NSSavePanel savePanel];
+
+ if ([panel runModal] == NSFileHandlingPanelOKButton) {
+
+ [pdfData writeToFile:[panel filename] atomically:YES];
+
+ }
+
+}
+
+
+
- (void)windowDidBecomeMain:(NSNotification *)aNotification {
- (void)resizeWebView {
- [[[resultWebView mainFrame] frameView] setFrame:[resultWebView frame]];
+// [[[resultWebView mainFrame] frameView] setFrame:[resultWebView frame]];
[resultWebView setNeedsDisplay:YES];
}
- (void)windowControllerDidLoadNib:(NSWindowController *) aController
{
- NSFont *computerFont = [resultView font];
+
- NSLog(@"resultview: ", resultView);
- NSLog(@"font: ", computerFont);
NSSize errorDrawerSize;
[super windowControllerDidLoadNib:aController];
-
- // Add any code here that need to be executed once the windowController has loaded the document's window.
-
- // register our two input text views to receive file drags
- //
-// [xmlView registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType, nil]];
-// [xsltView registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType, nil]];
-
-/*
- [xmlView setFont:computerFont];
- [xsltView setFont:computerFont];
-*/
- [xmlView setAllowsUndo:YES];
- [xsltView setAllowsUndo:YES];
-
+ [resultImageView setImageFrameStyle:NSImageFramePhoto];
+ [resultImageView setImageScaling:NSScaleNone];
+ [resultImageView setImageAlignment:NSImageAlignCenter];
+ [resultImageView setEditable:NO];
+
[resultWebView setTextSizeMultiplier:0.9];
warningIcon = [xmlWellFormedIcon image];
[self updateCompleteUI];
-
+
errorDrawerSize = [errorDrawer contentSize];
errorDrawerSize.height = 130;
[errorDrawer setContentSize:errorDrawerSize];
+
+ NSFont *computerFont = [NSFont fontWithName:@"Courier" size:12.0];
+ [resultView setFont:computerFont];
+ [tabView registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType, nil]];
+
+
+
if (findPanelController == nil) {
findPanelController = [[FindPanelController alloc] initWithWindowNibName:@"FindPanel"];
// NSLog(@"init find panel controller: %@", findPanelController);
unsavedChangesPanelController = [[UnsavedChangesPanelController alloc] initWithWindowNibName:@"UnsavedChanges"];
// NSLog(@"init unsaved changes panel controller: %@", unsavedChangesPanelController);
}
-
+}
-
+
+- (void)canCloseDocumentWithDelegate:(id)delegate shouldCloseSelector:(SEL)shouldCloseSelector contextInfo:(void *)contextInfo {
+
+ [uiUpdateTimer invalidate];
+ [super canCloseDocumentWithDelegate:delegate shouldCloseSelector:shouldCloseSelector contextInfo:contextInfo];
}
+
+
+
+
+
- (IBAction)showErrorLocation:(id)sender {
XMLTextView *textView;