2014-10-02 13:01:18 +02:00
package org.gcube.portlets.widgets.pickitem.client.dialog ;
import java.util.ArrayList ;
2018-06-08 17:59:28 +02:00
import java.util.List ;
2014-10-02 13:01:18 +02:00
import org.gcube.portlets.widgets.pickitem.client.bundle.CssAndImages ;
2014-10-02 13:06:40 +02:00
import org.gcube.portlets.widgets.pickitem.client.events.PickedItemEvent ;
2016-06-30 14:47:00 +02:00
import org.gcube.portlets.widgets.pickitem.client.events.PickedItemEventHandler ;
2018-06-08 17:59:28 +02:00
import org.gcube.portlets.widgets.pickitem.client.oracle.UserOracle ;
import org.gcube.portlets.widgets.pickitem.client.oracle.UserSuggestion ;
2014-10-02 15:07:19 +02:00
import org.gcube.portlets.widgets.pickitem.client.uibinder.NoPhotoTemplate ;
2014-10-02 13:01:18 +02:00
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 ;
2015-07-14 19:21:21 +02:00
import com.google.gwt.core.shared.GWT ;
2014-10-02 13:01:18 +02:00
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 @
*
2014-10-02 13:06:40 +02:00
* To get to know which user was selected listen for the { @link PickedItemEvent } on the { @link HandlerManager } instance you pass to this widget .
2014-10-02 13:01:18 +02:00
*
* /
public class PickItemsDialog extends PopupPanel {
2014-10-02 19:44:49 +02:00
2014-10-02 13:01:18 +02:00
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 ;
2015-07-15 12:33:13 +02:00
private int itemCursorIndexEnd ;
private int itemCursorIndexStart = - 1 ;
boolean handleNonCharKeys = false ;
2018-06-08 17:59:28 +02:00
private MultiWordSuggestOracle oracle = new UserOracle ( ) ; //by default we use the async version;
2014-10-02 13:01:18 +02:00
private int displayIndexSelected ;
private FocusPanel focusPanel = new FocusPanel ( ) ;
private VerticalPanel mainPanel = new VerticalPanel ( ) ;
2015-07-14 19:21:21 +02:00
private char triggerChar ;
2016-05-25 12:18:44 +02:00
private ArrayList < ItemBean > beans ;
2014-10-02 13:01:18 +02:00
//needed because is selected when it popups
private Widget first ;
2014-10-02 15:07:19 +02:00
private boolean hasPhoto ;
2014-10-03 00:33:14 +02:00
private boolean includeTriggerChar ;
2016-06-30 14:47:00 +02:00
//to explain
private boolean stopListening = true ;
2018-06-08 17:59:28 +02:00
2014-10-02 13:01:18 +02:00
static {
CssAndImages . INSTANCE . css ( ) . ensureInjected ( ) ;
}
2015-07-14 19:21:21 +02:00
2014-10-02 13:01:18 +02:00
/ * *
* @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 )
2014-10-02 15:07:19 +02:00
* @param hasPhoto tell of you have want to show photo for the item or not
2014-10-03 00:33:14 +02:00
* @param includeTriggerChar true if your suggestions start with the trigger char ( e . g . # anHashTag triggered by # ) false otherwise
2014-10-02 13:01:18 +02:00
* /
2016-05-25 12:18:44 +02:00
public PickItemsDialog ( char triggerChar , ArrayList < ItemBean > beans , final HandlerManager eventBus , int widthInPixel ) {
2018-06-08 17:59:28 +02:00
this ( triggerChar , eventBus , widthInPixel ) ;
this . beans = beans ;
oracle = new MultiWordSuggestOracle ( ) ; //not async version
GWT . log ( " new constructor " ) ;
//add the user fill names to the oracle
for ( ItemBean bean : beans ) {
oracle . add ( bean . getAlternativeName ( ) ) ;
// if it is a team, set the avatar
if ( bean . isItemGroup ( ) )
bean . setThumbnailURL ( CssAndImages . INSTANCE . iconTeam ( ) . getSafeUri ( ) . toString ( ) ) ;
}
}
/ * *
* Use this constructor for users , the list of the users is automatically loaded form the VRE members if in a VRE or from the union of the current ' s user VRE members if at root level
* Note that you must declare the pick item widget servlet in this case
* @param triggerChar the ' single char ' used to trigger the items list show , e . g . '@' , '#' . . . .
* @param eventBus the event bus on where the widget will fire the selected user event
* @param widthInPixel the desired width ( grater than 199 pixel )
* @param hasPhoto tell of you have want to show photo for the item or not
* @param includeTriggerChar true if your suggestions start with the trigger char ( e . g . # anHashTag triggered by # ) false otherwise
* /
public PickItemsDialog ( char triggerChar , final HandlerManager eventBus , int widthInPixel ) {
2014-10-02 13:01:18 +02:00
super ( true , false ) ;
if ( widthInPixel < 200 ) {
throw new IllegalArgumentException ( " width must be greater than 199 " ) ;
}
this . eventBus = eventBus ;
2015-07-14 19:21:21 +02:00
this . triggerChar = triggerChar ;
2014-10-03 00:33:14 +02:00
this . includeTriggerChar = false ;
this . hasPhoto = false ;
2018-06-08 17:59:28 +02:00
this . beans = new ArrayList < > ( ) ;
2014-10-02 13:01:18 +02:00
focusPanel . setWidth ( widthInPixel + " px " ) ;
mainPanel . setWidth ( widthInPixel + " px " ) ;
setWidth ( widthInPixel + " px " ) ;
focusPanel . add ( mainPanel ) ;
setWidget ( focusPanel ) ;
2018-06-08 17:59:28 +02:00
setStyleName ( " pickDialog " ) ;
if ( oracle instanceof UserOracle ) {
UserOracle asyncOracle = ( UserOracle ) oracle ;
asyncOracle . addContacts ( getAllUsers ( ) ) ;
}
2014-10-02 13:01:18 +02:00
//remove the first selected when hovering
focusPanel . addMouseOverHandler ( new MouseOverHandler ( ) {
@Override
public void onMouseOver ( MouseOverEvent event ) {
2014-10-03 00:33:14 +02:00
String styleSelected = hasPhoto ? " pickperson-selected " : " pickitem-selected " ;
2014-10-02 13:01:18 +02:00
if ( first ! = null )
2014-10-03 00:33:14 +02:00
first . removeStyleName ( styleSelected ) ;
2014-10-02 13:01:18 +02:00
}
} ) ;
focusPanel . addMouseOutHandler ( new MouseOutHandler ( ) {
@Override
public void onMouseOut ( MouseOutEvent event ) {
select ( displayIndexSelected ) ;
}
} ) ;
2014-10-02 19:44:49 +02:00
2014-10-02 18:19:43 +02:00
focusPanel . addMouseDownHandler ( new MouseDownHandler ( ) {
2014-10-02 13:01:18 +02:00
@Override
public void onMouseDown ( MouseDownEvent event ) {
2014-10-02 19:44:49 +02:00
handleMouseDown ( ) ;
2014-10-02 13:01:18 +02:00
}
} ) ;
2018-06-08 17:59:28 +02:00
2016-06-30 14:47:00 +02:00
eventBus . addHandler ( PickedItemEvent . TYPE , new PickedItemEventHandler ( ) {
@Override
public void onSelectedItem ( PickedItemEvent event ) {
2018-06-08 17:59:28 +02:00
GWT . log ( " GOT EVENT " + event . getSelectedItem ( ) . getAlternativeName ( ) ) ;
2016-06-30 14:47:00 +02:00
stopListening = true ;
}
} ) ;
2014-10-02 13:01:18 +02:00
}
2018-06-08 17:59:28 +02:00
//just used in devlopment
private List < ItemBean > getAllUsers ( ) {
List < ItemBean > toReturn = new ArrayList < > ( ) ;
toReturn . add ( new ItemBean ( " andrea.rossi " , " andrea.rossi " , " Andrea Rossi " , " m.assante@gmail.com " ) ) ;
return toReturn ;
}
2014-10-03 00:33:14 +02:00
/ * *
* use if you have want to show a photo for the item or not , remember to provide it in { @link ItemBean } instances
* /
public void withPhoto ( ) {
hasPhoto = true ;
}
/ * *
* use to include the trigger char in search if your suggestions start with the trigger char ( e . g . # anHashTag triggered by # )
* /
public void withTriggerCharIncluded ( ) {
includeTriggerChar = true ;
}
2015-07-14 19:21:21 +02:00
2014-10-02 18:19:43 +02:00
private void handleMouseDown ( ) {
SelectableItem ut = ( SelectableItem ) mainPanel . getWidget ( displayIndexSelected ) ;
2018-03-18 17:17:06 +01:00
ItemBean itemBean = new ItemBean ( ut . getItemId ( ) , " username " , ut . getItemName ( ) , " thumb " ) ;
itemBean . setItemGroup ( ut . isGroup ( ) ) ;
eventBus . fireEvent ( new PickedItemEvent ( itemBean , this . triggerChar , itemCursorIndexStart , itemCursorIndexEnd ) ) ;
2014-10-02 18:19:43 +02:00
hide ( ) ;
select ( 0 ) ; //RESET
}
2014-10-02 13:01:18 +02:00
/ * *
2015-07-14 19:21:21 +02:00
* called for each onKeyPress event from the user
2014-10-02 13:01:18 +02:00
* @param keyCode the event keycode
* @param x
* @param y
* @param currText
* /
2015-07-14 19:21:21 +02:00
public void onKeyPress ( int cursorPos , int keyCode , int x , int y , String currText ) {
char ch = ( char ) keyCode ;
if ( ch = = triggerChar ) {
2014-10-02 13:01:18 +02:00
setPopupPosition ( x , y ) ;
hide ( ) ;
2015-07-14 19:21:21 +02:00
handleNonCharKeys = false ;
2016-06-30 14:47:00 +02:00
stopListening = false ;
2015-07-14 19:21:21 +02:00
this . itemCursorIndexStart = cursorPos ;
}
2014-10-02 19:44:49 +02:00
else {
2018-06-08 17:59:28 +02:00
2015-07-14 19:21:21 +02:00
itemCursorIndexEnd = cursorPos ;
currText = currText . substring ( itemCursorIndexStart , cursorPos ) + ch ;
2018-06-08 17:59:28 +02:00
2016-06-30 14:47:00 +02:00
if ( currText . contains ( " " + triggerChar ) & & currText . length ( ) > 1 & & ! stopListening ) {
2015-07-14 19:21:21 +02:00
if ( pickingUser ( currText . substring ( 1 ) ) ) {
handleNonCharKeys = true ;
2016-06-30 14:47:00 +02:00
}
} else if ( ! currText . contains ( " " + triggerChar ) | | stopListening ) {
2014-10-02 19:44:49 +02:00
hide ( ) ;
2015-07-14 19:21:21 +02:00
handleNonCharKeys = false ;
2016-06-30 14:47:00 +02:00
GWT . log ( " stopListening = " + stopListening ) ;
2015-07-14 19:21:21 +02:00
}
2014-10-02 19:44:49 +02:00
}
2014-10-02 13:01:18 +02:00
}
2015-07-15 12:33:13 +02:00
2015-07-14 19:21:21 +02:00
/ * *
* called for each onKeyUp event from the user
* @param keyCode the event keycode
* /
public void onKeyUp ( int keyCode ) {
2016-06-30 14:47:00 +02:00
if ( handleNonCharKeys ) {
2015-07-14 19:21:21 +02:00
handleNonCharKeys ( keyCode ) ;
2016-06-30 14:47:00 +02:00
}
if ( keyCode = = ENTER ) {
stopListening = true ;
handleNonCharKeys = false ;
}
2015-07-14 19:21:21 +02:00
}
2014-10-02 13:01:18 +02:00
/ * *
* split the text and keeps listening for user keyboard events
* @param currText the text being typed
* /
private boolean pickingUser ( String currText ) {
2018-06-08 17:59:28 +02:00
GWT . log ( " ci arriva " ) ;
2015-07-14 19:21:21 +02:00
if ( currText . trim ( ) . length ( ) > 0 ) {
2014-10-03 00:33:14 +02:00
if ( includeTriggerChar )
2015-07-14 19:21:21 +02:00
showSuggestions ( triggerChar + currText ) ;
2014-10-03 00:33:14 +02:00
else
2015-07-14 19:21:21 +02:00
showSuggestions ( currText ) ;
2014-10-02 13:01:18 +02:00
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 ( ) ;
2015-07-15 12:33:13 +02:00
break ;
2014-10-02 13:01:18 +02:00
case ENTER : //selectd with keyboard
2016-06-30 14:47:00 +02:00
GWT . log ( " Enter selcted " ) ;
2014-10-02 13:01:18 +02:00
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 ) ;
2018-03-18 17:17:06 +01:00
ItemBean itemBean = new ItemBean ( ut . getItemId ( ) , " username " , ut . getItemName ( ) , " thumb " ) ;
itemBean . setItemGroup ( ut . isGroup ( ) ) ;
eventBus . fireEvent ( new PickedItemEvent ( itemBean , this . triggerChar , itemCursorIndexStart , itemCursorIndexEnd ) ) ;
2014-10-02 13:01:18 +02:00
hide ( ) ;
select ( 0 ) ; //RESET
}
2016-06-30 14:47:00 +02:00
else {
GWT . log ( " mainPanel.getWidgetCount() non ci entra " ) ;
hide ( ) ;
select ( 0 ) ; //RESET
}
2014-10-02 13:01:18 +02:00
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 ) {
2014-10-02 15:07:19 +02:00
first = getUserTemplate ( getUserModelBySuggestion ( s ) , i , hasPhoto ) ;
2014-10-03 00:33:14 +02:00
String styleSelected = hasPhoto ? " pickperson-selected " : " pickitem-selected " ;
first . addStyleName ( styleSelected ) ;
2014-10-02 13:01:18 +02:00
mainPanel . add ( first ) ;
}
else
2014-10-02 15:07:19 +02:00
mainPanel . add ( getUserTemplate ( getUserModelBySuggestion ( s ) , i , hasPhoto ) ) ;
2014-10-02 13:01:18 +02:00
i + + ;
}
if ( i > 0 ) {
show ( ) ;
}
}
} ) ;
}
2018-06-08 17:59:28 +02:00
2014-10-02 13:01:18 +02:00
}
2018-06-08 17:59:28 +02:00
2014-10-02 13:01:18 +02:00
private ItemBean getUserModelBySuggestion ( Suggestion suggestion ) {
2018-06-08 17:59:28 +02:00
if ( suggestion instanceof UserSuggestion ) {
UserSuggestion us = ( UserSuggestion ) suggestion ;
return us . getUser ( ) ;
} else { //the user were preloaded client side
for ( ItemBean bean : beans ) {
if ( suggestion . getReplacementString ( ) . compareTo ( bean . getAlternativeName ( ) ) = = 0 )
return bean ;
}
return new ItemBean ( " no-match " , " no-match " , " no-match " , " no-match " ) ;
2014-10-02 13:01:18 +02:00
}
}
2014-10-02 15:07:19 +02:00
private Widget getUserTemplate ( ItemBean user , int displayIndex , boolean hasPhoto ) {
if ( hasPhoto )
2014-10-02 19:44:49 +02:00
return new WithPhotoTemplate ( this , user , displayIndex ) ;
2014-10-02 15:07:19 +02:00
return new NoPhotoTemplate ( this , user , displayIndex ) ;
2014-10-02 13:01:18 +02:00
}
/ * *
* select the user in the model and in the view
* @param displayIndex
* /
public void select ( int displayIndex ) {
2014-10-03 00:33:14 +02:00
String styleSelected = hasPhoto ? " pickperson-selected " : " pickitem-selected " ;
2014-10-02 13:01:18 +02:00
for ( int i = 0 ; i < mainPanel . getWidgetCount ( ) ; i + + ) {
Widget ut = ( Widget ) mainPanel . getWidget ( i ) ;
if ( i = = displayIndex ) {
2014-10-03 00:33:14 +02:00
ut . addStyleName ( styleSelected ) ;
2014-10-02 13:01:18 +02:00
displayIndexSelected = i ;
}
else
2014-10-03 00:33:14 +02:00
ut . removeStyleName ( styleSelected ) ;
2014-10-02 13:01:18 +02:00
}
}
}