/**
* Copyright 2011 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.toolbar.gadget;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.event.dom.client.KeyUpEvent;
import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.DockLayoutPanel;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.TextBox;
import org.waveprotocol.wave.client.wavepanel.impl.toolbar.gadget.GadgetInfoProvider.GadgetCategoryType;
import org.waveprotocol.wave.client.wavepanel.impl.toolbar.gadget.GadgetInfoProvider.GadgetInfo;
import org.waveprotocol.wave.client.widget.common.ImplPanel;
import org.waveprotocol.wave.client.widget.popup.CenterPopupPositioner;
import org.waveprotocol.wave.client.widget.popup.PopupChrome;
import org.waveprotocol.wave.client.widget.popup.PopupChromeFactory;
import org.waveprotocol.wave.client.widget.popup.PopupFactory;
import org.waveprotocol.wave.client.widget.popup.TitleBar;
import org.waveprotocol.wave.client.widget.popup.UniversalPopup;
import java.util.List;
/**
* Selector for gadgets, allowing selection from a list and entering a custom
* gadget URL.
*
* @author danilatos@google.com (Daniel Danilatos)
*/
public class GadgetSelectorWidget extends Composite implements
org.waveprotocol.wave.client.wavepanel.impl.toolbar.gadget.GadgetInfoProvider.Listener {
public interface Listener {
void onSelect(String url);
}
interface Binder extends UiBinder<ImplPanel, GadgetSelectorWidget> {
}
private static final Binder BINDER = GWT.create(Binder.class);
@UiField ImplPanel self;
@UiField DockLayoutPanel dockPanel;
@UiField TextBox gadgetUrl;
@UiField Button useCustom;
@UiField FlowPanel options;
@UiField TextBox gadgetFilter;
@UiField ListBox categoryDropBox;
private Listener listener;
private GadgetInfoProvider gadgetInfoProvider;
private GadgetInfoWidget selectedWidget = null;
private String categoryFilter = GadgetCategoryType.ALL.getType();
public GadgetSelectorWidget(GadgetInfoProvider provider) {
initWidget(self = BINDER.createAndBindUi(this));
gadgetInfoProvider = provider;
gadgetInfoProvider.setListener(this);
gadgetInfoProvider.startLoadingGadgetList();
}
public void setListener(Listener listener) {
this.listener = listener;
}
/**
* Shows in a popup, and returns the popup.
*/
public UniversalPopup showInPopup() {
PopupChrome chrome = PopupChromeFactory.createPopupChrome();
UniversalPopup popup = PopupFactory.createPopup(
null, new CenterPopupPositioner(), chrome, true);
TitleBar titleBar = popup.getTitleBar();
titleBar.setTitleText("Select Gadget");
popup.add(GadgetSelectorWidget.this);
popup.show();
setFocusAndHeight();
setupEventHandlers();
return popup;
}
private void setFocusAndHeight() {
Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand() {
@Override
public void execute() {
gadgetFilter.setFocus(true);
dockPanel
.setHeight((GadgetSelectorWidget.this.getParent()
.getElement().getOffsetHeight() - 20) + "px");
}
});
}
private void setupEventHandlers() {
// Handle live filtering of the inserted text.
// (TODO: need to do it in a KeyUpHandler since change handler does fire
// in response to character deletion, and the text is not changed until KeyUp)
gadgetFilter.addKeyUpHandler(new KeyUpHandler() {
public void onKeyUp(KeyUpEvent event) {
filter(gadgetFilter.getText());
}
});
// Handle enter key event to select the filtered gadget.
gadgetFilter.addKeyPressHandler(new KeyPressHandler() {
public void onKeyPress(KeyPressEvent event) {
filter(gadgetFilter.getText());
if (event.getNativeEvent().getKeyCode() == KeyCodes.KEY_ENTER && selectedWidget != null) {
select(selectedWidget.getGadgetUrl());
}
}
});
// Handle enter key on the url textbox to select the inserted gadget url.
gadgetUrl.addKeyPressHandler(new KeyPressHandler() {
public void onKeyPress(KeyPressEvent event) {
String gadgetUrlText = gadgetUrl.getText();
if (event.getNativeEvent().getKeyCode() == KeyCodes.KEY_ENTER && !gadgetUrlText.equals("")) {
select(gadgetUrlText);
}
}
});
// Handle category filtering events.
categoryDropBox.addChangeHandler(new ChangeHandler() {
@Override
public void onChange(ChangeEvent event) {
categoryFilter = categoryDropBox.getValue(categoryDropBox.getSelectedIndex());
filter(gadgetFilter.getText());
}
});
}
public void clear() {
options.clear();
}
public void addFeaturedOptions() {
// Add the full gadget list to this widget.
filter("");
// Add the categories to the category drop box.
for (GadgetCategoryType category : GadgetCategoryType.values()) {
categoryDropBox.addItem(category.getType());
}
}
/**
* Adds one gadget to the gadget list.
*
* @param gadgetInfo the gadget info to add to the list.
*/
private void addGadgetInfo(final GadgetInfo gadgetInfo) {
GadgetInfoWidget option = new GadgetInfoWidget();
option.setTitle(gadgetInfo.getName());
option.setImage(gadgetInfo.getImageUrl());
option.setDescription(gadgetInfo.getDescription());
option.setAuthor(gadgetInfo.getAuthor());
option.setGadgetUrl(gadgetInfo.getGadgetUrl());
option.setCategory1(gadgetInfo.getPrimaryCategory());
option.setCategory2(gadgetInfo.getSecondaryCategory());
option.setListener(new GadgetInfoWidget.Listener() {
@Override public void onSelect() {
select(gadgetInfo.getGadgetUrl());
}
@Override
public void onMouseOver(GadgetInfoWidget widget) {
if (selectedWidget != null) {
selectedWidget.unMark();
}
selectedWidget = widget;
widget.mark();
}
@Override
public void onMouseOut(GadgetInfoWidget widget) {
widget.unMark();
}
});
options.add(option);
}
public void filter(String filterText) {
if (selectedWidget != null) {
selectedWidget.unMark();
selectedWidget = null;
}
clear();
List<GadgetInfo> gadgetList =
gadgetInfoProvider.getGadgetInfoList(filterText, categoryFilter);
for (GadgetInfo g : gadgetList) {
addGadgetInfo(g);
}
// Mark the top filtered gadget as selected.
if (options.getWidgetCount() > 0 && !filterText.equals("")) {
GadgetInfoWidget widget = (GadgetInfoWidget)options.getWidget(0);
selectedWidget = widget;
selectedWidget.mark();
}
}
@UiHandler("useCustom")
void onClickCustom(ClickEvent event) {
select(gadgetUrl.getText());
}
private void select(String url) {
if (listener != null) {
listener.onSelect(url);
}
}
@Override
public void onUpdate() {
filter("");
}
}