diff --git a/.classpath b/.classpath
new file mode 100644
index 0000000..1a0e679
--- /dev/null
+++ b/.classpath
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.project b/.project
new file mode 100644
index 0000000..32abe99
--- /dev/null
+++ b/.project
@@ -0,0 +1,59 @@
+
+
+ pickitem-widget
+ pickuser-widget project
+
+
+
+
+ org.eclipse.wst.jsdt.core.javascriptValidator
+
+
+
+
+ org.eclipse.wst.common.project.facet.core.builder
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.wst.validation.validationbuilder
+
+
+
+
+ org.maven.ide.eclipse.maven2Builder
+
+
+
+
+ com.google.gdt.eclipse.core.webAppProjectValidator
+
+
+
+
+ com.google.gwt.eclipse.core.gwtProjectValidator
+
+
+
+
+ org.eclipse.m2e.core.maven2Builder
+
+
+
+
+
+ org.eclipse.m2e.core.maven2Nature
+ org.eclipse.jem.workbench.JavaEMFNature
+ org.eclipse.wst.common.modulecore.ModuleCoreNature
+ org.maven.ide.eclipse.maven2Nature
+ org.eclipse.jdt.core.javanature
+ org.eclipse.wst.common.project.facet.core.nature
+ org.eclipse.wst.jsdt.core.jsNature
+ com.google.gwt.eclipse.core.gwtNature
+
+
diff --git a/.settings/.jsdtscope b/.settings/.jsdtscope
new file mode 100644
index 0000000..ba3c245
--- /dev/null
+++ b/.settings/.jsdtscope
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.settings/com.google.appengine.eclipse.core.prefs b/.settings/com.google.appengine.eclipse.core.prefs
new file mode 100644
index 0000000..30a797d
--- /dev/null
+++ b/.settings/com.google.appengine.eclipse.core.prefs
@@ -0,0 +1,3 @@
+#Tue Apr 16 14:53:45 CEST 2013
+eclipse.preferences.version=1
+filesCopiedToWebInfLib=
diff --git a/.settings/com.google.gdt.eclipse.core.prefs b/.settings/com.google.gdt.eclipse.core.prefs
new file mode 100644
index 0000000..d32685b
--- /dev/null
+++ b/.settings/com.google.gdt.eclipse.core.prefs
@@ -0,0 +1,5 @@
+eclipse.preferences.version=1
+jarsExcludedFromWebInfLib=
+lastWarOutDir=/Users/massi/Documents/workspace/pickitem-widget/target/pickitem-widget-1.0.0-SNAPSHOT
+warSrcDir=src/main/webapp
+warSrcDirIsOutput=false
diff --git a/.settings/com.google.gwt.eclipse.core.prefs b/.settings/com.google.gwt.eclipse.core.prefs
new file mode 100644
index 0000000..c803c44
--- /dev/null
+++ b/.settings/com.google.gwt.eclipse.core.prefs
@@ -0,0 +1,5 @@
+#Thu Jun 16 11:14:17 CEST 2011
+eclipse.preferences.version=1
+entryPointModules=
+filesCopiedToWebInfLib=gwt-servlet.jar
+gwtCompileSettings=PGd3dC1jb21waWxlLXNldHRpbmdzPjxsb2ctbGV2ZWw+SU5GTzwvbG9nLWxldmVsPjxvdXRwdXQtc3R5bGU+T0JGVVNDQVRFRDwvb3V0cHV0LXN0eWxlPjxleHRyYS1hcmdzPjwhW0NEQVRBWy13YXIgc3JjL21haW4vd2ViYXBwXV0+PC9leHRyYS1hcmdzPjx2bS1hcmdzPjwhW0NEQVRBWy1YbXg1MTJtXV0+PC92bS1hcmdzPjxlbnRyeS1wb2ludC1tb2R1bGU+Y29tLmNvbXBhbnkuU29tZU1vZHVsZTwvZW50cnktcG9pbnQtbW9kdWxlPjwvZ3d0LWNvbXBpbGUtc2V0dGluZ3M+
diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..b9e7d56
--- /dev/null
+++ b/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,7 @@
+#Tue Apr 16 14:53:45 CEST 2013
+eclipse.preferences.version=1
+encoding//src/main/java=UTF-8
+encoding//src/main/resources=UTF-8
+encoding//src/test/java=UTF-8
+encoding//src/test/resources=UTF-8
+encoding/=UTF-8
diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..6249222
--- /dev/null
+++ b/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,12 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.7
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
+org.eclipse.jdt.core.compiler.source=1.7
diff --git a/.settings/org.eclipse.m2e.core.prefs b/.settings/org.eclipse.m2e.core.prefs
new file mode 100644
index 0000000..66a4e4d
--- /dev/null
+++ b/.settings/org.eclipse.m2e.core.prefs
@@ -0,0 +1,5 @@
+#Tue Apr 16 14:53:45 CEST 2013
+activeProfiles=
+eclipse.preferences.version=1
+resolveWorkspaceProjects=true
+version=1
diff --git a/.settings/org.eclipse.wst.common.component b/.settings/org.eclipse.wst.common.component
new file mode 100644
index 0000000..7282477
--- /dev/null
+++ b/.settings/org.eclipse.wst.common.component
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/.settings/org.eclipse.wst.common.project.facet.core.xml b/.settings/org.eclipse.wst.common.project.facet.core.xml
new file mode 100644
index 0000000..4045d87
--- /dev/null
+++ b/.settings/org.eclipse.wst.common.project.facet.core.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/.settings/org.eclipse.wst.jsdt.ui.superType.container b/.settings/org.eclipse.wst.jsdt.ui.superType.container
new file mode 100644
index 0000000..3bd5d0a
--- /dev/null
+++ b/.settings/org.eclipse.wst.jsdt.ui.superType.container
@@ -0,0 +1 @@
+org.eclipse.wst.jsdt.launching.baseBrowserLibrary
\ No newline at end of file
diff --git a/.settings/org.eclipse.wst.validation.prefs b/.settings/org.eclipse.wst.validation.prefs
new file mode 100644
index 0000000..04cad8c
--- /dev/null
+++ b/.settings/org.eclipse.wst.validation.prefs
@@ -0,0 +1,2 @@
+disabled=06target
+eclipse.preferences.version=1
diff --git a/.settings/org.maven.ide.eclipse.prefs b/.settings/org.maven.ide.eclipse.prefs
new file mode 100644
index 0000000..c74c58e
--- /dev/null
+++ b/.settings/org.maven.ide.eclipse.prefs
@@ -0,0 +1,9 @@
+#Thu Sep 02 10:42:12 CEST 2010
+activeProfiles=
+eclipse.preferences.version=1
+fullBuildGoals=process-test-resources
+includeModules=false
+resolveWorkspaceProjects=true
+resourceFilterGoals=process-resources resources\:testResources
+skipCompilerPlugin=true
+version=1
diff --git a/PickUserTest-dev.launch b/PickUserTest-dev.launch
new file mode 100644
index 0000000..51167d6
--- /dev/null
+++ b/PickUserTest-dev.launch
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/PickUserTest-prod.launch b/PickUserTest-prod.launch
new file mode 100644
index 0000000..4ae5888
--- /dev/null
+++ b/PickUserTest-prod.launch
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/distro/INSTALL b/distro/INSTALL
new file mode 100644
index 0000000..139597f
--- /dev/null
+++ b/distro/INSTALL
@@ -0,0 +1,2 @@
+
+
diff --git a/distro/LICENSE b/distro/LICENSE
new file mode 100644
index 0000000..cdb5851
--- /dev/null
+++ b/distro/LICENSE
@@ -0,0 +1,7 @@
+gCube System - License
+------------------------------------------------------------
+
+The gCube/gCore software is licensed as Free Open Source software conveying to the EUPL (http://ec.europa.eu/idabc/eupl).
+The software and documentation is provided by its authors/distributors "as is" and no expressed or
+implied warranty is given for its use, quality or fitness for a particular case.
+
diff --git a/distro/MAINTAINERS b/distro/MAINTAINERS
new file mode 100644
index 0000000..680cebb
--- /dev/null
+++ b/distro/MAINTAINERS
@@ -0,0 +1,6 @@
+Mantainers
+-------
+
+* Massimiliano Assante (massimiliano.assante@isti.cnr.it), CNR Pisa,
+ Istituto di Scienza e Tecnologie dell'Informazione "A. Faedo".
+
diff --git a/distro/README b/distro/README
new file mode 100644
index 0000000..b84ad3a
--- /dev/null
+++ b/distro/README
@@ -0,0 +1,35 @@
+The gCube System - Pick User Widget
+------------------------------------------------------------
+
+This work is partially funded by the European Commission in the
+context of the iMarine project (www.i-marine.eu), under the 1st call of FP7 IST priority.
+
+Authors
+-------
+Massimiliano Assante
+*
+Version and Release Date
+------------------------
+APR 2013
+
+
+Description
+-----------
+Social networking Library
+
+Download information
+--------------------
+Source code is available from SVN:
+https://svn.d4science.research-infrastructures.eu/gcube/trunk/portlets/user/pickuser-widget
+
+Binaries can be downloaded from:
+http://maven.research-infrastructures.eu/nexus/index.html#welcome
+
+Documentation
+-------------
+Documentation is available on-line from the Projects Documentation Wiki:
+
+Licensing
+---------
+
+This software is licensed under the terms you may find in the file named "LICENSE" in this directory.
diff --git a/distro/changelog.xml b/distro/changelog.xml
new file mode 100644
index 0000000..3b3de47
--- /dev/null
+++ b/distro/changelog.xml
@@ -0,0 +1,6 @@
+
+
+ Refactored and ported to GWT 2.5.1
+
+
diff --git a/distro/descriptor.xml b/distro/descriptor.xml
new file mode 100644
index 0000000..c468f13
--- /dev/null
+++ b/distro/descriptor.xml
@@ -0,0 +1,48 @@
+
+ servicearchive
+
+ tar.gz
+
+ /
+
+
+ ${distroDirectory}
+ /
+ true
+
+ README
+ LICENSE
+ INSTALL
+ MAINTAINERS
+ changelog.xml
+
+ 755
+ true
+
+
+ target/apidocs
+ /${artifactId}/doc/api
+ true
+ 755
+
+
+
+
+
+ ./
+ true
+
+
+
+ /${artifactId}
+
+
+
+ /${artifactId}
+ true
+
+
+
\ No newline at end of file
diff --git a/distro/profile.xml b/distro/profile.xml
new file mode 100644
index 0000000..7528423
--- /dev/null
+++ b/distro/profile.xml
@@ -0,0 +1,25 @@
+
+
+
+ Library
+
+ {description}
+ PortletsUser
+ ${artifactId}
+ 1.0.0
+
+
+ ${artifactId}
+ ${version}
+
+ ${groupId}
+ ${artifactId}
+ ${version}
+
+
+ ${build.finalName}.jar
+
+
+
+
+
diff --git a/distro/svnpath.txt b/distro/svnpath.txt
new file mode 100644
index 0000000..edacb04
--- /dev/null
+++ b/distro/svnpath.txt
@@ -0,0 +1 @@
+${scm.url}
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..4538963
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,168 @@
+
+
+ 4.0.0
+
+ maven-parent
+ org.gcube.tools
+ 1.0.0
+
+
+
+ org.gcube.portlets.widgets
+ pickitem-widget
+ 1.0.0-SNAPSHOT
+ war
+ gCube Pick User Widget
+
+ gCube Pick Item Widget is a dropdown item list you can attach to a textbox to select items
+
+
+ scm:svn:http://svn.d4science.research-infrastructures.eu/gcube/trunk/portlets/widgets/${project.artifactId}
+ scm:https://svn.d4science.research-infrastructures.eu/gcube/trunk/portlets/widgets/${project.artifactId}
+ http://svn.d4science.research-infrastructures.eu/gcube/trunk/portlets/widgets/${project.artifactId}
+
+
+
+ 2.5.1
+ distro
+
+ 1.7
+ 1.7
+ ${project.build.directory}/${project.build.finalName}
+
+ UTF-8
+ UTF-8
+
+
+
+
+ org.gcube.distribution
+ maven-portal-bom
+ LATEST
+ pom
+ import
+
+
+
+
+
+
+ com.google.gwt
+ gwt-user
+
+ provided
+
+
+
+
+
+ src/main/java
+
+ **/*.*
+
+
+
+
+
+ maven-compiler-plugin
+
+
+ 1.7
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+ 2.2
+
+
+
+ test-jar
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 2.12
+
+ true
+
+
+
+ org.apache.maven.plugins
+ maven-resources-plugin
+ 2.5
+
+
+ copy-profile
+ install
+
+ copy-resources
+
+
+ target
+
+
+ ${distroDirectory}
+ true
+
+ profile.xml
+
+
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-assembly-plugin
+ 2.2
+
+
+ ${distroDirectory}/descriptor.xml
+
+
+
+ fully.qualified.MainClass
+
+
+
+
+
+ servicearchive
+ install
+
+ single
+
+
+
+
+
+
+ org.codehaus.mojo
+ gwt-maven-plugin
+ 2.5.1
+
+
+
+ compile
+ test
+
+
+
+
+ PickItem.html
+ ${webappDirectory}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/org/gcube/portlets/widgets/pickitem/PickItem.gwt.xml b/src/main/java/org/gcube/portlets/widgets/pickitem/PickItem.gwt.xml
new file mode 100644
index 0000000..e6e727e
--- /dev/null
+++ b/src/main/java/org/gcube/portlets/widgets/pickitem/PickItem.gwt.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/java/org/gcube/portlets/widgets/pickitem/client/PickItem.java b/src/main/java/org/gcube/portlets/widgets/pickitem/client/PickItem.java
new file mode 100644
index 0000000..6b37dc9
--- /dev/null
+++ b/src/main/java/org/gcube/portlets/widgets/pickitem/client/PickItem.java
@@ -0,0 +1,61 @@
+package org.gcube.portlets.widgets.pickitem.client;
+
+import java.util.ArrayList;
+
+import org.gcube.portlets.widgets.pickitem.client.bundle.CssAndImages;
+import org.gcube.portlets.widgets.pickitem.client.dialog.PickItemsDialog;
+import org.gcube.portlets.widgets.pickitem.client.events.PickedUserEvent;
+import org.gcube.portlets.widgets.pickitem.shared.ItemBean;
+
+import com.google.gwt.core.client.EntryPoint;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.event.dom.client.KeyUpEvent;
+import com.google.gwt.event.dom.client.KeyUpHandler;
+import com.google.gwt.event.shared.HandlerManager;
+import com.google.gwt.user.client.ui.RootPanel;
+import com.google.gwt.user.client.ui.TextBox;
+
+/**
+ *
+ * @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 @
+ * uncomment //sample in the onModuleLoad() to see it working
+ *
+ * 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 PickItem implements EntryPoint {
+
+
+ /**
+ * This is the entry point method.
+ */
+ public void onModuleLoad() {
+ sample();
+ }
+
+ private void sample() {
+ HandlerManager eventbus = new HandlerManager(null);
+ ArrayList users = new ArrayList();
+ users.add(new ItemBean("id", "test.user1", "Test Foo", "phot URL"));
+ users.add(new ItemBean("id", "test.user2", "Test Fie", "phot URL"));
+ users.add(new ItemBean("id", "test.user3", "Abba Foo", "phot URL"));
+ users.add(new ItemBean("id", "test.user4", "ABabba Fie", "phot URL"));
+ users.add(new ItemBean("id", "test.user5", "ACaro Foo", "phot URL"));
+ users.add(new ItemBean("id", "test.user6", "Dario Fie", "phot URL"));
+ users.add(new ItemBean("id", "test.user7", "Ergo Fie", "phot URL"));
+
+ final TextBox tb = new TextBox();
+ final int popUpY = tb.getAbsoluteTop()+30;
+
+ final PickItemsDialog pickUserDlg = new PickItemsDialog('#', users, eventbus, 300);
+ tb.addKeyUpHandler(new KeyUpHandler() {
+ @Override
+ public void onKeyUp(KeyUpEvent event) {
+ pickUserDlg.onKeyUp(event.getNativeKeyCode(), tb.getAbsoluteLeft(), popUpY, tb.getText());
+ }
+ });
+
+ RootPanel.get().add(tb);
+ }
+}
diff --git a/src/main/java/org/gcube/portlets/widgets/pickitem/client/bundle/CssAndImages.java b/src/main/java/org/gcube/portlets/widgets/pickitem/client/bundle/CssAndImages.java
new file mode 100644
index 0000000..7ecc676
--- /dev/null
+++ b/src/main/java/org/gcube/portlets/widgets/pickitem/client/bundle/CssAndImages.java
@@ -0,0 +1,18 @@
+package org.gcube.portlets.widgets.pickitem.client.bundle;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.resources.client.ClientBundle;
+import com.google.gwt.resources.client.CssResource;
+import com.google.gwt.resources.client.ImageResource;
+import com.google.gwt.resources.client.ClientBundle.Source;
+import com.google.gwt.resources.client.ImageResource.ImageOptions;
+import com.google.gwt.resources.client.ImageResource.RepeatStyle;
+
+public interface CssAndImages extends ClientBundle {
+
+ public static final CssAndImages INSTANCE = GWT.create(CssAndImages.class);
+
+ @Source("PickItem.css")
+ public CssResource css();
+
+}
diff --git a/src/main/java/org/gcube/portlets/widgets/pickitem/client/bundle/PickItem.css b/src/main/java/org/gcube/portlets/widgets/pickitem/client/bundle/PickItem.css
new file mode 100644
index 0000000..b54d961
--- /dev/null
+++ b/src/main/java/org/gcube/portlets/widgets/pickitem/client/bundle/PickItem.css
@@ -0,0 +1,86 @@
+@external pickDialog, pick-label, pickperson, pickperson-selected, pickperson-photo, user-table, user-table-row, user-table-col, user-table-col.content, .user-table-col.smallphoto, user-token, content, smallphoto;
+
+.pickDialog {
+ border: 1px solid #333;
+ background-color: #FFF;
+}
+
+.pick-label {
+ font-family: 'Helvetica Neue', Arial, sans-serif;
+ font-size: 15px;
+ line-height: 18px;
+ color: inherit;
+}
+
+
+.pickperson {
+ color: #0B61A4;
+ cursor: pointer;
+ cursor: hand;
+ background: #FFF;
+
+ -webkit-transition: background-color .25s ease-in-out;
+ -moz-transition: background-color .25s ease-in-out;
+ -o-transition: background-color .25s ease-in-out;
+ transition: background-color .25s ease-in-out;
+}
+
+.pickperson-selected {
+ background-color: #033E6B;
+ color: whitesmoke;
+}
+
+.pickperson:active,.pickperson:focus,.pickperson:hover {
+ background-color: #033E6B;
+ color: whitesmoke;
+}
+
+.pickperson-photo {
+ display: block;
+ padding: 2px;
+ border: 1px solid #E6E6E6;
+ margin-left: 2px;
+}
+
+.user-table {
+ margin: 1px 0px;
+ display: table;
+ width: 100%;
+ background-clip: border-box;
+ background-image: none;
+ background-origin: padding-box;
+}
+
+.user-table-row {
+ display: table-row;
+ text-align: left;
+}
+
+.user-table-col {
+ display: table-cell;
+ text-align: left;
+}
+
+.user-table-col.content {
+ padding: 10px 0px 0px 10px;
+ vertical-align: top;
+}
+
+.user-table-col.smallphoto {
+ width: 40px;
+}
+
+.user-token {
+ margin: 3px;
+ height: auto !important;
+ padding: 1px 3px;
+ background-color: #E2E6F0 !important;
+ border: 1px solid #9DACCC;
+ color: #1C2A47;
+ cursor: default;
+ font-family: verdana, arial, sans-serif;
+ font-size: 11px;
+ border-radius: 5px;
+ -moz-border-radius: 5px;
+ -webkit-border-radius: 5px;
+}
\ No newline at end of file
diff --git a/src/main/java/org/gcube/portlets/widgets/pickitem/client/dialog/PickItemsDialog.java b/src/main/java/org/gcube/portlets/widgets/pickitem/client/dialog/PickItemsDialog.java
new file mode 100644
index 0000000..67b85a8
--- /dev/null
+++ b/src/main/java/org/gcube/portlets/widgets/pickitem/client/dialog/PickItemsDialog.java
@@ -0,0 +1,238 @@
+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 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 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");
+ }
+ }
+}
diff --git a/src/main/java/org/gcube/portlets/widgets/pickitem/client/events/PickedUserEvent.java b/src/main/java/org/gcube/portlets/widgets/pickitem/client/events/PickedUserEvent.java
new file mode 100644
index 0000000..24d9ce5
--- /dev/null
+++ b/src/main/java/org/gcube/portlets/widgets/pickitem/client/events/PickedUserEvent.java
@@ -0,0 +1,31 @@
+package org.gcube.portlets.widgets.pickitem.client.events;
+
+import org.gcube.portlets.widgets.pickitem.shared.ItemBean;
+
+import com.google.gwt.event.shared.GwtEvent;
+
+
+
+public class PickedUserEvent extends GwtEvent {
+ public static Type TYPE = new Type();
+
+ private ItemBean user;
+
+
+ public ItemBean getSelectedUser() {
+ return user;
+ }
+ public PickedUserEvent(ItemBean user) {
+ this.user = user;
+ }
+
+ @Override
+ public Type getAssociatedType() {
+ return TYPE;
+ }
+
+ @Override
+ protected void dispatch(PickedUserEventHandler handler) {
+ handler.onSelectedUser(this);
+ }
+}
diff --git a/src/main/java/org/gcube/portlets/widgets/pickitem/client/events/PickedUserEventHandler.java b/src/main/java/org/gcube/portlets/widgets/pickitem/client/events/PickedUserEventHandler.java
new file mode 100644
index 0000000..1d92048
--- /dev/null
+++ b/src/main/java/org/gcube/portlets/widgets/pickitem/client/events/PickedUserEventHandler.java
@@ -0,0 +1,7 @@
+package org.gcube.portlets.widgets.pickitem.client.events;
+
+import com.google.gwt.event.shared.EventHandler;
+
+public interface PickedUserEventHandler extends EventHandler {
+ void onSelectedUser(PickedUserEvent event);
+}
diff --git a/src/main/java/org/gcube/portlets/widgets/pickitem/client/uibinder/SelectableItem.java b/src/main/java/org/gcube/portlets/widgets/pickitem/client/uibinder/SelectableItem.java
new file mode 100644
index 0000000..6c6be82
--- /dev/null
+++ b/src/main/java/org/gcube/portlets/widgets/pickitem/client/uibinder/SelectableItem.java
@@ -0,0 +1,5 @@
+package org.gcube.portlets.widgets.pickitem.client.uibinder;
+
+public interface SelectableItem {
+ String getItemName();
+}
diff --git a/src/main/java/org/gcube/portlets/widgets/pickitem/client/uibinder/WithPhotoTemplate.java b/src/main/java/org/gcube/portlets/widgets/pickitem/client/uibinder/WithPhotoTemplate.java
new file mode 100644
index 0000000..e9b8f93
--- /dev/null
+++ b/src/main/java/org/gcube/portlets/widgets/pickitem/client/uibinder/WithPhotoTemplate.java
@@ -0,0 +1,56 @@
+package org.gcube.portlets.widgets.pickitem.client.uibinder;
+
+import org.gcube.portlets.widgets.pickitem.client.dialog.PickItemsDialog;
+import org.gcube.portlets.widgets.pickitem.shared.ItemBean;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.event.dom.client.MouseOverEvent;
+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.Composite;
+import com.google.gwt.user.client.ui.FocusPanel;
+import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.Image;
+import com.google.gwt.user.client.ui.Widget;
+
+public class WithPhotoTemplate extends Composite implements SelectableItem {
+
+ private static PhotoTemplateUiBinder uiBinder = GWT
+ .create(PhotoTemplateUiBinder.class);
+
+ interface PhotoTemplateUiBinder extends UiBinder {
+ }
+ PickItemsDialog owner;
+ private int currDisplayIndex;
+
+ @UiField
+ FocusPanel focusDiv;
+ @UiField
+ Image avatarImage;
+ @UiField
+ HTML contentArea;
+
+ public WithPhotoTemplate(PickItemsDialog owner, ItemBean user, int displayIndex) {
+ initWidget(uiBinder.createAndBindUi(this));
+ this.owner = owner;
+ currDisplayIndex = displayIndex;
+ if (user.getThumbnailURL() != null)
+ avatarImage.setUrl(user.getThumbnailURL());
+
+ avatarImage.setPixelSize(30, 30);
+ contentArea.setHTML(user.getAlternativeName());
+
+
+ }
+
+ @UiHandler("focusDiv")
+ void onMouseOver(MouseOverEvent e) {
+ owner.select(currDisplayIndex);
+ }
+
+ @Override
+ public String getItemName() {
+ return contentArea.getText();
+ }
+}
diff --git a/src/main/java/org/gcube/portlets/widgets/pickitem/client/uibinder/WithPhotoTemplate.ui.xml b/src/main/java/org/gcube/portlets/widgets/pickitem/client/uibinder/WithPhotoTemplate.ui.xml
new file mode 100644
index 0000000..f22ad8d
--- /dev/null
+++ b/src/main/java/org/gcube/portlets/widgets/pickitem/client/uibinder/WithPhotoTemplate.ui.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/org/gcube/portlets/widgets/pickitem/shared/ItemBean.java b/src/main/java/org/gcube/portlets/widgets/pickitem/shared/ItemBean.java
new file mode 100644
index 0000000..f37f80e
--- /dev/null
+++ b/src/main/java/org/gcube/portlets/widgets/pickitem/shared/ItemBean.java
@@ -0,0 +1,54 @@
+package org.gcube.portlets.widgets.pickitem.shared;
+
+import java.io.Serializable;
+
+@SuppressWarnings("serial")
+public class ItemBean implements Serializable {
+ private String id;
+ private String name;
+ private String alternativeName;
+ private String thumbnailURL;
+
+ public ItemBean() {
+ super();
+ }
+ public ItemBean(String id, String username, String fullName, String thumbnailURL) {
+ super();
+ this.id = id;
+ this.name = username;
+ this.alternativeName = fullName;
+ this.thumbnailURL = thumbnailURL;
+ }
+ public String getId() {
+ return id;
+ }
+ public void setId(String id) {
+ this.id = id;
+ }
+ public String getName() {
+ return name;
+ }
+ public void setName(String name) {
+ this.name = name;
+ }
+ public String getAlternativeName() {
+ return alternativeName;
+ }
+ public void setAlternativeName(String altname) {
+ this.alternativeName = altname;
+ }
+
+ public String getThumbnailURL() {
+ return thumbnailURL;
+ }
+ public void setThumbnailURL(String thumbnailURL) {
+ this.thumbnailURL = thumbnailURL;
+ }
+ @Override
+ public String toString() {
+ return "ItemBean [id=" + id + ", name=" + name
+ + ", alternativeName=" + alternativeName + ", thumbnailURL=" + thumbnailURL
+ + "]";
+ }
+
+}
diff --git a/src/main/webapp/PickItem.html b/src/main/webapp/PickItem.html
new file mode 100644
index 0000000..8a37e8b
--- /dev/null
+++ b/src/main/webapp/PickItem.html
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+ PickItem Widget Project
+
+
+
+
+
+
+
diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000..0f8bc3d
--- /dev/null
+++ b/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+ PickUser.html
+
+
+
diff --git a/src/test/resources/org/gcube/portlets/user/pickuser/PickUserJUnit.gwt.xml b/src/test/resources/org/gcube/portlets/user/pickuser/PickUserJUnit.gwt.xml
new file mode 100644
index 0000000..8cc192d
--- /dev/null
+++ b/src/test/resources/org/gcube/portlets/user/pickuser/PickUserJUnit.gwt.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+