/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.wavepanel.impl.toolbar.gadget.i18n.GadgetCategoryMessages;
import org.waveprotocol.wave.client.wavepanel.impl.toolbar.gadget.i18n.GadgetSelectorMessages;
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);
private static final GadgetCategoryMessages categoryMessages = GWT.create(GadgetCategoryMessages.class);
private static final GadgetSelectorMessages messages = GWT.create(GadgetSelectorMessages.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(messages.selectGadget());
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(getCategoryName(category), category.getType());
}
}
private String getCategoryName(GadgetCategoryType category) {
switch (category) {
case ALL: return categoryMessages.all();
case GAME: return categoryMessages.game();
case IMAGE: return categoryMessages.image();
case MAP: return categoryMessages.map();
case MUSIC: return categoryMessages.music();
case OTHER: return categoryMessages.other();
case PRODUCTIVITY: return categoryMessages.productivity();
case SEARCH: return categoryMessages.search();
case TEAM: return categoryMessages.team();
case TIME: return categoryMessages.time();
case TRAVEL: return categoryMessages.travel();
case UTILITY: return categoryMessages.utility();
case VIDEO: return categoryMessages.video();
case VOICE: return categoryMessages.voice();
case VOTING: return categoryMessages.voting();
default: return 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("");
}
}