diff --git a/.idea/modules.xml b/.idea/modules.xml index 9e15d0263725..00d78128e8be 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -9,7 +9,8 @@ - + + diff --git a/build/scripts/layouts.gant b/build/scripts/layouts.gant index c26409ec2350..6dc01096ba64 100644 --- a/build/scripts/layouts.gant +++ b/build/scripts/layouts.gant @@ -364,6 +364,8 @@ public def layoutCommunityPlugins(String home) { include(name: "**/*.jar") exclude(name: "**/ddmlib_1.jar") } + + jar("android_rt.jar") {module("android-rt")} } } } diff --git a/build/scripts/libLicenses.gant b/build/scripts/libLicenses.gant index e0fe9f0cfa10..38597d626387 100644 --- a/build/scripts/libLicenses.gant +++ b/build/scripts/libLicenses.gant @@ -190,9 +190,9 @@ libraryLicense(name: "JavaHelp", version: "2.0_02", license: "included as licens libraryLicense(name: "JCIP Annotations", libraryName: "jcip", license: "Creative Commons Attribution License", url: "http://www.jcip.net", licenseUrl: "http://creativecommons.org/licenses/by/2.5") libraryLicense(name: "JDOM", version: "1.1 (with patches by JetBrains)", license: "modified Apache", url: "http://www.jdom.org/", licenseUrl: "http://www.jdom.org/docs/faq.html#a0030") libraryLicense(name: "jgit-1.1.0", version: "1.1.0.201109151100", license: "EDL/BSD", url: "http://www.eclipse.org/jgit/", licenseUrl: "http://www.eclipse.org/org/documents/edl-v10.php", attachedTo: "git4idea") -libraryLicense(name: "JGoodies Forms", libraryName: "jgoodies-forms", version: "CVS snapshot as of 5 May 2006", license: "BSD ", url: "http://www.jgoodies.com/freeware/forms/", licenseUrl: "http://www.jgoodies.com/downloads/libraries.html") -libraryLicense(name: "JGoodies Looks", attachedTo: "platform-impl", version: "2.4.2", license: "BSD ", url: "http://www.jgoodies.com/freeware/looks/", licenseUrl: "http://www.jgoodies.com/downloads/libraries.html") -libraryLicense(name: "JGoodies Common", attachedTo: "platform-impl", version: "1.2.1", license: "BSD ", url: "http://www.jgoodies.com/freeware/looks/", licenseUrl: "http://www.jgoodies.com/downloads/libraries.html") +libraryLicense(name: "JGoodies Forms", libraryName: "jgoodies-forms", version: "1.1-preview 2006-05-04 11:55:37", license: "BSD ", url: "http://www.jgoodies.com/freeware/forms/", licenseUrl: "http://www.jgoodies.com/downloads/libraries.html") +libraryLicense(name: "JGoodies Looks", libraryName: "jgoodies-looks", version: "2.4.2", license: "BSD ", url: "http://www.jgoodies.com/freeware/looks/", licenseUrl: "http://www.jgoodies.com/downloads/libraries.html") +libraryLicense(name: "JGoodies Common", libraryName: "jgoodies-common", version: "1.2.1", license: "BSD ", url: "http://www.jgoodies.com/freeware/looks/", licenseUrl: "http://www.jgoodies.com/downloads/libraries.html") libraryLicense(name: "JNA", libraryName: "jna", version: "3.2.4", license: "LGPL 2.1", url: "https://jna.dev.java.net/", licenseUrl: "http://www.opensource.org/licenses/lgpl-2.1.php") libraryLicense(name: "JNA", libraryName: "jna.jar", version: "3.2.7", license: "LGPL 2.1", url: "https://jna.dev.java.net/", licenseUrl: "http://www.opensource.org/licenses/lgpl-2.1.php") libraryLicense(name: "JSch", libraryName: "JSch", version: "0.1.44", license: "BSD", url: "http://www.jcraft.com/jsch/", licenseUrl: "http://www.jcraft.com/jsch/LICENSE.txt") @@ -238,4 +238,5 @@ libraryLicense(name: "Kryo", libraryName: "Kryo", version: "1.04", license: "New jetbrainsLibrary("JPS") jetbrainsLibrary("Maven Embedder") jetbrainsLibrary("tcServiceMessages") -jetbrainsLibrary("optimizedFileManager.jar") \ No newline at end of file +jetbrainsLibrary("optimizedFileManager.jar") +jetbrainsLibrary("RunTime") diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/FramesPanel.java b/java/debugger/impl/src/com/intellij/debugger/ui/FramesPanel.java index bcde86b2c743..79a45ec2c7b1 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/FramesPanel.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/FramesPanel.java @@ -51,8 +51,10 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.ComboBoxWithWidePopup; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.IconLoader; +import com.intellij.ui.CaptionPanel; import com.intellij.ui.PopupHandler; import com.intellij.ui.ScrollPaneFactory; +import com.intellij.ui.border.CustomLineBorder; import com.intellij.ui.components.panels.Wrapper; import com.intellij.util.Alarm; import com.sun.jdi.ObjectCollectedException; @@ -114,6 +116,8 @@ public class FramesPanel extends UpdatableDebuggerView { final ActionToolbar toolbar = createToolbar(); Wrapper threads = new Wrapper(); + CustomLineBorder border = new CustomLineBorder(CaptionPanel.CNT_ACTIVE_COLOR, 0, 0, 1, 0); + threads.setBorder(border); threads.add(toolbar.getComponent(), BorderLayout.EAST); threads.add(myThreadsCombo, BorderLayout.CENTER); add(threads, BorderLayout.NORTH); diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/MainWatchPanel.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/MainWatchPanel.java index 314e360d2442..1674be4a3b11 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/MainWatchPanel.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/MainWatchPanel.java @@ -43,10 +43,10 @@ import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; -import com.intellij.ui.AnActionButton; -import com.intellij.ui.AnActionButtonRunnable; -import com.intellij.ui.ListenerUtil; -import com.intellij.ui.ToolbarDecorator; +import com.intellij.openapi.util.SystemInfo; +import com.intellij.ui.*; +import com.intellij.ui.border.CustomLineBorder; +import com.intellij.xdebugger.impl.actions.XDebuggerActions; import javax.swing.*; import java.awt.*; @@ -218,13 +218,20 @@ public class MainWatchPanel extends WatchPanel implements DataProvider { executeAction(DebuggerActions.NEW_WATCH, tree); } }); - // TODO[den]: add "Add to watches action" + // TODO[den]: add "Add to watches action" on Mac + if (!SystemInfo.isMac) { + decorator.addExtraAction(AnActionButton.fromAction(ActionManager.getInstance().getAction(XDebuggerActions.ADD_TO_WATCH))); + } decorator.setRemoveAction(new AnActionButtonRunnable() { @Override public void run(AnActionButton button) { executeAction(DebuggerActions.REMOVE_WATCH, tree); } }); + CustomLineBorder border = new CustomLineBorder(CaptionPanel.CNT_ACTIVE_COLOR, + SystemInfo.isMac ? 1 : 0, 0, + SystemInfo.isMac ? 0 : 1, 0); + decorator.setToolbarBorder(border); final JPanel panel = decorator.createPanel(); panel.setBorder(null); return panel; diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/PostHighlightingPass.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/PostHighlightingPass.java index 815715a494fa..94249f82e089 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/PostHighlightingPass.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/PostHighlightingPass.java @@ -640,9 +640,9 @@ public class PostHighlightingPass extends TextEditorHighlightingPass { } private static boolean isEnumValuesMethodUsed(PsiMember member, ProgressIndicator progress, GlobalUsageHelper helper) { - final PsiClassImpl containingClass = (PsiClassImpl)member.getContainingClass(); - if (containingClass == null) return true; - final PsiMethod valuesMethod = containingClass.getValuesMethod(); + final PsiClass containingClass = member.getContainingClass(); + if (containingClass == null || !(containingClass instanceof PsiClassImpl)) return true; + final PsiMethod valuesMethod = ((PsiClassImpl)containingClass).getValuesMethod(); if (valuesMethod == null) return true; return isMethodReferenced(valuesMethod, progress, helper); } diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddOnDemandStaticImportAction.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddOnDemandStaticImportAction.java index 1810ff8cef1b..517f21e8def5 100644 --- a/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddOnDemandStaticImportAction.java +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddOnDemandStaticImportAction.java @@ -34,6 +34,8 @@ import gnu.trove.TIntProcedure; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.List; + /** * @author ven */ @@ -104,7 +106,7 @@ public class AddOnDemandStaticImportAction extends PsiElementBaseIntentionAction } importList.add(importStaticStatement); - PsiFile[] roots = file.getPsiRoots(); + List roots = file.getViewProvider().getAllFiles(); for (final PsiFile root : roots) { PsiElement copy = root.copy(); final PsiManager manager = root.getManager(); diff --git a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/ImportHelper.java b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/ImportHelper.java index 840947dedf8e..c85b542a0d13 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/ImportHelper.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/ImportHelper.java @@ -696,7 +696,7 @@ public class ImportHelper{ PsiFile context) { String packageName = file.getPackageName(); - final PsiElement[] roots = file.getPsiRoots(); + final List roots = file.getViewProvider().getAllFiles(); for (PsiElement root : roots) { addNamesToImport(names, comments, root, packageName, context); } diff --git a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/JavaCodeStyleManagerImpl.java b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/JavaCodeStyleManagerImpl.java index 1da1f5915186..8e6d81444213 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/JavaCodeStyleManagerImpl.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/JavaCodeStyleManagerImpl.java @@ -153,7 +153,7 @@ public class JavaCodeStyleManagerImpl extends JavaCodeStyleManager { } else { redundants = allImports; - final PsiElement[] roots = file.getPsiRoots(); + final List roots = file.getViewProvider().getAllFiles(); for (PsiElement root : roots) { root.accept(new JavaRecursiveElementWalkingVisitor() { @Override public void visitReferenceElement(PsiJavaCodeReferenceElement reference) { diff --git a/java/java-psi-impl/src/com/intellij/psi/ClassFileViewProviderFactory.java b/java/java-psi-impl/src/com/intellij/psi/ClassFileViewProviderFactory.java index bb7fd8e6d9de..213468b0669f 100644 --- a/java/java-psi-impl/src/com/intellij/psi/ClassFileViewProviderFactory.java +++ b/java/java-psi-impl/src/com/intellij/psi/ClassFileViewProviderFactory.java @@ -23,10 +23,11 @@ import com.intellij.lang.Language; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.fileTypes.ContentBasedFileSubstitutor; import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; public class ClassFileViewProviderFactory implements FileViewProviderFactory{ @Override - public FileViewProvider createFileViewProvider(final VirtualFile file, final Language language, final PsiManager manager, final boolean physical) { + public FileViewProvider createFileViewProvider(@NotNull final VirtualFile file, final Language language, @NotNull final PsiManager manager, final boolean physical) { // Define language for compiled file final ContentBasedFileSubstitutor[] processors = Extensions.getExtensions(ContentBasedFileSubstitutor.EP_NAME); for (ContentBasedFileSubstitutor processor : processors) { diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/StubBuildingVisitor.java b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/StubBuildingVisitor.java index 72de4e653c72..b071cc0053bc 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/StubBuildingVisitor.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/StubBuildingVisitor.java @@ -350,8 +350,13 @@ public class StubBuildingVisitor implements ClassVisitor { final String desc, final String signature, final String[] exceptions) { - if ((access & Opcodes.ACC_SYNTHETIC) != 0) return null; - if ((access & Opcodes.ACC_BRIDGE) != 0) return null; + boolean isSynthetic = (access & Opcodes.ACC_SYNTHETIC) != 0; + + // JLS 13.1 says: Any constructs introduced by the compiler that do not have a corresponding construct in the source code + // must be marked as synthetic, except for default constructors and the class initialization method. + // However Scala compiler erroneously generates ACC_BRIDGE instead of ACC_SYNTHETIC flag for in-trait implementation delegation. See IDEA-78649 + if (isSynthetic) return null; + if (SYNTHETIC_CLINIT_METHOD.equals(name)) return null; boolean isDeprecated = (access & Opcodes.ACC_DEPRECATED) != 0; diff --git a/java/java-tests/testSrc/com/intellij/lang/java/parser/JavaParsingTestCase.java b/java/java-tests/testSrc/com/intellij/lang/java/parser/JavaParsingTestCase.java index bd5c08833ab1..79915cc67295 100644 --- a/java/java-tests/testSrc/com/intellij/lang/java/parser/JavaParsingTestCase.java +++ b/java/java-tests/testSrc/com/intellij/lang/java/parser/JavaParsingTestCase.java @@ -108,7 +108,7 @@ public abstract class JavaParsingTestCase extends ParsingTestCase { myFile = createPsiFile(name, text, parser); myFile.putUserData(PsiUtil.FILE_LANGUAGE_LEVEL_KEY, myLanguageLevel); try { - checkResult(name + ".txt", myFile); + checkResult(name, myFile); } catch (IOException e) { throw new RuntimeException(e); diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java index de7c5fde53b0..1399c69ed651 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java @@ -77,11 +77,13 @@ public class IncProjectBuilder { } catch (ProjectBuildException e) { final Throwable cause = e.getCause(); - if (cause instanceof PersistentEnumerator.CorruptedException || cause instanceof MappingFailedException) { + if (cause instanceof PersistentEnumerator.CorruptedException || cause instanceof MappingFailedException || cause instanceof IOException) { // force rebuild - myMessageDispatcher.processMessage(new CompilerMessage(COMPILE_SERVER_NAME, BuildMessage.Kind.INFO, - "Internal caches are corrupted or have outdated format, forcing project rebuild: " + - e.getMessage())); + myMessageDispatcher.processMessage(new CompilerMessage( + COMPILE_SERVER_NAME, BuildMessage.Kind.INFO, + "Internal caches are corrupted or have outdated format, forcing project rebuild: " + + e.getMessage()) + ); flushContext(context); context = createContext(new AllProjectScope(scope.getProject(), Collections.emptySet(), true), false, true); runBuild(context); diff --git a/platform/core-api/src/com/intellij/openapi/editor/event/DocumentEvent.java b/platform/core-api/src/com/intellij/openapi/editor/event/DocumentEvent.java index 181072e30c89..10f2b7ee9126 100644 --- a/platform/core-api/src/com/intellij/openapi/editor/event/DocumentEvent.java +++ b/platform/core-api/src/com/intellij/openapi/editor/event/DocumentEvent.java @@ -21,22 +21,27 @@ import org.jetbrains.annotations.NotNull; import java.util.EventObject; public abstract class DocumentEvent extends EventObject { - protected DocumentEvent(Document document) { + protected DocumentEvent(@NotNull Document document) { super(document); } - @NotNull public abstract Document getDocument(); + @NotNull + public abstract Document getDocument(); public abstract int getOffset(); public abstract int getOldLength(); + public abstract int getNewLength(); + @NotNull public abstract CharSequence getOldFragment(); + + @NotNull public abstract CharSequence getNewFragment(); public abstract long getOldTimeStamp(); - + public boolean isWholeTextReplaced() { return getOffset() == 0 && getNewLength() == getDocument().getTextLength(); } diff --git a/platform/core-api/src/com/intellij/psi/FileViewProviderFactory.java b/platform/core-api/src/com/intellij/psi/FileViewProviderFactory.java index a59327bf1409..66e25e3f9ca7 100644 --- a/platform/core-api/src/com/intellij/psi/FileViewProviderFactory.java +++ b/platform/core-api/src/com/intellij/psi/FileViewProviderFactory.java @@ -18,6 +18,7 @@ package com.intellij.psi; import com.intellij.lang.Language; import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; /** * Register in extension point {@code com.intellij.fileType.fileViewProviderFactory} @@ -26,5 +27,5 @@ import com.intellij.openapi.vfs.VirtualFile; * @author yole */ public interface FileViewProviderFactory { - FileViewProvider createFileViewProvider(final VirtualFile file, final Language language, final PsiManager manager, final boolean physical); + FileViewProvider createFileViewProvider(@NotNull VirtualFile file, Language language, @NotNull PsiManager manager, final boolean physical); } \ No newline at end of file diff --git a/platform/core-api/src/com/intellij/psi/search/LocalSearchScope.java b/platform/core-api/src/com/intellij/psi/search/LocalSearchScope.java index 562c2b617f85..c092c70e2d10 100644 --- a/platform/core-api/src/com/intellij/psi/search/LocalSearchScope.java +++ b/platform/core-api/src/com/intellij/psi/search/LocalSearchScope.java @@ -66,7 +66,8 @@ public class LocalSearchScope extends SearchScope { for (final PsiElement element : scope) { LOG.assertTrue(element.getContainingFile() != null, element.getClass().getName()); if (element instanceof PsiFile) { - ContainerUtil.addAll(localScope, ((PsiFile)element).getPsiRoots()); + List files = ((PsiFile)element).getViewProvider().getAllFiles(); + ContainerUtil.addAll(localScope, files); } else { localScope.add(element); diff --git a/platform/core-api/src/com/intellij/psi/util/PsiTreeUtil.java b/platform/core-api/src/com/intellij/psi/util/PsiTreeUtil.java index 9aac4bf4323d..c43925dde0ff 100644 --- a/platform/core-api/src/com/intellij/psi/util/PsiTreeUtil.java +++ b/platform/core-api/src/com/intellij/psi/util/PsiTreeUtil.java @@ -713,7 +713,7 @@ public class PsiTreeUtil { int offset, @NotNull Class clazz, boolean strictStart) { - final PsiElement[] psiRoots = file.getPsiRoots(); + final List psiRoots = file.getViewProvider().getAllFiles(); T result = null; for (PsiElement root : psiRoots) { final PsiElement elementAt = root.findElementAt(offset); @@ -739,7 +739,7 @@ public class PsiTreeUtil { @NotNull Class clazz, boolean strictStart, @NotNull Class... stopAt) { - final PsiElement[] psiRoots = file.getPsiRoots(); + final List psiRoots = file.getViewProvider().getAllFiles(); T result = null; for (PsiElement root : psiRoots) { final PsiElement elementAt = root.findElementAt(offset); diff --git a/platform/core-impl/src/com/intellij/openapi/editor/impl/PersistentRangeMarker.java b/platform/core-impl/src/com/intellij/openapi/editor/impl/PersistentRangeMarker.java index e09639f0aded..e1b34cc49ad7 100644 --- a/platform/core-impl/src/com/intellij/openapi/editor/impl/PersistentRangeMarker.java +++ b/platform/core-impl/src/com/intellij/openapi/editor/impl/PersistentRangeMarker.java @@ -25,8 +25,8 @@ import com.intellij.util.diff.FilesTooBigForDiffException; * is replaced. *

* Example: consider that the user selects all text at editor (Ctrl+A), copies it to the buffer (Ctrl+C) and performs paste (Ctrl+V). - * All document text is replaced then but in essence it's the same, hence, we may want particular range markers to be still valid. - * + * All document text is replaced then but in essence it's the same, hence, we may want particular range markers to be still valid. + * * @author max */ class PersistentRangeMarker extends RangeMarkerImpl { @@ -69,22 +69,23 @@ class PersistentRangeMarker extends RangeMarkerImpl { private boolean translateViaDiff(final DocumentEventImpl event) { try { myStartLine = event.translateLineViaDiffStrict(myStartLine); - if (myStartLine < 0 || myStartLine >= getDocument().getLineCount()){ + if (myStartLine < 0 || myStartLine >= getDocument().getLineCount()) { invalidate(event); } - else{ + else { setIntervalStart(getDocument().getLineStartOffset(myStartLine) + myStartColumn); } myEndLine = event.translateLineViaDiffStrict(myEndLine); - if (myEndLine < 0 || myEndLine >= getDocument().getLineCount()){ + if (myEndLine < 0 || myEndLine >= getDocument().getLineCount()) { invalidate(event); } - else{ + else { setIntervalEnd(getDocument().getLineStartOffset(myEndLine) + myEndColumn); } return true; - } catch (FilesTooBigForDiffException e) { + } + catch (FilesTooBigForDiffException e) { return false; } } @@ -94,12 +95,12 @@ class PersistentRangeMarker extends RangeMarkerImpl { DocumentEventImpl event = (DocumentEventImpl)e; final boolean shouldTranslateViaDiff = PersistentRangeMarkerUtil.shouldTranslateViaDiff(event, this); boolean wasTranslated = shouldTranslateViaDiff; - if (shouldTranslateViaDiff){ + if (shouldTranslateViaDiff) { wasTranslated = translateViaDiff(event); } - if (! wasTranslated) { + if (!wasTranslated) { super.changedUpdateImpl(e); - if (isValid()){ + if (isValid()) { storeLinesAndCols(e); } } diff --git a/platform/core-impl/src/com/intellij/openapi/editor/impl/event/DocumentEventImpl.java b/platform/core-impl/src/com/intellij/openapi/editor/impl/event/DocumentEventImpl.java index 1bd95fca7b5c..993dda9c0535 100644 --- a/platform/core-impl/src/com/intellij/openapi/editor/impl/event/DocumentEventImpl.java +++ b/platform/core-impl/src/com/intellij/openapi/editor/impl/event/DocumentEventImpl.java @@ -38,6 +38,8 @@ public class DocumentEventImpl extends DocumentEvent { private final long myOldTimeStamp; private final boolean myIsWholeDocReplaced; private Diff.Change myChange; + private static final Diff.Change TOO_BIG_FILE = new Diff.Change(0, 0, 0, 0, null) { + }; private int myOptimizedLineShift = -1; private boolean myOptimizedLineShiftCalculated; @@ -45,7 +47,11 @@ public class DocumentEventImpl extends DocumentEvent { private int myOptimizedOldLineShift = -1; private boolean myOptimizedOldLineShiftCalculated; - public DocumentEventImpl(Document document, int offset, CharSequence oldString, CharSequence newString, long oldTimeStamp, + public DocumentEventImpl(@NotNull Document document, + int offset, + CharSequence oldString, + CharSequence newString, + long oldTimeStamp, boolean wholeTextReplaced) { super(document); myOffset = offset; @@ -83,11 +89,13 @@ public class DocumentEventImpl extends DocumentEvent { return myNewLength; } + @NotNull @Override public CharSequence getOldFragment() { return myOldString; } + @NotNull @Override public CharSequence getNewFragment() { return myNewString; @@ -96,11 +104,11 @@ public class DocumentEventImpl extends DocumentEvent { @Override @NotNull public Document getDocument() { - return (Document) getSource(); + return (Document)getSource(); } public int getStartOldIndex() { - if(isStartOldIndexCalculated) return myStartOldIndex; + if (isStartOldIndexCalculated) return myStartOldIndex; isStartOldIndexCalculated = true; myStartOldIndex = getDocument().getLineNumber(myOffset); @@ -108,21 +116,21 @@ public class DocumentEventImpl extends DocumentEvent { } public boolean isOnlyOneLineChanged() { - if(isOnlyOneLineChangedCalculated) return isOnlyOneLineChanged; + if (isOnlyOneLineChangedCalculated) return isOnlyOneLineChanged; isOnlyOneLineChangedCalculated = true; isOnlyOneLineChanged = true; - for(int i=0; i= change.line0 + change.deleted) { newLine += change.inserted - change.deleted; - } else { + } + else { int delta = Math.min(change.inserted, line - change.line0); newLine = change.line1 + delta; break; @@ -172,16 +179,23 @@ public class DocumentEventImpl extends DocumentEvent { } public int translateLineViaDiffStrict(int line) throws FilesTooBigForDiffException { - if (myChange == null) buildDiff(); - Diff.Change change = myChange; + Diff.Change change = reBuildDiffIfNeeded(); if (change == null) return line; return Diff.translateLine(change, line); } - private void buildDiff() throws FilesTooBigForDiffException { - //Diff diff = new Diff(strings1, strings2); - //myChange = diff.diff_2(false); - myChange = Diff.buildChanges(myOldString, myNewString); + private Diff.Change reBuildDiffIfNeeded() throws FilesTooBigForDiffException { + if (myChange == TOO_BIG_FILE) throw new FilesTooBigForDiffException(0); + if (myChange == null) { + try { + myChange = Diff.buildChanges(myOldString, myNewString); + } + catch (FilesTooBigForDiffException e) { + myChange = TOO_BIG_FILE; + throw e; + } + } + return myChange; } public int getOptimizedLineShift() { diff --git a/platform/core-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java b/platform/core-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java index 553de3e50cb9..dd202dd57883 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java +++ b/platform/core-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java @@ -519,18 +519,17 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF } roots[i++] = psi; } - // getPsiRoots() returns languages in the same order - //if (roots.length > 1) { - // Arrays.sort(roots, FILE_BY_LANGUAGE_ID); - //} + if (roots.length > 1) { + Arrays.sort(roots, FILE_BY_LANGUAGE_ID); + } return roots; } - //private static final Comparator FILE_BY_LANGUAGE_ID = new Comparator() { - // @Override - // public int compare(PsiFile o1, PsiFile o2) { - // return o1.getLanguage().getID().compareTo(o2.getLanguage().getID()); - // } - //}; + private static final Comparator FILE_BY_LANGUAGE_ID = new Comparator() { + @Override + public int compare(PsiFile o1, PsiFile o2) { + return o1.getLanguage().getID().compareTo(o2.getLanguage().getID()); + } + }; @Override public boolean isPhysical() { diff --git a/platform/lang-api/src/com/intellij/codeInspection/ProblemsHolder.java b/platform/lang-api/src/com/intellij/codeInspection/ProblemsHolder.java index 9d1a226294f3..8933cb6006b8 100644 --- a/platform/lang-api/src/com/intellij/codeInspection/ProblemsHolder.java +++ b/platform/lang-api/src/com/intellij/codeInspection/ProblemsHolder.java @@ -28,7 +28,6 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiReference; import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.util.ArrayUtil; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -91,7 +90,7 @@ public class ProblemsHolder { private boolean isInPsiFile(@NotNull PsiElement element) { PsiFile file = element.getContainingFile(); - return ArrayUtil.indexOf(myFile.getPsiRoots(), file) != -1; + return myFile.getViewProvider() == file.getViewProvider(); } private void redirectProblem(@NotNull final ProblemDescriptor problem, @NotNull final PsiElement target) { diff --git a/platform/lang-api/src/com/intellij/psi/util/PsiUtilBase.java b/platform/lang-api/src/com/intellij/psi/util/PsiUtilBase.java index 283c09222413..56a9c1960525 100644 --- a/platform/lang-api/src/com/intellij/psi/util/PsiUtilBase.java +++ b/platform/lang-api/src/com/intellij/psi/util/PsiUtilBase.java @@ -42,6 +42,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; +import java.util.*; public class PsiUtilBase extends PsiUtilCore { @@ -51,6 +52,12 @@ public class PsiUtilBase extends PsiUtilCore { throw new IllegalAccessError(); } }; + public static final Comparator LANGUAGE_COMPARATOR = new Comparator() { + @Override + public int compare(Language o1, Language o2) { + return o1.getID().compareTo(o2.getID()); + } + }; public static int getRootIndex(PsiElement root) { ASTNode node = root.getNode(); @@ -59,11 +66,18 @@ public class PsiUtilBase extends PsiUtilCore { } if(node != null) root = node.getPsi(); final PsiFile containingFile = root.getContainingFile(); - final PsiFile[] psiRoots = containingFile.getPsiRoots(); - for (int i = 0; i < psiRoots.length; i++) { - if(root == psiRoots[i]) return i; + FileViewProvider provider = containingFile.getViewProvider(); + Set languages = provider.getLanguages(); + if (languages.size() == 1) { + return 0; } - throw new RuntimeException("invalid element"); + List array = new ArrayList(languages); + Collections.sort(array, LANGUAGE_COMPARATOR); + for (int i = 0; i < array.size(); i++) { + Language language = array.get(i); + if (provider.getPsi(language) == containingFile) return i; + } + throw new RuntimeException("Cannot find root for: "+root); } @NotNull diff --git a/platform/lang-impl/src/com/intellij/application/options/CodeStyleAbstractPanel.java b/platform/lang-impl/src/com/intellij/application/options/CodeStyleAbstractPanel.java index cb467e646318..2ba65b47b927 100644 --- a/platform/lang-impl/src/com/intellij/application/options/CodeStyleAbstractPanel.java +++ b/platform/lang-impl/src/com/intellij/application/options/CodeStyleAbstractPanel.java @@ -615,10 +615,8 @@ public abstract class CodeStyleAbstractPanel implements Disposable { return myCurrentSettings; } - public void setupCopyFromMenu(Menu copyMenu) { - if (copyMenu.getItemCount() > 0) { - copyMenu.removeAll(); - } + public void setupCopyFromMenu(JPopupMenu copyMenu) { + copyMenu.removeAll(); } public boolean isCopyFromMenuAvailable() { diff --git a/platform/lang-impl/src/com/intellij/application/options/TabbedLanguageCodeStylePanel.java b/platform/lang-impl/src/com/intellij/application/options/TabbedLanguageCodeStylePanel.java index d0732dd73fab..8de3532808a5 100644 --- a/platform/lang-impl/src/com/intellij/application/options/TabbedLanguageCodeStylePanel.java +++ b/platform/lang-impl/src/com/intellij/application/options/TabbedLanguageCodeStylePanel.java @@ -28,7 +28,6 @@ import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectUtil; import com.intellij.openapi.util.Disposer; -import com.intellij.openapi.util.IconLoader; import com.intellij.psi.codeStyle.*; import com.intellij.ui.components.JBTabbedPane; import org.jetbrains.annotations.NotNull; @@ -36,7 +35,8 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; -import java.awt.event.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -47,15 +47,12 @@ import java.util.List; */ public abstract class TabbedLanguageCodeStylePanel extends CodeStyleAbstractPanel { - - private final static Icon COPY_ICON = IconLoader.getIcon("/actions/import.png"); - private CodeStyleAbstractPanel myActiveTab; private List myTabs; private JPanel myPanel; private JTabbedPane myTabbedPane; private PredefinedCodeStyle[] myPredefinedCodeStyles; - private PopupMenu myCopyFromMenu; + private JPopupMenu myCopyFromMenu; protected TabbedLanguageCodeStylePanel(@Nullable Language language, CodeStyleSettings currentSettings, CodeStyleSettings settings) { super(language, currentSettings, settings); @@ -120,37 +117,22 @@ public abstract class TabbedLanguageCodeStylePanel extends CodeStyleAbstractPane myTabs = new ArrayList(); myPanel.add(myTabbedPane); initTabs(getSettings()); - addSetFrom(); } assert !myTabs.isEmpty(); } - private void addSetFrom() { - myPredefinedCodeStyles = getPredefinedStyles(); - JLabel dummyLabel = new JLabel(""); - myTabbedPane.addTab("Set From...", dummyLabel); - int dummyIndex = myTabbedPane.indexOfComponent(dummyLabel); - myTabbedPane.setEnabledAt(dummyIndex, false); - JPanel setFromPanel = new JPanel(); - setFromPanel.setBorder(BorderFactory.createEtchedBorder()); - setFromPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 10, 0)); - final JLabel setFromLabel = new JLabel("Set from..."); - setFromPanel.add(setFromLabel); - setFromLabel.setIcon(COPY_ICON); - setFromLabel.addMouseListener(new MouseAdapter() { - @Override - public void mousePressed(MouseEvent e) { - initCopyFromMenu(setFromLabel); - myCopyFromMenu.show(e.getComponent(), e.getX(), e.getY()); - } - }); - myTabbedPane.setTabComponentAt(dummyIndex, setFromPanel); + public void showSetFrom(Object e) { + final Container component = (Container)e; + final Component[] components = component.getComponents(); + final Component last = components[components.length - 1]; + initCopyFromMenu(last); + myCopyFromMenu.show(last, 0, last.getHeight() + 3); } - - private void initCopyFromMenu(JComponent parent) { + + private void initCopyFromMenu(Component component) { if (myCopyFromMenu == null) { - myCopyFromMenu = new PopupMenu(); - parent.add(myCopyFromMenu); + myCopyFromMenu = new JPopupMenu(); + //component.add(myCopyFromMenu); setupCopyFromMenu(myCopyFromMenu); } } @@ -283,13 +265,13 @@ public abstract class TabbedLanguageCodeStylePanel extends CodeStyleAbstractPane @Override - public void setupCopyFromMenu(Menu copyMenu) { + public void setupCopyFromMenu(JPopupMenu copyMenu) { super.setupCopyFromMenu(copyMenu); if (myPredefinedCodeStyles.length > 0) { - Menu langs = new Menu("Language"); //TODO: Move to resource bundle + JMenuItem langs = new JMenuItem("Language"); //TODO: Move to resource bundle copyMenu.add(langs); fillLanguages(langs); - Menu predefined = new Menu("Predefined Style"); //TODO: Move to resource bundle + JMenuItem predefined = new JMenuItem("Predefined Style"); //TODO: Move to resource bundle copyMenu.add(predefined); fillPredefined(predefined); } @@ -299,14 +281,14 @@ public abstract class TabbedLanguageCodeStylePanel extends CodeStyleAbstractPane } - private void fillLanguages(Menu parentMenu) { + private void fillLanguages(JComponent parentMenu) { Language[] languages = LanguageCodeStyleSettingsProvider.getLanguagesWithCodeStyleSettings(); @SuppressWarnings("UnnecessaryFullyQualifiedName") - java.util.List langItems = new ArrayList(); + java.util.List langItems = new ArrayList(); for (final Language lang : languages) { if (!lang.equals(getDefaultLanguage())) { final String langName = LanguageCodeStyleSettingsProvider.getLanguageName(lang); - MenuItem langItem = new MenuItem(langName); + JMenuItem langItem = new JMenuItem(langName); langItem.addActionListener(new ActionListener(){ @Override public void actionPerformed(ActionEvent e) { @@ -316,20 +298,20 @@ public abstract class TabbedLanguageCodeStylePanel extends CodeStyleAbstractPane langItems.add(langItem); } } - Collections.sort(langItems, new Comparator() { + Collections.sort(langItems, new Comparator() { @Override - public int compare(MenuItem item1, MenuItem item2) { - return item1.getLabel().compareToIgnoreCase(item2.getLabel()); + public int compare(JMenuItem item1, JMenuItem item2) { + return item1.getText().compareToIgnoreCase(item2.getText()); } }); - for (MenuItem langItem : langItems) { + for (JMenuItem langItem : langItems) { parentMenu.add(langItem); } } - private void fillPredefined(Menu parentMenu) { + private void fillPredefined(JMenuItem parentMenu) { for (final PredefinedCodeStyle predefinedCodeStyle : myPredefinedCodeStyles) { - MenuItem predefinedItem = new MenuItem(predefinedCodeStyle.getName()); + JMenuItem predefinedItem = new JMenuItem(predefinedCodeStyle.getName()); parentMenu.add(predefinedItem); predefinedItem.addActionListener(new ActionListener() { @Override diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/CodeStyleMainPanel.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/CodeStyleMainPanel.java index 3ac71f3f27d8..f998dfb410c7 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/CodeStyleMainPanel.java +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/CodeStyleMainPanel.java @@ -16,18 +16,20 @@ package com.intellij.application.options.codeStyle; +import com.intellij.application.options.CodeStyleAbstractPanel; +import com.intellij.application.options.TabbedLanguageCodeStylePanel; import com.intellij.lang.Language; import com.intellij.openapi.application.ApplicationBundle; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.ui.DetailsComponent; import com.intellij.psi.codeStyle.CodeStyleScheme; import com.intellij.psi.codeStyle.CodeStyleSchemes; -import com.intellij.psi.codeStyle.LanguageCodeStyleSettingsProvider; import com.intellij.util.Alarm; import org.jetbrains.annotations.NonNls; import javax.swing.*; import java.awt.*; +import java.awt.event.ActionEvent; import java.util.Collection; import java.util.HashMap; import java.util.Map; @@ -93,6 +95,7 @@ public class CodeStyleMainPanel extends JPanel implements LanguageSelectorListen myDetailsComponent.setPaintBorder(false); myDetailsComponent.setContent(mySettingsPanel); myDetailsComponent.setText(getDisplayName()); + myDetailsComponent.setBannerMinHeight(24); add(myDetailsComponent.getComponent(), BorderLayout.CENTER); @@ -120,6 +123,7 @@ public class CodeStyleMainPanel extends JPanel implements LanguageSelectorListen ensureCurrentPanel().onSomethingChanged(); String schemeName = myModel.getSelectedScheme().getName(); myDetailsComponent.setText(schemeName); + updateSetFrom(); myLayout.show(mySettingsPanel, schemeName); } } @@ -137,6 +141,21 @@ public class CodeStyleMainPanel extends JPanel implements LanguageSelectorListen } } + private void updateSetFrom() { + final CodeStyleAbstractPanel selectedPanel = ensureCurrentPanel().getSelectedPanel(); + if (selectedPanel instanceof TabbedLanguageCodeStylePanel) { + myDetailsComponent.setBannerActions(new Action[]{new AbstractAction("Set from...") { + @Override + public void actionPerformed(ActionEvent e) { + final CodeStyleAbstractPanel selectedPanel = ensureCurrentPanel().getSelectedPanel(); + if (selectedPanel instanceof TabbedLanguageCodeStylePanel) { + ((TabbedLanguageCodeStylePanel)selectedPanel).showSetFrom(e.getSource()); + } + } + }}); + } + } + public NewCodeStyleSettingsPanel[] getPanels() { final Collection panels = mySettingsPanels.values(); return panels.toArray(new NewCodeStyleSettingsPanel[panels.size()]); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/HectorComponent.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/HectorComponent.java index f43f4e7ad6ce..d8d1cea46466 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/HectorComponent.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/HectorComponent.java @@ -39,11 +39,13 @@ import com.intellij.profile.codeInspection.ui.ErrorsConfigurable; import com.intellij.psi.FileViewProvider; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; +import com.intellij.psi.util.PsiUtilBase; import com.intellij.ui.Gray; import com.intellij.ui.HyperlinkLabel; import com.intellij.ui.IdeBorderFactory; import com.intellij.ui.awt.RelativePoint; import com.intellij.util.ui.UIUtil; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; @@ -55,6 +57,7 @@ import javax.swing.plaf.basic.BasicSliderUI; import java.awt.*; import java.lang.ref.WeakReference; import java.util.*; +import java.util.List; /** * User: anna @@ -70,7 +73,7 @@ public class HectorComponent extends JPanel { private final String myTitle = EditorBundle.message("hector.highlighting.level.title"); - public HectorComponent(PsiFile file) { + public HectorComponent(@NotNull PsiFile file) { super(new GridBagLayout()); setBorder(BorderFactory.createEmptyBorder(0, 0, 7, 0)); myFile = file; @@ -83,15 +86,8 @@ public class HectorComponent extends JPanel { final boolean notInLibrary = !fileIndex.isInLibrarySource(virtualFile) && !fileIndex.isInLibraryClasses(virtualFile) || fileIndex.isInContent(virtualFile); final FileViewProvider viewProvider = myFile.getViewProvider(); - //List languages = new ArrayList(viewProvider.getLanguages()); - //Collections.sort(languages, new Comparator() { - // @Override - // public int compare(Language o1, Language o2) { - // return o1.getID().compareTo(o2.getID()); - // } - //}); - Collection languages = viewProvider.getLanguages(); - + List languages = new ArrayList(viewProvider.getLanguages()); + Collections.sort(languages, PsiUtilBase.LANGUAGE_COMPARATOR); for (Language language : languages) { @SuppressWarnings("UseOfObsoleteCollectionType") final Hashtable sliderLabels = new Hashtable(); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/TrafficLightRenderer.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/TrafficLightRenderer.java index 592797f8b32e..dd89cd16c6e2 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/TrafficLightRenderer.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/TrafficLightRenderer.java @@ -20,6 +20,7 @@ import com.intellij.codeHighlighting.HighlightDisplayLevel; import com.intellij.codeHighlighting.TextEditorHighlightingPass; import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer; import com.intellij.codeInsight.daemon.impl.analysis.HighlightLevelUtil; +import com.intellij.lang.Language; import com.intellij.lang.annotation.HighlightSeverity; import com.intellij.openapi.Disposable; import com.intellij.openapi.application.ApplicationManager; @@ -36,6 +37,7 @@ import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.IconLoader; +import com.intellij.psi.FileViewProvider; import com.intellij.psi.PsiFile; import com.intellij.ui.LayeredIcon; import com.intellij.util.ArrayUtil; @@ -50,6 +52,7 @@ import java.awt.*; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Set; public class TrafficLightRenderer implements ErrorStripeRenderer, Disposable { private static final Icon IN_PROGRESS_ICON = IconLoader.getIcon("/general/errorsInProgress.png"); @@ -166,13 +169,15 @@ public class TrafficLightRenderer implements ErrorStripeRenderer, Disposable { List noInspectionRoots = new ArrayList(); List noHighlightingRoots = new ArrayList(); - final PsiFile[] roots = myFile.getPsiRoots(); - for (PsiFile file : roots) { - if (!HighlightLevelUtil.shouldHighlight(file)) { - noHighlightingRoots.add(file.getLanguage().getID()); + FileViewProvider provider = myFile.getViewProvider(); + Set languages = provider.getLanguages(); + for (Language language : languages) { + PsiFile root = provider.getPsi(language); + if (!HighlightLevelUtil.shouldHighlight(root)) { + noHighlightingRoots.add(language.getID()); } - else if (!HighlightLevelUtil.shouldInspect(file)) { - noInspectionRoots.add(file.getLanguage().getID()); + else if (!HighlightLevelUtil.shouldInspect(root)) { + noInspectionRoots.add(language.getID()); } } DaemonCodeAnalyzerStatus status = new DaemonCodeAnalyzerStatus(); @@ -180,7 +185,7 @@ public class TrafficLightRenderer implements ErrorStripeRenderer, Disposable { status.noHighlightingRoots = noHighlightingRoots.isEmpty() ? null : ArrayUtil.toStringArray(noHighlightingRoots); status.errorCount = errorCount.clone(); - status.rootsNumber = roots.length; + status.rootsNumber = languages.size(); fillDaemonCodeAnalyzerErrorsStatus(status, fillErrorsCount, severityRegistrar); List passes = myDaemonCodeAnalyzer.getPassesToShowProgressFor(myDocument); status.passStati = passes.isEmpty() ? Collections.emptyList() : diff --git a/platform/lang-impl/src/com/intellij/codeInspection/LossyEncodingInspection.java b/platform/lang-impl/src/com/intellij/codeInspection/LossyEncodingInspection.java index 0da4475a2058..38747fe3759f 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/LossyEncodingInspection.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/LossyEncodingInspection.java @@ -78,8 +78,8 @@ public class LossyEncodingInspection extends LocalInspectionTool { @Nullable public ProblemDescriptor[] checkFile(@NotNull PsiFile file, @NotNull InspectionManager manager, boolean isOnTheFly) { if (InjectedLanguageManager.getInstance(file.getProject()).isInjectedFragment(file)) return null; - if (ArrayUtil.find(file.getPsiRoots(), file) != 0) return null; if (!file.isPhysical()) return null; + if (file.getViewProvider().getBaseLanguage() != file.getLanguage()) return null; VirtualFile virtualFile = file.getVirtualFile(); if (virtualFile == null) return null; if (virtualFile.getFileSystem() != LocalFileSystem.getInstance() diff --git a/platform/lang-impl/src/com/intellij/execution/ui/layout/impl/RunnerContentUi.java b/platform/lang-impl/src/com/intellij/execution/ui/layout/impl/RunnerContentUi.java index 23ce51a8eddf..59c1dfd29bc9 100644 --- a/platform/lang-impl/src/com/intellij/execution/ui/layout/impl/RunnerContentUi.java +++ b/platform/lang-impl/src/com/intellij/execution/ui/layout/impl/RunnerContentUi.java @@ -811,9 +811,10 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac private void updateTabsUI(final boolean validateNow) { boolean hasToolbarContent = rebuildToolbar(); + Set usedNames = new HashSet(); List tabs = myTabs.getTabs(); for (TabInfo each : tabs) { - hasToolbarContent |= updateTabUI(each); + hasToolbarContent |= updateTabUI(each, usedNames); } int tabsCount = tabs.size(); for (RunnerContentUi child : myChildren) { @@ -827,7 +828,7 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac } } - private boolean updateTabUI(TabInfo tab) { + private boolean updateTabUI(TabInfo tab, Set usedNames) { TabImpl t = getTabFor(tab); if (t == null) { return false; @@ -842,7 +843,7 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac String title = contents.size() > 1 ? t.getDisplayName() : null; if (title == null) { final String name = myLayoutSettings.getDefaultDisplayName(t.getDefaultIndex()); - if (name != null && contents.size() > 1) { + if (name != null && contents.size() > 1 && !usedNames.contains(name)) { title = name; } else { title = StringUtil.join(contents, new NotNullFunction() { @@ -854,14 +855,16 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac }, " | "); } } + usedNames.add(title); - tab.setHidden(true); + boolean hidden = true; for (Content content : contents) { if (!grid.isMinimized(content)) { - tab.setHidden(false); + hidden = false; break; } } + tab.setHidden(hidden); if (icon == null && contents.size() == 1) { icon = contents.get(0).getIcon(); } diff --git a/platform/lang-impl/src/com/intellij/formatting/IndentInfo.java b/platform/lang-impl/src/com/intellij/formatting/IndentInfo.java index 16788a89382e..6d7c0e80627b 100644 --- a/platform/lang-impl/src/com/intellij/formatting/IndentInfo.java +++ b/platform/lang-impl/src/com/intellij/formatting/IndentInfo.java @@ -24,6 +24,11 @@ public class IndentInfo { private final int mySpaces; private final int myIndentSpaces; private final int myLineFeeds; + // + // The flag is used for compatibility with older versions of Intellij IDEA where spaces could be replaced with tabs inside a line of code, + // not only in the beginning of the line. + // + private static boolean myInlineTabsEnabled = "true".equalsIgnoreCase(System.getProperty("enable.inline.tabs")); /** @see WhiteSpace#setForceSkipTabulationsUsage(boolean) */ private boolean myForceSkipTabulationsUsage; @@ -58,40 +63,47 @@ public class IndentInfo { if (options.USE_TAB_CHARACTER && !myForceSkipTabulationsUsage) { if (options.SMART_TABS) { - int tabCount = myIndentSpaces / options.TAB_SIZE; - int leftSpaces = myIndentSpaces - tabCount * options.TAB_SIZE; - if (tabCount > 0) { - StringUtil.repeatSymbol(buffer, '\t', tabCount); - } - if (leftSpaces + mySpaces > 0) { - StringUtil.repeatSymbol(buffer, ' ', leftSpaces + mySpaces); - } + return fillUsingSmartTabs(buffer, options); } - else { - int size = getTotalSpaces(); - while (size > 0) { - if (size >= options.TAB_SIZE) { - buffer.append('\t'); - size -= options.TAB_SIZE; - } - else { - buffer.append(' '); - size--; - } - } + else if (myLineFeeds > 0 || myInlineTabsEnabled) { + return fillUsingTabs(buffer, options); } } - else { - int spaces = getTotalSpaces(); - if (spaces > 0) { - StringUtil.repeatSymbol(buffer, ' ', spaces); - } + int spaces = getTotalSpaces(); + if (spaces > 0) { + StringUtil.repeatSymbol(buffer, ' ', spaces); } - return buffer.toString(); } + private String fillUsingTabs(StringBuffer buffer, CommonCodeStyleSettings.IndentOptions options) { + int size = getTotalSpaces(); + while (size > 0) { + if (size >= options.TAB_SIZE) { + buffer.append('\t'); + size -= options.TAB_SIZE; + } + else { + buffer.append(' '); + size--; + } + } + return buffer.toString(); + } + + private String fillUsingSmartTabs(StringBuffer buffer, CommonCodeStyleSettings.IndentOptions options) { + int tabCount = myIndentSpaces / options.TAB_SIZE; + int leftSpaces = myIndentSpaces - tabCount * options.TAB_SIZE; + if (tabCount > 0) { + StringUtil.repeatSymbol(buffer, '\t', tabCount); + } + if (leftSpaces + mySpaces > 0) { + StringUtil.repeatSymbol(buffer, ' ', leftSpaces + mySpaces); + } + return buffer.toString(); + } + public int getTotalSpaces() { return myIndentSpaces + mySpaces; } diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/impl/AbstractProjectViewPane.java b/platform/lang-impl/src/com/intellij/ide/projectView/impl/AbstractProjectViewPane.java index daa29aefff5c..d04635ae967b 100644 --- a/platform/lang-impl/src/com/intellij/ide/projectView/impl/AbstractProjectViewPane.java +++ b/platform/lang-impl/src/com/intellij/ide/projectView/impl/AbstractProjectViewPane.java @@ -450,7 +450,7 @@ public abstract class AbstractProjectViewPane implements DataProvider, Disposabl } } - void saveExpandedPaths() { + protected void saveExpandedPaths() { if (myTree != null) { TreeState treeState = TreeState.createOn(myTree); myReadTreeState.put(getSubId(), treeState); diff --git a/platform/lang-impl/src/com/intellij/ide/scopeView/ScopeViewPane.java b/platform/lang-impl/src/com/intellij/ide/scopeView/ScopeViewPane.java index f4af769a5f14..0ac0f595d497 100644 --- a/platform/lang-impl/src/com/intellij/ide/scopeView/ScopeViewPane.java +++ b/platform/lang-impl/src/com/intellij/ide/scopeView/ScopeViewPane.java @@ -108,8 +108,7 @@ public class ScopeViewPane extends AbstractProjectViewPane { myViewPanel = new ScopeTreeViewPanel(myProject); Disposer.register(this, myViewPanel); myViewPanel.initListeners(); - updateFromRoot(true); - + myViewPanel.selectScope(NamedScopesHolder.getScope(myProject, getSubId())); myTree = myViewPanel.getTree(); PopupHandler.installPopupHandler(myTree, IdeActions.GROUP_SCOPE_VIEW_POPUP, ActionPlaces.SCOPE_VIEW_POPUP); enableDnD(); @@ -152,7 +151,9 @@ public class ScopeViewPane extends AbstractProjectViewPane { } public ActionCallback updateFromRoot(boolean restoreExpandedPaths) { + saveExpandedPaths(); myViewPanel.selectScope(NamedScopesHolder.getScope(myProject, getSubId())); + restoreExpandedPaths(); return new ActionCallback.Done(); } diff --git a/platform/lang-impl/src/com/intellij/internal/psiView/ViewerTreeStructure.java b/platform/lang-impl/src/com/intellij/internal/psiView/ViewerTreeStructure.java index b6e1235c8ab3..77fff7a7c9db 100644 --- a/platform/lang-impl/src/com/intellij/internal/psiView/ViewerTreeStructure.java +++ b/platform/lang-impl/src/com/intellij/internal/psiView/ViewerTreeStructure.java @@ -67,7 +67,11 @@ public class ViewerTreeStructure extends AbstractTreeStructure { if (myRootPsiElement == null) { return ArrayUtil.EMPTY_OBJECT_ARRAY; } - return myRootPsiElement instanceof PsiFile ? ((PsiFile)myRootPsiElement).getPsiRoots() : new Object[]{myRootPsiElement}; + if (!(myRootPsiElement instanceof PsiFile)) { + return new Object[]{myRootPsiElement}; + } + List files = ((PsiFile)myRootPsiElement).getViewProvider().getAllFiles(); + return PsiUtilCore.toPsiFileArray(files); } final Object[][] children = new Object[1][]; children[0] = ArrayUtil.EMPTY_OBJECT_ARRAY; @@ -79,10 +83,8 @@ public class ViewerTreeStructure extends AbstractTreeStructure { final ArrayList list = new ArrayList(); ASTNode root = element instanceof PsiElement? SourceTreeToPsiMap.psiElementToTree((PsiElement)element) : element instanceof ASTNode? (ASTNode)element : null; - boolean injected = false; if (element instanceof Inject) { root = SourceTreeToPsiMap.psiElementToTree(((Inject)element).getPsi()); - injected = true; } if (root != null) { diff --git a/platform/lang-impl/src/com/intellij/psi/impl/search/PsiSearchHelperImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/search/PsiSearchHelperImpl.java index d264b1b5807b..addd3ad3365d 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/search/PsiSearchHelperImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/search/PsiSearchHelperImpl.java @@ -298,8 +298,8 @@ public class PsiSearchHelperImpl implements PsiSearchHelper { public void run() { try { if (myManager.getProject().isDisposed()) throw new ProcessCanceledException(); - PsiElement[] psiRoots = file.getPsiRoots(); - Set processed = new HashSet(psiRoots.length * 2, (float)0.5); + List psiRoots = file.getViewProvider().getAllFiles(); + Set processed = new HashSet(psiRoots.size() * 2, (float)0.5); for (PsiElement psiRoot : psiRoots) { if (progress != null) progress.checkCanceled(); if (!processed.add(psiRoot)) continue; diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/MultiHostRegistrarImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/MultiHostRegistrarImpl.java index 0c5d2887a08c..600282b97fe6 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/MultiHostRegistrarImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/MultiHostRegistrarImpl.java @@ -472,22 +472,23 @@ public class MultiHostRegistrarImpl implements MultiHostRegistrar, ModificationT while (range != null && !range.isEmpty()) { if (range.getStartOffset() >= shredEndOffset) { hostNum++; - shredEndOffset = shreds.get(hostNum).range.getEndOffset(); + PsiLanguageInjectionHost.Shred shred = shreds.get(hostNum); + shredEndOffset = shred.range.getEndOffset(); prevHostEndOffset = range.getStartOffset(); - host = shreds.get(hostNum).host; + host = shred.host; escaper = escapers.get(hostNum); - rangeInsideHost = shreds.get(hostNum).getRangeInsideHost(); - prefixLength = shreds.get(hostNum).prefix.length(); - suffixLength = shreds.get(hostNum).suffix.length(); + rangeInsideHost = shred.getRangeInsideHost(); + prefixLength = shred.prefix.length(); + suffixLength = shred.suffix.length(); } //in prefix/suffix or spills over to next fragment if (range.getStartOffset() < prevHostEndOffset + prefixLength) { range = new TextRange(prevHostEndOffset + prefixLength, range.getEndOffset()); } TextRange spilled = null; - if (range.getEndOffset() >= shredEndOffset - suffixLength) { + if (range.getEndOffset() > shredEndOffset - suffixLength) { spilled = new TextRange(shredEndOffset, range.getEndOffset()); - range = new TextRange(range.getStartOffset(), shredEndOffset); + range = new TextRange(range.getStartOffset(), shredEndOffset-suffixLength); } if (!range.isEmpty()) { int start = escaper.getOffsetInHost(range.getStartOffset() - prevHostEndOffset - prefixLength, rangeInsideHost); diff --git a/platform/platform-api/src/com/intellij/openapi/editor/event/MockDocumentEvent.java b/platform/platform-api/src/com/intellij/openapi/editor/event/MockDocumentEvent.java index 61df2222ab78..9efef1db5d3c 100644 --- a/platform/platform-api/src/com/intellij/openapi/editor/event/MockDocumentEvent.java +++ b/platform/platform-api/src/com/intellij/openapi/editor/event/MockDocumentEvent.java @@ -22,7 +22,7 @@ public class MockDocumentEvent extends DocumentEvent { private final int myOffset; private final long myTimestamp; - public MockDocumentEvent(Document document, int offset) { + public MockDocumentEvent(@NotNull Document document, int offset) { super(document); myOffset = offset; myTimestamp = document.getModificationStamp(); @@ -45,10 +45,12 @@ public class MockDocumentEvent extends DocumentEvent { return 0; } + @NotNull public CharSequence getOldFragment() { return ""; } + @NotNull public CharSequence getNewFragment() { return ""; } diff --git a/platform/platform-api/src/com/intellij/openapi/ui/SimpleToolWindowPanel.java b/platform/platform-api/src/com/intellij/openapi/ui/SimpleToolWindowPanel.java index 5db53a0c3157..8198230777a4 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/SimpleToolWindowPanel.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/SimpleToolWindowPanel.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 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. @@ -24,6 +24,7 @@ import com.intellij.ui.switcher.QuickActionProvider; import com.intellij.util.ui.AwtVisitor; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; @@ -87,6 +88,7 @@ public class SimpleToolWindowPanel extends JPanel implements QuickActionProvider repaint(); } + @Nullable public Object getData(@NonNls String dataId) { return QuickActionProvider.KEY.is(dataId) && myProvideQuickActions ? this : null; } diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/AvailablePluginsManagerMain.java b/platform/platform-impl/src/com/intellij/ide/plugins/AvailablePluginsManagerMain.java index 04da5ea0bba2..39eaad692359 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/AvailablePluginsManagerMain.java +++ b/platform/platform-impl/src/com/intellij/ide/plugins/AvailablePluginsManagerMain.java @@ -21,6 +21,7 @@ import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.DefaultActionGroup; import com.intellij.openapi.actionSystem.ex.ComboBoxAction; +import com.intellij.openapi.extensions.PluginId; import com.intellij.openapi.options.ShowSettingsUtil; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.updateSettings.impl.UpdateSettings; @@ -101,7 +102,25 @@ public class AvailablePluginsManagerMain extends PluginManagerMain { if (e.getClickCount() != 2) return; if (pluginTable.columnAtPoint(e.getPoint()) < 0) return; if (pluginTable.rowAtPoint(e.getPoint()) < 0) return; - new ActionInstallPlugin(AvailablePluginsManagerMain.this, installed).install(); + IdeaPluginDescriptor[] selection = pluginTable.getSelectedObjects(); + if (selection != null) { + boolean enabled = true; + for (IdeaPluginDescriptor descr : selection) { + if (descr instanceof PluginNode) { + enabled &= !PluginManagerColumnInfo.isDownloaded((PluginNode)descr); + if (((PluginNode)descr).getStatus() == PluginNode.STATUS_INSTALLED) { + enabled &= InstalledPluginsTableModel.hasNewerVersion(descr.getPluginId()); + } + } + else if (descr instanceof IdeaPluginDescriptorImpl) { + PluginId id = descr.getPluginId(); + enabled &= InstalledPluginsTableModel.hasNewerVersion(id); + } + } + if (enabled) { + new ActionInstallPlugin(AvailablePluginsManagerMain.this, installed).install(); + } + } } }); } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java index f286def57c1f..90af164413ba 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java @@ -6090,6 +6090,11 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi Rectangle visibleArea = getScrollingModel().getVisibleArea(); startToUse = yPositionToLogicalLine(visibleArea.getLocation().y); endToUse = Math.min(endToUse, yPositionToLogicalLine(visibleArea.y + visibleArea.height)); + if (endToUse <= startToUse) { + // There is a possible case that there is the only soft-wrapped line, i.e. end == start. We still want to update the + // size container's width then. + endToUse = Math.min(myLineWidths.size(), startToUse + 1); + } } int maxWidth = 0; for (int i = startToUse; i < endToUse; i++) { diff --git a/platform/testFramework/src/com/intellij/testFramework/ParsingTestCase.java b/platform/testFramework/src/com/intellij/testFramework/ParsingTestCase.java index 85b0685884e9..81275c29dd81 100644 --- a/platform/testFramework/src/com/intellij/testFramework/ParsingTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/ParsingTestCase.java @@ -51,17 +51,14 @@ import com.intellij.util.messages.MessageBus; import com.intellij.util.messages.MessageBusFactory; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; -import org.picocontainer.ComponentAdapter; -import org.picocontainer.MutablePicoContainer; -import org.picocontainer.PicoContainer; -import org.picocontainer.PicoInitializationException; -import org.picocontainer.PicoIntrospectionException; +import org.picocontainer.*; import org.picocontainer.defaults.AbstractComponentAdapter; import java.io.File; import java.io.FileNotFoundException; import java.io.FileWriter; import java.io.IOException; +import java.util.Set; public abstract class ParsingTestCase extends PlatformLiteFixture { protected String myFilePrefix = ""; @@ -201,7 +198,7 @@ public abstract class ParsingTestCase extends PlatformLiteFixture { assertEquals("doc text mismatch", text, myFile.getViewProvider().getDocument().getText()); assertEquals("psi text mismatch", text, myFile.getText()); if (checkResult){ - checkResult(name + ".txt", myFile); + checkResult(name, myFile); } else{ toParseTreeText(myFile, skipSpaces(), includeRanges()); @@ -218,7 +215,7 @@ public abstract class ParsingTestCase extends PlatformLiteFixture { myFile = createPsiFile(name, text); ensureParsed(myFile); assertEquals(text, myFile.getText()); - checkResult(name + suffix + ".txt", myFile); + checkResult(name + suffix, myFile); } protected void doCodeTest(String code) throws IOException { @@ -226,7 +223,7 @@ public abstract class ParsingTestCase extends PlatformLiteFixture { myFile = createPsiFile("a", code); ensureParsed(myFile); assertEquals(code, myFile.getText()); - checkResult(myFilePrefix + name + ".txt", myFile); + checkResult(myFilePrefix + name, myFile); } protected PsiFile createPsiFile(String name, String text) { @@ -253,15 +250,18 @@ public abstract class ParsingTestCase extends PlatformLiteFixture { String targetDataName, boolean skipSpaces, boolean printRanges) throws IOException { - final PsiElement[] psiRoots = checkAllPsiRoots? file.getPsiRoots() : PsiElement.EMPTY_ARRAY; - if(psiRoots.length > 1){ - for (int i = 0; i < psiRoots.length; i++) { - final PsiElement psiRoot = psiRoots[i]; - doCheckResult(myFullDataPath, targetDataName + "." + i, toParseTreeText(psiRoot, skipSpaces, printRanges).trim()); - } + FileViewProvider provider = file.getViewProvider(); + Set languages = provider.getLanguages(); + + if (!checkAllPsiRoots || languages.size() == 1) { + doCheckResult(myFullDataPath, targetDataName + ".txt", toParseTreeText(file, skipSpaces, printRanges).trim()); + return; } - else{ - doCheckResult(myFullDataPath, targetDataName, toParseTreeText(file, skipSpaces, printRanges).trim()); + + for (Language language : languages) { + PsiFile root = provider.getPsi(language); + String expectedName = targetDataName + "." + language.getID() + ".txt"; + doCheckResult(myFullDataPath, expectedName, toParseTreeText(root, skipSpaces, printRanges).trim()); } } @@ -297,8 +297,7 @@ public abstract class ParsingTestCase extends PlatformLiteFixture { } private static String doLoadFile(String myFullDataPath, String name) throws IOException { - String fullName = myFullDataPath + File.separatorChar + name; - String text = FileUtil.loadFile(new File(fullName), CharsetToolkit.UTF8).trim(); + String text = FileUtil.loadFile(new File(myFullDataPath, name), CharsetToolkit.UTF8).trim(); text = StringUtil.convertLineSeparators(text); return text; } diff --git a/platform/util/src/com/intellij/util/containers/ContainerUtil.java b/platform/util/src/com/intellij/util/containers/ContainerUtil.java index 4e64bb40842c..190020b187aa 100644 --- a/platform/util/src/com/intellij/util/containers/ContainerUtil.java +++ b/platform/util/src/com/intellij/util/containers/ContainerUtil.java @@ -128,11 +128,11 @@ public class ContainerUtil { return list.subList(from, list.size()); } - public static void addAll(@NotNull Collection collection, @NotNull Iterable appendix) { + public static void addAll(@NotNull Collection collection, @NotNull Iterable appendix) { addAll(collection, appendix.iterator()); } - public static void addAll(@NotNull Collection collection, @NotNull Iterator iterator) { + public static void addAll(@NotNull Collection collection, @NotNull Iterator iterator) { while (iterator.hasNext()) { T o = iterator.next(); collection.add(o); @@ -516,7 +516,7 @@ public class ContainerUtil { return collect(FilteringIterator.create((Iterator)iterator, instanceOf)); } - public static void addAll(@NotNull Collection collection, @NotNull Enumeration enumeration) { + public static void addAll(@NotNull Collection collection, @NotNull Enumeration enumeration) { while (enumeration.hasMoreElements()) { T element = enumeration.nextElement(); collection.add(element); diff --git a/platform/util/src/com/intellij/util/io/PersistentStringEnumerator.java b/platform/util/src/com/intellij/util/io/PersistentStringEnumerator.java index 3f98c07fcd1f..4a88a2a5490b 100644 --- a/platform/util/src/com/intellij/util/io/PersistentStringEnumerator.java +++ b/platform/util/src/com/intellij/util/io/PersistentStringEnumerator.java @@ -77,7 +77,11 @@ public class PersistentStringEnumerator extends PersistentEnumeratorDelegate - + diff --git a/plugins/android-designer/src/META-INF/plugin.xml b/plugins/android-designer/src/META-INF/plugin.xml index d7a2c911ecc7..6705ae7c0b31 100644 --- a/plugins/android-designer/src/META-INF/plugin.xml +++ b/plugins/android-designer/src/META-INF/plugin.xml @@ -6,5 +6,5 @@ com.intellij.java-i18n com.intellij.properties org.jetbrains.android - com.intellij.uiDesigner + com.intellij.ui-designer-new diff --git a/plugins/android/android.iml b/plugins/android/android.iml index 1acddaf410cf..b6502266fba7 100644 --- a/plugins/android/android.iml +++ b/plugins/android/android.iml @@ -61,6 +61,7 @@ + diff --git a/plugins/android/rt/android-rt.iml b/plugins/android/rt/android-rt.iml new file mode 100644 index 000000000000..13bee7b61859 --- /dev/null +++ b/plugins/android/rt/android-rt.iml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/android/src/org/jetbrains/android/compiler/tools/AndroidApt.java b/plugins/android/rt/src/org/jetbrains/android/compiler/tools/AndroidApt.java similarity index 73% rename from plugins/android/src/org/jetbrains/android/compiler/tools/AndroidApt.java rename to plugins/android/rt/src/org/jetbrains/android/compiler/tools/AndroidApt.java index 465f38fbeeaf..7f112779b051 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/tools/AndroidApt.java +++ b/plugins/android/rt/src/org/jetbrains/android/compiler/tools/AndroidApt.java @@ -16,13 +16,12 @@ package org.jetbrains.android.compiler.tools; import com.android.sdklib.IAndroidTarget; -import com.intellij.openapi.compiler.CompilerMessageCategory; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.io.FileUtil; import com.intellij.util.ArrayUtil; import com.intellij.util.containers.HashMap; -import org.jetbrains.android.compiler.AndroidCompileUtil; -import org.jetbrains.android.util.AndroidUtils; +import org.jetbrains.android.util.AndroidCommonUtils; +import org.jetbrains.android.util.AndroidCompilerMessageKind; import org.jetbrains.android.util.ExecutionUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -47,22 +46,22 @@ public final class AndroidApt { private AndroidApt() { } - public static Map> compile(@NotNull IAndroidTarget target, - int platformToolsRevision, - @NotNull String manifestFileOsPath, - @NotNull String aPackage, - @NotNull String outDirOsPath, - @NotNull String[] resourceDirsOsPaths, - @NotNull String[] libPackages, - boolean isLibrary) throws IOException { - final Map> messages = new HashMap>(); - messages.put(CompilerMessageCategory.ERROR, new ArrayList()); - messages.put(CompilerMessageCategory.INFORMATION, new ArrayList()); + public static Map> compile(@NotNull IAndroidTarget target, + int platformToolsRevision, + @NotNull String manifestFileOsPath, + @NotNull String aPackage, + @NotNull String outDirOsPath, + @NotNull String[] resourceDirsOsPaths, + @NotNull String[] libPackages, + boolean isLibrary) throws IOException { + final Map> messages = new HashMap>(); + messages.put(AndroidCompilerMessageKind.ERROR, new ArrayList()); + messages.put(AndroidCompilerMessageKind.INFORMATION, new ArrayList()); final File outOsDir = new File(outDirOsPath); if (!outOsDir.exists()) { if (!outOsDir.mkdirs()) { - messages.get(CompilerMessageCategory.ERROR).add("Unable to create directory " + outDirOsPath); + messages.get(AndroidCompilerMessageKind.ERROR).add("Unable to create directory " + outDirOsPath); } } @@ -71,55 +70,55 @@ public final class AndroidApt { /* We actually need to delete the manifest.java as it may become empty and in this case aapt doesn't generate an empty one, but instead doesn't touch it */ - final File manifestJavaFile = new File(packageFolderOsPath + File.separatorChar + AndroidUtils.MANIFEST_JAVA_FILE_NAME); + final File manifestJavaFile = new File(packageFolderOsPath + File.separatorChar + AndroidCommonUtils.MANIFEST_JAVA_FILE_NAME); if (manifestJavaFile.exists()) { if (!FileUtil.delete(manifestJavaFile)) { - messages.get(CompilerMessageCategory.ERROR).add("Unable to delete " + manifestJavaFile.getPath()); + messages.get(AndroidCompilerMessageKind.ERROR).add("Unable to delete " + manifestJavaFile.getPath()); } } - - final File rJavaFile = new File(packageFolderOsPath + File.separatorChar + AndroidUtils.R_JAVA_FILENAME); + + final File rJavaFile = new File(packageFolderOsPath + File.separatorChar + AndroidCommonUtils.R_JAVA_FILENAME); if (rJavaFile.exists()) { if (!FileUtil.delete(rJavaFile)) { - messages.get(CompilerMessageCategory.ERROR).add("Unable to delete " + rJavaFile.getPath()); + messages.get(AndroidCompilerMessageKind.ERROR).add("Unable to delete " + rJavaFile.getPath()); } } - + final File[] libRJavaFiles = new File[libPackages.length]; - + for (int i = 0; i < libPackages.length; i++) { final String libPackageFolderOsPath = FileUtil.toSystemDependentName(outDirOsPath + '/' + libPackages[i].replace('.', '/')); - libRJavaFiles[i] = new File(libPackageFolderOsPath + File.separatorChar + AndroidUtils.R_JAVA_FILENAME); + libRJavaFiles[i] = new File(libPackageFolderOsPath + File.separatorChar + AndroidCommonUtils.R_JAVA_FILENAME); } for (File libRJavaFile : libRJavaFiles) { if (libRJavaFile.exists()) { if (!FileUtil.delete(libRJavaFile)) { - messages.get(CompilerMessageCategory.ERROR).add("Unable to delete " + libRJavaFile.getPath()); + messages.get(AndroidCompilerMessageKind.ERROR).add("Unable to delete " + libRJavaFile.getPath()); } } } if (platformToolsRevision < 0 || platformToolsRevision > 7) { - Map> map = + Map> map = doCompile(target, manifestFileOsPath, outDirOsPath, resourceDirsOsPaths, libPackages, null, isLibrary); - if (map.get(CompilerMessageCategory.ERROR).isEmpty()) { + if (map.get(AndroidCompilerMessageKind.ERROR).isEmpty()) { makeFieldsNotFinal(libRJavaFiles); } - AndroidCompileUtil.addMessages(messages, map); + ExecutionUtil.addMessages(messages, map); return messages; } else { - Map> map; + Map> map; map = doCompile(target, manifestFileOsPath, outDirOsPath, resourceDirsOsPaths, ArrayUtil.EMPTY_STRING_ARRAY, null, false); - AndroidCompileUtil.addMessages(messages, map); + ExecutionUtil.addMessages(messages, map); for (String libPackage : libPackages) { map = doCompile(target, manifestFileOsPath, outDirOsPath, resourceDirsOsPaths, ArrayUtil.EMPTY_STRING_ARRAY, libPackage, false); - AndroidCompileUtil.addMessages(messages, map); + ExecutionUtil.addMessages(messages, map); } return messages; } @@ -148,13 +147,13 @@ public final class AndroidApt { } } - private static Map> doCompile(@NotNull IAndroidTarget target, - @NotNull String manifestFileOsPath, - @NotNull String outDirOsPath, - @NotNull String[] resourceDirsOsPaths, - @NotNull String[] extraPackages, - @Nullable String customPackage, - boolean nonConstantIds) + private static Map> doCompile(@NotNull IAndroidTarget target, + @NotNull String manifestFileOsPath, + @NotNull String outDirOsPath, + @NotNull String[] resourceDirsOsPaths, + @NotNull String[] extraPackages, + @Nullable String customPackage, + boolean nonConstantIds) throws IOException { final List args = new ArrayList(); @@ -174,7 +173,7 @@ public final class AndroidApt { args.add("--extra-packages"); args.add(toPackagesString(extraPackages)); } - + if (customPackage != null) { args.add("--custom-package"); args.add(customPackage); @@ -193,8 +192,8 @@ public final class AndroidApt { args.add("-I"); args.add(target.getPath(IAndroidTarget.ANDROID_JAR)); - LOG.info(AndroidUtils.command2string(args)); - return ExecutionUtil.execute(ArrayUtil.toStringArray(args)); + LOG.info(AndroidCommonUtils.command2string(args)); + return ExecutionUtil.doExecute(ArrayUtil.toStringArray(args)); } @NotNull @@ -209,9 +208,9 @@ public final class AndroidApt { return builder.toString(); } - public static Map> crunch(@NotNull IAndroidTarget target, - @NotNull List resPaths, - @NotNull String outputPath) throws IOException { + public static Map> crunch(@NotNull IAndroidTarget target, + @NotNull List resPaths, + @NotNull String outputPath) throws IOException { final ArrayList args = new ArrayList(); //noinspection deprecation @@ -227,19 +226,19 @@ public final class AndroidApt { args.add("-C"); args.add(outputPath); - LOG.info(AndroidUtils.command2string(args)); - return ExecutionUtil.execute(ArrayUtil.toStringArray(args)); + LOG.info(AndroidCommonUtils.command2string(args)); + return ExecutionUtil.doExecute(ArrayUtil.toStringArray(args)); } - public static Map> packageResources(@NotNull IAndroidTarget target, - int platformToolsRevision, - @NotNull String manifestPath, - @NotNull String[] resPaths, - @Nullable String osAssetsPath, - @NotNull String outputPath, - @Nullable String configFilter, - boolean debugMode, - int versionCode) throws IOException { + public static Map> packageResources(@NotNull IAndroidTarget target, + int platformToolsRevision, + @NotNull String manifestPath, + @NotNull String[] resPaths, + @Nullable String osAssetsPath, + @NotNull String outputPath, + @Nullable String configFilter, + boolean debugMode, + int versionCode) throws IOException { final ArrayList args = new ArrayList(); //noinspection deprecation @@ -290,7 +289,7 @@ public final class AndroidApt { args.add("-F"); args.add(outputPath); - LOG.info(AndroidUtils.command2string(args)); - return ExecutionUtil.execute(ArrayUtil.toStringArray(args)); + LOG.info(AndroidCommonUtils.command2string(args)); + return ExecutionUtil.doExecute(ArrayUtil.toStringArray(args)); } } diff --git a/plugins/android/src/org/jetbrains/android/compiler/tools/AndroidDxRunner.java b/plugins/android/rt/src/org/jetbrains/android/compiler/tools/AndroidDxRunner.java similarity index 100% rename from plugins/android/src/org/jetbrains/android/compiler/tools/AndroidDxRunner.java rename to plugins/android/rt/src/org/jetbrains/android/compiler/tools/AndroidDxRunner.java diff --git a/plugins/android/src/org/jetbrains/android/compiler/tools/AndroidIdl.java b/plugins/android/rt/src/org/jetbrains/android/compiler/tools/AndroidIdl.java similarity index 74% rename from plugins/android/src/org/jetbrains/android/compiler/tools/AndroidIdl.java rename to plugins/android/rt/src/org/jetbrains/android/compiler/tools/AndroidIdl.java index daa4083bef6a..16e0bc1a3175 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/tools/AndroidIdl.java +++ b/plugins/android/rt/src/org/jetbrains/android/compiler/tools/AndroidIdl.java @@ -16,8 +16,8 @@ package org.jetbrains.android.compiler.tools; import com.android.sdklib.IAndroidTarget; -import com.intellij.openapi.compiler.CompilerMessageCategory; import com.intellij.util.ArrayUtil; +import org.jetbrains.android.util.AndroidCompilerMessageKind; import org.jetbrains.android.util.ExecutionUtil; import org.jetbrains.annotations.NotNull; @@ -36,20 +36,22 @@ public final class AndroidIdl { } @NotNull - public static Map> execute(@NotNull IAndroidTarget target, - @NotNull String file, - @NotNull String outFile, - @NotNull String[] sourceRootPaths) throws IOException { - List commands = new ArrayList(); - String frameworkAidlPath = target.getPath(IAndroidTarget.ANDROID_AIDL); + public static Map> execute(@NotNull IAndroidTarget target, + @NotNull String file, + @NotNull String outFile, + @NotNull String[] sourceRootPaths) throws IOException { + final List commands = new ArrayList(); + final String frameworkAidlPath = target.getPath(IAndroidTarget.ANDROID_AIDL); + commands.add(target.getPath(IAndroidTarget.AIDL)); commands.add("-p" + frameworkAidlPath); + for (String path : sourceRootPaths) { commands.add("-I" + path); } commands.add(file); commands.add(outFile); - return ExecutionUtil.execute(ArrayUtil.toStringArray(commands)); + return ExecutionUtil.doExecute(ArrayUtil.toStringArray(commands)); } } diff --git a/plugins/android/rt/src/org/jetbrains/android/util/AndroidCommonUtils.java b/plugins/android/rt/src/org/jetbrains/android/util/AndroidCommonUtils.java new file mode 100644 index 000000000000..450687945d47 --- /dev/null +++ b/plugins/android/rt/src/org/jetbrains/android/util/AndroidCommonUtils.java @@ -0,0 +1,32 @@ +package org.jetbrains.android.util; + +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; +import java.util.Iterator; + +/** + * @author Eugene.Kudelevsky + */ +public class AndroidCommonUtils { + @NonNls public static final Object MANIFEST_JAVA_FILE_NAME = "Manifest.java"; + public static final String R_JAVA_FILENAME = "R.java"; + + private AndroidCommonUtils() { + } + + public static String command2string(@NotNull Collection command) { + final StringBuilder builder = new StringBuilder(); + for (Iterator it = command.iterator(); it.hasNext(); ) { + String s = it.next(); + builder.append('['); + builder.append(s); + builder.append(']'); + if (it.hasNext()) { + builder.append(' '); + } + } + return builder.toString(); + } +} diff --git a/plugins/android/rt/src/org/jetbrains/android/util/AndroidCompilerMessageKind.java b/plugins/android/rt/src/org/jetbrains/android/util/AndroidCompilerMessageKind.java new file mode 100644 index 000000000000..6c8a8cb80c50 --- /dev/null +++ b/plugins/android/rt/src/org/jetbrains/android/util/AndroidCompilerMessageKind.java @@ -0,0 +1,8 @@ +package org.jetbrains.android.util; + +/** + * @author Eugene.Kudelevsky + */ +public enum AndroidCompilerMessageKind { + ERROR, INFORMATION, WARNING +} diff --git a/plugins/android/rt/src/org/jetbrains/android/util/AndroidOSProcessHandler.java b/plugins/android/rt/src/org/jetbrains/android/util/AndroidOSProcessHandler.java new file mode 100644 index 000000000000..1811d0e24fc7 --- /dev/null +++ b/plugins/android/rt/src/org/jetbrains/android/util/AndroidOSProcessHandler.java @@ -0,0 +1,61 @@ +package org.jetbrains.android.util; + +import com.intellij.execution.process.BaseOSProcessHandler; +import com.intellij.execution.process.ProcessOutputTypes; +import com.intellij.openapi.util.Key; +import com.intellij.openapi.util.text.StringUtil; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Eugene.Kudelevsky + */ +public class AndroidOSProcessHandler extends BaseOSProcessHandler { + @NonNls private static final String IGNORING = "ignoring"; + @NonNls private static final String SKIPPING = "skipping"; + + private final List myInfoMessages = new ArrayList(); + private final List myErrorMessages = new ArrayList(); + + public AndroidOSProcessHandler(@NotNull final Process process, @Nullable final String commandLine) { + super(process, commandLine, null); + } + + @Override + public void notifyTextAvailable(String text, Key outputType) { + super.notifyTextAvailable(text, outputType); + + if (StringUtil.isEmptyOrSpaces(text)) { + return; + } + String[] lines = text.split("[\\n\\r]+"); + for (String line : lines) { + String l = line.toLowerCase(); + if (outputType == ProcessOutputTypes.STDOUT) { + myInfoMessages.add(line); + } + else if (outputType == ProcessOutputTypes.STDERR) { + if (l.contains(IGNORING) || l.contains(SKIPPING)) { + myInfoMessages.add(line); + } + else { + myErrorMessages.add(line); + } + } + } + } + + @NotNull + public List getInfoMessages() { + return myInfoMessages; + } + + @NotNull + public List getErrorMessages() { + return myErrorMessages; + } +} diff --git a/plugins/android/rt/src/org/jetbrains/android/util/ExecutionUtil.java b/plugins/android/rt/src/org/jetbrains/android/util/ExecutionUtil.java new file mode 100644 index 000000000000..a65663d4fc76 --- /dev/null +++ b/plugins/android/rt/src/org/jetbrains/android/util/ExecutionUtil.java @@ -0,0 +1,106 @@ +/* + * Copyright 2000-2010 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.android.util; + +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Abstract external tool for compiler. + * + * @author Alexey Efimov + */ +public final class ExecutionUtil { + + private ExecutionUtil() { + } + + @NotNull + public static Map> doExecute(String... argv) throws IOException { + ProcessBuilder builder = new ProcessBuilder(argv); + ProcessResult result = readProcessOutput(builder.start()); + Map> messages = result.getMessages(); + int code = result.getExitCode(); + List errMessages = messages.get(AndroidCompilerMessageKind.ERROR); + + if (code != 0 && errMessages.isEmpty()) { + throw new IOException("Command \"" + concat(argv) + "\" execution failed with exit code " + code); + } + else { + if (code == 0) { + messages.get(AndroidCompilerMessageKind.INFORMATION).addAll(errMessages); + errMessages.clear(); + } + return messages; + } + } + + private static String concat(String... strs) { + StringBuilder builder = new StringBuilder(); + for (int i = 0, n = strs.length; i < n; i++) { + builder.append(strs[i]); + if (i < n - 1) { + builder.append(' '); + } + } + return builder.toString(); + } + + @NotNull + private static ProcessResult readProcessOutput(Process process) throws IOException { + final AndroidOSProcessHandler handler = new AndroidOSProcessHandler(process, ""); + handler.startNotify(); + handler.waitFor(); + int exitCode = handler.getProcess().exitValue(); + return new ProcessResult(handler.getInfoMessages(), handler.getErrorMessages(), exitCode); + } + + private static final class ProcessResult { + private final int myExitCode; + private final Map> myMessages; + + public ProcessResult(List information, List error, int exitCode) { + myExitCode = exitCode; + myMessages = new HashMap>(2); + myMessages.put(AndroidCompilerMessageKind.INFORMATION, information); + myMessages.put(AndroidCompilerMessageKind.ERROR, error); + } + + public Map> getMessages() { + return myMessages; + } + + public int getExitCode() { + return myExitCode; + } + } + + public static void addMessages(@NotNull Map> messages, @NotNull Map> toAdd) { + for (Map.Entry> entry : toAdd.entrySet()) { + List list = messages.get(entry.getKey()); + if (list == null) { + list = new ArrayList(); + messages.put(entry.getKey(), list); + } + list.addAll(entry.getValue()); + } + } +} diff --git a/plugins/android/src/org/jetbrains/android/AndroidProjectComponent.java b/plugins/android/src/org/jetbrains/android/AndroidProjectComponent.java index 65bff27a39de..e047daf6bb8b 100644 --- a/plugins/android/src/org/jetbrains/android/AndroidProjectComponent.java +++ b/plugins/android/src/org/jetbrains/android/AndroidProjectComponent.java @@ -19,15 +19,11 @@ import com.intellij.openapi.compiler.CompilerManager; import com.intellij.openapi.components.AbstractProjectComponent; import com.intellij.openapi.project.Project; import org.jetbrains.android.compiler.AndroidPrecompileTask; -import org.jetbrains.annotations.NotNull; /** * @author Eugene.Kudelevsky */ public class AndroidProjectComponent extends AbstractProjectComponent { - private volatile boolean myCompilationRunning = false; - private final Object COMPILATION_FLAG_LOCK = new Object(); - protected AndroidProjectComponent(Project project) { super(project); } @@ -35,26 +31,6 @@ public class AndroidProjectComponent extends AbstractProjectComponent { @Override public void projectOpened() { final CompilerManager manager = CompilerManager.getInstance(myProject); - manager.addBeforeTask(new AndroidPrecompileTask(this)); - } - - public void setCompilationStarted() { - synchronized (COMPILATION_FLAG_LOCK) { - myCompilationRunning = true; - } - } - - public void setCompilationFinished() { - synchronized (COMPILATION_FLAG_LOCK) { - myCompilationRunning = false; - } - } - - public void runIfNotInCompilation(@NotNull Runnable r) { - synchronized (COMPILATION_FLAG_LOCK) { - if (!myCompilationRunning) { - r.run(); - } - } + manager.addBeforeTask(new AndroidPrecompileTask()); } } diff --git a/plugins/android/src/org/jetbrains/android/actions/AndroidRegenerateRJavaFileAction.java b/plugins/android/src/org/jetbrains/android/actions/AndroidRegenerateRJavaFileAction.java index 43597a15b8b3..bce1ab0ace7e 100644 --- a/plugins/android/src/org/jetbrains/android/actions/AndroidRegenerateRJavaFileAction.java +++ b/plugins/android/src/org/jetbrains/android/actions/AndroidRegenerateRJavaFileAction.java @@ -26,6 +26,7 @@ import com.intellij.openapi.compiler.CompilerManager; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; import org.jetbrains.android.compiler.AndroidAptCompiler; +import org.jetbrains.android.compiler.AndroidAutogeneratorMode; import org.jetbrains.android.compiler.AndroidCompileUtil; import org.jetbrains.android.facet.AndroidFacet; import org.jetbrains.android.util.AndroidBundle; @@ -96,7 +97,10 @@ public class AndroidRegenerateRJavaFileAction extends AnAction { @Override public boolean execute(CompileContext context) { // todo: compatibility with background autogenerating - AndroidCompileUtil.generate(new AndroidAptCompiler(), context); + + for (Module module : modules) { + AndroidCompileUtil.generate(module, AndroidAutogeneratorMode.AAPT, context); + } return true; } }, new ModuleCompileScope(project, modules, false), AndroidBundle.message("android.compile.messages.generating.r.java.content.name"), diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidAptCompiler.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidAptCompiler.java index 154a71673ab2..a2f70b19129c 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/AndroidAptCompiler.java +++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidAptCompiler.java @@ -17,19 +17,16 @@ package org.jetbrains.android.compiler; import com.android.sdklib.IAndroidTarget; import com.android.sdklib.SdkConstants; -import com.intellij.compiler.impl.CompilerUtil; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.compiler.*; -import com.intellij.openapi.compiler.ex.CompileContextEx; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.io.FileUtil; -import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.util.containers.HashMap; +import com.intellij.util.ArrayUtil; import com.intellij.util.containers.HashSet; import org.jetbrains.android.compiler.tools.AndroidApt; import org.jetbrains.android.dom.manifest.Manifest; @@ -39,13 +36,13 @@ import org.jetbrains.android.facet.AndroidRootUtil; import org.jetbrains.android.maven.AndroidMavenUtil; import org.jetbrains.android.sdk.AndroidPlatform; import org.jetbrains.android.util.AndroidBundle; +import org.jetbrains.android.util.AndroidCommonUtils; import org.jetbrains.android.util.AndroidUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.DataInput; import java.io.DataOutput; -import java.io.File; import java.io.IOException; import java.util.*; @@ -58,6 +55,7 @@ public class AndroidAptCompiler implements SourceGeneratingCompiler { private static final Logger LOG = Logger.getInstance("#org.jetbrains.android.compiler.AndroidAptCompiler"); private static final GenerationItem[] EMPTY_GENERATION_ITEM_ARRAY = {}; + @Nullable @Override public VirtualFile getPresentableFile(CompileContext context, Module module, VirtualFile outputRoot, VirtualFile generatedFile) { return null; @@ -77,37 +75,15 @@ public class AndroidAptCompiler implements SourceGeneratingCompiler { public GenerationItem[] generate(final CompileContext context, final GenerationItem[] items, VirtualFile outputRootDirectory) { if (items != null && items.length > 0) { context.getProgressIndicator().setText(AndroidBundle.message("android.compile.messages.generating.r.java")); - Computable computation = new Computable() { - public GenerationItem[] compute() { - if (context.getProject().isDisposed()) { - return EMPTY_GENERATION_ITEM_ARRAY; - } - return doGenerate(context, items); - } - }; - GenerationItem[] generationItems = computation.compute(); - List generatedVFiles = new ArrayList(); - for (GenerationItem item : generationItems) { - final Set generatedFiles = ((AptGenerationItem)item).myGeneratedFile2Package.keySet(); - for (File generatedFile : generatedFiles) { - CompilerUtil.refreshIOFile(generatedFile); - CompilerUtil.refreshIOFile(generatedFile.getParentFile()); - VirtualFile generatedVFile = LocalFileSystem.getInstance().findFileByIoFile(generatedFile); - if (generatedVFile != null) { - generatedVFiles.add(generatedVFile); - } - } + if (!context.getProject().isDisposed()) { + return doGenerate(context, items, outputRootDirectory); } - if (context instanceof CompileContextEx) { - ((CompileContextEx)context).markGenerated(generatedVFiles); - } - return generationItems; } return EMPTY_GENERATION_ITEM_ARRAY; } - private static GenerationItem[] doGenerate(final CompileContext context, GenerationItem[] items) { + private static GenerationItem[] doGenerate(final CompileContext context, GenerationItem[] items, VirtualFile outputRootDirectory) { List results = new ArrayList(items.length); for (GenerationItem item : items) { if (item instanceof AptGenerationItem) { @@ -117,33 +93,19 @@ public class AndroidAptCompiler implements SourceGeneratingCompiler { continue; } + final String outputDirOsPath = FileUtil.toSystemDependentName(outputRootDirectory.getPath()); + try { - Map> messages = AndroidApt.compile(aptItem.myAndroidTarget, aptItem.myPlatformToolsRevision, - aptItem.myManifestFile.getPath(), aptItem.myPackage, - aptItem.mySourceRootPath, aptItem.myResourcesPaths, - aptItem.myLibraryPackages, aptItem.myIsLibrary); + Map> messages = AndroidCompileUtil.toCompilerMessageCategoryKeys( + AndroidApt.compile(aptItem.myAndroidTarget, aptItem.myPlatformToolsRevision, + aptItem.myManifestFile.getPath(), aptItem.myPackage, + outputDirOsPath, aptItem.myResourcesPaths, + aptItem.myLibraryPackages, aptItem.myIsLibrary)); AndroidCompileUtil.addMessages(context, messages); if (messages.get(CompilerMessageCategory.ERROR).isEmpty()) { results.add(aptItem); } - for (Map.Entry entry : aptItem.myGeneratedFile2Package.entrySet()) { - final File generatedFile = entry.getKey(); - final String aPackage = entry.getValue(); - - if (generatedFile.exists()) { - ApplicationManager.getApplication().runReadAction(new Runnable() { - public void run() { - if (context.getProject().isDisposed() || aptItem.myModule.isDisposed()) { - return; - } - String className = FileUtil.getNameWithoutExtension(generatedFile); - AndroidCompileUtil.removeDuplicatingClasses(aptItem.myModule, aPackage, className, - generatedFile, aptItem.mySourceRootPath); - } - }); - } - } } catch (final IOException e) { LOG.info(e); @@ -183,22 +145,17 @@ public class AndroidAptCompiler implements SourceGeneratingCompiler { final Module myModule; final VirtualFile myManifestFile; final String[] myResourcesPaths; - final String mySourceRootPath; final IAndroidTarget myAndroidTarget; - final Map myGeneratedFile2Package; - final String myPackage; final String[] myLibraryPackages; final boolean myIsLibrary; - private final Set myNonExistingFiles; final int myPlatformToolsRevision; private AptGenerationItem(@NotNull Module module, @NotNull VirtualFile manifestFile, @NotNull String[] resourcesPaths, - @NotNull String sourceRootPath, @NotNull IAndroidTarget target, int platformToolsRevision, @NotNull String aPackage, @@ -207,55 +164,19 @@ public class AndroidAptCompiler implements SourceGeneratingCompiler { myModule = module; myManifestFile = manifestFile; myResourcesPaths = resourcesPaths; - mySourceRootPath = sourceRootPath; myAndroidTarget = target; myPackage = aPackage; myLibraryPackages = libPackages; myIsLibrary = isLibrary; myPlatformToolsRevision = platformToolsRevision; - - myGeneratedFile2Package = new HashMap(); - - myGeneratedFile2Package.put( - new File(sourceRootPath, aPackage.replace('.', File.separatorChar) + File.separator + AndroidUtils.R_JAVA_FILENAME), aPackage); - - for (String libPackage : myLibraryPackages) { - myGeneratedFile2Package - .put(new File(sourceRootPath, libPackage.replace('.', File.separatorChar) + File.separator + AndroidUtils.R_JAVA_FILENAME), - libPackage); - } - - myNonExistingFiles = new HashSet(); - - // We need to check only R.java files, not Manifest.java files, so add Manifest files LATER - for (File generatedFile : myGeneratedFile2Package.keySet()) { - if (!generatedFile.exists()) { - myNonExistingFiles.add(FileUtil.toSystemIndependentName(generatedFile.getPath())); - } - } - - myGeneratedFile2Package.put( - new File(sourceRootPath, aPackage.replace('.', File.separatorChar) + File.separator + AndroidUtils.MANIFEST_JAVA_FILE_NAME), - aPackage); - - for (String libraryPackage : myLibraryPackages) { - myGeneratedFile2Package.put( - new File(sourceRootPath, libraryPackage.replace('.', File.separatorChar) + File.separator + AndroidUtils.MANIFEST_JAVA_FILE_NAME), - libraryPackage); - } - } - - @NotNull - public Map getGeneratedFiles() { - return myGeneratedFile2Package; } public String getPath() { - return myPackage.replace('.', '/') + '/' + AndroidUtils.R_JAVA_FILENAME; + return myPackage.replace('.', '/') + '/' + AndroidCommonUtils.R_JAVA_FILENAME; } public ValidityState getValidityState() { - return new MyValidityState(myModule, myNonExistingFiles, myPlatformToolsRevision); + return new MyValidityState(myModule, Collections.emptySet(), myPlatformToolsRevision); } public Module getModule() { @@ -265,11 +186,6 @@ public class AndroidAptCompiler implements SourceGeneratingCompiler { public boolean isTestSource() { return false; } - - @NotNull - public String getPackageFolderPath() { - return FileUtil.toSystemDependentName(mySourceRootPath + '/' + myPackage.replace('.', '/')); - } } @Nullable @@ -338,13 +254,14 @@ public class AndroidAptCompiler implements SourceGeneratingCompiler { String sourceRootPath = facet.getAptGenSourceRootPath(); if (sourceRootPath == null) { myContext.addMessage(CompilerMessageCategory.ERROR, - AndroidBundle.message("android.compilation.error.apt.gen.not.specified", module.getName()), null, -1, -1); + AndroidBundle.message("android.compilation.error.apt.gen.not.specified", module.getName()), + null, -1, -1); continue; } final String[] libPackages = getLibPackages(module, packageName); - items.add(new AptGenerationItem(module, manifestFile, resPaths, sourceRootPath, target, platformToolsRevision, + items.add(new AptGenerationItem(module, manifestFile, resPaths, target, platformToolsRevision, packageName, libPackages, facet.getConfiguration().LIBRARY_PROJECT)); } } @@ -364,7 +281,7 @@ public class AndroidAptCompiler implements SourceGeneratingCompiler { } } - return result.toArray(new String[result.size()]); + return ArrayUtil.toStringArray(result); } } diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidAutogenerator.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidAutogenerator.java new file mode 100644 index 000000000000..5121f6a31a6f --- /dev/null +++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidAutogenerator.java @@ -0,0 +1,628 @@ +package org.jetbrains.android.compiler; + +import com.android.AndroidConstants; +import com.android.sdklib.IAndroidTarget; +import com.intellij.compiler.impl.CompilerUtil; +import com.intellij.compiler.impl.ModuleCompileScope; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ModalityState; +import com.intellij.openapi.compiler.CompileContext; +import com.intellij.openapi.compiler.CompilerMessageCategory; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Computable; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.vfs.*; +import com.intellij.psi.search.FilenameIndex; +import com.intellij.util.ArrayUtil; +import com.intellij.util.containers.HashMap; +import com.intellij.util.containers.HashSet; +import org.jetbrains.android.compiler.tools.AndroidApt; +import org.jetbrains.android.compiler.tools.AndroidIdl; +import org.jetbrains.android.dom.manifest.Manifest; +import org.jetbrains.android.facet.AndroidFacet; +import org.jetbrains.android.facet.AndroidRootUtil; +import org.jetbrains.android.fileTypes.AndroidIdlFileType; +import org.jetbrains.android.fileTypes.AndroidRenderscriptFileType; +import org.jetbrains.android.sdk.AndroidPlatform; +import org.jetbrains.android.util.AndroidBundle; +import org.jetbrains.android.util.AndroidCommonUtils; +import org.jetbrains.android.util.AndroidCompilerMessageKind; +import org.jetbrains.android.util.AndroidUtils; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.File; +import java.io.IOException; +import java.util.*; + +/** + * @author Eugene.Kudelevsky + */ +public class AndroidAutogenerator { + private static final Logger LOG = Logger.getInstance("#org.jetbrains.android.compiler.AndroidAutogenerator"); + + private AndroidAutogenerator() { + } + + public static void run(@NotNull AndroidAutogeneratorMode mode, @NotNull AndroidFacet facet, @NotNull CompileContext context) { + final Set obsoleteFiles = new HashSet(facet.getAutogeneratedFiles(mode)); + + switch (mode) { + case AAPT: + runAapt(facet, context); + break; + case AIDL: + runAidl(facet, context); + break; + case RENDERSCRIPT: + runRenderscript(facet, context); + break; + default: + LOG.error("Unknown mode" + mode); + } + obsoleteFiles.removeAll(facet.getAutogeneratedFiles(mode)); + + for (String path : obsoleteFiles) { + final File file = new File(path); + + if (file.isFile()) { + FileUtil.delete(file); + CompilerUtil.refreshIOFile(file); + } + } + } + + private static void runAapt(@NotNull final AndroidFacet facet, @NotNull final CompileContext context) { + final Module module = facet.getModule(); + + final AptAutogenerationItem item = ApplicationManager.getApplication().runReadAction(new Computable() { + @Nullable + @Override + public AptAutogenerationItem compute() { + if (module.isDisposed() || module.getProject().isDisposed()) { + return null; + } + + final AndroidPlatform platform = facet.getConfiguration().getAndroidPlatform(); + if (platform == null) { + context.addMessage(CompilerMessageCategory.ERROR, + AndroidBundle.message("android.compilation.error.specify.platform", module.getName()), null, -1, -1); + return null; + } + + final IAndroidTarget target = platform.getTarget(); + final int platformToolsRevision = platform.getSdk().getPlatformToolsRevision(); + final String[] resPaths = AndroidCompileUtil.collectResourceDirs(facet, false, context); + + if (resPaths.length == 0) { + return null; + } + + final VirtualFile manifestFile = AndroidRootUtil.getManifestFileForCompiler(facet); + if (manifestFile == null) { + context.addMessage(CompilerMessageCategory.ERROR, AndroidBundle.message("android.compilation.error.manifest.not.found"), + null, -1, -1); + return null; + } + + final Manifest manifest = AndroidUtils.loadDomElement(module, manifestFile, Manifest.class); + if (manifest == null) { + context.addMessage(CompilerMessageCategory.ERROR, "Cannot parse file", manifestFile.getUrl(), -1, -1); + return null; + } + + String packageName = manifest.getPackage().getValue(); + if (packageName != null) { + packageName = packageName.trim(); + } + + if (packageName == null || packageName.length() <= 0) { + context.addMessage(CompilerMessageCategory.ERROR, AndroidBundle.message("package.not.found.error"), manifestFile.getUrl(), + -1, -1); + return null; + } + + final String sourceRootPath = facet.getAptGenSourceRootPath(); + if (sourceRootPath == null) { + context.addMessage(CompilerMessageCategory.ERROR, + AndroidBundle.message("android.compilation.error.apt.gen.not.specified", module.getName()), + null, -1, -1); + return null; + } + + final Map genFilePath2Package = new HashMap(); + + final String packageDir = packageName.replace('.', '/') + '/'; + genFilePath2Package.put(packageDir + AndroidCommonUtils.MANIFEST_JAVA_FILE_NAME, packageName); + genFilePath2Package.put(packageDir + AndroidCommonUtils.R_JAVA_FILENAME, packageName); + + final String manifestFileOsPath = FileUtil.toSystemDependentName(manifestFile.getPath()); + + return new AptAutogenerationItem(target, platformToolsRevision, manifestFileOsPath, packageName, sourceRootPath, resPaths, + facet.getConfiguration().LIBRARY_PROJECT, genFilePath2Package); + } + }); + + if (item == null) { + return; + } + + final Set filesToCheck = new HashSet(); + + for (String genFileRelPath : item.myGenFileRelPath2package.keySet()) { + final String genFileFullPath = item.myOutputDirOsPath + '/' + genFileRelPath; + + if (new File(genFileFullPath).exists()) { + final VirtualFile genFile = LocalFileSystem.getInstance().findFileByPath(genFileFullPath); + + if (genFile != null) { + filesToCheck.add(genFile); + } + } + } + + if (!ensureFilesWritable(module.getProject(), filesToCheck)) { + return; + } + + File tempOutDir = null; + + try { + // Aapt generation can be very long, so we generate it in temp directory first + tempOutDir = FileUtil.createTempDirectory("android_apt_autogeneration", "tmp"); + + final Map> messages = + AndroidApt.compile(item.myTarget, item.myPlatformToolsRevision, item.myManifestFileOsPath, item.myPackage, + tempOutDir.getPath(), item.myResDirOsPaths, ArrayUtil.EMPTY_STRING_ARRAY, item.myLibrary); + + if (messages.get(AndroidCompilerMessageKind.ERROR).size() == 0) { + for (String genFileRelPath : item.myGenFileRelPath2package.keySet()) { + final File srcFile = new File(tempOutDir.getPath() + '/' + genFileRelPath); + + if (srcFile.isFile()) { + final File dstFile = new File(item.myOutputDirOsPath + '/' + genFileRelPath); + + if (dstFile.exists()) { + if (!FileUtil.delete(dstFile)) { + ApplicationManager.getApplication().runReadAction(new Runnable() { + @Override + public void run() { + if (module.isDisposed() || module.getProject().isDisposed()) { + return; + } + context.addMessage(CompilerMessageCategory.ERROR, + "Cannot delete " + FileUtil.toSystemDependentName(dstFile.getPath()), null, -1, -1); + } + }); + } + } + FileUtil.rename(srcFile, dstFile); + } + } + } + AndroidCompileUtil.addMessages(context, AndroidCompileUtil.toCompilerMessageCategoryKeys(messages)); + + for (Map.Entry entry : item.myGenFileRelPath2package.entrySet()) { + final String path = item.myOutputDirOsPath + '/' + entry.getKey(); + final String aPackage = entry.getValue(); + final File file = new File(path); + CompilerUtil.refreshIOFile(file); + + removeAllFilesWithSameName(module, file, item.myOutputDirOsPath); + removeDuplicateClasses(module, aPackage, file, item.myOutputDirOsPath); + } + + final VirtualFile genSourceRoot = LocalFileSystem.getInstance().findFileByPath(item.myOutputDirOsPath); + if (genSourceRoot != null) { + genSourceRoot.refresh(false, true); + } + + if (messages.get(AndroidCompilerMessageKind.ERROR).size() == 0) { + facet.clearAutogeneratedFiles(AndroidAutogeneratorMode.AAPT); + + for (String relPath : item.myGenFileRelPath2package.keySet()) { + final VirtualFile genFile = LocalFileSystem.getInstance().findFileByPath(item.myOutputDirOsPath + '/' + relPath); + + if (genFile != null && genFile.exists()) { + facet.markFileAutogenerated(AndroidAutogeneratorMode.AAPT, genFile); + } + } + } + } + catch (final IOException e) { + LOG.info(e); + ApplicationManager.getApplication().runReadAction(new Runnable() { + public void run() { + if (module.getProject().isDisposed()) return; + context.addMessage(CompilerMessageCategory.ERROR, "I/O error: " + e.getMessage(), null, -1, -1); + } + }); + } + finally { + if (tempOutDir != null) { + FileUtil.delete(tempOutDir); + } + } + } + + private static void removeAllFilesWithSameName(@NotNull final Module module, @NotNull File file, @NotNull String directoryPath) { + final VirtualFile vFile = LocalFileSystem.getInstance().findFileByIoFile(file); + final VirtualFile genDir = LocalFileSystem.getInstance().findFileByPath(directoryPath); + + if (vFile == null || genDir == null) { + return; + } + final Collection files = + FilenameIndex.getVirtualFilesByName(module.getProject(), file.getName(), module.getModuleScope(false)); + + final List filesToDelete = new ArrayList(); + + for (final VirtualFile f : files) { + if (f != vFile && VfsUtilCore.isAncestor(genDir, f, true)) { + filesToDelete.add(f); + } + } + + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + for (VirtualFile f : filesToDelete) { + if (f.isValid() && f.exists()) { + try { + f.delete(module.getProject()); + } + catch (IOException e) { + LOG.error(e); + } + } + } + } + }); + } + }); + } + + private static void runAidl(@NotNull final AndroidFacet facet, @NotNull final CompileContext context) { + final Module module = facet.getModule(); + final ModuleCompileScope moduleCompileScope = new ModuleCompileScope(module, false); + final VirtualFile[] files = moduleCompileScope.getFiles(AndroidIdlFileType.ourFileType, true); + final List items = new ArrayList(); + + for (final VirtualFile file : files) { + final IdlAutogenerationItem item = ApplicationManager.getApplication().runReadAction(new Computable() { + @Nullable + @Override + public IdlAutogenerationItem compute() { + if (module.isDisposed() || module.getProject().isDisposed()) { + return null; + } + + final IAndroidTarget target = facet.getConfiguration().getAndroidTarget(); + if (target == null) { + context.addMessage(CompilerMessageCategory.ERROR, + AndroidBundle.message("android.compilation.error.specify.platform", module.getName()), null, -1, -1); + return null; + } + + final String packageName = AndroidUtils.getPackageName(module, file); + if (packageName == null) { + context.addMessage(CompilerMessageCategory.ERROR, "Cannot compute package for file", file.getUrl(), -1, -1); + return null; + } + + final String sourceRootPath = facet.getAidlGenSourceRootPath(); + if (sourceRootPath == null) { + context.addMessage(CompilerMessageCategory.ERROR, + AndroidBundle.message("android.compilation.error.apt.gen.not.specified", module.getName()), null, -1, -1); + return null; + } + + final VirtualFile[] sourceRoots = AndroidPackagingCompiler.getSourceRootsForModuleAndDependencies(module, false); + final String[] sourceRootOsPaths = AndroidCompileUtil.toOsPaths(sourceRoots); + + final String outFileOsPath = FileUtil.toSystemDependentName( + sourceRootPath + '/' + packageName.replace('.', '/') + '/' + file.getNameWithoutExtension() + ".java"); + + return new IdlAutogenerationItem(file, target, outFileOsPath, sourceRootOsPaths, sourceRootPath, packageName); + } + }); + + if (item != null) { + items.add(item); + } + } + + final Set filesToCheck = new HashSet(); + + for (IdlAutogenerationItem item : items) { + if (new File(FileUtil.toSystemDependentName(item.myFile.getPath())).exists()) { + filesToCheck.add(item.myFile); + } + } + + if (!ensureFilesWritable(module.getProject(), filesToCheck)) { + return; + } + + facet.clearAutogeneratedFiles(AndroidAutogeneratorMode.AIDL); + + for (IdlAutogenerationItem item : items) { + final VirtualFile file = item.myFile; + final String fileOsPath = FileUtil.toSystemDependentName(file.getPath()); + + try { + final Map> messages = AndroidCompileUtil.toCompilerMessageCategoryKeys( + AndroidIdl.execute(item.myTarget, fileOsPath, item.myOutFileOsPath, item.mySourceRootOsPaths)); + + ApplicationManager.getApplication().runReadAction(new Runnable() { + public void run() { + if (module.getProject().isDisposed()) return; + + for (CompilerMessageCategory category : messages.keySet()) { + List messageList = messages.get(category); + for (String message : messageList) { + context.addMessage(category, message, file.getUrl(), -1, -1); + } + } + } + }); + + removeDuplicateClasses(module, item.myPackage, new File(item.myOutFileOsPath), item.myOutDirOsPath); + + final VirtualFile genDir = LocalFileSystem.getInstance().findFileByPath(item.myOutDirOsPath); + if (genDir != null) { + genDir.refresh(false, true); + } + + final VirtualFile outFile = LocalFileSystem.getInstance().findFileByPath(item.myOutFileOsPath); + if (outFile != null && outFile.exists()) { + facet.markFileAutogenerated(AndroidAutogeneratorMode.AIDL, outFile); + } + } + catch (final IOException e) { + LOG.info(e); + ApplicationManager.getApplication().runReadAction(new Runnable() { + public void run() { + if (module.getProject().isDisposed()) return; + context.addMessage(CompilerMessageCategory.ERROR, e.getMessage(), file.getUrl(), -1, -1); + } + }); + } + } + } + + private static void runRenderscript(@NotNull final AndroidFacet facet, @NotNull final CompileContext context) { + final Module module = facet.getModule(); + + final ModuleCompileScope moduleCompileScope = new ModuleCompileScope(module, false); + final VirtualFile[] files = moduleCompileScope.getFiles(AndroidRenderscriptFileType.INSTANCE, true); + + facet.clearAutogeneratedFiles(AndroidAutogeneratorMode.RENDERSCRIPT); + + for (final VirtualFile file : files) { + final RenderscriptAutogenerationItem item = + ApplicationManager.getApplication().runReadAction(new Computable() { + @Nullable + @Override + public RenderscriptAutogenerationItem compute() { + final AndroidPlatform platform = facet.getConfiguration().getAndroidPlatform(); + if (platform == null) { + context.addMessage(CompilerMessageCategory.ERROR, + AndroidBundle.message("android.compilation.error.specify.platform", module.getName()), null, -1, -1); + return null; + } + + final IAndroidTarget target = platform.getTarget(); + final String sdkLocation = platform.getSdk().getLocation(); + + final String packageName = AndroidUtils.getPackageName(module, file); + if (packageName == null) { + context.addMessage(CompilerMessageCategory.ERROR, "Cannot compute package for file", file.getUrl(), -1, -1); + return null; + } + + final String resourceDirPath = AndroidRootUtil.getResourceDirPath(facet); + assert resourceDirPath != null; + + final String sourceRootPath = AndroidRootUtil.getRenderscriptGenSourceRootPath(module); + if (sourceRootPath == null) { + return null; + } + + final String rawDirPath = resourceDirPath + '/' + AndroidConstants.FD_RES_RAW; + + return new RenderscriptAutogenerationItem(sdkLocation, target, sourceRootPath, rawDirPath); + } + }); + + if (item == null) { + continue; + } + + File tempOutDir = null; + + try { + tempOutDir = FileUtil.createTempDirectory("android_renderscript_autogeneration", "tmp"); + + final Map> messages = AndroidRenderscriptCompiler. + launchRenderscriptCompiler(module.getProject(), item.mySdkLocation, item.myTarget, file, tempOutDir.getPath(), item.myRawDirPath); + + if (messages.get(CompilerMessageCategory.ERROR).size() == 0) { + final List newFiles = new ArrayList(); + moveAllFiles(tempOutDir, new File(item.myGenDirPath), newFiles); + + for (File newFile : newFiles) { + final VirtualFile newVFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(newFile); + + if (newVFile != null) { + facet.markFileAutogenerated(AndroidAutogeneratorMode.RENDERSCRIPT, newVFile); + } + } + } + + ApplicationManager.getApplication().runReadAction(new Runnable() { + public void run() { + if (module.getProject().isDisposed()) { + return; + } + + for (final CompilerMessageCategory category : messages.keySet()) { + final List messageList = messages.get(category); + for (final String message : messageList) { + context.addMessage(category, message, file.getUrl(), -1, -1); + } + } + } + }); + + final VirtualFile genDir = LocalFileSystem.getInstance().findFileByPath(item.myGenDirPath); + if (genDir != null) { + genDir.refresh(false, true); + } + } + catch (final IOException e) { + LOG.info(e); + ApplicationManager.getApplication().runReadAction(new Runnable() { + public void run() { + if (module.getProject().isDisposed()) return; + context.addMessage(CompilerMessageCategory.ERROR, e.getMessage(), file.getUrl(), -1, -1); + } + }); + } + finally { + if (tempOutDir != null) { + FileUtil.delete(tempOutDir); + } + } + } + } + + private static void moveAllFiles(@NotNull File from, @NotNull File to, @NotNull Collection newFiles) throws IOException { + if (from.isFile()) { + FileUtil.rename(from, to); + newFiles.add(to); + } + else { + final File[] children = from.listFiles(); + + if (children != null) { + for (File child : children) { + moveAllFiles(child, new File(to, child.getName()), newFiles); + } + } + } + } + + private static boolean ensureFilesWritable(@NotNull final Project project, @NotNull final Collection filesToCheck) { + if (filesToCheck.size() == 0) { + return true; + } + final boolean[] run = {false}; + + ApplicationManager.getApplication().invokeAndWait(new Runnable() { + @Override + public void run() { + ApplicationManager.getApplication().runReadAction(new Runnable() { + @Override + public void run() { + run[0] = !project.isDisposed() && + ReadonlyStatusHandler.ensureFilesWritable(project, filesToCheck.toArray(new VirtualFile[filesToCheck.size()])); + } + }); + } + }, ModalityState.defaultModalityState()); + + return run[0]; + } + + private static void removeDuplicateClasses(@NotNull final Module module, + @NotNull final String aPackage, + @NotNull final File generatedFile, + @NotNull final String sourceRootPath) { + if (generatedFile.exists()) { + ApplicationManager.getApplication().runReadAction(new Runnable() { + public void run() { + if (module.getProject().isDisposed() || module.isDisposed()) { + return; + } + String className = FileUtil.getNameWithoutExtension(generatedFile); + AndroidCompileUtil.removeDuplicatingClasses(module, aPackage, className, generatedFile, sourceRootPath); + } + }); + } + } + + private static class AptAutogenerationItem { + final IAndroidTarget myTarget; + final int myPlatformToolsRevision; + final String myManifestFileOsPath; + final String myPackage; + final String myOutputDirOsPath; + final String[] myResDirOsPaths; + final boolean myLibrary; + final Map myGenFileRelPath2package; + + private AptAutogenerationItem(@NotNull IAndroidTarget target, + int platformToolsRevision, + @NotNull String manifestFileOsPath, + @NotNull String aPackage, + @NotNull String outputDirOsPath, + @NotNull String[] resDirOsPaths, + boolean library, + @NotNull Map genFileRelPath2package) { + myTarget = target; + myPlatformToolsRevision = platformToolsRevision; + myManifestFileOsPath = manifestFileOsPath; + myPackage = aPackage; + myOutputDirOsPath = outputDirOsPath; + myResDirOsPaths = resDirOsPaths; + myLibrary = library; + myGenFileRelPath2package = genFileRelPath2package; + } + } + + private static class IdlAutogenerationItem { + final VirtualFile myFile; + final IAndroidTarget myTarget; + final String myOutFileOsPath; + final String[] mySourceRootOsPaths; + final String myOutDirOsPath; + final String myPackage; + + private IdlAutogenerationItem(@NotNull VirtualFile file, + @NotNull IAndroidTarget target, + @NotNull String outFileOsPath, + @NotNull String[] sourceRootOsPaths, + @NotNull String outDirOsPath, + @NotNull String aPackage) { + myFile = file; + myTarget = target; + myOutFileOsPath = outFileOsPath; + mySourceRootOsPaths = sourceRootOsPaths; + myOutDirOsPath = outDirOsPath; + myPackage = aPackage; + } + } + + private static class RenderscriptAutogenerationItem { + final String mySdkLocation; + final IAndroidTarget myTarget; + final String myGenDirPath; + final String myRawDirPath; + + private RenderscriptAutogenerationItem(@NotNull String sdkLocation, + @NotNull IAndroidTarget target, + @NotNull String genDirPath, + @NotNull String rawDirPath) { + mySdkLocation = sdkLocation; + myTarget = target; + myGenDirPath = genDirPath; + myRawDirPath = rawDirPath; + } + } +} diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidAutogeneratorMode.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidAutogeneratorMode.java new file mode 100644 index 000000000000..7b8852e674a0 --- /dev/null +++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidAutogeneratorMode.java @@ -0,0 +1,8 @@ +package org.jetbrains.android.compiler; + +/** + * @author Eugene.Kudelevsky + */ +public enum AndroidAutogeneratorMode { + AAPT, AIDL, RENDERSCRIPT +} diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidCompileUtil.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidCompileUtil.java index 90a34eef8812..039ff5c9768f 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/AndroidCompileUtil.java +++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidCompileUtil.java @@ -17,6 +17,8 @@ package org.jetbrains.android.compiler; import com.android.resources.ResourceType; import com.intellij.CommonBundle; +import com.intellij.compiler.CompilerConfiguration; +import com.intellij.compiler.CompilerConfigurationImpl; import com.intellij.compiler.impl.CompileContextImpl; import com.intellij.compiler.impl.ModuleCompileScope; import com.intellij.compiler.options.CompileStepBeforeRun; @@ -27,6 +29,8 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.compiler.*; import com.intellij.openapi.compiler.Compiler; +import com.intellij.openapi.compiler.options.ExcludeEntryDescription; +import com.intellij.openapi.compiler.options.ExcludedEntriesConfiguration; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.module.Module; @@ -35,7 +39,6 @@ import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.*; import com.intellij.openapi.ui.Messages; -import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.io.FileUtil; @@ -46,8 +49,8 @@ import com.intellij.psi.PsiFile; import com.intellij.psi.search.FileTypeIndex; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.util.ArrayUtil; +import com.intellij.util.containers.HashMap; import com.intellij.util.containers.HashSet; -import org.jetbrains.android.AndroidProjectComponent; import org.jetbrains.android.dom.resources.Attr; import org.jetbrains.android.dom.resources.DeclareStyleable; import org.jetbrains.android.dom.resources.ResourceElement; @@ -58,7 +61,9 @@ import org.jetbrains.android.fileTypes.AndroidIdlFileType; import org.jetbrains.android.fileTypes.AndroidRenderscriptFileType; import org.jetbrains.android.resourceManagers.LocalResourceManager; import org.jetbrains.android.sdk.AndroidPlatform; +import org.jetbrains.android.util.AndroidCompilerMessageKind; import org.jetbrains.android.util.AndroidUtils; +import org.jetbrains.android.util.ExecutionUtil; import org.jetbrains.android.util.ResourceEntry; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -77,16 +82,16 @@ import java.util.regex.Pattern; public class AndroidCompileUtil { private static final Logger LOG = Logger.getInstance("#org.jetbrains.android.compiler.AndroidCompileUtil"); private static Pattern R_PATTERN = Pattern.compile("R(\\$.*)?\\.class"); - + private static final Pattern ourMessagePattern = Pattern.compile("(.+):(\\d+):.+"); private static final Key RELEASE_BUILD_KEY = new Key("RELEASE_BUILD_KEY"); @NonNls private static final String RESOURCES_CACHE_DIR_NAME = "res-cache"; @NonNls private static final String GEN_MODULE_PREFIX = "~generated_"; - + @NonNls private static final String PROGUARD_CFG_FILE_NAME = "proguard.cfg"; @NonNls public static final String CLASSES_JAR_FILE_NAME = "classes.jar"; - + @NonNls private static final String[] SCALA_TEST_CONFIGURATIONS = {"ScalaTestRunConfiguration", "SpecsRunConfiguration", "Specs2RunConfiguration"}; @@ -94,6 +99,29 @@ public class AndroidCompileUtil { private AndroidCompileUtil() { } + @NotNull + public static Map toCompilerMessageCategoryKeys(@NotNull Map map) { + final Map result = new HashMap(); + + for (Map.Entry entry : map.entrySet()) { + final AndroidCompilerMessageKind key = entry.getKey(); + final T value = entry.getValue(); + + switch (key) { + case ERROR: + result.put(CompilerMessageCategory.ERROR, value); + break; + case INFORMATION: + result.put(CompilerMessageCategory.INFORMATION, value); + break; + case WARNING: + result.put(CompilerMessageCategory.WARNING, value); + break; + } + } + return result; + } + @Nullable public static VirtualFile getProguardConfigFile(@NotNull AndroidFacet facet) { final VirtualFile root = AndroidRootUtil.getMainContentRoot(facet); @@ -166,7 +194,7 @@ public class AndroidCompileUtil { if (root == anchor) { return; } - + VirtualFile parent = anchor.getParent(); if (parent == null) { return; @@ -191,7 +219,7 @@ public class AndroidCompileUtil { return; } Set rootsToExclude = new HashSet(); - collectChildrenRecursively(excludedRoot, root, rootsToExclude); + collectChildrenRecursively(excludedRoot, root, rootsToExclude); final ModifiableRootModel model = manager.getModifiableModel(); ContentEntry contentEntry = findContentEntryForRoot(model, excludedRoot); if (contentEntry != null) { @@ -218,7 +246,7 @@ public class AndroidCompileUtil { } }); } - + @NotNull private static String getGenModuleName(@NotNull Module module) { return GEN_MODULE_PREFIX + module.getName(); @@ -259,17 +287,40 @@ public class AndroidCompileUtil { if (root != null) { final ModuleRootManager manager = ModuleRootManager.getInstance(module); unexcludeRootIfNeccessary(root, manager); + + boolean markedAsSource = false; + for (VirtualFile existingRoot : manager.getSourceRoots()) { - if (existingRoot == root) return; - } - ApplicationManager.getApplication().runWriteAction(new Runnable() { - public void run() { - addSourceRoot(manager, root); + if (existingRoot == root) { + markedAsSource = true; } - }); + } + + if (!markedAsSource) { + ApplicationManager.getApplication().runWriteAction(new Runnable() { + public void run() { + addSourceRoot(manager, root); + } + }); + } + + excludeFromCompilation(project, root); } } + private static void excludeFromCompilation(@NotNull Project project, @NotNull VirtualFile dir) { + final ExcludedEntriesConfiguration configuration = + ((CompilerConfigurationImpl)CompilerConfiguration.getInstance(project)).getExcludedEntriesConfiguration(); + + for (ExcludeEntryDescription description : configuration.getExcludeEntryDescriptions()) { + if (description.getVirtualFile() == dir) { + return; + } + } + + configuration.addExcludeEntryDescription(new ExcludeEntryDescription(dir, true, false, project)); + } + private static void removeGenModule(@NotNull final Module libModule) { final String genModuleName = getGenModuleName(libModule); final ModuleManager moduleManager = ModuleManager.getInstance(libModule.getProject()); @@ -295,7 +346,7 @@ public class AndroidCompileUtil { } final VirtualFile moduleFile = genModule.getModuleFile(); moduleManager.disposeModule(genModule); - + if (moduleFile != null) { ApplicationManager.getApplication().invokeLater(new Runnable() { @Override @@ -338,132 +389,70 @@ public class AndroidCompileUtil { return contentEntry; } - public static void generate(final Module module, final GeneratingCompiler compiler, boolean withDependentModules) { + public static void generate(final Module module, final AndroidAutogeneratorMode mode, boolean withDependentModules) { if (withDependentModules) { Set modules = new HashSet(); collectModules(module, modules, ModuleManager.getInstance(module.getProject()).getModules()); for (Module module1 : modules) { - generate(module1, compiler); + generate(module1, mode); } } else { - generate(module, compiler); + generate(module, mode); } } - public static void generate(final Module module, final GeneratingCompiler compiler) { + public static void generate(final Module module, final AndroidAutogeneratorMode mode) { final AndroidFacet facet = AndroidFacet.getInstance(module); if (facet != null) { - facet.scheduleSourceRegenerating(compiler); + facet.scheduleSourceRegenerating(mode); } } - public static void doGenerate(final Module module, final GeneratingCompiler compiler) { + public static boolean doGenerate(final Module module, final AndroidAutogeneratorMode mode) { final Project project = module.getProject(); - final AndroidProjectComponent component = ApplicationManager.getApplication().runReadAction(new Computable() { - @Nullable - @Override - public AndroidProjectComponent compute() { - return !project.isDisposed() ? project.getComponent(AndroidProjectComponent.class) : null; - } - }); - if (component == null) { - return; - } - component.runIfNotInCompilation(new Runnable() { - @Override + assert !ApplicationManager.getApplication().isDispatchThread(); + final CompileContext[] contextWrapper = new CompileContext[1]; + + ApplicationManager.getApplication().runReadAction(new Runnable() { public void run() { - assert !ApplicationManager.getApplication().isDispatchThread(); - final CompileContext[] contextWrapper = new CompileContext[1]; - ApplicationManager.getApplication().runReadAction(new Runnable() { - public void run() { - if (project.isDisposed()) return; - CompilerTask task = new CompilerTask(project, true, "Android auto-generation", true); - CompileScope scope = new ModuleCompileScope(module, false); - contextWrapper[0] = new CompileContextImpl(project, task, scope, null, false, false); - } - }); - generate(compiler, contextWrapper[0]); + if (project.isDisposed()) return; + CompilerTask task = new CompilerTask(project, true, "Android auto-generation", true); + CompileScope scope = new ModuleCompileScope(module, false); + contextWrapper[0] = new CompileContextImpl(project, task, scope, null, false, false); } }); + generate(module, mode, contextWrapper[0]); + + return contextWrapper[0].getMessages(CompilerMessageCategory.ERROR).length == 0; } public static boolean isModuleAffected(CompileContext context, Module module) { return ArrayUtil.find(context.getCompileScope().getAffectedModules(), module) >= 0; } - public static void generate(GeneratingCompiler compiler, final CompileContext context) { + public static void generate(final Module module, AndroidAutogeneratorMode mode, final CompileContext context) { if (context == null) { return; } - - final Set affectedModules = new HashSet(); - Collections.addAll(affectedModules, context.getCompileScope().getAffectedModules()); - + + final AndroidFacet facet = AndroidFacet.getInstance(module); + if (facet == null) { + return; + } + ApplicationManager.getApplication().invokeAndWait(new Runnable() { @Override public void run() { - for (Module module : affectedModules) { - if (module.isDisposed() || module.getProject().isDisposed()) { - continue; - } - - final AndroidFacet facet = AndroidFacet.getInstance(module); - if (facet != null) { - AndroidCompileUtil.createGenModulesAndSourceRoots(facet); - } + if (facet.getModule().isDisposed() || facet.getModule().getProject().isDisposed()) { + return; } + AndroidCompileUtil.createGenModulesAndSourceRoots(facet); } }, ModalityState.defaultModalityState()); - - List itemsToGenerate = new ArrayList(); - for (GeneratingCompiler.GenerationItem item : compiler.getGenerationItems(context)) { - if (affectedModules.contains(item.getModule())) { - itemsToGenerate.add(item); - } - } - GeneratingCompiler.GenerationItem[] items = itemsToGenerate.toArray(new GeneratingCompiler.GenerationItem[itemsToGenerate.size()]); - - final boolean[] run = {true}; - final VirtualFile[] files = getFilesToCheckReadonlyStatus(items); - if (files.length > 0) { - ApplicationManager.getApplication().invokeAndWait(new Runnable() { - @Override - public void run() { - ApplicationManager.getApplication().runReadAction(new Runnable() { - @Override - public void run() { - final Project project = context.getProject(); - run[0] = !project.isDisposed() && ReadonlyStatusHandler.ensureFilesWritable(project, files); - } - }); - } - }, ModalityState.defaultModalityState()); - } - - if (run[0]) { - compiler.generate(context, items, null); - } - } - - private static VirtualFile[] getFilesToCheckReadonlyStatus(GeneratingCompiler.GenerationItem[] items) { - List filesToCheck = new ArrayList(); - for (GeneratingCompiler.GenerationItem item : items) { - if (item instanceof AndroidAptCompiler.AptGenerationItem) { - final Set generatedFiles = ((AndroidAptCompiler.AptGenerationItem)item).getGeneratedFiles().keySet(); - for (File generatedFile : generatedFiles) { - if (generatedFile.exists()) { - VirtualFile generatedVFile = LocalFileSystem.getInstance().findFileByIoFile(generatedFile); - if (generatedVFile != null) { - filesToCheck.add(generatedVFile); - } - } - } - } - } - return VfsUtil.toVirtualFileArray(filesToCheck); + AndroidAutogenerator.run(mode, facet, context); } private static void collectModules(Module module, Set result, Module[] allModules) { @@ -530,15 +519,15 @@ public class AndroidCompileUtil { final Project project = facet.getModule().getProject(); final IntermediateOutputCompiler pngFilesCachingCompiler = collectResCacheDirs ? Extensions.findExtension(Compiler.EP_NAME, project, AndroidPngFilesCachingCompiler.class) : null; - + if (collectResCacheDirs) { assert pngFilesCachingCompiler != null; } - + final List result = new ArrayList(); doCollectResourceDirs(facet, collectResCacheDirs, result, context); - + for (AndroidFacet depFacet : AndroidUtils.getAllAndroidDependencies(facet.getModule(), true)) { doCollectResourceDirs(depFacet, collectResCacheDirs, result, context); } @@ -623,11 +612,11 @@ public class AndroidCompileUtil { public static boolean isFullBuild(@NotNull CompileContext context) { final RunConfiguration runConfiguration = CompileStepBeforeRun.getRunConfiguration(context); - + if (runConfiguration == null) { return true; } - + if (runConfiguration instanceof JUnitConfiguration) { return false; } @@ -802,7 +791,7 @@ public class AndroidCompileUtil { boolean packRClasses, @NotNull List> files) throws IOException { - + if (file.isDirectory()) { final File[] children = file.listFiles(); @@ -816,13 +805,13 @@ public class AndroidCompileUtil { if (!FileUtil.getExtension(file.getName()).equals("class")) { return; } - + if (!packRClasses && R_PATTERN.matcher(file.getName()).matches()) { return; } final String rootPath = rootDirectory.getAbsolutePath(); - + String path = file.getAbsolutePath(); path = FileUtil.toSystemIndependentName(path.substring(rootPath.length())); if (path.charAt(0) == '/') { @@ -861,4 +850,12 @@ public class AndroidCompileUtil { } return classFilesDirOsPaths; } + + // can't be invoked from dispatch thread + @NotNull + public static Map> execute(String... argv) throws IOException { + assert !ApplicationManager.getApplication().isDispatchThread(); + final Map> messages = ExecutionUtil.doExecute(argv); + return toCompilerMessageCategoryKeys(messages); + } } \ No newline at end of file diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidIdlCompiler.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidIdlCompiler.java index dddc60b173d4..0c74c8766383 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/AndroidIdlCompiler.java +++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidIdlCompiler.java @@ -17,18 +17,15 @@ package org.jetbrains.android.compiler; import com.android.sdklib.IAndroidTarget; import com.android.sdklib.SdkConstants; -import com.intellij.compiler.impl.CompilerUtil; import com.intellij.facet.FacetManager; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.compiler.*; -import com.intellij.openapi.compiler.ex.CompileContextEx; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ProjectFileIndex; import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.io.FileUtil; -import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.android.compiler.tools.AndroidIdl; import org.jetbrains.android.facet.AndroidFacet; @@ -39,7 +36,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.DataInput; -import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -59,6 +55,7 @@ public class AndroidIdlCompiler implements SourceGeneratingCompiler { myProject = project; } + @Nullable @Override public VirtualFile getPresentableFile(CompileContext context, Module module, VirtualFile outputRoot, VirtualFile generatedFile) { return null; @@ -71,23 +68,7 @@ public class AndroidIdlCompiler implements SourceGeneratingCompiler { public GenerationItem[] generate(CompileContext context, GenerationItem[] items, VirtualFile outputRootDirectory) { if (items != null && items.length > 0) { context.getProgressIndicator().setText("Generating AIDL files..."); - //Application application = ApplicationManager.getApplication(); - GenerationItem[] generationItems = /*application.runReadAction(new GenerateAction(context, items))*/ doGenerate(context, items); - List generatedVFiles = new ArrayList(); - for (GenerationItem item : generationItems) { - File generatedFile = ((IdlGenerationItem)item).myGeneratedFile; - if (generatedFile != null) { - CompilerUtil.refreshIOFile(generatedFile); - VirtualFile generatedVFile = LocalFileSystem.getInstance().findFileByIoFile(generatedFile); - if (generatedVFile != null) { - generatedVFiles.add(generatedVFile); - } - } - } - if (context instanceof CompileContextEx) { - ((CompileContextEx)context).markGenerated(generatedVFiles); - } - return generationItems; + return doGenerate(context, items, outputRootDirectory); } return EMPTY_GENERATION_ITEM_ARRAY; } @@ -103,7 +84,7 @@ public class AndroidIdlCompiler implements SourceGeneratingCompiler { @Nullable public ValidityState createValidityState(DataInput is) throws IOException { - return null; + return TimestampValidityState.load(is); } private final static class IdlGenerationItem implements GenerationItem { @@ -111,13 +92,10 @@ public class AndroidIdlCompiler implements SourceGeneratingCompiler { final VirtualFile myFile; final boolean myTestSource; final IAndroidTarget myAndroidTarget; - final File myGeneratedFile; final String myPackageName; - final String mySourceRootPath; public IdlGenerationItem(@NotNull Module module, @NotNull VirtualFile file, - @NotNull String sourceRootPath, boolean testSource, @NotNull IAndroidTarget androidTarget, @NotNull String packageName) { @@ -126,19 +104,16 @@ public class AndroidIdlCompiler implements SourceGeneratingCompiler { myTestSource = testSource; myAndroidTarget = androidTarget; myPackageName = packageName; - mySourceRootPath = sourceRootPath; - myGeneratedFile = - new File(sourceRootPath, packageName.replace('.', File.separatorChar) + File.separator + file.getNameWithoutExtension() + ".java"); } @Nullable public String getPath() { - return null; + return myPackageName.replace('.', '/') + '/' + myFile.getNameWithoutExtension() + ".java"; } @Nullable public ValidityState getValidityState() { - return null; + return new TimestampValidityState(myFile.getTimeStamp()); } public Module getModule() { @@ -198,21 +173,11 @@ public class AndroidIdlCompiler implements SourceGeneratingCompiler { return; } ProjectFileIndex fileIndex = ProjectRootManager.getInstance(myProject).getFileIndex(); - IdlGenerationItem generationItem = - new IdlGenerationItem(module, file, sourceRootPath, fileIndex.isInTestSourceContent(file), target, packageName); - if (myContext.isMake()) { - File generatedFile = generationItem.myGeneratedFile; - if (generatedFile == null || !generatedFile.exists() || generatedFile.lastModified() <= file.getModificationCount()) { - items.add(generationItem); - } - } - else { - items.add(generationItem); - } + items.add(new IdlGenerationItem(module, file, fileIndex.isInTestSourceContent(file), target, packageName)); } } - private static GenerationItem[] doGenerate(final CompileContext context, GenerationItem[] items) { + private static GenerationItem[] doGenerate(final CompileContext context, GenerationItem[] items, VirtualFile outputRootDirectory) { if (context.getProject().isDisposed()) { return EMPTY_GENERATION_ITEM_ARRAY; } @@ -229,8 +194,12 @@ public class AndroidIdlCompiler implements SourceGeneratingCompiler { VirtualFile[] sourceRoots = AndroidPackagingCompiler.getSourceRootsForModuleAndDependencies(idlItem.myModule, false); final String[] sourceRootPaths = AndroidCompileUtil.toOsPaths(sourceRoots); - final Map> messages = AndroidIdl - .execute(idlItem.myAndroidTarget, idlItem.myFile.getPath(), idlItem.myGeneratedFile.getPath(), sourceRootPaths); + final String outFilePath = FileUtil.toSystemDependentName( + outputRootDirectory.getPath() + '/' + idlItem.myPackageName.replace('.', '/') + '/' + + idlItem.myFile.getNameWithoutExtension() + ".java"); + + final Map> messages = AndroidCompileUtil.toCompilerMessageCategoryKeys( + AndroidIdl.execute(idlItem.myAndroidTarget, idlItem.myFile.getPath(), outFilePath, sourceRootPaths)); ApplicationManager.getApplication().runReadAction(new Runnable() { public void run() { @@ -241,17 +210,6 @@ public class AndroidIdlCompiler implements SourceGeneratingCompiler { if (messages.get(CompilerMessageCategory.ERROR).isEmpty()) { results.add(idlItem); } - if (idlItem.myGeneratedFile.exists()) { - ApplicationManager.getApplication().runReadAction(new Runnable() { - public void run() { - if (idlItem.myModule.getProject().isDisposed()) return; - String className = FileUtil.getNameWithoutExtension(idlItem.myGeneratedFile); - AndroidCompileUtil.removeDuplicatingClasses(idlItem.myModule, idlItem.myPackageName, className, - idlItem.myGeneratedFile.exists() ? idlItem.myGeneratedFile : null, - idlItem.mySourceRootPath); - } - }); - } } catch (final IOException e) { ApplicationManager.getApplication().runReadAction(new Runnable() { diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidMavenResourcesCompiler.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidMavenResourcesCompiler.java index 17d70f0d0d1d..7025e7bebf79 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/AndroidMavenResourcesCompiler.java +++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidMavenResourcesCompiler.java @@ -31,7 +31,7 @@ import org.jetbrains.android.facet.AndroidFacet; import org.jetbrains.android.facet.AndroidRootUtil; import org.jetbrains.android.maven.AndroidMavenProvider; import org.jetbrains.android.maven.AndroidMavenUtil; -import org.jetbrains.android.util.AndroidUtils; +import org.jetbrains.android.util.AndroidCommonUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.maven.project.MavenProject; @@ -144,13 +144,13 @@ public class AndroidMavenResourcesCompiler implements SourceGeneratingCompiler { myModule = module; myPackage = aPackage; myGeneratedFile = - new File(sourceRootPath, aPackage.replace('.', File.separatorChar) + File.separator + AndroidUtils.R_JAVA_FILENAME); + new File(sourceRootPath, aPackage.replace('.', File.separatorChar) + File.separator + AndroidCommonUtils.R_JAVA_FILENAME); mySourceRootPath = sourceRootPath; } @Nullable public String getPath() { - return myPackage.replace('.', '/') + '/' + AndroidUtils.R_JAVA_FILENAME; + return myPackage.replace('.', '/') + '/' + AndroidCommonUtils.R_JAVA_FILENAME; } public ValidityState getValidityState() { diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidPngFilesCachingCompiler.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidPngFilesCachingCompiler.java index a4a2a76d1e71..248c180d07f3 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/AndroidPngFilesCachingCompiler.java +++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidPngFilesCachingCompiler.java @@ -98,9 +98,9 @@ public class AndroidPngFilesCachingCompiler implements SourceGeneratingCompiler if (resCacheDirOsPath == null) { continue; } - - final Map> messages = - AndroidApt.crunch(item.getTarget(), Collections.singletonList(resDirOsPath), resCacheDirOsPath); + + final Map> messages = AndroidCompileUtil.toCompilerMessageCategoryKeys( + AndroidApt.crunch(item.getTarget(), Collections.singletonList(resDirOsPath), resCacheDirOsPath)); AndroidCompileUtil.addMessages(context, messages, null); if (context.getMessages(CompilerMessageCategory.ERROR).length == 0) { processedItems.add(item); diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidPrecompileTask.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidPrecompileTask.java index f8355f3b7b68..83b77b39ec26 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/AndroidPrecompileTask.java +++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidPrecompileTask.java @@ -19,7 +19,10 @@ import com.intellij.compiler.CompilerConfiguration; import com.intellij.compiler.CompilerConfigurationImpl; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; -import com.intellij.openapi.compiler.*; +import com.intellij.openapi.compiler.CompilationStatusAdapter; +import com.intellij.openapi.compiler.CompileContext; +import com.intellij.openapi.compiler.CompileTask; +import com.intellij.openapi.compiler.CompilerManager; import com.intellij.openapi.compiler.options.ExcludeEntryDescription; import com.intellij.openapi.compiler.options.ExcludedEntriesConfiguration; import com.intellij.openapi.diagnostic.Logger; @@ -30,16 +33,13 @@ import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.util.io.FileUtil; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.containers.hash.HashSet; -import org.jetbrains.android.AndroidProjectComponent; import org.jetbrains.android.facet.AndroidFacet; import org.jetbrains.android.facet.AndroidRootUtil; import org.jetbrains.android.sdk.AndroidPlatform; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.io.File; import java.util.Arrays; @@ -50,20 +50,12 @@ import java.util.Set; * @author Eugene.Kudelevsky */ public class AndroidPrecompileTask implements CompileTask { - private final AndroidProjectComponent myOwner; - private static final Logger LOG = Logger.getInstance("#org.jetbrains.android.compiler.AndroidPrecompileTask"); - public AndroidPrecompileTask(@NotNull AndroidProjectComponent owner) { - myOwner = owner; - } - @Override public boolean execute(CompileContext context) { final Project project = context.getProject(); - myOwner.setCompilationStarted(); - ExcludedEntriesConfiguration configuration = ((CompilerConfigurationImpl)CompilerConfiguration.getInstance(project)).getExcludedEntriesConfiguration(); @@ -85,7 +77,7 @@ public class AndroidPrecompileTask implements CompileTask { }, indicator != null ? indicator.getModalityState() : ModalityState.NON_MODAL); if (context.isRebuild()) { - clearGenRootsAndResCache(facet, context); + clearResCache(facet, context); } final AndroidPlatform platform = facet.getConfiguration().getAndroidPlatform(); @@ -99,7 +91,7 @@ public class AndroidPrecompileTask implements CompileTask { excludeAllSourceRoots(module, configuration, addedEntries); } else { - unexcludeAllSourceRoots(module, configuration); + unexcludeAllSourceRoots(facet, configuration); } } } @@ -108,28 +100,11 @@ public class AndroidPrecompileTask implements CompileTask { LOG.debug("Files excluded by Android: " + addedEntries.size()); CompilerManager.getInstance(project).addCompilationStatusListener(new MyCompilationStatusListener(project, addedEntries), project); } - - CompilerManager.getInstance(project).addCompilationStatusListener(new CompilationStatusAdapter() { - @Override - public void compilationFinished(boolean aborted, int errors, int warnings, final CompileContext compileContext) { - ApplicationManager.getApplication().executeOnPooledThread(new Runnable() { - @Override - public void run() { - myOwner.setCompilationFinished(); - } - }); - } - }, project); - return true; } - private static void clearGenRootsAndResCache(@NotNull AndroidFacet facet, @NotNull CompileContext context) { + private static void clearResCache(@NotNull AndroidFacet facet, @NotNull CompileContext context) { final Module module = facet.getModule(); - - removeAllPackages(AndroidRootUtil.getRenderscriptGenSourceRootPath(module), context); - removeAllPackages(facet.getAptGenSourceRootPath(), context); - removeAllPackages(facet.getAidlGenSourceRootPath(), context); final String dirPath = AndroidCompileUtil.findResourcesCacheDirectory(module, false, null); if (dirPath != null) { @@ -139,38 +114,36 @@ public class AndroidPrecompileTask implements CompileTask { } } } - - private static void removeAllPackages(@Nullable String sourceRootPath, @NotNull CompileContext context) { - final File sourceRoot = new File(sourceRootPath); - final File[] children = sourceRoot.listFiles(); - - if (children != null) { - for (File child : children) { - if (child.isDirectory() && - child.getName() != null && - StringUtil.isJavaIdentifier(child.getName())) { - - if (!FileUtil.delete(child)) { - context.addMessage(CompilerMessageCategory.ERROR, "Cannot delete file " + child.getAbsolutePath(), - null, -1, -1); - } - } - } - } - final VirtualFile vFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(sourceRoot); - - if (vFile != null) { - vFile.refresh(false, true); - } - } - - private static void unexcludeAllSourceRoots(Module module, + private static void unexcludeAllSourceRoots(AndroidFacet facet, ExcludedEntriesConfiguration configuration) { - final VirtualFile[] sourceRoots = ModuleRootManager.getInstance(module).getSourceRoots(); + final VirtualFile[] sourceRoots = ModuleRootManager.getInstance(facet.getModule()).getSourceRoots(); final Set sourceRootSet = new HashSet(); sourceRootSet.addAll(Arrays.asList(sourceRoots)); + final String aidlGenSourceRootPath = facet.getAidlGenSourceRootPath(); + if (aidlGenSourceRootPath != null) { + final VirtualFile aidlGenSourceRoot = LocalFileSystem.getInstance().findFileByPath(aidlGenSourceRootPath); + + if (aidlGenSourceRoot != null) { + sourceRootSet.remove(aidlGenSourceRoot); + } + } + + final String aptGenSourceRootPath = facet.getAptGenSourceRootPath(); + if (aptGenSourceRootPath != null) { + final VirtualFile aptGenSourceRoot = LocalFileSystem.getInstance().findFileByPath(aptGenSourceRootPath); + + if (aptGenSourceRoot != null) { + sourceRootSet.remove(aptGenSourceRoot); + } + } + + final VirtualFile rsGenRoot = AndroidRootUtil.getRenderscriptGenDir(facet.getModule()); + if (rsGenRoot != null) { + sourceRootSet.remove(rsGenRoot); + } + final ExcludeEntryDescription[] descriptions = configuration.getExcludeEntryDescriptions(); configuration.removeAllExcludeEntryDescriptions(); diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidProguardCompiler.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidProguardCompiler.java index 466dbf7512a3..fb3ed1174edb 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/AndroidProguardCompiler.java +++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidProguardCompiler.java @@ -23,14 +23,19 @@ import org.jetbrains.android.facet.AndroidFacet; import org.jetbrains.android.facet.AndroidRootUtil; import org.jetbrains.android.sdk.AndroidPlatform; import org.jetbrains.android.util.AndroidBundle; -import org.jetbrains.android.util.AndroidUtils; -import org.jetbrains.android.util.ExecutionUtil; +import org.jetbrains.android.util.AndroidCommonUtils; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.io.*; -import java.util.*; +import java.io.DataInput; +import java.io.DataOutput; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; /** * @author Eugene.Kudelevsky @@ -250,8 +255,8 @@ public class AndroidProguardCompiler implements ClassPostProcessingCompiler { commands.add(quotePath(new File(logDirOutputOsPath, "mapping.txt").getAbsolutePath())); } - LOG.info(AndroidUtils.command2string(commands)); - return ExecutionUtil.execute(ArrayUtil.toStringArray(commands)); + LOG.info(AndroidCommonUtils.command2string(commands)); + return AndroidCompileUtil.execute(ArrayUtil.toStringArray(commands)); } private static String quotePath(String path) { diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidRenderscriptCompiler.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidRenderscriptCompiler.java index bb30b7b3ea2c..9dff00c3448f 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/AndroidRenderscriptCompiler.java +++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidRenderscriptCompiler.java @@ -3,7 +3,6 @@ package org.jetbrains.android.compiler; import com.android.AndroidConstants; import com.android.sdklib.IAndroidTarget; import com.android.sdklib.SdkConstants; -import com.intellij.compiler.impl.CompilerUtil; import com.intellij.facet.FacetManager; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.compiler.*; @@ -19,14 +18,15 @@ import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.ArrayUtil; +import com.intellij.util.containers.HashMap; import com.intellij.util.containers.HashSet; import org.jetbrains.android.facet.AndroidFacet; import org.jetbrains.android.facet.AndroidRootUtil; import org.jetbrains.android.fileTypes.AndroidRenderscriptFileType; import org.jetbrains.android.sdk.AndroidPlatform; import org.jetbrains.android.util.AndroidBundle; +import org.jetbrains.android.util.AndroidCommonUtils; import org.jetbrains.android.util.AndroidUtils; -import org.jetbrains.android.util.ExecutionUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -60,68 +60,64 @@ public class AndroidRenderscriptCompiler implements SourceGeneratingCompiler { } final VirtualFile[] files = context.getProjectCompileScope().getFiles(AndroidRenderscriptFileType.INSTANCE, true); - final List items = new ArrayList(files.length); - for (final VirtualFile file : files) { + final Map> module2files = new HashMap>(); + + for (VirtualFile file : files) { final Module module = context.getModuleByFile(file); - final AndroidFacet facet = FacetManager.getInstance(module).getFacetByType(AndroidFacet.ID); - if (facet != null) { - final AndroidPlatform platform = facet.getConfiguration().getAndroidPlatform(); - if (platform == null) { - context.addMessage(CompilerMessageCategory.ERROR, - AndroidBundle.message("android.compilation.error.specify.platform", module.getName()), null, -1, -1); - continue; + + if (module != null) { + Collection filesForModule = module2files.get(module); + + if (filesForModule == null) { + filesForModule = new ArrayList(); + module2files.put(module, filesForModule); } - final IAndroidTarget target = platform.getTarget(); - final String sdkLocation = platform.getSdk().getLocation(); - - final String packageName = AndroidUtils.getPackageName(module, file); - if (packageName == null) { - context.addMessage(CompilerMessageCategory.ERROR, "Cannot compute package for file", file.getUrl(), -1, -1); - continue; - } - - final String resourceDirPath = AndroidRootUtil.getResourceDirPath(facet); - assert resourceDirPath != null; - - addItem(context, file, facet, resourceDirPath, sdkLocation, target, packageName, items); - - if (facet.getConfiguration().LIBRARY_PROJECT) { - final HashSet usingModules = new HashSet(); - AndroidUtils.collectModulesDependingOn(module, usingModules); - - for (final Module module1 : usingModules) { - final AndroidFacet facet1 = AndroidFacet.getInstance(module1); - if (facet1 != null) { - addItem(context, file, facet1, resourceDirPath, sdkLocation, target, packageName, items); - } - } - } + filesForModule.add(file); } } + final List items = new ArrayList(files.length); + + for (Map.Entry> entry : module2files.entrySet()) { + final Module module = entry.getKey(); + final AndroidFacet facet = FacetManager.getInstance(module).getFacetByType(AndroidFacet.ID); + if (facet == null) { + continue; + } + + final AndroidPlatform platform = facet.getConfiguration().getAndroidPlatform(); + if (platform == null) { + context.addMessage(CompilerMessageCategory.ERROR, + AndroidBundle.message("android.compilation.error.specify.platform", module.getName()), null, -1, -1); + continue; + } + + final IAndroidTarget target = platform.getTarget(); + final String sdkLocation = platform.getSdk().getLocation(); + + final String resourceDirPath = AndroidRootUtil.getResourceDirPath(facet); + assert resourceDirPath != null; + + addItem(entry.getValue(), facet, resourceDirPath, sdkLocation, target, items); + } return items.toArray(new GenerationItem[items.size()]); } }); } - private static void addItem(@NotNull final CompileContext context, - @NotNull final VirtualFile sourceFile, + private static void addItem(@NotNull final Collection sourceFiles, @NotNull final AndroidFacet facet, @NotNull final String resourceDirPath, @NotNull String sdkLocation, @NotNull final IAndroidTarget target, - @NotNull final String packageName, @NotNull final List items) { final Module module = facet.getModule(); final String sourceRootPath = AndroidRootUtil.getRenderscriptGenSourceRootPath(module); if (sourceRootPath == null) { return; } - final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(context.getProject()).getFileIndex(); final String rawDirPath = resourceDirPath + '/' + AndroidConstants.FD_RES_RAW; - - items.add(new MyGenerationItem(module, sourceFile, sourceRootPath, packageName, rawDirPath, fileIndex.isInTestSourceContent(sourceFile), - sdkLocation, target)); + items.add(new MyGenerationItem(module, sourceFiles, rawDirPath, sdkLocation, target)); } @Override @@ -133,19 +129,13 @@ public class AndroidRenderscriptCompiler implements SourceGeneratingCompiler { } context.getProgressIndicator().setText("Compiling RenderScript files..."); - final GenerationItem[] generationItems = doGenerate(context, items); + final GenerationItem[] generationItems = doGenerate(context, items, outputRootDirectory); final Set generatedVFiles = new HashSet(); final HashSet visited = new HashSet(); - for (GenerationItem item : generationItems) { - final MyGenerationItem genItem = (MyGenerationItem)item; - final File genDir = new File(genItem.myGenRootPath); - CompilerUtil.refreshIODirectories(Arrays.asList(genDir)); - final VirtualFile generatedVFile = LocalFileSystem.getInstance().findFileByIoFile(genDir); - if (generatedVFile != null) { - AndroidUtils.collectFiles(generatedVFile, visited, generatedVFiles); - } - } + outputRootDirectory.refresh(false, true); + AndroidUtils.collectFiles(outputRootDirectory, visited, generatedVFiles); + if (context instanceof CompileContextEx) { ((CompileContextEx)context).markGenerated(generatedVFiles); } @@ -169,11 +159,27 @@ public class AndroidRenderscriptCompiler implements SourceGeneratingCompiler { return new MyValidityState(in); } - private static GenerationItem[] doGenerate(@NotNull final CompileContext context, @NotNull final GenerationItem[] items) { + private static GenerationItem[] doGenerate(@NotNull final CompileContext context, + @NotNull final GenerationItem[] items, + VirtualFile outputRootDirectory) { if (context.getProject().isDisposed()) { return EMPTY_GENERATION_ITEM_ARRAY; } + // we have one item per module there, so clear output directory + final String genRootPath = FileUtil.toSystemDependentName(outputRootDirectory.getPath()); + final File genRootDir = new File(genRootPath); + if (genRootDir.exists()) { + if (!FileUtil.delete(genRootDir)) { + context.addMessage(CompilerMessageCategory.ERROR, "Cannot delete directory " + genRootPath, null, -1, -1); + return EMPTY_GENERATION_ITEM_ARRAY; + } + if (!genRootDir.mkdir()) { + context.addMessage(CompilerMessageCategory.ERROR, "Cannot create directory " + genRootPath, null, -1, -1); + return EMPTY_GENERATION_ITEM_ARRAY; + } + } + final List results = new ArrayList(items.length); for (final GenerationItem item : items) { if (item instanceof MyGenerationItem) { @@ -183,33 +189,35 @@ public class AndroidRenderscriptCompiler implements SourceGeneratingCompiler { continue; } - try { - final Map> messages = launchRenderscriptCompiler(context.getProject(), - genItem.mySdkLocation, - genItem.myAndroidTarget, - genItem.mySourceFile, - genItem.myGenRootPath, - genItem.myRawDirPath); - ApplicationManager.getApplication().runReadAction(new Runnable() { - public void run() { - if (context.getProject().isDisposed()) { - return; + for (final VirtualFile sourceFile : genItem.myFiles) { + try { + final Map> messages = launchRenderscriptCompiler(context.getProject(), + genItem.mySdkLocation, + genItem.myAndroidTarget, + sourceFile, + genRootPath, + genItem.myRawDirPath); + ApplicationManager.getApplication().runReadAction(new Runnable() { + public void run() { + if (context.getProject().isDisposed()) { + return; + } + addMessages(context, messages, sourceFile.getUrl()); } - addMessages(context, messages, genItem.mySourceFile.getUrl()); - } - }); + }); - if (messages.get(CompilerMessageCategory.ERROR).isEmpty()) { - results.add(genItem); - } - } - catch (final IOException e) { - ApplicationManager.getApplication().runReadAction(new Runnable() { - public void run() { - if (context.getProject().isDisposed()) return; - context.addMessage(CompilerMessageCategory.ERROR, e.getMessage(), genItem.mySourceFile.getUrl(), -1, -1); + if (messages.get(CompilerMessageCategory.ERROR).isEmpty()) { + results.add(genItem); } - }); + } + catch (final IOException e) { + ApplicationManager.getApplication().runReadAction(new Runnable() { + public void run() { + if (context.getProject().isDisposed()) return; + context.addMessage(CompilerMessageCategory.ERROR, e.getMessage(), sourceFile.getUrl(), -1, -1); + } + }); + } } } } @@ -227,12 +235,12 @@ public class AndroidRenderscriptCompiler implements SourceGeneratingCompiler { } } - private static Map> launchRenderscriptCompiler(@NotNull Project project, - @NotNull final String sdkLocation, - @NotNull IAndroidTarget target, - @NotNull final VirtualFile sourceFile, - @NotNull final String genFolderPath, - @NotNull final String rawDirPath) + static Map> launchRenderscriptCompiler(@NotNull Project project, + @NotNull final String sdkLocation, + @NotNull IAndroidTarget target, + @NotNull final VirtualFile sourceFile, + @NotNull final String genFolderPath, + @NotNull final String rawDirPath) throws IOException { final List command = new ArrayList(); command.add( @@ -260,8 +268,8 @@ public class AndroidRenderscriptCompiler implements SourceGeneratingCompiler { command.add("-MD"); command.add(sourceFilePath); - LOG.info(AndroidUtils.command2string(command)); - return ExecutionUtil.execute(ArrayUtil.toStringArray(command)); + LOG.info(AndroidCommonUtils.command2string(command)); + return AndroidCompileUtil.execute(ArrayUtil.toStringArray(command)); } @Nullable @@ -288,43 +296,30 @@ public class AndroidRenderscriptCompiler implements SourceGeneratingCompiler { private static class MyGenerationItem implements GenerationItem { final Module myModule; final String mySdkLocation; - final VirtualFile mySourceFile; - final boolean myTestSource; + final Collection myFiles; final IAndroidTarget myAndroidTarget; - final String myGenRootPath; final String myRawDirPath; - final String myPackageName; - final boolean myFileExists; - final File myParentDirectory; public MyGenerationItem(@NotNull Module module, - @NotNull VirtualFile sourceFile, - @NotNull String genRootPath, - @NotNull String packageName, + @NotNull Collection files, @NotNull String rawDirPath, - boolean testSource, @NotNull String sdkLocation, @NotNull IAndroidTarget target) { myModule = module; - mySourceFile = sourceFile; + myFiles = files; myRawDirPath = rawDirPath; - myTestSource = testSource; mySdkLocation = sdkLocation; myAndroidTarget = target; - myGenRootPath = genRootPath; - myPackageName = packageName; - myParentDirectory = new File(myGenRootPath, myPackageName.replace('.', File.separatorChar)); - myFileExists = myParentDirectory.exists(); } @Nullable public String getPath() { - return null; + return ""; } @Nullable public ValidityState getValidityState() { - return new MyValidityState(mySourceFile, myFileExists); + return new MyValidityState(myFiles); } public Module getModule() { @@ -332,22 +327,28 @@ public class AndroidRenderscriptCompiler implements SourceGeneratingCompiler { } public boolean isTestSource() { - return myTestSource; + return false; } } - + private static class MyValidityState implements ValidityState { - private final long myTimestamp; - private final boolean myFileExists; - - public MyValidityState(@NotNull DataInput in) throws IOException { - myTimestamp = in.readLong(); - myFileExists = true; + private final Map myTimestamps = new HashMap(); + + MyValidityState(DataInput in) throws IOException { + final int size = in.readInt(); + + for (int i = 0; i < size; i++) { + final String path = in.readUTF(); + final long timestamp = in.readLong(); + + myTimestamps.put(path, timestamp); + } } - public MyValidityState(@NotNull VirtualFile file, boolean fileExists) { - myTimestamp = file.getTimeStamp(); - myFileExists = fileExists; + MyValidityState(@NotNull Collection files) { + for (VirtualFile file : files) { + myTimestamps.put(file.getPath(), file.getTimeStamp()); + } } @Override @@ -355,15 +356,17 @@ public class AndroidRenderscriptCompiler implements SourceGeneratingCompiler { if (!(otherState instanceof MyValidityState)) { return false; } - - final MyValidityState st = (MyValidityState)otherState; - return myTimestamp == st.myTimestamp && - myFileExists == st.myFileExists; + return ((MyValidityState)otherState).myTimestamps.equals(myTimestamps); } @Override public void save(DataOutput out) throws IOException { - out.writeLong(myTimestamp); + out.writeInt(myTimestamps.size()); + + for (Map.Entry entry : myTimestamps.entrySet()) { + out.writeUTF(entry.getKey()); + out.writeLong(entry.getValue()); + } } } } diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidResourcesPackagingCompiler.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidResourcesPackagingCompiler.java index 50783b06c374..920bd48041dc 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/AndroidResourcesPackagingCompiler.java +++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidResourcesPackagingCompiler.java @@ -152,12 +152,14 @@ public class AndroidResourcesPackagingCompiler implements ClassPostProcessingCom ? item.myOutputPath + RELEASE_SUFFIX : item.myOutputPath; - Map> messages = AndroidApt.packageResources(item.myAndroidTarget, - item.myPlatformToolsRevision, - preprocessedManifestFile.getPath(), - item.myResourceDirPaths, - item.myAssetsDirPath, - outputPath, null, !releasePackage, 0); + Map> messages = AndroidCompileUtil.toCompilerMessageCategoryKeys( + AndroidApt.packageResources(item.myAndroidTarget, + item.myPlatformToolsRevision, + preprocessedManifestFile.getPath(), + item.myResourceDirPaths, + item.myAssetsDirPath, + outputPath, null, !releasePackage, 0)); + AndroidCompileUtil.addMessages(context, messages, presentableFilesMap); } catch (final IOException e) { diff --git a/plugins/android/src/org/jetbrains/android/compiler/tools/AndroidApkBuilder.java b/plugins/android/src/org/jetbrains/android/compiler/tools/AndroidApkBuilder.java index 5f097640f68d..a2e5c29d1997 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/tools/AndroidApkBuilder.java +++ b/plugins/android/src/org/jetbrains/android/compiler/tools/AndroidApkBuilder.java @@ -33,11 +33,11 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.containers.HashMap; import com.intellij.util.containers.HashSet; import com.intellij.util.text.DateFormatUtil; +import org.jetbrains.android.compiler.AndroidCompileUtil; import org.jetbrains.android.facet.AndroidFacet; import org.jetbrains.android.sdk.AndroidPlatform; import org.jetbrains.android.util.AndroidBundle; import org.jetbrains.android.util.AndroidUtils; -import org.jetbrains.android.util.ExecutionUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -141,7 +141,7 @@ public class AndroidApkBuilder { map.putAll(map2); if (withAlignment && map.get(ERROR).size() == 0) { - map2 = ExecutionUtil.execute(zipAlignPath, "-f", "4", unalignedApk, finalApk); + map2 = AndroidCompileUtil.execute(zipAlignPath, "-f", "4", unalignedApk, finalApk); map.putAll(map2); } return map; diff --git a/plugins/android/src/org/jetbrains/android/facet/AndroidFacet.java b/plugins/android/src/org/jetbrains/android/facet/AndroidFacet.java index 6e918c914c17..de9e8f017cda 100644 --- a/plugins/android/src/org/jetbrains/android/facet/AndroidFacet.java +++ b/plugins/android/src/org/jetbrains/android/facet/AndroidFacet.java @@ -37,7 +37,6 @@ import com.intellij.facet.FacetTypeRegistry; import com.intellij.lang.properties.IProperty; import com.intellij.lang.properties.psi.PropertiesFile; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.compiler.GeneratingCompiler; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleUtil; @@ -65,18 +64,16 @@ import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.ProjectScope; import com.intellij.psi.search.searches.ClassInheritorsSearch; import com.intellij.psi.xml.XmlTag; +import com.intellij.util.Alarm; import com.intellij.util.ArrayUtil; import com.intellij.util.Processor; import com.intellij.util.containers.HashMap; import com.intellij.util.containers.HashSet; -import com.intellij.util.ui.update.MergingUpdateQueue; -import com.intellij.util.ui.update.Update; import com.intellij.util.xml.ConvertContext; import com.intellij.util.xml.DomElement; import org.jetbrains.android.compiler.AndroidAptCompiler; +import org.jetbrains.android.compiler.AndroidAutogeneratorMode; import org.jetbrains.android.compiler.AndroidCompileUtil; -import org.jetbrains.android.compiler.AndroidIdlCompiler; -import org.jetbrains.android.compiler.AndroidRenderscriptCompiler; import org.jetbrains.android.dom.manifest.Manifest; import org.jetbrains.android.importDependencies.ImportDependenciesUtil; import org.jetbrains.android.resourceManagers.LocalResourceManager; @@ -112,27 +109,96 @@ public class AndroidFacet extends Facet { private final Map> myClassMaps = new HashMap>(); private final Object myClassMapLock = new Object(); - - private final Map, MergingUpdateQueue> mySourcesAutogeneratingQueueMap = new HashMap, MergingUpdateQueue>(); + + private final Set myDirtyModes = EnumSet.noneOf(AndroidAutogeneratorMode.class); + private final Map> myAutogeneratedFiles = new HashMap>(); + + private volatile boolean myAutogenerationEnabled = false; public AndroidFacet(@NotNull Module module, String name, @NotNull AndroidFacetConfiguration configuration) { super(getFacetType(), module, name, configuration, null); configuration.setFacet(this); - mySourcesAutogeneratingQueueMap.put(AndroidAptCompiler.class, createSourceGeneratingQueue("AndroidAptAutogeneratingQueue")); - mySourcesAutogeneratingQueueMap.put(AndroidIdlCompiler.class, createSourceGeneratingQueue("AndroidIdlAutogeneratingQueue")); - mySourcesAutogeneratingQueueMap - .put(AndroidRenderscriptCompiler.class, createSourceGeneratingQueue("AndroidRenderscriptAutogeneratingQueue")); + for (AndroidAutogeneratorMode mode : AndroidAutogeneratorMode.values()) { + createAlarm(mode); + } } - private MergingUpdateQueue createSourceGeneratingQueue(@NotNull String name) { - return new MergingUpdateQueue(name, 1000, false, null, this, null, false); + private Alarm createAlarm(@NotNull final AndroidAutogeneratorMode mode) { + final Alarm alarm = new Alarm(Alarm.ThreadToUse.OWN_THREAD, this); + alarm.addRequest(new Runnable() { + @Override + public void run() { + boolean regenerate; + + synchronized (myDirtyModes) { + regenerate = myDirtyModes.contains(mode); + } + regenerate = regenerate || isGeneratedFileRemoved(mode); + + if (myAutogenerationEnabled && regenerate) { + if (AndroidCompileUtil.doGenerate(getModule(), mode)) { + synchronized (myDirtyModes) { + myDirtyModes.remove(mode); + } + } + } + if (!alarm.isDisposed()) { + alarm.addRequest(this, 2000); + } + } + }, 2000); + return alarm; + } + + private boolean isGeneratedFileRemoved(@NotNull AndroidAutogeneratorMode mode) { + synchronized (myAutogeneratedFiles) { + final Set filePaths = myAutogeneratedFiles.get(mode); + + if (filePaths != null) { + for (String path : filePaths) { + final VirtualFile file = LocalFileSystem.getInstance().findFileByPath(path); + + if (file == null) { + return true; + } + } + } + } + return false; + } + + public void clearAutogeneratedFiles(@NotNull AndroidAutogeneratorMode mode) { + synchronized (myAutogeneratedFiles) { + final Set set = myAutogeneratedFiles.get(mode); + if (set != null) { + set.clear(); + } + } + } + + public void markFileAutogenerated(@NotNull AndroidAutogeneratorMode mode, @NotNull VirtualFile file) { + synchronized (myAutogeneratedFiles) { + Set set = myAutogeneratedFiles.get(mode); + + if (set == null) { + set = new HashSet(); + myAutogeneratedFiles.put(mode, set); + } + set.add(file.getPath()); + } + } + + @NotNull + public Set getAutogeneratedFiles(@NotNull AndroidAutogeneratorMode mode) { + synchronized (myAutogeneratedFiles) { + final Set set = myAutogeneratedFiles.get(mode); + return set != null ? new HashSet(set) : Collections.emptySet(); + } } private void activateSourceAutogenerating() { - for (MergingUpdateQueue queue : mySourcesAutogeneratingQueueMap.values()) { - queue.activate(); - } + myAutogenerationEnabled = true; } @Nullable @@ -385,12 +451,12 @@ public class AndroidFacet extends Facet { myListener.setResourceSet(resourceSet); if (getConfiguration().REGENERATE_R_JAVA && AndroidAptCompiler.isToCompileModule(module, getConfiguration())) { - AndroidCompileUtil.generate(module, new AndroidAptCompiler()); + AndroidCompileUtil.generate(module, AndroidAutogeneratorMode.AAPT); } if (getConfiguration().REGENERATE_JAVA_BY_AIDL) { - AndroidCompileUtil.generate(module, new AndroidIdlCompiler(project)); + AndroidCompileUtil.generate(module, AndroidAutogeneratorMode.AIDL); } - AndroidCompileUtil.generate(module, new AndroidRenderscriptCompiler()); + AndroidCompileUtil.generate(module, AndroidAutogeneratorMode.RENDERSCRIPT); activateSourceAutogenerating(); } @@ -774,19 +840,9 @@ public class AndroidFacet extends Facet { return moduleDirPath != null ? FileUtil.toSystemDependentName(moduleDirPath + path) : null; } - public void scheduleSourceRegenerating(@NotNull final GeneratingCompiler compiler) { - final MergingUpdateQueue queue = mySourcesAutogeneratingQueueMap.get(compiler.getClass()); - - if (queue == null) { - LOG.error("Autogenerating is not supported for compiler " + compiler.getClass().getCanonicalName()); - } - else { - queue.queue(new Update(this) { - @Override - public void run() { - AndroidCompileUtil.doGenerate(getModule(), compiler); - } - }); + public void scheduleSourceRegenerating(@NotNull final AndroidAutogeneratorMode mode) { + synchronized (myDirtyModes) { + myDirtyModes.add(mode); } } } diff --git a/plugins/android/src/org/jetbrains/android/facet/AndroidFacetEditorTab.java b/plugins/android/src/org/jetbrains/android/facet/AndroidFacetEditorTab.java index 26cf05e4d4c8..9799c579ca92 100644 --- a/plugins/android/src/org/jetbrains/android/facet/AndroidFacetEditorTab.java +++ b/plugins/android/src/org/jetbrains/android/facet/AndroidFacetEditorTab.java @@ -37,8 +37,8 @@ import com.intellij.ui.components.JBLabel; import com.intellij.util.ArrayUtil; import com.intellij.util.ui.UIUtil; import org.jetbrains.android.compiler.AndroidAptCompiler; +import org.jetbrains.android.compiler.AndroidAutogeneratorMode; import org.jetbrains.android.compiler.AndroidCompileUtil; -import org.jetbrains.android.compiler.AndroidIdlCompiler; import org.jetbrains.android.maven.AndroidMavenProvider; import org.jetbrains.android.maven.AndroidMavenUtil; import org.jetbrains.android.util.AndroidBundle; @@ -437,10 +437,10 @@ public class AndroidFacetEditorTab extends FacetEditorTab { final Project project = module.getProject(); if (runApt) { - AndroidCompileUtil.generate(module, new AndroidAptCompiler(), true); + AndroidCompileUtil.generate(module, AndroidAutogeneratorMode.AAPT, true); } if (runIdl) { - AndroidCompileUtil.generate(module, new AndroidIdlCompiler(project)); + AndroidCompileUtil.generate(module, AndroidAutogeneratorMode.AIDL); } } } diff --git a/plugins/android/src/org/jetbrains/android/facet/AndroidResourceFilesListener.java b/plugins/android/src/org/jetbrains/android/facet/AndroidResourceFilesListener.java index e422429d59a3..37e9c4105441 100644 --- a/plugins/android/src/org/jetbrains/android/facet/AndroidResourceFilesListener.java +++ b/plugins/android/src/org/jetbrains/android/facet/AndroidResourceFilesListener.java @@ -18,7 +18,6 @@ package org.jetbrains.android.facet; import com.android.resources.ResourceFolderType; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.compiler.GeneratingCompiler; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleUtil; import com.intellij.openapi.project.DumbService; @@ -28,7 +27,9 @@ import com.intellij.openapi.vfs.*; import com.intellij.util.containers.HashSet; import com.intellij.util.ui.update.MergingUpdateQueue; import com.intellij.util.ui.update.Update; -import org.jetbrains.android.compiler.*; +import org.jetbrains.android.compiler.AndroidAptCompiler; +import org.jetbrains.android.compiler.AndroidAutogeneratorMode; +import org.jetbrains.android.compiler.AndroidCompileUtil; import org.jetbrains.android.dom.manifest.Manifest; import org.jetbrains.android.fileTypes.AndroidIdlFileType; import org.jetbrains.android.fileTypes.AndroidRenderscriptFileType; @@ -111,9 +112,6 @@ class AndroidResourceFilesListener extends VirtualFileAdapter { private void fileChanged(@NotNull final VirtualFileEvent e) { VirtualFile file = e.getFile(); - if (!file.isValid()) { - return; - } VirtualFile parent = e.getParent(); VirtualFile gp = parent != null ? parent.getParent() : null; @@ -146,18 +144,19 @@ class AndroidResourceFilesListener extends VirtualFileAdapter { return; } - final GeneratingCompiler compilerToRun = ApplicationManager.getApplication().runReadAction(new Computable() { - @Nullable - public GeneratingCompiler compute() { - return computeCompilerToRunAndInvalidateLocalAttributesMap(); - } - }); + final AndroidAutogeneratorMode autogenerationMode = + ApplicationManager.getApplication().runReadAction(new Computable() { + @Nullable + public AndroidAutogeneratorMode compute() { + return computeCompilerToRunAndInvalidateLocalAttributesMap(); + } + }); - if (compilerToRun == null) { + if (autogenerationMode == null) { return; } - if (compilerToRun instanceof AndroidAptCompiler && + if (autogenerationMode == AndroidAutogeneratorMode.AAPT && AndroidRootUtil.getManifestFile(myFacet.getModule()) != myEvent.getFile()) { final HashSet resourceSet = new HashSet(); @@ -173,11 +172,11 @@ class AndroidResourceFilesListener extends VirtualFileAdapter { myResourceSet = resourceSet; } } - AndroidCompileUtil.generate(myFacet.getModule(), compilerToRun, true); + AndroidCompileUtil.generate(myFacet.getModule(), autogenerationMode, true); } @Nullable - private GeneratingCompiler computeCompilerToRunAndInvalidateLocalAttributesMap() { + private AndroidAutogeneratorMode computeCompilerToRunAndInvalidateLocalAttributesMap() { if (myFacet.isDisposed()) { return null; } @@ -219,20 +218,20 @@ class AndroidResourceFilesListener extends VirtualFileAdapter { AndroidCompileUtil.removeDuplicatingClasses(myModule, myCachedPackage, AndroidUtils.R_CLASS_NAME, null, aptGenDirPath); } myCachedPackage = aPackage; - return new AndroidAptCompiler(); + return AndroidAutogeneratorMode.AAPT; } if (myFacet.getConfiguration().REGENERATE_JAVA_BY_AIDL && file.getFileType() == AndroidIdlFileType.ourFileType) { VirtualFile sourceRoot = findSourceRoot(myModule, file); if (sourceRoot != null && AndroidRootUtil.getAidlGenDir(module, myFacet) != sourceRoot) { - return new AndroidIdlCompiler(project); + return AndroidAutogeneratorMode.AIDL; } } if (file.getFileType() == AndroidRenderscriptFileType.INSTANCE) { final VirtualFile sourceRoot = findSourceRoot(myModule, file); if (sourceRoot != null && AndroidRootUtil.getRenderscriptGenDir(myModule) != sourceRoot) { - return new AndroidRenderscriptCompiler(); + return AndroidAutogeneratorMode.RENDERSCRIPT; } } return null; diff --git a/plugins/android/src/org/jetbrains/android/util/AndroidResourceUtil.java b/plugins/android/src/org/jetbrains/android/util/AndroidResourceUtil.java index 553fb41e9c4a..d36a90ded8a2 100644 --- a/plugins/android/src/org/jetbrains/android/util/AndroidResourceUtil.java +++ b/plugins/android/src/org/jetbrains/android/util/AndroidResourceUtil.java @@ -99,7 +99,7 @@ public class AndroidResourceUtil { collectDirsForPackage(module, project, null, dirs, new HashSet(), onlyInOwnPackages); List rJavaFiles = new ArrayList(); for (PsiDirectory dir : dirs) { - VirtualFile file = dir.getVirtualFile().findChild(AndroidUtils.R_JAVA_FILENAME); + VirtualFile file = dir.getVirtualFile().findChild(AndroidCommonUtils.R_JAVA_FILENAME); if (file != null) { PsiFile psiFile = PsiManager.getInstance(project).findFile(file); if (psiFile instanceof PsiJavaFile) { diff --git a/plugins/android/src/org/jetbrains/android/util/AndroidUtils.java b/plugins/android/src/org/jetbrains/android/util/AndroidUtils.java index 9bc4c6a0675a..34333f8885fc 100644 --- a/plugins/android/src/org/jetbrains/android/util/AndroidUtils.java +++ b/plugins/android/src/org/jetbrains/android/util/AndroidUtils.java @@ -113,7 +113,6 @@ public class AndroidUtils { public static final Icon RESTART_LOGCAT_ICON = IconLoader.getIcon("/icons/restartLogcat.png"); public static final String NAMESPACE_KEY = "android"; public static final String SYSTEM_RESOURCE_PACKAGE = "android"; - public static final String R_JAVA_FILENAME = "R.java"; public static final String ANDROID_PACKAGE = "android"; public static final String VIEW_CLASS_NAME = ANDROID_PACKAGE + ".view.View"; public static final String APPLICATION_CLASS_NAME = "android.app.Application"; @@ -148,7 +147,6 @@ public class AndroidUtils { public static final String PROVIDER_CLASS_NAME = "android.content.ContentProvider"; @NonNls public static final String DEFAULT_PROPERTIES_FILE_NAME = "default.properties"; @NonNls public static final String PNG_EXTENSION = "png"; - @NonNls public static final Object MANIFEST_JAVA_FILE_NAME = "Manifest.java"; private AndroidUtils() { } @@ -259,7 +257,7 @@ public class AndroidUtils { } public static boolean isRClassFile(@NotNull AndroidFacet facet, @NotNull PsiFile file) { - if (file.getName().equals(R_JAVA_FILENAME) && file instanceof PsiJavaFile) { + if (file.getName().equals(AndroidCommonUtils.R_JAVA_FILENAME) && file instanceof PsiJavaFile) { PsiJavaFile javaFile = (PsiJavaFile)file; Manifest manifest = facet.getManifest(); if (manifest == null) return false; @@ -961,20 +959,6 @@ public class AndroidUtils { return xmlFiles; } - public static String command2string(@NotNull Collection command) { - final StringBuilder builder = new StringBuilder(); - for (Iterator it = command.iterator(); it.hasNext(); ) { - String s = it.next(); - builder.append('['); - builder.append(s); - builder.append(']'); - if (it.hasNext()) { - builder.append(' '); - } - } - return builder.toString(); - } - @Nullable public static String getProjectPropertyValue(Module module, String propertyName) { final String result = getPropertyValue(module, SdkConstants.FN_PROJECT_PROPERTIES, propertyName); diff --git a/plugins/android/src/org/jetbrains/android/util/ExecutionUtil.java b/plugins/android/src/org/jetbrains/android/util/ExecutionUtil.java deleted file mode 100644 index 9c5efe24f589..000000000000 --- a/plugins/android/src/org/jetbrains/android/util/ExecutionUtil.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright 2000-2010 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.android.util; - -import com.intellij.execution.process.OSProcessHandler; -import com.intellij.execution.process.ProcessAdapter; -import com.intellij.execution.process.ProcessEvent; -import com.intellij.execution.process.ProcessOutputTypes; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.compiler.CompilerMessageCategory; -import com.intellij.openapi.util.Key; -import com.intellij.openapi.util.text.StringUtil; -import org.jetbrains.annotations.NotNull; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * Abstract external tool for compiler. - * - * @author Alexey Efimov - */ -public final class ExecutionUtil { - - private static final String IGNORING = "ignoring"; - private static final String SKIPPING = "skipping"; - - private ExecutionUtil() { - } - - // can't be invoked from dispatch thread - @NotNull - public static Map> execute(String... argv) throws IOException { - assert !ApplicationManager.getApplication().isDispatchThread(); - ProcessBuilder builder = new ProcessBuilder(argv); - ProcessResult result = readProcessOutput(builder.start()); - Map> messages = result.getMessages(); - int code = result.getExitCode(); - List errMessages = messages.get(CompilerMessageCategory.ERROR); - - if (code != 0 && errMessages.isEmpty()) { - throw new IOException(AndroidBundle.message("command.0.execution.failed.with.exit.code.1", concat(argv), code)); - } - else { - if (code == 0) { - messages.get(CompilerMessageCategory.INFORMATION).addAll(errMessages); - errMessages.clear(); - } - return messages; - } - } - - private static String concat(String... strs) { - StringBuilder builder = new StringBuilder(); - for (int i = 0, n = strs.length; i < n; i++) { - builder.append(strs[i]); - if (i < n - 1) { - builder.append(' '); - } - } - return builder.toString(); - } - - @NotNull - private static ProcessResult readProcessOutput(Process process) throws IOException { - assert !ApplicationManager.getApplication().isDispatchThread(); - OSProcessHandler handler = new OSProcessHandler(process, ""); - final List information = new ArrayList(); - final List error = new ArrayList(); - handler.addProcessListener(new ProcessAdapter() { - public void onTextAvailable(final ProcessEvent event, final Key outputType) { - String output = event.getText(); - if (StringUtil.isEmptyOrSpaces(output)) { - return; - } - String[] lines = output.split("[\\n\\r]+"); - for (String line : lines) { - String l = line.toLowerCase(); - if (outputType == ProcessOutputTypes.STDOUT) { - information.add(line); - } - else if (outputType == ProcessOutputTypes.STDERR) { - if (l.contains(IGNORING) || l.contains(SKIPPING)) { - information.add(line); - } - else { - error.add(line); - } - } - } - } - }); - handler.startNotify(); - handler.waitFor(); - int exitCode = handler.getProcess().exitValue(); - return new ProcessResult(information, error, exitCode); - } - - private static final class ProcessResult { - private final int myExitCode; - private final Map> myMessages; - - public ProcessResult(List information, List error, int exitCode) { - myExitCode = exitCode; - myMessages = new HashMap>(2); - myMessages.put(CompilerMessageCategory.INFORMATION, information); - myMessages.put(CompilerMessageCategory.ERROR, error); - } - - public Map> getMessages() { - return myMessages; - } - - public int getExitCode() { - return myExitCode; - } - } -} diff --git a/plugins/eclipse/src/org/jetbrains/idea/eclipse/EclipseXml.java b/plugins/eclipse/src/org/jetbrains/idea/eclipse/EclipseXml.java index 3d38360c09c7..8503577ab94f 100644 --- a/plugins/eclipse/src/org/jetbrains/idea/eclipse/EclipseXml.java +++ b/plugins/eclipse/src/org/jetbrains/idea/eclipse/EclipseXml.java @@ -41,6 +41,7 @@ public interface EclipseXml { @NonNls String JRE_CONTAINER_SPECIFIC = JRE_CONTAINER + "/" + "org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType"; @NonNls String USER_LIBRARY = "org.eclipse.jdt.USER_LIBRARY"; @NonNls String JUNIT_CONTAINER = "org.eclipse.jdt.junit.JUNIT_CONTAINER"; + @NonNls String GROOVY_DSL_CONTAINER = "GROOVY_DSL_SUPPORT"; @NonNls String JUNIT3 = JUNIT_CONTAINER + "/" + "3.8.1"; @NonNls String JUNIT4 = JUNIT_CONTAINER + "/" + "4"; @NonNls String ECLIPSE_PLATFORM = "org.eclipse.pde.core.requiredPlugins"; diff --git a/plugins/eclipse/src/org/jetbrains/idea/eclipse/config/EclipseClasspathStorageProvider.java b/plugins/eclipse/src/org/jetbrains/idea/eclipse/config/EclipseClasspathStorageProvider.java index 28471448c01d..86867b40a344 100644 --- a/plugins/eclipse/src/org/jetbrains/idea/eclipse/config/EclipseClasspathStorageProvider.java +++ b/plugins/eclipse/src/org/jetbrains/idea/eclipse/config/EclipseClasspathStorageProvider.java @@ -148,6 +148,7 @@ public class EclipseClasspathStorageProvider implements ClasspathStorageProvider LocalFileSystem.getInstance().refreshAndFindFileByIoFile(target); } final CachedXmlDocumentSet fileCache = getFileCache(module); + DotProjectFileHelper.saveDotProjectFile(module, fileCache.getParent(EclipseXml.PROJECT_FILE)); fileCache.delete(oldEmlName); fileCache.register(newName + EclipseXml.IDEA_SETTINGS_POSTFIX, ClasspathStorage.getModuleDir(module)); fileCache.load(newName + EclipseXml.IDEA_SETTINGS_POSTFIX); diff --git a/plugins/eclipse/src/org/jetbrains/idea/eclipse/config/EclipseModuleManager.java b/plugins/eclipse/src/org/jetbrains/idea/eclipse/config/EclipseModuleManager.java index 6488c4a6b196..da5f40a100e3 100644 --- a/plugins/eclipse/src/org/jetbrains/idea/eclipse/config/EclipseModuleManager.java +++ b/plugins/eclipse/src/org/jetbrains/idea/eclipse/config/EclipseModuleManager.java @@ -62,6 +62,7 @@ public class EclipseModuleManager implements PersistentStateComponent{ private int myExpectedModuleSourcePlace; private Map mySrcPlace = new LinkedHashMap(); private String myInvalidJdk; + private boolean myGroovyDslSupport = false; public EclipseModuleManager(Module module) { myModule = module; @@ -75,6 +76,14 @@ public class EclipseModuleManager implements PersistentStateComponent{ return myInvalidJdk; } + public void setGroovyDslSupport() { + myGroovyDslSupport = true; + } + + public boolean isGroovyDslSupport() { + return myGroovyDslSupport; + } + public static EclipseModuleManager getInstance(Module module) { return ModuleServiceManager.getService(module, EclipseModuleManager.class); } diff --git a/plugins/eclipse/src/org/jetbrains/idea/eclipse/conversion/EclipseClasspathReader.java b/plugins/eclipse/src/org/jetbrains/idea/eclipse/conversion/EclipseClasspathReader.java index db948129570d..e00ca1c1e376 100644 --- a/plugins/eclipse/src/org/jetbrains/idea/eclipse/conversion/EclipseClasspathReader.java +++ b/plugins/eclipse/src/org/jetbrains/idea/eclipse/conversion/EclipseClasspathReader.java @@ -272,7 +272,12 @@ public class EclipseClasspathReader { final Library.ModifiableModel modifiableModel = library.getModifiableModel(); modifiableModel.addRoot(getJunitClsUrl(junitName.contains("4")), OrderRootType.CLASSES); modifiableModel.commit(); - } else { + } + else if (path.equals(EclipseXml.GROOVY_DSL_CONTAINER)) { + eclipseModuleManager.setGroovyDslSupport(); + eclipseModuleManager.registerSrcPlace(EclipseXml.GROOVY_DSL_CONTAINER, idx); + } + else { eclipseModuleManager.registerUnknownCons(path); addNamedLibrary(rootModel, new ArrayList(), exported, path, LibraryTablesRegistrar.APPLICATION_LEVEL); } diff --git a/plugins/eclipse/src/org/jetbrains/idea/eclipse/conversion/EclipseClasspathWriter.java b/plugins/eclipse/src/org/jetbrains/idea/eclipse/conversion/EclipseClasspathWriter.java index 959992f9a95a..cb6c69f8f5c5 100644 --- a/plugins/eclipse/src/org/jetbrains/idea/eclipse/conversion/EclipseClasspathWriter.java +++ b/plugins/eclipse/src/org/jetbrains/idea/eclipse/conversion/EclipseClasspathWriter.java @@ -64,7 +64,8 @@ public class EclipseClasspathWriter { @NonNls String outputPath = "bin"; final String compilerOutputUrl = myModel.getModuleExtension(CompilerModuleExtension.class).getCompilerOutputUrl(); - final String linkedPath = EclipseModuleManager.getInstance(myModel.getModule()).getEclipseLinkedVarPath(compilerOutputUrl); + final EclipseModuleManager eclipseModuleManager = EclipseModuleManager.getInstance(myModel.getModule()); + final String linkedPath = eclipseModuleManager.getEclipseLinkedVarPath(compilerOutputUrl); if (linkedPath != null) { outputPath = linkedPath; } else { @@ -77,6 +78,10 @@ public class EclipseClasspathWriter { outputPath = EPathUtil.collapse2EclipsePath(compilerOutputUrl, myModel); } } + if (eclipseModuleManager.isGroovyDslSupport()) { + final Integer place = eclipseModuleManager.getSrcPlace(EclipseXml.GROOVY_DSL_CONTAINER); + addOrderEntry(EclipseXml.CON_KIND, EclipseXml.GROOVY_DSL_CONTAINER, classpathElement, place != null ? place.intValue() : -1); + } final Element orderEntry = addOrderEntry(EclipseXml.OUTPUT_KIND, outputPath, classpathElement); setAttributeIfAbsent(orderEntry, EclipseXml.PATH_ATTR, EclipseXml.BIN_DIR); } diff --git a/plugins/gradle/resources/i18n/GradleBundle.properties b/plugins/gradle/resources/i18n/GradleBundle.properties index 205b4ac96bb6..e85e37d53385 100644 --- a/plugins/gradle/resources/i18n/GradleBundle.properties +++ b/plugins/gradle/resources/i18n/GradleBundle.properties @@ -77,6 +77,8 @@ gradle.action.refresh.project.text=Refresh gradle project gradle.action.refresh.project.description=Allows to force linked gradle project refresh gradle.action.open.script.text=Open linked gradle project gradle.action.open.script.description=Allows to open project file of the linked gradle project at the editor +gradle.action.import.entity.text=Import +gradle.action.import.entity.description=Import target gradle entity gradle.settings.color.text.sample.conflict.node.name=node-with-conflicting-setup gradle.settings.color.text.sample.node.sync.name=node-with-same-setup diff --git a/plugins/gradle/src/META-INF/plugin.xml b/plugins/gradle/src/META-INF/plugin.xml index ca35a79bc1eb..ff4374eb52a2 100644 --- a/plugins/gradle/src/META-INF/plugin.xml +++ b/plugins/gradle/src/META-INF/plugin.xml @@ -34,17 +34,25 @@ - - + - + + + + + + + + + + @@ -72,10 +80,14 @@ + + + + \ No newline at end of file diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/action/GradleImportEntityAction.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/action/GradleImportEntityAction.java new file mode 100644 index 000000000000..5000c5995b7e --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/action/GradleImportEntityAction.java @@ -0,0 +1,131 @@ +package org.jetbrains.plugins.gradle.action; + +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.actionSystem.PlatformDataKeys; +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.gradle.config.GradleTextAttributes; +import org.jetbrains.plugins.gradle.importing.GradleModuleDependencyImporter; +import org.jetbrains.plugins.gradle.importing.GradleModuleImporter; +import org.jetbrains.plugins.gradle.model.GradleLibraryDependency; +import org.jetbrains.plugins.gradle.model.GradleLibraryDependencyId; +import org.jetbrains.plugins.gradle.model.GradleModule; +import org.jetbrains.plugins.gradle.sync.GradleProjectStructureHelper; +import org.jetbrains.plugins.gradle.ui.GradleDataKeys; +import org.jetbrains.plugins.gradle.ui.GradleProjectStructureNode; +import org.jetbrains.plugins.gradle.util.GradleBundle; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +/** + * Imports target {@link GradleTextAttributes#GRADLE_LOCAL_CHANGE 'gradle local'} entity to the current intellij project. + *

+ * Not thread-safe. + * + * @author Denis Zhdanov + * @since 2/7/12 10:32 AM + */ +public class GradleImportEntityAction extends AnAction { + + private static final Logger LOG = Logger.getInstance("#" + GradleImportEntityAction.class.getName()); + + public GradleImportEntityAction() { + getTemplatePresentation().setText(GradleBundle.message("gradle.action.import.entity.text")); + getTemplatePresentation().setDescription(GradleBundle.message("gradle.action.import.entity.description")); + } + + @Override + public void update(AnActionEvent e) { + final Collection> nodes = getInterestedNodes(e.getDataContext()); + e.getPresentation().setEnabled(!nodes.isEmpty()); + } + + @Override + public void actionPerformed(AnActionEvent e) { + final Project project = PlatformDataKeys.PROJECT.getData(e.getDataContext()); + if (project == null) { + LOG.warn("Can't import gradle-local entities. Reason: target intellij project is undefined"); + return; + } + + final Collection> nodes = getInterestedNodes(e.getDataContext()); + + // We need to import not only the selected nodes but their gradle-local parents as well. + List> nodesToImport = new ArrayList>(); + for (GradleProjectStructureNode node : nodes) { + collectHierarchyToImport(node, nodesToImport); + } + + GradleProjectStructureHelper projectStructureHelper = project.getComponent(GradleProjectStructureHelper.class); + GradleModuleImporter moduleImporter = ServiceManager.getService(GradleModuleImporter.class); + GradleModuleDependencyImporter dependencyImporter = ServiceManager.getService(GradleModuleDependencyImporter.class); + + for (GradleProjectStructureNode node : nodesToImport) { + switch (node.getType()) { + case MODULE: + final GradleModule gradleModule = projectStructureHelper.findGradleModuleByName(node.getDescriptor().getName()); + if (gradleModule != null) { + moduleImporter.importModule(gradleModule, project); + } + break; + case LIBRARY_DEPENDENCY: + final Object element = node.getDescriptor().getElement(); + if (!(element instanceof GradleLibraryDependencyId)) { + break; + } + GradleLibraryDependencyId id = (GradleLibraryDependencyId)element; + final GradleLibraryDependency dependency = projectStructureHelper.findLibraryDependency(id); + final Module intellijModule = projectStructureHelper.findIntellijModuleByName(id.getModuleName()); + if (dependency != null && intellijModule != null) { + dependencyImporter.importDependency(dependency, intellijModule); + } + break; + default: // Do nothing + } + } + } + + /** + * When particular gradle-local node is asked to be imported we need to import its gradle-local parent hierarchy as well. + *

+ * This method allows to collect all parent nodes of the given nodes that should be imported as well. + *

+ * Note: those nodes are added to the given collection starting from the topmost one. + * + * @param node target node + * @param storage target nodes storage + */ + private static void collectHierarchyToImport(@Nullable GradleProjectStructureNode node, + @NotNull Collection> storage) + { + if (node == null || node.getDescriptor().getAttributes() != GradleTextAttributes.GRADLE_LOCAL_CHANGE) { + return; + } + collectHierarchyToImport(node.getParent(), storage); + storage.add(node); + } + + @NotNull + private static Collection> getInterestedNodes(@NotNull DataContext context) { + final Collection> selectedNodes = GradleDataKeys.SYNC_TREE_NODE.getData(context); + if (selectedNodes == null) { + return Collections.emptyList(); + } + List> result = new ArrayList>(); + for (GradleProjectStructureNode node : selectedNodes) { + if (node.getDescriptor().getAttributes() == GradleTextAttributes.GRADLE_LOCAL_CHANGE) { + result.add(node); + } + } + return result; + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/PlatformFacade.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/PlatformFacade.java index 529fea913a98..bc8c9302a5a3 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/PlatformFacade.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/PlatformFacade.java @@ -3,6 +3,7 @@ package org.jetbrains.plugins.gradle.diff; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.OrderEntry; +import com.intellij.openapi.roots.libraries.LibraryTable; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.pom.java.LanguageLevel; import org.jetbrains.annotations.NotNull; @@ -28,6 +29,9 @@ import java.util.Collection; */ public interface PlatformFacade { + @NotNull + LibraryTable getProjectLibraryTable(@NotNull Project project); + @NotNull LanguageLevel getLanguageLevel(@NotNull Project project); diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/PlatformFacadeImpl.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/PlatformFacadeImpl.java index b4a82429a169..84ae46eda4a4 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/PlatformFacadeImpl.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/PlatformFacadeImpl.java @@ -8,6 +8,8 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.LanguageLevelProjectExtension; import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.roots.OrderEntry; +import com.intellij.openapi.roots.impl.libraries.ProjectLibraryTable; +import com.intellij.openapi.roots.libraries.LibraryTable; import com.intellij.openapi.util.IconLoader; import com.intellij.openapi.vfs.JarFileSystem; import com.intellij.openapi.vfs.VirtualFile; @@ -24,6 +26,12 @@ import java.util.Collection; */ public class PlatformFacadeImpl implements PlatformFacade { + @NotNull + @Override + public LibraryTable getProjectLibraryTable(@NotNull Project project) { + return ProjectLibraryTable.getInstance(project); + } + @NotNull @Override public LanguageLevel getLanguageLevel(@NotNull Project project) { diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleContentRootImporter.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleContentRootImporter.java new file mode 100644 index 000000000000..16e0baf4b191 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleContentRootImporter.java @@ -0,0 +1,16 @@ +package org.jetbrains.plugins.gradle.importing; + +import com.intellij.openapi.module.Module; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.gradle.model.GradleContentRoot; + +/** + * @author Denis Zhdanov + * @since 2/7/12 3:20 PM + */ +public class GradleContentRootImporter { + + public void importContentRoots(@NotNull Iterable contentRoots, @NotNull Module module) { + // TODO den implement + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleModuleDependencyImporter.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleModuleDependencyImporter.java new file mode 100644 index 000000000000..ada5a3a5d389 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleModuleDependencyImporter.java @@ -0,0 +1,152 @@ +package org.jetbrains.plugins.gradle.importing; + +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.roots.*; +import com.intellij.openapi.roots.libraries.Library; +import com.intellij.openapi.roots.libraries.LibraryTable; +import com.intellij.openapi.vfs.JarFileSystem; +import com.intellij.openapi.vfs.LocalFileSystem; +import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.gradle.diff.PlatformFacade; +import org.jetbrains.plugins.gradle.model.*; +import org.jetbrains.plugins.gradle.util.GradleLog; + +import java.io.File; +import java.util.*; + +/** + * @author Denis Zhdanov + * @since 2/7/12 3:23 PM + */ +public class GradleModuleDependencyImporter { + + private static final Map LIBRARY_ROOT_MAPPINGS + = new EnumMap(LibraryPathType.class); + static { + LIBRARY_ROOT_MAPPINGS.put(LibraryPathType.BINARY, OrderRootType.CLASSES); + LIBRARY_ROOT_MAPPINGS.put(LibraryPathType.SOURCE, OrderRootType.SOURCES); + LIBRARY_ROOT_MAPPINGS.put(LibraryPathType.DOC, JavadocOrderRootType.getInstance()); + assert LibraryPathType.values().length == LIBRARY_ROOT_MAPPINGS.size(); + } + + @NotNull private final PlatformFacade myPlatformFacade; + + public GradleModuleDependencyImporter(@NotNull PlatformFacade platformFacade) { + myPlatformFacade = platformFacade; + } + + public void importDependency(@NotNull GradleDependency dependency, @NotNull Module module) { + importDependencies(Collections.singleton(dependency), module); + } + + public void importDependencies(@NotNull Iterable dependencies, @NotNull Module module) { + final List moduleDependencies = new ArrayList(); + final List libraryDependencies = new ArrayList(); + GradleEntityVisitor visitor = new GradleEntityVisitorAdapter() { + @Override + public void visit(@NotNull GradleModuleDependency dependency) { + moduleDependencies.add(dependency); + } + + @Override + public void visit(@NotNull GradleLibraryDependency dependency) { + libraryDependencies.add(dependency); + } + }; + for (GradleDependency dependency : dependencies) { + dependency.invite(visitor); + } + importLibraryDependencies(libraryDependencies, module); + importModuleDependencies(moduleDependencies, module); + } + + public void importModuleDependencies(@NotNull Iterable dependencies, @NotNull Module module) { + // TODO den implement + } + + public void importLibraryDependencies(@NotNull final Iterable dependencies, @NotNull final Module module) { + // TODO den make non-EDT agnostic + final LibraryTable libraryTable = myPlatformFacade.getProjectLibraryTable(module.getProject()); + final Map gradle2intellij = new HashMap(); + final Set librariesToCreate = new HashSet(); + for (final GradleLibraryDependency dependency : dependencies) { + // Try to find existing library in project libraries. + Library library = libraryTable.getLibraryByName(dependency.getName()); + if (library == null) { + librariesToCreate.add(dependency.getTarget()); + } + else { + gradle2intellij.put(dependency.getTarget(), library); + } + } + + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + // Create all necessary libraries. + if (!librariesToCreate.isEmpty()) { + final LibraryTable.ModifiableModel projectLibraryModel = libraryTable.getModifiableModel(); + try { + for (GradleLibrary library : librariesToCreate) { + final Library intellijLibrary = projectLibraryModel.createLibrary(library.getName()); + gradle2intellij.put(library, intellijLibrary); + final Library.ModifiableModel libraryModel = intellijLibrary.getModifiableModel(); + try { + registerPaths(library, libraryModel); + } + finally { + libraryModel.commit(); + } + } + } + finally { + projectLibraryModel.commit(); + } + } + + // Register library dependencies. + ModuleRootManager moduleRootManager = ModuleRootManager.getInstance(module); + final ModifiableRootModel moduleRootModel = moduleRootManager.getModifiableModel(); + try { + for (GradleLibraryDependency dependency : dependencies) { + LibraryOrderEntry orderEntry = moduleRootModel.addLibraryEntry(gradle2intellij.get(dependency.getTarget())); + orderEntry.setExported(dependency.isExported()); + orderEntry.setScope(dependency.getScope()); + } + } + finally { + moduleRootModel.commit(); + } + // TODO den refresh gradle project tree + } + }); + } + + private static void registerPaths(@NotNull GradleLibrary gradleLibrary, @NotNull Library.ModifiableModel model) { + for (LibraryPathType pathType : LibraryPathType.values()) { + for (String path : gradleLibrary.getPaths(pathType)) { + VirtualFile virtualFile = LocalFileSystem.getInstance().findFileByIoFile(new File(path)); + if (virtualFile == null) { + GradleLog.LOG.warn(String.format("Can't find %s of the library '%s' at path '%s'", pathType, gradleLibrary.getName(), path)); + continue; + } + if (virtualFile.isDirectory()) { + model.addRoot(virtualFile, LIBRARY_ROOT_MAPPINGS.get(pathType)); + } + else { + VirtualFile jarRoot = JarFileSystem.getInstance().getJarRootForLocalFile(virtualFile); + if (jarRoot == null) { + GradleLog.LOG.warn(String.format( + "Can't parse contents of the jar file at path '%s' for the library '%s''", path, gradleLibrary.getName() + )); + continue; + } + model.addRoot(jarRoot, LIBRARY_ROOT_MAPPINGS.get(pathType)); + } + } + } + } + +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleModuleImporter.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleModuleImporter.java new file mode 100644 index 000000000000..7ee3a1eac434 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleModuleImporter.java @@ -0,0 +1,125 @@ +package org.jetbrains.plugins.gradle.importing; + +import com.intellij.openapi.application.Application; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleManager; +import com.intellij.openapi.module.StdModuleTypes; +import com.intellij.openapi.project.Project; +import com.intellij.util.Alarm; +import com.intellij.util.containers.hash.HashMap; +import com.intellij.util.ui.UIUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.gradle.model.GradleModule; +import org.jetbrains.plugins.gradle.util.GradleLog; + +import java.io.File; +import java.util.Collections; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +/** + * Encapsulates functionality of importing gradle module to the intellij project. + * + * @author Denis Zhdanov + * @since 2/7/12 2:49 PM + */ +public class GradleModuleImporter { + + /** + * We can't modify project modules (add/remove) until it's initialised, so, we delay that activity. Current constant + * holds number of milliseconds to wait between 'after project initialisation' processing attempts. + */ + private static final int PROJECT_INITIALISATION_DELAY_MS = (int)TimeUnit.SECONDS.toMillis(1); + + private final Alarm myAlarm = new Alarm(Alarm.ThreadToUse.SHARED_THREAD); + + @NotNull private final GradleContentRootImporter myContentRootImporter; + @NotNull private final GradleModuleDependencyImporter myDependencyImporter; + + public GradleModuleImporter(@NotNull GradleContentRootImporter contentRootImporter, + @NotNull GradleModuleDependencyImporter dependencyImporter) + { + myContentRootImporter = contentRootImporter; + myDependencyImporter = dependencyImporter; + } + + public void importModule(@NotNull GradleModule module, @NotNull Project project) { + importModules(Collections.singleton(module), project, false); + } + + public void importModules(@NotNull final Iterable modules, @NotNull final Project project, final boolean recursive) { + if (!project.isInitialized()) { + myAlarm.addRequest(new ImportModulesTask(project, modules, recursive), PROJECT_INITIALISATION_DELAY_MS); + return; + } + UIUtil.invokeLaterIfNeeded(new Runnable() { + @Override + public void run() { + removeExistingModulesConfigs(modules); + Application application = ApplicationManager.getApplication(); + final Map moduleMappings = new HashMap(); + application.runWriteAction(new Runnable() { + @Override + public void run() { + final ModuleManager moduleManager = ModuleManager.getInstance(project); + for (GradleModule module : modules) { + final Module created = moduleManager.newModule(module.getModuleFilePath(), StdModuleTypes.JAVA); + moduleMappings.put(module, created); + } + } + }); + if (!recursive) { + return; + } + for (GradleModule gradleModule : modules) { + final Module intellijModule = moduleMappings.get(gradleModule); + myContentRootImporter.importContentRoots(gradleModule.getContentRoots(), intellijModule); + myDependencyImporter.importDependencies(gradleModule.getDependencies(), intellijModule); + } + } + }); + } + + private static void removeExistingModulesConfigs(@NotNull Iterable modules) { + for (GradleModule module : modules) { + // Remove existing '*.iml' file if necessary. + final String moduleFilePath = module.getModuleFilePath(); + File file = new File(moduleFilePath); + if (file.isFile()) { + boolean success = file.delete(); + if (!success) { + GradleLog.LOG.warn("Can't remove existing module file at '" + moduleFilePath + "'"); + } + } + } + } + + private class ImportModulesTask implements Runnable { + + private final Project myProject; + private final Iterable myModules; + private final boolean myRecursive; + + ImportModulesTask(@NotNull Project project, @NotNull Iterable modules, boolean recursive) { + myProject = project; + myModules = modules; + myRecursive = recursive; + } + + @Override + public void run() { + myAlarm.cancelAllRequests(); + if (!myProject.isInitialized()) { + myAlarm.addRequest( + new ImportModulesTask(myProject, myModules, myRecursive), + PROJECT_INITIALISATION_DELAY_MS + ); + return; + } + + importModules(myModules, myProject, myRecursive); + } + } + +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleModulesImporter.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleModulesImporter.java index 0753b80c148f..5a6de37bf1d0 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleModulesImporter.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleModulesImporter.java @@ -40,6 +40,7 @@ import java.util.concurrent.TimeUnit; * @author Denis Zhdanov * @since 8/26/11 10:01 AM */ +// TODO den remove public class GradleModulesImporter { private static final Map LIBRARY_ROOT_MAPPINGS diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/wizard/adjust/GradleAdjustImportSettingsStep.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/wizard/adjust/GradleAdjustImportSettingsStep.java index 4d6fb05e6100..f9bd8e7d8f6f 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/wizard/adjust/GradleAdjustImportSettingsStep.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/wizard/adjust/GradleAdjustImportSettingsStep.java @@ -260,7 +260,7 @@ public class GradleAdjustImportSettingsStep extends AbstractImportFromGradleWiza // We build tree node, its settings control and map them altogether. The only trick here is that nodes can reuse the same // settings control (e.g. more than one node may have the same library as a dependency, so, library dependency node for // every control will use the same settings control). - GradleProjectStructureNode result = new GradleProjectStructureNode(myFactory.buildDescriptor(entity)); + GradleProjectStructureNode result = new GradleProjectStructureNode(myFactory.buildDescriptor(entity), GradleEntityType.SYNTHETIC); Pair> pair = processed.get(entity); if (pair == null) { String cardName = String.valueOf(counter); diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/wizard/adjust/GradleProjectStructureFactory.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/wizard/adjust/GradleProjectStructureFactory.java index 95989623ae96..fef410ddc578 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/wizard/adjust/GradleProjectStructureFactory.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/wizard/adjust/GradleProjectStructureFactory.java @@ -138,7 +138,7 @@ public class GradleProjectStructureFactory { return; } for (GradleProjectStructureNode node : treeNodes) { - node.getDescriptor().setText(evt.getNewValue().toString()); + node.getDescriptor().setName(evt.getNewValue().toString()); model.nodeChanged(node); } } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/model/GradleDependency.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/GradleDependency.java index cc6558f17909..a20b775c2a06 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/model/GradleDependency.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/GradleDependency.java @@ -15,6 +15,9 @@ public interface GradleDependency extends GradleEntity { @NotNull DependencyScope getScope(); + + @NotNull + GradleModule getOwnerModule(); @NotNull GradleDependency clone(@NotNull GradleEntityCloneContext context); diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/model/GradleEntityType.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/GradleEntityType.java new file mode 100644 index 000000000000..948903544476 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/GradleEntityType.java @@ -0,0 +1,9 @@ +package org.jetbrains.plugins.gradle.model; + +/** + * @author Denis Zhdanov + * @since 2/7/12 11:18 AM + */ +public enum GradleEntityType { + PROJECT, MODULE, LIBRARY_DEPENDENCY, SYNTHETIC +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesPanel.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesPanel.java index 72c5e424f100..ee03292076d2 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesPanel.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesPanel.java @@ -1,20 +1,27 @@ package org.jetbrains.plugins.gradle.sync; +import com.intellij.ide.ui.customization.CustomizationUtil; import com.intellij.openapi.project.Project; import com.intellij.ui.treeStructure.Tree; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.UIUtil; +import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.gradle.config.GradleToolWindowPanel; import org.jetbrains.plugins.gradle.diff.GradleProjectStructureChange; import org.jetbrains.plugins.gradle.diff.PlatformFacade; +import org.jetbrains.plugins.gradle.ui.GradleDataKeys; +import org.jetbrains.plugins.gradle.ui.GradleProjectStructureNode; import org.jetbrains.plugins.gradle.util.GradleConstants; import javax.swing.*; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.TreePath; import java.awt.*; +import java.util.ArrayList; import java.util.Collection; +import java.util.List; /** * UI control for showing difference between the gradle and intellij project structure. @@ -24,6 +31,7 @@ import java.util.Collection; */ public class GradleProjectStructureChangesPanel extends GradleToolWindowPanel { + private Tree myTree; private GradleProjectStructureTreeModel myTreeModel; private JPanel myContent; @@ -52,14 +60,16 @@ public class GradleProjectStructureChangesPanel extends GradleToolWindowPanel { private void init() { myContent = new JPanel(new GridBagLayout()); myTreeModel = new GradleProjectStructureTreeModel(getProject(), getProjectFacade(), getProjectStructureHelper()); - Tree tree = new Tree(myTreeModel); - applyInitialAppearance(tree, (DefaultMutableTreeNode)myTreeModel.getRoot()); + myTree = new Tree(myTreeModel); + applyInitialAppearance(myTree, (DefaultMutableTreeNode)myTreeModel.getRoot()); GridBagConstraints constraints = new GridBagConstraints(); constraints.fill = GridBagConstraints.BOTH; constraints.weightx = constraints.weighty = 1; - myContent.add(tree, constraints); - myContent.setBackground(tree.getBackground()); + myContent.add(myTree, constraints); + myContent.setBackground(myTree.getBackground()); + + CustomizationUtil.installPopupHandler(myTree, GradleConstants.ACTION_GROUP_SYNC_TREE, GradleConstants.SYNC_TREE_PLACE); } @NotNull @@ -75,6 +85,25 @@ public class GradleProjectStructureChangesPanel extends GradleToolWindowPanel { int i = 1; } + @Nullable + @Override + public Object getData(@NonNls String dataId) { + if (GradleDataKeys.SYNC_TREE_NODE.is(dataId)) { + TreePath[] paths = myTree.getSelectionPaths(); + if (paths == null) { + return null; + } + List> result = new ArrayList>(); + for (TreePath path : paths) { + result.add((GradleProjectStructureNode)path.getLastPathComponent()); + } + return result; + } + else { + return super.getData(dataId); + } + } + private static void applyInitialAppearance(@NotNull Tree tree, @NotNull DefaultMutableTreeNode node) { if (node.getUserObject() == GradleProjectStructureTreeModel.DEPENDENCIES_NODE_DESCRIPTOR) { tree.expandPath(new TreePath(node.getPath())); diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureHelper.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureHelper.java index 96b2c8d8ece0..8fba1b558e74 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureHelper.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureHelper.java @@ -8,6 +8,7 @@ import com.intellij.openapi.roots.OrderEntry; import com.intellij.openapi.roots.RootPolicy; import com.intellij.openapi.util.Ref; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.gradle.diff.PlatformFacade; import org.jetbrains.plugins.gradle.model.*; @@ -37,20 +38,20 @@ public class GradleProjectStructureHelper extends AbstractProjectComponent { * false otherwise */ public boolean isIntellijLibraryDependencyExist(@NotNull final GradleLibraryDependencyId id) { - for (Module module : myFacade.getModules(myProject)) { - if (!id.getModuleName().equals(module.getName())) { - continue; + final Module module = findIntellijModuleByName(id.getModuleName()); + if (module == null) { + return false; + } + + RootPolicy visitor = new RootPolicy() { + @Override + public Boolean visitLibraryOrderEntry(LibraryOrderEntry libraryOrderEntry, Boolean value) { + return id.getLibraryName().equals(libraryOrderEntry.getLibraryName()); } - RootPolicy visitor = new RootPolicy() { - @Override - public Boolean visitLibraryOrderEntry(LibraryOrderEntry libraryOrderEntry, Boolean value) { - return id.getLibraryName().equals(libraryOrderEntry.getLibraryName()); - } - }; - for (OrderEntry entry : myFacade.getOrderEntries(module)) { - if (entry.accept(visitor, false)) { - return true; - } + }; + for (OrderEntry entry : myFacade.getOrderEntries(module)) { + if (entry.accept(visitor, false)) { + return true; } } return false; @@ -64,29 +65,55 @@ public class GradleProjectStructureHelper extends AbstractProjectComponent { * false otherwise */ public boolean isGradleLibraryDependencyExist(@NotNull final GradleLibraryDependencyId id) { + return findLibraryDependency(id) != null; + } + + @Nullable + public Module findIntellijModuleByName(@NotNull String name) { + for (Module module : myFacade.getModules(myProject)) { + if (name.equals(module.getName())) { + return module; + } + } + return null; + } + + @Nullable + public GradleModule findGradleModuleByName(@NotNull String name) { final GradleProject project = myModel.getGradleProject(); if (project == null) { - return false; + return null; } - final Ref matched = new Ref(); + for (GradleModule module : project.getModules()) { + if (name.equals(module.getName())) { + return module; + } + } + return null; + } + + @Nullable + public GradleLibraryDependency findLibraryDependency(@NotNull final GradleLibraryDependencyId id) { + final GradleModule module = findGradleModuleByName(id.getModuleName()); + if (module == null) { + return null; + } + final Ref ref = new Ref(); GradleEntityVisitor visitor = new GradleEntityVisitorAdapter() { @Override public void visit(@NotNull GradleLibraryDependency dependency) { - matched.set(id.getLibraryName().equals(dependency.getName())); - } - }; - for (GradleModule module : project.getModules()) { - if (!id.getModuleName().equals(module.getName())) { - continue; - } - for (GradleDependency dependency : module.getDependencies()) { - dependency.invite(visitor); - if (matched.get()) { - return true; + if (id.getLibraryName().equals(dependency.getName())) { + ref.set(dependency); } } - return false; + }; + for (GradleDependency dependency : module.getDependencies()) { + dependency.invite(visitor); + final GradleLibraryDependency result = ref.get(); + if (result != null) { + return result; + } } - return false; + return null; } } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureTreeModel.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureTreeModel.java index 9374826609b2..9a32b95e3338 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureTreeModel.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureTreeModel.java @@ -10,6 +10,7 @@ import com.intellij.util.containers.hash.HashMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.gradle.config.GradleTextAttributes; import org.jetbrains.plugins.gradle.diff.*; +import org.jetbrains.plugins.gradle.model.GradleEntityType; import org.jetbrains.plugins.gradle.model.GradleLibraryDependencyId; import org.jetbrains.plugins.gradle.ui.GradleIcons; import org.jetbrains.plugins.gradle.ui.GradleProjectStructureNode; @@ -77,7 +78,8 @@ public class GradleProjectStructureTreeModel extends DefaultTreeModel { myModuleDependencies.clear(); myModules.clear(); - GradleProjectStructureNode root = buildNode(getProject(), getProject().getName(), myPlatformFacade.getProjectIcon()); + GradleProjectStructureNode root + = buildNode(getProject(), GradleEntityType.PROJECT, getProject().getName(), myPlatformFacade.getProjectIcon()); final Collection modules = myPlatformFacade.getModules(getProject()); RootPolicy policy = new RootPolicy() { @Override @@ -86,7 +88,7 @@ public class GradleProjectStructureTreeModel extends DefaultTreeModel { } }; for (Module module : modules) { - final GradleProjectStructureNode moduleNode = buildNode(module.getName(), GradleIcons.MODULE_ICON); + final GradleProjectStructureNode moduleNode = buildNode(GradleEntityType.MODULE, module.getName(), GradleIcons.MODULE_ICON); myModules.put(module.getName(), moduleNode); // Assuming that module names are unique. List libraryDependencies = new ArrayList(); for (OrderEntry orderEntry : myPlatformFacade.getOrderEntries(module)) { @@ -100,7 +102,7 @@ public class GradleProjectStructureTreeModel extends DefaultTreeModel { if (id == null) { continue; } - dependenciesNode.add(buildNode(id, id.getLibraryName(), GradleIcons.LIB_ICON)); + dependenciesNode.add(buildNode(id, GradleEntityType.LIBRARY_DEPENDENCY, id.getLibraryName(), GradleIcons.LIB_ICON)); } moduleNode.add(dependenciesNode); } @@ -119,14 +121,18 @@ public class GradleProjectStructureTreeModel extends DefaultTreeModel { return new GradleProjectStructureNodeDescriptor(entity, name, icon); } - private static GradleProjectStructureNode buildNode(@NotNull String name, @NotNull Icon icon) { - return buildNode(name, name, icon); + private static GradleProjectStructureNode buildNode(@NotNull GradleEntityType type, @NotNull String name, @NotNull Icon icon) { + return buildNode(name, type, name, icon); } - private static GradleProjectStructureNode buildNode(@NotNull T entity, @NotNull String name, @NotNull Icon icon) { - return new GradleProjectStructureNode(buildDescriptor(entity, name, icon)); + private static GradleProjectStructureNode buildNode(@NotNull T entity, + @NotNull GradleEntityType type, + @NotNull String name, + @NotNull Icon icon) + { + return new GradleProjectStructureNode(buildDescriptor(entity, name, icon), type); } - + private GradleProjectStructureNode getDependenciesNode(@NotNull String moduleName) { final GradleProjectStructureNode cached = myModuleDependencies.get(moduleName); if (cached != null) { @@ -134,11 +140,11 @@ public class GradleProjectStructureTreeModel extends DefaultTreeModel { } GradleProjectStructureNode moduleNode = myModules.get(moduleName); if (moduleNode == null) { - moduleNode = buildNode(moduleName, GradleIcons.MODULE_ICON); + moduleNode = buildNode(GradleEntityType.MODULE, moduleName, GradleIcons.MODULE_ICON); myModules.put(moduleName, moduleNode); } - GradleProjectStructureNode result = new GradleProjectStructureNode(DEPENDENCIES_NODE_DESCRIPTOR); + GradleProjectStructureNode result = new GradleProjectStructureNode(DEPENDENCIES_NODE_DESCRIPTOR, GradleEntityType.SYNTHETIC); moduleNode.add(result); myModuleDependencies.put(moduleName, result); @@ -184,7 +190,8 @@ public class GradleProjectStructureTreeModel extends DefaultTreeModel { return; } } - GradleProjectStructureNode newNode = buildNode(id, id.getLibraryName(), GradleIcons.LIB_ICON); + GradleProjectStructureNode newNode + = buildNode(id, GradleEntityType.LIBRARY_DEPENDENCY, id.getLibraryName(), GradleIcons.LIB_ICON); newNode.getDescriptor().setAttributes(attributes); dependenciesNode.add(newNode); nodeStructureChanged(dependenciesNode); diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/ui/GradleDataKeys.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/ui/GradleDataKeys.java new file mode 100644 index 000000000000..134db91a6efc --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/ui/GradleDataKeys.java @@ -0,0 +1,18 @@ +package org.jetbrains.plugins.gradle.ui; + +import com.intellij.openapi.actionSystem.DataKey; + +import java.util.Collection; + +/** + * @author Denis Zhdanov + * @since 2/7/12 11:19 AM + */ +public class GradleDataKeys { + + /** Key for obtaining currently selected nodes at the gradle 'sync project structure' tree. */ + public static final DataKey>> SYNC_TREE_NODE = DataKey.create("gradle.sync.tree.node"); + + private GradleDataKeys() { + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/ui/GradleProjectStructureNode.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/ui/GradleProjectStructureNode.java index 2551a3162a2e..e009d1a88b19 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/ui/GradleProjectStructureNode.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/ui/GradleProjectStructureNode.java @@ -3,6 +3,7 @@ package org.jetbrains.plugins.gradle.ui; import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.gradle.config.GradleTextAttributes; import org.jetbrains.plugins.gradle.diff.GradleProjectStructureChange; +import org.jetbrains.plugins.gradle.model.GradleEntityType; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.MutableTreeNode; @@ -16,11 +17,14 @@ import java.util.*; public class GradleProjectStructureNode extends DefaultMutableTreeNode implements Iterable> { private final Set myConflictChanges = new HashSet(); - private final GradleProjectStructureNodeDescriptor myDescriptor; - public GradleProjectStructureNode(@NotNull GradleProjectStructureNodeDescriptor descriptor) { + private final GradleProjectStructureNodeDescriptor myDescriptor; + private final GradleEntityType myType; + + public GradleProjectStructureNode(@NotNull GradleProjectStructureNodeDescriptor descriptor, @NotNull GradleEntityType type) { super(descriptor); myDescriptor = descriptor; + myType = type; } @NotNull @@ -28,6 +32,11 @@ public class GradleProjectStructureNode extends DefaultMutableTreeNode implem return myDescriptor; } + @NotNull + public GradleEntityType getType() { + return myType; + } + @Override public GradleProjectStructureNode getChildAt(int index) { return (GradleProjectStructureNode)super.getChildAt(index); @@ -41,10 +50,10 @@ public class GradleProjectStructureNode extends DefaultMutableTreeNode implem @Override public void add(MutableTreeNode newChild) { GradleProjectStructureNode child = (GradleProjectStructureNode)newChild; - final String newText = child.getDescriptor().getText(); + final String newName = child.getDescriptor().getName(); for (int i = 0; i < getChildCount(); i++) { GradleProjectStructureNode node = getChildAt(i); - if (newText.compareTo(node.getDescriptor().getText()) < 0) { + if (newName.compareTo(node.getDescriptor().getName()) < 0) { insert(newChild, i); return; } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/ui/GradleProjectStructureNodeDescriptor.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/ui/GradleProjectStructureNodeDescriptor.java index 6fe8baa490f0..031e5077fa2e 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/ui/GradleProjectStructureNodeDescriptor.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/ui/GradleProjectStructureNodeDescriptor.java @@ -46,12 +46,7 @@ public class GradleProjectStructureNodeDescriptor extends PresentableNodeDesc return myData; } - @NotNull - public String getText() { - return myName; - } - - public void setText(@NotNull String name) { + public void setName(@NotNull String name) { myName = name; } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleConstants.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleConstants.java index 49f441744592..acc24a256475 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleConstants.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleConstants.java @@ -1,10 +1,7 @@ package org.jetbrains.plugins.gradle.util; -import com.intellij.openapi.util.IconLoader; import org.jetbrains.annotations.NonNls; -import javax.swing.*; - /** * Holds object representation of icons used at the Gradle plugin. * @@ -13,9 +10,13 @@ import javax.swing.*; */ public class GradleConstants { - @NonNls public static final String EXTENSION = "gradle"; - @NonNls public static final String DEFAULT_SCRIPT_NAME = "build.gradle"; + @NonNls public static final String EXTENSION = "gradle"; + @NonNls public static final String DEFAULT_SCRIPT_NAME = "build.gradle"; + @NonNls public static final String TOOL_WINDOW_TOOLBAR_PLACE = "GRADLE_SYNC_CHANGES_TOOLBAR"; + @NonNls public static final String SYNC_TREE_PLACE = "GRADLE_SYNC_TREE_PLACE"; + + @NonNls public static final String ACTION_GROUP_SYNC_TREE = "Gradle.SyncTreeGroup"; private GradleConstants() { } diff --git a/plugins/junit_rt/src/com/intellij/junit4/JUnit4TestResultsSender.java b/plugins/junit_rt/src/com/intellij/junit4/JUnit4TestResultsSender.java index c427e578a122..bfb590a18a02 100644 --- a/plugins/junit_rt/src/com/intellij/junit4/JUnit4TestResultsSender.java +++ b/plugins/junit_rt/src/com/intellij/junit4/JUnit4TestResultsSender.java @@ -99,10 +99,10 @@ public class JUnit4TestResultsSender extends RunListener { Matcher matcher = Pattern.compile("\nExpected: (.*)\n\\s*got: (.*)", Pattern.DOTALL).matcher(message); if (!matcher.matches()) { - matcher = Pattern.compile("expected same:<(.*)> was not:<(.*)>", Pattern.DOTALL).matcher(message); + matcher = Pattern.compile("\\s*expected same:<(.*)> was not:<(.*)>", Pattern.DOTALL).matcher(message); } if (!matcher.matches()) { - matcher = Pattern.compile("expected:<(.*)> but was:<(.*)>", Pattern.DOTALL).matcher(message); + matcher = Pattern.compile("\\s*expected:<(.*)> but was:<(.*)>", Pattern.DOTALL).matcher(message); } if (!matcher.matches()) { matcher = Pattern.compile("\nExpected: \"(.*)\"\n\\s*but: was \"(.*)\"", Pattern.DOTALL).matcher(message); diff --git a/plugins/svn4idea/lib/svnkit-javahl.jar b/plugins/svn4idea/lib/svnkit-javahl.jar index 01ecf37bb43c..d7eb592d28f6 100644 Binary files a/plugins/svn4idea/lib/svnkit-javahl.jar and b/plugins/svn4idea/lib/svnkit-javahl.jar differ diff --git a/plugins/svn4idea/lib/svnkit-javahl16.zip b/plugins/svn4idea/lib/svnkit-javahl16.zip index fbe729c06c7e..00c4886fd4f6 100644 Binary files a/plugins/svn4idea/lib/svnkit-javahl16.zip and b/plugins/svn4idea/lib/svnkit-javahl16.zip differ diff --git a/plugins/svn4idea/lib/svnkit.jar b/plugins/svn4idea/lib/svnkit.jar index 37d118155a25..0087d15e25dd 100644 Binary files a/plugins/svn4idea/lib/svnkit.jar and b/plugins/svn4idea/lib/svnkit.jar differ diff --git a/plugins/svn4idea/lib/svnkitsrc.zip b/plugins/svn4idea/lib/svnkitsrc.zip index 0d48d754443e..1bc2a1918888 100644 Binary files a/plugins/svn4idea/lib/svnkitsrc.zip and b/plugins/svn4idea/lib/svnkitsrc.zip differ diff --git a/plugins/swing-designer/src/META-INF/plugin.xml b/plugins/swing-designer/src/META-INF/plugin.xml index 7159d40459dc..48e8a04476fe 100644 --- a/plugins/swing-designer/src/META-INF/plugin.xml +++ b/plugins/swing-designer/src/META-INF/plugin.xml @@ -5,5 +5,5 @@ messages.SwingDesignerBundle com.intellij.java-i18n com.intellij.properties - com.intellij.uiDesigner + com.intellij.ui-designer-new diff --git a/plugins/swing-designer/swing-designer.iml b/plugins/swing-designer/swing-designer.iml index d77bfc09c235..8c4b67627078 100644 --- a/plugins/swing-designer/swing-designer.iml +++ b/plugins/swing-designer/swing-designer.iml @@ -20,7 +20,7 @@ - + diff --git a/plugins/ui-designer/ui-designer-new/src/META-INF/plugin.xml b/plugins/ui-designer/ui-designer-new/src/META-INF/plugin.xml new file mode 100644 index 000000000000..1f86521a5c16 --- /dev/null +++ b/plugins/ui-designer/ui-designer-new/src/META-INF/plugin.xml @@ -0,0 +1,8 @@ + + UI Designer + com.intellij.ui-designer-new + JetBrains + messages.UIDesignerBundle + com.intellij.java-i18n + com.intellij.properties + diff --git a/plugins/ui-designer/ui-designer-new/src/messages/UIDesignerBundle.properties b/plugins/ui-designer/ui-designer-new/src/messages/UIDesignerBundle.properties new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/plugins/ui-designer/ui-designer-new/ui-designer-new.iml b/plugins/ui-designer/ui-designer-new/ui-designer-new.iml new file mode 100644 index 000000000000..9503087bf8c9 --- /dev/null +++ b/plugins/ui-designer/ui-designer-new/ui-designer-new.iml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + +