Browse Source

Make it possible to drop things on top of Grid rows (#8747)

* Create initial grid drop target classes

* Reorganize event listener attach and removal

* Add Javadocs and annotations

* Make it possible to drop things on top of Grid rows (#8400)

* Fix javadocs for indicator methods

* Add drop target indicator on dragover event as well in case the element doesn't have one yet.

* Remove additional drop target and formatting

* Create grid drop event and listener

* Create API for getting info about drop target row

* Add javadocs

* Rename server RPC method

* Fix javadocs

* Use Optional instead of null as return type

* Add addListener method for grid drop target and fix javadocs

* Fix some javascript
reviewable/pr8979/r1
Adam Wagner 7 years ago
parent
commit
583410dbda

+ 2
- 2
client/src/main/java/com/vaadin/client/connectors/grid/GridDragSourceExtensionConnector.java View File

@@ -29,6 +29,7 @@ import com.vaadin.client.widgets.Escalator;
import com.vaadin.client.widgets.Grid;
import com.vaadin.shared.Range;
import com.vaadin.shared.ui.Connect;
import com.vaadin.shared.ui.dnd.DragSourceState;
import com.vaadin.shared.ui.grid.GridDragSourceExtensionState;
import com.vaadin.ui.GridDragSourceExtension;

@@ -83,8 +84,7 @@ public class GridDragSourceExtensionConnector extends

// Set drag data in DataTransfer object
((NativeEvent) event).getDataTransfer()
.setData(GridDragSourceExtensionState.DATA_TYPE_DRAG_DATA,
dragData.toJson());
.setData(DragSourceState.DATA_TYPE_TEXT, dragData.toJson());
}
}


+ 119
- 0
client/src/main/java/com/vaadin/client/connectors/grid/GridDropTargetExtensionConnector.java View File

@@ -0,0 +1,119 @@
/*
* 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.client.connectors.grid;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;

import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.TableRowElement;
import com.vaadin.client.ServerConnector;
import com.vaadin.client.extensions.DropTargetExtensionConnector;
import com.vaadin.client.widget.escalator.RowContainer;
import com.vaadin.client.widgets.Escalator;
import com.vaadin.shared.ui.Connect;
import com.vaadin.shared.ui.grid.GridDropTargetExtensionRpc;
import com.vaadin.shared.ui.grid.GridDropTargetExtensionState;
import com.vaadin.shared.ui.grid.GridState;
import com.vaadin.ui.GridDropTargetExtension;

import elemental.events.Event;
import elemental.json.JsonObject;

/**
* Makes Grid an HTML5 drop target. This is the client side counterpart of
* {@link GridDropTargetExtension}.
*
* @author Vaadin Ltd
* @since
*/
@Connect(GridDropTargetExtension.class)
public class GridDropTargetExtensionConnector extends
DropTargetExtensionConnector {

private GridConnector gridConnector;

@Override
protected void extend(ServerConnector target) {
gridConnector = (GridConnector) target;

super.extend(target);
}

@Override
protected void sendDropEventToServer(String dataTransferText,
Event dropEvent) {

String rowKey = null;
Optional<TableRowElement> targetRow = getTargetRow(
(Element) dropEvent.getTarget());
if (targetRow.isPresent()) {
rowKey = getRowData(targetRow.get())
.getString(GridState.JSONKEY_ROWKEY);
}

getRpcProxy(GridDropTargetExtensionRpc.class)
.drop(dataTransferText, rowKey);
}

private JsonObject getRowData(TableRowElement row) {
int rowIndex = ((Escalator.AbstractRowContainer) getGridBody())
.getLogicalRowIndex(row);
return gridConnector.getDataSource().getRow(rowIndex);
}

@Override
protected void addTargetIndicator(Event event) {
getTargetRow(((Element) event.getTarget()))
.ifPresent(e -> e.addClassName(CLASS_DRAG_OVER));
}

@Override
protected void removeTargetIndicator(Event event) {
getTargetRow(((Element) event.getTarget()))
.ifPresent(e -> e.removeClassName(CLASS_DRAG_OVER));
}

private Optional<TableRowElement> getTargetRow(Element source) {
while (!Objects.equals(source, getGridBody().getElement())) {
if (TableRowElement.is(source)) {
return Optional.of(source.cast());
}
source = source.getParentElement();
}
return Optional.empty();
}

@Override
protected Element getDropTargetElement() {
return getGridBody().getElement();
}

private Escalator getEscalator() {
return gridConnector.getWidget().getEscalator();
}

private RowContainer.BodyRowContainer getGridBody() {
return getEscalator().getBody();
}

@Override
public GridDropTargetExtensionState getState() {
return (GridDropTargetExtensionState) super.getState();
}
}

+ 1
- 1
client/src/main/java/com/vaadin/client/extensions/DragSourceExtensionConnector.java View File

@@ -161,7 +161,7 @@ public class DragSourceExtensionConnector extends AbstractExtensionConnector {
((NativeEvent) event).getDataTransfer());

assert dropEffect != null : "Drop effect should never be null";
getRpcProxy(DragSourceRpc.class)
.dragEnd(DropEffect.valueOf(dropEffect.toUpperCase()));
}

+ 71
- 30
client/src/main/java/com/vaadin/client/extensions/DropTargetExtensionConnector.java View File

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

import com.google.gwt.dom.client.BrowserEvents;
import com.google.gwt.dom.client.DataTransfer;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.NativeEvent;
@@ -42,7 +41,7 @@ import elemental.events.EventTarget;
@Connect(DropTargetExtension.class)
public class DropTargetExtensionConnector extends AbstractExtensionConnector {

private static final String CLASS_DRAG_OVER = "v-drag-over";
protected static final String CLASS_DRAG_OVER = "v-drag-over";

// Create event listeners
private final EventListener dragEnterListener = this::onDragEnter;
@@ -59,35 +58,46 @@ public class DropTargetExtensionConnector extends AbstractExtensionConnector {
protected void extend(ServerConnector target) {
dropTargetWidget = ((ComponentConnector) target).getWidget();

EventTarget dropTarget = getDropTargetElement().cast();
addDropListeners(getDropTargetElement());
}

// dragenter event
dropTarget.addEventListener(BrowserEvents.DRAGENTER, dragEnterListener);
/**
* Adds dragenter, dragover, dragleave and drop event listeners to the given
* DOM element.
*
* @param element
* DOM element to attach event listeners to.
*/
protected void addDropListeners(Element element) {
EventTarget target = element.cast();

// dragover event
dropTarget.addEventListener(BrowserEvents.DRAGOVER, dragOverListener);
target.addEventListener(Event.DRAGENTER, dragEnterListener);
target.addEventListener(Event.DRAGOVER, dragOverListener);
target.addEventListener(Event.DRAGLEAVE, dragLeaveListener);
target.addEventListener(Event.DROP, dropListener);
}

// dragleave event
dropTarget.addEventListener(BrowserEvents.DRAGLEAVE, dragLeaveListener);
/**
* Removes dragenter, dragover, dragleave and drop event listeners from the
* given DOM element.
*
* @param element
* DOM element to remove event listeners from.
*/
protected void removeDropListeners(Element element) {
EventTarget target = element.cast();

// drop event
dropTarget.addEventListener(BrowserEvents.DROP, dropListener);
target.removeEventListener(Event.DRAGENTER, dragEnterListener);
target.removeEventListener(Event.DRAGOVER, dragOverListener);
target.removeEventListener(Event.DRAGLEAVE, dragLeaveListener);
target.removeEventListener(Event.DROP, dropListener);
}

@Override
public void onUnregister() {
super.onUnregister();

EventTarget dropTarget = getDropTargetElement().cast();

// Remove listeners
dropTarget.removeEventListener(BrowserEvents.DRAGENTER,
dragEnterListener);
dropTarget.removeEventListener(BrowserEvents.DRAGOVER,
dragOverListener);
dropTarget.removeEventListener(BrowserEvents.DRAGLEAVE,
dragLeaveListener);
dropTarget.removeEventListener(BrowserEvents.DROP, dropListener);
removeDropListeners(getDropTargetElement());
}

/**
@@ -107,7 +117,7 @@ public class DropTargetExtensionConnector extends AbstractExtensionConnector {
* browser event to be handled
*/
protected void onDragEnter(Event event) {
addTargetIndicator(getDropTargetElement());
addTargetIndicator(event);
}

/**
@@ -126,6 +136,9 @@ public class DropTargetExtensionConnector extends AbstractExtensionConnector {
.valueOf(getState().dropEffect.name()));
}

// Add drop target indicator in case the element doesn't have one
addTargetIndicator(event);

// Prevent default to allow drop
nativeEvent.preventDefault();
nativeEvent.stopPropagation();
@@ -135,7 +148,7 @@ public class DropTargetExtensionConnector extends AbstractExtensionConnector {
.setDropEffect(DataTransfer.DropEffect.NONE);

// Remove drop target indicator
removeTargetIndicator(getDropTargetElement());
removeTargetIndicator(event);
}
}

@@ -164,7 +177,7 @@ public class DropTargetExtensionConnector extends AbstractExtensionConnector {
* browser event to be handled
*/
protected void onDragLeave(Event event) {
removeTargetIndicator(getDropTargetElement());
removeTargetIndicator(event);
}

/**
@@ -182,10 +195,10 @@ public class DropTargetExtensionConnector extends AbstractExtensionConnector {
String dataTransferText = nativeEvent.getDataTransfer().getData(
DragSourceState.DATA_TYPE_TEXT);

getRpcProxy(DropTargetRpc.class).drop(dataTransferText);
sendDropEventToServer(dataTransferText, event);
}

removeTargetIndicator(getDropTargetElement());
removeTargetIndicator(event);
}

private boolean dropAllowed(NativeEvent event) {
@@ -197,12 +210,40 @@ public class DropTargetExtensionConnector extends AbstractExtensionConnector {
return true;
}

private void addTargetIndicator(Element element) {
element.addClassName(CLASS_DRAG_OVER);
/**
* Initiates a server RPC for the drop event.
*
* @param dataTransferText
* Client side textual data that can be set for the drag source and
* is transferred to the drop target.
* @param dropEvent
* Client side drop event.
*/
protected void sendDropEventToServer(String dataTransferText,
Event dropEvent) {
getRpcProxy(DropTargetRpc.class).drop(dataTransferText);
}

private void removeTargetIndicator(Element element) {
element.removeClassName(CLASS_DRAG_OVER);
/**
* Add class that indicates that the component is a target.
*
* @param event
* The drag enter or dragover event that triggered the indication.
*/
protected void addTargetIndicator(Event event) {
getDropTargetElement().addClassName(CLASS_DRAG_OVER);
}

/**
* Remove the drag target indicator class name from the target element.
* <p>
* This is triggered on dragleave, drop and dragover events.
*
* @param event
* the event that triggered the removal of the indicator
*/
protected void removeTargetIndicator(Event event) {
getDropTargetElement().removeClassName(CLASS_DRAG_OVER);
}

private native boolean executeScript(NativeEvent event, String script)/*-{

+ 13
- 2
server/src/main/java/com/vaadin/event/dnd/DropTargetExtension.java View File

@@ -43,14 +43,25 @@ public class DropTargetExtension<T extends AbstractComponent> extends
* Component to be extended.
*/
public DropTargetExtension(T target) {

registerDropTargetRpc(target);

super.extend(target);
}

/**
* Register server RPC.
*
* @param target
* Extended component.
*/
protected void registerDropTargetRpc(T target) {
registerRpc((DropTargetRpc) dataTransferText -> {
DropEvent<T> event = new DropEvent<>(target, dataTransferText,
getUI().getActiveDragSource());

fireEvent(event);
});

super.extend(target);
}

/**

+ 67
- 0
server/src/main/java/com/vaadin/event/dnd/grid/GridDropEvent.java View File

@@ -0,0 +1,67 @@
/*
* 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.event.dnd.grid;

import com.vaadin.event.dnd.DragSourceExtension;
import com.vaadin.event.dnd.DropEvent;
import com.vaadin.ui.AbstractComponent;
import com.vaadin.ui.Grid;

/**
* Server side drop event on an HTML5 drop target {@link Grid} row.
*
* @param <T>
* The Grid bean type.
* @author Vaadin Ltd.
* @see com.vaadin.ui.GridDropTargetExtension#addDropListener(GridDropListener)
* @since
*/
public class GridDropEvent<T> extends DropEvent<Grid<T>> {

private final T dropTargetRow;

/**
* Creates a server side Grid row drop event.
*
* @param target
* Grid that received the drop.
* @param dataTransferText
* Data of type {@code "text"} from the {@code DataTransfer}
* object.
* @param dragSourceExtension
* Drag source extension of the component that initiated the drop
* event.
* @param dropTargetRowKey
* Key of the target row that received the drop.
*/
public GridDropEvent(Grid<T> target, String dataTransferText,
DragSourceExtension<? extends AbstractComponent> dragSourceExtension,
String dropTargetRowKey) {
super(target, dataTransferText, dragSourceExtension);

dropTargetRow = target.getDataCommunicator().getKeyMapper()
.get(dropTargetRowKey);
}

/**
* Get the row item source of this event.
*
* @return The row item this event was originated from.
*/
public T getDropTargetRow() {
return dropTargetRow;
}
}

+ 46
- 0
server/src/main/java/com/vaadin/event/dnd/grid/GridDropListener.java View File

@@ -0,0 +1,46 @@
/*
* 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.event.dnd.grid;

import java.lang.reflect.Method;

import com.vaadin.event.ConnectorEventListener;
import com.vaadin.event.dnd.DropListener;
import com.vaadin.event.dnd.DropTargetExtension;

/**
* Drop listener for HTML5 drop on a Grid row.
*
* @param <T>
* The Grid bean type.
* @author Vaadin Ltd.
* @see com.vaadin.ui.GridDropTargetExtension#addDropListener(GridDropListener)
* @since
*/
@FunctionalInterface
public interface GridDropListener<T> extends ConnectorEventListener {

static final Method DROP_METHOD = GridDropListener.class
.getDeclaredMethods()[0];

/**
* Called when drop event is fired on a Grid row.
*
* @param event
* Server side drop event.
*/
void drop(GridDropEvent<T> event);
}

+ 72
- 0
server/src/main/java/com/vaadin/ui/GridDropTargetExtension.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.ui;

import com.vaadin.event.dnd.DropTargetExtension;
import com.vaadin.event.dnd.grid.GridDropEvent;
import com.vaadin.event.dnd.grid.GridDropListener;
import com.vaadin.shared.Registration;
import com.vaadin.shared.ui.grid.GridDropTargetExtensionRpc;
import com.vaadin.shared.ui.grid.GridDropTargetExtensionState;

/**
* Makes the rows of a Grid HTML5 drop targets. This is the server side
* counterpart of GridDropTargetExtensionConnector.
*
* @param <T>
* Type of the Grid bean.
* @author Vaadin Ltd
* @since
*/
public class GridDropTargetExtension<T> extends DropTargetExtension<Grid<T>> {
public GridDropTargetExtension(Grid<T> target) {
super(target);
}

@Override
protected void registerDropTargetRpc(Grid<T> target) {
registerRpc((GridDropTargetExtensionRpc) (dataTransferText, rowKey) -> {
GridDropEvent<T> event = new GridDropEvent<>(target,
dataTransferText, getUI().getActiveDragSource(), rowKey);

fireEvent(event);
});
}

/**
* Attaches drop listener for the current drop target. {@link
* GridDropListener#drop(GridDropEvent)} is called when drop event happens
* on the client side.
*
* @param listener
* Listener to handle drop event.
* @return Handle to be used to remove this listener.
*/
public Registration addDropListener(GridDropListener<T> listener) {
return addListener(GridDropEvent.class, listener,
GridDropListener.DROP_METHOD);
}

@Override
protected GridDropTargetExtensionState getState() {
return (GridDropTargetExtensionState) super.getState();
}

@Override
protected GridDropTargetExtensionState getState(boolean markAsDirty) {
return (GridDropTargetExtensionState) super.getState(markAsDirty);
}
}

+ 0
- 5
shared/src/main/java/com/vaadin/shared/ui/grid/GridDragSourceExtensionState.java View File

@@ -25,11 +25,6 @@ import com.vaadin.shared.ui.dnd.DragSourceState;
*/
public class GridDragSourceExtensionState extends DragSourceState {

/**
* Data type for storing the dragged row's data.
*/
public static final String DATA_TYPE_DRAG_DATA = "grid-drag-data";

/**
* Json key for storing data for a dragged row.
*/

+ 39
- 0
shared/src/main/java/com/vaadin/shared/ui/grid/GridDropTargetExtensionRpc.java View File

@@ -0,0 +1,39 @@
/*
* 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.shared.ui.grid;

import com.vaadin.shared.communication.ServerRpc;

/**
* RPC for firing server side drop event when client side drop event happens on
* drop target Grid.
*
* @author Vaadin Ltd.
* @since
*/
public interface GridDropTargetExtensionRpc extends ServerRpc {

/**
* Called when drop event happens on client side.
*
* @param dataTransferText
* Data of type {@code "text"} from the {@code DataTransfer}
* object.
* @param rowKey
* Key of the row on which the drop event occured.
*/
public void drop(String dataTransferText, String rowKey);
}

+ 28
- 0
shared/src/main/java/com/vaadin/shared/ui/grid/GridDropTargetExtensionState.java View File

@@ -0,0 +1,28 @@
/*
* 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.shared.ui.grid;

import com.vaadin.shared.ui.dnd.DropTargetState;

/**
* State class containing parameters for GridDropTargetExtension.
*
* @author Vaadin Ltd
* @since
*/
public class GridDropTargetExtensionState extends DropTargetState {

}

+ 18
- 13
uitest/src/main/java/com/vaadin/tests/components/grid/GridDragAndDrop.java View File

@@ -20,28 +20,25 @@ import java.util.Arrays;
import java.util.List;
import java.util.stream.IntStream;

import com.vaadin.annotations.Widgetset;
import com.vaadin.event.dnd.DropTargetExtension;
import com.vaadin.event.dnd.grid.GridDropListener;
import com.vaadin.server.Page;
import com.vaadin.server.VaadinRequest;
import com.vaadin.shared.ui.grid.GridDragSourceExtensionState;
import com.vaadin.tests.components.AbstractTestUIWithLog;
import com.vaadin.ui.ComboBox;
import com.vaadin.ui.Grid;
import com.vaadin.ui.GridDragSourceExtension;
import com.vaadin.ui.GridDropTargetExtension;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Label;
import com.vaadin.ui.Layout;

import elemental.json.Json;
import elemental.json.JsonObject;

@Widgetset("com.vaadin.DefaultWidgetSet")
public class GridDragAndDrop extends AbstractTestUIWithLog {
@Override
protected void setup(VaadinRequest request) {
// Drag source
// Drag source Grid
Grid<Bean> dragSourceComponent = new Grid<>();

dragSourceComponent.setItems(createItems(50));
dragSourceComponent.addColumn(Bean::getId).setCaption("ID");
dragSourceComponent.addColumn(Bean::getValue).setCaption("Value");
@@ -54,15 +51,20 @@ public class GridDragAndDrop extends AbstractTestUIWithLog {
return ret;
});

Label dropTargetComponent = new Label("Drop here");
DropTargetExtension<Label> dropTarget = new DropTargetExtension<>(
dropTargetComponent);
// Drop target Grid
Grid<Bean> dropTargetComponent = new Grid<>();
dropTargetComponent.setItems(createItems(5));
dropTargetComponent.addColumn(Bean::getId).setCaption("ID");
dropTargetComponent.addColumn(Bean::getValue).setCaption("Value");

dropTarget.addDropListener(event -> {
log(event.getTransferData(
GridDragSourceExtensionState.DATA_TYPE_DRAG_DATA));
GridDropTargetExtension<Bean> dropTarget = new GridDropTargetExtension<>(
dropTargetComponent);
dropTarget.addDropListener((GridDropListener<Bean>) event -> {
log(event.getDataTransferText() + ", targetId=" + event
.getDropTargetRow().getId());
});

// Layout grids
Layout layout = new HorizontalLayout();
layout.addComponents(dragSourceComponent, dropTargetComponent);

@@ -77,6 +79,9 @@ public class GridDragAndDrop extends AbstractTestUIWithLog {
selectionModeSwitch.setSelectedItem(Grid.SelectionMode.SINGLE);

addComponents(selectionModeSwitch, layout);

// Set dragover styling
Page.getCurrent().getStyles().add(".v-drag-over {color: red;}");
}

private List<Bean> createItems(int num) {

+ 9
- 0
uitest/src/main/java/com/vaadin/tests/widgetset/client/grid/EscalatorProxy.java View File

@@ -15,7 +15,9 @@
*/
package com.vaadin.tests.widgetset.client.grid;

import java.util.List;
import java.util.Map;
import java.util.function.Consumer;

import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.TableRowElement;
@@ -126,6 +128,13 @@ public class EscalatorProxy extends Escalator {
public SpacerUpdater getSpacerUpdater() {
return rowContainer.getSpacerUpdater();
}

@Override
public void setNewEscalatorRowCallback(
Consumer<List<TableRowElement>> consumer) {
throw new UnsupportedOperationException(
"NewEscalatorRowCallback function is not supported");
}
}

private class RowContainerProxy implements RowContainer {

Loading…
Cancel
Save