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    }