blob: d7e3399372ce7125f1926c76eddb847467c44568 (
plain)
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
|
// Copyright (c) 2011 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/ui/cocoa/toolbar/reload_button.h"
#include "chrome/app/chrome_command_ids.h"
#import "chrome/browser/ui/cocoa/view_id_util.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "grit/theme_resources_standard.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/l10n/l10n_util_mac.h"
namespace {
// Constant matches Windows.
NSTimeInterval kPendingReloadTimeout = 1.35;
} // namespace
@interface ReloadButton ()
- (void)invalidatePendingReloadTimer;
- (void)forceReloadState:(NSTimer *)timer;
@end
@implementation ReloadButton
+ (Class)cellClass {
return [ImageButtonCell class];
}
- (id)initWithFrame:(NSRect)frameRect {
if ((self = [super initWithFrame:frameRect])) {
// Since this is not a custom view, -awakeFromNib won't be called twice.
[self awakeFromNib];
}
return self;
}
- (void)viewWillMoveToWindow:(NSWindow *)newWindow {
// If this view is moved to a new window, reset its state.
[self setIsLoading:NO force:YES];
[super viewWillMoveToWindow:newWindow];
}
- (void)awakeFromNib {
// Don't allow multi-clicks, because the user probably wouldn't ever
// want to stop+reload or reload+stop.
[self setIgnoresMultiClick:YES];
}
- (void)invalidatePendingReloadTimer {
[pendingReloadTimer_ invalidate];
pendingReloadTimer_ = nil;
}
- (void)updateTag:(NSInteger)anInt {
if ([self tag] == anInt)
return;
// Forcibly remove any stale tooltip which is being displayed.
[self removeAllToolTips];
id cell = [self cell];
[self setTag:anInt];
if (anInt == IDC_RELOAD) {
[cell setImageID:IDR_RELOAD
forButtonState:image_button_cell::kDefaultState];
[cell setImageID:IDR_RELOAD_H
forButtonState:image_button_cell::kHoverState];
[cell setImageID:IDR_RELOAD_P
forButtonState:image_button_cell::kPressedState];
// The stop button has a disabled image but the reload button doesn't. To
// unset it we have to explicilty change the image ID to 0.
[cell setImageID:0
forButtonState:image_button_cell::kDisabledState];
[self setToolTip:l10n_util::GetNSStringWithFixup(IDS_TOOLTIP_RELOAD)];
} else if (anInt == IDC_STOP) {
[cell setImageID:IDR_STOP
forButtonState:image_button_cell::kDefaultState];
[cell setImageID:IDR_STOP_H
forButtonState:image_button_cell::kHoverState];
[cell setImageID:IDR_STOP_P
forButtonState:image_button_cell::kPressedState];
[cell setImageID:IDR_STOP_D
forButtonState:image_button_cell::kDisabledState];
[self setToolTip:l10n_util::GetNSStringWithFixup(IDS_TOOLTIP_STOP)];
} else {
NOTREACHED();
}
}
- (id)accessibilityAttributeValue:(NSString *)attribute {
if ([attribute isEqualToString:NSAccessibilityEnabledAttribute] &&
pendingReloadTimer_) {
return [NSNumber numberWithBool:NO];
} else {
return [super accessibilityAttributeValue:attribute];
}
}
- (void)setIsLoading:(BOOL)isLoading force:(BOOL)force {
// Can always transition to stop mode. Only transition to reload
// mode if forced or if the mouse isn't hovering. Otherwise, note
// that reload mode is desired and disable the button.
if (isLoading) {
[self invalidatePendingReloadTimer];
[self updateTag:IDC_STOP];
} else if (force) {
[self invalidatePendingReloadTimer];
[self updateTag:IDC_RELOAD];
} else if ([self tag] == IDC_STOP &&
!pendingReloadTimer_ &&
[[self cell] isMouseInside]) {
id cell = [self cell];
[cell setImageID:IDR_STOP_D
forButtonState:image_button_cell::kDefaultState];
[cell setImageID:IDR_STOP_D
forButtonState:image_button_cell::kDisabledState];
[cell setImageID:IDR_STOP_D
forButtonState:image_button_cell::kHoverState];
[cell setImageID:IDR_STOP_D
forButtonState:image_button_cell::kPressedState];
pendingReloadTimer_ =
[NSTimer timerWithTimeInterval:kPendingReloadTimeout
target:self
selector:@selector(forceReloadState:)
userInfo:nil
repeats:NO];
// Must add the timer to |NSRunLoopCommonModes| because
// it should run in |NSEventTrackingRunLoopMode| as well as
// |NSDefaultRunLoopMode|.
[[NSRunLoop currentRunLoop] addTimer:pendingReloadTimer_
forMode:NSRunLoopCommonModes];
} else {
[self invalidatePendingReloadTimer];
[self updateTag:IDC_RELOAD];
}
[self setEnabled:pendingReloadTimer_ == nil];
}
- (void)forceReloadState:(NSTimer *)timer {
DCHECK_EQ(timer, pendingReloadTimer_);
[self setIsLoading:NO force:YES];
// Verify that |pendingReloadTimer_| is nil so it is not left dangling.
DCHECK(!pendingReloadTimer_);
}
- (BOOL)sendAction:(SEL)theAction to:(id)theTarget {
if ([self tag] == IDC_STOP) {
if (pendingReloadTimer_) {
// If |pendingReloadTimer_| then the control is currently being
// drawn in a disabled state, so just return. The control is NOT actually
// disabled, otherwise mousetracking (courtesy of the NSButtonCell)
// would not work.
return YES;
} else {
// When the stop is processed, immediately change to reload mode,
// even though the IPC still has to bounce off the renderer and
// back before the regular |-setIsLoaded:force:| will be called.
// [This is how views and gtk do it.]
BOOL ret = [super sendAction:theAction to:theTarget];
if (ret)
[self forceReloadState:pendingReloadTimer_];
return ret;
}
}
return [super sendAction:theAction to:theTarget];
}
- (ViewID)viewID {
return VIEW_ID_RELOAD_BUTTON;
}
- (void)mouseInsideStateDidChange:(BOOL)isInside {
[pendingReloadTimer_ fire];
}
@end // ReloadButton
@implementation ReloadButton (Testing)
+ (void)setPendingReloadTimeout:(NSTimeInterval)seconds {
kPendingReloadTimeout = seconds;
}
@end
|