diff --git a/build/scripts/layouts.gant b/build/scripts/layouts.gant index 9b87f8a1dd57..106b834d52a2 100644 --- a/build/scripts/layouts.gant +++ b/build/scripts/layouts.gant @@ -238,7 +238,14 @@ public def layoutCommunityPlugins(String home) { } } fileset(dir: "$home/plugins/xslt-debugger/rt/lib") { - includes: "**/*.jar, **/*.html" + include(name: "**/rmi-stubs.jar") + } + dir("rt") { + fileset(dir: "$home/plugins/xslt-debugger/rt/lib") { + include(name: "**/*.jar") + exclude(name: "**/rmi-stubs.jar") + include(name: "**/*.html") + } } } diff --git a/platform/lang-api/src/com/intellij/codeInspection/InspectionProfileEntry.java b/platform/lang-api/src/com/intellij/codeInspection/InspectionProfileEntry.java index 0edd0ae5ffeb..befc780184eb 100644 --- a/platform/lang-api/src/com/intellij/codeInspection/InspectionProfileEntry.java +++ b/platform/lang-api/src/com/intellij/codeInspection/InspectionProfileEntry.java @@ -46,6 +46,7 @@ public abstract class InspectionProfileEntry { private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.InspectionProfileEntry"); + private static final SkipDefaultValuesSerializationFilters DEFAULT_FILTER = new SkipDefaultValuesSerializationFilters(); private static Set myBlackList = null; private Boolean myUseNewSerializer = null; @@ -189,7 +190,7 @@ public abstract class InspectionProfileEntry { @SuppressWarnings("MethodMayBeStatic") @Nullable protected SerializationFilter getSerializationFilter() { - return new SkipDefaultValuesSerializationFilters(); + return DEFAULT_FILTER; } /** diff --git a/platform/lang-api/src/com/intellij/psi/impl/ElementBase.java b/platform/lang-api/src/com/intellij/psi/impl/ElementBase.java index eb9b176fb911..8d308e4394a0 100644 --- a/platform/lang-api/src/com/intellij/psi/impl/ElementBase.java +++ b/platform/lang-api/src/com/intellij/psi/impl/ElementBase.java @@ -25,6 +25,7 @@ import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.project.IndexNotReadyException; import com.intellij.openapi.util.IconLoader; import com.intellij.openapi.util.Iconable; +import com.intellij.openapi.util.Key; import com.intellij.openapi.util.UserDataHolderBase; import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.vfs.VirtualFile; @@ -57,7 +58,7 @@ public abstract class ElementBase extends UserDataHolderBase implements Iconable return computeIconNow(element, request.getFlags()); } }; - private TIntObjectHashMap myBaseIcon; + private static final Key> BASE_ICONS = Key.create("BASE_ICONS"); private static final Icon VISIBILITY_ICON_PLACEHOLDER = new EmptyIcon(Icons.PUBLIC_ICON); public static final Icon ICON_PLACEHOLDER = IconLoader.getIcon("/nodes/nodePlaceholder.png"); @@ -86,28 +87,26 @@ public abstract class ElementBase extends UserDataHolderBase implements Iconable @Nullable private Icon computeIcon(final int flags) { PsiElement psiElement = (PsiElement)this; - Icon baseIcon = LastComputedIcon.get(psiElement, flags); - if (baseIcon == null) { - if (myBaseIcon == null) { - myBaseIcon = new TIntObjectHashMap(3); - } - if (!myBaseIcon.containsKey(flags)) { - myBaseIcon.put(flags, computeBaseIcon(flags)); - } - baseIcon = myBaseIcon.get(flags); - } - if (!psiElement.isValid()) return null; - if (isToDeferIconLoading()) { + + if (Registry.is("psi.deferIconLoading")) { + Icon baseIcon = LastComputedIcon.get(psiElement, flags); + if (baseIcon == null) { + TIntObjectHashMap cache = getUserData(BASE_ICONS); + if (cache == null) { + cache = putUserDataIfAbsent(BASE_ICONS, new TIntObjectHashMap()); + } + synchronized (cache) { + if (!cache.containsKey(flags)) { + cache.put(flags, computeBaseIcon(flags)); + } + baseIcon = cache.get(flags); + } + } return IconDeferrer.getInstance().defer(baseIcon, new ElementIconRequest(psiElement, flags), ICON_COMPUTE); } - else { - return computeIconNow(psiElement, flags); - } - } - protected boolean isToDeferIconLoading() { - return Registry.is("psi.deferIconLoading"); + return computeIconNow(psiElement, flags); } @Nullable diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LocalInspectionsPass.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LocalInspectionsPass.java index e251fa62fd99..07d6811a66cb 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LocalInspectionsPass.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LocalInspectionsPass.java @@ -534,8 +534,10 @@ public class LocalInspectionsPass extends ProgressableTextEditorHighlightingPass for (TextRange editable : editables) { TextRange hostRange = ((DocumentWindow)documentRange).injectedToHost(editable); HighlightInfo patched = HighlightInfo.createHighlightInfo(info.type, element, hostRange.getStartOffset(), - hostRange.getEndOffset(), info.description, info.toolTip); - if (patched != null) { + hostRange.getEndOffset(), info.description, info.toolTip); + if (patched != null && + (patched.startOffset != patched.endOffset || + info.startOffset == info.endOffset)) { registerQuickFixes(tool, descriptor, patched, emptyActionRegistered); outInfos.add(patched); } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/BraceMatcherBasedSelectioner.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/BraceMatcherBasedSelectioner.java index 3b3ce3bdb2fc..3a645dbfd8a5 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/BraceMatcherBasedSelectioner.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/BraceMatcherBasedSelectioner.java @@ -24,6 +24,7 @@ import com.intellij.openapi.editor.highlighter.HighlighterIterator; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.util.Trinity; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiElement; import com.intellij.psi.tree.IElementType; @@ -46,19 +47,18 @@ public abstract class BraceMatcherBasedSelectioner extends ExtendWordSelectionHa final BraceMatcher braceMatcher = BraceMatchingUtil.getBraceMatcher(fileType, iterator); final ArrayList result = new ArrayList(); - final LinkedList> stack = new LinkedList>(); + final LinkedList> stack = new LinkedList>(); while (!iterator.atEnd() && iterator.getStart() < totalRange.getEndOffset()) { - final Pair last; + final Trinity last; if (braceMatcher.isLBraceToken(iterator, editorText, fileType)) { - stack.addLast(Pair.create(iterator.getStart(), iterator.getTokenType())); + stack.addLast(Trinity.create(iterator.getStart(), iterator.getEnd(), iterator.getTokenType())); } else if (braceMatcher.isRBraceToken(iterator, editorText, fileType) - && !stack.isEmpty() && braceMatcher.isPairBraces((last = stack.getLast()).second, iterator.getTokenType())) { + && !stack.isEmpty() && braceMatcher.isPairBraces((last = stack.getLast()).third, iterator.getTokenType())) { stack.removeLast(); - final int start = last.first; - result.addAll(expandToWholeLine(editorText, new TextRange(start, iterator.getEnd()))); - int bodyStart = start + 1; - int bodyEnd = iterator.getEnd() - 1; + result.addAll(expandToWholeLine(editorText, new TextRange(last.first, iterator.getEnd()))); + int bodyStart = last.second + 1; + int bodyEnd = iterator.getStart(); while (Character.isWhitespace(editorText.charAt(bodyStart))) bodyStart ++; while (Character.isWhitespace(editorText.charAt(bodyEnd - 1))) bodyEnd --; result.addAll(expandToWholeLine(editorText, new TextRange(bodyStart, bodyEnd))); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/highlighting/PairedBraceMatcherAdapter.java b/platform/lang-impl/src/com/intellij/codeInsight/highlighting/PairedBraceMatcherAdapter.java index 261a0820c440..58bfade6356a 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/highlighting/PairedBraceMatcherAdapter.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/highlighting/PairedBraceMatcherAdapter.java @@ -30,7 +30,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -class PairedBraceMatcherAdapter implements NontrivialBraceMatcher { +public class PairedBraceMatcherAdapter implements NontrivialBraceMatcher { private final PairedBraceMatcher myMatcher; private final Language myLanguage; @@ -47,22 +47,22 @@ class PairedBraceMatcherAdapter implements NontrivialBraceMatcher { return -1; } - public boolean isLBraceToken(HighlighterIterator iterator, CharSequence fileText, FileType fileType) { + @Nullable + public BracePair findPair(boolean left, HighlighterIterator iterator, CharSequence fileText, FileType fileType) { final IElementType tokenType = iterator.getTokenType(); final BracePair[] pairs = myMatcher.getPairs(); for (BracePair pair : pairs) { - if (tokenType == pair.getLeftBraceType()) return true; + if (tokenType == (left? pair.getLeftBraceType() : pair.getRightBraceType())) return pair; } - return false; + return null; + } + + public boolean isLBraceToken(HighlighterIterator iterator, CharSequence fileText, FileType fileType) { + return findPair(true, iterator, fileText, fileType) != null; } public boolean isRBraceToken(HighlighterIterator iterator, CharSequence fileText, FileType fileType) { - final IElementType tokenType = iterator.getTokenType(); - final BracePair[] pairs = myMatcher.getPairs(); - for (BracePair pair : pairs) { - if (tokenType == pair.getRightBraceType()) return true; - } - return false; + return findPair(false, iterator, fileText, fileType) != null; } public IElementType getOppositeBraceTokenType(@NotNull final IElementType type) { diff --git a/platform/lang-impl/src/com/intellij/find/findUsages/FindUsagesManager.java b/platform/lang-impl/src/com/intellij/find/findUsages/FindUsagesManager.java index 31573488a236..612beaa15a70 100644 --- a/platform/lang-impl/src/com/intellij/find/findUsages/FindUsagesManager.java +++ b/platform/lang-impl/src/com/intellij/find/findUsages/FindUsagesManager.java @@ -38,6 +38,7 @@ import com.intellij.openapi.keymap.KeymapUtil; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.progress.Task; +import com.intellij.openapi.project.IndexNotReadyException; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.Messages; @@ -134,6 +135,9 @@ public class FindUsagesManager implements JDOMExternalizable { return true; } } + catch (IndexNotReadyException e) { + throw e; + } catch (Exception e) { LOG.error(e); } @@ -144,6 +148,9 @@ public class FindUsagesManager implements JDOMExternalizable { return true; } } + catch (IndexNotReadyException e) { + throw e; + } catch (Exception e) { LOG.error(e); } diff --git a/platform/lang-impl/src/com/intellij/notification/EventLog.java b/platform/lang-impl/src/com/intellij/notification/EventLog.java index 29978ebd5587..22f976e76b7c 100644 --- a/platform/lang-impl/src/com/intellij/notification/EventLog.java +++ b/platform/lang-impl/src/com/intellij/notification/EventLog.java @@ -20,23 +20,32 @@ import com.intellij.execution.filters.HyperlinkInfo; import com.intellij.execution.impl.ConsoleViewImpl; import com.intellij.execution.ui.ConsoleViewContentType; import com.intellij.notification.impl.NotificationSettings; +import com.intellij.notification.impl.NotificationsConfigurable; import com.intellij.notification.impl.NotificationsConfiguration; import com.intellij.notification.impl.NotificationsManagerImpl; +import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.components.AbstractProjectComponent; +import com.intellij.openapi.options.ShowSettingsUtil; import com.intellij.openapi.project.DumbAware; +import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; +import com.intellij.openapi.ui.SimpleToolWindowPanel; +import com.intellij.openapi.ui.popup.Balloon; +import com.intellij.openapi.util.IconLoader; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.wm.*; import com.intellij.openapi.wm.ex.StatusBarEx; import com.intellij.ui.content.Content; import com.intellij.ui.content.ContentFactory; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.text.DateFormat; import java.util.ArrayList; +import java.util.Arrays; import java.util.Date; import java.util.List; @@ -111,15 +120,20 @@ public class EventLog implements Notifications { final NotificationType type = notification.getType(); view.print(mainText, type == NotificationType.ERROR - ? ConsoleViewContentType.ERROR_OUTPUT - : type == NotificationType.INFORMATION - ? ConsoleViewContentType.NORMAL_OUTPUT - : ConsoleViewContentType.WARNING_OUTPUT); + ? ConsoleViewContentType.ERROR_OUTPUT + : type == NotificationType.INFORMATION + ? ConsoleViewContentType.NORMAL_OUTPUT + : ConsoleViewContentType.WARNING_OUTPUT); if (showLink) { view.print(" ", ConsoleViewContentType.NORMAL_OUTPUT); view.printHyperlink("more", new HyperlinkInfo() { @Override public void navigate(Project project) { + Balloon balloon = notification.getBalloon(); + if (balloon != null) { + balloon.hide(); + } + NotificationsManagerImpl.notifyByBalloon(notification, NotificationDisplayType.STICKY_BALLOON, project); } }); @@ -194,9 +208,25 @@ public class EventLog implements Notifications { return project.getComponent(ProjectTracker.class); } public static class FactoryItself implements ToolWindowFactory, DumbAware { - public void createToolWindowContent(Project project, ToolWindow toolWindow) { + public void createToolWindowContent(final Project project, ToolWindow toolWindow) { final ProjectTracker tracker = getProjectComponent(project); - final Content content = ContentFactory.SERVICE.getInstance().createContent(tracker.myConsoleView.getComponent(), "", false); + + SimpleToolWindowPanel panel = new SimpleToolWindowPanel(false, true); + panel.setContent(tracker.myConsoleView.getComponent()); + + DefaultActionGroup group = new DefaultActionGroup(); + group.add(new DumbAwareAction("Settings", "Edit notification settings", IconLoader.getIcon("/general/secondaryGroup.png")) { + @Override + public void actionPerformed(AnActionEvent e) { + ShowSettingsUtil.getInstance().editConfigurable(project, new NotificationsConfigurable()); + } + }); + group.addAll(ContainerUtil.subList(Arrays.asList(tracker.myConsoleView.createConsoleActions()), 2)); // no next/prev + ActionToolbar toolbar = ActionManager.getInstance().createActionToolbar(ActionPlaces.UNKNOWN, group, false); + toolbar.setTargetComponent(panel); + panel.setToolbar(toolbar.getComponent()); + + final Content content = ContentFactory.SERVICE.getInstance().createContent(panel, "", false); toolWindow.getContentManager().addContent(content); } diff --git a/platform/platform-impl/src/com/intellij/buildfiles/ForcedBuildFileAttribute.java b/platform/platform-impl/src/com/intellij/buildfiles/ForcedBuildFileAttribute.java index 0cfd2cc9e319..b83cc2028a8a 100644 --- a/platform/platform-impl/src/com/intellij/buildfiles/ForcedBuildFileAttribute.java +++ b/platform/platform-impl/src/com/intellij/buildfiles/ForcedBuildFileAttribute.java @@ -21,6 +21,7 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.newvfs.FileAttribute; import com.intellij.openapi.vfs.newvfs.NewVirtualFile; +import com.intellij.util.io.IOUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -55,17 +56,10 @@ public class ForcedBuildFileAttribute { if (is != null) { try { try { - /* - //todo[lene] IOUtil throws java.io.EOFException - at java.io.DataInputStream.readFully(DataInputStream.java:180) - at java.io.DataInputStream.readFully(DataInputStream.java:152) - at com.intellij.util.io.IOUtil.readString(IOUtil.java:40) - at com.intellij.buildfiles.ForcedBuildFileAttribute.getFrameworkIdOfBuildFile(ForcedBuildFileAttribute.java:59) - */ if (is.available() == 0) { return null; } - return is.readUTF(); + return IOUtil.readString(is); } finally { is.close(); @@ -82,12 +76,12 @@ public class ForcedBuildFileAttribute { public static void forceFileToFramework(VirtualFile file, String frameworkId, boolean value) { - if (value) {//belongs to other framework - String existingFrameworkId = getFrameworkIdOfBuildFile(file); - if (!StringUtil.isEmpty(existingFrameworkId) && !frameworkId.equals(existingFrameworkId)) { - return; - } + //belongs to other framework - do not override! + String existingFrameworkId = getFrameworkIdOfBuildFile(file); + if (!StringUtil.isEmpty(existingFrameworkId) && !frameworkId.equals(existingFrameworkId)) { + return; } + if (value) {//write framework forceBuildFile(file, frameworkId); } @@ -102,7 +96,7 @@ public class ForcedBuildFileAttribute { final DataOutputStream os = FRAMEWORK_FILE_ATTRIBUTE.writeAttribute(file); try { try { - os.writeUTF(StringUtil.notNullize(value)); + IOUtil.writeString(StringUtil.notNullize(value), os); } finally { os.close(); diff --git a/platform/platform-impl/src/com/intellij/execution/process/ScriptRunnerUtil.java b/platform/platform-impl/src/com/intellij/execution/process/ScriptRunnerUtil.java index a48a73bbf8bc..c1380bae4ae1 100644 --- a/platform/platform-impl/src/com/intellij/execution/process/ScriptRunnerUtil.java +++ b/platform/platform-impl/src/com/intellij/execution/process/ScriptRunnerUtil.java @@ -20,17 +20,11 @@ import com.intellij.execution.ExecutionException; import com.intellij.execution.configurations.GeneralCommandLine; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Key; -import com.intellij.openapi.util.Pair; -import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.encoding.EncodingManager; -import com.intellij.util.ArrayUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; -import java.util.List; - /** * Created by IntelliJ IDEA. * User: lene @@ -72,68 +66,11 @@ public class ScriptRunnerUtil { } }); } - processHandler.startNotify(); + //ProcessTerminatedListener.attach(processHandler, project); return processHandler; } - public static Pair getExePathAndCommand(List commandToExecute) { - @NonNls String exePath = ""; - @NonNls List parameters = new ArrayList(); - if (SystemInfo.isOS2) { - exePath = "cmd"; - parameters.add("/c"); - } - else if (SystemInfo.isWindows) { - if (!SystemInfo.isWindows9x) { - exePath = "cmd"; - } - else { - exePath = "command.com"; - } - parameters.add("/c"); - - /*if exe-path and at least one of parameters contain spaces the whole command must be quoted, - e.g. instead of - cmd /c "C:\Program Files\jdk1.5\bin\java" "-Dproperty=a b c" myclass - must be used - cmd /c ""C:\Program Files\jdk1.5\bin\java" "-Dproperty=a b c" myclass" - */ - boolean quoteWholeCommand = false; - for (int i = 1; i < commandToExecute.size(); i++) { - quoteWholeCommand |= commandToExecute.get(i).contains(" "); - } - quoteWholeCommand &= commandToExecute.size() > 0 && commandToExecute.get(0).contains(" "); - - if (quoteWholeCommand) { - StringBuilder builder = new StringBuilder(); - builder.append('"'); - for (int i = 0; i < commandToExecute.size(); i++) { - if (i > 0) { - builder.append(' '); - } - builder.append(GeneralCommandLine.quote(commandToExecute.get(i))); - } - builder.append('"'); - - parameters.add(builder.toString()); - return Pair.create(exePath, ArrayUtil.toStringArray(parameters)); - } - } - - int firstParamIdx = 0; - if (SystemInfo.isUnix) { - exePath = commandToExecute.get(0); - firstParamIdx = 1; - } - - for (int i = firstParamIdx; i < commandToExecute.size(); i++) { - parameters.add(commandToExecute.get(i)); - } - - return Pair.create(exePath, ArrayUtil.toStringArray(parameters)); - } - public static ScriptOutput executeScriptInConsoleWithFullOutput(String exePathString, @Nullable VirtualFile scriptFile, @Nullable String workingDirectory, @@ -148,6 +85,7 @@ public class ScriptRunnerUtil { final StringBuilder mergedOutput = (scriptOutputType.readStandardOutput() && scriptOutputType.readErrorOutput()) ? new StringBuilder() : null; addReadingProcessListener(scriptOutputType, processHandler, standardOutput, errorOutput, mergedOutput); + processHandler.startNotify(); if (!processHandler.waitFor(timeout)) { LOG.warn("Process did not complete in " + timeout / 1000 + "s"); diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/IdeStatusBarImpl.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/IdeStatusBarImpl.java index 99728b488599..97cd0ed008ca 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/IdeStatusBarImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/IdeStatusBarImpl.java @@ -302,7 +302,7 @@ public class IdeStatusBarImpl extends JComponent implements StatusBarEx { if (!anchor.equals("__AUTODETECT__")) { final List parts = StringUtil.split(anchor, " "); if (parts.size() < 2 || !myWidgetMap.keySet().contains(parts.get(1))) { - wid = "Notifications"; + wid = "Memory"; before = true; } else { diff --git a/platform/util/src/com/intellij/util/containers/ContainerUtil.java b/platform/util/src/com/intellij/util/containers/ContainerUtil.java index 183f307b26de..efe4f675788a 100644 --- a/platform/util/src/com/intellij/util/containers/ContainerUtil.java +++ b/platform/util/src/com/intellij/util/containers/ContainerUtil.java @@ -122,6 +122,10 @@ public class ContainerUtil { return result; } + public static List subList(List list, int from) { + return list.subList(from, list.size()); + } + public static void addAll(@NotNull Collection collection, @NotNull Iterable appendix) { addAll(collection, appendix.iterator()); } diff --git a/platform/util/src/com/intellij/util/xmlb/BeanBinding.java b/platform/util/src/com/intellij/util/xmlb/BeanBinding.java index 1bb499ffcb82..df01309ed849 100644 --- a/platform/util/src/com/intellij/util/xmlb/BeanBinding.java +++ b/platform/util/src/com/intellij/util/xmlb/BeanBinding.java @@ -110,7 +110,6 @@ class BeanBinding implements Binding { } } - public void deserializeInto(final Object bean, final Element element) { _deserializeInto(bean, element); } @@ -134,11 +133,11 @@ class BeanBinding implements Binding { ArrayList bindings = new ArrayList(myPropertyBindings.keySet()); - MultiMap data = new MultiMap(); final Object[] children = JDOMUtil.getChildNodesWithAttrs(e); - nextNode: for (Object child : children) { + nextNode: + for (Object child : children) { if (XmlSerializerImpl.isIgnoredNode(child)) continue; for (Binding binding : bindings) { @@ -188,11 +187,9 @@ class BeanBinding implements Binding { return Element.class; } - private static String getTagName(Class aClass) { Tag tag = aClass.getAnnotation(Tag.class); if (tag != null && tag.value().length() != 0) return tag.value(); - return aClass.getSimpleName(); } @@ -201,27 +198,26 @@ class BeanBinding implements Binding { try { List accessors = new ArrayList(); - BeanInfo info = Introspector.getBeanInfo(aClass); + BeanInfo info = Introspector.getBeanInfo(aClass, Introspector.IGNORE_ALL_BEANINFO); PropertyDescriptor[] propertyDescriptors = info.getPropertyDescriptors(); for (PropertyDescriptor propertyDescriptor : propertyDescriptors) { if (propertyDescriptor.getName().equals(CLASS_PROPERTY)) continue; + final Method readMethod = propertyDescriptor.getReadMethod(); final Method writeMethod = propertyDescriptor.getWriteMethod(); - - if (readMethod == null) continue; - if (writeMethod == null) continue; - - if (XmlSerializerImpl.findAnnotation(readMethod.getAnnotations(), Transient.class) != null || - XmlSerializerImpl.findAnnotation(writeMethod.getAnnotations(), Transient.class) != null) continue; - - accessors.add(new PropertyAccessor(propertyDescriptor)); + if (readMethod != null && writeMethod != null && + XmlSerializerImpl.findAnnotation(readMethod.getAnnotations(), Transient.class) == null && + XmlSerializerImpl.findAnnotation(writeMethod.getAnnotations(), Transient.class) == null) { + accessors.add(new PropertyAccessor(propertyDescriptor)); + } } Field[] fields = aClass.getFields(); for (Field field : fields) { - int modifiers = field.getModifiers(); - if (Modifier.isPublic(modifiers) && !Modifier.isStatic(modifiers) && !Modifier.isFinal(modifiers) && + final int modifiers = field.getModifiers(); + if (Modifier.isPublic(modifiers) && !Modifier.isStatic(modifiers) && + !Modifier.isFinal(modifiers) && !Modifier.isTransient(modifiers) && XmlSerializerImpl.findAnnotation(field.getAnnotations(), Transient.class) == null) { accessors.add(new FieldAccessor(field)); } @@ -260,7 +256,6 @@ class BeanBinding implements Binding { return new AttributeBinding(accessor, attribute, xmlSerializer); } - if (tag != null) { if (tag.value().length() > 0) return new TagBinding(accessor, tag, xmlSerializer); } @@ -281,5 +276,4 @@ class BeanBinding implements Binding { OptionTag optionTag = XmlSerializerImpl.findAnnotation(accessor.getAnnotations(), OptionTag.class); return new OptionTagBinding(accessor, xmlSerializer, optionTag); } - } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesBrowserNode.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesBrowserNode.java index 4ed46939777f..8406bd08b0e9 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesBrowserNode.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesBrowserNode.java @@ -144,13 +144,17 @@ public class ChangesBrowserNode extends DefaultMutableTreeNode { } public List getAllChangesUnder() { - List changes = new ArrayList(); + return getAllObjectsUnder(Change.class); + } + + public List getAllObjectsUnder(final Class clazz) { + List changes = new ArrayList(); final Enumeration enumeration = depthFirstEnumeration(); while (enumeration.hasMoreElements()) { ChangesBrowserNode child = (ChangesBrowserNode)enumeration.nextElement(); final Object value = child.getUserObject(); - if (value instanceof Change) { - changes.add((Change)value); + if (clazz.isAssignableFrom(value.getClass())) { + changes.add((T) value); } } return changes; diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesListView.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesListView.java index b970975ee2ce..c7012dc45b12 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesListView.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesListView.java @@ -77,6 +77,7 @@ public class ChangesListView extends Tree implements TypeSafeDataProvider, Advan @NonNls public static final String ourHelpId = "ideaInterface.changes"; @NonNls public static final DataKey> UNVERSIONED_FILES_DATA_KEY = DataKey.create("ChangeListView.UnversionedFiles"); @NonNls public static final DataKey> MISSING_FILES_DATA_KEY = DataKey.create("ChangeListView.MissingFiles"); + @NonNls public static final DataKey> LOCALLY_DELETED_CHANGES = DataKey.create("ChangeListView.LocallyDeletedChanges"); @NonNls public static final DataKey HELP_ID_DATA_KEY = DataKey.create(HELP_ID_KEY); private ActionGroup myMenuGroup; @@ -195,8 +196,9 @@ public class ChangesListView extends Tree implements TypeSafeDataProvider, Advan } else if (key == VcsDataKeys.MODIFIED_WITHOUT_EDITING_DATA_KEY) { sink.put(VcsDataKeys.MODIFIED_WITHOUT_EDITING_DATA_KEY, getSelectedModifiedWithoutEditing()); - } - else if (key == MISSING_FILES_DATA_KEY) { + } else if (key == LOCALLY_DELETED_CHANGES) { + sink.put(LOCALLY_DELETED_CHANGES, getSelectedLocallyDeletedChanges()); + } else if (key == MISSING_FILES_DATA_KEY) { sink.put(MISSING_FILES_DATA_KEY, getSelectedMissingFiles()); } else if (VcsDataKeys.HAVE_LOCALLY_DELETED == key) { sink.put(VcsDataKeys.HAVE_LOCALLY_DELETED, haveLocallyDeleted()); @@ -265,6 +267,24 @@ public class ChangesListView extends Tree implements TypeSafeDataProvider, Advan return new ArrayList(files); } + private List getSelectedLocallyDeletedChanges() { + Set files = new HashSet(); + final TreePath[] paths = getSelectionPaths(); + if (paths != null) { + for (TreePath path : paths) { + if (path.getPathCount() > 1) { + ChangesBrowserNode firstNode = (ChangesBrowserNode)path.getPathComponent(1); + if (firstNode.getUserObject() == TreeModelBuilder.LOCALLY_DELETED_NODE) { + ChangesBrowserNode node = (ChangesBrowserNode)path.getLastPathComponent(); + final List objectsUnder = node.getAllObjectsUnder(LocallyDeletedChange.class); + files.addAll(objectsUnder); + } + } + } + } + return new ArrayList(files); + } + private List getSelectedMissingFiles() { return getSelectedFilePaths(TreeModelBuilder.LOCALLY_DELETED_NODE); } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/CommitHelper.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/CommitHelper.java index 01b1a940e397..f1500aa0ccf3 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/CommitHelper.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/CommitHelper.java @@ -29,6 +29,7 @@ import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.Computable; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.*; import com.intellij.openapi.vcs.changes.*; import com.intellij.openapi.vcs.changes.actions.MoveChangesToAnotherListAction; @@ -123,14 +124,16 @@ public class CommitHelper { @Override public NotificationInfo notifyFinished() { final List changesFailedToCommit = processor.getChangesFailedToCommit(); - - String text = (myIncludedChanges.size() - changesFailedToCommit.size()) + " Change(s) Commited"; - if (changesFailedToCommit.size() > 0) { - text += ", " + changesFailedToCommit.size() + " Change(s) Failed To Commit"; + + int failed = changesFailedToCommit.size(); + int committed = myIncludedChanges.size() - failed; + + String text = committed + " " + StringUtil.pluralize("change", committed) + " committed"; + if (failed > 0) { + text += ", " + failed + " " + StringUtil.pluralize("change", failed) + " failed to commit"; } - final String title = "VCS Commit Finished"; - AbstractCommonUpdateAction.NOTIFICATION_GROUP.createNotification(title + ", " + text, myCommitMessage, NotificationType.INFORMATION, null).notify( myProject); - return new NotificationInfo("VCS Commit", title, text, true); + AbstractCommonUpdateAction.NOTIFICATION_GROUP.createNotification(text, myCommitMessage, NotificationType.INFORMATION, null).notify( myProject); + return new NotificationInfo("VCS Commit", "VCS Commit Finished", text, true); } }; ProgressManager.getInstance().run(task); diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubOpenInBrowserAction.java b/plugins/github/src/org/jetbrains/plugins/github/GithubOpenInBrowserAction.java index 90e534486535..0919d1d6eb05 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/GithubOpenInBrowserAction.java +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubOpenInBrowserAction.java @@ -19,6 +19,7 @@ import com.intellij.ide.BrowserUtil; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; @@ -148,6 +149,14 @@ public class GithubOpenInBrowserAction extends DumbAwareAction { if (branch.startsWith("origin/")){ branch = branch.substring(7); } - BrowserUtil.launchBrowser("https://github.com/" + repoInfo + "/blob/" + branch + path.substring(rootPath.length())); + + final StringBuilder builder = new StringBuilder(); + builder.append("https://github.com/").append(repoInfo).append("/blob/").append(branch).append(path.substring(rootPath.length())); + final Editor editor = e.getData(PlatformDataKeys.EDITOR); + if (editor != null){ + final int line = editor.getCaretModel().getLogicalPosition().line; + builder.append("#L").append(line); + } + BrowserUtil.launchBrowser(builder.toString()); } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/conversions/ConvertConcatenationToGstringIntention.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/conversions/ConvertConcatenationToGstringIntention.java index 18f7e2533624..2b939f109e79 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/conversions/ConvertConcatenationToGstringIntention.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/conversions/ConvertConcatenationToGstringIntention.java @@ -66,8 +66,13 @@ public class ConvertConcatenationToGstringIntention extends Intention { else { return; } + + String text = builder.toString(); + if (builder.indexOf("\n") < 0 && builder.indexOf("\r") < 0) { + text = GrStringUtil.escapeSymbols(builder.toString(), "\""); + } final GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(element.getProject()); - final GrExpression newExpr = factory.createExpressionFromText(GrStringUtil.addQuotes(builder.toString(), true)); + final GrExpression newExpr = factory.createExpressionFromText(GrStringUtil.addQuotes(text, true)); final GrExpression expression = ((GrExpression)element).replaceWithExpression(newExpr, true); if (expression instanceof GrString) { GrStringUtil.removeUnnecessaryBracesInGString((GrString)expression); @@ -87,7 +92,6 @@ public class ConvertConcatenationToGstringIntention extends Intention { } else if (operand instanceof GrLiteral) { String text = GrStringUtil.escapeSymbolsForGString(GrStringUtil.removeQuotes(operand.getText()), false); - if (text.contains("\n")) text = GrStringUtil.escapeSymbolsForGString(text, true); builder.append(text); } else if (MyPredicate.satisfiedBy(operand, false)) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/conversions/ConvertGStringToStringIntention.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/conversions/ConvertGStringToStringIntention.java index 073dcdfe85ef..fbf728a3f980 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/conversions/ConvertGStringToStringIntention.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/conversions/ConvertGStringToStringIntention.java @@ -152,8 +152,7 @@ public class ConvertGStringToStringIntention extends Intention { } if (text.length() == 0) return null; - String escaped = GrStringUtil.escapeSymbolsForString(text, false); - if (escaped.contains("\n")) escaped = GrStringUtil.escapeSymbolsForGString(escaped, true); + String escaped = GrStringUtil.escapeSymbolsForString(text, !text.contains("\n") && !text.contains("\r")); return GrStringUtil.addQuotes(escaped, false); } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/arithmetic/PathExpression.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/arithmetic/PathExpression.java index 2abd3cad518c..ba5e4b9c6805 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/arithmetic/PathExpression.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/arithmetic/PathExpression.java @@ -50,10 +50,19 @@ public class PathExpression implements GroovyElementTypes { */ public static Result parsePathExprQualifierForExprStatement(PsiBuilder builder, GroovyParser parser) { PsiBuilder.Marker marker = builder.mark(); - final IElementType qualifierType = PrimaryExpression.parsePrimaryExpression(builder, parser); + final PsiBuilder.Marker marker1 = builder.mark(); + IElementType qualifierType = PrimaryExpression.parsePrimaryExpression(builder, parser); if (qualifierType != WRONGWAY) { Result result; if (isPathElementStart(builder)) { + if (builder.getTokenType() == mLPAREN && qualifierType == LITERAL) { + marker1.rollbackTo(); + qualifierType = PrimaryExpression.parsePrimaryExpression(builder, parser, true); + assert qualifierType != WRONGWAY; + } + else { + marker1.drop(); + } PsiBuilder.Marker newMarker = marker.precede(); marker.drop(); if (checkForLCurly(builder)) { @@ -67,12 +76,14 @@ public class PathExpression implements GroovyElementTypes { } } else { + marker1.drop(); marker.drop(); result = INVOKED_EXPR; } return result; } else { + marker1.drop(); marker.drop(); return WRONG_WAY; } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/primary/PrimaryExpression.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/primary/PrimaryExpression.java index 2c889765a7f7..dac94ad6b66e 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/primary/PrimaryExpression.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/primary/PrimaryExpression.java @@ -36,47 +36,56 @@ import org.jetbrains.plugins.groovy.lang.parser.parsing.util.ParserUtils; */ public class PrimaryExpression implements GroovyElementTypes { - public static IElementType parsePrimaryExpression(PsiBuilder builder, GroovyParser parser) { - if (TokenSets.BUILT_IN_TYPE.contains(builder.getTokenType())) { + public static IElementType parsePrimaryExpression(PsiBuilder builder, GroovyParser parser) { + return parsePrimaryExpression(builder, parser, false); + } + public static IElementType parsePrimaryExpression(PsiBuilder builder, GroovyParser parser, boolean literalsAsRefExprs) { + + final IElementType tokenType = builder.getTokenType(); + if (TokenSets.BUILT_IN_TYPE.contains(tokenType)) { ParserUtils.eatElement(builder, BUILT_IN_TYPE_EXPRESSION); return BUILT_IN_TYPE_EXPRESSION; } - if (kTHIS == builder.getTokenType()) { + if (kTHIS == tokenType) { ParserUtils.eatElement(builder, THIS_REFERENCE_EXPRESSION); return THIS_REFERENCE_EXPRESSION; } - if (kSUPER == builder.getTokenType()) { + if (kSUPER == tokenType) { ParserUtils.eatElement(builder, SUPER_REFERENCE_EXPRESSION); return SUPER_REFERENCE_EXPRESSION; } - if (kNEW == builder.getTokenType()) { + if (kNEW == tokenType) { return newExprParse(builder, parser); } - if (mIDENT == builder.getTokenType()) { + if (mIDENT == tokenType) { ParserUtils.eatElement(builder, REFERENCE_EXPRESSION); return REFERENCE_EXPRESSION; } - if (mGSTRING_BEGIN == builder.getTokenType()) { + if (mGSTRING_BEGIN == tokenType) { return StringConstructorExpression.parse(builder, parser); } - if (mREGEX_BEGIN == builder.getTokenType()) { + if (mREGEX_BEGIN == tokenType) { return RegexConstructorExpression.parse(builder, parser); } - if (mLBRACK == builder.getTokenType()) { + if (mLBRACK == tokenType) { return ListOrMapConstructorExpression.parse(builder, parser); } - if (mLPAREN == builder.getTokenType()) { + if (mLPAREN == tokenType) { return parenthesizedExprParse(builder, parser); } - if (mLCURLY == builder.getTokenType()) { + if (mLCURLY == tokenType) { return OpenOrClosableBlock.parseClosableBlock(builder, parser); } - if (TokenSets.CONSTANTS.contains(builder.getTokenType())) { - ParserUtils.eatElement(builder, LITERAL); - return LITERAL; + if (tokenType == mSTRING_LITERAL || + tokenType == mGSTRING_LITERAL || + tokenType == mREGEX_LITERAL) { + return ParserUtils.eatElement(builder, literalsAsRefExprs ? REFERENCE_EXPRESSION : LITERAL); } - if (mWRONG_REGEX_LITERAL == builder.getTokenType()) { + if (TokenSets.CONSTANTS.contains(tokenType)) { + return ParserUtils.eatElement(builder, LITERAL); + } + if (mWRONG_REGEX_LITERAL == tokenType) { PsiBuilder.Marker marker = builder.mark(); builder.advanceLexer(); builder.error(GroovyBundle.message("wrong.string")); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/primary/StringConstructorExpression.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/primary/StringConstructorExpression.java index c17cfdad04a4..e4ac24ae22b7 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/primary/StringConstructorExpression.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/primary/StringConstructorExpression.java @@ -35,17 +35,6 @@ public class StringConstructorExpression implements GroovyElementTypes { Marker sMarker = builder.mark(); if (ParserUtils.getToken(builder, mGSTRING_BEGIN)) { - ParserUtils.getToken(builder, mGSTRING_CONTENT); - if (mGSTRING_END.equals(builder.getTokenType())) { - sMarker.rollbackTo(); - sMarker = builder.mark(); - builder.advanceLexer(); - builder.advanceLexer(); - builder.advanceLexer(); - sMarker.done(LITERAL); - return LITERAL; - } - while (ParserUtils.getToken(builder, mGSTRING_CONTENT) || mDOLLAR.equals(builder.getTokenType())) { if (mDOLLAR.equals(builder.getTokenType())) { stringConstructorValuePart(builder, parser); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/arguments/GrArgumentLabelImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/arguments/GrArgumentLabelImpl.java index 599f27ec3236..7e9d5fc342d3 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/arguments/GrArgumentLabelImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/arguments/GrArgumentLabelImpl.java @@ -155,9 +155,6 @@ public class GrArgumentLabelImpl extends GroovyPsiElementImpl implements GrArgum if (value instanceof String) { return (String)value; } - if (value instanceof Number) { - return value.toString(); - } } final IElementType elemType = element.getNode().getElementType(); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/TypesUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/TypesUtil.java index b1294e0a2007..6c5e36b20a6b 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/TypesUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/TypesUtil.java @@ -22,6 +22,7 @@ import com.intellij.psi.impl.PsiSubstitutorImpl; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.InheritanceUtil; +import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.TypeConversionUtil; import com.intellij.util.containers.ComparatorUtil; import com.intellij.util.containers.HashMap; @@ -38,6 +39,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrBinary import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrClosureSignature; import org.jetbrains.plugins.groovy.lang.psi.impl.GrClosureType; +import org.jetbrains.plugins.groovy.lang.psi.impl.GrMapType; import org.jetbrains.plugins.groovy.lang.psi.impl.GrTupleType; import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiManager; import org.jetbrains.plugins.groovy.lang.psi.impl.types.GrClosureSignatureImpl; @@ -283,14 +285,11 @@ public class TypesUtil { public static boolean isAssignableByMethodCallConversion(PsiType lType, PsiType rType, PsiManager manager, GlobalSearchScope scope) { if (lType == null || rType == null) return false; - if (rType instanceof GrTupleType) { - final GrTupleType tuple = (GrTupleType)rType; - if (tuple.getComponentTypes().length == 0) { - if (lType instanceof PsiArrayType || - InheritanceUtil.isInheritor(lType, JAVA_UTIL_LIST) || - InheritanceUtil.isInheritor(lType, JAVA_UTIL_SET)) { - return true; - } + if (rType instanceof GrTupleType && ((GrTupleType)rType).getComponentTypes().length == 0) { + if (lType instanceof PsiArrayType || + InheritanceUtil.isInheritor(lType, JAVA_UTIL_LIST) || + InheritanceUtil.isInheritor(lType, JAVA_UTIL_SET)) { + return true; } } @@ -318,10 +317,54 @@ public class TypesUtil { return true; } + if (rType instanceof GrMapType || rType instanceof GrTupleType) { + Boolean result = isAssignableForNativeTypes(lType, (PsiClassType)rType, manager, scope); + if (result != null) return result.booleanValue(); + } + return TypeConversionUtil.isAssignable(lType, rType); } + @Nullable + private static Boolean isAssignableForNativeTypes(PsiType lType, PsiClassType rType, PsiManager manager, GlobalSearchScope scope) { + if (!(lType instanceof PsiClassType)) return null; + final PsiClassType.ClassResolveResult leftResult = ((PsiClassType)lType).resolveGenerics(); + final PsiClassType.ClassResolveResult rightResult = rType.resolveGenerics(); + final PsiClass leftClass = leftResult.getElement(); + PsiClass rightClass = rightResult.getElement(); + if (rightClass == null || leftClass == null) return null; + + if (!InheritanceUtil.isInheritorOrSelf(rightClass, leftClass, true)) return Boolean.FALSE; + + PsiSubstitutor rightSubstitutor = rightResult.getSubstitutor(); + + if (!leftClass.hasTypeParameters()) return Boolean.TRUE; + PsiSubstitutor leftSubstitutor = leftResult.getSubstitutor(); + + if (!leftClass.getManager().areElementsEquivalent(leftClass, rightClass)) { + rightSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(leftClass, rightClass, rightSubstitutor); + rightClass = leftClass; + } + else if (!rightClass.hasTypeParameters()) return Boolean.TRUE; + + Iterator li = PsiUtil.typeParametersIterator(leftClass); + Iterator ri = PsiUtil.typeParametersIterator(rightClass); + while (li.hasNext()) { + if (!ri.hasNext()) return Boolean.FALSE; + PsiTypeParameter lp = li.next(); + PsiTypeParameter rp = ri.next(); + final PsiType typeLeft = leftSubstitutor.substitute(lp); + if (typeLeft == null) continue; + final PsiType typeRight = rightSubstitutor.substituteWithBoundsPromotion(rp); + if (typeRight == null) { + return Boolean.TRUE; + } + if (!isAssignableByMethodCallConversion(typeLeft, typeRight, manager, scope)) return Boolean.FALSE; + } + return Boolean.TRUE; + } + public static boolean isNumericType(PsiType type) { if (type instanceof PsiClassType) { return TYPE_TO_RANK.contains(type.getCanonicalText()); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/GrStringUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/GrStringUtil.java index b7743111fb6e..e9cd9265ee10 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/GrStringUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/GrStringUtil.java @@ -4,7 +4,9 @@ import com.intellij.lang.ASTNode; import com.intellij.openapi.util.Comparing; import com.intellij.psi.PsiElement; import com.intellij.psi.impl.source.tree.LeafPsiElement; +import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement; import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; @@ -27,76 +29,145 @@ public class GrStringUtil { } public static String escapeSymbolsForGString(String s, boolean escapeDoubleQuotes) { + return escapeSymbolsForGString(s, escapeDoubleQuotes, false); + } + + public static String escapeSymbolsForGString(String s, boolean escapeDoubleQuotes, boolean forInjection) { StringBuilder b = new StringBuilder(); - final char[] chars = s.toCharArray(); - final int len = chars.length - 1; - int i; - for (i = 0; i < len; i++) { - if (chars[i] == '\\') { - final char next = chars[i + 1]; - if (next == '\'') { - b.append('\''); - i++; - } - else if (next == 'n') { - b.append('\n'); - i++; - } - else if (escapeDoubleQuotes && next == '"') { - b.append('"'); - i++; - } - else { - b.append(chars[i]); - i++; - b.append(chars[i]); - } - continue; - } - if (chars[i] == '"' || chars[i] == '$') b.append('\\'); - b.append(chars[i]); - } - if (i == len) { - if (chars[i] == '"') b.append('\\'); - b.append(chars[i]); + escapeStringCharacters(s.length(), s, escapeDoubleQuotes ? "$\"" : "$", false, forInjection, b); + if (!forInjection) { + unescapeCharacters(b, escapeDoubleQuotes ? "'" : "'\"", true); } return b.toString(); } public static String escapeSymbolsForString(String s, boolean escapeQuotes) { - StringBuilder b = new StringBuilder(); - final char[] chars = s.toCharArray(); - final int len = chars.length - 1; - int i; - for (i = 0; i < len; i++) { - if (chars[i] == '\\') { - final char next = chars[i + 1]; - if (next == '"' || next == '$') { - b.append(next); + return escapeSymbolsForString(s, escapeQuotes, false); + } + + public static String escapeSymbolsForString(String s, boolean escapeQuotes, boolean forInjection) { + final StringBuilder builder = new StringBuilder(); + escapeStringCharacters(s.length(), s, escapeQuotes ? "'" : "", false, forInjection, builder); + if (!forInjection) { + unescapeCharacters(builder, escapeQuotes ? "$\"" : "$'\"", true); + } + return builder.toString(); + } + + @NotNull + public static StringBuilder escapeStringCharacters(int length, + @NotNull String str, + @Nullable String additionalChars, + boolean escapeNR, + boolean escapeSlash, + @NotNull @NonNls StringBuilder buffer) { + for (int idx = 0; idx < length; idx++) { + char ch = str.charAt(idx); + switch (ch) { + case '\b': + buffer.append("\\b"); + break; + + case '\t': + buffer.append("\\t"); + break; + + case '\f': + buffer.append("\\f"); + break; + + case '\\': + if (escapeSlash) { + buffer.append("\\\\"); + } + else { + buffer.append("\\"); + } + break; + + case '\n': + if (escapeNR) { + buffer.append("\\n"); + } + else { + buffer.append('\n'); + } + break; + + case '\r': + if (escapeNR) { + buffer.append("\\r"); + } + else { + buffer.append('\r'); + } + break; + + default: + if (additionalChars != null && additionalChars.indexOf(ch) > -1) { + buffer.append("\\").append(ch); + } + else if (Character.isISOControl(ch)) { + String hexCode = Integer.toHexString(ch).toUpperCase(); + buffer.append("\\u"); + int paddingCount = 4 - hexCode.length(); + while (paddingCount-- > 0) { + buffer.append(0); + } + buffer.append(hexCode); + } + else { + buffer.append(ch); + } + } + } + return buffer; + } + + public static void unescapeCharacters(StringBuilder builder, String toUnescape, boolean isMultiLine) { + for (int i = 0; i < builder.length(); i++) { + if (builder.charAt(i) != '\\') continue; + if (i + 1 == builder.length()) break; + char next = builder.charAt(i + 1); + if (next == 'n') { + if (isMultiLine) { + builder.replace(i, i + 2, "\n"); } - else if (next == 'n') { - b.append('\n'); - } - else if (escapeQuotes && next == '\'') { - b.append(next); - } - else { - b.append('\\'); - b.append(next); + } + else if (next == 'r') { + if (isMultiLine) { + builder.replace(i, i + 2, "\r"); } + } + else if (toUnescape.indexOf(next) != -1) { + builder.delete(i, i + 1); + } + else { i++; + } + } + } + + public static String escapeSymbols(String s, String toEscape) { + StringBuilder builder = new StringBuilder(); + boolean escaped = false; + for (int i = 0; i < s.length(); i++) { + final char ch = s.charAt(i); + if (escaped) { + builder.append(ch); + escaped = false; continue; } - if (chars[i] == '\'') b.append('\\'); - b.append(chars[i]); - } + if (ch == '\\') { + escaped = true; + } + if (toEscape.indexOf(ch) >= 0) { + builder.append('\\'); + } - if (i == len) { - if (chars[i] == '\'') b.append('\\'); - b.append(chars[i]); + builder.append(ch); } - return b.toString(); - + return builder.toString(); } public static String removeQuotes(@NotNull String s) { @@ -121,7 +192,7 @@ public class GrStringUtil { public static String addQuotes(String s, boolean forGString) { if (forGString) { - if (s.contains("\n")) { + if (s.contains("\n") || s.contains("\r")) { return TRIPLE_DOUBLE_QUOTES + s + TRIPLE_DOUBLE_QUOTES; } else { @@ -129,7 +200,7 @@ public class GrStringUtil { } } else { - if (s.contains("\n")) { + if (s.contains("\n") || s.contains("\r")) { return TRIPLE_QUOTES + s + TRIPLE_QUOTES; } else { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/GroovyStringLiteralManipulator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/GroovyStringLiteralManipulator.java index 1f05cf5c2096..e39d43639cb6 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/GroovyStringLiteralManipulator.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/GroovyStringLiteralManipulator.java @@ -16,20 +16,32 @@ package org.jetbrains.plugins.groovy.lang.resolve; import com.intellij.openapi.util.TextRange; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.AbstractElementManipulator; import com.intellij.psi.PsiElement; import com.intellij.util.IncorrectOperationException; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrLiteral; +import org.jetbrains.plugins.groovy.lang.psi.util.GrStringUtil; public class GroovyStringLiteralManipulator extends AbstractElementManipulator { public GrLiteral handleContentChange(GrLiteral expr, TextRange range, String newContent) throws IncorrectOperationException { if (!(expr.getValue() instanceof String)) throw new IncorrectOperationException("cannot handle content change"); String oldText = expr.getText(); - newContent = StringUtil.escapeStringCharacters(newContent); - String newText = oldText.substring(0, range.getStartOffset()) + newContent + oldText.substring(range.getEndOffset()); + if (oldText.startsWith("'")) { + newContent = GrStringUtil.escapeSymbolsForString(newContent, !oldText.startsWith("'''"), true); + } + else { + newContent = GrStringUtil.escapeSymbolsForGString(newContent, !oldText.startsWith("\"\"\""), true); + } + String newText; + if (range.getStartOffset() == 1 && (newContent.indexOf('\n') >= 0 || newContent.indexOf('\r') >= 0)) { + String corner = oldText.substring(0, 1) + oldText.substring(0, 1) + oldText.substring(0, 1); + newText = corner + newContent + corner; + } + else { + newText = oldText.substring(0, range.getStartOffset()) + newContent + oldText.substring(range.getEndOffset()); + } final GrExpression newExpr = GroovyPsiElementFactory.getInstance(expr.getProject()).createExpressionFromText(newText); PsiElement firstChild = expr.getFirstChild(); @@ -48,9 +60,18 @@ public class GroovyStringLiteralManipulator extends AbstractElementManipulator 6 && text.startsWith("\"\"\"") && text.endsWith("\"\"\"")) { - return new TextRange(3, text.length() - 3); + int start = 1; + int fin = text.length(); + + String begin = text.substring(0, 1); + if (text.startsWith("\"\"\"") || text.startsWith("'''")) { + start += 2; + begin = text.substring(0, 3); } - return new TextRange(1, Math.max(1, text.length() - 1)); + + if (text.length() >= begin.length()*2 && text.endsWith(begin)) { + fin -= begin.length(); + } + return new TextRange(start, Math.max(1, fin)); } } \ No newline at end of file diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.java index fa1112c49f61..be64439c4b1a 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.java +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.java @@ -420,4 +420,8 @@ public class GroovyHighlightingTest extends LightCodeInsightFixtureTestCase { public void testResultOfIncUsed() { doTest(new GroovyResultOfIncrementOrDecrementUsedInspection()); } + + public void testNativeMapAssignability() { + doTest(new GroovyAssignabilityCheckInspection()); + } } \ No newline at end of file diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/ExpressionsParsingTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/ExpressionsParsingTest.groovy index ca41c84868ef..da89e29ed17a 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/ExpressionsParsingTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/ExpressionsParsingTest.groovy @@ -281,4 +281,7 @@ public class ExpressionsParsingTest extends GroovyParsingTestCase { public void testcommandExpr$keywords() {doTest()} public void testDiamond() {doTest()} + + void testpath$stringMethodCall1() {doTest()} + void testpath$stringMethodCall2() {doTest()} } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveMethodTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveMethodTest.groovy index 85e6d88a51da..d6dcfa02096f 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveMethodTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveMethodTest.groovy @@ -713,4 +713,16 @@ class Foo { PsiReference ref = configureByFile("staticImportInSamePackage/A.groovy", "A.groovy"); assertNotNull(ref.resolve()) } + + void testStringRefExpr1() { + assertNotNull(resolve("a.groovy")); + } + + void testStringRefExpr2() { + assertNotNull(resolve("a.groovy")); + } + + void testStringRefExpr3() { + assertNotNull(resolve("a.groovy")); + } } diff --git a/plugins/groovy/testdata/highlighting/NativeMapAssignability.groovy b/plugins/groovy/testdata/highlighting/NativeMapAssignability.groovy new file mode 100644 index 000000000000..194dfd1d6bb4 --- /dev/null +++ b/plugins/groovy/testdata/highlighting/NativeMapAssignability.groovy @@ -0,0 +1,5 @@ +def foo(Map> m) {} + +foo(a:[b:'c']) +foo(a:'b') +foo(a:[(2):4]) \ No newline at end of file diff --git a/plugins/groovy/testdata/highlighting/NumberDuplicatesInMaps.groovy b/plugins/groovy/testdata/highlighting/NumberDuplicatesInMaps.groovy index 79850ae0531a..75b643b63990 100644 --- a/plugins/groovy/testdata/highlighting/NumberDuplicatesInMaps.groovy +++ b/plugins/groovy/testdata/highlighting/NumberDuplicatesInMaps.groovy @@ -1 +1 @@ -def map = [1:'d', (1):'sd'] \ No newline at end of file +def map = [1:'d', 1:'sd'] \ No newline at end of file diff --git a/plugins/groovy/testdata/parsing/groovy/expressions/path/stringMethodCall1.test b/plugins/groovy/testdata/parsing/groovy/expressions/path/stringMethodCall1.test new file mode 100644 index 000000000000..570dd565016e --- /dev/null +++ b/plugins/groovy/testdata/parsing/groovy/expressions/path/stringMethodCall1.test @@ -0,0 +1,9 @@ +'foo'() +----- +Groovy script + Method call + Reference expression + PsiElement(string)(''foo'') + Arguments + PsiElement(()('(') + PsiElement())(')') \ No newline at end of file diff --git a/plugins/groovy/testdata/parsing/groovy/expressions/path/stringMethodCall2.test b/plugins/groovy/testdata/parsing/groovy/expressions/path/stringMethodCall2.test new file mode 100644 index 000000000000..44b0e78720fb --- /dev/null +++ b/plugins/groovy/testdata/parsing/groovy/expressions/path/stringMethodCall2.test @@ -0,0 +1,18 @@ +'foo'.substring(0, 1) +----- +Groovy script + Method call + Reference expression + Literal + PsiElement(string)(''foo'') + PsiElement(.)('.') + PsiElement(identifier)('substring') + Arguments + PsiElement(()('(') + Literal + PsiElement(Integer)('0') + PsiElement(,)(',') + PsiWhiteSpace(' ') + Literal + PsiElement(Integer)('1') + PsiElement())(')') \ No newline at end of file diff --git a/plugins/groovy/testdata/resolve/method/stringRefExpr1/a.groovy b/plugins/groovy/testdata/resolve/method/stringRefExpr1/a.groovy new file mode 100644 index 000000000000..f6b636731b04 --- /dev/null +++ b/plugins/groovy/testdata/resolve/method/stringRefExpr1/a.groovy @@ -0,0 +1,3 @@ +def foo(){} + +'foo'() \ No newline at end of file diff --git a/plugins/groovy/testdata/resolve/method/stringRefExpr2/a.groovy b/plugins/groovy/testdata/resolve/method/stringRefExpr2/a.groovy new file mode 100644 index 000000000000..2d91530b5e38 --- /dev/null +++ b/plugins/groovy/testdata/resolve/method/stringRefExpr2/a.groovy @@ -0,0 +1,3 @@ +def foo(){} + +"foo"() \ No newline at end of file diff --git a/plugins/groovy/testdata/resolve/method/stringRefExpr3/a.groovy b/plugins/groovy/testdata/resolve/method/stringRefExpr3/a.groovy new file mode 100644 index 000000000000..4905ed36cba9 --- /dev/null +++ b/plugins/groovy/testdata/resolve/method/stringRefExpr3/a.groovy @@ -0,0 +1,3 @@ +def 'foo bar'(){} + +'foo bar'() \ No newline at end of file diff --git a/plugins/svn4idea/src/META-INF/plugin.xml b/plugins/svn4idea/src/META-INF/plugin.xml index 83678d867667..4dfe7269b05b 100644 --- a/plugins/svn4idea/src/META-INF/plugin.xml +++ b/plugins/svn4idea/src/META-INF/plugin.xml @@ -86,6 +86,12 @@ + + + + + + diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnChangeProviderContext.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnChangeProviderContext.java index 7e1f78e3a04a..1b137549d159 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnChangeProviderContext.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnChangeProviderContext.java @@ -239,6 +239,9 @@ class SvnChangeProviderContext implements StatusReceiver { myChangelistBuilder.processChangeInList(createChange(SvnContentRevision.create(myVcs, filePath, status.getCommittedRevision()), CurrentContentRevision.create(filePath), FileStatus.MODIFIED, status), changeListNameFromStatus(status), SvnVcs.getKey()); + } else if (status.getTreeConflict() != null) { + myChangelistBuilder.processChange(createChange(SvnContentRevision.create(myVcs, filePath, status.getCommittedRevision()), + CurrentContentRevision.create(filePath), FileStatus.MODIFIED, status), SvnVcs.getKey()); } checkSwitched(filePath, myChangelistBuilder, status, fStatus); } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnLocallyDeletedChange.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnLocallyDeletedChange.java index 33278d97abf1..c290aa7b5ad5 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnLocallyDeletedChange.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnLocallyDeletedChange.java @@ -15,8 +15,8 @@ */ package org.jetbrains.idea.svn; -import com.intellij.openapi.vcs.changes.LocallyDeletedChange; import com.intellij.openapi.vcs.FilePath; +import com.intellij.openapi.vcs.changes.LocallyDeletedChange; import org.jetbrains.annotations.NotNull; import javax.swing.*; @@ -42,4 +42,8 @@ public class SvnLocallyDeletedChange extends LocallyDeletedChange { } return description; } + + public ConflictState getConflictState() { + return myConflictState; + } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/MarkLocallyDeletedTreeConflictResolvedAction.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/MarkLocallyDeletedTreeConflictResolvedAction.java new file mode 100644 index 000000000000..a363423aba5a --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/MarkLocallyDeletedTreeConflictResolvedAction.java @@ -0,0 +1,163 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.idea.svn.actions; + +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.actionSystem.PlatformDataKeys; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.progress.Task; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.util.Ref; +import com.intellij.openapi.vcs.AbstractVcsHelper; +import com.intellij.openapi.vcs.FilePath; +import com.intellij.openapi.vcs.VcsDataKeys; +import com.intellij.openapi.vcs.VcsException; +import com.intellij.openapi.vcs.changes.BackgroundFromStartOption; +import com.intellij.openapi.vcs.changes.Change; +import com.intellij.openapi.vcs.changes.LocallyDeletedChange; +import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager; +import com.intellij.openapi.vcs.changes.ui.ChangesListView; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.idea.svn.ConflictedSvnChange; +import org.jetbrains.idea.svn.SvnBundle; +import org.jetbrains.idea.svn.SvnLocallyDeletedChange; +import org.jetbrains.idea.svn.SvnVcs; +import org.tmatesoft.svn.core.SVNDepth; +import org.tmatesoft.svn.core.SVNException; +import org.tmatesoft.svn.core.wc.SVNConflictChoice; +import org.tmatesoft.svn.core.wc.SVNWCClient; + +import java.util.Collections; +import java.util.List; + +/** + * @author irengrig + * Date: 6/8/11 + * Time: 4:58 PM + */ +public class MarkLocallyDeletedTreeConflictResolvedAction extends AnAction { + public MarkLocallyDeletedTreeConflictResolvedAction() { + super(SvnBundle.message("action.mark.tree.conflict.resolved.text")); + } + + @Override + public void actionPerformed(AnActionEvent e) { + final MyLocallyDeletedChecker locallyDeletedChecker = new MyLocallyDeletedChecker(e); + if (! locallyDeletedChecker.isEnabled()) return; + + final String markText = SvnBundle.message("action.mark.tree.conflict.resolved.confirmation.title"); + final Project project = locallyDeletedChecker.getProject(); + final int result = Messages.showYesNoDialog(project, + SvnBundle.message("action.mark.tree.conflict.resolved.confirmation.text"), markText, + Messages.getQuestionIcon()); + if (result == DialogWrapper.OK_EXIT_CODE) { + final Ref exception = new Ref(); + ProgressManager + .getInstance().run(new Task.Backgroundable(project, markText, true, BackgroundFromStartOption.getInstance()) { + public void run(@NotNull ProgressIndicator indicator) { + resolveLocallyDeletedTextConflict(locallyDeletedChecker, exception); + } + }); + if (! exception.isNull()) { + AbstractVcsHelper.getInstance(project).showError(exception.get(), markText); + } + } + } + + @Override + public void update(AnActionEvent e) { + final MyLocallyDeletedChecker locallyDeletedChecker = new MyLocallyDeletedChecker(e); + e.getPresentation().setVisible(locallyDeletedChecker.isEnabled()); + e.getPresentation().setEnabled(locallyDeletedChecker.isEnabled()); + //e.getPresentation().setText(SvnBundle.message("action.mark.tree.conflict.resolved.text")); + } + + private void resolveLocallyDeletedTextConflict(MyLocallyDeletedChecker checker, Ref exception) { + final FilePath path = checker.getPath(); + resolve(checker.getProject(), exception, path); + VcsDirtyScopeManager.getInstance(checker.getProject()).filePathsDirty(Collections.singletonList(path), null); + } + + private void resolve(Project project, Ref exception, FilePath path) { + final SVNWCClient client = SvnVcs.getInstance(project).createWCClient(); + try { + client.doResolve(path.getIOFile(), SVNDepth.EMPTY, false, false, true, SVNConflictChoice.MERGED); + } + catch (SVNException e1) { + exception.set(new VcsException(e1)); + } + } + + private static class MyLocallyDeletedChecker { + private final boolean myEnabled; + private final FilePath myPath; + private final Project myProject; + + public MyLocallyDeletedChecker(final AnActionEvent e) { + final DataContext dc = e.getDataContext(); + myProject = PlatformDataKeys.PROJECT.getData(dc); + if (myProject == null) { + myPath = null; + myEnabled = false; + return; + } + + final List missingFiles = e.getData(ChangesListView.LOCALLY_DELETED_CHANGES); + + if (missingFiles == null || missingFiles.size() != 1) { + final Change[] changes = e.getData(VcsDataKeys.CHANGES); + if (changes == null || changes.length != 1 || changes[0].getAfterRevision() != null) { + myPath = null; + myEnabled = false; + return; + } + myEnabled = changes[0] instanceof ConflictedSvnChange && ((ConflictedSvnChange) changes[0]).getConflictState().isTree(); + if (myEnabled) { + myPath = changes[0].getBeforeRevision().getFile(); + } else { + myPath = null; + } + return; + } + + final LocallyDeletedChange change = missingFiles.get(0); + myEnabled = change instanceof SvnLocallyDeletedChange && ((SvnLocallyDeletedChange) change).getConflictState().isTree(); + if (myEnabled) { + myPath = ((SvnLocallyDeletedChange) change).getPath(); + } + else { + myPath = null; + } + } + + public boolean isEnabled() { + return myEnabled; + } + + public FilePath getPath() { + return myPath; + } + + public Project getProject() { + return myProject; + } + } +}