Package org.eclipse.sapphire.ui.assist.internal

Source Code of org.eclipse.sapphire.ui.assist.internal.PropertyEditorAssistDecorator

/******************************************************************************
* Copyright (c) 2014 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.assist.internal;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;

import org.eclipse.jface.fieldassist.FieldDecoration;
import org.eclipse.jface.fieldassist.FieldDecorationRegistry;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.sapphire.Event;
import org.eclipse.sapphire.FilteredListener;
import org.eclipse.sapphire.Listener;
import org.eclipse.sapphire.LoggingService;
import org.eclipse.sapphire.Property;
import org.eclipse.sapphire.PropertyEvent;
import org.eclipse.sapphire.Sapphire;
import org.eclipse.sapphire.modeling.Status;
import org.eclipse.sapphire.ui.PartValidationEvent;
import org.eclipse.sapphire.ui.Presentation;
import org.eclipse.sapphire.ui.SapphireAction;
import org.eclipse.sapphire.ui.SapphireActionHandler;
import org.eclipse.sapphire.ui.SapphireActionSystem;
import org.eclipse.sapphire.ui.SapphirePart;
import org.eclipse.sapphire.ui.assist.PropertyEditorAssistContext;
import org.eclipse.sapphire.ui.assist.PropertyEditorAssistContributor;
import org.eclipse.sapphire.ui.def.ISapphireUiDef;
import org.eclipse.sapphire.ui.def.PartDef;
import org.eclipse.sapphire.ui.forms.PropertyEditorDef;
import org.eclipse.sapphire.ui.forms.PropertyEditorPart;
import org.eclipse.sapphire.ui.forms.swt.SwtResourceCache;
import org.eclipse.sapphire.ui.forms.swt.SwtUtil;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseTrackAdapter;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;

/**
* @author <a href="mailto:konstantin.komissarchik@oracle.com">Konstantin Komissarchik</a>
*/

public final class PropertyEditorAssistDecorator
{
    private static final List<Class<? extends PropertyEditorAssistContributor>> SYSTEM_CONTRIBUTORS
        = new ArrayList<Class<? extends PropertyEditorAssistContributor>>();
   
    static
    {
        SYSTEM_CONTRIBUTORS.add( InfoSectionAssistContributor.class );
        SYSTEM_CONTRIBUTORS.add( FactsAssistContributor.class );
        SYSTEM_CONTRIBUTORS.add( ProblemsSectionAssistContributor.class );
        SYSTEM_CONTRIBUTORS.add( ActionsSectionAssistContributor.class );
        SYSTEM_CONTRIBUTORS.add( ResetActionsAssistContributor.class );
        SYSTEM_CONTRIBUTORS.add( RestoreInitialValueActionsAssistContributor.class );
        SYSTEM_CONTRIBUTORS.add( ShowInSourceActionAssistContributor.class );
        SYSTEM_CONTRIBUTORS.add( ProblemsAssistContributor.class );
    }
   
    private static final ImageDescriptor IMG_ASSIST
        = SwtUtil.createImageDescriptor( PropertyEditorAssistContext.class, "Assist.png" );
   
    private static final ImageDescriptor IMG_ASSIST_FAINT
        = SwtUtil.createImageDescriptor( PropertyEditorAssistContext.class, "AssistFaint.png" );
   
    private static final ImageDescriptor IMG_ASSIST_CLEAR
        = SwtUtil.createImageDescriptor( PropertyEditorAssistContext.class, "AssistClear.png" );
   
    private final SapphirePart part;
    private final Property property;
    private final Label control;
    private Control primary;
    private PropertyEditorAssistContext assistContext;
    private Status problem;
    private boolean mouseOverEditorControl;
    private EditorControlMouseTrackListener mouseTrackListener;
    private final Listener modelPropertyListener;
    private final Listener partValidationListener;
    private final SapphireAction assistAction;
    private final SapphireActionHandler assistActionHandler;
    private final List<PropertyEditorAssistContributor> contributors;
   
    public PropertyEditorAssistDecorator( final PropertyEditorPart part,
                                          final Composite parent )
    {
        this( part, part.property(), parent );
    }
   
    public PropertyEditorAssistDecorator( final SapphirePart part,
                                          final Property property,
                                          final Composite parent )
    {
        this.part = part;
        this.property = property;
        this.mouseOverEditorControl = false;
        this.mouseTrackListener = new EditorControlMouseTrackListener();
       
        final PartDef def = this.part.definition();
       
        final List<Class<?>> contributorClasses = new ArrayList<Class<?>>();
       
        contributorClasses.addAll( SYSTEM_CONTRIBUTORS );
       
        final String additionalContributorsStr = def.getHint( PropertyEditorDef.HINT_ASSIST_CONTRIBUTORS );
       
        if( additionalContributorsStr != null )
        {
            final ISapphireUiDef rootdef = def.nearest( ISapphireUiDef.class );
           
            for( String segment : additionalContributorsStr.split( "," ) )
            {
                final Class<?> cl = rootdef.resolveClass( segment.trim() );
               
                if( cl != null )
                {
                    contributorClasses.add( cl );
                }
            }
        }
       
        this.contributors = new ArrayList<PropertyEditorAssistContributor>();
       
        for( Class<?> cl : contributorClasses )
        {
            try
            {
                this.contributors.add( (PropertyEditorAssistContributor) cl.newInstance() );
            }
            catch( Exception e )
            {
                Sapphire.service( LoggingService.class ).log( e );
            }
        }
       
        final String contributorsToSuppressStr = def.getHint( PropertyEditorDef.HINT_SUPPRESS_ASSIST_CONTRIBUTORS );
       
        if( contributorsToSuppressStr != null )
        {
            for( String segment : contributorsToSuppressStr.split( "," ) )
            {
                final String id = segment.trim();

                for( Iterator<PropertyEditorAssistContributor> itr = this.contributors.iterator(); itr.hasNext(); )
                {
                    final PropertyEditorAssistContributor contributor = itr.next();
                   
                    if( contributor.getId().equals( id ) )
                    {
                        itr.remove();
                        break;
                    }
                }
            }
        }
       
        final Listener contributorListener = new Listener()
        {
            @Override
            public void handle( final Event event )
            {
                Display.getDefault().asyncExec
                (
                    new Runnable()
                    {
                        public void run()
                        {
                            refresh();
                        }
                    }
                );
            }
        };
       
        for( PropertyEditorAssistContributor contributor : this.contributors )
        {
            try
            {
                contributor.init( this.part );
            }
            catch( Exception e )
            {
                Sapphire.service( LoggingService.class ).log( e );
            }
           
            contributor.attach( contributorListener );
        }
       
        Collections.sort
        (
            this.contributors,
            new Comparator<PropertyEditorAssistContributor>()
            {
                public int compare( final PropertyEditorAssistContributor c1,
                                    final PropertyEditorAssistContributor c2 )
                {
                    return ( c1.getPriority() - c2.getPriority() );
                }
            }
        );
       
        this.modelPropertyListener = new FilteredListener<PropertyEvent>()
        {
            @Override
            protected void handleTypedEvent( final PropertyEvent event )
            {
                Display.getDefault().asyncExec
                (
                    new Runnable()
                    {
                        public void run()
                        {
                            refresh();
                        }
                    }
                );
            }
        };
       
        this.property.attach( this.modelPropertyListener );
       
        this.partValidationListener = new FilteredListener<PartValidationEvent>()
        {
            @Override
            protected void handleTypedEvent( final PartValidationEvent event )
            {
                Display.getDefault().asyncExec
                (
                    new Runnable()
                    {
                        public void run()
                        {
                            refresh();
                        }
                    }
                );
            }
        };
       
        this.part.attach( this.partValidationListener );
       
        this.assistAction = part.getActions().getAction( SapphireActionSystem.ACTION_ASSIST );
       
        this.assistActionHandler = new SapphireActionHandler()
        {
            @Override
            protected Object run( final Presentation context )
            {
                openAssistDialog();
                return null;
            }
        };
       
        this.assistActionHandler.init( this.assistAction, null );
        this.assistAction.addHandler( this.assistActionHandler );
       
        this.control = new Label( parent, SWT.NONE );
       
        this.control.addMouseListener
        (
            new MouseAdapter()
            {
                @Override
                public void mouseUp( final MouseEvent event )
                {
                    openAssistDialog();
                }
            }
        );
       
        this.control.addMouseTrackListener
        (
            new EditorControlMouseTrackListener()
            {
                @Override
                public void mouseEnter( MouseEvent event )
                {
                    super.mouseEnter( event );
                    refreshImageAndCursor();
                }

                @Override
                public void mouseHover( final MouseEvent event )
                {
                    // Suppress default behavior.
                }
            }
        );
       
        this.control.addDisposeListener
        (
            new DisposeListener()
            {
                public void widgetDisposed( final DisposeEvent event )
                {
                    dispose();
                }
            }
        );
       
        refresh();
    }
   
    public Label control()
    {
        return this.control;
    }
   
    public Shell shell()
    {
        return this.control.getShell();
    }
   
    public SapphirePart part()
    {
        return this.part;
    }
   
    public Property property()
    {
        return this.property;
    }
   
    public void addEditorControl( final Control control )
    {
        addEditorControl( control, false );
    }
   
    public void addEditorControl( final Control control,
                                  final boolean primary )
    {
        if( control instanceof Composite )
        {
            for( Control child : ( (Composite) control ).getChildren() )
            {
                addEditorControl( child );
            }
        }
       
        control.addMouseTrackListener( this.mouseTrackListener );
       
        if( primary )
        {
            this.primary = control;
        }
    }
   
    public void removeEditorControl( final Control control )
    {
        if( control instanceof Composite )
        {
            for( Control child : ( (Composite) control ).getChildren() )
            {
                removeEditorControl( child );
            }
        }
       
        control.removeMouseTrackListener( this.mouseTrackListener );
       
        if( this.primary == control )
        {
            this.primary = null;
        }
    }

    private void openAssistDialog()
    {
        if( this.assistContext != null && ! this.assistContext.isEmpty() )
        {
            final Rectangle decoratorControlBounds = this.control.getBounds();
            final Rectangle primaryControlBounds = ( this.primary == null ? null : this.primary.getBounds() );
           
            Point position;
           
            if( primaryControlBounds != null && primaryControlBounds.height < 50 )
            {
                position = new Point( primaryControlBounds.x, primaryControlBounds.y + primaryControlBounds.height + 1 );
                position = this.primary.getParent().toDisplay( position );
            }
            else
            {
                position = new Point( decoratorControlBounds.x + decoratorControlBounds.width + 2, decoratorControlBounds.y );
                position = this.control.getParent().toDisplay( position );
            }
           
            final PropertyEditorAssistDialog dialog = new PropertyEditorAssistDialog( shell(), position, this.assistContext );
           
            dialog.open();
        }
    }
   
    private void refresh()
    {
        if( this.control.isDisposed() )
        {
            return;
        }
       
        if( this.property.enabled() )
        {
            this.assistContext = new PropertyEditorAssistContext( this.part, shell() );
            this.problem = this.part.validation();
           
            for( PropertyEditorAssistContributor c : this.contributors )
            {
                c.contribute( this.assistContext );
            }
           
            if( this.assistContext.isEmpty() )
            {
                this.assistContext = null;
            }
            else
            {
                final Status.Severity valResultSeverity = this.problem.severity();
               
                if( valResultSeverity != Status.Severity.ERROR && valResultSeverity != Status.Severity.WARNING )
                {
                    this.problem = null;
                }
            }
        }
        else
        {
            this.assistContext = null;
            this.problem = null;
        }

        refreshImageAndCursor();
    }
   
    private void refreshImageAndCursor()
    {
        if( this.control.isDisposed() )
        {
            return;
        }
       
        final SwtResourceCache imageCache = this.part.getSwtResourceCache();
       
        if( this.assistContext != null )
        {
            if( this.problem != null )
            {
                final String fieldDecorationId;
               
                switch( this.problem.severity() )
                {
                    case ERROR:
                    {
                        fieldDecorationId = FieldDecorationRegistry.DEC_ERROR;
                        break;
                    }
                    case WARNING:
                    {
                        fieldDecorationId = FieldDecorationRegistry.DEC_WARNING;
                        break;
                    }
                    default:
                    {
                        throw new IllegalStateException();
                    }
                }
               
                final FieldDecoration fieldDecoration
                    = FieldDecorationRegistry.getDefault().getFieldDecoration( fieldDecorationId );
           
                this.control.setImage( fieldDecoration.getImage() );
            }
            else
            {
                if( this.mouseOverEditorControl )
                {
                    this.control.setImage( imageCache.image( IMG_ASSIST ) );
                }
                else
                {
                    this.control.setImage( imageCache.image( IMG_ASSIST_FAINT ) );
                }
            }
           
            this.control.setVisible( true );
            this.control.setCursor( Display.getCurrent().getSystemCursor( SWT.CURSOR_HAND ) );
        }
        else
        {
            this.control.setVisible( false );
            this.control.setImage( imageCache.image( IMG_ASSIST_CLEAR ) );
            this.control.setCursor( null );
        }
    }
   
    private void dispose()
    {
        this.part.detach( this.partValidationListener );
        this.property.detach( this.modelPropertyListener );
        this.assistAction.removeHandler( this.assistActionHandler );
       
        for( PropertyEditorAssistContributor contributor : this.contributors )
        {
            try
            {
                contributor.dispose();
            }
            catch( Exception e )
            {
                Sapphire.service( LoggingService.class ).log( e );
            }
        }
    }
   
    private class EditorControlMouseTrackListener extends MouseTrackAdapter
    {
        @Override
        public void mouseEnter( final MouseEvent event )
        {
            PropertyEditorAssistDecorator.this.mouseOverEditorControl = true;
        }
       
        @Override
        public void mouseHover( final MouseEvent event )
        {
            refreshImageAndCursor();
        }

        @Override
        public void mouseExit( final MouseEvent event )
        {
            PropertyEditorAssistDecorator.this.mouseOverEditorControl = false;
            performedDelayedImageRefresh();
        }
       
        private void performedDelayedImageRefresh()
        {
            final Runnable op = new Runnable()
            {
                public void run()
                {
                    refreshImageAndCursor();
                }
            };
           
            final Thread thread = new Thread()
            {
                public void run()
                {
                    try
                    {
                        Thread.sleep( 250 );
                    }
                    catch( InterruptedException e ) {}
                   
                    Display.getDefault().asyncExec( op );
                }
            };
           
            thread.start();
        }
    };

}
TOP

Related Classes of org.eclipse.sapphire.ui.assist.internal.PropertyEditorAssistDecorator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.