From aa90b40661edfeeba201e0a542c69c93310fe07c Mon Sep 17 00:00:00 2001 From: Alexander Lobas Date: Tue, 10 Apr 2012 17:49:02 +0400 Subject: [PATCH 01/30] LinearLayout --- .../layout/LayoutMarginOperation.java | 95 ++++++++------ .../layout/LayoutWeightOperation.java | 122 ++++++++++++++++++ .../designSurface/layout/ResizeOperation.java | 3 + .../model/layout/RadLinearLayout.java | 32 +++-- 4 files changed, 207 insertions(+), 45 deletions(-) create mode 100644 plugins/android-designer/src/com/intellij/android/designer/designSurface/layout/LayoutWeightOperation.java diff --git a/plugins/android-designer/src/com/intellij/android/designer/designSurface/layout/LayoutMarginOperation.java b/plugins/android-designer/src/com/intellij/android/designer/designSurface/layout/LayoutMarginOperation.java index 56d34b91ed82..65413cf7b733 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/designSurface/layout/LayoutMarginOperation.java +++ b/plugins/android-designer/src/com/intellij/android/designer/designSurface/layout/LayoutMarginOperation.java @@ -43,11 +43,11 @@ import java.util.List; public class LayoutMarginOperation implements EditOperation { public static final String TYPE = "layout_margin"; - private final OperationContext myContext; - private RadViewComponent myComponent; - private RectangleFeedback myFeedback; - private TextFeedback myTextFeedback; - private Rectangle myMargins; + protected final OperationContext myContext; + protected RadViewComponent myComponent; + protected RectangleFeedback myFeedback; + protected TextFeedback myTextFeedback; + protected Rectangle myMargins; public LayoutMarginOperation(OperationContext context) { myContext = context; @@ -71,13 +71,17 @@ public class LayoutMarginOperation implements EditOperation { myTextFeedback.setBorder(new LineMarginBorder(0, 5, 3, 0)); layer.add(myTextFeedback); - myFeedback = new RectangleFeedback(Color.orange, 2); + myFeedback = new RectangleFeedback(getFeedbackColor(), 2); layer.add(myFeedback); layer.repaint(); } } + protected Color getFeedbackColor() { + return Color.orange; + } + @Override public void showFeedback() { createFeedback(); @@ -86,17 +90,20 @@ public class LayoutMarginOperation implements EditOperation { applyMargins(bounds, myMargins); myFeedback.setBounds(bounds); + myTextFeedback.clear(); + fillTextFeedback(); + myTextFeedback.locationTo(myContext.getLocation(), 15); + } + + protected void fillTextFeedback() { Point moveDelta = myContext.getMoveDelta(); Dimension sizeDelta = myContext.getSizeDelta(); int direction = myContext.getResizeDirection(); - myTextFeedback.clear(); - if (direction == Position.WEST) { // left myTextFeedback.append(Integer.toString(myMargins.x - moveDelta.x)); } else if (direction == Position.EAST) { // right - myTextFeedback.append(Integer.toString(myMargins.width + sizeDelta.width)); } else if (direction == Position.NORTH) { // top @@ -107,7 +114,6 @@ public class LayoutMarginOperation implements EditOperation { } myTextFeedback.dimension("dp"); - myTextFeedback.locationTo(myContext.getLocation(), 15); } @Override @@ -181,11 +187,42 @@ public class LayoutMarginOperation implements EditOperation { } } + ////////////////////////////////////////////////////////////////////////////////////////// + // + // ResizePoint + // + ////////////////////////////////////////////////////////////////////////////////////////// + private static final BasicStroke STROKE = new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 1, new float[]{1, 2}, 0); public static void points(ResizeSelectionDecorator decorator) { - decorator.addPoint(new ResizePoint() { + pointFeedback(decorator); + decorator.addPoint(new DirectionResizePoint(Color.orange, Color.black, Position.WEST, TYPE) { // left + @Override + protected Point getLocation(DecorationLayer layer, RadComponent component) { + Point location = super.getLocation(layer, component); + location.x -= ((RadViewComponent)component).getMargins().x; + return location; + } + }); + + pointRight(decorator, Color.orange, 0.25, TYPE); + + decorator.addPoint(new DirectionResizePoint(Color.orange, Color.black, Position.NORTH, TYPE) { // top + @Override + protected Point getLocation(DecorationLayer layer, RadComponent component) { + Point location = super.getLocation(layer, component); + location.y -= ((RadViewComponent)component).getMargins().y; + return location; + } + }); + + pointBottom(decorator, Color.orange, 0.25, TYPE); + } + + protected static void pointFeedback(ResizeSelectionDecorator decorator) { + decorator.addPoint(new ResizePoint() { @Override protected void paint(DecorationLayer layer, Graphics2D g, RadComponent component) { Rectangle bounds = component.getBounds(layer); @@ -216,44 +253,28 @@ public class LayoutMarginOperation implements EditOperation { return null; } }); + } - decorator.addPoint(new DirectionResizePoint(Color.orange, Color.black, Position.WEST, LayoutMarginOperation.TYPE) { // left + protected static void pointRight(ResizeSelectionDecorator decorator, Color color, double ySeparator, Object type) { + decorator.addPoint(new DirectionResizePoint(color, Color.black, Position.EAST, type) { @Override protected Point getLocation(DecorationLayer layer, RadComponent component) { Point location = super.getLocation(layer, component); - location.x -= ((RadViewComponent)component).getMargins().x; + location.x += ((RadViewComponent)component).getMargins().width; return location; } - }); + }.move(1, ySeparator)); + } - decorator - .addPoint(new DirectionResizePoint(Color.orange, Color.black, Position.EAST, LayoutMarginOperation.TYPE) { // right - @Override - protected Point getLocation(DecorationLayer layer, RadComponent component) { - Point location = super.getLocation(layer, component); - location.x += ((RadViewComponent)component).getMargins().width; - return location; - } - }.move(1, 0.25)); - - decorator.addPoint(new DirectionResizePoint(Color.orange, Color.black, Position.NORTH, LayoutMarginOperation.TYPE) { // top + protected static void pointBottom(ResizeSelectionDecorator decorator, Color color, double xSeparator, Object type) { + decorator.addPoint(new DirectionResizePoint(color, Color.black, Position.SOUTH, type) { @Override protected Point getLocation(DecorationLayer layer, RadComponent component) { Point location = super.getLocation(layer, component); - location.y -= ((RadViewComponent)component).getMargins().y; + location.y += ((RadViewComponent)component).getMargins().height; return location; } - }); - - decorator.addPoint( - new DirectionResizePoint(Color.orange, Color.black, Position.SOUTH, LayoutMarginOperation.TYPE) { // bottom - @Override - protected Point getLocation(DecorationLayer layer, RadComponent component) { - Point location = super.getLocation(layer, component); - location.y += ((RadViewComponent)component).getMargins().height; - return location; - } - }.move(0.25, 1)); + }.move(xSeparator, 1)); } private static void applyMargins(Rectangle bounds, Rectangle margins) { diff --git a/plugins/android-designer/src/com/intellij/android/designer/designSurface/layout/LayoutWeightOperation.java b/plugins/android-designer/src/com/intellij/android/designer/designSurface/layout/LayoutWeightOperation.java new file mode 100644 index 000000000000..a9eb2fca3a87 --- /dev/null +++ b/plugins/android-designer/src/com/intellij/android/designer/designSurface/layout/LayoutWeightOperation.java @@ -0,0 +1,122 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.android.designer.designSurface.layout; + +import com.intellij.designer.designSurface.OperationContext; +import com.intellij.designer.designSurface.selection.ResizeSelectionDecorator; +import com.intellij.designer.model.RadComponent; +import com.intellij.designer.utils.Position; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.psi.xml.XmlAttribute; + +import java.awt.*; +import java.text.DecimalFormat; + +/** + * @author Alexander Lobas + */ +public class LayoutWeightOperation extends LayoutMarginOperation { + public static final String TYPE = "layout_weight"; + + private float myWeight; + + public LayoutWeightOperation(OperationContext context) { + super(context); + } + + @Override + public void setComponent(RadComponent component) { + super.setComponent(component); + + try { + myWeight = Float.parseFloat(myComponent.getTag().getAttributeValue("android:layout_weight")); + } + catch (Throwable e) { + myWeight = 0; + } + } + + @Override + protected Color getFeedbackColor() { + return Color.cyan; + } + + @Override + protected void fillTextFeedback() { + Dimension sizeDelta = myContext.getSizeDelta(); + int direction = myContext.getResizeDirection(); + + if (direction == Position.EAST) { // right + myTextFeedback.append(getWeight(sizeDelta.width)); + } + else if (direction == Position.SOUTH) { // bottom + myTextFeedback.append(getWeight(sizeDelta.height)); + } + } + + private static final DecimalFormat FORMAT = new DecimalFormat("#.##"); + + private String getWeight(int value) { + double weight = myWeight + value / 100.0; + if (weight <= 0) { + return "0"; + } + return FORMAT.format(weight); + } + + @Override + public void execute() throws Exception { + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + Dimension sizeDelta = myContext.getSizeDelta(); + int direction = myContext.getResizeDirection(); + + if (direction == Position.EAST) { // right + setWeight(sizeDelta.width); + } + else if (direction == Position.SOUTH) { // bottom + setWeight(sizeDelta.height); + } + } + }); + } + + private void setWeight(int value) { + float weight = myWeight + value / 100f; + if (weight <= 0) { + XmlAttribute attribute = myComponent.getTag().getAttribute("android:layout_weight"); + if (attribute != null) { + attribute.delete(); + } + } + else { + myComponent.getTag().setAttribute("android:layout_weight", FORMAT.format(weight).replace(',', '.')); + } + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // + // ResizePoint + // + ////////////////////////////////////////////////////////////////////////////////////////// + + public static void point(ResizeSelectionDecorator decorator) { + pointFeedback(decorator); + pointRight(decorator, Color.cyan, 0.75, TYPE); + pointBottom(decorator, Color.cyan, 0.75, TYPE); + } +} \ No newline at end of file diff --git a/plugins/android-designer/src/com/intellij/android/designer/designSurface/layout/ResizeOperation.java b/plugins/android-designer/src/com/intellij/android/designer/designSurface/layout/ResizeOperation.java index d54861641b44..70af4bbc4c40 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/designSurface/layout/ResizeOperation.java +++ b/plugins/android-designer/src/com/intellij/android/designer/designSurface/layout/ResizeOperation.java @@ -209,6 +209,9 @@ public class ResizeOperation implements EditOperation { createFeedback(); myBounds = myContext.getTransformedRectangle(myComponent.getBounds(myContext.getArea().getFeedbackLayer())); + myBounds.width = Math.max(myBounds.width, 0); + myBounds.height = Math.max(myBounds.height, 0); + int direction = myContext.getResizeDirection(); if ((direction & Position.EAST) != 0) { diff --git a/plugins/android-designer/src/com/intellij/android/designer/model/layout/RadLinearLayout.java b/plugins/android-designer/src/com/intellij/android/designer/model/layout/RadLinearLayout.java index 6b3a8a8299f3..bd669b6484c0 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/model/layout/RadLinearLayout.java +++ b/plugins/android-designer/src/com/intellij/android/designer/model/layout/RadLinearLayout.java @@ -16,10 +16,7 @@ package com.intellij.android.designer.model.layout; import com.intellij.android.designer.designSurface.TreeDropToOperation; -import com.intellij.android.designer.designSurface.layout.FlowStaticDecorator; -import com.intellij.android.designer.designSurface.layout.LayoutMarginOperation; -import com.intellij.android.designer.designSurface.layout.LinearLayoutOperation; -import com.intellij.android.designer.designSurface.layout.ResizeOperation; +import com.intellij.android.designer.designSurface.layout.*; import com.intellij.android.designer.model.RadViewComponent; import com.intellij.android.designer.model.RadViewLayoutWithData; import com.intellij.designer.actions.AbstractComboBoxAction; @@ -82,6 +79,9 @@ public class RadLinearLayout extends RadViewLayoutWithData implements ILayoutDec else if (context.is(LayoutMarginOperation.TYPE)) { return new LayoutMarginOperation(context); } + else if (context.is(LayoutWeightOperation.TYPE)) { + return new LayoutWeightOperation(context); + } return null; } @@ -115,6 +115,8 @@ public class RadLinearLayout extends RadViewLayoutWithData implements ILayoutDec } } + private static final int POINTS_SIZE = 16; + @Override public ComponentDecorator getChildSelectionDecorator(RadComponent component, List selection) { if (mySelectionDecorator == null) { @@ -125,18 +127,31 @@ public class RadLinearLayout extends RadViewLayoutWithData implements ILayoutDec boolean horizontal = isHorizontal(); Pair gravity = Gravity.getSides(component); int direction = ((DirectionResizePoint)point).getDirection(); + Rectangle bounds = component.getBounds(); + boolean goodWidth = bounds.width >= POINTS_SIZE; + boolean goodHeight = bounds.height >= POINTS_SIZE; if (direction == Position.WEST) { // left - return horizontal || gravity.first != Gravity.right; + return (horizontal || gravity.first != Gravity.right) && goodHeight; } if (direction == Position.EAST) { // right - return horizontal || gravity.first != Gravity.left; + return (horizontal || gravity.first != Gravity.left) && goodHeight; } if (direction == Position.NORTH) { // top - return !horizontal || gravity.second != Gravity.bottom; + return (!horizontal || gravity.second != Gravity.bottom) && goodWidth; } if (direction == Position.SOUTH) { // bottom - return !horizontal || gravity.second != Gravity.top; + return (!horizontal || gravity.second != Gravity.top) && goodWidth; + } + } + if (point.getType() == LayoutWeightOperation.TYPE) { + int direction = ((DirectionResizePoint)point).getDirection(); + + if (direction == Position.EAST) { // right + return isHorizontal() && component.getBounds().height >= POINTS_SIZE; + } + if (direction == Position.SOUTH) { // bottom + return !isHorizontal() && component.getBounds().width >= POINTS_SIZE; } } return true; @@ -147,6 +162,7 @@ public class RadLinearLayout extends RadViewLayoutWithData implements ILayoutDec mySelectionDecorator.clear(); if (selection.size() == 1) { LayoutMarginOperation.points(mySelectionDecorator); + LayoutWeightOperation.point(mySelectionDecorator); } ResizeOperation.points(mySelectionDecorator); From 548e6e5f60117a62a3154a91dd8d0ca83444a315 Mon Sep 17 00:00:00 2001 From: Sergey Evdokimov Date: Tue, 10 Apr 2012 17:49:19 +0400 Subject: [PATCH 02/30] IDEA-83620 Find usages does not work for methods like 'encodeAsHTML()' --- .../groovy/codeInsight/GroovyTargetElementEvaluator.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInsight/GroovyTargetElementEvaluator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInsight/GroovyTargetElementEvaluator.java index 01500a678208..a81a55bb942f 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInsight/GroovyTargetElementEvaluator.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInsight/GroovyTargetElementEvaluator.java @@ -17,6 +17,7 @@ package org.jetbrains.plugins.groovy.codeInsight; import com.intellij.codeInsight.TargetElementEvaluator; +import com.intellij.openapi.util.Key; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiMethod; import com.intellij.psi.PsiReference; @@ -34,6 +35,9 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrRenameableLightEle * @author Maxim.Medvedev */ public class GroovyTargetElementEvaluator implements TargetElementEvaluator { + + public static final Key NAVIGATION_ELEMENT_IS_NOT_TARGET = Key.create("GroovyTargetElementEvaluator.DONT_FOLLOW_NAVIGATION_ELEMENT"); + public boolean includeSelfInGotoImplementation(@NotNull PsiElement element) { return false; } @@ -79,7 +83,8 @@ public class GroovyTargetElementEvaluator implements TargetElementEvaluator { @Nullable public static PsiElement correctSearchTargets(@Nullable PsiElement target) { - if (target != null && !(target instanceof GrAccessorMethod) && !target.isPhysical()) { + if (target != null && !(target instanceof GrAccessorMethod) && !target.isPhysical() + && target.getUserData(NAVIGATION_ELEMENT_IS_NOT_TARGET) == null) { return target.getNavigationElement(); } return target; From f3ecdf7de2d6ea03b26ee1fe302255b28af2ee0d Mon Sep 17 00:00:00 2001 From: Alexander Lobas Date: Tue, 10 Apr 2012 18:01:56 +0400 Subject: [PATCH 03/30] Properties --- .../designer/propertyTable/renderers/ResourceRenderer.java | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/android-designer/src/com/intellij/android/designer/propertyTable/renderers/ResourceRenderer.java b/plugins/android-designer/src/com/intellij/android/designer/propertyTable/renderers/ResourceRenderer.java index 4288b7a7da4b..79b1365d0568 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/propertyTable/renderers/ResourceRenderer.java +++ b/plugins/android-designer/src/com/intellij/android/designer/propertyTable/renderers/ResourceRenderer.java @@ -60,6 +60,7 @@ public class ResourceRenderer implements PropertyRenderer { String value = (String)object; if (myBooleanRenderer != null && (StringUtil.isEmpty(value) || "false".equals(value) || "true".equals(value))) { + myBooleanRenderer.setText(value); return myBooleanRenderer.getComponent(component, "true".equals(value), selected, hasFocus); } From e37ea5d533281bf62baa4be1ed81c2943d1abf66 Mon Sep 17 00:00:00 2001 From: Eugene Kudelevsky Date: Tue, 10 Apr 2012 17:11:56 +0400 Subject: [PATCH 04/30] android: take into account the order of value resources in aapt compilation --- .../AndroidResourcesLineMarkerProvider.java | 6 +- .../android/compiler/AndroidCompileUtil.java | 5 +- .../compiler/ResourceNamesValidityState.java | 179 ++++++++++++++++-- .../LocalResourceManager.java | 9 +- .../resourceManagers/ResourceManager.java | 32 ++-- 5 files changed, 192 insertions(+), 39 deletions(-) diff --git a/plugins/android/src/org/jetbrains/android/AndroidResourcesLineMarkerProvider.java b/plugins/android/src/org/jetbrains/android/AndroidResourcesLineMarkerProvider.java index a0c9497b5c38..021fd3e43888 100644 --- a/plugins/android/src/org/jetbrains/android/AndroidResourcesLineMarkerProvider.java +++ b/plugins/android/src/org/jetbrains/android/AndroidResourcesLineMarkerProvider.java @@ -24,6 +24,7 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.IconLoader; +import com.intellij.openapi.util.Pair; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; @@ -174,8 +175,9 @@ public class AndroidResourcesLineMarkerProvider implements LineMarkerProvider { private static Map> buildLocalResourceMap(@NotNull Project project, @NotNull final LocalResourceManager resManager) { final Map> result = new HashMap>(); - Collection resourceFiles = resManager.getResourceElements(); - for (Resources res : resourceFiles) { + List> resourceFiles = resManager.getResourceElements(); + for (Pair pair : resourceFiles) { + final Resources res = pair.getFirst(); for (ResourceType valueResourceType : AndroidResourceUtil.VALUE_RESOURCE_TYPES) { for (ResourceElement valueResource : AndroidResourceUtil.getValueResourcesFromElement(valueResourceType.getName(), res)) { addResource(valueResourceType.getName(), valueResource, result); diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidCompileUtil.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidCompileUtil.java index fec52eded011..8a469cede0f7 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/AndroidCompileUtil.java +++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidCompileUtil.java @@ -729,8 +729,9 @@ public class AndroidCompileUtil { } } - for (final Resources resources : manager.getResourceElements()) { - waitForSmartMode(project); + for (final Pair pair : manager.getResourceElements()) { + final Resources resources = pair.getFirst(); + waitForSmartMode(project); ApplicationManager.getApplication().runReadAction(new Runnable() { @Override diff --git a/plugins/android/src/org/jetbrains/android/compiler/ResourceNamesValidityState.java b/plugins/android/src/org/jetbrains/android/compiler/ResourceNamesValidityState.java index 6947ffd6e52b..0b1e8f17b196 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/ResourceNamesValidityState.java +++ b/plugins/android/src/org/jetbrains/android/compiler/ResourceNamesValidityState.java @@ -1,29 +1,44 @@ package org.jetbrains.android.compiler; +import com.android.resources.ResourceType; import com.android.sdklib.IAndroidTarget; import com.intellij.openapi.compiler.ValidityState; import com.intellij.openapi.module.Module; +import com.intellij.openapi.roots.ContentIterator; +import com.intellij.openapi.roots.impl.FileIndexImplUtil; +import com.intellij.openapi.util.Pair; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.util.containers.HashSet; +import com.intellij.openapi.vfs.VirtualFileFilter; +import com.intellij.util.ArrayUtil; +import com.intellij.util.containers.HashMap; +import org.jetbrains.android.dom.resources.ResourceElement; +import org.jetbrains.android.dom.resources.Resources; import org.jetbrains.android.facet.AndroidFacet; import org.jetbrains.android.facet.AndroidRootUtil; +import org.jetbrains.android.resourceManagers.LocalResourceManager; +import org.jetbrains.android.resourceManagers.ResourceManager; import org.jetbrains.android.sdk.AndroidPlatform; +import org.jetbrains.android.util.AndroidResourceUtil; import org.jetbrains.android.util.ResourceEntry; import org.jetbrains.annotations.NotNull; import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; -import java.util.Set; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; /** * @author Eugene.Kudelevsky */ public class ResourceNamesValidityState implements ValidityState { - private final Set myResourcesSet = new HashSet(); + private final Map myResources = new HashMap(); + private final String myAndroidTargetHashString; private final long myManifestTimestamp; - + public ResourceNamesValidityState(@NotNull Module module) { final AndroidFacet facet = AndroidFacet.getInstance(module); assert facet != null; @@ -35,19 +50,83 @@ public class ResourceNamesValidityState implements ValidityState { final VirtualFile manifestFile = AndroidRootUtil.getManifestFile(facet); myManifestTimestamp = manifestFile != null ? manifestFile.getModificationStamp() : -1; - AndroidCompileUtil.collectAllResources(facet, myResourcesSet); + final LocalResourceManager manager = facet.getLocalResourceManager(); + + for (final Pair pair : manager.getResourceElements()) { + final Resources resources = pair.getFirst(); + final VirtualFile file = pair.getSecond(); + + for (final ResourceType resType : AndroidResourceUtil.VALUE_RESOURCE_TYPES) { + addValueResources(file, resType, AndroidResourceUtil.getValueResourcesFromElement(resType.getName(), resources), myResources); + } + addValueResources(file, ResourceType.ATTR, resources.getAttrs(), myResources); + addValueResources(file, ResourceType.DECLARE_STYLEABLE, resources.getDeclareStyleables(), myResources); + } + + for (final VirtualFile subdir : manager.getResourceSubdirs(null)) { + final String subdirName = subdir.getName(); + final int index = subdirName.indexOf('-'); + final String typeName = index >= 0 ? subdirName.substring(0, index) : subdirName; + final ResourceType type = ResourceType.getEnum(typeName); + final boolean idProvidingResource = type != null && ArrayUtil.find(ResourceManager.ID_PROVIDING_RESOURCE_TYPES, type) >= 0; + + FileIndexImplUtil.iterateRecursively(subdir, VirtualFileFilter.ALL, new ContentIterator() { + @Override + public boolean processFile(VirtualFile fileOrDir) { + if (!fileOrDir.isDirectory()) { + MyResourceFileData data = myResources.get(fileOrDir.getPath()); + if (data == null) { + data = new MyResourceFileData(); + myResources.put(fileOrDir.getPath(), data); + } + + if (idProvidingResource) { + data.setTimestamp(fileOrDir.getTimeStamp()); + } + } + return true; + } + }); + } } - + + private static void addValueResources(VirtualFile file, + ResourceType resType, + Collection resourceElements, + Map result) { + for (ResourceElement element : resourceElements) { + final String name = element.getName().getValue(); + + if (name != null) { + MyResourceFileData data = result.get(file.getPath()); + if (data == null) { + data = new MyResourceFileData(); + result.put(file.getPath(), data); + } + data.addValueResource(new ResourceEntry(resType.getName(), name)); + } + } + } + public ResourceNamesValidityState(@NotNull DataInput in) throws IOException { myAndroidTargetHashString = in.readUTF(); myManifestTimestamp = in.readLong(); - + final int resourcesCount = in.readInt(); - + for (int i = 0; i < resourcesCount; i++) { - final String type = in.readUTF(); - final String name = in.readUTF(); - myResourcesSet.add(new ResourceEntry(type, name)); + final String filePath = in.readUTF(); + + final int valueResourcesCount = in.readInt(); + final List valueResources = new ArrayList(valueResourcesCount); + + for (int j = 0; j < valueResourcesCount; j++) { + final String resType = in.readUTF(); + final String resName = in.readUTF(); + valueResources.add(new ResourceEntry(resType, resName)); + } + final long fileTimestamp = in.readLong(); + myResources.put(filePath, new MyResourceFileData(valueResources, fileTimestamp)); } } @@ -56,24 +135,86 @@ public class ResourceNamesValidityState implements ValidityState { if (!(otherState instanceof ResourceNamesValidityState)) { return false; } - + final ResourceNamesValidityState other = (ResourceNamesValidityState)otherState; return other.myAndroidTargetHashString.equals(myAndroidTargetHashString) && other.myManifestTimestamp == myManifestTimestamp && - other.myResourcesSet.equals(myResourcesSet); + other.myResources.equals(myResources); } @Override public void save(DataOutput out) throws IOException { out.writeUTF(myAndroidTargetHashString); out.writeLong(myManifestTimestamp); - - out.writeInt(myResourcesSet.size()); - - for (ResourceEntry resourceEntry : myResourcesSet) { - out.writeUTF(resourceEntry.getType()); - out.writeUTF(resourceEntry.getName()); + + out.writeInt(myResources.size()); + + for (Map.Entry entry : myResources.entrySet()) { + out.writeUTF(entry.getKey()); + + final MyResourceFileData data = entry.getValue(); + final List valueResources = data.getValueResources(); + out.writeInt(valueResources.size()); + + for (ResourceEntry resource : valueResources) { + out.writeUTF(resource.getType()); + out.writeUTF(resource.getName()); + } + out.writeLong(data.getTimestamp()); + } + } + + private static class MyResourceFileData { + // order matters because of id assigning in R.java + private final List myValueResources; + + private long myTimestamp; + + MyResourceFileData() { + this(new ArrayList(), 0); + } + + private MyResourceFileData(@NotNull List valueResources, long timestamp) { + myValueResources = valueResources; + myTimestamp = timestamp; + } + + @NotNull + List getValueResources() { + return myValueResources; + } + + long getTimestamp() { + return myTimestamp; + } + + public void setTimestamp(long timestamp) { + myTimestamp = timestamp; + } + + public void addValueResource(@NotNull ResourceEntry entry) { + myValueResources.add(entry); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + MyResourceFileData data = (MyResourceFileData)o; + + if (myTimestamp != data.myTimestamp) return false; + if (!myValueResources.equals(data.myValueResources)) return false; + + return true; + } + + @Override + public int hashCode() { + int result = myValueResources.hashCode(); + result = 31 * result + (int)(myTimestamp ^ (myTimestamp >>> 32)); + return result; } } } diff --git a/plugins/android/src/org/jetbrains/android/resourceManagers/LocalResourceManager.java b/plugins/android/src/org/jetbrains/android/resourceManagers/LocalResourceManager.java index 8ee3f3974bf7..16cd938f0d43 100644 --- a/plugins/android/src/org/jetbrains/android/resourceManagers/LocalResourceManager.java +++ b/plugins/android/src/org/jetbrains/android/resourceManagers/LocalResourceManager.java @@ -24,6 +24,7 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.util.Pair; import com.intellij.openapi.vfs.ReadonlyStatusHandler; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; @@ -96,7 +97,7 @@ public class LocalResourceManager extends ResourceManager { return AndroidRootUtil.getResourceDir(getFacet()); } - public List getResourceElements() { + public List> getResourceElements() { return getResourceElements(null); } @@ -200,7 +201,8 @@ public class LocalResourceManager extends ResourceManager { @NotNull public List findAttrs(@NotNull String name) { List list = new ArrayList(); - for (Resources res : getResourceElements()) { + for (Pair pair : getResourceElements()) { + final Resources res = pair.getFirst(); for (Attr attr : res.getAttrs()) { if (name.equals(attr.getName().getValue())) { list.add(attr); @@ -219,7 +221,8 @@ public class LocalResourceManager extends ResourceManager { public List findStyleables(@NotNull String name) { List list = new ArrayList(); - for (Resources res : getResourceElements()) { + for (Pair pair : getResourceElements()) { + final Resources res = pair.getFirst(); for (DeclareStyleable styleable : res.getDeclareStyleables()) { if (name.equals(styleable.getName().getValue())) { list.add(styleable); diff --git a/plugins/android/src/org/jetbrains/android/resourceManagers/ResourceManager.java b/plugins/android/src/org/jetbrains/android/resourceManagers/ResourceManager.java index 0220bfeed1c7..dbdd4a6b5d9f 100644 --- a/plugins/android/src/org/jetbrains/android/resourceManagers/ResourceManager.java +++ b/plugins/android/src/org/jetbrains/android/resourceManagers/ResourceManager.java @@ -17,11 +17,11 @@ package org.jetbrains.android.resourceManagers; import com.android.resources.ResourceType; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Computable; +import com.intellij.openapi.util.Pair; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; @@ -53,7 +53,9 @@ import static java.util.Collections.addAll; * @author coyote */ public abstract class ResourceManager { - private static final Logger LOG = Logger.getInstance("#org.jetbrains.android.resourceManagers.LocalResourceManager"); + public static final ResourceType[] ID_PROVIDING_RESOURCE_TYPES = new ResourceType[] { + ResourceType.LAYOUT, ResourceType.MENU + }; protected final Module myModule; protected final AndroidFacet myFacet; @@ -130,17 +132,19 @@ public abstract class ResourceManager { return findResourceFiles(resType, null, true); } - protected List getResourceElements(@Nullable Set files) { + protected List> getResourceElements(@Nullable Set files) { return getRootDomElements(Resources.class, files); } - private List getRootDomElements(@NotNull Class elementType, - @Nullable Set files) { - final List result = new ArrayList(); + private List> getRootDomElements(@NotNull Class elementType, + @Nullable Set files) { + final List> result = new ArrayList>(); for (VirtualFile file : getAllValueResourceFiles()) { if ((files == null || files.contains(file)) && file.isValid()) { - T element = AndroidUtils.loadDomElement(myModule, file, elementType); - if (element != null) result.add(element); + final T element = AndroidUtils.loadDomElement(myModule, file, elementType); + if (element != null) { + result.add(new Pair(element, file)); + } } } return result; @@ -162,8 +166,9 @@ public abstract class ResourceManager { protected List getValueResources(@NotNull final String resourceType, @Nullable Set files) { final List result = new ArrayList(); - Collection resourceFiles = getResourceElements(files); - for (final Resources resources : resourceFiles) { + List> resourceFiles = getResourceElements(files); + for (final Pair pair : resourceFiles) { + final Resources resources = pair.getFirst(); ApplicationManager.getApplication().runReadAction(new Runnable() { @Override public void run() { @@ -337,10 +342,11 @@ public abstract class ResourceManager { } @NotNull - private List getResourceSubdirsToSearchIds() { + public List getResourceSubdirsToSearchIds() { final List resSubdirs = new ArrayList(); - resSubdirs.addAll(getResourceSubdirs(ResourceType.LAYOUT.getName())); - resSubdirs.addAll(getResourceSubdirs(ResourceType.MENU.getName())); + for (ResourceType type : ID_PROVIDING_RESOURCE_TYPES) { + resSubdirs.addAll(getResourceSubdirs(type.getName())); + } return resSubdirs; } From 1cdd00975f7fb2502e0b2632c9f47167a286e9c7 Mon Sep 17 00:00:00 2001 From: Eugene Kudelevsky Date: Tue, 10 Apr 2012 18:30:21 +0400 Subject: [PATCH 05/30] EA-33561 fix assertion --- .../codeInsight/completion/XmlTagInsertHandler.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/xml/impl/src/com/intellij/codeInsight/completion/XmlTagInsertHandler.java b/xml/impl/src/com/intellij/codeInsight/completion/XmlTagInsertHandler.java index 0ad958e47c7c..3fc28e1d7f66 100644 --- a/xml/impl/src/com/intellij/codeInsight/completion/XmlTagInsertHandler.java +++ b/xml/impl/src/com/intellij/codeInsight/completion/XmlTagInsertHandler.java @@ -31,6 +31,7 @@ import com.intellij.codeInspection.ex.LocalInspectionToolWrapper; import com.intellij.codeInspection.htmlInspections.RequiredAttributesInspection; import com.intellij.lang.ASTNode; import com.intellij.openapi.command.WriteCommandAction; +import com.intellij.openapi.command.undo.UndoManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.RangeMarker; @@ -170,6 +171,12 @@ public class XmlTagInsertHandler implements InsertHandler { if (myAttrValueMarker == null) { return; } + + final UndoManager manager = UndoManager.getInstance(project); + if (manager.isUndoInProgress() || manager.isRedoInProgress()) { + return; + } + if (chooseAttributeName) { final int startOffset = myAttrValueMarker.getStartOffset(); final int endOffset = myAttrValueMarker.getEndOffset(); From 1127062c51fbd99514f8e22a4c610a320cc01dc3 Mon Sep 17 00:00:00 2001 From: Alexander Lobas Date: Tue, 10 Apr 2012 19:25:02 +0400 Subject: [PATCH 06/30] RadioGroup --- .../android/designer/icons/RadioGroup.png | Bin 0 -> 624 bytes .../model/layout/RadLinearLayout.java | 2 +- .../model/layout/RadRadioGroupLayout.java | 28 ++++++++++++++++++ .../designer/model/views-meta-model.xml | 23 ++++++++++++++ 4 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 plugins/android-designer/src/com/intellij/android/designer/icons/RadioGroup.png create mode 100644 plugins/android-designer/src/com/intellij/android/designer/model/layout/RadRadioGroupLayout.java diff --git a/plugins/android-designer/src/com/intellij/android/designer/icons/RadioGroup.png b/plugins/android-designer/src/com/intellij/android/designer/icons/RadioGroup.png new file mode 100644 index 0000000000000000000000000000000000000000..647d084b8804f01f5ce9756a5addd80e1f0c6e69 GIT binary patch literal 624 zcmV-$0+0QPP)!g@8r!^Yg`fdwbLO@856n|NnnA z7~ZpIk0nrH8W4ye*{%U}Wy;m7R}DdGz=A*lkNNZGdjJJgpS^xybmQp>|0l1W7=ZY5 z=g#$yLa!N9@qe&Q(%a>;WO;kR2 z?wo$ldHu%|A1MECKdJNN+3V}Z4<00B}?ML z0XSj8gw*@@?`wceZr$a$vF@bI$L7sW>)(8Sqj~MxH638!rUS!)wW6Xz5a^xkj~_p( z0M)7kz2XD*LT6`Zz`}(KU4SMlp1Xd)a?A0V@fU6$GXwEK;?t*34+N<*Ha2DjS$62q zAtR97=g*%t!3Go+70CkQG!NuokOT~$I(5nb7(TfdCr_U0YI1K0R3r!oCrX!00yKVDB2e)O&h*0va0| zqk(=60J;nm&rIkk5g71nwY9Z|Ktnj60000< KMNUMnLSTY<+alfo literal 0 HcmV?d00001 diff --git a/plugins/android-designer/src/com/intellij/android/designer/model/layout/RadLinearLayout.java b/plugins/android-designer/src/com/intellij/android/designer/model/layout/RadLinearLayout.java index bd669b6484c0..12cdc9fd9bb3 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/model/layout/RadLinearLayout.java +++ b/plugins/android-designer/src/com/intellij/android/designer/model/layout/RadLinearLayout.java @@ -61,7 +61,7 @@ public class RadLinearLayout extends RadViewLayoutWithData implements ILayoutDec return LAYOUT_PARAMS; } - private boolean isHorizontal() { + protected boolean isHorizontal() { return !"vertical".equals(((RadViewComponent)myContainer).getTag().getAttributeValue("android:orientation")); } diff --git a/plugins/android-designer/src/com/intellij/android/designer/model/layout/RadRadioGroupLayout.java b/plugins/android-designer/src/com/intellij/android/designer/model/layout/RadRadioGroupLayout.java new file mode 100644 index 000000000000..93689059da6f --- /dev/null +++ b/plugins/android-designer/src/com/intellij/android/designer/model/layout/RadRadioGroupLayout.java @@ -0,0 +1,28 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.android.designer.model.layout; + +import com.intellij.android.designer.model.RadViewComponent; + +/** + * @author Alexander Lobas + */ +public class RadRadioGroupLayout extends RadLinearLayout { + @Override + protected boolean isHorizontal() { + return "horizontal".equals(((RadViewComponent)myContainer).getTag().getAttributeValue("android:orientation")); + } +} \ No newline at end of file diff --git a/plugins/android-designer/src/com/intellij/android/designer/model/views-meta-model.xml b/plugins/android-designer/src/com/intellij/android/designer/model/views-meta-model.xml index a61e17996723..8d3146b8f3ac 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/model/views-meta-model.xml +++ b/plugins/android-designer/src/com/intellij/android/designer/model/views-meta-model.xml @@ -1010,6 +1010,28 @@ + + + + + + + + + + + + ]]> + + + + From a46ee901e26d929a59d28bf612ec151e508b8c8c Mon Sep 17 00:00:00 2001 From: Alexander Lobas Date: Tue, 10 Apr 2012 19:53:39 +0400 Subject: [PATCH 07/30] GestureOverlayView --- .../designer/icons/GestureOverlayView.png | Bin 0 -> 506 bytes .../designer/model/views-meta-model.xml | 65 ++++++++++++------ 2 files changed, 43 insertions(+), 22 deletions(-) create mode 100644 plugins/android-designer/src/com/intellij/android/designer/icons/GestureOverlayView.png diff --git a/plugins/android-designer/src/com/intellij/android/designer/icons/GestureOverlayView.png b/plugins/android-designer/src/com/intellij/android/designer/icons/GestureOverlayView.png new file mode 100644 index 0000000000000000000000000000000000000000..911876ed42f5e0b22643849f83141259af7c8c3c GIT binary patch literal 506 zcmVPx#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipM| z6doRtJ%0HB000?uMObu0Z*6U5Zgc=ca%Ew3Wn>_CX>@2HM@dakSAh-}00041Nkl z!&B~@ZIB+K>kg#C9pL*7!V38Jk72mgqm;Wg27te4oMGi-Fg z=!Ahf!c3@&kTA@b=p(*jL{^IF>+m?L$n{U+kGVa=?;qL w4fSuQ0#a9>EzUPlQ&T$3lQpi_YyR8$3*7m&+#Ubw#{d8T07*qoM6N<$f|X;@`2YX_ literal 0 HcmV?d00001 diff --git a/plugins/android-designer/src/com/intellij/android/designer/model/views-meta-model.xml b/plugins/android-designer/src/com/intellij/android/designer/model/views-meta-model.xml index 8d3146b8f3ac..d1f9fdf69833 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/model/views-meta-model.xml +++ b/plugins/android-designer/src/com/intellij/android/designer/model/views-meta-model.xml @@ -545,6 +545,26 @@ + + + + + + + + + + ]]> + + + + @@ -983,6 +1003,28 @@ + + + + + + + + + + + + ]]> + + + - - - - - - - - - - - - ]]> - - - + From 0656feab876d32f23e37779d7513668534473615 Mon Sep 17 00:00:00 2001 From: Alexander Kirillin Date: Tue, 10 Apr 2012 19:57:42 +0400 Subject: [PATCH 08/30] Grouping the error inspections --- .../codeInspection/LocalDummyInspectionTool.java | 2 ++ .../codeInspection/ex/InspectionProfileImpl.java | 9 +++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/platform/lang-api/src/com/intellij/codeInspection/LocalDummyInspectionTool.java b/platform/lang-api/src/com/intellij/codeInspection/LocalDummyInspectionTool.java index 4420a564c8dd..6a879de0be24 100644 --- a/platform/lang-api/src/com/intellij/codeInspection/LocalDummyInspectionTool.java +++ b/platform/lang-api/src/com/intellij/codeInspection/LocalDummyInspectionTool.java @@ -25,4 +25,6 @@ import org.jetbrains.annotations.NotNull; public abstract class LocalDummyInspectionTool extends LocalInspectionTool { @NotNull public abstract String getProblemGroup(); + + public abstract boolean shouldBeShownInInspectionProfile(); } diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionProfileImpl.java b/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionProfileImpl.java index b79c4338312d..42c07c5d5d43 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionProfileImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionProfileImpl.java @@ -19,10 +19,7 @@ package com.intellij.codeInspection.ex; import com.intellij.codeHighlighting.HighlightDisplayLevel; import com.intellij.codeInsight.daemon.HighlightDisplayKey; import com.intellij.codeInsight.daemon.InspectionProfileConvertor; -import com.intellij.codeInspection.InspectionProfile; -import com.intellij.codeInspection.InspectionProfileEntry; -import com.intellij.codeInspection.InspectionsBundle; -import com.intellij.codeInspection.ModifiableModel; +import com.intellij.codeInspection.*; import com.intellij.lang.annotation.HighlightSeverity; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; @@ -447,6 +444,10 @@ public class InspectionProfileImpl extends ProfileEx implements ModifiableModel, return false; } for (InspectionToolWrapper tool : tools) { + if (tool.getTool() instanceof LocalDummyInspectionTool && !((LocalDummyInspectionTool)tool.getTool()).shouldBeShownInInspectionProfile()) { + continue; + } + final String shortName = tool.getShortName(); HighlightDisplayKey key = HighlightDisplayKey.find(shortName); if (key == null) { From 0029d0e8b1e664fb47486bcf806270d492bf4e5e Mon Sep 17 00:00:00 2001 From: Sergey Evdokimov Date: Tue, 10 Apr 2012 20:02:37 +0400 Subject: [PATCH 09/30] Fix incorrect closing of zip file. --- .../idea/maven/utils/MavenArtifactUtil.java | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenArtifactUtil.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenArtifactUtil.java index a5870b0b9b9d..cba0ef493d4e 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenArtifactUtil.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenArtifactUtil.java @@ -125,20 +125,24 @@ public class MavenArtifactUtil { if (!file.exists()) return null; ZipFile jar = new ZipFile(file); - ZipEntry entry = jar.getEntry(MAVEN_PLUGIN_DESCRIPTOR); - - if (entry == null) { - MavenLog.LOG.info(IndicesBundle.message("repository.plugin.corrupt", file)); - return null; - } - - InputStream is = jar.getInputStream(entry); try { - byte[] bytes = FileUtil.loadBytes(is); - return new MavenPluginInfo(bytes); + ZipEntry entry = jar.getEntry(MAVEN_PLUGIN_DESCRIPTOR); + + if (entry == null) { + MavenLog.LOG.info(IndicesBundle.message("repository.plugin.corrupt", file)); + return null; + } + + InputStream is = jar.getInputStream(entry); + try { + byte[] bytes = FileUtil.loadBytes(is); + return new MavenPluginInfo(bytes); + } + finally { + is.close(); + } } finally { - is.close(); jar.close(); } } From 4e5c53992aa23e658561dbc6a4256f1f6529c363 Mon Sep 17 00:00:00 2001 From: Alexander Kirillin Date: Tue, 10 Apr 2012 20:36:59 +0400 Subject: [PATCH 10/30] Provided a way not to show some inspections in the inspections profile view --- .../com/intellij/codeInspection/ex/Descriptor.java | 14 ++++++++++++++ .../codeInspection/ex/InspectionProfileImpl.java | 4 ---- .../ui/SingleInspectionProfilePanel.java | 12 +++--------- 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ex/Descriptor.java b/platform/lang-impl/src/com/intellij/codeInspection/ex/Descriptor.java index 8f3d92c65875..49de7ada2039 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ex/Descriptor.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ex/Descriptor.java @@ -19,6 +19,7 @@ package com.intellij.codeInspection.ex; import com.intellij.codeHighlighting.HighlightDisplayLevel; import com.intellij.codeInsight.daemon.HighlightDisplayKey; import com.intellij.codeInspection.InspectionProfileEntry; +import com.intellij.codeInspection.LocalDummyInspectionTool; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.WriteExternalException; import com.intellij.psi.search.scope.packageSet.NamedScope; @@ -43,6 +44,7 @@ public class Descriptor { private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.ex.Descriptor"); private final ScopeToolState myState; private final InspectionProfileImpl myInspectionProfile; + private boolean myShouldBeShown = true; public Descriptor(ScopeToolState pair, InspectionProfileImpl inspectionProfile) { myState = pair; @@ -56,6 +58,14 @@ public class Descriptor { myEnabled = ((InspectionProfileImpl)inspectionProfile).isToolEnabled(myKey, pair.getScope()); myTool = tool; myScope = pair.getScope(); + + if (tool instanceof InspectionToolWrapper) { + InspectionProfileEntry inspection = ((InspectionToolWrapper)tool).getTool(); + + if (inspection instanceof LocalDummyInspectionTool) { + myShouldBeShown = ((LocalDummyInspectionTool)inspection).shouldBeShownInInspectionProfile(); + } + } } public boolean equals(Object obj) { @@ -80,6 +90,10 @@ public class Descriptor { myEnabled = enabled; } + public boolean shouldBeShown() { + return myShouldBeShown; + } + public String getText() { return myText; } diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionProfileImpl.java b/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionProfileImpl.java index 42c07c5d5d43..401c3110e0f1 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionProfileImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionProfileImpl.java @@ -444,10 +444,6 @@ public class InspectionProfileImpl extends ProfileEx implements ModifiableModel, return false; } for (InspectionToolWrapper tool : tools) { - if (tool.getTool() instanceof LocalDummyInspectionTool && !((LocalDummyInspectionTool)tool.getTool()).shouldBeShownInInspectionProfile()) { - continue; - } - final String shortName = tool.getShortName(); HighlightDisplayKey key = HighlightDisplayKey.find(shortName); if (key == null) { diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/SingleInspectionProfilePanel.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/SingleInspectionProfilePanel.java index c93c098d9f67..a8d9f80553ab 100644 --- a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/SingleInspectionProfilePanel.java +++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/SingleInspectionProfilePanel.java @@ -21,14 +21,8 @@ import com.intellij.codeHighlighting.HighlightDisplayLevel; import com.intellij.codeInsight.daemon.HighlightDisplayKey; import com.intellij.codeInsight.daemon.impl.HighlightInfoType; import com.intellij.codeInsight.daemon.impl.SeverityRegistrar; -import com.intellij.codeInspection.InspectionProfile; -import com.intellij.codeInspection.InspectionProfileEntry; -import com.intellij.codeInspection.InspectionsBundle; -import com.intellij.codeInspection.ModifiableModel; -import com.intellij.codeInspection.ex.Descriptor; -import com.intellij.codeInspection.ex.InspectionProfileImpl; -import com.intellij.codeInspection.ex.InspectionToolRegistrar; -import com.intellij.codeInspection.ex.ScopeToolState; +import com.intellij.codeInspection.*; +import com.intellij.codeInspection.ex.*; import com.intellij.ide.CommonActionsManager; import com.intellij.ide.DefaultTreeExpander; import com.intellij.ide.IdeTooltipManager; @@ -685,7 +679,7 @@ public class SingleInspectionProfilePanel extends JPanel { keySetList.addAll(SearchUtil.findKeys(filter, quated)); } for (Descriptor descriptor : myDescriptors.keySet()) { - if (filter != null && filter.length() > 0 && !isDescriptorAccepted(descriptor, filter, forceInclude, keySetList, quated)) { + if (!descriptor.shouldBeShown() || filter != null && filter.length() > 0 && !isDescriptorAccepted(descriptor, filter, forceInclude, keySetList, quated)) { continue; } final List nonDefaultTools = mySelectedProfile.getNonDefaultTools(descriptor.getKey().toString()); From 4448f982c690fcd10b4a1de8b37ec5cb6b10c1cd Mon Sep 17 00:00:00 2001 From: "kirill.safonov" Date: Thu, 5 Apr 2012 23:11:22 +0400 Subject: [PATCH 11/30] cosmetics --- plugins/git4idea/src/git4idea/ui/branch/GitBranchUiUtil.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/git4idea/src/git4idea/ui/branch/GitBranchUiUtil.java b/plugins/git4idea/src/git4idea/ui/branch/GitBranchUiUtil.java index cbb17dfc7a05..9f5341545ec4 100644 --- a/plugins/git4idea/src/git4idea/ui/branch/GitBranchUiUtil.java +++ b/plugins/git4idea/src/git4idea/ui/branch/GitBranchUiUtil.java @@ -77,7 +77,7 @@ public class GitBranchUiUtil { */ @Nullable public static String getNewBranchNameFromUser(@NotNull Project project, @NotNull Collection repositories, @NotNull String dialogTitle) { - return Messages.showInputDialog(project, "Enter the name of new branch", dialogTitle, Messages.getQuestionIcon(), "", + return Messages.showInputDialog(project, "Enter the name of new branch:", dialogTitle, Messages.getQuestionIcon(), "", GitNewBranchNameValidator.newInstance(repositories)); } From b7bbb9bcbfe05c544032621d36584f9be03a694b Mon Sep 17 00:00:00 2001 From: "kirill.safonov" Date: Tue, 10 Apr 2012 20:17:01 +0400 Subject: [PATCH 12/30] assert then refactoring processor does not throw exceptions (in test mode for now), see IDEA-84373 --- .../src/com/intellij/refactoring/BaseRefactoringProcessor.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/platform/lang-impl/src/com/intellij/refactoring/BaseRefactoringProcessor.java b/platform/lang-impl/src/com/intellij/refactoring/BaseRefactoringProcessor.java index b65b5e289ff8..f54194be7251 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/BaseRefactoringProcessor.java +++ b/platform/lang-impl/src/com/intellij/refactoring/BaseRefactoringProcessor.java @@ -173,6 +173,9 @@ public abstract class BaseRefactoringProcessor { } catch (Throwable e) { anyException.set(Boolean.TRUE); + if (ApplicationManager.getApplication().isUnitTestMode()) { + LOG.error(e); + } } } }; From 5d8433e70f03fa9bf01ed9fac490ece963181210 Mon Sep 17 00:00:00 2001 From: Maxim Shafirov Date: Tue, 10 Apr 2012 21:06:27 +0400 Subject: [PATCH 13/30] Looks like I've optimized some code, that we don't need at all. refElement.getPsiElement(), which is slow is only used to get it's file to check if it belongs to search scope. --- .../deadCode/UnusedDeclarationInspection.java | 9 +++++---- .../ex/GlobalInspectionContextImpl.java | 14 ++++++++------ .../DuplicatePropertyInspection.java | 2 +- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationInspection.java b/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationInspection.java index d68b2a10970d..5a00b75a97f0 100644 --- a/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationInspection.java @@ -343,11 +343,12 @@ public class UnusedDeclarationInspection extends FilteringInspectionTool { final RefElementImpl refElement = (RefElementImpl)refEntity; if (!refElement.isSuspicious()) return; - final PsiElement element = refElement.getElement(); - if (element == null) return; + PsiFile file = refElement.getContainingFile(); + + if (file == null) return; final boolean isSuppressed = refElement.isSuppressed(getShortName()); - if (!getContext().isToCheckMember(element, UnusedDeclarationInspection.this) || isSuppressed) { - if (isSuppressed || !scope.contains(element)) { + if (!getContext().isToCheckFile(file, UnusedDeclarationInspection.this) || isSuppressed) { + if (isSuppressed || !scope.contains(file)) { getEntryPointsManager().addEntryPoint(refElement, false); } return; diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextImpl.java b/platform/lang-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextImpl.java index 6f083ee1eff2..61633adec49c 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextImpl.java @@ -71,7 +71,10 @@ import org.jetbrains.annotations.Nullable; import java.io.File; import java.io.IOException; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; public class GlobalInspectionContextImpl extends UserDataHolderBase implements GlobalInspectionContext { private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.ex.GlobalInspectionContextImpl"); @@ -346,16 +349,15 @@ public class GlobalInspectionContextImpl extends UserDataHolderBase implements G public boolean isToCheckMember(@NotNull RefElement owner, InspectionProfileEntry tool) { - final PsiElement element = owner.getElement(); - return isToCheckMember(element, tool) && !((RefElementImpl)owner).isSuppressed(tool.getShortName()); + return isToCheckFile(((RefElementImpl)owner).getContainingFile(), tool) && !((RefElementImpl)owner).isSuppressed(tool.getShortName()); } - public boolean isToCheckMember(final PsiElement element, final InspectionProfileEntry tool) { + public boolean isToCheckFile(PsiFile file, final InspectionProfileEntry tool) { final Tools tools = myTools.get(tool.getShortName()); if (tools != null) { for (ScopeToolState state : tools.getTools()) { - final NamedScope namedScope = state.getScope(element.getProject()); - if (namedScope == null || namedScope.getValue().contains(element.getContainingFile(), getCurrentProfile().getProfileManager().getScopesManager())) { + final NamedScope namedScope = state.getScope(file.getProject()); + if (namedScope == null || namedScope.getValue().contains(file, getCurrentProfile().getProfileManager().getScopesManager())) { if (state.isEnabled()) { final InspectionProfileEntry entry = state.getTool(); if (entry instanceof InspectionToolWrapper && ((InspectionToolWrapper)entry).getTool() == tool) return true; diff --git a/plugins/properties/src/com/intellij/codeInspection/duplicatePropertyInspection/DuplicatePropertyInspection.java b/plugins/properties/src/com/intellij/codeInspection/duplicatePropertyInspection/DuplicatePropertyInspection.java index e46ee8da92c3..085a8a9f5e25 100644 --- a/plugins/properties/src/com/intellij/codeInspection/duplicatePropertyInspection/DuplicatePropertyInspection.java +++ b/plugins/properties/src/com/intellij/codeInspection/duplicatePropertyInspection/DuplicatePropertyInspection.java @@ -145,7 +145,7 @@ public class DuplicatePropertyInspection extends GlobalSimpleInspectionTool { private void checkFile(final PsiFile file, final InspectionManager manager, GlobalInspectionContextImpl context, final RefManager refManager, final ProblemDescriptionsProcessor processor) { if (!(file instanceof PropertiesFile)) return; - if (!context.isToCheckMember(file, this)) return; + if (!context.isToCheckFile(file, this)) return; final PsiSearchHelper searchHelper = PsiSearchHelper.SERVICE.getInstance(file.getProject()); final PropertiesFile propertiesFile = (PropertiesFile)file; final List properties = propertiesFile.getProperties(); From 5269a132b463f2a0cde9735b049cbc656cab140d Mon Sep 17 00:00:00 2001 From: Eugene Kudelevsky Date: Tue, 10 Apr 2012 20:08:36 +0400 Subject: [PATCH 14/30] IDEA-84320 do not pack Manifest class from library project into apk --- .../org/jetbrains/android/util/AndroidCommonUtils.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/plugins/android/common/src/org/jetbrains/android/util/AndroidCommonUtils.java b/plugins/android/common/src/org/jetbrains/android/util/AndroidCommonUtils.java index d6db275a63c7..f52243482aa3 100644 --- a/plugins/android/common/src/org/jetbrains/android/util/AndroidCommonUtils.java +++ b/plugins/android/common/src/org/jetbrains/android/util/AndroidCommonUtils.java @@ -52,7 +52,9 @@ public class AndroidCommonUtils { private static final Pattern WARNING_PATTERN = Pattern.compile(".*warning.*"); private static final Pattern ERROR_PATTERN = Pattern.compile(".*error.*"); private static final Pattern EXCEPTION_PATTERN = Pattern.compile(".*exception.*"); + private static Pattern R_PATTERN = Pattern.compile("R(\\$.*)?\\.class"); + private static Pattern MANIFEST_PATTERN = Pattern.compile("Manifest(\\$.*)?\\.class"); public static final Pattern COMPILER_MESSAGE_PATTERN = Pattern.compile("(.+):(\\d+):.+"); @@ -204,7 +206,7 @@ public class AndroidCommonUtils { private static void addFileToJar(@NotNull File file, @NotNull File rootDirectory, - boolean packRClasses, + boolean packRAndManifestClasses, @NotNull List> files) throws IOException { @@ -213,7 +215,7 @@ public class AndroidCommonUtils { if (children != null) { for (File child : children) { - addFileToJar(child, rootDirectory, packRClasses, files); + addFileToJar(child, rootDirectory, packRAndManifestClasses, files); } } } @@ -222,7 +224,9 @@ public class AndroidCommonUtils { return; } - if (!packRClasses && R_PATTERN.matcher(file.getName()).matches()) { + if (!packRAndManifestClasses && + (R_PATTERN.matcher(file.getName()).matches() || + MANIFEST_PATTERN.matcher(file.getName()).matches())) { return; } From dfe12bae587833908c885ce5aa981801ababdf09 Mon Sep 17 00:00:00 2001 From: "Gregory.Shrago" Date: Tue, 10 Apr 2012 21:27:37 +0400 Subject: [PATCH 15/30] IDEA-84044 null URL allowed in maven service configurable --- .../idea/maven/indices/MavenRepositoriesConfigurable.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/indices/MavenRepositoriesConfigurable.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/indices/MavenRepositoriesConfigurable.java index 5db81b975933..01bed087383f 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/indices/MavenRepositoriesConfigurable.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/indices/MavenRepositoriesConfigurable.java @@ -95,8 +95,10 @@ public class MavenRepositoriesConfigurable extends BaseConfigurable implements S final String value = (String)myServiceList.getSelectedValue(); final String text = Messages.showInputDialog("Artifactory or Nexus Service URL", "Add Service URL", Messages.getQuestionIcon(), value == null ? "http://" : value, new URLInputVaslidator()); - myModel.add(text); - myServiceList.setSelectedValue(text, true); + if (StringUtil.isNotEmpty(text)) { + myModel.add(text); + myServiceList.setSelectedValue(text, true); + } } }); myEditButton.addActionListener(new ActionListener() { @@ -105,7 +107,7 @@ public class MavenRepositoriesConfigurable extends BaseConfigurable implements S final int index = myServiceList.getSelectedIndex(); final String text = Messages.showInputDialog("Artifactory or Nexus Service URL", "Edit Service URL", Messages.getQuestionIcon(), myModel.getElementAt(index), new URLInputVaslidator()); - if (text != null) { + if (StringUtil.isNotEmpty(text)) { myModel.setElementAt(text, index); } } From 1f63ce03a5c351c664def212662f3b6cc38d0565 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Tue, 10 Apr 2012 17:06:08 +0200 Subject: [PATCH 16/30] To English dic. --- plugins/spellchecker/src/com/intellij/spellchecker/english.dic | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/spellchecker/src/com/intellij/spellchecker/english.dic b/plugins/spellchecker/src/com/intellij/spellchecker/english.dic index 788f32996ce3..b6d95a792ff3 100644 --- a/plugins/spellchecker/src/com/intellij/spellchecker/english.dic +++ b/plugins/spellchecker/src/com/intellij/spellchecker/english.dic @@ -133140,6 +133140,7 @@ unwarrantably unwarranted unwary unwashed +unwatch unwatchable unwatched unwavering From 8487c658e408b5fa6c94e7accea5948bc6b9f3fc Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Tue, 10 Apr 2012 17:00:21 +0200 Subject: [PATCH 17/30] Linux file watcher: do not dive into flat roots --- bin/linux/fsnotifier | Bin 22566 -> 22566 bytes bin/linux/fsnotifier64 | Bin 24816 -> 24816 bytes native/fsNotifier/linux/fsnotifier.h | 6 ++-- native/fsNotifier/linux/inotify.c | 52 ++++++++++++++++----------- native/fsNotifier/linux/main.c | 24 +++++-------- 5 files changed, 44 insertions(+), 38 deletions(-) diff --git a/bin/linux/fsnotifier b/bin/linux/fsnotifier index e248974f4a941feb95fe52f71338c24739812fb7..f7a73126a13e38a3b51fd93601b8594961195074 100755 GIT binary patch delta 4536 zcmai2dsI|)9=~_Ez*PrkcnBT_Pgz228uSpQZB2Thuu#WzrETkUY{`<^JE7Zn}jkgV$jA?vzlwmdSSVwNCO?33gQCW_BSuR3-(%iWQi;M%%d4&4;rezA6F zsOvTH6-n&tS{70viQQfMCME=htZtX&2mI{gup_k};HYL^4g{2*s)zx}-uXJeSrW~!g1%m(!zsa;qSJ#q*m~3T zhPYQ*yQ$nV3^gM%`CASFm<<81dYYNd%kmb*2tu0~?x;s52tq@TsUb2*5LyWXcN>BM zK%k`=3`vs&p@lpLm$HSuXiha;p2!ZF7mAzNgovct7HDlfaZHlkl3gvfApU;k-2P1+ zl58sKcNf~Z2af}U!cg*Hmq8F5$CY!YhAD_!PpKOWj^pZG7kIuJ!p101gQDKd@m-=x zIRh2Y6iu3pc-AUCZe?j85U5&Dp*CxV;J={G=Z1WTaQ1i$z~WH~@l+bTm3WyN_7c%~9-aY!C+hN29HU8TplmBOy&ao-;M z|KsjNOcb{>7g`akA2GQHlz=l`&%sL+>0Rfwj`=!rZd-H4{Kx8b;{fr8KJdE17U zcRK~){*3L3EL&5e3Av-Lf_(^jJp%dp3D7@RVBNUHd;xiNGqN-C2vSMSr*4R(000SQ zKpRPLz&($59mn|CJyEgCmteHi8uGi^E>Uh;No-W@fG#zi6dIx8D2>A$s8IKr^rj+j zilR_Co9AUPwtX!QCcGX9k4a6?T~l2*oZkvWabsP6&Gz4gxcg zJebQ~iq5KSA!0jVw^Qrd7-;a-0r83fGv?$PY^1ee9Mg2Nw(1q>8prj-aql>e0^+!7 zZF|9(mSWO+KY3#;M(k zou}SNEe6JIU{rcAehoX(i|$dk(XKwhcE(z!W}sbQklfr$KF7i!R;L3om|p|D3*Hg& z&+NJa~|BMeHlr^TB=f7oKct6Mj4mi!zh zrTyd=fd~?!f_jv&1HZ=Zr~ICChGT6^q(y5|KGic^j+lJgbU@G6P=}NztHC6L<^8fw zv=Qfn0CblXwm)uKTsg`G+qkF%HHAE^;Qe07F2*HX9~Y)YHHxlS=qWu#k)AaQLSBE( z<1`pLsugT#Exnx_tT=wIxQIO&pB~Xgfqn$Fo>D&v-^1RCPr6GY{$AbE6k^$?S?29{ zP|F5i6ccF)&$BO7Be>P-cj4+F3EVTLGX&anM-H=D2^s0bqk%wMAFd{)XG50yq28hLr{$9|)<>pAS)3o9offhNsSr(IKG)07y&DiaThoM2xi zSYn%bvZ_+XQ-pmiJkcIr4DmLbK8{ydL1Od_p_7~DQND(q)XK?dE-NB!vx8UZ=@hGG zkp5;?ml!9WVb3K#Sn=CC>Q0%_Y@Q-{i|o2kZQ9=JtrY1{ngt9pRgq?)`+#hX^bx4^mwysIYZKiBwe z`tm6vItO*!V!C0U(QxllBFW}tHZNtm_)qpgO7;T^s$hBxW#rYQDtNtQ)qP0ag5j(` zf7P@#2jRK<4Tx7SAL}(Dm{8KOq6&+&_}TK*nI?-$@mBSEN+fK8J6UsTni$Xar&_08pu7JV zxyaXLKNxAQ$)#*0fn6lGSFHv8sYu5801bsC8|>aQkMh4u$$AvBTl9IdG^ zdc6KGp=_z9taDtBBUyLa9LVBKEQNDO)Etf2|wzu$wcpts4Qt<=OBnC!nr?F?g8)3y#5H8QZxj zb8gh73@p)8NuG!84sUlHvZZchLz&NolmV~ivnQtBBIa}*np!R5l|Ma8!t3Gej|>=` zyjl5TT-SzKYmCg8pDFI>%FPc*;ukEp&>Fl0Kg@TqI}6i-dvNMubvS7s=j}K(qSTFD zgM}l89AZScLXd#pnfN1idI!;`2mVNi-a$eHy@bZD(~I&&LuMD7xgtEDLbl5Z^& zTiCi=cScaksgWZPxF1{g7)vg*8qB-c{Ib+AClF*W6NWn3x-!auw=6rtzgv>=4;N0` i1e${#Da(%O8RyXG5&JSQQ@>#A3$t&smq`kv? zpZb%khON;Y7npAEb=ifTBos9&wCr{4FJd45R=6(IN!{`HK zlxh0!@EpgzOMg6%2D$<)TQX;yAk96R=DQ+s>H?XX-~LusEv01i?+3qL=OZZ2lWp)% zx3YTa29vU%wMumQ>hAuNf*26&N_qhQ(yqHj?%8Zte4M26nK!bRQ4mS zja|MolJ6n{E(@{kiAx%1>v93}2qgM|mCR98y&zvZfmvffIZH`z0x|=S14=}|DOHIS zD|TEwc8`-{FLEU~HOgn22XCrQ6NyH=H1wLX_6~RqG}r}%uB;$KL&~eLt`w3B3ykid z2AKjAidQnqjN%i48d>Q^r9w)pPZvewW=AKcWO685#q@)!g143|e1!F33U}ZX%S}#Y zF3O&mxY?#}V#ASws(ZQv7V73{7g7r&0Z zkW|1ou%k(7H*Oiz=EY$fT`&?6P`fQV0{dj zVf1BkQpZYC^749VseDiVJRYN3X-JavapE0k^(o1Xr)b%(i&Y^RVmoOpXI|7)3k}-G zBq!=Lt3msWXqUdzQnJxN_=IqU0eMb@V7?No4}(PN+FFHRsX@QceAq#U+Y|6K>dheDP+YWy6jV9o9isOBH+3K3JM4+`tDf;RekK1$2EsYWDZJI# z7-+q=U&t4g@3o{P|0@PF(gw*@*cc&u*}l{%sX3s+w?MwLDZ(XMy*t@Asp&U-V$ri2 zLRHkrwS$!DAn8zA>~}wmX^7= z8zyiU>Yjd}&f2Pb*2?i&9Sv<*jHgLlWv@~Ca7k76G#o*wyUFJAQJX!mW&|R$y!1&0 z9}cPNo^D)N{?Jp!$`d$8eOj&t{o1r_XOE?4&W*e=dOQzf#u4lWhD~58r=fu&EmP93 z8;RGASRg8r45_rUzVwvjJGH9tW{>5Ze1nao+v8?JeNT?jju)6C!&-6@^A5>qS+-#& z?bg^RuCvH=j~%l9P&@A}A^R&>eMTz(CEJv-s_L%hK`Ux4=)d}{mW?2LwI)A@tz2sX z$ha?uq&e@Eol+1G*W69w%a(RYHYamu7R^0Rdc6ZY&Qqi#S%LQhoacl3d1|BtOh=qg zrd@dp!j-)ZrwKMXFWJA1)Dh-OER>nHyp9ks>bru5H#$NM4`YPOK}`}4UXN%Xu28l*{(R|Qs@l}x zP)j{l8hVX(`_WGhpvXl!3H4PZ`fF3-gkyqk3O|sD)LD^q(TMi8x3}1j6=ndXK z!FZL^F4i{(iRtMxXsLAB?$&8X2yP0h>;kLJp2B~{p3E+t^$-qAUL*#rb|Z#k%2xDd z%jFSib0t6t^t_GS;9i5W;%AZknGI&AMo}3^HV6MXbK3G6o$aINN0SFPiX2O=L(`5> zy8=kiM$_fl@-jhr6g$0_mLp2Y#G~mgh*WEX2gVqy*Nj=HQf|P3`a>H^%V3@E9PQ3J zrxDpXo0X4Y!?uEj=WuM5z3UxvjVL>>i^&kHjCeo(8I>9gnQ_W2aP^C?>l=z)bN3{O zgc~|MCxgF}1#+s!Re+5{*f@p#Eoai?h~9cyITd3_%Kkwr0DlC3Z}L-ryunLBGt01gAXtxdeAGH|r{ z971;b-}jWDlqq~e{b=AjB?n{9@qWu?ReI)AR+nc@tS``nL!L*<)Pb0llFh|7T)d>4Ns^X5;# z`J!g+sauuB6tbgbB-0zy6J3m$c>>U-+px&N$XQrhpj&Iwq0p=?WCQuRaT$7dYImGH z!qV;Kd^@YPr)Bi~6KY*ZlhhFiP@xs@YGcjziTopMyWPg`VsF~*u72IDb`9MP?A}%J z3%>>wfEETArwo0qEAXY+q)-FDNRUqA7aHrda7Go8qPS+CQhEopJlgC&a6B3B~jy- z-M=*a7M7BYBH$JUzPkIamce*frK&6&Ru)4WT|MW29F`%HQHQ@~Z%@wVFR@Q2Zyw+M z55r+6TUS_WJAf@LOh;U0suF}VL^%l_9DUKEa)gBnZ<;uDGN$KXro7tj2zI6dE#&}< zEBb@EaT351bs@jH zV@9O1JG z{0mGn9+tibl|I192kn2vlfD+F8G9ab^!-5vNcYisLfyfm6q7=T|4?>=DEgSWJZ0gP?NI zs$#q6-v_Hd&A0tB@`@ndZScPY{~9)lz$T1+=mkNfj}Fow!M-1ROe$?3hi|a-k6?uE zVp(pRss9x=+npEN3 RD@&-8O_9AFJL)#Z{0Gno4B-F( diff --git a/bin/linux/fsnotifier64 b/bin/linux/fsnotifier64 index efba253b08b3a52e22e1bc09f1d93e5bd1f6fca5..1fc4f32ff7effedcfc451430f228bdf99e76d15f 100755 GIT binary patch delta 5194 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 delta 5151 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 CLt9w@ diff --git a/native/fsNotifier/linux/fsnotifier.h b/native/fsNotifier/linux/fsnotifier.h index 0ee04cd12639..f3234e2fde9d 100644 --- a/native/fsNotifier/linux/fsnotifier.h +++ b/native/fsNotifier/linux/fsnotifier.h @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 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,8 @@ // logging void userlog(int priority, const char* format, ...); +#define CHECK_NULL(p, r) if (p == NULL) { userlog(LOG_ERR, "out of memory"); return r; } + // variable-length array typedef struct __array array; @@ -38,7 +40,7 @@ void array_delete(array* a); void array_delete_vs_data(array* a); -// key/value pairs table +// poor man's hash table typedef struct __table table; table* table_create(int capacity); diff --git a/native/fsNotifier/linux/inotify.c b/native/fsNotifier/linux/inotify.c index ab605424d66c..04d749e48d83 100644 --- a/native/fsNotifier/linux/inotify.c +++ b/native/fsNotifier/linux/inotify.c @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 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. @@ -32,8 +32,6 @@ #define DEFAULT_SUBDIR_COUNT 5 -#define CHECK_NULL(p) if (p == NULL) { userlog(LOG_ERR, "out of memory"); return ERR_ABORT; } - typedef struct __watch_node { char* name; int wd; @@ -153,9 +151,9 @@ static int add_watch(const char* path, watch_node* parent) { node = malloc(sizeof(watch_node)); - CHECK_NULL(node); + CHECK_NULL(node, ERR_ABORT); node->name = strdup(path); - CHECK_NULL(node->name); + CHECK_NULL(node->name, ERR_ABORT); node->wd = wd; node->parent = parent; node->kids = NULL; @@ -163,9 +161,9 @@ static int add_watch(const char* path, watch_node* parent) { if (parent != NULL) { if (parent->kids == NULL) { parent->kids = array_create(DEFAULT_SUBDIR_COUNT); - CHECK_NULL(parent->kids); + CHECK_NULL(parent->kids, ERR_ABORT); } - CHECK_NULL(array_push(parent->kids, node)); + CHECK_NULL(array_push(parent->kids, node), ERR_ABORT); } if (table_put(watches, wd, node) == NULL) { @@ -238,25 +236,31 @@ static bool is_ignored(const char* path, array* ignores) { return false; } -static int walk_tree(const char* path, watch_node* parent, array* ignores) { +static int walk_tree(const char* path, watch_node* parent, array* ignores, bool recursive) { if (is_ignored(path, ignores)) { return ERR_IGNORE; } - DIR* dir = opendir(path); - if (dir == NULL) { - if (errno == EACCES) { - return ERR_IGNORE; + DIR* dir; + if (recursive) { + dir = opendir(path); + if (dir == NULL) { + if (errno == EACCES) { + return ERR_IGNORE; + } + else if (errno == ENOTDIR) { // "future" root + return add_watch(path, parent); + } + userlog(LOG_ERR, "opendir(%s): %s", path, strerror(errno)); + return ERR_CONTINUE; } - else if (errno == ENOTDIR) { // flat root - return add_watch(path, parent); - } - userlog(LOG_ERR, "opendir(%s): %s", path, strerror(errno)); - return ERR_CONTINUE; } int id = add_watch(path, parent); - if (id < 0) { + if (!recursive) { + return id; + } + else if (id < 0) { closedir(dir); return id; } @@ -279,7 +283,7 @@ static int walk_tree(const char* path, watch_node* parent, array* ignores) { continue; } - int subdir_id = walk_tree(subdir, table_get(watches, id), ignores); + int subdir_id = walk_tree(subdir, table_get(watches, id), ignores, recursive); if (subdir_id < 0 && subdir_id != ERR_IGNORE) { rm_watch(id, true); id = subdir_id; @@ -293,9 +297,15 @@ static int walk_tree(const char* path, watch_node* parent, array* ignores) { int watch(const char* root, array* ignores) { + bool recursive = true; + if (root[0] == '|') { + root++; + recursive = false; + } + char buf[PATH_MAX]; const char* normalized = realpath(root, buf); - return walk_tree((normalized != NULL ? normalized : root), NULL, ignores); + return walk_tree((normalized != NULL ? normalized : root), NULL, ignores, recursive); } @@ -323,7 +333,7 @@ static bool process_inotify_event(struct inotify_event* event) { } if ((event->mask & IN_CREATE || event->mask & IN_MOVED_TO) && event->mask & IN_ISDIR) { - int result = walk_tree(path, node, NULL); + int result = walk_tree(path, node, NULL, true); if (result < 0 && result != ERR_IGNORE) { return false; } diff --git a/native/fsNotifier/linux/main.c b/native/fsNotifier/linux/main.c index 3bef18521151..81dcdfead702 100644 --- a/native/fsNotifier/linux/main.c +++ b/native/fsNotifier/linux/main.c @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 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. @@ -33,7 +33,7 @@ #define LOG_ENV_ERROR "error" #define LOG_ENV_OFF "off" -#define VERSION "1.0" +#define VERSION "1.1" #define VERSION_MSG "fsnotifier " VERSION "\n" #define USAGE_MSG \ @@ -58,11 +58,8 @@ typedef struct { static array* roots = NULL; static bool show_warning = true; - static bool self_test = false; -#define CHECK_NULL(p) if (p == NULL) { userlog(LOG_ERR, "out of memory"); return false; } - static void init_log(); static void run_self_test(); static void main_loop(); @@ -223,7 +220,7 @@ static bool read_input() { if (strcmp(line, "ROOTS") == 0) { array* new_roots = array_create(20); - CHECK_NULL(new_roots); + CHECK_NULL(new_roots, false); while (1) { line = read_line(stdin); @@ -235,12 +232,9 @@ static bool read_input() { break; } else { - if (line[0] == '|') line++; // flat roots will be differentiated later - int l = strlen(line); if (l > 1 && line[l-1] == '/') line[l-1] = '\0'; - - CHECK_NULL(array_push(new_roots, strdup(line))); + CHECK_NULL(array_push(new_roots, strdup(line)), false); } } @@ -266,7 +260,7 @@ static bool update_roots(array* new_roots) { } array* unwatchable = array_create(20); - CHECK_NULL(unwatchable); + CHECK_NULL(unwatchable, false); if (!unwatchable_mounts(unwatchable)) { return false; } @@ -312,10 +306,10 @@ static bool register_roots(array* new_roots, array* unwatchable) { } else if (id >= 0) { watch_root* root = malloc(sizeof(watch_root)); - CHECK_NULL(root); + CHECK_NULL(root, false); root->id = id; root->name = new_root; - CHECK_NULL(array_push(roots, root)); + CHECK_NULL(array_push(roots, root), false); } else { if (show_warning && watch_limit_reached()) { @@ -324,7 +318,7 @@ static bool register_roots(array* new_roots, array* unwatchable) { output("MESSAGE\n" INOTIFY_LIMIT_MSG, limit); show_warning = false; // warn only once } - CHECK_NULL(array_push(unwatchable, new_root)); + CHECK_NULL(array_push(unwatchable, new_root), false); } } @@ -362,7 +356,7 @@ static bool unwatchable_mounts(array* mounts) { } if (!is_watchable(dev, point, fs)) { - CHECK_NULL(array_push(mounts, strdup(point))); + CHECK_NULL(array_push(mounts, strdup(point)), false); } } From a1e4dc645eb2fd8d0bd4753b459d1916f7a23a19 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Tue, 10 Apr 2012 19:21:03 +0200 Subject: [PATCH 18/30] File watcher: fix subst mapping; remove symlink mapping; clean locks; test --- .../openapi/vfs/impl/local/FileWatcher.java | 305 ++++++------ .../openapi/vfs/local/FileWatcherTest.java | 438 ++++++++++++++++++ .../vfs/local/SymlinkHandlingTest.java | 2 +- 3 files changed, 591 insertions(+), 154 deletions(-) create mode 100644 platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/FileWatcherTest.java diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/local/FileWatcher.java b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/local/FileWatcher.java index e11872c5a048..62b8a1a7ddf5 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/local/FileWatcher.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/local/FileWatcher.java @@ -20,34 +20,32 @@ import com.intellij.notification.Notification; import com.intellij.notification.NotificationListener; import com.intellij.notification.NotificationType; import com.intellij.notification.Notifications; +import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.PathManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.SystemInfo; -import com.intellij.openapi.util.io.FileSystemUtil; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.newvfs.ManagingFS; import com.intellij.openapi.vfs.newvfs.NewVirtualFile; import com.intellij.openapi.vfs.watcher.ChangeKind; -import com.intellij.util.PairFunction; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.TestOnly; import javax.swing.event.HyperlinkEvent; import java.io.*; import java.util.*; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; /** * @author max */ public class FileWatcher { - @NonNls public static final String PROPERTY_WATCHER_DISABLED = "filewatcher.disabled"; - @NonNls private static final String PROPERTY_WATCHER_EXECUTABLE_PATH = "idea.filewatcher.executable.path"; + @NonNls public static final String PROPERTY_WATCHER_DISABLED = "idea.filewatcher.disabled"; + @NonNls public static final String PROPERTY_WATCHER_EXECUTABLE_PATH = "idea.filewatcher.executable.path"; private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.vfs.impl.local.FileWatcher"); @@ -59,15 +57,7 @@ public class FileWatcher { @NonNls private static final String EXIT_COMMAND = "EXIT"; @NonNls private static final String MESSAGE_COMMAND = "MESSAGE"; - private static final PairFunction PATH_COMPARATOR = new PairFunction() { - @Override - public Boolean fun(final String s1, final String s2) { - return SystemInfo.isFileSystemCaseSensitive ? s1.equals(s2) : s1.equalsIgnoreCase(s2); - } - }; - private final Object LOCK = new Object(); - private final Lock SET_ROOTS_LOCK = new ReentrantLock(true); private List myDirtyPaths = new ArrayList(); private List myDirtyRecursivePaths = new ArrayList(); @@ -75,21 +65,23 @@ public class FileWatcher { private List myManualWatchRoots = new ArrayList(); private final List> myMapping = new ArrayList>(); - private List> myCanonicalMapping = new ArrayList>(); - private List myRecursiveWatchRoots = new ArrayList(); private List myFlatWatchRoots = new ArrayList(); + private final Collection myAllPaths = new ArrayList(2); + private final Collection myWatchedPaths = new ArrayList(2); + + private File executable; private volatile Process notifierProcess; private volatile BufferedReader notifierReader; - private volatile BufferedWriter notifierWriter; + private volatile BufferedWriter notifierWriter; private boolean myFailureShownToTheUser = false; private int attemptCount = 0; private static final int MAX_PROCESS_LAUNCH_ATTEMPT_COUNT = 10; private boolean isShuttingDown = false; - private final ManagingFS myManagingFS; + private final ManagingFS myManagingFS; private static final FileWatcher ourInstance = new FileWatcher(); public static FileWatcher getInstance() { @@ -140,7 +132,6 @@ public class FileWatcher { myDirtyRecursivePaths = new ArrayList(); return result; } - } public List getDirtyDirs() { @@ -158,26 +149,16 @@ public class FileWatcher { } public void setWatchRoots(final List recursive, final List flat) { - SET_ROOTS_LOCK.lock(); - try { - synchronized (LOCK) { - if (myRecursiveWatchRoots.equals(recursive) && myFlatWatchRoots.equals(flat)) return; - } - - final List> mapping = new ArrayList>(); - long t = System.nanoTime(); - final List checkedRecursive = checkPaths(recursive, mapping); - final List checkedFlat = checkPaths(flat, mapping); - t = (System.nanoTime() - t) / 1000; - LOG.info((recursive.size() + flat.size()) + " paths checked, " + mapping.size() + " mapped, " + t + " mks"); + synchronized (LOCK) { + if (myRecursiveWatchRoots.equals(recursive) && myFlatWatchRoots.equals(flat)) return; if (isAlive()) { try { writeLine(ROOTS_COMMAND); - for (String path : checkedRecursive) { + for (String path : recursive) { writeLine(path); } - for (String path : checkedFlat) { + for (String path : flat) { writeLine("|" + path); } writeLine("#"); @@ -187,37 +168,10 @@ public class FileWatcher { } } - synchronized (LOCK) { - myRecursiveWatchRoots = recursive; - myFlatWatchRoots = flat; - myMapping.clear(); - myCanonicalMapping = mapping; - } + myRecursiveWatchRoots = recursive; + myFlatWatchRoots = flat; + myMapping.clear(); } - finally { - SET_ROOTS_LOCK.unlock(); - } - } - - private static List checkPaths(final List paths, final List> mapping) { - if (!SystemInfo.areSymLinksSupported) return paths; - - final List checkedPaths = new ArrayList(paths.size()); - for (String path : paths) { - String watched = path; - final String canonical = getCanonicalPath(path); - //noinspection ConstantConditions - if (!PATH_COMPARATOR.fun(path, canonical)) { - mapping.add(Pair.create((watched = canonical), path)); - } - checkedPaths.add(watched); - } - return checkedPaths; - } - - private static String getCanonicalPath(final String path) { - final String realPath = FileSystemUtil.resolveSymLink(path); - return realPath != null ? realPath : path; } private boolean isAlive() { @@ -247,43 +201,34 @@ public class FileWatcher { shutdownProcess(); - String execPath = null; + if (executable == null) { + executable = getExecutable(); - final String altExecPath = System.getProperty(PROPERTY_WATCHER_EXECUTABLE_PATH); - if (altExecPath != null && new File(altExecPath).isFile()) { - execPath = FileUtil.toSystemDependentName(altExecPath); - } - - if (execPath == null) { - final String execName; - execName = getExecutableName(); - if (execName == null) { + if (executable == null) { myFailureShownToTheUser = true; // ignore unsupported platforms return; } - execPath = PathManager.getBinPath() + File.separatorChar + execName; + + if (!executable.exists()) { + notifyOnFailure("File watcher is not found at path: " + executable, null); + return; + } + + if (!executable.canExecute()) { + final String message = "File watcher is not executable: " + executable + ""; + final File exec = executable; + notifyOnFailure(message, new NotificationListener() { + @Override + public void hyperlinkUpdate(@NotNull Notification notification, @NotNull HyperlinkEvent event) { + ShowFilePathAction.openFile(exec); + } + }); + return; + } } - final File exec = new File(execPath); - if (!exec.exists()) { - notifyOnFailure("File watcher is not found at path: " + execPath, null); - return; - } - - if (!exec.canExecute()) { - notifyOnFailure("File watcher is not executable: " + execPath +"", new NotificationListener() { - @Override - public void hyperlinkUpdate(@NotNull Notification notification, @NotNull HyperlinkEvent event) { - ShowFilePathAction.openFile(exec); - } - }); - return; - } - - LOG.info("Starting file watcher: " + execPath); - - notifierProcess = Runtime.getRuntime().exec(new String[]{execPath}); - + LOG.info("Starting file watcher: " + executable); + notifierProcess = Runtime.getRuntime().exec(executable.getAbsolutePath()); notifierReader = new BufferedReader(new InputStreamReader(notifierProcess.getInputStream())); notifierWriter = new BufferedWriter(new OutputStreamWriter(notifierProcess.getOutputStream())); @@ -299,15 +244,43 @@ public class FileWatcher { } @Nullable - private static String getExecutableName() { + private static File getExecutable() { + String execPath = null; + + final String altExecPath = System.getProperty(PROPERTY_WATCHER_EXECUTABLE_PATH); + if (altExecPath != null && new File(altExecPath).isFile()) { + execPath = FileUtil.toSystemDependentName(altExecPath); + } + + if (execPath == null) { + final String execName = getExecutableName(false); + if (execName == null) { + return null; + } + execPath = FileUtil.join(PathManager.getBinPath(), execName); + } + + File exec = new File(execPath); + if (!exec.exists()) { + String homePath = PathManager.getHomePath(); + if (new File(homePath, "community").exists()) { + homePath += File.separator + "community"; + } + exec = new File(FileUtil.join(homePath, "bin", getExecutableName(true))); + } + return exec; + } + + @Nullable + private static String getExecutableName(final boolean withSubDir) { if (SystemInfo.isWindows) { - return "fsnotifier.exe"; + return (withSubDir ? "win" + File.separator : "") + "fsnotifier.exe"; } else if (SystemInfo.isMac) { - return "fsnotifier"; + return (withSubDir ? "mac" + File.separator : "") + "fsnotifier"; } else if (SystemInfo.isLinux) { - return SystemInfo.isAMD64 ? "fsnotifier64" : "fsnotifier"; + return (withSubDir ? "linux" + File.separator : "") + (SystemInfo.isAMD64 ? "fsnotifier64" : "fsnotifier"); } return null; @@ -316,7 +289,8 @@ public class FileWatcher { private void notifyOnFailure(String cause, @Nullable NotificationListener listener) { if (!myFailureShownToTheUser) { myFailureShownToTheUser = true; - Notifications.Bus.notify(new Notification(Notifications.SYSTEM_MESSAGES_GROUP_ID, "External file sync may be slow", cause, NotificationType.WARNING, listener)); + Notifications.Bus.notify(new Notification(Notifications.SYSTEM_MESSAGES_GROUP_ID, "External file sync may be slow", + cause, NotificationType.WARNING, listener)); } } @@ -339,6 +313,32 @@ public class FileWatcher { return notifierProcess != null; } + @TestOnly + public void startup() throws IOException { + final Application app = ApplicationManager.getApplication(); + assert app != null && app.isUnitTestMode() : app; + + myFailureShownToTheUser = true; + attemptCount = 0; + startupProcess(false); + attemptCount = 2 * MAX_PROCESS_LAUNCH_ATTEMPT_COUNT; + if (notifierProcess != null) { + new WatchForChangesThread().start(); + } + } + + @TestOnly + public void shutdown() throws InterruptedException { + final Application app = ApplicationManager.getApplication(); + assert app != null && app.isUnitTestMode() : app; + + final Process process = notifierProcess; + if (process != null) { + shutdownProcess(); + process.waitFor(); + } + } + private class WatchForChangesThread extends Thread { public WatchForChangesThread() { //noinspection HardCodedStringLiteral @@ -396,7 +396,7 @@ public class FileWatcher { final String pathB = readLine(); if (pathB == null || "#".equals(pathB)) break; - pairs.add(new Pair(ensureEndsWithSlash(pathA), ensureEndsWithSlash(pathB))); + pairs.add(Pair.create(preparePathForMapping(pathA), preparePathForMapping(pathB))); } while (true); @@ -414,10 +414,10 @@ public class FileWatcher { } synchronized (LOCK) { - final String watchedPath = checkWatchable(path); - if (watchedPath != null) { + final Collection watchedPaths = checkWatchable(path); + if (!watchedPaths.isEmpty()) { try { - onPathChange(ChangeKind.valueOf(command), watchedPath); + onPathChange(ChangeKind.valueOf(command), watchedPaths); } catch (IllegalArgumentException e) { LOG.error("Illegal watcher command: " + command); @@ -438,9 +438,9 @@ public class FileWatcher { } } - private static String ensureEndsWithSlash(String path) { - if (path.endsWith("/") || path.endsWith(File.separator)) return path; - return path + '/'; + private static String preparePathForMapping(final String path) { + final String localPath = FileUtil.toSystemDependentName(path); + return localPath.endsWith(File.separator) ? localPath : localPath + File.separator; } private void writeLine(String line) throws IOException { @@ -486,64 +486,76 @@ public class FileWatcher { return line; } - public boolean isWatched(VirtualFile file) { - return isOperational() && checkWatchable(file.getPresentableUrl()) != null; + public boolean isWatched(@NotNull final VirtualFile file) { + if (isOperational()) { + synchronized (LOCK) { + return !checkWatchable(file.getPresentableUrl()).isEmpty(); + } + } + return false; } - @Nullable - private String checkWatchable(String path) { - if (path == null) return null; + @NotNull + private Collection checkWatchable(final String reportedPath) { + if (reportedPath == null) return Collections.emptyList(); - for (Pair mapping : myCanonicalMapping) { - if (path.startsWith(mapping.first)) { - path = mapping.second + path.substring(mapping.first.length()); - break; + myAllPaths.clear(); + myAllPaths.add(reportedPath); + for (Pair map : myMapping) { + if (FileUtil.startsWith(reportedPath, map.first)) { + myAllPaths.add(map.second + reportedPath.substring(map.first.length())); + } + else if (FileUtil.startsWith(reportedPath, map.second)) { + myAllPaths.add(map.first + reportedPath.substring(map.second.length())); } } - for (String root : myRecursiveWatchRoots) { - if (FileUtil.startsWith(path, root)) { - return path; + myWatchedPaths.clear(); + ext: + for (String path : myAllPaths) { + for (String root : myRecursiveWatchRoots) { + if (FileUtil.startsWith(path, root)) { + myWatchedPaths.add(path); + continue ext; + } + } + + for (String root : myFlatWatchRoots) { + if (FileUtil.pathsEqual(path, root)) { + myWatchedPaths.add(path); + continue ext; + } + final File parentFile = new File(path).getParentFile(); + if (parentFile != null && FileUtil.pathsEqual(parentFile.getPath(), root)) { + myWatchedPaths.add(path); + continue ext; + } } } - - for (String root : myFlatWatchRoots) { - if (FileUtil.pathsEqual(path, root)) { - return path; - } - final File parentFile = new File(path).getParentFile(); - if (parentFile != null && FileUtil.pathsEqual(parentFile.getPath(), root)) { - return path; - } - } - - return null; + return myWatchedPaths; } - private void onPathChange(final ChangeKind changeKind, final String path) { + private void onPathChange(final ChangeKind changeKind, final Collection paths) { switch (changeKind) { case STATS: case CHANGE: - addPath(path, myDirtyPaths); + myDirtyPaths.addAll(paths); break; case CREATE: case DELETE: - final File parentFile = new File(path).getParentFile(); - if (parentFile != null) { - addPath(parentFile.getPath(), myDirtyPaths); - } - else { - addPath(path, myDirtyPaths); + for (String path : paths) { + final File parent = new File(path).getParentFile(); + myDirtyPaths.add(parent != null ? parent.getPath() : path); } break; case DIRTY: - addPath(path, myDirtyDirs); + myDirtyDirs.addAll(paths); break; case RECDIRTY: - addPath(path, myDirtyRecursivePaths); + myDirtyRecursivePaths.addAll(paths); break; case RESET: @@ -552,19 +564,6 @@ public class FileWatcher { } } - private void addPath(String path, List list) { - list.add(path); - - for (Pair map : myMapping) { - if (FileUtil.startsWith(path, map.getFirst())) { - list.add(map.getSecond() + path.substring(map.getFirst().length())); - } - else if (FileUtil.startsWith(path, map.getSecond())) { - list.add(map.getFirst() + path.substring(map.getSecond().length())); - } - } - } - private void reset() { synchronized (LOCK) { myDirtyPaths.clear(); diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/FileWatcherTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/FileWatcherTest.java new file mode 100644 index 000000000000..074522040598 --- /dev/null +++ b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/FileWatcherTest.java @@ -0,0 +1,438 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.vfs.local; + +import com.intellij.execution.configurations.GeneralCommandLine; +import com.intellij.idea.Bombed; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.util.SystemInfo; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.vfs.*; +import com.intellij.openapi.vfs.impl.local.FileWatcher; +import com.intellij.openapi.vfs.newvfs.BulkFileListener; +import com.intellij.openapi.vfs.newvfs.events.VFileContentChangeEvent; +import com.intellij.openapi.vfs.newvfs.events.VFileCreateEvent; +import com.intellij.openapi.vfs.newvfs.events.VFileDeleteEvent; +import com.intellij.openapi.vfs.newvfs.events.VFileEvent; +import com.intellij.testFramework.PlatformLangTestCase; +import com.intellij.util.Function; +import com.intellij.util.TimeoutUtil; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.messages.MessageBusConnection; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.util.*; + +public class FileWatcherTest extends PlatformLangTestCase { + private static final int NATIVE_PROCESS_DELAY = 500; // time to event to be caught by native watcher and passed to watcher thread + + private FileWatcher myWatcher; + private LocalFileSystem myFileSystem; + private MessageBusConnection myConnection; + private final List myEvents = new ArrayList(); + + @Override + protected void setUp() throws Exception { + super.setUp(); + + myWatcher = FileWatcher.getInstance(); + assertNotNull(myWatcher); + assertFalse(myWatcher.isOperational()); + myWatcher.startup(); + assertTrue(myWatcher.isOperational()); + + myFileSystem = LocalFileSystem.getInstance(); + assertNotNull(myFileSystem); + + myConnection = ApplicationManager.getApplication().getMessageBus().connect(); + myConnection.subscribe(VirtualFileManager.VFS_CHANGES, new BulkFileListener() { + @Override + public void before(@NotNull List events) { + } + + @Override + public void after(@NotNull List events) { + synchronized (myEvents) { + myEvents.addAll(events); + myEvents.notifyAll(); + } + } + }); + } + + @Override + protected void tearDown() throws Exception { + try { + myConnection.disconnect(); + myWatcher.shutdown(); + } + finally { + myFileSystem = null; + myWatcher = null; + super.tearDown(); + } + } + + + public void testFileRoot() throws Exception { + final File file = FileUtil.createTempFile("test.", ".txt"); + refresh(file); + final LocalFileSystem.WatchRequest request = watch(file); + try { + FileUtil.writeToFile(file, "new content"); + assertEvent(VFileContentChangeEvent.class, file.getAbsolutePath()); + + FileUtil.delete(file); + assertEvent(VFileDeleteEvent.class, file.getAbsolutePath()); + + FileUtil.writeToFile(file, "re-creation"); + assertEvent(VFileCreateEvent.class, file.getAbsolutePath()); + } + finally { + myFileSystem.removeWatchedRoot(request); + FileUtil.delete(file); + } + } + + public void testNonCanonicallyNamedFileRoot() throws Exception { + if (SystemInfo.isFileSystemCaseSensitive) { + System.out.println("Ignored: case-insensitive FS required"); + return; + } + + final File file = FileUtil.createTempFile("test.", ".txt"); + refresh(file); + + final String watchRoot = file.getAbsolutePath().toUpperCase(Locale.US); + final LocalFileSystem.WatchRequest request = watch(new File(watchRoot)); + try { + FileUtil.writeToFile(file, "new content"); + assertEvent(VFileContentChangeEvent.class, file.getAbsolutePath()); + + FileUtil.delete(file); + assertEvent(VFileDeleteEvent.class, file.getAbsolutePath()); + + FileUtil.writeToFile(file, "re-creation"); + assertEvent(VFileCreateEvent.class, file.getAbsolutePath()); + } + finally { + myFileSystem.removeWatchedRoot(request); + FileUtil.delete(file); + } + } + + public void testDirectoryRecursive() throws Exception { + final File topDir = FileUtil.createTempDirectory("top.", null); + refresh(topDir); + + final LocalFileSystem.WatchRequest request = watch(topDir); + try { + final File subDir = FileUtil.createTempDirectory(topDir, "sub.", null); + assertEvent(VFileCreateEvent.class, subDir.getAbsolutePath()); + refresh(subDir); + + final File file = FileUtil.createTempFile(subDir, "test.", ".txt", true, false); + assertEvent(VFileCreateEvent.class, file.getAbsolutePath()); + + FileUtil.writeToFile(file, "new content"); + assertEvent(VFileContentChangeEvent.class, file.getAbsolutePath()); + + FileUtil.delete(file); + assertEvent(VFileDeleteEvent.class, file.getAbsolutePath()); + + FileUtil.writeToFile(file, "re-creation"); + assertEvent(VFileCreateEvent.class, file.getAbsolutePath()); + } + finally { + myFileSystem.removeWatchedRoot(request); + FileUtil.delete(topDir); + } + } + + public void testDirectoryFlat() throws Exception { + final File topDir = FileUtil.createTempDirectory("top.", null); + final File watchedFile = FileUtil.createTempFile(topDir, "test.", ".txt", true, false); + final File subDir = FileUtil.createTempDirectory(topDir, "sub.", null); + final File unwatchedFile = FileUtil.createTempFile(subDir, "test.", ".txt", true, false); + refresh(topDir); + + final LocalFileSystem.WatchRequest request = watch(topDir, false); + try { + FileUtil.writeToFile(watchedFile, "new content"); + assertEvent(VFileContentChangeEvent.class, watchedFile.getAbsolutePath()); + + FileUtil.writeToFile(unwatchedFile, "new content"); + assertEvent(VFileEvent.class); + } + finally { + myFileSystem.removeWatchedRoot(request); + FileUtil.delete(topDir); + } + } + + public void testDirectoryNonExisting() throws Exception { + final File topDir = FileUtil.createTempDirectory("top.", null); + final File subDir = new File(topDir, "subDir"); + final File file = new File(subDir, "file.txt"); + refresh(topDir); + + final LocalFileSystem.WatchRequest request = watch(subDir); + try { + assertTrue(subDir.toString(), subDir.mkdir()); + assertEvent(VFileCreateEvent.class, subDir.getAbsolutePath()); + refresh(subDir); + + FileUtil.writeToFile(file, "new content"); + assertEvent(VFileCreateEvent.class, file.getAbsolutePath()); + } + finally { + myFileSystem.removeWatchedRoot(request); + FileUtil.delete(topDir); + } + } + + public void testDirectoryOverlapping() throws Exception { + final File topDir = FileUtil.createTempDirectory("top.", null); + final File file1 = FileUtil.createTempFile(topDir, "file1.", ".txt", true, false); + final File subDir = FileUtil.createTempDirectory(topDir, "sub.", null); + final File file2 = FileUtil.createTempFile(subDir, "file2.", ".txt", true, false); + final File sideDir = FileUtil.createTempDirectory("side.", null); + final File file3 = FileUtil.createTempFile(sideDir, "file3.", ".txt", true, false); + refresh(topDir); + refresh(sideDir); + + final LocalFileSystem.WatchRequest request1 = watch(subDir); + final LocalFileSystem.WatchRequest request2 = watch(sideDir); + try { + FileUtil.writeToFile(file1, "new content"); + FileUtil.writeToFile(file2, "new content"); + FileUtil.writeToFile(file3, "new content"); + assertEvent(VFileContentChangeEvent.class, file2.getAbsolutePath(), file3.getAbsolutePath()); + + final LocalFileSystem.WatchRequest request3 = watch(topDir); + try { + FileUtil.writeToFile(file1, "newer content"); + FileUtil.writeToFile(file2, "newer content"); + FileUtil.writeToFile(file3, "newer content"); + assertEvent(VFileContentChangeEvent.class, file1.getAbsolutePath(), file2.getAbsolutePath(), file3.getAbsolutePath()); + } + finally { + unwatch(request3); + } + + FileUtil.writeToFile(file1, "newest content"); + FileUtil.writeToFile(file2, "newest content"); + FileUtil.writeToFile(file3, "newest content"); + assertEvent(VFileContentChangeEvent.class, file2.getAbsolutePath(), file3.getAbsolutePath()); + + FileUtil.delete(file1); + FileUtil.delete(file2); + FileUtil.delete(file3); + assertEvent(VFileDeleteEvent.class, file1.getAbsolutePath(), file2.getAbsolutePath(), file3.getAbsolutePath()); + } + finally { + myFileSystem.removeWatchedRoots(Arrays.asList(request1, request2)); + FileUtil.delete(topDir); + } + } + + @Bombed(user = "roman.shevchenko", year = 2012, month = Calendar.MAY, day = 1) + public void testSymlinkAboveWatchRoot() throws Exception { + final File topDir = FileUtil.createTempDirectory("top.", null); + final File topLink = SymlinkHandlingTest.createTempLink(topDir.getAbsolutePath(), "link"); + final File subDir = FileUtil.createTempDirectory(topDir, "sub.", null); + final File file = FileUtil.createTempFile(subDir, "test.", ".txt", true, false); + final File fileLink = new File(new File(topLink, subDir.getName()), file.getName()); + refresh(topDir); + refresh(topLink); + + final LocalFileSystem.WatchRequest request = watch(topLink); + try { + FileUtil.writeToFile(file, "new content"); + assertEvent(VFileContentChangeEvent.class, fileLink.getAbsolutePath()); + + FileUtil.delete(file); + assertEvent(VFileDeleteEvent.class, fileLink.getAbsolutePath()); + + FileUtil.writeToFile(file, "re-creation"); + assertEvent(VFileCreateEvent.class, fileLink.getAbsolutePath()); + } + finally { + myFileSystem.removeWatchedRoot(request); + FileUtil.delete(topLink); + FileUtil.delete(topDir); + } + } + + @Bombed(user = "roman.shevchenko", year = 2012, month = Calendar.MAY, day = 1) + public void testSymlinkBelowWatchRoot() throws Exception { + final File targetDir = FileUtil.createTempDirectory("top.", null); + final File file = FileUtil.createTempFile(targetDir, "test.", ".txt", true, false); + final File linkDir = FileUtil.createTempDirectory("link.", null); + final File link = new File(linkDir, "link"); + SymlinkHandlingTest.createTempLink(targetDir.getAbsolutePath(), link.getAbsolutePath()); + final File fileLink = new File(link, file.getName()); + refresh(targetDir); + refresh(linkDir); + + final LocalFileSystem.WatchRequest request = watch(linkDir); + try { + FileUtil.writeToFile(file, "new content"); + assertEvent(VFileContentChangeEvent.class, fileLink.getAbsolutePath()); + + FileUtil.delete(file); + assertEvent(VFileDeleteEvent.class, fileLink.getAbsolutePath()); + + FileUtil.writeToFile(file, "re-creation"); + assertEvent(VFileCreateEvent.class, fileLink.getAbsolutePath()); + } + finally { + myFileSystem.removeWatchedRoot(request); + FileUtil.delete(linkDir); + FileUtil.delete(targetDir); + } + } + + public void testSubst() throws Exception { + if (!SystemInfo.isWindows) { + System.out.println("Ignored: Windows required"); + return; + } + + final Set roots = ContainerUtil.map2Set(File.listRoots(), new Function() { + @Override + public Character fun(File root) { + return root.getPath().toLowerCase(Locale.US).charAt(0); + } + }); + char subst = 0; + for (char c = 'e'; c <= 'z'; c++) { + if (!roots.contains(c)) { + subst = c; + break; + } + } + assertFalse("Occupied: " + roots.toString(), subst == 0); + + final File targetDir = FileUtil.createTempDirectory("top.", null); + final File subDir = FileUtil.createTempDirectory(targetDir, "sub.", null); + final File file = FileUtil.createTempFile(subDir, "test.", ".txt", true, false); + final int rv = new GeneralCommandLine("subst", subst + ":", targetDir.getAbsolutePath()).createProcess().waitFor(); + assertEquals(0, rv); + + final File substDir = new File((subst + ":\\").toUpperCase(Locale.US), subDir.getName()); + final File substFile = new File(substDir, file.getName()); + refresh(targetDir); + refresh(substDir); + + final LocalFileSystem.WatchRequest request = watch(substDir); + try { + FileUtil.writeToFile(file, "new content"); + assertEvent(VFileContentChangeEvent.class, substFile.getAbsolutePath()); + + final LocalFileSystem.WatchRequest request2 = watch(targetDir); + try { + FileUtil.delete(file); + assertEvent(VFileDeleteEvent.class, file.getAbsolutePath(), substFile.getAbsolutePath()); + } + finally { + unwatch(request2); + } + + FileUtil.writeToFile(file, "re-creation"); + assertEvent(VFileCreateEvent.class, substFile.getAbsolutePath()); + } + finally { + myFileSystem.removeWatchedRoot(request); + new GeneralCommandLine("subst", subst + ":", "/d").createProcess().waitFor(); + FileUtil.delete(targetDir); + } + } + + + private List getEvents() throws InterruptedException { + TimeoutUtil.sleep(NATIVE_PROCESS_DELAY); + myFileSystem.refresh(false); + + synchronized (myEvents) { + final ArrayList result = new ArrayList(myEvents); + myEvents.clear(); + return result; + } + } + + private void clearEvents() { + myFileSystem.refresh(false); + synchronized (myEvents) { + myEvents.clear(); + } + } + + @NotNull + private LocalFileSystem.WatchRequest watch(final File watchFile) throws InterruptedException { + return watch(watchFile, true); + } + + @NotNull + private LocalFileSystem.WatchRequest watch(final File watchFile, final boolean recursive) throws InterruptedException { + final LocalFileSystem.WatchRequest request = myFileSystem.addRootToWatch(watchFile.getAbsolutePath(), recursive); + assertNotNull(request); + TimeoutUtil.sleep(NATIVE_PROCESS_DELAY); + clearEvents(); + return request; + } + + private void unwatch(final LocalFileSystem.WatchRequest request) throws InterruptedException { + myFileSystem.removeWatchedRoot(request); + TimeoutUtil.sleep(NATIVE_PROCESS_DELAY); + clearEvents(); + } + + private VirtualFile refresh(final File file) { + final VirtualFile vFile = myFileSystem.refreshAndFindFileByIoFile(file); + assertNotNull(file.toString(), vFile); + VfsUtilCore.visitChildrenRecursively(vFile, new VirtualFileVisitor() { + @Override + public boolean visitFile(@NotNull VirtualFile file) { + file.getChildren(); + return true; + } + }); + return vFile; + } + + private void assertEvent(final Class type, final String... paths) throws InterruptedException { + final List events = getEvents(); + assertEquals(events.toString(), paths.length, events.size()); + + final Set pathSet = ContainerUtil.map2Set(paths, new Function() { + @Override + public String fun(final String path) { + return FileUtil.toSystemIndependentName(path); + } + }); + + for (final VFileEvent event : events) { + assertTrue(event.toString(), type.isInstance(event)); + + final VirtualFile eventFile = event.getFile(); + assertNotNull(event.toString(), eventFile); + + assertTrue(eventFile + " not in " + Arrays.toString(paths), pathSet.remove(eventFile.getPath())); + } + } +} diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/SymlinkHandlingTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/SymlinkHandlingTest.java index 025a888e1a20..2a8cb8d5d453 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/SymlinkHandlingTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/SymlinkHandlingTest.java @@ -266,7 +266,7 @@ public class SymlinkHandlingTest extends LightPlatformLangTestCase { } // todo[r.sh] use NIO2 API after migration to JDK 7 - private static File createTempLink(final String target, final String link) throws InterruptedException, ExecutionException { + public static File createTempLink(final String target, final String link) throws InterruptedException, ExecutionException { final boolean isAbsolute = SystemInfo.isUnix && StringUtil.startsWithChar(link, '/') || SystemInfo.isWindows && link.matches("^[c-zC-Z]:[/\\\\].*$"); final File linkFile = isAbsolute ? new File(link) : new File(FileUtil.getTempDirectory(), link); From d2898f101235a3dbabb0349c8e9e8a485f28d9b5 Mon Sep 17 00:00:00 2001 From: Alexander Lobas Date: Tue, 10 Apr 2012 21:58:59 +0400 Subject: [PATCH 19/30] AbsoluteLayout --- .../layout/AbsoluteLayoutOperation.java | 46 ++++++++++++ .../android/designer/icons/AbsoluteLayout.png | Bin 0 -> 462 bytes .../model/layout/RadAbsoluteLayout.java | 69 ++++++++++++++++++ .../designer/model/views-meta-model.xml | 18 +++++ 4 files changed, 133 insertions(+) create mode 100644 plugins/android-designer/src/com/intellij/android/designer/designSurface/layout/AbsoluteLayoutOperation.java create mode 100644 plugins/android-designer/src/com/intellij/android/designer/icons/AbsoluteLayout.png create mode 100644 plugins/android-designer/src/com/intellij/android/designer/model/layout/RadAbsoluteLayout.java diff --git a/plugins/android-designer/src/com/intellij/android/designer/designSurface/layout/AbsoluteLayoutOperation.java b/plugins/android-designer/src/com/intellij/android/designer/designSurface/layout/AbsoluteLayoutOperation.java new file mode 100644 index 000000000000..c42fec4c6987 --- /dev/null +++ b/plugins/android-designer/src/com/intellij/android/designer/designSurface/layout/AbsoluteLayoutOperation.java @@ -0,0 +1,46 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.android.designer.designSurface.layout; + +import com.intellij.android.designer.designSurface.AbstractEditOperation; +import com.intellij.android.designer.model.RadViewComponent; +import com.intellij.designer.designSurface.OperationContext; + +/** + * @author Alexander Lobas + */ +public class AbsoluteLayoutOperation extends AbstractEditOperation { + public AbsoluteLayoutOperation(RadViewComponent container, OperationContext context) { + super(container, context); + } + + @Override + public void showFeedback() { + // TODO: Auto-generated method stub + } + + @Override + public void eraseFeedback() { + // TODO: Auto-generated method stub + } + + @Override + public void execute() throws Exception { + if (!myContext.isMove()) { + super.execute(); + } + } +} \ No newline at end of file diff --git a/plugins/android-designer/src/com/intellij/android/designer/icons/AbsoluteLayout.png b/plugins/android-designer/src/com/intellij/android/designer/icons/AbsoluteLayout.png new file mode 100644 index 0000000000000000000000000000000000000000..382b11a207b13ab36b8fd3c9e4ae4065a9193b9a GIT binary patch literal 462 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|*pj^6T^Rm@ z;DWu&Cj&(|3p^r=85p>QL70(Y)*K0-AbW|YuPgg)MoAHAs|%iaxj-Sw64!_l=ltB< z)VvY~=c3falGGH1^30M91$R&1fbd2>aiCS2o-U3d7N?g68x|dM;E74A5R%m|aCVP- z(DwWTLmQLUbH)&x1OF9U3NGbw&E-F5;T!ODW4QL)bvD_v+;tLPCrTX>36gB;KEFTFar~q-VhFnaafeaskW4 z1#T?w40WZLRoFZQR6JVv@5gbjS@TTD?%HdwpzEbiE4Sa?>*bNwzp`s9f4j0u`(%N` zlegt|%Zna-ez|4gnM)^jWLV8VFPg{4u==XjY_VUv)=69HPvB#S(3`FhnX=d8gVrvc z&X)AM%-hTiZz}Kd*>E#QZT

9B0;=obG&E7OnENw*P37prKXr=E9z7LNnI)a~%$m zoiuf~f~n(!e selection) { + if (mySelectionDecorator == null) { + mySelectionDecorator = new ResizeSelectionDecorator(Color.red, 1); + ResizeOperation.points(mySelectionDecorator); + } + return mySelectionDecorator; + } +} \ No newline at end of file diff --git a/plugins/android-designer/src/com/intellij/android/designer/model/views-meta-model.xml b/plugins/android-designer/src/com/intellij/android/designer/model/views-meta-model.xml index d1f9fdf69833..8f9b927d0e53 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/model/views-meta-model.xml +++ b/plugins/android-designer/src/com/intellij/android/designer/model/views-meta-model.xml @@ -1074,6 +1074,24 @@ + + + + + + + + ]]> + + + From 0d13ec4cebf3f0ac0d4f6600a6faaa04a85f2899 Mon Sep 17 00:00:00 2001 From: Eugene Kudelevsky Date: Tue, 10 Apr 2012 22:02:04 +0400 Subject: [PATCH 20/30] IDEA-81559 informative warning about app->app dependency --- .../compiler/AndroidPrecompileTask.java | 47 +++++++++++++++++-- 1 file changed, 43 insertions(+), 4 deletions(-) diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidPrecompileTask.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidPrecompileTask.java index 3e71190f831e..577d46b4d98b 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/AndroidPrecompileTask.java +++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidPrecompileTask.java @@ -19,10 +19,7 @@ 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.CompilationStatusAdapter; -import com.intellij.openapi.compiler.CompileContext; -import com.intellij.openapi.compiler.CompileTask; -import com.intellij.openapi.compiler.CompilerManager; +import com.intellij.openapi.compiler.*; import com.intellij.openapi.compiler.options.ExcludeEntryDescription; import com.intellij.openapi.compiler.options.ExcludedEntriesConfiguration; import com.intellij.openapi.diagnostic.Logger; @@ -31,7 +28,10 @@ import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.DependencyScope; +import com.intellij.openapi.roots.ModuleOrderEntry; import com.intellij.openapi.roots.ModuleRootManager; +import com.intellij.openapi.roots.OrderEntry; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.LocalFileSystem; @@ -39,6 +39,7 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.containers.hash.HashSet; import org.jetbrains.android.facet.AndroidFacet; import org.jetbrains.android.facet.AndroidRootUtil; +import org.jetbrains.android.maven.AndroidMavenUtil; import org.jetbrains.android.sdk.AndroidPlatform; import org.jetbrains.android.util.AndroidCommonUtils; import org.jetbrains.annotations.NotNull; @@ -57,6 +58,8 @@ public class AndroidPrecompileTask implements CompileTask { @Override public boolean execute(CompileContext context) { + checkAndroidDependencies(context); + final Project project = context.getProject(); ExcludedEntriesConfiguration configuration = @@ -109,6 +112,42 @@ public class AndroidPrecompileTask implements CompileTask { } return true; } + + private static void checkAndroidDependencies(@NotNull CompileContext context) { + for (Module module : context.getCompileScope().getAffectedModules()) { + final AndroidFacet facet = AndroidFacet.getInstance(module); + + if (facet != null && !facet.getConfiguration().LIBRARY_PROJECT) { + + for (OrderEntry entry : ModuleRootManager.getInstance(module).getOrderEntries()) { + if (entry instanceof ModuleOrderEntry) { + final ModuleOrderEntry moduleOrderEntry = (ModuleOrderEntry)entry; + + if (moduleOrderEntry.getScope() == DependencyScope.COMPILE) { + final Module depModule = moduleOrderEntry.getModule(); + + if (depModule != null) { + final AndroidFacet depFacet = AndroidFacet.getInstance(depModule); + + if (depFacet != null && !depFacet.getConfiguration().LIBRARY_PROJECT) { + String message = "Suspicious module dependency " + + module.getName() + + " -> " + + depModule.getName() + + ": Android application module depends on other application module. Possibly, you should "; + if (AndroidMavenUtil.isMavenizedModule(depModule)) { + message += "change packaging type of module " + depModule.getName() + " to 'apklib' in pom.xml file or "; + } + message += "change dependency scope to 'Provided'."; + context.addMessage(CompilerMessageCategory.WARNING, message, null, -1, -1); + } + } + } + } + } + } + } + } private static void clearResCache(@NotNull AndroidFacet facet, @NotNull CompileContext context) { final Module module = facet.getModule(); From d6ada7f6e5b92de52aa9abf51c44084f9cfd1de1 Mon Sep 17 00:00:00 2001 From: anna Date: Tue, 10 Apr 2012 15:37:13 +0200 Subject: [PATCH 21/30] NPE (IDEA-51376) --- .../codeInspection/ui/ProjectInspectionToolsConfigurable.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/ProjectInspectionToolsConfigurable.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/ProjectInspectionToolsConfigurable.java index 56d9e859ffed..9d5b5143a75d 100644 --- a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/ProjectInspectionToolsConfigurable.java +++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/ProjectInspectionToolsConfigurable.java @@ -58,7 +58,8 @@ public class ProjectInspectionToolsConfigurable extends InspectionToolsConfigura @Override public boolean isModified() { - if (!Comparing.strEqual(getCurrentProfile().getName(), getSelectedObject().getName())) return true; + final InspectionProfileImpl selectedObject = getSelectedObject(); + if (selectedObject != null && !Comparing.strEqual(getCurrentProfile().getName(), selectedObject.getName())) return true; return super.isModified(); } } \ No newline at end of file From bdcae115407db1d27afbe2658960c436ef50a5bc Mon Sep 17 00:00:00 2001 From: anna Date: Tue, 10 Apr 2012 16:07:10 +0200 Subject: [PATCH 22/30] include all non-private methods in chooser to test (IDEA-59868) --- .../src/com/intellij/testIntegration/TestIntegrationUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/java-impl/src/com/intellij/testIntegration/TestIntegrationUtils.java b/java/java-impl/src/com/intellij/testIntegration/TestIntegrationUtils.java index ab378ccbc312..ef291f961544 100644 --- a/java/java-impl/src/com/intellij/testIntegration/TestIntegrationUtils.java +++ b/java/java-impl/src/com/intellij/testIntegration/TestIntegrationUtils.java @@ -118,7 +118,7 @@ public class TestIntegrationUtils { public boolean includeMember(PsiMember member) { if (!(member instanceof PsiMethod)) return false; PsiModifierList list = member.getModifierList(); - return list.hasModifierProperty(PsiModifier.PUBLIC); + return !list.hasModifierProperty(PsiModifier.PRIVATE); } }, false); clazz = clazz.getSuperClass(); From 91906892680ba9022732799cbe392ce1d365cb15 Mon Sep 17 00:00:00 2001 From: anna Date: Tue, 10 Apr 2012 16:45:52 +0200 Subject: [PATCH 23/30] EA-33743 - assert: RenameUtil.doRenameGenericNamedElement --- .../src/com/intellij/refactoring/rename/RenameUtil.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/refactoring/rename/RenameUtil.java b/platform/lang-impl/src/com/intellij/refactoring/rename/RenameUtil.java index e241dad57b2d..69f67380cd9c 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/rename/RenameUtil.java +++ b/platform/lang-impl/src/com/intellij/refactoring/rename/RenameUtil.java @@ -203,7 +203,7 @@ public class RenameUtil { }); } - public static void doRenameGenericNamedElement(PsiElement namedElement, String newName, UsageInfo[] usages, + public static void doRenameGenericNamedElement(@NotNull PsiElement namedElement, String newName, UsageInfo[] usages, @Nullable RefactoringElementListener listener) throws IncorrectOperationException { PsiWritableMetaData writableMetaData = null; if (namedElement instanceof PsiMetaOwner) { @@ -213,7 +213,7 @@ public class RenameUtil { } } if (writableMetaData == null && !(namedElement instanceof PsiNamedElement)) { - LOG.error("Unknown element type"); + LOG.error("Unknown element type:" + namedElement); } boolean hasBindables = false; From ccb85bd9e9ce6df6fb1f4471195cf4f187a564e9 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Tue, 10 Apr 2012 15:28:23 +0400 Subject: [PATCH 24/30] more thread safety --- .../openapi/vcs/changes/FilePathUnderVcs.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/FilePathUnderVcs.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/FilePathUnderVcs.java index b5e0e447a739..f3bed0b0a416 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/FilePathUnderVcs.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/FilePathUnderVcs.java @@ -20,11 +20,12 @@ import com.intellij.openapi.vcs.AbstractVcs; import com.intellij.openapi.vcs.FilePath; import com.intellij.openapi.vcs.FilePathImpl; import com.intellij.openapi.vcs.VcsRoot; +import org.jetbrains.annotations.NonNls; public class FilePathUnderVcs { private final FilePath myPath; private final AbstractVcs myVcs; - private int hashcode; + private int hashCode; public FilePathUnderVcs(final FilePath path, final AbstractVcs vcs) { myPath = path; @@ -59,13 +60,15 @@ public class FilePathUnderVcs { @Override public int hashCode() { - if (hashcode == 0) { - hashcode = myPath != null ? myPath.hashCode() : 0; - hashcode = 31 * hashcode + (myVcs != null ? myVcs.getName().hashCode() : 0); + if (hashCode == 0) { + int hc = myPath != null ? myPath.hashCode() : 0; + hc = 31 * hc + (myVcs != null ? myVcs.getName().hashCode() : 0); + hashCode = hc; } - return hashcode; + return hashCode; } + @NonNls @Override public String toString() { return "FilePathUnderVcs{" + From 3fd4a9900853e895eb89ceb22bc800334da6dd6e Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Wed, 11 Apr 2012 11:20:57 +0400 Subject: [PATCH 25/30] in case of floating editor, when intention popup opens, activeEditorsChanged(empty) called, causing intention popup to close --- .../daemon/impl/DaemonCodeAnalyzerImpl.java | 47 +++++++++++-------- .../daemon/impl/DaemonListeners.java | 24 ++++++---- .../editor/event/EditorFactoryAdapter.java | 2 + 3 files changed, 44 insertions(+), 29 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonCodeAnalyzerImpl.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonCodeAnalyzerImpl.java index 252b26675a03..b9e0f7d040af 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonCodeAnalyzerImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonCodeAnalyzerImpl.java @@ -114,7 +114,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx private volatile boolean allowToInterrupt = true; private StatusBarUpdater myStatusBarUpdater; - public DaemonCodeAnalyzerImpl(Project project, DaemonCodeAnalyzerSettings daemonCodeAnalyzerSettings, EditorTracker editorTracker) { + public DaemonCodeAnalyzerImpl(@NotNull Project project, DaemonCodeAnalyzerSettings daemonCodeAnalyzerSettings, EditorTracker editorTracker) { myProject = project; mySettings = daemonCodeAnalyzerSettings; @@ -125,7 +125,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx myPassExecutorService = new PassExecutorService(myProject) { @Override protected void afterApplyInformationToEditor(final TextEditorHighlightingPass pass, - final FileEditor fileEditor, + @NotNull final FileEditor fileEditor, final ProgressIndicator updateProgress) { if (fileEditor instanceof TextEditor) { log(updateProgress, pass, "Apply "); @@ -143,19 +143,20 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx Disposer.register(project, myFileStatusMap); } - static boolean hasErrors(Project project, Document document) { + static boolean hasErrors(@NotNull Project project, @NotNull Document document) { return !processHighlights(document, project, HighlightSeverity.ERROR, 0, document.getTextLength(), CommonProcessors.alwaysFalse()); } @NotNull @TestOnly - public static List getHighlights(Document document, HighlightSeverity minSeverity, Project project) { + public static List getHighlights(@NotNull Document document, HighlightSeverity minSeverity, @NotNull Project project) { List infos = new ArrayList(); processHighlights(document, project, minSeverity, 0, document.getTextLength(), new CommonProcessors.CollectProcessor(infos)); return infos; } + @NotNull public List runMainPasses(@NotNull PsiFile psiFile, @NotNull Document document, @NotNull final ProgressIndicator progress) { @@ -184,6 +185,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx return result; } + @NotNull @TestOnly public List runPasses(@NotNull PsiFile file, @NotNull Document document, @@ -326,7 +328,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx myLastSettings = null; } - void repaintErrorStripeRenderer(Editor editor) { + void repaintErrorStripeRenderer(@NotNull Editor editor) { if (!myProject.isInitialized()) return; final Document document = editor.getDocument(); final PsiFile psiFile = PsiDocumentManager.getInstance(myProject).getPsiFile(document); @@ -349,7 +351,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx dependencyValidationManager.reloadRules(); } - private static void addScopesToList(final List> scopeList, final NamedScopesHolder holder) { + private static void addScopesToList(@NotNull final List> scopeList, @NotNull final NamedScopesHolder holder) { NamedScope[] scopes = holder.getScopes(); for (NamedScope scope : scopes) { scopeList.add(Pair.create(scope, holder)); @@ -416,7 +418,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx } @Override - public boolean isHighlightingAvailable(PsiFile file) { + public boolean isHighlightingAvailable(@Nullable PsiFile file) { if (file == null || !file.isPhysical()) return false; if (myDisabledHighlightingFiles.contains(PsiUtilCore.getVirtualFile(file))) return false; @@ -453,6 +455,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx stopProcess(true); } + @NotNull public List getPassesToShowProgressFor(Document document) { List allPasses = myPassExecutorService.getAllSubmittedPasses(); List result = new ArrayList(allPasses.size()); @@ -472,7 +475,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx myFileStatusMap.allDirtyScopesAreNull(document); } - public boolean isErrorAnalyzingFinished(PsiFile file) { + public boolean isErrorAnalyzingFinished(@NotNull PsiFile file) { if (myDisposed) return false; Document document = PsiDocumentManager.getInstance(myProject).getCachedDocument(file); return document != null && @@ -480,6 +483,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx myFileStatusMap.getFileDirtyScope(document, Pass.UPDATE_ALL) == null; } + @NotNull public FileStatusMap getFileStatusMap() { return myFileStatusMap; } @@ -526,7 +530,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx MarkupModelEx model = (MarkupModelEx)DocumentMarkupModel.forDocument(document, project, true); return model.processRangeHighlightersOverlappingWith(startOffset, endOffset, new Processor() { @Override - public boolean process(RangeHighlighterEx marker) { + public boolean process(@NotNull RangeHighlighterEx marker) { Object tt = marker.getErrorStripeTooltip(); if (!(tt instanceof HighlightInfo)) return true; HighlightInfo info = (HighlightInfo)tt; @@ -549,7 +553,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx MarkupModelEx model = (MarkupModelEx)DocumentMarkupModel.forDocument(document, project, true); return model.processRangeHighlightersOutside(startOffset, endOffset, new Processor() { @Override - public boolean process(RangeHighlighterEx marker) { + public boolean process(@NotNull RangeHighlighterEx marker) { Object tt = marker.getErrorStripeTooltip(); if (!(tt instanceof HighlightInfo)) return true; HighlightInfo info = (HighlightInfo)tt; @@ -569,7 +573,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx @NotNull final Processor processor) { return processHighlights(document, project, null, 0, document.getTextLength(), new Processor() { @Override - public boolean process(HighlightInfo info) { + public boolean process(@NotNull HighlightInfo info) { if (!isOffsetInsideHighlightInfo(offset, info, includeFixRange)) return true; int compare = info.getSeverity().compareTo(minSeverity); @@ -579,11 +583,11 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx } @Nullable - public HighlightInfo findHighlightByOffset(Document document, final int offset, final boolean includeFixRange) { + public HighlightInfo findHighlightByOffset(@NotNull Document document, final int offset, final boolean includeFixRange) { final List foundInfoList = new SmartList(); processHighlightsNearOffset(document, myProject, HighlightSeverity.INFORMATION, offset, includeFixRange, new Processor() { @Override - public boolean process(HighlightInfo info) { + public boolean process(@NotNull HighlightInfo info) { if (!foundInfoList.isEmpty()) { HighlightInfo foundInfo = foundInfoList.get(0); int compare = foundInfo.getSeverity().compareTo(info.getSeverity()); @@ -604,7 +608,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx return new HighlightInfoComposite(foundInfoList); } - private static boolean isOffsetInsideHighlightInfo(int offset, HighlightInfo info, boolean includeFixRange) { + private static boolean isOffsetInsideHighlightInfo(int offset, @NotNull HighlightInfo info, boolean includeFixRange) { RangeHighlighterEx highlighter = info.highlighter; if (highlighter == null || !highlighter.isValid()) return false; int startOffset = highlighter.getStartOffset(); @@ -624,7 +628,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx } @Nullable - public static List getLineMarkers(Document document, Project project) { + public static List getLineMarkers(@NotNull Document document, Project project) { ApplicationManager.getApplication().assertIsDispatchThread(); MarkupModel markup = DocumentMarkupModel.forDocument(document, project, true); return markup.getUserData(MARKERS_IN_EDITOR_DOCUMENT_KEY); @@ -636,7 +640,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx markup.putUserData(MARKERS_IN_EDITOR_DOCUMENT_KEY, lineMarkers); } - public synchronized void setLastIntentionHint(Project project, PsiFile file, Editor editor, ShowIntentionsPass.IntentionsInfo intentions, boolean hasToRecreate) { + public synchronized void setLastIntentionHint(@NotNull Project project, @NotNull PsiFile file, @NotNull Editor editor, @NotNull ShowIntentionsPass.IntentionsInfo intentions, boolean hasToRecreate) { ApplicationManager.getApplication().assertIsDispatchThread(); hideLastIntentionHint(); IntentionHintComponent hintComponent = IntentionHintComponent.showIntentionHint(project, file, editor, intentions, false); @@ -653,12 +657,13 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx } } + @Nullable public synchronized IntentionHintComponent getLastIntentionHint() { return myLastIntentionHint; } @Override - public void writeExternal(Element parentNode) throws WriteExternalException { + public void writeExternal(@NotNull Element parentNode) throws WriteExternalException { Element disableHintsElement = new Element(DISABLE_HINTS_TAG); parentNode.addContent(disableHintsElement); @@ -678,7 +683,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx } @Override - public void readExternal(Element parentNode) throws InvalidDataException { + public void readExternal(@NotNull Element parentNode) throws InvalidDataException { myDisabledHintsFiles.clear(); Element element = parentNode.getChild(DISABLE_HINTS_TAG); @@ -697,6 +702,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx } } + @NotNull private Runnable createUpdateRunnable() { return new Runnable() { @Override @@ -754,6 +760,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx }; } + @NotNull private synchronized DaemonProgressIndicator createUpdateProgress() { DaemonProgressIndicator progress = new DaemonProgressIndicator() { @Override @@ -767,7 +774,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx return progress; } - public boolean canChangeFileSilently(PsiFileSystemItem file) { + public boolean canChangeFileSilently(@NotNull PsiFileSystemItem file) { return myDaemonListeners.canChangeFileSilently(file); } @@ -780,7 +787,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx @NotNull @TestOnly - public static List getFileLevelHighlights(Project project,PsiFile file ) { + public static List getFileLevelHighlights(@NotNull Project project, @NotNull PsiFile file ) { return UpdateHighlightersUtil.getFileLeveleHighlights(project, file); } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonListeners.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonListeners.java index 60d25f3665ed..61bced8f2d27 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonListeners.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonListeners.java @@ -148,20 +148,20 @@ class DaemonListeners implements Disposable { @Override public void activeEditorsChanged(@NotNull List editors) { List activeEditors = getActiveEditors(); - if (!myActiveEditors.equals(activeEditors)) { - myActiveEditors = activeEditors; - stopDaemon(true); // do not stop daemon if idea loses/gains focus - if (LaterInvocator.isInModalContext()) { - // editor appear in modal context, reenable the daemon - myDaemonCodeAnalyzer.setUpdateByTimerEnabled(true); - } - myDaemonCodeAnalyzer.hideLastIntentionHint(); // mem leak after closing last editor otherwise + if (myActiveEditors.equals(activeEditors)) { + return; + } + myActiveEditors = activeEditors; + stopDaemon(true); // do not stop daemon if idea loses/gains focus + if (LaterInvocator.isInModalContext()) { + // editor appear in modal context, re-enable the daemon + myDaemonCodeAnalyzer.setUpdateByTimerEnabled(true); } } }; myEditorTracker.addEditorTrackerListener(editorTrackerListener, this); - EditorFactoryListener editorFactoryListener = new EditorFactoryAdapter() { + EditorFactoryListener editorFactoryListener = new EditorFactoryListener() { @Override public void editorCreated(@NotNull EditorFactoryEvent event) { Editor editor = event.getEditor(); @@ -175,6 +175,12 @@ class DaemonListeners implements Disposable { } myDaemonCodeAnalyzer.repaintErrorStripeRenderer(editor); } + + @Override + public void editorReleased(@NotNull EditorFactoryEvent event) { + // mem leak after closing last editor otherwise + myDaemonCodeAnalyzer.hideLastIntentionHint(); + } }; EditorFactory.getInstance().addEditorFactoryListener(editorFactoryListener, this); diff --git a/platform/platform-api/src/com/intellij/openapi/editor/event/EditorFactoryAdapter.java b/platform/platform-api/src/com/intellij/openapi/editor/event/EditorFactoryAdapter.java index 79c53b939203..3f3fb311ee8e 100644 --- a/platform/platform-api/src/com/intellij/openapi/editor/event/EditorFactoryAdapter.java +++ b/platform/platform-api/src/com/intellij/openapi/editor/event/EditorFactoryAdapter.java @@ -21,9 +21,11 @@ import org.jetbrains.annotations.NotNull; * @author max */ public abstract class EditorFactoryAdapter implements EditorFactoryListener { + @Override public void editorCreated(@NotNull EditorFactoryEvent event) { } + @Override public void editorReleased(@NotNull EditorFactoryEvent event) { } } From 2aacbb79367b4bb757c9f499fab3d2ddfc869ea8 Mon Sep 17 00:00:00 2001 From: anna Date: Wed, 11 Apr 2012 09:23:53 +0200 Subject: [PATCH 26/30] log errors during find usages (IDEA-84373) --- .../com/intellij/refactoring/BaseRefactoringProcessor.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/refactoring/BaseRefactoringProcessor.java b/platform/lang-impl/src/com/intellij/refactoring/BaseRefactoringProcessor.java index f54194be7251..d5cb1d5dd353 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/BaseRefactoringProcessor.java +++ b/platform/lang-impl/src/com/intellij/refactoring/BaseRefactoringProcessor.java @@ -173,9 +173,7 @@ public abstract class BaseRefactoringProcessor { } catch (Throwable e) { anyException.set(Boolean.TRUE); - if (ApplicationManager.getApplication().isUnitTestMode()) { - LOG.error(e); - } + LOG.error(e); } } }; From a9d2bee8e633f4dbb2b92d367fba6230fca8cffe Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Wed, 11 Apr 2012 09:40:52 +0200 Subject: [PATCH 27/30] IDEA-84093 (augment library classes) --- .../psi/impl/compiled/ClsClassImpl.java | 138 ++++++++++-------- .../psi/impl/source/ClassInnerStuffCache.java | 24 ++- .../psi/impl/source/PsiClassImpl.java | 26 +++- .../psi/impl/source/PsiExtensibleClass.java | 34 +++++ .../util/src/com/intellij/util/ArrayUtil.java | 19 ++- 5 files changed, 152 insertions(+), 89 deletions(-) create mode 100644 java/java-psi-impl/src/com/intellij/psi/impl/source/PsiExtensibleClass.java diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsClassImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsClassImpl.java index e65932502fce..68ea27d5a7b0 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsClassImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsClassImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 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. @@ -30,31 +30,31 @@ import com.intellij.psi.impl.PsiImplUtil; import com.intellij.psi.impl.PsiSuperMethodImplUtil; import com.intellij.psi.impl.java.stubs.JavaStubElementTypes; import com.intellij.psi.impl.java.stubs.PsiClassStub; -import com.intellij.psi.impl.source.ClassInnerStuffCache; -import com.intellij.psi.impl.source.Constants; -import com.intellij.psi.impl.source.PsiClassImpl; -import com.intellij.psi.impl.source.SourceTreeToPsiMap; +import com.intellij.psi.impl.source.*; import com.intellij.psi.impl.source.tree.TreeElement; import com.intellij.psi.javadoc.PsiDocComment; import com.intellij.psi.scope.PsiScopeProcessor; import com.intellij.psi.search.SearchScope; +import com.intellij.util.ArrayUtil; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; +import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Map; -public class ClsClassImpl extends ClsRepositoryPsiElement> implements PsiClass, PsiQualifiedNamedElement, Queryable { +public class ClsClassImpl extends ClsRepositoryPsiElement> implements PsiExtensibleClass, PsiQualifiedNamedElement, Queryable { + public static final Key DELEGATE_KEY = Key.create("DELEGATE"); + private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.compiled.ClsClassImpl"); - private final ClassInnerStuffCache innersCache = new ClassInnerStuffCache(this); + private final ClassInnerStuffCache myInnersCache = new ClassInnerStuffCache(this); private final PsiIdentifier myNameIdentifier; private final PsiDocComment myDocComment; - public static final Key DELEGATE_KEY = Key.create("DELEGATE"); public ClsClassImpl(final PsiClassStub stub) { super(stub); @@ -70,9 +70,9 @@ public class ClsClassImpl extends ClsRepositoryPsiElement> imple PsiModifierList modifierList = getModifierList(); PsiReferenceList extendsList = getExtendsList(); PsiReferenceList implementsList = getImplementsList(); - PsiField[] fields = getFields(); - PsiMethod[] methods = getMethods(); - PsiClass[] classes = getInnerClasses(); + List fields = getOwnFields(); + List methods = getOwnMethods(); + List classes = getOwnInnerClasses(); int count = (docComment != null ? 1 : 0) @@ -80,9 +80,9 @@ public class ClsClassImpl extends ClsRepositoryPsiElement> imple + 1 // name + 1 // extends list + 1 // implementsList - + fields.length - + methods.length - + classes.length; + + fields.size() + + methods.size() + + classes.size(); PsiElement[] children = new PsiElement[count]; int offset = 0; @@ -95,12 +95,12 @@ public class ClsClassImpl extends ClsRepositoryPsiElement> imple children[offset++] = extendsList; children[offset++] = implementsList; - System.arraycopy(fields, 0, children, offset, fields.length); - offset += fields.length; - System.arraycopy(methods, 0, children, offset, methods.length); - offset += methods.length; - System.arraycopy(classes, 0, children, offset, classes.length); - /*offset += classes.length;*/ + ArrayUtil.copy(fields, children, offset); + offset += fields.size(); + ArrayUtil.copy(methods, children, offset); + offset += methods.size(); + ArrayUtil.copy(classes, children, offset); + /*offset += classes.size();*/ return children; } @@ -166,7 +166,6 @@ public class ClsClassImpl extends ClsRepositoryPsiElement> imple return getStub().findChildStubByType(JavaStubElementTypes.EXTENDS_LIST).getPsi(); } - @Override @NotNull public PsiReferenceList getImplementsList() { @@ -222,25 +221,43 @@ public class ClsClassImpl extends ClsRepositoryPsiElement> imple @Override @NotNull public PsiField[] getFields() { - return getStub().getChildrenByType(Constants.FIELD_BIT_SET, PsiField.ARRAY_FACTORY); + return myInnersCache.getFields(); } @Override @NotNull public PsiMethod[] getMethods() { - return getStub().getChildrenByType(Constants.METHOD_BIT_SET, PsiMethod.ARRAY_FACTORY); + return myInnersCache.getMethods(); } @Override @NotNull public PsiMethod[] getConstructors() { - return PsiImplUtil.getConstructors(this); + return myInnersCache.getConstructors(); } @Override @NotNull public PsiClass[] getInnerClasses() { - return getStub().getChildrenByType(JavaStubElementTypes.CLASS, ARRAY_FACTORY); + return myInnersCache.getInnerClasses(); + } + + @NotNull + @Override + public List getOwnFields() { + return Arrays.asList(getStub().getChildrenByType(Constants.FIELD_BIT_SET, PsiField.ARRAY_FACTORY)); + } + + @NotNull + @Override + public List getOwnMethods() { + return Arrays.asList(getStub().getChildrenByType(Constants.METHOD_BIT_SET, PsiMethod.ARRAY_FACTORY)); + } + + @NotNull + @Override + public List getOwnInnerClasses() { + return Arrays.asList(getStub().getChildrenByType(JavaStubElementTypes.CLASS, ARRAY_FACTORY)); } @Override @@ -275,7 +292,7 @@ public class ClsClassImpl extends ClsRepositoryPsiElement> imple @Override public PsiField findFieldByName(String name, boolean checkBases) { - return innersCache.findFieldByName(name, checkBases); + return myInnersCache.findFieldByName(name, checkBases); } @Override @@ -292,7 +309,7 @@ public class ClsClassImpl extends ClsRepositoryPsiElement> imple @Override @NotNull public PsiMethod[] findMethodsByName(String name, boolean checkBases) { - return innersCache.findMethodsByName(name, checkBases); + return myInnersCache.findMethodsByName(name, checkBases); } @Override @@ -309,7 +326,7 @@ public class ClsClassImpl extends ClsRepositoryPsiElement> imple @Override public PsiClass findInnerClassByName(String name, boolean checkBases) { - return innersCache.findInnerClassByName(name, checkBases); + return myInnersCache.findInnerClassByName(name, checkBases); } @Override @@ -386,50 +403,50 @@ public class ClsClassImpl extends ClsRepositoryPsiElement> imple } buffer.append('{'); final int newIndentLevel = indentLevel + getIndentSize(); - PsiField[] fields = getFields(); - if (fields.length > 0) { + List fields = getOwnFields(); + if (fields.size() > 0) { goNextLine(newIndentLevel, buffer); - for (int i = 0; i < fields.length; i++) { - PsiField field = fields[i]; + for (int i = 0; i < fields.size(); i++) { + PsiField field = fields.get(i); ((ClsElementImpl)field).appendMirrorText(newIndentLevel, buffer); if (field instanceof ClsEnumConstantImpl) { - if (i < fields.length - 1 && fields[i + 1] instanceof ClsEnumConstantImpl) { + if (i < fields.size() - 1 && fields.get(i + 1) instanceof ClsEnumConstantImpl) { buffer.append(", "); } else { buffer.append(";"); - if (i < fields.length - 1) { + if (i < fields.size() - 1) { goNextLine(newIndentLevel, buffer); } } - } else if (i < fields.length - 1) { + } else if (i < fields.size() - 1) { goNextLine(newIndentLevel, buffer); } } } - PsiMethod[] methods = getMethods(); - if (methods.length > 0) { + List methods = getOwnMethods(); + if (methods.size() > 0) { goNextLine(newIndentLevel, buffer); goNextLine(newIndentLevel, buffer); - for (int i = 0; i < methods.length; i++) { - PsiMethod method = methods[i]; + for (int i = 0; i < methods.size(); i++) { + PsiMethod method = methods.get(i); ((ClsElementImpl)method).appendMirrorText(newIndentLevel, buffer); - if (i < methods.length - 1) { + if (i < methods.size() - 1) { goNextLine(newIndentLevel, buffer); goNextLine(newIndentLevel, buffer); } } } - PsiClass[] classes = getInnerClasses(); - if (classes.length > 0) { + List classes = getOwnInnerClasses(); + if (classes.size() > 0) { goNextLine(newIndentLevel, buffer); goNextLine(newIndentLevel, buffer); - for (int i = 0; i < classes.length; i++) { - PsiClass aClass = classes[i]; + for (int i = 0; i < classes.size(); i++) { + PsiClass aClass = classes.get(i); ((ClsElementImpl)aClass).appendMirrorText(newIndentLevel, buffer); - if (i < classes.length - 1) { + if (i < classes.size() - 1) { goNextLine(newIndentLevel, buffer); goNextLine(newIndentLevel, buffer); } @@ -459,37 +476,37 @@ public class ClsClassImpl extends ClsRepositoryPsiElement> imple Ref extLog = Ref.create(true); - PsiField[] fields = getFields(); + List fields = getOwnFields(); PsiField[] mirrorFields = mirror.getFields(); - if (fields.length == mirrorFields.length) { - for (int i = 0; i < fields.length; i++) { - ((ClsElementImpl)fields[i]).setMirror(SourceTreeToPsiMap.psiToTreeNotNull(mirrorFields[i])); + if (fields.size() == mirrorFields.length) { + for (int i = 0; i < fields.size(); i++) { + ((ClsElementImpl)fields.get(i)).setMirror(SourceTreeToPsiMap.psiToTreeNotNull(mirrorFields[i])); } } else { - log(this, mirror, "fields:" + fields.length + "!=" + mirrorFields.length, extLog); + log(this, mirror, "fields:" + fields.size() + "!=" + mirrorFields.length, extLog); } - PsiMethod[] methods = getMethods(); + List methods = getOwnMethods(); PsiMethod[] mirrorMethods = mirror.getMethods(); - if (methods.length == mirrorMethods.length) { - for (int i = 0; i < methods.length; i++) { - ((ClsElementImpl)methods[i]).setMirror(SourceTreeToPsiMap.psiToTreeNotNull(mirrorMethods[i])); + if (methods.size() == mirrorMethods.length) { + for (int i = 0; i < methods.size(); i++) { + ((ClsElementImpl)methods.get(i)).setMirror(SourceTreeToPsiMap.psiToTreeNotNull(mirrorMethods[i])); } } else { - log(this, mirror, "methods:" + methods.length + "!=" + mirrorMethods.length, extLog); + log(this, mirror, "methods:" + methods.size() + "!=" + mirrorMethods.length, extLog); } - PsiClass[] classes = getInnerClasses(); + List classes = getOwnInnerClasses(); PsiClass[] mirrorClasses = mirror.getInnerClasses(); - if (classes.length == mirrorClasses.length) { - for (int i = 0; i < classes.length; i++) { - ((ClsElementImpl)classes[i]).setMirror(SourceTreeToPsiMap.psiToTreeNotNull(mirrorClasses[i])); + if (classes.size() == mirrorClasses.length) { + for (int i = 0; i < classes.size(); i++) { + ((ClsElementImpl)classes.get(i)).setMirror(SourceTreeToPsiMap.psiToTreeNotNull(mirrorClasses[i])); } } else { - log(this, mirror, "classes:" + classes.length + "!=" + mirrorClasses.length, extLog); + log(this, mirror, "classes:" + classes.size() + "!=" + mirrorClasses.length, extLog); } } @@ -628,5 +645,4 @@ public class ClsClassImpl extends ClsRepositoryPsiElement> imple protected boolean isVisibilitySupported() { return true; } - } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/ClassInnerStuffCache.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/ClassInnerStuffCache.java index 3a0afa1d0b46..d08934a61d44 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/ClassInnerStuffCache.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/ClassInnerStuffCache.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 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. @@ -37,7 +37,7 @@ import java.util.List; import java.util.Map; public class ClassInnerStuffCache { - private final PsiClass myClass; + private final PsiExtensibleClass myClass; private final MyModificationTracker myTreeChangeTracker; private CachedValue myConstructorsCache; @@ -48,7 +48,7 @@ public class ClassInnerStuffCache { private CachedValue>> myMethodsMapCache; private CachedValue> myInnerClassesMapCache; - public ClassInnerStuffCache(final PsiClass aClass) { + public ClassInnerStuffCache(final PsiExtensibleClass aClass) { myClass = aClass; myTreeChangeTracker = new MyModificationTracker(); } @@ -197,27 +197,21 @@ public class ClassInnerStuffCache { } private PsiField[] getAllFields() { - if (!(myClass instanceof PsiClassImpl)) return myClass.getFields(); - - final PsiField[] own = ((PsiClassImpl)myClass).getStubOrPsiChildren(Constants.FIELD_BIT_SET, PsiField.ARRAY_FACTORY); + final List own = myClass.getOwnFields(); final List ext = PsiAugmentProvider.collectAugments(myClass, PsiField.class); - return ArrayUtil.mergeArrayAndCollection(own, ext, PsiField.ARRAY_FACTORY); + return ArrayUtil.mergeCollections(own, ext, PsiField.ARRAY_FACTORY); } private PsiMethod[] getAllMethods() { - if (!(myClass instanceof PsiClassImpl)) return myClass.getMethods(); - - final PsiMethod[] own = ((PsiClassImpl)myClass).getStubOrPsiChildren(Constants.METHOD_BIT_SET, PsiMethod.ARRAY_FACTORY); + final List own = myClass.getOwnMethods(); final List ext = PsiAugmentProvider.collectAugments(myClass, PsiMethod.class); - return ArrayUtil.mergeArrayAndCollection(own, ext, PsiMethod.ARRAY_FACTORY); + return ArrayUtil.mergeCollections(own, ext, PsiMethod.ARRAY_FACTORY); } private PsiClass[] getAllInnerClasses() { - if (!(myClass instanceof PsiClassImpl)) return myClass.getInnerClasses(); - - final PsiClass[] own = ((PsiClassImpl)myClass).getInnerClassesRaw(); + final List own = myClass.getOwnInnerClasses(); final List ext = PsiAugmentProvider.collectAugments(myClass, PsiClass.class); - return ArrayUtil.mergeArrayAndCollection(own, ext, PsiClass.ARRAY_FACTORY); + return ArrayUtil.mergeCollections(own, ext, PsiClass.ARRAY_FACTORY); } @Nullable diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiClassImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiClassImpl.java index 186b3430cb39..eee618e80bff 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiClassImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiClassImpl.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. @@ -45,11 +45,12 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; +import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Map; -public class PsiClassImpl extends JavaStubPsiElement> implements PsiClass, PsiQualifiedNamedElement, Queryable { +public class PsiClassImpl extends JavaStubPsiElement> implements PsiExtensibleClass, PsiQualifiedNamedElement, Queryable { private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.PsiClassImpl"); private final ClassInnerStuffCache myInnersCache = new ClassInnerStuffCache(this); @@ -75,7 +76,6 @@ public class PsiClassImpl extends JavaStubPsiElement> implements @Override public void subtreeChanged() { dropCaches(); - super.subtreeChanged(); } @@ -87,9 +87,7 @@ public class PsiClassImpl extends JavaStubPsiElement> implements @Override protected Object clone() { PsiClassImpl clone = (PsiClassImpl)super.clone(); - clone.dropCaches(); - return clone; } @@ -299,8 +297,21 @@ public class PsiClassImpl extends JavaStubPsiElement> implements } @NotNull - public PsiClass[] getInnerClassesRaw() { - return getStubOrPsiChildren(JavaStubElementTypes.CLASS, ARRAY_FACTORY); + @Override + public List getOwnFields() { + return Arrays.asList(getStubOrPsiChildren(Constants.FIELD_BIT_SET, PsiField.ARRAY_FACTORY)); + } + + @NotNull + @Override + public List getOwnMethods() { + return Arrays.asList(getStubOrPsiChildren(Constants.METHOD_BIT_SET, PsiMethod.ARRAY_FACTORY)); + } + + @NotNull + @Override + public List getOwnInnerClasses() { + return Arrays.asList(getStubOrPsiChildren(JavaStubElementTypes.CLASS, ARRAY_FACTORY)); } @Override @@ -577,6 +588,7 @@ public class PsiClassImpl extends JavaStubPsiElement> implements final StubElement parentStub = stub.getParentStub(); final StubBasedPsiElementBase context = (StubBasedPsiElementBase)parentStub.getPsi(); + @SuppressWarnings("unchecked") PsiClass[] classesInScope = (PsiClass[])parentStub.getChildrenByType(Constants.CLASS_BIT_SET, ARRAY_FACTORY); boolean needPreciseContext = false; diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiExtensibleClass.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiExtensibleClass.java new file mode 100644 index 000000000000..781e75ced7a5 --- /dev/null +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiExtensibleClass.java @@ -0,0 +1,34 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.psi.impl.source; + +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiField; +import com.intellij.psi.PsiMethod; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +public interface PsiExtensibleClass extends PsiClass { + @NotNull + List getOwnFields(); + + @NotNull + List getOwnMethods(); + + @NotNull + List getOwnInnerClasses(); +} diff --git a/platform/util/src/com/intellij/util/ArrayUtil.java b/platform/util/src/com/intellij/util/ArrayUtil.java index d54b0d612219..081ac6923cd6 100644 --- a/platform/util/src/com/intellij/util/ArrayUtil.java +++ b/platform/util/src/com/intellij/util/ArrayUtil.java @@ -648,13 +648,16 @@ public class ArrayUtil extends ArrayUtilRt { return indexOf(objects, o) >= 0; } + @NotNull public static int[] newIntArray(int count) { return count == 0 ? EMPTY_INT_ARRAY : new int[count]; } + @NotNull public static String[] newStringArray(int count) { return count == 0 ? EMPTY_STRING_ARRAY : new String[count]; } + @NotNull public static Object[] newObjectArray(int count) { return count == 0 ? EMPTY_OBJECT_ARRAY : new Object[count]; @@ -664,7 +667,9 @@ public class ArrayUtil extends ArrayUtilRt { public static E[] ensureExactSize(int count, @NotNull E[] sample) { if (count == sample.length) return sample; - return (E[])Array.newInstance(sample.getClass().getComponentType(), count); + @SuppressWarnings({"unchecked", "UnnecessaryLocalVariable"}) + final E[] array = (E[])Array.newInstance(sample.getClass().getComponentType(), count); + return array; } @Nullable @@ -677,13 +682,15 @@ public class ArrayUtil extends ArrayUtilRt { return array.length > 0 ? array[array.length - 1] : null; } - /** @deprecated use {@linkplain #mergeArrays(Object[], Object[])} (to remove in IDEA 12) */ - public static T[] join(T[] array1, T[] array2) { - return mergeArrays(array1, array2); - } - @NotNull public static String[] toStringArray(@NotNull Collection collection) { return ArrayUtilRt.toStringArray(collection); } + + public static void copy(@NotNull final Collection src, @NotNull final T[] dst, final int dstOffset) { + int i = dstOffset; + for (T t : src) { + dst[i++] = t; + } + } } From 543bb4e69e508fbd88e6b0dc0e390dbdcfbab99a Mon Sep 17 00:00:00 2001 From: anna Date: Wed, 11 Apr 2012 10:08:55 +0200 Subject: [PATCH 28/30] NPE --- .../codeInspection/deadCode/UnusedDeclarationInspection.java | 1 + 1 file changed, 1 insertion(+) diff --git a/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationInspection.java b/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationInspection.java index 5a00b75a97f0..7a1b3d99a552 100644 --- a/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationInspection.java @@ -373,6 +373,7 @@ public class UnusedDeclarationInspection extends FilteringInspectionTool { @Override public void visitClass(RefClass aClass) { final PsiClass psiClass = aClass.getElement(); + if (psiClass == null) return; if ( isAddAppletEnabled() && aClass.isApplet() || isAddServletEnabled() && aClass.isServlet()) { From 1164fdf07876c75fc809afdd3c4a6fc63280ccc6 Mon Sep 17 00:00:00 2001 From: Dmitry Boulytchev Date: Wed, 11 Apr 2012 12:08:21 +0400 Subject: [PATCH 29/30] Added test on adding class (compile-server). --- .../incremental/common/addClass.log | 9 + .../incremental/common/addClass/.idea/.name | 1 + .../incremental/common/addClass/.idea/ant.xml | 7 + .../common/addClass/.idea/compiler.xml | 21 + .../.idea/copyright/profiles_settings.xml | 5 + .../common/addClass/.idea/encodings.xml | 5 + .../common/addClass/.idea/misc.xml | 13 + .../common/addClass/.idea/modules.xml | 10 + .../addClass/.idea/scopes/scope_settings.xml | 5 + .../common/addClass/.idea/uiDesigner.xml | 125 ++++ .../incremental/common/addClass/.idea/vcs.xml | 7 + .../common/addClass/.idea/workspace.xml | 559 ++++++++++++++++++ .../incremental/common/addClass/Util.java.new | 5 + .../incremental/common/addClass/addClass.iml | 13 + .../common/addClass/common/common.iml | 12 + .../common/addClass/common/src/Util.java | 12 + .../common/addClass/src/Client.java | 12 + .../org/jetbrains/ether/CommonTest.java | 6 +- 18 files changed, 826 insertions(+), 1 deletion(-) create mode 100644 java/java-tests/testData/compileServer/incremental/common/addClass.log create mode 100644 java/java-tests/testData/compileServer/incremental/common/addClass/.idea/.name create mode 100644 java/java-tests/testData/compileServer/incremental/common/addClass/.idea/ant.xml create mode 100644 java/java-tests/testData/compileServer/incremental/common/addClass/.idea/compiler.xml create mode 100644 java/java-tests/testData/compileServer/incremental/common/addClass/.idea/copyright/profiles_settings.xml create mode 100644 java/java-tests/testData/compileServer/incremental/common/addClass/.idea/encodings.xml create mode 100644 java/java-tests/testData/compileServer/incremental/common/addClass/.idea/misc.xml create mode 100644 java/java-tests/testData/compileServer/incremental/common/addClass/.idea/modules.xml create mode 100644 java/java-tests/testData/compileServer/incremental/common/addClass/.idea/scopes/scope_settings.xml create mode 100644 java/java-tests/testData/compileServer/incremental/common/addClass/.idea/uiDesigner.xml create mode 100644 java/java-tests/testData/compileServer/incremental/common/addClass/.idea/vcs.xml create mode 100644 java/java-tests/testData/compileServer/incremental/common/addClass/.idea/workspace.xml create mode 100644 java/java-tests/testData/compileServer/incremental/common/addClass/Util.java.new create mode 100644 java/java-tests/testData/compileServer/incremental/common/addClass/addClass.iml create mode 100644 java/java-tests/testData/compileServer/incremental/common/addClass/common/common.iml create mode 100644 java/java-tests/testData/compileServer/incremental/common/addClass/common/src/Util.java create mode 100644 java/java-tests/testData/compileServer/incremental/common/addClass/src/Client.java diff --git a/java/java-tests/testData/compileServer/incremental/common/addClass.log b/java/java-tests/testData/compileServer/incremental/common/addClass.log new file mode 100644 index 000000000000..5aaf6b1395b6 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/common/addClass.log @@ -0,0 +1,9 @@ +Compiling files: +src/Util.java +End of files +Cleaning output files: +out/production/addClass/Client.class +End of files +Compiling files: +src/Client.java +End of files diff --git a/java/java-tests/testData/compileServer/incremental/common/addClass/.idea/.name b/java/java-tests/testData/compileServer/incremental/common/addClass/.idea/.name new file mode 100644 index 000000000000..d13bc4b0b367 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/common/addClass/.idea/.name @@ -0,0 +1 @@ +addClass \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/common/addClass/.idea/ant.xml b/java/java-tests/testData/compileServer/incremental/common/addClass/.idea/ant.xml new file mode 100644 index 000000000000..2581ca3fe84c --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/common/addClass/.idea/ant.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/java/java-tests/testData/compileServer/incremental/common/addClass/.idea/compiler.xml b/java/java-tests/testData/compileServer/incremental/common/addClass/.idea/compiler.xml new file mode 100644 index 000000000000..a1b41c52c724 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/common/addClass/.idea/compiler.xml @@ -0,0 +1,21 @@ + + + + + + diff --git a/java/java-tests/testData/compileServer/incremental/common/addClass/.idea/copyright/profiles_settings.xml b/java/java-tests/testData/compileServer/incremental/common/addClass/.idea/copyright/profiles_settings.xml new file mode 100644 index 000000000000..3572571ad83c --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/common/addClass/.idea/copyright/profiles_settings.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/common/addClass/.idea/encodings.xml b/java/java-tests/testData/compileServer/incremental/common/addClass/.idea/encodings.xml new file mode 100644 index 000000000000..e206d70d8595 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/common/addClass/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/java/java-tests/testData/compileServer/incremental/common/addClass/.idea/misc.xml b/java/java-tests/testData/compileServer/incremental/common/addClass/.idea/misc.xml new file mode 100644 index 000000000000..9a249d2930c5 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/common/addClass/.idea/misc.xml @@ -0,0 +1,13 @@ + + + + + + + http://www.w3.org/1999/xhtml + + + + + + diff --git a/java/java-tests/testData/compileServer/incremental/common/addClass/.idea/modules.xml b/java/java-tests/testData/compileServer/incremental/common/addClass/.idea/modules.xml new file mode 100644 index 000000000000..ecefc643826b --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/common/addClass/.idea/modules.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/java/java-tests/testData/compileServer/incremental/common/addClass/.idea/scopes/scope_settings.xml b/java/java-tests/testData/compileServer/incremental/common/addClass/.idea/scopes/scope_settings.xml new file mode 100644 index 000000000000..922003b8433b --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/common/addClass/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/common/addClass/.idea/uiDesigner.xml b/java/java-tests/testData/compileServer/incremental/common/addClass/.idea/uiDesigner.xml new file mode 100644 index 000000000000..3b0002030884 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/common/addClass/.idea/uiDesigner.xml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/java/java-tests/testData/compileServer/incremental/common/addClass/.idea/vcs.xml b/java/java-tests/testData/compileServer/incremental/common/addClass/.idea/vcs.xml new file mode 100644 index 000000000000..def6a6a18457 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/common/addClass/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/java/java-tests/testData/compileServer/incremental/common/addClass/.idea/workspace.xml b/java/java-tests/testData/compileServer/incremental/common/addClass/.idea/workspace.xml new file mode 100644 index 000000000000..1ce5e7bc1f83 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/common/addClass/.idea/workspace.xml @@ -0,0 +1,559 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + localhost + 5050 + + + + + + + + 1334130093404 + 1334130093404 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + No facets are configured + + + + + + + + Gant + + + + + + + + IDEA jdk + + + + + + + + addClass + + + + + + + + IDEA jdk + + + + + + + + + + + + + + + + diff --git a/java/java-tests/testData/compileServer/incremental/common/addClass/Util.java.new b/java/java-tests/testData/compileServer/incremental/common/addClass/Util.java.new new file mode 100644 index 000000000000..1141151cae45 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/common/addClass/Util.java.new @@ -0,0 +1,5 @@ +public class Util { + public static void foo (int x) { + + } +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/common/addClass/addClass.iml b/java/java-tests/testData/compileServer/incremental/common/addClass/addClass.iml new file mode 100644 index 000000000000..0898b5451031 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/common/addClass/addClass.iml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/java/java-tests/testData/compileServer/incremental/common/addClass/common/common.iml b/java/java-tests/testData/compileServer/incremental/common/addClass/common/common.iml new file mode 100644 index 000000000000..d5c074327501 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/common/addClass/common/common.iml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/java/java-tests/testData/compileServer/incremental/common/addClass/common/src/Util.java b/java/java-tests/testData/compileServer/incremental/common/addClass/common/src/Util.java new file mode 100644 index 000000000000..ce35affc1568 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/common/addClass/common/src/Util.java @@ -0,0 +1,12 @@ +/** + * Created with IntelliJ IDEA. + * User: db + * Date: 11.04.12 + * Time: 11:43 + * To change this template use File | Settings | File Templates. + */ +public class Util { + public static void foo () { + + } +} diff --git a/java/java-tests/testData/compileServer/incremental/common/addClass/src/Client.java b/java/java-tests/testData/compileServer/incremental/common/addClass/src/Client.java new file mode 100644 index 000000000000..04b7ad769077 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/common/addClass/src/Client.java @@ -0,0 +1,12 @@ +/** + * Created with IntelliJ IDEA. + * User: db + * Date: 11.04.12 + * Time: 11:43 + * To change this template use File | Settings | File Templates. + */ +public class Client { + { + Util.foo(); + } +} diff --git a/jps/jps-builders/testSrc/org/jetbrains/ether/CommonTest.java b/jps/jps-builders/testSrc/org/jetbrains/ether/CommonTest.java index 6d9596c3b71c..9a36f6d40ee7 100644 --- a/jps/jps-builders/testSrc/org/jetbrains/ether/CommonTest.java +++ b/jps/jps-builders/testSrc/org/jetbrains/ether/CommonTest.java @@ -77,6 +77,10 @@ public class CommonTest extends IncrementalTestCase { } public void testDeleteClass4() throws Exception { - doTest(); + doTest(); + } + + public void testAddClass() throws Exception { + doTest(); } } From ec55118a78d6d33739baab27ac3868de7a62666d Mon Sep 17 00:00:00 2001 From: peter Date: Wed, 11 Apr 2012 10:10:55 +0200 Subject: [PATCH 30/30] debugging p4 test --- .../openapi/vcs/changes/UpdatingChangeListBuilder.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/UpdatingChangeListBuilder.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/UpdatingChangeListBuilder.java index e921957a81e8..d52e8aafbf25 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/UpdatingChangeListBuilder.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/UpdatingChangeListBuilder.java @@ -164,6 +164,10 @@ class UpdatingChangeListBuilder implements ChangelistBuilder { checkIfDisposed(); if (isExcluded(file)) return; if (myScope.belongsTo(new FilePathImpl(file))) { + if (ChangeListManagerImpl.DEBUG) { + System.out.println("UpdatingChangeListBuilder.processModifiedWithoutCheckout"); + System.out.println("file = " + file); + } myComposite.getVFHolder(FileHolder.HolderType.MODIFIED_WITHOUT_EDITING).addFile(file); } }