summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--AUTHORS1
-rw-r--r--chrome/app/app-Info.plist2
-rw-r--r--chrome/app/generated_resources.grd38
-rw-r--r--chrome/browser/bookmarks/bookmark_model.h3
-rw-r--r--chrome/browser/browser.h4
-rw-r--r--chrome/browser/cocoa/applescript/bookmark_applescript_utils_unittest.h63
-rw-r--r--chrome/browser/cocoa/applescript/bookmark_applescript_utils_unittest.mm45
-rw-r--r--chrome/browser/cocoa/applescript/bookmark_folder_applescript.h67
-rw-r--r--chrome/browser/cocoa/applescript/bookmark_folder_applescript.mm203
-rw-r--r--chrome/browser/cocoa/applescript/bookmark_folder_applescript_unittest.mm195
-rw-r--r--chrome/browser/cocoa/applescript/bookmark_item_applescript.h33
-rw-r--r--chrome/browser/cocoa/applescript/bookmark_item_applescript.mm66
-rw-r--r--chrome/browser/cocoa/applescript/bookmark_item_applescript_unittest.mm45
-rw-r--r--chrome/browser/cocoa/applescript/bookmark_node_applescript.h45
-rw-r--r--chrome/browser/cocoa/applescript/bookmark_node_applescript.mm123
-rw-r--r--chrome/browser/cocoa/applescript/browsercrapplication+applescript.h59
-rw-r--r--chrome/browser/cocoa/applescript/browsercrapplication+applescript.mm134
-rw-r--r--chrome/browser/cocoa/applescript/constants_applescript.h31
-rw-r--r--chrome/browser/cocoa/applescript/constants_applescript.mm25
-rw-r--r--chrome/browser/cocoa/applescript/element_applescript.h37
-rw-r--r--chrome/browser/cocoa/applescript/element_applescript.mm38
-rw-r--r--chrome/browser/cocoa/applescript/error_applescript.h41
-rw-r--r--chrome/browser/cocoa/applescript/error_applescript.mm56
-rw-r--r--chrome/browser/cocoa/applescript/scripting.sdef295
-rw-r--r--chrome/browser/cocoa/applescript/tab_applescript.h76
-rw-r--r--chrome/browser/cocoa/applescript/tab_applescript.mm274
-rw-r--r--chrome/browser/cocoa/applescript/window_applescript.h81
-rw-r--r--chrome/browser/cocoa/applescript/window_applescript.mm254
-rw-r--r--chrome/browser/cocoa/applescript/window_applescript_test.mm173
-rw-r--r--chrome/chrome_browser.gypi18
-rw-r--r--chrome/chrome_exe.gypi4
-rw-r--r--chrome/chrome_tests.gypi5
32 files changed, 2533 insertions, 1 deletions
diff --git a/AUTHORS b/AUTHORS
index 6fb3832..94e0e07 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -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">&lt;a href="$2"&gt;</ph>extensions<ph name="END_LINK">&lt;/a&gt;</ph> and <ph name="BEGIN_BUTTON">&lt;button&gt;</ph>bookmark sync<ph name="END_BUTTON">&lt;/button&gt;</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&apos;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 &apos;normal&apos; or &apos;incognito&apos;, 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 &apos;only html&apos; or &apos;complete html&apos;, default is &apos;complete html&apos;." 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&apos;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&apos;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',