/******************************************************************************* * Copyright (c) 2007, 2010 Innoopract Informationssysteme GmbH. * 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.graphics; import java.io.IOException; import javax.servlet.http.*; import org.eclipse.rwt.internal.lifecycle.LifeCycleFactory; import org.eclipse.rwt.internal.lifecycle.RWTLifeCycle; import org.eclipse.rwt.internal.service.ContextProvider; import org.eclipse.rwt.internal.service.ServletLog; import org.eclipse.rwt.lifecycle.*; import org.eclipse.rwt.service.ISessionStore; import org.eclipse.swt.custom.ScrolledComposite; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.internal.graphics.TextSizeDetermination.ICalculationItem; import org.eclipse.swt.internal.graphics.TextSizeProbeStore.IProbe; import org.eclipse.swt.internal.widgets.*; import org.eclipse.swt.internal.widgets.WidgetTreeVisitor.AllWidgetTreeVisitor; import org.eclipse.swt.widgets.*; final class TextSizeDeterminationHandler implements PhaseListener, HttpSessionBindingListener { private static final long serialVersionUID = 1L; private static final String CALCULATION_HANDLER = TextSizeDeterminationHandler.class.getName() + ".CalculationHandler"; ICalculationItem[] calculationItems; boolean renderDone; private final Display display; private IProbe[] probes; static void register() { Display display = RWTLifeCycle.getSessionDisplay(); if( display != null && display.getThread() == Thread.currentThread() ) { ISessionStore session = ContextProvider.getSession(); if( session.getAttribute( CALCULATION_HANDLER ) == null ) { TextSizeDeterminationHandler handler = new TextSizeDeterminationHandler( display ); session.setAttribute( CALCULATION_HANDLER, handler ); LifeCycleFactory.getLifeCycle().addPhaseListener( handler ); } } } TextSizeDeterminationHandler( final Display display ) { this.display = display; } ////////////////////////// // interface PhaseListener public void beforePhase( final PhaseEvent event ) { } public void afterPhase( final PhaseEvent event ) { if( display == RWTLifeCycle.getSessionDisplay() ) { try { if( renderDone && event.getPhaseId() == PhaseId.PROCESS_ACTION ) { readProbedFonts( probes ); readMeasuredStrings(); Object adapter = display.getAdapter( IDisplayAdapter.class ); IDisplayAdapter displayAdapter = ( IDisplayAdapter )adapter; Shell[] shells = displayAdapter.getShells(); for( int i = 0; i < shells.length; i++ ) { // TODO [fappel]: Think about a lighter recalculation trigger. Shell shell = shells[ i ]; Rectangle bufferedBounds = shell.getBounds(); AllWidgetTreeVisitor clearLayout = new AllWidgetTreeVisitor() { public boolean doVisit( final Widget widget ) { if( widget instanceof Composite ) { Composite composite = ( Composite )widget; composite.changed( composite.getChildren() ); } return true; } }; // TODO [rst] Special handling for ScrolledComposites: // Resizing makes SCs forget about their scroll position. final String scOriginKey = "org.eclipse.rap.sc-origin"; final String scContentSizeKey = "org.eclipse.rap.content-size"; AllWidgetTreeVisitor saveSCOrigins = new AllWidgetTreeVisitor() { public boolean doVisit( final Widget widget ) { if( widget instanceof ScrolledComposite ) { ScrolledComposite composite = ( ScrolledComposite )widget; composite.setData( scOriginKey, composite.getOrigin() ); Control content = composite.getContent(); if( content != null ) { content.setData( scContentSizeKey, content.getSize() ); } } return true; } }; AllWidgetTreeVisitor restoreSCOrigins = new AllWidgetTreeVisitor() { public boolean doVisit( final Widget widget ) { // restore sc origins if( widget instanceof ScrolledComposite ) { ScrolledComposite composite = ( ScrolledComposite )widget; Point oldOrigin = ( Point )composite.getData( scOriginKey ); if( oldOrigin != null ) { composite.setOrigin( oldOrigin ); composite.setData( scOriginKey, null ); Control content = composite.getContent(); if( content != null ) { Point size = ( Point )content.getData( scContentSizeKey ); if( size != null ) { content.setSize( size ); content.setData( scContentSizeKey, null ); } } } } return true; } }; WidgetTreeVisitor.accept( shell, saveSCOrigins ); WidgetTreeVisitor.accept( shell, clearLayout ); IShellAdapter shellAdapter = ( IShellAdapter )shell.getAdapter( IShellAdapter.class ); Rectangle bounds1000 = new Rectangle( bufferedBounds.x, bufferedBounds.y, bufferedBounds.width + 1000, bufferedBounds.height + 1000 ); shellAdapter.setBounds( bounds1000 ); WidgetTreeVisitor.accept( shell, clearLayout ); shellAdapter.setBounds( bufferedBounds ); WidgetTreeVisitor.accept( shell, restoreSCOrigins ); } } if( event.getPhaseId() == PhaseId.RENDER ) { probes = TextSizeDeterminationFacade.writeFontProbing(); calculationItems = TextSizeDeterminationFacade.writeStringMeasurements(); renderDone = true; } } catch( final IOException e ) { ServletLog.log( "", e ); } finally { if( renderDone && event.getPhaseId() == PhaseId.PROCESS_ACTION ) { LifeCycleFactory.getLifeCycle().removePhaseListener( this ); ISessionStore session = ContextProvider.getSession(); session.removeAttribute( CALCULATION_HANDLER ); } } } } public PhaseId getPhaseId() { return PhaseId.ANY; } public static void readProbedFonts( final IProbe[] probes ) { boolean hasProbes = probes != null; HttpServletRequest request = ContextProvider.getRequest(); for( int i = 0; hasProbes && i < probes.length; i++ ) { IProbe probe = probes[ i ]; String name = String.valueOf( probe.getFontData().hashCode() ); String value = request.getParameter( name ); if( value != null ) { Point size = getSize( value ); TextSizeProbeStore.getInstance().createProbeResult( probe, size ); } } } /////////////////////////////////////// // interface HttpSessionBindingListener public void valueBound( final HttpSessionBindingEvent event ) { } public void valueUnbound( final HttpSessionBindingEvent event ) { UICallBack.runNonUIThreadWithFakeContext( display, new Runnable() { public void run() { ILifeCycle lifeCycle = LifeCycleFactory.getLifeCycle(); lifeCycle.removePhaseListener( TextSizeDeterminationHandler.this ); } } ); } ////////////////// // helping methods void readMeasuredStrings() { boolean hasItems = calculationItems != null; HttpServletRequest request = ContextProvider.getRequest(); for( int i = 0; hasItems && i < calculationItems.length; i++ ) { ICalculationItem item = calculationItems[ i ]; String name = String.valueOf( item.hashCode() ); String value = request.getParameter( name ); // TODO [fappel]: Workaround for background process problem if( value != null ) { Point size = getSize( value ); TextSizeDataBase.store( item.getFontData(), item.getString(), item.getWrapWidth(), size ); } } } private static Point getSize( final String value ) { String[] split = value.split( "," ); return new Point( Integer.parseInt( split[ 0 ] ), Integer.parseInt( split[ 1 ] ) ); } }