blob: 81bc7914298209be861b87844e95194c3c428e1c [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2002, 2012 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.getId;
import static org.eclipse.rap.rwt.internal.protocol.ProtocolUtil.readPropertyValueAsString;
import java.io.IOException;
import org.eclipse.rap.rwt.branding.AbstractBranding;
import org.eclipse.rap.rwt.internal.application.RWTFactory;
import org.eclipse.rap.rwt.internal.branding.BrandingUtil;
import org.eclipse.rap.rwt.internal.lifecycle.DisplayUtil;
import org.eclipse.rap.rwt.internal.lifecycle.DisposedWidgets;
import org.eclipse.rap.rwt.internal.lifecycle.IDisplayLifeCycleAdapter;
import org.eclipse.rap.rwt.internal.lifecycle.RWTRequestVersionControl;
import org.eclipse.rap.rwt.internal.lifecycle.UITestUtil;
import org.eclipse.rap.rwt.internal.protocol.ClientObjectFactory;
import org.eclipse.rap.rwt.internal.protocol.IClientObject;
import org.eclipse.rap.rwt.internal.protocol.ProtocolMessageWriter;
import org.eclipse.rap.rwt.internal.protocol.ProtocolUtil;
import org.eclipse.rap.rwt.internal.service.ContextProvider;
import org.eclipse.rap.rwt.internal.service.RequestParams;
import org.eclipse.rap.rwt.internal.theme.Theme;
import org.eclipse.rap.rwt.internal.theme.ThemeUtil;
import org.eclipse.rap.rwt.internal.uicallback.UICallBackServiceHandler;
import org.eclipse.rap.rwt.internal.util.ActiveKeysUtil;
import org.eclipse.rap.rwt.internal.util.NumberFormatUtil;
import org.eclipse.rap.rwt.lifecycle.AbstractWidgetLCA;
import org.eclipse.rap.rwt.lifecycle.IWidgetAdapter;
import org.eclipse.rap.rwt.lifecycle.IWidgetLifeCycleAdapter;
import org.eclipse.rap.rwt.lifecycle.WidgetUtil;
import org.eclipse.swt.dnd.DragSource;
import org.eclipse.swt.dnd.DropTarget;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.internal.widgets.EventUtil;
import org.eclipse.swt.internal.widgets.IDisplayAdapter;
import org.eclipse.swt.internal.widgets.IShellAdapter;
import org.eclipse.swt.internal.widgets.WidgetAdapter;
import org.eclipse.swt.internal.widgets.WidgetTreeVisitor;
import org.eclipse.swt.internal.widgets.WidgetTreeVisitor.AllWidgetTreeVisitor;
import org.eclipse.swt.widgets.Composite;
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 implements IDisplayLifeCycleAdapter {
static final String PROP_REQUEST_COUNTER = "requestCounter";
static final String PROP_FOCUS_CONTROL = "focusControl";
static final String PROP_CURRENT_THEME = "currentTheme";
static final String PROP_EXIT_CONFIRMATION = "exitConfirmation";
private static final String METHOD_BEEP = "beep";
private static final class RenderVisitor extends AllWidgetTreeVisitor {
private IOException ioProblem;
@Override
public boolean doVisit( Widget widget ) {
ioProblem = null;
boolean result = true;
try {
render( widget );
runRenderRunnable( widget );
} catch( IOException ioe ) {
ioProblem = ioe;
result = false;
}
return result;
}
private void reThrowProblem() throws IOException {
if( ioProblem != null ) {
throw ioProblem;
}
}
private static void render( Widget widget ) throws IOException {
WidgetUtil.getLCA( widget ).render( widget );
}
private static void runRenderRunnable( Widget widget )
throws IOException
{
WidgetAdapter adapter = ( WidgetAdapter )WidgetUtil.getAdapter( widget );
if( adapter.getRenderRunnable() != null ) {
adapter.getRenderRunnable().afterRender();
adapter.clearRenderRunnable();
}
}
}
////////////////////////////////////////////////////////
// interface implementation of IDisplayLifeCycleAdapter
public void readData( Display display ) {
readBounds( display );
readCursorLocation( display );
readFocusControl( display );
WidgetTreeVisitor visitor = new AllWidgetTreeVisitor() {
@Override
public boolean doVisit( Widget widget ) {
IWidgetLifeCycleAdapter adapter = WidgetUtil.getLCA( widget );
adapter.readData( widget );
return true;
}
};
Shell[] shells = getShells( display );
for( int i = 0; i < shells.length; i++ ) {
Composite shell = shells[ i ];
WidgetTreeVisitor.accept( shell, visitor );
}
for( int i = 0; i < shells.length; i++ ) {
if( shells[ i ].getMaximized() || shells[ i ].getFullScreen() ) {
Object adapter = shells[ i ].getAdapter( IShellAdapter.class );
IShellAdapter shellAdapter = ( IShellAdapter )adapter;
shellAdapter.setBounds( display.getBounds() );
}
}
DNDSupport.processEvents();
}
public void preserveValues( Display display ) {
IWidgetAdapter adapter = DisplayUtil.getAdapter( display );
adapter.preserve( PROP_FOCUS_CONTROL, display.getFocusControl() );
adapter.preserve( PROP_CURRENT_THEME, ThemeUtil.getCurrentThemeId() );
adapter.preserve( PROP_EXIT_CONFIRMATION, getExitConfirmation() );
ActiveKeysUtil.preserveActiveKeys( display );
ActiveKeysUtil.preserveCancelKeys( display );
if( adapter.isInitialized() ) {
Shell[] shells = getShells( display );
for( int i = 0; i < shells.length; i++ ) {
WidgetTreeVisitor.accept( shells[ i ], new AllWidgetTreeVisitor() {
@Override
public boolean doVisit( Widget widget ) {
AbstractWidgetLCA widgetLCA = WidgetUtil.getLCA( widget );
widgetLCA.preserveValues( widget );
return true;
}
} );
}
}
}
public void render( Display display ) throws IOException {
// Note [rst] Startup page created in LifecycleServiceHandler#runLifeCycle
// TODO [rh] should be replaced by requestCounter != 0
if( ProtocolUtil.readHeadPropertyValue( RequestParams.UIROOT ) != null ) {
disposeWidgets();
renderRequestCounter();
renderTheme( display );
renderExitConfirmation( display );
renderEnableUiTests( display );
renderShells( display );
renderFocus( display );
renderBeep( display );
writeUICallBackActivation( display );
markInitialized( display );
ActiveKeysUtil.renderActiveKeys( display );
ActiveKeysUtil.renderCancelKeys( display );
}
}
public void clearPreserved( Display display ) {
WidgetAdapter widgetAdapter = ( WidgetAdapter )DisplayUtil.getAdapter( display );
widgetAdapter.clearPreserved();
Composite[] shells = getShells( display );
for( int i = 0; i < shells.length; i++ ) {
WidgetTreeVisitor.accept( shells[ i ], new AllWidgetTreeVisitor() {
@Override
public boolean doVisit( Widget widget ) {
WidgetAdapter widgetAdapter = ( WidgetAdapter )WidgetUtil.getAdapter( widget );
widgetAdapter.clearPreserved();
return true;
}
} );
}
}
private static void renderShells( Display display ) throws IOException {
RenderVisitor visitor = new RenderVisitor();
Composite[] shells = getShells( display );
for( int i = 0; i < shells.length; i++ ) {
WidgetTreeVisitor.accept( shells[ i ], visitor );
visitor.reThrowProblem();
}
}
private static void renderRequestCounter() {
ProtocolMessageWriter protocolWriter = ContextProvider.getProtocolWriter();
Integer requestId = RWTRequestVersionControl.getInstance().nextRequestId();
protocolWriter.appendHead( PROP_REQUEST_COUNTER, requestId.intValue() );
}
private static void renderTheme( Display display ) {
String currThemeId = ThemeUtil.getCurrentThemeId();
IWidgetAdapter adapter = DisplayUtil.getAdapter( display );
Object oldThemeId = adapter.getPreserved( PROP_CURRENT_THEME );
if( !currThemeId.equals( oldThemeId ) ) {
Theme theme = RWTFactory.getThemeManager().getTheme( currThemeId );
IClientObject clientObject = ClientObjectFactory.getClientObject( display );
clientObject.set( PROP_CURRENT_THEME, theme.getJsId() );
}
}
private static void renderExitConfirmation( Display display ) {
String exitConfirmation = getExitConfirmation();
IWidgetAdapter adapter = DisplayUtil.getAdapter( display );
Object oldExitConfirmation = adapter.getPreserved( PROP_EXIT_CONFIRMATION );
boolean hasChanged = exitConfirmation == null
? oldExitConfirmation != null
: !exitConfirmation.equals( oldExitConfirmation );
if( hasChanged ) {
IClientObject clientObject = ClientObjectFactory.getClientObject( display );
clientObject.set( PROP_EXIT_CONFIRMATION, exitConfirmation );
}
}
private static String getExitConfirmation() {
AbstractBranding branding = BrandingUtil.determineBranding();
String result = null; // does not display exit dialog
if( branding.showExitConfirmation() ) {
result = branding.getExitConfirmationText();
if( result == null ) {
result = ""; // displays an exit dialog with empty message
}
}
return result;
}
/////////////////////////////
// Helping methods for render
private static void disposeWidgets() throws IOException {
Widget[] disposedWidgets = DisposedWidgets.getAll();
// TODO [rh] get rid of dependency on DragSource/DropTarget
// Must dispose of DragSources and DropTargets first
for( int i = disposedWidgets.length - 1; i >= 0; i-- ) {
Widget toDispose = disposedWidgets[ i ];
if( toDispose instanceof DragSource || toDispose instanceof DropTarget ) {
AbstractWidgetLCA lca = WidgetUtil.getLCA( toDispose );
lca.renderDispose( toDispose );
}
}
// TODO [rst] since widget pooling is removed, the loop should be reverted
// again
// [fappel]: client side disposal order is crucial for the widget
// caching mechanism - we need to dispose of children first. This
// is reverse to the server side mechanism (which is analog to
// SWT).
for( int i = disposedWidgets.length - 1; i >= 0; i-- ) {
Widget toDispose = disposedWidgets[ i ];
if( !( toDispose instanceof DragSource )
&& !( toDispose instanceof DropTarget ) )
{
AbstractWidgetLCA lca = WidgetUtil.getLCA( toDispose );
lca.renderDispose( toDispose );
}
}
}
private static void renderFocus( Display display ) {
if( !display.isDisposed() ) {
IDisplayAdapter displayAdapter = getDisplayAdapter( display );
IWidgetAdapter widgetAdapter = DisplayUtil.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 ) {
IClientObject clientObject = ClientObjectFactory.getClientObject( display );
clientObject.set( PROP_FOCUS_CONTROL,
WidgetUtil.getId( display.getFocusControl() ) );
}
}
}
}
private static void renderBeep( Display display ) {
IDisplayAdapter displayAdapter = getDisplayAdapter( display );
if( displayAdapter.isBeepCalled() ) {
displayAdapter.resetBeep();
IClientObject clientObject = ClientObjectFactory.getClientObject( display );
clientObject.call( METHOD_BEEP, null );
}
}
private static void renderEnableUiTests( Display display ) {
if( UITestUtil.isEnabled() ) {
WidgetAdapter adapter = ( WidgetAdapter )DisplayUtil.getAdapter( display );
if( !adapter.isInitialized() ) {
IClientObject clientObject = ClientObjectFactory.getClientObject( display );
clientObject.set( "enableUiTests", true );
}
}
}
private static void writeUICallBackActivation( Display display ) {
ProtocolMessageWriter protocolWriter = ContextProvider.getProtocolWriter();
UICallBackServiceHandler.writeUICallBackActivation( protocolWriter );
}
private static void markInitialized( Display display ) {
WidgetAdapter adapter = ( WidgetAdapter )DisplayUtil.getAdapter( display );
adapter.setInitialized( true );
}
static void readBounds( Display display ) {
Rectangle oldBounds = display.getBounds();
Rectangle bounds = ProtocolUtil.readPropertyValueAsRectangle( "w1", "bounds" );
if( bounds == null ) {
bounds = new Rectangle( 0, 0, oldBounds.width, oldBounds.height );
}
getDisplayAdapter( display ).setBounds( bounds );
}
private static void readCursorLocation( Display display ) {
Point location = ProtocolUtil.readPropertyValueAsPoint( getId( display ), "cursorLocation" );
if( location == null ) {
location = new Point( 0, 0 );
}
getDisplayAdapter( display ).setCursorLocation( location.x, location.y );
}
static void readFocusControl( Display display ) {
// TODO [rh] revise this: traversing the widget tree once more only to find
// out which control is focused. Could that be optimized?
String id = readPropertyValue( display, "focusControl" );
if( id != null ) {
Control focusControl = null;
// Even though the loop below would anyway result in focusControl == null
// the client may send 'null' to indicate that no control on the active
// shell currently has the input focus.
if( !"null".equals( id ) ) {
Shell[] shells = getDisplayAdapter( display ).getShells();
for( int i = 0; focusControl == null && i < shells.length; i++ ) {
Widget widget = WidgetUtil.find( shells[ i ], id );
if( widget instanceof Control ) {
focusControl = ( Control )widget;
}
}
}
if( focusControl != null && EventUtil.isAccessible( focusControl ) ) {
getDisplayAdapter( display ).setFocusControl( focusControl );
}
}
}
private static String readPropertyValue( Display display, String propertyName ) {
return readPropertyValueAsString( getId( display ), propertyName );
}
private static int readIntPropertyValue( Display display, String propertyName, int defaultValue )
{
String value = readPropertyValue( display, propertyName );
int result;
if( value == null ) {
result = defaultValue;
} else {
result = NumberFormatUtil.parseInt( value );
}
return result;
}
private static IDisplayAdapter getDisplayAdapter( Display display ) {
Object adapter = display.getAdapter( IDisplayAdapter.class );
return ( IDisplayAdapter )adapter;
}
private static Shell[] getShells( Display display ) {
return getDisplayAdapter( display ).getShells();
}
}