First of all - I am a beginner with Java and GWT. I have a scripting language background so please be explicit.
I have a CellTable that is populated with data from a database( ServerKeyWord class gets the data ).
myCellTable.addColumn(new TextColumn<ServerKeyWord>() {
#Override
public String getValue(ServerKeyWord object) {
// TODO Auto-generated method stub
return object.getName();
}
});
The example from above works, but it only shows the data as a text. I need to make it a hyperlink, that when you click it, it opens a new tab to that location.
I've surfed the web and got to the conclusion that I need to override render.
public class HyperTextCell extends AbstractCell<ServerKeyWord> {
interface Template extends SafeHtmlTemplates {
#Template("<a target=\"_blank\" href=\"{0}\">{1}</a>")
SafeHtml hyperText(SafeUri link, String text);
}
private static Template template;
public static final int LINK_INDEX = 0, URL_INDEX = 1;
/**
* Construct a new linkCell.
*/
public HyperTextCell() {
if (template == null) {
template = GWT.create(Template.class);
}
}
#Override
public void render(Context context, ServerKeyWord value, SafeHtmlBuilder sb) {
if (value != null) {
// The template will sanitize the URI.
sb.append(template.hyperText(UriUtils.fromString(value.getName()), value.getName()));
}
}
}
Now ... How do I use the HyperTextCell class with the addColumn method as in the first code example?!
Thank you in advance!
HyperTextCell hyperTextCell = new HyperTextCell();
Column<ServerKeyWord, ServerKeyWord> hyperColumn = new Column<ServerKeyWord, ServerKeyWord>(
hyperTextCell) {
#Override
public ServerKeyWord getValue(ServerKeyWord keyWord) {
return keyWord;
}
};
myCellTable.addColumn(hyperColumn);
Related
In my project, I have a TableViewer which needs to show around 3000 items and also filter them. Without SWT.VIRTUAL the table takes multiple seconds to display.
So, I implemented ILazyContentProvider and not using "ArrayContentProvider" but now I am facing issues in filtering the elements of TableViewer.
I am writing the below code for filtering but the select method is not running at all.
private static class DefaultFilterextends ViewerFilter {
private String searchText;
public void setSearchText(final String searchText) {
this.searchText = searchText;
}
#Override
public boolean select(Viewer viewer, Object parentElement, Object element) {
if (this.searchText == null) {
return true;
}
return (element.toString().contains(searchText) || element.toString().equals(searchText));
}
}
The below ContentProvider, I am writting
private class LazyContentProvider implements ILazyContentProvider {
private TableViewer viewer;
private List<String> elements;
public LazyContentProvider(TableViewer viewer) {
this.viewer = viewer;
}
#Override
public void dispose() {
}
#Override
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
this.elements = (List<String>) newInput;
}
#Override
public void updateElement(int index) {
viewer.replace(elements.get(index), index);
}
}
Can someone please guide me how can I do the filteration of elements in TableViewer with SWT.VIRTUAL?
TableViewer does not support filtering when SWT.VIRTUAL is used. Instead you must do the filtering in the content provider.
The content provider will need to maintain a filtered list of elements. For example:
public class LazyContentProvider implements ILazyContentProvider
{
private TableViewer viewer;
private List<String> allElements;
private List<String> filteredElements;
public LazyContentProvider()
{
//
}
#Override
public void dispose()
{
//
}
#SuppressWarnings("unchecked")
#Override
public void inputChanged(final Viewer viewer, final Object oldInput, final Object newInput)
{
this.viewer = (TableViewer)viewer;
allElements = (List<String>)newInput;
filteredElements = allElements;
}
#Override
public void updateElement(final int index)
{
viewer.replace(filteredElements.get(index), index);
}
public void filter(final String searchText)
{
filteredElements = allElements.stream().filter(element -> element.contains(searchText)).toList();
viewer.setItemCount(filteredElements.size());
viewer.refresh();
}
}
Here I have added a filteredElements list that contains just the current filtered elements, this is used in updateElement.
I added a filter method which updates the filtered elements list. It also tells the table viewer about the new item count and refreshes the table.
The .toList() method in the filter stream requires Java 16, for older versions of Java use .collect(Collectors.toList()).
Normally if we have some textField in GWT we can add a BlurHandler by the following code:
textField.addBlurHandler(new BlurHandler() {
#Override
public void onBlur(BlurEvent event) {
//what we need
}
});
But if we use UiBinder and our textField is annotated by #UiField and it is mentioned in our ui.xml file we can add BlurHandler by this code as well:
#UiHandler("textField")
protected void createBlurHandler(BlurEvent event) {
}
I guess I am right here because it works like this. So, the question is, can we actually define BlurHandler inside ui.xml file?
For example, it is possible to add inputMaxLength and some other attributes there, does GWT has some possibility like onChange method or are these ways that I described the only possibilities?
I would like to have something like this:
<g:TextBox ui:field="textField" onBlur="methodName" />
Is it possible?
I am pretty sure what you are asking is not possible. The problem is that you wouldn't be able to use reflection to figure out which method you want to call. However you can extends the TextBox class and use that inside your template. The extended class could have it's own properties that can be set in the template. An example is as follows where I set the default test on my own DefaultTextBox.
public class DefaultTextBox extends TextBox {
/**
* The text color used when the box is disabled and empty.
*/
private static final String TEXTBOX_DISABLED_COLOR = "#AAAAAA";
private final String defaultText;
public #UiConstructor
DefaultTextBox(final String defaultText) {
this.defaultText = defaultText;
resetDefaultText();
// Add focus and blur handlers.
addFocusHandler(new FocusHandler() {
#Override
public void onFocus(FocusEvent event) {
getElement().getStyle().clearColor();
getElement().getStyle().clearFontStyle();
if (defaultText.equals(getText())) {
setText("");
}
}
});
addBlurHandler(new BlurHandler() {
#Override
public void onBlur(BlurEvent event) {
if ("".equals(getText())) {
resetDefaultText();
}
}
});
}
public String getDefaultText() {
return defaultText;
}
#Override
public void setText(String text) {
if (text == null) {
super.setText(getDefaultText());
} else {
getElement().getStyle().clearColor();
getElement().getStyle().clearFontStyle();
super.setText(text);
}
}
public String getText() {
return super.getText();
}
/**
* This is override so that the editor framework will not get the default
* value but the actual null value when the default text is in the box.
*/
#Override
public String getValue() {
try {
return getValueOrThrow();
} catch (ParseException e) {
return null;
}
}
#Override
public void setValue(String value) {
setText(value);
}
/**
* This is overridden from the parent class because this is
* how the editor gets the value.
*/
public String getValueOrThrow() throws ParseException {
if (defaultText.equals(super.getValueOrThrow())) {
return null;
}
return super.getValueOrThrow();
}
/**
* Reset the text box to the default text.
*/
public void resetDefaultText() {
setText(defaultText);
getElement().getStyle().setColor(TEXTBOX_DISABLED_COLOR);
getElement().getStyle().setFontStyle(FontStyle.ITALIC);
}
}
Then in the template you can set properties like this.
<w:DefaultTextBox defaultText="name" ui:field="nameTextBox" />
This will also work with setters, you can set properties without having to use the #UiConstructor but in my case I wanted to make sure that there was no empty constructor for this class.
I have an Enum SupplierCode:
public enum SupplierCode
{
BG("British Gas"), CNG("Contract Natural Gas"), COR("Corona Energy");
private String value;
SupplierCode(String value)
{
if(value != "")
{
this.value = value;
}
}
// ... toString() and fromString() omitted for brevity
// for editor framework (?)
public String getValue()
{
return value;
}
public void setValue(String value)
{
this.value = value;
}
}
I display it in my editors using a ValueListBox:
#UiField(provided = true)
ValueListBox<SupplierCode> supplierCode = new ValueListBox<SupplierCode>(new AbstractRenderer<SupplierCode>()
{
#Override
public String render(SupplierCode object)
{
return object == null ? "" : object.toString();
}
});
// in the constructor
public ContractEditor()
{
initWidget(uiBinder.createAndBindUi(this));
supplierCode.setAcceptableValues(Arrays.asList(SupplierCode.values()));
}
I have to edit this type a few times in my app so I wanted to make an editor for just this dropdown, called SupplierCodeEditor:
public class SupplierCodeEditor extends Composite implements Editor<SupplierCode>
{
private static SupplierCodeEditorUiBinder uiBinder = GWT.create(SupplierCodeEditorUiBinder.class);
interface SupplierCodeEditorUiBinder extends UiBinder<Widget, SupplierCodeEditor>
{
}
#UiField(provided = true)
ValueListBox<SupplierCode> value = new ValueListBox<SupplierCode>(new AbstractRenderer<SupplierCode>()
{
#Override
public String render(SupplierCode object)
{
return object == null ? "" : object.toString();
}
});
public SupplierCodeEditor()
{
initWidget(uiBinder.createAndBindUi(this));
value.setAcceptableValues(Arrays.asList(SupplierCode.values()));
}
}
However, when I use it, although it renders the list ok with the options, it doesn't select the actual value from the list. I thought having the getValue() and setValue() methods would work but seemingly not.
Does anyone know of a way to put this in one editor file? Then I won't have to repeat the code for the renderer and call setAcceptableValues() every place I want to use it.
Use LeafValueEditor<SupplierCode>:
public class SupplierEditor extends Composite implements LeafValueEditor<SupplierCode> {
interface SupplierEditorUiBinder extends UiBinder<Widget, SupplierEditor> {
}
private static SupplierEditorUiBinder uiBinder = GWT.create(SupplierEditorUiBinder.class);
#UiField(provided = true)
ValueListBox<SupplierCode> codes;
public SupplierEditor() {
codes = new ValueListBox<>(new AbstractRenderer<SupplierCode>() {
#Override
public String render(SupplierCode object) {
return object == null ? "" : object.toString();
}
});
initWidget(uiBinder.createAndBindUi(this));
codes.setAcceptableValues(Arrays.asList(SupplierCode.values()));
}
#Override
public SupplierCode getValue() {
return codes.getValue();
}
#Override
public void setValue(SupplierCode value) {
codes.setValue(value);
}
}
This way, your widget will be easily pluggable in a Editor hierarchy.
And you don't need the get/set methods in your SupplierCode enum.
You have to either:
use #Editor.Path("") on your child ValueListBox
make your SupplierCodeEditor implement LeafValueEditor<SupplierCode>, with delegating getValue and setValue to the ValueListBox
make your SupplierCodeEditor implement IsEditor<LeafValueEditor<SupplierCode>, returning the ValueListBox's asEditor() from your own asEditor().
BTW, you absolutely don't need the getValue and setValue on your enum values.
I want to create a Jface Listviewer, but it alway throw the following Exception:
org.eclipse.core.runtime.AssertionFailedException: assertion failed:
at org.eclipse.core.runtime.Assert.isTrue(Assert.java:110)
at org.eclipse.core.runtime.Assert.isTrue(Assert.java:96)
at org.eclipse.jface.viewers.StructuredViewer.assertContentProviderType(StructuredViewer.java:1671)
at org.eclipse.jface.viewers.StructuredViewer.setContentProvider(StructuredViewer.java:1661)
at property.sheet.internalConstraint.ConstraintDialog.createDialogArea(ConstraintDialog.java:26)
at org.eclipse.jface.dialogs.Dialog.createContents(Dialog.java:775)
at org.eclipse.jface.window.Window.create(Window.java:432)
at org.eclipse.jface.dialogs.Dialog.create(Dialog.java:1104)
at org.eclipse.jface.window.Window.open(Window.java:791)
....
My createDialogArea method (where I create the ListViewer) looks like this:
protected Control createDialogArea(Composite parent) {
Composite container = (Composite) super.createDialogArea(parent);
lv = new ListViewer(container, SWT.SINGLE);
lv.setContentProvider(new ConstraintDialogContentProvider());
lv.setLabelProvider(new ConstraintDialogLabelProvider());
lv.setInput(fm);
return container;
}
By debugging, it turned out that the exception is thrown after I set my contentProvider:
public class ConstraintDialogContentProvider implements IContentProvider {
private List<Feature> features = new ArrayList<Feature>();
#Override
public void dispose() {
}
#Override
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
}
public Object[] getElements(Object input) {
if (input instanceof FeatureMap) {
FeatureMap fm = (FeatureMap) input;
if (fm.getFeature() != null) {
getAllFeatures(fm.getFeature());
return features.toArray();
} else {
return null;
}
}
return null;
}
private void getAllFeatures(Feature feature) {
features.add(feature);
.....
// adds additional features
}
}
I don't really understand what I'm doing wrong here. Any ideas?
Cheers,
Phil
The content provider for ListViewer must implement IStructuredContentProvider not just IContentProvider. The assertContentProviderType call is checking this.
CompositeCell let us customize the content of a table cell's in GWT using Java. We can put almost any other group of widget within the table's cell and layout them as we want. Problem is that if we used the html tags to define the layout of the CompositeCell as yet another table (see CompositeCell anonymous class implementation bellow) we loose the event handling for the components of the cell :(.
Running the following code, when we click in the buttons of the cell will realize the popup in response of the event handling IF WE COMMENT the CompositeCell anonymous implementation.
I've been debugging CompositeCell.onBrowserEvent(Context, Element, C, NativeEvent, ValueUpdater) because i think that the definition of the cell layout using HTML table tags breaks the event chain within GWT widgets hierarchy but haven't been successful so far.
Remark: both commented and uncommented versions of the code realize the same GUI layout. This example just intent to show that we loose event handling when customizing cell's content.
public class ActionCellTest implements EntryPoint {
private static final String SERVER_ERROR = "An error occurred while " + "attempting to contact the server. Please check your network "
+ "connection and try again.";
private final GreetingServiceAsync greetingService = GWT.create(GreetingService.class);
public void onModuleLoad() {
CellTable<Person> table = new CellTable<ActionCellTest.Person>();
final List<HasCell<Person, ?>> cells = new LinkedList<HasCell<Person, ?>>();
cells.add(new HasCellImpl("first name", new ActionCell.Delegate<Person>() {
#Override
public void execute(Person object) {
Window.alert(object.getFirstName());
}
}));
cells.add(new HasCellImpl("last name", new ActionCell.Delegate<ActionCellTest.Person>() {
#Override
public void execute(Person object) {
Window.alert(object.getLastName());
}
}));
CompositeCell<Person> cell = new CompositeCell<Person>(cells) {
#Override
public void render(Context context, Person value, SafeHtmlBuilder sb) {
sb.appendHtmlConstant("<table><tbody><tr>");
for (HasCell<Person, ?> hasCell : cells) {
render(context, value, sb, hasCell);
}
sb.appendHtmlConstant("</tr></tbody></table>");
}
#Override
protected <X> void render(Context context, Person value, SafeHtmlBuilder sb, HasCell<Person, X> hasCell) {
Cell<X> cell = hasCell.getCell();
sb.appendHtmlConstant("<td>");
cell.render(context, hasCell.getValue(value), sb);
sb.appendHtmlConstant("</td>");
}
#Override
protected Element getContainerElement(Element parent) {
return parent.getFirstChildElement().getFirstChildElement().getFirstChildElement();
}
};
table.addColumn(new TextColumn<ActionCellTest.Person>() {
#Override
public String getValue(ActionCellTest.Person object) {
return object.getFirstName() + " " + object.getLastName();
}
}, "name");
table.addColumn(new Column<Person, Person>(cell) {
#Override
public Person getValue(ActionCellTest.Person object) {
return object;
}
}, "composite");
LinkedList<Person> data = new LinkedList<ActionCellTest.Person>();
data.add(new Person("Amy", "Reed"));
data.add(new Person("Tim", "Gardner"));
table.setRowData(data);
RootPanel.get().add(table);
}
private class HasCellImpl implements HasCell<Person, Person> {
private ActionCell<Person> fCell;
public HasCellImpl(String text, Delegate<Person> delegate) {
fCell = new ActionCell<Person>(text, delegate);
}
#Override
public Cell<Person> getCell() {
return fCell;
}
#Override
public FieldUpdater<Person, Person> getFieldUpdater() {
return null;
}
#Override
public Person getValue(Person object) {
return object;
}
}
private class Person {
private String fFirstName;
private String fLastName;
public Person(String first, String last) {
fFirstName = first;
fLastName = last;
}
public String getFirstName() {
return fFirstName;
}
public String getLastName() {
return fLastName;
}
}
}
This is a known issue which will be fixed in the upcoming GWT 2.5 (a matter of weeks): http://code.google.com/p/google-web-toolkit/issues/detail?id=5714
(in the mean time, you can run off trunk or try backporting the change)