How to make only some columns editable in a Vaadin Grid? - java

Vaadin Grid allows to be defined as editable with
grid.setEditorEnabled(true);
This makes all visible columns editable. However I don't want the user to edit an specific column, but seems like the editable is an all or nothing.
The next best solution I have found is to define an editor field with a disabled editor, which almost does the trick but the user is still able to select the text and move the cursor (but the field is not editable anymore).
Grid.Column nameColumn = grid.getColumn("fullName");
nameColumn.setHeaderCaption("Full Name");
nameColumn.setEditorField(getNoEditableTextField());
...
private Field<?> getNoEditableTextField() {
TextField noEditableTextFiled = new TextField();
noEditableTextFiled.setEnabled(false);
return noEditableTextFiled;
}
I believe Label cannot be used because it's not a Field.
Is there a better option to achieve this?
edit: as aakath said, there is a way of achieving this not enabling the column to be edited, but in doing so the cell value disappears when you edit the row, which is not desirable.

Did you try calling setEditable(false) method on the column? I believe it should make the field non-editable when the item editor is active.
grid.getColumn("fullName").setEditable(false);

my solution is below. i have just finished. it was not tested too much. but it may give you some ideas.
ati
getColumn(columnName).setEditable(true).setEditorField(getNoEditableField(columnName));
...
private Field<?> getNoEditableField(final String columnName) {
CustomField<Label> result = new CustomField() {
#Override
protected Component getContent() {
Label result = (Label) super.getContent();
Object editedItemId = getEditedItemId();
String value = DEFAULT_VALUE;
if (editedItemId != null) {
value = CustomizableGrid.this.toString(getContainerDataSource().getItem(editedItemId).getItemProperty(columnName).getValue());
}
result.setValue(value);
return result;
}
#Override
protected Component initContent() {
Label result = new Label(DEFAULT_VALUE, ContentMode.HTML);
result.setDescription(getColumnDescription(columnName));
result.setStyleName("immutablegridcellstyle");
return result;
}
#Override
public Class getType() {
return Label.class;
}
};
result.setConverter(new Converter<Label, Object>() {
//converter for your data
});
return result;
}

I had the same problem and didn't want that clicking on id column opens editor. I solved it with adding an ItemClickListener as below. It works fine for me.
grid.addItemClickListener((ItemClickListener<GridBean>) event -> grid.getEditor().setEnabled(!event.getColumn().getCaption().equals("Id")));
Also byc clicking on specific columns Grid is not editable any more.

There is one tricky way to do it! I've just found out it.
So, first of all you need to use grid with container, instead of direct rows adding:
BeanItemContainer<MyBean> container = new BeanItemContainer<>(MyBean.class);
setContainerDataSource(container);
Then remove fields setters from MyBean, except setters for fields what you have to edit.

I think the same can be achieved by making the grid an editable one by grid.setEditorEnabled(true); and disabling editing option for other columns like grid.getColumn(columnName).setEditable(false);. But I am not sure of any demerits of this method. Any suggestion is always appreciated.

Its simple just go to Vaadin Documentation what did from it is below:
you can see here I gave a specified column Name
grid = new Grid<>();
lst = new ArrayList<>();
provider = new ListDataProvider<>(lst);
lst.add(new Company(1, "Java"));
grid.setDataProvider(provider);
grid.addColumn(Company::getSerialNo).setCaption("Sr.no");
TextField tf = new TextField();
grid.getEditor().setEnabled(true);
HorizontalLayout hlyt = new HorizontalLayout();
grid.addColumn(Company::getName).setEditorComponent(tf, Company::setName).setCaption("Name").setExpandRatio(2);
hlyt.addComponent(grid);

I use the following approach to get a read-only field, the trick is override the setEnabled method to get a disabled textfield. If you trace the source code in Vaadin Grid, no matter what field you pass to a Grid, it will always call the field.setEnabled(true).
myGrid.getColumn(propertyId).setEditorField(new ReadOnlyField());
And
public class ReadOnlyField extends TextField
{
public ReadOnlyField()
{
super();
this.setReadOnly(true);
}
#Override
public void setEnabled(boolean enabled)
{
// always set to disabled state
super.setEnabled(false);
}
}

Related

Javafx - Hide TreeTableRow based on data content

I created a TableTree that contains object of class Component that has a boolean property "selected".
I want to hide the rows from the table where the rows component is not selected.
I tried this:
componentTree.setRowFactory(new Callback<TreeTableView<Component>, TreeTableRow<Component>>() {
#Override
public TreeTableRow<Component> call(TreeTableView<Component> param) {
TreeTableRow<Component> row = new TreeTableRow<Component>() {
#Override
protected void updateItem(Component component, boolean empty) {
if(!empty) {
if (!component.isSelected()) {
setVisible(false);
setManaged(false);
System.out.println("hide");
} else {
setVisible(true);
setManaged(true);
System.out.println("show");
}
}
}
};
return row;
}
});
On system.out I can see a lot of "show" and "hide" messages, but this doesn't affect the table, all rows are shown as before.
Any idea on this topic?
Thanks!
I used eclipse's fx.ui.controls library for the same achieve the same goal before.
<dependency>
<groupId>at.bestsolution.eclipse</groupId>
<artifactId>org.eclipse.fx.ui.controls</artifactId>
<version>2.2.0</version>
</dependency>
The library provides a class: FilterableTreeItem<T> under the tree package. This class was designed to be used in cases like yours. You can provide a Predicate to the root of the tree and the items will get hidden when the value given changes:
// Children
final FilterableTreeItem<Component> childNode1 = new FilterableTreeItem<>(component1);
final FilterableTreeItem<Component> childNode2 = new FilterableTreeItem<>(component2);
final FilterableTreeItem<Component> childNode3 = new FilterableTreeItem<>(component3);
// Root
final FilterableTreeItem<Component> root = new FilterableTreeItem<>(rootComponent);
root.getInternalChildren().setAll(childNode1, childNode2, childNode3);
root.setPredicate((parent, value) -> value.isSelected());
// TreeTableView
final TreeTableView<Component> treeTableView = new TreeTableView<>(root);
Note that you have to use getInternalChildren() to add children and the default getChildren().
FilterableTreeItem<T> also provides a predicateProperty() that you can bind to another property in case you need to update the how items are shown or hidden.
Another advatage of this class is that it shows the whole path up to the root of the items matching that predicate.

In LibGDX scene2d, after changing the items of a selectbox, it no longer has a default listener

I dont think my problem is that hard to solve but I have been searching for a while and cant figure it out.
I have two scene2d SelectBox widgets one above the other, in a table, on a stage. Let's call them A and B. Whatever is selected in A determines which list is shown in B. I implement this using a ChangeListener on A and all works fine (this isn't the problem).
However, my list A was getting extremely long (500+ items) so I wanted to add a TextField above it which would search and match the strings, replacing the old list of A with a shorter one, making it much easier to find what you are looking for. This works fine, I use a ChangeListener on the textfield to get the string, compare it to a main list of strings using a for loop and use aList.setItems(); to add the adjusted string to the SelectBox. The list displays (without a click, so I use aList.showList(); in the ChangeListener of the TextField) and I think this is where the problem occurs - instead of a click, showList() is called from elsewhere. Lets say I change my mind and want to select a different item from A, it will no longer drop down the menu on click. Yet if I change the text which is in the search bar, it displays the list. When the list is displayed, I can click an item and it hides as normal.
This might seems a bit confusing, so here is the code (edited for clarity, so if something is missing let me know)
SelectBox aSelect, bSelect;
TextField searchBar;
Stage stage;
Table table;
Skin skin;
ArrayList<String> completeAList;
ArrayList<String> abrevAList;
public chooseItemScreen()
{
stage = new Stage(new ScreenViewport());
skin = new Skin(Gdx.files.internal("uiskin.json"));
table = new Table();
table.setFillparent(true);
completeAList = new ArrayList<String>;
abrevAList = new ArrayList<String>;
aSelect = new SelectBox(skin);
//ItemList is a class with the list of strings as a static method
completeAList = ItemList.getAList();
aSelect.setItems(completeAList.toArray());
//bSelect omitted as is same as A
//aSelect changeListener also omitted as it is working fine
searchBar = new TextField("", skin);
searchBar.setMessageText("SEARCH LIST");
searchPokemon.addListener(new ChangeListener() {
#Override
public void changed(ChangeEvent event, Actor actor) {
updateASelect();
}
});
table.add(searchBar);
table.row();
table.add(aList);
stage.addActor(table);
Gdx.input.setInputProcessor(stage);
}
private void updateAList()
{
abrevAList.clear();
aSelect.clearItems();
aSelect.hideList()
for (String string: completeAList)
{
if (string.toLowerCase().startsWith(searchBar.getText().toLowerCase()))
{
abrevAList.add(string);
}
}
if (abrevAList.isEmpty())
{
abrevAList.add("NOT FOUND");
}
aSelect.setItems(abrevAList.toArray());
//It's at this point where I am no longer to click on aSelect
//I can still select an item from the drop down list, closing the list
//it's just I can't show list by clicking on the widget after that
aSelect.showList();
}
#Override
public void render(float delta) {
Gdx.gl20.glClearColor(0,0,0,0);
Gdx.gl20.glClear(GL20.GL_COLOR_BUFFER_BIT);
stage.act();
stage.draw();
}
I added the following listener to tell if the selectBox was being clicked (which it was). I gave all actors names
stage.getRoot().addCaptureListener(new InputListener() {
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
System.out.println(event.getTarget().getName());
return false;
}
});
The click is recognised, just the list doesn't show. In my opinion, it is a problem with calling showList() and changing the list at the same time.
Any help is appreciated, and if you need more code or any other information, let me know.
Thanks
Set a fixed size to the selectbox when adding it to the table, something like
table.add(selectBox).width(someValue);
or
table.add(selectBox).growX();
Also, after reviewing your code, I suggest you to remove
aSelect.clearItems();
aSelect.hideList();
And make ArrayList be just libgdx Array< String>, it will make things easier, wont cause allocation when iterating with ':' and you wont need .toArray() when setting the items of your selectboxes. You also can set SelectBox type with SelectBox< String>, and, you can add a row in the same line with table.add(something).row().
After changing the size of the selectbox cell your code worked just fine in my side.

GWT: Adding GWTP Tooltip to a CellTable cell

I want to use GWT-Bootstrap Tooltip for cells of a column in the CellTable. Each Tooltip will show description of a cell which is a field in the "MyCustomObject" class used for generating the table.
One of the quick solutions I found in one of the answers on this question is the following.
CellTable<MyCustomObject> table = new CellTable<MyCustomObject>();
table.addCellPreviewHandler(new Handler<MyCustomObject>() {
#Override
public void onCellPreview(CellPreviewEvent<MyCustomObject> event) {
if (event.getNativeEvent().getType().equals("mouseover")){
table.getRowElement(event.getIndex()).getCells()
.getItem(event.getColumn()).setTitle(event.getValue().getDescription());
}
}
}
);
It makes a little sense but I don't see anything when I hover the cursor over the table cells and nothing is attached to the DOM. Can anyone explain how this even works? I want to attach the Tooltip to table cell similar to the following.
Tooltip tt = new Tooltip("Here goes the description");
tt.setAnimation(true);
tt.setWidget(tableColumn);
tt.reconfigure();
The problem is that a CellTable cell is not a widget so it can't be attached in that way.
So is there any workaround for this?
I've faced this issue once and I created my own cell that displays a tooltip, here's how I did it: Note: My cell was displaying an image with a tooltip so I quickly changed the code to display String text... So I did not test it with text.
private class TooltipCell extends AbstractCell<String> {
private String tooltipText = "";
#Override
public void render(Context context, String value, SafeHtmlBuilder sb) {
if (value != null) {
sb.appendHtmlConstant("<div title=\"" + tooltipText + "\">");
sb.append(SafeHtmlUtils.fromString(value));
}
}
public void setTooltip(String tootltipTextToSet){
tooltipText = tootltipTextToSet;
}
}
And in your table use method setTooltip("tooltip text") in method getValue just before returning the cell text.
Hope this helps

SWT , TreeViewer , CellEditor with ComboBox

While using EditingSupport for a treeColumn in a TreeViewer, Is there any way i can just reflect the Changes in the View instead of changing the model and then using getViewer().update(element,null);
Detail:
I want to achieve the following functionality:
Show a tree View with |Object| (ComboBox)property|
Upon selection and clicking on the button i want to show user the summary of changes and then upon clicking confirm i want to apply those changes to the model (Object)
I am using a TreeViewer, Within that i have a column with EditingSupport Enabled.
Whenever I select a value from the ComboBox and click somewhere else (lostFocus kind of ) the Value sets to default.
I have figured out that after SetValue() is called the TreeLabelProvider is again called(using debug points)
Is there any way i can just reflect the Changes in the View instead of changing the model and using getViewer().update(element,null);
Some FYIs :
Package Object contains multiple versions
ContentProvider does the job to fetch the object
LabelProvider gets all the Versions from the package(String[]) and shows the first one.
//Code to Create the UI
// blah
TreeViewerColumn column2 = new TreeViewerColumn(treeViewer, SWT.LEFT);
column2.getColumn().setText("Version");
column2.getColumn().setWidth(130);
treeViewer.setLabelProvider(new PackageUpdateTreeLabelProvider());
EditingSupport exampleEditingSupport = new OperationEditingSupport(
column2.getViewer());
column2.setEditingSupport(exampleEditingSupport);
OperationEditingSupport Class
private class OperationEditingSupport extends EditingSupport {
private ComboBoxCellEditor cellEditor = null;
private OperationEditingSupport(ColumnViewer viewer) {
super(viewer);
cellEditor = new ComboBoxCellEditor(
((TreeViewer) viewer).getTree(), new String[] {},
SWT.READ_ONLY);
}
#Override
protected CellEditor getCellEditor(Object element) {
// TODO Auto-generated method stub
if (element instanceof IPackageInfo) {
IPackageInfo pkg = (IPackageInfo) element;
cellEditor.setItems(PackageMgrUtil.getInstance().getVersions(
(IdmPackage) pkg, false, true));
return cellEditor;
}
return null;
}
#Override
protected boolean canEdit(Object element) {
return true;
}
#Override
protected Object getValue(Object element) {
// TODO Auto-generated method stub
return 0;
}
#Override
protected void setValue(Object element, Object value) {
/* only set new value if it differs from old one */
}
}
***************************************************
When i click on the cell of column2 i get the combo box but when i select something and move the focus somewhere else.It again shows the default Value
on debuging i found that :
it agains calls the label Provider which fetches all the Version of the package and then shows the first one hence I can not see any change.
what i want is that it should keep the selection intact without changing the underlying object.
thanks for the help.
Figured it out.
following code added to the SetValue() method solves it.
m_tree = (Tree)getViewer.getControl();
TreeItem[] ti = m_tree.getSelection();
CCombo c = ((CCombo)cellEditor.getControl());
String str = c.getItem(c.getSelectionIndex());
ti[0].setText(1, str );

Java FX: TableView - display simple HTML

I'd like to know, if it is possible to render simple HTML tags in JavaFX TableView (b, i, subscript, supscript). In my code snippet I used default cellValueFactory, but maybe someone could tell me if exists any cell factory which allow me to display html.
From code:
class Data{
private String row = "<b> Sample data</b>"
public String getRow(){
return row;
}
TableView<Data> tableView = new TableView();
TableColumn<Data,String> column = new TableColumn("Sample Column");
column.setCellValueFactory(new PropertyValueFactory<Data, String>("row"));
tableView.getColumns().addAll(column);
I wish I could see Sample Data in my table in bold. Thanks in advance!
--UPDATE
Code that allows me to see my HTML, but resizes table cell, WebView size is ignored and not wrapped tight
private class HTMLCell extends TableCell<Component, Component> {
#Override
protected void updateItem(Component item, boolean empty) {
super.updateItem(item, empty);
if (!empty) {
WebView webView = new WebView();
webView.setMaxWidth(200);
webView.setMaxHeight(50);
WebEngine engine = webView.getEngine();
// setGraphic(new Label("Test"));
setGraphic(webView);
String formula = item.getFormula();
engine.loadContent(formula);
}
}
}
TableColumn<Component, Component> formulaColumn = new TableColumn<>("Formula");
formulaColumn.setMinWidth(300);
formulaColumn.setCellFactory(new Callback<TableColumn<Component, Component>, TableCell<Component, Component>>() {
#Override
public TableCell<Component, Component> call(TableColumn<Component, Component> param) {
return new HTMLCell();
}
});
formulaColumn.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Component, Component>, ObservableValue<Component>>() {
#Override
public ObservableValue<Component> call(CellDataFeatures<Component, Component> param) {
return new SimpleObjectProperty<Component>(param.getValue());
}
});
HTML in a WebView in a TableCell
You have to make your own cell factory which returns a WebView node into which you load your HTML content.
On Correctly Sizing the WebView
In terms of establishing the preferred size of the WebView node, that is a little tricky. It would be simpler if RT-25005 Automatic preferred sizing of WebView were implemented.
I think the sample code from your question will work if you just replace the maxSize setting for the WebView with a webView.setPrefSize(prefX, prefY) call. You will just have to guess what the prefX and prefY values should be as I don't know a good way of determining programmatically.
I think your code should work by setting the max size for the WebView, but the WebView doesn't seem to respect the max size setting and just uses the pref size setting, which I think may be a bug in Java 8b129 (you could file that in the JavaFX Issue Tracker with a minimal, executable test case which reproduces it and a description of your test environment).
TextFlow Alternative
You might also consider using TextFlow component for representing your styled text. It is not HTML, but if all you want to do is some simple styling like making some text in the cell bold or italic, it might be a good option.
Use HTML tables in WebEngine/WebView rather than TableView.
Table examples

Categories