Browse Source

Implement tree item context click

Fixes #9606
Fixes #9645
Fixes #9647
tags/8.1.0.rc2
Ilia Motornyi 6 years ago
parent
commit
a7b2de20d6

+ 2
- 1
client/src/main/java/com/vaadin/client/ui/AbstractComponentConnector.java View File

@@ -330,7 +330,8 @@ public abstract class AbstractComponentConnector extends AbstractConnector
* interface.
*
* @since 7.6
* @param event
* @param details
* @param eventTarget
*/
protected void sendContextClickEvent(MouseEventDetails details,
EventTarget eventTarget) {

+ 8
- 0
client/src/main/java/com/vaadin/client/ui/composite/CompositeConnector.java View File

@@ -15,6 +15,7 @@
*/
package com.vaadin.client.ui.composite;

import com.google.gwt.dom.client.EventTarget;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.client.ComponentConnector;
@@ -22,6 +23,7 @@ import com.vaadin.client.ConnectorHierarchyChangeEvent;
import com.vaadin.client.HasComponentsConnector;
import com.vaadin.client.ui.AbstractHasComponentsConnector;
import com.vaadin.shared.AbstractComponentState;
import com.vaadin.shared.MouseEventDetails;
import com.vaadin.shared.ui.Connect;
import com.vaadin.shared.ui.Connect.LoadStyle;
import com.vaadin.ui.Composite;
@@ -93,4 +95,10 @@ public class CompositeConnector extends AbstractHasComponentsConnector {
ConnectorHierarchyChangeEvent event) {
// Handled in getChildConnector
}

@Override
protected void sendContextClickEvent(MouseEventDetails details, EventTarget eventTarget) {
//Do nothing, because Composite is not an actual component, and the event
//must be handled in inner components.
}
}

+ 11
- 0
documentation/components/components-tree.asciidoc View File

@@ -98,6 +98,17 @@ tree.addItemClickListener(event ->
);
----

[[components.tree.right.clicks]]
=== Right-clicks
Right-clicks are supported similar way via `addContextClickListener()` method

[source, java]
----
tree.addContextClickListener(event -> Notification.show(
((TreeContextClickEvent<Person>)event).getItem() + " Clicked")
);
----

[[components.tree.expandcollapse]]
== Expanding and Collapsing Nodes


+ 11
- 0
server/src/main/java/com/vaadin/event/MouseEvents.java View File

@@ -182,6 +182,17 @@ public interface MouseEvents {
public String getButtonName() {
return details.getButtonName();
}

/**
* Returns an information about mouse event like position, buttons
* pressed etc.
*
* @since 8.1
* @return An information about mouse event
*/
public MouseEventDetails getMouseEventDetails() {
return details;
}
}

/**

+ 4
- 2
server/src/main/java/com/vaadin/server/communication/ServerRpcHandler.java View File

@@ -591,10 +591,12 @@ public class ServerRpcHandler implements Serializable {
* corresponding to the received method invocation has been
* registered.
*/
getLogger().warning("Ignoring RPC call to " + interfaceName + "."
String message = "Ignoring RPC call to " + interfaceName + "."
+ methodName + " in connector "
+ connector.getClass().getName() + "(" + connectorId
+ ") as no RPC implementation is registered");
+ ") as no RPC implementation is registered";
assert rpcManager != null : message;
getLogger().warning(message);
return null;
}


+ 110
- 8
server/src/main/java/com/vaadin/ui/Tree.java View File

@@ -34,12 +34,14 @@ import com.vaadin.data.provider.TreeDataProvider;
import com.vaadin.event.CollapseEvent;
import com.vaadin.event.CollapseEvent.CollapseListener;
import com.vaadin.event.ConnectorEvent;
import com.vaadin.event.ContextClickEvent;
import com.vaadin.event.ExpandEvent;
import com.vaadin.event.ExpandEvent.ExpandListener;
import com.vaadin.event.SerializableEventListener;
import com.vaadin.event.selection.SelectionListener;
import com.vaadin.server.ErrorMessage;
import com.vaadin.server.Resource;
import com.vaadin.shared.EventId;
import com.vaadin.shared.MouseEventDetails;
import com.vaadin.shared.Registration;
import com.vaadin.shared.ui.ContentMode;
@@ -69,6 +71,7 @@ public class Tree<T> extends Composite
@Deprecated
private static final Method ITEM_CLICK_METHOD = ReflectTools
.findMethod(ItemClickListener.class, "itemClick", ItemClick.class);
private Registration contextClickRegistration = null;

/**
* A listener for item click events.
@@ -483,7 +486,7 @@ public class Tree<T> extends Composite
* Adds a selection listener to the current selection model.
* <p>
* <strong>NOTE:</strong> If selection mode is switched with
* {@link setSelectionMode(SelectionMode)}, then this listener is not
* {@link #setSelectionMode(SelectionMode)}, then this listener is not
* triggered anymore when selection changes!
*
* @param listener
@@ -492,7 +495,7 @@ public class Tree<T> extends Composite
*
* @throws UnsupportedOperationException
* if selection has been disabled with
* {@link SelectionMode.NONE}
* {@link SelectionMode#NONE}
*/
public Registration addSelectionListener(SelectionListener<T> listener) {
return treeGrid.addSelectionListener(listener);
@@ -630,6 +633,7 @@ public class Tree<T> extends Composite
* @param listener
* the item click listener, not null
* @return a registration for the listener
* @see #addContextClickListener
*/
public Registration addItemClickListener(ItemClickListener<T> listener) {
return addListener(ItemClick.class, listener, ITEM_CLICK_METHOD);
@@ -655,12 +659,12 @@ public class Tree<T> extends Composite
Objects.requireNonNull(selectionMode,
"Can not set selection mode to null");
switch (selectionMode) {
case MULTI:
TreeMultiSelectionModel<T> model = new TreeMultiSelectionModel<>();
treeGrid.setSelectionModel(model);
return model;
default:
return treeGrid.setSelectionMode(selectionMode);
case MULTI:
TreeMultiSelectionModel<T> model = new TreeMultiSelectionModel<>();
treeGrid.setSelectionModel(model);
return model;
default:
return treeGrid.setSelectionMode(selectionMode);
}
}

@@ -811,4 +815,102 @@ public class Tree<T> extends Composite
public void setContentMode(ContentMode contentMode) {
renderer.getState().mode = contentMode;
}

/**
* Adds a context click listener that gets notified when a context click
* happens.
*
* @param listener
* the context click listener to add, not null
* actual event provided to the listener is {@link TreeContextClickEvent}
* @return a registration object for removing the listener
*
* @since 8.1
* @see #addItemClickListener
* @see Registration
*/
@Override
public Registration addContextClickListener(ContextClickEvent.ContextClickListener listener) {
Registration registration =
addListener(EventId.CONTEXT_CLICK, ContextClickEvent.class,
listener, ContextClickEvent.CONTEXT_CLICK_METHOD);
setupContextClickListener();
return () -> {
registration.remove();
setupContextClickListener();
};
}

@Override
@Deprecated
public void removeContextClickListener(ContextClickEvent.ContextClickListener listener) {
super.removeContextClickListener(listener);
setupContextClickListener();
}

private void setupContextClickListener() {
if (hasListeners(ContextClickEvent.class)) {
if (contextClickRegistration == null) {
contextClickRegistration = treeGrid.addContextClickListener(
event -> {
T item = null;
if (event instanceof Grid.GridContextClickEvent) {
item = ((Grid.GridContextClickEvent<T>) event).getItem();
}
fireEvent(new TreeContextClickEvent<>(this, event.getMouseEventDetails(), item));
}
);
}
} else if (contextClickRegistration != null) {
contextClickRegistration.remove();
contextClickRegistration = null;
}
}

/**
* ContextClickEvent for the Tree Component.
* <p>
* Usage:
* <pre>
* tree.addContextClickListener(event -&gt; Notification.show(
* ((TreeContextClickEvent&lt;Person&gt;)event).getItem() + " Clicked")
* );
* </pre>
*
* @param <T> the tree bean type
*/
public static class TreeContextClickEvent<T> extends ContextClickEvent {

private final T item;

/**
* Creates a new context click event.
*
* @param source the tree where the context click occurred
* @param mouseEventDetails details about mouse position
* @param item the item which was clicked or {@code null}
* if the click happened outside any item
*/
public TreeContextClickEvent(Tree<T> source,
MouseEventDetails mouseEventDetails,
T item) {
super(source, mouseEventDetails);
this.item = item;
}

/**
* Returns the item of context clicked row.
*
* @return clicked item; {@code null}
* the click happened outside any item
*/
public T getItem() {
return item;
}

@Override
public Tree<T> getComponent() {
return (Tree<T>) super.getComponent();
}
}
}

+ 72
- 0
uitest/src/main/java/com/vaadin/tests/contextclick/TreeV8ContextClick.java View File

@@ -0,0 +1,72 @@
/*
* Copyright 2000-2016 Vaadin Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.vaadin.tests.contextclick;

import com.vaadin.data.TreeData;
import com.vaadin.shared.Registration;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Tree;
import com.vaadin.ui.Tree.TreeContextClickEvent;

import java.util.Collections;

public class TreeV8ContextClick extends
AbstractContextClickUI<Tree<String>, TreeContextClickEvent<String>> {

@Override
protected Tree<String> createTestComponent() {
TreeData<String> treeData = new TreeData<>();
for (int i = 0; i < 3; i++) {
String grandDad = "Granddad " + i;
treeData.addItems(null, grandDad);
for (int j = 0; j < 4; j++) {
String dad = "Dad " + i + "/" + j;
treeData.addItems(grandDad, dad);
for (int k = 0; k < 5; k++) {
treeData.addItems(dad, "Son " + i + "/" + j + "/" + k);
}
}
}
Tree<String> tree = new Tree<>("Clane", treeData);
tree.setWidth("100%");
return tree;
}

@Override
protected void handleContextClickEvent(
TreeContextClickEvent<String> event) {
String value = event.getItem();
log("ContextClickEvent value: " + value);
}

@Override
protected HorizontalLayout createContextClickControls() {
HorizontalLayout controls = super.createContextClickControls();
controls.addComponent(
new Button("Remove all content", new Button.ClickListener() {

@Override
public void buttonClick(ClickEvent event) {
testComponent.setItems(Collections.emptyList());
testComponent.setHeight("200px");
}
}));
return controls;
}

}

+ 63
- 0
uitest/src/test/java/com/vaadin/tests/contextclick/TreeV8ContextClickTest.java View File

@@ -0,0 +1,63 @@
/*
* Copyright 2000-2016 Vaadin Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.vaadin.tests.contextclick;

import com.vaadin.testbench.elements.ButtonElement;
import com.vaadin.testbench.elements.TreeElement;
import org.junit.Test;
import org.openqa.selenium.WebElement;

import static org.junit.Assert.assertEquals;

public class TreeV8ContextClickTest extends AbstractContextClickTest {

@Test
public void testBodyContextClickWithTypedListener() {
addOrRemoveTypedListener();

TreeElement tree = $(TreeElement.class).first();
contextClick(tree.getItem(0));

assertEquals(
"1. ContextClickEvent value: Granddad 0",
getLogRow(0));

tree.expand(0);
tree.expand(2);
contextClick(tree.getItem(6));

assertEquals(
"2. ContextClickEvent value: Son 0/1/3",
getLogRow(0));
}

/**
* Performs a context click on given element at coordinates 20, 10 followed
* by a regular click. This prevents browser context menu from blocking
* future operations.
*
* A smaller X offset might hit the resize handle of the previous cell that
* overlaps with the next header cell.
*
* @param e
* web element
*/
@Override
protected void contextClick(WebElement e) {
contextClick(e, 20, 10);
}

}

Loading…
Cancel
Save