use of org.sablo.util.ValueReference in project servoy-client by Servoy.
the class DataproviderTypeSabloValue method browserUpdateReceived.
public void browserUpdateReceived(Object newJSONValue, IBrowserConverterContext dataConverterContext) {
Object oldUIValue = uiValue;
ValueReference<Boolean> serverSideValueIsNotTheSameAsClient = new ValueReference<>(Boolean.FALSE);
if (!findMode && typeOfDP != null) {
if (typeOfDP.getType() instanceof DatePropertyType && fieldFormat != null && fieldFormat.parsedFormat != null && newJSONValue != null && fieldFormat.parsedFormat.getDisplayFormat() != null && (oldUIValue instanceof Date || oldUIValue == null)) {
boolean hasNoDateConversion = NGDatePropertyType.hasNoDateConversion(typeOfDP);
Date newValue = NGDatePropertyType.NG_INSTANCE.fromJSON(newJSONValue, hasNoDateConversion);
if (oldUIValue != null) {
String format = fieldFormat.parsedFormat.getEditFormat() != null ? fieldFormat.parsedFormat.getEditFormat() : fieldFormat.parsedFormat.getDisplayFormat();
SimpleDateFormat sdf = new SimpleDateFormat(format);
if (!hasNoDateConversion)
sdf.setTimeZone(dataAdapterList.getApplication().getTimeZone());
try {
String oldFormatted = sdf.format(oldUIValue);
String newFormatted = sdf.format(newValue);
// need to go back to the default time zone so it doesn't make it sudden 2 jan 1970 because of the
// time zone difference between the default here and where it needs to go to.
sdf.setTimeZone(TimeZone.getDefault());
Date oldValueParsed = sdf.parse(oldFormatted);
Date newValueParsed = sdf.parse(newFormatted);
uiValue = new Date(((Date) oldUIValue).getTime() + (newValueParsed.getTime() - oldValueParsed.getTime()));
} catch (ParseException e) {
uiValue = newValue;
}
} else {
uiValue = newValue;
}
} else if (typeOfDP.getType() instanceof IPropertyConverterForBrowser<?>) {
try {
uiValue = ((IPropertyConverterForBrowser<Object>) typeOfDP.getType()).fromJSON(newJSONValue, uiValue, typeOfDP, dataConverterContext, serverSideValueIsNotTheSameAsClient);
} catch (ClassCastException e) {
// this can hapen if a find mode uiVaue keeps hanging
uiValue = ((IPropertyConverterForBrowser<Object>) typeOfDP.getType()).fromJSON(newJSONValue, null, typeOfDP, dataConverterContext, serverSideValueIsNotTheSameAsClient);
}
} else {
uiValue = newJSONValue;
}
} else
uiValue = newJSONValue;
if (oldUIValue != uiValue && (oldUIValue == null || !oldUIValue.equals(uiValue))) {
jsonValue = null;
}
if (serverSideValueIsNotTheSameAsClient.value.booleanValue()) {
// if we detect that the new server value (it's representation on client) is no longer what the client has showing, we must update the client's value
jsonValue = null;
// value changed from client so why do we need this one might ask (client already has the value)?
changeMonitor.valueChanged();
// because for example in a field an INTEGER dataprovider might be shown with format ##0.00 and if the user enters non-int value client side
// the server will trunc/round to an INTEGER and then the client shows double value while the server DP has the int value (which are not the same)
}
}
use of org.sablo.util.ValueReference in project servoy-client by Servoy.
the class FoundsetLinkedTypeSabloValue method updatePropertyValueForRecord.
protected void updatePropertyValueForRecord(FoundsetTypeSabloValue foundsetPropertyValue, String rowIDValue, Object value, PropertyDescription wrappedPropertyDescription, IBrowserConverterContext dataConverterContext) {
IFoundSetInternal foundset = foundsetPropertyValue.getFoundset();
Pair<String, Integer> splitHashAndIndex = FoundsetTypeSabloValue.splitPKHashAndIndex(rowIDValue);
if (foundset != null) {
int recordIndex = foundset.getRecordIndex(splitHashAndIndex.getLeft(), splitHashAndIndex.getRight().intValue());
if (recordIndex != -1) {
foundsetPropertyValue.getDataAdapterList().setRecordQuietly(foundset.getRecord(recordIndex));
try {
ValueReference<Boolean> returnValueAdjustedIncommingValueForRow = new ValueReference<Boolean>(Boolean.FALSE);
YT newWrappedValue = (YT) JSONUtils.fromJSONUnwrapped(wrappedSabloValue, value, wrappedPropertyDescription, dataConverterContext, returnValueAdjustedIncommingValueForRow);
if (newWrappedValue != wrappedSabloValue) {
// TODO should we make current method return a completely new instance instead and leave component code do the rest?
if (wrappedSabloValue instanceof IDataLinkedPropertyValue)
((IDataLinkedPropertyValue) wrappedSabloValue).detach();
setWrappedSabloValue(newWrappedValue);
if (wrappedSabloValue instanceof IDataLinkedPropertyValue)
((IDataLinkedPropertyValue) wrappedSabloValue).attachToBaseObject(changeMonitor, wrappedComponentContext);
// the full value has changed; the whole viewport might be affected
viewPortChangeMonitor.viewPortCompletelyChanged();
} else if (returnValueAdjustedIncommingValueForRow.value.booleanValue()) {
FoundsetTypeViewport viewPort = foundsetPropertyValue.getViewPort();
int firstViewPortIndex = Math.max(viewPort.getStartIndex(), recordIndex);
int lastViewPortIndex = Math.min(viewPort.getStartIndex() + viewPort.getSize() - 1, recordIndex);
if (firstViewPortIndex <= lastViewPortIndex) {
viewPortChangeMonitor.queueOperation(firstViewPortIndex - viewPort.getStartIndex(), lastViewPortIndex - viewPort.getStartIndex(), viewPort.getSize(), ArrayOperation.CHANGE);
}
}
} catch (JSONException e) {
Debug.error("Setting value for record dependent property '" + wrappedPropertyDescription + "' in foundset linked component to value: " + value + " failed.", e);
} finally {
foundsetPropertyValue.setDataAdapterListToSelectedRecord();
}
} else {
Debug.error("Cannot set foundset linked record dependent property for (" + rowIDValue + ") property '" + wrappedPropertyDescription + "' to value '" + value + "' of component: " + webObjectContext + ". Record not found.", new RuntimeException());
}
} else {
Debug.error("Cannot set foundset linked record dependent property for (" + rowIDValue + ") property '" + wrappedPropertyDescription + "' to value '" + value + "' of component: " + webObjectContext + ". Foundset is null.", new RuntimeException());
}
}
use of org.sablo.util.ValueReference in project servoy-client by Servoy.
the class FoundsetTypeSabloValue method browserUpdatesReceived.
public void browserUpdatesReceived(Object jsonValue, PropertyDescription pd, IBrowserConverterContext dataConverterContext) {
PushToServerEnum pushToServer = BrowserConverterContext.getPushToServerValue(dataConverterContext);
if (getFoundset() == null)
return;
try {
if (jsonValue instanceof JSONArray) {
JSONArray arr = (JSONArray) jsonValue;
for (int i = 0; i < arr.length(); i++) {
JSONObject update = (JSONObject) arr.get(i);
// {newViewPort: {startIndex : startIndex, size : size}}
if (update.has("newViewPort")) {
JSONObject newViewport = update.getJSONObject("newViewPort");
int requestID = update.getInt(ID_KEY);
viewPort.clearSendingInitialPreferredViewport();
viewPort.setBounds(newViewport.getInt(START_INDEX), newViewport.getInt(SIZE));
changeMonitor.requestIdHandled(requestID, true);
}
if (update.has(PREFERRED_VIEWPORT_SIZE)) {
viewPort.setPreferredViewportSize(update.getInt(PREFERRED_VIEWPORT_SIZE));
if (update.has(FoundsetPropertyTypeConfig.SEND_SELECTION_VIEWPORT_INITIALLY))
viewPort.setSendSelectionViewportInitially(update.getBoolean(FoundsetPropertyTypeConfig.SEND_SELECTION_VIEWPORT_INITIALLY));
if (update.has(INITIAL_SELECTION_VIEWPORT_CENTERED))
viewPort.setInitialSelectionViewportCentered(update.getBoolean(INITIAL_SELECTION_VIEWPORT_CENTERED));
} else // {loadExtraRecords: negativeOrPositiveCount}
if (update.has("loadExtraRecords")) {
int requestID = update.getInt(ID_KEY);
viewPort.clearSendingInitialPreferredViewport();
viewPort.loadExtraRecords(update.getInt("loadExtraRecords"));
changeMonitor.requestIdHandled(requestID, true);
} else // {loadLessRecords: negativeOrPositiveCount}
if (update.has("loadLessRecords")) {
int requestID = update.getInt(ID_KEY);
viewPort.clearSendingInitialPreferredViewport();
viewPort.loadLessRecords(update.getInt("loadLessRecords"));
changeMonitor.requestIdHandled(requestID, true);
} else if (update.has("sort")) {
int requestID = update.getInt(ID_KEY);
JSONArray columns = update.getJSONArray("sort");
StringBuilder sort = new StringBuilder();
Map<String, String> dp = dataproviders.size() > 0 ? dataproviders : recordDataLinkedPropertyIDToColumnDP;
String dataProviderID = null;
boolean sortAscending = true;
for (int j = 0; j < columns.length(); j++) {
JSONObject sortColumn = columns.getJSONObject(j);
String name = sortColumn.getString("name");
if (dp.containsKey(name)) {
sort.append(dp.get(name));
sort.append(" " + sortColumn.getString("direction"));
if (dataProviderID == null) {
dataProviderID = dp.get(name);
sortAscending = "asc".equalsIgnoreCase(sortColumn.getString("direction"));
}
if (j < columns.length() - 1)
sort.append(",");
}
}
IWebFormUI formUI = getFormUI();
IWebFormController fc = (formUI != null ? formUI.getController() : null);
if (fc != null && fc.getForm().getOnSortCmdMethodID() > 0 && dataProviderID != null) {
// our api only supports one dataproviderid sort at a time
JSEvent event = new JSEvent();
event.setFormName(fc.getName());
fc.executeFunction(String.valueOf(fc.getForm().getOnSortCmdMethodID()), Utils.arrayMerge((new Object[] { dataProviderID, Boolean.valueOf(sortAscending), event }), // $NON-NLS-1$
Utils.parseJSExpressions(fc.getForm().getFlattenedMethodArguments("onSortCmdMethodID"))), true, null, false, // $NON-NLS-1$
"onSortCmdMethodID");
} else {
try {
String currentSort = foundset.getSort();
String newSort = sort.toString();
foundset.setSort(newSort);
if (// really a new sort
!Utils.equalObjects(currentSort, newSort) || // not sorted, send back to client
!Utils.equalObjects(foundset.getSort(), newSort)) {
changeMonitor.foundsetSortChanged();
}
} catch (ServoyException e) {
Debug.error("Cannot sort foundset by " + sort.toString(), e);
}
}
changeMonitor.requestIdHandled(requestID, true);
} else // {newClientSelection: newSelectedIndexesArray}
if (update.has("newClientSelection")) {
JSONArray jsonSelectedIndexes = update.getJSONArray("newClientSelection");
int[] newSelectedIndexes = new int[jsonSelectedIndexes.length()];
for (int j = newSelectedIndexes.length - 1; j >= 0; j--) {
newSelectedIndexes[j] = jsonSelectedIndexes.getInt(j);
}
// this !Arrays.equals check in conjunction with pause()/resume() is needed to avoid an effect on the client that server always sends back changed selection in which case
// if the user quickly changes selection multiple times and the connection is slow, selection will jump all over
// the place until it stabilizes correctly
getListSelectionListener().pause();
try {
if (newSelectedIndexes.length == 1) {
foundset.setSelectedIndex(newSelectedIndexes[0]);
} else {
foundset.setSelectedIndexes(newSelectedIndexes);
}
} finally {
getListSelectionListener().resume();
// if server denies the new selection as invalid and doesn't change selection, send it to the client so that it doesn't keep invalid selection
if (!Arrays.equals(foundset.getSelectedIndexes(), newSelectedIndexes)) {
changeMonitor.selectionChanged(false);
}
}
} else // {newClientSelectionRequest: newSelectedIndexesArray}
if (update.has("newClientSelectionRequest")) {
int requestID = update.getInt(ID_KEY);
JSONArray jsonSelectedIndexes = update.getJSONArray("newClientSelectionRequest");
int[] newSelectedIndexes = new int[jsonSelectedIndexes.length()];
for (int j = newSelectedIndexes.length - 1; j >= 0; j--) {
newSelectedIndexes[j] = jsonSelectedIndexes.getInt(j);
}
int[] oldSelection = foundset.getSelectedIndexes();
// this !Arrays.equals check in conjunction with pause()/resume() is needed to avoid an effect on the client that server always sends back changed selection in which case
// if the user quickly changes selection multiple times and the connection is slow, selection will jump all over
// the place until it stabilizes correctly
getListSelectionListener().pause();
try {
if (newSelectedIndexes.length == 1) {
foundset.setSelectedIndex(newSelectedIndexes[0]);
} else {
foundset.setSelectedIndexes(newSelectedIndexes);
}
} finally {
getListSelectionListener().resume();
if (!Arrays.equals(oldSelection, foundset.getSelectedIndexes())) {
// if the selection is changed, send it back to the client so that its model is also updated
changeMonitor.selectionChanged(false);
changeMonitor.requestIdHandled(requestID, true);
} else {
if (!Arrays.equals(oldSelection, newSelectedIndexes)) {
// it was supposed to change but the server did not allow it
changeMonitor.requestIdHandled(requestID, false);
} else
changeMonitor.requestIdHandled(requestID, true);
}
}
} else if (update.has(ViewportDataChangeMonitor.VIEWPORT_CHANGED)) {
if (PushToServerEnum.allow.compareTo(pushToServer) <= 0) {
// {dataChanged: { ROW_ID_COL_KEY: rowIDValue, dataproviderName: value }}
JSONObject dataChangeJSON = (JSONObject) update.get(ViewportDataChangeMonitor.VIEWPORT_CHANGED);
String rowIDValue = dataChangeJSON.getString(ROW_ID_COL_KEY);
String dpKey = dataChangeJSON.getString(DATAPROVIDER_KEY);
String dataProviderName;
if (dataproviders.containsKey(dpKey)) {
dataProviderName = dataproviders.get(dpKey);
} else {
dataProviderName = recordDataLinkedPropertyIDToColumnDP.get(dpKey);
}
Object value = dataChangeJSON.get(VALUE_KEY);
if (foundset != null) {
Pair<String, Integer> splitHashAndIndex = splitPKHashAndIndex(rowIDValue);
int recordIndex = foundset.getRecordIndex(splitHashAndIndex.getLeft(), splitHashAndIndex.getRight().intValue());
if (recordIndex != -1) {
IRecordInternal record = foundset.getRecord(recordIndex);
// convert Dates where it's needed
// this should be enough for when only foundset dataproviders are used
PropertyDescription dataProviderPropDesc = getDataProviderPropertyDescription(dataProviderName);
ValueReference<Boolean> returnValueAdjustedIncommingValueForRow = new ValueReference<Boolean>(Boolean.FALSE);
value = JSONUtils.fromJSONUnwrapped(null, value, dataProviderPropDesc, dataConverterContext, returnValueAdjustedIncommingValueForRow);
try {
if (record.startEditing()) {
try {
record.setValue(dataProviderName, value);
} catch (IllegalArgumentException e) {
// TODO handle the validaton errors.
IWebFormUI formUI = getFormUI();
formUI.getController().getApplication().reportError("Validation for " + dataProviderName + " for value: " + value + " failed.", e);
}
}
// else cannot start editing; finally block will deal with it (send old value back to client as new one can't be pushed)
} finally {
// if server denies the new value as invalid and doesn't change it, send it to the client so that it doesn't keep invalid value; the same if for example a double was rounded to an int
if (!Utils.equalObjects(record.getValue(dataProviderName), value) || returnValueAdjustedIncommingValueForRow.value.booleanValue()) {
changeMonitor.recordsUpdated(recordIndex, recordIndex, foundset.getSize(), viewPort, Arrays.asList(new String[] { dataProviderName }));
}
}
} else {
Debug.error("Cannot set foundset record (" + rowIDValue + ") dataprovider '" + dataProviderName + "' to value '" + value + ". Record not found.");
}
}
} else {
log.error("Property (" + pd + ") that doesn't define a suitable pushToServer value (allow/shallow/deep) tried to modify foundset dataprovider value serverside. Denying and sending back full viewport!");
changeMonitor.viewPortCompletelyChanged();
}
}
}
}
} catch (JSONException e) {
Debug.error("Error when getting browser updates for property (" + this.toString() + ") for " + jsonValue, e);
}
}
use of org.sablo.util.ValueReference in project servoy-client by Servoy.
the class EventExecutor method executeEvent.
public Object executeEvent(WebComponent component, String eventType, int eventId, Object[] eventArgs) {
Scriptable scope = null;
Function f = null;
Object[] newargs = eventArgs != null ? Arrays.copyOf(eventArgs, eventArgs.length) : null;
if (eventId > 0) {
ScriptMethod scriptMethod = formController.getApplication().getFlattenedSolution().getScriptMethod(eventId);
if (scriptMethod != null) {
if (scriptMethod.getParent() instanceof Form) {
FormScope formScope = formController.getFormScope();
f = formScope.getFunctionByName(scriptMethod.getName());
if (f != null && f != Scriptable.NOT_FOUND) {
scope = formScope;
}
} else // is it a global method
if (scriptMethod.getParent() instanceof Solution) {
scope = formController.getApplication().getScriptEngine().getScopesScope().getGlobalScope(scriptMethod.getScopeName());
if (scope != null) {
f = ((GlobalScope) scope).getFunctionByName(scriptMethod.getName());
}
} else // very like a foundset/entity method
{
Scriptable foundsetScope = null;
if (component instanceof WebFormComponent) {
IRecord rec = ((WebFormComponent) component).getDataAdapterList().getRecord();
if (rec != null) {
foundsetScope = (Scriptable) rec.getParentFoundSet();
}
}
if (foundsetScope == null)
foundsetScope = (Scriptable) formController.getFormModel();
if (foundsetScope != null) {
// TODO ViewFoundSets should be come a scriptable if they have foundset methods..
scope = foundsetScope;
Object scopeMethod = scope.getPrototype().get(scriptMethod.getName(), scope);
if (scopeMethod instanceof Function)
f = (Function) scopeMethod;
}
}
if (f == null) {
Debug.error(// $NON-NLS-1$ //$NON-NLS-2$
"No function found for " + scriptMethod + " when trying to execute the event " + eventType + '(' + eventId + ") of component: " + component, // $NON-NLS-1$
new RuntimeException());
return null;
}
} else {
Debug.warn("Couldn't find the ScriptMethod for event: " + eventType + " with event id: " + eventId + " to execute for component " + component);
}
}
// $NON-NLS-1$
if (formController.isInFindMode() && !Utils.getAsBoolean(f.get("_AllowToRunInFind_", f)))
return null;
if (newargs != null) {
for (int i = 0; i < newargs.length; i++) {
if (newargs[i] instanceof JSONObject && "event".equals(((JSONObject) newargs[i]).optString("type"))) {
JSONObject json = (JSONObject) newargs[i];
JSEvent event = new JSEvent();
JSEventType.fillJSEvent(event, json, component, formController);
event.setType(getEventType(eventType));
event.setName(RepositoryHelper.getDisplayName(eventType, BaseComponent.class));
newargs[i] = event;
} else {
// try to convert the received arguments
WebObjectFunctionDefinition propertyDesc = component.getSpecification().getHandler(eventType);
List<PropertyDescription> parameters = propertyDesc.getParameters();
if (i < parameters.size()) {
PropertyDescription parameterPropertyDescription = parameters.get(i);
ValueReference<Boolean> returnValueAdjustedIncommingValueForIndex = new ValueReference<Boolean>(Boolean.FALSE);
newargs[i] = NGConversions.INSTANCE.convertSabloComponentToRhinoValue(JSONUtils.fromJSON(null, newargs[i], parameterPropertyDescription, new BrowserConverterContext(component, PushToServerEnum.allow), returnValueAdjustedIncommingValueForIndex), parameterPropertyDescription, component, scope);
}
// TODO? if in propertyDesc.getAsPropertyDescription().getConfig() we have "type":"${dataproviderType}" and parameterPropertyDescription.getType() is Object
// then get the type from the dataprovider and try to convert the json to that type instead of simply object
}
}
}
if (component instanceof WebFormComponent) {
IPersist persist = ((WebFormComponent) component).getFormElement().getPersistIfAvailable();
if (persist instanceof AbstractBase) {
List<Object> instanceMethodArguments = ((AbstractBase) persist).getFlattenedMethodArguments(eventType);
if (instanceMethodArguments != null && instanceMethodArguments.size() > 0) {
// create entries for the instanceMethodArguments if they are more then callback arguments
if (instanceMethodArguments.size() > newargs.length) {
newargs = Utils.arrayJoin(newargs, new Object[instanceMethodArguments.size() - newargs.length]);
}
// use instanceMethodArguments if not null, else just use the callback argument
for (int i = 0; i < instanceMethodArguments.size(); i++) {
Object value = instanceMethodArguments.get(i);
if (value != null && value != JSONObject.NULL) {
newargs[i] = Utils.parseJSExpression(value);
}
}
}
}
}
try {
formController.getApplication().updateLastAccessed();
return formController.getApplication().getScriptEngine().executeFunction(f, scope, scope, newargs, false, false);
} catch (Exception ex) {
formController.getApplication().reportJSError(ex.getMessage(), ex);
return null;
}
}
Aggregations