IDEA-114873 (Add Package Info item to New submenu)
authorBas Leijdekkers <basleijdekkers@gmail.com>
Mon, 14 Oct 2013 13:01:39 +0000 (15:01 +0200)
committerBas Leijdekkers <basleijdekkers@gmail.com>
Mon, 14 Oct 2013 13:01:39 +0000 (15:01 +0200)
java/java-impl/src/com/intellij/ide/actions/CreatePackageInfoAction.java [new file with mode: 0644]
java/java-impl/src/com/intellij/ide/fileTemplates/JavaCreateFromTemplateHandler.java
java/java-impl/src/com/intellij/ide/fileTemplates/JavaTemplateUtil.java
platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateUtil.java
platform/platform-resources-en/src/messages/IdeBundle.properties
resources-en/src/fileTemplates/internal/package-info.java.ft [new file with mode: 0644]
resources-en/src/fileTemplates/internal/package-info.java.html [new file with mode: 0644]
resources/src/META-INF/IdeaPlugin.xml
resources/src/idea/JavaActions.xml

diff --git a/java/java-impl/src/com/intellij/ide/actions/CreatePackageInfoAction.java b/java/java-impl/src/com/intellij/ide/actions/CreatePackageInfoAction.java
new file mode 100644 (file)
index 0000000..18a7f23
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed 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 com.intellij.ide.actions;
+
+import com.intellij.CommonBundle;
+import com.intellij.icons.AllIcons;
+import com.intellij.ide.IdeBundle;
+import com.intellij.ide.IdeView;
+import com.intellij.ide.fileTemplates.FileTemplate;
+import com.intellij.ide.fileTemplates.FileTemplateManager;
+import com.intellij.ide.fileTemplates.JavaTemplateUtil;
+import com.intellij.ide.fileTemplates.actions.AttributesDefaults;
+import com.intellij.ide.fileTemplates.actions.CreateFromTemplateActionBase;
+import com.intellij.openapi.actionSystem.*;
+import com.intellij.openapi.project.DumbAware;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.roots.ProjectFileIndex;
+import com.intellij.openapi.roots.ProjectRootManager;
+import com.intellij.openapi.ui.Messages;
+import com.intellij.psi.*;
+import com.intellij.psi.util.PsiUtil;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.generate.tostring.util.StringUtil;
+import org.jetbrains.jps.model.java.JavaModuleSourceRootTypes;
+
+/**
+ * @author Bas Leijdekkers
+ */
+public class CreatePackageInfoAction extends CreateFromTemplateActionBase implements DumbAware {
+
+  protected CreatePackageInfoAction() {
+    super("package-info.java", IdeBundle.message("action.create.new.package-info.description"), AllIcons.FileTypes.Java);
+  }
+
+  @Nullable
+  @Override
+  protected PsiDirectory getTargetDirectory(DataContext dataContext, IdeView view) {
+    final PsiDirectory[] directories = view.getDirectories();
+    for (PsiDirectory directory : directories) {
+      final PsiPackage aPackage = JavaDirectoryService.getInstance().getPackage(directory);
+      if (aPackage == null) {
+        continue;
+      }
+      if (directory.findFile(PsiPackage.PACKAGE_INFO_FILE) != null) {
+        Messages.showErrorDialog(CommonDataKeys.PROJECT.getData(dataContext),
+                                 "'package-info.java' already exists for package '" + aPackage.getQualifiedName() + '\'',
+                                 IdeBundle.message("title.cannot.create.file"));
+        return null;
+      }
+      else if (directory.findFile("package.html") != null) {
+        if (Messages.showOkCancelDialog(CommonDataKeys.PROJECT.getData(dataContext),
+                                    "Package '" + aPackage.getQualifiedName() + "' already has a 'package.html' file. Create 'package-info.java' anyway?",
+                                    "Found 'package.html'", "Create", CommonBundle.message("button.cancel"),
+                                    Messages.getQuestionIcon()) != Messages.OK) {
+          return null;
+        }
+      }
+
+    }
+    return super.getTargetDirectory(dataContext, view);
+  }
+
+  @Override
+  public void update(AnActionEvent e) {
+    e.getPresentation().setEnabledAndVisible(isAvailable(e.getDataContext()));
+  }
+
+  private static boolean isAvailable(DataContext dataContext) {
+    final Project project = CommonDataKeys.PROJECT.getData(dataContext);
+    final IdeView view = LangDataKeys.IDE_VIEW.getData(dataContext);
+    if (project == null || view == null) {
+      return false;
+    }
+    final PsiDirectory[] directories = view.getDirectories();
+    if (directories.length == 0) {
+      return false;
+    }
+    final ProjectFileIndex projectFileIndex = ProjectRootManager.getInstance(project).getFileIndex();
+    final JavaDirectoryService directoryService = JavaDirectoryService.getInstance();
+    final PsiNameHelper nameHelper = JavaPsiFacade.getInstance(project).getNameHelper();
+    for (PsiDirectory directory : directories) {
+      if (projectFileIndex.isUnderSourceRootOfType(directory.getVirtualFile(), JavaModuleSourceRootTypes.SOURCES) &&
+          PsiUtil.isLanguageLevel5OrHigher(directory)) {
+        final PsiPackage aPackage = directoryService.getPackage(directory);
+        if (aPackage != null) {
+          final String qualifiedName = aPackage.getQualifiedName();
+          if (StringUtil.isEmpty(qualifiedName) || nameHelper.isQualifiedName(qualifiedName)) {
+            return true;
+          }
+        }
+      }
+
+    }
+    return false;
+  }
+
+  @Nullable
+  @Override
+  public AttributesDefaults getAttributesDefaults(DataContext dataContext) {
+    return new AttributesDefaults("package-info").withFixedName(true);
+  }
+
+  @Nullable
+  @Override
+  protected AnAction getReplacedAction(FileTemplate selectedTemplate) {
+    return null;
+  }
+
+  @Override
+  protected FileTemplate getTemplate(Project project, PsiDirectory dir) {
+    return FileTemplateManager.getInstance().getInternalTemplate(JavaTemplateUtil.INTERNAL_PACKAGE_INFO_TEMPLATE_NAME);
+  }
+}
index d726cea50e181482ee8d3ef60fe19a6739733fd1..d84357b744f10a30651f38bf226fdc34d1890d78 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2012 JetBrains s.r.o.
+ * Copyright 2000-2013 JetBrains s.r.o.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -97,7 +97,7 @@ public class JavaCreateFromTemplateHandler implements CreateFromTemplateHandler
 
   public boolean handlesTemplate(final FileTemplate template) {
     FileType fileType = FileTypeManagerEx.getInstanceEx().getFileTypeByExtension(template.getExtension());
-    return fileType.equals(StdFileTypes.JAVA);
+    return fileType.equals(StdFileTypes.JAVA) && !JavaTemplateUtil.INTERNAL_PACKAGE_INFO_TEMPLATE_NAME.equals(template.getName());
   }
 
   public PsiElement createFromTemplate(final Project project, final PsiDirectory directory, final String fileName, FileTemplate template,
index 647357b0cd6b70837513b90d7510da814003a431..8466c9ff62cd0300ea51d7646ae39d1f30911b61 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2013 JetBrains s.r.o.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -19,7 +19,6 @@ import com.intellij.psi.*;
 import org.jetbrains.annotations.NonNls;
 import org.jetbrains.annotations.NotNull;
 
-import java.util.Map;
 import java.util.Properties;
 
 /**
@@ -37,6 +36,7 @@ public class JavaTemplateUtil {
   @NonNls public static final String INTERNAL_INTERFACE_TEMPLATE_NAME = "Interface";
   @NonNls public static final String INTERNAL_ANNOTATION_TYPE_TEMPLATE_NAME = "AnnotationType";
   @NonNls public static final String INTERNAL_ENUM_TEMPLATE_NAME = "Enum";
+  @NonNls public static final String INTERNAL_PACKAGE_INFO_TEMPLATE_NAME = "package-info";
 
   private JavaTemplateUtil() {
   }
index 4db5b6d88ac5b1519b3684e68ea910cb7d028087..a5826879de9088e8e2bea6ff03a27f7ed087a9d4 100644 (file)
@@ -349,7 +349,7 @@ public class FileTemplateUtil{
       }
     }
 
-    //Set escaped references to dummy values to remove leading "\" (if not already explicitely set)
+    //Set escaped references to dummy values to remove leading "\" (if not already explicitly set)
     String[] dummyRefs = calculateAttributes(template.getText(), propsMap, true);
     for (String dummyRef : dummyRefs) {
       propsMap.put(dummyRef, "");
@@ -384,7 +384,7 @@ public class FileTemplateUtil{
           }
         });
       }
-    }, template.isTemplateOfType(StdFileTypes.JAVA)
+    }, template.isTemplateOfType(StdFileTypes.JAVA) && !"package-info".equals(template.getName())
        ? IdeBundle.message("command.create.class.from.template")
        : IdeBundle.message("command.create.file.from.template"), null);
     if(commandException[0] != null){
index e99d3ddd84585de7796d1a2574c36876e4816fa5..b89d9d33ba5ff12f118bdad145529b331c137d10 100644 (file)
@@ -327,6 +327,7 @@ title.new.annotation.type=New @interface
 title.cannot.create.annotation.type=Cannot Create @interface
 action.create.new.class=Create New Class
 action.create.new.class.description=Create new Java class
+action.create.new.package-info.description=Create new package-info.java
 prompt.enter.new.class.name=Enter a new class name:
 title.new.class=New Class
 progress.creating.class=Creating class {0}
diff --git a/resources-en/src/fileTemplates/internal/package-info.java.ft b/resources-en/src/fileTemplates/internal/package-info.java.ft
new file mode 100644 (file)
index 0000000..5fb4fd4
--- /dev/null
@@ -0,0 +1,2 @@
+#parse("File Header.java")
+#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end
\ No newline at end of file
diff --git a/resources-en/src/fileTemplates/internal/package-info.java.html b/resources-en/src/fileTemplates/internal/package-info.java.html
new file mode 100644 (file)
index 0000000..32529e3
--- /dev/null
@@ -0,0 +1,86 @@
+<html>
+<body>
+<table border="0" cellpadding="2" cellspacing="0" style="border-collapse: collapse">
+  <tr>
+    <td><font face="verdana" size="-1">This is a built-in template used each time you create a new package-info.java file, by
+      selecting <i>New | package-info.java</i> from the popup menu in one of the project views.<br>
+      The template is editable. Along with Java expressions and comments, you can also use predefined variables
+      (listed below) that will then be expanded like macros into the corresponding values.<br>
+      It is also possible to specify an arbitrary number of custom variables in the format
+      <b>${&lt;VARIABLE_NAME&gt;}</b>. In this case, before the new
+      file is created, you will be prompted with a dialog where you can define particular values for all
+      custom variables.<br>
+      Using the <b>#parse</b> directive, you can include templates from the <i>Includes</i>
+      tab, by specifying the full name of the desired template as a parameter in quotation marks.
+      For example:<br>
+      <b>#parse("File Header.java")</b>
+    </font></td>
+  </tr>
+</table>
+<table border="0" cellpadding="5" cellspacing="0" style="border-collapse: collapse">
+  <tr>
+    <td colspan="3"><font face="verdana" size="-1">Predefined variables will take the following values:</font></td>
+  </tr>
+  <tr>
+    <td valign="top"><nobr><font face="verdana" size="-2"><b>${PACKAGE_NAME}</b></font></nobr></td>
+    <td width="10">&nbsp;</td>
+    <td valign="top"><font face="verdana" size="-1">name of the package in which the new package-info.java file is created</font></td>
+  </tr>
+  <tr>
+    <td valign="top"><nobr><font face="verdana" size="-2"><b>${USER}</b></font></nobr></td>
+    <td width="10">&nbsp;</td>
+    <td valign="top"><font face="verdana" size="-1">current user system login name</font></td>
+  </tr>
+  <tr>
+    <td valign="top"><nobr><font face="verdana" size="-2"><b>${DATE}</b></font></nobr></td>
+    <td width="10">&nbsp;</td>
+    <td valign="top"><font face="verdana" size="-1">current system date</font></td>
+  </tr>
+  <tr>
+    <td valign="top"><nobr><font face="verdana" size="-2"><b>${TIME}</b></font></nobr></td>
+    <td width="10">&nbsp;</td>
+    <td valign="top"><font face="verdana" size="-1">current system time</font></td>
+  </tr>
+  <tr>
+     <td valign="top"><nobr><font face="verdana" size="-2"><b>${YEAR}</b></font></nobr></td>
+     <td width="10">&nbsp;</td>
+     <td valign="top"><font face="verdana" size="-1">current year</font></td>
+   </tr>
+   <tr>
+     <td valign="top"><nobr><font face="verdana" size="-2"><b>${MONTH}</b></font></nobr></td>
+     <td width="10">&nbsp;</td>
+     <td valign="top"><font face="verdana" size="-1">current month</font></td>
+   </tr>
+   <tr>
+     <td valign="top"><nobr><font face="verdana" size="-2"><b>${MONTH_NAME_SHORT}</b></font></nobr></td>
+     <td width="10">&nbsp;</td>
+     <td valign="top"><font face="verdana" size="-1">first 3 letters of the current month name. Example: Jan, Feb, etc.</font></td>
+   </tr>
+   <tr>
+     <td valign="top"><nobr><font face="verdana" size="-2"><b>${MONTH_NAME_FULL}</b></font></nobr></td>
+     <td width="10">&nbsp;</td>
+     <td valign="top"><font face="verdana" size="-1">full name of the current month. Example: January, February, etc.</font></td>
+   </tr>
+   <tr>
+     <td valign="top"><nobr><font face="verdana" size="-2"><b>${DAY}</b></font></nobr></td>
+     <td width="10">&nbsp;</td>
+     <td valign="top"><font face="verdana" size="-1">current day of the month</font></td>
+   </tr>
+   <tr>
+     <td valign="top"><nobr><font face="verdana" size="-2"><b>${HOUR}</b></font></nobr></td>
+     <td width="10">&nbsp;</td>
+     <td valign="top"><font face="verdana" size="-1">current hour</font></td>
+   </tr>
+   <tr>
+     <td valign="top"><nobr><font face="verdana" size="-2"><b>${MINUTE}</b></font></nobr></td>
+     <td width="10">&nbsp;</td>
+     <td valign="top"><font face="verdana" size="-1">current minute</font></td>
+   </tr>
+   <tr>
+     <td valign="top"><nobr><font face="verdana" size="-2"><b>${PROJECT_NAME}</b></font></nobr></td>
+     <td width="10">&nbsp;</td>
+     <td valign="top"><font face="verdana" size="-1">the name of the current project</font></td>
+   </tr>
+</table>
+</body>
+</html>
\ No newline at end of file
index c12b6464232d5c509d93eadb0e6b48ccfded4520..6591dd0570b5385458f8fbc6b667675a32956b34 100644 (file)
     <internalFileTemplate name="Interface"/>
     <internalFileTemplate name="Enum"/>
     <internalFileTemplate name="AnnotationType" subject="@interface"/>
+    <internalFileTemplate name="package-info"/>
 
     <saveFileAsTemplateHandler implementation="com.intellij.ide.fileTemplates.SaveJavaAsTemplateHandler"/>
 
index 69fa91defe5ff82028a91a1299aba24df744f1f9..c808b36f93aeff59c64b1729f98e3f734019552a 100644 (file)
       <add-to-group group-id="NewGroup1" anchor="first"/>
     </action>
 
+    <action id="NewPackageInfo" class="com.intellij.ide.actions.CreatePackageInfoAction">
+      <add-to-group group-id="NewGroup1" anchor="after" relative-to-action="NewClass"/>
+    </action>
+
     <action id="CollapseBlock" class="com.intellij.codeInsight.folding.impl.actions.CollapseBlockAction">
       <add-to-group group-id="FoldingGroup" anchor="after" relative-to-action="CollapseSelection"/>
     </action>