/** * Copyright 2010 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 org.waveprotocol.wave.client.wavepanel.impl; import com.google.common.base.Preconditions; import com.google.gwt.dom.client.Element; import org.waveprotocol.wave.client.common.util.KeyCombo; import org.waveprotocol.wave.client.common.util.LogicalPanel; import org.waveprotocol.wave.client.wavepanel.WavePanel; import org.waveprotocol.wave.client.wavepanel.event.EventDispatcherPanel; import org.waveprotocol.wave.client.wavepanel.event.EventHandlerRegistry; import org.waveprotocol.wave.client.wavepanel.event.Focusable; import org.waveprotocol.wave.client.wavepanel.event.KeySignalRouter; import org.waveprotocol.wave.client.wavepanel.view.TopConversationView; import org.waveprotocol.wave.client.wavepanel.view.dom.DomAsViewProvider; import org.waveprotocol.wave.model.util.CopyOnWriteSet; /** * A wave panel, which is just a view and an event system. * */ public final class WavePanelImpl implements WavePanel, Focusable { /** Event system on which features install their controllers. */ private final EventDispatcherPanel panel; /** Key handlers for key events that are routed to this panel. */ private final KeySignalRouter keys = new KeySignalRouter(); /** Views through which features manipulate the UI. */ private final DomAsViewProvider views; private final CopyOnWriteSet<LifecycleListener> listeners = CopyOnWriteSet.create(); // // Fields referencing the wave rendering are dynamically inserted and removed. // /** True between {@link #init} and {@link #reset}. */ private boolean initialized; /** Main conversation shown in this panel. */ private TopConversationView main; private WavePanelImpl( DomAsViewProvider views, EventDispatcherPanel panel) { this.views = views; this.panel = panel; } /** * Creates a wave panel. * * @param views view bundle * @param panelDom element in the DOM on which to build the wave panel * @param container panel to adopt the wave panel's widget, or {@code null} * for the wave panel to be a root widget */ public static WavePanelImpl create( DomAsViewProvider views, Element panelDom, LogicalPanel container) { Preconditions.checkArgument(panelDom != null); EventDispatcherPanel events = (container != null) ? EventDispatcherPanel.inGwtContext(panelDom, container) : EventDispatcherPanel.of(panelDom); WavePanelImpl panel = new WavePanelImpl(views, events); // Existing content? Element frameDom = panelDom.getFirstChildElement(); if (frameDom != null) { panel.init(frameDom); } return panel; } /** * Destroys this wave panel, releasing its resources. */ public void destroy() { panel.removeFromParent(); } @Override public DomAsViewProvider getViewProvider() { return views; } @Override public EventHandlerRegistry getHandlers() { return panel; } @Override public LogicalPanel getGwtPanel() { return panel; } @Override public KeySignalRouter getKeyRouter() { return keys; } @Override public boolean hasContents() { return main != null; } @Override public TopConversationView getContents() { Preconditions.checkState(main != null); return main; } // // Key plumbing. // @Override public boolean onKeySignal(KeyCombo key) { return keys.onKeySignal(key); } @Override public void onFocus() { } @Override public void onBlur() { } // // Lifecycle. // public void init(Element main) { Preconditions.checkState(!initialized); boolean fireEvent; // true if onInit should be fired before exiting. if (main != null) { panel.getElement().appendChild(main); this.main = views.asTopConversation(main); fireEvent = true; } else { // Render empty message. panel.getElement().setInnerHTML("No conversations in this wave."); fireEvent = false; } initialized = true; if (fireEvent) { fireOnInit(); } } public void reset() { Preconditions.checkState(initialized); boolean fireEvent; // true if onInit should be fired before exiting. initialized = false; if (main != null) { main.remove(); main = null; fireEvent = true; } else { panel.getElement().setInnerHTML(""); fireEvent = false; } if (fireEvent) { fireOnReset(); } } @Override public void addListener(LifecycleListener listener) { listeners.add(listener); } @Override public void removeListener(LifecycleListener listener) { listeners.remove(listener); } private void fireOnInit() { for (LifecycleListener listener : listeners) { listener.onInit(); } } private void fireOnReset() { for (LifecycleListener listener : listeners) { listener.onReset(); } } }