diff options
author | Tor Norbye <tnorbye@google.com> | 2014-01-27 09:36:41 -0800 |
---|---|---|
committer | Tor Norbye <tnorbye@google.com> | 2014-01-27 09:36:49 -0800 |
commit | 809cb3e73653399e59e45e0b10749a8e37b85a75 (patch) | |
tree | 8aa7262925cc4eed902baa00f2193e98f6bb64e0 /plugins | |
parent | e2d6089d43d7ac1f62bafe06638d5ac2c21f5283 (diff) | |
download | idea-809cb3e73653399e59e45e0b10749a8e37b85a75.tar.gz |
Snapshot 9e6329d622cc9649c9c035f28faddc29564a5b7a from idea/133.696 of git://git.jetbrains.org/idea/community.git
9e6329d: IDEA-119035 Select All shortcut for any table on mac with Darcula
7642139: [log] IDEA-116322 Fix structure filter for multiple roots
5fe2227: [log] refactor: group filters before passing them to providers
a9bda1e: Problem with several users in log filter fixed.
bb353f3: [log] IDEA-119316 Fix "go to commit" if there are log filters
2825dd1: IDEA-119467 Gradle: auto discovery of buildSrc project (cherry picked from commit 3cb5420)
ca05350: Gradle: respect the order of dependencies (cherry picked from commit dca7107)
8a1d099: IDEA-115351 Idea UI hangs after performing Move Module to group (cherry picked from commit 673ed61) [r=Maxim.Mossienko]
9f006a4: NPE fix (cherry picked from commit 1eb3644)
2089b40: Gradle: test data fix (cherry picked from commit c864c4b)
6208324: IDEA-119336 Gradle build files: build.gradle scripts are checkout from Perforce even if the file is not changed (cherry picked from commit 3234c0b)
d1d776c: IDEA-119467 Gradle: auto discovery of buildSrc project IDEA-98930 IDEA does not resolve dependencies in Gradle buildSrc/ project (cherry picked from commit 0982afc)
6f6c403: Gradle: dependencies scope merge and sourceSets type handling updated related issues: IDEA-119365 Gradle import does not respect model customisations IDEA-118280 Gradle import: IDEA detect java folder as a resource folder IDEA-117668 IDEA v13 spontaneously changes additional test source root to source root (cherry picked from commit 68bfa5e)
a7f9d6f: Gradle: respect module build classpath for build scripts resolving review: http://crucible.labs.intellij.net/cru/CR-IC-4038
742c670: isEAP = false, time to release 13.0.2
3a5cfc7: add profiling parameters to the right part of the classpath (has been broken after Launcher was introduced)
ca42a66: fixed empty headers and import (dependant in language level) for qt, gtk... skeletons.
ba68876: update copyright in artworks
7c12cb3: IDEA-119619 Settings / Language Injections: project level XML tag injection loses Sub-Tags value on IDE restart
f7bd727: don't call robot on alt on Windows and when window is inactive (cherry picked from commit 0fe2cac)
8b62b1e: add WinXP definition (cherry picked from commit dde1494)
62c528a: consume Alt events on WinXP in default handler to avoid WindowsRootPaneUI.AltProcessor (cherry picked from commit f14aab9)
20c7faa: support table decoration on IntelliJ laf (cherry picked from commit 04425c9)
7dc2f34: IDEA-118211 (cherry picked from commit 55ee980) [r=Peter.Gromov]
b15f65d: fixed PY-11823 Test Runner detection in settings doesn't pick up just installed test runner
7a2bec9: Fixed dedent in case of tabs ( PY-10120).
56b5f81: Python keywords extracted. Cleanup.
f195253: Fixed test data to satisfy PEP8.
6b6bbc1: Make right par indent=none in import statement (PY-9075).
6a39911: Make continuation indent after continuation in indenting statement (PY-9573).
cf19307: Test for PY-9573
fb5186fa: Handle 'mode' as a keyword argument to open() as well
27a4d26: Detect text or binary I/O in pathlib.Path.open()
a5600e3: Return instance types for instance types of superclasses
f56e9b1: fixed PY-11837 nose test runner errors while formatting a test error
7420dd6: Nullity annotations
97ffd71: fixed test data
d0eb725: fixed test data
326185d: generator: do not drop the whole module in case there are broken __repr__ defined
982687a: performance for generator: Split big generated modules (like _Gtk, PyQt) into smaller ones
af679a5: Simplified always true condition
3174b9c: Extracted PyClassTypeImpl.findProperty()
777280e: Added 'inherited' parameter to PyClass.findProperty()
d5d8b23: Python skeletons class members provider now can provide new overridden members
6775ed3: Fixed code insight for returning 'self' in base class methods (PY-10977, PY-11413)
d4c641f: Fix formatter to add two blank lines between declarations with comment (PY-9923).
9c8134a: add field after super call
37813c6: Revert "Detect SQL fragments only in the beginning of string literals" (PY-11828)
9d5973f: Use default charset as python console encoding.
7fed382: Added Python 3.4 modules to the stdlib modules list
c772246: Don't ignore unused attributes of empty constructors (PY-7527)
91ae6bf: Fixed NPE in PyUnusedLocalInspectionVisitor.visitPyCallExpression()
464ae1c: fixed PY-11800 Parameter unfilled false positive for decorators with '*' arguments.
e3ec532: fixed test data
31bb1dd: fixed add field declaration to the beginning of __init__
2910f7d: fixed EA-52897 - CCE: ImportToggleAliasIntention$.execute
cca9133: fixed EA-53046 - NPE: PyExtractMethodUtil.a
2fcf769: fixed quickdoc test
fcf329f: fixed editing test
859c599: fixed testdata
ab7782a: fixed PY-11765 @ivar and @type in class documentation cause PyUnresolvedReferences inspection to file
8303e4f: IDEA-112303 Tool Windows Quick Access button: impossible to select item in list by mouse (cherry picked from commit 8e2ce03)
b206d2d: fix NPE
d923a83: Trying to fix EA-51665 - assert: FTManager.createAndStoreBundledTemplate (cherry picked from commit 47dee08) +review CR-IC
72fa58b: Add additional diagnostic to investigate EA-51665 (assert: FTManager.createAndStoreBundledTemplate). (cherry picked from commit a5e4cf4) +review CR-IC
6548f1a: java: incorrect parsing of bounds in class files fixed
8f5b22c: EA-42899 - CCE: XmlLanguageInjectionSupport.doEditInjection & cleanup
2a882e0: EA-53406 - IAE: ServiceManager.getService
ed41c77: WI-13685 PhpStorm doesn't save project name CR-PS-181
2c3ccec: IDEA-119445 Remove first slash in "copy reference" (cherry picked from commit 298bb04)
50bf901: IDEA-119153 file search too wide for users folder (cherry picked from commit 37521f0)
8ab790b: IDEA-119470 File and code templates: changes gone when switching tabs (cherry picked from commit 21cdea3)
7402508: EA-53393 - IOOBE: DomAnchorImpl.createAnchor (missing cherry pick)
f6ab2da: Bug fix: IDEA incorrect handle escaping.
c78400d: IDEA-105253 Missing icon for Thread dumps view
21b6f91: IDEA-104735 Dracula: INVALID string have not dracula style red color (cherry picked from commit 4a5e793)
53885c2: Don't show active editor in recent files
6cf74eb: IDEA-104706 Remove currently active file from "Recent Files" popup (cherry pick from master)
ffef358: IDEA-119406 IDEA make corrupts files when performing Maven resource filtering (default value of escapeString is null)
b8e9ab1: IDEA-119406 IDEA make corrupts files when performing Maven resource filtering (cherry picked from commit 5b6b3f6) +review CR-IC
d3dd646: EA-53308 - CCE: DfaVariableValue.<init> (cherry picked from commit 32a579d)
10f83e0: external build for artifacts: added API to filter contents of directory extracted from jar file [rev by Michael Golubev]
b7f4af0: make nonDefaultProject="true" really work
0bebc13: cosmetics
94e0a24: Merge remote-tracking branch 'origin/133' into 133
85cae29: IDEA-119347 ../jre64 JDK not being picked up by idea64.exe
2dd77af: IDEA-117127 Editor: Throwable on Select word at caret inside plain text (cherry picked from commit 2e3a0d8)
0a5e3ad: IDEA-117555 Search everywhere dialog is being closed immediately (cherry picked from commit ba8037d)
520da57: fix getDisplayName nullability assertion
0663734: IDEA-111122 remove attached jar artifact coming from "apklib" dependency from the dependencies of app module: users add it to deploy jar to Maven repository in addition to "apklib" file, but we don't need to add it to the classpath, because it leads to class duplication [rev=sergey.evdokimov]
c1fb468: IDEA-79522 need ability to set display names for xml attribute and xml tag language injections
3ae70b9: IDEA-119163 "Language Injections" settings should use toolbar decorator in the same way as other
50c78e9: IDEA-117327 Add a setting to switch off autopopup completion item selection by Enter (cherry picked from commit 84ddafc)
ae5ce9b: groovy debugging agent that produces less garbage (cherry picked from commit c7af9fe)
f6682f7: Roll-back FileChooserDescriptor API change.
1c64249: Merge remote-tracking branch 'origin/133' into 133
b293f8c: SearchEverywhere doesn't work on Linux
07b98c1: IDEA-74428 Ability to turn on log debug categories from the GUI
4257f6f: CR-IU-511 make abstract class abstract & leave getPresentableText mandatory
7cac7b7: allow to turn off suggestion to create a file when creating a directory with file-like name (IDEA-118250) (cherry picked from commit 5d81e8d)
acb9db2: don't show parameter info for invisible editors (EA-53161 - NPE: ParameterInfoComponent.<init>) (cherry picked from commit fb24d98)
e6bfbbf: the users don't care if we're preparing editors to open (IDEA-115130) (cherry picked from commit 9a116de)
3f1ebf3: rethrow PCE from KeyedExtensionFactory reflection (cherry picked from commit df8967b)
Change-Id: I8083d21f3faff4f899c53a5dea2710713dc1a2a9
Diffstat (limited to 'plugins')
81 files changed, 2021 insertions, 765 deletions
diff --git a/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/inject/config/ui/MethodParameterPanel.form b/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/inject/config/ui/MethodParameterPanel.form index b77dd37c29d0..62fdc0efa396 100644 --- a/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/inject/config/ui/MethodParameterPanel.form +++ b/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/inject/config/ui/MethodParameterPanel.form @@ -1,9 +1,9 @@ <?xml version="1.0" encoding="UTF-8"?> <form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="org.intellij.plugins.intelliLang.inject.config.ui.MethodParameterPanel"> - <grid id="27dc6" binding="myRoot" layout-manager="GridLayoutManager" row-count="4" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> + <grid id="27dc6" binding="myRoot" layout-manager="GridLayoutManager" row-count="3" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> <margin top="0" left="0" bottom="0" right="0"/> <constraints> - <xy x="20" y="20" width="500" height="400"/> + <xy x="20" y="20" width="500" height="697"/> </constraints> <properties/> <border type="none"/> @@ -13,16 +13,16 @@ <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="7" anchor="0" fill="1" indent="0" use-parent-layout="false"/> </constraints> </nested-form> - <grid id="84778" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> + <grid id="84778" layout-manager="GridLayoutManager" row-count="2" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="0" vgap="0"> <margin top="0" left="0" bottom="0" right="0"/> <constraints> <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/> </constraints> <properties/> <clientProperties> - <BorderFactoryClass class="java.lang.String" value="com.intellij.ui.IdeBorderFactory$PlainSmallWithIndent"/> + <BorderFactoryClass class="java.lang.String" value="com.intellij.ui.IdeBorderFactory$PlainSmallWithoutIndent"/> </clientProperties> - <border type="none" title="Class-Name"/> + <border type="none" title="Class Methods"/> <children> <grid id="5081f" binding="myClassPanel" layout-manager="BorderLayout" hgap="0" vgap="0"> <constraints> @@ -32,22 +32,9 @@ <border type="none"/> <children/> </grid> - </children> - </grid> - <grid id="b75a2" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> - <margin top="0" left="0" bottom="0" right="0"/> - <constraints> - <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/> - </constraints> - <properties/> - <clientProperties> - <BorderFactoryClass class="java.lang.String" value="com.intellij.ui.IdeBorderFactory$PlainSmallWithoutIndent"/> - </clientProperties> - <border type="none" title="Parameters"/> - <children> <scrollpane id="5dfaa" class="com.intellij.ui.components.JBScrollPane"> <constraints> - <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="7" hsize-policy="7" anchor="0" fill="3" indent="0" use-parent-layout="false"/> + <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="7" hsize-policy="7" anchor="0" fill="3" indent="0" use-parent-layout="false"/> </constraints> <properties/> <border type="none"/> @@ -62,7 +49,7 @@ </grid> <nested-form id="b6e0b" form-file="org/intellij/plugins/intelliLang/inject/config/ui/AdvancedPanel.form" binding="myAdvancedPanel" custom-create="true"> <constraints> - <grid row="3" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="7" anchor="0" fill="1" indent="0" use-parent-layout="false"/> + <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="7" anchor="0" fill="1" indent="0" use-parent-layout="false"/> </constraints> </nested-form> </children> diff --git a/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/inject/config/ui/MethodParameterPanel.java b/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/inject/config/ui/MethodParameterPanel.java index 36da2a930603..0c1cf6408c26 100644 --- a/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/inject/config/ui/MethodParameterPanel.java +++ b/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/inject/config/ui/MethodParameterPanel.java @@ -28,6 +28,7 @@ import com.intellij.openapi.util.Condition; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.PsiFormatUtil; +import com.intellij.psi.util.PsiFormatUtilBase; import com.intellij.ui.*; import com.intellij.ui.dualView.TreeTableView; import com.intellij.ui.treeStructure.treetable.ListTreeTableModelOnColumns; @@ -42,6 +43,7 @@ import gnu.trove.THashMap; import gnu.trove.THashSet; import org.intellij.plugins.intelliLang.inject.config.MethodParameterInjection; import org.intellij.plugins.intelliLang.util.PsiUtilEx; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; @@ -91,23 +93,23 @@ public class MethodParameterPanel extends AbstractInjectionPanel<MethodParameter myParamsTable.getTree().setShowsRootHandles(true); myParamsTable.getTree().setCellRenderer(new ColoredTreeCellRenderer() { - public void customizeCellRenderer(final JTree tree, - final Object value, - final boolean selected, - final boolean expanded, - final boolean leaf, - final int row, - final boolean hasFocus) { + public void customizeCellRenderer(@NotNull JTree tree, + Object value, + boolean selected, + boolean expanded, + boolean leaf, + int row, + boolean hasFocus) { final Object o = ((DefaultMutableTreeNode)value).getUserObject(); setIcon(o instanceof PsiMethod ? PlatformIcons.METHOD_ICON : o instanceof PsiParameter ? PlatformIcons.PARAMETER_ICON : null); final String name; if (o instanceof PsiMethod) { - name = PsiFormatUtil.formatMethod((PsiMethod)o, PsiSubstitutor.EMPTY, PsiFormatUtil.SHOW_NAME | PsiFormatUtil.SHOW_PARAMETERS, - PsiFormatUtil.SHOW_NAME | PsiFormatUtil.SHOW_TYPE); + name = PsiFormatUtil.formatMethod((PsiMethod)o, PsiSubstitutor.EMPTY, PsiFormatUtilBase.SHOW_NAME | PsiFormatUtilBase.SHOW_PARAMETERS, + PsiFormatUtilBase.SHOW_NAME | PsiFormatUtilBase.SHOW_TYPE); } else if (o instanceof PsiParameter) { - name = PsiFormatUtil.formatVariable((PsiParameter)o, PsiFormatUtil.SHOW_NAME | PsiFormatUtil.SHOW_TYPE, PsiSubstitutor.EMPTY); + name = PsiFormatUtil.formatVariable((PsiParameter)o, PsiFormatUtilBase.SHOW_NAME | PsiFormatUtilBase.SHOW_TYPE, PsiSubstitutor.EMPTY); } else name = null; final boolean missing = o instanceof PsiElement && !((PsiElement)o).isPhysical(); @@ -362,7 +364,7 @@ public class MethodParameterPanel extends AbstractInjectionPanel<MethodParameter return valueOf(o) != null; } - }, new TreeColumnInfo("Method/Parameters") + }, new TreeColumnInfo(" ") }; } @@ -386,7 +388,7 @@ public class MethodParameterPanel extends AbstractInjectionPanel<MethodParameter } } - private class MyView extends TreeTableView implements TypeSafeDataProvider { + private static class MyView extends TreeTableView implements TypeSafeDataProvider { public MyView(ListTreeTableModelOnColumns treeTableModel) { super(treeTableModel); } diff --git a/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/inject/config/ui/configurables/MethodParameterInjectionConfigurable.java b/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/inject/config/ui/configurables/MethodParameterInjectionConfigurable.java deleted file mode 100644 index 1b14fc204eca..000000000000 --- a/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/inject/config/ui/configurables/MethodParameterInjectionConfigurable.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2006 Sascha Weinreuter - * - * 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 org.intellij.plugins.intelliLang.inject.config.ui.configurables; - -import com.intellij.openapi.project.Project; -import org.intellij.plugins.intelliLang.inject.config.MethodParameterInjection; -import org.intellij.plugins.intelliLang.inject.config.ui.MethodParameterPanel; - -public class MethodParameterInjectionConfigurable extends InjectionConfigurable<MethodParameterInjection, MethodParameterPanel> { - public MethodParameterInjectionConfigurable(MethodParameterInjection injection, Runnable treeUpdater, Project project) { - super(injection, treeUpdater, project); - } - - protected MethodParameterPanel createOptionsPanelImpl() { - return new MethodParameterPanel(myInjection, myProject); - } - - public String getBannerSlogan() { - return "Edit Method Parameter Injection"; - } -} diff --git a/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/inject/java/JavaLanguageInjectionSupport.java b/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/inject/java/JavaLanguageInjectionSupport.java index 99a3ccd21eab..14c7535f8044 100644 --- a/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/inject/java/JavaLanguageInjectionSupport.java +++ b/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/inject/java/JavaLanguageInjectionSupport.java @@ -55,7 +55,6 @@ import org.intellij.plugins.intelliLang.inject.config.InjectionPlace; import org.intellij.plugins.intelliLang.inject.config.MethodParameterInjection; import org.intellij.plugins.intelliLang.inject.config.ui.AbstractInjectionPanel; import org.intellij.plugins.intelliLang.inject.config.ui.MethodParameterPanel; -import org.intellij.plugins.intelliLang.inject.config.ui.configurables.MethodParameterInjectionConfigurable; import org.intellij.plugins.intelliLang.util.ContextComputationProcessor; import org.intellij.plugins.intelliLang.util.PsiUtilEx; import org.jdom.Element; @@ -175,10 +174,7 @@ public class JavaLanguageInjectionSupport extends AbstractLanguageInjectionSuppo } public BaseInjection createInjection(final Element element) { - if (element.getName().equals(MethodParameterInjection.class.getSimpleName())) { - return new MethodParameterInjection(); - } - else return new BaseInjection(JAVA_SUPPORT_ID); + return new BaseInjection(JAVA_SUPPORT_ID); } private static boolean doInjectInJava(final Project project, @@ -371,16 +367,21 @@ public class JavaLanguageInjectionSupport extends AbstractLanguageInjectionSuppo originalCopy.setPlaceEnabled(currentPlace.getText(), true); methodParameterInjection = createFrom(project, originalCopy, contextMethod, false); } - if (InjectLanguageAction.doEditConfigurable(project, new MethodParameterInjectionConfigurable(methodParameterInjection, null, project))) { - final BaseInjection newInjection = new BaseInjection(methodParameterInjection.getSupportId()).copyFrom(methodParameterInjection); - if (originalInjection != null) { - newInjection.mergeOriginalPlacesFrom(originalInjection, true); - } - configuration.replaceInjectionsWithUndo( - project, Collections.singletonList(newInjection), - ContainerUtil.createMaybeSingletonList(originalInjection), - Collections.<PsiElement>emptyList()); + mergePlacesAndAddToConfiguration(project, configuration, methodParameterInjection, originalInjection); + } + + private static void mergePlacesAndAddToConfiguration(@NotNull Project project, + @NotNull Configuration configuration, + @NotNull MethodParameterInjection injection, + @Nullable BaseInjection originalInjection) { + BaseInjection newInjection = new BaseInjection(injection.getSupportId()).copyFrom(injection); + if (originalInjection != null) { + newInjection.mergeOriginalPlacesFrom(originalInjection, true); } + configuration.replaceInjectionsWithUndo( + project, Collections.singletonList(newInjection), + ContainerUtil.createMaybeSingletonList(originalInjection), + Collections.<PsiElement>emptyList()); } private static void collectInjections(PsiLiteralExpression host, diff --git a/plugins/IntelliLang/src/META-INF/plugin.xml b/plugins/IntelliLang/src/META-INF/plugin.xml index 8dad5cb4e41a..975422e0fdfc 100644 --- a/plugins/IntelliLang/src/META-INF/plugin.xml +++ b/plugins/IntelliLang/src/META-INF/plugin.xml @@ -36,7 +36,7 @@ <highlightErrorFilter implementation="org.intellij.plugins.intelliLang.inject.FrankensteinErrorFilter"/> <daemon.highlightInfoFilter implementation="org.intellij.plugins.intelliLang.inject.FrankensteinErrorFilter"/> - <projectConfigurable instance="org.intellij.plugins.intelliLang.InjectionsSettingsUI" nonDefaultProject="true"/> + <projectConfigurable displayName="Language Injections" instance="org.intellij.plugins.intelliLang.InjectionsSettingsUI" nonDefaultProject="true"/> <multiHostInjector implementation="org.intellij.plugins.intelliLang.inject.CommentLanguageInjector"/> <multiHostInjector implementation="org.intellij.plugins.intelliLang.inject.TemporaryPlacesInjector"/> diff --git a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/InjectionsSettingsUI.java b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/InjectionsSettingsUI.java index 414500ba2096..a0420939dfdc 100644 --- a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/InjectionsSettingsUI.java +++ b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/InjectionsSettingsUI.java @@ -30,6 +30,7 @@ import com.intellij.openapi.fileTypes.FileTypes; import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.openapi.options.Configurable; import com.intellij.openapi.options.SearchableConfigurable; +import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.ui.SplitterProportionsData; @@ -47,7 +48,6 @@ import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.Convertor; import com.intellij.util.ui.ColumnInfo; import com.intellij.util.ui.ListTableModel; -import gnu.trove.THashMap; import gnu.trove.THashSet; import gnu.trove.TObjectHashingStrategy; import org.intellij.plugins.intelliLang.inject.AbstractLanguageInjectionSupport; @@ -81,19 +81,14 @@ public class InjectionsSettingsUI implements SearchableConfigurable.Parent, Conf private final JPanel myRoot; private final InjectionsTable myInjectionsTable; - private final Map<String, LanguageInjectionSupport> mySupports = new THashMap<String, LanguageInjectionSupport>(); - private final Map<String, AnAction> myEditActions = new THashMap<String, AnAction>(); - private final List<AnAction> myAddActions = new ArrayList<AnAction>(); - private final ActionToolbar myToolbar; + private final Map<String, LanguageInjectionSupport> mySupports = ContainerUtil.newLinkedHashMap(); + private final Map<String, AnAction> myEditActions = ContainerUtil.newLinkedHashMap(); + private final List<AnAction> myAddActions = ContainerUtil.newArrayList(); private final JLabel myCountLabel; private Configurable[] myConfigurables; private Configuration myConfiguration; - public InjectionsSettingsUI(final Project project) { - this(project, Configuration.getProjectInstance(project)); - } - public InjectionsSettingsUI(final Project project, final Configuration configuration) { myProject = project; myConfiguration = configuration; @@ -107,16 +102,12 @@ public class InjectionsSettingsUI implements SearchableConfigurable.Parent, Conf myInjectionsTable = new InjectionsTable(getInjInfoList(myInfos)); myInjectionsTable.getEmptyText().setText("No injections configured"); - final JPanel tablePanel = new JPanel(new BorderLayout()); - - tablePanel.add(ScrollPaneFactory.createScrollPane(myInjectionsTable), BorderLayout.CENTER); - final DefaultActionGroup group = createActions(); + ToolbarDecorator decorator = ToolbarDecorator.createDecorator(myInjectionsTable); + createActions(decorator); - myToolbar = ActionManager.getInstance().createActionToolbar(ActionPlaces.UNKNOWN, group, true); - myToolbar.setTargetComponent(myInjectionsTable); - myRoot.add(myToolbar.getComponent(), BorderLayout.NORTH); - myRoot.add(tablePanel, BorderLayout.CENTER); + //myRoot.add(new TitledSeparator("Languages injection places"), BorderLayout.NORTH); + myRoot.add(decorator.createPanel(), BorderLayout.CENTER); myCountLabel = new JLabel(); myCountLabel.setHorizontalAlignment(SwingConstants.RIGHT); myCountLabel.setForeground(SimpleTextAttributes.GRAY_ITALIC_ATTRIBUTES.getFgColor()); @@ -124,7 +115,7 @@ public class InjectionsSettingsUI implements SearchableConfigurable.Parent, Conf updateCountLabel(); } - private DefaultActionGroup createActions() { + private void createActions(ToolbarDecorator decorator) { final Consumer<BaseInjection> consumer = new Consumer<BaseInjection>() { public void consume(final BaseInjection injection) { addInjection(injection); @@ -148,22 +139,22 @@ public class InjectionsSettingsUI implements SearchableConfigurable.Parent, Conf return Comparing.compare(o1.getTemplatePresentation().getText(), o2.getTemplatePresentation().getText()); } }); - - final DefaultActionGroup group = new DefaultActionGroup(); - final AnAction addAction = new AnAction("Add", "Add", IconUtil.getAddIcon()) { + decorator.disableUpDownActions(); + decorator.setAddActionUpdater(new AnActionButtonUpdater() { @Override - public void update(final AnActionEvent e) { - e.getPresentation().setEnabled(!myAddActions.isEmpty()); + public boolean isEnabled(AnActionEvent e) { + return !myAddActions.isEmpty(); } - + }); + decorator.setAddAction(new AnActionButtonRunnable() { @Override - public void actionPerformed(final AnActionEvent e) { - performAdd(e); + public void run(AnActionButton button) { + performAdd(button); } - }; - final AnAction removeAction = new AnAction("Remove", "Remove", PlatformIcons.DELETE_ICON) { + }); + decorator.setRemoveActionUpdater(new AnActionButtonUpdater() { @Override - public void update(final AnActionEvent e) { + public boolean isEnabled(AnActionEvent e) { boolean enabled = false; for (InjInfo info : getSelectedInjections()) { if (!info.bundled) { @@ -171,69 +162,63 @@ public class InjectionsSettingsUI implements SearchableConfigurable.Parent, Conf break; } } - e.getPresentation().setEnabled(enabled); + return enabled; } - + }); + decorator.setRemoveAction(new AnActionButtonRunnable() { @Override - public void actionPerformed(final AnActionEvent e) { + public void run(AnActionButton button) { performRemove(); } - }; + }); - final AnAction editAction = new AnAction("Edit", "Edit", PlatformIcons.PROPERTIES_ICON) { + decorator.setEditActionUpdater(new AnActionButtonUpdater() { @Override - public void update(final AnActionEvent e) { - final AnAction action = getEditAction(); - e.getPresentation().setEnabled(action != null); - if (action != null) action.update(e); + public boolean isEnabled(AnActionEvent e) { + AnAction edit = getEditAction(); + if (edit != null) edit.update(e); + return edit != null && edit.getTemplatePresentation().isEnabled(); } - + }); + decorator.setEditAction(new AnActionButtonRunnable() { @Override - public void actionPerformed(final AnActionEvent e) { - performEditAction(e); + public void run(AnActionButton button) { + performEditAction(); } - }; - final AnAction copyAction = new AnAction("Duplicate", "Duplicate", PlatformIcons.COPY_ICON) { + }); + decorator.addExtraAction(new DumbAwareActionButton("Duplicate", "Duplicate", PlatformIcons.COPY_ICON) { + @Override - public void update(final AnActionEvent e) { - final AnAction action = getEditAction(); - e.getPresentation().setEnabled(action != null); - if (action != null) action.update(e); + public boolean isEnabled() { + return getEditAction() != null; } @Override - public void actionPerformed(final AnActionEvent e) { + public void actionPerformed(AnActionEvent e) { final InjInfo injection = getSelectedInjection(); if (injection != null) { addInjection(injection.injection.copy()); //performEditAction(e); } } - }; - group.add(addAction); - group.add(removeAction); - group.add(copyAction); - group.add(editAction); + }); - addAction.registerCustomShortcutSet(CommonShortcuts.INSERT, myInjectionsTable); - removeAction.registerCustomShortcutSet(CommonShortcuts.DELETE, myInjectionsTable); - editAction.registerCustomShortcutSet(CommonShortcuts.ENTER, myInjectionsTable); + decorator.addExtraAction(new DumbAwareActionButton("Enable Selected Injections", "Enable Selected Injections", PlatformIcons.SELECT_ALL_ICON) { - group.addSeparator(); - group.add(new AnAction("Enable Selected Injections", "Enable Selected Injections", PlatformIcons.SELECT_ALL_ICON) { @Override public void actionPerformed(final AnActionEvent e) { performSelectedInjectionsEnabled(true); } }); - group.add(new AnAction("Disable Selected Injections", "Disable Selected Injections", PlatformIcons.UNSELECT_ALL_ICON) { - @Override - public void actionPerformed(final AnActionEvent e) { - performSelectedInjectionsEnabled(false); - } - }); + decorator.addExtraAction(new DumbAwareActionButton("Disable Selected Injections", "Disable Selected Injections", PlatformIcons.UNSELECT_ALL_ICON) { - new AnAction("Toggle") { + @Override + public void actionPerformed(final AnActionEvent e) { + performSelectedInjectionsEnabled(false); + } + }); + + new DumbAwareAction("Toggle") { @Override public void update(AnActionEvent e) { SpeedSearchSupply supply = SpeedSearchSupply.getSupply(myInjectionsTable); @@ -247,8 +232,18 @@ public class InjectionsSettingsUI implements SearchableConfigurable.Parent, Conf }.registerCustomShortcutSet(new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0)), myInjectionsTable); if (myInfos.length > 1) { - group.addSeparator(); - final AnAction shareAction = new AnAction("Make Global", null, PlatformIcons.IMPORT_ICON) { + AnActionButton shareAction = new DumbAwareActionButton("Make Global", null, PlatformIcons.IMPORT_ICON) { + { + addCustomUpdater(new AnActionButtonUpdater() { + @Override + public boolean isEnabled(AnActionEvent e) { + CfgInfo cfg = getTargetCfgInfo(getSelectedInjections()); + e.getPresentation().setText(cfg == getDefaultCfgInfo() ? "Make Global" : "Move to Project"); + return cfg != null; + } + }); + } + @Override public void actionPerformed(final AnActionEvent e) { final List<InjInfo> injections = getSelectedInjections(); @@ -265,14 +260,6 @@ public class InjectionsSettingsUI implements SearchableConfigurable.Parent, Conf TableUtil.selectRows(myInjectionsTable, selectedRows); } - @Override - public void update(final AnActionEvent e) { - final CfgInfo cfg = getTargetCfgInfo(getSelectedInjections()); - e.getPresentation().setEnabled(cfg != null); - e.getPresentation().setText(cfg == getDefaultCfgInfo() ? "Make Global" : "Move to Project"); - super.update(e); - } - @Nullable private CfgInfo getTargetCfgInfo(final List<InjInfo> injections) { CfgInfo cfg = null; @@ -283,25 +270,26 @@ public class InjectionsSettingsUI implements SearchableConfigurable.Parent, Conf if (cfg == null) cfg = info.cfgInfo; else if (cfg != info.cfgInfo) return info.cfgInfo; } - if (cfg == null) return cfg; + if (cfg == null) return null; for (CfgInfo info : myInfos) { if (info != cfg) return info; } throw new AssertionError(); } }; - shareAction.registerCustomShortcutSet(new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, InputEvent.SHIFT_DOWN_MASK)), myInjectionsTable); - group.add(shareAction); + shareAction.setShortcut(new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, InputEvent.SHIFT_DOWN_MASK))); + decorator.addExtraAction(shareAction); } - group.addSeparator(); - group.add(new AnAction("Import", "Import", AllIcons.Actions.Install) { + decorator.addExtraAction(new DumbAwareActionButton("Import", "Import", AllIcons.Actions.Install) { + @Override public void actionPerformed(final AnActionEvent e) { doImportAction(e.getDataContext()); updateCountLabel(); } }); - group.add(new AnAction("Export", "Export", AllIcons.Actions.Export) { + decorator.addExtraAction(new DumbAwareActionButton("Export", "Export", AllIcons.Actions.Export) { + @Override public void actionPerformed(final AnActionEvent e) { final List<BaseInjection> injections = getInjectionList(getSelectedInjections()); @@ -321,20 +309,19 @@ public class InjectionsSettingsUI implements SearchableConfigurable.Parent, Conf } @Override - public void update(final AnActionEvent e) { - e.getPresentation().setEnabled(!getSelectedInjections().isEmpty()); + public boolean isEnabled() { + return !getSelectedInjections().isEmpty(); } }); - - return group; } - private void performEditAction(AnActionEvent e) { + private void performEditAction() { final AnAction action = getEditAction(); if (action != null) { final int row = myInjectionsTable.getSelectedRow(); - action.actionPerformed(e); + action.actionPerformed(new AnActionEvent(null, DataManager.getInstance().getDataContext(myInjectionsTable), + ActionPlaces.UNKNOWN, new Presentation(""), ActionManager.getInstance(), 0)); myInjectionsTable.getListTableModel().fireTableDataChanged(); myInjectionsTable.getSelectionModel().setSelectionInterval(row, row); updateCountLabel(); @@ -352,10 +339,8 @@ public class InjectionsSettingsUI implements SearchableConfigurable.Parent, Conf if (place.isEnabled()) enablePlacesCount++; } } - final StringBuilder sb = new StringBuilder(); - sb.append(items.size()).append(" injection").append(items.size() > 1 ? "s" : "").append(" (").append(enablePlacesCount) - .append(" of ").append(placesCount).append(" place").append(placesCount > 1 ? "s" : "").append(" enabled) "); - myCountLabel.setText(sb.toString()); + myCountLabel.setText(items.size() + " injection" + (items.size() > 1 ? "s" : "") + " (" + enablePlacesCount + " of " + + placesCount + " place" + (placesCount > 1 ? "s" : "") + " enabled) "); } else { myCountLabel.setText("no injections configured "); @@ -511,17 +496,14 @@ public class InjectionsSettingsUI implements SearchableConfigurable.Parent, Conf return row < 0? null : myInjectionsTable.getItems().get(myInjectionsTable.convertRowIndexToModel(row)); } - private void performAdd(final AnActionEvent e) { - final DefaultActionGroup group = new DefaultActionGroup(); - for (AnAction action : myAddActions) { - group.add(action); - } + private void performAdd(AnActionButton e) { + DefaultActionGroup group = new DefaultActionGroup(myAddActions); JBPopupFactory.getInstance().createActionGroupPopup(null, group, e.getDataContext(), JBPopupFactory.ActionSelectionAid.NUMBERING, true, new Runnable() { public void run() { updateCountLabel(); } - }, -1).showUnderneathOf(myToolbar.getComponent()); + }, -1).show(e.getPreferredPopupPoint()); } @Nls @@ -552,8 +534,7 @@ public class InjectionsSettingsUI implements SearchableConfigurable.Parent, Conf if (row < 0) return false; if (columnAtPoint(e.getPoint()) <= 0) return false; myInjectionsTable.getSelectionModel().setSelectionInterval(row, row); - performEditAction(new AnActionEvent(e, DataManager.getInstance().getDataContext(InjectionsTable.this), - ActionPlaces.UNKNOWN, new Presentation(""), ActionManager.getInstance(), 0)); + performEditAction(); return true; } }.installOn(this); @@ -632,7 +613,7 @@ public class InjectionsSettingsUI implements SearchableConfigurable.Parent, Conf public TableCellRenderer getRenderer(final InjInfo injection) { return booleanCellRenderer; } - }, new ColumnInfo<InjInfo, InjInfo>("Display Name") { + }, new ColumnInfo<InjInfo, InjInfo>("Name") { @Override public InjInfo valueOf(final InjInfo info) { return info; diff --git a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/AbstractLanguageInjectionSupport.java b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/AbstractLanguageInjectionSupport.java index a18a26b529af..132393737525 100644 --- a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/AbstractLanguageInjectionSupport.java +++ b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/AbstractLanguageInjectionSupport.java @@ -114,12 +114,13 @@ public abstract class AbstractLanguageInjectionSupport extends LanguageInjection public static AnAction createDefaultAddAction(final Project project, final Consumer<BaseInjection> consumer, final AbstractLanguageInjectionSupport support) { + final String supportTitle = StringUtil.capitalize(support.getId()); Icon icon = FileTypeManager.getInstance().getFileTypeByExtension(support.getId()).getIcon(); - return new AnAction("Generic "+ StringUtil.capitalize(support.getId()), null, icon) { + return new AnAction("Generic "+ supportTitle, null, icon) { @Override public void actionPerformed(AnActionEvent e) { final BaseInjection injection = new BaseInjection(support.getId()); - injection.setDisplayName("New "+ StringUtil.capitalize(support.getId())+" Injection"); + injection.setDisplayName("New "+ supportTitle +" Injection"); final BaseInjection newInjection = showDefaultInjectionUI(project, injection); if (newInjection != null) { consumer.consume(injection); @@ -134,7 +135,7 @@ public abstract class AbstractLanguageInjectionSupport extends LanguageInjection panel.reset(); final DialogBuilder builder = new DialogBuilder(project); LanguageInjectionSupport support = InjectorUtils.findInjectionSupport(injection.getSupportId()); - if (support != null && support instanceof AbstractLanguageInjectionSupport) { + if (support instanceof AbstractLanguageInjectionSupport) { builder.setHelpId(((AbstractLanguageInjectionSupport)support).getHelpId()); } builder.addOkAction(); diff --git a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/InjectLanguageAction.java b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/InjectLanguageAction.java index 18f4c0147b12..b03a07de7233 100644 --- a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/InjectLanguageAction.java +++ b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/InjectLanguageAction.java @@ -28,7 +28,6 @@ import com.intellij.openapi.actionSystem.IdeActions; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.keymap.KeymapUtil; -import com.intellij.openapi.options.Configurable; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.popup.JBPopup; import com.intellij.openapi.ui.popup.PopupChooserBuilder; @@ -221,7 +220,4 @@ public class InjectLanguageAction implements IntentionAction { return false; } - public static boolean doEditConfigurable(final Project project, final Configurable configurable) { - return true; //ShowSettingsUtil.getInstance().editConfigurable(project, configurable); - } } diff --git a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/config/BaseInjection.java b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/config/BaseInjection.java index ffd54be5bd67..f5fddc277c04 100644 --- a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/config/BaseInjection.java +++ b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/config/BaseInjection.java @@ -56,7 +56,8 @@ public class BaseInjection implements Injection, PersistentStateComponent<Elemen public static final Key<BaseInjection> INJECTION_KEY = Key.create("INJECTION_KEY"); @NotNull private final String mySupportId; - private String myDisplayName; + + private String myDisplayName = ""; private String myInjectedLanguageId = ""; private String myPrefix = ""; @@ -98,7 +99,7 @@ public class BaseInjection implements Injection, PersistentStateComponent<Elemen return myDisplayName; } - public void setDisplayName(String displayName) { + public void setDisplayName(@NotNull String displayName) { myDisplayName = displayName; } diff --git a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/config/ui/AbstractInjectionPanel.java b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/config/ui/AbstractInjectionPanel.java index 2626d4f433ed..9b6fc83533fa 100644 --- a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/config/ui/AbstractInjectionPanel.java +++ b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/config/ui/AbstractInjectionPanel.java @@ -15,8 +15,6 @@ */ package org.intellij.plugins.intelliLang.inject.config.ui; -import com.intellij.openapi.editor.event.DocumentAdapter; -import com.intellij.openapi.editor.event.DocumentEvent; import com.intellij.openapi.project.Project; import com.intellij.util.ui.UIUtil; import org.intellij.plugins.intelliLang.inject.config.BaseInjection; @@ -73,7 +71,6 @@ public abstract class AbstractInjectionPanel<T extends BaseInjection> implements final InjectionPanel p = getField(panel); p.init(copy); } - reset(); } public final boolean isModified() { @@ -89,23 +86,28 @@ public abstract class AbstractInjectionPanel<T extends BaseInjection> implements @SuppressWarnings({"unchecked"}) public final void apply() { - apply(myOrigInjection); - for (Field panel : myOtherPanels) { getField(panel).apply(); } - myOrigInjection.generatePlaces(); - myEditCopy.copyFrom(myOrigInjection); + + // auto-generated name should go last + apply(myOrigInjection); + if (!myOtherPanels.isEmpty()) { + myOrigInjection.generatePlaces(); + myEditCopy.copyFrom(myOrigInjection); + } } protected abstract void apply(T other); @SuppressWarnings({"unchecked"}) public final void reset() { + if (!myOtherPanels.isEmpty()) { + myEditCopy.copyFrom(myOrigInjection); + } for (Field panel : myOtherPanels) { getField(panel).reset(); } - myEditCopy.copyFrom(myOrigInjection); UIUtil.invokeAndWaitIfNeeded(new Runnable() { public void run() { resetImpl(); @@ -138,10 +140,4 @@ public abstract class AbstractInjectionPanel<T extends BaseInjection> implements updater.run(); } } - - protected class TreeUpdateListener extends DocumentAdapter { - public void documentChanged(DocumentEvent e) { - updateTree(); - } - } } diff --git a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/config/ui/AdvancedPanel.form b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/config/ui/AdvancedPanel.form index a45bfaff44cc..0ac5d480dd01 100644 --- a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/config/ui/AdvancedPanel.form +++ b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/config/ui/AdvancedPanel.form @@ -26,7 +26,7 @@ </constraints> <properties> <labelFor value="7bf4e"/> - <text value="&Value Pattern:"/> + <text value="&Value pattern:"/> <toolTipText value="<html>Enter a regular expression that selects the parts of the tag's or attribute's value the language should be injected into.<br>The pattern should contain exactly one capturing group.</html>"/> </properties> </component> @@ -43,7 +43,7 @@ <grid row="0" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/> </constraints> <properties> - <text value="&Single File"/> + <text value="&Single file"/> </properties> </component> </children> diff --git a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/config/ui/BaseInjectionPanel.form b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/config/ui/BaseInjectionPanel.form index 0c9523fbb1ea..79dafacd8fa8 100644 --- a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/config/ui/BaseInjectionPanel.form +++ b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/config/ui/BaseInjectionPanel.form @@ -21,7 +21,7 @@ <clientProperties> <BorderFactoryClass class="java.lang.String" value="com.intellij.ui.IdeBorderFactory$PlainSmallWithoutIndent"/> </clientProperties> - <border type="none" title="Places Pattern"/> + <border type="none" title="Places Patterns"/> <children/> </grid> <nested-form id="b6e0b" form-file="org/intellij/plugins/intelliLang/inject/config/ui/AdvancedPanel.form" binding="myAdvancedPanel" custom-create="true"> @@ -43,7 +43,7 @@ </constraints> <properties> <labelFor value="5916a"/> - <text value="Display &Name:"/> + <text value="&Name:"/> </properties> </component> <component id="5916a" class="javax.swing.JTextField" binding="myNameTextField"> diff --git a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/config/ui/LanguagePanel.form b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/config/ui/LanguagePanel.form index 1f582bb85f03..e8e087e03189 100644 --- a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/config/ui/LanguagePanel.form +++ b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/config/ui/LanguagePanel.form @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="org.intellij.plugins.intelliLang.inject.config.ui.LanguagePanel"> - <grid id="27dc6" binding="myRoot" layout-manager="GridLayoutManager" row-count="3" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> + <grid id="27dc6" binding="myRoot" layout-manager="GridLayoutManager" row-count="3" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> <margin top="0" left="0" bottom="0" right="0"/> <constraints> <xy x="20" y="20" width="493" height="143"/> @@ -44,20 +44,15 @@ </constraints> <properties/> </component> - <hspacer id="7c4e8"> - <constraints> - <grid row="0" column="2" row-span="1" col-span="1" vsize-policy="1" hsize-policy="7" anchor="0" fill="1" indent="0" use-parent-layout="false"/> - </constraints> - </hspacer> <component id="96508" class="com.intellij.ui.EditorTextField" binding="myPrefix"> <constraints> - <grid row="1" column="1" row-span="1" col-span="2" vsize-policy="0" hsize-policy="7" anchor="0" fill="1" indent="0" use-parent-layout="false"/> + <grid row="1" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="7" anchor="0" fill="1" indent="0" use-parent-layout="false"/> </constraints> <properties/> </component> <component id="dcdf7" class="com.intellij.ui.EditorTextField" binding="mySuffix"> <constraints> - <grid row="2" column="1" row-span="1" col-span="2" vsize-policy="0" hsize-policy="7" anchor="0" fill="1" indent="0" use-parent-layout="false"/> + <grid row="2" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="7" anchor="0" fill="1" indent="0" use-parent-layout="false"/> </constraints> <properties/> </component> diff --git a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/config/ui/configurables/InjectionConfigurable.java b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/config/ui/configurables/InjectionConfigurable.java deleted file mode 100644 index b09de2e4c915..000000000000 --- a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/config/ui/configurables/InjectionConfigurable.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2006 Sascha Weinreuter - * - * 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 org.intellij.plugins.intelliLang.inject.config.ui.configurables; - -import com.intellij.openapi.options.ConfigurationException; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.NamedConfigurable; -import org.intellij.plugins.intelliLang.inject.config.Injection; -import org.intellij.plugins.intelliLang.inject.config.ui.InjectionPanel; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.Nullable; - -import javax.swing.*; - -public abstract class InjectionConfigurable<T extends Injection, P extends InjectionPanel<T>> extends NamedConfigurable<T> { - private final Runnable myTreeUpdater; - protected final T myInjection; - protected final Project myProject; - private P myPanel; - - public InjectionConfigurable(T injection, Runnable treeUpdater, Project project) { - myProject = project; - myInjection = injection; - myTreeUpdater = treeUpdater; - } - - public void setDisplayName(String name) { - } - - public T getEditableObject() { - return myInjection; - } - - @Nullable - @NonNls - public String getHelpTopic() { - return null; - } - - public JComponent createOptionsPanel() { - myPanel = createOptionsPanelImpl(); - myPanel.addUpdater(myTreeUpdater); - return myPanel.getComponent(); - } - - protected abstract P createOptionsPanelImpl(); - - public P getPanel() { - return myPanel; - } - - public boolean isModified() { - return myPanel.isModified(); - } - - public void apply() throws ConfigurationException { - myPanel.apply(); - } - - public void reset() { - myPanel.reset(); - } - - public void disposeUIResources() { - myPanel = null; - } - - public String getDisplayName() { - final P p = getPanel(); - return p != null ? p.getInjection().getDisplayName() : myInjection.getDisplayName(); - } -} diff --git a/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/config/AbstractTagInjection.java b/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/config/AbstractTagInjection.java index 0662837d0574..491b277b9393 100644 --- a/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/config/AbstractTagInjection.java +++ b/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/config/AbstractTagInjection.java @@ -16,7 +16,6 @@ package org.intellij.plugins.intelliLang.inject.config; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.util.JDOMExternalizer; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiElement; import com.intellij.psi.xml.XmlAttribute; @@ -44,7 +43,7 @@ import java.util.TreeSet; * * @see org.intellij.plugins.intelliLang.inject.config.XPathSupportProxy */ -public class AbstractTagInjection extends BaseInjection { +public abstract class AbstractTagInjection extends BaseInjection { private static final Logger LOG = Logger.getInstance("org.intellij.plugins.intelliLang.inject.config.AbstractTagInjection"); @@ -57,7 +56,7 @@ public class AbstractTagInjection extends BaseInjection { private String myXPathCondition = ""; private XPath myCompiledXPathCondition; - private boolean myApplyToSubTagTexts; + private boolean myApplyToSubTags; public AbstractTagInjection() { super(XmlLanguageInjectionSupport.XML_SUPPORT_ID); @@ -134,9 +133,7 @@ public class AbstractTagInjection extends BaseInjection { } @Override - public AbstractTagInjection copy() { - return new AbstractTagInjection().copyFrom(this); - } + public abstract AbstractTagInjection copy(); public AbstractTagInjection copyFrom(@NotNull BaseInjection o) { super.copyFrom(o); @@ -146,30 +143,21 @@ public class AbstractTagInjection extends BaseInjection { myTagNamespace = other.myTagNamespace; setXPathCondition(other.getXPathCondition()); - setApplyToSubTagTexts(other.isApplyToSubTagTexts()); + setApplyToSubTags(other.isApplyToSubTags()); } return this; } protected void readExternalImpl(Element e) { - if (e.getAttribute("injector-id") == null) { - setTagName(JDOMExternalizer.readString(e, "TAGNAME")); - setTagNamespace(JDOMExternalizer.readString(e, "TAGNAMESPACE")); - setXPathCondition(JDOMExternalizer.readString(e, "XPATH_CONDITION")); - - myApplyToSubTagTexts = JDOMExternalizer.readBoolean(e, "APPLY_TO_SUBTAGS"); - } - else { - setXPathCondition(e.getChildText("xpath-condition")); - myApplyToSubTagTexts = e.getChild("apply-to-subtags") != null; - } + setXPathCondition(e.getChildText("xpath-condition")); + myApplyToSubTags = e.getChild("apply-to-subtags") != null; } protected void writeExternalImpl(Element e) { if (StringUtil.isNotEmpty(myXPathCondition)) { e.addContent(new Element("xpath-condition").setText(myXPathCondition)); } - if (myApplyToSubTagTexts) { + if (myApplyToSubTags) { e.addContent(new Element("apply-to-subtags")); } } @@ -186,7 +174,7 @@ public class AbstractTagInjection extends BaseInjection { if (!myTagNamespace.equals(that.myTagNamespace)) return false; if (!myXPathCondition.equals(that.myXPathCondition)) return false; - if (myApplyToSubTagTexts != that.myApplyToSubTagTexts) return false; + if (myApplyToSubTags != that.myApplyToSubTags) return false; return true; } @@ -196,7 +184,7 @@ public class AbstractTagInjection extends BaseInjection { result = 31 * result + myTagNamespace.hashCode(); result = 31 * result + myXPathCondition.hashCode(); - result = 31 * result + (myApplyToSubTagTexts ? 1 : 0); + result = 31 * result + (myApplyToSubTags ? 1 : 0); return result; } @@ -215,12 +203,12 @@ public class AbstractTagInjection extends BaseInjection { return myXPathCondition.length() == 0; } - public boolean isApplyToSubTagTexts() { - return myApplyToSubTagTexts; + public boolean isApplyToSubTags() { + return myApplyToSubTags; } - public void setApplyToSubTagTexts(final boolean applyToSubTagTexts) { - myApplyToSubTagTexts = applyToSubTagTexts; + public void setApplyToSubTags(final boolean applyToSubTagTexts) { + myApplyToSubTags = applyToSubTagTexts; } @Override diff --git a/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/config/XmlAttributeInjection.java b/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/config/XmlAttributeInjection.java index 5ffe3271bb07..32a2239dd3a1 100644 --- a/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/config/XmlAttributeInjection.java +++ b/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/config/XmlAttributeInjection.java @@ -15,7 +15,6 @@ */ package org.intellij.plugins.intelliLang.inject.config; -import com.intellij.openapi.util.JDOMExternalizer; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiElement; import com.intellij.psi.xml.XmlAttribute; @@ -57,8 +56,7 @@ public class XmlAttributeInjection extends AbstractTagInjection { return element instanceof XmlAttribute && matches((XmlAttribute)element); } - @NotNull - public String getDisplayName() { + public String getGeneratedName() { final String tag = getTagName(); final String attributeName = getAttributeName(); if (!attributeName.equals(StringMatcher.NONE.getPattern())) { @@ -74,6 +72,7 @@ public class XmlAttributeInjection extends AbstractTagInjection { @Override public void generatePlaces() { + if (StringUtil.isEmpty(getDisplayName())) setDisplayName(getGeneratedName()); setInjectionPlaces(new InjectionPlace(getCompiler().createElementPattern(getPatternString(this), getDisplayName()), true)); } @@ -95,25 +94,14 @@ public class XmlAttributeInjection extends AbstractTagInjection { public XmlAttributeInjection copyFrom(@NotNull BaseInjection o) { super.copyFrom(o); if (o instanceof XmlAttributeInjection) { - final XmlAttributeInjection other = (XmlAttributeInjection)o; + XmlAttributeInjection other = (XmlAttributeInjection)o; + setApplyToSubTags(other.isApplyToSubTags()); setAttributeName(other.getAttributeName()); setAttributeNamespace(other.getAttributeNamespace()); } return this; } - protected void readExternalImpl(Element e) { - super.readExternalImpl(e); - if (e.getAttribute("injector-id") == null) { - setAttributeName(JDOMExternalizer.readString(e, "ATT_NAME")); - setAttributeNamespace(JDOMExternalizer.readString(e, "ATT_NAMESPACE")); - } - } - - protected void writeExternalImpl(Element e) { - super.writeExternalImpl(e); - } - @SuppressWarnings({"RedundantIfStatement"}) public boolean equals(Object o) { if (this == o) return true; @@ -142,7 +130,8 @@ public class XmlAttributeInjection extends AbstractTagInjection { if (StringUtil.isNotEmpty(name)) appendStringPattern(result, ".withLocalName(", name, ")"); if (StringUtil.isNotEmpty(namespace)) appendStringPattern(result, ".withNamespace(", namespace, ")"); if (StringUtil.isNotEmpty(injection.getTagName()) || StringUtil.isNotEmpty(injection.getTagNamespace())) { - result.append(".withParent(").append(XmlTagInjection.getPatternString(injection)).append(")"); + result.append(".").append(injection.isApplyToSubTags() ? "inside" : "withParent").append("(") + .append(XmlTagInjection.getPatternString(injection)).append(")"); } return result.toString(); } diff --git a/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/config/XmlTagInjection.java b/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/config/XmlTagInjection.java index ade0c399c84d..19d3a8c64f3b 100644 --- a/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/config/XmlTagInjection.java +++ b/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/config/XmlTagInjection.java @@ -31,8 +31,7 @@ public class XmlTagInjection extends AbstractTagInjection { return matches(context) && matchXPath(context); } - @NotNull - public String getDisplayName() { + public String getGeneratedName() { final String name = getTagName(); return name.length() > 0 ? name : "*"; } @@ -49,6 +48,7 @@ public class XmlTagInjection extends AbstractTagInjection { @Override public void generatePlaces() { + if (StringUtil.isEmpty(getDisplayName())) setDisplayName(getGeneratedName()); setInjectionPlaces(new InjectionPlace(getCompiler().createElementPattern(getPatternString(this), getDisplayName()), true)); } diff --git a/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/config/ui/AdvancedXmlPanel.form b/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/config/ui/AdvancedXmlPanel.form index c4cd838349cd..48df40018f5a 100644 --- a/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/config/ui/AdvancedXmlPanel.form +++ b/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/config/ui/AdvancedXmlPanel.form @@ -1,9 +1,9 @@ <?xml version="1.0" encoding="UTF-8"?> <form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="org.intellij.plugins.intelliLang.inject.config.ui.AdvancedXmlPanel"> - <grid id="27dc6" binding="myRoot" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> + <grid id="27dc6" binding="myRoot" layout-manager="GridLayoutManager" row-count="2" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> <margin top="0" left="0" bottom="0" right="0"/> <constraints> - <xy x="20" y="20" width="531" height="97"/> + <xy x="20" y="20" width="531" height="123"/> </constraints> <properties/> <border type="none"/> @@ -25,7 +25,7 @@ </constraints> <properties> <labelFor value="7bf4e"/> - <text value="&Value Pattern:"/> + <text value="&Value pattern:"/> <toolTipText value="<html>Enter a regular expression that selects the parts of the tag's or attribute's value the language should be injected into.<br>The pattern should contain exactly one capturing group.</html>"/> </properties> </component> @@ -43,7 +43,7 @@ </constraints> <properties> <labelFor value="a6f2"/> - <text value="&XPath Condition:"/> + <text value="&XPath condition:"/> <toolTipText value="<html>Enter an XPath expression that the tag/attribute must match additionally to the name-condition specified above.<br>This requires the XPathView plugin to be installed</html>"/> </properties> </component> @@ -60,11 +60,16 @@ <grid row="0" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/> </constraints> <properties> - <text value="&Single File"/> + <text value="Single &file"/> </properties> </component> </children> </grid> + <vspacer id="5c79c"> + <constraints> + <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/> + </constraints> + </vspacer> </children> </grid> </form> diff --git a/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/config/ui/TagPanel.form b/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/config/ui/TagPanel.form index bcbe680d8e0d..70051cbf3730 100644 --- a/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/config/ui/TagPanel.form +++ b/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/config/ui/TagPanel.form @@ -8,7 +8,7 @@ <properties/> <border type="none"/> <children> - <grid id="7e115" layout-manager="GridLayoutManager" row-count="2" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> + <grid id="49b27" layout-manager="GridLayoutManager" row-count="2" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> <margin top="0" left="0" bottom="0" right="0"/> <constraints> <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/> @@ -19,25 +19,25 @@ </clientProperties> <border type="none" title="XML Tag"/> <children> - <component id="edc9a" class="javax.swing.JLabel"> + <component id="9c78e" class="javax.swing.JLabel"> <constraints> <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/> </constraints> <properties> - <labelFor value="16487"/> - <text value="&Local Name:"/> + <labelFor value="8f17"/> + <text value="&Local name:"/> </properties> </component> - <component id="1068d" class="javax.swing.JLabel"> + <component id="7d32d" class="javax.swing.JLabel"> <constraints> <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/> </constraints> <properties> - <labelFor value="eeee3"/> + <labelFor value="3d65f"/> <text value="&Namespace:"/> </properties> </component> - <component id="16487" class="com.intellij.ui.EditorTextField" binding="myLocalName" custom-create="true"> + <component id="8f17" class="com.intellij.ui.EditorTextField" binding="myLocalName" custom-create="true"> <constraints> <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="7" anchor="8" fill="1" indent="0" use-parent-layout="false"> <preferred-size width="150" height="-1"/> @@ -45,24 +45,29 @@ </constraints> <properties/> </component> - <component id="eeee3" class="com.intellij.openapi.ui.ComboBox" binding="myNamespace" custom-create="true"> + <component id="3d65f" class="com.intellij.openapi.ui.ComboBox" binding="myNamespace" custom-create="true"> <constraints> - <grid row="1" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="7" anchor="8" fill="1" indent="0" use-parent-layout="false"/> + <grid row="1" column="1" row-span="1" col-span="2" vsize-policy="0" hsize-policy="7" anchor="8" fill="1" indent="0" use-parent-layout="false"/> </constraints> <properties> <editable value="true"/> </properties> </component> + <component id="3ed2c" class="javax.swing.JCheckBox" binding="myWithSubtags"> + <constraints> + <grid row="0" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/> + </constraints> + <properties> + <text value="Sub-&tags"/> + </properties> + </component> </children> </grid> - <component id="bc807" class="javax.swing.JCheckBox" binding="myApplyRecursivelyCheckBox"> + <vspacer id="bdf19"> <constraints> - <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/> + <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/> </constraints> - <properties> - <text value="Apply to all text fragments &recursively"/> - </properties> - </component> + </vspacer> </children> </grid> </form> diff --git a/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/config/ui/TagPanel.java b/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/config/ui/TagPanel.java index 42db562728ff..2b224a1be58d 100644 --- a/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/config/ui/TagPanel.java +++ b/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/config/ui/TagPanel.java @@ -28,7 +28,6 @@ import com.intellij.ui.LanguageTextField; import org.intellij.lang.regexp.RegExpLanguage; import org.intellij.plugins.intelliLang.inject.config.AbstractTagInjection; import org.intellij.plugins.intelliLang.inject.config.JspSupportProxy; -import org.intellij.plugins.intelliLang.inject.config.XmlTagInjection; import javax.swing.*; import java.util.ArrayList; @@ -43,14 +42,13 @@ public class TagPanel extends AbstractInjectionPanel<AbstractTagInjection> { private EditorTextField myLocalName; private ComboBox myNamespace; - private JCheckBox myApplyRecursivelyCheckBox; + private JCheckBox myWithSubtags; public TagPanel(Project project, AbstractTagInjection injection) { super(injection, project); $$$setupUI$$$(); myNamespace.setModel(createNamespaceUriModel(myProject)); - myLocalName.getDocument().addDocumentListener(new TreeUpdateListener()); } public static ComboBoxModel createNamespaceUriModel(Project project) { @@ -95,19 +93,13 @@ public class TagPanel extends AbstractInjectionPanel<AbstractTagInjection> { protected void resetImpl() { myLocalName.setText(myOrigInjection.getTagName()); myNamespace.getEditor().setItem(myOrigInjection.getTagNamespace()); - final boolean isXmlTag = myOrigInjection instanceof XmlTagInjection; - myApplyRecursivelyCheckBox.setVisible(isXmlTag); - if (isXmlTag) { - myApplyRecursivelyCheckBox.setSelected(((XmlTagInjection)myOrigInjection).isApplyToSubTagTexts()); - } + myWithSubtags.setSelected(myOrigInjection.isApplyToSubTags()); } - protected void apply(AbstractTagInjection i) { - i.setTagName(myLocalName.getText()); - i.setTagNamespace(getNamespace()); - if (i instanceof XmlTagInjection) { - ((XmlTagInjection)i).setApplyToSubTagTexts(myApplyRecursivelyCheckBox.isSelected()); - } + protected void apply(AbstractTagInjection other) { + other.setTagName(myLocalName.getText()); + other.setTagNamespace(getNamespace()); + other.setApplyToSubTags(myWithSubtags.isSelected()); } private String getNamespace() { diff --git a/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/config/ui/XmlAttributePanel.form b/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/config/ui/XmlAttributePanel.form index 1dce7a917205..a9d67f3f938d 100644 --- a/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/config/ui/XmlAttributePanel.form +++ b/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/config/ui/XmlAttributePanel.form @@ -1,22 +1,22 @@ <?xml version="1.0" encoding="UTF-8"?> <form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="org.intellij.plugins.intelliLang.inject.config.ui.XmlAttributePanel"> - <grid id="27dc6" binding="myRoot" layout-manager="GridLayoutManager" row-count="5" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> + <grid id="27dc6" binding="myRoot" layout-manager="GridLayoutManager" row-count="6" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> <margin top="0" left="0" bottom="0" right="0"/> <constraints> - <xy x="20" y="20" width="500" height="479"/> + <xy x="20" y="20" width="500" height="551"/> </constraints> <properties/> <border type="none"/> <children> <nested-form id="260fa" form-file="org/intellij/plugins/intelliLang/inject/config/ui/TagPanel.form" binding="myTagPanel" custom-create="true"> <constraints> - <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="7" anchor="0" fill="1" indent="0" use-parent-layout="false"/> + <grid row="2" column="0" row-span="1" col-span="2" vsize-policy="3" hsize-policy="7" anchor="0" fill="1" indent="0" use-parent-layout="false"/> </constraints> </nested-form> <grid id="ea19" layout-manager="GridLayoutManager" row-count="2" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> <margin top="0" left="0" bottom="0" right="0"/> <constraints> - <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/> + <grid row="3" column="0" row-span="1" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/> </constraints> <properties/> <clientProperties> @@ -30,7 +30,7 @@ </constraints> <properties> <labelFor value="cca5"/> - <text value="L&ocal Name:"/> + <text value="L&ocal name:"/> <toolTipText value="Regular expression to match the attribute name, e.g. "on.*""/> </properties> </component> @@ -65,19 +65,46 @@ </grid> <vspacer id="f7910"> <constraints> - <grid row="4" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/> + <grid row="5" column="0" row-span="1" col-span="2" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/> </constraints> </vspacer> <nested-form id="8cfe8" form-file="org/intellij/plugins/intelliLang/inject/config/ui/LanguagePanel.form" binding="myLanguagePanel" custom-create="true"> <constraints> - <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="7" anchor="0" fill="1" indent="0" use-parent-layout="false"/> + <grid row="1" column="0" row-span="1" col-span="2" vsize-policy="3" hsize-policy="7" anchor="0" fill="1" indent="0" use-parent-layout="false"/> </constraints> </nested-form> <nested-form id="b6e0b" form-file="org/intellij/plugins/intelliLang/inject/config/ui/AdvancedXmlPanel.form" binding="myAdvancedPanel" custom-create="true"> <constraints> - <grid row="3" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="7" anchor="0" fill="1" indent="0" use-parent-layout="false"/> + <grid row="4" column="0" row-span="1" col-span="2" vsize-policy="3" hsize-policy="7" anchor="0" fill="1" indent="0" use-parent-layout="false"/> </constraints> </nested-form> + <grid id="2032c" layout-manager="GridLayoutManager" row-count="1" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> + <margin top="0" left="0" bottom="0" right="0"/> + <constraints> + <grid row="0" column="0" row-span="1" col-span="2" vsize-policy="0" hsize-policy="0" anchor="0" fill="3" indent="0" use-parent-layout="false"/> + </constraints> + <properties/> + <border type="none"/> + <children> + <component id="e174b" class="javax.swing.JLabel"> + <constraints> + <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/> + </constraints> + <properties> + <labelFor value="80ca6"/> + <text value="&Name:"/> + </properties> + </component> + <component id="80ca6" class="javax.swing.JTextField" binding="myNameTextField"> + <constraints> + <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false"> + <preferred-size width="150" height="-1"/> + </grid> + </constraints> + <properties/> + </component> + </children> + </grid> </children> </grid> </form> diff --git a/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/config/ui/XmlAttributePanel.java b/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/config/ui/XmlAttributePanel.java index 9e8e935c39e8..79f451dd31f9 100644 --- a/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/config/ui/XmlAttributePanel.java +++ b/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/config/ui/XmlAttributePanel.java @@ -17,6 +17,8 @@ package org.intellij.plugins.intelliLang.inject.config.ui; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.ComboBox; +import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.ui.EditorTextField; import com.intellij.ui.LanguageTextField; import org.intellij.lang.regexp.RegExpLanguage; @@ -35,6 +37,9 @@ public class XmlAttributePanel extends AbstractInjectionPanel<XmlAttributeInject private EditorTextField myLocalName; private ComboBox myNamespace; + private JTextField myNameTextField; + + private boolean myUseGeneratedName; public XmlAttributePanel(XmlAttributeInjection injection, Project project) { super(injection, project); @@ -43,9 +48,6 @@ public class XmlAttributePanel extends AbstractInjectionPanel<XmlAttributeInject myNamespace.setModel(TagPanel.createNamespaceUriModel(project)); init(injection.copy()); - - // be sure to add the listener after initializing the textfield's value - myLocalName.getDocument().addDocumentListener(new TreeUpdateListener()); } public JPanel getComponent() { @@ -53,13 +55,21 @@ public class XmlAttributePanel extends AbstractInjectionPanel<XmlAttributeInject } protected void resetImpl() { + myNameTextField.setText(myOrigInjection.getDisplayName()); myLocalName.setText(myOrigInjection.getAttributeName()); myNamespace.getEditor().setItem(myOrigInjection.getAttributeNamespace()); + + myUseGeneratedName = Comparing.equal(myOrigInjection.getDisplayName(), myOrigInjection.getGeneratedName()); } - protected void apply(XmlAttributeInjection i) { - i.setAttributeName(myLocalName.getText()); - i.setAttributeNamespace(getNamespace()); + protected void apply(XmlAttributeInjection other) { + other.setAttributeName(myLocalName.getText()); + other.setAttributeNamespace(getNamespace()); + + String name = myNameTextField.getText(); + boolean useGenerated = myUseGeneratedName && Comparing.equal(myOrigInjection.getDisplayName(), name); + String newName = useGenerated || StringUtil.isEmptyOrSpaces(name) ? other.getGeneratedName() : name; + other.setDisplayName(newName); } private String getNamespace() { diff --git a/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/config/ui/XmlTagPanel.form b/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/config/ui/XmlTagPanel.form index d19d8571c038..36585ab8a020 100644 --- a/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/config/ui/XmlTagPanel.form +++ b/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/config/ui/XmlTagPanel.form @@ -1,33 +1,60 @@ <?xml version="1.0" encoding="UTF-8"?> <form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="org.intellij.plugins.intelliLang.inject.config.ui.XmlTagPanel"> - <grid id="27dc6" binding="myRoot" layout-manager="GridLayoutManager" row-count="4" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> + <grid id="27dc6" binding="myRoot" layout-manager="GridLayoutManager" row-count="5" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> <margin top="0" left="0" bottom="0" right="0"/> <constraints> - <xy x="20" y="20" width="500" height="400"/> + <xy x="20" y="20" width="500" height="437"/> </constraints> <properties/> <border type="none"/> <children> <nested-form id="4c744" form-file="org/intellij/plugins/intelliLang/inject/config/ui/TagPanel.form" binding="myPanel" custom-create="true"> <constraints> - <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="7" anchor="0" fill="1" indent="0" use-parent-layout="false"/> + <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="7" anchor="0" fill="1" indent="0" use-parent-layout="false"/> </constraints> </nested-form> <vspacer id="12f92"> <constraints> - <grid row="3" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/> + <grid row="4" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/> </constraints> </vspacer> <nested-form id="4e64b" form-file="org/intellij/plugins/intelliLang/inject/config/ui/LanguagePanel.form" binding="myLanguagePanel" custom-create="true"> <constraints> - <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="7" anchor="0" fill="1" indent="0" use-parent-layout="false"/> + <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="7" anchor="0" fill="1" indent="0" use-parent-layout="false"/> </constraints> </nested-form> <nested-form id="fa14a" form-file="org/intellij/plugins/intelliLang/inject/config/ui/AdvancedXmlPanel.form" binding="myAdvancedPanel" custom-create="true"> <constraints> - <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="7" anchor="0" fill="1" indent="0" use-parent-layout="false"/> + <grid row="3" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="7" anchor="0" fill="1" indent="0" use-parent-layout="false"/> </constraints> </nested-form> + <grid id="d9c54" layout-manager="GridLayoutManager" row-count="1" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> + <margin top="0" left="0" bottom="0" right="0"/> + <constraints> + <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="0" fill="3" indent="0" use-parent-layout="false"/> + </constraints> + <properties/> + <border type="none"/> + <children> + <component id="d2267" class="javax.swing.JLabel"> + <constraints> + <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/> + </constraints> + <properties> + <labelFor value="6c531"/> + <text value="&Name:"/> + </properties> + </component> + <component id="6c531" class="javax.swing.JTextField" binding="myNameTextField"> + <constraints> + <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false"> + <preferred-size width="150" height="-1"/> + </grid> + </constraints> + <properties/> + </component> + </children> + </grid> </children> </grid> </form> diff --git a/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/config/ui/XmlTagPanel.java b/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/config/ui/XmlTagPanel.java index ffc92143ba0c..342cfd61cbe7 100644 --- a/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/config/ui/XmlTagPanel.java +++ b/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/config/ui/XmlTagPanel.java @@ -16,6 +16,8 @@ package org.intellij.plugins.intelliLang.inject.config.ui; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.text.StringUtil; import org.intellij.plugins.intelliLang.inject.config.XmlTagInjection; import javax.swing.*; @@ -28,6 +30,9 @@ public class XmlTagPanel extends AbstractInjectionPanel<XmlTagInjection> { AdvancedXmlPanel myAdvancedPanel; private JPanel myRoot; + private JTextField myNameTextField; + + private boolean myUseGeneratedName; public XmlTagPanel(XmlTagInjection injection, Project project) { super(injection, project); @@ -37,11 +42,16 @@ public class XmlTagPanel extends AbstractInjectionPanel<XmlTagInjection> { } protected void apply(XmlTagInjection other) { - // nothing to do, TagPanel.apply() already does this + String name = myNameTextField.getText(); + boolean useGenerated = myUseGeneratedName && Comparing.equal(myOrigInjection.getDisplayName(), name); + String newName = useGenerated || StringUtil.isEmptyOrSpaces(name) ? other.getGeneratedName() : name; + other.setDisplayName(newName); } protected void resetImpl() { - // same here^ + myNameTextField.setText(myOrigInjection.getDisplayName()); + + myUseGeneratedName = Comparing.equal(myOrigInjection.getDisplayName(), myOrigInjection.getGeneratedName()); } public JPanel getComponent() { diff --git a/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/config/ui/configurables/XmlAttributeInjectionConfigurable.java b/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/config/ui/configurables/XmlAttributeInjectionConfigurable.java deleted file mode 100644 index a0898e0e8664..000000000000 --- a/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/config/ui/configurables/XmlAttributeInjectionConfigurable.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2006 Sascha Weinreuter - * - * 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 org.intellij.plugins.intelliLang.inject.config.ui.configurables; - -import com.intellij.openapi.project.Project; -import org.intellij.plugins.intelliLang.inject.config.XmlAttributeInjection; -import org.intellij.plugins.intelliLang.inject.config.ui.XmlAttributePanel; - -public class XmlAttributeInjectionConfigurable extends InjectionConfigurable<XmlAttributeInjection, XmlAttributePanel> { - public XmlAttributeInjectionConfigurable(XmlAttributeInjection injection, Runnable treeUpdater, Project project) { - super(injection, treeUpdater, project); - } - - protected XmlAttributePanel createOptionsPanelImpl() { - return new XmlAttributePanel(myInjection, myProject); - } - - public String getBannerSlogan() { - return "Edit XML Attribute Injection"; - } -} diff --git a/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/config/ui/configurables/XmlTagInjectionConfigurable.java b/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/config/ui/configurables/XmlTagInjectionConfigurable.java deleted file mode 100644 index 655590b2f4cf..000000000000 --- a/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/config/ui/configurables/XmlTagInjectionConfigurable.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2006 Sascha Weinreuter - * - * 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 org.intellij.plugins.intelliLang.inject.config.ui.configurables; - -import com.intellij.openapi.project.Project; -import org.intellij.plugins.intelliLang.inject.config.XmlTagInjection; -import org.intellij.plugins.intelliLang.inject.config.ui.XmlTagPanel; - -public class XmlTagInjectionConfigurable extends InjectionConfigurable<XmlTagInjection, XmlTagPanel> { - public XmlTagInjectionConfigurable(XmlTagInjection injection, Runnable treeUpdater, Project project) { - super(injection, treeUpdater, project); - } - - public String getBannerSlogan() { - return "Edit XML Text Injection"; - } - - protected XmlTagPanel createOptionsPanelImpl() { - return new XmlTagPanel(myInjection, myProject); - } -} diff --git a/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/xml/XmlLanguageInjectionSupport.java b/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/xml/XmlLanguageInjectionSupport.java index 6c84a879b1a6..abe3349a9c15 100644 --- a/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/xml/XmlLanguageInjectionSupport.java +++ b/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/xml/XmlLanguageInjectionSupport.java @@ -43,8 +43,6 @@ import org.intellij.plugins.intelliLang.inject.config.*; import org.intellij.plugins.intelliLang.inject.config.ui.AbstractInjectionPanel; import org.intellij.plugins.intelliLang.inject.config.ui.XmlAttributePanel; import org.intellij.plugins.intelliLang.inject.config.ui.XmlTagPanel; -import org.intellij.plugins.intelliLang.inject.config.ui.configurables.XmlAttributeInjectionConfigurable; -import org.intellij.plugins.intelliLang.inject.config.ui.configurables.XmlTagInjectionConfigurable; import org.jdom.Element; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -66,7 +64,7 @@ public class XmlLanguageInjectionSupport extends AbstractLanguageInjectionSuppor final PsiElement p = host.getParent(); if (p instanceof XmlAttribute) { final String s = ((XmlAttribute)p).getName(); - return !(s.equals("xmlns") || s.startsWith("xmlns:")); + return !("xmlns".equals(s) || s.startsWith("xmlns:")); } } else if (host instanceof XmlText) { @@ -177,7 +175,7 @@ public class XmlLanguageInjectionSupport extends AbstractLanguageInjectionSuppor } }); if (builder.show() == DialogWrapper.OK_EXIT_CODE) { - return new AbstractTagInjection().copyFrom(xmlInjection); + return xmlInjection.copy(); } return null; } @@ -219,12 +217,15 @@ public class XmlLanguageInjectionSupport extends AbstractLanguageInjectionSuppor result.setTagNamespace(value); } } - else if (result instanceof XmlAttributeInjection && - "inside".equals(condition.getDebugMethodName()) && condition instanceof PatternConditionPlus) { - final ElementPattern<?> insidePattern = ((PatternConditionPlus)condition).getValuePattern(); + else if (result instanceof XmlAttributeInjection && condition instanceof PatternConditionPlus) { + boolean strict = "withParent".equals(condition.getDebugMethodName()); + if (!strict && !"inside".equals(condition.getDebugMethodName())) return null; + + result.setApplyToSubTags(!strict); + ElementPattern<?> insidePattern = ((PatternConditionPlus)condition).getValuePattern(); if (!XmlTag.class.equals(insidePattern.getCondition().getInitialCondition().getAcceptedClass())) return null; for (PatternCondition<?> insideCondition : insidePattern.getCondition().getConditions()) { - final String tagValue = extractValue(insideCondition); + String tagValue = extractValue(insideCondition); if (tagValue == null) return null; if ("withLocalName".equals(insideCondition.getDebugMethodName())) { result.setTagName(tagValue); @@ -232,10 +233,11 @@ public class XmlLanguageInjectionSupport extends AbstractLanguageInjectionSuppor else if ("withNamespace".equals(insideCondition.getDebugMethodName())) { result.setTagNamespace(tagValue); } - } } - else return null; + else { + return null; + } } result.generatePlaces(); return result; @@ -265,14 +267,17 @@ public class XmlLanguageInjectionSupport extends AbstractLanguageInjectionSuppor return null; } - public BaseInjection createInjection(final Element element) { - if (element.getName().equals(XmlAttributeInjection.class.getSimpleName())) { + public BaseInjection createInjection(Element element) { + String place = StringUtil.notNullize(element.getChildText("place"), ""); + if (place.startsWith("xmlAttribute")) { return new XmlAttributeInjection(); } - else if (element.getName().equals(XmlTagInjection.class.getSimpleName())) { + else if (place.startsWith("xmlTag")) { return new XmlTagInjection(); } - return new AbstractTagInjection(); + else { + return new BaseInjection(XML_SUPPORT_ID); + } } public Configurable[] createSettings(final Project project, final Configuration configuration) { @@ -298,12 +303,10 @@ public class XmlLanguageInjectionSupport extends AbstractLanguageInjectionSuppor final AbstractTagInjection originalInjection = (AbstractTagInjection)configuration.findExistingInjection(template); final XmlTagInjection newInjection = originalInjection == null? template : new XmlTagInjection().copyFrom(originalInjection); - if (InjectLanguageAction.doEditConfigurable(project, new XmlTagInjectionConfigurable(newInjection, null, project))) { - configuration.replaceInjectionsWithUndo( - project, Collections.singletonList(newInjection), - ContainerUtil.createMaybeSingletonList(originalInjection), - Collections.<PsiElement>emptyList()); - } + configuration.replaceInjectionsWithUndo( + project, Collections.singletonList(newInjection), + ContainerUtil.createMaybeSingletonList(originalInjection), + Collections.<PsiElement>emptyList()); } private static boolean doInjectInAttributeValue(final XmlAttributeValue host, final String languageId) { @@ -327,12 +330,10 @@ public class XmlLanguageInjectionSupport extends AbstractLanguageInjectionSuppor final Configuration configuration = InjectorUtils.getEditableInstance(project); final BaseInjection originalInjection = configuration.findExistingInjection(template); final BaseInjection newInjection = originalInjection == null ? template : originalInjection.copy(); - if (InjectLanguageAction.doEditConfigurable(project, new XmlAttributeInjectionConfigurable((XmlAttributeInjection)newInjection, null, project))) { - configuration.replaceInjectionsWithUndo( - project, Collections.singletonList(newInjection), - ContainerUtil.createMaybeSingletonList(originalInjection), - Collections.<PsiElement>emptyList()); - } + configuration.replaceInjectionsWithUndo( + project, Collections.singletonList(newInjection), + ContainerUtil.createMaybeSingletonList(originalInjection), + Collections.<PsiElement>emptyList()); } private static ArrayList<BaseInjection> collectInjections(final PsiElement host, diff --git a/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/xml/XmlLanguageInjector.java b/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/xml/XmlLanguageInjector.java index f8026edb4f11..c7808b0c1c40 100644 --- a/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/xml/XmlLanguageInjector.java +++ b/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/xml/XmlLanguageInjector.java @@ -32,6 +32,7 @@ import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil; import com.intellij.psi.xml.*; import com.intellij.util.PairProcessor; import com.intellij.util.PatternValuesIndex; +import com.intellij.util.containers.ContainerUtil; import gnu.trove.THashMap; import org.intellij.plugins.intelliLang.Configuration; import org.intellij.plugins.intelliLang.inject.InjectedLanguage; @@ -113,8 +114,7 @@ public final class XmlLanguageInjector implements MultiHostInjector { if (language == null) continue; final boolean separateFiles = !injection.isSingleFile() && StringUtil.isNotEmpty(injection.getValuePattern()); - final List<Trinity<PsiLanguageInjectionHost, InjectedLanguage, TextRange>> result = - new ArrayList<Trinity<PsiLanguageInjectionHost, InjectedLanguage, TextRange>>(); + final List<Trinity<PsiLanguageInjectionHost, InjectedLanguage, TextRange>> result = ContainerUtil.newArrayList(); xmlTag.acceptChildren(new PsiElementVisitor() { @Override @@ -130,7 +130,7 @@ public final class XmlLanguageInjector implements MultiHostInjector { } else if (element instanceof XmlTag) { if (!separateFiles) unparsableRef.set(Boolean.TRUE); - if (injection instanceof AbstractTagInjection && ((AbstractTagInjection)injection).isApplyToSubTagTexts()) { + if (injection instanceof AbstractTagInjection && ((AbstractTagInjection)injection).isApplyToSubTags()) { element.acceptChildren(this); } } diff --git a/plugins/git4idea/src/git4idea/log/GitLogProvider.java b/plugins/git4idea/src/git4idea/log/GitLogProvider.java index 0a8bc3723d3f..672e4eb8dead 100644 --- a/plugins/git4idea/src/git4idea/log/GitLogProvider.java +++ b/plugins/git4idea/src/git4idea/log/GitLogProvider.java @@ -29,12 +29,7 @@ import com.intellij.util.ExceptionUtil; import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; import com.intellij.vcs.log.*; -import com.intellij.vcs.log.data.VcsLogBranchFilter; -import com.intellij.vcs.log.data.VcsLogDateFilter; -import com.intellij.vcs.log.data.VcsLogStructureFilter; -import com.intellij.vcs.log.data.VcsLogUserFilter; import com.intellij.vcs.log.impl.HashImpl; -import com.intellij.vcs.log.ui.filter.VcsLogTextFilter; import git4idea.GitLocalBranch; import git4idea.GitRemoteBranch; import git4idea.GitVcs; @@ -189,7 +184,11 @@ public class GitLogProvider implements VcsLogProvider { @NotNull @Override public List<? extends VcsFullCommitDetails> getFilteredDetails(@NotNull final VirtualFile root, - @NotNull Collection<VcsLogFilter> filters, + @NotNull Collection<VcsLogBranchFilter> branchFilters, + @NotNull Collection<VcsLogUserFilter> userFilters, + @NotNull Collection<VcsLogDateFilter> dateFilters, + @NotNull Collection<VcsLogTextFilter> textFilters, + @NotNull Collection<VcsLogStructureFilter> structureFilters, int maxCount) throws VcsException { if (!isRepositoryReady(root)) { return Collections.emptyList(); @@ -197,21 +196,19 @@ public class GitLogProvider implements VcsLogProvider { List<String> filterParameters = ContainerUtil.newArrayList(); - List<VcsLogBranchFilter> branchFilters = ContainerUtil.findAll(filters, VcsLogBranchFilter.class); if (!branchFilters.isEmpty()) { // git doesn't support filtering by several branches very well (--branches parameter give a weak pattern capabilities) // => by now assuming there is only one branch filter. if (branchFilters.size() > 1) { LOG.warn("More than one branch filter was passed. Using only the first one."); } - VcsLogBranchFilter branchFilter = branchFilters.get(0); + VcsLogBranchFilter branchFilter = branchFilters.iterator().next(); filterParameters.add(branchFilter.getBranchName()); } else { filterParameters.addAll(GitHistoryUtils.LOG_ALL); } - List<VcsLogUserFilter> userFilters = ContainerUtil.findAll(filters, VcsLogUserFilter.class); if (!userFilters.isEmpty()) { String authorFilter = joinFilters(userFilters, new Function<VcsLogUserFilter, String>() { @Override @@ -222,7 +219,6 @@ public class GitLogProvider implements VcsLogProvider { filterParameters.add(prepareParameter("author", authorFilter)); } - List<VcsLogDateFilter> dateFilters = ContainerUtil.findAll(filters, VcsLogDateFilter.class); if (!dateFilters.isEmpty()) { // assuming there is only one date filter, until filter expressions are defined VcsLogDateFilter filter = dateFilters.iterator().next(); @@ -234,7 +230,6 @@ public class GitLogProvider implements VcsLogProvider { } } - List<VcsLogTextFilter> textFilters = ContainerUtil.findAll(filters, VcsLogTextFilter.class); if (textFilters.size() > 1) { LOG.warn("Expected only one text filter: " + textFilters); } @@ -249,8 +244,7 @@ public class GitLogProvider implements VcsLogProvider { } filterParameters.add("--date-order"); - // note: this filter must be the last parameter, because it uses "--" which separates parameters from paths - List<VcsLogStructureFilter> structureFilters = ContainerUtil.findAll(filters, VcsLogStructureFilter.class); + // note: structure filter must be the last parameter, because it uses "--" which separates parameters from paths if (!structureFilters.isEmpty()) { filterParameters.add("--"); for (VcsLogStructureFilter filter : structureFilters) { @@ -281,7 +275,7 @@ public class GitLogProvider implements VcsLogProvider { return "--" + paramName + "=" + value; // no value escaping needed, because the parameter itself will be quoted by GeneralCommandLine } - private static <T> String joinFilters(List<T> filters, Function<T, String> toString) { + private static <T> String joinFilters(Collection<T> filters, Function<T, String> toString) { return StringUtil.join(filters, toString, "\\|"); } diff --git a/plugins/gradle/src/META-INF/plugin.xml b/plugins/gradle/src/META-INF/plugin.xml index fc7d25465569..034ef355421d 100644 --- a/plugins/gradle/src/META-INF/plugin.xml +++ b/plugins/gradle/src/META-INF/plugin.xml @@ -67,12 +67,14 @@ <externalSystemConfigLocator implementation="org.jetbrains.plugins.gradle.service.settings.GradleConfigLocator"/> <externalSystemManager implementation="org.jetbrains.plugins.gradle.GradleManager"/> + <externalProjectDataService implementation="org.jetbrains.plugins.gradle.service.project.data.BuildClasspathModuleGradleDataService"/> <applicationService serviceImplementation="org.jetbrains.plugins.gradle.service.GradleInstallationManager"/> <projectService serviceImplementation="org.jetbrains.plugins.gradle.settings.GradleSettings"/> <projectService serviceImplementation="org.jetbrains.plugins.gradle.settings.GradleLocalSettings"/> <projectService serviceImplementation="org.jetbrains.plugins.gradle.service.project.GradleNotification"/> + <projectService serviceImplementation="org.jetbrains.plugins.gradle.service.GradleBuildClasspathManager"/> <configurationProducer implementation="org.jetbrains.plugins.gradle.service.execution.GradleRuntimeConfigurationProducer"/> diff --git a/plugins/gradle/src/META-INF/services/org.jetbrains.plugins.gradle.model.ModelBuilderService b/plugins/gradle/src/META-INF/services/org.jetbrains.plugins.gradle.model.ModelBuilderService index 3989c7cb0610..430ac6f37ba0 100644 --- a/plugins/gradle/src/META-INF/services/org.jetbrains.plugins.gradle.model.ModelBuilderService +++ b/plugins/gradle/src/META-INF/services/org.jetbrains.plugins.gradle.model.ModelBuilderService @@ -16,3 +16,4 @@ org.jetbrains.plugins.gradle.model.builder.WarModelBuilderImpl org.jetbrains.plugins.gradle.model.builder.ModelDependenciesBuilderImpl org.jetbrains.plugins.gradle.model.builder.ModuleExtendedModelBuilderImpl +org.jetbrains.plugins.gradle.model.builder.ModelBuildScriptClasspathBuilderImpl diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleClassFinder.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleClassFinder.java index f85c75acce16..d1fa23ad150e 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleClassFinder.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleClassFinder.java @@ -16,13 +16,15 @@ package org.jetbrains.plugins.gradle.config; +import com.intellij.openapi.externalSystem.psi.search.ExternalModuleBuildGlobalSearchScope; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.NonClasspathClassFinder; +import com.intellij.psi.search.GlobalSearchScope; import org.jetbrains.annotations.NotNull; -import org.jetbrains.plugins.gradle.service.GradleInstallationManager; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.gradle.service.GradleBuildClasspathManager; -import java.util.Collections; import java.util.List; /** @@ -30,19 +32,31 @@ import java.util.List; */ public class GradleClassFinder extends NonClasspathClassFinder { - @NotNull private final GradleInstallationManager myLibraryManager; + @NotNull private final GradleBuildClasspathManager myBuildClasspathManager; - public GradleClassFinder(Project project, @NotNull GradleInstallationManager manager) { - super(project, true, true); - myLibraryManager = manager; + public GradleClassFinder(Project project, @NotNull GradleBuildClasspathManager buildClasspathManager) { + super(project, true); + myBuildClasspathManager = buildClasspathManager; } @Override protected List<VirtualFile> calcClassRoots() { - final List<VirtualFile> roots = myLibraryManager.getClassRoots(myProject); - if (roots != null) { - return roots; + // do not use default NonClasspathClassFinder caching strategy based on PSI change + // the caching performed in GradleBuildClasspathManager + throw new AssertionError(); + } + + @Override + protected List<VirtualFile> getClassRoots() { + return myBuildClasspathManager.getAllClasspathEntries(); + } + + @Override + protected List<VirtualFile> getClassRoots(@Nullable GlobalSearchScope scope) { + if (scope instanceof ExternalModuleBuildGlobalSearchScope) { + ExternalModuleBuildGlobalSearchScope externalModuleBuildGlobalSearchScope = (ExternalModuleBuildGlobalSearchScope)scope; + return myBuildClasspathManager.getModuleClasspathEntries(externalModuleBuildGlobalSearchScope.getExternalModulePath()); } - return Collections.emptyList(); + return myBuildClasspathManager.getAllClasspathEntries(); } }
\ No newline at end of file diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleScriptType.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleScriptType.java index b7ecd351d58d..d5984903fe90 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleScriptType.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleScriptType.java @@ -21,12 +21,18 @@ import com.intellij.execution.*; import com.intellij.execution.configurations.JavaParameters; import com.intellij.execution.configurations.RunProfile; import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.externalSystem.psi.search.ExternalModuleBuildGlobalSearchScope; import com.intellij.openapi.externalSystem.util.ExternalSystemConstants; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleUtilCore; import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.JdkOrderEntry; +import com.intellij.openapi.roots.ModuleRootManager; +import com.intellij.openapi.roots.OrderEntry; import com.intellij.openapi.roots.OrderEnumerator; +import com.intellij.openapi.roots.impl.LibraryScopeCache; import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.io.FileUtilRt; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; @@ -40,8 +46,10 @@ import icons.GradleIcons; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.gradle.execution.GradleTaskLocation; -import org.jetbrains.plugins.gradle.util.GradleConstants; +import org.jetbrains.plugins.gradle.service.GradleBuildClasspathManager; import org.jetbrains.plugins.gradle.service.GradleInstallationManager; +import org.jetbrains.plugins.gradle.service.resolve.GradleResolverUtil; +import org.jetbrains.plugins.gradle.util.GradleConstants; import org.jetbrains.plugins.groovy.config.GroovyConfigUtils; import org.jetbrains.plugins.groovy.extensions.GroovyScriptType; import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; @@ -72,9 +80,9 @@ public class GradleScriptType extends GroovyScriptType { private static final Pattern MAIN_CLASS_NAME_PATTERN = Pattern.compile("\nSTARTER_MAIN_CLASS=(.*)\n"); public static final GroovyScriptType INSTANCE = new GradleScriptType(); - + private GradleScriptType() { - super(GradleConstants.EXTENSION); + super(GradleConstants.EXTENSION); } @NotNull @@ -89,7 +97,7 @@ public class GradleScriptType extends GroovyScriptType { if (params == null) { return false; } - + final List<String> tasks = getTasksTarget(location); if (tasks == null) { return false; @@ -218,7 +226,9 @@ public class GradleScriptType extends GroovyScriptType { throw new CantRunException(String.format("Module '%s' is not backed by gradle", module.getName())); } final VirtualFile gradleHome = libraryManager.getGradleHome(module, project, rootProjectPath); - assert gradleHome != null; + if(gradleHome == null) { + throw new CantRunException("Gradle home can not be found"); + } params.setMainClass(findMainClass(gradleHome, script, project)); @@ -249,11 +259,11 @@ public class GradleScriptType extends GroovyScriptType { params.getVMParametersList().add("-Dgradle.home=" + FileUtil.toSystemDependentName(gradleHome.getPath())); setToolsJar(params); - + final String scriptPath = configuration.getScriptPath(); if (scriptPath == null) { throw new CantRunException("Target script is undefined"); - } + } params.getProgramParametersList().add("--build-file"); params.getProgramParametersList().add(FileUtil.toSystemDependentName(scriptPath)); params.getProgramParametersList().addParametersString(configuration.getProgramParameters()); @@ -298,22 +308,28 @@ public class GradleScriptType extends GroovyScriptType { @Override public GlobalSearchScope patchResolveScope(@NotNull GroovyFile file, @NotNull GlobalSearchScope baseScope) { + if (!FileUtilRt.extensionEquals(file.getName(), GradleConstants.EXTENSION)) return baseScope; + + final Collection<VirtualFile> files; + GlobalSearchScope result = GlobalSearchScope.EMPTY_SCOPE; final Module module = ModuleUtilCore.findModuleForPsiElement(file); - final GradleInstallationManager libraryManager = ServiceManager.getService(GradleInstallationManager.class); if (module != null) { - if (libraryManager.getGradleHome(module) != null) { - return baseScope; + for (OrderEntry entry : ModuleRootManager.getInstance(module).getOrderEntries()) { + if (entry instanceof JdkOrderEntry) { + GlobalSearchScope scopeForSdk = LibraryScopeCache.getInstance(module.getProject()).getScopeForSdk((JdkOrderEntry)entry); + result = result.uniteWith(scopeForSdk); + } } - } - final Collection<VirtualFile> files = libraryManager.getClassRoots(file.getProject()); - if (files == null || files.isEmpty()) { - return baseScope; - } + String modulePath = module.getOptionValue(ExternalSystemConstants.LINKED_PROJECT_PATH_KEY); + if(modulePath == null) return result; + + files = GradleBuildClasspathManager.getInstance(file.getProject()).getModuleClasspathEntries(modulePath); - GlobalSearchScope result = baseScope; - for (final VirtualFile root : files) { - result = result.uniteWith(new NonClasspathDirectoryScope(root)); + for (final VirtualFile root : files) { + result = result.uniteWith(new NonClasspathDirectoryScope(root)); + } + result = new ExternalModuleBuildGlobalSearchScope(result, modulePath); } return result; } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/integrations/maven/ImportMavenRepositoriesTask.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/integrations/maven/ImportMavenRepositoriesTask.java index f34748e44487..d14125e85122 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/integrations/maven/ImportMavenRepositoriesTask.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/integrations/maven/ImportMavenRepositoriesTask.java @@ -15,6 +15,7 @@ */ package org.jetbrains.plugins.gradle.integrations.maven; +import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.application.Result; import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.externalSystem.util.ExternalSystemConstants; @@ -97,9 +98,9 @@ public class ImportMavenRepositoriesTask implements Runnable { final PsiFile[] psiFiles = ArrayUtil.toObjectArray(psiFileList, PsiFile.class); - final Set<MavenRemoteRepository> mavenRemoteRepositories = new WriteCommandAction<Set<MavenRemoteRepository>>(myProject, psiFiles) { + final Set<MavenRemoteRepository> mavenRemoteRepositories = new ReadAction<Set<MavenRemoteRepository>>() { @Override - protected void run(Result<Set<MavenRemoteRepository>> result) throws Throwable { + protected void run(@NotNull Result<Set<MavenRemoteRepository>> result) throws Throwable { Set<MavenRemoteRepository> myRemoteRepositories = ContainerUtil.newHashSet(); for (PsiFile psiFile : psiFiles) { List<GrClosableBlock> repositoriesBlocks = ContainerUtil.newArrayList(); @@ -118,7 +119,7 @@ public class ImportMavenRepositoriesTask implements Runnable { } }.execute().getResultObject(); - if (mavenRemoteRepositories.isEmpty()) return; + if (mavenRemoteRepositories == null || mavenRemoteRepositories.isEmpty()) return; MavenRepositoriesHolder.getInstance(myProject).update(mavenRemoteRepositories); diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/model/BuildScriptClasspathModel.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/BuildScriptClasspathModel.java new file mode 100644 index 000000000000..6854655609ca --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/BuildScriptClasspathModel.java @@ -0,0 +1,28 @@ +/* + * Copyright 2000-2014 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 org.jetbrains.plugins.gradle.model; + +import org.gradle.tooling.model.DomainObjectSet; + +import java.io.Serializable; + +/** + * @author Vladislav.Soroka + * @since 12/20/13 + */ +public interface BuildScriptClasspathModel extends Serializable { + DomainObjectSet<? extends ClasspathEntryModel> getClasspath(); +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/model/ClasspathEntryModel.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/ClasspathEntryModel.java new file mode 100644 index 000000000000..09120caccacf --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/ClasspathEntryModel.java @@ -0,0 +1,36 @@ +/* + * Copyright 2000-2014 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 org.jetbrains.plugins.gradle.model; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.File; + +/** + * @author Vladislav.Soroka + * @since 12/20/13 + */ +public interface ClasspathEntryModel { + @NotNull + File getClassesFile(); + + @Nullable + File getSourcesFile(); + + @Nullable + File getJavadocFile(); +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/model/GradleDependencyScope.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/GradleDependencyScope.java index 7186312c24b4..78caa4d9f4d5 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/model/GradleDependencyScope.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/GradleDependencyScope.java @@ -22,11 +22,6 @@ import org.jetbrains.annotations.Nullable; * @since 11/25/13 */ public enum GradleDependencyScope { - // Implicit scopes - PROVIDED("provided", "provided", true, true, true, true), - OPTIONAL("optional", "compile", true, true, true, true), - - // Java Plugin Scopes /** * Compile time dependencies @@ -74,7 +69,11 @@ public enum GradleDependencyScope { /** * Compiles test Scala source files. */ - COMPILE_TEST_SCALA("compileTestScala", "test", false, false, true, true); + COMPILE_TEST_SCALA("compileTestScala", "test", false, false, true, true), + + // Implicit scopes + PROVIDED("provided", "provided", true, true, true, true), + OPTIONAL("optional", "compile", true, true, true, true),; private final String myGradleName; private final String myIdeaMappingName; @@ -124,7 +123,7 @@ public enum GradleDependencyScope { @Nullable public static GradleDependencyScope fromIdeaMappingName(final String ideaMappingName) { for (GradleDependencyScope scope : values()) { - if (scope.myIdeaMappingName.equals(ideaMappingName.toLowerCase())) return scope; + if (scope.myIdeaMappingName.equals(ideaMappingName)) return scope; } return null; } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/model/builder/ModelBuildScriptClasspathBuilderImpl.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/builder/ModelBuildScriptClasspathBuilderImpl.java new file mode 100644 index 000000000000..875d9cc26bc6 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/builder/ModelBuildScriptClasspathBuilderImpl.java @@ -0,0 +1,93 @@ +/* + * Copyright 2000-2014 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 org.jetbrains.plugins.gradle.model.builder; + +import org.gradle.api.Project; +import org.gradle.api.artifacts.Configuration; +import org.gradle.plugins.ide.idea.IdeaPlugin; +import org.gradle.plugins.ide.idea.model.IdeaModel; +import org.gradle.plugins.ide.internal.IdeDependenciesExtractor; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.gradle.model.BuildScriptClasspathModel; +import org.jetbrains.plugins.gradle.model.ModelBuilderService; +import org.jetbrains.plugins.gradle.model.internal.BuildScriptClasspathModelImpl; +import org.jetbrains.plugins.gradle.model.internal.ClasspathEntryModelImpl; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +/** + * @author Vladislav.Soroka + * @since 12/20/13 + */ +public class ModelBuildScriptClasspathBuilderImpl implements ModelBuilderService { + + @Override + public boolean canBuild(String modelName) { + return BuildScriptClasspathModel.class.getName().equals(modelName); + } + + @Nullable + @Override + public Object buildAll(final String modelName, final Project project) { + boolean offline = false; + boolean downloadJavadoc = false; + boolean downloadSources = true; + + final IdeaPlugin ideaPlugin = project.getPlugins().getPlugin(IdeaPlugin.class); + + if (ideaPlugin != null) { + IdeaModel ideaModel = ideaPlugin.getModel(); + if (ideaModel != null && ideaModel.getModule() != null) { + offline = ideaModel.getModule().isOffline(); + downloadJavadoc = ideaModel.getModule().isDownloadJavadoc(); + downloadSources = ideaModel.getModule().isDownloadSources(); + } + } + + final IdeDependenciesExtractor dependenciesExtractor = new IdeDependenciesExtractor(); + + final Configuration configuration = project.getBuildscript().getConfigurations().findByName("classpath"); + Collection<Configuration> plusConfigurations = Collections.singletonList(configuration); + + BuildScriptClasspathModelImpl buildScriptClasspath = new BuildScriptClasspathModelImpl(); + + if (!offline) { + // download sources and/or javadoc + List<IdeDependenciesExtractor.IdeRepoFileDependency> repoFileDependencies = dependenciesExtractor.extractRepoFileDependencies( + project.getConfigurations(), plusConfigurations, new ArrayList<Configuration>(), downloadSources, downloadJavadoc); + + for (IdeDependenciesExtractor.IdeRepoFileDependency dependency : repoFileDependencies) { + if (dependency.getFile() == null) continue; + + buildScriptClasspath.add( + new ClasspathEntryModelImpl(dependency.getFile(), dependency.getSourceFile(), dependency.getJavadocFile())); + } + } + + final List<IdeDependenciesExtractor.IdeLocalFileDependency> localFileDependencies = + dependenciesExtractor.extractLocalFileDependencies(plusConfigurations, new ArrayList<Configuration>()); + + for (IdeDependenciesExtractor.IdeLocalFileDependency dependency : localFileDependencies) { + if (dependency.getFile() == null) continue; + buildScriptClasspath.add(new ClasspathEntryModelImpl(dependency.getFile(), null, null)); + } + + return buildScriptClasspath; + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/model/builder/ModelDependenciesBuilderImpl.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/builder/ModelDependenciesBuilderImpl.java index 05864829e6ed..4c0e3914185e 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/model/builder/ModelDependenciesBuilderImpl.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/builder/ModelDependenciesBuilderImpl.java @@ -24,6 +24,7 @@ import org.gradle.plugins.ide.idea.IdeaPlugin; import org.gradle.plugins.ide.idea.model.IdeaModel; import org.gradle.plugins.ide.internal.IdeDependenciesExtractor; import org.gradle.tooling.model.idea.IdeaDependency; +import org.gradle.util.GradleVersion; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.gradle.model.GradleDependencyScope; import org.jetbrains.plugins.gradle.model.ModelBuilderService; @@ -54,7 +55,7 @@ public class ModelDependenciesBuilderImpl implements ModelBuilderService { public Object buildAll(final String modelName, final Project project) { final List<IdeaDependency> dependencies = new ArrayList<IdeaDependency>(); - final Map<DependencyVersionId, Scopes> scopesMap = new HashMap<DependencyVersionId, Scopes>(); + final Map<DependencyVersionId, Scopes> scopesMap = new LinkedHashMap<DependencyVersionId, Scopes>(); final IdeDependenciesExtractor dependenciesExtractor = new IdeDependenciesExtractor(); boolean offline = false; @@ -148,6 +149,7 @@ public class ModelDependenciesBuilderImpl implements ModelBuilderService { versionId.getClassifier() ); libraryDependency.setFile(fileDependency.getFile()); + attachGradleSdkSources(libraryDependency, fileDependency); dependencies.add(libraryDependency); } } @@ -156,6 +158,32 @@ public class ModelDependenciesBuilderImpl implements ModelBuilderService { return new ProjectDependenciesModelImpl(project.getPath(), dependencies); } + private static void attachGradleSdkSources(IdeaSingleEntryLibraryDependencyImpl libraryDependency, + IdeDependenciesExtractor.IdeLocalFileDependency localFileDependency) { + final String libName = localFileDependency.getFile().getName(); + if (localFileDependency.getFile() == null || !libName.startsWith("gradle-")) return; + + File libOrPluginsFile = localFileDependency.getFile().getParentFile(); + if (libOrPluginsFile != null && ("plugins".equals(libOrPluginsFile.getName()))) { + libOrPluginsFile = libOrPluginsFile.getParentFile(); + } + + if (libOrPluginsFile != null && "lib".equals(libOrPluginsFile.getName()) && libOrPluginsFile.getParentFile() != null) { + File srcDir = new File(libOrPluginsFile.getParentFile(), "src"); + if (GradleVersion.current().compareTo(GradleVersion.version("1.9")) >= 0) { + int endIndex = libName.indexOf(GradleVersion.current().getVersion() + ".jar"); + if (endIndex != -1) { + String srcDirChild = libName.substring("gradle-".length(), endIndex - 1); + srcDir = new File(srcDir, srcDirChild); + } + } + + if (srcDir.isDirectory()) { + libraryDependency.setSource(srcDir); + } + } + } + @Nullable private static String findDeDuplicatedModuleName(Project project) { if (project.hasProperty(MODULE_PROPERTY)) { @@ -261,15 +289,13 @@ public class ModelDependenciesBuilderImpl implements ModelBuilderService { private static GradleDependencyScope deduceScope(String configurationName, Map<String, Map<String, Collection<Configuration>>> userScopes) { GradleDependencyScope scope = GradleDependencyScope.fromName(configurationName); - if (scope == null) { - for (Map.Entry<String, Map<String, Collection<Configuration>>> entry : userScopes.entrySet()) { - Collection<Configuration> plusConfigurations = entry.getValue().get("plus"); - if (plusConfigurations == null) continue; - - for (Configuration plus : plusConfigurations) { - if (plus.getName().equals(configurationName)) { - return GradleDependencyScope.fromIdeaMappingName(entry.getKey()); - } + for (Map.Entry<String, Map<String, Collection<Configuration>>> entry : userScopes.entrySet()) { + Collection<Configuration> plusConfigurations = entry.getValue().get("plus"); + if (plusConfigurations == null) continue; + + for (Configuration plus : plusConfigurations) { + if (plus.getName().equals(configurationName)) { + return GradleDependencyScope.fromIdeaMappingName(entry.getKey().toLowerCase()); } } } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/model/builder/ModuleExtendedModelBuilderImpl.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/builder/ModuleExtendedModelBuilderImpl.java index 3dc854020c6c..44eb6cfe328b 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/model/builder/ModuleExtendedModelBuilderImpl.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/builder/ModuleExtendedModelBuilderImpl.java @@ -15,6 +15,7 @@ */ package org.jetbrains.plugins.gradle.model.builder; +import groovy.lang.GroovyObject; import org.gradle.api.Project; import org.gradle.api.Task; import org.gradle.api.tasks.SourceSet; @@ -69,10 +70,17 @@ public class ModuleExtendedModelBuilderImpl implements ModelBuilderService { moduleVersionModel.setArtifacts(artifacts); + final Set<String> sourceDirectories = new HashSet<String>(); final Set<String> testDirectories = new HashSet<String>(); + final Set<String> resourceDirectories = new HashSet<String>(); + final Set<String> testResourceDirectories = new HashSet<String>(); + + final List<File> testClassesDirs = new ArrayList<File>(); for (Task task : project.getTasks()) { if (task instanceof Test) { Test test = (Test)task; + testClassesDirs.add(test.getTestClassesDir()); + if (test.hasProperty(TEST_SRC_DIRS_PROPERTY)) { Object testSrcDirs = test.property(TEST_SRC_DIRS_PROPERTY); if (testSrcDirs instanceof Iterable) { @@ -84,40 +92,58 @@ public class ModuleExtendedModelBuilderImpl implements ModelBuilderService { } } - final Set<String> javaDirectories = new HashSet<String>(); - final Set<String> resourceDirectories = new HashSet<String>(); - if (project.hasProperty(SOURCE_SETS_PROPERTY)) { Object sourceSets = project.property(SOURCE_SETS_PROPERTY); if (sourceSets instanceof SourceSetContainer) { SourceSetContainer sourceSetContainer = (SourceSetContainer)sourceSets; for (SourceSet sourceSet : sourceSetContainer) { - for (File javaSrcDir : sourceSet.getAllJava().getSrcDirs()) { - addFilePath(javaDirectories, javaSrcDir); + for (File javaSrcDir : sourceSet.getJava().getSrcDirs()) { + boolean isTestDir = isTestDir(sourceSet, testClassesDirs); + addFilePath(isTestDir ? testDirectories : sourceDirectories, javaSrcDir); } for (File resourcesSrcDir : sourceSet.getResources().getSrcDirs()) { - addFilePath(resourceDirectories, resourcesSrcDir); + boolean isTestDir = isTestDir(sourceSet, testClassesDirs); + addFilePath(isTestDir ? testResourceDirectories : resourceDirectories, resourcesSrcDir); } } } } - File projectDir = project.getProjectDir(); IdeaContentRootImpl contentRoot = new IdeaContentRootImpl(projectDir); - enrichDataFromIdeaPlugin(project, contentRoot, javaDirectories, testDirectories); + final Set<String> ideaSourceDirectories = new HashSet<String>(); + final Set<String> ideaTestDirectories = new HashSet<String>(); + final Set<String> ideaExtResourceDirectories = new HashSet<String>(); + final Set<String> ideaExtTestResourceDirectories = new HashSet<String>(); + final Set<File> excludeDirectories = new HashSet<File>(); + + enrichDataFromIdeaPlugin(project, excludeDirectories, ideaSourceDirectories, ideaTestDirectories, + ideaExtResourceDirectories, ideaExtTestResourceDirectories); - javaDirectories.removeAll(testDirectories); - javaDirectories.removeAll(resourceDirectories); + if (ideaSourceDirectories.isEmpty()) { + sourceDirectories.clear(); + resourceDirectories.clear(); + } + if (ideaTestDirectories.isEmpty()) { + testDirectories.clear(); + testResourceDirectories.clear(); + } - final Set<String> testResourceDirectories = new HashSet<String>(resourceDirectories); - testResourceDirectories.retainAll(testDirectories); + ideaSourceDirectories.removeAll(resourceDirectories); + sourceDirectories.addAll(ideaSourceDirectories); + ideaTestDirectories.removeAll(testResourceDirectories); + testDirectories.addAll(ideaTestDirectories); - testDirectories.removeAll(resourceDirectories); - resourceDirectories.removeAll(testResourceDirectories); + resourceDirectories.addAll(ideaExtResourceDirectories); + testResourceDirectories.addAll(ideaExtTestResourceDirectories); - for (String javaDir : javaDirectories) { + // ensure disjoint directories with different type + resourceDirectories.removeAll(sourceDirectories); + testDirectories.removeAll(sourceDirectories); + testResourceDirectories.removeAll(testDirectories); + + for (String javaDir : sourceDirectories) { contentRoot.addSourceDirectory(new IdeaSourceDirectoryImpl(new File(javaDir))); } for (String testDir : testDirectories) { @@ -129,11 +155,29 @@ public class ModuleExtendedModelBuilderImpl implements ModelBuilderService { for (String testResourceDir : testResourceDirectories) { contentRoot.addTestResourceDirectory(new IdeaSourceDirectoryImpl(new File(testResourceDir))); } + for (File excludeDir : excludeDirectories) { + contentRoot.addExcludeDirectory(excludeDir); + } moduleVersionModel.setContentRoots(Collections.<ExtIdeaContentRoot>singleton(contentRoot)); return moduleVersionModel; } + private static boolean isTestDir(SourceSet sourceSet, List<File> testClassesDirs) { + if (SourceSet.TEST_SOURCE_SET_NAME.equals(sourceSet.getName())) return true; + if (SourceSet.MAIN_SOURCE_SET_NAME.equals(sourceSet.getName())) return false; + + File sourceSetClassesDir = sourceSet.getOutput().getClassesDir(); + for (File testClassesDir : testClassesDirs) { + do { + if (sourceSetClassesDir.getPath().equals(testClassesDir.getPath())) return true; + } + while ((testClassesDir = testClassesDir.getParentFile()) != null); + } + + return false; + } + private static void addFilePath(Set<String> filePathSet, Object file) { if (file instanceof File) { try { @@ -145,9 +189,11 @@ public class ModuleExtendedModelBuilderImpl implements ModelBuilderService { } private static void enrichDataFromIdeaPlugin(Project project, - IdeaContentRootImpl contentRoot, + Set<File> excludeDirectories, Set<String> javaDirectories, - Set<String> testDirectories) { + Set<String> testDirectories, + Set<String> ideaExtResourceDirectories, + Set<String> ideaExtTestResourceDirectories) { IdeaPlugin ideaPlugin = project.getPlugins().getPlugin(IdeaPlugin.class); if (ideaPlugin == null) return; @@ -156,7 +202,7 @@ public class ModuleExtendedModelBuilderImpl implements ModelBuilderService { if (ideaModel == null || ideaModel.getModule() == null) return; for (File excludeDir : ideaModel.getModule().getExcludeDirs()) { - contentRoot.addExcludeDirectory(excludeDir); + excludeDirectories.add(excludeDir); } for (File file : ideaModel.getModule().getSourceDirs()) { javaDirectories.add(file.getPath()); @@ -164,5 +210,25 @@ public class ModuleExtendedModelBuilderImpl implements ModelBuilderService { for (File file : ideaModel.getModule().getTestSourceDirs()) { testDirectories.add(file.getPath()); } + + ideaExtResourceDirectories.addAll(getExtDirs("resourceDirs", ideaModel.getModule())); + ideaExtTestResourceDirectories.addAll(getExtDirs("testResourceDirs", ideaModel.getModule())); + } + + private static List<String> getExtDirs(String propertyName, GroovyObject ideaModule) { + List<String> directories = new ArrayList<String>(); + Object resourceDirs = ideaModule.getProperty(propertyName); + if (resourceDirs instanceof Iterable) { + for (Object o : Iterable.class.cast(resourceDirs)) { + if (o instanceof File) { + directories.add(File.class.cast(o).getPath()); + } + else if (o instanceof String) { + directories.add((String)o); + } + } + } + + return directories; } } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/model/data/BuildScriptClasspathData.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/data/BuildScriptClasspathData.java new file mode 100644 index 000000000000..cc252a9750a0 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/data/BuildScriptClasspathData.java @@ -0,0 +1,49 @@ +/* + * Copyright 2000-2014 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 org.jetbrains.plugins.gradle.model.data; + +import com.intellij.openapi.externalSystem.model.Key; +import com.intellij.openapi.externalSystem.model.ProjectKeys; +import com.intellij.openapi.externalSystem.model.ProjectSystemId; +import com.intellij.openapi.externalSystem.model.project.AbstractExternalEntityData; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +/** + * @author Vladislav.Soroka + * @since 12/20/13 + */ +public class BuildScriptClasspathData extends AbstractExternalEntityData { + private static final long serialVersionUID = 1L; + @NotNull + public static final Key<BuildScriptClasspathData> KEY = + Key.create(BuildScriptClasspathData.class, ProjectKeys.LIBRARY_DEPENDENCY.getProcessingWeight() + 1); + + @NotNull + private final List<ClasspathEntry> myClasspathEntries; + + + public BuildScriptClasspathData(@NotNull ProjectSystemId owner, @NotNull List<ClasspathEntry> classpathEntries) { + super(owner); + myClasspathEntries = classpathEntries; + } + + @NotNull + public List<ClasspathEntry> getClasspathEntries() { + return myClasspathEntries; + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/model/data/ClasspathEntry.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/data/ClasspathEntry.java new file mode 100644 index 000000000000..fa0959ff74ad --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/data/ClasspathEntry.java @@ -0,0 +1,84 @@ +/* + * Copyright 2000-2014 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 org.jetbrains.plugins.gradle.model.data; + +import com.intellij.openapi.util.io.FileUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.File; +import java.io.Serializable; + +/** + * @author Vladislav.Soroka + * @since 12/23/13 + */ +public class ClasspathEntry implements Serializable { + + private static final long serialVersionUID = 1L; + + @NotNull + private final File myClassesFile; + + @Nullable + private final File mySourcesFile; + + @Nullable + private final File myJavadocFile; + + public ClasspathEntry(@NotNull File classesFile, @Nullable File sourcesFile, @Nullable File javadocFile) { + myClassesFile = classesFile; + mySourcesFile = sourcesFile; + myJavadocFile = javadocFile; + } + + @NotNull + public File getClassesFile() { + return myClassesFile; + } + + @Nullable + public File getSourcesFile() { + return mySourcesFile; + } + + @Nullable + public File getJavadocFile() { + return myJavadocFile; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof ClasspathEntry)) return false; + + ClasspathEntry entry = (ClasspathEntry)o; + + if (!FileUtil.filesEqual(myClassesFile, entry.myClassesFile)) return false; + if (!FileUtil.filesEqual(myJavadocFile, entry.myJavadocFile)) return false; + if (!FileUtil.filesEqual(mySourcesFile, entry.mySourcesFile)) return false; + + return true; + } + + @Override + public int hashCode() { + int result = FileUtil.fileHashCode(myClassesFile); + result = 31 * result + FileUtil.fileHashCode(mySourcesFile); + result = 31 * result + FileUtil.fileHashCode(myJavadocFile); + return result; + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/model/internal/BuildScriptClasspathModelImpl.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/internal/BuildScriptClasspathModelImpl.java new file mode 100644 index 000000000000..b59241181110 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/internal/BuildScriptClasspathModelImpl.java @@ -0,0 +1,47 @@ +/* + * Copyright 2000-2014 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 org.jetbrains.plugins.gradle.model.internal; + +import org.gradle.tooling.model.DomainObjectSet; +import org.gradle.tooling.model.internal.ImmutableDomainObjectSet; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.gradle.model.BuildScriptClasspathModel; +import org.jetbrains.plugins.gradle.model.ClasspathEntryModel; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Vladislav.Soroka + * @since 12/20/13 + */ +public class BuildScriptClasspathModelImpl implements BuildScriptClasspathModel { + + private final List<ClasspathEntryModel> myClasspathEntries; + + public BuildScriptClasspathModelImpl() { + myClasspathEntries = new ArrayList<ClasspathEntryModel>(); + } + + @Override + public DomainObjectSet<? extends ClasspathEntryModel> getClasspath() { + return ImmutableDomainObjectSet.of(myClasspathEntries); + } + + public void add(@NotNull ClasspathEntryModel classpathEntryModel) { + myClasspathEntries.add(classpathEntryModel); + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/model/internal/ClasspathEntryModelImpl.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/internal/ClasspathEntryModelImpl.java new file mode 100644 index 000000000000..06188100d4ab --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/internal/ClasspathEntryModelImpl.java @@ -0,0 +1,60 @@ +/* + * Copyright 2000-2014 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 org.jetbrains.plugins.gradle.model.internal; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.gradle.model.ClasspathEntryModel; + +import java.io.File; +import java.io.Serializable; + +/** + * @author Vladislav.Soroka + * @since 12/20/13 + */ +public class ClasspathEntryModelImpl implements ClasspathEntryModel, Serializable { + @NotNull + private final File classesFile; + @Nullable + private final File sourcesFile; + @Nullable + private final File javadocFile; + + public ClasspathEntryModelImpl(@NotNull File classesFile, @Nullable File sourcesFile, @Nullable File javadocFile) { + this.classesFile = classesFile; + this.sourcesFile = sourcesFile; + this.javadocFile = javadocFile; + } + + @NotNull + @Override + public File getClassesFile() { + return classesFile; + } + + @Nullable + @Override + public File getSourcesFile() { + return sourcesFile; + } + + @Nullable + @Override + public File getJavadocFile() { + return javadocFile; + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/model/internal/buildSrcInit.gradle b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/internal/buildSrcInit.gradle new file mode 100644 index 000000000000..91140f2fcec6 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/internal/buildSrcInit.gradle @@ -0,0 +1,25 @@ +/* + * Copyright 2000-2014 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. + */ + +allprojects { project -> + if(project.name == 'buildSrc') { + apply plugin: 'groovy' + dependencies { + compile gradleApi() + compile localGroovy() + } + } +}
\ No newline at end of file diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/model/internal/init.gradle b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/internal/init.gradle index a788cb85d83d..4f382fd42590 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/model/internal/init.gradle +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/internal/init.gradle @@ -34,6 +34,10 @@ try { URLClassLoader classLoader = new URLClassLoader(urls, getClass().classLoader) Class modelClass = classLoader.loadClass('org.jetbrains.plugins.gradle.model.internal.ExtraModelBuilder') allprojects { + apply plugin: 'idea' + idea.module.ext.set('resourceDirs', []) + idea.module.ext.set('testResourceDirs', []) + ext.jetExtraModelBuilderClass = modelClass apply plugin: JetGradlePlugin } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/GradleBuildClasspathManager.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/GradleBuildClasspathManager.java new file mode 100644 index 000000000000..512bd70ecfe0 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/GradleBuildClasspathManager.java @@ -0,0 +1,111 @@ +/* + * Copyright 2000-2014 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 org.jetbrains.plugins.gradle.service; + +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.externalSystem.ExternalSystemManager; +import com.intellij.openapi.externalSystem.model.project.ExternalModuleBuildClasspathPojo; +import com.intellij.openapi.externalSystem.model.project.ExternalProjectBuildClasspathPojo; +import com.intellij.openapi.externalSystem.settings.AbstractExternalSystemLocalSettings; +import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.JarFileSystem; +import com.intellij.openapi.vfs.LocalFileSystem; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.gradle.util.GradleConstants; + +import java.util.*; +import java.util.concurrent.atomic.AtomicReference; + +/** + * @author Vladislav.Soroka + * @since 12/27/13 + */ +public class GradleBuildClasspathManager { + @NotNull + private final Project myProject; + + @NotNull + private volatile List<VirtualFile> allFilesCache; + + @NotNull + private final AtomicReference<Map<String/*module path*/, List<VirtualFile> /*module build classpath*/>> myClasspathMap + = new AtomicReference<Map<String, List<VirtualFile>>>(new HashMap<String, List<VirtualFile>>()); + + public GradleBuildClasspathManager(@NotNull Project project) { + myProject = project; + reload(); + } + + @NotNull + public static GradleBuildClasspathManager getInstance(@NotNull Project project) { + return ServiceManager.getService(project, GradleBuildClasspathManager.class); + } + + public void reload() { + ExternalSystemManager<?, ?, ?, ?, ?> manager = ExternalSystemApiUtil.getManager(GradleConstants.SYSTEM_ID); + assert manager != null; + AbstractExternalSystemLocalSettings localSettings = manager.getLocalSettingsProvider().fun(myProject); + + Map<String/*module path*/, List<VirtualFile> /*module build classpath*/> map = ContainerUtil.newHashMap(); + + final LocalFileSystem localFileSystem = LocalFileSystem.getInstance(); + final JarFileSystem jarFileSystem = JarFileSystem.getInstance(); + for (ExternalProjectBuildClasspathPojo projectBuildClasspathPojo : localSettings.getProjectBuildClasspath().values()) { + List<VirtualFile> projectBuildClasspath = ContainerUtil.newArrayList(); + for (String path : projectBuildClasspathPojo.getProjectBuildClasspath()) { + final VirtualFile virtualFile = localFileSystem.refreshAndFindFileByPath(path); + if (virtualFile != null) { + ContainerUtil.addIfNotNull( + projectBuildClasspath, virtualFile.isDirectory() ? virtualFile : jarFileSystem.getJarRootForLocalFile(virtualFile)); + } + } + + for (ExternalModuleBuildClasspathPojo moduleBuildClasspathPojo : projectBuildClasspathPojo.getModulesBuildClasspath().values()) { + List<VirtualFile> moduleBuildClasspath = ContainerUtil.newArrayList(projectBuildClasspath); + for (String path : moduleBuildClasspathPojo.getEntries()) { + final VirtualFile virtualFile = localFileSystem.refreshAndFindFileByPath(path); + if (virtualFile != null) { + ContainerUtil.addIfNotNull(moduleBuildClasspath, jarFileSystem.getJarRootForLocalFile(virtualFile)); + } + } + + map.put(moduleBuildClasspathPojo.getPath(), moduleBuildClasspath); + } + } + + myClasspathMap.set(map); + + Set<VirtualFile> set = new LinkedHashSet<VirtualFile>(); + for (List<VirtualFile> virtualFiles : myClasspathMap.get().values()) { + set.addAll(virtualFiles); + } + allFilesCache = ContainerUtil.newArrayList(set); + } + + @NotNull + public List<VirtualFile> getAllClasspathEntries() { + return allFilesCache; + } + + @NotNull + public List<VirtualFile> getModuleClasspathEntries(@NotNull String externalModulePath) { + List<VirtualFile> virtualFiles = myClasspathMap.get().get(externalModulePath); + return virtualFiles == null ? Collections.<VirtualFile>emptyList() : virtualFiles; + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/GradleInstallationManager.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/GradleInstallationManager.java index 715db5a94015..95fdb0a7f244 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/GradleInstallationManager.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/GradleInstallationManager.java @@ -10,6 +10,7 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.JarFileSystem; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.ContainerUtilRt; import org.gradle.StartParameter; @@ -49,6 +50,9 @@ public class GradleInstallationManager { public static final Pattern GRADLE_JAR_FILE_PATTERN; public static final Pattern ANY_GRADLE_JAR_FILE_PATTERN; + public static final Pattern ANT_JAR_PATTERN = Pattern.compile("ant(-(.*))?\\.jar"); + public static final Pattern IVY_JAR_PATTERN = Pattern.compile("ivy(-(.*))?\\.jar"); + private static final String[] GRADLE_START_FILE_NAMES; @NonNls private static final String GRADLE_ENV_PROPERTY_NAME; @@ -375,57 +379,83 @@ public class GradleInstallationManager { */ @Nullable public List<VirtualFile> getClassRoots(@Nullable Project project) { + List<File> files = getClassRoots(project, null); + if(files == null) return null; + final LocalFileSystem localFileSystem = LocalFileSystem.getInstance(); + final JarFileSystem jarFileSystem = JarFileSystem.getInstance(); + return ContainerUtil.mapNotNull(files, new Function<File, VirtualFile>() { + @Override + public VirtualFile fun(File file) { + final VirtualFile virtualFile = localFileSystem.refreshAndFindFileByIoFile(file); + return virtualFile != null ? jarFileSystem.getJarRootForLocalFile(virtualFile) : null; + } + }); + } + + @Nullable + public List<File> getClassRoots(@Nullable Project project, @Nullable String rootProjectPath) { if (project == null) return null; - for (Module module : myPlatformFacade.getModules(project)) { - String rootProjectPath = module.getOptionValue(ExternalSystemConstants.ROOT_PROJECT_PATH_KEY); - if (StringUtil.isEmpty(rootProjectPath)) { - continue; + if(rootProjectPath == null) { + for (Module module : myPlatformFacade.getModules(project)) { + rootProjectPath = module.getOptionValue(ExternalSystemConstants.ROOT_PROJECT_PATH_KEY); + List<File> result = findGradleSdkClasspath(project, rootProjectPath); + if(!result.isEmpty()) return result; } - File gradleHome = getGradleHome(module.getProject(), rootProjectPath); + } else { + return findGradleSdkClasspath(project, rootProjectPath); + } - if (gradleHome == null || !gradleHome.isDirectory()) { - continue; - } + return null; + } - final Collection<File> libraries = getAllLibraries(gradleHome); - if (libraries == null) { - continue; - } - final LocalFileSystem localFileSystem = LocalFileSystem.getInstance(); - final JarFileSystem jarFileSystem = JarFileSystem.getInstance(); - List<VirtualFile> result = new ArrayList<VirtualFile>(); - for (File file : libraries) { - if (ANY_GRADLE_JAR_FILE_PATTERN.matcher(file.getName()).matches() || GroovyConfigUtils.matchesGroovyAll(file.getName())) { - final VirtualFile virtualFile = localFileSystem.refreshAndFindFileByIoFile(file); - if (virtualFile != null) { - ContainerUtil.addIfNotNull(result, jarFileSystem.getJarRootForLocalFile(virtualFile)); - } - } - } + private List<File> findGradleSdkClasspath(Project project, String rootProjectPath) { + List<File> result = new ArrayList<File>(); - File src = new File(gradleHome, "src"); - if (src.isDirectory()) { - if(new File(src, "org").isDirectory()) { - addRoots(localFileSystem, result, src); - } else { - addRoots(localFileSystem, result, src.listFiles()); - } - } + if (StringUtil.isEmpty(rootProjectPath)) return result; + + File gradleHome = getGradleHome(project, rootProjectPath); + if (gradleHome == null || !gradleHome.isDirectory()) { return result; } - return null; + + final Collection<File> libraries = getAllLibraries(gradleHome); + if (libraries == null) { + return result; + } + + for (File file : libraries) { + if (isGradleBuildClasspathLibrary(file)) { + ContainerUtil.addIfNotNull(result, file); + } + } + + File src = new File(gradleHome, "src"); + if (src.isDirectory()) { + if(new File(src, "org").isDirectory()) { + addRoots(result, src); + } else { + addRoots(result, src.listFiles()); + } + } + + return result; + } + + private boolean isGradleBuildClasspathLibrary(File file) { + String fileName = file.getName(); + return ANY_GRADLE_JAR_FILE_PATTERN.matcher(fileName).matches() + || ANT_JAR_PATTERN.matcher(fileName).matches() + || IVY_JAR_PATTERN.matcher(fileName).matches() + || GroovyConfigUtils.matchesGroovyAll(fileName); } - private void addRoots(@NotNull LocalFileSystem localFileSystem, @NotNull List<VirtualFile> result, @Nullable File... files) { - if(files == null) return; + private void addRoots(@NotNull List<File> result, @Nullable File... files) { + if (files == null) return; for (File file : files) { - if(file == null || !file.isDirectory()) continue; - final VirtualFile virtualFile = localFileSystem.refreshAndFindFileByIoFile(file); - if (virtualFile != null) { - result.add(0, virtualFile); - } + if (file == null || !file.isDirectory()) continue; + result.add(0, file); } } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/BaseGradleProjectResolverExtension.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/BaseGradleProjectResolverExtension.java index 0a28fccd3347..b2eb6a0e089e 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/BaseGradleProjectResolverExtension.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/BaseGradleProjectResolverExtension.java @@ -35,8 +35,10 @@ import com.intellij.openapi.module.StdModuleTypes; import com.intellij.openapi.roots.DependencyScope; import com.intellij.openapi.util.KeyValue; import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.pom.java.LanguageLevel; import com.intellij.util.BooleanFunction; +import com.intellij.util.Function; import com.intellij.util.PathUtil; import com.intellij.util.PathsList; import com.intellij.util.containers.ContainerUtil; @@ -51,9 +53,9 @@ import org.gradle.tooling.model.idea.*; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.plugins.gradle.model.ExtIdeaContentRoot; -import org.jetbrains.plugins.gradle.model.ModuleExtendedModel; -import org.jetbrains.plugins.gradle.model.ProjectDependenciesModel; +import org.jetbrains.plugins.gradle.model.*; +import org.jetbrains.plugins.gradle.model.data.BuildScriptClasspathData; +import org.jetbrains.plugins.gradle.model.data.ClasspathEntry; import org.jetbrains.plugins.gradle.util.GradleBundle; import org.jetbrains.plugins.gradle.util.GradleConstants; import org.jetbrains.plugins.gradle.util.GradleUtil; @@ -132,14 +134,16 @@ public class BaseGradleProjectResolverExtension implements GradleProjectResolver "Creating module data ('%s') with the external config path: '%s'", gradleModule.getGradleProject().getPath(), moduleConfigPath )); } - ModuleData moduleData = new ModuleData(gradleModule.getGradleProject().getPath(), + + final String path = gradleModule.getGradleProject().getPath(); + final ModuleData moduleData = new ModuleData(StringUtil.isEmpty(path) || ":".equals(path) ? moduleName : path, GradleConstants.SYSTEM_ID, StdModuleTypes.JAVA.getId(), moduleName, moduleConfigPath, moduleConfigPath); - ModuleExtendedModel moduleExtendedModel = resolverCtx.getExtraProject(gradleModule, ModuleExtendedModel.class); + final ModuleExtendedModel moduleExtendedModel = resolverCtx.getExtraProject(gradleModule, ModuleExtendedModel.class); if (moduleExtendedModel != null) { moduleData.setGroup(moduleExtendedModel.getGroup()); moduleData.setVersion(moduleExtendedModel.getVersion()); @@ -150,6 +154,19 @@ public class BaseGradleProjectResolverExtension implements GradleProjectResolver @Override public void populateModuleExtraModels(@NotNull IdeaModule gradleModule, @NotNull DataNode<ModuleData> ideModule) { + BuildScriptClasspathModel buildScriptClasspathModel = resolverCtx.getExtraProject(gradleModule, BuildScriptClasspathModel.class); + if (buildScriptClasspathModel != null) { + List<ClasspathEntry> classpathEntries = + ContainerUtil.map(buildScriptClasspathModel.getClasspath(), new Function<ClasspathEntryModel, ClasspathEntry>() { + @Override + public ClasspathEntry fun(ClasspathEntryModel model) { + return new ClasspathEntry(model.getClassesFile(), model.getSourcesFile(), model.getJavadocFile()); + } + }); + BuildScriptClasspathData buildScriptClasspathData = + new BuildScriptClasspathData(GradleConstants.SYSTEM_ID, classpathEntries); + ideModule.createChild(BuildScriptClasspathData.KEY, buildScriptClasspathData); + } } @Override @@ -289,7 +306,7 @@ public class BaseGradleProjectResolverExtension implements GradleProjectResolver @NotNull @Override public Set<Class> getExtraProjectModelClasses() { - return ContainerUtil.<Class>set(ModuleExtendedModel.class, ProjectDependenciesModel.class); + return ContainerUtil.<Class>set(ModuleExtendedModel.class, ProjectDependenciesModel.class, BuildScriptClasspathModel.class); } @NotNull diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleExecutionHelper.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleExecutionHelper.java index e4ae7b389306..39dfe9afdbe5 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleExecutionHelper.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleExecutionHelper.java @@ -355,22 +355,46 @@ public class GradleExecutionHelper { } @SuppressWarnings("IOResourceOpenedButNotSafelyClosed") - public static void setInitScript(LongRunningOperation longRunningOperation) { + public static boolean setInitScript(@NotNull LongRunningOperation longRunningOperation, boolean isBuildSrcProject) { try { InputStream stream = GradleProjectResolver.class.getResourceAsStream("/org/jetbrains/plugins/gradle/model/internal/init.gradle"); - if (stream == null) return; + if (stream == null) return isBuildSrcProject; String jarPath = PathUtil.getCanonicalPath(PathUtil.getJarPathForClass(GradleProjectResolver.class)); String s = FileUtil.loadTextAndClose(stream).replace("${JAR_PATH}", jarPath); + if(isBuildSrcProject) { + String buildSrcDefaultInitScript = getBuildSrcDefaultInitScript(); + if(buildSrcDefaultInitScript == null) return false; + s += buildSrcDefaultInitScript; + } + final File tempFile = FileUtil.createTempFile("ijinit", '.' + GradleConstants.EXTENSION, true); FileUtil.writeToFile(tempFile, s); String[] buildExecutorArgs = new String[]{"--init-script", tempFile.getAbsolutePath()}; longRunningOperation.withArguments(buildExecutorArgs); + + return true; + } + catch (Exception e) { + LOG.warn("Can't use IJ gradle init script", e); + return false; + } + } + + @Nullable + @SuppressWarnings("IOResourceOpenedButNotSafelyClosed") + public static String getBuildSrcDefaultInitScript() { + try { + InputStream stream = GradleProjectResolver.class.getResourceAsStream("/org/jetbrains/plugins/gradle/model/internal/buildSrcInit.gradle"); + if (stream == null) return null; + + return FileUtil.loadTextAndClose(stream); } catch (Exception e) { LOG.warn("Can't use IJ gradle init script", e); + return null; } } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleProjectResolver.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleProjectResolver.java index 1b1997b048a2..29a27ba94c0f 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleProjectResolver.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleProjectResolver.java @@ -32,6 +32,7 @@ import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; import com.intellij.openapi.externalSystem.util.ExternalSystemDebugEnvironment; import com.intellij.openapi.util.KeyValue; import com.intellij.openapi.util.Pair; +import com.intellij.util.BooleanFunction; import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.ContainerUtilRt; @@ -52,6 +53,7 @@ import org.jetbrains.plugins.gradle.settings.GradleExecutionSettings; import org.jetbrains.plugins.gradle.util.GradleConstants; import org.jetbrains.plugins.gradle.util.GradleEnvironment; +import java.io.File; import java.util.*; /** @@ -110,19 +112,19 @@ public class GradleProjectResolver implements ExternalSystemProjectResolver<Grad projectResolverChain = new BaseGradleProjectResolverExtension(); } - return myHelper.execute(projectPath, settings, new Function<ProjectConnection, DataNode<ProjectData>>() { - @Override - public DataNode<ProjectData> fun(ProjectConnection connection) { - try { - return doResolveProjectInfo( - new ProjectResolverContext(id, projectPath, settings, connection, listener, isPreviewMode), projectResolverChain); - } - catch (RuntimeException e) { - LOG.info("Gradle project resolve error", e); - throw projectResolverChain.getUserFriendlyError(e, projectPath, null); - } - } - }); + final DataNode<ProjectData> resultProjectDataNode = myHelper.execute( + projectPath, settings, + new ProjectConnectionDataNodeFunction( + id, projectPath, settings, listener, isPreviewMode, projectResolverChain, false) + ); + + // auto-discover buildSrc project if needed + final String buildSrcProjectPath = projectPath + "/buildSrc"; + handleBuildSrcProject( + resultProjectDataNode, + new ProjectConnectionDataNodeFunction(id, buildSrcProjectPath, settings, listener, isPreviewMode, projectResolverChain, true) + ); + return resultProjectDataNode; } @Override @@ -133,7 +135,8 @@ public class GradleProjectResolver implements ExternalSystemProjectResolver<Grad @NotNull private DataNode<ProjectData> doResolveProjectInfo(@NotNull final ProjectResolverContext resolverCtx, - @NotNull final GradleProjectResolverExtension projectResolverChain) + @NotNull final GradleProjectResolverExtension projectResolverChain, + boolean isBuildSrcProject) throws IllegalArgumentException, IllegalStateException { final ProjectImportAction projectImportAction = new ProjectImportAction(resolverCtx.isPreviewMode()); @@ -162,7 +165,7 @@ public class GradleProjectResolver implements ExternalSystemProjectResolver<Grad // TODO [vlad] remove the check if (!GradleEnvironment.DISABLE_ENHANCED_TOOLING_API) { - GradleExecutionHelper.setInitScript(buildActionExecutor); + GradleExecutionHelper.setInitScript(buildActionExecutor, isBuildSrcProject); } ProjectImportAction.AllModels allModels; @@ -242,8 +245,10 @@ public class GradleProjectResolver implements ExternalSystemProjectResolver<Grad projectResolverChain.populateModuleContentRoots(ideaModule, moduleDataNode); projectResolverChain.populateModuleCompileOutputSettings(ideaModule, moduleDataNode); projectResolverChain.populateModuleDependencies(ideaModule, moduleDataNode, projectDataNode); - final Collection<TaskData> moduleTasks = projectResolverChain.populateModuleTasks(ideaModule, moduleDataNode, projectDataNode); - allTasks.addAll(moduleTasks); + if(!isBuildSrcProject) { + final Collection<TaskData> moduleTasks = projectResolverChain.populateModuleTasks(ideaModule, moduleDataNode, projectDataNode); + allTasks.addAll(moduleTasks); + } } // populate root project tasks @@ -275,4 +280,78 @@ public class GradleProjectResolver implements ExternalSystemProjectResolver<Grad return null; } } + + private void handleBuildSrcProject(@NotNull final DataNode<ProjectData> resultProjectDataNode, + @NotNull final ProjectConnectionDataNodeFunction projectConnectionDataNodeFunction) { + + if (projectConnectionDataNodeFunction.myIsPreviewMode || GradleEnvironment.DISABLE_ENHANCED_TOOLING_API || + !new File(projectConnectionDataNodeFunction.myProjectPath).isDirectory()) return; + + final DataNode<ModuleData> buildSrcModuleDataNode = + ExternalSystemApiUtil.find(resultProjectDataNode, ProjectKeys.MODULE, new BooleanFunction<DataNode<ModuleData>>() { + @Override + public boolean fun(DataNode<ModuleData> node) { + return projectConnectionDataNodeFunction.myProjectPath.equals(node.getData().getLinkedExternalProjectPath()); + } + }); + + // check if buildSrc project was already exposed in settings.gradle file + if (buildSrcModuleDataNode != null) return; + + final DataNode<ProjectData> buildSrcProjectDataDataNode = myHelper.execute( + projectConnectionDataNodeFunction.myProjectPath, projectConnectionDataNodeFunction.mySettings, projectConnectionDataNodeFunction); + + if (buildSrcProjectDataDataNode != null) { + final DataNode<ModuleData> moduleDataNode = ExternalSystemApiUtil.find(buildSrcProjectDataDataNode, ProjectKeys.MODULE); + if (moduleDataNode != null) { + for (DataNode<LibraryData> libraryDataNode : ExternalSystemApiUtil.findAll(buildSrcProjectDataDataNode, ProjectKeys.LIBRARY)) { + resultProjectDataNode.createChild(libraryDataNode.getKey(), libraryDataNode.getData()); + } + + final DataNode<ModuleData> newModuleDataNode = resultProjectDataNode.createChild(ProjectKeys.MODULE, moduleDataNode.getData()); + for (DataNode node : moduleDataNode.getChildren()) { + newModuleDataNode.createChild(node.getKey(), node.getData()); + } + } + } + } + + private class ProjectConnectionDataNodeFunction implements Function<ProjectConnection, DataNode<ProjectData>> { + @NotNull private final ExternalSystemTaskId myId; + @NotNull private final String myProjectPath; + @Nullable private final GradleExecutionSettings mySettings; + @NotNull private final ExternalSystemTaskNotificationListener myListener; + private final boolean myIsPreviewMode; + @NotNull private final GradleProjectResolverExtension myProjectResolverChain; + private final boolean myIsBuildSrcProject; + + public ProjectConnectionDataNodeFunction(@NotNull ExternalSystemTaskId id, + @NotNull String projectPath, + @Nullable GradleExecutionSettings settings, + @NotNull ExternalSystemTaskNotificationListener listener, + boolean isPreviewMode, + @NotNull GradleProjectResolverExtension projectResolverChain, + boolean isBuildSrcProject) { + myId = id; + myProjectPath = projectPath; + mySettings = settings; + myListener = listener; + myIsPreviewMode = isPreviewMode; + myProjectResolverChain = projectResolverChain; + myIsBuildSrcProject = isBuildSrcProject; + } + + @Override + public DataNode<ProjectData> fun(ProjectConnection connection) { + try { + return doResolveProjectInfo( + new ProjectResolverContext(myId, myProjectPath, mySettings, connection, myListener, myIsPreviewMode), + myProjectResolverChain, myIsBuildSrcProject); + } + catch (RuntimeException e) { + LOG.info("Gradle project resolve error", e); + throw myProjectResolverChain.getUserFriendlyError(e, myProjectPath, null); + } + } + } } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleStartupActivity.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleStartupActivity.java index 623a79736028..fc4805e81058 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleStartupActivity.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleStartupActivity.java @@ -30,6 +30,7 @@ import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VfsUtilCore; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.gradle.service.GradleBuildClasspathManager; import org.jetbrains.plugins.gradle.service.project.wizard.GradleProjectImportBuilder; import org.jetbrains.plugins.gradle.service.project.wizard.GradleProjectImportProvider; import org.jetbrains.plugins.gradle.settings.GradleSettings; @@ -52,9 +53,14 @@ public class GradleStartupActivity implements StartupActivity { @Override public void runActivity(@NotNull Project project) { + configureBuildClasspath(project); showNotificationForUnlinkedGradleProject(project); } + private static void configureBuildClasspath(@NotNull final Project project) { + GradleBuildClasspathManager.getInstance(project).reload(); + } + private static void showNotificationForUnlinkedGradleProject(@NotNull final Project project) { if (!PropertiesComponent.getInstance(project).getBoolean(SHOW_UNLINKED_GRADLE_POPUP, true) || !GradleSettings.getInstance(project).getLinkedProjectsSettings().isEmpty() diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/data/BuildClasspathModuleGradleDataService.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/data/BuildClasspathModuleGradleDataService.java new file mode 100644 index 000000000000..907f2903ef09 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/data/BuildClasspathModuleGradleDataService.java @@ -0,0 +1,161 @@ +/* + * Copyright 2000-2014 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 org.jetbrains.plugins.gradle.service.project.data; + +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.externalSystem.ExternalSystemManager; +import com.intellij.openapi.externalSystem.model.DataNode; +import com.intellij.openapi.externalSystem.model.Key; +import com.intellij.openapi.externalSystem.model.ProjectKeys; +import com.intellij.openapi.externalSystem.model.project.ExternalModuleBuildClasspathPojo; +import com.intellij.openapi.externalSystem.model.project.ExternalProjectBuildClasspathPojo; +import com.intellij.openapi.externalSystem.model.project.ModuleData; +import com.intellij.openapi.externalSystem.model.project.ProjectData; +import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataService; +import com.intellij.openapi.externalSystem.settings.AbstractExternalSystemLocalSettings; +import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; +import com.intellij.openapi.externalSystem.util.ExternalSystemConstants; +import com.intellij.openapi.externalSystem.util.Order; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.FactoryMap; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.gradle.model.data.BuildScriptClasspathData; +import org.jetbrains.plugins.gradle.model.data.ClasspathEntry; +import org.jetbrains.plugins.gradle.service.GradleBuildClasspathManager; +import org.jetbrains.plugins.gradle.service.GradleInstallationManager; +import org.jetbrains.plugins.gradle.settings.GradleProjectSettings; +import org.jetbrains.plugins.gradle.settings.GradleSettings; +import org.jetbrains.plugins.gradle.util.GradleConstants; + +import java.io.File; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * @author Vladislav.Soroka + * @since 8/27/13 + */ +@Order(ExternalSystemConstants.UNORDERED) +public class BuildClasspathModuleGradleDataService implements ProjectDataService<BuildScriptClasspathData, Module> { + + @NotNull + @Override + public Key<BuildScriptClasspathData> getTargetDataKey() { + return BuildScriptClasspathData.KEY; + } + + @Override + public void importData(@NotNull final Collection<DataNode<BuildScriptClasspathData>> toImport, + @NotNull final Project project, + boolean synchronous) { + if (toImport.isEmpty()) { + return; + } + if (!project.isInitialized()) { + return; + } + + final GradleInstallationManager gradleInstallationManager = ServiceManager.getService(GradleInstallationManager.class); + + ExternalSystemManager<?, ?, ?, ?, ?> manager = ExternalSystemApiUtil.getManager(GradleConstants.SYSTEM_ID); + assert manager != null; + AbstractExternalSystemLocalSettings localSettings = manager.getLocalSettingsProvider().fun(project); + + //noinspection MismatchedQueryAndUpdateOfCollection + Map<String/* externalProjectPath */, Set<String>> externalProjectGradleSdkLibs = new FactoryMap<String, Set<String>>() { + @Nullable + @Override + protected Set<String> create(String externalProjectPath) { + GradleProjectSettings settings = GradleSettings.getInstance(project).getLinkedProjectSettings(externalProjectPath); + if (settings == null || settings.getDistributionType() == null) return null; + + final Set<String> gradleSdkLibraries = ContainerUtil.newHashSet(); + File gradleHome = + gradleInstallationManager.getGradleHome(settings.getDistributionType(), externalProjectPath, settings.getGradleHome()); + if (gradleHome != null && gradleHome.isDirectory()) { + + final Collection<File> libraries = gradleInstallationManager.getClassRoots(project, externalProjectPath); + if (libraries != null) { + for (File library : libraries) { + gradleSdkLibraries.add(FileUtil.toCanonicalPath(library.getPath())); + } + } + } + return gradleSdkLibraries; + } + }; + + for (final DataNode<BuildScriptClasspathData> node : toImport) { + if (GradleConstants.SYSTEM_ID.equals(node.getData().getOwner())) { + + + DataNode<ProjectData> projectDataNode = ExternalSystemApiUtil.findParent(node, ProjectKeys.PROJECT); + assert projectDataNode != null; + + String linkedExternalProjectPath = projectDataNode.getData().getLinkedExternalProjectPath(); + DataNode<ModuleData> moduleDataNode = ExternalSystemApiUtil.findParent(node, ProjectKeys.MODULE); + if (moduleDataNode == null) continue; + + String externalModulePath = moduleDataNode.getData().getLinkedExternalProjectPath(); + GradleProjectSettings settings = GradleSettings.getInstance(project).getLinkedProjectSettings(linkedExternalProjectPath); + if (settings == null || settings.getDistributionType() == null) continue; + + final Set<String> buildClasspath = ContainerUtil.newHashSet(); + BuildScriptClasspathData buildScriptClasspathData = node.getData(); + for (ClasspathEntry classpathEntry : buildScriptClasspathData.getClasspathEntries()) { + if (classpathEntry.getSourcesFile() != null) { + buildClasspath.add(FileUtil.toCanonicalPath(classpathEntry.getSourcesFile().getPath())); + } + else { + buildClasspath.add(FileUtil.toCanonicalPath(classpathEntry.getClassesFile().getPath())); + } + } + + ExternalProjectBuildClasspathPojo projectBuildClasspathPojo = + localSettings.getProjectBuildClasspath().get(linkedExternalProjectPath); + if (projectBuildClasspathPojo == null) { + projectBuildClasspathPojo = new ExternalProjectBuildClasspathPojo( + moduleDataNode.getData().getExternalName(), + ContainerUtil.<String>newArrayList(), + ContainerUtil.<String, ExternalModuleBuildClasspathPojo>newHashMap()); + localSettings.getProjectBuildClasspath().put(linkedExternalProjectPath, projectBuildClasspathPojo); + } + + List<String> projectBuildClasspath = ContainerUtil.newArrayList(externalProjectGradleSdkLibs.get(linkedExternalProjectPath)); + // add main java root of buildSrc project + projectBuildClasspath.add(linkedExternalProjectPath + "/buildSrc/src/main/java"); + // add main groovy root of buildSrc project + projectBuildClasspath.add(linkedExternalProjectPath + "/buildSrc/src/main/groovy"); + + projectBuildClasspathPojo.setProjectBuildClasspath(projectBuildClasspath); + projectBuildClasspathPojo.getModulesBuildClasspath().put( + externalModulePath, new ExternalModuleBuildClasspathPojo(externalModulePath, ContainerUtil.newArrayList(buildClasspath))); + } + } + + GradleBuildClasspathManager.getInstance(project).reload(); + } + + @Override + public void removeData(@NotNull Collection<? extends Module> toRemove, @NotNull Project project, boolean synchronous) { + } +} diff --git a/plugins/gradle/testData/testAddMavenDependencyInEmptyFile.gradle b/plugins/gradle/testData/testAddMavenDependencyInEmptyFile.gradle index f90814d636ed..e69de29bb2d1 100644 --- a/plugins/gradle/testData/testAddMavenDependencyInEmptyFile.gradle +++ b/plugins/gradle/testData/testAddMavenDependencyInEmptyFile.gradle @@ -1 +0,0 @@ -//empty file
\ No newline at end of file diff --git a/plugins/gradle/testData/testAddMavenDependencyInEmptyFile_after.gradle b/plugins/gradle/testData/testAddMavenDependencyInEmptyFile_after.gradle index aa2892d73dc4..54c09742fd5c 100644 --- a/plugins/gradle/testData/testAddMavenDependencyInEmptyFile_after.gradle +++ b/plugins/gradle/testData/testAddMavenDependencyInEmptyFile_after.gradle @@ -1,4 +1,3 @@ -//empty file dependencies{ compile 'testGroupId:testArtifactId:1.0' }
\ No newline at end of file diff --git a/plugins/gradle/testData/testDefaultDependenciesModel/build.gradle b/plugins/gradle/testData/testDefaultDependenciesModel/build.gradle index 849b1b486dd2..a6c9dde56871 100644 --- a/plugins/gradle/testData/testDefaultDependenciesModel/build.gradle +++ b/plugins/gradle/testData/testDefaultDependenciesModel/build.gradle @@ -4,8 +4,8 @@ allprojects{ apply plugin: 'java' } -project(":group2:subgroup11:project") { +project("dependentProject") { dependencies { - compile project(":project") + compile project(":dependencyProject") } }
\ No newline at end of file diff --git a/plugins/gradle/testData/testDefaultDependenciesModel/settings.gradle b/plugins/gradle/testData/testDefaultDependenciesModel/settings.gradle index cf870fe6d6d1..ef853f062e1c 100644 --- a/plugins/gradle/testData/testDefaultDependenciesModel/settings.gradle +++ b/plugins/gradle/testData/testDefaultDependenciesModel/settings.gradle @@ -1,5 +1,4 @@ //noinspection GrPackage -include 'group1:subgroup11:project' -include 'group2:subgroup11:project' -include 'project'
\ No newline at end of file +include 'dependencyProject' +include 'dependentProject'
\ No newline at end of file diff --git a/plugins/gradle/testData/testGradleIdeaPluginPlusScopesDependenciesModel/build.gradle b/plugins/gradle/testData/testGradleIdeaPluginPlusScopesDependenciesModel/build.gradle index 6f9afa4b8d09..73cb6a15b5cd 100644 --- a/plugins/gradle/testData/testGradleIdeaPluginPlusScopesDependenciesModel/build.gradle +++ b/plugins/gradle/testData/testGradleIdeaPluginPlusScopesDependenciesModel/build.gradle @@ -27,7 +27,7 @@ allprojects { project(":service") { dependencies { - compile (project(':api')) + compile(project(':api')) } } @@ -35,4 +35,21 @@ project(":api") { dependencies { provided(project(':lib')) } -}
\ No newline at end of file +} + +project(":withIdeaModelCustomisations") { + dependencies { + //compile 'org.slf4j:slf4j-api:1.7.5' + //testCompile 'junit:junit:4.11' + + compile files("lib/someDep.jar") + testCompile files("lib/someTestDep.jar") + } + + idea { + module { + scopes.COMPILE.plus += scopes.TEST.plus + scopes.TEST.plus = [] + } + } +} diff --git a/plugins/gradle/testData/testGradleIdeaPluginPlusScopesDependenciesModel/settings.gradle b/plugins/gradle/testData/testGradleIdeaPluginPlusScopesDependenciesModel/settings.gradle index 271f7343d37b..26ee835a9fb1 100644 --- a/plugins/gradle/testData/testGradleIdeaPluginPlusScopesDependenciesModel/settings.gradle +++ b/plugins/gradle/testData/testGradleIdeaPluginPlusScopesDependenciesModel/settings.gradle @@ -1,4 +1,5 @@ //noinspection GrPackage include "lib" include "api" -include "service"
\ No newline at end of file +include "service" +include "withIdeaModelCustomisations"
\ No newline at end of file diff --git a/plugins/gradle/testData/testGradleSourcesSetsInterpretation/build.gradle b/plugins/gradle/testData/testGradleSourcesSetsInterpretation/build.gradle new file mode 100644 index 000000000000..8c7584942858 --- /dev/null +++ b/plugins/gradle/testData/testGradleSourcesSetsInterpretation/build.gradle @@ -0,0 +1,74 @@ +//noinspection GrPackage + +project("defaultJavaModule") { + apply plugin: "java" +} + +project("moduleWithSourceSetDirBothAsResourceAndJava") { + apply plugin: "java" + + sourceSets.main.resources.srcDir 'src/main/java' + sourceSets.test.resources.srcDir 'src/test/java' +} + +project("moduleWithCustomSourceSet") { + apply plugin: "java" + + sourceSets { + custom + } + + sourceSets.custom.java.srcDir 'src/custom/java' +} + +project("withIntegrationTests") { + apply plugin: 'java' + + sourceSets { + integrationTest { + java.srcDir file('src/integration-test/java') + resources.srcDir file('src/integration-test/resources') + } + } + + dependencies { + integrationTestCompile sourceSets.main.output + integrationTestCompile configurations.testCompile + integrationTestCompile sourceSets.test.output + integrationTestRuntime configurations.testRuntime + } + + //noinspection GrUnresolvedAccess + task integrationTest(type: Test, dependsOn: jar) { + testClassesDir = sourceSets.integrationTest.output.classesDir + classpath = sourceSets.integrationTest.runtimeClasspath + } + + check.dependsOn integrationTest +} + +project("withIdeaPluginCustomization1") { + apply plugin: 'java' + + idea { + module { + testSourceDirs += file('src/intTest/java') + testSourceDirs += file('src/intTest/resources') + excludeDirs += file('some-extra-exclude-folder') + } + } +} + +// see http://youtrack.jetbrains.com/issue/IDEA-119365 +project("withIdeaPluginCustomization2") { + apply plugin: 'java' + + idea { + module { + sourceDirs += testSourceDirs + testSourceDirs = [] + ext.resourceDirs += file('some-extra-resource-folder') + ext.testResourceDirs += file('some-extra-test-resource-folder') + } + } +} diff --git a/plugins/gradle/testData/testGradleSourcesSetsInterpretation/settings.gradle b/plugins/gradle/testData/testGradleSourcesSetsInterpretation/settings.gradle new file mode 100644 index 000000000000..4f7ab785f8fd --- /dev/null +++ b/plugins/gradle/testData/testGradleSourcesSetsInterpretation/settings.gradle @@ -0,0 +1,8 @@ +//noinspection GrPackage + +include 'defaultJavaModule' +include 'moduleWithSourceSetDirBothAsResourceAndJava' +include 'moduleWithCustomSourceSet' +include 'withIntegrationTests' +include 'withIdeaPluginCustomization1' +include 'withIdeaPluginCustomization2'
\ No newline at end of file diff --git a/plugins/gradle/testData/testModelBuildScriptClasspathBuilder/build.gradle b/plugins/gradle/testData/testModelBuildScriptClasspathBuilder/build.gradle new file mode 100644 index 000000000000..5b09fca15f4d --- /dev/null +++ b/plugins/gradle/testData/testModelBuildScriptClasspathBuilder/build.gradle @@ -0,0 +1,9 @@ +//noinspection GrPackage + +project("moduleWithAdditionalClasspath") { + buildscript { + dependencies { + classpath files("lib/someDep.jar") + } + } +} diff --git a/plugins/gradle/testData/testModelBuildScriptClasspathBuilder/settings.gradle b/plugins/gradle/testData/testModelBuildScriptClasspathBuilder/settings.gradle new file mode 100644 index 000000000000..02978875f494 --- /dev/null +++ b/plugins/gradle/testData/testModelBuildScriptClasspathBuilder/settings.gradle @@ -0,0 +1,4 @@ +//noinspection GrPackage + +include 'moduleWithoutAdditionalClasspath' +include 'moduleWithAdditionalClasspath' diff --git a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/model/builder/AbstractModelBuilderTest.java b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/model/builder/AbstractModelBuilderTest.java index 835d7305bd1b..0cdd2f032b78 100644 --- a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/model/builder/AbstractModelBuilderTest.java +++ b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/model/builder/AbstractModelBuilderTest.java @@ -73,7 +73,7 @@ public abstract class AbstractModelBuilderTest { final ProjectImportAction projectImportAction = new ProjectImportAction(true); projectImportAction.addExtraProjectModelClasses(getModels()); BuildActionExecuter<ProjectImportAction.AllModels> buildActionExecutor = connection.action(projectImportAction); - GradleExecutionHelper.setInitScript(buildActionExecutor); + GradleExecutionHelper.setInitScript(buildActionExecutor, false); allModels = buildActionExecutor.run(); assertNotNull(allModels); diff --git a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/model/builder/ModelBuildScriptClasspathBuilderImplTest.java b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/model/builder/ModelBuildScriptClasspathBuilderImplTest.java new file mode 100644 index 000000000000..d812d8df6a68 --- /dev/null +++ b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/model/builder/ModelBuildScriptClasspathBuilderImplTest.java @@ -0,0 +1,78 @@ +/* + * Copyright 2000-2014 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 org.jetbrains.plugins.gradle.model.builder; + +import com.intellij.util.Function; +import com.intellij.util.containers.ContainerUtil; +import org.gradle.tooling.model.DomainObjectSet; +import org.gradle.tooling.model.idea.IdeaModule; +import org.jetbrains.plugins.gradle.model.BuildScriptClasspathModel; +import org.jetbrains.plugins.gradle.model.ClasspathEntryModel; +import org.junit.Test; + +import java.util.List; +import java.util.Set; + +import static junit.framework.Assert.*; +import static org.junit.Assert.assertTrue; + +/** + * @author Vladislav.Soroka + * @since 1/16/14 + */ +public class ModelBuildScriptClasspathBuilderImplTest extends AbstractModelBuilderTest { + + @Test + public void testModelBuildScriptClasspathBuilder() throws Exception { + ModelBuildScriptClasspathBuilderImpl buildScriptClasspathBuilder = new ModelBuildScriptClasspathBuilderImpl(); + assertTrue(buildScriptClasspathBuilder.canBuild("org.jetbrains.plugins.gradle.model.BuildScriptClasspathModel")); + + DomainObjectSet<? extends IdeaModule> ideaModules = allModels.getIdeaProject().getModules(); + + List<BuildScriptClasspathModel> ideaModule = + ContainerUtil.mapNotNull(ideaModules, new Function<IdeaModule, BuildScriptClasspathModel>() { + @Override + public BuildScriptClasspathModel fun(IdeaModule module) { + BuildScriptClasspathModel classpathModel = allModels.getExtraProject(module, BuildScriptClasspathModel.class); + + if (module.getName().equals("moduleWithAdditionalClasspath")) { + assertNotNull(classpathModel); + assertEquals(1, classpathModel.getClasspath().size()); + + ClasspathEntryModel classpathEntry = classpathModel.getClasspath().getAt(0); + assertEquals("someDep.jar", classpathEntry.getClassesFile().getName()); + } + else if (module.getName().equals("moduleWithoutAdditionalClasspath") || + module.getName().equals("testModelBuildScriptClasspathBuilder")) { + assertNotNull(classpathModel); + assertTrue(classpathModel.getClasspath().isEmpty()); + } + else { + fail(); + } + + return classpathModel; + } + }); + + assertEquals(3, ideaModule.size()); + } + + @Override + protected Set<Class> getModels() { + return ContainerUtil.<Class>set(BuildScriptClasspathModel.class); + } +} diff --git a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/model/builder/ModelDependenciesBuilderImplTest.java b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/model/builder/ModelDependenciesBuilderImplTest.java index 6bb9b6f5eb9c..8cf50ef62af5 100644 --- a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/model/builder/ModelDependenciesBuilderImplTest.java +++ b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/model/builder/ModelDependenciesBuilderImplTest.java @@ -15,19 +15,26 @@ */ package org.jetbrains.plugins.gradle.model.builder; -import com.intellij.openapi.util.Condition; +import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; import org.gradle.tooling.model.DomainObjectSet; import org.gradle.tooling.model.idea.IdeaDependency; import org.gradle.tooling.model.idea.IdeaModule; import org.gradle.tooling.model.idea.IdeaModuleDependency; +import org.gradle.tooling.model.idea.IdeaSingleEntryLibraryDependency; +import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.gradle.model.GradleDependencyScope; import org.jetbrains.plugins.gradle.model.ProjectDependenciesModel; +import org.junit.Assert; import org.junit.Test; +import java.util.List; import java.util.Set; -import static org.junit.Assert.*; +import static junit.framework.Assert.assertTrue; +import static junit.framework.Assert.fail; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; /** * @author Vladislav.Soroka @@ -42,17 +49,29 @@ public class ModelDependenciesBuilderImplTest extends AbstractModelBuilderTest { DomainObjectSet<? extends IdeaModule> ideaModules = allModels.getIdeaProject().getModules(); - IdeaModule ideaModule = ContainerUtil.find(ideaModules, new Condition<IdeaModule>() { - @Override - public boolean value(IdeaModule module) { - return module.getName().equals("group2-subgroup11-project"); - } - }); - - assertNotNull(ideaModule); + final int modulesSize = 3; + assertEquals(modulesSize, ideaModules.size()); - DomainObjectSet<? extends IdeaDependency> dependencies = ideaModule.getDependencies(); - assertEquals(1, dependencies.size()); + for (IdeaModule ideaModule : ideaModules) { + if (ideaModule.getName().equals("dependencyProject") || + ideaModule.getName().equals("testDefaultDependenciesModel")) { + DomainObjectSet<? extends IdeaDependency> dependencies = ideaModule.getDependencies(); + assertTrue((dependencies.isEmpty())); + } + else if (ideaModule.getName().equals("dependentProject")) { + DomainObjectSet<? extends IdeaDependency> dependencies = ideaModule.getDependencies(); + assertEquals(1, dependencies.size()); + assertTrue(dependencies.getAt(0) instanceof IdeaModuleDependency); + IdeaModuleDependency moduleDependency = (IdeaModuleDependency)dependencies.getAt(0); + + assertEquals("dependencyProject", moduleDependency.getDependencyModule().getName()); + assertEquals("COMPILE", moduleDependency.getScope().getScope()); + assertTrue(moduleDependency.getExported()); + } + else { + fail(); + } + } } @Test @@ -62,44 +81,71 @@ public class ModelDependenciesBuilderImplTest extends AbstractModelBuilderTest { DomainObjectSet<? extends IdeaModule> ideaModules = allModels.getIdeaProject().getModules(); - // test api module dependencies - IdeaModule apiModule = ContainerUtil.find(ideaModules, new Condition<IdeaModule>() { - @Override - public boolean value(IdeaModule module) { - return module.getName().equals("api"); + final int modulesSize = 5; + assertEquals(modulesSize, ideaModules.size()); + + for (IdeaModule ideaModule : ideaModules) { + DomainObjectSet<? extends IdeaDependency> dependencies = ideaModule.getDependencies(); + if (ideaModule.getName().equals("lib") || + ideaModule.getName().equals("testGradleIdeaPluginPlusScopesDependenciesModel")) { + assertTrue((dependencies.isEmpty())); } - }); - assertNotNull(apiModule); + else if (ideaModule.getName().equals("api")) { + assertEquals(1, dependencies.size()); + IdeaDependency libDependency = dependencies.getAt(0); + assertEquals(GradleDependencyScope.PROVIDED.getIdeaMappingName(), libDependency.getScope().getScope().toLowerCase()); + assertTrue(libDependency instanceof IdeaModuleDependency); + + IdeaModuleDependency libModuleDependency = (IdeaModuleDependency)libDependency; + assertNotNull(libModuleDependency.getDependencyModule()); + assertEquals("lib", libModuleDependency.getDependencyModule().getName()); + } + else if (ideaModule.getName().equals("service")) { + assertEquals(1, dependencies.size()); + IdeaDependency apiDependency = dependencies.getAt(0); + assertEquals(GradleDependencyScope.COMPILE.getIdeaMappingName(), apiDependency.getScope().getScope().toLowerCase()); + assertTrue(apiDependency instanceof IdeaModuleDependency); + + IdeaModuleDependency apiModuleDependency = (IdeaModuleDependency)apiDependency; + assertNotNull(apiModuleDependency.getDependencyModule()); + assertEquals("api", apiModuleDependency.getDependencyModule().getName()); + } + else if (ideaModule.getName().equals("withIdeaModelCustomisations")) { + + assertTrue(findLocalLibraries(dependencies, GradleDependencyScope.TEST_COMPILE.getIdeaMappingName()).isEmpty()); - DomainObjectSet<? extends IdeaDependency> dependencies = apiModule.getDependencies(); - assertEquals(1, dependencies.size()); - IdeaDependency libDependency = dependencies.getAt(0); - assertEquals(GradleDependencyScope.PROVIDED.name(), libDependency.getScope().getScope()); - assertTrue(libDependency instanceof IdeaModuleDependency); + List<IdeaSingleEntryLibraryDependency> libraryDependencies = + findLocalLibraries(dependencies, GradleDependencyScope.COMPILE.getIdeaMappingName()); + assertEquals(2, libraryDependencies.size()); - IdeaModuleDependency libModuleDependency = (IdeaModuleDependency)libDependency; - assertNotNull(libModuleDependency.getDependencyModule()); - assertEquals("lib", libModuleDependency.getDependencyModule().getName()); + IdeaSingleEntryLibraryDependency someDep = libraryDependencies.get(0); + assertEquals(GradleDependencyScope.COMPILE.getIdeaMappingName(), someDep.getScope().getScope().toLowerCase()); + assertEquals("someDep.jar", someDep.getFile().getName()); + IdeaSingleEntryLibraryDependency someTestDep = libraryDependencies.get(1); + assertEquals(GradleDependencyScope.COMPILE.getIdeaMappingName(), someTestDep.getScope().getScope().toLowerCase()); + assertEquals("someTestDep.jar", someTestDep.getFile().getName()); + } + else { + fail(); + } + } + } - // test service module dependencies - IdeaModule serviceModule = ContainerUtil.find(ideaModules, new Condition<IdeaModule>() { - @Override - public boolean value(IdeaModule module) { - return module.getName().equals("service"); + @NotNull + private static List<IdeaSingleEntryLibraryDependency> findLocalLibraries( + @NotNull final DomainObjectSet<? extends IdeaDependency> dependencies, @NotNull final String scope) { + return ContainerUtil.mapNotNull( + dependencies, + new Function<IdeaDependency, IdeaSingleEntryLibraryDependency>() { + @Override + public IdeaSingleEntryLibraryDependency fun(IdeaDependency dependency) { + return dependency instanceof IdeaSingleEntryLibraryDependency && scope.equals(dependency.getScope().getScope().toLowerCase()) + ? (IdeaSingleEntryLibraryDependency)dependency + : null; + } } - }); - assertNotNull(serviceModule); - - DomainObjectSet<? extends IdeaDependency> serviceModuleDependencies = serviceModule.getDependencies(); - assertEquals(1, serviceModuleDependencies.size()); - IdeaDependency apiDependency = serviceModuleDependencies.getAt(0); - assertEquals(GradleDependencyScope.COMPILE.name(), apiDependency.getScope().getScope()); - assertTrue(apiDependency instanceof IdeaModuleDependency); - - IdeaModuleDependency apiModuleDependency = (IdeaModuleDependency)apiDependency; - assertNotNull(apiModuleDependency.getDependencyModule()); - assertEquals("api", apiModuleDependency.getDependencyModule().getName()); + ); } @Override diff --git a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/model/builder/ModuleExtendedModelBuilderImplTest.java b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/model/builder/ModuleExtendedModelBuilderImplTest.java new file mode 100644 index 000000000000..9694c9d37345 --- /dev/null +++ b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/model/builder/ModuleExtendedModelBuilderImplTest.java @@ -0,0 +1,177 @@ +/* + * Copyright 2000-2014 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 org.jetbrains.plugins.gradle.model.builder; + +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.util.Function; +import com.intellij.util.containers.ContainerUtil; +import org.gradle.tooling.model.DomainObjectSet; +import org.gradle.tooling.model.idea.IdeaModule; +import org.gradle.tooling.model.idea.IdeaSourceDirectory; +import org.jetbrains.plugins.gradle.model.ExtIdeaContentRoot; +import org.jetbrains.plugins.gradle.model.ModuleExtendedModel; +import org.junit.Assert; +import org.junit.Test; + +import java.io.File; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Set; + +import static junit.framework.Assert.assertNotNull; +import static junit.framework.Assert.fail; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/** + * @author Vladislav.Soroka + * @since 1/16/14 + */ +public class ModuleExtendedModelBuilderImplTest extends AbstractModelBuilderTest { + + @Test + public void testGradleSourcesSetsInterpretation() throws Exception { + final int modulesSize = 7; + + ModuleExtendedModelBuilderImpl moduleExtendedModelBuilder = new ModuleExtendedModelBuilderImpl(); + assertTrue(moduleExtendedModelBuilder.canBuild("org.jetbrains.plugins.gradle.model.ModuleExtendedModel")); + + DomainObjectSet<? extends IdeaModule> ideaModules = allModels.getIdeaProject().getModules(); + + List<ModuleExtendedModel> models = + ContainerUtil.mapNotNull(ideaModules, new Function<IdeaModule, ModuleExtendedModel>() { + @Override + public ModuleExtendedModel fun(IdeaModule module) { + ModuleExtendedModel moduleExtendedModel = allModels.getExtraProject(module, ModuleExtendedModel.class); + + assertNotNull(moduleExtendedModel); + + List<String> sourceDirectories = ContainerUtil.newArrayList(); + List<String> resourceDirectories = ContainerUtil.newArrayList(); + List<String> testResourceDirectories = ContainerUtil.newArrayList(); + List<String> testDirectories = ContainerUtil.newArrayList(); + List<String> excludeDirectories = ContainerUtil.newArrayList(); + + fillDirectories(moduleExtendedModel, + sourceDirectories, resourceDirectories, + testDirectories, testResourceDirectories, + excludeDirectories); + + if (module.getName().equals("defaultJavaModule") || module.getName().equals("moduleWithSourceSetDirBothAsResourceAndJava")) { + assertEquals(ContainerUtil.newArrayList("src/main/java"), sourceDirectories); + assertEquals(ContainerUtil.newArrayList("src/main/resources"), resourceDirectories); + assertEquals(ContainerUtil.newArrayList("src/test/java"), testDirectories); + assertEquals(ContainerUtil.newArrayList("src/test/resources"), testResourceDirectories); + assertEquals(ContainerUtil.newArrayList(".gradle", "build"), excludeDirectories); + } + else if (module.getName().equals("moduleWithCustomSourceSet")) { + assertEquals(ContainerUtil.newArrayList("src/custom/java", "src/main/java"), sourceDirectories); + assertEquals(ContainerUtil.newArrayList("src/custom/resources", "src/main/resources"), resourceDirectories); + assertEquals(ContainerUtil.newArrayList("src/test/java"), testDirectories); + assertEquals(ContainerUtil.newArrayList("src/test/resources"), testResourceDirectories); + assertEquals(ContainerUtil.newArrayList(".gradle", "build"), excludeDirectories); + } + else if (module.getName().equals("withIntegrationTests")) { + assertEquals(ContainerUtil.newArrayList("src/main/java"), sourceDirectories); + assertEquals(ContainerUtil.newArrayList("src/main/resources"), resourceDirectories); + assertEquals(ContainerUtil.newArrayList( + "src/integration-test/java", "src/integrationTest/java", "src/test/java"), testDirectories); + assertEquals(ContainerUtil.newArrayList( + "src/integration-test/resources", + "src/integrationTest/resources", + "src/test/resources"), testResourceDirectories); + assertEquals(ContainerUtil.newArrayList(".gradle", "build"), excludeDirectories); + } + else if (module.getName().equals("testGradleSourcesSetsInterpretation")) { + assertTrue(sourceDirectories.isEmpty()); + assertTrue(resourceDirectories.isEmpty()); + assertTrue(testDirectories.isEmpty()); + assertTrue(testResourceDirectories.isEmpty()); + assertEquals(ContainerUtil.newArrayList(".gradle", "build"), excludeDirectories); + } + else if (module.getName().equals("withIdeaPluginCustomization1")) { + assertEquals(ContainerUtil.newArrayList("src/main/java"), sourceDirectories); + assertEquals(ContainerUtil.newArrayList("src/main/resources"), resourceDirectories); + assertEquals(ContainerUtil.newArrayList("src/intTest/java", "src/intTest/resources", "src/test/java"), testDirectories); + assertEquals(ContainerUtil.newArrayList("src/test/resources"), testResourceDirectories); + assertEquals(ContainerUtil.newArrayList(".gradle", "build", "some-extra-exclude-folder"), excludeDirectories); + } + else if (module.getName().equals("withIdeaPluginCustomization2")) { + assertEquals(ContainerUtil.newArrayList("src/main/java", "src/test/java", "src/test/resources"), sourceDirectories); + assertEquals(ContainerUtil.newArrayList("some-extra-resource-folder", "src/main/resources"), resourceDirectories); + assertTrue(testDirectories.isEmpty()); + assertEquals(ContainerUtil.newArrayList("some-extra-test-resource-folder"), testResourceDirectories); + assertEquals(ContainerUtil.newArrayList(".gradle", "build"), excludeDirectories); + } + else { + fail(); + } + + return moduleExtendedModel; + } + }); + + assertEquals(modulesSize, models.size()); + } + + private void fillDirectories(final ModuleExtendedModel model, + List<String> sourceDirectories, List<String> resourceDirectories, + List<String> testDirectories, List<String> resourceTestDirectories, + List<String> excludeDirectories) { + for (ExtIdeaContentRoot contentRoot : model.getContentRoots()) { + sourceDirectories.addAll(getAllPaths(contentRoot.getSourceDirectories(), model.getName())); + resourceDirectories.addAll(getAllPaths(contentRoot.getResourceDirectories(), model.getName())); + testDirectories.addAll(getAllPaths(contentRoot.getTestDirectories(), model.getName())); + resourceTestDirectories.addAll(getAllPaths(contentRoot.getTestResourceDirectories(), model.getName())); + excludeDirectories.addAll(getAllPaths(contentRoot.getExcludeDirectories(), model.getName())); + } + } + + private Collection<? extends String> getAllPaths(Collection<? extends File> directories, final String moduleName) { + List<String> list = ContainerUtil.map2List(directories, new Function<File, String>() { + @Override + public String fun(File sourceDirectory) { + String path = + FileUtil.toCanonicalPath(FileUtil.getRelativePath(new File(testDir, moduleName), sourceDirectory)); + Assert.assertNotNull(path); + return path.substring(path.indexOf("/") + 1); + } + }); + Collections.sort(list); + return list; + } + + private Collection<? extends String> getAllPaths(DomainObjectSet<? extends IdeaSourceDirectory> directories, final String moduleName) { + List<String> list = ContainerUtil.map2List(directories, new Function<IdeaSourceDirectory, String>() { + @Override + public String fun(IdeaSourceDirectory sourceDirectory) { + String path = + FileUtil.toCanonicalPath(FileUtil.getRelativePath(new File(testDir, moduleName), sourceDirectory.getDirectory())); + Assert.assertNotNull(path); + return path.substring(path.indexOf("/") + 1); + } + }); + Collections.sort(list); + return list; + } + + @Override + protected Set<Class> getModels() { + return ContainerUtil.<Class>set(ModuleExtendedModel.class); + } +} + diff --git a/plugins/groovy/hotswap/agentSrc/org/groovy/debug/hotswap/ResetAgent.java b/plugins/groovy/hotswap/agentSrc/org/groovy/debug/hotswap/ResetAgent.java index a3e7023cf8f7..35b3577e258b 100644 --- a/plugins/groovy/hotswap/agentSrc/org/groovy/debug/hotswap/ResetAgent.java +++ b/plugins/groovy/hotswap/agentSrc/org/groovy/debug/hotswap/ResetAgent.java @@ -2,6 +2,7 @@ package org.groovy.debug.hotswap; import org.objectweb.asm.*; +import java.lang.String; import java.lang.instrument.ClassFileTransformer; import java.lang.instrument.IllegalClassFormatException; import java.lang.instrument.Instrumentation; @@ -18,7 +19,15 @@ import java.security.ProtectionDomain; */ @SuppressWarnings({"UtilityClassWithoutPrivateConstructor", "UnusedDeclaration"}) public class ResetAgent { - private static final String timStampFieldStart = "__timeStamp__239_neverHappen"; + private static final String timeStampFieldStart = "__timeStamp__239_neverHappen"; + private static final byte[] timeStampFieldStartBytes; + + static { + timeStampFieldStartBytes = new byte[timeStampFieldStart.length()]; + for (int i = 0; i < timeStampFieldStart.length(); i++) { + timeStampFieldStartBytes[i] = (byte)timeStampFieldStart.charAt(i); + } + } private static boolean initialized; @@ -44,18 +53,30 @@ public class ResetAgent { }); } - private static boolean hasTimestampField(byte[] buffer) { - try { - return new String(buffer, "ISO-8859-1").contains(timStampFieldStart); - } catch (Throwable e) { - return true; + private static boolean matches(byte[] array, byte[] subArray, int start) { + for (int i = 0; i < subArray.length; i++) { + if (array[start + i] != subArray[i]) { + return false; + } + } + return true; + } + + private static boolean containsSubArray(byte[] array, byte[] subArray) { + int maxLength = array.length - subArray.length; + for (int i = 0; i < maxLength; i++) { + if (matches(array, subArray, i)) { + return true; + } } + return false; } private static byte[] removeTimestampField(byte[] newBytes) { - if (!hasTimestampField(newBytes)) { + if (!containsSubArray(newBytes, timeStampFieldStartBytes)) { return null; } + final boolean[] changed = new boolean[]{false}; final ClassWriter writer = new ClassWriter(0); @@ -76,7 +97,7 @@ public class ResetAgent { @Override public FieldVisitor visitField(int i, String name, String s1, String s2, Object o) { - if (name.startsWith(timStampFieldStart)) { + if (name.startsWith(timeStampFieldStart)) { //remove the field changed[0] = true; return null; @@ -92,7 +113,7 @@ public class ResetAgent { return new MethodAdapter(mw) { @Override public void visitFieldInsn(int opCode, String s, String name, String desc) { - if (name.startsWith(timStampFieldStart) && opCode == Opcodes.PUTSTATIC) { + if (name.startsWith(timeStampFieldStart) && opCode == Opcodes.PUTSTATIC) { visitInsn(Type.LONG_TYPE.getDescriptor().equals(desc) ? Opcodes.POP2 : Opcodes.POP); } else { super.visitFieldInsn(opCode, s, name, desc); diff --git a/plugins/groovy/hotswap/gragent.jar b/plugins/groovy/hotswap/gragent.jar Binary files differindex 8794d675ad24..b0e17671dfaf 100644 --- a/plugins/groovy/hotswap/gragent.jar +++ b/plugins/groovy/hotswap/gragent.jar diff --git a/plugins/groovy/resources/fileTemplates/code/Spock SetUp Method.groovy.ft b/plugins/groovy/resources/fileTemplates/code/Spock_SetUp_Method.groovy.ft index 303209e1a46f..303209e1a46f 100644 --- a/plugins/groovy/resources/fileTemplates/code/Spock SetUp Method.groovy.ft +++ b/plugins/groovy/resources/fileTemplates/code/Spock_SetUp_Method.groovy.ft diff --git a/plugins/groovy/resources/fileTemplates/code/Spock SetUp Method.groovy.html b/plugins/groovy/resources/fileTemplates/code/Spock_SetUp_Method.groovy.html index 379785f36c3f..379785f36c3f 100644 --- a/plugins/groovy/resources/fileTemplates/code/Spock SetUp Method.groovy.html +++ b/plugins/groovy/resources/fileTemplates/code/Spock_SetUp_Method.groovy.html diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/navbar/GrNavBarModelExtension.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/navbar/GrNavBarModelExtension.java index e5b5681fc4fa..9116dbe42fd2 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/navbar/GrNavBarModelExtension.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/navbar/GrNavBarModelExtension.java @@ -22,6 +22,7 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jps.model.java.JavaModuleSourceRootTypes; import org.jetbrains.plugins.groovy.GroovyFileType; import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase; @@ -32,6 +33,12 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefini */ public class GrNavBarModelExtension extends AbstractNavBarModelExtension { + @Nullable + @Override + public String getPresentableText(Object object) { + return null; + } + @Override public PsiElement adjustElement(PsiElement psiElement) { final ProjectFileIndex index = ProjectRootManager.getInstance(psiElement.getProject()).getFileIndex(); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/spock/SpockTestFramework.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/spock/SpockTestFramework.java index b7872dcc9730..9a36c8c83990 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/spock/SpockTestFramework.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/spock/SpockTestFramework.java @@ -51,7 +51,7 @@ public class SpockTestFramework extends GroovyTestFramework { @Override public FileTemplateDescriptor getSetUpMethodFileTemplateDescriptor() { - return new FileTemplateDescriptor("Spock SetUp Method.groovy"); + return new FileTemplateDescriptor("Spock_SetUp_Method.groovy"); } @Override diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/log/HgLogProvider.java b/plugins/hg4idea/src/org/zmlx/hg4idea/log/HgLogProvider.java index 53cb43d9e457..9fc2b16aedaf 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/log/HgLogProvider.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/log/HgLogProvider.java @@ -19,20 +19,14 @@ package org.zmlx.hg4idea.log; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vcs.VcsKey; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.ArrayUtil; import com.intellij.util.Consumer; -import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; import com.intellij.vcs.log.*; -import com.intellij.vcs.log.data.VcsLogBranchFilter; -import com.intellij.vcs.log.data.VcsLogDateFilter; -import com.intellij.vcs.log.data.VcsLogStructureFilter; -import com.intellij.vcs.log.data.VcsLogUserFilter; -import com.intellij.vcs.log.ui.filter.VcsLogTextFilter; +import com.intellij.vcs.log.VcsLogTextFilter; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.zmlx.hg4idea.HgNameWithHashInfo; @@ -162,33 +156,28 @@ public class HgLogProvider implements VcsLogProvider { @NotNull @Override public List<? extends VcsFullCommitDetails> getFilteredDetails(@NotNull final VirtualFile root, - @NotNull Collection<VcsLogFilter> filters, + @NotNull Collection<VcsLogBranchFilter> branchFilters, + @NotNull Collection<VcsLogUserFilter> userFilters, + @NotNull Collection<VcsLogDateFilter> dateFilters, + @NotNull Collection<VcsLogTextFilter> textFilters, + @NotNull Collection<VcsLogStructureFilter> structureFilters, int maxCount) throws VcsException { List<String> filterParameters = ContainerUtil.newArrayList(); - List<VcsLogBranchFilter> branchFilters = ContainerUtil.findAll(filters, VcsLogBranchFilter.class); + // branch filter and user filter may be used several times without delimiter + // or -r options with appropriate revset arguments delimited by '|' or 'and'. if (!branchFilters.isEmpty()) { - String branchFilter = joinFilters(branchFilters, new Function<VcsLogBranchFilter, String>() { - @Override - public String fun(VcsLogBranchFilter filter) { - return filter.getBranchName(); - } - }); - filterParameters.add(prepareParameter("branch", branchFilter)); + for (VcsLogBranchFilter branchFilter : branchFilters) { + filterParameters.add(prepareParameter("branch", branchFilter.getBranchName())); + } } - List<VcsLogUserFilter> userFilters = ContainerUtil.findAll(filters, VcsLogUserFilter.class); if (!userFilters.isEmpty()) { - String authorFilter = joinFilters(userFilters, new Function<VcsLogUserFilter, String>() { - @Override - public String fun(VcsLogUserFilter filter) { - return filter.getUserName(root); - } - }); - filterParameters.add(prepareParameter("user", authorFilter)); + for (VcsLogUserFilter authorFilter : userFilters) { + filterParameters.add(prepareParameter("user", authorFilter.getUserName(root))); + } } - List<VcsLogDateFilter> dateFilters = ContainerUtil.findAll(filters, VcsLogDateFilter.class); if (!dateFilters.isEmpty()) { StringBuilder args = new StringBuilder(); final SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm"); @@ -208,7 +197,6 @@ public class HgLogProvider implements VcsLogProvider { filterParameters.add(args.toString()); } - List<VcsLogTextFilter> textFilters = ContainerUtil.findAll(filters, VcsLogTextFilter.class); if (textFilters.size() > 1) { LOG.warn("Expected only one text filter: " + textFilters); } @@ -217,7 +205,6 @@ public class HgLogProvider implements VcsLogProvider { filterParameters.add(prepareParameter("keyword", textFilter)); } - List<VcsLogStructureFilter> structureFilters = ContainerUtil.findAll(filters, VcsLogStructureFilter.class); if (!structureFilters.isEmpty()) { for (VcsLogStructureFilter filter : structureFilters) { for (VirtualFile file : filter.getFiles(root)) { @@ -249,8 +236,4 @@ public class HgLogProvider implements VcsLogProvider { private static String prepareParameter(String paramName, String value) { return "--" + paramName + "=" + value; // no value escaping needed, because the parameter itself will be quoted by GeneralCommandLine } - - private static <T> String joinFilters(List<T> filters, Function<T, String> toString) { - return StringUtil.join(filters, toString, "\\|"); - } } diff --git a/plugins/maven/jps-plugin/src/org/jetbrains/jps/maven/compiler/MavenResourcesBuilder.java b/plugins/maven/jps-plugin/src/org/jetbrains/jps/maven/compiler/MavenResourcesBuilder.java index 8f9a7b85b9cc..13bf78686482 100644 --- a/plugins/maven/jps-plugin/src/org/jetbrains/jps/maven/compiler/MavenResourcesBuilder.java +++ b/plugins/maven/jps-plugin/src/org/jetbrains/jps/maven/compiler/MavenResourcesBuilder.java @@ -1,6 +1,7 @@ package org.jetbrains.jps.maven.compiler; import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.text.StringUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jps.builders.BuildOutputConsumer; @@ -116,7 +117,13 @@ public class MavenResourcesBuilder extends TargetBuilder<MavenResourceRootDescri private Pattern getDelimitersPattern() { Pattern pattern = myDelimitersPattern; if (pattern == null) { - pattern = Pattern.compile(config.delimitersPattern); + if (StringUtil.isEmpty(config.escapeString)) { + pattern = Pattern.compile(config.delimitersPattern); + } + else { + String quotedEscapeString = Pattern.quote(config.escapeString); + pattern = Pattern.compile("(" + quotedEscapeString + quotedEscapeString + ")|(?:(" + quotedEscapeString + ")?(" + config.delimitersPattern + "))"); + } myDelimitersPattern = pattern; } return pattern; @@ -168,28 +175,31 @@ public class MavenResourcesBuilder extends TargetBuilder<MavenResourceRootDescri Map<String, String> resolvedProperties = resolvedPropertiesParam; final Matcher matcher = delimitersPattern.matcher(text); + + boolean hasEscapeString = !StringUtil.isEmpty(moduleConfig.escapeString); + final int groupCount = matcher.groupCount(); - final String escapeString = moduleConfig.escapeString; + int firstPropertyGroupIndex = hasEscapeString ? 3 : 0; + int last = 0; while (matcher.find()) { - if (escapeString != null) { - int escapeStringStartIndex = matcher.start() - escapeString.length(); - if (escapeStringStartIndex >= last) { - if (text.startsWith(escapeString, escapeStringStartIndex)) { - out.append(text, last, escapeStringStartIndex); - out.append(matcher.group()); - last = matcher.end(); - continue; - } - } - } - out.append(text, last, matcher.start()); last = matcher.end(); + if (hasEscapeString) { + if (matcher.group(1) != null) { + out.append(moduleConfig.escapeString).append(moduleConfig.escapeString); // double escape string + continue; + } + else if (matcher.group(2) != null) { + out.append(matcher.group(3)); // escaped value + continue; + } + } + String propertyName = null; - for (int i = 0; i < groupCount; i++) { + for (int i = firstPropertyGroupIndex; i < groupCount; i++) { propertyName = matcher.group(i + 1); if (propertyName != null) { break; diff --git a/plugins/maven/jps-plugin/src/org/jetbrains/jps/maven/model/impl/MavenModuleResourceConfiguration.java b/plugins/maven/jps-plugin/src/org/jetbrains/jps/maven/model/impl/MavenModuleResourceConfiguration.java index 3c4c47c18e56..86340adf0ea7 100644 --- a/plugins/maven/jps-plugin/src/org/jetbrains/jps/maven/model/impl/MavenModuleResourceConfiguration.java +++ b/plugins/maven/jps-plugin/src/org/jetbrains/jps/maven/model/impl/MavenModuleResourceConfiguration.java @@ -58,7 +58,7 @@ public class MavenModuleResourceConfiguration { public Set<String> filteringExclusions = new THashSet<String>(FileUtil.PATH_HASHING_STRATEGY); @OptionTag - public String escapeString = MavenProjectConfiguration.DEFAULT_ESCAPE_STRING; + public String escapeString = null; @OptionTag public boolean escapeWindowsPaths = true; diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/compiler/MavenResourceCompiler.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/compiler/MavenResourceCompiler.java index 209583b6f731..d5eb4a69d7f7 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/compiler/MavenResourceCompiler.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/compiler/MavenResourceCompiler.java @@ -167,7 +167,7 @@ public class MavenResourceCompiler implements ClassPostProcessingCompiler { Set<String> nonFilteredExtensions = collectNonFilteredExtensions(mavenProject); String escapeString = MavenJDOMUtil.findChildValueByPath(mavenProject.getPluginConfiguration("org.apache.maven.plugins", "maven-resources-plugin"), - "escapeString", "\\"); + "escapeString", null); List<MyProcessingItem> moduleItemsToProcess = new ArrayList<MyProcessingItem>(); collectProcessingItems(eachModule, mavenProject, context, properties, propertiesHashCode, @@ -245,7 +245,7 @@ public class MavenResourceCompiler implements ClassPostProcessingCompiler { Properties properties, long propertiesHashCode, Set<String> nonFilteredExtensions, - String escapeString, + @Nullable String escapeString, boolean tests, List<MyProcessingItem> result) { String outputDir = CompilerPaths.getModuleOutputPath(module, tests); @@ -305,7 +305,7 @@ public class MavenResourceCompiler implements ClassPostProcessingCompiler { final Properties properties, final long propertiesHashCode, final Set<String> nonFilteredExtensions, - final String escapeString, + @Nullable final String escapeString, final List<MyProcessingItem> result, final ProgressIndicator indicator) { VfsUtilCore.visitChildrenRecursively(currentDir, new VirtualFileVisitor() { @@ -476,7 +476,7 @@ public class MavenResourceCompiler implements ClassPostProcessingCompiler { boolean isFiltered, Properties properties, long propertiesHashCode, - String escapeString) { + @Nullable String escapeString) { myModule = module; mySourceFile = sourceFile; myOutputPath = outputPath; @@ -507,6 +507,7 @@ public class MavenResourceCompiler implements ClassPostProcessingCompiler { return myProperties; } + @Nullable public String getEscapeString() { return myEscapeString; } diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/MavenPropertyResolver.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/MavenPropertyResolver.java index 979e182bad25..66875895f278 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/MavenPropertyResolver.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/MavenPropertyResolver.java @@ -47,7 +47,7 @@ public class MavenPropertyResolver { public static void doFilterText(Module module, String text, Properties additionalProperties, - String propertyEscapeString, + @Nullable String propertyEscapeString, Appendable out) throws IOException { MavenProjectsManager manager = MavenProjectsManager.getInstance(module.getProject()); MavenProject mavenProject = manager.findProject(module); diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenModuleImporter.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenModuleImporter.java index 553175e5a07e..0d4b06b21cb0 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenModuleImporter.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenModuleImporter.java @@ -294,9 +294,7 @@ public class MavenModuleImporter { if (file == null) continue; if (libraryModel == null) { - String libraryName = artifact.getLibraryName(); - assert libraryName.startsWith(MavenArtifact.MAVEN_LIB_PREFIX); - libraryName = MavenArtifact.MAVEN_LIB_PREFIX + "ATTACHED-JAR: " + libraryName.substring(MavenArtifact.MAVEN_LIB_PREFIX.length()); + String libraryName = getAttachedJarsLibName(artifact); Library library = myModifiableModelsProvider.getLibraryByName(libraryName); if (library == null) { @@ -314,6 +312,14 @@ public class MavenModuleImporter { } @NotNull + public static String getAttachedJarsLibName(@NotNull MavenArtifact artifact) { + String libraryName = artifact.getLibraryName(); + assert libraryName.startsWith(MavenArtifact.MAVEN_LIB_PREFIX); + libraryName = MavenArtifact.MAVEN_LIB_PREFIX + "ATTACHED-JAR: " + libraryName.substring(MavenArtifact.MAVEN_LIB_PREFIX.length()); + return libraryName; + } + + @NotNull public static DependencyScope selectScope(String mavenScope) { if (MavenConstants.SCOPE_RUNTIME.equals(mavenScope)) return DependencyScope.RUNTIME; if (MavenConstants.SCOPE_TEST.equals(mavenScope)) return DependencyScope.TEST; diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenResourceCompilerConfigurationGenerator.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenResourceCompilerConfigurationGenerator.java index 523d5cbec958..c2b0aa9ba49b 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenResourceCompilerConfigurationGenerator.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenResourceCompilerConfigurationGenerator.java @@ -129,7 +129,7 @@ public class MavenResourceCompilerConfigurationGenerator { } Element pluginConfiguration = mavenProject.getPluginConfiguration("org.apache.maven.plugins", "maven-resources-plugin"); - resourceConfig.escapeString = MavenJDOMUtil.findChildValueByPath(pluginConfiguration, "escapeString", "\\"); + resourceConfig.escapeString = MavenJDOMUtil.findChildValueByPath(pluginConfiguration, "escapeString", null); String escapeWindowsPaths = MavenJDOMUtil.findChildValueByPath(pluginConfiguration, "escapeWindowsPaths"); if (escapeWindowsPaths != null) { resourceConfig.escapeWindowsPaths = Boolean.parseBoolean(escapeWindowsPaths); diff --git a/plugins/maven/src/test/java/org/jetbrains/idea/maven/compiler/ResourceFilteringTest.java b/plugins/maven/src/test/java/org/jetbrains/idea/maven/compiler/ResourceFilteringTest.java index 4c2c7815e5ff..80e738fa6a81 100644 --- a/plugins/maven/src/test/java/org/jetbrains/idea/maven/compiler/ResourceFilteringTest.java +++ b/plugins/maven/src/test/java/org/jetbrains/idea/maven/compiler/ResourceFilteringTest.java @@ -868,10 +868,15 @@ public abstract class ResourceFilteringTest extends MavenImportingTestCase { } public void testEscapingFiltering() throws Exception { + if (!useJps()) return; + createProjectSubFile("filters/filter.properties", "xxx=value"); createProjectSubFile("resources/file.properties", "value1=\\${xxx}\n" + - "value2=${xxx}\n"); + "value2=\\\\${xxx}\n" + + "value3=\\\\\\${xxx}\n" + + "value3=\\\\\\\\${xxx}\n" + + "value4=.\\.\\\\.\\\\\\."); importProject("<groupId>test</groupId>" + "<artifactId>project</artifactId>" + @@ -887,12 +892,24 @@ public abstract class ResourceFilteringTest extends MavenImportingTestCase { " <filtering>true</filtering>" + " </resource>" + " </resources>" + + " <plugins>" + + " <plugin>" + + " <groupId>org.apache.maven.plugins</groupId>" + + " <artifactId>maven-resources-plugin</artifactId>" + + " <configuration>" + + " <escapeString>\\</escapeString>" + + " </configuration>" + + " </plugin>" + + " </plugins>" + "</build>"); compileModules("project"); assertResult("target/classes/file.properties", "value1=${xxx}\n" + - "value2=value\n"); + "value2=\\\\value\n" + + "value3=\\\\${xxx}\n" + + "value3=\\\\\\\\value\n" + + "value4=.\\.\\\\.\\\\\\."); } public void testPropertyPriority() throws Exception { |