/*******************************************************************************
* Copyright (c) 2002, 2017 Innoopract Informationssysteme GmbH 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:
* Innoopract Informationssysteme GmbH - initial API and implementation
* EclipseSource - ongoing development
******************************************************************************/
package org.eclipse.swt.internal.widgets.displaykit;
import static org.eclipse.rap.rwt.internal.lifecycle.DisplayUtil.getAdapter;
import static org.eclipse.rap.rwt.internal.lifecycle.DisplayUtil.getId;
import static org.eclipse.rap.rwt.internal.lifecycle.WidgetUtil.getAdapter;
import static org.eclipse.rap.rwt.internal.lifecycle.WidgetUtil.getId;
import static org.eclipse.rap.rwt.internal.lifecycle.WidgetUtil.getLCA;
import static org.eclipse.rap.rwt.internal.protocol.ClientMessageConst.EVENT_RESIZE;
import static org.eclipse.rap.rwt.internal.protocol.ProtocolUtil.handleOperation;
import static org.eclipse.rap.rwt.internal.protocol.RemoteObjectFactory.getRemoteObject;
import static org.eclipse.rap.rwt.internal.service.ContextProvider.getRequest;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.eclipse.rap.rwt.RWT;
import org.eclipse.rap.rwt.client.WebClient;
import org.eclipse.rap.rwt.client.service.ExitConfirmation;
import org.eclipse.rap.rwt.internal.application.ApplicationContextImpl;
import org.eclipse.rap.rwt.internal.lifecycle.DisposedWidgets;
import org.eclipse.rap.rwt.internal.lifecycle.EntryPointManager;
import org.eclipse.rap.rwt.internal.lifecycle.EntryPointRegistration;
import org.eclipse.rap.rwt.internal.lifecycle.RemoteAdapter;
import org.eclipse.rap.rwt.internal.lifecycle.ReparentedControls;
import org.eclipse.rap.rwt.internal.lifecycle.UITestUtil;
import org.eclipse.rap.rwt.internal.protocol.ClientMessage;
import org.eclipse.rap.rwt.internal.protocol.Operation;
import org.eclipse.rap.rwt.internal.protocol.ProtocolUtil;
import org.eclipse.rap.rwt.internal.protocol.RemoteObjectFactory;
import org.eclipse.rap.rwt.internal.remote.RemoteObjectLifeCycleAdapter;
import org.eclipse.rap.rwt.internal.service.ContextProvider;
import org.eclipse.rap.rwt.internal.textsize.MeasurementUtil;
import org.eclipse.rap.rwt.internal.util.ActiveKeysUtil;
import org.eclipse.rap.rwt.remote.OperationHandler;
import org.eclipse.swt.SWT;
import org.eclipse.swt.internal.widgets.ControlRemoteAdapter;
import org.eclipse.swt.internal.widgets.IDisplayAdapter;
import org.eclipse.swt.internal.widgets.WidgetRemoteAdapter;
import org.eclipse.swt.internal.widgets.WidgetTreeUtil;
import org.eclipse.swt.internal.widgets.WidgetTreeVisitor;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Widget;
public class DisplayLCA {
static final String PROP_FOCUS_CONTROL = "focusControl";
static final String PROP_EXIT_CONFIRMATION = "exitConfirmation";
private static final String METHOD_BEEP = "beep";
private static final String PROP_RESIZE_LISTENER = "listener_Resize";
public void readData( Display display ) {
handleOperations( display );
visitWidgets( display );
DNDSupport.handleOperations();
RemoteObjectLifeCycleAdapter.readData( ProtocolUtil.getClientMessage() );
}
public void preserveValues( Display display ) {
RemoteAdapter adapter = getAdapter( display );
adapter.preserve( PROP_FOCUS_CONTROL, display.getFocusControl() );
adapter.preserve( PROP_EXIT_CONFIRMATION, getExitConfirmation() );
adapter.preserve( PROP_RESIZE_LISTENER, Boolean.valueOf( hasResizeListener( display ) ) );
ActiveKeysUtil.preserveActiveKeys( display );
ActiveKeysUtil.preserveCancelKeys( display );
ActiveKeysUtil.preserveMnemonicActivator( display );
if( adapter.isInitialized() ) {
for( Shell shell : getShells( display ) ) {
WidgetTreeUtil.accept( shell, new WidgetTreeVisitor() {
@Override
public boolean visit( Widget widget ) {
getLCA( widget ).preserveValues( widget );
return true;
}
} );
}
}
}
public void render( Display display ) throws IOException {
renderOverflow( display );
renderReparentControls();
renderDisposeWidgets();
renderExitConfirmation( display );
renderEnableUiTests( display );
renderShells( display );
renderFocus( display );
renderBeep( display );
renderResizeListener( display );
renderServerPush( display );
ActiveKeysUtil.renderActiveKeys( display );
ActiveKeysUtil.renderCancelKeys( display );
ActiveKeysUtil.renderMnemonicActivator( display );
RemoteObjectLifeCycleAdapter.render();
MeasurementUtil.renderMeasurementItems();
runRenderRunnables( display );
markInitialized( display );
}
public void clearPreserved( Display display ) {
( ( WidgetRemoteAdapter )getAdapter( display ) ).clearPreserved();
for( Shell shell : getShells( display ) ) {
WidgetTreeUtil.accept( shell, new WidgetTreeVisitor() {
@Override
public boolean visit( Widget widget ) {
( ( WidgetRemoteAdapter )getAdapter( widget ) ).clearPreserved();
return true;
}
} );
}
}
private static void handleOperations( Display display ) {
ClientMessage clientMessage = ProtocolUtil.getClientMessage();
List<Operation> operations = clientMessage .getAllOperationsFor( getId( display ) );
if( !operations.isEmpty() ) {
OperationHandler handler = new DisplayOperationHandler( display );
for( Operation operation : operations ) {
handleOperation( handler, operation );
}
}
}
private static void visitWidgets( Display display ) {
WidgetTreeVisitor visitor = new WidgetTreeVisitor() {
@Override
public boolean visit( Widget widget ) {
getLCA( widget ).readData( widget );
return true;
}
};
for( Shell shell : getShells( display ) ) {
WidgetTreeUtil.accept( shell, visitor );
}
}
private static void renderOverflow( Display display ) {
if( !getAdapter( display ).isInitialized() ) {
String overflow = getEntryPointProperties().get( WebClient.PAGE_OVERFLOW );
if( overflow != null ) {
RemoteObjectFactory.getRemoteObject( display ).set( "overflow", overflow );
}
}
}
private static Map<String, String> getEntryPointProperties() {
ApplicationContextImpl applicationContext = ContextProvider.getApplicationContext();
EntryPointManager entryPointManager = applicationContext.getEntryPointManager();
String servletPath = getRequest().getServletPath();
EntryPointRegistration registration = entryPointManager.getRegistrationByPath( servletPath );
if( registration != null ) {
return registration.getProperties();
}
return Collections.emptyMap();
}
private static void renderShells( Display display ) throws IOException {
RenderVisitor visitor = new RenderVisitor();
for( Shell shell : getShells( display ) ) {
WidgetTreeUtil.accept( shell, visitor );
visitor.reThrowProblem();
}
}
private static void renderExitConfirmation( Display display ) {
String exitConfirmation = getExitConfirmation();
RemoteAdapter adapter = getAdapter( display );
Object oldExitConfirmation = adapter.getPreserved( PROP_EXIT_CONFIRMATION );
boolean hasChanged = exitConfirmation == null
? oldExitConfirmation != null
: !exitConfirmation.equals( oldExitConfirmation );
if( hasChanged ) {
getRemoteObject( display ).set( PROP_EXIT_CONFIRMATION, exitConfirmation );
}
}
private static String getExitConfirmation() {
ExitConfirmation exitConfirmation = RWT.getClient().getService( ExitConfirmation.class );
return exitConfirmation == null ? null : exitConfirmation.getMessage();
}
private static void renderReparentControls() {
for( Control control : ReparentedControls.getAll() ) {
if( !control.isDisposed() ) {
getRemoteAdapter( control ).renderParent( control );
}
}
}
private static ControlRemoteAdapter getRemoteAdapter( Control control ) {
return ( ControlRemoteAdapter )control.getAdapter( RemoteAdapter.class );
}
private static void renderDisposeWidgets() throws IOException {
for( Widget widget : DisposedWidgets.getAll() ) {
getLCA( widget ).renderDispose( widget );
}
}
private static void renderFocus( Display display ) {
if( !display.isDisposed() ) {
IDisplayAdapter displayAdapter = getDisplayAdapter( display );
RemoteAdapter widgetAdapter = getAdapter( display );
Object oldValue = widgetAdapter.getPreserved( PROP_FOCUS_CONTROL );
if( !widgetAdapter.isInitialized()
|| oldValue != display.getFocusControl()
|| displayAdapter.isFocusInvalidated() )
{
// TODO [rst] Added null check as a NPE occurred in some rare cases
Control focusControl = display.getFocusControl();
if( focusControl != null ) {
getRemoteObject( display ).set( PROP_FOCUS_CONTROL, getId( display.getFocusControl() ) );
}
}
}
}
private static void renderBeep( Display display ) {
IDisplayAdapter displayAdapter = getDisplayAdapter( display );
if( displayAdapter.isBeepCalled() ) {
displayAdapter.resetBeep();
getRemoteObject( display ).call( METHOD_BEEP, null );
}
}
private static void renderResizeListener( Display display ) {
RemoteAdapter adapter = getAdapter( display );
Boolean oldValue = ( Boolean )adapter.getPreserved( PROP_RESIZE_LISTENER );
if( oldValue == null ) {
oldValue = Boolean.FALSE;
}
Boolean newValue = Boolean.valueOf( hasResizeListener( display ) );
if( !oldValue.equals( newValue ) ) {
getRemoteObject( display ).listen( EVENT_RESIZE, newValue.booleanValue() );
}
}
private static void renderServerPush( Display display ) {
ServerPushRenderer serverPushRenderer = new ServerPushRenderer();
if( display.isDisposed() ) {
serverPushRenderer.renderActivation( false );
} else {
serverPushRenderer.render();
}
}
private static void renderEnableUiTests( Display display ) {
if( UITestUtil.isEnabled() ) {
if( !getAdapter( display ).isInitialized() ) {
RemoteObjectFactory.getRemoteObject( display ).set( "enableUiTests", true );
}
}
}
private static void runRenderRunnables( Display display ) {
WidgetRemoteAdapter adapter = ( WidgetRemoteAdapter )getAdapter( display );
for( Runnable runnable : adapter.getRenderRunnables() ) {
runnable.run();
}
adapter.clearRenderRunnables();
}
private static void markInitialized( Display display ) {
( ( WidgetRemoteAdapter )getAdapter( display ) ).setInitialized( true );
}
private static boolean hasResizeListener( Display display ) {
return getDisplayAdapter( display ).isListening( SWT.Resize );
}
private static IDisplayAdapter getDisplayAdapter( Display display ) {
return display.getAdapter( IDisplayAdapter.class );
}
private static Shell[] getShells( Display display ) {
return getDisplayAdapter( display ).getShells();
}
private static final class RenderVisitor implements WidgetTreeVisitor {
private IOException ioProblem;
@Override
public boolean visit( Widget widget ) {
ioProblem = null;
try {
render( widget );
runRenderRunnables( widget );
} catch( IOException ioe ) {
ioProblem = ioe;
return false;
}
return true;
}
private void reThrowProblem() throws IOException {
if( ioProblem != null ) {
throw ioProblem;
}
}
private static void render( Widget widget ) throws IOException {
getLCA( widget ).render( widget );
}
private static void runRenderRunnables( Widget widget ) {
WidgetRemoteAdapter adapter = ( WidgetRemoteAdapter )getAdapter( widget );
for( Runnable runnable : adapter.getRenderRunnables() ) {
runnable.run();
}
adapter.clearRenderRunnables();
}
}
}