Sorry for my too long question. I am totally a newbie on GWT and I have still less experiences.I would like to create simple chat application using GWT.
I found for a link simple java chat application using java+servlet+jsp from this. I refrenced it and converted to GWT compactable codes. (I deployed it on http://gwt-chatting-test.appspot.com using GAE). I believe my codes may have plenty of weak points and security holes but I have less experience to handle them .(If you found , pls correct me kindfully).
I would like to describe full of my codes. I used servlet 2.4 , GWT 2.5 ,UI Binder and other required libs.
1) . For Login page
Index.ui.xml
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
xmlns:g="urn:import:com.google.gwt.user.client.ui" xmlns:d="urn:import:com.google.gwt.dom.client">
<ui:style>
.important {
font-weight: bold;
}
.lblUserName {
margin-right: 3px;
}
</ui:style>
<g:HTMLPanel>
<center>
<g:HorizontalPanel>
<g:Label ui:field="lblUserName" text="User Name : " styleName="{style.lblUserName}"/><g:TextBox height="15px" ui:field="txtUserName"/>
<g:Button styleName="{style.important}" text="Login" ui:field="btnLogin" />
</g:HorizontalPanel>
</center>
</g:HTMLPanel>
Index.java
public class Index extends Composite {
interface IndexUiBinder extends UiBinder<Widget, Index> {}
private static IndexUiBinder uiBinder = GWT.create(IndexUiBinder.class);
#UiField Button btnLogin;
#UiField TextBox txtUserName;
private ChatServiceAsync chatService = GWT.create(ChatService.class);
public Index() {
initWidget(uiBinder.createAndBindUi(this));
}
#UiHandler("btnLogin")
void onClick(ClickEvent e) {
login();
}
#UiHandler("txtUserName")
void onKeyDown(KeyDownEvent event) {
if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER) {
if (txtUserName.getText().trim().length() == 0) {
Window.alert("Enter your name for chat-room !");
}
else {
login();
}
}
}
private void login() {
AsyncCallback<String> callback = new AsyncCallback<String>() {
#Override
public void onSuccess(String result) {
RootPanel.get().clear();
RootPanel.get().add(new Chat());
}
#Override
public void onFailure(Throwable caught) {
System.err.println(caught.getMessage());
}
};
chatService.login(txtUserName.getText(), callback);
}
}
2) . For Chatting Page
Chat.ui.xml
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
xmlns:g="urn:import:com.google.gwt.user.client.ui">
<ui:style>
.main {
height: 420px;
border: 1px solid silver;
padding: 2px;
width: 620px;
margin-bottom: 5px;
}
.txtInputMsg {
margin-right: 3px;
width : 560px;
height :25px;
}
</ui:style>
<g:HTMLPanel>
<center>
<g:VerticalPanel>
<g:ScrollPanel styleName="{style.main}" height="420px" width="620px" ui:field="pnlMain">
<g:VerticalPanel ui:field="pnlMessage"/>
</g:ScrollPanel>
<g:HorizontalPanel ><g:TextBox styleName="{style.txtInputMsg}" ui:field="txtInputMsg"/><g:Button ui:field="btnLogout" text="Logout"/></g:HorizontalPanel>
</g:VerticalPanel>
</center>
</g:HTMLPanel>
Chat.java
public class Chat extends Composite {
public interface MessageTemlate extends SafeHtmlTemplates {
#Template("<div class =\"{2}\"><div class = \"msgTitle\"> {0}</div><div class=\"msgDescription\">{1}</div></div>")
SafeHtml getFormattedMessage(String name, SafeHtml message, String backgroundColor);
#Template("<div class =\"loginInform\"><span class=\"userName\">{0}</span> has been joined to this conversation !</div>")
SafeHtml notifyLoginUser(String userName);
#Template("<div class =\"logoutInform\"><span class=\"userName\">{0}</span> has been left from this conversation !</div>")
SafeHtml notifyLogoutUser(String userName);
}
private static ChatUiBinder uiBinder = GWT.create(ChatUiBinder.class);
#UiField TextBox txtInputMsg;
#UiField ScrollPanel pnlMain;
#UiField VerticalPanel pnlMessage;
#UiField Button btnLogout;
private static final XMLHttpRequest request = XMLHttpRequest.create();
private static final MessageTemlate TEMPLATES = GWT.create(MessageTemlate.class);
private ChatServiceAsync chatService = GWT.create(ChatService.class);
private String loginUser;
private Timer timer;
interface ChatUiBinder extends UiBinder<Widget, Chat> {}
public Chat() {
initWidget(uiBinder.createAndBindUi(this));
pnlMessage.getElement().setAttribute("style", "width:100%");
initLoginUserName();
request.open("post", URL.encode(GWT.getModuleBaseURL()
+ "chat.do?action=login&time='" + new Date().getTime() + ""));
request.send(null);
}
#UiHandler("txtInputMsg")
void sendMessage(KeyDownEvent event) {
if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER) {
if (txtInputMsg.getText().trim().length() > 0) {
SafeHtml message = SafeHtmlUtils.fromTrustedString(txtInputMsg.getText());
request.open("post", URL.encode(GWT.getModuleBaseURL()
+ "chat.do?action=send&msg=" + message.asString() + "&time='" + new Date().getTime() + ""));
txtInputMsg.setText("");
pnlMessage.add(new HTML(TEMPLATES.getFormattedMessage(loginUser, message, "myMessage")));
pnlMain.scrollToBottom();
txtInputMsg.setFocus(true);
request.send(null);
}
}
}
#UiHandler("btnLogout")
void logout(ClickEvent e) {
boolean confirm = Window.confirm("Are you sure you want to logout now ?");
if (confirm) {
timer.cancel();
request.open("post", URL.encode(GWT.getModuleBaseURL()
+ "chat.do?action=logout&time='" + new Date().getTime() + ""));
request.send(null);
AsyncCallback<String> callback = new AsyncCallback<String>() {
#Override
public void onSuccess(String result) {
RootPanel.get().clear();
RootPanel.get().add(new Index());
}
#Override
public void onFailure(Throwable caught) {
System.err.println(caught.getMessage());
}
};
chatService.logOut(loginUser, callback);
}
}
private void initChatListener() {
timer = new Timer() {
#Override
public void run() {
request.open("post", URL.encode(GWT.getModuleBaseURL()
+ "chat.do?action=get&time='"
+ new Date().getTime() + ""));
request.send(null);
request.setOnReadyStateChange(new ReadyStateChangeHandler() {
#Override
public void onReadyStateChange(XMLHttpRequest xhr) {
if (xhr.getReadyState() == 4) {
if (xhr.getStatus() == 200 && xhr.getResponseText().trim().length() > 1) {
HTML html = new HTML(xhr.getResponseText().trim());
JSONValue value = JSONParser.parseLenient(html.getText());
JSONWrapper json = new JSONWrapper(value);
for (int i = 0; i < json.getValue().isArray().size(); i++) {
String[] chatData = json.get(i).getValue().toString()
.replaceAll("\"", "").split(":");
if (chatData.length >= 3) {
if (chatData[2].equals("login")) {
pnlMessage.add(new HTML(TEMPLATES.notifyLoginUser(chatData[0])));
}
else {
pnlMessage.add(new HTML(TEMPLATES.notifyLogoutUser(chatData[0])));
}
}
else {
pnlMessage.add(new HTML(TEMPLATES.getFormattedMessage(chatData[0],
SafeHtmlUtils.fromTrustedString(chatData[1]), "receivedMessage")
.asString()));
}
pnlMain.scrollToBottom();
}
}
}
}
});
}
};
timer.scheduleRepeating(1000);
}
private void initLoginUserName() {
AsyncCallback<String> callback = new AsyncCallback<String>() {
#Override
public void onSuccess(String result) {
loginUser = result;
if (loginUser == null) {
Window.alert("You need to login !");
RootPanel.get().clear();
RootPanel.get().add(new Index());
}
else {
initChatListener();
}
}
#Override
public void onFailure(Throwable caught) {
System.err.println(caught.getMessage());
}
};
chatService.getUsername(callback);
}
}
3) . Service and ServiceAsync for RPC
ChatService.java
#RemoteServiceRelativePath("chatService")
public interface ChatService extends RemoteService {
String login(String userName);
String getUsername();
String logOut(String username);
}
ChatServiceAsync.java
public interface ChatServiceAsync {
void login(String userName, AsyncCallback<String> callback);
void getUsername(AsyncCallback<String> callback);
void logOut(String username, AsyncCallback<String> callback);
}
4) . Server side control
ChatServiceImpl.java
#SuppressWarnings("serial")
public class ChatServiceImpl extends RemoteServiceServlet implements ChatService {
public String login(final String userName) {
String newUserName = userName;
HttpSession httpSession = getThreadLocalRequest().getSession();
Map<String, List<String>> chat = ChatSupport.getChattingUsers();
synchronized (chat) {
// prevent userName conflict
int i = 1;
while (chat.containsKey(newUserName)) {
++i;
newUserName = userName + "(" + i + ")";
}
chat.put(newUserName, new ArrayList<String>());
}
httpSession.setAttribute("UID", newUserName);
return "LOGIN_SUCCESS";
}
public String logOut(String username) {
// remove the mapping of user name
ChatSupport.getChattingUsers().remove(username);
getThreadLocalRequest().getSession().invalidate();
return "LOGOUT_SUCCESS";
}
public String getUsername() {
// check if there is a HTTP session setup.
HttpSession httpSession = getThreadLocalRequest().getSession(false);
if (httpSession == null) {
return null;
}
// return the user name
return (String) httpSession.getAttribute("UID");
}
}
ChatSupport.java
#SuppressWarnings("serial")
public class ChatSupport extends HttpServlet {
// message map, mapping user UID with a message list
private static Map<String, List<String>> users = new HashMap<String, List<String>>();
#Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
String action = req.getParameter("action");
if ("login".equals(action)) {
String userName = (String) req.getSession().getAttribute("UID");
for (String key : users.keySet()) {
if (!key.equals(userName)) {
synchronized (users.get(key)) {
users.get(key).add(userName + "::login");
}
}
}
}
else if ("logout".equals(action)) {
String userName = (String) req.getSession().getAttribute("UID");
for (String key : users.keySet()) {
if (!key.equals(userName)) {
synchronized (users.get(key)) {
users.get(key).add(userName + "::logout");
}
}
}
}
// send message
else if ("send".equals(action)) {
// get param with UTF-8 enconding
String msg = new String(req.getParameter("msg").getBytes("ISO-8859-1"), "UTF-8");
String userName = (String) req.getSession().getAttribute("UID");
for (String key : users.keySet()) {
if (!key.equals(userName)) {
synchronized (users.get(key)) {
// put message to any other user's msg list
users.get(key).add(userName + ":" + msg);
}
}
}
}
else if ("get".equals(action)) { // get message
String userName = (String) req.getSession().getAttribute("UID");
if (userName == null) resp.sendError(HttpServletResponse.SC_BAD_REQUEST);
List<String> messages = users.get(userName);
synchronized (messages) {
if (messages.size() > 0) {
// for UTF-8 chars
resp.setCharacterEncoding("UTF-8");
PrintWriter out = resp.getWriter();
JSONArray result = new JSONArray();
// add all msg to json array and clear list
while (messages.size() > 0) {
result.add(messages.remove(0));
}
out.println(result);
out.close();
}
}
}
}
public static Map<String, List<String>> getChattingUsers() {
return users;
}
}
5) . My gwt.xml
....
<module rename-to='testing'>
<inherits name='com.google.gwt.user.User'/>
<inherits name='com.google.gwt.user.theme.clean.Clean'/>
<inherits name="com.google.gwt.http.HTTP" />
<inherits name="com.google.gwt.json.JSON" />
<inherits name="com.pathf.gwt.util.json.jsonwrapper" />
<entry-point class='test.client.TestingEntry'/>
<source path='client'/><source path='shared'/>
</module>
6) . Servlet configurations at web.xml
<servlet>
<servlet-name>chatServlet</servlet-name>
<servlet-class>test.server.ChatServiceImpl</servlet-class>
</servlet>
<servlet>
<servlet-name>ChatServlet</servlet-name>
<servlet-class>test.server.ChatSupport</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>ChatServlet</servlet-name>
<url-pattern>/testing/chat.do</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>chatServlet</servlet-name>
<url-pattern>/testing/chatService</url-pattern>
My program was run properly on multiple browsers but can't work on same broswer. I can't run this program by using same brower with multi-tabs. I think I am using same session and I need to create new session for every login. But I have no idea how to create it. From How to get multiple session in single browser , that may causes security problems and I shouldn't. But currently I forgot about securtiy issues.
So , How can I do for multiple-tab browser supports ?
Related
I'm new to ICEFaces and I have to maintain someone else's code. I'm working on a web chat where the user can send and receive messages. I would like the messages to have different colors depending on whether they were sent by the user or by someone else.
I currently have the following code in my xhtml file:
<h:dataTable id="history" value="#{chatBean.messages}" var="message" border="0" align="left" style="width: 100%" >
<h:column width="590" height="25" align="left" valign="bottom" >
<h:outputText value="#{message}" styleClass="#{chatBean.messageColor}" />
</h:column>
</h:dataTable>
This shows all messages sent and received, but all with the same color, even though the messageColor property of the chat bean changes: I did an experiment and appended the result of getMessageColor() at the end of each message and it does change, but the text is still rendered in the same color.
The CSS has the following classes (among others):
.class1
{
color:#818181;
width: 100%;
font-size: 15px;
font-family: Arial, Helvetica, sans-serif;
font-weight: bold;
}
.class2
{
color:#00657c;
width: 100%;
font-size: 15px;
font-family: Arial, Helvetica, sans-serif;
font-weight: bold;
}
Here's the code for the ChatBean class:
#ManagedBean(name = "chatBean")
#SessionScoped
public class ChatBean implements Serializable {
private static final long serialVersionUID = -12636320254821872L;
private static final String PUSH_GROUP = "chatPage";
private PortableRenderer renderer;
private String message;
private String lastMessageSent = "";
private Date lastMessageTime = new Date();
private String isDown = "false";
private List<String> messages = new ArrayList<String>();
private String buttonDisabled = "true";
private String buttonCancelDisabled = "true";
private String pollDisabled = "false";
private String id = "";
private ChatClient chat;
private Timer timer = new Timer();
private String messageColor;
public class ChatThread extends Thread implements Serializable {
private static final long serialVersionUID = -7636532554421738019L;
private Map<String, String> data;
private String mail;
public ChatThread(final Map<String, String> data, final String mail) {
this.data = data;
this.mail = mail;
}
#Override
public void run() {
chat = new ChatClient(new ChatClient.Event() {
#Override
public void handle(String msg) {
if(msg != null && msg.length() > 0)
pushMessage(msg);
}
#Override
public void agentConnected(String msg) {
buttonDisabled = "false";
buttonCancelDisabled = "false";
pushMessage(msg);
}
#Override
public void agentDisconnected(String msg) {
buttonDisabled = "true";
pushMessage(msg);
try {
timer.cancel();
} catch (Exception e) {
e.printStackTrace();
}
}
});
chat.login(mail, data);
chat.join(mail, data.get("partner"), data.get("business"));
timer.scheduleAtFixedRate(new RefreshTimerTask(), 0, 1000);
}
}
public class RefreshTimerTask extends TimerTask implements Serializable {
private static final long serialVersionUID = 1852678537009150141L;
public void run() {
chat.refresh();
}
}
public ChatBean() {
if(getSession() != null) {
id = getSession().getId();
PushRenderer.addCurrentSession(PUSH_GROUP + id);
renderer = PushRenderer.getPortableRenderer();
setMessageColor("class1");
Log.getLogger().debug("New chat bean.");
if(getData().containsKey("login_chat")) {
ChatThread chat = new ChatThread(getData(), getSessionAttribute(GenesysSingleton.getInstance().getConfigApp().getDisplayName(), "<mail>"));
chat.start();
}
}
}
private void pushMessage(String msg) {
if(msg != null && !msg.isEmpty()) {
ChatBean.this.isDown = "true";
messages.add(msg);//Acá se puede acceder a textColor.
try {
PushRenderer.render(PUSH_GROUP + id);
} catch (Exception e) {
renderer.render(PUSH_GROUP + id);
}
setMessageColor("class1");
}
}
private String getSessionAttribute(String key, String ref) {
Object value = getSession().getAttribute(key);
return value != null ? value.toString() : ref;
}
private Map<String, String> getData() {
Map<String, String> data = new HashMap<String, String>();
HttpSession session = getSession();
#SuppressWarnings("rawtypes")
Enumeration enums = session.getAttributeNames();
while(enums.hasMoreElements()) {
String key = enums.nextElement().toString();
if(!"com.sun.faces.application.view.activeViewMaps".equals(key)
&& !"com.sun.faces.renderkit.ServerSideStateHelper.LogicalViewMap".equals(key)
&& !"javax.faces.request.charset".equals(key))
data.put(key, session.getAttribute(key).toString());
}
return data;
}
public void sendMessage(ActionEvent event) {
sendMessage();
}
protected synchronized void sendMessage() {
if (message != null && !message.trim().isEmpty()){
Date now = new Date();
//No permito mandar el mismo mensaje 2 veces seguidas en un intervalo menor a un segundo.
message = message.trim();
if (message.equals(lastMessageSent)&&(now.getTime()<(1000+lastMessageTime.getTime()))){
message = null;
}
else{
setMessageColor("class2");
lastMessageSent = message;
message = null;
lastMessageTime = new Date();
chat.refresh(lastMessageSent);
}
}
}
public String disconnect() {
pollDisabled = "true";
return "login";
}
public void sendClose(ActionEvent event) {
}
public void receiveMessage() {
}
#PreDestroy
public void destroy() {
buttonDisabled = "true";
try {
//pushMessage(SISTEMA_3);
} catch (Exception e) {
e.printStackTrace();
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
};
System.out.println(id + "- ssssssss");
try {
timer.cancel();
} catch (Exception e) {
}
chat.logout();
chat.close();
}
private HttpSession getSession() {
return (HttpSession) getContext().getSession(false);
}
private ExternalContext getContext() {
return getFacesContext().getExternalContext();
}
private FacesContext getFacesContext() {
return FacesContext.getCurrentInstance();
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getButtonDisabled() {
return buttonDisabled;
}
public void setButtonDisabled(String buttonDisabled) {
this.buttonDisabled = buttonDisabled;
}
public List<String> getMessages() {
try {
JavascriptContext.addJavascriptCall(getFacesContext(), "document.getElementById('scrollDataTable').scrollIntoView();");
} catch (Exception e) {
e.printStackTrace();
}
return messages;
}
public void setMessages(List<String> messages) {
this.messages = messages;
}
public String getPollDisabled() {
return pollDisabled;
}
public void setPollDisabled(String pollDisabled) {
this.pollDisabled = pollDisabled;
}
public String getButtonCancelDisabled() {
return buttonCancelDisabled;
}
public void setButtonCancelDisabled(String buttonCancelDisabled) {
this.buttonCancelDisabled = buttonCancelDisabled;
}
public String getIsDown() {
return isDown;
}
public void setIsDown(String isDown) {
this.isDown = isDown;
}
public String getMessageColor() {
return messageColor;
}
public void setMessageColor(String textColor) {
this.messageColor = textColor;
}
}
All help will be appreciated. Thank you in advance.
One possible way which I have changed css dynamically depending on a bean property is through using the styleClass attribute of the <h:outputText>.
In your css file define two varying classes such as
.class1
{
color:red; //Put your colour here (#818181)
}
.class2
{
color:green; //Put your colour here (#00657c)
}
Then in your java bean code you could declare a String field with getters and setters such as
private String messageColor;
Then in your code where you do
setTextColor(COLOR_AGENTE);
You can change this to the class which you would like to change the text to such as:
setMessageColor("class1");
Then on your <h:outputText> attach
styleClass="#{chatBean.messageColor}"
This should hopefully work;
Due to my original suggestion not working, you could try this.
Remove private String messageColor; from you chatBean and the getters/setters along with any calls to setMessageColor("class1");.
But keep the two classes in your css.
Now declare a boolean property with getters and setters in your chatBean:
private boolean colourAgente;
Declare a method:
public String setColor() {
if (colourAgente) {
return "class1";
} else {
return "class2";
}
}
Then in your xhtml change the styleClass attribute to:
styleClass="#{chatBean.setColor()}"
Finally, in your java code change:
setMessageColor("class1");
to either colourAgente = true; or colourAgente=false; depending on what colour you want to set.
I finally did it, but I had to use an ugly JavaScript workaround. That is, I'm now running this script every time the chat is refreshed:
function updateColors(){
var username = document.getElementById("form:username").value;
if (username.length > 0){
var x = document.getElementsByClassName("class1");
if (x != null){
for (i = 0; i < x.length; i++){
if (x[i].innerHTML.indexOf(username) === 0){
x[i].className = "class2";
}
}
}
}
}
Anyway, thanks for your help, LiamWilson94. I still don't know what part of the code I'm working with makes it so that your answers don't work, but you have given me a lot of insight which helped me arrive to this "solution", and I have learnt a few things about IceFaces in the process.
OK, I have found a better solution.
I created a TextModel class:
import java.io.Serializable;
public class TextModel implements Serializable {
private static final long serialVersionUID = -8470475291191399871L;
private String text;
private String clase;
public TextModel() {
}
public TextModel(String text, String clase) {
this.text = text;
this.clase = clase;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public String getClase() {
return clase;
}
public void setClase(String clase) {
this.clase = clase;
}
public String toString() {
return text;
}
}
Then I changed messages in ChatBean from List to List, and changed the following functions in ChatBean.java:
private void pushMessage(String msg) {
if(msg != null && !msg.isEmpty()) {
ChatBean.this.isDown = "true";
messages.add(new TextModel(msg,clase));
try {
PushRenderer.render(PUSH_GROUP + id);
} catch (Exception e) {
renderer.render(PUSH_GROUP + id);
}
clase = "class1";
}
}
protected synchronized void sendMessage() {
if (message != null && !message.trim().isEmpty()){
Date now = new Date();
message = message.trim();
if (message.equals(lastMessageSent)&&(now.getTime()<(1000+lastMessageTime.getTime()))){
message = null;
}
else{
clase = "class2";
lastMessageSent = message;
message = null;
lastMessageTime = new Date();
chat.refresh(lastMessageSent);
}
}
}
Where clase is either "class1" or "class2" (could be neater, but it works for now, I can always make it neater later).
Finally, on chat.xhtml, I changed the outputtext tag to:
<h:outputText value="#{message.text}" styleClass="#{message.clase}" />
That's it. No more messy JavaScript patches.
The trick was making the class a property of the message itself rather than the ChatBean.
I hope this helps someone else in the future.
I have a celltable and I'm trying implement pagination, but it doesn't work. I looked for solutions but without any success. I click in next page, nothing happens. I forgot to implement something? Someone can help me? Thanks for attention! Below, my implementation:
Java:
public class TaskPanel extends Composite {
private static TaskPanelUiBinder uiBinder = GWT
.create(TaskPanelUiBinder.class);
interface TaskPanelUiBinder extends UiBinder<Widget, TaskPanel> {
}
public TaskPanel() {
this.tableTask = createTableTask();
//Populate celltable
preencheListaTask();
initWidget(uiBinder.createAndBindUi(this));
}
#UiField(provided = true)
CellTable<Task> tableTask;
#UiField
AccordionGroup accordionTable;
#UiField Button btnRefresh;
#UiField SimplePager pager;
#UiField FormTaskPanel formTask;
List<Task> listTasks = new ArrayList<Task>();
ListDataProvider<Task> tableTaskProvider;
public List<Task> getListTasks() {
return this.listTasks;
}
public void setListTasks(List<Task> lista) {
this.listTasks = lista;
}
public TaskPanel getTaskPanel() {
return this;
}
//Create celltable
public CellTable<Task> createTableTask() {
tableTask = new CellTable<Task>();
tableTask.setPageSize(2);
TextColumn<Task> dataInicioColumn = new TextColumn<Task>() {
#Override
public String getValue(Task task) {
return task.getDataInicial();
}
};
tableTask.addColumn(dataInicioColumn, "Data Inicio");
TextColumn<Task> dataFinalColumn = new TextColumn<Task>() {
#Override
public String getValue(Task task) {
return task.getDataFinal();
}
};
tableTask.addColumn(dataFinalColumn, "Data Final");
TextColumn<Task> descricaoColumn = new TextColumn<Task>() {
#Override
public String getValue(Task task) {
return task.getDescricao();
}
};
tableTask.addColumn(descricaoColumn, "Descricao");
TextColumn<Task> categoriaColumn = new TextColumn<Task>() {
#Override
public String getValue(Task task) {
return task.getCategoria();
}
};
tableTask.addColumn(categoriaColumn, "Categoria");
TextColumn<Task> prioridadeColumn = new TextColumn<Task>() {
#Override
public String getValue(Task task) {
return task.getPrioridade();
}
};
tableTask.addColumn(prioridadeColumn, "Prioridade");
return tableTask;
}
//Generate a JSON, and I parse for List<Task> to populate celltable
public List<Task> preencheListaTask() {
final List<Task> lista = new ArrayList<Task>();
String url = "http://127.0.0.1:8888/financecontrol/jsonTableTasks.json";
RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, url);
try {
Request request = builder.sendRequest(null, new RequestCallback() {
public void onError(Request request, Throwable exception) {
System.out.println("Error to retrieve JSON");
}
#Override
public void onResponseReceived(Request arg0, Response response) {
if (200 == response.getStatusCode()) {
JSONValue value = JSONParser.parse(response.getText());
com.google.gwt.json.client.JSONObject taskObjs = value
.isObject();
JSONArray tasksArray = taskObjs.get("tasks").isArray();
if (tasksArray != null) {
for (int i = 0; i < tasksArray.size(); i++) {
com.google.gwt.json.client.JSONObject taskObj = tasksArray
.get(i).isObject();
String id = taskObj.get("ID").isNumber().toString();
String dataInicial = taskObj
.get("Data Inicial").isString()
.stringValue();
String dataFinal = taskObj.get("Data Final")
.isString().stringValue();
String descricao = taskObj.get("Descricao")
.isString().stringValue();
String categoria = taskObj.get("Categoria").isString().toString();
String prioridade = taskObj.get("Prioridade").isString().toString();
Task task = new Task(Integer.parseInt(id),
dataInicial, dataFinal,
descricao, categoria, prioridade);
lista.add(task);
}
setListTasks(lista);
System.out.println("JSON retrieve");
}
addLinhas();
} else {
System.out.println("Couldn't retrieve JSON ("
+ response.getStatusText() + ")");
}
}
});
} catch (RequestException e) {
System.err.println("Erro cath - " + e.getMessage());
}
return lista;
}
//add rows to celltable
public void addLinhas() {
this.tableTask.setRowCount(getListTasks().size(), true);
this.tableTask.setRowData(0, getListTasks());
tableTask.redraw();
tableTaskProvider = new ListDataProvider<Task>(getListTasks());
tableTaskProvider.addDataDisplay(tableTask);
//Pagination
SimplePager.Resources pagerResources = GWT.create(SimplePager.Resources.class);
pager = new SimplePager(TextLocation.CENTER, pagerResources, false, 0, true);
pager.setDisplay(tableTask);
}
#UiHandler("btnRefresh")
public void onClickRefresh(ClickEvent e) {
preencheListaTask();
}
}
UiBinder:
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:style>
.formContent {
height: 70%;
}
</ui:style>
<b:Container addStyleNames="{style.formContent}">
<r:FormTaskPanel ui:field="formTask"/>
<b:AccordionGroup ui:field="accordionTable" defaultOpen="false" heading="Task List">
<b:CellTable ui:field="tableTask" />
<b:SimplePager ui:field="pager" location="CENTER"/>
<b:Button ui:field="btnRefresh" text="Refresh" icon="REFRESH"/>
</b:AccordionGroup>
</b:Container>
You have pager = new SimplePager(...), so you have to declare #uiField(provided = true) for pager, and move pager declaration/initialisation into your createTableTask function (pager must be set before initwidget).
I'm still learning plugin dev. This is my first one.
I would like to persist the configuration of my plugin, but it won't work.
Could you please tell me, what am I doing wrong?
I have tried debuging the process, starting from the addition of the plugin to the job 'til the saving of the job config.
I have found, that inside the load() method of the descriptor, no xml file is found!
The path it is looking for is something like: c:\users\Peter\workspace\r-script.\work\whatEverDir\xy.xml
I don't think that the .\ part is causing the config file not to be found, but since it is a Jenkins class generating this path, I would not bet on it. Although the system might have tried to create it here at the first place.
Thanks in advance!
Scriptrunner.jelly
<f:block>
<f:entry title="RScript" field="command">
<f:textarea style="width:99%" />
</f:entry>
</f:block>
<f:entry field="installedPackages" title="Installed packages">
<f:select style="width:40%" />
</f:entry>
<f:entry field="mirrors" title="Choose a mirror">
<f:select style="width:40%" />
</f:entry>
<f:entry>
<f:repeatableProperty field="availablePackages" minimum="1"/>
</f:entry>
AvailablePackage.jelly
<f:entry field="availablePackages">
<f:select style="width:40%" />
<f:repeatableDeleteButton />
</f:entry>
ScriptRunner.java
public class ScriptRunner extends Builder {
private static final String fileExtension = ".R";
private ArrayList<AvailablePackage> availablePackages;
private String command;
private String chosenMirror;
private List<String> mirrorList = new ArrayList<String>();
#DataBoundConstructor
public ScriptRunner(String command, ArrayList<String> installedPackages, ArrayList<String> mirrors, ArrayList<AvailablePackage> availablePackages) {
this.chosenMirror = mirrors.get(0);
this.availablePackages = availablePackages;
this.command = command;
}
public final String getCommand() {
return command;
}
#Override
public boolean perform(AbstractBuild<?, ?> build, Launcher launcher,
BuildListener listener) throws InterruptedException {
return perform(build, launcher, (TaskListener) listener);
}
public boolean perform(AbstractBuild<?, ?> build, Launcher launcher,
TaskListener listener) throws InterruptedException {
FilePath workSpace = build.getWorkspace();
FilePath rScript = null;
if (workSpace == null) {
try {
throw new NoSuchFileException("Workspace could not be set!");
} catch (NoSuchFileException e) {
e.printStackTrace();
}
}
try {
try {
String fullScript;
if (command.contains("options(repos=structure(")) {
fullScript = PackagesManager.singleton().createFullScript(availablePackages, "", command);
} else {
fullScript = PackagesManager.singleton().createFullScript(availablePackages, chosenMirror, command);
}
rScript = workSpace.createTextTempFile("RScriptTemp",
getFileExtension(), fullScript, false);
} catch (IOException e) {
Util.displayIOException(e, listener);
e.printStackTrace(listener.fatalError(Messages
.CommandInterpreter_UnableToProduceScript()));
return false;
}
boolean successfullyRan = false;
try {
EnvVars envVars = build.getEnvironment(listener);
for (Map.Entry<String, String> e : build.getBuildVariables()
.entrySet()) {
envVars.put(e.getKey(), e.getValue());
}
if (launcher.launch().cmds(buildCommandLine(rScript))
.envs(envVars).stdout(listener).pwd(workSpace).join() == 1) {
successfullyRan = true;
}
} catch (IOException e) {
Util.displayIOException(e, listener);
e.printStackTrace(listener.fatalError(Messages
.CommandInterpreter_CommandFailed()));
}
return successfullyRan;
} finally {
try {
if (rScript != null) {
rScript.delete();
}
} catch (IOException e) {
Util.displayIOException(e, listener);
e.printStackTrace(listener.fatalError(Messages
.CommandInterpreter_UnableToDelete(rScript)));
} catch (Exception e) {
e.printStackTrace(listener.fatalError(Messages
.CommandInterpreter_UnableToDelete(rScript)));
}
}
}
public String[] buildCommandLine(FilePath script) {
return new String[] { "Rscript", script.getRemote() };
}
protected String getFileExtension() {
return fileExtension;
}
public List<String> getMirrorList() {
return mirrorList;
}
public void setMirrorList(List<String> mirrorList) {
this.mirrorList = mirrorList;
}
public String getChosenMirror() {
return chosenMirror;
}
public void setChosenMirror(String chosenMirror) {
this.chosenMirror = chosenMirror;
}
public ArrayList<AvailablePackage> getAvailablePackages() {
return availablePackages;
}
#Override
public ScriptBuildStepDescriptorImplementation getDescriptor() {
return (ScriptBuildStepDescriptorImplementation)super.getDescriptor();
}
#Extension
public static class ScriptBuildStepDescriptorImplementation extends
BuildStepDescriptor<Builder> {
private boolean showInstalled;
private String command;
private String chosenMirror;
private ArrayList<AvailablePackage> availablePackages;
public ScriptBuildStepDescriptorImplementation() {
load();
}
#Override
public boolean configure(StaplerRequest req, JSONObject formData) throws FormException {
req.bindJSON(this, formData);
save();
return super.configure(req,formData);
}
#Override
public String getDisplayName() {
return "Advanced R script runner";
}
#Override
public boolean isApplicable(Class<? extends AbstractProject> jobType) {
return true;
}
public ListBoxModel doFillInstalledPackagesItems() {
ListBoxModel mirrors = new ListBoxModel();
Set<String> mirrorsList = PackagesManager.singleton()
.getInstalledPackages();
for (String entry : mirrorsList) {
mirrors.add(entry);
}
return mirrors;
}
public ListBoxModel doFillAvailablePackagesItems() {
ListBoxModel packages = new ListBoxModel();
List<String> packageList = PackagesManager.singleton().getAvailablePackages();
Set<String> alreadyInstalled = PackagesManager.singleton().getInstalledPackages();
for (String entry : packageList) {
if (!alreadyInstalled.contains(entry)) {
packages.add(entry);
}
}
return packages;
}
public ListBoxModel doFillMirrorsItems() {
ListBoxModel mirrors = new ListBoxModel();
String[] mirrorsList = MirrorManager.singleton().getMirrors();
int selected = 34;
for (int i = 0; i < mirrorsList.length; i++) {
String[] splitCurrent = mirrorsList[i].split(" - ");
if (chosenMirror != null && chosenMirror.equals(splitCurrent[1])) {
selected = i;
}
mirrors.add(splitCurrent[1], splitCurrent[0]);
}
mirrors.get(selected).selected = true;
return mirrors;
}
public boolean getShowInstalled() {
return showInstalled;
}
public void setShowInstalled(boolean showInstalled) {
this.showInstalled = showInstalled;
}
public String getCommand() {
return command;
}
public void setCommand(String command) {
this.command = command;
}
public String getChosenMirror() {
return chosenMirror;
}
public void setChosenMirror(String chosenMirror) {
this.chosenMirror = chosenMirror;
}
}
}
AvailablePackage.java
public class AvailablePackage extends AbstractDescribableImpl<AvailablePackage> {
private String name;
#DataBoundConstructor
public AvailablePackage(String availablePackages) {
this.name = availablePackages;
}
public String getName() {
return name;
}
#Override
public DescriptorImpl getDescriptor() {
return (DescriptorImpl)super.getDescriptor();
}
#Extension
public static class DescriptorImpl extends Descriptor<AvailablePackage> {
private String name;
public DescriptorImpl() {
load();
}
#Override
public boolean configure(StaplerRequest req, JSONObject formData) throws FormException {
req.bindJSON(this, formData);
save();
return super.configure(req,formData);
}
public ListBoxModel doFillAvailablePackagesItems() {
return PackagesManager.singleton().getAvailablePackagesAsListBoxModel(name);
}
#Override
public String getDisplayName() {
return "";
}
public String getName() {
return name;
}
}
}
Sorry for the code formatting! First timer at stackoverflow code posting.
I think you may need to comment this line out
#Override
public boolean configure(StaplerRequest req, JSONObject formData) throws FormException {
req.bindJSON(this, formData);
save();
//return super.configure(req,formData);
return true;
}
as it will then save again but with no fields.
A good place to locate Jenkins plugin examples is in https://github.com/jenkinsci
I'm using the new maps v3 API from gwt-google-apis.
Is it possible to capture events from GWT widgets that are inside InfoWindow? Am I missing something?
Tried code above (button.addClickHandler) and it doesn't show the alert:
Marker m = Marker.create();
m.setIcon(MarkerImage.create(icone));
m.setPosition(LatLng.create(posicao.lat(), posicao.lng()));
m.setMap(map);
m.addClickHandler(new ClickHandler() {
#Override
public void handle(MouseEvent event) {
InfoWindow info = InfoWindow.create();
Button button = new Button("Desativar");
button.addClickHandler(new com.google.gwt.event.dom.client.ClickHandler() {
#Override
public void onClick(ClickEvent event) {
Window.alert("click");
}
});
final HTMLPanel html = new HTMLPanel(("<div id='button'></div>"));
html.add(button, "button");
info.setContent(html.getElement());
info.setPosition(posicao);
info.open(map);
}
});
Thanks.
The problem is result of a broken hierarchy between the widgets, the normal way to do it is by attach / detach widget. You do it by setting of the widget's element. This is also matter of Google Maps API.
This can be resolved by using fake panel which will be part of the InfoWindow, so when you make setContent(Widget widget) the fake panel will be updated and the element of the widget will be set to the content (as previous).
Please take a look at this class:
public class MyInfoWindow extends InfoWindow {
static class FakePanel extends ComplexPanel {
public FakePanel(Widget w) {
w.removeFromParent();
getChildren().add(w);
adopt(w);
}
#Override
public boolean isAttached() {
return true;
}
public void detachWidget() {
this.remove(0);
}
}
private IsWidget widgetContent = null;
FakePanel widgetAttacher;
public MyInfoWindow() {
super(InfoWindowImpl.impl.construct());
}
private void detachWidget() {
if (this.widgetAttacher != null) {
this.widgetAttacher.detachWidget();
this.widgetAttacher = null;
}
}
public void close() {
super.close();
detachWidget();
}
public void setContent(String content) {
this.widgetContent = null;
this.detachWidget();
super.setContent(content);
}
/** */
public void setContent(Widget value) {
this.widgetContent = value;
setContent(value.getElement());
if (this.widgetAttacher == null) {
addListener(getJso(), "closeclick", new Runnable() {
#Override
public void run() {
detachWidget();
}
});
this.widgetAttacher = new FakePanel(value);
} else if (this.widgetAttacher.getWidget(0) != value) {
this.widgetAttacher.detachWidget();
this.widgetAttacher = new FakePanel(value);
}
}
private void setContent(Element element) {
InfoWindowImpl.impl.setContent(getJso(), element);
}
public IsWidget getContentWidget() {
return widgetContent;
}
public final native void addListener(JavaScriptObject jso, String whichEvent, Runnable handler)
/*-{
var that = jso;
$wnd.google.maps.event.addListener(jso, whichEvent, function() {
handler.#java.lang.Runnable::run()();
});
}-*/;
}
I had to build a wrapper over InfoWindow to make it work.
public class NXInfoWindow {
static class FakePanel extends ComplexPanel {
public FakePanel(Widget w) {
w.removeFromParent();
getChildren().add(w);
adopt(w);
}
#Override
public boolean isAttached() {
return true;
}
public void detachWidget() {
this.remove(0);
}
}
private InfoWindow info;
private IsWidget widgetContent = null;
private Long id;
FakePanel widgetAttacher;
public static NXInfoWindow create(Long id){
NXInfoWindow myInfo = new NXInfoWindow();
myInfo.info = InfoWindow.create();
myInfo.id = id;
return myInfo;
};
private void detachWidget() {
if (this.widgetAttacher != null) {
this.widgetAttacher.detachWidget();
this.widgetAttacher = null;
}
}
public void close() {
info.close();
detachWidget();
}
public void setPosition(LatLng posicao) {
info.setPosition(posicao);
}
public void open(GoogleMap map) {
info.open(map);
}
public void setContent(Widget value) {
this.widgetContent = value;
info.setContent(value.getElement());
if (this.widgetAttacher == null) {
addListener(info, "closeclick", new Runnable() {
#Override
public void run() {
detachWidget();
}
});
this.widgetAttacher = new FakePanel(value);
} else if (this.widgetAttacher.getWidget(0) != value) {
this.widgetAttacher.detachWidget();
this.widgetAttacher = new FakePanel(value);
}
}
private void setContent(Element element) {
this.setContent(element);
}
public IsWidget getContentWidget() {
return widgetContent;
}
public final native void addListener(JavaScriptObject jso, String whichEvent, Runnable handler)
/*-{
var that = jso;
$wnd.google.maps.event.addListener(jso, whichEvent, function() {
handler.#java.lang.Runnable::run()();
});
}-*/;
}
Is there anyway to have the autocomplete for a combo box to start from anywhere in the text, let me give you an example. If I have someone named john smith in the combobox if I start with the letter 'j' it pulls up john smith but less say I want to start with the letter 's' to search for his last name, is that possible, if so does anyone have code or a link to code that does this.
Have you looked at SuggestBox? The MultiWordSuggestOracle that feeds the data to the suggest box seems to do exactly what you want - see the javadocs for usage and examples.
Update: Here's a rather nice example of customizing GWT's SuggestBox to look like the one on Facebook: http://raibledesigns.com/rd/entry/creating_a_facebook_style_autocomplete Be sure to follow all the links in that tutorial, as they contain a lot of info about using the SuggestBox.
I been have any problems with AdvancedComboBoxExample sencha
http://www.sencha.com/examples/#ExamplePlace:advancedcombobox
I found in this link http://www.sencha.com/forum/showthread.php?222543-CRTL-C-triggers-a-reload-of-data-in-Combobox the response for my problem.
I had to make some adjustments to my code. Below is the code for those who need it.
ComboBox ajax without paging:
import com.extjs.gxt.ui.client.data.*;
import com.extjs.gxt.ui.client.store.ListStore;
import com.extjs.gxt.ui.client.widget.form.ComboBox;
import com.google.gwt.user.client.rpc.AsyncCallback;
import java.util.List;
import java.util.Map;
public class AjaxComboBox<T extends ModelData> extends ComboBox<T> {
public AjaxComboBox() {
}
public interface GetDataCallback<T> {
void getData(String query, AsyncCallback<List<T>> dataCallback);
}
public AjaxComboBox(final String displayField, final int minChars, final GetDataCallback<T> getDataCallback) {
final RpcProxy<ListLoadResult<T>> proxy = new RpcProxy<ListLoadResult<T>>() {
#Override
protected void load(final Object loadConfig, final AsyncCallback<ListLoadResult<T>> callback) {
ListLoadConfig load = (ListLoadConfig) loadConfig;
final Map<String, Object> properties = load.getProperties();
getDataCallback.getData((String) properties.get("query"), new AsyncCallback<List<T>>() {
public void onFailure(Throwable caught) {
caught.printStackTrace();
}
public void onSuccess(List<T> result) {
callback.onSuccess(new BaseListLoadResult<T>(result));
}
});
}
};
final BaseListLoader<ListLoadResult<T>> loader = new BaseListLoader<ListLoadResult<T>>(proxy);
final ListStore<T> store = new ListStore<T>(loader);
setFieldLabel(displayField);
setStore(store);
setHideTrigger(true);
setMinChars(minChars);
setWidth(300);
}
}
ComboBox lazy with paging
import com.extjs.gxt.ui.client.data.*;
import com.extjs.gxt.ui.client.event.Listener;
import com.extjs.gxt.ui.client.store.ListStore;
import com.extjs.gxt.ui.client.widget.form.ComboBox;
import com.google.gwt.user.client.rpc.AsyncCallback;
import java.util.Map;
public class ComboBoxLazy<T extends ModelData> extends ComboBox<T> {
public interface GetPagingDataCallback<T> {
void getData(String query, PagingLoadConfig loadConfig,
AsyncCallback<PagingLoadResult<T>> dataCallback);
}
public ComboBoxLazy(final String displayField, final int minChars,
final GetPagingDataCallback<T> getDataCallback) {
final RpcProxy<PagingLoadResult<T>> proxy = new RpcProxy<PagingLoadResult<T>>() {
#Override
protected void load(Object loadConfig,
final AsyncCallback<PagingLoadResult<T>> callback) {
final Map<String, Object> properties = ((PagingLoadConfig) loadConfig).getProperties();
getDataCallback.getData((String) properties.get("query"),
((PagingLoadConfig) loadConfig),
new AsyncCallback<PagingLoadResult<T>>() {
#Override
public void onSuccess(
final PagingLoadResult<T> result) {
callback.onSuccess(result);
}
#Override
public void onFailure(Throwable caught) {
callback.onFailure(caught);
}
});
}
};
ModelReader reader = new ModelReader();
final BasePagingLoader<PagingLoadResult<T>> loader = new BasePagingLoader<PagingLoadResult<T>>(
proxy, reader);
loader.addListener(Loader.BeforeLoad, new Listener<LoadEvent>() {
public void handleEvent(LoadEvent be) {
be.<ModelData>getConfig().set("start",
be.<ModelData>getConfig().get("offset"));
}
});
setFieldLabel(displayField);
final ListStore<T> store = new ListStore<T>(loader);
setStore(store);
setHideTrigger(true);
setMinChars(minChars);
setPageSize(10);
setWidth(300);
}
}
Class Test
import br.ueg.escala.client.view.ConversorBeanModel;
import com.extjs.gxt.ui.client.data.*;
import com.extjs.gxt.ui.client.event.SelectionChangedEvent;
import com.extjs.gxt.ui.client.event.SelectionChangedListener;
import com.extjs.gxt.ui.client.widget.LayoutContainer;
import com.extjs.gxt.ui.client.widget.VerticalPanel;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.rpc.AsyncCallback;
import java.util.List;
public class ComboBoxTest extends LayoutContainer {
#Override
protected void onRender(Element parent, int index) {
super.onRender(parent, index);
criarComboBox();
criarComboBoxLazy();
}
private void criarComboBox() {
final AjaxComboBox<BeanModel> combo = new AjaxComboBox<BeanModel>("name", 3, new AjaxComboBox.GetDataCallback<BeanModel>() {
public void getData(String query, final AsyncCallback<List<BeanModel>> dataCallback) {
servico.loadLike(query, new AsyncCallback<List<Person>>() {
public void onFailure(Throwable caught) {
caught.printStackTrace();
}
public void onSuccess(List<Person> result) {
List<BeanModel> dados = ConversorBeanModel.getListBeanModel(result);
dataCallback.onSuccess(dados);
}
});
}
});
combo.addSelectionChangedListener(new SelectionChangedListener<BeanModel>() {
#Override
public void selectionChanged(SelectionChangedEvent<BeanModel> se) {
BeanModel bm = combo.getView().getSelectionModel().getSelectedItem();
Person p = bm.getBean();
combo.setValue(bm);
try {
combo.setValue(bm);
combo.setRawValue(p.getName());
} catch (Exception e) {
e.printStackTrace();
}
}
});
combo.setItemSelector("div.search-item");
combo.setTemplate(getTemplate());
addText("Any text");
add(combo);
}
private void criarComboBoxLazy() {
String field = "name";
final ComboBoxLazy<BeanModel> comboLazy = new ComboBoxLazy<BeanModel>(field, 3, new ComboBoxLazy.GetPagingDataCallback<BeanModel>() {
public void getData(String query, PagingLoadConfig loadConfig, final AsyncCallback<PagingLoadResult<BeanModel>> dataCallback) {
final PagingLoadConfig load = (PagingLoadConfig) loadConfig;
servico.loadLike(load, new Person(), "name", query, new AsyncCallback<List>() {
public void onFailure(Throwable caught) {
caught.printStackTrace();
}
public void onSuccess(List result) {
PagingLoadResult<BeanModel> dados = ConversorBeanModel.getPagingLoadResultBeanModel(result, load);
dataCallback.onSuccess(dados);
}
});
}
});
comboLazy.addSelectionChangedListener(new SelectionChangedListener<BeanModel>() {
#Override
public void selectionChanged(SelectionChangedEvent<BeanModel> se) {
BeanModel bm = comboLazy.getView().getSelectionModel().getSelectedItem();
Person p = bm.getBean();
comboLazy.setValue(bm);
try {
comboLazy.setValue(bm);
comboLazy.setRawValue(p.getName());
} catch (Exception e) {
e.printStackTrace();
}
}
});
comboLazy.setItemSelector("div.search-item");
comboLazy.setTemplate(getTemplate());
VerticalPanel vp2 = new VerticalPanel();
vp2.setSpacing(10);
vp2.addText("<span class='text'><b>Combo lazy</span>");
vp2.add(comboLazy);
add(vp2);
}
private native String getTemplate() /*-{
return [ '<tpl for="."><div class="search-item">',
' <h3> <span> Name:</span> <span style="font-weight:normal;">{name}</span> ',
' <span> - Last name:</span> <span style="font-weight: normal">{lastName}</span></h3>', '</div></tpl>'].join("");
}-*/;
}
Application.css:
.searchItem {
font: normal 11px tahoma, arial, helvetica, sans-serif;
padding: 3px 10px 3px 10px;
white-space: normal;
color: #555;
}
.searchItem h3 {
display: block;
font: inherit;
font-weight: bold;
color: #222;
}
.searchItem h3 span {
float: right;
font-weight: normal;
margin: 0 0 5px 5px;
width: 100px;
display: block;
clear: none;
}
Code server
public List loadLike(PagingLoadConfig config, Person classe, String field, String query) {
List<Person> list = null;
try {
List listEntity = genericoBC.loadLike(config.getOffset(), config.getLimit(), field, query, classe.getClass());
list = clone(listEntity);
final int totalCount = genericoBC.contarRegistros(classe.getClass());
config.setLimit(totalCount);
} catch (Exception e) {
tratarExcecao("", e);
}
return list;
}
public List<Person> loadLike(String query) {
List<Person> list = null;
try {
List<Person> listEntity = genericoBC.loadLike(query);
list = clone(listEntity);
} catch (Exception e) {
tratarExcecao("Error:genericoBC.loadLike(query)", e);
}
return list;
}
Override the method boolean isFiltered(ModelData record, String property) of the ListStore of the combobox.The method body will be following:
if (filterBeginsWith != null && property != null) {
Object o = record.get(property);
if (o != null) {
if (!o.toString().toLowerCase().contains(filterBeginsWith.toLowerCase())) {
return true;
}
}
}
if (filters != null) {
for (StoreFilter filter : filters) {
boolean result = filter.select(this, record, record, property);
if (!result) {
return true;
}
}
}
return false;
This is for GXT 3.0.
First, create an instance of the overridden ListStore class like this:
public static class MyListStore extends ListStore<Course>{
private String userText="";
public MyListStore(ModelKeyProvider<Course> k){
super(k);
}
#Override
protected boolean isFilteredOut(Course item) {
boolean result = false;
if(item.getTitle()!=null &&
!item.getTitle().toUpperCase().contains(userText.toUpperCase())){
result = true;
}
return result;
}
public void setUserText(String t){ userText = t; }
}
In this case, I had a Course model class that had the course title (a string) as the label provider for the combobox. So in your overridden class, do similar: use your specific model (the type of this instance of the combobox) in place of 'Course' in the code above.
Next, create an instance of this store for use by the combobox:
private MyListStore courses ;
Next, make sure you initialize the combobox appropriately with this. In my case, I used uibinder, so my initializer is this:
#UiFactory
ListStore<Course> createListStore() {
courses = new MyListStore(courseProps.key());
return courses;
}
The relevant uibinder snippets:
<ui:with type="com.sencha.gxt.data.shared.LabelProvider" field="titles"/>
<ui:with type="com.sencha.gxt.data.shared.ListStore" field="courses"/>
...
<form:ComboBox ui:field="classTitle" store="{courses}" labelProvider="{titles}"
allowBlank="false" forceSelection="true" triggerAction="ALL" width="200" />
Of course, the linkage into your bound java class:
#UiField ComboBox<Course> classTitle;
And, finally, make sure you handle the keyup event from the combobox input:
classTitle.addKeyUpHandler(new KeyUpHandler(){
#Override
public void onKeyUp(KeyUpEvent event) {
courses.setUserText(classTitle.getText());
}
});
This worked perfectly (first time!).