Vaadin tree onclick expand - vaadin

I am new to Vaadin and I want to know how can I expand tree node on click? More precisely I want the tree to expand when I click on parent node not expand button.

It is quite easy to create a tree in Vaadin: https://vaadin.com/book/vaadin7/-/page/components.tree.html

For example if you want to expand all nodes in vaadin.ui.Tree:
// --- Expand all nodes
for (Iterator<?> it = tree.rootItemIds().iterator(); it.hasNext();) {
tree.expandItemsRecursively(it.next());
}

This working for me:
#Override
public void itemClick(ItemClickEvent itemClickEvent) {
final String column = itemClickEvent.getPropertyId().toString();
final String item = (String) itemClickEvent.getItemId();
if (column.equals(something)) {
Boolean collapsed = functieTree.isCollapsed(item);
LOGGER.debug("COLLAPSED: " + collapsed);
tableTree.setCollapsed(item, !collapsed);
}
}

tree.addItemClickListener(new ItemClickListener() {
#Override
public void itemClick(ItemClickEvent event) {
menu.expandItem(event.getItemId());
}
});
this works to me

Related

Vaadin 11: refreshAll (again)

here is a good thread about DataProvider.refreshAll() on Vaadin 8.5.1, but it doesn't seem to work this way in Vaadin 11.
I used this starter app to play around. It displays some imaginary product data in a grid.
At first, I added a refresh command to SampleCrudView:
public HorizontalLayout createTopBar() {
...
HorizontalLayout topLayout = new HorizontalLayout();
Button btn = new Button("refresh");
btn.addClickListener(event -> dataProvider.refreshAll());
topLayout.add(btn);
...
return topLayout;
}
The folks from vaadin override getId() in their ProductDataProvider like this to use it as an object identifier:
#Override
public Integer getId(Product product) {
Objects.requireNonNull(product,
"Cannot provide an id for a null product.");
return product.getId();
}
That ProductDataProvider extends ListDataProvider, which is initialized on startup with data from MockDataService, so that we always deal with the same objects. I changed that:
public class MockDataService extends DataService {
...
#Override
public synchronized List<Product> getAllProducts() {
//added ->
MockDataGenerator.resetProductCounter(); //this one sets nextProductId = 1
products = MockDataGenerator.createProducts(categories);
products.stream().forEach(p -> System.out.println(p.getId() + ", " + p.getProductName()));
//<- added
return products;
}
So now you will get new Product instances within the same ID range every time you call getAllProducts():
public class ProductDataProvider extends ListDataProvider<Product> {
...
#Override
public Stream<Product> fetch(Query<Product, SerializablePredicate<Product>> query) {
//added ->
this.getItems().clear();
this.getItems().addAll(DataService.get().getAllProducts());
//<- added
return super.fetch(query);
}
So the point is, this doesn't work - the data in the grid is still the same after "refresh" has been clicked.
Any suggestions?
Regards,
m_OO_m
This is caused by a bug that was fixed a couple a days ago. The fix will be included in the next maintenance release.

Vaadin Grid middle mouse click

I'm trying to emulate normal browser behaviour in my vaadin grid, which includes middle mouse click to open in a new tab:
addItemClickListener(e -> {
boolean newTab = e.getMouseEventDetails().getButton() == MouseEventDetails.MouseButton.MIDDLE || e.getMouseEventDetails().isCtrlKey();
//open in window or new tab
});
However, the middle mouse button is not registered by vaadin. How could I get this to work?
That feature was included in vaadin-grid (which goes into Vaadin 10) and will not work in Vaadin 8.
For Vaadin 8, you can either intercept the event with some client-side extension, or use a ComponentRenderer for adding a Panel to each component (which works, but is not ideal because it degrades performance):
grid.addColumn(item->{
Panel p = new Panel(item.getName());
p.setStyleName(ValoTheme.PANEL_BORDERLESS);
p.addClickListener(ev->{
System.out.println(ev.getButtonName());
});
return p;
}).setRenderer(new ComponentRenderer());
A client-side extension, on the other hand, allows listening to javascript events (such as MouseEvent) and triggering a server event in response. Creating a extension is quite a complex topic (since it uses a part of the API that is normally hidden from the developer) but it allows direct access to rendered DOM, which is not possible otherwise.
The following resources from the documentation may give you a starting point:
Creating a component extension (which describes a simple extension with Java code only) and Integrating JavaScript Components and Extension (which explains how to add native JavaScript code to your extension).
How I solved the problem in my specific case:
Server side:
public class MyGrid<T> extends Grid<T> {
public MyGrid(String caption, DataProvider<T, ?> dataProvider) {
super(caption, dataProvider);
MiddleClickExtension.extend(this);
}
public static class MiddleClickExtension<T> extends AbstractGridExtension<T> {
private MiddleClickExtension(MyGrid<T> grid) {
super.extend(grid);
registerRpc((rowKey, columnInternalId, details) -> grid.fireEvent(
new ItemClick<>(grid, grid.getColumnByInternalId(columnInternalId), grid.getDataCommunicator().getKeyMapper().get(rowKey), details)),
MiddleClickGridExtensionConnector.Rpc.class);
}
public static void extend(MyGrid<?> grid) {
new MiddleClickExtension<>(grid);
}
#Override
public void generateData(Object item, JsonObject jsonObject) {
}
#Override
public void destroyData(Object item) {
}
#Override
public void destroyAllData() {
}
#Override
public void refreshData(Object item) {
}
}
}
Client side:
#Connect(MyGrid.MiddleClickExtension.class)
public class MiddleClickGridExtensionConnector extends AbstractExtensionConnector {
#Override
protected void extend(ServerConnector target) {
getParent().getWidget().addDomHandler(event -> {
if (event.getNativeButton() == NativeEvent.BUTTON_MIDDLE) {
event.preventDefault();
CellReference<JsonObject> cell = getParent().getWidget().getEventCell();
getRpcProxy(Rpc.class).middleClick(cell.getRow().getString(DataCommunicatorConstants.KEY), getParent().getColumnId(cell.getColumn()),
MouseEventDetailsBuilder.buildMouseEventDetails(event.getNativeEvent(), event.getRelativeElement()));
}
}, MouseDownEvent.getType());
}
#Override
public GridConnector getParent() {
return (GridConnector) super.getParent();
}
public interface Rpc extends ServerRpc {
void middleClick(String rowKey, String columnInternalId, MouseEventDetails details);
}
}

Multiselection of cells with muose and copy of TableView using JAVAFX

I have a TableView which is editable and multiple selection enabled. I wish to enter new data to some columns and rows. Then I wish to select using mouse and press CTRL-C to copy to clipboard.
I can use column.setCellFactory (TextFieldTableCell.forTableColumn ()); and my code works well for entering data like EXCEL. I could not select using mouse.
I read the reference How can I select multiple cells in tableview with javafx only by mouse?. If I try to implement it I need to use
final Callback<TableColumn<MyDataClass, String>, TableCell<MyDataClass, String>> myCellFactory = new DragSelectionCellFactory ();
column.setCellFactory (myCellFactory);.
Then I am unable to enter any data as CellFactory is different now..
How may I enter data like EXCEL and also select mouse and use CTRL-C to copy? Thanks for any help.
You can refactor the code in the link you provided so that it references another cell factory, and "decorates" the cells with the dragging functionality:
public class DragSelectionCellFactory<S,T> implements Callback<TableColumn<S,T>, TableCell<S,T>> {
private final Callback<TableColumn<S,T>, TableCell<S,T>> factory ;
public DragSelectionCellFactory(Callback<TableColumn<S,T>, TableCell<S,T>> factory) {
this.factory = factory ;
}
public DragSelectionCellFactory() {
this(col -> new TableCell<S,T>() {
#Override
protected void updateItem(T item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null) {
setText(null);
} else {
setText(item.toString());
}
}
});
}
#Override
public TableCell<S,T> call(final TableColumn<S,T> col) {
TableCell<S,T> cell = factory.call(col);
cell.setOnDragDetected(event -> {
cell.startFullDrag();
col.getTableView().getSelectionModel().select(cell.getIndex(), col);
});
cell.setOnMouseDragEntered(event -> {
col.getTableView().getSelectionModel().select(cell.getIndex(), col);
});
return cell ;
}
}
Then you can do
TableColumn<Person, String> column = ...
column.setCellFactory(
new DragSelectionCellFactory<Person, String>(TextFieldTableCell.forTableColumn()));

How to start a file download in vaadin without button?

I know that it is really easy to create a FileDownloader and call extend with a Button. But how do I start a download without the Button?
In my specific situation right now I have a ComboBox and the file I'd like to send to the user is generated after changing its value, based on the input. The file should be sent immediately without waiting for another click. Is that easily possible?
Thanks
raffael
I found a solution myself. Actually two.
The first one uses the deprecated method Page.open()
public class DownloadComponent extends CustomComponent implements ValueChangeListener {
private ComboBox cb = new ComboBox();
public DownloadComponent() {
cb.addValueChangeListener(this);
cb.setNewItemsAllowed(true);
cb.setImmediate(true);
cb.setNullSelectionAllowed(false);
setCompositionRoot(cb);
}
#Override
public void valueChange(ValueChangeEvent event) {
String val = (String) event.getProperty().getValue();
FileResource res = new FileResource(new File(val));
Page.getCurrent().open(res, null, false);
}
}
The javadoc here mentions some memory and security problems as reason for marking it deprecated
In the second I try to go around this deprecated method by registering the resource in the DownloadComponent. I'd be glad if a vaadin expert comments this solution.
public class DownloadComponent extends CustomComponent implements ValueChangeListener {
private ComboBox cb = new ComboBox();
private static final String MYKEY = "download";
public DownloadComponent() {
cb.addValueChangeListener(this);
cb.setNewItemsAllowed(true);
cb.setImmediate(true);
cb.setNullSelectionAllowed(false);
setCompositionRoot(cb);
}
#Override
public void valueChange(ValueChangeEvent event) {
String val = (String) event.getProperty().getValue();
FileResource res = new FileResource(new File(val));
setResource(MYKEY, res);
ResourceReference rr = ResourceReference.create(res, this, MYKEY);
Page.getCurrent().open(rr.getURL(), null);
}
}
Note: I do not really allow the user to open all my files on the server and you should not do that either. It is just for demonstration.
Here is my work-around. It works like a charm for me. Hope it will help you.
Create a button and hide it by Css (NOT by code: button.setInvisible(false))
final Button downloadInvisibleButton = new Button();
downloadInvisibleButton.setId("DownloadButtonId");
downloadInvisibleButton.addStyleName("InvisibleButton");
In your theme, add this rule to hide the downloadInvisibleButton:
.InvisibleButton {
display: none;
}
When the user clicks on menuItem: extend the fileDownloader to the downloadInvisibleButton, then simulate the click on the downloadInvisibleButton by JavaScript.
menuBar.addItem("Download", new MenuBar.Command() {
#Override
public void menuSelected(MenuBar.MenuItem selectedItem) {
FileDownloader fileDownloader = new FileDownloader(...);
fileDownloader.extend(downloadInvisibleButton);
//Simulate the click on downloadInvisibleButton by JavaScript
Page.getCurrent().getJavaScript()
.execute("document.getElementById('DownloadButtonId').click();");
}
});

smartGWT TileGrid::onKeyPress -- how to override Enter key, but keep default processing for other keys

I am loading file icons on a tile grid in a smartGWT project. When Enter key is pressed, I want to open the selected file for display.
When I override the onKeyPress handler, it does work, but the tile grid navigational behavior using left/right/up/down arrow keys is lost.
My question is.., how to retain the default processing behavior, while still override the Enter key.
tileGrid.addKeyPressHandler (new KeyPressHandler() {
#Override
public void onKeyPress(KeyPressEvent event) {
if (EventHandler.getKey().equals("Enter")) {
//do something special here
}
else {
**//TODO: do the default processing..**.
}
}
});
EDIT:
#Ras, here is the code that simulates the problem.
package com.rv.gwtsample.client;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.smartgwt.client.data.Record;
import com.smartgwt.client.widgets.events.KeyPressEvent;
import com.smartgwt.client.widgets.events.KeyPressHandler;
import com.smartgwt.client.widgets.tile.TileGrid;
import com.smartgwt.client.widgets.tile.TileRecord;
/**
* #author rvnath
*
*/
public class MyTileGrid implements EntryPoint {
/* (non-Javadoc)
* #see com.google.gwt.core.client.EntryPoint#onModuleLoad()
*/
#Override
public void onModuleLoad() {
// TODO Auto-generated method stub
TileGrid grid = new TileGrid();
grid.setLeft(50);
grid.setTop(50);
grid.setWidth("300");
grid.setHeight("200");
DetailViewerField field = new DetailViewerField("Name");
grid.setFields(field);
grid.addKeyPressHandler(new KeyPressHandler() {
#Override
public void onKeyPress(KeyPressEvent event) {
if (event.getKeyName().equals("Enter"))
GWT.log("Enter pressed");
}
});
Record[] rec = new TileRecord[32];
for (int i=0; i<32; ++i) {
rec[i] = new TileRecord();
}
grid.setData(rec);
grid.draw();
}
}
If I disable the onKeyPress handler, arrow keys can navigate between the elements of the tile grid. If I enable, then the entire tile grid panel scrolls, instead of selection change.
Instead of using KeyPressHandler, try the KeyDownHandler, it works.
tileGrid.addKeyDownHandler(new KeyDownHandler() {
#Override
public void onKeyDown(KeyDownEvent event) {
if (EventHandler.getKey().equalsIgnoreCase("Enter")){
openModal(tileGrid.getSelectedRecord());
}
}
});
Tested with the latest 3.0 smartgwt build.
#Mupparthy, I've also implemented keyPressHandler() for TextAreaItem. I also had the same requirement that only delete & backspace keys were needed to be handled. What I did is, don't handle the else part. It automatically did default processing for other keys including all the arrow keys. So if it's not working for you, provide me a stand alone code so that we can make it work.

Resources