My favorites | Sign in
Project Home Downloads Wiki Issues Source
Checkout   Browse   Changes    
 
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
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
/*
* Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.gwt.user.client.ui;

import com.google.gwt.dom.client.Element;
import com.google.gwt.event.dom.client.DomEvent;
import com.google.gwt.event.shared.EventHandler;
import com.google.gwt.event.shared.GwtEvent;
import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.event.shared.HasHandlers;
import com.google.gwt.event.shared.GwtEvent.Type;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.EventListener;

/**
* The base class for the majority of user-interface objects. Widget adds
* support for receiving events from the browser and being added directly to
* {@link com.google.gwt.user.client.ui.Panel panels}.
*/
public class Widget extends UIObject implements EventListener, HasHandlers {

/**
* A bit-map of the events that should be sunk when the widget is attached to
* the DOM. (We delay the sinking of events to improve startup performance.)
* When the widget is attached, this is set to -1
* <p>
* Package protected to allow Composite to see it.
*/
int eventsToSink;
private boolean attached;
private Object layoutData;
private Widget parent;
private HandlerManager handlerManager;

public void fireEvent(GwtEvent<?> event) {
if (handlerManager != null) {
handlerManager.fireEvent(event);
}
}

/**
* Gets the panel-defined layout data associated with this widget.
*
* @return the widget's layout data
* @see #setLayoutData
*/
public Object getLayoutData() {
return layoutData;
}

/**
* Gets this widget's parent panel.
*
* @return the widget's parent panel
*/
public Widget getParent() {
return parent;
}

/**
* Determines whether this widget is currently attached to the browser's
* document (i.e., there is an unbroken chain of widgets between this widget
* and the underlying browser document).
*
* @return <code>true</code> if the widget is attached
*/
public boolean isAttached() {
return attached;
}

public void onBrowserEvent(Event event) {
switch (DOM.eventGetType(event)) {
case Event.ONMOUSEOVER:
// Only fire the mouse over event if it's coming from outside this
// widget.
case Event.ONMOUSEOUT:
// Only fire the mouse out event if it's leaving this
// widget.
Element related = event.getRelatedTarget();
if (related != null && getElement().isOrHasChild(related)) {
return;
}
break;
}
DomEvent.fireNativeEvent(event, this, this.getElement());
}

/**
* Removes this widget from its parent widget, if one exists.
*
* <p>
* If it has no parent, this method does nothing. If it is a "root" widget
* (meaning it's been added to the detach list via
* {@link RootPanel#detachOnWindowClose(Widget)}), it will be removed from the
* detached immediately. This makes it possible for Composites and Panels to
* adopt root widgets.
* </p>
*
* @throws IllegalStateException if this widget's parent does not support
* removal (e.g. {@link Composite})
*/
public void removeFromParent() {
if (parent == null) {
// If the widget had no parent, check to see if it was in the detach list
// and remove it if necessary.
if (RootPanel.isInDetachList(this)) {
RootPanel.detachNow(this);
}
} else if (parent instanceof HasWidgets) {
((HasWidgets) parent).remove(this);
} else if (parent != null) {
throw new IllegalStateException(
"This widget's parent does not implement HasWidgets");
}
}

/**
* Sets the panel-defined layout data associated with this widget. Only the
* panel that currently contains a widget should ever set this value. It
* serves as a place to store layout bookkeeping data associated with a
* widget.
*
* @param layoutData the widget's layout data
*/
public void setLayoutData(Object layoutData) {
this.layoutData = layoutData;
}

/**
* Overridden to defer the call to super.sinkEvents until the first time this
* widget is attached to the dom, as a performance enhancement. Subclasses
* wishing to customize sinkEvents can preserve this deferred sink behavior by
* putting their implementation behind a check of
* <code>isOrWasAttached()</code>:
*
* <pre>
* {@literal @}Override
* public void sinkEvents(int eventBitsToAdd) {
* if (isOrWasAttached()) {
* /{@literal *} customized sink code goes here {@literal *}/
* } else {
* super.sinkEvents(eventBitsToAdd);
* }
*} </pre>
*/
@Override
public void sinkEvents(int eventBitsToAdd) {
if (isOrWasAttached()) {
super.sinkEvents(eventBitsToAdd);
} else {
eventsToSink |= eventBitsToAdd;
}
}

/**
* Adds a native event handler to the widget and sinks the corresponding
* native event. If you do not want to sink the native event, use the generic
* addHandler method instead.
*
* @param <H> the type of handler to add
* @param type the event key
* @param handler the handler
* @return {@link HandlerRegistration} used to remove the handler
*/
protected final <H extends EventHandler> HandlerRegistration addDomHandler(
final H handler, DomEvent.Type<H> type) {
assert handler != null : "handler must not be null";
assert type != null : "type must not be null";
sinkEvents(Event.getTypeInt(type.getName()));
return ensureHandlers().addHandler(type, handler);
}

/**
* Adds this handler to the widget.
*
* @param <H> the type of handler to add
* @param type the event type
* @param handler the handler
* @return {@link HandlerRegistration} used to remove the handler
*/
protected final <H extends EventHandler> HandlerRegistration addHandler(
final H handler, GwtEvent.Type<H> type) {
return ensureHandlers().addHandler(type, handler);
}

/**
* Fires an event on a child widget. Used to delegate the handling of an event
* from one widget to another.
*
* @param event the event
* @param target fire the event on the given target
*/
protected void delegateEvent(Widget target, GwtEvent<?> event) {
target.fireEvent(event);
}

/**
* If a widget contains one or more child widgets that are not in the logical
* widget hierarchy (the child is physically connected only on the DOM level),
* it must override this method and call {@link #onAttach()} for each of its
* child widgets.
*
* @see #onAttach()
*/
protected void doAttachChildren() {
}

/**
* If a widget contains one or more child widgets that are not in the logical
* widget hierarchy (the child is physically connected only on the DOM level),
* it must override this method and call {@link #onDetach()} for each of its
* child widgets.
*
* @see #onDetach()
*/
protected void doDetachChildren() {
}

/**
* Gets the number of handlers listening to the event type.
*
* @param type the event type
* @return the number of registered handlers
*/
protected int getHandlerCount(Type<?> type) {
return handlerManager == null ? 0 : handlerManager.getHandlerCount(type);
}

/**
* Has this widget ever been attached?
*
* @return true if this widget ever been attached to the DOM, false otherwise
*/
protected final boolean isOrWasAttached() {
return eventsToSink == -1;
}

/**
* <p>
* This method is called when a widget is attached to the browser's document.
* To receive notification after a Widget has been added to the document,
* override the {@link #onLoad} method.
* </p>
* <p>
* It is strongly recommended that you override {@link #onLoad()} or
* {@link #doAttachChildren()} instead of this method to avoid
* inconsistencies between logical and physical attachment states.
* </p>
* <p>
* Subclasses that override this method must call
* <code>super.onAttach()</code> to ensure that the Widget has been attached
* to its underlying Element.
* </p>
*
* @throws IllegalStateException if this widget is already attached
* @see #onLoad()
* @see #doAttachChildren()
*/
protected void onAttach() {
if (isAttached()) {
throw new IllegalStateException(
"Should only call onAttach when the widget is detached from the browser's document");
}

attached = true;

// Event hookup code
DOM.setEventListener(getElement(), this);
int bitsToAdd = eventsToSink;
eventsToSink = -1;
if (bitsToAdd > 0) {
sinkEvents(bitsToAdd);
}
doAttachChildren();

// onLoad() gets called only *after* all of the children are attached and
// the attached flag is set. This allows widgets to be notified when they
// are fully attached, and panels when all of their children are attached.
onLoad();
}

/**
* <p>
* This method is called when a widget is detached from the browser's
* document. To receive notification before a Widget is removed from the
* document, override the {@link #onUnload} method.
* </p>
* <p>
* It is strongly recommended that you override {@link #onUnload()} or
* {@link #doDetachChildren()} instead of this method to avoid
* inconsistencies between logical and physical attachment states.
* </p>
* <p>
* Subclasses that override this method must call
* <code>super.onDetach()</code> to ensure that the Widget has been detached
* from the underlying Element. Failure to do so will result in application
* memory leaks due to circular references between DOM Elements and JavaScript
* objects.
* </p>
*
* @throws IllegalStateException if this widget is already detached
* @see #onUnload()
* @see #doDetachChildren()
*/
protected void onDetach() {
if (!isAttached()) {
throw new IllegalStateException(
"Should only call onDetach when the widget is attached to the browser's document");
}

try {
// onUnload() gets called *before* everything else (the opposite of
// onLoad()).
onUnload();
} finally {
// Put this in a finally, just in case onUnload throws an exception.
try {
doDetachChildren();
} finally {
// Put this in a finally, in case doDetachChildren throws an exception.
DOM.setEventListener(getElement(), null);
attached = false;
}
}
}

/**
* This method is called immediately after a widget becomes attached to the
* browser's document.
*/
protected void onLoad() {
}

/**
* This method is called immediately before a widget will be detached from the
* browser's document.
*/
protected void onUnload() {
}

/**
* Ensures the existence of the handler manager.
*
* @return the handler manager
* */
HandlerManager ensureHandlers() {
return handlerManager == null ? handlerManager = new HandlerManager(this)
: handlerManager;
}

HandlerManager getHandlerManager() {
return handlerManager;
}

@Override
void replaceElement(com.google.gwt.dom.client.Element elem) {
if (isAttached()) {
// Remove old event listener to avoid leaking. onDetach will not do this
// for us, because it is only called when the widget itself is detached
// from the document.
DOM.setEventListener(getElement(), null);
}

super.replaceElement(elem);

if (isAttached()) {
// Hook the event listener back up on the new element. onAttach will not
// do this for us, because it is only called when the widget itself is
// attached to the document.
DOM.setEventListener(getElement(), this);
}
}

/**
* Sets this widget's parent. This method should only be called by
* {@link Panel} and {@link Composite}.
*
* @param parent the widget's new parent
* @throws IllegalStateException if <code>parent</code> is non-null and the
* widget already has a parent
*/
void setParent(Widget parent) {
Widget oldParent = this.parent;
if (parent == null) {
try {
if (oldParent != null && oldParent.isAttached()) {
onDetach();
assert !isAttached() : "Failure of " + this.getClass().getName()
+ " to call super.onDetach()";
}
} finally {
// Put this in a finally in case onDetach throws an exception.
this.parent = null;
}
} else {
if (oldParent != null) {
throw new IllegalStateException(
"Cannot set a new parent without first clearing the old parent");
}
this.parent = parent;
if (parent.isAttached()) {
onAttach();
assert isAttached() : "Failure of " + this.getClass().getName()
+ " to call super.onAttach()";
}
}
}
}

Change log

r7335 by sco...@google.com on Dec 18, 2009   Diff
Tagging 2.0.0.
Go to: 
Project members, sign in to write a code review

Older revisions

r6420 by rj...@google.com on Oct 19, 2009   Diff
Creates the 2.0 release branch for MS2
and beyond as a
straight copy of trunk@6417.

svn cp -r 6417 https://google-web-
...
r6197 by jlaba...@google.com on Sep 23, 2009   Diff
Wraps all calls that affect phsyical
and logical attach state to ensure
that the physical and logical state of
children match the state of their
parents. Essentially, this patch
...
r5877 by j...@google.com on Aug 4, 2009   Diff
Initial implementation of layout
system, along with the first two
layout widgets.
Review: http://gwt-code-
reviews.appspot.com/51830
...
All revisions of this file

File info

Size: 13532 bytes, 423 lines

File properties

svn:mime-type
text/x-java
svn:eol-style
native
Powered by Google Project Hosting