Browse Source

Use a separate data received handler in VFilterSelect (#19929)

Move parts of the request handling to a separate handler
class that keeps track of the current communication state etc.

This is an intermediate change. Later changes should move
waitingForFilteringResponse etc. to the handler.

Change-Id: I762d15cc4b54ead3003e6d9d913e2a975256644c
feature/eventbus
Henri Sara 8 years ago
parent
commit
7b5986965a

+ 147
- 34
client/src/main/java/com/vaadin/client/ui/VFilterSelect.java View File

@@ -1130,7 +1130,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,

/**
* Send the current selection to the server. Triggered when a selection
* is made or on a blur event.
* is made with the ENTER key.
*/
public void doSelectedItemAction() {
debug("VFS.SM: doSelectedItemAction()");
@@ -1151,22 +1151,30 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
return;
}

setUpdateSelectionWhenReponseIsReceived(isWaitingForFilteringResponse());
if (!isWaitingForFilteringResponse()) {
doPostFilterWhenReady();
}

/**
* Perform the post-filter action either now (if not waiting for a
* server response) or when a response is received.
*/
private void doPostFilterWhenReady() {
if (isWaitingForFilteringResponse()) {
dataReceivedHandler.setUpdateOnDataReceived(true);
} else {
dataReceivedHandler.setUpdateOnDataReceived(false);
doPostFilterSelectedItemAction();
}
}

/**
* Triggered after a selection has been made
* Triggered after a selection has been made.
*/
public void doPostFilterSelectedItemAction() {
debug("VFS.SM: doPostFilterSelectedItemAction()");
final MenuItem item = getSelectedItem();
final String enteredItemValue = tb.getText();

setUpdateSelectionWhenReponseIsReceived(false);

// check for exact match in menu
int p = getItems().size();
if (p > 0) {
@@ -1388,6 +1396,128 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,

}

/**
* Handler receiving notifications from the connector and updating the
* widget state accordingly.
*
* This class is still subject to change and should not be considered as
* public stable API.
*
* @since
*/
public class DataReceivedHandler {

private Runnable navigationCallback = null;
/**
* Set true when popupopened has been clicked. Cleared on each
* UIDL-update. This handles the special case where are not filtering
* yet and the selected value has changed on the server-side. See #2119
* <p>
* For internal use only. May be removed or replaced in the future.
*/
private boolean popupOpenerClicked = false;
private boolean updateOnDataReceived = false;

/**
* Called by the connector when new data for the last requested filter
* is received from the server.
*/
public void dataReceived() {
suggestionPopup.showSuggestions(currentSuggestions, currentPage,
totalMatches);

setWaitingForFilteringResponse(false);

if (!popupOpenerClicked) {
navigateItemAfterPageChange();
}

if (updateOnDataReceived) {
updateOnDataReceived = false;
suggestionPopup.menu.doPostFilterSelectedItemAction();
}

popupOpenerClicked = false;
}

/*
* This method navigates to the proper item in the combobox page. This
* should be executed after setSuggestions() method which is called from
* vFilterSelect.showSuggestions(). ShowSuggestions() method builds the
* page content. As far as setSuggestions() method is called as
* deferred, navigateItemAfterPageChange method should be also be called
* as deferred. #11333
*/
private void navigateItemAfterPageChange() {
if (navigationCallback != null) {
// pageChangeCallback is not reset here but after any server
// request in case you are in between two requests both changing
// the page back and forth

// we're paging w/ arrows
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
@Override
public void execute() {
if (navigationCallback != null) {
navigationCallback.run();
}
}
});
}
}

/**
* Called by the connector when any request has been sent to the server,
* before waiting for a reply.
*/
public void anyRequestSentToServer() {
navigationCallback = null;
}

/**
* Set a callback that is invoked when a page change occurs if there
* have not been intervening requests to the server. The callback is
* reset when any additional request is made to the server.
*
* @param callback
*/
public void setNavigationCallback(Runnable callback) {
navigationCallback = callback;
}

/**
* Record that the popup opener has been clicked and the popup should be
* opened on the next request.
*
* This handles the special case where are not filtering yet and the
* selected value has changed on the server-side. See #2119. The flag is
* cleared on each UIDL reply.
*/
public void popupOpenerClicked() {
popupOpenerClicked = true;
}

/**
* Returns true if the popup opener has been clicked. This method is for
* internal use only and will most likely be removed in the future.
*/
public boolean isPopupOpenerClicked() {
return popupOpenerClicked;
}

public void setUpdateOnDataReceived(boolean update) {
updateOnDataReceived = update;
}

/**
* Called by the connector when it has finished handling any reply from
* the server, regardless of what was updated.
*/
public void serverReplyHandled() {
popupOpenerClicked = false;
}
}

@Deprecated
public static final FilteringMode FILTERINGMODE_OFF = FilteringMode.OFF;
@Deprecated
@@ -1469,9 +1599,6 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
/** For internal use only. May be removed or replaced in the future. */
private boolean waitingForFilteringResponse = false;

/** For internal use only. May be removed or replaced in the future. */
private boolean updateSelectionWhenReponseIsReceived = false;

/** For internal use only. May be removed or replaced in the future. */
public boolean initDone = false;

@@ -1540,6 +1667,8 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
*/
private boolean textInputEnabled = true;

private final DataReceivedHandler dataReceivedHandler = new DataReceivedHandler();

/**
* Default constructor.
*/
@@ -1814,7 +1943,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
debug("VFS: onSuggestionSelected(" + suggestion.caption + ": "
+ suggestion.key + ")");
}
setUpdateSelectionWhenReponseIsReceived(false);
dataReceivedHandler.setUpdateOnDataReceived(false);

currentSuggestion = suggestion;
String newKey;
@@ -2085,7 +2214,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
private void selectPrevPage() {
if (currentPage > 0) {
filterOptions(currentPage - 1, lastFilter);
connector.setNavigateAfterPageReceivedCallback(new Runnable() {
dataReceivedHandler.setNavigationCallback(new Runnable() {
@Override
public void run() {
suggestionPopup.selectLastItem();
@@ -2100,7 +2229,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
private void selectNextPage() {
if (hasNextPage()) {
filterOptions(currentPage + 1, lastFilter);
connector.setNavigateAfterPageReceivedCallback(new Runnable() {
dataReceivedHandler.setNavigationCallback(new Runnable() {
@Override
public void run() {
suggestionPopup.selectFirstItem();
@@ -2196,7 +2325,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
boolean immediate = focused
|| !connector.hasEventListener(EventId.FOCUS);
filterOptions(-1, "", immediate);
connector.popupOpenerClicked();
dataReceivedHandler.popupOpenerClicked();
lastFilter = "";
}
DOM.eventPreventDefault(DOM.eventGetCurrentEvent());
@@ -2557,29 +2686,13 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
}

/**
* For internal use only - this method will be removed in the future.
*
* This flag should not be set when not waiting for a reply from the server.
*
* @return true if the selection should be updated when a server response is
* received
*/
public boolean isUpdateSelectionWhenReponseIsReceived() {
return updateSelectionWhenReponseIsReceived;
}

/**
* For internal use only - this method will be removed in the future.
*
* This flag should not be set when not waiting for a reply from the server.
* Returns a handler receiving notifications from the connector about
* communications.
*
* @param updateSelectionWhenReponseIsReceived
* true if the selection should be updated when a server response
* is received
* @return the dataReceivedHandler
*/
public void setUpdateSelectionWhenReponseIsReceived(
boolean updateSelectionWhenReponseIsReceived) {
this.updateSelectionWhenReponseIsReceived = updateSelectionWhenReponseIsReceived;
public DataReceivedHandler getDataReceivedHandler() {
return dataReceivedHandler;
}

}

+ 9
- 85
client/src/main/java/com/vaadin/client/ui/combobox/ComboBoxConnector.java View File

@@ -19,8 +19,6 @@ import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.vaadin.client.ApplicationConnection;
import com.vaadin.client.Paintable;
import com.vaadin.client.Profiler;
@@ -54,17 +52,6 @@ public class ComboBoxConnector extends AbstractFieldConnector implements

private boolean immediate;

private Runnable pageChangeCallback;

/**
* Set true when popupopened has been clicked. Cleared on each UIDL-update.
* This handles the special case where are not filtering yet and the
* selected value has changed on the server-side. See #2119
* <p>
* For internal use only. May be removed or replaced in the future.
*/
private boolean popupOpenerClicked;

@Override
protected void init() {
super.init();
@@ -222,31 +209,16 @@ public class ComboBoxConnector extends AbstractFieldConnector implements
}
}

// TODO even this condition should probably be moved to the handler
if ((getWidget().isWaitingForFilteringResponse() && getWidget().lastFilter
.toLowerCase().equals(uidl.getStringVariable("filter")))
|| popupOpenAndCleared) {

getWidget().suggestionPopup.showSuggestions(
getWidget().currentSuggestions, getWidget().currentPage,
getWidget().totalMatches);

getWidget().setWaitingForFilteringResponse(false);

if (!popupOpenerClicked) {
navigateItemAfterPageChange();
}

if (getWidget().isUpdateSelectionWhenReponseIsReceived()) {
getWidget().suggestionPopup.menu
.doPostFilterSelectedItemAction();
}
getWidget().getDataReceivedHandler().dataReceived();
}

// Calculate minimum textarea width
getWidget().updateSuggestionPopupMinWidth();

popupOpenerClicked = false;

/*
* if this is our first time we need to recalculate the root width.
*/
@@ -262,32 +234,9 @@ public class ComboBoxConnector extends AbstractFieldConnector implements
}

getWidget().initDone = true;
}

/*
* This method navigates to the proper item in the combobox page. This
* should be executed after setSuggestions() method which is called from
* vFilterSelect.showSuggestions(). ShowSuggestions() method builds the page
* content. As far as setSuggestions() method is called as deferred,
* navigateItemAfterPageChange method should be also be called as deferred.
* #11333
*/
private void navigateItemAfterPageChange() {
if (pageChangeCallback != null) {
// pageChangeCallback is not reset here but after any server request
// in case you are in between two requests both changing the page
// back and forth

// we're paging w/ arrows
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
@Override
public void execute() {
if (pageChangeCallback != null) {
pageChangeCallback.run();
}
}
});
}
// TODO this should perhaps be moved to be a part of dataReceived()
getWidget().getDataReceivedHandler().serverReplyHandled();
}

private void performSelection(String selectedKey) {
@@ -298,7 +247,8 @@ public class ComboBoxConnector extends AbstractFieldConnector implements
continue;
}
if (!getWidget().isWaitingForFilteringResponse()
|| popupOpenerClicked) {
|| getWidget().getDataReceivedHandler()
.isPopupOpenerClicked()) {
if (!suggestionKey.equals(getWidget().selectedOptionKey)
|| suggestion.getReplacementString().equals(
getWidget().tb.getText())
@@ -327,7 +277,8 @@ public class ComboBoxConnector extends AbstractFieldConnector implements
}

private void resetSelection() {
if (!getWidget().isWaitingForFilteringResponse() || popupOpenerClicked) {
if (!getWidget().isWaitingForFilteringResponse()
|| getWidget().getDataReceivedHandler().isPopupOpenerClicked()) {
// select nulled
if (!getWidget().focused) {
/*
@@ -485,19 +436,6 @@ public class ComboBoxConnector extends AbstractFieldConnector implements
}
}

/**
* Set a callback that is invoked when a page change occurs if there have
* not been intervening requests to the server. The callback is reset when
* any additional request is made to the server.
*
* @since
* @param callback
*/
public void setNavigateAfterPageReceivedCallback(Runnable callback) {
pageChangeCallback = callback;

}

/*
* Anything that should be set after the client updates the server.
*/
@@ -505,21 +443,7 @@ public class ComboBoxConnector extends AbstractFieldConnector implements
// We need this here to be consistent with the all the calls.
// Then set your specific selection type only after
// a server request method call.
pageChangeCallback = null;
}

/**
* Record that the popup opener has been clicked and the popup should be
* opened on the next request.
*
* This handles the special case where are not filtering yet and the
* selected value has changed on the server-side. See #2119. The flag is
* cleared on each UIDL reply.
*
* @since
*/
public void popupOpenerClicked() {
popupOpenerClicked = true;
getWidget().getDataReceivedHandler().anyRequestSentToServer();
}

}

Loading…
Cancel
Save