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 }