Package org.eclipse.sapphire.java.jdt.ui.internal

Source Code of org.eclipse.sapphire.java.jdt.ui.internal.JavaTypeCreateActionHandler$Condition

/******************************************************************************
* Copyright (c) 2014 Oracle and Liferay
* 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
*    Gregory Amereson - [363551] JavaTypeConstraintService
******************************************************************************/

package org.eclipse.sapphire.java.jdt.ui.internal;

import static java.lang.Math.min;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IWorkspaceRunnable;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jdt.core.Flags;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.NodeFinder;
import org.eclipse.jdt.ui.JavaUI;
import org.eclipse.jdt.ui.actions.AddUnimplementedConstructorsAction;
import org.eclipse.jdt.ui.actions.FormatAllAction;
import org.eclipse.jdt.ui.actions.OrganizeImportsAction;
import org.eclipse.jdt.ui.actions.OverrideMethodsAction;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.sapphire.DisposeEvent;
import org.eclipse.sapphire.Event;
import org.eclipse.sapphire.FilteredListener;
import org.eclipse.sapphire.Listener;
import org.eclipse.sapphire.LocalizableText;
import org.eclipse.sapphire.LoggingService;
import org.eclipse.sapphire.Property;
import org.eclipse.sapphire.PropertyEvent;
import org.eclipse.sapphire.ReferenceValue;
import org.eclipse.sapphire.Sapphire;
import org.eclipse.sapphire.Text;
import org.eclipse.sapphire.Value;
import org.eclipse.sapphire.java.JavaType;
import org.eclipse.sapphire.java.JavaTypeConstraintBehavior;
import org.eclipse.sapphire.java.JavaTypeConstraintService;
import org.eclipse.sapphire.java.JavaTypeKind;
import org.eclipse.sapphire.java.JavaTypeName;
import org.eclipse.sapphire.modeling.annotations.Reference;
import org.eclipse.sapphire.ui.Presentation;
import org.eclipse.sapphire.ui.SapphireAction;
import org.eclipse.sapphire.ui.def.ActionHandlerDef;
import org.eclipse.sapphire.ui.forms.PropertyEditorActionHandler;
import org.eclipse.sapphire.ui.forms.PropertyEditorCondition;
import org.eclipse.sapphire.ui.forms.PropertyEditorPart;
import org.eclipse.sapphire.ui.forms.swt.FormComponentPresentation;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbenchPartSite;

/**
* @author <a href="mailto:konstantin.komissarchik@oracle.com">Konstantin Komissarchik</a>
* @author <a href="mailto:gregory.amerson@liferay.com">Gregory Amerson</a>
*/

public abstract class JavaTypeCreateActionHandler extends PropertyEditorActionHandler
{
    @Text( "Java Convention Violation" )
    private static LocalizableText discourageDialogTitle;
   
    @Text( "The use of the default package is discouraged. Do you want to proceed?" )
    private static LocalizableText discourageDefaultPackage;
   
    @Text( "Type name is discourage. By convention, Java type names should start with an upper case letter. Do you want to proceed?" )
    private static LocalizableText discourageLowerCase;

    static
    {
        LocalizableText.init( JavaTypeCreateActionHandler.class );
    }

    private final JavaTypeKind kind;
   
    public JavaTypeCreateActionHandler( final JavaTypeKind kind )
    {
        this.kind = kind;
    }
   
    @Override
    public void init( final SapphireAction action,
                      final ActionHandlerDef def )
    {
        super.init( action, def );

        final Property property = property();
       
        final Listener listener = new FilteredListener<PropertyEvent>()
        {
            @Override
            protected void handleTypedEvent( final PropertyEvent event )
            {
                refreshEnablementState();
            }
        };
       
        property.attach( listener );
       
        attach
        (
            new Listener()
            {
                @Override
                public void handle( final Event event )
                {
                    if( event instanceof DisposeEvent )
                    {
                        property.detach( listener );
                    }
                }
            }
        );
    }
   
    @Override

    protected Object run( final Presentation context )
    {
        final Shell shell = ( (FormComponentPresentation) context ).shell();
        final Value<?> javaTypeNameValue = (Value<?>) property();
       
        if( javaTypeNameValue.malformed() )
        {
            return null;
        }
       
        final JavaTypeName javaTypeName = (JavaTypeName) javaTypeNameValue.content();
       
        if( javaTypeName.pkg() == null )
        {
            if( ! MessageDialog.openConfirm( shell, discourageDialogTitle.text(), discourageDefaultPackage.text() ) )
            {
                return null;
            }
        }
       
        if( ! Character.isUpperCase( javaTypeName.simple().charAt( 0 ) ) )
        {
            if( ! MessageDialog.openConfirm( shell, discourageDialogTitle.text(), discourageLowerCase.text() ) )
            {
                return null;
            }
        }
       
        final JavaTypeConstraintService javaTypeConstraintService = javaTypeNameValue.service( JavaTypeConstraintService.class );
       
        final IJavaProject jproj = javaTypeNameValue.element().adapt( IJavaProject.class );

        JavaTypeName expectedBaseClassTemp = null;
        final List<JavaTypeName> expectedInterfaces = new ArrayList<JavaTypeName>();
       
        if( javaTypeConstraintService != null )
        {
            final JavaTypeConstraintBehavior behavior = javaTypeConstraintService.behavior();

            final Collection<String> types = javaTypeConstraintService.types();
            final Iterator<String> iterator = types.iterator();

            for( int i = 0, n = ( behavior == JavaTypeConstraintBehavior.ALL ? types.size() : min( 1, types.size() ) ); i < n; i++ )
            {
                final String typeName = iterator.next();
               
                try
                {
                    final IType type = jproj.findType( typeName.replace( '$', '.' ) );
                   
                    if( type != null && type.exists() )
                    {
                        if( type.isClass() )
                        {
                            expectedBaseClassTemp = new JavaTypeName( typeName );
                        }
                        else if( type.isInterface() )
                        {
                            expectedInterfaces.add( new JavaTypeName( typeName ) );
                        }
                    }
                }
                catch( Exception e )
                {
                    Sapphire.service( LoggingService.class ).log( e );
                }
            }
        }
       
        final JavaTypeName expectedBaseClass = expectedBaseClassTemp;
       
        final IRunnableWithProgress op = new IRunnableWithProgress()
        {
            public void run( final IProgressMonitor monitor ) throws InvocationTargetException, InterruptedException
            {
                monitor.beginTask( "", 7 );
               
                final JavaTypeKind kind = JavaTypeCreateActionHandler.this.kind;
               
                final StringBuilder buf = new StringBuilder();
               
                if( javaTypeName.pkg() != null )
                {
                    buf.append( "package " );
                    buf.append( javaTypeName.pkg() );
                    buf.append( ";\n\n" );
                }
               
                final List<JavaTypeName> imports = new ArrayList<JavaTypeName>();
                imports.add( javaTypeName );
               
                String base = null;
               
                if ( kind == JavaTypeKind.CLASS && expectedBaseClass != null )
                {
                    base = deriveSafeLocalName( expectedBaseClass, imports );
                }
               
                final List<String> interfaces = new ArrayList<String>();
               
                if( kind == JavaTypeKind.CLASS || kind == JavaTypeKind.INTERFACE )
                {
                    for( JavaTypeName t : expectedInterfaces )
                    {
                        interfaces.add( deriveSafeLocalName( t, imports ) );
                    }
                }
               
                imports.remove( javaTypeName );
               
                if( ! imports.isEmpty() )
                {
                    for( JavaTypeName t : imports )
                    {
                        buf.append( "import " );
                        buf.append( t.qualified().replace( '$', '.' ) );
                        buf.append( ";\n" );
                    }
                   
                    buf.append( '\n' );
                }
               
                buf.append( "public " );
               
                switch( kind )
                {
                    case ANNOTATION:  buf.append( "@interface" ); break;
                    case ENUM:        buf.append( "enum" ); break;
                    case INTERFACE:   buf.append( "interface" ); break;
                    default:          buf.append( "class" );
                }
               
                buf.append( ' ' );
                buf.append( javaTypeName.simple() );
               
                if( base != null )
                {
                    buf.append( " extends " );
                    buf.append( base );
                }
               
                if( ! interfaces.isEmpty() )
                {
                    buf.append( kind == JavaTypeKind.INTERFACE ? " extends " : " implements " );
                   
                    boolean first = true;
                   
                    for( String implementsType : interfaces )
                    {
                        if( first )
                        {
                            first = false;
                        }
                        else
                        {
                            buf.append( ", " );
                        }
                       
                        buf.append( implementsType );
                    }
                }
               
                buf.append( "\n{\n}\n" );
               
                monitor.worked( 1 );
               
                final IProject proj = javaTypeNameValue.element().adapt( IProject.class );
                final IJavaProject jproj = JavaCore.create( proj );
               
                try
                {
                    final IPackageFragmentRoot src = src( jproj );
                    final IPackageFragment pkg = src.createPackageFragment( ( javaTypeName.pkg() == null ? "" : javaTypeName.pkg() ), true, null );
                    final ICompilationUnit cu = pkg.createCompilationUnit( javaTypeName.simple() + ".java", buf.toString(), true, null );
                   
                    cu.save( null, true );
                   
                    monitor.worked( 1 );
                   
                    final IEditorPart editor = JavaUI.openInEditor( cu );
                    final IWorkbenchPartSite site = editor.getSite();
                   
                    monitor.worked( 1 );
                   
                    if( kind == JavaTypeKind.CLASS )
                    {
                        final IType type = cu.getType( javaTypeName.simple() );

                        final ASTParser parser = createAstParser();
                        parser.setResolveBindings( true );
                        parser.setSource( cu );
                       
                        final CompilationUnit ast = (CompilationUnit) parser.createAST( null );
                       
                        ASTNode node = NodeFinder.perform( ast, type.getNameRange() );
                       
                        while( ! ( node instanceof AbstractTypeDeclaration ) )
                        {
                            node = node.getParent();
                        }
                       
                        final ITypeBinding typeBinding = ( (AbstractTypeDeclaration) node ).resolveBinding();
                       
                        final IWorkspaceRunnable addUnimplementedConstructorsOp
                            = AddUnimplementedConstructorsAction.createRunnable( ast, typeBinding, null, -1, false, Flags.AccPublic, false );
                       
                        addUnimplementedConstructorsOp.run( null );
                       
                        final IWorkspaceRunnable overrideMethodsOp
                            = OverrideMethodsAction.createRunnable( ast, typeBinding, null, -1, false );
                       
                        overrideMethodsOp.run( null );
                    }
                   
                    monitor.worked( 1 );
                   
                    final OrganizeImportsAction organizeImportsAction = new OrganizeImportsAction( site );
                    organizeImportsAction.run( cu );
                   
                    monitor.worked( 1 );
                   
                    final FormatAllAction formatAllAction = new FormatAllAction( site );
                    formatAllAction.runOnMultiple( new ICompilationUnit[] { cu } );
                   
                    monitor.worked( 1 );
                   
                    editor.doSave( null );
                   
                    monitor.worked( 1 );                   
                }
                catch( CoreException e )
                {
                    Sapphire.service( LoggingService.class ).log( e );
                }
               
                monitor.done();
            }
        };
       
        try
        {
            ( new ProgressMonitorDialog( shell ) ).run( false, false, op );
        }
        catch( InvocationTargetException e )
        {
            Sapphire.service( LoggingService.class ).log( e );
        }
        catch( InterruptedException e )
        {
            // Should not happen.

            Sapphire.service( LoggingService.class ).log( e );
        }
       
        return null;
    }
   
    @Override
    protected boolean computeEnablementState()
    {
        boolean enabled = super.computeEnablementState();
       
        if( enabled )
        {
            final ReferenceValue<?,?> ref = (ReferenceValue<?,?>) property();
           
            enabled = false;
           
            if( ! ref.malformed() )
            {
                final String typeName = ref.text();
               
                if( typeName != null && typeName.indexOf( '$' ) == -1 && ref.target() == null )
                {
                    enabled = true;
                }
            }
        }
       
        return enabled;
    }

    private final IPackageFragmentRoot src( final IJavaProject project ) throws JavaModelException
    {
        for( IPackageFragmentRoot root : project.getPackageFragmentRoots() )
        {
            if( root.getKind() == IPackageFragmentRoot.K_SOURCE )
            {
                return root;
            }
        }
       
        return null;
    }
   
    private static String deriveSafeLocalName( final JavaTypeName type,
                                               final Collection<JavaTypeName> imports )
    {
        boolean collision = false;
       
        for( JavaTypeName n : imports )
        {
            if( n.simple().equals( type.simple() ) )
            {
                collision = true;
                break;
            }
        }
       
        if( collision )
        {
            return type.qualified().replace( '$', '.' );
        }
        else
        {
            imports.add( type );
            return type.simple();
        }
    }
   
    private static ASTParser createAstParser()
    {
        final int level;
       
        if( isJavaLanguageSpecSupported( 8 ) )
        {
            // Kepler SR2 with Java 8 Patch; Luna or newer
           
            level = 8;
        }
        else if( isJavaLanguageSpecSupported( 4 ) )
        {
            // Indigo SR1 or newer
           
            level = 4;
        }
        else
        {
            level = 3;
        }

        return ASTParser.newParser( level );
    }
   
    private static boolean isJavaLanguageSpecSupported( final int version )
    {
        try
        {
            AST.class.getField( "JLS" + String.valueOf( version ) );
            return true;
        }
        catch( final NoSuchFieldException e )
        {
            return false;
        }
    }
   
    protected static abstract class Condition extends PropertyEditorCondition
    {
        @Override
        protected final boolean evaluate( final PropertyEditorPart part )
        {
            final Property property = part.property();
           
            if( property instanceof Value && property.definition().isOfType( JavaTypeName.class ) )
            {
                final Reference referenceAnnotation = property.definition().getAnnotation( Reference.class );
               
                return
                (
                    referenceAnnotation != null &&
                    referenceAnnotation.target() == JavaType.class &&
                    evaluate( property.service( JavaTypeConstraintService.class ) ) &&
                    property.element().adapt( IJavaProject.class ) != null
                );
            }
           
            return false;
        }
       
        protected abstract boolean evaluate( JavaTypeConstraintService javaTypeConstraintService );
    }
   
}
TOP

Related Classes of org.eclipse.sapphire.java.jdt.ui.internal.JavaTypeCreateActionHandler$Condition

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.