diff options
author | pinkerton@chromium.org <pinkerton@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-08-10 16:27:41 +0000 |
---|---|---|
committer | pinkerton@chromium.org <pinkerton@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-08-10 16:27:41 +0000 |
commit | 187eaa7886d5c8045889f32f363dc8820e0168d1 (patch) | |
tree | 2880fb7cfe5d8b49e1f6b030462f22490a01a580 /chrome | |
parent | e08cc13997d6f129fbc58d9100ff5e9d4a819237 (diff) | |
download | chromium_src-187eaa7886d5c8045889f32f363dc8820e0168d1.zip chromium_src-187eaa7886d5c8045889f32f363dc8820e0168d1.tar.gz chromium_src-187eaa7886d5c8045889f32f363dc8820e0168d1.tar.bz2 |
Added a method to check if a browser is closing.
Added a method to get the next node ID for bookmarks managed by the bookmark
model.
Added AppleScript support.
Added scripting definition file.
Added support for saving tab.
Added localization support.
Added consistent error nos/error messages.
(patch developed by v.a.shreyas@gmail.com)
BUG=27468
TEST=none
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@55569 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
31 files changed, 2532 insertions, 1 deletions
diff --git a/chrome/app/app-Info.plist b/chrome/app/app-Info.plist index 334f3f1..98eebd4 100644 --- a/chrome/app/app-Info.plist +++ b/chrome/app/app-Info.plist @@ -152,6 +152,8 @@ <string>${CHROMIUM_CREATOR}</string> <key>NSAppleScriptEnabled</key> <true/> + <key>OSAScriptingDefinition</key> + <string>scripting.sdef</string> <key>CFBundleURLTypes</key> <array> <dict> diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 492e86b..56acd3e 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd @@ -7278,6 +7278,44 @@ Keep your key file in a safe place. You will need it to create new versions of y </ph> now has <ph name="BEGIN_LINK"><a href="$2"></ph>extensions<ph name="END_LINK"></a></ph> and <ph name="BEGIN_BUTTON"><button></ph>bookmark sync<ph name="END_BUTTON"></button></ph>. </message> + <!-- Mac AppleScript --> + <if expr="os == 'darwin'"> + <message name="IDS_GET_PROFILE_ERROR_APPLESCRIPT_MAC" desc="Error dialog title to be displayed when profile fails to load. Mac-only."> + Could not get profile. + </message> + <message name="IDS_BOOKMARK_MODEL_LOAD_ERROR_APPLESCRIPT_MAC" desc="Error dialog title to be displayed when bookmark model fails to load. Mac-only."> + Could not load bookmark model. + </message> + <message name="IDS_CREATE_BOOKMARK_FOLDER_ERROR_APPLESCRIPT_MAC" desc="Error dialog title to be displayed when bookmark folder cannot be created. Mac-only."> + Could not create bookmark folder. + </message> + <message name="IDS_CREATE_BOOKMARK_ITEM_ERROR_APPLESCRIPT_MAC" desc="Error dialog title to be displayed when bookmark item cannot be created. Mac-only."> + Could not create bookmark item. + </message> + <message name="IDS_INVALID_URL_APPLESCRIPT_MAC" desc="Error dialog title to be displayed when invalid URL is entered. Mac-only."> + Invalid URL entered. + </message> + <message name="IDS_INITIATE_PRINTING_ERROR_APPLESCRIPT_MAC" desc="Error dialog title to be displayed when printing could not be initiated. Mac-only."> + Could not initiate printing. + </message> + <message name="IDS_INVALID_SAVE_TYPE_ERROR_APPLESCRIPT_MAC" desc="Error dialog title to be displayed when wrong save type is entered. Mac-only."> + Invalid save type entered. + </message> + <message name="IDS_INVALID_MODE_ERROR_APPLESCRIPT_MAC" desc="Error dialog title to be displayed when wrong save type is entered. Mac-only."> + Invalid mode entered. + </message> + <message name="IDS_INVALID_TAB_INDEX_APPLESCRIPT_MAC" desc="Error dialog title to be displayed when invalid tab index is entered. Mac-only."> + Invalid tab index entered. + </message> + <message name="IDS_SET_MODE_APPLESCRIPT_MAC" desc="Error dialog title to be displayed when mode is entered after window is created. Mac-only."> + Cannot set mode after window is set. + </message> + <message name="IDS_WRONG_INDEX_ERROR_APPLESCRIPT_MAC" desc="Error dialog title to be displayed when ordered index is out of bounds. Mac-only."> + Wrong index. + </message> + </if> <!-- os == 'darwin' --> + + <!-- Mac Menubar Menus --> <if expr="os == 'darwin'"> <!-- Menubar Menu Titles --> diff --git a/chrome/browser/bookmarks/bookmark_model.h b/chrome/browser/bookmarks/bookmark_model.h index 6048315..00730d7 100644 --- a/chrome/browser/bookmarks/bookmark_model.h +++ b/chrome/browser/bookmarks/bookmark_model.h @@ -366,6 +366,9 @@ class BookmarkModel : public NotificationObserver, public BookmarkService { // Returns whether the bookmarks file changed externally. bool file_changed() const { return file_changed_; } + // Returns the next node ID. + int64 next_node_id() const { return next_node_id_; } + private: // Used to order BookmarkNodes by URL. class NodeURLComparator { diff --git a/chrome/browser/browser.h b/chrome/browser/browser.h index 2fc5d61..d210854 100644 --- a/chrome/browser/browser.h +++ b/chrome/browser/browser.h @@ -278,6 +278,10 @@ class Browser : public TabStripModelDelegate, // Gives beforeunload handlers the chance to cancel the close. bool ShouldCloseWindow(); + bool IsAttemptingToCloseBrowser() const { + return is_attempting_to_close_browser_; + } + // Invoked when the window containing us is closing. Performs the necessary // cleanup. void OnWindowClosing(); diff --git a/chrome/browser/cocoa/applescript/bookmark_applescript_utils_unittest.h b/chrome/browser/cocoa/applescript/bookmark_applescript_utils_unittest.h new file mode 100644 index 0000000..c3d6e83 --- /dev/null +++ b/chrome/browser/cocoa/applescript/bookmark_applescript_utils_unittest.h @@ -0,0 +1,63 @@ +// 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. + +#ifndef CHROME_BROWSER_COCOA_APPLESCRIPT_BOOKMARK_APPLESCRIPT_UTILS_UNITTEST_H_ +#define CHROME_BROWSER_COCOA_APPLESCRIPT_BOOKMARK_APPLESCRIPT_UTILS_UNITTEST_H_ + +#import <objc/objc-runtime.h> +#import <Cocoa/Cocoa.h> + +#include "base/scoped_nsobject.h" +#include "base/scoped_ptr.h" +#import "chrome/browser/app_controller_mac.h" +#import "chrome/browser/cocoa/applescript/bookmark_folder_applescript.h" +#include "chrome/browser/cocoa/browser_test_helper.h" +#include "chrome/browser/cocoa/cocoa_test_helper.h" +#include "chrome/test/model_test_utils.h" +#include "testing/platform_test.h" + +// The fake object that acts as our app's delegate, useful for testing purposes. +@interface FakeAppDelegate : AppController { + @public + BrowserTestHelper* helper_; // weak. +} +@property (nonatomic) BrowserTestHelper* helper; +// Return the |TestingProfile*| which is used for testing. +- (Profile*)defaultProfile; +@end + + +// Used to emulate an active running script, useful for testing purposes. +@interface FakeScriptCommand : NSScriptCommand { + Method originalMethod_; + Method alternateMethod_; +} +@end + + +// The base class for all our bookmark releated unit tests. +class BookmarkAppleScriptTest : public CocoaTest { + public: + BookmarkAppleScriptTest() { + appDelegate_.reset([[FakeAppDelegate alloc] init]); + [appDelegate_.get() setHelper:&helper_]; + [NSApp setDelegate:appDelegate_]; + const BookmarkNode* root = model().GetBookmarkBarNode(); + const std::wstring modelString(L"a f1:[ b d c ] d f2:[ e f g ] h "); + model_test_utils::AddNodesFromModelString(model(), root, modelString); + bookmarkBar_.reset([[BookmarkFolderAppleScript alloc] + initWithBookmarkNode:model().GetBookmarkBarNode()]); + } + private: + BrowserTestHelper helper_; + scoped_nsobject<FakeAppDelegate> appDelegate_; + protected: + scoped_nsobject<BookmarkFolderAppleScript> bookmarkBar_; + BookmarkModel& model() { + return *helper_.profile()->GetBookmarkModel(); + } +}; + +#endif +// CHROME_BROWSER_COCOA_APPLESCRIPT_BOOKMARK_APPLESCRIPT_UTILS_UNITTEST_H_ diff --git a/chrome/browser/cocoa/applescript/bookmark_applescript_utils_unittest.mm b/chrome/browser/cocoa/applescript/bookmark_applescript_utils_unittest.mm new file mode 100644 index 0000000..5616774 --- /dev/null +++ b/chrome/browser/cocoa/applescript/bookmark_applescript_utils_unittest.mm @@ -0,0 +1,45 @@ +// 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/bookmark_applescript_utils_unittest.h" + +@implementation FakeAppDelegate + +@synthesize helper = helper_; + +- (Profile*)defaultProfile { + if (!helper_) + return NULL; + return helper_->profile(); +} +@end + +// Represents the current fake command that is executing. +static FakeScriptCommand* kFakeCurrentCommand; + +@implementation FakeScriptCommand + +- (id)init { + if ((self = [super init])) { + originalMethod_ = class_getClassMethod([NSScriptCommand class], + @selector(currentCommand)); + alternateMethod_ = class_getClassMethod([self class], + @selector(currentCommand)); + method_exchangeImplementations(originalMethod_, alternateMethod_); + kFakeCurrentCommand = self; + } + return self; +} + ++ (NSScriptCommand*)currentCommand { + return kFakeCurrentCommand; +} + +- (void)dealloc { + method_exchangeImplementations(originalMethod_, alternateMethod_); + kFakeCurrentCommand = nil; + [super dealloc]; +} + +@end diff --git a/chrome/browser/cocoa/applescript/bookmark_folder_applescript.h b/chrome/browser/cocoa/applescript/bookmark_folder_applescript.h new file mode 100644 index 0000000..c8969de --- /dev/null +++ b/chrome/browser/cocoa/applescript/bookmark_folder_applescript.h @@ -0,0 +1,67 @@ +// 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. + +#ifndef CHROME_BROWSER_COCOA_APPLESCRIPT_BOOKMARK_FOLDER_APPLESCRIPT_H_ +#define CHROME_BROWSER_COCOA_APPLESCRIPT_BOOKMARK_FOLDER_APPLESCRIPT_H_ + +#import <Cocoa/Cocoa.h> + +#import "chrome/browser/cocoa/applescript/bookmark_node_applescript.h" + +// Represent a bookmark folder scriptable object in applescript. +@interface BookmarkFolderAppleScript : BookmarkNodeAppleScript { + +} + +// Bookmark folder manipulation methods. +// Returns an array of |BookmarkFolderAppleScript*| of all the bookmark folders +// contained within this particular folder. +- (NSArray*)bookmarkFolders; + +// Inserts a bookmark folder at the end. +- (void)insertInBookmarkFolders:(id)aBookmarkFolder; + +// Inserts a bookmark folder at some position in the list. +// Called by applescript which takes care of bounds checking, make sure of it +// before calling directly. +- (void)insertInBookmarkFolders:(id)aBookmarkFolder atIndex:(int)index; + +// Remove a bookmark folder from the list. +// Called by applescript which takes care of bounds checking, make sure of it +// before calling directly. +- (void)removeFromBookmarkFoldersAtIndex:(int)index; + +// Bookmark item manipulation methods. +// Returns an array of |BookmarkItemAppleScript*| of all the bookmark items +// contained within this particular folder. +- (NSArray*)bookmarkItems; + +// Inserts a bookmark item at the end. +- (void)insertInBookmarkItems:(id)aBookmarkItem; + +// Inserts a bookmark item at some position in the list. +// Called by applescript which takes care of bounds checking, make sure of it +// before calling directly. +- (void)insertInBookmarkItems:(id)aBookmarkItem atIndex:(int)index; + +// Removes a bookmarks folder from the list. +// Called by applescript which takes care of bounds checking, make sure of it +// before calling directly. +- (void)removeFromBookmarkItemsAtIndex:(int)index; + +// Returns the position of a bookmark folder within the current bookmark folder +// which consists of bookmark folders as well as bookmark items. +// AppleScript makes sure that there is a bookmark folder before calling this +// method, make sure of that before calling directly. +- (int)calculatePositionOfBookmarkFolderAt:(int)index; + +// Returns the position of a bookmark item within the current bookmark folder +// which consists of bookmark folders as well as bookmark items. +// AppleScript makes sure that there is a bookmark item before calling this +// method, make sure of that before calling directly. +- (int)calculatePositionOfBookmarkItemAt:(int)index; + +@end + +#endif // CHROME_BROWSER_COCOA_APPLESCRIPT_BOOKMARK_FOLDER_APPLESCRIPT_H_ diff --git a/chrome/browser/cocoa/applescript/bookmark_folder_applescript.mm b/chrome/browser/cocoa/applescript/bookmark_folder_applescript.mm new file mode 100644 index 0000000..d7acc58 --- /dev/null +++ b/chrome/browser/cocoa/applescript/bookmark_folder_applescript.mm @@ -0,0 +1,203 @@ +// 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/bookmark_folder_applescript.h" + +#import "base/scoped_nsobject.h" +#include "base/sys_string_conversions.h" +#include "chrome/browser/bookmarks/bookmark_model.h" +#import "chrome/browser/cocoa/applescript/bookmark_item_applescript.h" +#import "chrome/browser/cocoa/applescript/constants_applescript.h" +#include "chrome/browser/cocoa/applescript/error_applescript.h" +#include "googleurl/src/gurl.h" + +@implementation BookmarkFolderAppleScript + +- (NSArray*)bookmarkFolders { + NSMutableArray* bookmarkFolders = [NSMutableArray + arrayWithCapacity:bookmarkNode_->GetChildCount()]; + + for (int i = 0; i < bookmarkNode_->GetChildCount(); ++i) { + const BookmarkNode* node = bookmarkNode_->GetChild(i); + + if (!node->is_folder()) + continue; + scoped_nsobject<BookmarkFolderAppleScript> bookmarkFolder( + [[BookmarkFolderAppleScript alloc] + initWithBookmarkNode:node]); + [bookmarkFolder setContainer:self + property:AppleScript::kBookmarkFoldersProperty]; + [bookmarkFolders addObject:bookmarkFolder]; + } + + return bookmarkFolders; +} + +- (void)insertInBookmarkFolders:(id)aBookmarkFolder { + // This method gets called when a new bookmark folder is created so + // the container and property are set here. + [aBookmarkFolder setContainer:self + property:AppleScript::kBookmarkFoldersProperty]; + BookmarkModel* model = [self bookmarkModel]; + if (!model) + return; + + const BookmarkNode* node = model->AddGroup(bookmarkNode_, + bookmarkNode_->GetChildCount(), + std::wstring()); + if (!node) { + AppleScript::SetError(AppleScript::errCreateBookmarkFolder); + return; + } + + [aBookmarkFolder setBookmarkNode:node]; +} + +- (void)insertInBookmarkFolders:(id)aBookmarkFolder atIndex:(int)index { + // This method gets called when a new bookmark folder is created so + // the container and property are set here. + [aBookmarkFolder setContainer:self + property:AppleScript::kBookmarkFoldersProperty]; + int position = [self calculatePositionOfBookmarkFolderAt:index]; + + BookmarkModel* model = [self bookmarkModel]; + if (!model) + return; + + const BookmarkNode* node = model->AddGroup(bookmarkNode_, + position, + std::wstring()); + if (!node) { + AppleScript::SetError(AppleScript::errCreateBookmarkFolder); + return; + } + + [aBookmarkFolder setBookmarkNode:node]; +} + +- (void)removeFromBookmarkFoldersAtIndex:(int)index { + int position = [self calculatePositionOfBookmarkFolderAt:index]; + + BookmarkModel* model = [self bookmarkModel]; + if (!model) + return; + + model->Remove(bookmarkNode_, position); +} + +- (NSArray*)bookmarkItems { + NSMutableArray* bookmarkItems = [NSMutableArray + arrayWithCapacity:bookmarkNode_->GetChildCount()]; + + for (int i = 0; i < bookmarkNode_->GetChildCount(); ++i) { + const BookmarkNode* node = bookmarkNode_->GetChild(i); + + if (!node->is_url()) + continue; + scoped_nsobject<BookmarkFolderAppleScript> bookmarkItem( + [[BookmarkItemAppleScript alloc] + initWithBookmarkNode:node]); + [bookmarkItem setContainer:self + property:AppleScript::kBookmarkItemsProperty]; + [bookmarkItems addObject:bookmarkItem]; + } + + return bookmarkItems; +} + +- (void)insertInBookmarkItems:(BookmarkItemAppleScript*)aBookmarkItem { + // This method gets called when a new bookmark item is created so + // the container and property are set here. + [aBookmarkItem setContainer:self + property:AppleScript::kBookmarkItemsProperty]; + + BookmarkModel* model = [self bookmarkModel]; + if (!model) + return; + + GURL url = GURL(base::SysNSStringToUTF8([aBookmarkItem URL])); + if (!url.is_valid()) { + AppleScript::SetError(AppleScript::errInvalidURL); + return; + } + + const BookmarkNode* node = model->AddURL(bookmarkNode_, + bookmarkNode_->GetChildCount(), + std::wstring(), + url); + if (!node) { + AppleScript::SetError(AppleScript::errCreateBookmarkItem); + return; + } + + [aBookmarkItem setBookmarkNode:node]; +} + +- (void)insertInBookmarkItems:(BookmarkItemAppleScript*)aBookmarkItem + atIndex:(int)index { + // This method gets called when a new bookmark item is created so + // the container and property are set here. + [aBookmarkItem setContainer:self + property:AppleScript::kBookmarkItemsProperty]; + int position = [self calculatePositionOfBookmarkItemAt:index]; + + BookmarkModel* model = [self bookmarkModel]; + if (!model) + return; + + GURL url(base::SysNSStringToUTF8([aBookmarkItem URL])); + if (!url.is_valid()) { + AppleScript::SetError(AppleScript::errInvalidURL); + return; + } + + const BookmarkNode* node = model->AddURL(bookmarkNode_, + position, + std::wstring(), + url); + if (!node) { + AppleScript::SetError(AppleScript::errCreateBookmarkItem); + return; + } + + [aBookmarkItem setBookmarkNode:node]; +} + +- (void)removeFromBookmarkItemsAtIndex:(int)index { + int position = [self calculatePositionOfBookmarkItemAt:index]; + + BookmarkModel* model = [self bookmarkModel]; + if (!model) + return; + + model->Remove(bookmarkNode_, position); +} + +- (int)calculatePositionOfBookmarkFolderAt:(int)index { + // Traverse through all the child nodes till the required node is found and + // return its position. + // AppleScript is 1-based therefore index is incremented by 1. + ++index; + int count = -1; + while (index) { + if (bookmarkNode_->GetChild(++count)->is_folder()) + --index; + } + return count; +} + +- (int)calculatePositionOfBookmarkItemAt:(int)index { + // Traverse through all the child nodes till the required node is found and + // return its position. + // AppleScript is 1-based therefore index is incremented by 1. + ++index; + int count = -1; + while (index) { + if (bookmarkNode_->GetChild(++count)->is_url()) + --index; + } + return count; +} + +@end diff --git a/chrome/browser/cocoa/applescript/bookmark_folder_applescript_unittest.mm b/chrome/browser/cocoa/applescript/bookmark_folder_applescript_unittest.mm new file mode 100644 index 0000000..f0f7d10 --- /dev/null +++ b/chrome/browser/cocoa/applescript/bookmark_folder_applescript_unittest.mm @@ -0,0 +1,195 @@ +// 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 <Cocoa/Cocoa.h> + +#include "base/scoped_nsobject.h" +#include "base/sys_string_conversions.h" +#import "chrome/browser/cocoa/applescript/bookmark_applescript_utils_unittest.h" +#import "chrome/browser/cocoa/applescript/bookmark_folder_applescript.h" +#import "chrome/browser/cocoa/applescript/bookmark_item_applescript.h" +#import "chrome/browser/cocoa/applescript/constants_applescript.h" +#import "chrome/browser/cocoa/applescript/error_applescript.h" +#include "googleurl/src/gurl.h" +#include "testing/gtest/include/gtest/gtest.h" +#import "testing/gtest_mac.h" +#include "testing/platform_test.h" + +typedef BookmarkAppleScriptTest BookmarkFolderAppleScriptTest; + +namespace { + +// Test all the bookmark folders within. +TEST_F(BookmarkFolderAppleScriptTest, BookmarkFolders) { + NSArray* bookmarkFolders = [bookmarkBar_.get() bookmarkFolders]; + BookmarkFolderAppleScript* folder1 = [bookmarkFolders objectAtIndex:0]; + BookmarkFolderAppleScript* folder2 = [bookmarkFolders objectAtIndex:1]; + + EXPECT_EQ(2U, [bookmarkFolders count]); + + EXPECT_NSEQ(@"f1", [folder1 title]); + EXPECT_NSEQ(@"f2", [folder2 title]); + EXPECT_EQ([folder1 container], bookmarkBar_.get()); + EXPECT_EQ([folder2 container], bookmarkBar_.get()); + EXPECT_NSEQ(AppleScript::kBookmarkFoldersProperty, + [folder1 containerProperty]); + EXPECT_NSEQ(AppleScript::kBookmarkFoldersProperty, + [folder2 containerProperty]); +} + +// Insert a new bookmark folder. +TEST_F(BookmarkFolderAppleScriptTest, InsertBookmarkFolder) { + // Emulate what applescript would do when inserting a new bookmark folder. + // Emulates a script like |set var to make new bookmark folder with + // properties {title:"foo"}|. + scoped_nsobject<BookmarkFolderAppleScript> bookmarkFolder( + [[BookmarkFolderAppleScript alloc] init]); + scoped_nsobject<NSNumber> var([[bookmarkFolder.get() uniqueID] copy]); + [bookmarkFolder.get() setTitle:@"foo"]; + [bookmarkBar_.get() insertInBookmarkFolders:bookmarkFolder.get()]; + + // Represents the bookmark folder after its added. + BookmarkFolderAppleScript* bf = + [[bookmarkBar_.get() bookmarkFolders] objectAtIndex:2]; + EXPECT_NSEQ(@"foo", [bf title]); + EXPECT_EQ([bf container], bookmarkBar_.get()); + EXPECT_NSEQ(AppleScript::kBookmarkFoldersProperty, + [bf containerProperty]); + EXPECT_NSEQ(var.get(), [bf uniqueID]); +} + +// Insert a new bookmark folder at a particular position. +TEST_F(BookmarkFolderAppleScriptTest, InsertBookmarkFolderAtPosition) { + // Emulate what applescript would do when inserting a new bookmark folder. + // Emulates a script like |set var to make new bookmark folder with + // properties {title:"foo"} at after bookmark folder 1|. + scoped_nsobject<BookmarkFolderAppleScript> bookmarkFolder( + [[BookmarkFolderAppleScript alloc] init]); + scoped_nsobject<NSNumber> var([[bookmarkFolder.get() uniqueID] copy]); + [bookmarkFolder.get() setTitle:@"foo"]; + [bookmarkBar_.get() insertInBookmarkFolders:bookmarkFolder.get() atIndex:1]; + + // Represents the bookmark folder after its added. + BookmarkFolderAppleScript* bf = + [[bookmarkBar_.get() bookmarkFolders] objectAtIndex:1]; + EXPECT_NSEQ(@"foo", [bf title]); + EXPECT_EQ([bf container], bookmarkBar_.get()); + EXPECT_NSEQ(AppleScript::kBookmarkFoldersProperty, [bf containerProperty]); + EXPECT_NSEQ(var.get(), [bf uniqueID]); +} + +// Delete bookmark folders. +TEST_F(BookmarkFolderAppleScriptTest, DeleteBookmarkFolders) { + unsigned int folderCount = 2, itemCount = 3; + for (unsigned int i = 0; i < folderCount; ++i) { + EXPECT_EQ(folderCount - i, [[bookmarkBar_.get() bookmarkFolders] count]); + EXPECT_EQ(itemCount, [[bookmarkBar_.get() bookmarkItems] count]); + [bookmarkBar_.get() removeFromBookmarkFoldersAtIndex:0]; + } +} + +// Test all the bookmark items within. +TEST_F(BookmarkFolderAppleScriptTest, BookmarkItems) { + NSArray* bookmarkItems = [bookmarkBar_.get() bookmarkItems]; + BookmarkItemAppleScript* item1 = [bookmarkItems objectAtIndex:0]; + BookmarkItemAppleScript* item2 = [bookmarkItems objectAtIndex:1]; + BookmarkItemAppleScript* item3 = [bookmarkItems objectAtIndex:2]; + + EXPECT_EQ(3U, [bookmarkItems count]); + + EXPECT_NSEQ(@"a", [item1 title]); + EXPECT_NSEQ(@"d", [item2 title]); + EXPECT_NSEQ(@"h", [item3 title]); + EXPECT_EQ([item1 container], bookmarkBar_.get()); + EXPECT_EQ([item2 container], bookmarkBar_.get()); + EXPECT_EQ([item3 container], bookmarkBar_.get()); + EXPECT_NSEQ(AppleScript::kBookmarkItemsProperty, [item1 containerProperty]); + EXPECT_NSEQ(AppleScript::kBookmarkItemsProperty, [item2 containerProperty]); + EXPECT_NSEQ(AppleScript::kBookmarkItemsProperty, [item3 containerProperty]); +} + +// Insert a new bookmark item. +TEST_F(BookmarkFolderAppleScriptTest, InsertBookmarkItem) { + // Emulate what applescript would do when inserting a new bookmark folder. + // Emulates a script like |set var to make new bookmark item with + // properties {title:"Google", URL:"http://google.com"}|. + scoped_nsobject<BookmarkItemAppleScript> bookmarkItem( + [[BookmarkItemAppleScript alloc] init]); + scoped_nsobject<NSNumber> var([[bookmarkItem.get() uniqueID] copy]); + [bookmarkItem.get() setTitle:@"Google"]; + [bookmarkItem.get() setURL:@"http://google.com"]; + [bookmarkBar_.get() insertInBookmarkItems:bookmarkItem.get()]; + + // Represents the bookmark item after its added. + BookmarkItemAppleScript* bi = + [[bookmarkBar_.get() bookmarkItems] objectAtIndex:3]; + EXPECT_NSEQ(@"Google", [bi title]); + EXPECT_EQ(GURL("http://google.com/"), + GURL(base::SysNSStringToUTF8([bi URL]))); + EXPECT_EQ([bi container], bookmarkBar_.get()); + EXPECT_NSEQ(AppleScript::kBookmarkItemsProperty, [bi containerProperty]); + EXPECT_NSEQ(var.get(), [bi uniqueID]); + + // Test to see no bookmark item is created when no/invlid URL is entered. + scoped_nsobject<FakeScriptCommand> fakeScriptCommand( + [[FakeScriptCommand alloc] init]); + bookmarkItem.reset([[BookmarkItemAppleScript alloc] init]); + [bookmarkBar_.get() insertInBookmarkItems:bookmarkItem.get()]; + EXPECT_EQ((int)AppleScript::errInvalidURL, + [fakeScriptCommand.get() scriptErrorNumber]); +} + +// Insert a new bookmark item at a particular position. +TEST_F(BookmarkFolderAppleScriptTest, InsertBookmarkItemAtPosition) { + // Emulate what applescript would do when inserting a new bookmark item. + // Emulates a script like |set var to make new bookmark item with + // properties {title:"XKCD", URL:"http://xkcd.org} + // at after bookmark item 1|. + scoped_nsobject<BookmarkItemAppleScript> bookmarkItem( + [[BookmarkItemAppleScript alloc] init]); + scoped_nsobject<NSNumber> var([[bookmarkItem.get() uniqueID] copy]); + [bookmarkItem.get() setTitle:@"XKCD"]; + [bookmarkItem.get() setURL:@"http://xkcd.org"]; + + [bookmarkBar_.get() insertInBookmarkItems:bookmarkItem.get() atIndex:1]; + + // Represents the bookmark item after its added. + BookmarkItemAppleScript* bi = + [[bookmarkBar_.get() bookmarkItems] objectAtIndex:1]; + EXPECT_NSEQ(@"XKCD", [bi title]); + EXPECT_EQ(GURL("http://xkcd.org/"), + GURL(base::SysNSStringToUTF8([bi URL]))); + EXPECT_EQ([bi container], bookmarkBar_.get()); + EXPECT_NSEQ(AppleScript::kBookmarkItemsProperty, + [bi containerProperty]); + EXPECT_NSEQ(var.get(), [bi uniqueID]); + + // Test to see no bookmark item is created when no/invlid URL is entered. + scoped_nsobject<FakeScriptCommand> fakeScriptCommand( + [[FakeScriptCommand alloc] init]); + bookmarkItem.reset([[BookmarkItemAppleScript alloc] init]); + [bookmarkBar_.get() insertInBookmarkItems:bookmarkItem.get() atIndex:1]; + EXPECT_EQ((int)AppleScript::errInvalidURL, + [fakeScriptCommand.get() scriptErrorNumber]); +} + +// Delete bookmark items. +TEST_F(BookmarkFolderAppleScriptTest, DeleteBookmarkItems) { + unsigned int folderCount = 2, itemCount = 3; + for (unsigned int i = 0; i < itemCount; ++i) { + EXPECT_EQ(folderCount, [[bookmarkBar_.get() bookmarkFolders] count]); + EXPECT_EQ(itemCount - i, [[bookmarkBar_.get() bookmarkItems] count]); + [bookmarkBar_.get() removeFromBookmarkItemsAtIndex:0]; + } +} + +// Set and get title. +TEST_F(BookmarkFolderAppleScriptTest, GetAndSetTitle) { + NSArray* bookmarkFolders = [bookmarkBar_.get() bookmarkFolders]; + BookmarkFolderAppleScript* folder1 = [bookmarkFolders objectAtIndex:0]; + [folder1 setTitle:@"Foo"]; + EXPECT_NSEQ(@"Foo", [folder1 title]); +} + +} // namespace diff --git a/chrome/browser/cocoa/applescript/bookmark_item_applescript.h b/chrome/browser/cocoa/applescript/bookmark_item_applescript.h new file mode 100644 index 0000000..97c07af --- /dev/null +++ b/chrome/browser/cocoa/applescript/bookmark_item_applescript.h @@ -0,0 +1,33 @@ +// 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. + +#ifndef CHROME_BROWSER_COCOA_APPLESCRIPT_BOOKMARK_ITEM_APPLESCRIPT_H_ +#define CHROME_BROWSER_COCOA_APPLESCRIPT_BOOKMARK_ITEM_APPLESCRIPT_H_ + +#import <Cocoa/Cocoa.h> + +#import "chrome/browser/cocoa/applescript/bookmark_node_applescript.h" + +// Represents a bookmark item scriptable object in applescript. +@interface BookmarkItemAppleScript : BookmarkNodeAppleScript { + @private + // Contains the temporary title when a user creates a new item with + // title specified like + // |make new bookmarks item with properties {title:"foo"}|. + NSString* tempURL_; +} + +// Assigns a node, sets its unique ID and also copies temporary values. +- (void)setBookmarkNode:(const BookmarkNode*)aBookmarkNode; + +// Returns the URL that the bookmark item holds. +- (NSString*)URL; + +// Sets the URL of the bookmark item, displays error in applescript console +// if URL is invalid. +- (void)setURL:(NSString*)aURL; + +@end + +#endif // CHROME_BROWSER_COCOA_APPLESCRIPT_BOOKMARK_ITEM_APPLESCRIPT_H_ diff --git a/chrome/browser/cocoa/applescript/bookmark_item_applescript.mm b/chrome/browser/cocoa/applescript/bookmark_item_applescript.mm new file mode 100644 index 0000000..e42a764 --- /dev/null +++ b/chrome/browser/cocoa/applescript/bookmark_item_applescript.mm @@ -0,0 +1,66 @@ +// 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/bookmark_item_applescript.h" + +#include "base/sys_string_conversions.h" +#include "chrome/browser/bookmarks/bookmark_model.h" +#import "chrome/browser/cocoa/applescript/error_applescript.h" +#include "chrome/browser/profile_manager.h" + +@interface BookmarkItemAppleScript() +@property (nonatomic, copy) NSString* tempURL; +@end + +@implementation BookmarkItemAppleScript + +@synthesize tempURL = tempURL_; + +- (id)init { + if ((self = [super init])) { + [self setTempURL:@""]; + } + return self; +} + +- (void)dealloc { + [tempURL_ release]; + [super dealloc]; +} + +- (void)setBookmarkNode:(const BookmarkNode*)aBookmarkNode { + [super setBookmarkNode:aBookmarkNode]; + [self setURL:[self tempURL]]; +} + +- (NSString*)URL { + if (!bookmarkNode_) + return tempURL_; + + const GURL& url = bookmarkNode_->GetURL(); + return base::SysUTF8ToNSString(url.spec()); +} + +- (void)setURL:(NSString*)aURL { + // If a scripter sets a URL before the node is added, URL is saved at a + // temporary location. + if (!bookmarkNode_) { + [self setTempURL:aURL]; + return; + } + + BookmarkModel* model = [self bookmarkModel]; + if (!model) + return; + + GURL url(base::SysNSStringToUTF8(aURL)); + if (!url.is_valid()) { + AppleScript::SetError(AppleScript::errInvalidURL); + return; + } + + model->SetURL(bookmarkNode_, url); +} + +@end diff --git a/chrome/browser/cocoa/applescript/bookmark_item_applescript_unittest.mm b/chrome/browser/cocoa/applescript/bookmark_item_applescript_unittest.mm new file mode 100644 index 0000000..68289dc --- /dev/null +++ b/chrome/browser/cocoa/applescript/bookmark_item_applescript_unittest.mm @@ -0,0 +1,45 @@ +// 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 <Cocoa/Cocoa.h> + +#include "base/scoped_nsobject.h" +#include "base/sys_string_conversions.h" +#import "chrome/browser/cocoa/applescript/bookmark_applescript_utils_unittest.h" +#import "chrome/browser/cocoa/applescript/bookmark_item_applescript.h" +#import "chrome/browser/cocoa/applescript/error_applescript.h" +#include "googleurl/src/gurl.h" +#include "testing/gtest/include/gtest/gtest.h" +#import "testing/gtest_mac.h" +#include "testing/platform_test.h" + +typedef BookmarkAppleScriptTest BookmarkItemAppleScriptTest; + +namespace { + +// Set and get title. +TEST_F(BookmarkItemAppleScriptTest, GetAndSetTitle) { + NSArray* bookmarkItems = [bookmarkBar_.get() bookmarkItems]; + BookmarkItemAppleScript* item1 = [bookmarkItems objectAtIndex:0]; + [item1 setTitle:@"Foo"]; + EXPECT_NSEQ(@"Foo", [item1 title]); +} + +// Set and get URL. +TEST_F(BookmarkItemAppleScriptTest, GetAndSetURL) { + NSArray* bookmarkItems = [bookmarkBar_.get() bookmarkItems]; + BookmarkItemAppleScript* item1 = [bookmarkItems objectAtIndex:0]; + [item1 setURL:@"http://foo-bar.org"]; + EXPECT_EQ(GURL("http://foo-bar.org"), + GURL(base::SysNSStringToUTF8([item1 URL]))); + + // If scripter enters invalid URL. + scoped_nsobject<FakeScriptCommand> fakeScriptCommand( + [[FakeScriptCommand alloc] init]); + [item1 setURL:@"invalid-url.org"]; + EXPECT_EQ((int)AppleScript::errInvalidURL, + [fakeScriptCommand.get() scriptErrorNumber]); +} + +} // namespace diff --git a/chrome/browser/cocoa/applescript/bookmark_node_applescript.h b/chrome/browser/cocoa/applescript/bookmark_node_applescript.h new file mode 100644 index 0000000..818b8ba --- /dev/null +++ b/chrome/browser/cocoa/applescript/bookmark_node_applescript.h @@ -0,0 +1,45 @@ +// 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. + +#ifndef CHROME_BROWSER_COCOA_APPLESCRIPT_BOOKMARK_NODE_APPLESCRIPT_H_ +#define CHROME_BROWSER_COCOA_APPLESCRIPT_BOOKMARK_NODE_APPLESCRIPT_H_ + +#import <Cocoa/Cocoa.h> + +#import "chrome/browser/cocoa/applescript/element_applescript.h" + +class BookmarkModel; +class BookmarkNode; + +// Contains all the elements that are common to both a bookmark folder and +// bookmark item. +@interface BookmarkNodeAppleScript : ElementAppleScript { + @protected + const BookmarkNode* bookmarkNode_; // weak. + // Contains the temporary title when a scripter creates a new folder/item with + // title specified like + // |make new bookmark folder with properties {title:"foo"}|. + NSString* tempTitle_; +} + +// Does not actually create a folder/item but just sets its ID, the folder is +// created in insertInBookmarksFolder: in the corresponding bookmarks folder. +- (id)init; + +// Does not make a folder/item but instead uses an existing one. +- (id)initWithBookmarkNode:(const BookmarkNode*)aBookmarkNode; + +// Assigns a node, sets its unique ID and also copies temporary values. +- (void)setBookmarkNode:(const BookmarkNode*)aBookmarkNode; + +// Get and Set title. +- (NSString*)title; +- (void)setTitle:(NSString*)aTitle; + +// Returns the bookmark model of the browser, returns NULL if there is an error. +- (BookmarkModel*)bookmarkModel; + +@end + +#endif // CHROME_BROWSER_COCOA_APPLESCRIPT_BOOKMARK_NODE_APPLESCRIPT_H_ diff --git a/chrome/browser/cocoa/applescript/bookmark_node_applescript.mm b/chrome/browser/cocoa/applescript/bookmark_node_applescript.mm new file mode 100644 index 0000000..14f0259 --- /dev/null +++ b/chrome/browser/cocoa/applescript/bookmark_node_applescript.mm @@ -0,0 +1,123 @@ +// 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/bookmark_node_applescript.h" + +#include "base/logging.h" +#include "base/sys_string_conversions.h" +#import "base/scoped_nsobject.h" +#import "chrome/browser/app_controller_mac.h" +#include "chrome/browser/bookmarks/bookmark_model.h" +#import "chrome/browser/chrome_browser_application_mac.h" +#import "chrome/browser/cocoa/applescript/error_applescript.h" +#include "chrome/browser/profile.h" +#import "chrome/browser/cocoa/applescript/bookmark_item_applescript.h" + +@interface BookmarkNodeAppleScript() +@property (nonatomic, copy) NSString* tempTitle; +@end + +@implementation BookmarkNodeAppleScript + +@synthesize tempTitle = tempTitle_; + +- (id)init { + if ((self = [super init])) { + BookmarkModel* model = [self bookmarkModel]; + if (!model) { + [self release]; + return nil; + } + + scoped_nsobject<NSNumber> numID( + [[NSNumber alloc] initWithLongLong:model->next_node_id()]); + [self setUniqueID:numID]; + [self setTempTitle:@""]; + } + return self; +} + +- (void)dealloc { + [tempTitle_ release]; + [super dealloc]; +} + + +- (id)initWithBookmarkNode:(const BookmarkNode*)aBookmarkNode { + if (!aBookmarkNode) { + [self release]; + return nil; + } + + if ((self = [super init])) { + // It is safe to be weak, if a bookmark item/folder goes away + // (eg user deleting a folder) the applescript runtime calls + // bookmarkFolders/bookmarkItems in BookmarkFolderAppleScript + // and this particular bookmark item/folder is never returned. + bookmarkNode_ = aBookmarkNode; + + scoped_nsobject<NSNumber> numID( + [[NSNumber alloc] initWithLongLong:aBookmarkNode->id()]); + [self setUniqueID:numID]; + } + return self; +} + +- (void)setBookmarkNode:(const BookmarkNode*)aBookmarkNode { + DCHECK(aBookmarkNode); + // It is safe to be weak, if a bookmark item/folder goes away + // (eg user deleting a folder) the applescript runtime calls + // bookmarkFolders/bookmarkItems in BookmarkFolderAppleScript + // and this particular bookmark item/folder is never returned. + bookmarkNode_ = aBookmarkNode; + + scoped_nsobject<NSNumber> numID( + [[NSNumber alloc] initWithLongLong:aBookmarkNode->id()]); + [self setUniqueID:numID]; + + [self setTitle:[self tempTitle]]; +} + +- (NSString*)title { + if (!bookmarkNode_) + return tempTitle_; + + return base::SysWideToNSString(bookmarkNode_->GetTitle()); +} + +- (void)setTitle:(NSString*)aTitle { + // If the scripter enters |make new bookmarks folder with properties + // {title:"foo"}|, the node has not yet been created so title is stored in the + // temp title. + if (!bookmarkNode_) { + [self setTempTitle:aTitle]; + return; + } + + BookmarkModel* model = [self bookmarkModel]; + if (!model) + return; + + model->SetTitle(bookmarkNode_, base::SysNSStringToWide(aTitle)); +} + +- (BookmarkModel*)bookmarkModel { + AppController* appDelegate = [NSApp delegate]; + + Profile* defaultProfile = [appDelegate defaultProfile]; + if (!defaultProfile) { + AppleScript::SetError(AppleScript::errGetProfile); + return NULL; + } + + BookmarkModel* model = defaultProfile->GetBookmarkModel(); + if (!model->IsLoaded()) { + AppleScript::SetError(AppleScript::errBookmarkModelLoad); + return NULL; + } + + return model; +} + +@end diff --git a/chrome/browser/cocoa/applescript/browsercrapplication+applescript.h b/chrome/browser/cocoa/applescript/browsercrapplication+applescript.h new file mode 100644 index 0000000..527df48 --- /dev/null +++ b/chrome/browser/cocoa/applescript/browsercrapplication+applescript.h @@ -0,0 +1,59 @@ +// 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. + +#ifndef CHROME_BROWSER_COCOA_APPLESCRIPT_BROWSERCRAPPLICATION_APPLESCRIPT_H_ +#define CHROME_BROWSER_COCOA_APPLESCRIPT_BROWSERCRAPPLICATION_APPLESCRIPT_H_ + +#import <Cocoa/Cocoa.h> + +#import "chrome/browser/chrome_browser_application_mac.h" + +@class BookmarkFolderAppleScript; +@class WindowAppleScript; + +// Represent the top level application scripting object in applescript. +@interface BrowserCrApplication (AppleScriptAdditions) + +// Application window manipulation methods. +// Returns an array of |WindowAppleScript*| of all windows present in the +// application. +- (NSArray*)appleScriptWindows; + +// Inserts a window at the beginning. +- (void)insertInAppleScriptWindows:(WindowAppleScript*)aWindow; + +// Inserts a window at some position in the list. +// Called by applescript which takes care of bounds checking, make sure of it +// before calling directly. +- (void)insertInAppleScriptWindows:(WindowAppleScript*)aWindow + atIndex:(int)index; + +// Removes a window from the list. +// Called by applescript which takes care of bounds checking, make sure of it +// before calling directly. +- (void)removeFromAppleScriptWindowsAtIndex:(int)index; + +// Always returns nil to indicate that it is the root container object. +- (NSScriptObjectSpecifier*)objectSpecifier; + +// Returns the other bookmarks bookmark folder, +// returns nil if there is an error. +- (BookmarkFolderAppleScript*)otherBookmarks; + +// Returns the bookmarks bar bookmark folder, return nil if there is an error. +- (BookmarkFolderAppleScript*)bookmarksBar; + +// Returns the Bookmarks Bar and Other Bookmarks Folders, each is of type +// |BookmarkFolderAppleScript*|. +- (NSArray*)bookmarkFolders; + +// Required functions, even though bookmarkFolders is declared as +// read-only, cocoa scripting does not currently prevent writing. +- (void)insertInBookmarksFolders:(id)aBookmarkFolder; +- (void)insertInBookmarksFolders:(id)aBookmarkFolder atIndex:(int)index; +- (void)removeFromBookmarksFoldersAtIndex:(int)index; + +@end + +#endif// CHROME_BROWSER_COCOA_APPLESCRIPT_BROWSERCRAPPLICATION_APPLESCRIPT_H_ diff --git a/chrome/browser/cocoa/applescript/browsercrapplication+applescript.mm b/chrome/browser/cocoa/applescript/browsercrapplication+applescript.mm new file mode 100644 index 0000000..f01a318 --- /dev/null +++ b/chrome/browser/cocoa/applescript/browsercrapplication+applescript.mm @@ -0,0 +1,134 @@ +// 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/browsercrapplication+applescript.h" + +#include "base/logging.h" +#import "base/scoped_nsobject.h" +#import "chrome/browser/app_controller_mac.h" +#include "chrome/browser/bookmarks/bookmark_model.h" +#include "chrome/browser/browser_list.h" +#import "chrome/browser/cocoa/applescript/bookmark_folder_applescript.h" +#import "chrome/browser/cocoa/applescript/constants_applescript.h" +#import "chrome/browser/cocoa/applescript/error_applescript.h" +#import "chrome/browser/cocoa/applescript/window_applescript.h" +#include "chrome/browser/profile.h" + +@implementation BrowserCrApplication (AppleScriptAdditions) + +- (NSArray*)appleScriptWindows { + NSMutableArray* appleScriptWindows = [NSMutableArray + arrayWithCapacity:BrowserList::size()]; + // Iterate through all browsers and check if it closing, + // if not add it to list. + for (BrowserList::const_iterator browserIterator = BrowserList::begin(); + browserIterator != BrowserList::end(); ++browserIterator) { + if ((*browserIterator)->IsAttemptingToCloseBrowser()) + continue; + + scoped_nsobject<WindowAppleScript> window( + [[WindowAppleScript alloc] initWithBrowser:*browserIterator]); + [appleScriptWindows addObject:window]; + } + // Windows sorted by their index value, which is obtained by calling + // orderedIndex: on each window. + [appleScriptWindows sortUsingSelector:@selector(windowComparator:)]; + return appleScriptWindows; +} + +- (void)insertInAppleScriptWindows:(WindowAppleScript*)aWindow { + // This method gets called when a new window is created so + // the container and property are set here. + [aWindow setContainer:self + property:AppleScript::kWindowsProperty]; +} + +- (void)insertInAppleScriptWindows:(WindowAppleScript*)aWindow + atIndex:(int)index { + // This method gets called when a new window is created so + // the container and property are set here. + [aWindow setContainer:self + property:AppleScript::kWindowsProperty]; + // Note: AppleScript is 1-based. + index--; + [aWindow setOrderedIndex:[NSNumber numberWithInt:index]]; +} + +- (void)removeFromAppleScriptWindowsAtIndex:(int)index { + [[[self appleScriptWindows] objectAtIndex:index] + handlesCloseScriptCommand:nil]; +} + +- (NSScriptObjectSpecifier*)objectSpecifier { + return nil; +} + +- (BookmarkFolderAppleScript*)otherBookmarks { + AppController* appDelegate = [NSApp delegate]; + + Profile* defaultProfile = [appDelegate defaultProfile]; + if (!defaultProfile) { + AppleScript::SetError(AppleScript::errGetProfile); + return nil; + } + + BookmarkModel* model = defaultProfile->GetBookmarkModel(); + if (!model->IsLoaded()) { + AppleScript::SetError(AppleScript::errBookmarkModelLoad); + return nil; + } + + BookmarkFolderAppleScript* otherBookmarks = + [[[BookmarkFolderAppleScript alloc] + initWithBookmarkNode:model->other_node()] autorelease]; + [otherBookmarks setContainer:self + property:AppleScript::kBookmarkFoldersProperty]; + return otherBookmarks; +} + +- (BookmarkFolderAppleScript*)bookmarksBar { + AppController* appDelegate = [NSApp delegate]; + + Profile* defaultProfile = [appDelegate defaultProfile]; + if (!defaultProfile) { + AppleScript::SetError(AppleScript::errGetProfile); + return nil; + } + + BookmarkModel* model = defaultProfile->GetBookmarkModel(); + if (!model->IsLoaded()) { + AppleScript::SetError(AppleScript::errBookmarkModelLoad); + return NULL; + } + + BookmarkFolderAppleScript* bookmarksBar = + [[[BookmarkFolderAppleScript alloc] + initWithBookmarkNode:model->GetBookmarkBarNode()] autorelease]; + [bookmarksBar setContainer:self + property:AppleScript::kBookmarkFoldersProperty]; + return bookmarksBar; +} + +- (NSArray*)bookmarkFolders { + BookmarkFolderAppleScript* otherBookmarks = [self otherBookmarks]; + BookmarkFolderAppleScript* bookmarksBar = [self bookmarksBar]; + NSArray* folderArray = [NSArray arrayWithObjects:otherBookmarks, + bookmarksBar, + nil]; + return folderArray; +} + +- (void)insertInBookmarksFolders:(id)aBookmarkFolder { + NOTIMPLEMENTED(); +} + +- (void)insertInBookmarksFolders:(id)aBookmarkFolder atIndex:(int)index { + NOTIMPLEMENTED(); +} + +- (void)removeFromBookmarksFoldersAtIndex:(int)index { + NOTIMPLEMENTED(); +} + +@end diff --git a/chrome/browser/cocoa/applescript/constants_applescript.h b/chrome/browser/cocoa/applescript/constants_applescript.h new file mode 100644 index 0000000..13a96df --- /dev/null +++ b/chrome/browser/cocoa/applescript/constants_applescript.h @@ -0,0 +1,31 @@ +// 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. + +#ifndef CHROME_BROWSER_COCOA_APPLESCRIPT_CONSTANTS_APPLESCRIPT_H_ +#define CHROME_BROWSER_COCOA_APPLESCRIPT_CONSTANTS_APPLESCRIPT_H_ + +#import <Cocoa/Cocoa.h> + +// This file contains the constant that are use to set the property of an +// applescript scriptable item. +namespace AppleScript { +// Property to access windows. +extern NSString* const kWindowsProperty; + +// Property to access tabs. +extern NSString* const kTabsProperty; + +// Property to access bookmarks folders. +extern NSString* const kBookmarkFoldersProperty; + +// Property to access bookmark items. +extern NSString* const kBookmarkItemsProperty; + +// To indicate a window in normal mode. +extern NSString* const kNormalWindowMode; + +// To indicate a window in incognito mode. +extern NSString* const kIncognitoWindowMode; +} +#endif // CHROME_BROWSER_COCOA_APPLESCRIPT_CONSTANTS_APPLESCRIPT_H_ diff --git a/chrome/browser/cocoa/applescript/constants_applescript.mm b/chrome/browser/cocoa/applescript/constants_applescript.mm new file mode 100644 index 0000000..3eddc9a --- /dev/null +++ b/chrome/browser/cocoa/applescript/constants_applescript.mm @@ -0,0 +1,25 @@ +// 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/constants_applescript.h" + +namespace AppleScript { +// Property to access windows. +NSString* const kWindowsProperty = @"appleScriptWindows"; + +// Property to access tabs. +NSString* const kTabsProperty = @"tabs"; + +// Property to access bookmarks folders. +NSString* const kBookmarkFoldersProperty = @"bookmarkFolders"; + +// Property to access bookmark items. +NSString* const kBookmarkItemsProperty = @"bookmarkItems"; + +// To indicate a window in normal mode. +NSString* const kNormalWindowMode = @"normal"; + +// To indicate a window in incognito mode. +NSString* const kIncognitoWindowMode = @"incognito"; +} diff --git a/chrome/browser/cocoa/applescript/element_applescript.h b/chrome/browser/cocoa/applescript/element_applescript.h new file mode 100644 index 0000000..ba3d65c --- /dev/null +++ b/chrome/browser/cocoa/applescript/element_applescript.h @@ -0,0 +1,37 @@ +// 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. + +#ifndef CHROME_BROWSER_COCOA_APPLESCRIPT_ELEMENT_APPLESCRIPT_H_ +#define CHROME_BROWSER_COCOA_APPLESCRIPT_ELEMENT_APPLESCRIPT_H_ + +#import <Cocoa/Cocoa.h> + +// This class is the root class for all the other applescript classes. +// It takes care of all the infrastructure type operations. +@interface ElementAppleScript : NSObject { + @protected + // Used by the applescript runtime to identify each unique scriptable object. + NSNumber* uniqueID_; + // Used by object specifier to find a scriptable object's place in a + // collection. + id container_; + NSString* containerProperty_; +} + +@property (nonatomic, copy) NSNumber* uniqueID; +@property (nonatomic, retain) id container; +@property (nonatomic, copy) NSString* containerProperty; + +// Calculates the objectspecifier by using the uniqueID, container and +// container property. +// An object specifier is used to identify objects within a +// collection. +- (NSScriptObjectSpecifier*)objectSpecifier; + +// Sets both container and property, retains container and copies property. +- (void)setContainer:(id)value property:(NSString*)property; + +@end + +#endif// CHROME_BROWSER_COCOA_APPLESCRIPT_ELEMENT_APPLESCRIPT_H_ diff --git a/chrome/browser/cocoa/applescript/element_applescript.mm b/chrome/browser/cocoa/applescript/element_applescript.mm new file mode 100644 index 0000000..270fd25 --- /dev/null +++ b/chrome/browser/cocoa/applescript/element_applescript.mm @@ -0,0 +1,38 @@ +// 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/element_applescript.h" + +@implementation ElementAppleScript + +@synthesize uniqueID = uniqueID_; +@synthesize container = container_; +@synthesize containerProperty = containerProperty_; + +// calling objectSpecifier asks an object to return an object specifier +// record referring to itself. You must call setContainer:property: before +// you can call this method. +- (NSScriptObjectSpecifier*)objectSpecifier { + return [[NSUniqueIDSpecifier allocWithZone:[self zone]] + initWithContainerClassDescription: + (NSScriptClassDescription*)[[self container] classDescription] + containerSpecifier: + [[self container] objectSpecifier] + key:[self containerProperty] + uniqueID:[self uniqueID]]; +} + +- (void)setContainer:(id)value property:(NSString*)property { + [self setContainer:value]; + [self setContainerProperty:property]; +} + +- (void)dealloc { + [uniqueID_ release]; + [container_ release]; + [containerProperty_ release]; + [super dealloc]; +} + +@end diff --git a/chrome/browser/cocoa/applescript/error_applescript.h b/chrome/browser/cocoa/applescript/error_applescript.h new file mode 100644 index 0000000..2635b2f --- /dev/null +++ b/chrome/browser/cocoa/applescript/error_applescript.h @@ -0,0 +1,41 @@ +// 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. + +#ifndef CHROME_BROWSER_COCOA_APPLESCRIPT_ERROR_APPLESCRIPT_H_ +#define CHROME_BROWSER_COCOA_APPLESCRIPT_ERROR_APPLESCRIPT_H_ + +#import <Cocoa/Cocoa.h> + +namespace AppleScript { + +enum ErrorCode { + // Error when default profile cannot be obtained. + errGetProfile = 1, + // Error when bookmark model fails to load. + errBookmarkModelLoad, + // Error when bookmark folder cannot be created. + errCreateBookmarkFolder, + // Error when bookmark item cannot be created. + errCreateBookmarkItem, + // Error when URL entered is invalid. + errInvalidURL, + // Error when printing cannot be initiated. + errInitiatePrinting, + // Error when invalid tab save type is entered. + errInvalidSaveType, + // Error when invalid browser mode is entered. + errInvalidMode, + // Error when tab index is out of bounds. + errInvalidTabIndex, + // Error when mode is set after browser window is created. + errSetMode, + // Error when index of browser window is out of bounds. + errWrongIndex +}; + +// This function sets an error message to the currently executing command. +void SetError(ErrorCode errorCode); +} + +#endif // CHROME_BROWSER_COCOA_APPLESCRIPT_ERROR_APPLESCRIPT_H_ diff --git a/chrome/browser/cocoa/applescript/error_applescript.mm b/chrome/browser/cocoa/applescript/error_applescript.mm new file mode 100644 index 0000000..cc25ad3 --- /dev/null +++ b/chrome/browser/cocoa/applescript/error_applescript.mm @@ -0,0 +1,56 @@ +// 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/error_applescript.h" + +#import "app/l10n_util_mac.h" +#include "base/logging.h" +#include "grit/generated_resources.h" + +void AppleScript::SetError(AppleScript::ErrorCode errorCode) { + using namespace l10n_util; + NSScriptCommand* current_command = [NSScriptCommand currentCommand]; + [current_command setScriptErrorNumber:(int)errorCode]; + NSString* error_string = @""; + switch (errorCode) { + case errGetProfile: + error_string = GetNSString(IDS_GET_PROFILE_ERROR_APPLESCRIPT_MAC); + break; + case errBookmarkModelLoad: + error_string = GetNSString(IDS_BOOKMARK_MODEL_LOAD_ERROR_APPLESCRIPT_MAC); + break; + case errCreateBookmarkFolder: + error_string = + GetNSString(IDS_CREATE_BOOKMARK_FOLDER_ERROR_APPLESCRIPT_MAC); + break; + case errCreateBookmarkItem: + error_string = + GetNSString(IDS_CREATE_BOOKMARK_ITEM_ERROR_APPLESCRIPT_MAC); + break; + case errInvalidURL: + error_string = GetNSString(IDS_INVALID_URL_APPLESCRIPT_MAC); + break; + case errInitiatePrinting: + error_string = GetNSString(IDS_INITIATE_PRINTING_ERROR_APPLESCRIPT_MAC); + break; + case errInvalidSaveType: + error_string = GetNSString(IDS_INVALID_SAVE_TYPE_ERROR_APPLESCRIPT_MAC); + break; + case errInvalidMode: + error_string = GetNSString(IDS_INVALID_MODE_ERROR_APPLESCRIPT_MAC); + break; + case errInvalidTabIndex: + error_string = GetNSString(IDS_INVALID_TAB_INDEX_APPLESCRIPT_MAC); + break; + case errSetMode: + error_string = GetNSString(IDS_SET_MODE_APPLESCRIPT_MAC); + break; + case errWrongIndex: + error_string = GetNSString(IDS_WRONG_INDEX_ERROR_APPLESCRIPT_MAC); + break; + default: + NOTREACHED(); + } + [current_command setScriptErrorString:error_string]; +} diff --git a/chrome/browser/cocoa/applescript/scripting.sdef b/chrome/browser/cocoa/applescript/scripting.sdef new file mode 100644 index 0000000..6200f7f --- /dev/null +++ b/chrome/browser/cocoa/applescript/scripting.sdef @@ -0,0 +1,295 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE dictionary SYSTEM "file://localhost/System/Library/DTDs/sdef.dtd"> +<dictionary title="Dictionary"> + <!-- + STANDARD SUITE + --> + <suite name="Standard Suite" code="core" description="Common classes and commands for all applications."> + <cocoa name="NSCoreSuite"/> + <class name="application" code="capp" description="The application's top-level scripting object."> + <cocoa class="BrowserCrApplication"/> + <element description="The windows contained within this application, ordered front to back." type="window"> + <cocoa key="appleScriptWindows"/> + </element> + <property name="name" code="pnam" description="The name of the application." type="text" access="r"/> + <property name="frontmost" code="pisf" description="Is this the frontmost (active) application?" type="boolean" access="r"> + <cocoa key="isActive"/> + </property> + <property name="version" code="vers" description="The version of the application." type="text" access="r"/> + <responds-to command="open"> + <cocoa method="handleOpenScriptCommand:"/> + </responds-to> + <responds-to command="quit"> + <cocoa method="handleQuitScriptCommand:"/> + </responds-to> + </class> + <class name="window" code="cwin" description="A window."> + <cocoa class="WindowAppleScript"/> + <element description="The tabs contained within the window." type="tab"> + <cocoa key="tabs"/> + </element> + <property name="name" code="pnam" description="The full title of the window." type="text" access="r"> + <cocoa key="title"/> + </property> + <property name="id" code="ID " description="The unique identifier of the window." type="integer" access="r"> + <cocoa key="uniqueID"/> + </property> + <property name="index" code="pidx" description="The index of the window, ordered front to back." type="integer"> + <cocoa key="orderedIndex"/> + </property> + <property name="bounds" code="pbnd" description="The bounding rectangle of the window." type="rectangle"> + <cocoa key="boundsAsQDRect"/> + </property> + <property name="closeable" code="hclb" description="Whether the window has a close box." type="boolean" access="r"> + <cocoa key="hasCloseBox"/> + </property> + <property name="minimizable" code="ismn" description="Whether the window can be minimized." type="boolean" access="r"> + <cocoa key="isMiniaturizable"/> + </property> + <property name="minimized" code="pmnd" description="Whether the window is currently minimized." type="boolean"> + <cocoa key="isMiniaturized"/> + </property> + <property name="resizable" code="prsz" description="Whether the window can be resized." type="boolean" access="r"> + <cocoa key="isResizable"/> + </property> + <property name="visible" code="pvis" description="Whether the window is currently visible." type="boolean"> + <cocoa key="isVisible"/> + </property> + <property name="zoomable" code="iszm" description="Whether the window can be zoomed." type="boolean" access="r"> + <cocoa key="isZoomable"/> + </property> + <property name="zoomed" code="pzum" description="Whether the window is currently zoomed." type="boolean"> + <cocoa key="isZoomed"/> + </property> + <property name="active tab" code="acTa" description="Returns the currently selected tab" type="tab" access="r"> + <cocoa key="activeTab"/> + </property> + <property name="mode" code="mode" description="Represents the mode of the window which can be 'normal' or 'incognito', can be set only once during creation of the window." type="text"> + <cocoa key="mode"/> + </property> + <property name="active tab index" code="acTI" description="The index of the active tab." type="integer"/> + <responds-to command="close"> + <cocoa method="handlesCloseScriptCommand:"/> + </responds-to> + </class> + <command name="save" code="coresave" description="Save an object."> + <direct-parameter description="the object to save, usually a document or window" type="specifier"/> + <parameter name="in" code="kfil" description="The file in which to save the object." type="file" optional="yes"> + <cocoa key="File"/> + </parameter> + <parameter name="as" code="fltp" description="The file type in which to save the data. Can be 'only html' or 'complete html', default is 'complete html'." type="text" optional="yes"> + <cocoa key="FileType"/> + </parameter> + </command> + <!-- + According to TN2106, 'open' should return the resulting document + object. However, the Cocoa implementation does not do this yet. + <result type="specifier"/> + --> + <command name="open" code="aevtodoc" description="Open a document."> + <direct-parameter description="The file(s) to be opened."> + <type type="file" list="yes"/> + </direct-parameter> + </command> + <command name="close" code="coreclos" description="Close a window."> + <cocoa class="NSCloseCommand"/> + <direct-parameter description="the document(s) or window(s) to close." type="specifier"/> + </command> + <command name="quit" code="aevtquit" description="Quit the application."> + <cocoa class="NSQuitCommand"/> + </command> + <command name="count" code="corecnte" description="Return the number of elements of a particular class within an object."> + <cocoa class="NSCountCommand"/> + <direct-parameter description="the object whose elements are to be counted" type="specifier"/> + <parameter name="each" code="kocl" description="The class of objects to be counted." type="type" optional="yes"> + <cocoa key="ObjectClass"/> + </parameter> + <result description="the number of elements" type="integer"/> + </command> + <command name="delete" code="coredelo" description="Delete an object."> + <cocoa class="NSDeleteCommand"/> + <direct-parameter description="the object to delete" type="specifier"/> + </command> + <command name="duplicate" code="coreclon" description="Copy object(s) and put the copies at a new location."> + <cocoa class="NSCloneCommand"/> + <direct-parameter description="the object(s) to duplicate" type="specifier"/> + <parameter name="to" code="insh" description="The location for the new object(s)." type="location specifier" optional="yes"> + <cocoa key="ToLocation"/> + </parameter> + <parameter name="with properties" code="prdt" description="Properties to be set in the new duplicated object(s)." type="record" optional="yes"> + <cocoa key="WithProperties"/> + </parameter> + <result description="the duplicated object(s)" type="specifier"/> + </command> + <command name="exists" code="coredoex" description="Verify if an object exists."> + <cocoa class="NSExistsCommand"/> + <direct-parameter description="the object in question" type="any"/> + <result description="true if it exists, false if not" type="boolean"/> + </command> + <command name="make" code="corecrel" description="Make a new object."> + <cocoa class="NSCreateCommand"/> + <parameter name="new" code="kocl" description="The class of the new object." type="type"> + <cocoa key="ObjectClass"/> + </parameter> + <parameter name="at" code="insh" description="The location at which to insert the object." type="location specifier" optional="yes"> + <cocoa key="Location"/> + </parameter> + <parameter name="with data" code="data" description="The initial contents of the object." type="any" optional="yes"> + <cocoa key="ObjectData"/> + </parameter> + <parameter name="with properties" code="prdt" description="The initial values for properties of the object." type="record" optional="yes"> + <cocoa key="KeyDictionary"/> + </parameter> + <result description="to the new object" type="specifier"/> + </command> + <command name="move" code="coremove" description="Move object(s) to a new location."> + <cocoa class="NSMoveCommand"/> + <direct-parameter description="the object(s) to move" type="specifier"/> + <parameter name="to" code="insh" description="The new location for the object(s)." type="location specifier"> + <cocoa key="ToLocation"/> + </parameter> + <result description="the moved object(s)" type="specifier"/> + </command> + <!-- NSCoreSuite doesn't define these. + <command name="run" code="aevtoapp" description="Run an application. Most applications will open an empty, untitled window."/> + <command name="reopen" code="aevtrapp" description="Reactivate a running application. Some applications will open a new untitled window if no window is open."/> + --> + <command name="print" code="aevtpdoc" description="Print an object."> + <!-- type would be better written as "file | document". --> + <direct-parameter description="The file(s) or document(s) to be printed." type="specifier"/> + </command> + <!-- "set" is supposed to be hidden. --> + <command name="set" code="coresetd" description="Set an object's data."> + <cocoa class="NSSetCommand"/> + <direct-parameter type="specifier"/> + <!-- "set" is supposed to return the fully evaluated "to" data. + <result type="any"/> + --> + <parameter name="to" code="data" description="The new value." type="any"> + <cocoa key="Value"/> + </parameter> + </command> + <!-- "get" is supposed to be hidden. --> + <command name="get" code="coregetd" description="Get the data for an object."> + <cocoa class="NSGetCommand"/> + <direct-parameter type="specifier"/> + <result type="any"/> + </command> + </suite> + <suite name="Chromium Suite" code="CrSu" description="Common classes and commands for Chrome."> + <class-extension description="The application's top-level scripting object." extends="application"> + <cocoa class="BrowserCrApplication"/> + <element description="Contains the bookmarks bar and other bookmarks folder." type="bookmark folder" access="r"> + <cocoa key="bookmarkFolders"/> + </element> + <property name="bookmarks bar" code="ChBB" description="The bookmarks bar bookmark folder." type="bookmark folder" access="r"> + <cocoa key="bookmarksBar"/> + </property> + <property name="other bookmarks" code="ChOB" description="The other bookmarks bookmark folder." type="bookmark folder" access="r"> + <cocoa key="otherBookmarks"/> + </property> + </class-extension> + <class name="tab" code="CrTb" description="A tab."> + <cocoa class="TabAppleScript"/> + <property name="id" code="ID " description="Unique ID of the tab." type="integer" access="r"> + <cocoa key="uniqueID"/> + </property> + <property name="title" code="pnam" description="The title of the tab." type="text" access="r"/> + <property name="URL" code="URL " description="The url visible to the user." type="text"/> + <property name="loading" code="ldng" description="Is loading?" type="boolean" access="r"/> + <responds-to command="undo"> + <cocoa method="handlesUndoScriptCommand:"/> + </responds-to> + <responds-to command="redo"> + <cocoa method="handlesRedoScriptCommand:"/> + </responds-to> + <responds-to command="cut"> + <cocoa method="handlesCutScriptCommand:"/> + </responds-to> + <responds-to command="copy"> + <cocoa method="handlesCopyScriptCommand:"/> + </responds-to> + <responds-to command="paste"> + <cocoa method="handlesPasteScriptCommand:"/> + </responds-to> + <responds-to command="select all"> + <cocoa method="handlesSelectAllScriptCommand:"/> + </responds-to> + <responds-to command="go back"> + <cocoa method="handlesGoBackScriptCommand:"/> + </responds-to> + <responds-to command="go forward"> + <cocoa method="handlesGoForwardScriptCommand:"/> + </responds-to> + <responds-to command="reload"> + <cocoa method="handlesReloadScriptCommand:"/> + </responds-to> + <responds-to command="stop"> + <cocoa method="handlesStopScriptCommand:"/> + </responds-to> + <responds-to command="print"> + <cocoa method="handlesPrintScriptCommand:"/> + </responds-to> + <responds-to command="view source"> + <cocoa method="handlesViewSourceScriptCommand:"/> + </responds-to> + <responds-to command="save"> + <cocoa method="handlesSaveScriptCommand:"/> + </responds-to> + </class> + <class name="bookmark folder" code="CrBF" description="A bookmarks folder that contains other bookmarks folder and bookmark items."> + <cocoa class="BookmarkFolderAppleScript"/> + <element description="The bookmark folders present within." type="bookmark folder"> + <cocoa key="bookmarkFolders"/> + </element> + <element description="The bookmarks present within." type="bookmark item"> + <cocoa key="bookmarkItems"/> + </element> + <property name="id" code="ID " description="Unique ID of the bookmark folder." type="number" access="r"> + <cocoa key="uniqueID"/> + </property> + <property name="title" code="pnam" description="The title of the folder." type="text"/> + </class> + <class name="bookmark item" code="CrBI" description="An item consists of an URL and the title of a bookmark"> + <cocoa class="BookmarkItemAppleScript"/> + <property name="id" code="ID " description="Unique ID of the bookmark item." type="integer" access="r"> + <cocoa key="uniqueID"/> + </property> + <property name="title" code="pnam" description="The title of the bookmark item." type="text"/> + <property name="URL" code="URL " description="The URL of the bookmark." type="text"/> + </class> + <command name="reload" code="CrSuRlod" description="Reload a tab."> + <direct-parameter type="specifier"/> + </command> + <command name="go back" code="CrSuBack" description="Go Back (If Possible)."> + <direct-parameter type="specifier"/> + </command> + <command name="go forward" code="CrSuFwd " description="Go Forward (If Possible)."> + <direct-parameter type="specifier"/> + </command> + <command name="select all" code="CrSuSlAl" description="Select all."> + <direct-parameter type="specifier"/> + </command> + <command name="cut selection" code="CrSuCut " description="Cut selected text (If Possible)."> + <direct-parameter type="specifier"/> + </command> + <command name="copy selection" code="CrSuCop " description="Copy text."> + <direct-parameter type="specifier"/> + </command> + <command name="paste" code="CrSuPast" description="Paste text (If Possible)."> + <direct-parameter type="specifier"/> + </command> + <command name="undo" code="CrSuUndo" description="Undo the last change."> + <direct-parameter type="specifier"/> + </command> + <command name="redo" code="CrSuRedo" description="Redo the last change."> + <direct-parameter type="specifier"/> + </command> + <command name="stop" code="CrSustop" description="Stop the current tab from loading."> + <direct-parameter type="specifier"/> + </command> + <command name="view source" code="CrSuVSrc" description="View the HTML source of the tab."> + <direct-parameter type="specifier"/> + </command> + </suite> +</dictionary>
\ No newline at end of file diff --git a/chrome/browser/cocoa/applescript/tab_applescript.h b/chrome/browser/cocoa/applescript/tab_applescript.h new file mode 100644 index 0000000..b4e6269 --- /dev/null +++ b/chrome/browser/cocoa/applescript/tab_applescript.h @@ -0,0 +1,76 @@ +// 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. + +#ifndef CHROME_BROWSER_COCOA_APPLESCRIPT_TAB_APPLESCRIPT_H_ +#define CHROME_BROWSER_COCOA_APPLESCRIPT_TAB_APPLESCRIPT_H_ + +#import <Cocoa/Cocoa.h> + +#import "chrome/browser/cocoa/applescript/element_applescript.h" + +class TabContents; + +// Represents a tab scriptable item in applescript. +@interface TabAppleScript : ElementAppleScript { + @private + TabContents* tabContents_; // weak. + // Contains the temporary URL when a user creates a new folder/item with + // url specified like + // |make new tab with properties {url:"http://google.com"}|. + NSString* tempURL_; +} + +// Doesn't actually create the tab here but just assigns the ID, tab is created +// when it calls insertInTabs: of a particular window, it is used in cases +// where user assigns a tab to a variable like |set var to make new tab|. +- (id)init; + +// Does not create a new tab but uses an existing one. +- (id)initWithTabContent:(TabContents*)aTabContent; + +// Assigns a tab, sets its unique ID and also copies temporary values. +- (void)setTabContent:(TabContents*)aTabContent; + +// Return the URL currently visible to the user in the location bar. +- (NSString*)URL; + +// Sets the URL, returns an error if it is invalid. +- (void)setURL:(NSString*)aURL; + +// The title of the tab. +- (NSString*)title; + +// Is the tab loading any resource? +- (NSNumber*)loading; + +// Standard user commands. +- (void)handlesUndoScriptCommand:(NSScriptCommand*)command; +- (void)handlesRedoScriptCommand:(NSScriptCommand*)command; + +// Edit operations on the page. +- (void)handlesCutScriptCommand:(NSScriptCommand*)command; +- (void)handlesCopyScriptCommand:(NSScriptCommand*)command; +- (void)handlesPasteScriptCommand:(NSScriptCommand*)command; + +// Selects all contents on the page. +- (void)handlesSelectAllScriptCommand:(NSScriptCommand*)command; + +// Navigation operations. +- (void)handlesGoBackScriptCommand:(NSScriptCommand*)command; +- (void)handlesGoForwardScriptCommand:(NSScriptCommand*)command; +- (void)handlesReloadScriptCommand:(NSScriptCommand*)command; +- (void)handlesStopScriptCommand:(NSScriptCommand*)command; + +// Used to print a tab. +- (void)handlesPrintScriptCommand:(NSScriptCommand*)command; + +// Used to save a tab, if no file is specified, prompts the user to enter it. +- (void)handlesSaveScriptCommand:(NSScriptCommand*)command; + +// Displays the HTML of the tab in a new tab. +- (void)handlesViewSourceScriptCommand:(NSScriptCommand*)command; + +@end + +#endif// CHROME_BROWSER_COCOA_APPLESCRIPT_TAB_APPLESCRIPT_H_ diff --git a/chrome/browser/cocoa/applescript/tab_applescript.mm b/chrome/browser/cocoa/applescript/tab_applescript.mm new file mode 100644 index 0000000..73b4f8b --- /dev/null +++ b/chrome/browser/cocoa/applescript/tab_applescript.mm @@ -0,0 +1,274 @@ +// 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])) { + [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<NSNumber> 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<NSNumber> 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); + } +} + +@end diff --git a/chrome/browser/cocoa/applescript/window_applescript.h b/chrome/browser/cocoa/applescript/window_applescript.h new file mode 100644 index 0000000..5bda32f --- /dev/null +++ b/chrome/browser/cocoa/applescript/window_applescript.h @@ -0,0 +1,81 @@ +// 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. + +#ifndef CHROME_BROWSER_COCOA_APPLESCRIPT_WINDOW_APPLESCRIPT_H_ +#define CHROME_BROWSER_COCOA_APPLESCRIPT_WINDOW_APPLESCRIPT_H_ + +#import <Cocoa/Cocoa.h> + +#import "chrome/browser/cocoa/applescript/element_applescript.h" + +class Browser; +class Profile; +@class TabAppleScript; + +// Represents a window class. +@interface WindowAppleScript : ElementAppleScript { + @private + Browser* browser_; // weak. +} + +// Creates a new window, returns nil if there is an error. +- (id)init; + +// Creates a new window with a particular profile. +- (id)initWithProfile:(Profile*)aProfile; + +// Does not create a new window but uses an existing one. +- (id)initWithBrowser:(Browser*)aBrowser; + +// Sets and gets the index of the currently selected tab. +- (NSNumber*)activeTabIndex; +- (void)setActiveTabIndex:(NSNumber*)anActiveTabIndex; + +// Mode refers to whether a window is a normal window or an incognito window +// it can be set only once while creating the window. +- (NSString*)mode; +- (void)setMode:(NSString*)theMode; + +// Returns the currently selected tab. +- (TabAppleScript*)activeTab; + +// Tab manipulation functions. +// The tabs inside the window. +// Returns |TabAppleScript*| of all the tabs contained +// within this particular folder. +- (NSArray*)tabs; + +// Insert a tab at the end. +- (void)insertInTabs:(TabAppleScript*)aTab; + +// Insert a tab at some position in the list. +// Called by applescript which takes care of bounds checking, make sure of it +// before calling directly. +- (void)insertInTabs:(TabAppleScript*)aTab atIndex:(int)index; + +// Remove a window from the list. +// Called by applescript which takes care of bounds checking, make sure of it +// before calling directly. +- (void)removeFromTabsAtIndex:(int)index; + +// Set the index of a window. +- (void)setOrderedIndex:(NSNumber*)anIndex; + +// Used to sort windows by index. +- (NSComparisonResult)windowComparator:(WindowAppleScript*)otherWindow; + +// For standard window functions like zoomable, bounds etc, we dont handle it +// but instead pass it onto the NSWindow associated with the window. +- (id)valueForUndefinedKey:(NSString*)key; +- (void)setValue:(id)value forUndefinedKey:(NSString*)key; + +// Used to close window. +- (void)handlesCloseScriptCommand:(NSCloseCommand*)command; + +// The index of the window, windows are ordered front to back. +- (NSNumber*)orderedIndex; + +@end + +#endif // CHROME_BROWSER_COCOA_APPLESCRIPT_WINDOW_APPLESCRIPT_H_ diff --git a/chrome/browser/cocoa/applescript/window_applescript.mm b/chrome/browser/cocoa/applescript/window_applescript.mm new file mode 100644 index 0000000..6fcb10b --- /dev/null +++ b/chrome/browser/cocoa/applescript/window_applescript.mm @@ -0,0 +1,254 @@ +// 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/window_applescript.h" + +#include "base/logging.h" +#import "base/scoped_nsobject.h" +#include "base/scoped_ptr.h" +#include "base/time.h" +#import "chrome/browser/app_controller_mac.h" +#include "chrome/browser/browser.h" +#include "chrome/browser/browser_list.h" +#include "chrome/browser/browser_window.h" +#import "chrome/browser/chrome_browser_application_mac.h" +#include "chrome/browser/cocoa/applescript/constants_applescript.h" +#include "chrome/browser/cocoa/applescript/error_applescript.h" +#import "chrome/browser/cocoa/applescript/tab_applescript.h" +#include "chrome/browser/profile.h" +#include "chrome/browser/tab_contents/tab_contents.h" +#include "chrome/common/url_constants.h" + +@interface WindowAppleScript(WindowAppleScriptPrivateMethods) +// The NSWindow that corresponds to this window. +- (NSWindow*)nativeHandle; +@end + +@implementation WindowAppleScript + +- (id)init { + // Check which mode to open a new window. + NSScriptCommand* command = [NSScriptCommand currentCommand]; + NSString* mode = [[[command evaluatedArguments] + objectForKey:@"KeyDictionary"] objectForKey:@"mode"]; + AppController* appDelegate = [NSApp delegate]; + + Profile* defaultProfile = [appDelegate defaultProfile]; + + if (!defaultProfile) { + AppleScript::SetError(AppleScript::errGetProfile); + return nil; + } + + Profile* profile; + if ([mode isEqualToString:AppleScript::kIncognitoWindowMode]) { + profile = defaultProfile->GetOffTheRecordProfile(); + } + else if ([mode isEqualToString:AppleScript::kNormalWindowMode] || !mode) { + profile = defaultProfile; + } else { + // Mode cannot be anything else + AppleScript::SetError(AppleScript::errInvalidMode); + return nil; + } + // Set the mode to nil, to ensure that it is not set once more. + [[[command evaluatedArguments] objectForKey:@"KeyDictionary"] + setValue:nil forKey:@"mode"]; + return [self initWithProfile:profile]; +} + +- (id)initWithProfile:(Profile*)aProfile { + if (!aProfile) { + [self release]; + return nil; + } + + if ((self = [super init])) { + browser_ = Browser::Create(aProfile); + browser_->NewTab(); + browser_->window()->Show(); + scoped_nsobject<NSNumber> numID( + [[NSNumber alloc] initWithInt:browser_->session_id().id()]); + [self setUniqueID:numID]; + [self setContainer: + (BrowserCrApplication*)[BrowserCrApplication sharedApplication] + property:AppleScript::kWindowsProperty]; + } + return self; +} + +- (id)initWithBrowser:(Browser*)aBrowser { + if (!aBrowser) { + [self release]; + return nil; + } + + if ((self = [super init])) { + // It is safe to be weak, if a window goes away (eg user closing a window) + // the applescript runtime calls appleScriptWindows in + // BrowserCrApplication and this particular window is never returned. + browser_ = aBrowser; + scoped_nsobject<NSNumber> numID( + [[NSNumber alloc] initWithInt:browser_->session_id().id()]); + [self setUniqueID:numID]; + [self setContainer:NSApp + property:AppleScript::kWindowsProperty]; + } + return self; +} + +- (NSWindow*)nativeHandle { + // window() can be NULL during startup. + if (browser_->window()) + return browser_->window()->GetNativeHandle(); + return nil; +} + +- (NSNumber*)activeTabIndex { + // Note: applescript is 1-based, that is lists begin with index 1. + int activeTabIndex = browser_->selected_index() + 1; + if (!activeTabIndex) { + return nil; + } + return [NSNumber numberWithInt:activeTabIndex]; +} + +- (void)setActiveTabIndex:(NSNumber*)anActiveTabIndex { + // Note: applescript is 1-based, that is lists begin with index 1. + int atIndex = [anActiveTabIndex intValue] - 1; + if (atIndex >= 0 && atIndex < browser_->tab_count()) + browser_->SelectTabContentsAt(atIndex, true); + else + AppleScript::SetError(AppleScript::errInvalidTabIndex); +} + +- (NSString*)mode { + Profile* profile = browser_->profile(); + if (profile->IsOffTheRecord()) + return AppleScript::kIncognitoWindowMode; + return AppleScript::kNormalWindowMode; +} + +- (void)setMode:(NSString*)theMode { + // cannot set mode after window is created. + if (theMode) { + AppleScript::SetError(AppleScript::errSetMode); + } +} + +- (TabAppleScript*)activeTab { + TabAppleScript* currentTab = [[[TabAppleScript alloc] + initWithTabContent:browser_->GetSelectedTabContents()] autorelease]; + [currentTab setContainer:self + property:AppleScript::kTabsProperty]; + return currentTab; +} + +- (NSArray*)tabs { + NSMutableArray* tabs = [NSMutableArray + arrayWithCapacity:browser_->tab_count()]; + + for (int i = 0; i < browser_->tab_count(); ++i) { + // Check to see if tab is closing. + if (browser_->GetTabContentsAt(i)->is_being_destroyed()) { + continue; + } + + scoped_nsobject<TabAppleScript> tab( + [[TabAppleScript alloc] + initWithTabContent:(browser_->GetTabContentsAt(i))]); + [tab setContainer:self + property:AppleScript::kTabsProperty]; + [tabs addObject:tab]; + } + return tabs; +} + +- (void)insertInTabs:(TabAppleScript*)aTab { + // This method gets called when a new tab is created so + // the container and property are set here. + [aTab setContainer:self + property:AppleScript::kTabsProperty]; + + // Set how long it takes a tab to be created. + base::TimeTicks newTabStartTime = base::TimeTicks::Now(); + TabContents* tabContents = browser_->AddTabWithURL( + GURL(chrome::kChromeUINewTabURL), + GURL(), + PageTransition::TYPED, + -1, // To indicate tab is inserted at end. + TabStripModel::ADD_SELECTED, + NULL, + std::string()); + tabContents->set_new_tab_start_time(newTabStartTime); + + [aTab setTabContent:tabContents]; +} + +- (void)insertInTabs:(TabAppleScript*)aTab atIndex:(int)index { + // This method gets called when a new tab is created so + // the container and property are set here. + [aTab setContainer:self + property:AppleScript::kTabsProperty]; + + // Set how long it takes a tab to be created. + base::TimeTicks newTabStartTime = base::TimeTicks::Now(); + TabContents* tabContents = browser_->AddTabWithURL( + GURL(chrome::kChromeUINewTabURL), + GURL(), + PageTransition::TYPED, + index, + TabStripModel::ADD_SELECTED, + NULL, + std::string()); + tabContents->set_new_tab_start_time(newTabStartTime); + + [aTab setTabContent:tabContents]; +} + +- (void)removeFromTabsAtIndex:(int)index { + browser_->tabstrip_model()->DetachTabContentsAt(index); +} + +- (NSNumber*)orderedIndex{ + return [NSNumber numberWithInt:[[self nativeHandle] orderedIndex]]; +} + +- (void)setOrderedIndex:(NSNumber*)anIndex { + int index = [anIndex intValue] - 1; + if (index < 0 || index >= (int)BrowserList::size()) { + AppleScript::SetError(AppleScript::errWrongIndex); + return; + } + [[self nativeHandle] setOrderedIndex:index]; +} + +- (NSComparisonResult)windowComparator:(WindowAppleScript*)otherWindow { + int thisIndex = [[self orderedIndex] intValue]; + int otherIndex = [[otherWindow orderedIndex] intValue]; + if (thisIndex < otherIndex) + return NSOrderedAscending; + else if (thisIndex > otherIndex) + return NSOrderedDescending; + // Indexes can never be same. + NOTREACHED(); + return NSOrderedSame; +} + +// Get and set values from the associated NSWindow. +- (id)valueForUndefinedKey:(NSString*)key { + return [[self nativeHandle] valueForKey:key]; +} + +- (void)setValue:(id)value forUndefinedKey:(NSString*)key { + [[self nativeHandle] setValue:(id)value forKey:key]; +} + +- (void)handlesCloseScriptCommand:(NSCloseCommand*)command { + // window() can be NULL during startup. + if (browser_->window()) + browser_->window()->Close(); +} + +@end diff --git a/chrome/browser/cocoa/applescript/window_applescript_test.mm b/chrome/browser/cocoa/applescript/window_applescript_test.mm new file mode 100644 index 0000000..6b4425a --- /dev/null +++ b/chrome/browser/cocoa/applescript/window_applescript_test.mm @@ -0,0 +1,173 @@ +// 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 "base/scoped_nsobject.h" +#include "base/sys_string_conversions.h" +#import "chrome/browser/app_controller_mac.h" +#import "chrome/browser/chrome_browser_application_mac.h" +#import "chrome/browser/cocoa/applescript/constants_applescript.h" +#import "chrome/browser/cocoa/applescript/error_applescript.h" +#import "chrome/browser/cocoa/applescript/tab_applescript.h" +#import "chrome/browser/cocoa/applescript/window_applescript.h" +#include "chrome/browser/profile.h" +#include "chrome/test/in_process_browser_test.h" +#include "googleurl/src/gurl.h" +#include "testing/gtest/include/gtest/gtest.h" +#import "testing/gtest_mac.h" + +typedef InProcessBrowserTest WindowAppleScriptTest; + +// Create a window in default/normal mode. +IN_PROC_BROWSER_TEST_F(WindowAppleScriptTest, DefaultCreation) { + scoped_nsobject<WindowAppleScript> aWindow( + [[WindowAppleScript alloc] init]); + EXPECT_TRUE(aWindow.get()); + NSString* mode = [aWindow.get() mode]; + EXPECT_NSEQ(AppleScript::kNormalWindowMode, + mode); +} + +// Create a window with a |NULL profile|. +IN_PROC_BROWSER_TEST_F(WindowAppleScriptTest, CreationWithNoProfile) { + scoped_nsobject<WindowAppleScript> aWindow( + [[WindowAppleScript alloc] initWithProfile:NULL]); + EXPECT_FALSE(aWindow.get()); +} + +// Create a window with a particular profile. +IN_PROC_BROWSER_TEST_F(WindowAppleScriptTest, CreationWithProfile) { + Profile* defaultProfile = [[NSApp delegate] defaultProfile]; + scoped_nsobject<WindowAppleScript> aWindow( + [[WindowAppleScript alloc] initWithProfile:defaultProfile]); + EXPECT_TRUE(aWindow.get()); + EXPECT_TRUE([aWindow.get() uniqueID]); + EXPECT_EQ([aWindow.get() container], + [BrowserCrApplication sharedApplication]); + EXPECT_NSEQ(AppleScript::kWindowsProperty, + [aWindow.get() containerProperty]); +} + +// Create a window with no |Browser*|. +IN_PROC_BROWSER_TEST_F(WindowAppleScriptTest, CreationWithNoBrowser) { + scoped_nsobject<WindowAppleScript> aWindow( + [[WindowAppleScript alloc] initWithBrowser:NULL]); + EXPECT_FALSE(aWindow.get()); +} + +// Create a window with |Browser*| already present. +IN_PROC_BROWSER_TEST_F(WindowAppleScriptTest, CreationWithBrowser) { + scoped_nsobject<WindowAppleScript> aWindow( + [[WindowAppleScript alloc] initWithBrowser:browser()]); + EXPECT_TRUE(aWindow.get()); + EXPECT_TRUE([aWindow.get() uniqueID]); + EXPECT_EQ([aWindow.get() container], + [BrowserCrApplication sharedApplication]); + EXPECT_NSEQ(AppleScript::kWindowsProperty, + [aWindow.get() containerProperty]); +} + +// Tabs within the window. +IN_PROC_BROWSER_TEST_F(WindowAppleScriptTest, Tabs) { + scoped_nsobject<WindowAppleScript> aWindow( + [[WindowAppleScript alloc] initWithBrowser:browser()]); + NSArray* tabs = [aWindow.get() tabs]; + EXPECT_EQ(1U, [tabs count]); + TabAppleScript* tab1 = [tabs objectAtIndex:0]; + EXPECT_EQ([tab1 container], aWindow.get()); + EXPECT_NSEQ(AppleScript::kTabsProperty, + [tab1 containerProperty]); +} + +// Insert a new tab. +IN_PROC_BROWSER_TEST_F(WindowAppleScriptTest, InsertTab) { + // Emulate what applescript would do when creating a new tab. + scoped_nsobject<TabAppleScript> aTab([[TabAppleScript alloc] init]); + [aTab.get() setURL:@"http://google.com"]; + scoped_nsobject<WindowAppleScript> aWindow( + [[WindowAppleScript alloc] initWithBrowser:browser()]); + [aWindow.get() insertInTabs:aTab.get()]; + EXPECT_EQ([aTab.get() container], aWindow.get()); + EXPECT_NSEQ(AppleScript::kTabsProperty, + [aTab.get() containerProperty]); + TabAppleScript* tab2 = [[aWindow.get() tabs] objectAtIndex:1]; + EXPECT_EQ(GURL("http://google.com"), + GURL(base::SysNSStringToUTF8([tab2 URL]))); +} + +// Insert a new tab at a particular position +IN_PROC_BROWSER_TEST_F(WindowAppleScriptTest, InsertTabAtPosition) { + scoped_nsobject<TabAppleScript> tab1([[TabAppleScript alloc] init]); + scoped_nsobject<TabAppleScript> tab2([[TabAppleScript alloc] init]); + scoped_nsobject<WindowAppleScript> aWindow( + [[WindowAppleScript alloc] initWithBrowser:browser()]); + [aWindow.get() insertInTabs:tab1.get()]; + [aWindow.get() insertInTabs:tab2.get()]; + + scoped_nsobject<TabAppleScript> aTab([[TabAppleScript alloc] init]); + [aWindow.get() insertInTabs:aTab.get() atIndex:1]; + TabAppleScript* tab = [[aWindow.get() tabs] objectAtIndex:1]; + EXPECT_NSEQ([aTab.get() uniqueID], + [tab uniqueID]); +} + +// Inserting and deleting tabs. +IN_PROC_BROWSER_TEST_F(WindowAppleScriptTest, InsertAndDeleteTabs) { + scoped_nsobject<WindowAppleScript> aWindow( + [[WindowAppleScript alloc] initWithBrowser:browser()]); + scoped_nsobject<TabAppleScript> aTab; + int count; + for (int i = 0; i < 5; ++i) { + for (int j = 0; j < 3; ++j) { + aTab.reset([[TabAppleScript alloc] init]); + [aWindow.get() insertInTabs:aTab.get()]; + } + count = 3 * i + 4; + EXPECT_EQ((int)[[aWindow.get() tabs] count], count); + } + + count = (int)[[aWindow.get() tabs] count]; + for (int i = 0; i < 5; ++i) { + for(int j = 0; j < 3; ++j) { + [aWindow.get() removeFromTabsAtIndex:0]; + } + count = count - 3; + EXPECT_EQ((int)[[aWindow.get() tabs] count], count); + } +} + +// Getting and setting values from the NSWindow. +IN_PROC_BROWSER_TEST_F(WindowAppleScriptTest, NSWindowTest) { + scoped_nsobject<WindowAppleScript> aWindow( + [[WindowAppleScript alloc] initWithBrowser:browser()]); + [aWindow.get() setValue:[NSNumber numberWithBool:YES] + forKey:@"isMiniaturized"]; + EXPECT_TRUE([[aWindow.get() valueForKey:@"isMiniaturized"] boolValue]); + [aWindow.get() setValue:[NSNumber numberWithBool:NO] + forKey:@"isMiniaturized"]; + EXPECT_FALSE([[aWindow.get() valueForKey:@"isMiniaturized"] boolValue]); +} + +// Getting and setting the active tab. +IN_PROC_BROWSER_TEST_F(WindowAppleScriptTest, ActiveTab) { + scoped_nsobject<WindowAppleScript> aWindow( + [[WindowAppleScript alloc] initWithBrowser:browser()]); + scoped_nsobject<TabAppleScript> aTab([[TabAppleScript alloc] init]); + [aWindow.get() insertInTabs:aTab.get()]; + [aWindow.get() setActiveTabIndex:[NSNumber numberWithInt:2]]; + EXPECT_EQ(2, [[aWindow.get() activeTabIndex] intValue]); + TabAppleScript* tab2 = [[aWindow.get() tabs] objectAtIndex:1]; + EXPECT_NSEQ([[aWindow.get() activeTab] uniqueID], + [tab2 uniqueID]); +} + +// Order of windows. +IN_PROC_BROWSER_TEST_F(WindowAppleScriptTest, WindowOrder) { + scoped_nsobject<WindowAppleScript> window2( + [[WindowAppleScript alloc] initWithBrowser:browser()]); + scoped_nsobject<WindowAppleScript> window1( + [[WindowAppleScript alloc] init]); + EXPECT_EQ([window1.get() windowComparator:window2.get()], NSOrderedAscending); + EXPECT_EQ([window2.get() windowComparator:window1.get()], + NSOrderedDescending); +} diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 3e5fe39..474482c 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -659,6 +659,24 @@ 'browser/cocoa/animatable_image.mm', 'browser/cocoa/animatable_view.h', 'browser/cocoa/animatable_view.mm', + 'browser/cocoa/applescript/bookmark_folder_applescript.h', + 'browser/cocoa/applescript/bookmark_folder_applescript.mm', + 'browser/cocoa/applescript/bookmark_item_applescript.h', + 'browser/cocoa/applescript/bookmark_item_applescript.mm', + 'browser/cocoa/applescript/bookmark_node_applescript.h', + 'browser/cocoa/applescript/bookmark_node_applescript.mm', + 'browser/cocoa/applescript/browsercrapplication+applescript.h', + 'browser/cocoa/applescript/browsercrapplication+applescript.mm', + 'browser/cocoa/applescript/constants_applescript.h', + 'browser/cocoa/applescript/constants_applescript.mm', + 'browser/cocoa/applescript/element_applescript.h', + 'browser/cocoa/applescript/element_applescript.mm', + 'browser/cocoa/applescript/error_applescript.h', + 'browser/cocoa/applescript/error_applescript.mm', + 'browser/cocoa/applescript/tab_applescript.h', + 'browser/cocoa/applescript/tab_applescript.mm', + 'browser/cocoa/applescript/window_applescript.h', + 'browser/cocoa/applescript/window_applescript.mm', 'browser/cocoa/authorization_util.h', 'browser/cocoa/authorization_util.mm', 'browser/cocoa/back_forward_menu_controller.h', diff --git a/chrome/chrome_exe.gypi b/chrome/chrome_exe.gypi index 383c941..04d2d9c 100644 --- a/chrome/chrome_exe.gypi +++ b/chrome/chrome_exe.gypi @@ -1,4 +1,4 @@ -# Copyright (c) 2009-2010 The Chromium Authors. All rights reserved. +# 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. @@ -220,11 +220,13 @@ 'mac_bundle_resources': [ 'app/theme/google_chrome/app.icns', 'app/theme/google_chrome/document.icns', + 'browser/cocoa/applescript/scripting.sdef', ], }, { # else: 'branding!="Chrome" 'mac_bundle_resources': [ 'app/theme/chromium/app.icns', 'app/theme/chromium/document.icns', + 'browser/cocoa/applescript/scripting.sdef', ], }], ['mac_breakpad==1', { diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index 9975270..67bcfc3e 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -768,6 +768,10 @@ 'browser/cocoa/accelerators_cocoa_unittest.mm', 'browser/cocoa/animatable_image_unittest.mm', 'browser/cocoa/animatable_view_unittest.mm', + 'browser/cocoa/applescript/bookmark_applescript_utils_unittest.h', + 'browser/cocoa/applescript/bookmark_applescript_utils_unittest.mm', + 'browser/cocoa/applescript/bookmark_item_applescript_unittest.mm', + 'browser/cocoa/applescript/bookmark_folder_applescript_unittest.mm', 'browser/cocoa/background_gradient_view_unittest.mm', 'browser/cocoa/background_tile_view_unittest.mm', 'browser/cocoa/base_view_unittest.mm', @@ -1539,6 +1543,7 @@ 'browser/chromeos/tab_closeable_state_watcher_browsertest.cc', 'browser/chromeos/update_browsertest.cc', 'browser/cocoa/view_id_util_browsertest.mm', + 'browser/cocoa/applescript/window_applescript_test.mm', 'browser/crash_recovery_browsertest.cc', 'browser/device_orientation/enable_switch_browsertest.cc', 'browser/dom_ui/file_browse_browsertest.cc', |