/*******************************************************************************
* Copyright (c) 2011, 2014 Frank Appel and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Frank Appel - initial API and implementation
* EclipseSource - ongoing development
******************************************************************************/
package org.eclipse.rap.rwt.internal.textsize;
import static org.eclipse.rap.rwt.internal.service.ContextProvider.getApplicationContext;
import static org.eclipse.rap.rwt.internal.service.ContextProvider.getProtocolWriter;
import static org.eclipse.rap.rwt.internal.textsize.MeasurementUtil.createItemParamObject;
import static org.eclipse.rap.rwt.internal.textsize.MeasurementUtil.createProbeParamObject;
import static org.eclipse.rap.rwt.internal.textsize.MeasurementUtil.getId;
import static org.eclipse.rap.rwt.remote.JsonMapping.readPoint;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import org.eclipse.rap.json.JsonArray;
import org.eclipse.rap.json.JsonObject;
import org.eclipse.rap.json.JsonValue;
import org.eclipse.rap.rwt.RWT;
import org.eclipse.rap.rwt.internal.lifecycle.LifeCycleUtil;
import org.eclipse.rap.rwt.internal.lifecycle.ProcessActionRunner;
import org.eclipse.rap.rwt.internal.remote.ConnectionImpl;
import org.eclipse.rap.rwt.remote.AbstractOperationHandler;
import org.eclipse.rap.rwt.remote.RemoteObject;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.internal.SerializableCompatibility;
class MeasurementOperator implements SerializableCompatibility {
static final String TYPE = "rwt.client.TextSizeMeasurement";
static final String METHOD_MEASURE_ITEMS = "measureItems";
static final String PARAM_ITEMS = "items";
static final String METHOD_STORE_MEASUREMENTS = "storeMeasurements";
static final String PARAM_RESULTS = "results";
private final RemoteObject remoteObject;
private final Set<Probe> probes;
private final Set<MeasurementItem> items;
MeasurementOperator() {
ConnectionImpl connection = ( ConnectionImpl )RWT.getUISession().getConnection();
remoteObject = connection.createServiceObject( TYPE );
remoteObject.setHandler( new MeasurementOperatorHandler() );
probes = new HashSet<>();
items = new HashSet<>();
addStartupProbesToBuffer();
}
private void addStartupProbesToBuffer() {
Probe[] probeList = getApplicationContext().getProbeStore().getProbes();
probes.addAll( Arrays.asList( probeList ) );
}
int getProbeCount() {
return probes.size();
}
Probe[] getProbes() {
return probes.toArray( new Probe[ probes.size() ] );
}
void addProbeToMeasure( FontData fontData ) {
Probe probe = getApplicationContext().getProbeStore().getProbe( fontData );
if( probe == null ) {
probe = getApplicationContext().getProbeStore().createProbe( fontData );
}
probes.add( probe );
}
int getItemCount() {
return items.size();
}
MeasurementItem[] getItems() {
return items.toArray( new MeasurementItem[ items.size() ] );
}
void addItemToMeasure( MeasurementItem newItem ) {
items.add( newItem );
}
void renderMeasurementItems() {
Probe[] probes = getProbes();
MeasurementItem[] items = getItems();
if( probes.length > 0 || items.length > 0 ) {
JsonArray itemsArray = new JsonArray();
for( Probe probe : probes ) {
itemsArray.add( createProbeParamObject( probe ) );
}
for( MeasurementItem item : items ) {
itemsArray.add( createItemParamObject( item ) );
}
// [if] This call operation must be at the end of protocol message.
// Render call operation directly to protocol writer (instead through remote object) as
// this method is called after RemoteObjectLifeCycleAdapter.render() in DisplayLCA.render().
JsonObject parameters = new JsonObject().add( PARAM_ITEMS, itemsArray );
getProtocolWriter().appendCall( TYPE, METHOD_MEASURE_ITEMS, parameters );
}
}
private final class MeasurementOperatorHandler extends AbstractOperationHandler {
@Override
public void handleCall( String method, JsonObject parameters ) {
if( METHOD_STORE_MEASUREMENTS.equals( method ) ) {
final JsonObject results = parameters.get( PARAM_RESULTS ).asObject();
if( LifeCycleUtil.isStartup() ) {
handleMeasuredFontProbeSizes( results );
} else {
ProcessActionRunner.add( new Runnable() {
@Override
public void run() {
handleMeasuredFontProbeSizes( results );
if( handleMeasuredTextSizes( results ) ) {
TextSizeRecalculation.execute();
}
}
} );
}
}
}
private void handleMeasuredFontProbeSizes( JsonObject results ) {
Iterator<Probe> probeList = probes.iterator();
while( probeList.hasNext() ) {
Probe probe = probeList.next();
Point size = readMeasuredSize( results, getId( probe ) );
if( size != null ) {
createProbeResult( probe, size );
probeList.remove();
}
}
}
private boolean handleMeasuredTextSizes( JsonObject results ) {
int originalItemsSize = items.size();
Iterator<MeasurementItem> itemList = items.iterator();
while( itemList.hasNext() ) {
MeasurementItem item = itemList.next();
Point size = readMeasuredSize( results, getId( item ) );
if( size != null ) {
storeTextMeasurement( item, size );
itemList.remove();
}
}
return originalItemsSize != items.size();
}
private Point readMeasuredSize( JsonObject results, String id ) {
JsonValue value = results.get( id );
if( value != null ) {
return readPoint( value );
}
return null;
}
private void createProbeResult( Probe probe, Point size ) {
ProbeResultStore.getInstance().createProbeResult( probe, size );
}
private void storeTextMeasurement( MeasurementItem item, Point size ) {
FontData fontData = item.getFontData();
String textToMeasure = item.getTextToMeasure();
int wrapWidth = item.getWrapWidth();
int mode = item.getMode();
TextSizeStorageUtil.store( fontData, textToMeasure, wrapWidth, mode, size );
}
}
}