1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
|
// Copyright (c) 2009 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/toolbar_controller.h"
#include "base/mac_util.h"
#include "base/sys_string_conversions.h"
#include "chrome/app/chrome_dll_resource.h"
#import "chrome/browser/cocoa/location_bar_view_mac.h"
#include "chrome/browser/cocoa/nsimage_cache.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/toolbar_model.h"
#include "chrome/common/notification_details.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_type.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/pref_service.h"
// Names of images in the bundle for the star icon (normal and 'starred').
static NSString* const kStarImageName = @"star_Template.pdf";
static NSString* const kStarredImageName = @"starred.pdf";
@implementation LocationBarFieldEditor
- (void)copy:(id)sender {
NSPasteboard* pb = [NSPasteboard generalPasteboard];
[self performCopy:pb];
}
- (void)cut:(id)sender {
NSPasteboard* pb = [NSPasteboard generalPasteboard];
[self performCut:pb];
}
- (void)performCopy:(NSPasteboard*)pb {
[pb declareTypes:[NSArray array] owner:nil];
[self writeSelectionToPasteboard:pb types:
[NSArray arrayWithObject:NSStringPboardType]];
}
- (void)performCut:(NSPasteboard*)pb {
[self performCopy:pb];
[self delete:nil];
}
@end
@interface ToolbarController(Private)
- (void)initCommandStatus:(CommandUpdater*)commands;
- (void)prefChanged:(std::wstring*)prefName;
@end
namespace ToolbarControllerInternal {
// A C++ class registered for changes in preferences. Bridges the
// notification back to the ToolbarController.
class PrefObserverBridge : public NotificationObserver {
public:
PrefObserverBridge(ToolbarController* controller)
: controller_(controller) { }
// Overridden from NotificationObserver:
virtual void Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
if (type == NotificationType::PREF_CHANGED)
[controller_ prefChanged:Details<std::wstring>(details).ptr()];
}
private:
ToolbarController* controller_; // weak, owns us
};
} // namespace
@implementation ToolbarController
- (id)initWithModel:(ToolbarModel*)model
commands:(CommandUpdater*)commands
profile:(Profile*)profile
webContentView:(NSView*)webContentView
bookmarkDelegate:(id<BookmarkURLOpener>)delegate {
DCHECK(model && commands && profile);
if ((self = [super initWithNibName:@"Toolbar"
bundle:mac_util::MainAppBundle()])) {
toolbarModel_ = model;
commands_ = commands;
profile_ = profile;
bookmarkBarDelegate_ = delegate;
webContentView_ = webContentView;
hasToolbar_ = YES;
// Register for notifications about state changes for the toolbar buttons
commandObserver_.reset(new CommandObserverBridge(self, commands));
commandObserver_->ObserveCommand(IDC_BACK);
commandObserver_->ObserveCommand(IDC_FORWARD);
commandObserver_->ObserveCommand(IDC_RELOAD);
commandObserver_->ObserveCommand(IDC_HOME);
commandObserver_->ObserveCommand(IDC_STAR);
}
return self;
}
- (void)dealloc {
// Make sure any code in the base class which assumes [self view] is
// the "parent" view continues to work.
hasToolbar_ = YES;
[super dealloc];
}
// Called after the view is done loading and the outlets have been hooked up.
// Now we can hook up bridges that rely on UI objects such as the location
// bar and button state.
- (void)awakeFromNib {
[self initCommandStatus:commands_];
locationBarView_.reset(new LocationBarViewMac(locationBar_, commands_,
toolbarModel_, profile_));
[locationBar_ setFont:[NSFont systemFontOfSize:[NSFont systemFontSize]]];
// Register pref observers for the optional home and page/options buttons
// and then add them to the toolbar them based on those prefs.
prefObserver_.reset(new ToolbarControllerInternal::PrefObserverBridge(self));
PrefService* prefs = profile_->GetPrefs();
showHomeButton_.Init(prefs::kShowHomeButton, prefs, prefObserver_.get());
showPageOptionButtons_.Init(prefs::kShowPageOptionsButtons, prefs,
prefObserver_.get());
[self showOptionalHomeButton];
[self showOptionalPageWrenchButtons];
// Create a sub-controller for the bookmark bar.
bookmarkBarController_.reset([[BookmarkBarController alloc]
initWithProfile:profile_
parentView:[self view]
webContentView:webContentView_
delegate:bookmarkBarDelegate_]);
// Add bookmark bar to the view hierarchy. This also triggers the
// nib load. The bookmark bar is defined (in the nib) to be
// bottom-aligned to it's parent view (among other things), so
// position and resize properties don't need to be set.
[[self view] addSubview:[bookmarkBarController_ view]];
}
- (LocationBar*)locationBar {
return locationBarView_.get();
}
- (void)focusLocationBar {
if (locationBarView_.get()) {
locationBarView_->FocusLocation();
}
}
// Called when the state for a command changes to |enabled|. Update the
// corresponding UI element.
- (void)enabledStateChangedForCommand:(NSInteger)command enabled:(BOOL)enabled {
NSButton* button = nil;
switch (command) {
case IDC_BACK:
button = backButton_;
break;
case IDC_FORWARD:
button = forwardButton_;
break;
case IDC_HOME:
button = homeButton_;
break;
case IDC_STAR:
button = starButton_;
break;
}
[button setEnabled:enabled];
}
// Init the enabled state of the buttons on the toolbar to match the state in
// the controller.
- (void)initCommandStatus:(CommandUpdater*)commands {
[backButton_ setEnabled:commands->IsCommandEnabled(IDC_BACK) ? YES : NO];
[forwardButton_
setEnabled:commands->IsCommandEnabled(IDC_FORWARD) ? YES : NO];
[reloadButton_ setEnabled:commands->IsCommandEnabled(IDC_RELOAD) ? YES : NO];
[homeButton_ setEnabled:commands->IsCommandEnabled(IDC_HOME) ? YES : NO];
[starButton_ setEnabled:commands->IsCommandEnabled(IDC_STAR) ? YES : NO];
}
- (void)updateToolbarWithContents:(TabContents*)tab
shouldRestoreState:(BOOL)shouldRestore {
locationBarView_->Update(tab, shouldRestore ? true : false);
}
- (void)setStarredState:(BOOL)isStarred {
NSString* starImageName = kStarImageName;
BOOL isTemplate = YES;
if (isStarred) {
starImageName = kStarredImageName;
isTemplate = NO;
}
NSImage* starImage = nsimage_cache::ImageNamed(starImageName);
if (isTemplate)
[starImage setTemplate:YES];
[starButton_ setImage:starImage];
}
- (void)setIsLoading:(BOOL)isLoading {
NSString* imageName = @"go_Template.pdf";
NSInteger tag = IDC_GO;
if (isLoading) {
imageName = @"stop_Template.pdf";
tag = IDC_STOP;
}
NSImage* stopStartImage = nsimage_cache::ImageNamed(imageName);
[stopStartImage setTemplate:YES];
[goButton_ setImage:stopStartImage];
[goButton_ setTag:tag];
}
- (void)setHasToolbar:(BOOL)toolbar {
[self view]; // force nib loading
hasToolbar_ = toolbar;
// App mode allows turning off the location bar as well.
// TODO(???): add more code here when implementing app mode to allow
// turning off both toolbar AND location bar.
// TODO(jrg): add mode code to make the location bar NOT editable
// when in a pop-up.
}
- (NSView*)view {
if (hasToolbar_)
return [super view];
return locationBar_;
}
- (BookmarkBarController*)bookmarkBarController {
// Browser has a FEATURE_BOOKMARKBAR but it is ignored by Safari
// when using window.open(); the logic seems to be "if no toolbar,
// no bookmark bar".
// TODO(jrg): investigate non-Mac Chrome behavior and possibly expand this.
if (hasToolbar_ == NO)
return nil;
return bookmarkBarController_.get();
}
- (id)customFieldEditorForObject:(id)obj {
if (obj == locationBar_) {
// Lazilly construct Field editor, Cocoa UI code always runs on the
// same thread, so there shoudn't be a race condition here.
if (locationBarFieldEditor_.get() == nil) {
locationBarFieldEditor_.reset([[LocationBarFieldEditor alloc] init]);
}
// This needs to be called every time, otherwise notifications
// aren't sent correctly.
DCHECK(locationBarFieldEditor_.get());
[locationBarFieldEditor_.get() setFieldEditor:YES];
return locationBarFieldEditor_.get();
}
return nil;
}
// Returns an array of views in the order of the outlets above.
- (NSArray*)toolbarViews {
return [NSArray arrayWithObjects:backButton_, forwardButton_, reloadButton_,
homeButton_, starButton_, goButton_, pageButton_, wrenchButton_,
locationBar_, nil];
}
// Moves |rect| to the right by |delta|, keeping the right side fixed by
// shrinking the width to compensate. Passing a negative value for |deltaX|
// moves to the left and increases the width.
- (NSRect)adjustRect:(NSRect)rect byAmount:(float)deltaX {
NSRect frame = NSOffsetRect(rect, deltaX, 0);
frame.size.width -= deltaX;
return frame;
}
// Computes the padding between the buttons that should have a separation from
// the positions in the nib. Since the forward and reload buttons are always
// visible, we use those buttons as the canonical spacing.
- (float)interButtonSpacing {
NSRect forwardFrame = [forwardButton_ frame];
NSRect reloadFrame = [reloadButton_ frame];
DCHECK(NSMinX(reloadFrame) > NSMaxX(forwardFrame));
return NSMinX(reloadFrame) - NSMaxX(forwardFrame);
}
// Show or hide the home button based on the pref.
- (void)showOptionalHomeButton {
BOOL hide = showHomeButton_.GetValue() ? NO : YES;
if (hide == [homeButton_ isHidden])
return; // Nothing to do, view state matches pref state.
// Always shift the star and text field by the width of the home button plus
// the appropriate gap width. If we're hiding the button, we have to
// reverse the direction of the movement (to the left).
float moveX = [self interButtonSpacing] + [homeButton_ frame].size.width;
if (hide)
moveX *= -1; // Reverse the direction of the move.
[starButton_ setFrame:NSOffsetRect([starButton_ frame], moveX, 0)];
[locationBar_ setFrame:[self adjustRect:[locationBar_ frame]
byAmount:moveX]];
[homeButton_ setHidden:hide];
}
// Show or hide the page and wrench buttons based on the pref.
- (void)showOptionalPageWrenchButtons {
DCHECK([pageButton_ isHidden] == [wrenchButton_ isHidden]);
BOOL hide = showPageOptionButtons_.GetValue() ? NO : YES;
if (hide == [pageButton_ isHidden])
return; // Nothing to do, view state matches pref state.
// Shift the go button and resize the text field by the width of the
// page/wrench buttons plus two times the gap width. If we're showing the
// buttons, we have to reverse the direction of movement (to the left). Unlike
// the home button above, we only ever have to resize the text field, we don't
// have to move it.
float moveX = 2 * [self interButtonSpacing] + NSWidth([pageButton_ frame]) +
NSWidth([wrenchButton_ frame]);
if (!hide)
moveX *= -1; // Reverse the direction of the move.
[goButton_ setFrame:NSOffsetRect([goButton_ frame], moveX, 0)];
NSRect locationFrame = [locationBar_ frame];
locationFrame.size.width += moveX;
[locationBar_ setFrame:locationFrame];
[pageButton_ setHidden:hide];
[wrenchButton_ setHidden:hide];
}
- (void)prefChanged:(std::wstring*)prefName {
if (!prefName) return;
if (*prefName == prefs::kShowHomeButton) {
[self showOptionalHomeButton];
} else if (*prefName == prefs::kShowPageOptionsButtons) {
[self showOptionalPageWrenchButtons];
}
}
- (IBAction)showPageMenu:(id)sender {
[NSMenu popUpContextMenu:pageMenu_
withEvent:[NSApp currentEvent]
forView:pageButton_];
}
- (IBAction)showWrenchMenu:(id)sender {
[NSMenu popUpContextMenu:wrenchMenu_
withEvent:[NSApp currentEvent]
forView:wrenchButton_];
}
@end
|