// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #import "chrome/browser/cocoa/applescript/tab_applescript.h" #include "base/file_path.h" #include "base/logging.h" #import "base/scoped_nsobject.h" #include "base/sys_string_conversions.h" #include "base/utf_string_conversions.h" #include "chrome/browser/cocoa/applescript/error_applescript.h" #include "chrome/browser/download/save_package.h" #include "chrome/browser/renderer_host/render_view_host.h" #include "chrome/browser/tab_contents/navigation_controller.h" #include "chrome/browser/tab_contents/navigation_entry.h" #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/browser/sessions/session_id.h" #include "chrome/common/url_constants.h" #include "googleurl/src/gurl.h" @interface TabAppleScript() @property (nonatomic, copy) NSString* tempURL; @end @implementation TabAppleScript @synthesize tempURL = tempURL_; - (id)init { if ((self = [super init])) { SessionID session; SessionID::id_type futureSessionIDOfTab = session.id() + 1; // Holds the SessionID that the new tab is going to get. scoped_nsobject numID( [[NSNumber alloc] initWithInt:futureSessionIDOfTab]); [self setUniqueID:numID]; [self setTempURL:@""]; } return self; } - (void)dealloc { [tempURL_ release]; [super dealloc]; } - (id)initWithTabContent:(TabContents*)aTabContent { if (!aTabContent) { [self release]; return nil; } if ((self = [super init])) { // It is safe to be weak, if a tab goes away (eg user closing a tab) // the applescript runtime calls tabs in AppleScriptWindow and this // particular tab is never returned. tabContents_ = aTabContent; scoped_nsobject numID( [[NSNumber alloc] initWithInt:tabContents_->controller().session_id().id()]); [self setUniqueID:numID]; } return self; } - (void)setTabContent:(TabContents*)aTabContent { DCHECK(aTabContent); // It is safe to be weak, if a tab goes away (eg user closing a tab) // the applescript runtime calls tabs in AppleScriptWindow and this // particular tab is never returned. tabContents_ = aTabContent; scoped_nsobject numID( [[NSNumber alloc] initWithInt:tabContents_->controller().session_id().id()]); [self setUniqueID:numID]; [self setURL:[self tempURL]]; } - (NSString*)URL { if (!tabContents_) { return nil; } NavigationEntry* entry = tabContents_->controller().GetActiveEntry(); if (!entry) { return nil; } const GURL& url = entry->virtual_url(); return base::SysUTF8ToNSString(url.spec()); } - (void)setURL:(NSString*)aURL { // If a scripter sets a URL before the node is added save it at a temporary // location. if (!tabContents_) { [self setTempURL:aURL]; return; } GURL url(base::SysNSStringToUTF8(aURL)); // check for valid url. if (!url.is_empty() && !url.is_valid()) { AppleScript::SetError(AppleScript::errInvalidURL); return; } NavigationEntry* entry = tabContents_->controller().GetActiveEntry(); if (!entry) return; const GURL& previousURL = entry->virtual_url(); tabContents_->OpenURL(url, previousURL, CURRENT_TAB, PageTransition::TYPED); } - (NSString*)title { NavigationEntry* entry = tabContents_->controller().GetActiveEntry(); if (!entry) return nil; std::wstring title; if (entry != NULL) { title = UTF16ToWideHack(entry->title()); } return base::SysWideToNSString(title); } - (NSNumber*)loading { BOOL loadingValue = tabContents_->is_loading() ? YES : NO; return [NSNumber numberWithBool:loadingValue]; } - (void)handlesUndoScriptCommand:(NSScriptCommand*)command { RenderViewHost* view = tabContents_->render_view_host(); if (!view) { NOTREACHED(); return; } view->Undo(); } - (void)handlesRedoScriptCommand:(NSScriptCommand*)command { RenderViewHost* view = tabContents_->render_view_host(); if (!view) { NOTREACHED(); return; } view->Redo(); } - (void)handlesCutScriptCommand:(NSScriptCommand*)command { RenderViewHost* view = tabContents_->render_view_host(); if (!view) { NOTREACHED(); return; } view->Cut(); } - (void)handlesCopyScriptCommand:(NSScriptCommand*)command { RenderViewHost* view = tabContents_->render_view_host(); if (!view) { NOTREACHED(); return; } view->Copy(); } - (void)handlesPasteScriptCommand:(NSScriptCommand*)command { RenderViewHost* view = tabContents_->render_view_host(); if (!view) { NOTREACHED(); return; } view->Paste(); } - (void)handlesSelectAllScriptCommand:(NSScriptCommand*)command { RenderViewHost* view = tabContents_->render_view_host(); if (!view) { NOTREACHED(); return; } view->SelectAll(); } - (void)handlesGoBackScriptCommand:(NSScriptCommand*)command { NavigationController& navigationController = tabContents_->controller(); if (navigationController.CanGoBack()) navigationController.GoBack(); } - (void)handlesGoForwardScriptCommand:(NSScriptCommand*)command { NavigationController& navigationController = tabContents_->controller(); if (navigationController.CanGoForward()) navigationController.GoForward(); } - (void)handlesReloadScriptCommand:(NSScriptCommand*)command { NavigationController& navigationController = tabContents_->controller(); const bool checkForRepost = true; navigationController.Reload(checkForRepost); } - (void)handlesStopScriptCommand:(NSScriptCommand*)command { RenderViewHost* view = tabContents_->render_view_host(); if (!view) { // We tolerate Stop being called even before a view has been created. // So just log a warning instead of a NOTREACHED(). DLOG(WARNING) << "Stop: no view for handle "; return; } view->Stop(); } - (void)handlesPrintScriptCommand:(NSScriptCommand*)command { bool initiateStatus = tabContents_->PrintNow(); if (initiateStatus == false) { AppleScript::SetError(AppleScript::errInitiatePrinting); } } - (void)handlesSaveScriptCommand:(NSScriptCommand*)command { NSDictionary* dictionary = [command evaluatedArguments]; NSURL* fileURL = [dictionary objectForKey:@"File"]; // Scripter has not specifed the location at which to save, so we prompt for // it. if (!fileURL) { tabContents_->OnSavePage(); return; } FilePath mainFile(base::SysNSStringToUTF8([fileURL path])); // We create a directory path at the folder within which the file exists. // Eg. if main_file = '/Users/Foo/Documents/Google.html' // then directory_path = '/Users/Foo/Documents/Google_files/'. FilePath directoryPath = mainFile.RemoveExtension(); directoryPath = directoryPath.InsertBeforeExtension(std::string("_files/")); NSString* saveType = [dictionary objectForKey:@"FileType"]; SavePackage::SavePackageType savePackageType = SavePackage::SAVE_AS_COMPLETE_HTML; if (saveType) { if ([saveType isEqualToString:@"only html"]) { savePackageType = SavePackage::SAVE_AS_ONLY_HTML; } else if ([saveType isEqualToString:@"complete html"]) { savePackageType = SavePackage::SAVE_AS_COMPLETE_HTML; } else { AppleScript::SetError(AppleScript::errInvalidSaveType); return; } } tabContents_->SavePage(mainFile, directoryPath, savePackageType); } - (void)handlesViewSourceScriptCommand:(NSScriptCommand*)command { NavigationEntry* entry = tabContents_->controller().GetLastCommittedEntry(); if (entry) { tabContents_->OpenURL(GURL(chrome::kViewSourceScheme + std::string(":") + entry->url().spec()), GURL(), NEW_FOREGROUND_TAB, PageTransition::LINK); } } - (id)handlesExecuteJavascriptScriptCommand:(NSScriptCommand*)command { RenderViewHost* view = tabContents_->render_view_host(); if (!view) { NOTREACHED(); return nil; } std::wstring script = base::SysNSStringToWide( [[command evaluatedArguments] objectForKey:@"javascript"]); view->ExecuteJavascriptInWebFrame(L"", script); // TODO(Shreyas): Figure out a way to get the response back. return nil; } @end