The R Project SVN R-packages

Rev

Rev 6408 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
714 iacus 1
/*
2
 *  R.app : a Cocoa front end to: "R A Computer Language for Statistical Data Analysis"
3
 *  
4
 *  R.app Copyright notes:
1254 iacus 5
 *                     Copyright (C) 2004-5  The R Foundation
714 iacus 6
 *                     written by Stefano M. Iacus and Simon Urbanek
7
 *
8
 *                  
9
 *  R Copyright notes:
10
 *                     Copyright (C) 1995-1996   Robert Gentleman and Ross Ihaka
11
 *                     Copyright (C) 1998-2001   The R Development Core Team
12
 *                     Copyright (C) 2002-2004   The R Foundation
13
 *
14
 *  This program is free software; you can redistribute it and/or modify
15
 *  it under the terms of the GNU General Public License as published by
16
 *  the Free Software Foundation; either version 2 of the License, or
17
 *  (at your option) any later version.
18
 *
19
 *  This program is distributed in the hope that it will be useful,
20
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
21
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22
 *  GNU General Public License for more details.
23
 *
24
 *  A copy of the GNU General Public License is available via WWW at
25
 *  http://www.gnu.org/copyleft/gpl.html.  You can also obtain it by
26
 *  writing to the Free Software Foundation, Inc., 59 Temple Place,
27
 *  Suite 330, Boston, MA  02111-1307  USA.
28
 */
29
 
1048 urbaneks 30
#import "RGUI.h"
568 iacus 31
#import "HelpManager.h"
32
#import "RController.h"
816 urbaneks 33
#import "REngine/REngine.h"
5733 urbaneks 34
#import "RegexKitLite.h"
568 iacus 35
 
36
static id sharedHMController;
37
 
38
@implementation HelpManager
39
 
40
- (id)init
41
{
42
    self = [super init];
43
    if (self) {
44
		sharedHMController = self;
5504 urbaneks 45
		home = nil;
5732 urbaneks 46
		searchType = kExactMatch;
568 iacus 47
	}
48
 
49
    return self;
50
}
51
 
5732 urbaneks 52
- (void)dealloc
53
{
54
	[[NSNotificationCenter defaultCenter] removeObserver: self];
568 iacus 55
	[super dealloc];
56
}
57
 
58
- (IBAction)runHelpSearch:(id)sender
59
{
60
	if([[sender stringValue] length]==0) 
61
		return;
62
 
1136 urbaneks 63
	NSString *searchString;
64
	NSCharacterSet *charSet;
65
	charSet = [NSCharacterSet characterSetWithCharactersInString:@"'\""];
66
	searchString = [[sender stringValue] stringByTrimmingCharactersInSet:charSet];
1483 urbaneks 67
	SLog(@"runHelpSearch: <%@>", searchString);
1136 urbaneks 68
 
69
	//		[self sendInput:[NSString stringWithFormat:@"help(\"%@\")", searchString]];
1483 urbaneks 70
	if(searchType == kFuzzyMatch){
1136 urbaneks 71
		[[REngine mainEngine] executeString:[NSString stringWithFormat:@"print(help.search(\"%@\"))", searchString]];
568 iacus 72
			[sender setStringValue:@""];
73
	} else {
1136 urbaneks 74
		[self showHelpFor: searchString];
568 iacus 75
	}
76
}
77
 
1155 urbaneks 78
- (void)showHelpUsingFile: (NSString *)file topic: (NSString*) topic
1146 urbaneks 79
{
2332 urbaneks 80
	if (!file) return;
81
	if (!topic) topic=@"<unknown>";
5504 urbaneks 82
	NSString *url = nil;
83
	if ([file hasPrefix:@"http://"]) 
84
		url = file;
85
	else {
86
		int port = [[RController sharedController] helpServerPort];
87
		if (port == 0) {
88
			NSRunInformationalAlertPanel(NLS(@"Cannot start HTML help server."), NLS(@"Help"), NLS(@"Ok"), nil, nil);
89
			return;
90
		}
91
		if (!home) home = [[RController sharedController] home];
92
		if ([file hasPrefix:home])
93
			file = [file substringFromIndex:[home length]];
7337 urbaneks 94
		url = [NSString stringWithFormat:@"http://localhost:%d%@", port, file];
5504 urbaneks 95
	}
96
	SLog(@"HelpManager.showHelpUsingFile:\"%@\", topic=%@, URL=%@", file, topic, url);
5536 urbaneks 97
	if(url != nil) {
98
		if ([Preferences flagForKey:kExternalHelp withDefault:NO])
99
			[[REngine mainEngine] executeString:[NSString stringWithFormat:@"browseURL(\"%@\")", url]];
100
		else {
101
			[[HelpView mainFrame] loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:url]]];
102
			[helpWindow makeKeyAndOrderFront:self];
103
		}
104
	}
1146 urbaneks 105
}
106
 
5733 urbaneks 107
- (IBAction)executeSelection:(id)sender
108
{
109
	DOMRange *dr = [HelpView selectedDOMRange];
110
	if (dr) { /* we don't do line-exec since we don't get the text outside the selection */
111
		NSString *stx = [dr markupString];
112
		// Ok, some simple processing here - it may not work in all cases
5737 urbaneks 113
		stx = [stx stringByReplacingOccurrencesOfRegex:@"(?i)<br[^>]*?>" withString:@"\n"];
114
		stx = [stx stringByReplacingOccurrencesOfRegex:@"<[^>]*?>" withString:@""];
5733 urbaneks 115
		stx = [stx stringByReplacingOccurrencesOfString:@"&lt;" withString:@"<"];
116
		stx = [stx stringByReplacingOccurrencesOfString:@"&gt;" withString:@">"];
117
		stx = [stx stringByReplacingOccurrencesOfString:@"&amp;" withString:@"&"];
118
		[[RController sharedController] sendInput:stx];
119
	}
120
}
121
 
1136 urbaneks 122
- (void)showHelpFor:(NSString *)topic
123
{
124
	NSString *searchString;
125
	NSCharacterSet *charSet;
2332 urbaneks 126
	if (!topic) return; /* should we issue an error? This happens only if the encoding is wrong */
1136 urbaneks 127
	charSet = [NSCharacterSet characterSetWithCharactersInString:@"'\""];
128
	searchString = [topic stringByTrimmingCharactersInSet:charSet];
5504 urbaneks 129
	SLog(@"showHelpFor: <%@>", searchString);
5732 urbaneks 130
 
131
	if(searchType == kFuzzyMatch) {
132
		[[REngine mainEngine] executeString:[NSString stringWithFormat:@"print(help.search(\"%@\"))", searchString]];
133
		return;
134
	}
135
 
1136 urbaneks 136
	REngine *re = [REngine mainEngine];	
5504 urbaneks 137
	RSEXP *x= [re evaluateString:[NSString stringWithFormat:@"as.character(help(\"%@\", help_type='html'))",searchString]];
1136 urbaneks 138
	if ((x==nil) || ([x string]==NULL)) {
5705 urbaneks 139
		NSString *topicString = [NSString stringWithFormat:@"Topic: %@", searchString];
1136 urbaneks 140
		int res = NSRunInformationalAlertPanel(NLS(@"Can't find help for topic, would you like to expand the search?"), topicString, NLS(@"No"), NLS(@"Yes"), nil);
141
		if (!res)
142
			[[REngine mainEngine] executeString:[NSString stringWithFormat:@"print(help.search(\"%@\"))", searchString]];
5705 urbaneks 143
		else {
144
			// if user dismiss alert panel set focus back to caller window
145
			NSArray *orderedWindows = [NSApp orderedWindows];
146
			int i;
147
			for(i=0; i<[orderedWindows count]; i++) {
148
				if([[orderedWindows objectAtIndex:i] isVisible]) {
149
					[[orderedWindows objectAtIndex:i] makeKeyAndOrderFront:nil];
150
					return;
151
				}
152
			}
153
		}
1136 urbaneks 154
		return;
155
	}
156
	[x release];
5509 urbaneks 157
	[re executeString:[NSString stringWithFormat:@"print(help(\"%@\", help_type='html'))",searchString]];
1136 urbaneks 158
}
159
 
1490 urbaneks 160
- (NSWindow*) window
161
{
162
	return helpWindow;
163
}
164
 
6097 bibiko 165
- (WebView*)webView
166
{
167
	return HelpView;
168
}
169
 
568 iacus 170
- (IBAction)showMainHelp:(id)sender
171
{
172
	 REngine *re = [REngine mainEngine];	
173
	 RSEXP *x = [re evaluateString:@"try(getOption(\"main.help.url\"))"];
174
 
175
	 if ((x==nil) | ([x string]==nil)){
176
		[re executeString:@"try(main.help.url())"];            
177
		[x release];
178
		x = [re evaluateString:@"try(getOption(\"main.help.url\"))"];
179
		if((x == nil) | ([x string]==nil)){
180
			[x release];	
181
			return;		
182
		}
183
	 }
184
 
185
	NSString *url = [x string];
186
 
187
	if(url != nil)
188
	 	[[HelpView mainFrame] loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:url]]];
189
	[helpWindow makeKeyAndOrderFront:self];
190
	[x release];
191
 
192
}
193
 
194
- (IBAction)showRFAQ:(id)sender
195
{
1361 urbaneks 196
	NSString *url = [[NSBundle mainBundle] resourcePath];
197
	if (!url) {
198
		REngine *re = [REngine mainEngine];	
199
		RSEXP *x= [re evaluateString:@"file.path(R.home(),\"RMacOSX-FAQ.html\")"];
200
		if(x==nil)
201
			return;
202
		url = [x string];
203
		[x release];
204
		if (url) url = [NSString stringWithFormat:@"file://%@", url];
205
	} else
206
		url = [NSString stringWithFormat:@"file://%@/RMacOSX-FAQ.html", url];
568 iacus 207
 
1361 urbaneks 208
	if(url != nil) {
568 iacus 209
	 	[[HelpView mainFrame] loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:url]]];
1361 urbaneks 210
		[helpWindow makeKeyAndOrderFront:self];
211
	}
568 iacus 212
}
213
 
214
- (IBAction)whatsNew:(id)sender
215
{
5732 urbaneks 216
 
217
	SLog(@"What's New");
218
 
219
	REngine *re = [REngine mainEngine];
220
 
4297 urbaneks 221
	/* syntax-highlighting kills us, so we use TextEdit for now */
5732 urbaneks 222
	// [re executeString:@"system(paste('open -a /Applications/TextEdit.app',file.path(R.home(),'NEWS')))"];
223
	// {
224
	// 	NSBundle* myBundle = [NSBundle mainBundle];
225
	// 	if (myBundle)
226
	// 		system([[NSString stringWithFormat:@"open -a /Applications/TextEdit.app \"%@/NEWS\"", [myBundle resourcePath]] UTF8String]);
227
	// }
228
 
229
	NSBundle *myBundle = [NSBundle mainBundle];
230
	if(myBundle) {
231
		SLog(@" - resource path: %@", [myBundle resourcePath]);
232
		RSEXP *xx = [re evaluateString:[NSString stringWithFormat:@"file.show('%@/NEWS')", [[myBundle resourcePath] stringByReplacingOccurrencesOfString:@"'" withString:@"\\'"]]];
233
		if(xx) [xx release];
4297 urbaneks 234
	}
5732 urbaneks 235
 
236
	RSEXP *x = [re evaluateString:@"file.show(file.path(R.home(),\"NEWS\"))"];
237
	if(!x) return;
238
	[x release]; 
239
 
568 iacus 240
}
241
 
796 urbaneks 242
+ (id) sharedController{
568 iacus 243
	return sharedHMController;
244
}
245
 
5993 bibiko 246
- (void)showHelpFileForURL:(NSURL*)url
247
{
248
	if(url != nil) {
6109 bibiko 249
		SLog(@"HelpManager:showHelpFileForURL %@", [url absoluteString]);
5993 bibiko 250
		[[HelpView mainFrame] loadRequest:[NSURLRequest requestWithURL:url]];
251
		[helpWindow makeKeyAndOrderFront:self];
252
		return;
253
	}
254
	NSBeep();
255
}
256
 
824 urbaneks 257
- (IBAction)printDocument:(id)sender
258
{
6007 bibiko 259
 
260
	//TODO: for now, if displayed doc is a PDF open it via "Preview" for printing
261
	NSString *currentURL = [[HelpView mainFrameURL] lowercaseString];
262
	if([currentURL hasSuffix:@".pdf"]) {
263
		REngine *re = [REngine mainEngine];
264
		if (![re beginProtected]) {
265
			SLog(@"HelpManager.printPDF bailed because protected REngine entry failed [***]");
266
			return;
267
		}
268
		[re executeString:[NSString stringWithFormat:@"system('open \"%@\"', intern=TRUE, wait=FALSE)", currentURL]];
269
		[re endProtected];
270
		return;
271
	}
272
 
273
 
824 urbaneks 274
	NSPrintInfo *printInfo;
275
	NSPrintOperation *printOp;
6007 bibiko 276
 
5705 urbaneks 277
	printInfo = [NSPrintInfo sharedPrintInfo];
824 urbaneks 278
	[printInfo setHorizontalPagination: NSFitPagination];
279
	[printInfo setVerticalPagination: NSAutoPagination];
280
	[printInfo setVerticallyCentered:NO];
6007 bibiko 281
 
824 urbaneks 282
	printOp = [NSPrintOperation printOperationWithView:[[[HelpView mainFrame] frameView] documentView] 
283
											 printInfo:printInfo];
284
	[printOp setShowPanels:YES];
5737 urbaneks 285
	[printOp runOperationModalForWindow:[self window] 
286
							   delegate:self 
287
						 didRunSelector:@selector(sheetDidEnd:returnCode:contextInfo:) 
288
						    contextInfo:@""];
824 urbaneks 289
}
568 iacus 290
 
5732 urbaneks 291
- (void) setSearchTypeViaSender:(id)sender
1483 urbaneks 292
{
5732 urbaneks 293
 
294
	if(sender == nil) {
295
		[self setSearchType:kExactMatch];
296
		return;
297
	}
298
 
299
	int type = [sender tag];
300
 
1483 urbaneks 301
	if (type==kFuzzyMatch || type==kExactMatch) {
5732 urbaneks 302
		[self setSearchType:type];
303
		NSMenu *m = [(NSSearchFieldCell*)sender menu];
304
		if(!m) return;
1483 urbaneks 305
		[[m itemWithTag:kFuzzyMatch] setState:(searchType==kFuzzyMatch)?NSOnState:NSOffState];
306
		[[m itemWithTag:kExactMatch] setState:(searchType==kExactMatch)?NSOnState:NSOffState];
307
	}
308
}
309
 
310
- (void) awakeFromNib
311
{
5732 urbaneks 312
	[self setSearchTypeViaSender:nil];
1483 urbaneks 313
}
314
 
315
- (IBAction)changeSearchType:(id)sender
316
{
5732 urbaneks 317
	[self setSearchTypeViaSender:sender];
1483 urbaneks 318
}
319
 
5732 urbaneks 320
- (void)setSearchType:(int)type
321
{
322
	if(type == kExactMatch || type == kFuzzyMatch) {
323
		if(type != searchType) {
324
			SLog(@"HelpManger - searchType was changed from %d to %d", searchType, type);
325
			searchType = type;
326
 
327
			// Update searchField's searchMenuTemplate
328
			NSMenu *m = [[searchField cell] searchMenuTemplate];
329
			[[m itemWithTag:kExactMatch] setState:(type == kExactMatch) ? NSOnState : NSOffState];
330
			[[m itemWithTag:kFuzzyMatch] setState:(type == kExactMatch) ? NSOffState : NSOnState];
331
			[[searchField cell] setSearchMenuTemplate:m];
332
 
333
			// If searchType was changed notify all other help search fields
334
			[[NSNotificationCenter defaultCenter] postNotificationName:@"HelpSearchTypeChanged" object:nil];
335
		}
336
	}
337
}
338
 
339
- (int)searchType
340
{
341
	return searchType;
342
}
343
 
965 urbaneks 344
- (void)webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame {
345
}
346
 
347
- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
348
	[back setEnabled: [sender canGoBack]];
349
	[forward setEnabled: [sender canGoForward]];
350
}
351
 
5737 urbaneks 352
- (BOOL)validateMenuItem:(NSMenuItem *)menuItem
353
{
354
	if ([menuItem action] == @selector(executeSelection:)) {
355
		return ([HelpView selectedDOMRange] == nil) ? NO : YES;
356
	}
357
 
358
	return YES;
359
}
360
 
6097 bibiko 361
- (void)supportsWebViewSwipingInHistory
362
{
363
	return;
364
}
365
 
366
- (void)supportsWebViewMagnifying
367
{
368
	return;
369
}
370
 
5737 urbaneks 371
- (void)sheetDidEnd:(id)sheet returnCode:(int)returnCode contextInfo:(NSString *)contextInfo
372
{
373
 
374
	SLog(@"HelpManger: sheetDidEnd: returnCode: %d contextInfo: %@", returnCode, contextInfo);
375
 
376
	// Order out the sheet - could be a NSPanel or NSWindow
377
	if ([sheet respondsToSelector:@selector(orderOut:)]) {
378
		[sheet orderOut:nil];
379
	}
380
	else if ([sheet respondsToSelector:@selector(window)]) {
381
		[[sheet window] orderOut:nil];
382
	}
383
 
384
	[helpWindow makeKeyAndOrderFront:nil];
385
 
386
}
387
 
568 iacus 388
@end