diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionData.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionData.java index 164aa4f884bd..4ec737110c59 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionData.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionData.java @@ -120,7 +120,7 @@ public class JavaCompletionData extends JavaAwareCompletionData{ not(new FilterPattern(START_SWITCH))); - protected static final AndFilter CLASS_START = new AndFilter( + public static final AndFilter CLASS_START = new AndFilter( new OrFilter( END_OF_BLOCK, new PatternFilter(psiElement().afterLeaf( diff --git a/java/java-impl/src/com/intellij/codeInsight/template/JavaCodeContextType.java b/java/java-impl/src/com/intellij/codeInsight/template/JavaCodeContextType.java index 8f9126648094..d5aac60c111b 100644 --- a/java/java-impl/src/com/intellij/codeInsight/template/JavaCodeContextType.java +++ b/java/java-impl/src/com/intellij/codeInsight/template/JavaCodeContextType.java @@ -16,44 +16,43 @@ package com.intellij.codeInsight.template; import com.intellij.codeInsight.CodeInsightBundle; -import com.intellij.ide.DataManager; +import com.intellij.codeInsight.completion.JavaCompletionData; import com.intellij.ide.highlighter.JavaFileHighlighter; import com.intellij.lang.StdLanguages; -import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.editor.Document; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.openapi.fileTypes.SyntaxHighlighter; import com.intellij.openapi.project.Project; import com.intellij.psi.*; -import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtilBase; +import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -public class JavaCodeContextType extends TemplateContextType { - public JavaCodeContextType() { - super("JAVA_CODE", CodeInsightBundle.message("dialog.edit.template.checkbox.java.code")); +import static com.intellij.patterns.PlatformPatterns.psiElement; + +public abstract class JavaCodeContextType extends TemplateContextType { + + protected JavaCodeContextType(@NotNull @NonNls String id, + @NotNull String presentableName, + @Nullable Class baseContextType) { + super(id, presentableName, baseContextType); } - public boolean isInContext(@NotNull final PsiFile file, final int offset) { if (PsiUtilBase.getLanguageAtOffset(file, offset).isKindOf(StdLanguages.JAVA)) { PsiElement element = file.findElementAt(offset); if (element instanceof PsiWhiteSpace && offset > 0) { element = file.findElementAt(offset - 1); } - if (element != null && - element.getParent() instanceof PsiReferenceExpression && - ((PsiReferenceExpression)element.getParent()).isQualified()) { - return false; - } - - return element != null && PsiTreeUtil.getParentOfType(element, PsiComment.class, false) == null && - !(element instanceof PsiJavaToken && ((PsiJavaToken)element).getTokenType() == JavaTokenType.STRING_LITERAL); + return element != null && isInContext(element); } return false; } + + protected abstract boolean isInContext(@NotNull PsiElement element); @Override public boolean isInContext(@NotNull final FileType fileType) { @@ -76,4 +75,78 @@ public class JavaCodeContextType extends TemplateContextType { final JavaCodeFragment fragment = factory.createCodeBlockCodeFragment((String)text, psiFacade.findPackage(""), true); return PsiDocumentManager.getInstance(project).getDocument(fragment); } + + public static class Generic extends JavaCodeContextType { + public Generic() { + super("JAVA_CODE", "Java", EverywhereContextType.class); + } + + @Override + protected boolean isInContext(@NotNull PsiElement element) { + return true; + } + } + + public static class Statement extends JavaCodeContextType { + public Statement() { + super("JAVA_STATEMENT", "Statement", Generic.class); + } + + @Override + protected boolean isInContext(@NotNull PsiElement element) { + return isStatementContext(element); + } + + private static boolean isStatementContext(PsiElement element) { + return Expression.isExpressionContext(element) && element.getParent().getParent() instanceof PsiExpressionStatement; + } + } + public static class Expression extends JavaCodeContextType { + public Expression() { + super("JAVA_EXPRESSION", "Expression", Generic.class); + } + + @Override + protected boolean isInContext(@NotNull PsiElement element) { + return isExpressionContext(element); + } + + private static boolean isExpressionContext(PsiElement element) { + final PsiElement parent = element.getParent(); + if (!(parent instanceof PsiReferenceExpression)) { + return false; + } + if (((PsiReferenceExpression)parent).isQualified()) { + return false; + } + if (parent.getParent() instanceof PsiMethodCallExpression) { + return false; + } + if ( + psiElement().afterLeaf( + psiElement().inside( + psiElement(PsiExpression.class).afterLeaf( + psiElement().withText("(").withParent(PsiIfStatement.class)))) + .accepts(element)) { + return false; + } + return true; + } + } + public static class Declaration extends JavaCodeContextType { + public Declaration() { + super("JAVA_DECLARATION", "Declaration", Generic.class); + } + + @Override + protected boolean isInContext(@NotNull PsiElement element) { + if (Statement.isStatementContext(element)) { + return false; + } + + return JavaCompletionData.CLASS_START.isAcceptable(element, element) || JavaCompletionData.INSIDE_PARAMETER_LIST.accepts(element); + } + } + + } diff --git a/java/java-impl/src/com/intellij/codeInsight/template/JavaCommentContextType.java b/java/java-impl/src/com/intellij/codeInsight/template/JavaCommentContextType.java index 706a4fc715f8..149bc6caa0c8 100644 --- a/java/java-impl/src/com/intellij/codeInsight/template/JavaCommentContextType.java +++ b/java/java-impl/src/com/intellij/codeInsight/template/JavaCommentContextType.java @@ -22,7 +22,6 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiWhiteSpace; import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.codeInsight.CodeInsightBundle; import org.jetbrains.annotations.NotNull; /** @@ -30,7 +29,7 @@ import org.jetbrains.annotations.NotNull; */ public class JavaCommentContextType extends TemplateContextType { public JavaCommentContextType() { - super("JAVA_COMMENT", CodeInsightBundle.message("dialog.edit.template.checkbox.java.comment")); + super("JAVA_COMMENT", "Comment", JavaCodeContextType.Generic.class); } public boolean isInContext(@NotNull final PsiFile file, final int offset) { diff --git a/java/java-impl/src/com/intellij/codeInsight/template/JavaStringContextType.java b/java/java-impl/src/com/intellij/codeInsight/template/JavaStringContextType.java index 0ceeae65a6e4..3dfeeee560cc 100644 --- a/java/java-impl/src/com/intellij/codeInsight/template/JavaStringContextType.java +++ b/java/java-impl/src/com/intellij/codeInsight/template/JavaStringContextType.java @@ -29,7 +29,7 @@ import org.jetbrains.annotations.NotNull; */ public class JavaStringContextType extends TemplateContextType { public JavaStringContextType() { - super("JAVA_STRING", CodeInsightBundle.message("dialog.edit.template.checkbox.java.string")); + super("JAVA_STRING", "String", JavaCodeContextType.Generic.class); } public boolean isInContext(@NotNull final PsiFile file, final int offset) { diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/editorActions/BlockIndentOnPasteTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/editorActions/BlockIndentOnPasteTest.groovy index 6375b31c67af..eb43d1c08517 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/editorActions/BlockIndentOnPasteTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/editorActions/BlockIndentOnPasteTest.groovy @@ -58,6 +58,31 @@ class Test { doTest(before, toPaste, expected) } + void _testStringBeforeAnotherStringShouldNotIncreaseIndentOfTheFollowingString() { + def before = '''\ +class Test { + void test() { + int a = 100; + int b = 200; + }\ +''' + + def toPaste = '''\ + int b = 200; +''' + + def expected = '''\ +class Test { + void test() { + int b = 200; + int a = 100; + int b = 200; + }\ +''' + + doTest(before, toPaste, expected) + } + void testJavaComplexBlockWithDecreasedIndent() { def before = '''\ class Test { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/OtherContextType.java b/platform/lang-impl/src/com/intellij/codeInsight/template/EverywhereContextType.java similarity index 81% rename from platform/lang-impl/src/com/intellij/codeInsight/template/OtherContextType.java rename to platform/lang-impl/src/com/intellij/codeInsight/template/EverywhereContextType.java index a9f290766ca0..42c1b146087a 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/OtherContextType.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/EverywhereContextType.java @@ -16,7 +16,6 @@ package com.intellij.codeInsight.template; -import com.intellij.codeInsight.CodeInsightBundle; import com.intellij.openapi.fileTypes.FileType; import com.intellij.psi.PsiFile; import org.jetbrains.annotations.NotNull; @@ -24,9 +23,9 @@ import org.jetbrains.annotations.NotNull; /** * @author yole */ -public class OtherContextType extends TemplateContextType { - public OtherContextType() { - super("OTHER", CodeInsightBundle.message("dialog.edit.template.checkbox.other")); +public class EverywhereContextType extends TemplateContextType { + public EverywhereContextType() { + super("OTHER", "Everywhere", null); } public boolean isInContext(@NotNull final FileType fileType) { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/TemplateContextType.java b/platform/lang-impl/src/com/intellij/codeInsight/template/TemplateContextType.java index bd17c61d48f0..c1c646a99e9f 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/TemplateContextType.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/TemplateContextType.java @@ -38,9 +38,7 @@ public abstract class TemplateContextType { private final Class myBaseContextType; protected TemplateContextType(@NotNull @NonNls String id, @NotNull String presentableName) { - myPresentableName = presentableName; - myContextId = id; - myBaseContextType = null; + this(id, presentableName, EverywhereContextType.class); } protected TemplateContextType(@NotNull @NonNls String id, diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/TemplateManager.java b/platform/lang-impl/src/com/intellij/codeInsight/template/TemplateManager.java index 960847206223..48d3d7eedba3 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/TemplateManager.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/TemplateManager.java @@ -17,9 +17,7 @@ package com.intellij.codeInsight.template; import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.project.Project; -import com.intellij.psi.PsiFile; import com.intellij.util.PairProcessor; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -51,9 +49,6 @@ public abstract class TemplateManager { public abstract boolean startTemplate(@NotNull Editor editor, char shortcutChar); - public abstract TemplateContextType getContextType(@NotNull PsiFile file, int offset); - public abstract TemplateContextType getContextType(@NotNull FileType fileType); - public abstract Template createTemplate(@NotNull String key, String group); public abstract Template createTemplate(@NotNull String key, String group, @NonNls String text); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/LiveTemplateLookupActionProvider.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/LiveTemplateLookupActionProvider.java new file mode 100644 index 000000000000..121dc776b541 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/LiveTemplateLookupActionProvider.java @@ -0,0 +1,45 @@ +package com.intellij.codeInsight.template.impl; + +import com.intellij.codeInsight.lookup.Lookup; +import com.intellij.codeInsight.lookup.LookupActionProvider; +import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.codeInsight.lookup.LookupElementAction; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.options.ShowSettingsUtil; +import com.intellij.openapi.project.Project; +import com.intellij.util.Consumer; +import com.intellij.util.PlatformIcons; + +/** + * @author peter + */ +public class LiveTemplateLookupActionProvider implements LookupActionProvider{ + @Override + public void fillActions(LookupElement element, final Lookup lookup, Consumer consumer) { + if (element instanceof LiveTemplateLookupElement) { + final TemplateImpl template = ((LiveTemplateLookupElement)element).getTemplate(); + + consumer.consume(new LookupElementAction(PlatformIcons.EDIT, "Edit live template settings") { + @Override + public Result performLookupAction() { + final Project project = lookup.getEditor().getProject(); + assert project != null; + ApplicationManager.getApplication().invokeLater(new Runnable() { + public void run() { + if (project.isDisposed()) return; + + final LiveTemplatesConfigurable configurable = new LiveTemplatesConfigurable(); + ShowSettingsUtil.getInstance().editConfigurable(project, configurable, new Runnable() { + @Override + public void run() { + configurable.getTemplateListPanel().editTemplate(template); + } + }); + } + }); + return Result.HIDE_LOOKUP; + } + }); + } + } +} diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/LiveTemplateSettingsEditor.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/LiveTemplateSettingsEditor.java index 06ca21ba80dc..6f5385ad98d9 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/LiveTemplateSettingsEditor.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/LiveTemplateSettingsEditor.java @@ -17,8 +17,8 @@ package com.intellij.codeInsight.template.impl; import com.intellij.codeInsight.CodeInsightBundle; +import com.intellij.codeInsight.template.EverywhereContextType; import com.intellij.codeInsight.template.TemplateContextType; -import com.intellij.openapi.MnemonicHelper; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.command.CommandProcessor; @@ -30,19 +30,26 @@ import com.intellij.openapi.editor.event.DocumentEvent; import com.intellij.openapi.editor.ex.EditorEx; import com.intellij.openapi.ui.popup.JBPopup; import com.intellij.openapi.ui.popup.JBPopupFactory; +import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.wm.IdeFocusManager; +import com.intellij.ui.CheckboxTree; +import com.intellij.ui.CheckedTreeNode; import com.intellij.ui.IdeBorderFactory; +import com.intellij.ui.ScrollPaneFactory; import com.intellij.ui.awt.RelativePoint; import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.MultiMap; import com.intellij.util.ui.GridBag; import com.intellij.util.ui.UIUtil; +import com.intellij.util.ui.tree.TreeUtil; import org.jetbrains.annotations.Nullable; import javax.swing.*; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.TreePath; import java.awt.*; import java.awt.event.*; import java.util.*; @@ -259,15 +266,31 @@ public class LiveTemplateSettingsEditor extends JPanel { final Runnable updateLabel = new Runnable() { public void run() { - List contexts = new ArrayList(); + StringBuilder sb = new StringBuilder(); + String oldPrefix = ""; for (TemplateContextType type : myContext.keySet()) { if (myContext.get(type).booleanValue()) { - contexts.add(UIUtil.removeMnemonic(type.getPresentableName())); + final TemplateContextType base = type.getBaseContextType(); + String ownName = UIUtil.removeMnemonic(type.getPresentableName()); + String prefix = ""; + if (base != null && !(base instanceof EverywhereContextType)) { + prefix = UIUtil.removeMnemonic(base.getPresentableName()) + ": "; + ownName = StringUtil.decapitalize(ownName); + } + if (sb.length() > 0) { + sb.append(oldPrefix.equals(prefix) ? ", " : "; "); + } + if (!oldPrefix.equals(prefix)) { + sb.append(prefix); + oldPrefix = prefix; + } + sb.append(ownName); } } - ctxLabel.setText((contexts.isEmpty() ? "No applicable contexts yet" : "Applicable in " + StringUtil.join(contexts, ", ")) + ". "); - ctxLabel.setForeground(contexts.isEmpty() ? Color.RED : UIUtil.getLabelForeground()); - change.setText(contexts.isEmpty() ? "Define" : "Change"); + final boolean noContexts = sb.length() == 0; + ctxLabel.setText((noContexts ? "No applicable contexts yet" : "Applicable in " + sb.toString()) + ". "); + ctxLabel.setForeground(noContexts ? Color.GRAY : UIUtil.getLabelForeground()); + change.setText(noContexts ? "Define" : "Change"); } }; @@ -282,7 +305,7 @@ public class LiveTemplateSettingsEditor extends JPanel { } JPanel content = createPopupContextPanel(updateLabel); - myPopup = JBPopupFactory.getInstance().createComponentPopupBuilder(content, null).createPopup(); + myPopup = JBPopupFactory.getInstance().createComponentPopupBuilder(content, null).setResizable(true).createPopup(); myPopup.show(new RelativePoint(change, new Point(change.getWidth() , -content.getPreferredSize().height - 10))); } }); @@ -293,69 +316,86 @@ public class LiveTemplateSettingsEditor extends JPanel { } private JPanel createPopupContextPanel(final Runnable onChange) { - final Map contextComboBoxes = new HashMap(); + JPanel panel = new JPanel(new BorderLayout()); - ChangeListener listener = new ChangeListener() { - public void stateChanged(ChangeEvent e) { - myExpandByCombo.setEnabled(isExpandableFromEditor()); - } - - }; - - JPanel panel = new JPanel(new GridBagLayout()); - GridBagConstraints gbConstraints = new GridBagConstraints(); - gbConstraints.fill = GridBagConstraints.BOTH; - gbConstraints.weightx = 1; - gbConstraints.weighty = 1; - - final Runnable updateContextTypesEnabledState = new Runnable() { - public void run() { - for (Map.Entry entry : contextComboBoxes.entrySet()) { - TemplateContextType contextType = entry.getKey(); - TemplateContextType baseContextType = contextType.getBaseContextType(); - boolean enabled = baseContextType == null || !contextComboBoxes.get(baseContextType).isSelected(); - entry.getValue().setEnabled(enabled); - } + MultiMap hierarchy = new MultiMap() { + @Override + protected Map> createMap() { + return new LinkedHashMap>(); } }; - - int row = 0; - int col = 0; - for (final TemplateContextType contextType : myContext.keySet()) { - gbConstraints.gridy = row; - gbConstraints.gridx = col; - final JCheckBox cb = new JCheckBox(contextType.getPresentableName()); - cb.getModel().addChangeListener(listener); - panel.add(cb, gbConstraints); - contextComboBoxes.put(contextType, cb); - - if (row == (myContext.size() + 1) / 2 - 1) { - row = 0; - col = 1; - } - else { - row++; - } - cb.setSelected(myContext.get(contextType).booleanValue()); - - cb.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - myContext.put(contextType, cb.isSelected()); - updateContextTypesEnabledState.run(); - updateHighlighter(); - onChange.run(); - } - } - ); + for (TemplateContextType type : myContext.keySet()) { + hierarchy.putValue(type.getBaseContextType(), type); } - - updateContextTypesEnabledState.run(); - new MnemonicHelper().register(panel); + final CheckedTreeNode root = new CheckedTreeNode(Pair.create(null, "Hi")); + final CheckboxTree checkboxTree = new CheckboxTree(new CheckboxTree.CheckboxTreeCellRenderer() { + @Override + public void customizeRenderer(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) { + final Object o = ((DefaultMutableTreeNode)value).getUserObject(); + if (o instanceof Pair) { + getTextRenderer().append((String)((Pair)o).second); + } + } + }, root) { + @Override + protected void onNodeStateChanged(CheckedTreeNode node) { + final TemplateContextType type = (TemplateContextType)((Pair)node.getUserObject()).first; + if (type != null) { + myContext.put(type, node.isChecked()); + } + myExpandByCombo.setEnabled(isExpandableFromEditor()); + updateHighlighter(); + onChange.run(); + + } + }; + + for (TemplateContextType type : hierarchy.get(null)) { + addContextNode(hierarchy, root, type); + } + + ((DefaultTreeModel)checkboxTree.getModel()).nodeStructureChanged(root); + + TreeUtil.traverse(root, new TreeUtil.Traverse() { + @Override + public boolean accept(Object _node) { + final CheckedTreeNode node = (CheckedTreeNode)_node; + if (node.isChecked()) { + checkboxTree.expandPath(new TreePath(node.getPath()).getParentPath()); + } + return true; + } + }); + + panel.add(ScrollPaneFactory.createScrollPane(checkboxTree)); + final Dimension size = checkboxTree.getPreferredSize(); + panel.setPreferredSize(new Dimension(size.width + 30, size.height + 10)); return panel; } + private void addContextNode(MultiMap hierarchy, + CheckedTreeNode parent, + TemplateContextType type) { + final Collection children = hierarchy.get(type); + final String name = UIUtil.removeMnemonic(type.getPresentableName()); + final CheckedTreeNode node = new CheckedTreeNode(Pair.create(children.isEmpty() ? type : null, name)); + parent.add(node); + + if (children.isEmpty()) { + node.setChecked(myContext.get(type)); + } + else { + for (TemplateContextType child : children) { + addContextNode(hierarchy, node, child); + } + final CheckedTreeNode other = new CheckedTreeNode(Pair.create(type, "Other")); + other.setChecked(myContext.get(type)); + node.add(other); + } + } + private boolean isExpandableFromEditor() { boolean hasNonExpandable = false; for (TemplateContextType type : myContext.keySet()) { @@ -377,7 +417,7 @@ public class LiveTemplateSettingsEditor extends JPanel { } private void validateEditVariablesButton() { - myEditVariablesButton.setEnabled(!parseVariables(myTemplateEditor.getDocument().getCharsSequence(), false).isEmpty()); + myEditVariablesButton.setEnabled(!parseVariables(myTemplateEditor.getDocument().getCharsSequence()).isEmpty()); } private void reset() { @@ -447,7 +487,7 @@ public class LiveTemplateSettingsEditor extends JPanel { }); - ArrayList parsedVariables = parseVariables(myTemplateEditor.getDocument().getCharsSequence(), false); + ArrayList parsedVariables = parseVariables(myTemplateEditor.getDocument().getCharsSequence()); Map newVariableNames = new HashMap(); for (Object parsedVariable : parsedVariables) { @@ -517,16 +557,9 @@ public class LiveTemplateSettingsEditor extends JPanel { }, modalityState); } - private static ArrayList parseVariables(CharSequence text, boolean includeInternal) { + private static ArrayList parseVariables(CharSequence text) { ArrayList variables = new ArrayList(); TemplateImplUtil.parseVariables(text, variables, TemplateImpl.INTERNAL_VARS_SET); - if (!includeInternal) { - for (Iterator iterator = variables.iterator(); iterator.hasNext(); ) { - if (TemplateImpl.INTERNAL_VARS_SET.contains(iterator.next().getName())) { - iterator.remove(); - } - } - } return variables; } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateContext.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateContext.java index 1eb79d250957..5ce06a194944 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateContext.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateContext.java @@ -17,6 +17,7 @@ package com.intellij.codeInsight.template.impl; +import com.intellij.codeInsight.template.EverywhereContextType; import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.WriteExternalException; import com.intellij.codeInsight.template.TemplateContextType; @@ -46,14 +47,14 @@ public class TemplateContext { synchronized (myAdditionalContexts) { storedValue = myAdditionalContexts.get(contextType.getContextId()); } - boolean result = storedValue == null ? false : storedValue.booleanValue(); - if (!result) { + if (storedValue == null) { TemplateContextType baseContextType = contextType.getBaseContextType(); - if (baseContextType != null) { - result = isEnabled(baseContextType); + if (baseContextType != null && !(baseContextType instanceof EverywhereContextType)) { + return isEnabled(baseContextType); } + return false; } - return result; + return storedValue.booleanValue(); } public void setEnabled(TemplateContextType contextType, boolean value) { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateManagerImpl.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateManagerImpl.java index ce304937be14..ffbce303141f 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateManagerImpl.java @@ -430,18 +430,33 @@ public class TemplateManagerImpl extends TemplateManager implements ProjectCompo return result; } - public TemplateContextType getContextType(@NotNull PsiFile file, int offset) { - LinkedList userDefinedExtensionsFirst = buildOrderedContextTypes(); - for (TemplateContextType contextType : userDefinedExtensionsFirst) { - if (contextType.isInContext(file, offset)) { - return contextType; + private static boolean isEnabled(@Nullable PsiFile file, int offset, @Nullable FileType fileType, TemplateContext context) { + LinkedHashSet set = new LinkedHashSet(); + LinkedList contexts = buildOrderedContextTypes(); + for (TemplateContextType contextType : contexts) { + if (fileType == null ? contextType.isInContext(file, offset) : contextType.isInContext(fileType)) { + set.add(contextType); } } - assert false : "OtherContextType should match any context"; - return null; + + removeBases: + while (true) { + for (TemplateContextType type : set) { + if (set.remove(type.getBaseContextType())) { + continue removeBases; + } + } + + for (TemplateContextType type : set) { + if (context.isEnabled(type)) { + return true; + } + } + return false; + } } - private LinkedList buildOrderedContextTypes() { + private static LinkedList buildOrderedContextTypes() { final TemplateContextType[] typeCollection = getAllContextTypes(); LinkedList userDefinedExtensionsFirst = new LinkedList(); for (TemplateContextType contextType : typeCollection) { @@ -455,18 +470,6 @@ public class TemplateManagerImpl extends TemplateManager implements ProjectCompo return userDefinedExtensionsFirst; } - @Override - public TemplateContextType getContextType(@NotNull FileType fileType) { - LinkedList userDefinedExtensionsFirst = buildOrderedContextTypes(); - for (TemplateContextType contextType : userDefinedExtensionsFirst) { - if (contextType.isInContext(fileType)) { - return contextType; - } - } - assert false : "OtherContextType should match any context"; - return null; - } - public static TemplateContextType[] getAllContextTypes() { return Extensions.getExtensions(TemplateContextType.EP_NAME); } @@ -485,7 +488,7 @@ public class TemplateManagerImpl extends TemplateManager implements ProjectCompo public static boolean isApplicable(PsiFile file, int offset, TemplateImpl template) { TemplateManager instance = getInstance(file.getProject()); TemplateContext context = template.getTemplateContext(); - if (context.isEnabled(instance.getContextType(file, offset))) { + if (isEnabled(file, offset, null, context)) { return true; } @@ -493,7 +496,7 @@ public class TemplateManagerImpl extends TemplateManager implements ProjectCompo if (baseLanguage != file.getLanguage()) { PsiFile basePsi = file.getViewProvider().getPsi(baseLanguage); - if (basePsi != null && context.isEnabled(instance.getContextType(basePsi, offset))) { + if (basePsi != null && isEnabled(basePsi, offset, null, context)) { return true; } } @@ -502,7 +505,7 @@ public class TemplateManagerImpl extends TemplateManager implements ProjectCompo if (baseLanguageForBaseLanguage != null) { final LanguageFileType associatedFileType = baseLanguageForBaseLanguage.getAssociatedFileType(); if (associatedFileType != null && associatedFileType != file.getFileType()) { - if (context.isEnabled(instance.getContextType(associatedFileType))) { + if (isEnabled(null, 0, associatedFileType, context)) { return true; } } @@ -513,7 +516,7 @@ public class TemplateManagerImpl extends TemplateManager implements ProjectCompo if (offset > 0) { final Language prevLanguage = PsiUtilBase.getLanguageAtOffset(file, offset - 1); final PsiFile prevPsi = file.getViewProvider().getPsi(prevLanguage); - if (prevPsi != null && context.isEnabled(instance.getContextType(prevPsi, offset - 1))) { + if (prevPsi != null && isEnabled(prevPsi, offset - 1, null, context)) { return true; } } diff --git a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/OptionsEditor.java b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/OptionsEditor.java index 83d1a6f418ed..53a90978b8fb 100644 --- a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/OptionsEditor.java +++ b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/OptionsEditor.java @@ -1004,7 +1004,7 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat private boolean isPopupOverEditor(Component c) { final Window wnd = SwingUtilities.getWindowAncestor(c); - return wnd instanceof JWindow && myWindow != null && wnd.getParent() == myWindow; + return (wnd instanceof JWindow || wnd instanceof JDialog && ((JDialog)wnd).getModalityType() == Dialog.ModalityType.MODELESS) && myWindow != null && wnd.getParent() == myWindow; } private static class MySearchField extends SearchTextField { diff --git a/platform/platform-resources-en/src/messages/CodeInsightBundle.properties b/platform/platform-resources-en/src/messages/CodeInsightBundle.properties index 28e47a49087b..9267f4cc55a8 100644 --- a/platform/platform-resources-en/src/messages/CodeInsightBundle.properties +++ b/platform/platform-resources-en/src/messages/CodeInsightBundle.properties @@ -294,14 +294,10 @@ dialog.edit.template.checkbox.reformat.according.to.style=&Reformat according to dialog.edit.template.checkbox.shorten.fq.names=Shorten &FQ names dialog.edit.template.checkbox.use.static.import=Use static import if possible dialog.edit.template.context.title=Context -dialog.edit.template.checkbox.java.code=&Java code dialog.edit.template.checkbox.html=&HTML -dialog.edit.template.checkbox.java.comment=Java &comment dialog.edit.template.checkbox.xml=&XML -dialog.edit.template.checkbox.java.string=Java &string dialog.edit.template.checkbox.jsp=JS&P dialog.edit.template.checkbox.smart.type.completion=Smart type c&ompletion -dialog.edit.template.checkbox.other=O&ther dialog.edit.template.error.title=Cannot Save dialog.edit.template.error.malformed.abbreviation=Cannot save the template.\nTemplate abbreviation should contain only letters, digits, dots and hyphens. dialog.edit.template.error.already.exists=Cannot save the template.\nTemplate with the abbreviation \"{0}\"\nalready exists in group \"{1}\".\nPlease choose a different abbreviation or group. diff --git a/platform/platform-resources/src/META-INF/LangExtensions.xml b/platform/platform-resources/src/META-INF/LangExtensions.xml index 56465b94f3cb..fa464b836fa0 100644 --- a/platform/platform-resources/src/META-INF/LangExtensions.xml +++ b/platform/platform-resources/src/META-INF/LangExtensions.xml @@ -317,6 +317,7 @@ + @@ -553,7 +554,7 @@ - + - + + + + diff --git a/resources/src/liveTemplates/iterations.xml b/resources/src/liveTemplates/iterations.xml index 10479e3c937c..0c224edb9dba 100644 --- a/resources/src/liveTemplates/iterations.xml +++ b/resources/src/liveTemplates/iterations.xml @@ -7,16 +7,10 @@ - diff --git a/resources/src/liveTemplates/other.xml b/resources/src/liveTemplates/other.xml index c69e1baeb8a2..3759fb9e725a 100644 --- a/resources/src/liveTemplates/other.xml +++ b/resources/src/liveTemplates/other.xml @@ -6,79 +6,49 @@ - diff --git a/resources/src/liveTemplates/output.xml b/resources/src/liveTemplates/output.xml index 851c2319fbd6..9878f2a5a8ef 100644 --- a/resources/src/liveTemplates/output.xml +++ b/resources/src/liveTemplates/output.xml @@ -3,46 +3,25 @@ diff --git a/resources/src/liveTemplates/plain.xml b/resources/src/liveTemplates/plain.xml index 238c50cb27f3..2f5833a71f24 100644 --- a/resources/src/liveTemplates/plain.xml +++ b/resources/src/liveTemplates/plain.xml @@ -3,76 +3,48 @@ diff --git a/resources/src/liveTemplates/surround.xml b/resources/src/liveTemplates/surround.xml index f50411c785eb..3bf9fc64bbf3 100644 --- a/resources/src/liveTemplates/surround.xml +++ b/resources/src/liveTemplates/surround.xml @@ -35,15 +35,9 @@ -