You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@polygene.apache.org by ni...@apache.org on 2016/12/17 10:28:50 UTC
[74/81] [abbrv] zest-java git commit: ZEST-195, ZEST-201 ;
Rename of everything else from zest to polygene.
http://git-wip-us.apache.org/repos/asf/zest-java/blob/e0e1d7d4/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/appliesTo/inspections/AppliesToAnnotationDeclaredCorrectlyInspection.java
----------------------------------------------------------------------
diff --git a/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/appliesTo/inspections/AppliesToAnnotationDeclaredCorrectlyInspection.java b/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/appliesTo/inspections/AppliesToAnnotationDeclaredCorrectlyInspection.java
new file mode 100644
index 0000000..b64d762
--- /dev/null
+++ b/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/appliesTo/inspections/AppliesToAnnotationDeclaredCorrectlyInspection.java
@@ -0,0 +1,294 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+package org.apache.polygene.ide.plugin.idea.appliesTo.inspections;
+
+import com.intellij.codeInspection.InspectionManager;
+import com.intellij.codeInspection.ProblemDescriptor;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.*;
+import com.intellij.psi.search.GlobalSearchScope;
+import org.jetbrains.annotations.NotNull;
+import org.apache.polygene.ide.plugin.idea.common.inspections.AbstractFix;
+import org.apache.polygene.ide.plugin.idea.common.inspections.AbstractInspection;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import static com.intellij.codeInspection.ProblemHighlightType.GENERIC_ERROR_OR_WARNING;
+import static org.apache.polygene.ide.plugin.idea.appliesTo.common.PolygeneAppliesToUtil.*;
+import static org.apache.polygene.ide.plugin.idea.common.psi.PsiClassUtil.isImplementsInvocationHandler;
+import static org.apache.polygene.ide.plugin.idea.common.psi.search.GlobalSearchScopeUtil.determineSearchScope;
+import static org.apache.polygene.ide.plugin.idea.common.resource.PolygeneResourceBundle.message;
+import static org.apache.polygene.ide.plugin.idea.concerns.common.PolygeneConcernUtil.isAConcern;
+import static org.apache.polygene.ide.plugin.idea.concerns.common.PolygeneConcernUtil.isAGenericConcern;
+import static org.apache.polygene.ide.plugin.idea.sideEffects.common.PolygeneSideEffectUtil.isAGenericSideEffect;
+import static org.apache.polygene.ide.plugin.idea.sideEffects.common.PolygeneSideEffectUtil.isASideEffect;
+
+/**
+ * @author edward.yakop@gmail.com
+ * @since 0.1
+ */
+public final class AppliesToAnnotationDeclaredCorrectlyInspection extends AbstractInspection
+{
+ @NotNull
+ protected final String resourceBundlePrefixId()
+ {
+ return "applies.to.annotation.declared.correctly";
+ }
+
+ @NotNull
+ public final String getShortName()
+ {
+ return "AppliesToAnnotationDeclaredCorrectlyInspection";
+ }
+
+ @Override
+ public final ProblemDescriptor[] checkClass( @NotNull PsiClass psiClass,
+ @NotNull InspectionManager manager,
+ boolean isOnTheFly )
+ {
+ PsiAnnotation appliesToAnnotation = getAppliesToAnnotation( psiClass );
+ if( appliesToAnnotation == null )
+ {
+ // If class does not have @AppliesTo, ignore
+ return null;
+ }
+
+ String classQualifiedName = psiClass.getQualifiedName();
+ // @AppliesTo can only be declared on class
+ if( psiClass.isInterface() )
+ {
+ // Suggest remove applies to
+ String message = message(
+ "applies.to.annotation.declared.correctly.error.annotation.must.be.declared.on.class"
+ );
+ ProblemDescriptor problemDescriptor = createRemoveAppliesToFilterProblemDescriptor(
+ manager, message, appliesToAnnotation );
+ return new ProblemDescriptor[]{ problemDescriptor };
+ }
+
+ // If @AppliesTo annotation is empty, ignore
+ List<PsiAnnotationMemberValue> appliesToAnnotationValues = getAppliesToAnnotationValue( appliesToAnnotation );
+ if( appliesToAnnotationValues.isEmpty() )
+ {
+ return null;
+ }
+
+ // If AppliesToFilter is not resolved, ignore
+ Project project = psiClass.getProject();
+ GlobalSearchScope searchScope = determineSearchScope( psiClass );
+ PsiClass appliesToFilterClass = getAppliesToFilterClass( project, searchScope );
+ if( appliesToFilterClass == null )
+ {
+ return null;
+ }
+
+ boolean classIsAConcern = isAConcern( psiClass );
+ boolean classIsASideEffect = isASideEffect( psiClass );
+ boolean classIsAGenericConcern = classIsAConcern && isAGenericConcern( psiClass );
+ boolean classIsAGenericSideEffect = classIsASideEffect && isAGenericSideEffect( psiClass );
+ boolean classIsAMixin = !classIsAConcern && !classIsASideEffect;
+ boolean classIsAGenericMixin = classIsAMixin && isImplementsInvocationHandler( psiClass );
+
+ List<ProblemDescriptor> problems = new LinkedList<ProblemDescriptor>();
+ for( PsiAnnotationMemberValue appliesToAnnotationValue : appliesToAnnotationValues )
+ {
+ PsiJavaCodeReferenceElement appliesToValueClassReference =
+ getAppliesToValueClassReference( appliesToAnnotationValue );
+
+ // If it's not a class reference, ignore
+ if( appliesToValueClassReference == null )
+ {
+ continue;
+ }
+
+ // If class reference can't be resolved, ignore
+ PsiClass appliesToValueClass = (PsiClass) appliesToValueClassReference.resolve();
+ if( appliesToValueClass == null )
+ {
+ continue;
+ }
+
+ String appliesToValueQualifiedName = appliesToValueClass.getQualifiedName();
+ boolean appliesToValueIsAnAnnotation = appliesToValueClass.isAnnotationType();
+ boolean appliesToValueIsImplementingAppliesToFilter =
+ appliesToValueClass.isInheritor( appliesToFilterClass, true );
+
+ String message = null;
+ if( appliesToValueIsAnAnnotation && classIsAMixin )
+ {
+ // If Class is a mixin and appliesToValueClass is an annotation
+ message = message(
+ "applies.to.annotation.declared.correctly.error.value.is.invalid.for.mixin",
+ appliesToValueQualifiedName
+ );
+ }
+ else if( appliesToValueIsAnAnnotation || appliesToValueIsImplementingAppliesToFilter )
+ {
+ if( classIsAConcern && !classIsAGenericConcern )
+ {
+ // If psiClass is a concern but not generic concern
+ message = message(
+ "applies.to.annotation.declared.correctly.error.value.requires.class.to.extends.GenericConcern",
+ appliesToValueQualifiedName, classQualifiedName
+ );
+ }
+ else if( classIsASideEffect && !classIsAGenericSideEffect )
+ {
+ // If psiClass a side effect but not a generic side effect
+ message = message(
+ "applies.to.annotation.declared.correctly.error.value.requires.class.to.extends.GenericSideEffect",
+ appliesToValueQualifiedName, classQualifiedName
+ );
+ }
+ else if( appliesToValueIsImplementingAppliesToFilter && !classIsAGenericMixin )
+ {
+ message = message(
+ "applies.to.annotation.declared.correctly.error.value.requires.class.to.implements.InvocationHandler",
+ appliesToValueQualifiedName, classQualifiedName
+ );
+ }
+ }
+ else if( appliesToValueClass.isInterface() )
+ {
+ if( !psiClass.isInheritor( appliesToValueClass, true ) &&
+ !( classIsAGenericConcern || classIsAGenericSideEffect ) )
+ {
+ // If psiClass does not implement that interface and it's not a generic concern or generic side effect
+ if( classIsAConcern )
+ {
+ message = message(
+ "applies.to.annotation.declared.correctly.error.value.requires.class.to.implement.interface.or.extends.GenericConcern",
+ appliesToValueQualifiedName, classQualifiedName );
+ }
+ else if( classIsASideEffect )
+ {
+ message = message(
+ "applies.to.annotation.declared.correctly.error.value.requires.class.to.implement.interface.or.extends.GenericSideEffect",
+ appliesToValueQualifiedName, classQualifiedName );
+ }
+ else
+ {
+ message = message(
+ "applies.to.annotation.declared.correctly.error.value.requires.class.to.implement.value.interface.or.implements.InvocationHandler",
+ appliesToValueQualifiedName, classQualifiedName );
+ }
+ }
+ }
+ else
+ {
+ if( classIsAMixin )
+ {
+ message = message(
+ "applies.to.annotation.declared.correctly.error.value.is.invalid.for.mixin",
+ appliesToValueQualifiedName
+ );
+ }
+ else
+ {
+ message = message(
+ "applies.to.annotation.declared.correctly.error.annotation.value.is.invalid.for.non.mixin",
+ appliesToValueQualifiedName
+ );
+ }
+ }
+
+ if( message != null )
+ {
+ ProblemDescriptor problemDescriptor = manager.createProblemDescriptor(
+ appliesToAnnotationValue,
+ message,
+ new RemoveAnnotationValueFix( appliesToAnnotationValue, appliesToValueClassReference ),
+ GENERIC_ERROR_OR_WARNING );
+ problems.add( problemDescriptor );
+ }
+ }
+
+ return problems.toArray( new ProblemDescriptor[problems.size()] );
+ }
+
+ @NotNull
+ private ProblemDescriptor createRemoveAppliesToFilterProblemDescriptor( @NotNull InspectionManager manager,
+ @NotNull String problemMessage,
+ @NotNull PsiAnnotation appliesToAnnotation )
+ {
+ RemoveAppliesToFilterAnnotationFix fix = new RemoveAppliesToFilterAnnotationFix( appliesToAnnotation );
+ return manager.createProblemDescriptor( appliesToAnnotation, problemMessage, fix, GENERIC_ERROR_OR_WARNING );
+ }
+
+ private static class RemoveAppliesToFilterAnnotationFix extends AbstractFix
+ {
+ private final PsiAnnotation appliesToFilterAnnotation;
+
+ private RemoveAppliesToFilterAnnotationFix( @NotNull PsiAnnotation appliesToFilterAnnotation )
+ {
+ super( message( "applies.to.annotation.declared.correctly.fix.remove.annotation" ) );
+ this.appliesToFilterAnnotation = appliesToFilterAnnotation;
+ }
+
+ public final void applyFix( @NotNull Project project, @NotNull ProblemDescriptor descriptor )
+ {
+ appliesToFilterAnnotation.delete();
+ }
+ }
+
+ private static class RemoveAnnotationValueFix extends AbstractFix
+ {
+ private final PsiAnnotationMemberValue annotationValueToRemove;
+
+ private RemoveAnnotationValueFix( @NotNull PsiAnnotationMemberValue annotationValueToRemove,
+ @NotNull PsiJavaCodeReferenceElement appliesToValueClassReference )
+ {
+ super( message( "applies.to.annotation.declared.correctly.fix.remove.class.reference",
+ appliesToValueClassReference.getQualifiedName() ) );
+ this.annotationValueToRemove = annotationValueToRemove;
+ }
+
+ public final void applyFix( @NotNull Project project, @NotNull ProblemDescriptor descriptor )
+ {
+ annotationValueToRemove.delete();
+ }
+ }
+
+ private static class ClassImplementInterfaceFix extends AbstractFix
+ {
+ private final PsiClass psiClass;
+ private final PsiClass interfaceToImplement;
+
+ private ClassImplementInterfaceFix( @NotNull PsiClass psiClass,
+ @NotNull PsiClass interfaceToImplement )
+ {
+ super( message( "applies.to.annotation.declared.correctly.fix.remove.class.reference",
+ interfaceToImplement.getQualifiedName() ) );
+ this.psiClass = psiClass;
+ this.interfaceToImplement = interfaceToImplement;
+ }
+
+ public final void applyFix( @NotNull Project project, @NotNull ProblemDescriptor descriptor )
+ {
+ PsiReferenceList implementList = psiClass.getImplementsList();
+ if( implementList != null )
+ {
+
+ implementList.add( interfaceToImplement );
+ }
+ }
+ }
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/zest-java/blob/e0e1d7d4/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/common/actions/AbstractCreateElementActionBase.java
----------------------------------------------------------------------
diff --git a/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/common/actions/AbstractCreateElementActionBase.java b/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/common/actions/AbstractCreateElementActionBase.java
new file mode 100644
index 0000000..b47a045
--- /dev/null
+++ b/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/common/actions/AbstractCreateElementActionBase.java
@@ -0,0 +1,153 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+package org.apache.polygene.ide.plugin.idea.common.actions;
+
+import com.intellij.CommonBundle;
+import com.intellij.ide.actions.CreateElementActionBase;
+import com.intellij.ide.fileTemplates.FileTemplate;
+import com.intellij.ide.fileTemplates.FileTemplateManager;
+import com.intellij.ide.fileTemplates.JavaTemplateUtil;
+import com.intellij.openapi.fileTypes.StdFileTypes;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.module.ModuleUtil;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.Messages;
+import com.intellij.psi.*;
+import com.intellij.psi.codeStyle.CodeStyleManager;
+import com.intellij.util.IncorrectOperationException;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Properties;
+
+/**
+ * @author edward.yakop@gmail.com
+ * @since 0.1
+ */
+public abstract class AbstractCreateElementActionBase extends CreateElementActionBase
+{
+ @NonNls
+ private static final String NAME_TEMPLATE_PROPERTY = "NAME";
+
+ protected AbstractCreateElementActionBase( String text, String description )
+ {
+ super( text, description, null );
+ }
+
+ @NotNull
+ protected final PsiElement[] invokeDialog( Project project, PsiDirectory directory )
+ {
+ Module module = ModuleUtil.findModuleForFile( directory.getVirtualFile(), project );
+ if( module == null )
+ {
+ return PsiElement.EMPTY_ARRAY;
+ }
+
+ MyInputValidator validator = doInvokeDialog( project, directory );
+ return validator.getCreatedElements();
+ }
+
+ protected MyInputValidator doInvokeDialog( Project project, PsiDirectory directory )
+ {
+ MyInputValidator validator = new MyInputValidator( project, directory );
+ Messages.showInputDialog( project, getDialogPrompt(), getDialogTitle(), Messages.getQuestionIcon(), "", validator );
+ return validator;
+ }
+
+ /**
+ * @return Dialog prompt.
+ */
+ protected abstract String getDialogPrompt();
+
+ /**
+ * @return Dialog title.
+ */
+ protected abstract String getDialogTitle();
+
+ protected String getErrorTitle()
+ {
+ return CommonBundle.getErrorTitle();
+ }
+
+ protected final void checkBeforeCreate( String newName, PsiDirectory directory )
+ throws IncorrectOperationException
+ {
+ JavaDirectoryService javaDirectoryService = JavaDirectoryService.getInstance();
+ javaDirectoryService.checkCreateClass( directory, newName );
+ }
+
+ protected static PsiClass createClassFromTemplate( @NotNull PsiDirectory directory,
+ @NotNull String className,
+ @NotNull String templateName,
+ @NonNls String... parameters )
+ throws IncorrectOperationException
+ {
+ String classFileName = className + "." + StdFileTypes.JAVA.getDefaultExtension();
+ PsiFile file = createFromTemplateInternal( directory, className, classFileName, templateName, parameters );
+ return ( (PsiJavaFile) file ).getClasses()[ 0 ];
+ }
+
+ protected static PsiFile createFromTemplateInternal( @NotNull PsiDirectory directory,
+ @NotNull String name,
+ @NotNull String fileName,
+ @NotNull String templateName,
+ @NonNls String... parameters )
+ throws IncorrectOperationException
+ {
+ // Load template
+ FileTemplateManager fileTemplateManager = FileTemplateManager.getInstance();
+ FileTemplate template = fileTemplateManager.getJ2eeTemplate( templateName );
+
+ // Process template properties
+ Properties properties = new Properties( fileTemplateManager.getDefaultProperties() );
+ JavaTemplateUtil.setPackageNameAttribute( properties, directory );
+ properties.setProperty( NAME_TEMPLATE_PROPERTY, name );
+
+ // Add parameters
+ for( int i = 0; i < parameters.length; i += 2 )
+ {
+ properties.setProperty( parameters[ i ], parameters[ i + 1 ] );
+ }
+
+ // Create text from template with specified properties
+ String text;
+ try
+ {
+ text = template.getText( properties );
+ }
+ catch( Exception e )
+ {
+ String message = "Unable to load template for " +
+ fileTemplateManager.internalTemplateToSubject( templateName );
+ throw new RuntimeException( message, e );
+ }
+
+ // Serialized text to file
+ PsiManager psiManager = PsiManager.getInstance( directory.getProject() );
+ PsiFileFactory fileFactory = PsiFileFactory.getInstance( directory.getProject() );
+ PsiFile file = fileFactory.createFileFromText( fileName, text );
+
+ // Reformat the file according to project/default style
+ CodeStyleManager codeStyleManager = CodeStyleManager.getInstance( psiManager );
+ codeStyleManager.reformat( file );
+
+ // Add newly created file to directory
+ return (PsiFile) directory.add( file );
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/e0e1d7d4/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/common/actions/PolygeneCreateActionGroup.java
----------------------------------------------------------------------
diff --git a/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/common/actions/PolygeneCreateActionGroup.java b/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/common/actions/PolygeneCreateActionGroup.java
new file mode 100644
index 0000000..d53e0e1
--- /dev/null
+++ b/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/common/actions/PolygeneCreateActionGroup.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+package org.apache.polygene.ide.plugin.idea.common.actions;
+
+import com.intellij.ide.IdeView;
+import com.intellij.openapi.actionSystem.*;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.roots.ProjectFileIndex;
+import com.intellij.openapi.roots.ProjectRootManager;
+import com.intellij.psi.JavaDirectoryService;
+import com.intellij.psi.PsiDirectory;
+
+import static org.apache.polygene.ide.plugin.idea.common.resource.PolygeneResourceBundle.message;
+
+/**
+ * @author edward.yakop@gmail.com
+ * @since 0.1
+ */
+public final class PolygeneCreateActionGroup extends DefaultActionGroup
+{
+ public PolygeneCreateActionGroup()
+ {
+ super( message( "polygene.action.group.title" ), true );
+ getTemplatePresentation().setDescription( message( "polygene.action.group.description" ) );
+ }
+
+ public void update( AnActionEvent e )
+ {
+ Presentation presentation = e.getPresentation();
+ presentation.setVisible( shouldActionGroupVisible( e ) );
+ }
+
+ private boolean shouldActionGroupVisible( AnActionEvent e )
+ {
+ Module module = e.getData( LangDataKeys.MODULE );
+ if( module == null )
+ {
+ return false;
+ }
+
+ // TODO: Enable this once PolygeneFacet can be automatically added/removed
+// if( PolygeneFacet.getInstance( module ) == null )
+// {
+// return false;
+// }
+
+ // Are we on IDE View and under project source folder?
+ Project project = e.getData( PlatformDataKeys.PROJECT );
+ IdeView view = e.getData( LangDataKeys.IDE_VIEW );
+ if( view != null && project != null )
+ {
+ ProjectFileIndex projectFileIndex = ProjectRootManager.getInstance( project ).getFileIndex();
+ PsiDirectory[] dirs = view.getDirectories();
+ for( PsiDirectory dir : dirs )
+ {
+ if( projectFileIndex.isInSourceContent( dir.getVirtualFile() ) && JavaDirectoryService.getInstance().getPackage( dir ) != null )
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/e0e1d7d4/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/common/facet/PolygeneFacet.java
----------------------------------------------------------------------
diff --git a/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/common/facet/PolygeneFacet.java b/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/common/facet/PolygeneFacet.java
new file mode 100644
index 0000000..7342707
--- /dev/null
+++ b/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/common/facet/PolygeneFacet.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+package org.apache.polygene.ide.plugin.idea.common.facet;
+
+import com.intellij.facet.Facet;
+import com.intellij.facet.FacetManager;
+import com.intellij.facet.FacetType;
+import com.intellij.openapi.module.Module;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author edward.yakop@gmail.com
+ * @since 0.1
+ */
+public final class PolygeneFacet extends Facet<PolygeneFacetConfiguration>
+{
+ public PolygeneFacet( @NotNull FacetType facetType,
+ @NotNull Module module,
+ String name,
+ @NotNull PolygeneFacetConfiguration configuration,
+ Facet underlyingFacet
+ )
+ {
+ super( facetType, module, name, configuration, underlyingFacet );
+ }
+
+ @Nullable
+ public static PolygeneFacet getInstance( @NotNull Module module )
+ {
+ return FacetManager.getInstance( module ).getFacetByType( PolygeneFacetType.ID );
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/e0e1d7d4/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/common/facet/PolygeneFacetConfiguration.java
----------------------------------------------------------------------
diff --git a/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/common/facet/PolygeneFacetConfiguration.java b/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/common/facet/PolygeneFacetConfiguration.java
new file mode 100644
index 0000000..6a6f28e
--- /dev/null
+++ b/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/common/facet/PolygeneFacetConfiguration.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+package org.apache.polygene.ide.plugin.idea.common.facet;
+
+import com.intellij.facet.FacetConfiguration;
+import com.intellij.facet.ui.FacetEditorContext;
+import com.intellij.facet.ui.FacetEditorTab;
+import com.intellij.facet.ui.FacetValidatorsManager;
+import com.intellij.openapi.util.InvalidDataException;
+import com.intellij.openapi.util.WriteExternalException;
+import org.jdom.Element;
+import org.apache.polygene.ide.plugin.idea.common.facet.ui.PolygeneFacetEditorTab;
+
+/**
+ * @author edward.yakop@gmail.com
+ * @since 0.1
+ */
+public final class PolygeneFacetConfiguration
+ implements FacetConfiguration
+{
+ public FacetEditorTab[] createEditorTabs( FacetEditorContext editorContext,
+ FacetValidatorsManager validatorsManager )
+ {
+ return new FacetEditorTab[]{
+ new PolygeneFacetEditorTab( editorContext )
+ };
+ }
+
+ public final void readExternal( Element element )
+ throws InvalidDataException
+ {
+ // Do nothing
+ }
+
+ public final void writeExternal( Element element )
+ throws WriteExternalException
+ {
+ // Do nothing
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/e0e1d7d4/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/common/facet/PolygeneFacetType.java
----------------------------------------------------------------------
diff --git a/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/common/facet/PolygeneFacetType.java b/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/common/facet/PolygeneFacetType.java
new file mode 100644
index 0000000..b45de9f
--- /dev/null
+++ b/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/common/facet/PolygeneFacetType.java
@@ -0,0 +1,122 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+package org.apache.polygene.ide.plugin.idea.common.facet;
+
+import com.intellij.facet.Facet;
+import com.intellij.facet.FacetType;
+import com.intellij.facet.FacetTypeId;
+import com.intellij.facet.autodetecting.FacetDetector;
+import com.intellij.facet.autodetecting.FacetDetectorRegistry;
+import com.intellij.openapi.fileTypes.StdFileTypes;
+import com.intellij.openapi.module.JavaModuleType;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.module.ModuleType;
+import com.intellij.openapi.util.Condition;
+import com.intellij.openapi.vfs.VirtualFileFilter;
+import com.intellij.psi.JavaElementVisitor;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiImportStatement;
+import com.intellij.psi.PsiReferenceExpression;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Collection;
+
+/**
+ * @author edward.yakop@gmail.com
+ * @since 0.1
+ */
+public final class PolygeneFacetType extends FacetType<PolygeneFacet, PolygeneFacetConfiguration>
+{
+ public static final FacetTypeId<PolygeneFacet> ID = new FacetTypeId<PolygeneFacet>();
+
+ public PolygeneFacetType()
+ {
+ super( ID, "PolygeneFacet", "Polygene Facet" );
+ }
+
+ public final PolygeneFacetConfiguration createDefaultConfiguration()
+ {
+ return new PolygeneFacetConfiguration();
+ }
+
+ public final PolygeneFacet createFacet( @NotNull Module module,
+ String name,
+ @NotNull PolygeneFacetConfiguration configuration,
+ @Nullable Facet underlyingFacet )
+ {
+ return new PolygeneFacet( this, module, name, configuration, underlyingFacet );
+ }
+
+ public final boolean isSuitableModuleType( ModuleType moduleType )
+ {
+ return moduleType instanceof JavaModuleType;
+ }
+
+ @Override
+ public final void registerDetectors( FacetDetectorRegistry<PolygeneFacetConfiguration> registry )
+ {
+ registry.registerOnTheFlyDetector(
+ StdFileTypes.JAVA, VirtualFileFilter.ALL, new HasPolygeneImportPackageCondition(),
+ new FacetDetector<PsiFile, PolygeneFacetConfiguration>( "PolygeneFacetDetector" )
+ {
+ @Override
+ public PolygeneFacetConfiguration detectFacet( PsiFile source,
+ Collection<PolygeneFacetConfiguration> existingConfigurations )
+ {
+ if( !existingConfigurations.isEmpty() )
+ {
+ return existingConfigurations.iterator().next();
+ }
+
+ return createDefaultConfiguration();
+ }
+ }
+ );
+ }
+
+ private static class HasPolygeneImportPackageCondition
+ implements Condition<PsiFile>
+ {
+ public final boolean value( PsiFile psiFile )
+ {
+ final boolean[] hasPolygeneImportPackage = new boolean[]{ false };
+
+ psiFile.accept( new JavaElementVisitor()
+ {
+ @Override
+ public final void visitImportStatement( PsiImportStatement statement )
+ {
+ String packageName = statement.getQualifiedName();
+ if( packageName != null && packageName.startsWith( "org.apache.polygene" ) )
+ {
+ hasPolygeneImportPackage[ 0 ] = true;
+ }
+ }
+
+ @Override
+ public void visitReferenceExpression( PsiReferenceExpression expression )
+ {
+ // Ignore
+ }
+ } );
+ return hasPolygeneImportPackage[ 0 ];
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/e0e1d7d4/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/common/facet/ui/PolygeneFacetEditorTab.java
----------------------------------------------------------------------
diff --git a/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/common/facet/ui/PolygeneFacetEditorTab.java b/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/common/facet/ui/PolygeneFacetEditorTab.java
new file mode 100644
index 0000000..dc4b121
--- /dev/null
+++ b/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/common/facet/ui/PolygeneFacetEditorTab.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+package org.apache.polygene.ide.plugin.idea.common.facet.ui;
+
+import com.intellij.facet.ui.FacetEditorContext;
+import com.intellij.facet.ui.FacetEditorTab;
+import com.intellij.openapi.options.ConfigurationException;
+import org.jetbrains.annotations.Nls;
+
+import javax.swing.*;
+
+/**
+ * @author edward.yakop@gmail.com
+ * @since 0.1
+ */
+public final class PolygeneFacetEditorTab extends FacetEditorTab
+{
+ private final FacetEditorContext editorContext;
+
+ public PolygeneFacetEditorTab( FacetEditorContext aContext )
+ {
+ editorContext = aContext;
+ }
+
+ @Nls
+ public final String getDisplayName()
+ {
+ return "Polygene";
+ }
+
+ public JComponent createComponent()
+ {
+ return new JPanel();
+ }
+
+ public final boolean isModified()
+ {
+ return false;
+ }
+
+ public final void apply()
+ throws ConfigurationException
+ {
+ // From UI to configuration
+ }
+
+ public final void reset()
+ {
+ // From Configuration to UI
+ }
+
+ public final void disposeUIResources()
+ {
+ // Do nothing for now
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/e0e1d7d4/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/common/inspections/AbstractFix.java
----------------------------------------------------------------------
diff --git a/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/common/inspections/AbstractFix.java b/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/common/inspections/AbstractFix.java
new file mode 100644
index 0000000..1369766
--- /dev/null
+++ b/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/common/inspections/AbstractFix.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+package org.apache.polygene.ide.plugin.idea.common.inspections;
+
+import com.intellij.codeInspection.LocalQuickFix;
+import org.jetbrains.annotations.NotNull;
+
+import static org.apache.polygene.ide.plugin.idea.common.resource.PolygeneResourceBundle.message;
+
+/**
+ * @author edward.yakop@gmail.com
+ * @since 0.1
+ */
+public abstract class AbstractFix
+ implements LocalQuickFix
+{
+ private String fixName;
+
+ protected AbstractFix( @NotNull String name )
+ {
+ fixName = name;
+ }
+
+ @NotNull
+ public final String getName()
+ {
+ return fixName;
+ }
+
+ @NotNull
+ public final String getFamilyName()
+ {
+ return message( "polygene.quick.fixes.family.name" );
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/e0e1d7d4/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/common/inspections/AbstractInspection.java
----------------------------------------------------------------------
diff --git a/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/common/inspections/AbstractInspection.java b/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/common/inspections/AbstractInspection.java
new file mode 100644
index 0000000..a6d0a38
--- /dev/null
+++ b/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/common/inspections/AbstractInspection.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+package org.apache.polygene.ide.plugin.idea.common.inspections;
+
+import com.intellij.codeHighlighting.HighlightDisplayLevel;
+import com.intellij.codeInspection.BaseJavaLocalInspectionTool;
+import org.jetbrains.annotations.Nls;
+import org.jetbrains.annotations.NotNull;
+import org.apache.polygene.ide.plugin.idea.common.resource.PolygeneResourceBundle;
+
+import static com.intellij.codeHighlighting.HighlightDisplayLevel.ERROR;
+
+/**
+ * @author edward.yakop@gmail.com
+ * @since 0.1
+ */
+public abstract class AbstractInspection extends BaseJavaLocalInspectionTool
+{
+ private static final String POLYGENE_IDEA_INSPECTIONS_NAME = "polygene.inspections.name";
+
+ @Nls @NotNull public String getGroupDisplayName()
+ {
+ return PolygeneResourceBundle.message( POLYGENE_IDEA_INSPECTIONS_NAME );
+ }
+
+ @NotNull
+ protected abstract String resourceBundlePrefixId();
+
+ @Nls @NotNull
+ public final String getDisplayName()
+ {
+ return PolygeneResourceBundle.message( resourceBundlePrefixId() + ".name.display" );
+ }
+
+ @NotNull @Override
+ public HighlightDisplayLevel getDefaultLevel()
+ {
+ return ERROR;
+ }
+
+ @Override
+ public boolean isEnabledByDefault()
+ {
+ return true;
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/e0e1d7d4/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/common/intentions/AbstractIntention.java
----------------------------------------------------------------------
diff --git a/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/common/intentions/AbstractIntention.java b/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/common/intentions/AbstractIntention.java
new file mode 100644
index 0000000..d50693f
--- /dev/null
+++ b/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/common/intentions/AbstractIntention.java
@@ -0,0 +1,132 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+package org.apache.polygene.ide.plugin.idea.common.intentions;
+
+import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction;
+import com.intellij.openapi.editor.CaretModel;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.ReadonlyStatusHandler;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.util.IncorrectOperationException;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import static org.apache.polygene.ide.plugin.idea.common.resource.PolygeneResourceBundle.message;
+
+/**
+ * This class is based from {@code com.siyeh.ipp.base.Intention}
+ *
+ * @author edward.yakop@gmail.com
+ */
+public abstract class AbstractIntention extends PsiElementBaseIntentionAction
+{
+ protected abstract boolean isIntentionValidFor( PsiElement element );
+
+ protected abstract String resourceBundlePrefixId();
+
+ /**
+ * Implement this method to process intention.
+ *
+ * @param project The project in which the availability is checked.
+ * @param editor The editor in which the intention will be invoked.
+ * @param element The element under caret.
+ */
+ protected abstract void processIntention( @NotNull Project project,
+ @NotNull Editor editor,
+ @NotNull PsiElement element );
+
+ public void invoke( @NotNull Project project, Editor editor, PsiFile file )
+ throws IncorrectOperationException
+ {
+ if( isFileReadOnly( project, file ) )
+ {
+ return;
+ }
+
+ final PsiElement element = findMatchingElement( file, editor );
+ if( element == null )
+ {
+ return;
+ }
+
+ processIntention( project, editor, element );
+ }
+
+ protected static boolean isFileReadOnly( @NotNull Project project, @NotNull PsiFile file )
+ {
+ VirtualFile virtualFile = file.getVirtualFile();
+ ReadonlyStatusHandler readonlyStatusHandler = ReadonlyStatusHandler.getInstance( project );
+ ReadonlyStatusHandler.OperationStatus operationStatus =
+ readonlyStatusHandler.ensureFilesWritable( virtualFile );
+ return operationStatus.hasReadonlyFiles();
+ }
+
+ @Nullable
+ private PsiElement findMatchingElement( @NotNull PsiFile file, @NotNull Editor editor )
+ {
+ CaretModel caretModel = editor.getCaretModel();
+ int position = caretModel.getOffset();
+ PsiElement element = file.findElementAt( position );
+ return findMatchingElement( element );
+ }
+
+ @Nullable
+ private PsiElement findMatchingElement( @Nullable PsiElement element )
+ {
+ while( element != null )
+ {
+ if( isIntentionValidFor( element ) )
+ {
+ return element;
+ }
+ else
+ {
+ element = element.getParent();
+ if( element instanceof PsiFile )
+ {
+ break;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ public boolean isAvailable( @NotNull Project project, Editor editor, @Nullable PsiElement element )
+ {
+ return isIntentionValidFor( element );
+ }
+
+ @NotNull
+ public final String getFamilyName()
+ {
+ return message( resourceBundlePrefixId() + ".family.name" );
+ }
+
+ @NotNull
+ @Override
+ public final String getText()
+ {
+ return message( resourceBundlePrefixId() + ".name" );
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/e0e1d7d4/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/common/psi/PsiAnnotationUtil.java
----------------------------------------------------------------------
diff --git a/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/common/psi/PsiAnnotationUtil.java b/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/common/psi/PsiAnnotationUtil.java
new file mode 100644
index 0000000..4840a04
--- /dev/null
+++ b/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/common/psi/PsiAnnotationUtil.java
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+package org.apache.polygene.ide.plugin.idea.common.psi;
+
+import com.intellij.psi.*;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import static java.util.Collections.emptyList;
+
+/**
+ * @author edward.yakop@gmail.com
+ * @since 0.1
+ */
+public class PsiAnnotationUtil
+{
+ @NotNull
+ public static List<PsiAnnotationMemberValue> getAnnotationDefaultParameterValue( @Nullable PsiAnnotation annotation )
+ {
+ if( annotation == null )
+ {
+ return emptyList();
+ }
+
+ List<PsiAnnotationMemberValue> defaultParameterValues = new LinkedList<PsiAnnotationMemberValue>();
+
+ PsiAnnotationParameterList list = annotation.getParameterList();
+ PsiNameValuePair[] attributes = list.getAttributes();
+ for( PsiNameValuePair valuePair : attributes )
+ {
+ String parameterName = valuePair.getName();
+ if( parameterName == null || PsiAnnotation.DEFAULT_REFERENCED_METHOD_NAME.equals( parameterName ) )
+ {
+ PsiAnnotationMemberValue value = valuePair.getValue();
+ if( value == null )
+ {
+ continue;
+ }
+
+ if( value instanceof PsiArrayInitializerMemberValue )
+ {
+ // If It's an array
+ PsiArrayInitializerMemberValue valueWrapper = (PsiArrayInitializerMemberValue) value;
+ PsiAnnotationMemberValue[] values = valueWrapper.getInitializers();
+ for( PsiAnnotationMemberValue psiAnnotationMemberValue : values )
+ {
+ if( psiAnnotationMemberValue != null )
+ {
+ defaultParameterValues.add( psiAnnotationMemberValue );
+ }
+ }
+ }
+ else
+ {
+ // If there's only one value
+ defaultParameterValues.add( value );
+ }
+
+ break;
+ }
+ }
+
+ return defaultParameterValues;
+ }
+
+ @Nullable
+ public static PsiJavaCodeReferenceElement getClassReference( @NotNull PsiAnnotationMemberValue value )
+ {
+ if( value instanceof PsiClassObjectAccessExpression )
+ {
+ PsiClassObjectAccessExpression objectAccessExpression = (PsiClassObjectAccessExpression) value;
+ PsiTypeElement typeElement = objectAccessExpression.getOperand();
+ return typeElement.getInnermostComponentReferenceElement();
+ }
+
+ return null;
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/e0e1d7d4/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/common/psi/PsiClassUtil.java
----------------------------------------------------------------------
diff --git a/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/common/psi/PsiClassUtil.java b/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/common/psi/PsiClassUtil.java
new file mode 100644
index 0000000..1f7dbb2
--- /dev/null
+++ b/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/common/psi/PsiClassUtil.java
@@ -0,0 +1,134 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+package org.apache.polygene.ide.plugin.idea.common.psi;
+
+import com.intellij.psi.*;
+import com.intellij.psi.search.GlobalSearchScope;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.lang.reflect.InvocationHandler;
+import java.util.HashSet;
+import java.util.Set;
+
+import static org.apache.polygene.ide.plugin.idea.common.psi.search.GlobalSearchScopeUtil.determineSearchScope;
+
+/**
+ * @author edward.yakop@gmail.com
+ * @since 0.1
+ */
+public final class PsiClassUtil
+{
+ @Nullable
+ public static PsiClass getPSIClass( @NotNull PsiElement element )
+ {
+ if( element instanceof PsiClass )
+ {
+ return (PsiClass) element;
+ }
+
+ if( element instanceof PsiTypeElement )
+ {
+ PsiTypeElement psiTypeElement = (PsiTypeElement) element;
+ PsiJavaCodeReferenceElement componentRef = psiTypeElement.getInnermostComponentReferenceElement();
+ if( componentRef == null )
+ {
+ return null;
+ }
+
+ return (PsiClass) componentRef.resolve();
+ }
+
+ PsiElement context = element.getContext();
+ if( context instanceof PsiClass )
+ {
+ return (PsiClass) context;
+ }
+
+ return null;
+ }
+
+ @NotNull
+ public static Set<PsiClass> getExtends( @NotNull PsiClass psiClass )
+ {
+ HashSet<PsiClass> extendsClasses = new HashSet<PsiClass>();
+ PsiClassType[] extendsClassTypes = psiClass.getExtendsListTypes();
+ for( PsiClassType extendClassType : extendsClassTypes )
+ {
+ PsiClass extendClass = extendClassType.resolve();
+ if( extendClass != null )
+ {
+ extendsClasses.add( extendClass );
+ }
+ }
+
+ return extendsClasses;
+ }
+
+ /**
+ * Returns all extends of the specified {@code psiClass}.
+ *
+ * @param psiClass class to process.
+ * @return all extends of the specified {@code psiClass}.
+ * @since 0.1
+ */
+ @NotNull
+ public static Set<PsiClass> getExtendsDeep( @NotNull PsiClass psiClass )
+ {
+ HashSet<PsiClass> extendsClasses = new HashSet<PsiClass>();
+ PsiClassType[] extendsClassTypes = psiClass.getExtendsListTypes();
+ for( PsiClassType extendClassType : extendsClassTypes )
+ {
+ PsiClass extendClass = extendClassType.resolve();
+ if( extendClass != null )
+ {
+ extendsClasses.add( extendClass );
+ extendsClasses.addAll( getExtendsDeep( extendClass ) );
+ }
+ }
+
+ return extendsClasses;
+ }
+
+ /**
+ * @param psiClass Psi class to check.
+ * @return {@code true} if psi class implements {@code InvocationHandler}, {@code false} otherwise.
+ * @see InvocationHandler
+ */
+ public static boolean isImplementsInvocationHandler( @NotNull PsiClass psiClass )
+ {
+ if( psiClass.isInterface() )
+ {
+ return false;
+ }
+
+ GlobalSearchScope searchScope = determineSearchScope( psiClass );
+ assert searchScope != null;
+
+ JavaPsiFacade psiFacade = JavaPsiFacade.getInstance( psiClass.getProject() );
+ PsiClass invocationHandler = psiFacade.findClass( "java.lang.reflect.InvocationHandler", searchScope );
+ assert invocationHandler != null;
+
+ return psiClass.isInheritor( invocationHandler, true );
+ }
+
+ private PsiClassUtil()
+ {
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/e0e1d7d4/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/common/psi/search/GlobalSearchScopeUtil.java
----------------------------------------------------------------------
diff --git a/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/common/psi/search/GlobalSearchScopeUtil.java b/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/common/psi/search/GlobalSearchScopeUtil.java
new file mode 100644
index 0000000..4beda1f
--- /dev/null
+++ b/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/common/psi/search/GlobalSearchScopeUtil.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+package org.apache.polygene.ide.plugin.idea.common.psi.search;
+
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.roots.ProjectRootManager;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.search.GlobalSearchScope;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import static com.intellij.openapi.module.ModuleUtil.findModuleForPsiElement;
+import static org.apache.polygene.ide.plugin.idea.common.vfs.VirtualFileUtil.getVirtualFile;
+
+/**
+ * @author edward.yakop@gmail.com
+ * @since 0.1
+ */
+public class GlobalSearchScopeUtil
+{
+ /**
+ * Determine search scope given a psi element.
+ *
+ * @param psiElement context.
+ * @return Search scope given psi class.
+ * @since 0.1
+ */
+ @Nullable
+ public static GlobalSearchScope determineSearchScope( @NotNull PsiElement psiElement )
+ {
+ VirtualFile classVirtualFile = getVirtualFile( psiElement );
+ if( classVirtualFile == null )
+ {
+ return null;
+ }
+
+ Module module = findModuleForPsiElement( psiElement );
+ if( module == null )
+ {
+ return null;
+ }
+
+ Project project = psiElement.getProject();
+ ProjectRootManager projectRootManager = ProjectRootManager.getInstance( project );
+ boolean includeTestClasses = projectRootManager.getFileIndex().isInTestSourceContent( classVirtualFile );
+ return module.getModuleWithDependenciesAndLibrariesScope( includeTestClasses );
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/e0e1d7d4/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/common/resource/PolygeneResourceBundle.java
----------------------------------------------------------------------
diff --git a/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/common/resource/PolygeneResourceBundle.java b/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/common/resource/PolygeneResourceBundle.java
new file mode 100644
index 0000000..c5f29b4
--- /dev/null
+++ b/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/common/resource/PolygeneResourceBundle.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+package org.apache.polygene.ide.plugin.idea.common.resource;
+
+import com.intellij.CommonBundle;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.PropertyKey;
+
+import java.lang.ref.Reference;
+import java.lang.ref.SoftReference;
+import java.util.ResourceBundle;
+
+/**
+ * @author edward.yakop@gmail.com
+ * @since 0.1
+ */
+public final class PolygeneResourceBundle
+{
+
+ @NonNls
+ private static final String RESOURCE_BUNDLE_NAME = "org.apache.polygene.ide.plugin.idea.common.resource.PolygeneResourceBundle";
+
+ private static Reference<ResourceBundle> BUNDLE_REF;
+
+ private PolygeneResourceBundle()
+ {
+ }
+
+ public static String message( @PropertyKey( resourceBundle = RESOURCE_BUNDLE_NAME ) String key,
+ Object... params )
+ {
+ ResourceBundle resourceBundle = getBundle();
+ return CommonBundle.message( resourceBundle, key, params );
+ }
+
+ private static ResourceBundle getBundle()
+ {
+ ResourceBundle bundle = null;
+ if( BUNDLE_REF != null )
+ {
+ bundle = BUNDLE_REF.get();
+ }
+
+ if( bundle == null )
+ {
+ bundle = ResourceBundle.getBundle( PolygeneResourceBundle.class.getName() );
+ BUNDLE_REF = new SoftReference<ResourceBundle>( bundle );
+ }
+
+ return bundle;
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/e0e1d7d4/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/common/vfs/VirtualFileUtil.java
----------------------------------------------------------------------
diff --git a/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/common/vfs/VirtualFileUtil.java b/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/common/vfs/VirtualFileUtil.java
new file mode 100644
index 0000000..d5b95b6
--- /dev/null
+++ b/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/common/vfs/VirtualFileUtil.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+package org.apache.polygene.ide.plugin.idea.common.vfs;
+
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiFileSystemItem;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author edward.yakop@gmail.com
+ * @since 0.1
+ */
+public final class VirtualFileUtil
+{
+ /**
+ * @param element element to process.
+ * @return The containing virtual file of the element.
+ * @since 0.1
+ */
+ @Nullable
+ public static VirtualFile getVirtualFile( @NotNull PsiElement element )
+ {
+ if( element instanceof PsiFileSystemItem )
+ {
+ PsiFileSystemItem fileSystemItem = (PsiFileSystemItem) element;
+ return fileSystemItem.getVirtualFile();
+ }
+
+ // If it's not a file system, assume that this is an element within a file
+ PsiFile containingFile = element.getContainingFile();
+ if( containingFile == null )
+ {
+ return null;
+ }
+
+ VirtualFile virtualFile = containingFile.getVirtualFile();
+ if( virtualFile != null )
+ {
+ return virtualFile;
+ }
+
+ PsiFile originalFile = containingFile.getOriginalFile();
+ if( originalFile == null )
+ {
+ return null;
+ }
+
+ return originalFile.getVirtualFile();
+ }
+
+ private VirtualFileUtil()
+ {
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/e0e1d7d4/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/concerns/actions/create/CreateConcernFromMixinTypeOrCompositeAction.java
----------------------------------------------------------------------
diff --git a/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/concerns/actions/create/CreateConcernFromMixinTypeOrCompositeAction.java b/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/concerns/actions/create/CreateConcernFromMixinTypeOrCompositeAction.java
new file mode 100644
index 0000000..b6abdfb
--- /dev/null
+++ b/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/concerns/actions/create/CreateConcernFromMixinTypeOrCompositeAction.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.polygene.ide.plugin.idea.concerns.actions.create;
+
+import com.intellij.psi.PsiDirectory;
+import com.intellij.psi.PsiElement;
+import org.jetbrains.annotations.NotNull;
+import org.apache.polygene.ide.plugin.idea.common.actions.AbstractCreateElementActionBase;
+
+/**
+ * @author edward.yakop@gmail.com
+ */
+public class CreateConcernFromMixinTypeOrCompositeAction extends AbstractCreateElementActionBase
+{
+ public CreateConcernFromMixinTypeOrCompositeAction()
+ {
+ super( "TODO", "TODO" );
+ }
+
+ protected String getCommandName()
+ {
+ return "CreateConcernFromMixinTypeOrCompositeAction";
+ }
+
+ protected String getActionName( PsiDirectory directory, String newName )
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ protected String getDialogPrompt()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ protected String getDialogTitle()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @NotNull
+ protected PsiElement[] create( String newName, PsiDirectory directory )
+ throws Exception
+ {
+ return new PsiElement[0]; //To change body of implemented methods use File | Settings | File Templates.
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/e0e1d7d4/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/concerns/actions/create/inPackage/CreateConcernOfInPackageAction.java
----------------------------------------------------------------------
diff --git a/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/concerns/actions/create/inPackage/CreateConcernOfInPackageAction.java b/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/concerns/actions/create/inPackage/CreateConcernOfInPackageAction.java
new file mode 100644
index 0000000..402df3e
--- /dev/null
+++ b/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/concerns/actions/create/inPackage/CreateConcernOfInPackageAction.java
@@ -0,0 +1,121 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+package org.apache.polygene.ide.plugin.idea.concerns.actions.create.inPackage;
+
+import com.intellij.ide.actions.CreateInPackageActionBase;
+import com.intellij.openapi.actionSystem.DataContext;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.Messages;
+import com.intellij.psi.JavaDirectoryService;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiDirectory;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.util.IncorrectOperationException;
+import org.jetbrains.annotations.NotNull;
+
+import static com.intellij.openapi.actionSystem.DataKeys.PROJECT;
+import static com.intellij.openapi.actionSystem.DataKeys.PSI_ELEMENT;
+import static com.intellij.util.Icons.CLASS_ICON;
+import static org.apache.polygene.ide.plugin.idea.common.psi.search.GlobalSearchScopeUtil.determineSearchScope;
+import static org.apache.polygene.ide.plugin.idea.common.resource.PolygeneResourceBundle.message;
+import static org.apache.polygene.ide.plugin.idea.concerns.common.PolygeneConcernConstants.TEMPLATE_GENERIC_CONCERN_OF;
+import static org.apache.polygene.ide.plugin.idea.concerns.common.PolygeneConcernUtil.getConcernOfClass;
+
+/**
+ * JAVADOC: Non generic concern
+ *
+ * @author edward.yakop@gmail.com
+ * @since 0.1
+ */
+public class CreateConcernOfInPackageAction extends CreateInPackageActionBase
+{
+ protected CreateConcernOfInPackageAction()
+ {
+ super( message( "createConcernOfInPackage.menu.action.text" ),
+ message( "createConcernOfInPackage.menu.action.description" ),
+ CLASS_ICON );
+ }
+
+ @Override
+ protected final boolean isAvailable( DataContext dataContext )
+ {
+ boolean isAvailable = super.isAvailable( dataContext );
+ if( !isAvailable )
+ {
+ return false;
+ }
+
+ PsiElement psiElement = PSI_ELEMENT.getData( dataContext );
+ if( psiElement == null )
+ {
+ return false;
+ }
+
+ GlobalSearchScope searchScope = determineSearchScope( psiElement );
+ if( searchScope == null )
+ {
+ return false;
+ }
+
+ Project project = PROJECT.getData( dataContext );
+ PsiClass psiClass = getConcernOfClass( project, searchScope );
+ return psiClass != null;
+ }
+
+ @NotNull
+ protected final PsiElement[] invokeDialog( Project project, PsiDirectory directory )
+ {
+ MyInputValidator validator = new MyInputValidator( project, directory );
+ Messages.showInputDialog( project, message( "createConcernOfInPackage.dlg.prompt" ),
+ message( "createConcernOfInPackage.dlg.title" ),
+ Messages.getQuestionIcon(), "", validator );
+ return validator.getCreatedElements();
+ }
+
+ protected final String getCommandName()
+ {
+ return message( "createConcernOfInPackage.command.name" );
+ }
+
+ protected final String getErrorTitle()
+ {
+ return message( "createConcernOfInPackage.error.title" );
+ }
+
+ protected final String getActionName( PsiDirectory directory, String newName )
+ {
+ return message( "createConcernOfInPackage.progress.text", newName );
+ }
+
+ protected final void doCheckCreate( final PsiDirectory dir, final String className )
+ throws IncorrectOperationException
+ {
+ JavaDirectoryService javaDirectoryService = JavaDirectoryService.getInstance();
+ javaDirectoryService.checkCreateClass( dir, className );
+ }
+
+ @NotNull
+ protected PsiClass doCreate( final PsiDirectory dir, final String className )
+ throws IncorrectOperationException
+ {
+ JavaDirectoryService javaDirectoryService = JavaDirectoryService.getInstance();
+ return javaDirectoryService.createClass( dir, className, TEMPLATE_GENERIC_CONCERN_OF );
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/e0e1d7d4/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/concerns/common/PolygeneConcernConstants.java
----------------------------------------------------------------------
diff --git a/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/concerns/common/PolygeneConcernConstants.java b/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/concerns/common/PolygeneConcernConstants.java
new file mode 100644
index 0000000..0bbe3a1
--- /dev/null
+++ b/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/concerns/common/PolygeneConcernConstants.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+package org.apache.polygene.ide.plugin.idea.concerns.common;
+
+import org.jetbrains.annotations.NonNls;
+
+/**
+ * @author edward.yakop@gmail.com
+ * @since 0.1
+ */
+public final class PolygeneConcernConstants
+{
+ public static final String QUALIFIED_NAME_CONCERNS = "org.apache.polygene.api.concern.Concerns";
+
+ public static final String QUALIFIED_NAME_CONCERN_OF = "org.apache.polygene.api.concern.ConcernOf";
+ public static final String QUALIFIED_NAME_GENERIC_CONCERN = "org.apache.polygene.api.concern.GenericConcern";
+
+ @NonNls
+ public static final String TEMPLATE_GENERIC_CONCERN_OF = "GenericConcernOf.java";
+
+ private PolygeneConcernConstants()
+ {
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/e0e1d7d4/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/concerns/common/PolygeneConcernUtil.java
----------------------------------------------------------------------
diff --git a/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/concerns/common/PolygeneConcernUtil.java b/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/concerns/common/PolygeneConcernUtil.java
new file mode 100644
index 0000000..4499143
--- /dev/null
+++ b/tools/qidea/src/main/java/org/apache/polygene/ide/plugin/idea/concerns/common/PolygeneConcernUtil.java
@@ -0,0 +1,228 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+package org.apache.polygene.ide.plugin.idea.concerns.common;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.*;
+import com.intellij.psi.codeStyle.JavaCodeStyleManager;
+import com.intellij.psi.search.GlobalSearchScope;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+
+import static com.intellij.codeInsight.AnnotationUtil.findAnnotation;
+import static java.util.Collections.emptyList;
+import static org.apache.polygene.ide.plugin.idea.common.psi.PsiAnnotationUtil.getAnnotationDefaultParameterValue;
+import static org.apache.polygene.ide.plugin.idea.common.psi.PsiAnnotationUtil.getClassReference;
+import static org.apache.polygene.ide.plugin.idea.common.psi.PsiClassUtil.getPSIClass;
+import static org.apache.polygene.ide.plugin.idea.common.psi.search.GlobalSearchScopeUtil.determineSearchScope;
+import static org.apache.polygene.ide.plugin.idea.concerns.common.PolygeneConcernConstants.*;
+
+/**
+ * @author edward.yakop@gmail.com
+ * @since 0.1
+ */
+public final class PolygeneConcernUtil
+{
+
+
+ /**
+ * @param searchContext Search context.
+ * @return {@code GenericConcern} psi class if found, {@code null} otherwise.
+ * @since 0.1
+ */
+ @Nullable
+ public static PsiClass getGenericConcernClass( @NotNull PsiElement searchContext )
+ {
+ Project project = searchContext.getProject();
+ GlobalSearchScope searchScope = determineSearchScope( searchContext );
+ return getGenericConcernClass( project, searchScope );
+ }
+
+ /**
+ * @param project project.
+ * @param scope search scope.
+ * @return {@code GenericConcern} psi class if found, {@code null} otherwise.
+ * @since 0.1
+ */
+ @Nullable
+ public static PsiClass getGenericConcernClass( @NotNull Project project,
+ @Nullable GlobalSearchScope scope )
+ {
+ JavaPsiFacade psiFacade = JavaPsiFacade.getInstance( project );
+ return scope != null ? psiFacade.findClass( QUALIFIED_NAME_GENERIC_CONCERN, scope ) : null;
+ }
+
+ @Nullable
+ public static PsiClass getConcernOfClass( @NotNull PsiElement searchContext )
+ {
+ Project project = searchContext.getProject();
+ GlobalSearchScope searchScope = determineSearchScope( searchContext );
+ return getConcernOfClass( project, searchScope );
+ }
+
+ @Nullable
+ public static PsiClass getConcernOfClass( @NotNull Project project,
+ @Nullable GlobalSearchScope scope )
+ {
+ JavaPsiFacade psiFacade = JavaPsiFacade.getInstance( project );
+ return scope != null ? psiFacade.findClass( QUALIFIED_NAME_CONCERN_OF, scope ) : null;
+ }
+
+ @Nullable
+ public static PsiAnnotation getConcernsAnnotation( @NotNull PsiElement element )
+ {
+ PsiClass psiClass = getPSIClass( element );
+ return findAnnotation( psiClass, QUALIFIED_NAME_CONCERNS );
+ }
+
+ @NotNull
+ public static PsiAnnotation addOrReplaceConcernAnnotation( @NotNull PsiModifierListOwner modifierListOwner,
+ @NotNull PsiClass concernClassToAdd )
+ {
+ Project project = modifierListOwner.getProject();
+ JavaPsiFacade psiFacade = JavaPsiFacade.getInstance( project );
+ PsiElementFactory factory = psiFacade.getElementFactory();
+ PsiAnnotation existingConcernsAnnotation = findAnnotation( modifierListOwner, QUALIFIED_NAME_CONCERNS );
+
+ boolean isReplace = false;
+ PsiAnnotation newConcernsAnnotation;
+ if( existingConcernsAnnotation != null )
+ {
+ // Check duplicate
+ List<PsiAnnotationMemberValue> concernsValues = getConcernsAnnotationValue( existingConcernsAnnotation );
+ for( PsiAnnotationMemberValue concernValue : concernsValues )
+ {
+ PsiJavaCodeReferenceElement concernClassReference = getConcernClassReference( concernValue );
+ if( concernClassReference == null )
+ {
+ continue;
+ }
+
+ PsiElement concernClass = concernClassReference.resolve();
+ if( concernClassToAdd.equals( concernClass ) )
+ {
+ return existingConcernsAnnotation;
+ }
+ }
+
+ isReplace = true;
+ }
+
+ String concernAnnotationText = createConcernAnnotationText( existingConcernsAnnotation, concernClassToAdd );
+ newConcernsAnnotation =
+ factory.createAnnotationFromText( concernAnnotationText, modifierListOwner );
+
+ if( isReplace )
+ {
+ // Replace @Concerns instead
+ existingConcernsAnnotation.replace( newConcernsAnnotation );
+ }
+ else
+ {
+ // @Concerns doesn't exists, add it as first child
+ PsiModifierList modifierList = modifierListOwner.getModifierList();
+ modifierList.addBefore( newConcernsAnnotation, modifierList.getFirstChild() );
+ }
+
+ // Shorten all class references if possible
+ JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance( project );
+ codeStyleManager.shortenClassReferences( newConcernsAnnotation );
+
+ return newConcernsAnnotation;
+ }
+
+ @NotNull
+ private static String createConcernAnnotationText( @Nullable PsiAnnotation concernAnnotationBase,
+ @NotNull PsiClass concernClassToAdd )
+ {
+ StringBuilder annotationTextBuilder = new StringBuilder();
+ annotationTextBuilder.append( "@" ).append( QUALIFIED_NAME_CONCERNS ).append( "( {" );
+ List<PsiAnnotationMemberValue> concernsAnnotationValue = getConcernsAnnotationValue( concernAnnotationBase );
+ for( PsiAnnotationMemberValue concernValue : concernsAnnotationValue )
+ {
+ annotationTextBuilder.append( concernValue.getText() ).append( ", " );
+ }
+ annotationTextBuilder.append( concernClassToAdd.getQualifiedName() ).append( ".class" );
+ annotationTextBuilder.append( "} )" );
+ return annotationTextBuilder.toString();
+ }
+
+ @NotNull
+ public static List<PsiAnnotationMemberValue> getConcernsAnnotationValue( @Nullable PsiAnnotation concernsAnnotation )
+ {
+ if( concernsAnnotation == null )
+ {
+ return emptyList();
+ }
+
+ String concernsQualifiedName = concernsAnnotation.getQualifiedName();
+ if( !QUALIFIED_NAME_CONCERNS.equals( concernsQualifiedName ) )
+ {
+ return emptyList();
+ }
+
+ return getAnnotationDefaultParameterValue( concernsAnnotation );
+ }
+
+ @Nullable
+ public static PsiJavaCodeReferenceElement getConcernClassReference( @NotNull PsiAnnotationMemberValue value )
+ {
+ return getClassReference( value );
+ }
+
+ /**
+ * @param psiClass psi class to check.
+ * @return {@code true} if {@code psiClass} extends {@code ConcernOf}, {@code false} if {@code psiClass} does
+ * not extends {@code ConcernOf} or {@code ConcernOf} is not found.
+ * @since 0.1
+ */
+ public static boolean isAConcern( @NotNull PsiClass psiClass )
+ {
+ if( psiClass.isInterface() )
+ {
+ return false;
+ }
+
+ PsiClass concernOfClass = getConcernOfClass( psiClass );
+ return concernOfClass != null && psiClass.isInheritor( concernOfClass, true );
+ }
+
+ /**
+ * @param psiClass psi class to check.
+ * @return {@code true} if {@code psiClass} extends {@code GenericConcern}, {@code false} if {@code psiClass} does
+ * not extends {@code GenericConcern} or {@code GenericConcern} is not found.
+ * @since 0.1
+ */
+ public static boolean isAGenericConcern( @NotNull PsiClass psiClass )
+ {
+ if( psiClass.isInterface() )
+ {
+ return false;
+ }
+
+ PsiClass genericConcern = getGenericConcernClass( psiClass );
+ return genericConcern != null && psiClass.isInheritor( genericConcern, true );
+ }
+
+ private PolygeneConcernUtil()
+ {
+ }
+}