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
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
|
// Copyright (c) 2012 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.
#ifndef UI_VIEWS_WINDOW_DIALOG_DELEGATE_H_
#define UI_VIEWS_WINDOW_DIALOG_DELEGATE_H_
#include <memory>
#include <utility>
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "base/strings/string16.h"
#include "base/time/time.h"
#include "ui/accessibility/ax_enums.mojom-forward.h"
#include "ui/base/ui_base_types.h"
#include "ui/views/views_export.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
namespace views {
class BubbleFrameView;
class DialogClientView;
class DialogObserver;
class LabelButton;
///////////////////////////////////////////////////////////////////////////////
//
// DialogDelegate
//
// DialogDelegate is an interface implemented by objects that wish to show a
// dialog box Window. The window that is displayed uses this interface to
// determine how it should be displayed and notify the delegate object of
// certain events.
//
///////////////////////////////////////////////////////////////////////////////
class VIEWS_EXPORT DialogDelegate : public WidgetDelegate {
public:
struct Params {
Params();
~Params();
base::Optional<int> default_button = base::nullopt;
bool round_corners = true;
bool draggable = false;
// Whether to use the Views-styled frame (if true) or a platform-native
// frame if false. In general, dialogs that look like fully separate windows
// should use the platform-native frame, and all other dialogs should use
// the Views-styled one.
bool custom_frame = true;
// A bitmask of buttons (from ui::DialogButton) that are present in this
// dialog.
int buttons = ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL;
// Text labels for the buttons on this dialog. Any button without a label
// here will get the default text for its type from GetDialogButtonLabel.
// Prefer to use this field (via SetButtonLabel) rather than override
// GetDialogButtonLabel - see https://crbug.com/1011446
base::string16 button_labels[ui::DIALOG_BUTTON_LAST + 1];
// A bitmask of buttons (from ui::DialogButton) that are enabled in this
// dialog. It's legal for a button to be marked enabled that isn't present
// in |buttons| (see above).
int enabled_buttons = ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL;
};
DialogDelegate();
~DialogDelegate() override;
// Creates a widget at a default location.
// There are two variant of this method. The newer one is the unique_ptr
// method, which simply takes ownership of the WidgetDelegate and passes it to
// the created Widget. When using the unique_ptr version, it is required that
// delegate->owned_by_widget(). Unless you have a good reason, you should use
// this variant.
//
// If !delegate->owned_by_widget() *or* if your WidgetDelegate subclass has a
// custom override of WidgetDelegate::DeleteDelegate, use the raw pointer
// variant instead, and please talk to one of the //ui/views owners about
// your use case.
static Widget* CreateDialogWidget(std::unique_ptr<WidgetDelegate> delegate,
gfx::NativeWindow context,
gfx::NativeView parent);
static Widget* CreateDialogWidget(WidgetDelegate* delegate,
gfx::NativeWindow context,
gfx::NativeView parent);
// Whether using custom dialog frame is supported for this dialog.
static bool CanSupportCustomFrame(gfx::NativeView parent);
// Returns the dialog widget InitParams for a given |context| or |parent|.
// If |bounds| is not empty, used to initially place the dialog, otherwise
// a default location is used.
static Widget::InitParams GetDialogWidgetInitParams(WidgetDelegate* delegate,
gfx::NativeWindow context,
gfx::NativeView parent,
const gfx::Rect& bounds);
// Called when the DialogDelegate and its frame have finished initializing but
// not been shown yet. Override this to perform customizations to the dialog
// that need to happen after the dialog's widget, border, buttons, and so on
// are ready.
//
// Overrides of this method should be quite rare - prefer to do dialog
// customization before the frame/widget/etc are ready if at all possible, via
// other setters on this class.
virtual void OnDialogInitialized() {}
// Returns a mask specifying which of the available DialogButtons are visible
// for the dialog.
// TODO(https://crbug.com/1011446): Rename this to buttons().
int GetDialogButtons() const { return params_.buttons; }
// Returns the default dialog button. This should not be a mask as only
// one button should ever be the default button. Return
// ui::DIALOG_BUTTON_NONE if there is no default. Default
// behavior is to return ui::DIALOG_BUTTON_OK or
// ui::DIALOG_BUTTON_CANCEL (in that order) if they are
// present, ui::DIALOG_BUTTON_NONE otherwise.
int GetDefaultDialogButton() const;
// Returns the label of the specified dialog button.
base::string16 GetDialogButtonLabel(ui::DialogButton button) const;
// Returns whether the specified dialog button is enabled.
virtual bool IsDialogButtonEnabled(ui::DialogButton button) const;
// For Dialog boxes, if there is a "Cancel" button or no dialog button at all,
// this is called when the user presses the "Cancel" button. This function
// should return true if the window can be closed after it returns, or false
// if it must remain open. By default, return true without doing anything.
// DEPRECATED: use |SetCancelCallback| instead.
virtual bool Cancel();
// For Dialog boxes, this is called when the user presses the "OK" button, or
// the Enter key. This function should return true if the window can be closed
// after it returns, or false if it must remain open. By default, return true
// without doing anything.
// DEPRECATED: use |SetAcceptCallback| instead.
virtual bool Accept();
// Overridden from WidgetDelegate:
View* GetInitiallyFocusedView() override;
DialogDelegate* AsDialogDelegate() override;
ClientView* CreateClientView(Widget* widget) override;
std::unique_ptr<NonClientFrameView> CreateNonClientFrameView(
Widget* widget) override;
static std::unique_ptr<NonClientFrameView> CreateDialogFrameView(
Widget* widget);
const gfx::Insets& margins() const { return margins_; }
void set_margins(const gfx::Insets& margins) { margins_ = margins; }
// Set a fixed width for the dialog. Used by DialogClientView.
void set_fixed_width(int fixed_width) { fixed_width_ = fixed_width; }
int fixed_width() const { return fixed_width_; }
template <typename T>
T* SetExtraView(std::unique_ptr<T> extra_view) {
T* view = extra_view.get();
extra_view_ = std::move(extra_view);
return view;
}
template <typename T>
T* SetFootnoteView(std::unique_ptr<T> footnote_view) {
T* view = footnote_view.get();
footnote_view_ = std::move(footnote_view);
return view;
}
// Returns the BubbleFrameView of this dialog delegate. A bubble frame view
// will only be created when use_custom_frame() is true.
BubbleFrameView* GetBubbleFrameView() const;
// Helpers for accessing parts of the DialogClientView without needing to know
// about DialogClientView. Do not call these before OnDialogInitialized.
views::LabelButton* GetOkButton() const;
views::LabelButton* GetCancelButton() const;
views::View* GetExtraView() const;
// Helper for accessing the footnote view. Unlike the three methods just
// above, this *is* safe to call before OnDialogInitialized.
views::View* GetFootnoteViewForTesting() const;
// Add or remove an observer notified by calls to DialogModelChanged().
void AddObserver(DialogObserver* observer);
void RemoveObserver(DialogObserver* observer);
// Notifies DialogDelegate that the result of one of the virtual getter
// functions above has changed, which causes it to rebuild its layout. It is
// not necessary to call this unless you are overriding
// IsDialogButtonEnabled() or manually manipulating the dialog buttons.
// TODO(https://crbug.com/1011446): Make this private.
void DialogModelChanged();
void set_use_round_corners(bool round) { params_.round_corners = round; }
void set_draggable(bool draggable) { params_.draggable = draggable; }
bool draggable() const { return params_.draggable; }
void set_use_custom_frame(bool use) { params_.custom_frame = use; }
bool use_custom_frame() const { return params_.custom_frame; }
// These methods internally call DialogModelChanged() if needed, so it is not
// necessary to call DialogModelChanged() yourself after calling them.
void SetDefaultButton(int button);
void SetButtons(int buttons);
void SetButtonLabel(ui::DialogButton button, base::string16 label);
void SetButtonEnabled(ui::DialogButton button, bool enabled);
// Called when the user presses the dialog's "OK" button or presses the dialog
// accept accelerator, if there is one.
void SetAcceptCallback(base::OnceClosure callback);
// Called when the user presses the dialog's "Cancel" button or presses the
// dialog close accelerator (which is always VKEY_ESCAPE).
void SetCancelCallback(base::OnceClosure callback);
// Called when:
// * The user presses the dialog's close button, if it has one
// * The dialog's widget is closed via Widget::Close()
// NOT called when the dialog's widget is closed via Widget::CloseNow() - in
// that case, the normal widget close path is skipped, so no orderly teardown
// of the dialog's widget happens. The main way that can happen in production
// use is if the dialog's parent widget is closed.
void SetCloseCallback(base::OnceClosure callback);
// Returns ownership of the extra view for this dialog, if one was provided
// via SetExtraView(). This is only for use by DialogClientView; don't call
// it.
// It would be good to instead have a DialogClientView::SetExtraView method
// that passes ownership into DialogClientView once. Unfortunately doing this
// broke a bunch of tests in a subtle way: the obvious place to call
// DCV::SetExtraView was from DD::OnWidgetInitialized. DCV::SetExtraView
// would then add the new view to DCV, which would invalidate its layout.
// However, many tests were doing essentially this:
//
// TestDialogDelegate delegate;
// ShowBubble(&delegate);
// TryToUseExtraView();
//
// and then trying to use the extra view's bounds, most commonly by
// synthesizing mouse clicks on it. At this point the extra view's layout is
// invalid *but* it has not yet been laid out, because View::InvalidateLayout
// schedules a deferred re-layout later. The design where DCV pulls the extra
// view from DD doesn't have this issue: during the initial construction of
// DCV, DCV fetches the extra view and slots it into its layout, and then the
// initial layout pass in Widget::Init causes the extra view to get laid out.
// Deferring inserting the extra view until after Widget::Init has finished is
// what causes the extra view to not be laid out (and hence the tests to
// fail).
//
// Potential future fixes:
// 1) The tests could manually force a re-layout here, or
// 2) The tests could be rewritten to not depend on the extra view's
// bounds, by not trying to deliver mouse events to it somehow, or
// 3) DCV::SetupLayout could always force an explicit Layout, ignoring the
// lazy layout system in View::InvalidateLayout
std::unique_ptr<View> DisownExtraView();
// Accept or cancel the dialog, as though the user had pressed the
// Accept/Cancel buttons. These methods:
// 1) Invoke the DialogDelegate's Cancel or Accept methods
// 2) Depending on their return value, close the dialog's widget.
// Neither of these methods can be called before the dialog has been
// initialized.
void AcceptDialog();
void CancelDialog();
// This method invokes the behavior that *would* happen if this dialog's
// containing widget were closed. It is present only as a compatibility shim
// for unit tests; do not add new calls to it.
// TODO(https://crbug.com/1011446): Delete this.
bool Close();
// Reset the dialog's shown timestamp, for tests that are subject to the
// "unintended interaction" detection mechanism.
void ResetViewShownTimeStampForTesting();
// Set the insets used for the dialog's button row. This should be used only
// rarely.
// TODO(ellyjones): Investigate getting rid of this entirely and having all
// dialogs use the same button row insets.
void SetButtonRowInsets(const gfx::Insets& insets);
// Callback for WidgetDelegate when the window this dialog is hosted in is
// closing. Don't call this yourself.
void WindowWillClose();
protected:
// Overridden from WidgetDelegate:
ax::mojom::Role GetAccessibleWindowRole() override;
const Params& GetParams() const { return params_; }
int GetCornerRadius() const;
// Return ownership of the footnote view for this dialog. Only use this in
// subclass overrides of CreateNonClientFrameView.
std::unique_ptr<View> DisownFootnoteView();
private:
// Overridden from WidgetDelegate. If you need to hook after widget
// initialization, use OnDialogInitialized above.
void OnWidgetInitialized() final;
// A helper for accessing the DialogClientView object contained by this
// delegate's Window.
const DialogClientView* GetDialogClientView() const;
DialogClientView* GetDialogClientView();
// Runs a close callback, ensuring that at most one close callback is ever
// run.
void RunCloseCallback(base::OnceClosure callback);
// The margins between the content and the inside of the border.
// TODO(crbug.com/733040): Most subclasses assume they must set their own
// margins explicitly, so we set them to 0 here for now to avoid doubled
// margins.
gfx::Insets margins_{0};
// Use a fixed dialog width for dialog. Used by DialogClientView.
int fixed_width_ = 0;
// The time the dialog is created.
base::TimeTicks creation_time_;
// Dialog parameters for this dialog.
Params params_;
// The extra view for this dialog, if there is one.
std::unique_ptr<View> extra_view_ = nullptr;
// The footnote view for this dialog, if there is one.
std::unique_ptr<View> footnote_view_ = nullptr;
// Observers for DialogModel changes.
base::ObserverList<DialogObserver>::Unchecked observer_list_;
// Callbacks for the dialog's actions:
base::OnceClosure accept_callback_;
base::OnceClosure cancel_callback_;
base::OnceClosure close_callback_;
// Whether any of the three callbacks just above has been delivered yet, *or*
// one of the Accept/Cancel methods have been called and returned true.
bool already_started_close_ = false;
DISALLOW_COPY_AND_ASSIGN(DialogDelegate);
};
// A DialogDelegate implementation that is-a View. Used to override GetWidget()
// to call View's GetWidget() for the common case where a DialogDelegate
// implementation is-a View. Note that DialogDelegateView is not owned by
// view's hierarchy and is expected to be deleted on DeleteDelegate call.
class VIEWS_EXPORT DialogDelegateView : public DialogDelegate, public View {
public:
DialogDelegateView();
~DialogDelegateView() override;
// DialogDelegate:
Widget* GetWidget() override;
const Widget* GetWidget() const override;
View* GetContentsView() override;
private:
DISALLOW_COPY_AND_ASSIGN(DialogDelegateView);
};
} // namespace views
#endif // UI_VIEWS_WINDOW_DIALOG_DELEGATE_H_
|