/* * Copyright 2011 Sven Weidauer * * This file is part of NetSurf, http://www.netsurf-browser.org/ * * NetSurf is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 of the License. * * NetSurf is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #import "cocoa/BrowserViewController.h" #import "cocoa/BrowserView.h" #import "cocoa/BrowserWindowController.h" #import "desktop/browser_private.h" #import "desktop/history_core.h" #import "desktop/textinput.h" #import "desktop/options.h" #import "desktop/selection.h" #import "utils/corestrings.h" #import "utils/filename.h" #import "utils/url.h" @implementation BrowserViewController @synthesize browser; @synthesize url; @synthesize browserView; @synthesize windowController; @synthesize title; @synthesize status; @synthesize isProcessing; @synthesize favicon; @synthesize canGoBack; @synthesize canGoForward; - (void) dealloc; { [self setUrl: nil]; [self setBrowserView: nil]; [self setWindowController: nil]; [self setTitle: nil]; [self setStatus: nil]; [self setFavicon: nil]; [super dealloc]; } - initWithBrowser: (struct browser_window *) bw; { if ((self = [super initWithNibName: @"Browser" bundle: nil]) == nil) return nil; browser = bw; return self; } - (IBAction) navigate: (id) sender; { browser_window_go( browser, [url UTF8String], NULL, true ); } - (void) awakeFromNib; { [browserView setBrowser: browser]; } - (IBAction) zoomIn: (id) sender; { browser_window_set_scale( browser, browser->scale * 1.1, true ); } - (IBAction) zoomOut: (id) sender; { browser_window_set_scale( browser, browser->scale * 0.9, true ); } - (IBAction) zoomOriginal: (id) sender; { browser_window_set_scale( browser, (float)nsoption_int(scale) / 100.0, true ); } - (IBAction) backForwardSelected: (id) sender; { if ([sender selectedSegment] == 0) [self goBack: sender]; else [self goForward: sender]; } - (IBAction) goBack: (id) sender; { if (browser && history_back_available( browser->history )) { history_back(browser, browser->history); [self updateBackForward]; } } - (IBAction) goForward: (id) sender; { if (browser && history_forward_available( browser->history )) { history_forward(browser, browser->history); [self updateBackForward]; } } - (IBAction) goHome: (id) sender; { browser_window_go( browser, nsoption_charp(homepage_url), NULL, true ); } - (IBAction) reloadPage: (id) sender; { browser_window_reload( browser, true ); } - (IBAction) stopLoading: (id) sender; { browser_window_stop( browser ); } - (IBAction) viewSource: (id) sender; { struct hlcache_handle *content; size_t size; const char *source; const char *path = NULL; if (browser == NULL) return; content = browser->current_content; if (content == NULL) return; source = content_get_source_data(content, &size); if (source == NULL) return; /* try to load local files directly. */ lwc_string *scheme = nsurl_get_component(hlcache_handle_get_url(content), NSURL_SCHEME); if (scheme == NULL) return; bool match; if (lwc_string_isequal(scheme, corestring_lwc_file, &match) == lwc_error_ok && match == true) path = url_to_path(nsurl_access(hlcache_handle_get_url(content))); lwc_string_unref(scheme); if (path == NULL) { /* We cannot release the requested filename until after it * has finished being used. As we can't easily find out when * this is, we simply don't bother releasing it and simply * allow it to be re-used next time NetSurf is started. The * memory overhead from doing this is under 1 byte per * filename. */ const char *filename = filename_request(); const char *extension = "txt"; fprintf(stderr, "filename '%p'\n", filename); if (filename == NULL) return; lwc_string *str = content_get_mime_type(content); if (str) { NSString *mime = [NSString stringWithUTF8String:lwc_string_data(str)]; NSString *uti = (NSString *)UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, (CFStringRef)mime, NULL); NSString *ext = (NSString *)UTTypeCopyPreferredTagWithClass((CFStringRef)uti, kUTTagClassFilenameExtension); extension = [ext UTF8String]; lwc_string_unref(str); } NSURL *dataUrl = [NSURL URLWithString:[NSString stringWithFormat:@"%s.%s", filename, extension] relativeToURL:[NSURL fileURLWithPath:@TEMP_FILENAME_PREFIX]]; NSData *data = [NSData dataWithBytes:source length:size]; [data writeToURL:dataUrl atomically:NO]; path = [[dataUrl path] UTF8String]; } if (path) { NSString * p = [NSString stringWithUTF8String: path]; NSWorkspace * ws = [NSWorkspace sharedWorkspace]; [ws openFile:p withApplication:@"Xcode"]; } } static inline bool compare_float( float a, float b ) { const float epsilon = 0.00001; if (a == b) return true; return fabs( (a - b) / b ) <= epsilon; } - (BOOL) validateUserInterfaceItem: (id) item; { SEL action = [item action]; if (action == @selector(copy:)) { return browser_window_has_selection( browser ); } if (action == @selector(cut:)) { return browser_window_has_selection( browser ) && browser->caret_callback != NULL; } if (action == @selector(paste:)) { return browser->paste_callback != NULL; } if (action == @selector( stopLoading: )) { return browser->loading_content != NULL; } if (action == @selector( zoomOriginal: )) { return !compare_float( browser->scale, (float)nsoption_int(scale) / 100.0 ); } if (action == @selector( goBack: )) { return canGoBack; } if (action == @selector( goForward: )) { return canGoForward; } return YES; } - (void) updateBackForward; { [browserView updateHistory]; [self setCanGoBack: browser != NULL && history_back_available( browser->history )]; [self setCanGoForward: browser != NULL && history_forward_available( browser->history )]; } - (void) contentUpdated; { [browserView updateHistory]; } struct history_add_menu_item_data { NSInteger index; NSMenu *menu; id target; }; static bool history_add_menu_item_cb( const struct history *history, int x0, int y0, int x1, int y1, const struct history_entry *page, void *user_data ) { struct history_add_menu_item_data *data = user_data; NSMenuItem *item = nil; if (data->index < [data->menu numberOfItems]) { item = [data->menu itemAtIndex: data->index]; } else { item = [[NSMenuItem alloc] initWithTitle: @"" action: @selector( historyItemSelected: ) keyEquivalent: @""]; [data->menu addItem: item]; [item release]; } ++data->index; [item setTarget: data->target]; [item setTitle: [NSString stringWithUTF8String: history_entry_get_title( page )]]; [item setRepresentedObject: [NSValue valueWithPointer: page]]; return true; } - (IBAction) historyItemSelected: (id) sender; { struct history_entry *entry = [[sender representedObject] pointerValue]; history_go( browser, browser->history, entry, false ); [self updateBackForward]; } - (void) buildBackMenu: (NSMenu *)menu; { struct history_add_menu_item_data data = { .index = 0, .menu = menu, .target = self }; history_enumerate_back( browser->history, history_add_menu_item_cb, &data ); while (data.index < [menu numberOfItems]) [menu removeItemAtIndex: data.index]; } - (void) buildForwardMenu: (NSMenu *)menu; { struct history_add_menu_item_data data = { .index = 0, .menu = menu, .target = self }; history_enumerate_forward( browser->history, history_add_menu_item_cb, &data ); while (data.index < [menu numberOfItems]) [menu removeItemAtIndex: data.index]; } @end