diff options
32 files changed, 2533 insertions, 1 deletions
@@ -82,3 +82,4 @@ Michael Gilbert <floppymaster@gmail.com> Giuseppe Iuculano <giuseppe@iuculano.it> litl LLC James Willcox <jwillcox@litl.com> +Shreyas VA <v.a.shreyas@gmail.com> 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', |