GWT: TextArea in Column - gwt

I've dabbled in GWT in the past and know just enough to burn myself. My current hurt can be described as follows:
I have a CellTable. This contains a number of Columns and TextColumns. The TextColumns contain variables from a report object, the Columns render radio buttons, check boxes etc.
I would like to insert another column which will provide a TextArea per table row, into which the user can enter some text.
My problem is I cannot figure out how to create the TextArea.
Could anyone possibly give me a code snippet to get me started?

Have a look at this showcase: http://gwt.google.com/samples/Showcase/Showcase.html#!CwCellSampler. You can use a TextInputCell for your purpose.

There's no built-in cell with a textarea as input, but it's easy to create one yourself. See http://code.google.com/webtoolkit/doc/latest/DevGuideUiCustomCells.html
(and have a look at either the TextInputCell or EditTextCell source code as a guide)

I've modeled my TextAreaInputCell after the TextInputCell that GWT ships with. It's basically the same code, except that the Template info is specific to a textarea (you can copy/paste this class, it's fully functional):
package com.xxx.scorecard.client.view.cell;
import com.google.gwt.cell.client.AbstractCell;
import com.google.gwt.cell.client.AbstractInputCell;
import com.google.gwt.cell.client.ValueUpdater;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.InputElement;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.safehtml.client.SafeHtmlTemplates;
import com.google.gwt.safehtml.client.SafeHtmlTemplates.Template;
import com.google.gwt.safehtml.shared.SafeHtml;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
/**
* An {#link AbstractCell} used to render a text input.
*/
public class TextAreaInputCell extends AbstractInputCell<String, TextAreaInputCell.ViewData> {
interface Template extends SafeHtmlTemplates {
#Template("<textarea type=\"text\" cols=\"30\" rows=\"5\" tabindex=\"-1\">{0}</textarea>")
SafeHtml input(String value);
}
/**
* The {#code ViewData} for this cell.
*/
public static class ViewData {
/**
* The last value that was updated.
*/
private String lastValue;
/**
* The current value.
*/
private String curValue;
/**
* Construct a ViewData instance containing a given value.
*
* #param value
* a String value
*/
public ViewData(String value) {
this.lastValue = value;
this.curValue = value;
}
/**
* Return true if the last and current values of this ViewData object
* are equal to those of the other object.
*/
#Override
public boolean equals(Object other) {
if (!(other instanceof ViewData)) {
return false;
}
ViewData vd = (ViewData) other;
return equalsOrNull(lastValue, vd.lastValue) && equalsOrNull(curValue, vd.curValue);
}
/**
* Return the current value of the input element.
*
* #return the current value String
* #see #setCurrentValue(String)
*/
public String getCurrentValue() {
return curValue;
}
/**
* Return the last value sent to the {#link ValueUpdater}.
*
* #return the last value String
* #see #setLastValue(String)
*/
public String getLastValue() {
return lastValue;
}
/**
* Return a hash code based on the last and current values.
*/
#Override
public int hashCode() {
return (lastValue + "_*!#HASH_SEPARATOR#!*_" + curValue).hashCode();
}
/**
* Set the current value.
*
* #param curValue
* the current value
* #see #getCurrentValue()
*/
protected void setCurrentValue(String curValue) {
this.curValue = curValue;
}
/**
* Set the last value.
*
* #param lastValue
* the last value
* #see #getLastValue()
*/
protected void setLastValue(String lastValue) {
this.lastValue = lastValue;
}
private boolean equalsOrNull(Object a, Object b) {
return (a != null) ? a.equals(b) : ((b == null) ? true : false);
}
}
private static Template template;
/**
* Constructs a TextInputCell that renders its text without HTML markup.
*/
public TextAreaInputCell() {
super("change", "keyup");
if (template == null) {
template = GWT.create(Template.class);
}
}
#Override
public void onBrowserEvent(Context context, Element parent, String value, NativeEvent event,
ValueUpdater<String> valueUpdater) {
super.onBrowserEvent(context, parent, value, event, valueUpdater);
// Ignore events that don't target the input.
InputElement input = getInputElement(parent);
Element target = event.getEventTarget().cast();
if (!input.isOrHasChild(target)) {
return;
}
String eventType = event.getType();
Object key = context.getKey();
if ("change".equals(eventType)) {
finishEditing(parent, value, key, valueUpdater);
} else if ("keyup".equals(eventType)) {
// Record keys as they are typed.
ViewData vd = getViewData(key);
if (vd == null) {
vd = new ViewData(value);
setViewData(key, vd);
}
vd.setCurrentValue(input.getValue());
}
}
#Override
public void render(Context context, String value, SafeHtmlBuilder sb) {
// Get the view data.
Object key = context.getKey();
ViewData viewData = getViewData(key);
if (viewData != null && viewData.getCurrentValue().equals(value)) {
clearViewData(key);
viewData = null;
}
String s = (viewData != null) ? viewData.getCurrentValue() : value;
if (s != null) {
sb.append(template.input(s));
} else {
sb.appendHtmlConstant("<input type=\"text\" tabindex=\"-1\"></input>");
}
}
#Override
protected void finishEditing(Element parent, String value, Object key, ValueUpdater<String> valueUpdater) {
String newValue = getInputElement(parent).getValue();
// Get the view data.
ViewData vd = getViewData(key);
if (vd == null) {
vd = new ViewData(value);
setViewData(key, vd);
}
vd.setCurrentValue(newValue);
// Fire the value updater if the value has changed.
if (valueUpdater != null && !vd.getCurrentValue().equals(vd.getLastValue())) {
vd.setLastValue(newValue);
valueUpdater.update(newValue);
}
// Blur the element.
super.finishEditing(parent, newValue, key, valueUpdater);
}
#Override
protected InputElement getInputElement(Element parent) {
return super.getInputElement(parent).<InputElement> cast();
}
}
And here's how you use the cell:
Column<ScorecardEntryDTO, String> commentColumn = new Column<ScorecardEntryDTO, String>(new TextAreaInputCell()) {
#Override
public String getValue(ScorecardEntryDTO object) {
return object.getComment();
}
};

Try some like this:
TextArea outputArea = new TextArea();
outputArea.getElement().setAttribute("cols", "100");
outputArea.getElement().setAttribute("rows", "20");
locPanel.add(outputArea);

Related

Why "mouseover".equals(event.getType()) is not recognized in GWT Header?

I have a table with a nameColumn.
I want that when user mouseOver the title of nameColumn it will trigger a method
I tried:
Header<String> nameColumnHeader = new Header<String>(new ClickableTextCell()) {
#Override
public String getValue() {
return "Name";
}
#Override
public final void onBrowserEvent(Context context, Element elem, NativeEvent event) {
if ("mouseover".equals(event.getType())) {
//
meaningMessagesPopup.show();
}
else if("mouseout".equals(event.getType())){
meaningMessagesPopup.hide();
}
}
};
table.addColumn(nameColumn, nameColumnHeader);
But seem Gwt did not recognize "mouseover".equals(event.getType())
Do you know how to do the MOUSEOVER event in GWT Header?
i found the answer, that is to create a CustomCell that extends AbstractCell
private class HeaderCell extends AbstractCell<String> {
private String text;
public HeaderCell(String text) {
/*
* Let the parent class know that our cell responds to click events and
* keydown events.
*/
//super("click", "keydown");
super("mouseover");
this.text=text;
}
#Override
public void onBrowserEvent(Context context, Element parent, String value,
NativeEvent event, ValueUpdater<String> valueUpdater) {
// Check that the value is not null.
if (value == null) {
return;
}
// Call the super handler, which handlers the enter key.
super.onBrowserEvent(context, parent, value, event, valueUpdater);
if ("mouseover".equals(event.getType())) {
SafeHtmlBuilder sb=new SafeHtmlBuilder();
sb.appendHtmlConstant("<b>");
sb.appendHtmlConstant("<font color=\"blue\">");
sb.appendEscaped(text);
sb.appendHtmlConstant("</font></b>");
meaningMessagesPopup.setWidget(new HTML(sb.toSafeHtml()));
int left = event.getClientX() -140;
int top = event.getClientY() +30;
meaningMessagesPopup.setPopupPosition(left, top);
// Show the popup
meaningMessagesPopup.show();
}
else if ("mouseout".equals(event.getType())) {
meaningMessagesPopup.hide();
}
}
#Override
public void render(Context context, String value, SafeHtmlBuilder sb) {
/*
* Always do a null check on the value. Cell widgets can pass null to
* cells if the underlying data contains a null, or if the data arrives
* out of order.
*/
if (value == null) {
return;
}
sb.appendEscaped(value);
}
}
Then
Header<String> nameColumnHeader = new Header<String>(new HeaderCell("my Text...")) {
#Override
public String getValue() {
return "Name";
}
};
table.addColumn(nameColumn, nameColumnHeader);

I want to attach a widget to a cell built using TableCellBuilder in GWT . How do I do it?

I have a table declared and initialised in the following manner
TableRowBuilder detailCell;
detailCell = startRow();
TableCellBuilder td = detailCell.startTD();
Now I have an anchor declared and initialised in the following manner
Anchor removeAnchor = new Anchor(rowValue);
removeAnchor.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent arg0) {
Window.alert("clicked");
}
});
td.html(new SafeHtmlBuilder().appendHtmlConstant(removeAnchor.toString()).toSafeHtml());
detailCell.endTD();
Because I am not directly appending that anchor to the cell , the click event is not being handled. What I want is to append the anchor to the cell.How do I do it?
How about using JSNI
http://www.gwtproject.org/doc/latest/DevGuideCodingBasicsJSNI.html#calling
public void onModuleLoad() {
exportStaticMethod();
HTML html=new HTML("<a onclick='doAlert()'>hello</a>");
RootPanel.get().add(html);
}
public final static void doAlert(){
Window.alert("hello");
}
public static native void exportStaticMethod() /*-{
$wnd.doAlert =
$entry(#com.akjava.gwt.test2.client.GWTTest2::doAlert());
}-*/;
It's not the use case of the CellTable.
You can create a custom Cell for your use case :
http://www.gwtproject.org/doc/latest/DevGuideUiCustomCells.html
static class AnchorCell extends AbstractCell<String> {
/**
* The HTML templates used to render the cell.
*/
interface Templates extends SafeHtmlTemplates {
/**
* The template for this Cell, which includes a balise.
*
* #param value the safe value. Since the value type is {#link SafeHtml},
* it will not be escaped before including it in the template.
* Alternatively, you could make the value type String, in which
* case the value would be escaped.
* #return a {#link SafeHtml} instance
*/
#SafeHtmlTemplates.Template("<a href=\"javascript:;\">{0}</div>")
SafeHtml cell(SafeHtml value);
}
/**
* Create a singleton instance of the templates used to render the cell.
*/
private static Templates templates = GWT.create(Templates.class);
public AnchorCell() {
/*
* Sink the click and keydown events. We handle click events in this
* class. AbstractCell will handle the keydown event and call
* onEnterKeyDown() if the user presses the enter key while the cell is
* selected.
*/
super("click", "keydown");
}
/**
* Called when an event occurs in a rendered instance of this Cell. The
* parent element refers to the element that contains the rendered cell, NOT
* to the outermost element that the Cell rendered.
*/
#Override
public void onBrowserEvent(Context context, Element parent, String value, NativeEvent event,
ValueUpdater<String> valueUpdater) {
// Let AbstractCell handle the keydown event.
super.onBrowserEvent(context, parent, value, event, valueUpdater);
// Handle the click event.
if ("click".equals(event.getType())) {
// Ignore clicks that occur outside of the outermost element.
EventTarget eventTarget = event.getEventTarget();
if (parent.getFirstChildElement().isOrHasChild(Element.as(eventTarget))) {
doAction(value, valueUpdater);
}
}
}
#Override
public void render(Context context, String value, SafeHtmlBuilder sb) {
/*
* Always do a null check on the value. Cell widgets can pass null to
* cells if the underlying data contains a null, or if the data arrives
* out of order.
*/
if (value == null) {
return;
}
// If the value comes from the user, we escape it to avoid XSS attacks.
SafeHtml safeValue = SafeHtmlUtils.fromString(value);
SafeHtml rendered = templates.cell(safeValue);
sb.append(rendered);
}
/**
* onEnterKeyDown is called when the user presses the ENTER key will the
* Cell is selected. You are not required to override this method, but its a
* common convention that allows your cell to respond to key events.
*/
#Override
protected void onEnterKeyDown(Context context, Element parent, String value, NativeEvent event,
ValueUpdater<String> valueUpdater) {
doAction(value, valueUpdater);
}
private void doAction(String value, ValueUpdater<String> valueUpdater) {
// Alert the user that they selected a value.
Window.alert("You clicked on " + value);
// Trigger a value updater. In this case, the value doesn't actually
// change, but we use a ValueUpdater to let the app know that a value
// was clicked.
valueUpdater.update(value);
}
}

how to convert flextable cell into editable text cell in GWT

Here is the code I tried to make the flextable's cell editable
The flex table is loaded with db values, when user clicks on the cell of flextable, it has to become editable and the user entered value has to be stored in db, after the user clicks submit button which is present at each row.
I'm using EditTextCell(), to make the cell editable but it not becoming editable when I test it. I have included all my codes below. Please let me know , if i'm missing anything.
private List<PendingChange<?>> pendingChanges = new ArrayList<PendingChange<?>>();
private List<AbstractEditableCell<?, ?>> editableCells = new ArrayList<AbstractEditableCell<?, ?>>();
CellTable cellTable= new CellTable<MessageEvent>();
EditTextCell editCell = new EditTextCell();
protected FlexTable flextable;
//flextable creation
private final void createWorkflows(List<MessageEvent> theWorkflowMessageEvents, boolean isSelectAll) {
int row = 1;
if (theWorkflowMessageEvents != null) {
for (final MessageEvent workflowMessageEvent : theWorkflowMessageEvents) {
flextable.getRowFormatter().setStyleName(row,ACTIVE_COLLECTION);
flextable.getCellFormatter().setHorizontalAlignment(row, 0, HasHorizontalAlignment.ALIGN_LEFT);
flextable.getCellFormatter().setWordWrap(row, 0, false);
flextable.setText(row, 0, workflowMessageEvent.getTransferReceived());
flextable.getCellFormatter().setHorizontalAlignment(row, 1, HasHorizontalAlignment.ALIGN_LEFT);
flextable.getCellFormatter().setWordWrap(row, 1, false);
flextable.setText(row, 1, workflowMessageEvent.getLoadReceived());
makeFlexTableEditable() ;
Button submitButton= new Button("Submit");
flextable.getCellFormatter().setHorizontalAlignment(row, 3, HasHorizontalAlignment.ALIGN_LEFT);
flextable.getCellFormatter().setWordWrap(row, 3, false);
flextable.setWidget(row, 3,submitButton );
submitWorklow(submitButton,row, workflowMessageEvent);
flextable.getRowFormatter().setVisible(row, true);
row++;
}
}
}
//adding flextable to main panel
protected void displayPendingWorkflows(final List<MessageEvent> theWorkflowMessageEvents) {
this.createPendingWorkflows(theWorkflowMessageEvents, false);
//some code
mainPanel.add(flextable);
mainPanel.add(cellTable);
}
//code for making flex table editable for TransferReceived column
private void makeFlexTableEditable() {
addColumn(new EditTextCell(), new GetValue() {
#Override
public String getValue(MessageEvent workflowMessageEvent) {
return workflowMessageEvent.getTransferReceived();
}
}, new FieldUpdater<MessageEvent, String>() {
public void update(int index, MessageEvent workflowMessageEvent, String value) {
try { pendingChanges.add(new TransferReceived(workflowMessageEvent, value));
}catch (Exception e) {
}
}
});
}
private <C> Column<MessageEvent, String> addColumn(EditTextCell cell,
final GetValue<String> getter,FieldUpdater<MessageEvent, String> fieldUpdater) {
Column<MessageEvent, String> transColumn = new Column<MessageEvent, String>(cell){
#Override
public String getValue(MessageEvent object) {
return getter.getValue(object);
}
};
transColumn.setFieldUpdater(fieldUpdater);
if (cell instanceof AbstractEditableCell<?, ?>) {
editableCells.add((AbstractEditableCell<?, ?>) cell);
}
cellTable.addColumn(transColumn);
return transColumn;
}
/**
* A pending change to a {#link MessageEvent}. Changes aren't committed
* immediately to illustrate that cells can remember their pending changes.
*
* #param <T> the data type being changed
*/
private abstract static class PendingChange<T> {
private final MessageEvent message;
private final T value;
public PendingChange(MessageEvent message, T value) {
this.message = message;
this.value = value;
}
/**
* Commit the change to the contact.
*/
public void commit() {
doCommit(message, value);
}
/**
* Update the appropriate field in the .
*
* #param message to update
* #param value the new value
*/
protected abstract void doCommit(MessageEvent message, T value);
}
/**
* Updates the Transfered Received.
*/
private static class TransferReceived extends PendingChange<String> {
public TransferReceived(MessageEvent message, String value) {
super(message, value);
}
#Override
protected void doCommit(MessageEvent message, String value) {
message.setTransferReceived(value);
}
}
/**
* Get a cell value from a record.
*
* #param <C> the cell type
*/
private static interface GetValue<C> {
C getValue(MessageEvent message);
}
I did something like this in my app. Sorry if the syntax is a bit off but the main idea is to use a clickevent and then get this events position and exchange the widget in that position.
final FlexTable flexTable = new FlexTable();
flexTable.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
Cell cell = flexTable.getCellForClickEvent(event);
final int row = cell.getRow();
final int column = cell.getIndex();
final TextBox textBox = new TextBox();
// Get the text from the cell in some way. Maybe use flextTable.getHTML(row, column) or what ever you prefer
// textBox.setText("Something other than this");
textBox.addKeyDownHandler(new KeyDownHandler() {
public void onKeyDownEvent(KeyDownEvent event) {
int code = event.getNativeKeyCode();
if (KeyCodes.KEY_ENTER == code) {
flexTable.setWidget(row, column, new Label(textBox.getText()));
}
}
});
flexTable.setWidget(row, column, textBox);
// You may also need something like this
textBox.setFocus(true);
}
});

How to add multiple lines of text in GWT celltable EditTextCell?

I have a celltable displayed with data. I want to edit the cells to give information in multiple lines.
Example:
key1=value1| In next line add anoter key:
key2=value2|
After editing the values, when the celltable is displayed/ redrawn then the info should be displayed as above in the cells.
I have solved part of the issue. I am using CellTable with customized TextAreaEditCell. Now I am able to enter multiple lines of data. But when it goes to database or when celltable displayed the information, the info is in sequential form.
Example:
when i enter data like this in TestAreaCell:
abcd
In next line, enter efgh then the
Output when displayed is:
abcdefgh
Issue: Seems the enter key is not getting considered:
My TextAreaEditCell class is below. Please let me know if any corrections need to be done.
I have solved part of the issue. I am using CellTable with customized TextAreaEditCell. Now I am able to enter multiple lines of data. But when it goes to database or when celltable displayed the information, the info is in sequential form.
Example:
when i enter data like this in TestAreaCell:
abcd
In next line, enter efgh then the
Output when displayed is:
abcdefgh
Issue: Seems the enter key is not getting considered:
My TestAreaEditCell class is below. Please let me know if any corrections need to be done.
import com.google.gwt.cell.client.AbstractEditableCell;
import com.google.gwt.cell.client.Cell.Context;
import com.google.gwt.cell.client.ValueUpdater;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.EventTarget;
import com.google.gwt.dom.client.InputElement;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.dom.client.TextAreaElement;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.safehtml.client.SafeHtmlTemplates;
import com.google.gwt.safehtml.shared.SafeHtml;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.text.shared.SafeHtmlRenderer;
import com.google.gwt.text.shared.SimpleSafeHtmlRenderer;
/**
* An editable text cell. Click to edit, escape to cancel, return to commit.
*/
public class TextAreaEditCell extends
AbstractEditableCell<String, TextAreaEditCell .ViewData> {
interface Template extends SafeHtmlTemplates {
//#Template("<input type=\"text\" value=\"{0}\" tabindex=\"-1\"></input>")
//SafeHtml input(String value);
//using textarea (instead of text) to add multiple lines of data in a cell.
#Template("<textarea tabindex=\"-1\" rows=\"{1}\" cols=\"{2}\" >{0}</textarea>")
SafeHtml input(String value, Integer rows, Integer cols);
}
/**
* The view data object used by this cell. We need to store both the text and
* the state because this cell is rendered differently in edit mode. If we did
* not store the edit state, refreshing the cell with view data would always
* put us in to edit state, rendering a text box instead of the new text
* string.
*/
static class ViewData {
private boolean isEditing;
/**
* If true, this is not the first edit.
*/
private boolean isEditingAgain;
/**
* Keep track of the original value at the start of the edit, which might be
* the edited value from the previous edit and NOT the actual value.
*/
private String original;
private String text;
/**
* Construct a new ViewData in editing mode.
*
* #param text the text to edit
*/
public ViewData(String text) {
this.original = text;
this.text = text;
this.isEditing = true;
this.isEditingAgain = false;
}
#Override
public boolean equals(Object o) {
if (o == null) {
return false;
}
ViewData vd = (ViewData) o;
return equalsOrBothNull(original, vd.original)
&& equalsOrBothNull(text, vd.text) && isEditing == vd.isEditing
&& isEditingAgain == vd.isEditingAgain;
}
public String getOriginal() {
return original;
}
public String getText() {
return text;
}
#Override
public int hashCode() {
return original.hashCode() + text.hashCode()
+ Boolean.valueOf(isEditing).hashCode() * 29
+ Boolean.valueOf(isEditingAgain).hashCode();
}
public boolean isEditing() {
return isEditing;
}
public boolean isEditingAgain() {
return isEditingAgain;
}
public void setEditing(boolean isEditing) {
boolean wasEditing = this.isEditing;
this.isEditing = isEditing;
// This is a subsequent edit, so start from where we left off.
if (!wasEditing && isEditing) {
isEditingAgain = true;
original = text;
}
}
public void setText(String text) {
this.text = text;
}
private boolean equalsOrBothNull(Object o1, Object o2) {
return (o1 == null) ? o2 == null : o1.equals(o2);
}
}
private static Template template;
private int inputWidth;
private int inputLength;
public int getInputWidth() {
return inputWidth;
}
public void setInputWidth(int inputWidth) {
this.inputWidth = inputWidth;
}
public int getInputLength() {
return inputLength;
}
public void setInputLength(int inputLength) {
this.inputLength = inputLength;
}
private final SafeHtmlRenderer<String> renderer;
/**
* Construct a new EditTextCell that will use a
* {#link SimpleSafeHtmlRenderer}.
*/
public TextAreaEditCell() {
this(SimpleSafeHtmlRenderer.getInstance(), 1, 20);
this.inputWidth = 10;
this.inputLength =2;
}
private int rows, cols;
/**
* Construct a new TextAreaEditCell that will use a given {#link SafeHtmlRenderer}
* to render the value when not in edit mode.
*
* #param renderer a {#link SafeHtmlRenderer SafeHtmlRenderer<String>}
* instance
*/
public TextAreaEditCell(SafeHtmlRenderer<String> renderer, int r, int c) {
super("click", "keyup", "keydown", "blur");
rows = r;
cols = c;
if (template == null) {
template = GWT.create(Template.class);
}
if (renderer == null) {
throw new IllegalArgumentException("renderer == null");
}
this.renderer = renderer;
}
#Override
public boolean isEditing(Context context, Element parent, String value) {
ViewData viewData = getViewData(context.getKey());
return viewData == null ? false : viewData.isEditing();
}
#Override
public void onBrowserEvent(Context context, Element parent, String value,
NativeEvent event, ValueUpdater<String> valueUpdater) {
Object key = context.getKey();
ViewData viewData = getViewData(key);
if (viewData != null && viewData.isEditing()) {
// Handle the edit event.
editEvent(context, parent, value, viewData, event, valueUpdater);
} else {
String type = event.getType();
int keyCode = event.getKeyCode();
boolean enterPressed = "keyup".equals(type) ;
// && keyCode == KeyCodes.KEY_ENTER;
if ("click".equals(type) || enterPressed) {
// Go into edit mode.
if (viewData == null) {
viewData = new ViewData(value);
setViewData(key, viewData);
} else {
viewData.setEditing(true);
}
edit(context, parent, value);
}
}
}
#Override
public void render(Context context, String value, SafeHtmlBuilder sb) {
// Get the view data.
Object key = context.getKey();
ViewData viewData = getViewData(key);
if (viewData != null && !viewData.isEditing() && value != null
&& value.equals(viewData.getText())) {
clearViewData(key);
viewData = null;
}
if (viewData != null) {
String text = viewData.getText();
if (viewData.isEditing()) {
/*
* Do not use the renderer in edit mode because the value of a text
* input element is always treated as text. SafeHtml isn't valid in the
* context of the value attribute.
*/
sb.append(template.input(text, inputLength, inputWidth));
}
else {
// The user pressed enter, but view data still exists.
sb.append(renderer.render(text));
}
} else if (value != null) {
sb.append(renderer.render(value));
}
}
#Override
public boolean resetFocus(Context context, Element parent, String value) {
if (isEditing(context, parent, value)) {
getInputElement(parent).focus();
return true;
}
return false;
}
/**
* Convert the cell to edit mode.
*
* #param context the {#link Context} of the cell
* #param parent the parent element
* #param value the current value
*/
protected void edit(Context context, Element parent, String value) {
setValue(context, parent, value);
TextAreaElement input = getInputElement(parent);
input.focus();
input.select();
}
/**
* Convert the cell to non-edit mode.
*
* #param context the context of the cell
* #param parent the parent Element
* #param value the value associated with the cell
*/
private void cancel(Context context, Element parent, String value) {
clearInput(getInputElement(parent));
setValue(context, parent, value);
}
/**
* Clear selected from the input element. Both Firefox and IE fire spurious
* onblur events after the input is removed from the DOM if selection is not
* cleared.
*
* #param input the input element
*/
private native void clearInput(Element input) /*-{
if (input.selectionEnd)
input.selectionEnd = input.selectionStart;
else if ($doc.selection)
$doc.selection.clear();
}-*/;
/**
* Commit the current value.
*
* #param context the context of the cell
* #param parent the parent Element
* #param viewData the {#link ViewData} object
* #param valueUpdater the {#link ValueUpdater}
*/
private void commit(Context context, Element parent, ViewData viewData,
ValueUpdater<String> valueUpdater) {
String value = updateViewData(parent, viewData, false);
clearInput(getInputElement(parent));
setValue(context, parent, viewData.getOriginal());
if (valueUpdater != null) {
valueUpdater.update(value);
}
}
private void editEvent(Context context, Element parent, String value,
ViewData viewData, NativeEvent event, ValueUpdater<String> valueUpdater) {
String type = event.getType();
boolean keyUp = "keyup".equals(type);
boolean keyDown = "keydown".equals(type);
if (keyUp || keyDown) {
int keyCode = event.getKeyCode();
/* if (keyUp && keyCode == KeyCodes.KEY_ENTER) {
// Commit the change.
commit(context, parent, viewData, valueUpdater);
}
else*/
if (keyUp && keyCode == KeyCodes.KEY_ESCAPE) {
// Cancel edit mode.
String originalText = viewData.getOriginal();
if (viewData.isEditingAgain()) {
viewData.setText(originalText);
viewData.setEditing(false);
} else {
setViewData(context.getKey(), null);
}
cancel(context, parent, value);
} else {
// Update the text in the view data on each key.
updateViewData(parent, viewData, true);
}
} else if ("blur".equals(type)) {
// Commit the change. Ensure that we are blurring the input element and
// not the parent element itself.
EventTarget eventTarget = event.getEventTarget();
if (Element.is(eventTarget)) {
Element target = Element.as(eventTarget);
if ("textarea".equals(target.getTagName().toLowerCase())) {
commit(context, parent, viewData, valueUpdater);
}
}
}
}
/**
* Get the input element in edit mode.
*/
private TextAreaElement getInputElement(Element parent) {
return parent.getFirstChild().<TextAreaElement> cast();
}
/**
* Update the view data based on the current value.
*
* #param parent the parent element
* #param viewData the {#link ViewData} object to update
* #param isEditing true if in edit mode
* #return the new value
*/
private String updateViewData(Element parent, ViewData viewData,
boolean isEditing) {
TextAreaElement input = (TextAreaElement) parent.getFirstChild();
String value = input.getValue();
viewData.setText(value);
viewData.setEditing(isEditing);
return value;
}
}
I have done a similar thing; although not exactly the same. So maybe SOMETHING like this will work.
You need to provide your own render() method. So in the render() method below, you can add whatever you want.
Column selectCheckBoxColumn =
new Column(new MyCheckBoxCell()) {
#Override
public String getValue(MyJSONObject object) {
return object.getInternalId();
}
};
MyCellTable.addColumn(selectCheckBoxColumn, "Display title");
.....
.....
.....
private class MyCheckBoxCell extends AbstractCell<String> {
#Override
public void render(Context context, String value, SafeHtmlBuilder sb) {
/*
* Always do a null check on the value. Cell widgets can pass null to
* cells if the underlying data contains a null, or if the data arrives
* out of order.
*/
if (value == null) {
return;
}
sb.appendHtmlConstant("<input type='checkbox' name='" + htmlDOMId1 + "'" +
" id='" + htmlDOMId1 + "'" +
" value='" + value + "'" +
"></input>");
}
}
You have to convert the line-breaks (\n) to HTML line breaks (<BR>)
Either you can do this when you save the data on your backend or you can do it in the render method of your TextAreaEditCell
Something like that:
#Override
public void render(Context context, String value, SafeHtmlBuilder sb) {
// Get the view data.
Object key = context.getKey();
ViewData viewData = getViewData(key);
if (viewData != null && !viewData.isEditing() && value != null
&& value.equals(viewData.getText())) {
clearViewData(key);
viewData = null;
}
if (viewData != null) {
String text = viewData.getText();
if (viewData.isEditing()) {
/*
* Do not use the renderer in edit mode because the value of a text
* input element is always treated as text. SafeHtml isn't valid in the
* context of the value attribute.
*/
sb.append(template.input(text, inputLength, inputWidth));
}
else {
// The user pressed enter, but view data still exists.
String escaped_text = text.replace("\n","<BR>").replace("\r","");
sb.append(renderer.render(escaped_text));
}
} else if (value != null) {
String escaped_text = value.replace("\n","<BR>").replace("\r","");
sb.append(renderer.render(escaped_text));
}
}
Here is a working solution of the render method which will display multi line in a TextAreaEditCell. Basically you are splitting the stored string based on the \n character and then joining them appending the tag as a HTML constant for the SafeBuilder.
#Override
public void render(Context context, String value, SafeHtmlBuilder sb) {
// Get the view data.
Object key = context.getKey();
ViewData viewData = getViewData(key);
if (viewData != null && !viewData.isEditing() && value != null
&& value.equals(viewData.getText())) {
clearViewData(key);
viewData = null;
/*
* Render a blank space to force the rendered element to have a height.
* Otherwise it is not clickable.
*/
sb.appendHtmlConstant("\u00A0");
}
if (viewData != null) {
String text = viewData.getText();
if (viewData.isEditing()) {
/*
* Do not use the renderer in edit mode because the value of a text
* input element is always treated as text. SafeHtml isn't valid in the
* context of the value attribute.
*/
sb.append(template.input(text, inputLength, inputWidth));
}
else {
// The user pressed enter, but view data still exists.
String[] items = text.split("\n");
for (String item : items) {
sb.append(renderer.render(item));
sb.appendHtmlConstant("<br/>");
}
sb.appendHtmlConstant("\u00A0");
}
} else if (value != null) {
String[] items = value.split("\n");
for (String item : items) {
sb.append(renderer.render(item));
sb.appendHtmlConstant("<br/>");
}
/*
* Render a blank space to force the rendered element to have a height.
* Otherwise it is not clickable.
*/
sb.appendHtmlConstant("\u00A0");
}
}

Layout problems in FieldEditorPreferencePage

I have following problems with layout settings in the FieldEditorPreferencePage.
My code is something like this:
public void createFieldEditors () {
Group pv = new group(getfieldEditorParent(), SWT.SHADOW_OUT);
Group of = new group(getfieldEditorParent(), SWT.SHADOW_OUT);
pv.setText(“pv”);
of.setText(“of”);
GridLayout layout = new GridLayout(2,false);
pv.setLayout(layout);
of.setLayout(layout);
addField(new StringFieldEditor(“PreferenceStore name”,“Text:”, pv);
addField(new StringFieldEditor(“PreferenceStore name”,“Text:”, pv);
addField(new StringFieldEditor(“PreferenceStore name”,“Text:”, of);
addField(new StringFieldEditor(“PreferenceStore name”,“Text:”, of);
and so on.
}
The problem is that it does not work with GridLayout.
The StringFieldEditors are not parallel. The number of columns is always 1. Also when I try to change the size of StringFieldEditors in the groups, it doesn’t work too.
Anybody have any ideas?
Thanks.
The problem is that when you are using FieldEditorPreferencePage, you can use only FieldEditor subclasses as components. Here's a snippet from a documentation:
FieldEditorPreferencePage implements a
page that uses these field editors to
display and store the preference
values on the page. Instead of
creating SWT controls to fill its
contents, a FieldEditorPreferencePage
subclass creates field editors to
display the contents. All of the
fields on the page must be implemented
as field editors.
That means you have two options how to achieve what you want:
Implement your own subclass of FieldEditor, which would represent the Group widget.
Do not extend FieldEditorPreferencePage, but only a PreferencePage instead. Then you have to implement createContents method instead of createFieldEditors. You will also have to manage loading and saving of the properties.
I think the second way might be easier if you want to provide some complex layout. You may find some information more here
Another (easy) workaround:
You can also create new Composites to create more columns. The problem is that these FieldEditors communicate with their parent and mess up your layout. So, by creating an "empty" composite, they can communicate as much as they want :)
someGroup = new Group(..., SWT.NONE);
someGroup .setLayout(new GridLayout(16, false));
Composite myC1= new Composite(someGroup,SWT.NONE);
addField(new BooleanFieldEditor(...,C1);
Composite myC2= new Composite(someGroup,SWT.NONE);
addField(new BooleanFieldEditor(...,C2);
Two things to understand about FieldEditorPreferencePage (with GRID style):
The layout of field editor parents is always set to GridLayout even for "custom" components like Groups;
The number of columns in layout is adjusted according to the maximum number of components in any of the field editors (which is 2 in case of StringFieldEditor).
In the above example, the layout data of Groups should take this into account:
GridDataFactory.defaultsFor(pv).grab(true, false).span(2, 1).applyTo(pv);
GridDataFactory.defaultsFor(of).grab(true, false).span(2, 1).applyTo(of);
I implementer the Group-FieldEditor which can contain other FieldEditors and layout them as a Group.
import java.util.Collection;
import org.eclipse.jface.preference.FieldEditor;
import org.eclipse.jface.preference.FieldEditorPreferencePage;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Group;
/**
* Class is intended to create a Group Widgets, inside of the {#link FieldEditorPreferencePage}
* objects.
* This class should be used as following:
*
* use the {#link #getFieldEditorParent()} to as a parent, while creating new Field Editors.
* use {#link #setFieldEditors(Collection)} to add the collection of FieldEditors to the
* {#link GroupFieldEditor}.
*
*
* #author alf
*
*/
public class GroupFieldEditor extends FieldEditor {
private String name;
private Collection members;
private int numcolumns;
private Group group;
private Composite parent;
/**
* The gap outside, between the group-frame and the widgets around the group
*/
private static final int GROUP_PADDING = 5; // px
/**
* The gap inside, between the group-frame and the content
*/
private static final int GROUP_VERTICAL_MARGIN = 5; // px
/**
* The inside-distance creates a new boolean field editor
*/
protected GroupFieldEditor() {
}
/**
* Creates a Group of {#link FieldEditor} objects
*
* #param name
* - name
* #param fieldEditorParent
* - parent
*/
public GroupFieldEditor(String name, Composite fieldEditorParent) {
this.name = name;
// the parent is a Composite, which is contained inside of the preference page. Initially it
// does not have any layout.
this.parent = fieldEditorParent;
FillLayout fillLayout = new FillLayout();
fillLayout.marginHeight = GROUP_VERTICAL_MARGIN;
this.parent.setLayout(fillLayout);
this.group = new Group(parent, SWT.DEFAULT);
this.group.setText(this.name);
}
/**
* The parent for all the FieldEditors inside of this Group.
*
* #return - the parent
*/
public Composite getFieldEditorParent() {
return group;
}
/**
* Sets the FieldeditorChildren for this {#link GroupFieldEditor}
*
* #param membersParam
*/
public void setFieldEditors(Collection membersParam) {
this.members = membersParam;
doFillIntoGrid(getFieldEditorParent(), numcolumns);
}
/*
* (non-Javadoc) Method declared on FieldEditor.
*/
#Override
protected void adjustForNumColumns(int numColumns) {
this.numcolumns = numColumns;
}
/*
* (non-Javadoc) Method declared on FieldEditor.
*/
#Override
protected void doFillIntoGrid(Composite parentParam, int numColumns) {
GridLayout gridLayout = new GridLayout();
gridLayout.marginLeft = GROUP_PADDING;
gridLayout.marginRight = GROUP_PADDING;
gridLayout.marginTop = GROUP_PADDING;
gridLayout.marginBottom = GROUP_PADDING;
this.group.setLayout(gridLayout);
this.parent.layout();
this.parent.redraw();
if (members != null) {
for (FieldEditor editor : members) {
editor.fillIntoGrid(getFieldEditorParent(), 1);
}
}
}
/*
* (non-Javadoc) Method declared on FieldEditor. Loads the value from the
* preference store and sets it to the check box.
*/
#Override
protected void doLoad() {
if (members != null) {
for (FieldEditor editor : members) {
editor.load();
}
}
}
/*
* (non-Javadoc) Method declared on FieldEditor. Loads the default value
* from the preference store and sets it to the check box.
*/
#Override
protected void doLoadDefault() {
if (members != null) {
for (FieldEditor editor : members) {
editor.loadDefault();
}
}
}
/*
* (non-Javadoc) Method declared on FieldEditor.
*/
#Override
protected void doStore() {
if (members != null) {
for (FieldEditor editor : members) {
editor.store();
}
}
}
#Override
public void store() {
super.store();
doStore();
}
/*
* (non-Javadoc) Method declared on FieldEditor.
*/
#Override
public int getNumberOfControls() {
return 1;
}
/*
* (non-Javadoc) Method declared on FieldEditor.
*/
#Override
public void setFocus() {
if (members != null && !members.isEmpty()) {
members.iterator().next().setFocus();
}
}
/*
* #see FieldEditor.setEnabled
*/
#Override
public void setEnabled(boolean enabled, Composite parentParam) {
if (members != null) {
for (FieldEditor editor : members) {
editor.setEnabled(enabled, parentParam);
}
}
}
#Override
public void setPreferenceStore(IPreferenceStore store) {
super.setPreferenceStore(store);
if (members != null) {
for (FieldEditor editor : members) {
editor.setPreferenceStore(store);
}
}
}
}
Yet another workaround:
Use Labels to separate groups of fields.
The following creates a vertical line separator and puts text directly beneath it:
new Label(getFieldEditorParent(), SWT.SEPARATOR | SWT.HORIZONTAL)
.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1));
new Label(getFieldEditorParent(), SWT.NONE).setText("My Group Title");