diff options
Diffstat (limited to 'chrome/browser')
-rw-r--r-- | chrome/browser/browser_main.cc | 15 | ||||
-rw-r--r-- | chrome/browser/cocoa/first_run_dialog.h | 15 | ||||
-rw-r--r-- | chrome/browser/cocoa/first_run_dialog.mm | 108 | ||||
-rw-r--r-- | chrome/browser/cocoa/search_engine_dialog_controller.h | 45 | ||||
-rw-r--r-- | chrome/browser/cocoa/search_engine_dialog_controller.mm | 279 | ||||
-rw-r--r-- | chrome/browser/first_run/first_run.cc | 83 | ||||
-rw-r--r-- | chrome/browser/first_run/first_run.h | 27 | ||||
-rw-r--r-- | chrome/browser/first_run/first_run_gtk.cc | 61 | ||||
-rw-r--r-- | chrome/browser/first_run/first_run_mac.mm | 179 |
9 files changed, 517 insertions, 295 deletions
diff --git a/chrome/browser/browser_main.cc b/chrome/browser/browser_main.cc index 53eeadb..3712a06 100644 --- a/chrome/browser/browser_main.cc +++ b/chrome/browser/browser_main.cc @@ -1203,7 +1203,8 @@ int BrowserMain(const MainFunctionParams& parameters) { #if !defined(OS_MACOSX) // Importing other browser settings is done in a browser-like process // that exits when this task has finished. - // TODO(port): Port to Mac + // TODO(port): Port the Mac's IPC-based implementation to other platforms to + // replace this implementation. http://crbug.com/22142 if (parsed_command_line.HasSwitch(switches::kImport) || parsed_command_line.HasSwitch(switches::kImportFromFile)) { return FirstRun::ImportNow(profile, parsed_command_line); @@ -1248,7 +1249,6 @@ int BrowserMain(const MainFunctionParams& parameters) { // touches reads preferences. if (is_first_run) { if (!first_run_ui_bypass) { -#if defined(OS_WIN) || defined(OS_LINUX) FirstRun::AutoImport(profile, master_prefs.homepage_defined, master_prefs.do_import_items, @@ -1257,17 +1257,6 @@ int BrowserMain(const MainFunctionParams& parameters) { master_prefs.randomize_search_engine_experiment, master_prefs.make_chrome_default, &process_singleton); -#else - if (!OpenFirstRunDialog(profile, - master_prefs.homepage_defined, - master_prefs.do_import_items, - master_prefs.dont_import_items, - master_prefs.run_search_engine_experiment, - master_prefs.randomize_search_engine_experiment, - &process_singleton)) { - return ResultCodes::NORMAL_EXIT; - } -#endif #if defined(OS_POSIX) // On Windows, the download is tagged with enable/disable stats so there // is no need for this code. diff --git a/chrome/browser/cocoa/first_run_dialog.h b/chrome/browser/cocoa/first_run_dialog.h index a96ed17..3e575a3 100644 --- a/chrome/browser/cocoa/first_run_dialog.h +++ b/chrome/browser/cocoa/first_run_dialog.h @@ -13,14 +13,8 @@ // us improve Chromium. @interface FirstRunDialogController : NSWindowController { @private - BOOL userDidCancel_; BOOL statsEnabled_; - BOOL statsCheckboxHidden_; BOOL makeDefaultBrowser_; - BOOL importBookmarks_; - int browserImportSelectedIndex_; - NSArray* browserImportList_; - BOOL browserImportListHidden_; IBOutlet NSArray* objectsToSize_; IBOutlet NSButton* statsCheckbox_; @@ -30,21 +24,12 @@ // Called when the "Start Google Chrome" button is pressed. - (IBAction)ok:(id)sender; -// Cancel button calls this. -- (IBAction)cancel:(id)sender; - // Called when the "Learn More" button is pressed. - (IBAction)learnMore:(id)sender; // Properties for bindings. -@property(assign, nonatomic) BOOL userDidCancel; @property(assign, nonatomic) BOOL statsEnabled; -@property(assign, nonatomic) BOOL statsCheckboxHidden; @property(assign, nonatomic) BOOL makeDefaultBrowser; -@property(assign, nonatomic) BOOL importBookmarks; -@property(assign, nonatomic) int browserImportSelectedIndex; -@property(retain, nonatomic) NSArray* browserImportList; -@property(assign, nonatomic) BOOL browserImportListHidden; @end diff --git a/chrome/browser/cocoa/first_run_dialog.mm b/chrome/browser/cocoa/first_run_dialog.mm index c71750e..123b80b 100644 --- a/chrome/browser/cocoa/first_run_dialog.mm +++ b/chrome/browser/cocoa/first_run_dialog.mm @@ -1,19 +1,21 @@ -// Copyright (c) 2009 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. #import "chrome/browser/cocoa/first_run_dialog.h" #include "app/l10n_util_mac.h" -#include "base/logging.h" #include "base/mac_util.h" -#import "base/scoped_nsobject.h" -#include "chrome/browser/browser_process.h" -#include "chrome/browser/prefs/pref_service.h" -#include "chrome/common/pref_names.h" +#include "base/message_loop.h" +#include "base/ref_counted.h" #include "grit/locale_settings.h" #import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h" +@interface FirstRunDialogController (PrivateMethods) +// Show the dialog. +- (void)show; +@end + namespace { // Compare function for -[NSArray sortedArrayUsingFunction:context:] that @@ -29,18 +31,30 @@ NSInteger CompareFrameY(id view1, id view2, void* context) { return NSOrderedSame; } +class FirstRunShowBridge : public base::RefCounted<FirstRunShowBridge> { + public: + FirstRunShowBridge(FirstRunDialogController* controller); + + void ShowDialog(); + private: + FirstRunDialogController* controller_; +}; + +FirstRunShowBridge::FirstRunShowBridge( + FirstRunDialogController* controller) : controller_(controller) { +} + +void FirstRunShowBridge::ShowDialog() { + [controller_ show]; + MessageLoop::current()->QuitNow(); +} + }; @implementation FirstRunDialogController -@synthesize userDidCancel = userDidCancel_; @synthesize statsEnabled = statsEnabled_; -@synthesize statsCheckboxHidden = statsCheckboxHidden_; @synthesize makeDefaultBrowser = makeDefaultBrowser_; -@synthesize importBookmarks = importBookmarks_; -@synthesize browserImportSelectedIndex = browserImportSelectedIndex_; -@synthesize browserImportList = browserImportList_; -@synthesize browserImportListHidden = browserImportListHidden_; - (id)init { NSString* nibpath = @@ -50,31 +64,28 @@ NSInteger CompareFrameY(id view1, id view2, void* context) { if (self != nil) { // Bound to the dialog checkbox, default to true. statsEnabled_ = YES; - importBookmarks_ = YES; - -#if defined(GOOGLE_CHROME_BUILD) - // If the send stats option is controlled by enterprise configuration - // management, hide the checkbox. - const PrefService::Preference* metrics_reporting_pref = - g_browser_process->local_state()->FindPreference( - prefs::kMetricsReportingEnabled); - if (metrics_reporting_pref && metrics_reporting_pref->IsManaged()) - statsCheckboxHidden_ = YES; -#else - // In Chromium builds all stats reporting is disabled so there's no reason - // to display the checkbox - the setting is always OFF. - statsCheckboxHidden_ = YES; -#endif // !GOOGLE_CHROME_BUILD } return self; } - (void)dealloc { - [browserImportList_ release]; [super dealloc]; } - (IBAction)showWindow:(id)sender { + // The main MessageLoop has not yet run, but has been spun. If we call + // -[NSApplication runModalForWindow:] we will hang <http://crbug.com/54248>. + // Therefore the main MessageLoop is run so things work. + + scoped_refptr<FirstRunShowBridge> bridge = new FirstRunShowBridge(self); + MessageLoop::current()->PostTask( + FROM_HERE, + NewRunnableMethod(bridge.get(), + &FirstRunShowBridge::ShowDialog)); + MessageLoop::current()->Run(); +} + +- (void)show { NSWindow* win = [self window]; // Only support the sizing the window once. @@ -106,15 +117,13 @@ NSInteger CompareFrameY(id view1, id view2, void* context) { [win setFrame:windowFrame display:NO]; } - // The stats checkbox (if visible) gets some really long text, so it gets - // word wrapped and then sized. + // The stats checkbox gets some really long text, so it gets word wrapped + // and then sized. DCHECK(statsCheckbox_); CGFloat statsCheckboxHeightChange = 0.0; - if (![self statsCheckboxHidden]) { - [GTMUILocalizerAndLayoutTweaker wrapButtonTitleForWidth:statsCheckbox_]; - statsCheckboxHeightChange = - [GTMUILocalizerAndLayoutTweaker sizeToFitView:statsCheckbox_].height; - } + [GTMUILocalizerAndLayoutTweaker wrapButtonTitleForWidth:statsCheckbox_]; + statsCheckboxHeightChange = + [GTMUILocalizerAndLayoutTweaker sizeToFitView:statsCheckbox_].height; // Walk bottom up shuffling for all the hidden views. NSArray* subViews = @@ -172,42 +181,15 @@ NSInteger CompareFrameY(id view1, id view2, void* context) { [NSApp runModalForWindow:win]; } -- (void)closeDialog { +- (IBAction)ok:(id)sender { [[self window] close]; [NSApp stopModal]; } -- (IBAction)ok:(id)sender { - [self closeDialog]; -} - -- (IBAction)cancel:(id)sender { - [self closeDialog]; - [self setUserDidCancel:YES]; -} - - (IBAction)learnMore:(id)sender { NSString* urlStr = l10n_util::GetNSString(IDS_LEARN_MORE_REPORTING_URL); NSURL* learnMoreUrl = [NSURL URLWithString:urlStr]; [[NSWorkspace sharedWorkspace] openURL:learnMoreUrl]; } -// Custom property getters - -- (BOOL)importBookmarks { - // If the UI for browser import is hidden, report the choice as off. - if ([self browserImportListHidden]) { - return NO; - } - return importBookmarks_; -} - -- (BOOL)statsEnabled { - // If the UI for stats is hidden, report the choice as off. - if ([self statsCheckboxHidden]) { - return NO; - } - return statsEnabled_; -} - @end diff --git a/chrome/browser/cocoa/search_engine_dialog_controller.h b/chrome/browser/cocoa/search_engine_dialog_controller.h new file mode 100644 index 0000000..a410614 --- /dev/null +++ b/chrome/browser/cocoa/search_engine_dialog_controller.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. + +#import <Cocoa/Cocoa.h> + +#include <vector> + +#import "base/scoped_nsobject.h" +#include "base/scoped_ptr.h" + +class Profile; +class SearchEngineDialogControllerBridge; +class TemplateURL; +class TemplateURLModel; + +// Class that acts as a controller for the search engine choice dialog. +@interface SearchEngineDialogController : NSWindowController { + @private + // Our current profile. + Profile* profile_; + + // If logos are to be displayed in random order. Used for UX testing. + bool randomize_; + + // Owned by the profile_. + TemplateURLModel* searchEnginesModel_; + + // Bridge to the C++ world. + scoped_ptr<SearchEngineDialogControllerBridge> bridge_; + + // Offered search engine choices. + std::vector<const TemplateURL*> choices_; + + IBOutlet NSImageView* headerImageView_; + IBOutlet NSView* searchEngineView_; +} + +@property(assign, nonatomic) Profile* profile; +@property(assign, nonatomic) bool randomize; + +// Properties for bindings. +@property(readonly) NSFont* mainLabelFont; + +@end diff --git a/chrome/browser/cocoa/search_engine_dialog_controller.mm b/chrome/browser/cocoa/search_engine_dialog_controller.mm new file mode 100644 index 0000000..4863c07 --- /dev/null +++ b/chrome/browser/cocoa/search_engine_dialog_controller.mm @@ -0,0 +1,279 @@ +// 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/search_engine_dialog_controller.h" + +#include <algorithm> + +#include "app/l10n_util_mac.h" +#include "app/resource_bundle.h" +#include "base/mac_util.h" +#include "base/nsimage_cache_mac.h" +#include "base/sys_string_conversions.h" +#include "base/time.h" +#include "chrome/browser/profile.h" +#include "chrome/browser/search_engines/template_url.h" +#include "chrome/browser/search_engines/template_url_model.h" +#include "chrome/browser/search_engines/template_url_model_observer.h" +#include "grit/generated_resources.h" +#include "grit/theme_resources.h" +#import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h" + +// Horizontal spacing between search engine choices. +const int kSearchEngineSpacing = 20; + +// Vertical spacing between the search engine logo and the button underneath. +const int kLogoButtonSpacing = 10; + +// Width of a label used in place of a logo. +const int kLogoLabelWidth = 170; + +// Height of a label used in place of a logo. +const int kLogoLabelHeight = 25; + +@interface SearchEngineDialogController (Private) +- (void)onTemplateURLModelChanged; +- (void)buildSearchEngineView; +- (NSView*)viewForSearchEngine:(const TemplateURL*)engine + atIndex:(size_t)index; +- (IBAction)searchEngineSelected:(id)sender; +@end + +class SearchEngineDialogControllerBridge : public TemplateURLModelObserver { + public: + SearchEngineDialogControllerBridge(SearchEngineDialogController* controller); + + // TemplateURLModelObserver + virtual void OnTemplateURLModelChanged(); + + private: + SearchEngineDialogController* controller_; +}; + +SearchEngineDialogControllerBridge::SearchEngineDialogControllerBridge( + SearchEngineDialogController* controller) : controller_(controller) { +} + +void SearchEngineDialogControllerBridge::OnTemplateURLModelChanged() { + [controller_ onTemplateURLModelChanged]; + MessageLoop::current()->QuitNow(); +} + +@implementation SearchEngineDialogController + +@synthesize profile = profile_; +@synthesize randomize = randomize_; + +- (id)init { + NSString* nibpath = + [mac_util::MainAppBundle() pathForResource:@"SearchEngineDialog" + ofType:@"nib"]; + self = [super initWithWindowNibPath:nibpath owner:self]; + if (self != nil) { + bridge_.reset(new SearchEngineDialogControllerBridge(self)); + } + return self; +} + +- (void)dealloc { + [super dealloc]; +} + +- (IBAction)showWindow:(id)sender { + searchEnginesModel_ = profile_->GetTemplateURLModel(); + searchEnginesModel_->AddObserver(bridge_.get()); + + if (searchEnginesModel_->loaded()) { + [self onTemplateURLModelChanged]; + } else { + searchEnginesModel_->Load(); + MessageLoop::current()->Run(); + } +} + +- (void)onTemplateURLModelChanged { + searchEnginesModel_->RemoveObserver(bridge_.get()); + + // Add the search engines in the search_engines_model_ to the buttons list. + // The first three will always be from prepopulated data. + std::vector<const TemplateURL*> templateUrls = + searchEnginesModel_->GetTemplateURLs(); + + // If we have fewer than two search engines, end the search engine dialog + // immediately, leaving the imported default search engine setting intact. + if (templateUrls.size() < 2) { + return; + } + + NSWindow* win = [self window]; + + [win setBackgroundColor:[NSColor whiteColor]]; + + NSImage* headerImage = ResourceBundle::GetSharedInstance(). + GetNSImageNamed(IDR_SEARCH_ENGINE_DIALOG_TOP); + [headerImageView_ setImage:headerImage]; + + // Is the user's default search engine included in the first three + // prepopulated set? If not, we need to expand the dialog to include a fourth + // engine. + const TemplateURL* defaultSearchEngine = + searchEnginesModel_->GetDefaultSearchProvider(); + + std::vector<const TemplateURL*>::iterator engineIter = + templateUrls.begin(); + for (int i = 0; engineIter != templateUrls.end(); ++i, ++engineIter) { + if (i < 3) { + choices_.push_back(*engineIter); + } else { + if (*engineIter == defaultSearchEngine) + choices_.push_back(*engineIter); + } + } + + // Randomize the order of the logos if the option has been set. + if (randomize_) { + int seed = static_cast<int>(base::Time::Now().ToInternalValue()); + srand(seed); + std::random_shuffle(choices_.begin(), choices_.end()); + } + + [self buildSearchEngineView]; + + // Display the dialog. + NSInteger choice = [NSApp runModalForWindow:win]; + searchEnginesModel_->SetDefaultSearchProvider(choices_.at(choice)); +} + +- (void)buildSearchEngineView { + scoped_nsobject<NSMutableArray> searchEngineViews + ([[NSMutableArray alloc] init]); + + for (size_t i = 0; i < choices_.size(); ++i) + [searchEngineViews addObject:[self viewForSearchEngine:choices_.at(i) + atIndex:i]]; + + NSSize newOverallSize = NSZeroSize; + for (NSView* view in searchEngineViews.get()) { + NSRect engineFrame = [view frame]; + engineFrame.origin = NSMakePoint(newOverallSize.width, 0); + [searchEngineView_ addSubview:view]; + [view setFrame:engineFrame]; + newOverallSize = NSMakeSize( + newOverallSize.width + NSWidth(engineFrame) + kSearchEngineSpacing, + std::max(newOverallSize.height, NSHeight(engineFrame))); + } + newOverallSize.width -= kSearchEngineSpacing; + + // Resize the window to fit (and because it's bound on all sides it will + // resize the search engine view). + NSSize currentOverallSize = [searchEngineView_ bounds].size; + NSSize deltaSize = NSMakeSize( + newOverallSize.width - currentOverallSize.width, + newOverallSize.height - currentOverallSize.height); + NSSize windowDeltaSize = [searchEngineView_ convertSize:deltaSize toView:nil]; + NSRect windowFrame = [[self window] frame]; + windowFrame.size.width += windowDeltaSize.width; + windowFrame.size.height += windowDeltaSize.height; + [[self window] setFrame:windowFrame display:NO]; +} + +- (NSView*)viewForSearchEngine:(const TemplateURL*)engine + atIndex:(size_t)index { + bool useImages = false; +#if defined(GOOGLE_CHROME_BUILD) + useImages = true; +#endif + + // Make the engine identifier. + NSView* engineIdentifier = nil; // either the logo or the text label + + int logoId = engine->logo_id(); + if (useImages && logoId > 0) { + NSImage* logoImage = + ResourceBundle::GetSharedInstance().GetNSImageNamed(logoId); + NSRect logoBounds = NSZeroRect; + logoBounds.size = [logoImage size]; + NSImageView* logoView = + [[[NSImageView alloc] initWithFrame:logoBounds] autorelease]; + [logoView setImage:logoImage]; + [logoView setEditable:NO]; + + // Tooltip text provides accessibility. + [logoView setToolTip:base::SysWideToNSString(engine->short_name())]; + engineIdentifier = logoView; + } else { + // No logo -- we must show a text label. + NSRect labelBounds = NSMakeRect(0, 0, kLogoLabelWidth, kLogoLabelHeight); + NSTextField* labelField = + [[[NSTextField alloc] initWithFrame:labelBounds] autorelease]; + [labelField setBezeled:NO]; + [labelField setEditable:NO]; + [labelField setSelectable:NO]; + + scoped_nsobject<NSMutableParagraphStyle> paragraphStyle( + [[NSMutableParagraphStyle alloc] init]); + [paragraphStyle setAlignment:NSCenterTextAlignment]; + NSDictionary* attrs = [NSDictionary dictionaryWithObjectsAndKeys: + [NSFont boldSystemFontOfSize:13], NSFontAttributeName, + paragraphStyle.get(), NSParagraphStyleAttributeName, + nil]; + + NSString* value = base::SysWideToNSString(engine->short_name()); + scoped_nsobject<NSAttributedString> attrValue( + [[NSAttributedString alloc] initWithString:value + attributes:attrs]); + + [labelField setAttributedStringValue:attrValue.get()]; + + engineIdentifier = labelField; + } + + // Make the "Choose" button. + scoped_nsobject<NSButton> chooseButton( + [[NSButton alloc] initWithFrame:NSMakeRect(0, 0, 100, 34)]); + [chooseButton setBezelStyle:NSRoundedBezelStyle]; + [[chooseButton cell] setFont:[NSFont systemFontOfSize: + [NSFont systemFontSizeForControlSize:NSRegularControlSize]]]; + [chooseButton setTitle:l10n_util::GetNSStringWithFixup(IDS_FR_SEARCH_CHOOSE)]; + [GTMUILocalizerAndLayoutTweaker sizeToFitView:chooseButton.get()]; + [chooseButton setTag:index]; + [chooseButton setTarget:self]; + [chooseButton setAction:@selector(searchEngineSelected:)]; + + // Put 'em together. + NSRect engineIdentifierFrame = [engineIdentifier frame]; + NSRect chooseButtonFrame = [chooseButton frame]; + + NSRect containingViewFrame = NSZeroRect; + containingViewFrame.size.width += engineIdentifierFrame.size.width; + containingViewFrame.size.height += engineIdentifierFrame.size.height; + containingViewFrame.size.height += kLogoButtonSpacing; + containingViewFrame.size.height += chooseButtonFrame.size.height; + + NSView* containingView = + [[[NSView alloc] initWithFrame:containingViewFrame] autorelease]; + + [containingView addSubview:engineIdentifier]; + engineIdentifierFrame.origin.y = + chooseButtonFrame.size.height + kLogoButtonSpacing; + [engineIdentifier setFrame:engineIdentifierFrame]; + + [containingView addSubview:chooseButton]; + chooseButtonFrame.origin.x = + int((containingViewFrame.size.width - chooseButtonFrame.size.width) / 2); + [chooseButton setFrame:chooseButtonFrame]; + + return containingView; +} + +- (NSFont*)mainLabelFont { + return [NSFont boldSystemFontOfSize:13]; +} + +- (IBAction)searchEngineSelected:(id)sender { + [[self window] close]; + [NSApp stopModalWithCode:[sender tag]]; +} + +@end diff --git a/chrome/browser/first_run/first_run.cc b/chrome/browser/first_run/first_run.cc index b072ef8..6f43ddf 100644 --- a/chrome/browser/first_run/first_run.cc +++ b/chrome/browser/first_run/first_run.cc @@ -461,8 +461,6 @@ void FirstRunImportObserver::Finish() { MessageLoop::current()->Quit(); } -// TODO(avi): port the relevant pieces and enable this. -#if !defined(OS_MACOSX) // static void FirstRun::AutoImport( Profile* profile, @@ -487,7 +485,15 @@ void FirstRun::AutoImport( bool local_state_file_exists = file_util::PathExists(local_state_path); scoped_refptr<ImporterHost> importer_host; - importer_host = new ImporterHost(); + // TODO(csilv,mirandac): Out-of-process import has only been qualified on + // MacOS X, so we will only use it on that platform since it is required. + // Remove this conditional logic once oop import is qualified for + // Linux/Windows. http://crbug.com/22142 +#if defined(OS_MACOSX) + importer_host = new ExternalProcessImporterHost; +#else + importer_host = new ImporterHost; +#endif // Do import if there is an available profile for us to import. if (importer_host->GetAvailableProfileCount() > 0) { // Don't show the warning dialog if import fails. @@ -547,4 +553,73 @@ void FirstRun::AutoImport( process_singleton->Unlock(); FirstRun::CreateSentinel(); } -#endif // !defined(OS_MACOSX) + +#if defined(OS_POSIX) +namespace { + +// This class acts as an observer for the ImporterHost::Observer::ImportEnded +// callback. When the import process is started, certain errors may cause +// ImportEnded() to be called synchronously, but the typical case is that +// ImportEnded() is called asynchronously. Thus we have to handle both cases. +class ImportEndedObserver : public ImporterHost::Observer { + public: + ImportEndedObserver() : ended_(false), + should_quit_message_loop_(false) {} + virtual ~ImportEndedObserver() {} + + virtual void ImportItemStarted(importer::ImportItem item) {} + virtual void ImportItemEnded(importer::ImportItem item) {} + virtual void ImportStarted() {} + virtual void ImportEnded() { + ended_ = true; + if (should_quit_message_loop_) + MessageLoop::current()->Quit(); + } + + void set_should_quit_message_loop() { + should_quit_message_loop_ = true; + } + + bool ended() { + return ended_; + } + + private: + // Set if the import has ended. + bool ended_; + + // Set by the client (via set_should_quit_message_loop) if, when the import + // ends, this class should quit the message loop. + bool should_quit_message_loop_; +}; + +} // namespace + +// static +bool FirstRun::ImportSettings(Profile* profile, + scoped_refptr<ImporterHost> importer_host, + int items_to_import) { + const ProfileInfo& source_profile = importer_host->GetSourceProfileInfoAt(0); + + // Ensure that importers aren't requested to import items that they do not + // support. + items_to_import &= source_profile.services_supported; + + scoped_ptr<ImportEndedObserver> observer(new ImportEndedObserver); + importer_host->SetObserver(observer.get()); + importer_host->StartImportSettings(source_profile, + profile, + items_to_import, + new ProfileWriter(profile), + true); + // If the import process has not errored out, block on it. + if (!observer->ended()) { + observer->set_should_quit_message_loop(); + MessageLoop::current()->Run(); + } + + // Unfortunately there's no success/fail signal in ImporterHost. + return true; +} + +#endif // OS_POSIX diff --git a/chrome/browser/first_run/first_run.h b/chrome/browser/first_run/first_run.h index 87b2524..ea6489d 100644 --- a/chrome/browser/first_run/first_run.h +++ b/chrome/browser/first_run/first_run.h @@ -306,31 +306,4 @@ class FirstRunImportObserver : public ImportObserver { DISALLOW_COPY_AND_ASSIGN(FirstRunImportObserver); }; -#if defined(OS_MACOSX) -// Show the First Run UI to the user, allowing them to create shortcuts for -// the app, import their bookmarks and other data from another browser into -// |profile| and perhaps some other tasks. -// |process_singleton| is used to lock the handling of CopyData messages -// while the First Run UI is visible. -// |homepage_defined| true indicates that homepage is defined in master -// preferences and should not be imported from another browser. -// |import_items| specifies the items to import, specified in master -// preferences and will override default behavior of importer. -// |dont_import_items| specifies the items *not* to import, specified in master -// preferences and will override default behavior of importer. -// |search_engine_experiment| indicates whether the experimental search engine -// window should be shown. -// |randomize_search_engine_experiment| is true if the logos in the search -// engine window should be shown in randomized order. -// Returns true if the user clicked "Start", false if the user pressed "Cancel" -// or closed the dialog. -bool OpenFirstRunDialog(Profile* profile, - bool homepage_defined, - int import_items, - int dont_import_items, - bool search_engine_experiment, - bool randomize_search_engine_experiment, - ProcessSingleton* process_singleton); -#endif // OS_MACOSX - #endif // CHROME_BROWSER_FIRST_RUN_FIRST_RUN_H_ diff --git a/chrome/browser/first_run/first_run_gtk.cc b/chrome/browser/first_run/first_run_gtk.cc index 06febbd..3dd5ffa 100644 --- a/chrome/browser/first_run/first_run_gtk.cc +++ b/chrome/browser/first_run/first_run_gtk.cc @@ -22,44 +22,6 @@ #include "chrome/installer/util/google_update_settings.h" #include "googleurl/src/gurl.h" -namespace { - -// This class acts as an observer for the ImporterHost::Observer::ImportEnded -// callback. When the import process is started, certain errors may cause -// ImportEnded() to be called synchronously, but the typical case is that -// ImportEnded() is called asynchronously. Thus we have to handle both cases. -class ImportEndedObserver : public ImporterHost::Observer { - public: - ImportEndedObserver() - : ended_(false), - quit_message_loop_(false) { - } - virtual ~ImportEndedObserver() {} - - virtual void ImportItemStarted(importer::ImportItem item) {} - virtual void ImportItemEnded(importer::ImportItem item) {} - virtual void ImportStarted() {} - virtual void ImportEnded() { - ended_ = true; - if (quit_message_loop_) - MessageLoop::current()->Quit(); - } - - void set_quit_message_loop() { - quit_message_loop_ = true; - } - - bool ended() { - return ended_; - } - - private: - bool ended_; - bool quit_message_loop_; -}; - -} // namespace - // TODO(port): This is just a piece of the silent import functionality from // ImportSettings for Windows. It would be nice to get the rest of it ported. bool FirstRun::ImportBookmarks(const FilePath& import_bookmarks_path) { @@ -121,29 +83,6 @@ double Upgrade::GetLastModifiedTimeOfExe() { } #endif // defined(OS_LINUX) && !defined(OS_CHROMEOS) -// At least for now, we do profile import in-process on Linux. -// static -bool FirstRun::ImportSettings(Profile* profile, - scoped_refptr<ImporterHost> importer_host, - int items_to_import) { - // Import data. - const ProfileInfo& source_profile = importer_host->GetSourceProfileInfoAt(0); - scoped_ptr<ImportEndedObserver> observer(new ImportEndedObserver); - importer_host->SetObserver(observer.get()); - importer_host->StartImportSettings(source_profile, - profile, - items_to_import, - new ProfileWriter(profile), - true); - // If the import process has not errored out, block on it. - if (!observer->ended()) { - observer->set_quit_message_loop(); - MessageLoop::current()->Run(); - } - // Unfortunately there's no success/fail signal in ImporterHost. - return true; -} - // static void FirstRun::ShowFirstRunDialog(Profile* profile, bool randomize_search_engine_experiment) { diff --git a/chrome/browser/first_run/first_run_mac.mm b/chrome/browser/first_run/first_run_mac.mm index 0795bce..3159e9d 100644 --- a/chrome/browser/first_run/first_run_mac.mm +++ b/chrome/browser/first_run/first_run_mac.mm @@ -5,110 +5,50 @@ #include "chrome/browser/first_run/first_run.h" #import "base/scoped_nsobject.h" -#include "base/sys_string_conversions.h" #import "chrome/app/breakpad_mac.h" #import "chrome/browser/cocoa/first_run_dialog.h" -#import "chrome/browser/cocoa/import_progress_dialog.h" -#include "chrome/browser/importer/importer.h" -#include "chrome/browser/importer/importer_data_types.h" -#include "chrome/browser/metrics/user_metrics.h" +#import "chrome/browser/cocoa/search_engine_dialog_controller.h" +#include "chrome/browser/prefs/pref_service.h" #include "chrome/browser/shell_integration.h" +#include "chrome/common/pref_names.h" #include "chrome/installer/util/google_update_constants.h" #include "chrome/installer/util/google_update_settings.h" -// Class that handles conducting the first run operation. -// FirstRunController deletes itself when the first run operation ends. -class FirstRunController : public ImportObserver { - public: - explicit FirstRunController(); - virtual ~FirstRunController() {} +namespace { - // Overridden methods from ImportObserver. - virtual void ImportCanceled() { - FirstRunDone(); - } - virtual void ImportComplete() { - FirstRunDone(); - } - - // Display first run UI, start the import and return when it's all over. - bool DoFirstRun(Profile* profile, ProcessSingleton* process_singleton); - - private: - // This method closes the first run window and quits the message loop so that - // the Chrome startup can continue. This should be called when all the - // first run tasks are done. - void FirstRunDone(); - - scoped_refptr<ImporterHost> importer_host_; - - DISALLOW_COPY_AND_ASSIGN(FirstRunController); -}; - - -bool OpenFirstRunDialog(Profile* profile, - bool homepage_defined, - int import_items, - int dont_import_items, - bool search_engine_experiment, - bool randomize_search_engine_experiment, - ProcessSingleton* process_singleton) { - FirstRunController* controller = new FirstRunController; - return controller->DoFirstRun(profile, process_singleton); -} - -FirstRunController::FirstRunController() - : importer_host_(new ExternalProcessImporterHost) { -} - -void FirstRunController::FirstRunDone() { - // Set preference to show first run bubble and welcome page. - FirstRun::SetShowFirstRunBubblePref(true); - FirstRun::SetShowWelcomePagePref(); -} - -bool FirstRunController::DoFirstRun(Profile* profile, - ProcessSingleton* process_singleton) { - // This object is responsible for deleting itself, make sure that happens. - scoped_ptr<FirstRunController> gc(this); - - scoped_nsobject<FirstRunDialogController> dialog( - [[FirstRunDialogController alloc] init]); +// Show the search engine selection dialog. +void ShowSearchEngineSelectionDialog(Profile* profile, + bool randomize_search_engine_experiment) { + scoped_nsobject<SearchEngineDialogController> dialog( + [[SearchEngineDialogController alloc] init]); + [dialog.get() setProfile:profile]; + [dialog.get() setRandomize:randomize_search_engine_experiment]; - // Set list of browsers we know how to import. - ssize_t profiles_count = importer_host_->GetAvailableProfileCount(); - - // TODO(jeremy): Test on newly created account. - // TODO(jeremy): Correctly handle case where no browsers to import from - // are detected. - NSMutableArray *browsers = [NSMutableArray arrayWithCapacity:profiles_count]; - for (int i = 0; i < profiles_count; ++i) { - std::wstring profile = importer_host_->GetSourceProfileNameAt(i); - [browsers addObject:base::SysWideToNSString(profile)]; - } - [dialog.get() setBrowserImportList:browsers]; - - BOOL browser_import_disabled = profiles_count == 0; - [dialog.get() setBrowserImportListHidden:browser_import_disabled]; - - // FirstRunDialogController will call exit if "Cancel" is clicked. [dialog.get() showWindow:nil]; +} - // If user clicked cancel, bail - browser_main will return if we haven't - // turned off the first run flag when this function returns. - if ([dialog.get() userDidCancel]) { - return false; - } - - FirstRun::CreateSentinel(); - - // If the dialog asked the user to opt-in for stats and crash reporting, - // record the decision and enable the crash reporter if appropriate. - if (![dialog.get() statsCheckboxHidden]) { +// Show the first run UI. +void ShowFirstRun(Profile* profile) { +#if defined(GOOGLE_CHROME_BUILD) + // The purpose of the dialog is to ask the user to enable stats and crash + // reporting. This setting may be controlled through configuration management + // in enterprise scenarios. If that is the case, skip the dialog entirely, as + // it's not worth bothering the user for only the default browser question + // (which is likely to be forced in enterprise deployments anyway). + const PrefService::Preference* metrics_reporting_pref = + g_browser_process->local_state()->FindPreference( + prefs::kMetricsReportingEnabled); + if (!metrics_reporting_pref || !metrics_reporting_pref->IsManaged()) { + scoped_nsobject<FirstRunDialogController> dialog( + [[FirstRunDialogController alloc] init]); + + [dialog.get() showWindow:nil]; + + // If the dialog asked the user to opt-in for stats and crash reporting, + // record the decision and enable the crash reporter if appropriate. bool stats_enabled = [dialog.get() statsEnabled]; GoogleUpdateSettings::SetCollectStatsConsent(stats_enabled); -#if defined(GOOGLE_CHROME_BUILD) // Breakpad is normally enabled very early in the startup process. However, // on the first run it may not have been enabled due to the missing opt-in // from the user. If the user agreed now, enable breakpad if necessary. @@ -116,33 +56,48 @@ bool FirstRunController::DoFirstRun(Profile* profile, InitCrashReporter(); InitCrashProcessInfo(); } -#endif // GOOGLE_CHROME_BUILD - } - // If selected set as default browser. - BOOL make_default_browser = [dialog.get() makeDefaultBrowser]; - if (make_default_browser) { - bool success = ShellIntegration::SetAsDefaultBrowser(); - DCHECK(success); + // If selected set as default browser. + BOOL make_default_browser = [dialog.get() makeDefaultBrowser]; + if (make_default_browser) { + bool success = ShellIntegration::SetAsDefaultBrowser(); + DCHECK(success); + } } +#else // GOOGLE_CHROME_BUILD + // We don't show the dialog in Chromium. +#endif // GOOGLE_CHROME_BUILD - // Import bookmarks. - if (!browser_import_disabled && [dialog.get() importBookmarks]) { - const importer::ProfileInfo& source_profile = importer_host_-> - GetSourceProfileInfoAt([dialog.get() browserImportSelectedIndex]); - int16 items = source_profile.services_supported; - // TODO(port): Do the actual import in a new process like Windows. - ignore_result(gc.release()); - StartImportingWithUI(nil, items, importer_host_.get(), - source_profile, profile, this, true); - } else { - // This is called by the importer if it runs. - FirstRunDone(); - } + FirstRun::CreateSentinel(); - return true; + // Set preference to show first run bubble and welcome page. + FirstRun::SetShowFirstRunBubblePref(true); + FirstRun::SetShowWelcomePagePref(); +} + +} // namespace + +// static +void FirstRun::ShowFirstRunDialog(Profile* profile, + bool randomize_search_engine_experiment) { + ShowSearchEngineSelectionDialog(profile, + randomize_search_engine_experiment); + ShowFirstRun(profile); } + bool FirstRun::ImportBookmarks(const FilePath& import_bookmarks_path) { // http://crbug.com/48880 return false; } + +// static +bool FirstRun::IsOrganic() { + // We treat all installs as organic. + return true; +} + +// static +void FirstRun::PlatformSetup() { + // Things that Windows does here (creating a desktop icon, for example) are + // not needed. +} |