001 /*
002 * Copyright 2006 Mat Gessel <mat.gessel@gmail.com>
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005 * use this file except in compliance with the License. You may obtain a copy of
006 * the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013 * License for the specific language governing permissions and limitations under
014 * the License.
015 */
016 package asquare.gwt.tk.client.ui.behavior;
017
018 import java.util.List;
019 import java.util.Vector;
020
021 import com.google.gwt.user.client.DOM;
022 import com.google.gwt.user.client.Event;
023 import com.google.gwt.user.client.EventListener;
024 import com.google.gwt.user.client.ui.Widget;
025
026 /**
027 * A delegate class which manages controller bookkeeping and lifecycle.
028 * Ideally, this fuctionality would be in a superclass like
029 * {@link com.google.gwt.user.client.ui.Widget Widget}.
030 */
031 public class ControllerSupportDelegate
032 {
033 private final Widget m_widget;
034
035 private List m_controllers;
036 private int m_legacyEventBits = 0;
037 // private boolean m_processing = false;
038
039 /**
040 * Creates a delegate for the specified widget.
041 */
042 public ControllerSupportDelegate(Widget widget)
043 {
044 m_widget = widget;
045 m_legacyEventBits = DOM.getEventsSunk(widget.getElement());
046 }
047
048 /**
049 * Gets the event bits which were sunk on the widget itself. Used to
050 * determine which events should be passed to a widget's
051 * {@link EventListener#onBrowserEvent(Event) onBrowserEvent()} method. This
052 * can happen when subclassing or wrapping a widget.
053 *
054 * @return a bitmask of the event types
055 * @see Event
056 */
057 public int getLegacyEventBits()
058 {
059 return m_legacyEventBits;
060 }
061
062 private void sinkAllBits()
063 {
064 int controllerEventBits = 0;
065 if (m_controllers != null)
066 {
067 for (int i = 0, size = m_controllers.size(); i < size; i++)
068 {
069 controllerEventBits |= ((Controller) m_controllers.get(i)).getEventBits();
070 }
071 }
072 DOM.sinkEvents(m_widget.getElement(), m_legacyEventBits | controllerEventBits);
073 }
074
075 public void sinkEvents(int eventBits)
076 {
077 m_legacyEventBits |= eventBits;
078 DOM.sinkEvents(m_widget.getElement(),
079 DOM.getEventsSunk(m_widget.getElement()) | m_legacyEventBits);
080 }
081
082 public void unsinkEvents(int eventBits)
083 {
084 m_legacyEventBits &= ~eventBits;
085 sinkAllBits();
086 }
087
088 public Controller getController(Class id)
089 {
090 for (int i = 0, size = m_controllers.size(); i < size; i++)
091 {
092 if (((Controller) m_controllers.get(i)).getId() == id)
093 {
094 return (Controller) m_controllers.get(i);
095 }
096 }
097 return null;
098 }
099
100 /**
101 * @throws IllegalArgumentException if <code>controller</code> is null
102 */
103 public Widget addController(Controller controller)
104 {
105 if (controller == null)
106 throw new IllegalArgumentException();
107
108 if (m_controllers == null)
109 {
110 m_controllers = new Vector();
111 }
112 m_controllers.add(controller);
113 DOM.sinkEvents(m_widget.getElement(),
114 DOM.getEventsSunk(m_widget.getElement()) | controller.getEventBits()); // adding bits is easy
115 if (m_widget.isAttached())
116 {
117 controller.plugIn(m_widget);
118 }
119 return m_widget;
120 }
121
122 /**
123 * @throws IllegalArgumentException if <code>controller</code> is not present
124 */
125 public Widget removeController(Controller controller)
126 {
127 int index = -1;
128 if (m_controllers != null)
129 {
130 index = m_controllers.indexOf(controller);
131 }
132
133 if (index == -1)
134 throw new IllegalArgumentException();
135
136 m_controllers.remove(index);
137 if (m_widget.isAttached())
138 {
139 controller.unplug(m_widget);
140 }
141 sinkAllBits();
142 return m_widget;
143 }
144
145 public void setControllers(List controllers)
146 {
147 if (m_widget.isAttached())
148 {
149 unplugControllers();
150 }
151
152 m_controllers = null;
153
154 if (controllers != null)
155 {
156 m_controllers = new Vector();
157 for (int i = 0, size = controllers.size(); i < size; i++)
158 {
159 m_controllers.add((Controller) controllers.get(i));
160 }
161 }
162
163 if (m_widget.isAttached())
164 {
165 plugInControllers();
166 }
167
168 sinkAllBits();
169 }
170
171 private void plugInControllers()
172 {
173 if (m_controllers != null)
174 {
175 for (int i = 0, size = m_controllers.size(); i < size; i++)
176 {
177 ((Controller) m_controllers.get(i)).plugIn(m_widget);
178 }
179 }
180 }
181
182 private void unplugControllers()
183 {
184 if (m_controllers != null)
185 {
186 for (int i = m_controllers.size() - 1; i >= 0; i--)
187 {
188 ((Controller) m_controllers.get(i)).unplug(m_widget);
189 }
190 }
191 }
192
193 public void onAttach()
194 {
195 plugInControllers();
196 }
197
198 // /**
199 // * @throws IllegalStateException if the widget is detached while controllers
200 // * are processing an event. To prevent this from happening, use
201 // * {@link com.google.gwt.user.client.DeferredCommand DeferredCommand}
202 // * to remove the widget.
203 // */
204 public void onDetach()
205 {
206 // if (m_processing)
207 // throw new IllegalStateException("Detach called while calling onBrowserEvent(Event event)");
208 //
209 unplugControllers();
210 }
211
212 public void onBrowserEvent(Event event)
213 {
214 if (m_controllers != null)
215 {
216 // m_processing = true;
217 for (int i = 0, size = m_controllers.size(); i < size; i++)
218 {
219 Controller controller = (Controller) m_controllers.get(i);
220 if ((controller.getEventBits() & DOM.eventGetType(event)) != 0)
221 {
222 controller.onBrowserEvent(m_widget, event);
223 }
224 }
225 // m_processing = false;
226 }
227 }
228 }