001 /**
002 * Copyright 2010 The Kuali Foundation Licensed under the
003 * Educational Community License, Version 2.0 (the "License"); you may
004 * not use this file except in compliance with the License. You may
005 * obtain a copy of the License at
006 *
007 * http://www.osedu.org/licenses/ECL-2.0
008 *
009 * Unless required by applicable law or agreed to in writing,
010 * software distributed under the License is distributed on an "AS IS"
011 * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
012 * or implied. See the License for the specific language governing
013 * permissions and limitations under the License.
014 */
015
016 package org.kuali.student.common.ui.client.widgets.focus;
017
018 import java.util.HashMap;
019 import java.util.Map;
020
021 import com.google.gwt.event.dom.client.BlurEvent;
022 import com.google.gwt.event.dom.client.BlurHandler;
023 import com.google.gwt.event.dom.client.FocusEvent;
024 import com.google.gwt.event.dom.client.FocusHandler;
025 import com.google.gwt.event.dom.client.HasBlurHandlers;
026 import com.google.gwt.event.dom.client.HasFocusHandlers;
027 import com.google.gwt.event.shared.GwtEvent;
028 import com.google.gwt.event.shared.HandlerManager;
029 import com.google.gwt.event.shared.HandlerRegistration;
030 import com.google.gwt.event.shared.HasHandlers;
031 import com.google.gwt.user.client.Command;
032 import com.google.gwt.user.client.DeferredCommand;
033 import com.google.gwt.user.client.ui.Widget;
034
035 public class FocusGroup implements HasBlurHandlers, HasFocusHandlers, HasHandlers {
036 private static class SyntheticBlurEvent extends BlurEvent {
037 public SyntheticBlurEvent() {
038 // do nothing
039 }
040 }
041
042 private static class SyntheticFocusEvent extends FocusEvent {
043 public SyntheticFocusEvent() {
044 // do nothing
045 }
046 }
047
048 private final HandlerManager handlers;
049 private final Map<Widget, Boolean> focusTrackers = new HashMap<Widget, Boolean>();
050 private boolean focusEventPending = false;
051 private boolean suppressed = false;
052
053 private boolean focused = false;
054
055 private final Command checkFocusState = new Command() {
056 @Override
057 public void execute() {
058 focusEventPending = false;
059 boolean nowFocused = false;
060 for (final Boolean b : focusTrackers.values()) {
061 if (b) {
062 nowFocused = true;
063 break;
064 }
065 }
066
067 if (!suppressed && (focused ^ nowFocused)) {
068 if (nowFocused) {
069 // we weren't focused, but now we are
070 // FocusEvent.fireNativeEvent(lastFocusEvent, FocusGroup.this);
071 handlers.fireEvent(new SyntheticFocusEvent());
072 } else {
073 // we were focused, now we aren't
074 // BlurEvent.fireNativeEvent(lastBlurEvent, FocusGroup.this);
075 handlers.fireEvent(new SyntheticBlurEvent());
076 }
077 }
078
079 focused = nowFocused;
080 }
081 };
082
083 public FocusGroup(final Widget parentWidget) {
084 this.handlers = new HandlerManager(parentWidget);
085 }
086
087 @Override
088 public HandlerRegistration addBlurHandler(final BlurHandler handler) {
089 return handlers.addHandler(BlurEvent.getType(), handler);
090 }
091
092 @Override
093 public HandlerRegistration addFocusHandler(final FocusHandler handler) {
094 return handlers.addHandler(FocusEvent.getType(), handler);
095 }
096
097 public void addWidget(final Widget w) {
098 if (w instanceof HasBlurHandlers) {
099 ((HasBlurHandlers) w).addBlurHandler(new BlurHandler() {
100 @Override
101 public void onBlur(final BlurEvent event) {
102 focusTrackers.put(w, false);
103 queueCheckFocusState();
104 }
105 });
106 }
107 if (w instanceof HasFocusHandlers) {
108 ((HasFocusHandlers) w).addFocusHandler(new FocusHandler() {
109 @Override
110 public void onFocus(final FocusEvent event) {
111 focusTrackers.put(w, true);
112 queueCheckFocusState();
113 }
114 });
115 }
116 }
117
118 @Override
119 public void fireEvent(final GwtEvent<?> event) {
120 handlers.fireEvent(event);
121 }
122
123 private void queueCheckFocusState() {
124 if (!focusEventPending) {
125 focusEventPending = true;
126 DeferredCommand.addCommand(checkFocusState);
127 }
128 }
129
130 public boolean isSuppressed() {
131 return suppressed;
132 }
133
134 public void setSuppressed(boolean suppressed) {
135 this.suppressed = suppressed;
136 }
137
138
139 }