/******************************************************************************
* Copyright (c) 2016 Oracle
* 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:
* Konstantin Komissarchik - initial implementation and ongoing maintenance
******************************************************************************/
package org.eclipse.sapphire.ui.forms.swt.internal;
import static org.eclipse.sapphire.ui.forms.swt.GridLayoutUtil.gd;
import static org.eclipse.sapphire.ui.forms.swt.GridLayoutUtil.gdfill;
import static org.eclipse.sapphire.ui.forms.swt.GridLayoutUtil.gdhfill;
import static org.eclipse.sapphire.ui.forms.swt.GridLayoutUtil.gdhhint;
import static org.eclipse.sapphire.ui.forms.swt.GridLayoutUtil.gdhspan;
import static org.eclipse.sapphire.ui.forms.swt.GridLayoutUtil.gdwhint;
import static org.eclipse.sapphire.ui.forms.swt.GridLayoutUtil.glayout;
import java.util.List;
import org.eclipse.sapphire.FilteredListener;
import org.eclipse.sapphire.ui.ISapphirePart;
import org.eclipse.sapphire.ui.SapphirePart;
import org.eclipse.sapphire.ui.def.ISapphireDocumentation;
import org.eclipse.sapphire.ui.def.ISapphireDocumentationDef;
import org.eclipse.sapphire.ui.def.ISapphireDocumentationRef;
import org.eclipse.sapphire.ui.forms.CompositeDef;
import org.eclipse.sapphire.ui.forms.CompositePart;
import org.eclipse.sapphire.ui.forms.ContainerPart.VisibleChildrenEvent;
import org.eclipse.sapphire.ui.forms.FormComponentPart;
import org.eclipse.sapphire.ui.forms.MasterDetailsContentNodePart;
import org.eclipse.sapphire.ui.forms.swt.FormComponentPresentation;
import org.eclipse.sapphire.ui.forms.swt.HelpSystem;
import org.eclipse.sapphire.ui.forms.swt.SwtPresentation;
import org.eclipse.sapphire.util.ListFactory;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
/**
* @author <a href="mailto:konstantin.komissarchik@oracle.com">Konstantin Komissarchik</a>
*/
public class CompositePresentation extends FormComponentPresentation
{
private ScrolledComposite scrolledComposite;
private Composite innerComposite;
private List<FormComponentPresentation> children;
public CompositePresentation( final FormComponentPart part, final SwtPresentation parent, final Composite composite )
{
super( part, parent, composite );
}
@Override
public CompositePart part()
{
return (CompositePart) super.part();
}
@Override
public void render()
{
final CompositePart part = part();
final CompositeDef def = part.definition();
final boolean indent = ( def.getIndent().content() && ! ( part.parent() instanceof MasterDetailsContentNodePart ) );
if( indent )
{
final Label label = new Label( composite(), SWT.NONE );
label.setLayoutData( gd() );
register( label );
}
final boolean scaleVertically = def.getScaleVertically().content();
final int width = part.getWidth( -1 );
final int height = part.getHeight( -1 );
final Composite outerComposite = renderOuterComposite( gdwhint( gdhhint( gdhspan( ( scaleVertically ? gdfill() : gdhfill() ), ( indent ? 1 : 2 ) ), height ), width ) );
render( outerComposite );
}
protected void render( final Composite composite )
{
final CompositePart part = part();
final CompositeDef def = part.definition();
composite.setBackground( resources().color( part.getBackgroundColor() ) );
composite.setBackgroundMode( SWT.INHERIT_DEFAULT );
composite.setLayout( glayout( 1, 0, 0 ) );
final boolean scrollVertically = def.getScrollVertically().content();
final boolean scrollHorizontally = def.getScrollHorizontally().content();
if( scrollVertically || scrollHorizontally )
{
final int style
= ( scrollVertically ? SWT.V_SCROLL : SWT.NONE ) |
( scrollHorizontally ? SWT.H_SCROLL : SWT.NONE );
this.scrolledComposite = new ScrolledComposite( composite, style );
this.scrolledComposite.setExpandHorizontal( true );
this.scrolledComposite.setExpandVertical( true );
// ScrolledComposite does not seem to inherit background color like other controls, so
// we need to set it explicitly.
this.scrolledComposite.setBackground( composite.getBackground() );
this.scrolledComposite.setBackgroundMode( SWT.INHERIT_DEFAULT );
}
final int marginLeft = def.getMarginLeft().content();
final int marginRight = def.getMarginRight().content();
final int marginTop = def.getMarginTop().content();
final int marginBottom = def.getMarginBottom().content();
this.innerComposite = new Composite( ( this.scrolledComposite != null ? this.scrolledComposite : composite ), SWT.NONE ) {
public Point computeSize (int wHint, int hHint, boolean changed) {
if (this.getChildren().length == 0) {
return new Point(0, 0);
}
return super.computeSize(wHint, hHint, changed);
}
};
this.innerComposite.setLayout( glayout( 2, marginLeft, marginRight, marginTop, marginBottom ) );
if( this.scrolledComposite != null )
{
this.scrolledComposite.setContent( this.innerComposite );
this.scrolledComposite.setLayoutData( gdfill() );
}
else
{
this.innerComposite.setLayoutData( gdfill() );
}
final ISapphireDocumentation doc = def.getDocumentation().content();
if( doc != null )
{
ISapphireDocumentationDef docdef = null;
if( doc instanceof ISapphireDocumentationDef )
{
docdef = (ISapphireDocumentationDef) doc;
}
else
{
docdef = ( (ISapphireDocumentationRef) doc ).resolve();
}
if( docdef != null )
{
HelpSystem.setHelp( this.innerComposite, docdef );
}
}
refresh();
attachPartListener
(
new FilteredListener<VisibleChildrenEvent>()
{
@Override
protected void handleTypedEvent( final VisibleChildrenEvent event )
{
refresh();
}
}
);
}
protected Composite renderOuterComposite( final GridData gd )
{
final Composite composite = new Composite( composite(), SWT.NONE );
composite.setLayoutData( gd );
composite.setBackground( resources().color( part().getBackgroundColor() ) );
composite.setBackgroundMode( SWT.INHERIT_DEFAULT );
register( composite );
return composite;
}
protected void renderChildren( final Composite composite )
{
final ListFactory<FormComponentPresentation> childrenListFactory = ListFactory.start();
for( final FormComponentPart child : part().children().visible() )
{
childrenListFactory.add( child.createPresentation( this, composite ) );
}
this.children = childrenListFactory.result();
for( final FormComponentPresentation child : this.children )
{
if( ! child.disposed() )
{
child.render();
}
}
}
@Override
public void refresh()
{
final Control previousFocusControl = Display.getCurrent().getFocusControl();
SapphirePart previousFocusPart = null;
if( contains( this.innerComposite, previousFocusControl ) )
{
previousFocusPart = (SapphirePart) previousFocusControl.getData( "Sapphire.Part" );
}
boolean needToLayout = false;
if( this.children != null )
{
for( final FormComponentPresentation child : this.children )
{
child.dispose();
}
this.children = null;
needToLayout = true;
}
if( disposed() )
{
return;
}
for( final Control control : this.innerComposite.getChildren() )
{
control.dispose();
}
renderChildren( this.innerComposite );
if( previousFocusPart != null && previousFocusPart.visible() && contains( part(), previousFocusPart ) )
{
previousFocusPart.setFocus();
}
if( this.scrolledComposite != null )
{
this.scrolledComposite.setMinSize( this.innerComposite.computeSize( SWT.DEFAULT, SWT.DEFAULT ) );
}
if( needToLayout )
{
layout();
}
}
private static final boolean contains( final ISapphirePart container, final ISapphirePart part )
{
if( part == null )
{
return false;
}
final ISapphirePart parent = part.parent();
if( parent == container )
{
return true;
}
return contains( container, parent );
}
private static final boolean contains( final Composite composite, final Control control )
{
if( control == null )
{
return false;
}
final Composite parent = control.getParent();
if( parent == composite )
{
return true;
}
return contains( composite, parent );
}
@Override
public void dispose()
{
if( this.children != null )
{
for( final FormComponentPresentation child : this.children )
{
child.dispose();
}
this.children = null;
}
this.scrolledComposite = null;
this.innerComposite = null;
super.dispose();
}
}