Clarify the documentation for url::{AddStandardScheme,IsStandard}.
[chromium-blink-merge.git] / ui / message_center / cocoa / settings_controller.mm
blob37adba2b098f33f5902ed0eb966b293c9db0bf4f
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #import "ui/message_center/cocoa/settings_controller.h"
7 #include <algorithm>
9 #include "base/mac/foundation_util.h"
10 #import "base/mac/scoped_nsobject.h"
11 #include "base/stl_util.h"
12 #include "base/strings/sys_string_conversions.h"
13 #include "skia/ext/skia_utils_mac.h"
14 #include "ui/base/l10n/l10n_util.h"
15 #import "ui/message_center/cocoa/opaque_views.h"
16 #import "ui/message_center/cocoa/settings_entry_view.h"
17 #import "ui/message_center/cocoa/tray_view_controller.h"
18 #include "ui/message_center/message_center_style.h"
19 #include "ui/strings/grit/ui_strings.h"
21 using message_center::settings::kHorizontalMargin;
22 using message_center::settings::kEntryHeight;
24 // Intrinsic padding pixels out of our control.
25 const int kIntrinsicHeaderTextTopPadding = 3;
26 const int kIntrinsicSubheaderTextTopPadding = 5;
27 const int kIntrinsicSubheaderTextBottomPadding = 3;
28 const int kIntrinsicDropDownVerticalPadding = 2;
29 const int kIntrinsicDropDownHorizontalPadding = 3;
31 // Corrected padding values used in layout.
32 // Calculated additional blank space above the header text, including
33 // the intrinsic blank space above the header label.
34 const int kCorrectedHeaderTextTopPadding =
35     message_center::settings::kTopMargin - kIntrinsicHeaderTextTopPadding;
37 // Calculated additional blank space above the subheader text, including
38 // the intrinsic blank space above the subheader label.
39 const int kCorrectedSubheaderTextTopPadding =
40     message_center::settings::kTitleToDescriptionSpace -
41     kIntrinsicSubheaderTextTopPadding;
43 // Calcoulated additional vertical padding for the drop-down, including the
44 // blank space included with the drop-down control.
45 const int kCorrectedDropDownTopPadding =
46     message_center::settings::kDescriptionToSwitcherSpace -
47     kIntrinsicDropDownVerticalPadding - kIntrinsicSubheaderTextBottomPadding;
49 // Calculated additional horizontal blank space for the drop down, including
50 // the blank space included with the drop-down control.
51 const int kCorrectedDropDownMargin =
52     kHorizontalMargin - kIntrinsicDropDownHorizontalPadding;
54 @interface MCSettingsController (Private)
55 // Sets the icon on the checkbox corresponding to |notifiers_[index]|.
56 - (void)setIcon:(NSImage*)icon forNotifierIndex:(size_t)index;
58 - (void)setIcon:(NSImage*)icon
59     forNotifierId:(const message_center::NotifierId&)id;
61 // Returns the NSButton corresponding to the checkbox for |notifiers_[index]|.
62 - (MCSettingsEntryView*)entryForNotifierAtIndex:(size_t)index;
64 // Update the contents view.
65 - (void)updateView;
67 // Handler for the notifier group dropdown menu.
68 - (void)notifierGroupSelectionChanged:(id)sender;
70 @end
72 namespace message_center {
74 NotifierSettingsObserverMac::~NotifierSettingsObserverMac() {}
76 void NotifierSettingsObserverMac::UpdateIconImage(const NotifierId& notifier_id,
77                                                   const gfx::Image& icon) {
78   [settings_controller_ setIcon:icon.AsNSImage() forNotifierId:notifier_id];
81 void NotifierSettingsObserverMac::NotifierGroupChanged() {
82   [settings_controller_ updateView];
85 void NotifierSettingsObserverMac::NotifierEnabledChanged(
86     const NotifierId& notifier_id, bool enabled) {}
88 }  // namespace message_center
90 @implementation MCSettingsController
92 - (id)initWithProvider:(message_center::NotifierSettingsProvider*)provider
93     trayViewController:(MCTrayViewController*)trayViewController {
94   if ((self = [super initWithNibName:nil bundle:nil])) {
95     observer_.reset(new message_center::NotifierSettingsObserverMac(self));
96     provider_ = provider;
97     trayViewController_ = trayViewController;
98     provider_->AddObserver(observer_.get());
99   }
100   return self;
103 - (void)dealloc {
104   provider_->RemoveObserver(observer_.get());
105   provider_->OnNotifierSettingsClosing();
106   STLDeleteElements(&notifiers_);
107   [super dealloc];
110 - (NSTextField*)newLabelWithFrame:(NSRect)frame {
111   NSColor* color = gfx::SkColorToCalibratedNSColor(
112       message_center::kMessageCenterBackgroundColor);
113   MCTextField* label =
114       [[MCTextField alloc] initWithFrame:frame backgroundColor:color];
116   return label;
119 - (void)updateView {
120   notifiers_.clear();
121   [trayViewController_ updateSettings];
124 - (void)loadView {
125   DCHECK(notifiers_.empty());
126   provider_->GetNotifierList(&notifiers_);
127   CGFloat maxHeight = [MCTrayViewController maxTrayClientHeight];
129   // Container view.
130   NSRect fullFrame =
131       NSMakeRect(0, 0, [MCTrayViewController trayWidth], maxHeight);
132   base::scoped_nsobject<NSBox> view([[NSBox alloc] initWithFrame:fullFrame]);
133   [view setBorderType:NSNoBorder];
134   [view setBoxType:NSBoxCustom];
135   [view setContentViewMargins:NSZeroSize];
136   [view setFillColor:gfx::SkColorToCalibratedNSColor(
137       message_center::kMessageCenterBackgroundColor)];
138   [view setTitlePosition:NSNoTitle];
139   [self setView:view];
141   // "Settings" text.
142   NSRect headerFrame = NSMakeRect(kHorizontalMargin,
143                                   kHorizontalMargin,
144                                   NSWidth(fullFrame),
145                                   NSHeight(fullFrame));
146   settingsText_.reset([self newLabelWithFrame:headerFrame]);
147   [settingsText_ setTextColor:
148           gfx::SkColorToCalibratedNSColor(message_center::kRegularTextColor)];
149   [settingsText_
150       setFont:[NSFont messageFontOfSize:message_center::kTitleFontSize]];
152   [settingsText_ setStringValue:
153           l10n_util::GetNSString(IDS_MESSAGE_CENTER_SETTINGS_BUTTON_LABEL)];
154   [settingsText_ sizeToFit];
155   headerFrame = [settingsText_ frame];
156   headerFrame.origin.y = NSMaxY(fullFrame) - kCorrectedHeaderTextTopPadding -
157                          NSHeight(headerFrame);
158   [[self view] addSubview:settingsText_];
160   // Subheader.
161   NSRect subheaderFrame = NSMakeRect(kHorizontalMargin,
162                                      kHorizontalMargin,
163                                      NSWidth(fullFrame),
164                                      NSHeight(fullFrame));
165   detailsText_.reset([self newLabelWithFrame:subheaderFrame]);
166   [detailsText_ setTextColor:
167       gfx::SkColorToCalibratedNSColor(message_center::kDimTextColor)];
168   [detailsText_
169       setFont:[NSFont messageFontOfSize:message_center::kMessageFontSize]];
171   size_t groupCount = provider_->GetNotifierGroupCount();
172   [detailsText_ setStringValue:l10n_util::GetNSString(
173       groupCount > 1 ? IDS_MESSAGE_CENTER_SETTINGS_DESCRIPTION_MULTIUSER
174                      : IDS_MESSAGE_CENTER_SETTINGS_DIALOG_DESCRIPTION)];
175   [detailsText_ sizeToFit];
176   subheaderFrame = [detailsText_ frame];
177   subheaderFrame.origin.y =
178       NSMinY(headerFrame) - kCorrectedSubheaderTextTopPadding -
179       NSHeight(subheaderFrame);
180   [[self view] addSubview:detailsText_];
182   // Profile switcher is only needed for more than one profile.
183   NSRect dropDownButtonFrame = subheaderFrame;
184   if (groupCount > 1) {
185     dropDownButtonFrame = NSMakeRect(kCorrectedDropDownMargin,
186                                      kHorizontalMargin,
187                                      NSWidth(fullFrame),
188                                      NSHeight(fullFrame));
189     groupDropDownButton_.reset(
190         [[MCDropDown alloc] initWithFrame:dropDownButtonFrame pullsDown:YES]);
191     [groupDropDownButton_
192         setBackgroundColor:gfx::SkColorToCalibratedNSColor(
193                                message_center::kMessageCenterBackgroundColor)];
194     [groupDropDownButton_ setAction:@selector(notifierGroupSelectionChanged:)];
195     [groupDropDownButton_ setTarget:self];
196     // Add a dummy item for pull-down.
197     [groupDropDownButton_ addItemWithTitle:@""];
198     base::string16 title;
199     for (size_t i = 0; i < groupCount; ++i) {
200       const message_center::NotifierGroup& group =
201           provider_->GetNotifierGroupAt(i);
202       base::string16 item =
203           group.login_info.empty() ? group.name : group.login_info;
204       [groupDropDownButton_ addItemWithTitle:base::SysUTF16ToNSString(item)];
205       if (provider_->IsNotifierGroupActiveAt(i)) {
206         title = item;
207         [[groupDropDownButton_ lastItem] setState:NSOnState];
208       }
209     }
210     [groupDropDownButton_ setTitle:base::SysUTF16ToNSString(title)];
211     [groupDropDownButton_ sizeToFit];
212     dropDownButtonFrame = [groupDropDownButton_ frame];
213     dropDownButtonFrame.origin.y =
214         NSMinY(subheaderFrame) - kCorrectedDropDownTopPadding -
215         NSHeight(dropDownButtonFrame);
216     dropDownButtonFrame.size.width =
217         NSWidth(fullFrame) - 2 * kCorrectedDropDownMargin;
218     [[self view] addSubview:groupDropDownButton_];
219   }
221   // Document view for the notifier settings.
222   CGFloat y = 0;
223   NSRect documentFrame = NSMakeRect(0, 0, NSWidth(fullFrame), 0);
224   base::scoped_nsobject<NSView> documentView(
225       [[NSView alloc] initWithFrame:documentFrame]);
226   int notifierCount = notifiers_.size();
227   for (int i = notifierCount - 1; i >= 0; --i) {
228     message_center::Notifier* notifier = notifiers_[i];
229     // TODO(thakis): Use a custom button cell.
230     NSRect frame = NSMakeRect(kHorizontalMargin,
231                               y,
232                               NSWidth(documentFrame) - kHorizontalMargin * 2,
233                               kEntryHeight);
235     base::scoped_nsobject<MCSettingsEntryView> entryView(
236         [[MCSettingsEntryView alloc]
237             initWithController:self
238                       notifier:notifier
239                          frame:frame
240                   hasSeparator:(i != notifierCount - 1)]);
241     [documentView addSubview:entryView];
242     y += NSHeight(frame);
243   }
245   documentFrame.size.height = y - kIntrinsicDropDownVerticalPadding;
246   [documentView setFrame:documentFrame];
248   // Scroll view for the notifier settings.
249   NSRect scrollFrame = documentFrame;
250   scrollFrame.origin.y = 0;
251   CGFloat remainingHeight = NSMinY(dropDownButtonFrame) - NSMinY(scrollFrame);
253   if (NSHeight(documentFrame) < remainingHeight) {
254     // Everything fits without scrolling.
255     CGFloat delta = remainingHeight - NSHeight(documentFrame);
256     headerFrame.origin.y -= delta;
257     subheaderFrame.origin.y -= delta;
258     dropDownButtonFrame.origin.y -= delta;
259     fullFrame.size.height -= delta;
260   } else {
261     scrollFrame.size.height = remainingHeight;
262   }
264   scrollView_.reset([[NSScrollView alloc] initWithFrame:scrollFrame]);
265   [scrollView_ setAutohidesScrollers:YES];
266   [scrollView_ setAutoresizingMask:NSViewMinYMargin];
267   [scrollView_ setDocumentView:documentView];
268   [scrollView_ setDrawsBackground:NO];
269   [scrollView_ setHasHorizontalScroller:NO];
270   [scrollView_ setHasVerticalScroller:YES];
272   // Scroll to top.
273   NSPoint newScrollOrigin =
274       NSMakePoint(0.0,
275                   NSMaxY([[scrollView_ documentView] frame]) -
276                       NSHeight([[scrollView_ contentView] bounds]));
277   [[scrollView_ documentView] scrollPoint:newScrollOrigin];
279   // Set final sizes.
280   [[self view] setFrame:fullFrame];
281   [[self view] addSubview:scrollView_];
282   [settingsText_ setFrame:headerFrame];
283   [detailsText_ setFrame:subheaderFrame];
284   [groupDropDownButton_ setFrame:dropDownButtonFrame];
287 - (void)setSettingsNotifier:(message_center::Notifier*)notifier
288                     enabled:(BOOL)enabled {
289   provider_->SetNotifierEnabled(*notifier, enabled);
292 - (void)learnMoreClicked:(message_center::Notifier*)notifier {
293   provider_->OnNotifierAdvancedSettingsRequested(notifier->notifier_id, NULL);
296 // Testing API /////////////////////////////////////////////////////////////////
298 - (NSPopUpButton*)groupDropDownButton {
299   return groupDropDownButton_;
302 - (NSScrollView*)scrollView {
303   return scrollView_;
306 // Private API /////////////////////////////////////////////////////////////////
308 - (void)setIcon:(NSImage*)icon forNotifierIndex:(size_t)index {
309   MCSettingsEntryView* entry = [self entryForNotifierAtIndex:index];
310   [entry setNotifierIcon:icon];
313 - (void)setIcon:(NSImage*)icon
314     forNotifierId:(const message_center::NotifierId&)id {
315   for (size_t i = 0; i < notifiers_.size(); ++i) {
316     if (notifiers_[i]->notifier_id == id) {
317       [self setIcon:icon forNotifierIndex:i];
318       return;
319     }
320   }
323 - (MCSettingsEntryView*)entryForNotifierAtIndex:(size_t)index {
324   NSArray* subviews = [[scrollView_ documentView] subviews];
325   // The checkboxes are in bottom-top order, the checkbox for notifiers_[0] is
326   // last.
327   DCHECK_LT(notifiers_.size() - 1 - index, [subviews count]);
328   NSView* view = [subviews objectAtIndex:notifiers_.size() - 1 - index];
329   return base::mac::ObjCCastStrict<MCSettingsEntryView>(view);
332 - (void)notifierGroupSelectionChanged:(id)sender {
333   DCHECK_EQ(groupDropDownButton_.get(), sender);
334   NSPopUpButton* button = static_cast<NSPopUpButton*>(sender);
335   // The first item is a dummy item.
336   provider_->SwitchToNotifierGroup([button indexOfSelectedItem] - 1);
339 - (BOOL)notifierHasAdvancedSettings:(const message_center::NotifierId&)id {
340   return provider_->NotifierHasAdvancedSettings(id);
343 @end