| // Copyright (c) 2013 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 "ui/message_center/cocoa/settings_controller.h" |
| |
| #include <algorithm> |
| |
| #include "base/mac/foundation_util.h" |
| #import "base/mac/scoped_nsobject.h" |
| #include "base/stl_util.h" |
| #include "base/strings/sys_string_conversions.h" |
| #include "skia/ext/skia_utils_mac.h" |
| #include "ui/base/l10n/l10n_util.h" |
| #import "ui/message_center/cocoa/opaque_views.h" |
| #import "ui/message_center/cocoa/settings_entry_view.h" |
| #import "ui/message_center/cocoa/tray_view_controller.h" |
| #include "ui/message_center/message_center_style.h" |
| #include "ui/strings/grit/ui_strings.h" |
| |
| using message_center::settings::kHorizontalMargin; |
| using message_center::settings::kEntryHeight; |
| |
| // Intrinsic padding pixels out of our control. |
| const int kIntrinsicHeaderTextTopPadding = 3; |
| const int kIntrinsicSubheaderTextTopPadding = 5; |
| const int kIntrinsicSubheaderTextBottomPadding = 3; |
| const int kIntrinsicDropDownVerticalPadding = 2; |
| const int kIntrinsicDropDownHorizontalPadding = 3; |
| |
| // Corrected padding values used in layout. |
| // Calculated additional blank space above the header text, including |
| // the intrinsic blank space above the header label. |
| const int kCorrectedHeaderTextTopPadding = |
| message_center::settings::kTopMargin - kIntrinsicHeaderTextTopPadding; |
| |
| // Calculated additional blank space above the subheader text, including |
| // the intrinsic blank space above the subheader label. |
| const int kCorrectedSubheaderTextTopPadding = |
| message_center::settings::kTitleToDescriptionSpace - |
| kIntrinsicSubheaderTextTopPadding; |
| |
| // Calcoulated additional vertical padding for the drop-down, including the |
| // blank space included with the drop-down control. |
| const int kCorrectedDropDownTopPadding = |
| message_center::settings::kDescriptionToSwitcherSpace - |
| kIntrinsicDropDownVerticalPadding - kIntrinsicSubheaderTextBottomPadding; |
| |
| // Calculated additional horizontal blank space for the drop down, including |
| // the blank space included with the drop-down control. |
| const int kCorrectedDropDownMargin = |
| kHorizontalMargin - kIntrinsicDropDownHorizontalPadding; |
| |
| @interface MCSettingsController (Private) |
| // Sets the icon on the checkbox corresponding to |notifiers_[index]|. |
| - (void)setIcon:(NSImage*)icon forNotifierIndex:(size_t)index; |
| |
| - (void)setIcon:(NSImage*)icon |
| forNotifierId:(const message_center::NotifierId&)id; |
| |
| // Returns the NSButton corresponding to the checkbox for |notifiers_[index]|. |
| - (MCSettingsEntryView*)entryForNotifierAtIndex:(size_t)index; |
| |
| // Update the contents view. |
| - (void)updateView; |
| |
| // Handler for the notifier group dropdown menu. |
| - (void)notifierGroupSelectionChanged:(id)sender; |
| |
| @end |
| |
| namespace message_center { |
| |
| NotifierSettingsObserverMac::~NotifierSettingsObserverMac() {} |
| |
| void NotifierSettingsObserverMac::UpdateIconImage(const NotifierId& notifier_id, |
| const gfx::Image& icon) { |
| [settings_controller_ setIcon:icon.AsNSImage() forNotifierId:notifier_id]; |
| } |
| |
| void NotifierSettingsObserverMac::NotifierGroupChanged() { |
| [settings_controller_ updateView]; |
| } |
| |
| void NotifierSettingsObserverMac::NotifierEnabledChanged( |
| const NotifierId& notifier_id, bool enabled) {} |
| |
| } // namespace message_center |
| |
| @implementation MCSettingsController |
| |
| - (id)initWithProvider:(message_center::NotifierSettingsProvider*)provider |
| trayViewController:(MCTrayViewController*)trayViewController { |
| if ((self = [super initWithNibName:nil bundle:nil])) { |
| observer_.reset(new message_center::NotifierSettingsObserverMac(self)); |
| provider_ = provider; |
| trayViewController_ = trayViewController; |
| provider_->AddObserver(observer_.get()); |
| } |
| return self; |
| } |
| |
| - (void)dealloc { |
| provider_->RemoveObserver(observer_.get()); |
| provider_->OnNotifierSettingsClosing(); |
| STLDeleteElements(¬ifiers_); |
| [super dealloc]; |
| } |
| |
| - (NSTextField*)newLabelWithFrame:(NSRect)frame { |
| NSColor* color = gfx::SkColorToCalibratedNSColor( |
| message_center::kMessageCenterBackgroundColor); |
| MCTextField* label = |
| [[MCTextField alloc] initWithFrame:frame backgroundColor:color]; |
| |
| return label; |
| } |
| |
| - (void)updateView { |
| notifiers_.clear(); |
| [trayViewController_ updateSettings]; |
| } |
| |
| - (void)loadView { |
| DCHECK(notifiers_.empty()); |
| provider_->GetNotifierList(¬ifiers_); |
| CGFloat maxHeight = [MCTrayViewController maxTrayClientHeight]; |
| |
| // Container view. |
| NSRect fullFrame = |
| NSMakeRect(0, 0, [MCTrayViewController trayWidth], maxHeight); |
| base::scoped_nsobject<NSBox> view([[NSBox alloc] initWithFrame:fullFrame]); |
| [view setBorderType:NSNoBorder]; |
| [view setBoxType:NSBoxCustom]; |
| [view setContentViewMargins:NSZeroSize]; |
| [view setFillColor:gfx::SkColorToCalibratedNSColor( |
| message_center::kMessageCenterBackgroundColor)]; |
| [view setTitlePosition:NSNoTitle]; |
| [self setView:view]; |
| |
| // "Settings" text. |
| NSRect headerFrame = NSMakeRect(kHorizontalMargin, |
| kHorizontalMargin, |
| NSWidth(fullFrame), |
| NSHeight(fullFrame)); |
| settingsText_.reset([self newLabelWithFrame:headerFrame]); |
| [settingsText_ setTextColor: |
| gfx::SkColorToCalibratedNSColor(message_center::kRegularTextColor)]; |
| [settingsText_ |
| setFont:[NSFont messageFontOfSize:message_center::kTitleFontSize]]; |
| |
| [settingsText_ setStringValue: |
| l10n_util::GetNSString(IDS_MESSAGE_CENTER_SETTINGS_BUTTON_LABEL)]; |
| [settingsText_ sizeToFit]; |
| headerFrame = [settingsText_ frame]; |
| headerFrame.origin.y = NSMaxY(fullFrame) - kCorrectedHeaderTextTopPadding - |
| NSHeight(headerFrame); |
| [[self view] addSubview:settingsText_]; |
| |
| // Subheader. |
| NSRect subheaderFrame = NSMakeRect(kHorizontalMargin, |
| kHorizontalMargin, |
| NSWidth(fullFrame), |
| NSHeight(fullFrame)); |
| detailsText_.reset([self newLabelWithFrame:subheaderFrame]); |
| [detailsText_ setTextColor: |
| gfx::SkColorToCalibratedNSColor(message_center::kDimTextColor)]; |
| [detailsText_ |
| setFont:[NSFont messageFontOfSize:message_center::kMessageFontSize]]; |
| |
| size_t groupCount = provider_->GetNotifierGroupCount(); |
| [detailsText_ setStringValue:l10n_util::GetNSString( |
| groupCount > 1 ? IDS_MESSAGE_CENTER_SETTINGS_DESCRIPTION_MULTIUSER |
| : IDS_MESSAGE_CENTER_SETTINGS_DIALOG_DESCRIPTION)]; |
| [detailsText_ sizeToFit]; |
| subheaderFrame = [detailsText_ frame]; |
| subheaderFrame.origin.y = |
| NSMinY(headerFrame) - kCorrectedSubheaderTextTopPadding - |
| NSHeight(subheaderFrame); |
| [[self view] addSubview:detailsText_]; |
| |
| // Profile switcher is only needed for more than one profile. |
| NSRect dropDownButtonFrame = subheaderFrame; |
| if (groupCount > 1) { |
| dropDownButtonFrame = NSMakeRect(kCorrectedDropDownMargin, |
| kHorizontalMargin, |
| NSWidth(fullFrame), |
| NSHeight(fullFrame)); |
| groupDropDownButton_.reset( |
| [[MCDropDown alloc] initWithFrame:dropDownButtonFrame pullsDown:YES]); |
| [groupDropDownButton_ |
| setBackgroundColor:gfx::SkColorToCalibratedNSColor( |
| message_center::kMessageCenterBackgroundColor)]; |
| [groupDropDownButton_ setAction:@selector(notifierGroupSelectionChanged:)]; |
| [groupDropDownButton_ setTarget:self]; |
| // Add a dummy item for pull-down. |
| [groupDropDownButton_ addItemWithTitle:@""]; |
| base::string16 title; |
| for (size_t i = 0; i < groupCount; ++i) { |
| const message_center::NotifierGroup& group = |
| provider_->GetNotifierGroupAt(i); |
| base::string16 item = |
| group.login_info.empty() ? group.name : group.login_info; |
| [groupDropDownButton_ addItemWithTitle:base::SysUTF16ToNSString(item)]; |
| if (provider_->IsNotifierGroupActiveAt(i)) { |
| title = item; |
| [[groupDropDownButton_ lastItem] setState:NSOnState]; |
| } |
| } |
| [groupDropDownButton_ setTitle:base::SysUTF16ToNSString(title)]; |
| [groupDropDownButton_ sizeToFit]; |
| dropDownButtonFrame = [groupDropDownButton_ frame]; |
| dropDownButtonFrame.origin.y = |
| NSMinY(subheaderFrame) - kCorrectedDropDownTopPadding - |
| NSHeight(dropDownButtonFrame); |
| dropDownButtonFrame.size.width = |
| NSWidth(fullFrame) - 2 * kCorrectedDropDownMargin; |
| [[self view] addSubview:groupDropDownButton_]; |
| } |
| |
| // Document view for the notifier settings. |
| CGFloat y = 0; |
| NSRect documentFrame = NSMakeRect(0, 0, NSWidth(fullFrame), 0); |
| base::scoped_nsobject<NSView> documentView( |
| [[NSView alloc] initWithFrame:documentFrame]); |
| int notifierCount = notifiers_.size(); |
| for (int i = notifierCount - 1; i >= 0; --i) { |
| message_center::Notifier* notifier = notifiers_[i]; |
| // TODO(thakis): Use a custom button cell. |
| NSRect frame = NSMakeRect(kHorizontalMargin, |
| y, |
| NSWidth(documentFrame) - kHorizontalMargin * 2, |
| kEntryHeight); |
| |
| base::scoped_nsobject<MCSettingsEntryView> entryView( |
| [[MCSettingsEntryView alloc] |
| initWithController:self |
| notifier:notifier |
| frame:frame |
| hasSeparator:(i != notifierCount - 1)]); |
| [documentView addSubview:entryView]; |
| y += NSHeight(frame); |
| } |
| |
| documentFrame.size.height = y - kIntrinsicDropDownVerticalPadding; |
| [documentView setFrame:documentFrame]; |
| |
| // Scroll view for the notifier settings. |
| NSRect scrollFrame = documentFrame; |
| scrollFrame.origin.y = 0; |
| CGFloat remainingHeight = NSMinY(dropDownButtonFrame) - NSMinY(scrollFrame); |
| |
| if (NSHeight(documentFrame) < remainingHeight) { |
| // Everything fits without scrolling. |
| CGFloat delta = remainingHeight - NSHeight(documentFrame); |
| headerFrame.origin.y -= delta; |
| subheaderFrame.origin.y -= delta; |
| dropDownButtonFrame.origin.y -= delta; |
| fullFrame.size.height -= delta; |
| } else { |
| scrollFrame.size.height = remainingHeight; |
| } |
| |
| scrollView_.reset([[NSScrollView alloc] initWithFrame:scrollFrame]); |
| [scrollView_ setAutohidesScrollers:YES]; |
| [scrollView_ setAutoresizingMask:NSViewMinYMargin]; |
| [scrollView_ setDocumentView:documentView]; |
| [scrollView_ setDrawsBackground:NO]; |
| [scrollView_ setHasHorizontalScroller:NO]; |
| [scrollView_ setHasVerticalScroller:YES]; |
| |
| // Scroll to top. |
| NSPoint newScrollOrigin = |
| NSMakePoint(0.0, |
| NSMaxY([[scrollView_ documentView] frame]) - |
| NSHeight([[scrollView_ contentView] bounds])); |
| [[scrollView_ documentView] scrollPoint:newScrollOrigin]; |
| |
| // Set final sizes. |
| [[self view] setFrame:fullFrame]; |
| [[self view] addSubview:scrollView_]; |
| [settingsText_ setFrame:headerFrame]; |
| [detailsText_ setFrame:subheaderFrame]; |
| [groupDropDownButton_ setFrame:dropDownButtonFrame]; |
| } |
| |
| - (void)setSettingsNotifier:(message_center::Notifier*)notifier |
| enabled:(BOOL)enabled { |
| provider_->SetNotifierEnabled(*notifier, enabled); |
| } |
| |
| - (void)learnMoreClicked:(message_center::Notifier*)notifier { |
| provider_->OnNotifierAdvancedSettingsRequested(notifier->notifier_id, NULL); |
| } |
| |
| // Testing API ///////////////////////////////////////////////////////////////// |
| |
| - (NSPopUpButton*)groupDropDownButton { |
| return groupDropDownButton_; |
| } |
| |
| - (NSScrollView*)scrollView { |
| return scrollView_; |
| } |
| |
| // Private API ///////////////////////////////////////////////////////////////// |
| |
| - (void)setIcon:(NSImage*)icon forNotifierIndex:(size_t)index { |
| MCSettingsEntryView* entry = [self entryForNotifierAtIndex:index]; |
| [entry setNotifierIcon:icon]; |
| } |
| |
| - (void)setIcon:(NSImage*)icon |
| forNotifierId:(const message_center::NotifierId&)id { |
| for (size_t i = 0; i < notifiers_.size(); ++i) { |
| if (notifiers_[i]->notifier_id == id) { |
| [self setIcon:icon forNotifierIndex:i]; |
| return; |
| } |
| } |
| } |
| |
| - (MCSettingsEntryView*)entryForNotifierAtIndex:(size_t)index { |
| NSArray* subviews = [[scrollView_ documentView] subviews]; |
| // The checkboxes are in bottom-top order, the checkbox for notifiers_[0] is |
| // last. |
| DCHECK_LT(notifiers_.size() - 1 - index, [subviews count]); |
| NSView* view = [subviews objectAtIndex:notifiers_.size() - 1 - index]; |
| return base::mac::ObjCCastStrict<MCSettingsEntryView>(view); |
| } |
| |
| - (void)notifierGroupSelectionChanged:(id)sender { |
| DCHECK_EQ(groupDropDownButton_.get(), sender); |
| NSPopUpButton* button = static_cast<NSPopUpButton*>(sender); |
| // The first item is a dummy item. |
| provider_->SwitchToNotifierGroup([button indexOfSelectedItem] - 1); |
| } |
| |
| - (BOOL)notifierHasAdvancedSettings:(const message_center::NotifierId&)id { |
| return provider_->NotifierHasAdvancedSettings(id); |
| } |
| |
| @end |