pickitem-widget/src/main/java/org/gcube/portlets/widgets/pickitem/client/dialog/PickItemsDialog.java

239 lines
7.5 KiB
Java

package org.gcube.portlets.widgets.pickitem.client.dialog;
import java.util.ArrayList;
import org.gcube.portlets.widgets.pickitem.client.bundle.CssAndImages;
import org.gcube.portlets.widgets.pickitem.client.events.PickedUserEvent;
import org.gcube.portlets.widgets.pickitem.client.uibinder.SelectableItem;
import org.gcube.portlets.widgets.pickitem.client.uibinder.WithPhotoTemplate;
import org.gcube.portlets.widgets.pickitem.shared.ItemBean;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.MouseDownEvent;
import com.google.gwt.event.dom.client.MouseDownHandler;
import com.google.gwt.event.dom.client.MouseOutEvent;
import com.google.gwt.event.dom.client.MouseOutHandler;
import com.google.gwt.event.dom.client.MouseOverEvent;
import com.google.gwt.event.dom.client.MouseOverHandler;
import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.user.client.ui.FocusPanel;
import com.google.gwt.user.client.ui.MultiWordSuggestOracle;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.SuggestOracle.Callback;
import com.google.gwt.user.client.ui.SuggestOracle.Request;
import com.google.gwt.user.client.ui.SuggestOracle.Response;
import com.google.gwt.user.client.ui.SuggestOracle.Suggestion;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
/**
*
* @author Massimiliano Assante, ISTI-CNR
* Use this widget to display a a dropdown user list you can attach to a textbox to make select portal users typing @
*
* To get to know which user was selected listen for the {@link PickedUserEvent} on the {@link HandlerManager} instance you pass to this widget.
*
*/
public class PickItemsDialog extends PopupPanel {
public final static int ARROW_UP = 38;
public final static int ARROW_DOWN = 40;
public final static int DELETE = KeyCodes.KEY_DELETE;
public final static int ENTER = KeyCodes.KEY_ENTER;
public final static int ESCAPE = KeyCodes.KEY_ESCAPE;
public final static int TAB = KeyCodes.KEY_TAB;
private HandlerManager eventBus;
private int limit = 10;
private final MultiWordSuggestOracle oracle = new MultiWordSuggestOracle();
private int displayIndexSelected;
private FocusPanel focusPanel = new FocusPanel();
private VerticalPanel mainPanel = new VerticalPanel();
private String triggerChar;
private ArrayList<ItemBean> users;
//needed because is selected when it popups
private Widget first;
static {
CssAndImages.INSTANCE.css().ensureInjected();
}
/**
* @param triggerChar the 'single char' used to trigger the items list show, e.g. '@', '#' ....
* @param the list of user to pick
* @param eventBus the event bus on where the widget will fire the selected user event
* @param widthInPixel the desired width (grater than 199 pixel)
*/
public PickItemsDialog(char triggerChar, ArrayList<ItemBean> users, final HandlerManager eventBus, int widthInPixel) {
super(true, false);
if (widthInPixel < 200) {
throw new IllegalArgumentException("width must be greater than 199");
}
this.eventBus = eventBus;
this.triggerChar = ""+triggerChar;
this.users = users;
focusPanel.setWidth(widthInPixel+"px");
mainPanel.setWidth(widthInPixel+"px");
setWidth(widthInPixel+"px");
focusPanel.add(mainPanel);
setWidget(focusPanel);
setStyleName("pickDialog");
//add the user fill names to the oracle
for (ItemBean user : users) {
oracle.add(user.getAlternativeName());
}
//remove the first selected when hovering
focusPanel.addMouseOverHandler(new MouseOverHandler() {
@Override
public void onMouseOver(MouseOverEvent event) {
if (first != null)
first.removeStyleName("pickperson-selected");
}
});
focusPanel.addMouseOutHandler(new MouseOutHandler() {
@Override
public void onMouseOut(MouseOutEvent event) {
select(displayIndexSelected);
}
});
focusPanel.addMouseDownHandler(new MouseDownHandler() {
@Override
public void onMouseDown(MouseDownEvent event) {
SelectableItem ut = (SelectableItem) mainPanel.getWidget(displayIndexSelected);
eventBus.fireEvent(new PickedUserEvent(new ItemBean("id", "username", ut.getItemName(), "thumb")));
hide();
select(0); //RESET
}
});
}
/**
* called for each keyUp event from the user
* @param keyCode the event keycode
* @param x
* @param y
* @param currText
*/
public void onKeyUp(int keyCode, int x, int y, String currText) {
if (currText.endsWith(triggerChar)) { //the only way i found to intercept @
setPopupPosition(x, y);
hide();
} else if (currText.contains(triggerChar)) {
if (pickingUser(currText)) {
handleNonCharKeys(keyCode);
}
} else if (!currText.contains(triggerChar))
hide();
}
/**
* split the text and keeps listening for user keyboard events
* @param currText the text being typed
*/
private boolean pickingUser(String currText) {
String[] toSplit = currText.split(triggerChar); //get the interesting part
if (toSplit[1].trim().length() > 0) {
showSuggestions(toSplit[1]);
return true;
}
hide();
return false;
}
/**
* handles the nonchar events (arrows, esc, enter etc)
* @param event
*/
private void handleNonCharKeys(int keyCode) {
switch (keyCode) {
case ARROW_UP:
if (displayIndexSelected > 0)
select(--displayIndexSelected);
break;
case ARROW_DOWN:
case TAB:
if (displayIndexSelected+1 < mainPanel.getWidgetCount())
select(displayIndexSelected+1);
break;
case ESCAPE:
case DELETE:
hide();
case ENTER: //selectd with keyboard
SelectableItem ut = null;
if (mainPanel.getWidgetCount() > 0) {
if (displayIndexSelected < 0 || displayIndexSelected >= mainPanel.getWidgetCount()) //when there's only one left sometimes here i get -sth, no time to see why :)
ut = (SelectableItem) mainPanel.getWidget(0);
else
ut = (SelectableItem) mainPanel.getWidget(displayIndexSelected);
eventBus.fireEvent(new PickedUserEvent(new ItemBean("id", "username", ut.getItemName(), "thumb")));
hide();
select(0); //RESET
}
break;
default:
break;
}
}
public void showSuggestions(String query) {
if (query.length() > 0) {
oracle.requestSuggestions(new Request(query, limit), new Callback() {
public void onSuggestionsReady(Request request, Response response) {
mainPanel.clear();
int i = 0;
for (Suggestion s : response.getSuggestions()) {
if (i == 0) {
first = getUserTemplate(getUserModelBySuggestion(s), i);
first.addStyleName("pickperson-selected");
mainPanel.add(first);
}
else
mainPanel.add(getUserTemplate(getUserModelBySuggestion(s), i));
i++;
}
if (i > 0) {
show();
}
}
});
}
}
private ItemBean getUserModelBySuggestion(Suggestion suggestion) {
for (ItemBean user : users) {
if (suggestion.getReplacementString().compareTo(user.getAlternativeName()) ==0)
return user;
}
return new ItemBean("no-match","no-match","no-match","no-match");
}
private WithPhotoTemplate getUserTemplate(ItemBean user, int displayIndex) {
return new WithPhotoTemplate(this, user, displayIndex);
}
/**
* select the user in the model and in the view
* @param displayIndex
*/
public void select(int displayIndex) {
for (int i = 0; i < mainPanel.getWidgetCount(); i++) {
Widget ut = (Widget) mainPanel.getWidget(i);
if (i == displayIndex) {
ut.addStyleName("pickperson-selected");
displayIndexSelected = i;
}
else
ut.removeStyleName("pickperson-selected");
}
}
}